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
);
76 void TableImpl::markFldNull(int fldpos
)
78 if (fldpos
<1 || fldpos
> numFlds_
) return;
79 if (isIntUsedForNULL
) {
80 if (!BITSET(iNotNullInfo
, fldpos
)) SETBIT(iNullInfo
, fldpos
);
83 if (!BITSET(iNotNullInfo
, fldpos
)) cNullInfo
[fldpos
-1] = 1;
87 void TableImpl::clearFldNull(const char *name
)
89 int colpos
= fldList_
.getFieldPosition(name
);
92 printError(ErrNotExists
, "Field %s does not exist", name
);
99 void TableImpl::clearFldNull(int colpos
)
101 if (colpos
<1 || colpos
> numFlds_
) return;
102 if (isIntUsedForNULL
) {
103 CLEARBIT(iNullInfo
, colpos
);
106 cNullInfo
[colpos
-1] = 0;
111 DbRetVal
TableImpl::execute()
115 printError(ErrAlready
,"Scan already open:Close and re execute");
118 //table ptr is set in predicate because it needs to access the
119 //type and length to evaluate
122 PredicateImpl
*pred
= (PredicateImpl
*) pred_
;
123 pred
->setTable(this);
130 printError(ErrSysInternal
,"Unable to create the plan");
131 return ErrSysInternal
;
134 iter
= new TupleIterator(pred_
, scanType_
, idxInfo
[useIndex_
], chunkPtr_
, sysDB_
->procSlot
);
135 else if (scanType_
== fullTableScan
)
136 iter
= new TupleIterator(pred_
, scanType_
, NULL
, chunkPtr_
, sysDB_
->procSlot
);
139 printError(ErrSysFatal
,"Unable to create tuple iterator");//should never happen
145 printError(ErrSysInternal
,"Unable to open the iterator");
146 return ErrSysInternal
;
152 DbRetVal
TableImpl::createPlan()
155 //will do early return here. plan is generated only when setPredicate is called.
156 if (scanType_
== unknownScan
) return ErrSysFatal
; //this should never happen
160 //if there are no predicates then go for full scan
161 //if there are no indexes then go for full scan
162 if (NULL
== pred_
|| NULL
== indexPtr_
)
164 scanType_
= fullTableScan
;
165 isPlanCreated
= true;
168 if (NULL
!= indexPtr_
)
170 PredicateImpl
*pred
= (PredicateImpl
*)pred_
;
171 printDebug(DM_Predicate
, "predicate does not involve NOT , OR operator");
172 if (!pred
->isNotOrInvolved())
174 printDebug(DM_Predicate
, "predicate does not involve NOT , OR operator");
175 for (int i
=0; i
< numIndexes_
; i
++)
177 char *fName
= ((SingleFieldHashIndexInfo
*)idxInfo
[i
])->fldName
;
178 if (pred
->pointLookupInvolved(fName
))
180 printDebug(DM_Predicate
, "point lookup involved for field %s",fName
);
181 scanType_
= hashIndexScan
;
183 isPlanCreated
= true;
189 scanType_
= fullTableScan
;
190 isPlanCreated
= true;
194 void* TableImpl::fetch()
197 if (NULL
== curTuple_
) return curTuple_
;
198 copyValuesToBindBuffer(curTuple_
);
202 void* TableImpl::fetchNoBind()
206 printError(ErrNotOpen
,"Scan not open or Scan is closed\n");
209 curTuple_
= iter
->next();
210 if (NULL
== curTuple_
)
214 DbRetVal lockRet
= OK
;
215 if ((*trans
)->isoLevel_
== READ_REPEATABLE
) {
216 lockRet
= lMgr_
->getSharedLock(curTuple_
, trans
);
219 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
224 else if ((*trans
)->isoLevel_
== READ_COMMITTED
)
226 //if iso level is read committed, operation duration lock is sufficent
227 //so release it here itself.
229 struct timeval timeout
;
230 timeout
.tv_sec
= Conf::config
.getMutexSecs();
231 timeout
.tv_usec
= Conf::config
.getMutexUSecs();
235 lockRet
= lMgr_
->isExclusiveLocked( curTuple_
, trans
, status
);
238 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
243 if (tries
== 0) break;
244 os::select(0, 0, 0, 0, &timeout
);
249 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
257 DbRetVal
TableImpl::insertTuple()
260 void *tptr
= ((Chunk
*)chunkPtr_
)->allocate(db_
, &ret
);
263 printError(ret
, "Unable to allocate from chunk");
267 ret
= lMgr_
->getExclusiveLock(tptr
, trans
);
270 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
271 printError(ret
, "Could not get lock for the insert tuple %x", tptr
);
276 ret
= copyValuesFromBindBuffer(tptr
);
279 printError(ret
, "Unable to copy values from bind buffer");
280 lMgr_
->releaseLock(tptr
);
281 (*trans
)->removeFromHasList(db_
, tptr
);
282 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
290 *(int*)((char*)(tptr
) + (length_
-addSize
)) = iNullInfo
;
294 addSize
= os::align(numFlds_
);
295 os::memcpy(((char*)(tptr
) + (length_
-addSize
)), cNullInfo
, addSize
);
298 //int tupleSize = length_ + addSize;
299 if (NULL
!= indexPtr_
)
303 for (i
= 0; i
< numIndexes_
; i
++)
305 ret
= insertIndexNode(*trans
, indexPtr_
[i
], idxInfo
[i
], tptr
);
306 if (ret
!= OK
) { printError(ret
, "Error in inserting to index"); break;}
308 if (i
!= numIndexes_
)
310 for (int j
= 0; j
< i
; j
++)
311 deleteIndexNode(*trans
, indexPtr_
[j
], idxInfo
[j
], tptr
);
312 lMgr_
->releaseLock(tptr
);
313 (*trans
)->removeFromHasList(db_
, tptr
);
314 ((Chunk
*)chunkPtr_
)->free(db_
, tptr
);
315 printError(ret
, "Unable to insert index node for tuple %x", tptr
);
320 ret
= (*trans
)->appendUndoLog(sysDB_
, InsertOperation
, tptr
, length_
);
324 DbRetVal
TableImpl::deleteTuple()
326 if (NULL
== curTuple_
)
328 printError(ErrNotOpen
, "Scan not open: No Current tuple");
331 DbRetVal ret
= lMgr_
->getExclusiveLock(curTuple_
, trans
);
334 printError(ret
, "Could not get lock for the delete tuple %x", curTuple_
);
338 if (NULL
!= indexPtr_
)
342 for (i
= 0; i
< numIndexes_
; i
++)
344 ret
= deleteIndexNode(*trans
, indexPtr_
[i
], idxInfo
[i
], curTuple_
);
345 if (ret
!= OK
) break;
347 if (i
!= numIndexes_
)
349 for (int j
= 0; j
< i
; j
++)
350 insertIndexNode(*trans
, indexPtr_
[j
], idxInfo
[j
], curTuple_
);
351 lMgr_
->releaseLock(curTuple_
);
352 (*trans
)->removeFromHasList(db_
, curTuple_
);
353 printError(ret
, "Unable to insert index node for tuple %x", curTuple_
);
357 ((Chunk
*)chunkPtr_
)->free(db_
, curTuple_
);
359 ret
= (*trans
)->appendUndoLog(sysDB_
, DeleteOperation
, curTuple_
, length_
);
363 DbRetVal
TableImpl::updateTuple()
365 if (NULL
== curTuple_
)
367 printError(ErrNotOpen
, "Scan not open: No Current tuple");
370 DbRetVal ret
= lMgr_
->getExclusiveLock(curTuple_
, trans
);
373 printError(ret
, "Could not get lock for the update tuple %x", curTuple_
);
376 if (NULL
!= indexPtr_
)
379 //TODO::If it fails while updating index node, we have to undo all the updates
380 //on other indexes on the table.Currently it will leave the database in an
381 //inconsistent state.
382 for (int i
= 0; i
< numIndexes_
; i
++)
384 ret
= updateIndexNode(*trans
, indexPtr_
[i
], idxInfo
[i
], curTuple_
);
387 lMgr_
->releaseLock(curTuple_
);
388 (*trans
)->removeFromHasList(db_
, curTuple_
);
389 printError(ret
, "Unable to update index node for tuple %x", curTuple_
);
395 ret
= (*trans
)->appendUndoLog(sysDB_
, UpdateOperation
, curTuple_
, length_
);
396 if (ret
!= OK
) return ret
;
397 return copyValuesFromBindBuffer(curTuple_
);
400 void TableImpl::printInfo()
402 printf(" <TableName> %s </TableName>\n", tblName_
);
403 printf(" <TupleCount> %d </TupleCount>\n", numTuples());
404 printf(" <PagesUsed> %d </PagesUsed>\n", pagesUsed());
405 printf(" <SpaceUsed> %d </SpaceUsed>\n", spaceUsed());
406 printf(" <Indexes> %d <Indexes>\n", numIndexes_
);
407 printf(" <TupleLength> %d </TupleLength>\n", length_
);
408 printf(" <Fields> %d </Fields>\n", numFlds_
);
409 printf(" <Indexes>\n");
410 for (int i
=0; i
<numIndexes_
; i
++)
411 printf("<IndexName> %s </IndexName>\n", CatalogTableINDEX::getName(indexPtr_
[i
]));
412 printf(" </Indexes>\n");
416 DbRetVal
TableImpl::copyValuesFromBindBuffer(void *tuplePtr
)
418 //Iterate through the bind list and copy the value here
419 FieldIterator fIter
= fldList_
.getIterator();
420 char *colPtr
= (char*) tuplePtr
;
422 while (fIter
.hasElement())
424 FieldDef def
= fIter
.nextElement();
428 if (NULL
!= def
.bindVal_
)
430 strcpy((char*)colPtr
, (char*)def
.bindVal_
);
431 *(((char*)colPtr
) + (def
.length_
-1)) = '\0';
433 else if (!def
.isNull_
) setNullBit(fldpos
);
434 colPtr
= colPtr
+ os::align(def
.length_
);
437 if (NULL
!= def
.bindVal_
)
438 os::memcpy((char*)colPtr
, (char*)def
.bindVal_
, def
.length_
);
439 else if (!def
.isNull_
) setNullBit(fldpos
);
440 colPtr
= colPtr
+ os::align(def
.length_
);
443 if (NULL
!= def
.bindVal_
)
444 AllDataType::copyVal(colPtr
, def
.bindVal_
, def
.type_
);
445 else { if (!def
.isNull_
) setNullBit(fldpos
); }
446 colPtr
= colPtr
+ os::align(AllDataType::size(def
.type_
));
453 void TableImpl::setNullBit(int fldpos
)
455 if (isIntUsedForNULL
)
456 SETBIT(iNullInfo
, fldpos
);
458 cNullInfo
[fldpos
-1] = 1;
460 DbRetVal
TableImpl::copyValuesToBindBuffer(void *tuplePtr
)
462 //Iterate through the bind list and copy the value here
463 FieldIterator fIter
= fldList_
.getIterator();
464 char *colPtr
= (char*) tuplePtr
;
465 while (fIter
.hasElement())
467 FieldDef def
= fIter
.nextElement();
471 if (NULL
!= def
.bindVal_
)
472 strcpy((char*)def
.bindVal_
, (char*)colPtr
);
473 colPtr
= colPtr
+ os::align(def
.length_
);
476 if (NULL
!= def
.bindVal_
)
477 os::memcpy((char*)def
.bindVal_
, (char*)colPtr
, def
.length_
);
478 colPtr
= colPtr
+ os::align(def
.length_
);
481 if (NULL
!= def
.bindVal_
)
482 AllDataType::copyVal(def
.bindVal_
, colPtr
, def
.type_
);
483 colPtr
= colPtr
+ os::align(AllDataType::size(def
.type_
));
490 //-1 index not supported
491 DbRetVal
TableImpl::insertIndexNode(Transaction
*tr
, void *indexPtr
, IndexInfo
*info
, void *tuple
)
493 INDEX
*iptr
= (INDEX
*)indexPtr
;
495 printDebug(DM_Table
, "Inside insertIndexNode type %d", iptr
->indexType_
);
496 Index
* idx
= Index::getIndex(iptr
->indexType_
);
497 ret
= idx
->insert(this, tr
, indexPtr
, info
, tuple
,undoFlag
);
501 DbRetVal
TableImpl::deleteIndexNode(Transaction
*tr
, void *indexPtr
, IndexInfo
*info
, void *tuple
)
503 INDEX
*iptr
= (INDEX
*)indexPtr
;
505 Index
* idx
= Index::getIndex(iptr
->indexType_
);
506 ret
= idx
->remove(this, tr
, indexPtr
, info
, tuple
, undoFlag
);
511 DbRetVal
TableImpl::updateIndexNode(Transaction
*tr
, void *indexPtr
, IndexInfo
*info
, void *tuple
)
513 INDEX
*iptr
= (INDEX
*)indexPtr
;
515 Index
* idx
= Index::getIndex(iptr
->indexType_
);
516 //TODO::currently it updates irrespective of whether the key changed or not
517 //because of this commenting the whole index update code. relook at it and uncomment
519 //ret = idx->update(this, tr, indexPtr, info, tuple, undoFlag);
525 void TableImpl::setTableInfo(char *name
, int tblid
, size_t length
,
526 int numFld
, int numIdx
, void *chunk
)
528 strcpy(tblName_
, name
);
532 numIndexes_
= numIdx
;
536 long TableImpl::spaceUsed()
538 Chunk
*chk
= (Chunk
*)chunkPtr_
;
539 long totSize
= chk
->getTotalDataNodes() * chk
->getSize();
540 totSize
= totSize
+ (chk
->totalPages() * sizeof (PageInfo
));
544 int TableImpl::pagesUsed()
546 Chunk
*chk
= (Chunk
*)chunkPtr_
;
547 return chk
->totalPages();
550 long TableImpl::numTuples()
552 return ((Chunk
*)chunkPtr_
)->getTotalDataNodes();
555 List
TableImpl::getFieldNameList()
558 FieldIterator fIter
= fldList_
.getIterator();
559 while (fIter
.hasElement())
561 FieldDef def
= fIter
.nextElement();
562 Identifier
*elem
= new Identifier();
563 strcpy(elem
->name
, def
.fldName_
);
564 fldNameList
.append(elem
);
568 DbRetVal
TableImpl::close()
572 printError(ErrNotOpen
,"Scan not open");
580 DbRetVal
TableImpl::lock(bool shared
)
584 ret
= lMgr_
->getSharedLock(chunkPtr_
, NULL
);
586 ret
= lMgr_
->getExclusiveLock(chunkPtr_
, NULL
);
589 printError(ret
, "Could not exclusive lock on the table %x", chunkPtr_
);
591 //do not append for S to X upgrade
592 if (!ProcessManager::hasLockList
.exists(chunkPtr_
))
593 ProcessManager::hasLockList
.append(chunkPtr_
);
597 DbRetVal
TableImpl::unlock()
599 if (!ProcessManager::hasLockList
.exists(chunkPtr_
)) return OK
;
600 DbRetVal ret
= lMgr_
->releaseLock(chunkPtr_
);
603 printError(ret
, "Could not release exclusive lock on the table %x", chunkPtr_
);
606 ProcessManager::hasLockList
.remove(chunkPtr_
);
611 TableImpl::~TableImpl()
613 if (NULL
!= iter
) { delete iter
; iter
= NULL
; }
614 if (NULL
!= idxInfo
) { delete idxInfo
; idxInfo
= NULL
; }
615 if (NULL
!= indexPtr_
) { delete[] indexPtr_
; indexPtr_
= NULL
; }
618 for (int i
= 0; i
< numIndexes_
; i
++) delete idxInfo
[i
];
622 if (numFlds_
> 31 && cNullInfo
!= NULL
) { free(cNullInfo
); cNullInfo
= NULL
; }
624 fldList_
.removeAll();