Fixes for err time out rc
[csql.git] / src / server / TableImpl.cxx
blob612dc040b349d4a3cd7f300d2060e7cf7176d1c1
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;
72 markFldNull(colpos);
75 void TableImpl::markFldNull(int fldpos)
77 if (fldpos <1 || fldpos > numFlds_) return;
78 if (isIntUsedForNULL) {
79 if (!BITSET(iNotNullInfo, fldpos)) SETBIT(iNullInfo, fldpos);
81 else
82 if (!BITSET(iNotNullInfo, fldpos)) cNullInfo[fldpos-1] = 1;
83 return;
86 void TableImpl::clearFldNull(const char *name)
88 int colpos = fldList_.getFieldPosition(name);
89 if (-1 == colpos)
91 printError(ErrNotExists, "Field %s does not exist", name);
92 return;
95 clearFldNull(colpos);
98 void TableImpl::clearFldNull(int colpos)
100 if (colpos <1 || colpos > numFlds_) return;
101 if (isIntUsedForNULL) {
102 CLEARBIT(iNullInfo, colpos);
104 else
105 cNullInfo[colpos-1] = 0;
106 return;
110 DbRetVal TableImpl::execute()
112 if (NULL != iter)
114 printError(ErrAlready,"Scan already open:Close and re execute");
115 return ErrAlready;
117 //table ptr is set in predicate because it needs to access the
118 //type and length to evaluate
119 if( NULL != pred_)
121 PredicateImpl *pred = (PredicateImpl*) pred_;
122 pred->setTable(this);
124 DbRetVal ret = OK;
126 ret = createPlan();
127 if (OK != ret)
129 printError(ErrSysInternal,"Unable to create the plan");
130 return ErrSysInternal;
132 if (useIndex_ >= 0)
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);
136 else
138 printError(ErrSysFatal,"Unable to create tuple iterator");//should never happen
139 return ErrSysFatal;
141 ret = iter->open();
142 if (OK != ret)
144 printError(ret,"Unable to open the iterator");
145 return ret;
147 return OK;
151 DbRetVal TableImpl::createPlan()
153 if (isPlanCreated) {
154 //will do early return here. plan is generated only when setPredicate is called.
155 if (scanType_ == unknownScan) return ErrSysFatal; //this should never happen
156 else return OK;
158 useIndex_ = -1;
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;
165 return OK;
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 char *fName = ((SingleFieldHashIndexInfo*)idxInfo[i])->fldName;
177 if (pred->pointLookupInvolved(fName))
179 printDebug(DM_Predicate, "point lookup involved for field %s",fName);
180 scanType_ = hashIndexScan;
181 useIndex_ = i;
182 isPlanCreated = true;
183 return OK;
188 scanType_ = fullTableScan;
189 isPlanCreated = true;
190 return OK;
193 void* TableImpl::fetch()
195 fetchNoBind();
196 if (NULL == curTuple_) return curTuple_;
197 copyValuesToBindBuffer(curTuple_);
198 return curTuple_;
200 void* TableImpl::fetch(DbRetVal &rv)
202 fetchNoBind(rv);
203 if (NULL == curTuple_) return curTuple_;
204 copyValuesToBindBuffer(curTuple_);
205 return curTuple_;
208 void* TableImpl::fetchNoBind()
210 if (NULL == iter)
212 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
213 return NULL;
215 void *prevTuple = curTuple_;
216 curTuple_ = iter->next();
217 if (NULL == curTuple_)
219 return NULL;
221 DbRetVal lockRet = OK;
222 if ((*trans)->isoLevel_ == READ_REPEATABLE) {
223 lockRet = lMgr_->getSharedLock(curTuple_, trans);
224 if (OK != lockRet)
226 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
227 curTuple_ = prevTuple;
228 return NULL;
232 else if ((*trans)->isoLevel_ == READ_COMMITTED)
234 //if iso level is read committed, operation duration lock is sufficent
235 //so release it here itself.
236 int tries = 5;
237 struct timeval timeout;
238 timeout.tv_sec = Conf::config.getMutexSecs();
239 timeout.tv_usec = Conf::config.getMutexUSecs();
241 bool status = false;
242 while(true) {
243 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
244 if (OK != lockRet)
246 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
247 curTuple_ = prevTuple;
248 return NULL;
250 if (!status) break;
251 tries--;
252 if (tries == 0) break;
253 os::select(0, 0, 0, 0, &timeout);
256 if (tries == 0)
258 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
259 curTuple_ = prevTuple;
260 return NULL;
263 return curTuple_;
266 void* TableImpl::fetchNoBind(DbRetVal &rv)
268 rv = OK;
269 if (NULL == iter)
271 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
272 rv = ErrNotOpen;
273 return NULL;
275 void *prevTuple = curTuple_;
276 curTuple_ = iter->next();
277 if (NULL == curTuple_)
279 return NULL;
281 DbRetVal lockRet = OK;
282 if ((*trans)->isoLevel_ == READ_REPEATABLE) {
283 lockRet = lMgr_->getSharedLock(curTuple_, trans);
284 if (OK != lockRet)
286 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
287 rv = ErrLockTimeOut;
288 curTuple_ = prevTuple;
289 return NULL;
293 else if ((*trans)->isoLevel_ == READ_COMMITTED)
295 //if iso level is read committed, operation duration lock is sufficent
296 //so release it here itself.
297 int tries = 5;
298 struct timeval timeout;
299 timeout.tv_sec = Conf::config.getMutexSecs();
300 timeout.tv_usec = Conf::config.getMutexUSecs();
302 bool status = false;
303 while(true) {
304 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
305 if (OK != lockRet)
307 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
308 curTuple_ = prevTuple;
309 rv = ErrLockTimeOut;
310 return NULL;
312 if (!status) break;
313 tries--;
314 if (tries == 0) break;
315 os::select(0, 0, 0, 0, &timeout);
318 if (tries == 0)
320 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
321 curTuple_ = prevTuple;
322 rv = ErrLockTimeOut;
323 return NULL;
326 return curTuple_;
329 DbRetVal TableImpl::insertTuple()
331 DbRetVal ret =OK;
332 void *tptr = ((Chunk*)chunkPtr_)->allocate(db_, &ret);
333 if (NULL == tptr)
335 printError(ret, "Unable to allocate record from chunk");
336 return ret;
338 ret = lMgr_->getExclusiveLock(tptr, trans);
339 if (OK != ret)
341 ((Chunk*)chunkPtr_)->free(db_, tptr);
342 printError(ret, "Could not get lock for the insert tuple %x", tptr);
343 return ErrLockTimeOut;
347 ret = copyValuesFromBindBuffer(tptr);
348 if (ret != OK)
350 printError(ret, "Unable to copy values from bind buffer");
351 (*trans)->removeFromHasList(db_, tptr);
352 lMgr_->releaseLock(tptr);
353 ((Chunk*)chunkPtr_)->free(db_, tptr);
354 return ret;
357 int addSize = 0;
358 if (numFlds_ < 31)
360 addSize = 4;
361 *(int*)((char*)(tptr) + (length_-addSize)) = iNullInfo;
363 else
365 addSize = os::align(numFlds_);
366 os::memcpy(((char*)(tptr) + (length_-addSize)), cNullInfo, addSize);
369 //int tupleSize = length_ + addSize;
370 if (NULL != indexPtr_)
372 int i;
373 //it has index
374 for (i = 0; i < numIndexes_ ; i++)
376 ret = insertIndexNode(*trans, indexPtr_[i], idxInfo[i], tptr);
377 if (ret != OK) { printError(ret, "Error in inserting to index"); break;}
379 if (i != numIndexes_ )
381 for (int j = 0; j < i ; j++) {
382 printError(ErrWarning, "Deleting index node");
383 deleteIndexNode(*trans, indexPtr_[j], idxInfo[j], tptr);
385 lMgr_->releaseLock(tptr);
386 (*trans)->removeFromHasList(db_, tptr);
387 ((Chunk*)chunkPtr_)->free(db_, tptr);
388 //TMP::remove int derefernce
389 printError(ret, "PRABA:::Unable to insert index node for tuple %x %d", tptr, *(int*)tptr);
390 return ret;
393 if (undoFlag)
394 ret = (*trans)->appendUndoLog(sysDB_, InsertOperation, tptr, length_);
395 return ret;
398 DbRetVal TableImpl::deleteTuple()
400 if (NULL == curTuple_)
402 printError(ErrNotOpen, "Scan not open: No Current tuple");
403 return ErrNotOpen;
405 DbRetVal ret = lMgr_->getExclusiveLock(curTuple_, trans);
406 if (OK != ret)
408 printError(ret, "Could not get lock for the delete tuple %x", curTuple_);
409 return ErrLockTimeOut;
412 if (NULL != indexPtr_)
414 int i;
415 //it has index
416 for (i = 0; i < numIndexes_ ; i++)
418 ret = deleteIndexNode(*trans, indexPtr_[i], idxInfo[i], curTuple_);
419 if (ret != OK) break;
421 if (i != numIndexes_ )
423 for (int j = 0; j < i ; j++)
424 insertIndexNode(*trans, indexPtr_[j], idxInfo[j], curTuple_);
425 lMgr_->releaseLock(curTuple_);
426 (*trans)->removeFromHasList(db_, curTuple_);
427 printError(ret, "Unable to insert index node for tuple %x", curTuple_);
428 return ret;
431 ((Chunk*)chunkPtr_)->free(db_, curTuple_);
432 if (undoFlag)
433 ret = (*trans)->appendUndoLog(sysDB_, DeleteOperation, curTuple_, length_);
434 return ret;
437 int TableImpl::deleteWhere()
439 int tuplesDeleted = 0;
440 DbRetVal rv = OK;
441 rv = execute();
442 if (rv !=OK) return (int) rv;
443 while(true){
444 fetchNoBind( rv);
445 if (rv != OK) { tuplesDeleted = (int)rv; break; }
446 if (NULL == curTuple_) break;
447 rv = deleteTuple();
448 if (rv != OK) {
449 printError(rv, "Error: Could only delete %d tuples", tuplesDeleted);
450 close();
451 return (int) rv;
453 tuplesDeleted++;
455 close();
456 return tuplesDeleted;
459 int TableImpl::truncate()
461 //take exclusive lock on the table
462 //get the chunk ptr of the table
463 //traverse the tablechunks and free all the pages except the first one
464 //get the chunk ptr of all its indexes
465 //traverse the indexchunks and free all the pages except the first one
466 //release table lock
468 //TEMPORARY FIX
469 DbRetVal rv = OK;
470 Predicate* tmpPred = pred_;
471 pred_ = NULL;
472 isPlanCreated = false;
473 int tuplesDeleted = deleteWhere();
474 isPlanCreated = false;
475 pred_ = tmpPred;
476 return tuplesDeleted;
479 DbRetVal TableImpl::updateTuple()
481 if (NULL == curTuple_)
483 printError(ErrNotOpen, "Scan not open: No Current tuple");
484 return ErrNotOpen;
486 DbRetVal ret = lMgr_->getExclusiveLock(curTuple_, trans);
487 if (OK != ret)
489 printError(ret, "Could not get lock for the update tuple %x", curTuple_);
490 return ErrLockTimeOut;
492 if (NULL != indexPtr_)
494 //it has index
495 //TODO::If it fails while updating index node, we have to undo all the updates
496 //on other indexes on the table.Currently it will leave the database in an
497 //inconsistent state.
498 for (int i = 0; i < numIndexes_ ; i++)
500 ret = updateIndexNode(*trans, indexPtr_[i], idxInfo[i], curTuple_);
501 if (ret != OK)
503 lMgr_->releaseLock(curTuple_);
504 (*trans)->removeFromHasList(db_, curTuple_);
505 printError(ret, "Unable to update index node for tuple %x", curTuple_);
506 return ret;
510 if (undoFlag)
511 ret = (*trans)->appendUndoLog(sysDB_, UpdateOperation, curTuple_, length_);
512 if (ret != OK) return ret;
513 int addSize = 0;
514 if (numFlds_ < 31)
516 addSize = 4;
517 *(int*)((char*)(curTuple_) + (length_-addSize)) |= iNullInfo;
519 else
521 addSize = os::align(numFlds_);
522 //TODO::Do not do blind memcpy. It should OR each and every char
523 //os::memcpy(((char*)(curTuple_) + (length_-addSize)), cNullInfo, addSize);
527 DbRetVal rv = copyValuesFromBindBuffer(curTuple_, false);
528 if (rv != OK) {
529 lMgr_->releaseLock(curTuple_);
530 (*trans)->removeFromHasList(db_, curTuple_);
531 return rv;
533 return OK;
536 void TableImpl::printInfo()
538 printf(" <TableName> %s </TableName>\n", tblName_);
539 printf(" <TupleCount> %d </TupleCount>\n", numTuples());
540 printf(" <PagesUsed> %d </PagesUsed>\n", pagesUsed());
541 printf(" <SpaceUsed> %d </SpaceUsed>\n", spaceUsed());
542 printf(" <Indexes> %d <Indexes>\n", numIndexes_);
543 printf(" <TupleLength> %d </TupleLength>\n", length_);
544 printf(" <Fields> %d </Fields>\n", numFlds_);
545 printf(" <Indexes>\n");
546 for (int i =0; i<numIndexes_; i++)
547 printf("<IndexName> %s </IndexName>\n", CatalogTableINDEX::getName(indexPtr_[i]));
548 printf(" </Indexes>\n");
552 DbRetVal TableImpl::copyValuesFromBindBuffer(void *tuplePtr, bool isInsert)
554 //Iterate through the bind list and copy the value here
555 FieldIterator fIter = fldList_.getIterator();
556 char *colPtr = (char*) tuplePtr;
557 int fldpos=1;
558 while (fIter.hasElement())
560 FieldDef def = fIter.nextElement();
561 if (def.isNull_ && !def.isDefault_ && NULL == def.bindVal_ && isInsert)
563 printError(ErrNullViolation, "NOT NULL constraint violation for field %s\n", def.fldName_);
564 return ErrNullViolation;
566 if (def.isDefault_ && NULL == def.bindVal_ && isInsert)
568 void *dest = AllDataType::alloc(def.type_, def.length_);
569 AllDataType::convert(typeString, def.defaultValueBuf_, def.type_, dest);
570 AllDataType::copyVal(colPtr, dest, def.type_, def.length_);
571 colPtr = colPtr + os::align(AllDataType::size(def.type_, def.length_));
572 fldpos++;
573 free (dest);
574 continue;
576 switch(def.type_)
578 case typeString:
579 if (NULL != def.bindVal_)
581 strcpy((char*)colPtr, (char*)def.bindVal_);
582 *(((char*)colPtr) + (def.length_-1)) = '\0';
584 else if (!def.isNull_ && isInsert) setNullBit(fldpos);
585 colPtr = colPtr + os::align(def.length_);
586 break;
587 case typeBinary:
588 if (NULL != def.bindVal_ )
589 os::memcpy((char*)colPtr, (char*)def.bindVal_, def.length_);
590 else if (!def.isNull_ && isInsert) setNullBit(fldpos);
591 colPtr = colPtr + os::align(def.length_);
592 break;
593 default:
594 if (NULL != def.bindVal_)
595 AllDataType::copyVal(colPtr, def.bindVal_, def.type_);
596 else { if (!def.isNull_ && isInsert) setNullBit(fldpos); }
597 colPtr = colPtr + os::align(AllDataType::size(def.type_));
598 break;
600 fldpos++;
602 return OK;
604 void TableImpl::setNullBit(int fldpos)
606 if (isIntUsedForNULL)
607 SETBIT(iNullInfo, fldpos);
608 else
609 cNullInfo[fldpos-1] = 1;
611 DbRetVal TableImpl::copyValuesToBindBuffer(void *tuplePtr)
613 //Iterate through the bind list and copy the value here
614 FieldIterator fIter = fldList_.getIterator();
615 char *colPtr = (char*) tuplePtr;
616 while (fIter.hasElement())
618 FieldDef def = fIter.nextElement();
619 switch(def.type_)
621 case typeString:
622 if (NULL != def.bindVal_)
623 strcpy((char*)def.bindVal_, (char*)colPtr);
624 colPtr = colPtr + os::align(def.length_);
625 break;
626 case typeBinary:
627 if (NULL != def.bindVal_)
628 os::memcpy((char*)def.bindVal_, (char*)colPtr, def.length_);
629 colPtr = colPtr + os::align(def.length_);
630 break;
631 default:
632 if (NULL != def.bindVal_)
633 AllDataType::copyVal(def.bindVal_, colPtr, def.type_);
634 colPtr = colPtr + os::align(AllDataType::size(def.type_));
635 break;
638 return OK;
641 //-1 index not supported
642 DbRetVal TableImpl::insertIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple)
644 INDEX *iptr = (INDEX*)indexPtr;
645 DbRetVal ret = OK;
646 printDebug(DM_Table, "Inside insertIndexNode type %d", iptr->indexType_);
647 Index* idx = Index::getIndex(iptr->indexType_);
648 ret = idx->insert(this, tr, indexPtr, info, tuple,undoFlag);
649 return ret;
652 DbRetVal TableImpl::deleteIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple)
654 INDEX *iptr = (INDEX*)indexPtr;
655 DbRetVal ret = OK;
656 Index* idx = Index::getIndex(iptr->indexType_);
657 ret = idx->remove(this, tr, indexPtr, info, tuple, undoFlag);
658 return ret;
660 void TableImpl::printSQLIndexString()
662 CatalogTableINDEXFIELD cIndexField(sysDB_);
663 char fName[IDENTIFIER_LENGTH];
664 char *fldName = fName;
665 DataType type;
666 for (int i = 0; i < numIndexes_ ; i++)
668 INDEX *iptr = (INDEX*) indexPtr_[i];
669 cIndexField.getFieldNameAndType((void*)iptr, fldName, type);
670 printf("CREATE INDEX %s on %s ( %s ) ", iptr->indName_, getName(), fldName);
671 if (((SingleFieldHashIndexInfo*) idxInfo[i])->isUnique) printf(" UNIQUE;\n"); else printf(";\n");
676 DbRetVal TableImpl::updateIndexNode(Transaction *tr, void *indexPtr, IndexInfo *info, void *tuple)
678 INDEX *iptr = (INDEX*)indexPtr;
679 DbRetVal ret = OK;
680 Index* idx = Index::getIndex(iptr->indexType_);
681 //TODO::currently it updates irrespective of whether the key changed or not
682 //because of this commenting the whole index update code. relook at it and uncomment
684 //ret = idx->update(this, tr, indexPtr, info, tuple, undoFlag);
686 return ret;
690 void TableImpl::setTableInfo(char *name, int tblid, size_t length,
691 int numFld, int numIdx, void *chunk)
693 strcpy(tblName_, name);
694 tblID_ = tblid;
695 length_ = length;
696 numFlds_ = numFld;
697 numIndexes_ = numIdx;
698 chunkPtr_ = chunk;
701 long TableImpl::spaceUsed()
703 Chunk *chk = (Chunk*)chunkPtr_;
704 long totSize = chk->getTotalDataNodes() * chk->getSize();
705 totSize = totSize + (chk->totalPages() * sizeof (PageInfo));
706 return totSize;
709 int TableImpl::pagesUsed()
711 Chunk *chk = (Chunk*)chunkPtr_;
712 return chk->totalPages();
715 long TableImpl::numTuples()
717 return ((Chunk*)chunkPtr_)->getTotalDataNodes();
720 List TableImpl::getFieldNameList()
722 List fldNameList;
723 FieldIterator fIter = fldList_.getIterator();
724 while (fIter.hasElement())
726 FieldDef def = fIter.nextElement();
727 Identifier *elem = new Identifier();
728 strcpy(elem->name, def.fldName_);
729 fldNameList.append(elem);
731 return fldNameList;
733 DbRetVal TableImpl::close()
735 if (NULL == iter)
737 printError(ErrNotOpen,"Scan not open");
738 return ErrNotOpen;
740 iter->close();
741 delete iter;
742 iter = NULL;
743 return OK;
745 DbRetVal TableImpl::lock(bool shared)
748 DbRetVal ret = OK;
750 if (shared)
751 ret = lMgr_->getSharedLock(chunkPtr_, NULL);
752 else
753 ret = lMgr_->getExclusiveLock(chunkPtr_, NULL);
754 if (OK != ret)
756 printError(ret, "Could not exclusive lock on the table %x", chunkPtr_);
757 }else {
758 //do not append for S to X upgrade
759 if (!ProcessManager::hasLockList.exists(chunkPtr_))
760 ProcessManager::hasLockList.append(chunkPtr_);
763 return ret;
765 DbRetVal TableImpl::unlock()
768 if (!ProcessManager::hasLockList.exists(chunkPtr_)) return OK;
769 DbRetVal ret = lMgr_->releaseLock(chunkPtr_);
770 if (OK != ret)
772 printError(ret, "Could not release exclusive lock on the table %x", chunkPtr_);
773 }else
775 ProcessManager::hasLockList.remove(chunkPtr_);
778 return OK;
781 TableImpl::~TableImpl()
783 if (NULL != iter ) { delete iter; iter = NULL; }
784 if (NULL != indexPtr_) { delete[] indexPtr_; indexPtr_ = NULL; }
785 if (NULL != idxInfo)
787 for (int i = 0; i < numIndexes_; i++) delete idxInfo[i];
788 delete[] idxInfo;
789 idxInfo = NULL;
791 if (numFlds_ > 31 && cNullInfo != NULL) { free(cNullInfo); cNullInfo = NULL; }
793 fldList_.removeAll();