1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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. *
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. *
15 ***************************************************************************/
17 #include<DatabaseManager.h>
18 #include<DatabaseManagerImpl.h>
22 #include<Transaction.h>
23 #include<CatalogTables.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
)
35 if (!Util::isIdentifier((char*)name
)) {
36 printError(ErrBadArg
, "Invalid character for index name");
39 int fldCount
= def
.getFieldCount();
42 printError(ErrNotExists
,"Table can't be created without Field");
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
51 if (fldCount
<= 32) addSize
= 4; else addSize
= os::align(fldCount
);
52 size_t sizeofTuple
= os::alignLong(def
.getTupleSize()+addSize
);
53 rv
= systemDatabase_
->getXCheckpointMutex();
55 printError(rv
, "Unable to get Database mutex");
63 //check whether table already exists
64 CatalogTableTABLE
cTable(systemDatabase_
);
65 cTable
.getChunkAndTblPtr(name
, chunk
, tptr
, vcchunk
);
68 systemDatabase_
->releaseCheckpointMutex();
69 printError(ErrAlready
, "Table %s already exists", name
);
73 //create a chunk to store the tuples
74 Chunk
*ptr
= createUserChunk(sizeofTuple
);
77 systemDatabase_
->releaseCheckpointMutex();
78 printError(ErrNoResource
, "Unable to create user chunk");
81 printDebug(DM_Database
,"Created UserChunk:%x", ptr
);
82 ptr
->setChunkName(name
);
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
);
90 if (isVarcharPresent
) {
91 //creat chunk to store varchar values
92 vcptr
= createUserChunk();
96 systemDatabase_
->releaseCheckpointMutex();
97 printError(ErrNoResource
, "Unable to create user chunk for varchar");
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
);
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
);
115 FieldIterator iter
= def
.getFieldIterator();
116 CatalogTableFIELD
cField(systemDatabase_
);
117 rv
= cField
.insert(iter
, tblID
,tptr
);
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
);
135 DbRetVal
DatabaseManagerImpl::renameTable(const char *oldName
,const char *newName
)
138 DbRetVal rv
= systemDatabase_
->getXCheckpointMutex();
140 printError(ErrSysInternal
, "Unable to get database mutex for rename table");
141 return ErrSysInternal
;
143 CatalogTableTABLE
cTable(systemDatabase_
);
144 rv
= cTable
.renameTable(oldName
,newName
);
146 printError(ErrSysInternal
, "Unable to rename table");
147 systemDatabase_
->releaseCheckpointMutex();
148 return ErrSysInternal
;
150 systemDatabase_
->releaseCheckpointMutex();
154 DbRetVal
DatabaseManagerImpl::renameField(const char *tableName
,const char *oldName
,const char *newName
)
156 DbRetVal rv
= systemDatabase_
->getXCheckpointMutex();
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
);
164 printError(ErrSysInternal
, "Unable to rename field.");
165 systemDatabase_
->releaseCheckpointMutex();
166 return ErrSysInternal
;
168 systemDatabase_
->releaseCheckpointMutex();
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
)
181 void *vcchunk
= NULL
;
182 DbRetVal rv
= systemDatabase_
->getXCheckpointMutex();
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
);
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
);
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
);
209 systemDatabase_
->releaseCheckpointMutex();
210 txnMgr()->rollback(lockMgr());
211 printError(ErrLockTimeOut
, "Unable to acquire exclusive lock on the table\n");
214 rv
= cTable
.remove(name
, chunk
, tptr
);
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
);
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
);
236 systemDatabase_
->releaseCheckpointMutex();
237 txnMgr()->rollback(lockMgr());
238 printError(rv
, "Unable to delete the chunk");
241 printDebug(DM_Database
,"Deleted UserChunk:%x", chunk
);
243 if (vcchunk
!= NULL
) {
244 rv
= deleteUserChunk((Chunk
*)vcchunk
);
246 systemDatabase_
->releaseCheckpointMutex();
247 txnMgr()->rollback(lockMgr());
248 printError(rv
, "Unable to delete the chunk");
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
);
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());
272 printError(ErrLockTimeOut
, "Unable to release exclusive lock on the table\n");
278 //Return values: NULL for table not found
279 Table
* DatabaseManagerImpl::openTable(const char *name
,bool checkpkfk
)
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();
286 table
->setSystemDB(systemDatabase_
);
287 table
->setLockManager(lMgr_
);
288 table
->setTrans(ProcessManager::getThreadTransAddr(systemDatabase_
->procSlot
));
290 //to store the chunk pointer of table
292 void *vcchunk
= NULL
;
294 //to store the tuple pointer of the table
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();
303 printError(ErrSysInternal
, "Unable to get database mutex");
307 CatalogTableTABLE
cTable(systemDatabase_
);
308 ret
= cTable
.getChunkAndTblPtr(name
, chunk
, tptr
, vcchunk
);
311 systemDatabase_
->releaseAllocDatabaseMutex();
313 printError(ErrNotExists
, "Table not exists %s", name
);
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
323 printError(ErrLockTimeOut
, "Unable to acquire shared lock on the table\n");
324 systemDatabase_
->releaseAllocDatabaseMutex();
329 if (tTuple
->numFlds_
<= 32)
331 table
->isIntUsedForNULL
= true;
332 table
->iNullInfo
= 0;
333 table
->iNotNullInfo
=0;
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();
353 while (fIter
.hasElement())
355 FieldDef
*def
= fIter
.nextElement();
356 if (table
->isIntUsedForNULL
) {
357 if (def
->isNull_
) SETBIT(table
->iNotNullInfo
, fldpos
-1);
360 if (def
->isNull_
) table
->cNotNullInfo
[fldpos
-1] = 1;
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_
];
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();
394 hIdxInfo
->fldOffset
= table
->fldList_
.getFieldOffset(def
->fldName_
);
395 hIdxInfo
->type
= table
->fldList_
.getFieldType(def
->fldName_
);
396 hIdxInfo
->compLength
= table
->fldList_
.getFieldLength(def
->fldName_
);
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
412 CatalogTableFK
cFk(systemDatabase_
);
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
);
426 printError(ErrSysInternal
, "Unable to open foreign key tables");
435 char *tblName
= NULL
;
436 table
->isFkTbl
= cFk
.isFkTable(tptr
);
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
);
447 printError(ErrSysInternal
, "Unable to open foreign key tables");
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
);
462 List
DatabaseManagerImpl::getAllTableNames(int *retval
)
465 //to store the tuple pointer of the table
468 /*DbRetVal rv = systemDatabase_->getSCheckpointMutex();
470 printError(ErrSysInternal, "Unable to get checkpoint mutex");
471 if(retval) *retval = rv;
475 CatalogTableTABLE
cTable(systemDatabase_
);
476 List tableList
= cTable
.getTableList();
477 //systemDatabase_->releaseCheckpointMutex();
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;
488 /* TableImpl *fkTbl =NULL;
489 ListIterator tblIter = ((TableImpl*)table)->tblList.getIterator();
491 while (tblIter.hasElement()){
492 fkTbl = (TableImpl *) tblIter.nextElement();
495 ((TableImpl*)table)->tblList.reset();
496 tblIter = ((TableImpl*)table)->tblFkList.getIterator();
498 while (tblIter.hasElement()){
499 fkTbl = (TableImpl *) tblIter.nextElement();
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
);
511 printError(ErrSysInternal
, "Unable to open table %s", tblName
);
514 TableImpl
*tb
= (TableImpl
*) tbl
;
516 if (tb
->numTuples()) pages
= tb
->pagesUsed();