*** empty log message ***
[csql.git] / src / storage / DbMgrTableImpl.cxx
blob6479936dfc5ddd18079018207e1ee2398ca35985
1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 ***************************************************************************/
16 #include<Database.h>
17 #include<DatabaseManager.h>
18 #include<DatabaseManagerImpl.h>
19 #include<os.h>
20 #include<Table.h>
21 #include<TableImpl.h>
22 #include<Transaction.h>
23 #include<CatalogTables.h>
24 #include<Index.h>
25 #include<Lock.h>
26 #include<Debug.h>
27 #include<Config.h>
28 #include<Process.h>
30 //-1 -> Unable to create chunk. No memory
31 //-2 -> Unable to update the catalog tables
32 DbRetVal DatabaseManagerImpl::createTable(const char *name, TableDef &def)
34 DbRetVal rv = OK;
35 if (!Util::isIdentifier((char*)name)) {
36 printError(ErrBadArg, "Invalid character for index name");
37 return ErrBadArg;
39 int fldCount = def.getFieldCount();
40 if(0==fldCount)
42 printError(ErrNotExists,"Table can't be created without Field");
43 return ErrNotExists;
46 //If total field count is within 32, then 1 integer is used to store all
47 // null information, if it is more then 1 char is used to store null
48 // information of each field
49 //This is to done to reduce cpu cycles for small tables
50 int addSize = 0;
51 if (fldCount <= 32) addSize = 4; else addSize = os::align(fldCount);
52 size_t sizeofTuple = os::alignLong(def.getTupleSize()+addSize);
53 rv = systemDatabase_->getXCheckpointMutex();
54 if (OK != rv ) {
55 printError(rv, "Unable to get Database mutex");
56 return rv;
59 void *tptr =NULL;
60 void *chunk = NULL;
61 void *vcchunk = NULL;
63 //check whether table already exists
64 CatalogTableTABLE cTable(systemDatabase_);
65 cTable.getChunkAndTblPtr(name, chunk, tptr, vcchunk);
66 if (NULL != tptr)
68 systemDatabase_->releaseCheckpointMutex();
69 printError(ErrAlready, "Table %s already exists", name);
70 return ErrAlready;
73 //create a chunk to store the tuples
74 Chunk *ptr = createUserChunk(sizeofTuple);
75 if (NULL == ptr)
77 systemDatabase_->releaseCheckpointMutex();
78 printError(ErrNoResource, "Unable to create user chunk");
79 return ErrNoResource;
81 printDebug(DM_Database,"Created UserChunk:%x", ptr);
82 ptr->setChunkName(name);
83 //add row to TABLE
84 int tblID = ((Chunk*)ptr)->getChunkID();
86 //check whether varchar is present in table
87 FieldIterator fiter = def.getFieldIterator();
88 bool isVarcharPresent = def.isVarcharPresentInSchema(fiter);
89 Chunk *vcptr = NULL;
90 if (isVarcharPresent) {
91 //creat chunk to store varchar values
92 vcptr = createUserChunk();
93 if (NULL == vcptr)
95 deleteUserChunk(ptr);
96 systemDatabase_->releaseCheckpointMutex();
97 printError(ErrNoResource, "Unable to create user chunk for varchar");
98 return ErrNoResource;
100 printDebug(DM_Database,"Created UserChunk for Varchar:%x", vcptr);
101 vcptr->setChunkName(name);
103 rv = cTable.insert(name, tblID, sizeofTuple,
104 def.getFieldCount(), ptr, tptr, vcptr);
105 if (OK != rv)
107 deleteUserChunk(ptr);
108 if (vcptr) deleteUserChunk(vcptr);
109 systemDatabase_->releaseCheckpointMutex();
110 printError(ErrSysInternal, "Unable to update catalog table TABLE");
111 return ErrSysInternal;
113 printDebug(DM_Database,"Inserted into TABLE:%s",name);
114 //add rows to FIELD
115 FieldIterator iter = def.getFieldIterator();
116 CatalogTableFIELD cField(systemDatabase_);
117 rv = cField.insert(iter, tblID ,tptr);
118 if (OK != rv)
120 deleteUserChunk(ptr);
121 if (vcptr) deleteUserChunk(vcptr);
122 void *cptr, *ttptr;//Dummy as remove below needs both these OUT params
123 cTable.remove(name, cptr, ttptr);
124 systemDatabase_->releaseCheckpointMutex();
125 printError(ErrSysInternal, "Unable to update catalog table FIELD");
126 return ErrSysInternal;
128 printDebug(DM_Database,"Inserted into FIELD:%s",name);
129 systemDatabase_->releaseCheckpointMutex();
130 printDebug(DM_Database,"Table Created:%s",name);
131 logFinest(Conf::logger, "Table Created %s" , name);
132 return OK;
135 DbRetVal DatabaseManagerImpl::renameTable(const char *oldName,const char *newName)
137 void *chunk = NULL;
138 DbRetVal rv = systemDatabase_->getXCheckpointMutex();
139 if (OK != rv) {
140 printError(ErrSysInternal, "Unable to get database mutex for rename table");
141 return ErrSysInternal;
143 CatalogTableTABLE cTable(systemDatabase_);
144 rv = cTable.renameTable(oldName,newName);
145 if (OK != rv) {
146 printError(ErrSysInternal, "Unable to rename table");
147 systemDatabase_->releaseCheckpointMutex();
148 return ErrSysInternal;
150 systemDatabase_->releaseCheckpointMutex();
151 return OK;
154 DbRetVal DatabaseManagerImpl::renameField(const char *tableName,const char *oldName,const char *newName)
156 DbRetVal rv = systemDatabase_->getXCheckpointMutex();
157 if (OK != rv) {
158 printError(ErrSysInternal, "Unable to get database mutex for rename table");
159 return ErrSysInternal;
161 CatalogTableFIELD fTable(systemDatabase_);
162 rv = fTable.renameField(tableName, oldName, newName);
163 if (OK != rv) {
164 printError(ErrSysInternal, "Unable to rename field.");
165 systemDatabase_->releaseCheckpointMutex();
166 return ErrSysInternal;
168 systemDatabase_->releaseCheckpointMutex();
169 return rv;
172 //TODO::If any operation fails in between, then we may have some
173 //dangling tuples, say we have have rows in INDEX table
174 //which will not have any corresponding entries in TABLE
175 //CHANGE the sequence so that it deletes from the bottom as
176 //opposed to start from top as is written now
177 DbRetVal DatabaseManagerImpl::dropTable(const char *name)
179 void *chunk = NULL;
180 void *tptr =NULL;
181 void *vcchunk = NULL;
182 DbRetVal rv = systemDatabase_->getXCheckpointMutex();
183 if (OK != rv) {
184 printError(ErrSysInternal, "Unable to get database mutex");
185 return ErrSysInternal;
187 //remove the entry in TABLE
188 CatalogTableTABLE cTable(systemDatabase_);
189 rv = cTable.getChunkAndTblPtr(name, chunk, tptr, vcchunk);
190 if (OK != rv) {
191 systemDatabase_->releaseCheckpointMutex();
192 printError(ErrSysInternal, "Table %s does not exist", name);
193 return ErrSysInternal;
195 CatalogTableFK cFK(systemDatabase_);
196 int noOfRelation =cFK.getNumFkTable(tptr);
197 if(noOfRelation)
199 printError(ErrSysInternal, "Unable to drop table due to relation exist.Drop child table...");
200 systemDatabase_->releaseCheckpointMutex();
201 return ErrSysInternal;
203 txnMgr()->rollback(lockMgr());
204 txnMgr()->startTransaction(lockMgr(), READ_COMMITTED);
205 Transaction **trans = ProcessManager::getThreadTransAddr(systemDatabase_->procSlot);
206 rv = lMgr_->getExclusiveLock(chunk, trans);
207 if (rv !=OK)
209 systemDatabase_->releaseCheckpointMutex();
210 txnMgr()->rollback(lockMgr());
211 printError(ErrLockTimeOut, "Unable to acquire exclusive lock on the table\n");
212 return rv;
214 rv = cTable.remove(name, chunk, tptr);
215 if (OK != rv) {
216 systemDatabase_->releaseCheckpointMutex();
217 txnMgr()->rollback(lockMgr());
218 printError(ErrSysInternal, "Unable to update catalog table TABLE");
219 return ErrSysInternal;
221 printDebug(DM_Database,"Deleted from TABLE:%s",name);
223 //remove the entries in the FIELD table
224 CatalogTableFIELD cField(systemDatabase_);
225 rv = cField.remove(tptr);
226 if (OK != rv) {
227 systemDatabase_->releaseCheckpointMutex();
228 txnMgr()->rollback(lockMgr());
229 printError(ErrSysInternal, "Unable to update catalog table FIELD");
230 return ErrSysInternal;
232 printDebug(DM_Database,"Deleted from FIELD:%s",name);
234 rv = deleteUserChunk((Chunk*)chunk);
235 if (OK != rv) {
236 systemDatabase_->releaseCheckpointMutex();
237 txnMgr()->rollback(lockMgr());
238 printError(rv, "Unable to delete the chunk");
239 return rv;
241 printDebug(DM_Database,"Deleted UserChunk:%x", chunk);
243 if (vcchunk != NULL) {
244 rv = deleteUserChunk((Chunk*)vcchunk);
245 if (OK != rv) {
246 systemDatabase_->releaseCheckpointMutex();
247 txnMgr()->rollback(lockMgr());
248 printError(rv, "Unable to delete the chunk");
249 return rv;
251 printDebug(DM_Database,"Deleted UserChunk for Varchar:%x", chunk);
254 //TODO::check whether indexes are available and drop that also.
255 CatalogTableINDEX cIndex(systemDatabase_);
256 int noIndexes = cIndex.getNumIndexes(tptr);
257 for (int i =1 ; i<= noIndexes; i++) {
258 char *idxName = cIndex.getIndexName(tptr, 1);
259 dropIndexInt(idxName, false);
261 bool isFkExist=cFK.isFkTable(tptr);
262 if(isFkExist)
264 dropForeignKey(tptr,false);
266 systemDatabase_->releaseCheckpointMutex();
267 printDebug(DM_Database, "Deleted Table %s" , name);
268 logFinest(Conf::logger, "Deleted Table %s" , name);
269 rv = txnMgr()->commit(lockMgr());
270 if (rv !=OK)
272 printError(ErrLockTimeOut, "Unable to release exclusive lock on the table\n");
273 return rv;
275 return OK;
278 //Return values: NULL for table not found
279 Table* DatabaseManagerImpl::openTable(const char *name,bool checkpkfk)
281 DbRetVal ret = OK;
282 //TODO::store table handles in list so that if it is
283 //not closed by the application. destructor shall close it.
284 TableImpl *table = new TableImpl();
285 table->setDB(db_);
286 table->setSystemDB(systemDatabase_);
287 table->setLockManager(lMgr_);
288 table->setTrans(ProcessManager::getThreadTransAddr(systemDatabase_->procSlot));
290 //to store the chunk pointer of table
291 void *chunk = NULL;
292 void *vcchunk = NULL;
294 //to store the tuple pointer of the table
295 void *tptr =NULL;
297 //TODO::need to take shared lock on the table so that
298 //all ddl operation will be denied on that table
299 //which includes index creation, alter table
301 DbRetVal rv = systemDatabase_->getAllocDatabaseMutex();
302 if (OK != rv) {
303 printError(ErrSysInternal, "Unable to get database mutex");
304 delete table;
305 return NULL;
307 CatalogTableTABLE cTable(systemDatabase_);
308 ret = cTable.getChunkAndTblPtr(name, chunk, tptr, vcchunk);
309 if ( OK != ret)
311 systemDatabase_->releaseAllocDatabaseMutex();
312 delete table;
313 printError(ErrNotExists, "Table not exists %s", name);
314 return NULL;
316 CTABLE *tTuple = (CTABLE*)tptr;
317 table->setTableInfo(tTuple->tblName_, tTuple->tblID_, tTuple->length_,
318 tTuple->numFlds_, tTuple->numIndexes_,
319 tTuple->chunkPtr_, tTuple->varcharChunkPtr_);
320 rv = table->lock(true); //take shared lock
321 if (rv !=OK)
323 printError(ErrLockTimeOut, "Unable to acquire shared lock on the table\n");
324 systemDatabase_->releaseAllocDatabaseMutex();
325 delete table;
326 return NULL;
329 if (tTuple->numFlds_ <= 32)
331 table->isIntUsedForNULL = true;
332 table->iNullInfo = 0;
333 table->iNotNullInfo =0;
335 else
337 table->isIntUsedForNULL = false;
338 int noFields = os::align(tTuple->numFlds_);
339 table->cNullInfo = (char*) malloc(noFields);
340 table->cNotNullInfo = (char*) malloc(noFields);
341 for (int i =0 ; i < noFields; i++) table->cNullInfo[i] =0;
342 for (int i =0 ; i < noFields; i++) table->cNotNullInfo[i] =0;
346 //get field information from FIELD table
347 CatalogTableFIELD cField(systemDatabase_);
348 table->ptrToAuto = cField.getFieldInfo(tptr, table->fldList_);
350 //populate the notnull info
351 FieldIterator fIter = table->fldList_.getIterator();
352 int fldpos=1;
353 while (fIter.hasElement())
355 FieldDef *def = fIter.nextElement();
356 if (table->isIntUsedForNULL) {
357 if (def->isNull_) SETBIT(table->iNotNullInfo, fldpos-1);
359 else {
360 if (def->isNull_) table->cNotNullInfo[fldpos-1] = 1;
362 fldpos++;
365 //get the number of indexes on this table
366 //and populate the indexPtr array
367 CatalogTableINDEX cIndex(systemDatabase_);
368 table->numIndexes_ = cIndex.getNumIndexes(tptr);
369 if (table->numIndexes_) {
370 table->indexPtr_ = new char*[table->numIndexes_];
371 table->idxInfo = new IndexInfo*[table->numIndexes_];
373 else
375 table->indexPtr_ = NULL;
377 cIndex.getIndexPtrs(tptr, table->indexPtr_);
378 for (int i =0 ; i < table->numIndexes_; i++ )
380 HashIndexInfo *hIdxInfo = new HashIndexInfo();
381 CatalogTableINDEXFIELD cIndexField(systemDatabase_);
382 cIndexField.getFieldInfo(table->indexPtr_[i], hIdxInfo->idxFldList);
383 ChunkIterator citer = CatalogTableINDEX::getIterator(table->indexPtr_[i]);
384 hIdxInfo->indexPtr = table->indexPtr_[i];
385 hIdxInfo->indType = ((CINDEX*)hIdxInfo->indexPtr)->indexType_;
386 hIdxInfo->noOfBuckets = CatalogTableINDEX::getNoOfBuckets(table->indexPtr_[i]);
387 FieldIterator fIter = hIdxInfo->idxFldList.getIterator();
388 bool firstFld = true;
389 while (fIter.hasElement())
391 FieldDef *def = fIter.nextElement();
392 if (firstFld)
394 hIdxInfo->fldOffset = table->fldList_.getFieldOffset(def->fldName_);
395 hIdxInfo->type = table->fldList_.getFieldType(def->fldName_);
396 hIdxInfo->compLength = table->fldList_.getFieldLength(def->fldName_);
397 firstFld = false;
398 }else {
399 hIdxInfo->type = typeComposite;
400 hIdxInfo->compLength = hIdxInfo->compLength +
401 table->fldList_.getFieldLength(def->fldName_);
405 hIdxInfo->isUnique = CatalogTableINDEX::getUnique(table->indexPtr_[i]);
406 hIdxInfo->buckets = (Bucket*)citer.nextElement();
407 table->idxInfo[i] = (IndexInfo*) hIdxInfo;
409 systemDatabase_->releaseAllocDatabaseMutex();
410 //Foreign key Operation
411 if(checkpkfk){
412 CatalogTableFK cFk(systemDatabase_);
413 int totalFld=0;
414 table->numFkRelation_ = cFk.getNumFkTable(tptr);
415 if (table->numFkRelation_) {
416 table->isPkTbl=true;//TODO:for Delete In casecade
417 totalFld=cFk.getNoOfFkTable(tptr);
418 //printDebug(DM_TEST,"Total table is %d\n",totalFld);
419 char **fptr = new char* [totalFld];
420 cFk.getFkTableName(tptr,fptr);
421 for(int count=0; count < totalFld; count++){
422 //printDebug(DM_TEST,"FK Name is %s\n",fptr[count]);
423 Table *pkTable=openTable(fptr[count],false);
424 if (pkTable) table->tblFkList.append(pkTable);
425 else {
426 printError(ErrSysInternal, "Unable to open foreign key tables");
427 delete[] fptr;
428 pkTable->close();
429 return NULL;
432 delete[] fptr;
435 char *tblName = NULL;
436 table->isFkTbl = cFk.isFkTable(tptr);
437 if(table->isFkTbl)
439 totalFld=cFk.getNoOfPkTable(tptr);
440 char **fptr = new char* [totalFld];
441 cFk.getPkTableName(tptr,fptr);
442 for(int count=0; count<totalFld; count++){
443 //printDebug(DM_TEST,"Parent Name is %s\n",fptr[count]);
444 Table *fkTable = openTable(fptr[count],false);
445 if (fkTable) table->tblList.append(fkTable);
446 else {
447 printError(ErrSysInternal, "Unable to open foreign key tables");
448 delete[] fptr;
449 fkTable->close();
450 return NULL;
453 delete[] fptr;
456 printDebug(DM_Database,"Opening table handle name:%s chunk:%x numIndex:%d",
457 name, chunk, table->numIndexes_);
458 logFinest(Conf::logger, "Opening Table %s" , name);
459 return table;
462 List DatabaseManagerImpl::getAllTableNames(int *retval)
464 DbRetVal ret = OK;
465 //to store the tuple pointer of the table
466 void *tptr =NULL;
468 /*DbRetVal rv = systemDatabase_->getSCheckpointMutex();
469 if (OK != rv) {
470 printError(ErrSysInternal, "Unable to get checkpoint mutex");
471 if(retval) *retval = rv;
472 List tableList;
473 return tableList;
475 CatalogTableTABLE cTable(systemDatabase_);
476 List tableList = cTable.getTableList();
477 //systemDatabase_->releaseCheckpointMutex();
478 return tableList;
482 //Return values: -1 for table not found
483 void DatabaseManagerImpl::closeTable(Table *table)
485 printDebug(DM_Database,"Closing table handle: %x", table);
486 if (NULL == table) return;
487 table->unlock();
488 /* TableImpl *fkTbl =NULL;
489 ListIterator tblIter = ((TableImpl*)table)->tblList.getIterator();
490 tblIter.reset();
491 while (tblIter.hasElement()){
492 fkTbl = (TableImpl *) tblIter.nextElement();
493 closeTable(fkTbl);
495 ((TableImpl*)table)->tblList.reset();
496 tblIter = ((TableImpl*)table)->tblFkList.getIterator();
497 tblIter.reset();
498 while (tblIter.hasElement()){
499 fkTbl = (TableImpl *) tblIter.nextElement();
500 closeTable(fkTbl);
502 ((TableImpl*)table)->tblFkList.reset();*/
503 if (table) delete table; table = NULL;
504 logFinest(Conf::logger, "Closing Table");
507 int DatabaseManagerImpl::getNoOfPagesForTable(char *tblName)
509 Table *tbl = openTable(tblName);
510 if (NULL == tbl) {
511 printError(ErrSysInternal, "Unable to open table %s", tblName);
512 return 0;
514 TableImpl *tb = (TableImpl *) tbl;
515 int pages = 0;
516 if (tb->numTuples()) pages = tb->pagesUsed();
517 closeTable(tbl);
518 return pages;