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<CatalogTables.h>
23 #include<PredicateImpl.h>
26 #include<AggTableImpl.h> //for AggType
28 void Table::getFieldNameAlone(char *fname
, char *name
) {
30 char *fullname
= fname
;
31 while(*fullname
!= '\0')
33 if (*fullname
== '.') { dotFound
= true; break; }
36 if (dotFound
) strcpy(name
, ++fullname
); else strcpy(name
, fname
);
40 void Table::getTableNameAlone(char *fname
, char *name
) {
43 bool dotFound
= false;
46 if (*name
== '.') { *name
='\0'; dotFound
= true; break; }
49 if (!dotFound
) strcpy(start
, "");
52 DbRetVal
TableImpl::getQualifiedName(const char *fldname
, char *qualName
)
54 FieldInfo
*info
= new FieldInfo();
55 DbRetVal rv
= getFieldInfo(fldname
,info
);
57 sprintf(qualName
, "%s.%s", getName(), fldname
);
62 DbRetVal
TableImpl::bindFld(const char *name
, void *val
, bool isNullExpl
)
64 if (name
[0] == '*' ) return OK
;
65 //set it in the field list
66 char fieldName
[IDENTIFIER_LENGTH
];
67 getFieldNameAlone((char*)name
, fieldName
);
68 DbRetVal rv
= fldList_
.updateBindVal(fieldName
, val
, isNullExpl
);
70 printError(ErrNotExists
, "Field %s does not exist", fieldName
);
76 int TableImpl::getFldPos(char *name
)
78 return fldList_
.getFieldPosition(name
);
81 void TableImpl::setAliasName(char *name
)
83 strcpy(aliasName
, name
);
86 bool TableImpl::hasIndex(char* fName
)
88 if (NULL
== indexPtr_
) return false;
89 for (int i
=0; i
< numIndexes_
; i
++)
91 HashIndexInfo
* info
= (HashIndexInfo
*) idxInfo
[i
];
92 FieldIterator iter
= info
->idxFldList
.getIterator();
95 FieldDef
*def
= iter
.nextElement();
96 if(strcmp(def
->fldName_
, fName
) == 0)
97 if(!iter
.hasElement())//neglet if it is composite index
104 IndexType
TableImpl::getIndexType(char *fName
, int *pos
)
106 if (NULL
== indexPtr_
) return unknownIndex
;
107 for (int i
=0; i
< numIndexes_
; i
++)
109 HashIndexInfo
* info
= (HashIndexInfo
*) idxInfo
[i
];
110 FieldIterator iter
= info
->idxFldList
.getIterator();
111 if(iter
.hasElement())
113 FieldDef
*def
= iter
.nextElement();
114 if(strcmp(def
->fldName_
, fName
) == 0)
115 if(!iter
.hasElement()) {//neglet if it is composite index
117 return info
->indType
;
125 void TableImpl::addPredicate(char *fName
, ComparisionOp op
, void *buf
)
127 char fieldName
[IDENTIFIER_LENGTH
];
128 Table::getFieldNameAlone(fName
, fieldName
);
129 PredicateImpl
*pred
= (PredicateImpl
*) pred_
;
130 PredicateImpl
*newPred
= new PredicateImpl();
131 newPred
->setTerm(fName
, op
, buf
);
132 if (NULL
== pred
) { pred_
= newPred
; predList
.append(newPred
); return; }
133 if (pred
->isSingleTerm())
135 bool res
= pred
->appendIfSameFld(fName
, op
, buf
);
141 PredicateImpl
*bothPred
= new PredicateImpl();
142 bothPred
->setTerm(pred
, OpAnd
, newPred
);
143 predList
.append(bothPred
);
147 DbRetVal
TableImpl::trySharedLock(void *curTuple
, Transaction
**trans
)
149 DbRetVal lockRet
= OK
;
150 int tries
= Conf::config
.getMutexRetries();
151 while((lockRet
= lMgr_
->getSharedLock(curTuple_
, trans
)) == ErrLockTimeOut
)
154 if (tries
<=0) break;
159 DbRetVal
TableImpl::tryExclusiveLock(void *curTuple
, Transaction
**trans
)
161 DbRetVal lockRet
= OK
;
162 int tries
= Conf::config
.getMutexRetries();
163 while((lockRet
= lMgr_
->getExclusiveLock(curTuple_
, trans
)) == ErrLockTimeOut
)
166 if (tries
<=0) break;
171 DbRetVal
TableImpl::getCheckpointMutex()
175 int totalTries
= Conf::config
.getMutexRetries();
176 struct timeval timeout
, timeval
;
177 timeout
.tv_sec
= Conf::config
.getMutexSecs();
178 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
180 while (tries
< totalTries
)
182 rv
= sysDB_
->getSCheckpointMutex();
184 timeval
.tv_sec
= timeout
.tv_sec
;
185 timeval
.tv_usec
= timeout
.tv_usec
;
186 os::select(0,0,0,0,&timeval
);
189 if (tries
== totalTries
) {
190 printError(ErrLockTimeOut
, "Checkpoint server is running. Retry after sometime.");
191 return ErrLockTimeOut
;
196 void TableImpl::printInfo()
198 printf(" <TableName> %s </TableName>\n", tblName_
);
199 printf(" <TupleCount> %d </TupleCount>\n", numTuples());
200 printf(" <PagesUsed> %d </PagesUsed>\n", pagesUsed());
201 printf(" <SpaceUsed> %d </SpaceUsed>\n", spaceUsed());
202 printf(" <Indexes> %d <Indexes>\n", numIndexes_
);
203 printf(" <TupleLength> %d </TupleLength>\n", length_
);
204 printf(" <Fields> %d </Fields>\n", numFlds_
);
205 printf(" <Indexes>\n");
206 for (int i
=0; i
<numIndexes_
; i
++)
207 printf("<IndexName> %s </IndexName>\n", CatalogTableINDEX::getName(indexPtr_
[i
]));
208 printf(" </Indexes>\n");
212 DbRetVal
TableImpl::copyValuesFromBindBuffer(void *tuplePtr
, bool isInsert
)
214 //Iterate through the bind list and copy the value here
215 FieldIterator fIter
= fldList_
.getIterator();
216 char *colPtr
= (char*) tuplePtr
;
218 while (fIter
.hasElement())
220 FieldDef
*def
= fIter
.nextElement();
221 if(def
->isAutoIncrement_
&& isInsert
)
223 if (OK
!= takeTableMutex())
225 printError(ErrLockTimeOut
,
226 " Unable to take table mutex for increment key");
227 return ErrLockTimeOut
;
229 AllDataType::copyVal(&tempAutoVal
,ptrToAuto
, def
->type_
, def
->length_
);
230 if(def
->bindVal_
==NULL
)
232 AllDataType::increment(colPtr
, &tempAutoVal
, def
->type_
);
233 AllDataType::copyVal(ptrToAuto
,colPtr
, def
->type_
,
235 colPtr
= colPtr
+ def
->length_
;
238 if(AllDataType::compareVal(def
->bindVal_
, &tempAutoVal
,
239 OpGreaterThan
, def
->type_
))
241 AllDataType::copyVal(ptrToAuto
,def
->bindVal_
, def
->type_
,
244 AllDataType::copyVal(colPtr
, def
->bindVal_
, def
->type_
,
246 colPtr
= colPtr
+ def
->length_
;
253 if (def
->isNull_
&& !def
->isDefault_
&& NULL
== def
->bindVal_
&&
256 printError(ErrNullViolation
,
257 "NOT NULL constraint violation for field %s", def
->fldName_
);
258 return ErrNullViolation
;
260 if (def
->isDefault_
&& NULL
== def
->bindVal_
&& isInsert
)
262 if (! def
->isNullExplicit_
) {
263 if (def
->type_
== typeVarchar
) {
266 ((Chunk
*) vcChunkPtr_
)->allocate(db_
, def
->length_
, &rv
);
267 *(long *)colPtr
= (long)ptr
;
268 AllDataType::convert(typeString
, def
->defaultValueBuf_
,
269 def
->type_
, ptr
, def
->length_
);
271 void *dest
= AllDataType::alloc(def
->type_
, def
->length_
);
272 AllDataType::convert(typeString
, def
->defaultValueBuf_
,
273 def
->type_
, dest
, def
->length_
);
274 AllDataType::copyVal(colPtr
, dest
, def
->type_
,
280 *(long *) colPtr
= 0L;
282 if (def
->type_
!= typeVarchar
) colPtr
= colPtr
+ def
->length_
;
283 else colPtr
= colPtr
+ sizeof(void *);
290 if (NULL
!= def
->bindVal_
)
292 if(!isInsert
&& isFldNull(fldpos
)){clearNullBit(fldpos
);}
293 // strncpy((char*)colPtr, (char*)def->bindVal_, def->length_);
294 // *(((char*)colPtr) + (def->length_-1)) = '\0';
295 strcpy((char*)colPtr
, (char*)def
->bindVal_
);
297 else if (!def
->isNull_
&& isInsert
) setNullBit(fldpos
);
298 colPtr
= colPtr
+ def
->length_
;
301 if (NULL
!= def
->bindVal_
)
303 if(!isInsert
&& isFldNull(fldpos
)){clearNullBit(fldpos
);}
304 DbRetVal rv
= AllDataType::strToValue(colPtr
,
305 (char *) def
->bindVal_
, def
->type_
, def
->length_
);
306 if (rv
!= OK
) return ErrBadArg
;
307 } else if (!def
->isNull_
&& isInsert
&& !def
->bindVal_
) {
310 colPtr
= colPtr
+ def
->length_
;
313 if (NULL
!= def
->bindVal_
) {
314 if (!isInsert
&& isFldNull(fldpos
)) {clearNullBit(fldpos
);}
317 if (*(long *) colPtr
!= 0L)
318 ((Chunk
*) vcChunkPtr_
)->free(db_
,
319 (void *)*(long *)colPtr
);
320 *(long *) colPtr
= 0L;
322 if (strcmp((char *)def
->bindVal_
,"") != 0) {
324 ((Chunk
*) vcChunkPtr_
)->allocate(db_
,
326 if (rv
!= OK
) return ErrBadArg
;
327 *(long *)colPtr
= (long)ptr
;
328 strcpy((char *)ptr
, (char *)def
->bindVal_
);
329 } else { setNullBit(fldpos
); }
330 } else if (!def
->isNull_
&& isInsert
) setNullBit(fldpos
);
331 colPtr
= colPtr
+ sizeof(void *);
334 if (NULL
!= def
->bindVal_
) {
335 if(!isInsert
&& isFldNull(fldpos
)){clearNullBit(fldpos
);}
336 AllDataType::copyVal(colPtr
, def
->bindVal_
, def
->type_
);
337 } else { if (!def
->isNull_
&& isInsert
) setNullBit(fldpos
); }
338 colPtr
= colPtr
+ def
->length_
;
347 DbRetVal
TableImpl::copyValuesToBindBuffer(void *tuplePtr
)
349 //Iterate through the bind list and copy the value here
350 char *colPtr
= (char*) tuplePtr
;
351 FieldDef
*def
= NULL
;
352 for (int i
= 0; i
< numBindFlds_
; i
++) {
353 def
= (FieldDef
*) bindListArray_
[i
];
354 colPtr
= (char *) tuplePtr
+ def
->offset_
;
355 if (def
->type_
!= typeVarchar
)
356 AllDataType::copyVal(def
->bindVal_
, colPtr
, def
->type_
,
359 char *ptr
= (char *) *(long *) colPtr
;
360 if (ptr
!= NULL
) strcpy((char *)def
->bindVal_
, ptr
);
366 void TableImpl::printSQLIndexString(FILE *fp
, int fd
)
368 if (fp
== NULL
) fp
= stdout
;
369 CatalogTableINDEXFIELD
cIndexField(sysDB_
);
370 char fName
[IDENTIFIER_LENGTH
];
371 char idxName
[IDENTIFIER_LENGTH
];
372 char *fldName
= fName
;
374 for (int i
= 0; i
< numIndexes_
; i
++)
376 CINDEX
*iptr
= (CINDEX
*) indexPtr_
[i
];
377 sprintf(idxName
,"%s_idx_Auto_increment",getName());
378 if(strcmp(iptr
->indName_
,idxName
)==0){ continue; }
379 if (Conf::config
.useDurability()) {
381 strcpy(obj
.name
, iptr
->indName_
);
382 if (iptr
->indexType_
== hashIndex
) {
384 obj
.bucketChunk
= ((Chunk
*)iptr
->chunkPtr_
)->getFirstPage();
385 obj
.firstPage
= ((Chunk
*)iptr
->hashNodeChunk_
)->getFirstPage();
386 obj
.curPage
= ((Chunk
*)iptr
->hashNodeChunk_
)->getCurrentPage();
387 } else if (iptr
->indexType_
== treeIndex
) {
389 obj
.firstPage
= ((Chunk
*)iptr
->chunkPtr_
)->getFirstPage();
390 obj
.curPage
= ((Chunk
*)iptr
->chunkPtr_
)->getCurrentPage();
391 long nodes
= ((Chunk
*)iptr
->chunkPtr_
)->getTotalDataNodes();
393 ChunkIterator cIter
= ((Chunk
*)iptr
->chunkPtr_
)->getIterator();
394 obj
.bucketChunk
= cIter
.nextElement();
395 } else obj
.bucketChunk
= NULL
;
399 write(fd
, buf
, sizeof(obj
));
401 fprintf(fp
, "CREATE INDEX %s on %s ( ", iptr
->indName_
, getName());
403 cIndexField
.getFieldInfo(iptr
, fldList
);
404 FieldIterator fIter
= fldList
.getIterator();
405 bool firstFld
= true;
406 while(fIter
.hasElement())
408 FieldDef
*def
= fIter
.nextElement();
409 if (firstFld
) { fprintf(fp
, " %s ", def
->fldName_
); firstFld
= false; }
410 else fprintf(fp
, " ,%s ", def
->fldName_
);
415 if (iptr
->indexType_
== hashIndex
) fprintf(fp
, " HASH ");
416 else if (iptr
->indexType_
== treeIndex
) fprintf(fp
, " TREE ");
417 else fprintf(fp
, " TRIE ");
419 HashIndexInfo
* hInfo
= (HashIndexInfo
*)idxInfo
[i
];
420 if (hInfo
->isUnique
) fprintf(fp
, " UNIQUE");
421 if(hInfo
->noOfBuckets
!= 1009 &&
422 hInfo
->noOfBuckets
!=0) fprintf(fp
, " SIZE %d ",((HashIndexInfo
*) idxInfo
[i
])->noOfBuckets
);
428 void TableImpl::setTableInfo(char *name
, int tblid
, size_t length
,
429 int numFld
, int numIdx
, void *chunk
, void *vcchunk
)
431 strcpy(tblName_
, name
);
435 numIndexes_
= numIdx
;
437 vcChunkPtr_
= vcchunk
;
440 long TableImpl::spaceUsed()
442 Chunk
*chk
= (Chunk
*)chunkPtr_
;
443 long totSize
= chk
->getTotalDataNodes() * chk
->getSize();
444 totSize
= totSize
+ (chk
->totalPages() * sizeof (PageInfo
));
448 int TableImpl::pagesUsed()
450 Chunk
*chk
= (Chunk
*)chunkPtr_
;
451 return chk
->totalPages();
454 List
TableImpl::getFieldNameList()
457 FieldIterator fIter
= fldList_
.getIterator();
458 char fieldName
[IDENTIFIER_LENGTH
];
459 while (fIter
.hasElement())
461 FieldDef
*def
= fIter
.nextElement();
462 Identifier
*elem
= new Identifier();
463 Table::getFieldNameAlone(def
->fldName_
, fieldName
);
464 sprintf(elem
->name
, "%s.%s", getName(), fieldName
);
465 fldNameList
.append(elem
);
470 DbRetVal
TableImpl::close()
472 if (iter
) { iter
->close(); delete iter
; iter
= NULL
; }
473 TableImpl
*fkTbl
=NULL
;
474 ListIterator tblIter
= tblList
.getIterator();
476 while (tblIter
.hasElement()){
477 fkTbl
= (TableImpl
*) tblIter
.nextElement();
481 tblIter
= tblFkList
.getIterator();
483 while (tblIter
.hasElement()){
484 fkTbl
= (TableImpl
*) tblIter
.nextElement();
488 printDebug(DM_Database
,"Closing table handle: %x", this);
491 ListIterator pIter
= predList
.getIterator();
492 while (pIter
.hasElement())
494 PredicateImpl
*pImpl
= (PredicateImpl
*) pIter
.nextElement();
499 logFinest(Conf::logger
, "Closing Table");
503 DbRetVal
TableImpl::takeTableMutex()
505 struct timeval timeout
, timeval
;
506 timeout
.tv_sec
= Conf::config
.getMutexSecs();
507 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
509 int totalTries
= Conf::config
.getMutexRetries() *2;
511 while (tries
< totalTries
)
513 ret
= sysDB_
->getAllocDatabaseMutex();
515 timeval
.tv_sec
= timeout
.tv_sec
;
516 timeval
.tv_usec
= timeout
.tv_usec
;
517 os::select(0, 0, 0, 0, &timeval
);
520 if (tries
>= totalTries
) return ErrLockTimeOut
;
524 DbRetVal
TableImpl::releaseTableMutex()
526 sysDB_
->releaseAllocDatabaseMutex();
530 DbRetVal
TableImpl::lock(bool shared
)
536 ret = lMgr_->getSharedLock(chunkPtr_, NULL);
538 ret = lMgr_->getExclusiveLock(chunkPtr_, NULL);
541 printError(ret, "Could not exclusive lock on the table %x", chunkPtr_);
543 //do not append for S to X upgrade
544 if (!ProcessManager::hasLockList.exists(chunkPtr_))
545 ProcessManager::hasLockList.append(chunkPtr_);
551 DbRetVal
TableImpl::unlock()
554 if (!ProcessManager::hasLockList.exists(chunkPtr_)) return OK;
555 DbRetVal ret = lMgr_->releaseLock(chunkPtr_);
558 printError(ret, "Could not release exclusive lock on the table %x", chunkPtr_);
561 ProcessManager::hasLockList.remove(chunkPtr_);
567 TableImpl::~TableImpl()
569 if (NULL
!= iter
) { delete iter
; iter
= NULL
; }
570 if (NULL
!= indexPtr_
) { delete[] indexPtr_
; indexPtr_
= NULL
; }
573 for (int i
= 0; i
< numIndexes_
; i
++) delete idxInfo
[i
];
577 if (numFlds_
> 32 && cNullInfo
!= NULL
) {
578 free(cNullInfo
); cNullInfo
= NULL
;
580 if (bindList_
.size()) bindList_
.reset();
581 if (bindListArray_
) { free (bindListArray_
); bindListArray_
= NULL
; }
582 fldList_
.removeAll();
586 void *TableImpl::getBindFldAddr(const char *name
)
588 return fldList_
.getBindField(name
);
591 bool TableImpl::isTableInvolved(char *tblName
)
593 //printf("Table isTableInvolved called for %s with %s\n", tblName, getName());
594 if (0 == strcmp(getName(), tblName
)) return true; else return false;
597 void TableImpl::setCondition(Condition
*p
)
599 isPlanCreated
= false;
600 ListIterator pIter
= predList
.getIterator();
601 while (pIter
.hasElement())
603 PredicateImpl
*pImpl
= (PredicateImpl
*) pIter
.nextElement();
608 if (p
) pred_
= p
->getPredicate(); else pred_
= NULL
;
611 void TableImpl::setPredicate(Predicate
*pred
)
613 if (NULL
== pred_
) { pred_
= pred
; return; }
615 Predicate
*curPred
= pred_
;
616 PredicateImpl
*newPred
= new PredicateImpl();
617 newPred
->setTerm(curPred
, OpAnd
, pred
);
618 newPred
->setTable(this);
623 void TableImpl::printPlan(int space
)
625 char spaceBuf
[IDENTIFIER_LENGTH
];
626 memset(spaceBuf
, 32, IDENTIFIER_LENGTH
);
627 spaceBuf
[space
] = '\0';
628 printf("%s <TABLE-NODE>\n", spaceBuf
);
629 printf("%s <NAME> %s </NAME>\n", spaceBuf
, getName());
630 printf("%s <ScanType> %s </ScanType>\n", spaceBuf
, ScanTypeNames
[scanType_
]);
631 PredicateImpl
*pred
= (PredicateImpl
*)pred_
;
632 if (pred
) pred
->print(space
+2);
633 printf("%s </TABLE-NODE>\n", spaceBuf
);
636 void TableImpl::printSQLForeignString()
639 FieldNameList pkFieldList
,fkFieldList
;
642 void *chunkPk
= NULL
;
643 void *vcchunkPk
= NULL
;
644 CatalogTableTABLE
cTable(sysDB_
);
645 TableImpl
*fkTbl
=NULL
;
646 ListIterator tblIter
= tblList
.getIterator();
649 while (tblIter
.hasElement()){
650 fkTbl
= (TableImpl
*) tblIter
.nextElement();
651 rv
= cTable
.getChunkAndTblPtr(fkTbl
->getName(), chunkPk
, tPkptr
,vcchunkPk
);
652 if ( OK
!= rv
){return ;}
653 rv
= cTable
.getChunkAndTblPtr(getName(), chunkPk
, tFkptr
, vcchunkPk
);
654 if ( OK
!= rv
){return ;}
655 CatalogTableFK
cFk(sysDB_
);
656 rv
= cFk
.getPkFkFieldInfo(tPkptr
,tFkptr
,pkFieldList
,fkFieldList
);
657 if ( OK
!= rv
){return;}
658 pkFieldList
.resetIter();
659 fkFieldList
.resetIter();
660 char *fldName
= NULL
;
661 bool firstField
=true;
662 if(!firstFK
) printf(", ");
663 printf(", FOREIGN KEY ( ");
664 while((fldName
= fkFieldList
.nextFieldName())!= NULL
)
667 printf("%s",fldName
);
671 printf(",%s",fldName
);
673 printf(" ) REFERENCES %s ( ",fkTbl
->getName());
675 while((fldName
= pkFieldList
.nextFieldName())!= NULL
)
678 printf("%s",fldName
);
682 printf(",%s",fldName
);
686 pkFieldList
.removeAll();
687 fkFieldList
.removeAll();
692 DbRetVal
TableImpl::compact()
695 int ret
=((Chunk
*)chunkPtr_
)->compact(db_
->procSlot
);
696 if(ret
!=0) return ErrLockTimeOut
;
698 if (NULL
!= vcChunkPtr_
) {
699 ret
= ((Chunk
*)vcChunkPtr_
)->compact(db_
->procSlot
);
700 if(ret
!=0) return ErrLockTimeOut
;
703 if (NULL
!= indexPtr_
)
707 for (i
= 0; i
< numIndexes_
; i
++)
709 rv
= compactIndexNode(indexPtr_
[i
]);
711 printError(rv
, "Error in compacting index Node");
719 DbRetVal
TableImpl::compactIndexNode( void *indexPtr
)
721 CINDEX
*iptr
= (CINDEX
*)indexPtr
;
723 printDebug(DM_Table
, "Inside insertIndexNode type %d", iptr
->indexType_
);
724 if( hashIndex
== (iptr
->indexType_
) )
726 ret1
=((Chunk
*)iptr
->hashNodeChunk_
)->compact(db_
->procSlot
);
728 return ErrLockTimeOut
;
730 }else if (treeIndex
== (iptr
->indexType_
))
732 ret1
=((Chunk
*)iptr
->chunkPtr_
)->compact(db_
->procSlot
);
734 return ErrLockTimeOut
;
736 } else if ( trieIndex
== (iptr
->indexType_
))
738 ret1
=((Chunk
*)iptr
->chunkPtr_
)->compact(db_
->procSlot
);
740 return ErrLockTimeOut
;
742 ret1
=((Chunk
*)iptr
->hashNodeChunk_
)->compact(db_
->procSlot
);
744 return ErrLockTimeOut
;