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>
27 DbRetVal
TableImpl::bindFld(const char *name
, void *val
)
29 //set it in the field list
30 DbRetVal rv
= fldList_
.updateBindVal(name
, val
);
32 printError(ErrNotExists
, "Field %s does not exist", name
);
38 bool TableImpl::isFldNull(const char *name
){
39 int colpos
= fldList_
.getFieldPosition(name
);
42 printError(ErrNotExists
, "Field %s does not exist", name
);
46 return isFldNull(colpos
);
49 bool TableImpl::isFldNull(int colpos
)
51 if (!curTuple_
) return false;
52 if (colpos
<1 || colpos
> numFlds_
) return false;
53 char *nullOffset
= (char*)curTuple_
- 4;
54 if (isIntUsedForNULL
) {
55 int nullVal
= *(int*)((char*)curTuple_
+ (length_
- 4));
56 if (BITSET(nullVal
, colpos
)) return true;
59 char *nullOffset
= (char*)curTuple_
- os::align(numFlds_
);
60 if (nullOffset
[colpos
-1]) return true;
64 void TableImpl::markFldNull(char const* name
)
66 int colpos
= fldList_
.getFieldPosition(name
);
69 printError(ErrNotExists
, "Field %s does not exist", name
);
75 void TableImpl::markFldNull(int fldpos
)
77 if (fldpos
<1 || fldpos
> numFlds_
) return;
78 if (isIntUsedForNULL
) {
79 if (!BITSET(iNotNullInfo
, fldpos
)) SETBIT(iNullInfo
, fldpos
);
82 if (!BITSET(iNotNullInfo
, fldpos
)) cNullInfo
[fldpos
-1] = 1;
86 void TableImpl::clearFldNull(const char *name
)
88 int colpos
= fldList_
.getFieldPosition(name
);
91 printError(ErrNotExists
, "Field %s does not exist", name
);
98 void TableImpl::clearFldNull(int colpos
)
100 if (colpos
<1 || colpos
> numFlds_
) return;
101 if (isIntUsedForNULL
) {
102 CLEARBIT(iNullInfo
, colpos
);
105 cNullInfo
[colpos
-1] = 0;
110 DbRetVal
TableImpl::execute()
114 printError(ErrAlready
,"Scan already open:Close and re execute");
117 //table ptr is set in predicate because it needs to access the
118 //type and length to evaluate
121 PredicateImpl
*pred
= (PredicateImpl
*) pred_
;
122 pred
->setTable(this);
129 printError(ErrSysInternal
,"Unable to create the plan");
130 return ErrSysInternal
;
133 iter
= new TupleIterator(pred_
, scanType_
, idxInfo
[useIndex_
], chunkPtr_
, sysDB_
->procSlot
);
134 else if (scanType_
== fullTableScan
)
135 iter
= new TupleIterator(pred_
, scanType_
, NULL
, chunkPtr_
, sysDB_
->procSlot
);
138 printError(ErrSysFatal
,"Unable to create tuple iterator");//should never happen
144 printError(ret
,"Unable to open the iterator");
151 DbRetVal
TableImpl::createPlan()
154 //will do early return here. plan is generated only when setPredicate is called.
155 if (scanType_
== unknownScan
) return ErrSysFatal
; //this should never happen
159 //if there are no predicates then go for full scan
160 //if there are no indexes then go for full scan
161 if (NULL
== pred_
|| NULL
== indexPtr_
)
163 scanType_
= fullTableScan
;
164 isPlanCreated
= true;
167 if (NULL
!= indexPtr_
)
169 PredicateImpl
*pred
= (PredicateImpl
*)pred_
;
170 printDebug(DM_Predicate
, "predicate does not involve NOT , OR operator");
171 if (!pred
->isNotOrInvolved())
173 printDebug(DM_Predicate
, "predicate does not involve NOT , OR operator");
174 for (int i
=0; i
< numIndexes_
; i
++)
176 HashIndexInfo
* info
= (HashIndexInfo
*) idxInfo
[i
];
177 FieldIterator iter
= info
->idxFldList
.getIterator();
178 while(iter
.hasElement())
180 FieldDef def
= iter
.nextElement();
181 if (pred
->pointLookupInvolved(def
.fldName_
))
183 printDebug(DM_Predicate
, "point lookup involved for field %s",def
.fldName_
);
184 scanType_
= hashIndexScan
;
185 isPlanCreated
= true;
193 }//while iter.hasElement()
194 if (useIndex_
!= -1) return OK
;
198 scanType_
= fullTableScan
;
199 isPlanCreated
= true;
203 void* TableImpl::fetch()
206 if (NULL
== curTuple_
) return curTuple_
;
207 copyValuesToBindBuffer(curTuple_
);
210 void* TableImpl::fetch(DbRetVal
&rv
)
213 if (NULL
== curTuple_
) return curTuple_
;
214 copyValuesToBindBuffer(curTuple_
);
218 void* TableImpl::fetchNoBind()
222 printError(ErrNotOpen
,"Scan not open or Scan is closed\n");
225 void *prevTuple
= curTuple_
;
226 curTuple_
= iter
->next();
227 if (NULL
== curTuple_
)
231 DbRetVal lockRet
= OK
;
232 if ((*trans
)->isoLevel_
== READ_REPEATABLE
) {
233 lockRet
= lMgr_
->getSharedLock(curTuple_
, trans
);
236 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
237 curTuple_
= prevTuple
;
242 else if ((*trans
)->isoLevel_
== READ_COMMITTED
)
244 //if iso level is read committed, operation duration lock is sufficent
245 //so release it here itself.
247 struct timeval timeout
;
248 timeout
.tv_sec
= Conf::config
.getMutexSecs();
249 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
253 lockRet
= lMgr_
->isExclusiveLocked( curTuple_
, trans
, status
);
256 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
257 curTuple_
= prevTuple
;
262 if (tries
== 0) break;
263 os::select(0, 0, 0, 0, &timeout
);
268 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
269 curTuple_
= prevTuple
;
276 void* TableImpl::fetchNoBind(DbRetVal
&rv
)
281 printError(ErrNotOpen
,"Scan not open or Scan is closed\n");
285 void *prevTuple
= curTuple_
;
286 curTuple_
= iter
->next();
287 if (NULL
== curTuple_
)
291 DbRetVal lockRet
= OK
;
292 if ((*trans
)->isoLevel_
== READ_REPEATABLE
) {
293 lockRet
= lMgr_
->getSharedLock(curTuple_
, trans
);
296 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
298 curTuple_
= prevTuple
;
303 else if ((*trans
)->isoLevel_
== READ_COMMITTED
)
305 //if iso level is read committed, operation duration lock is sufficent
306 //so release it here itself.
308 struct timeval timeout
;
309 timeout
.tv_sec
= Conf::config
.getMutexSecs();
310 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
314 lockRet
= lMgr_
->isExclusiveLocked( curTuple_
, trans
, status
);
317 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
318 curTuple_
= prevTuple
;
324 if (tries
== 0) break;
325 os::select(0, 0, 0, 0, &timeout
);
330 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
331 curTuple_
= prevTuple
;
339 DbRetVal
TableImpl::insertTuple()
342 void *tptr
= ((Chunk
*)chunkPtr_
)->allocate(db_
, &ret
);
345 printError(ret
, "Unable to allocate record from chunk");
348 ret
= lMgr_
->getExclusiveLock(tptr
, trans
);
351 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
352 printError(ret
, "Could not get lock for the insert tuple %x", tptr
);
353 return ErrLockTimeOut
;
357 ret
= copyValuesFromBindBuffer(tptr
);
360 printError(ret
, "Unable to copy values from bind buffer");
361 (*trans
)->removeFromHasList(db_
, tptr
);
362 lMgr_
->releaseLock(tptr
);
363 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
371 *(int*)((char*)(tptr
) + (length_
-addSize
)) = iNullInfo
;
375 addSize
= os::align(numFlds_
);
376 os::memcpy(((char*)(tptr
) + (length_
-addSize
)), cNullInfo
, addSize
);
379 //int tupleSize = length_ + addSize;
380 if (NULL
!= indexPtr_
)
384 for (i
= 0; i
< numIndexes_
; i
++)
386 ret
= insertIndexNode(*trans
, indexPtr_
[i
], idxInfo
[i
], tptr
);
387 if (ret
!= OK
) { printError(ret
, "Error in inserting to index"); break;}
389 if (i
!= numIndexes_
)
391 for (int j
= 0; j
< i
; j
++) {
392 printError(ErrWarning
, "Deleting index node");
393 deleteIndexNode(*trans
, indexPtr_
[j
], idxInfo
[j
], tptr
);
395 lMgr_
->releaseLock(tptr
);
396 (*trans
)->removeFromHasList(db_
, tptr
);
397 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
399 //printError(ret, "Unable to insert index node for tuple %x ", tptr);
400 printError(ret
, "Unable to insert index node for tuple %x %d", tptr
, *(int*)tptr
);
405 ret
= (*trans
)->appendUndoLog(sysDB_
, InsertOperation
, tptr
, length_
);
407 printError(ret
, "Unable to create undo log for %x %d", tptr
, *(int*)tptr
);
408 for (int j
= 0; j
< numIndexes_
; j
++) {
409 printError(ErrWarning
, "Deleting index node");
410 deleteIndexNode(*trans
, indexPtr_
[j
], idxInfo
[j
], tptr
);
412 lMgr_
->releaseLock(tptr
);
413 (*trans
)->removeFromHasList(db_
, tptr
);
414 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
419 DbRetVal
TableImpl::deleteTuple()
421 if (NULL
== curTuple_
)
423 printError(ErrNotOpen
, "Scan not open: No Current tuple");
426 DbRetVal ret
= lMgr_
->getExclusiveLock(curTuple_
, trans
);
429 printError(ret
, "Could not get lock for the delete tuple %x", curTuple_
);
430 return ErrLockTimeOut
;
433 if (NULL
!= indexPtr_
)
437 for (i
= 0; i
< numIndexes_
; i
++)
439 ret
= deleteIndexNode(*trans
, indexPtr_
[i
], idxInfo
[i
], curTuple_
);
440 if (ret
!= OK
) break;
442 if (i
!= numIndexes_
)
444 for (int j
= 0; j
< i
; j
++)
445 insertIndexNode(*trans
, indexPtr_
[j
], idxInfo
[j
], curTuple_
);
446 lMgr_
->releaseLock(curTuple_
);
447 (*trans
)->removeFromHasList(db_
, curTuple_
);
448 printError(ret
, "Unable to insert index node for tuple %x", curTuple_
);
452 ((Chunk
*)chunkPtr_
)->free(db_
, curTuple_
);
454 ret
= (*trans
)->appendUndoLog(sysDB_
, DeleteOperation
, curTuple_
, length_
);
458 int TableImpl::deleteWhere()
460 int tuplesDeleted
= 0;
463 if (rv
!=OK
) return (int) rv
;
466 if (rv
!= OK
) { tuplesDeleted
= (int)rv
; break; }
467 if (NULL
== curTuple_
) break;
470 printError(rv
, "Error: Could only delete %d tuples", tuplesDeleted
);
477 return tuplesDeleted
;
480 int TableImpl::truncate()
482 //take exclusive lock on the table
483 //get the chunk ptr of the table
484 //traverse the tablechunks and free all the pages except the first one
485 //get the chunk ptr of all its indexes
486 //traverse the indexchunks and free all the pages except the first one
491 Predicate
* tmpPred
= pred_
;
493 isPlanCreated
= false;
494 int tuplesDeleted
= deleteWhere();
495 isPlanCreated
= false;
497 return tuplesDeleted
;
500 DbRetVal
TableImpl::updateTuple()
502 if (NULL
== curTuple_
)
504 printError(ErrNotOpen
, "Scan not open: No Current tuple");
507 DbRetVal ret
= lMgr_
->getExclusiveLock(curTuple_
, trans
);
510 printError(ret
, "Could not get lock for the update tuple %x", curTuple_
);
511 return ErrLockTimeOut
;
513 if (NULL
!= indexPtr_
)
516 //TODO::If it fails while updating index node, we have to undo all the updates
517 //on other indexes on the table.Currently it will leave the database in an
518 //inconsistent state.
519 for (int i
= 0; i
< numIndexes_
; i
++)
521 ret
= updateIndexNode(*trans
, indexPtr_
[i
], idxInfo
[i
], curTuple_
);
524 lMgr_
->releaseLock(curTuple_
);
525 (*trans
)->removeFromHasList(db_
, curTuple_
);
526 printError(ret
, "Unable to update index node for tuple %x", curTuple_
);
532 ret
= (*trans
)->appendUndoLog(sysDB_
, UpdateOperation
, curTuple_
, length_
);
533 if (ret
!= OK
) return ret
;
538 *(int*)((char*)(curTuple_
) + (length_
-addSize
)) |= iNullInfo
;
542 addSize
= os::align(numFlds_
);
543 //TODO::Do not do blind memcpy. It should OR each and every char
544 //os::memcpy(((char*)(curTuple_) + (length_-addSize)), cNullInfo, addSize);
548 DbRetVal rv
= copyValuesFromBindBuffer(curTuple_
, false);
550 lMgr_
->releaseLock(curTuple_
);
551 (*trans
)->removeFromHasList(db_
, curTuple_
);
557 void TableImpl::printInfo()
559 printf(" <TableName> %s </TableName>\n", tblName_
);
560 printf(" <TupleCount> %d </TupleCount>\n", numTuples());
561 printf(" <PagesUsed> %d </PagesUsed>\n", pagesUsed());
562 printf(" <SpaceUsed> %d </SpaceUsed>\n", spaceUsed());
563 printf(" <Indexes> %d <Indexes>\n", numIndexes_
);
564 printf(" <TupleLength> %d </TupleLength>\n", length_
);
565 printf(" <Fields> %d </Fields>\n", numFlds_
);
566 printf(" <Indexes>\n");
567 for (int i
=0; i
<numIndexes_
; i
++)
568 printf("<IndexName> %s </IndexName>\n", CatalogTableINDEX::getName(indexPtr_
[i
]));
569 printf(" </Indexes>\n");
573 DbRetVal
TableImpl::copyValuesFromBindBuffer(void *tuplePtr
, bool isInsert
)
575 //Iterate through the bind list and copy the value here
576 FieldIterator fIter
= fldList_
.getIterator();
577 char *colPtr
= (char*) tuplePtr
;
579 while (fIter
.hasElement())
581 FieldDef def
= fIter
.nextElement();
582 if (def
.isNull_
&& !def
.isDefault_
&& NULL
== def
.bindVal_
&& isInsert
)
584 printError(ErrNullViolation
, "NOT NULL constraint violation for field %s\n", def
.fldName_
);
585 return ErrNullViolation
;
587 if (def
.isDefault_
&& NULL
== def
.bindVal_
&& isInsert
)
589 void *dest
= AllDataType::alloc(def
.type_
, def
.length_
);
590 AllDataType::convert(typeString
, def
.defaultValueBuf_
, def
.type_
, dest
, def
.length_
);
591 AllDataType::copyVal(colPtr
, dest
, def
.type_
, def
.length_
);
592 colPtr
= colPtr
+ os::align(AllDataType::size(def
.type_
, def
.length_
));
600 if (NULL
!= def
.bindVal_
)
602 strcpy((char*)colPtr
, (char*)def
.bindVal_
);
603 *(((char*)colPtr
) + (def
.length_
-1)) = '\0';
605 else if (!def
.isNull_
&& isInsert
) setNullBit(fldpos
);
606 colPtr
= colPtr
+ os::align(def
.length_
);
609 if (NULL
!= def
.bindVal_
) {
610 DbRetVal rv
= AllDataType::strToValue(colPtr
, (char *) def
.bindVal_
, def
.type_
, def
.length_
);
611 if (rv
!= OK
) return ErrBadArg
;
613 else if (!def
.isNull_
&& isInsert
) setNullBit(fldpos
);
614 colPtr
= colPtr
+ os::align(def
.length_
);
617 if (NULL
!= def
.bindVal_
)
618 AllDataType::copyVal(colPtr
, def
.bindVal_
, def
.type_
);
619 else { if (!def
.isNull_
&& isInsert
) setNullBit(fldpos
); }
620 colPtr
= colPtr
+ os::align(AllDataType::size(def
.type_
));
627 void TableImpl::setNullBit(int fldpos
)
629 if (isIntUsedForNULL
)
630 SETBIT(iNullInfo
, fldpos
);
632 cNullInfo
[fldpos
-1] = 1;
634 DbRetVal
TableImpl::copyValuesToBindBuffer(void *tuplePtr
)
636 //Iterate through the bind list and copy the value here
637 FieldIterator fIter
= fldList_
.getIterator();
638 char *colPtr
= (char*) tuplePtr
;
639 while (fIter
.hasElement())
641 FieldDef def
= fIter
.nextElement();
642 if (NULL
!= def
.bindVal_
)
643 AllDataType::copyVal(def
.bindVal_
, colPtr
, def
.type_
, def
.length_
);
644 colPtr
= colPtr
+ os::align(AllDataType::size(def
.type_
, def
.length_
));
649 //-1 index not supported
650 DbRetVal
TableImpl::insertIndexNode(Transaction
*tr
, void *indexPtr
, IndexInfo
*info
, void *tuple
)
652 INDEX
*iptr
= (INDEX
*)indexPtr
;
654 printDebug(DM_Table
, "Inside insertIndexNode type %d", iptr
->indexType_
);
655 Index
* idx
= Index::getIndex(iptr
->indexType_
);
656 ret
= idx
->insert(this, tr
, indexPtr
, info
, tuple
,undoFlag
);
660 DbRetVal
TableImpl::deleteIndexNode(Transaction
*tr
, void *indexPtr
, IndexInfo
*info
, void *tuple
)
662 INDEX
*iptr
= (INDEX
*)indexPtr
;
664 Index
* idx
= Index::getIndex(iptr
->indexType_
);
665 ret
= idx
->remove(this, tr
, indexPtr
, info
, tuple
, undoFlag
);
668 void TableImpl::printSQLIndexString()
670 CatalogTableINDEXFIELD
cIndexField(sysDB_
);
671 char fName
[IDENTIFIER_LENGTH
];
672 char *fldName
= fName
;
674 for (int i
= 0; i
< numIndexes_
; i
++)
676 INDEX
*iptr
= (INDEX
*) indexPtr_
[i
];
677 //cIndexField.getFieldNameAndType((void*)iptr, fldName, type);
678 //printf("CREATE INDEX %s on %s ( %s ) ", iptr->indName_, getName(), fldName);
679 printf("CREATE INDEX %s on %s ( ", iptr
->indName_
, getName());
681 cIndexField
.getFieldInfo(iptr
, fldList
);
682 FieldIterator fIter
= fldList
.getIterator();
683 bool firstFld
= true;
684 while(fIter
.hasElement())
686 FieldDef def
= fIter
.nextElement();
687 if (firstFld
) { printf(" %s ", def
.fldName_
); firstFld
= false; }
688 else printf(" ,%s ", def
.fldName_
);
691 if (((HashIndexInfo
*) idxInfo
[i
])->isUnique
) printf(" UNIQUE;\n"); else printf(";\n");
696 DbRetVal
TableImpl::updateIndexNode(Transaction
*tr
, void *indexPtr
, IndexInfo
*info
, void *tuple
)
698 INDEX
*iptr
= (INDEX
*)indexPtr
;
700 Index
* idx
= Index::getIndex(iptr
->indexType_
);
701 //TODO::currently it updates irrespective of whether the key changed or not
702 //because of this commenting the whole index update code. relook at it and uncomment
704 ret
= idx
->update(this, tr
, indexPtr
, info
, tuple
, undoFlag
);
710 void TableImpl::setTableInfo(char *name
, int tblid
, size_t length
,
711 int numFld
, int numIdx
, void *chunk
)
713 strcpy(tblName_
, name
);
717 numIndexes_
= numIdx
;
721 long TableImpl::spaceUsed()
723 Chunk
*chk
= (Chunk
*)chunkPtr_
;
724 long totSize
= chk
->getTotalDataNodes() * chk
->getSize();
725 totSize
= totSize
+ (chk
->totalPages() * sizeof (PageInfo
));
729 int TableImpl::pagesUsed()
731 Chunk
*chk
= (Chunk
*)chunkPtr_
;
732 return chk
->totalPages();
735 long TableImpl::numTuples()
737 return ((Chunk
*)chunkPtr_
)->getTotalDataNodes();
740 List
TableImpl::getFieldNameList()
743 FieldIterator fIter
= fldList_
.getIterator();
744 while (fIter
.hasElement())
746 FieldDef def
= fIter
.nextElement();
747 Identifier
*elem
= new Identifier();
748 strcpy(elem
->name
, def
.fldName_
);
749 fldNameList
.append(elem
);
753 DbRetVal
TableImpl::close()
757 printError(ErrNotOpen
,"Scan not open");
765 DbRetVal
TableImpl::lock(bool shared
)
771 ret = lMgr_->getSharedLock(chunkPtr_, NULL);
773 ret = lMgr_->getExclusiveLock(chunkPtr_, NULL);
776 printError(ret, "Could not exclusive lock on the table %x", chunkPtr_);
778 //do not append for S to X upgrade
779 if (!ProcessManager::hasLockList.exists(chunkPtr_))
780 ProcessManager::hasLockList.append(chunkPtr_);
785 DbRetVal
TableImpl::unlock()
788 if (!ProcessManager::hasLockList.exists(chunkPtr_)) return OK;
789 DbRetVal ret = lMgr_->releaseLock(chunkPtr_);
792 printError(ret, "Could not release exclusive lock on the table %x", chunkPtr_);
795 ProcessManager::hasLockList.remove(chunkPtr_);
801 TableImpl::~TableImpl()
803 if (NULL
!= iter
) { delete iter
; iter
= NULL
; }
804 if (NULL
!= indexPtr_
) { delete[] indexPtr_
; indexPtr_
= NULL
; }
807 for (int i
= 0; i
< numIndexes_
; i
++) delete idxInfo
[i
];
811 if (numFlds_
> 31 && cNullInfo
!= NULL
) { free(cNullInfo
); cNullInfo
= NULL
; }
813 fldList_
.removeAll();