Full table read caching implementation, also contains deleteWhere and truncate for...
[csql.git] / src / server / TableImpl.cxx
blob0b25da5ad8a35a88ae8d4d0145d4eeccff25be10
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<Index.h>
17 #include<CatalogTables.h>
18 #include<Lock.h>
19 #include<Debug.h>
20 #include<Table.h>
21 #include<TableImpl.h>
22 #include<Predicate.h>
23 #include<PredicateImpl.h>
24 #include<Index.h>
25 #include<Config.h>
27 DbRetVal TableImpl::bindFld(const char *name, void *val)
29 //set it in the field list
30 DbRetVal rv = fldList_.updateBindVal(name, val);
31 if (OK != rv) {
32 printError(ErrNotExists, "Field %s does not exist", name);
33 return rv;
35 return OK;
38 bool TableImpl::isFldNull(const char *name){
39 int colpos = fldList_.getFieldPosition(name);
40 if (-1 == colpos)
42 printError(ErrNotExists, "Field %s does not exist", name);
43 return false;
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;
58 else {
59 char *nullOffset = (char*)curTuple_ - os::align(numFlds_);
60 if (nullOffset[colpos-1]) return true;
62 return false;
64 void TableImpl::markFldNull(char const* name)
66 int colpos = fldList_.getFieldPosition(name);
67 if (-1 == colpos)
69 printError(ErrNotExists, "Field %s does not exist", name);
70 return;
73 markFldNull(colpos);
76 void TableImpl::markFldNull(int fldpos)
78 if (fldpos <1 || fldpos > numFlds_) return;
79 if (isIntUsedForNULL) {
80 if (!BITSET(iNotNullInfo, fldpos)) SETBIT(iNullInfo, fldpos);
82 else
83 if (!BITSET(iNotNullInfo, fldpos)) cNullInfo[fldpos-1] = 1;
84 return;
87 void TableImpl::clearFldNull(const char *name)
89 int colpos = fldList_.getFieldPosition(name);
90 if (-1 == colpos)
92 printError(ErrNotExists, "Field %s does not exist", name);
93 return;
96 clearFldNull(colpos);
99 void TableImpl::clearFldNull(int colpos)
101 if (colpos <1 || colpos > numFlds_) return;
102 if (isIntUsedForNULL) {
103 CLEARBIT(iNullInfo, colpos);
105 else
106 cNullInfo[colpos-1] = 0;
107 return;
111 DbRetVal TableImpl::execute()
113 if (NULL != iter)
115 printError(ErrAlready,"Scan already open:Close and re execute");
116 return ErrAlready;
118 //table ptr is set in predicate because it needs to access the
119 //type and length to evaluate
120 if( NULL != pred_)
122 PredicateImpl *pred = (PredicateImpl*) pred_;
123 pred->setTable(this);
125 DbRetVal ret = OK;
127 ret = createPlan();
128 if (OK != ret)
130 printError(ErrSysInternal,"Unable to create the plan");
131 return ErrSysInternal;
133 if (useIndex_ >= 0)
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);
137 else
139 printError(ErrSysFatal,"Unable to create tuple iterator");//should never happen
140 return ErrSysFatal;
142 ret = iter->open();
143 if (OK != ret)
145 printError(ErrSysInternal,"Unable to open the iterator");
146 return ErrSysInternal;
148 return OK;
152 DbRetVal TableImpl::createPlan()
154 if (isPlanCreated) {
155 //will do early return here. plan is generated only when setPredicate is called.
156 if (scanType_ == unknownScan) return ErrSysFatal; //this should never happen
157 else return OK;
159 useIndex_ = -1;
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;
166 return OK;
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;
182 useIndex_ = i;
183 isPlanCreated = true;
184 return OK;
189 scanType_ = fullTableScan;
190 isPlanCreated = true;
191 return OK;
194 void* TableImpl::fetch()
196 fetchNoBind();
197 if (NULL == curTuple_) return curTuple_;
198 copyValuesToBindBuffer(curTuple_);
199 return curTuple_;
202 void* TableImpl::fetchNoBind()
204 if (NULL == iter)
206 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
207 return NULL;
209 curTuple_ = iter->next();
210 if (NULL == curTuple_)
212 return NULL;
214 DbRetVal lockRet = OK;
215 if ((*trans)->isoLevel_ == READ_REPEATABLE) {
216 lockRet = lMgr_->getSharedLock(curTuple_, trans);
217 if (OK != lockRet)
219 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
220 return NULL;
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.
228 int tries = 5;
229 struct timeval timeout;
230 timeout.tv_sec = Conf::config.getMutexSecs();
231 timeout.tv_usec = Conf::config.getMutexUSecs();
233 bool status = false;
234 while(true) {
235 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
236 if (OK != lockRet)
238 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
239 return NULL;
241 if (!status) break;
242 tries--;
243 if (tries == 0) break;
244 os::select(0, 0, 0, 0, &timeout);
247 if (tries == 0)
249 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
250 curTuple_ = NULL;
251 return NULL;
254 return curTuple_;
257 DbRetVal TableImpl::insertTuple()
259 DbRetVal ret =OK;
260 void *tptr = ((Chunk*)chunkPtr_)->allocate(db_, &ret);
261 if (NULL == tptr)
263 printError(ret, "Unable to allocate from chunk");
264 return ret;
267 ret = lMgr_->getExclusiveLock(tptr, trans);
268 if (OK != ret)
270 ((Chunk*)chunkPtr_)->free(db_, tptr);
271 printError(ret, "Could not get lock for the insert tuple %x", tptr);
272 return ret;
276 ret = copyValuesFromBindBuffer(tptr);
277 if (ret != OK)
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);
283 return ret;
286 int addSize = 0;
287 if (numFlds_ < 31)
289 addSize = 4;
290 *(int*)((char*)(tptr) + (length_-addSize)) = iNullInfo;
292 else
294 addSize = os::align(numFlds_);
295 os::memcpy(((char*)(tptr) + (length_-addSize)), cNullInfo, addSize);
298 //int tupleSize = length_ + addSize;
299 if (NULL != indexPtr_)
301 int i;
302 //it has index
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);
316 return ret;
319 if (undoFlag)
320 ret = (*trans)->appendUndoLog(sysDB_, InsertOperation, tptr, length_);
321 return ret;
324 DbRetVal TableImpl::deleteTuple()
326 if (NULL == curTuple_)
328 printError(ErrNotOpen, "Scan not open: No Current tuple");
329 return ErrNotOpen;
331 DbRetVal ret = lMgr_->getExclusiveLock(curTuple_, trans);
332 if (OK != ret)
334 printError(ret, "Could not get lock for the delete tuple %x", curTuple_);
335 return ret;
338 if (NULL != indexPtr_)
340 int i;
341 //it has index
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_);
354 return ret;
357 ((Chunk*)chunkPtr_)->free(db_, curTuple_);
358 if (undoFlag)
359 ret = (*trans)->appendUndoLog(sysDB_, DeleteOperation, curTuple_, length_);
360 return ret;
363 int TableImpl::deleteWhere()
365 int tuplesDeleted = 0;
366 DbRetVal rv = OK;
367 rv = execute();
368 if (rv !=OK) return (int) rv;
369 while(true){
370 fetchNoBind();
371 if (NULL == curTuple_) break;
372 rv = deleteTuple();
373 if (rv != OK) {
374 printError(rv, "Error: Could only delete %d tuples", tuplesDeleted);
375 close();
376 return (int) rv;
378 tuplesDeleted++;
380 close();
381 return tuplesDeleted;
384 int TableImpl::truncate()
386 //take exclusive lock on the table
387 //get the chunk ptr of the table
388 //traverse the tablechunks and free all the pages except the first one
389 //get the chunk ptr of all its indexes
390 //traverse the indexchunks and free all the pages except the first one
391 //release table lock
393 //TEMPORARY FIX
394 DbRetVal rv = OK;
395 Predicate* tmpPred = pred_;
396 pred_ = NULL;
397 isPlanCreated = false;
398 int tuplesDeleted = deleteWhere();
399 isPlanCreated = false;
400 pred_ = tmpPred;
401 return tuplesDeleted;
404 DbRetVal TableImpl::updateTuple()
406 if (NULL == curTuple_)
408 printError(ErrNotOpen, "Scan not open: No Current tuple");
409 return ErrNotOpen;
411 DbRetVal ret = lMgr_->getExclusiveLock(curTuple_, trans);
412 if (OK != ret)
414 printError(ret, "Could not get lock for the update tuple %x", curTuple_);
415 return ret;
417 if (NULL != indexPtr_)
419 //it has index
420 //TODO::If it fails while updating index node, we have to undo all the updates
421 //on other indexes on the table.Currently it will leave the database in an
422 //inconsistent state.
423 for (int i = 0; i < numIndexes_ ; i++)
425 ret = updateIndexNode(*trans, indexPtr_[i], idxInfo[i], curTuple_);
426 if (ret != OK)
428 lMgr_->releaseLock(curTuple_);
429 (*trans)->removeFromHasList(db_, curTuple_);
430 printError(ret, "Unable to update index node for tuple %x", curTuple_);
431 return ret;
435 if (undoFlag)
436 ret = (*trans)->appendUndoLog(sysDB_, UpdateOperation, curTuple_, length_);
437 if (ret != OK) return ret;
438 return copyValuesFromBindBuffer(curTuple_);
441 void TableImpl::printInfo()
443 printf(" <TableName> %s </TableName>\n", tblName_);
444 printf(" <TupleCount> %d </TupleCount>\n", numTuples());
445 printf(" <PagesUsed> %d </PagesUsed>\n", pagesUsed());
446 printf(" <SpaceUsed> %d </SpaceUsed>\n", spaceUsed());
447 printf(" <Indexes> %d <Indexes>\n", numIndexes_);
448 printf(" <TupleLength> %d </TupleLength>\n", length_);
449 printf(" <Fields> %d </Fields>\n", numFlds_);
450 printf(" <Indexes>\n");
451 for (int i =0; i<numIndexes_; i++)
452 printf("<IndexName> %s </IndexName>\n", CatalogTableINDEX::getName(indexPtr_[i]));
453 printf(" </Indexes>\n");
457 DbRetVal TableImpl::copyValuesFromBindBuffer(void *tuplePtr)
459 //Iterate through the bind list and copy the value here
460 FieldIterator fIter = fldList_.getIterator();
461 char *colPtr = (char*) tuplePtr;
462 int fldpos=1;
463 while (fIter.hasElement())
465 FieldDef def = fIter.nextElement();
466 if (def.isNull_ && NULL == def.bindVal_)
468 printError(ErrNullViolation, "NOT NULL constraint violation for field %s\n", def.fldName_);
469 return ErrNullViolation;
471 switch(def.type_)
473 case typeString:
474 if (NULL != def.bindVal_)
476 strcpy((char*)colPtr, (char*)def.bindVal_);
477 *(((char*)colPtr) + (def.length_-1)) = '\0';
479 else if (!def.isNull_) setNullBit(fldpos);
480 colPtr = colPtr + os::align(def.length_);
481 break;
482 case typeBinary:
483 if (NULL != def.bindVal_)
484 os::memcpy((char*)colPtr, (char*)def.bindVal_, def.length_);
485 else if (!def.isNull_) setNullBit(fldpos);
486 colPtr = colPtr + os::align(def.length_);
487 break;
488 default:
489 if (NULL != def.bindVal_)
490 AllDataType::copyVal(colPtr, def.bindVal_, def.type_);
491 else { if (!def.isNull_) setNullBit(fldpos); }
492 colPtr = colPtr + os::align(AllDataType::size(def.type_));
493 break;
495 fldpos++;
497 return OK;
499 void TableImpl::setNullBit(int fldpos)
501 if (isIntUsedForNULL)
502 SETBIT(iNullInfo, fldpos);
503 else
504 cNullInfo[fldpos-1] = 1;
506 DbRetVal TableImpl::copyValuesToBindBuffer(void *tuplePtr)
508 //Iterate through the bind list and copy the value here
509 FieldIterator fIter = fldList_.getIterator();
510 char *colPtr = (char*) tuplePtr;
511 while (fIter.hasElement())
513 FieldDef def = fIter.nextElement();
514 switch(def.type_)
516 case typeString:
517 if (NULL != def.bindVal_)
518 strcpy((char*)def.bindVal_, (char*)colPtr);
519 colPtr = colPtr + os::align(def.length_);
520 break;
521 case typeBinary:
522 if (NULL != def.bindVal_)
523 os::memcpy((char*)def.bindVal_, (char*)colPtr, def.length_);
524 colPtr = colPtr + os::align(def.length_);
525 break;
526 default:
527 if (NULL != def.bindVal_)
528 AllDataType::copyVal(def.bindVal_, colPtr, def.type_);
529 colPtr = colPtr + os::align(AllDataType::size(def.type_));
530 break;
533 return OK;
536 //-1 index not supported
537 DbRetVal TableImpl::insertIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple)
539 INDEX *iptr = (INDEX*)indexPtr;
540 DbRetVal ret = OK;
541 printDebug(DM_Table, "Inside insertIndexNode type %d", iptr->indexType_);
542 Index* idx = Index::getIndex(iptr->indexType_);
543 ret = idx->insert(this, tr, indexPtr, info, tuple,undoFlag);
544 return ret;
547 DbRetVal TableImpl::deleteIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple)
549 INDEX *iptr = (INDEX*)indexPtr;
550 DbRetVal ret = OK;
551 Index* idx = Index::getIndex(iptr->indexType_);
552 ret = idx->remove(this, tr, indexPtr, info, tuple, undoFlag);
553 return ret;
557 DbRetVal TableImpl::updateIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple)
559 INDEX *iptr = (INDEX*)indexPtr;
560 DbRetVal ret = OK;
561 Index* idx = Index::getIndex(iptr->indexType_);
562 //TODO::currently it updates irrespective of whether the key changed or not
563 //because of this commenting the whole index update code. relook at it and uncomment
565 //ret = idx->update(this, tr, indexPtr, info, tuple, undoFlag);
567 return ret;
571 void TableImpl::setTableInfo(char *name, int tblid, size_t length,
572 int numFld, int numIdx, void *chunk)
574 strcpy(tblName_, name);
575 tblID_ = tblid;
576 length_ = length;
577 numFlds_ = numFld;
578 numIndexes_ = numIdx;
579 chunkPtr_ = chunk;
582 long TableImpl::spaceUsed()
584 Chunk *chk = (Chunk*)chunkPtr_;
585 long totSize = chk->getTotalDataNodes() * chk->getSize();
586 totSize = totSize + (chk->totalPages() * sizeof (PageInfo));
587 return totSize;
590 int TableImpl::pagesUsed()
592 Chunk *chk = (Chunk*)chunkPtr_;
593 return chk->totalPages();
596 long TableImpl::numTuples()
598 return ((Chunk*)chunkPtr_)->getTotalDataNodes();
601 List TableImpl::getFieldNameList()
603 List fldNameList;
604 FieldIterator fIter = fldList_.getIterator();
605 while (fIter.hasElement())
607 FieldDef def = fIter.nextElement();
608 Identifier *elem = new Identifier();
609 strcpy(elem->name, def.fldName_);
610 fldNameList.append(elem);
612 return fldNameList;
614 DbRetVal TableImpl::close()
616 if (NULL == iter)
618 printError(ErrNotOpen,"Scan not open");
619 return ErrNotOpen;
621 iter->close();
622 delete iter;
623 iter = NULL;
624 return OK;
626 DbRetVal TableImpl::lock(bool shared)
629 DbRetVal ret = OK;
631 if (shared)
632 ret = lMgr_->getSharedLock(chunkPtr_, NULL);
633 else
634 ret = lMgr_->getExclusiveLock(chunkPtr_, NULL);
635 if (OK != ret)
637 printError(ret, "Could not exclusive lock on the table %x", chunkPtr_);
638 }else {
639 //do not append for S to X upgrade
640 if (!ProcessManager::hasLockList.exists(chunkPtr_))
641 ProcessManager::hasLockList.append(chunkPtr_);
644 return ret;
646 DbRetVal TableImpl::unlock()
649 if (!ProcessManager::hasLockList.exists(chunkPtr_)) return OK;
650 DbRetVal ret = lMgr_->releaseLock(chunkPtr_);
651 if (OK != ret)
653 printError(ret, "Could not release exclusive lock on the table %x", chunkPtr_);
654 }else
656 ProcessManager::hasLockList.remove(chunkPtr_);
659 return OK;
662 TableImpl::~TableImpl()
664 if (NULL != iter ) { delete iter; iter = NULL; }
665 if (NULL != idxInfo) { delete idxInfo; idxInfo = NULL; }
666 if (NULL != indexPtr_) { delete[] indexPtr_; indexPtr_ = NULL; }
667 if (NULL != idxInfo)
669 for (int i = 0; i < numIndexes_; i++) delete idxInfo[i];
670 delete[] idxInfo;
671 idxInfo = NULL;
673 if (numFlds_ > 31 && cNullInfo != NULL) { free(cNullInfo); cNullInfo = NULL; }
675 fldList_.removeAll();