code reorg
[csql.git] / src / storage / TableImplReadOp.cxx
blob38eb62489095ed91f1f6ca0429359ca72480d3ee
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>
26 #include<AggTableImpl.h> //for AggType
28 DbRetVal TableImpl::optimize()
30 //table ptr is set in predicate because it needs to access the
31 //type and length to evaluate
32 if( NULL != pred_)
34 PredicateImpl *pred = (PredicateImpl*) pred_;
35 pred->setTable(this);
36 pred->setProjectionList(NULL);
37 pred->setOffsetAndType();
39 DbRetVal rv = createPlan();
40 if (rv != OK) return rv;
41 if (iter) { iter->close(); delete iter; iter = NULL; }
42 if (useIndex_ >= 0)
43 iter = new TupleIterator(pred_, scanType_, idxInfo[useIndex_], chunkPtr_, sysDB_->procSlot,isBetween,isPointLook,shouldNullSearch);
44 else if (scanType_ == fullTableScan)
45 iter = new TupleIterator(pred_, scanType_, NULL, chunkPtr_, sysDB_->procSlot,isBetween,isPointLook,shouldNullSearch);
46 else
48 printError(ErrSysFatal,"Unable to create tuple iterator");
49 //should never happen
50 return ErrSysFatal;
52 iter->setPlan();
53 return OK;
56 DbRetVal TableImpl::execute()
58 if (iter && !iter->isIterClosed())
60 //printError(ErrAlready,"Scan already open:Close and re execute");
61 return ErrAlready;
63 DbRetVal ret = OK;
64 if (!isPlanCreated) ret = optimize();
65 if (OK != ret)
67 printError(ErrSysInternal,"Unable to create the plan");
68 return ErrSysInternal;
70 ret = iter->open();
71 if (OK != ret)
73 printError(ret,"Unable to open the iterator");
74 return ret;
76 return OK;
80 DbRetVal TableImpl::createPlan()
82 if (isPlanCreated) {
83 //will do early return here. plan is generated only when setPredicate is called.
84 if (scanType_ == unknownScan) return ErrSysFatal; //this should never happen
85 else return OK;
87 isBetween=false;
88 isPointLook = false;
89 useIndex_ = -1;
91 FieldIterator fIter = fldList_.getIterator();
92 FieldDef *def = NULL;
93 while ((def = fIter.nextElement())!= NULL) {
94 if (NULL != def->bindVal_) bindList_.append(def);
96 numBindFlds_ = bindList_.size();
97 if (bindListArray_) { ::free(bindListArray_); bindListArray_ = NULL; }
98 bindListArray_ = (void **) malloc(numBindFlds_ * sizeof (void *));
99 void *elem = NULL;
100 int i = 0;
101 ListIterator it = bindList_.getIterator();
102 while ((elem = it.nextElement()) != NULL) bindListArray_[i++] = elem;
103 scanType_ = fullTableScan;
104 isPlanCreated = true;
106 //if there are no predicates then go for full scan
107 //if there are no indexes then go for full scan
108 if (NULL == pred_ || NULL == indexPtr_)
110 return OK;
112 if (NULL != indexPtr_)
114 PredicateImpl *pred = (PredicateImpl*)pred_;
115 //If searching for IS NULL or IS NOT NULL then fullscan
116 if(pred->isIsNullInvolved())
118 scanType_ = fullTableScan;
119 shouldNullSearch=true;
120 return OK;
122 printDebug(DM_Predicate, "predicate does not involve NOT , OR operator");
123 if (!pred->isNotOrInvolved())
125 printDebug(DM_Predicate, "predicate does not involve NOT , OR operator");
126 for (int i =0; i < numIndexes_; i++)
128 bool isAllFldPointLookup = true;
129 HashIndexInfo* info = (HashIndexInfo*) idxInfo[i];
130 FieldIterator iter = info->idxFldList.getIterator();
131 int noOfIfld =0;
132 while(iter.hasElement())
134 noOfIfld++;
135 FieldDef *def = iter.nextElement();
136 if (pred->pointLookupInvolved(def->fldName_))
138 if (!isAllFldPointLookup) break;
139 printDebug(DM_Predicate, "point lookup involved for field %s",def->fldName_);
140 if(hashIndex == info->indType)
141 scanType_ = hashIndexScan;
142 else if (trieIndex == info->indType)
143 scanType_ = trieIndexScan;
144 else
145 scanType_ = treeIndexScan;
146 isPointLook = true;
147 useIndex_ = i;
149 else if (pred->isBetweenInvolved(def->fldName_))
151 if (treeIndex == info->indType)
153 scanType_ = treeIndexScan;
154 useIndex_ = i;
155 isBetween=true;
156 break; //no composite index for tree index
157 } else isAllFldPointLookup= false;
159 else if (pred->rangeQueryInvolved(def->fldName_))
161 printDebug(DM_Predicate, "range lookup involved for field %s",def->fldName_);
162 if (treeIndex == info->indType)
164 scanType_ = treeIndexScan;
165 useIndex_ = i;
166 break; //no composite index for tree index
167 } else isAllFldPointLookup=false;
168 }else {
169 useIndex_ = -1;
170 isAllFldPointLookup = false;
171 break;
173 }//while iter.hasElement()
174 if( noOfIfld == 1 && useIndex_ != -1)return OK;
175 if (!isAllFldPointLookup && useIndex_ != -1) return OK;
176 }//for
179 scanType_ = fullTableScan;
180 return OK;
183 void* TableImpl::fetch()
185 fetchNoBind();
186 if (NULL == curTuple_) return curTuple_;
187 copyValuesToBindBuffer(curTuple_);
188 return curTuple_;
190 void* TableImpl::fetch(DbRetVal &rv)
192 fetchNoBind(rv);
193 if (NULL == curTuple_) return curTuple_;
194 copyValuesToBindBuffer(curTuple_);
195 return curTuple_;
198 void* TableImpl::fetchNoBind()
200 if (NULL == iter)
202 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
203 return NULL;
205 void *prevTuple = curTuple_;
206 curTuple_ = iter->next();
207 if (NULL == curTuple_)
209 return NULL;
211 DbRetVal lockRet = OK;
212 if (!loadFlag) {
213 if ((*trans)->isoLevel_ == READ_COMMITTED)
215 //if iso level is read committed, operation duration lock is sufficent
216 //so release it here itself.
217 int tries = Conf::config.getMutexRetries();
218 struct timeval timeout, timeval;
219 timeout.tv_sec = Conf::config.getMutexSecs();
220 timeout.tv_usec = Conf::config.getMutexUSecs();
222 bool status = false;
223 while(true) {
224 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
225 if (OK != lockRet)
227 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
228 curTuple_ = prevTuple;
229 return NULL;
231 if (!status) break;
232 tries--;
233 if (tries == 0) break;
234 timeval.tv_sec = timeout.tv_sec;
235 timeval.tv_usec = timeout.tv_usec;
236 os::select(0, 0, 0, 0, &timeval);
238 if (tries == 0)
240 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
241 curTuple_ = prevTuple;
242 return NULL;
245 else if ((*trans)->isoLevel_ == READ_REPEATABLE) {
246 if (OK != trySharedLock(curTuple_, trans))
248 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
249 curTuple_ = prevTuple;
250 return NULL;
255 return curTuple_;
258 void* TableImpl::fetchNoBind(DbRetVal &rv)
260 rv = OK;
261 if (NULL == iter)
263 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
264 rv = ErrNotOpen;
265 return NULL;
267 void *prevTuple = curTuple_;
268 curTuple_ = iter->next();
269 if (NULL == curTuple_)
271 return NULL;
273 DbRetVal lockRet = OK;
274 if (!loadFlag) {
275 if ((*trans)->isoLevel_ == READ_REPEATABLE) {
276 lockRet = lMgr_->getSharedLock(curTuple_, trans);
277 if (OK != lockRet)
279 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
280 rv = ErrLockTimeOut;
281 curTuple_ = prevTuple;
282 return NULL;
286 else if ((*trans)->isoLevel_ == READ_COMMITTED)
288 //if iso level is read committed, operation duration lock is sufficent
289 //so release it here itself.
290 int tries = Conf::config.getMutexRetries();
291 //struct timeval timeout;
292 //timeout.tv_sec = Conf::config.getMutexSecs();
293 //timeout.tv_usec = Conf::config.getMutexUSecs();
295 bool status = false;
296 while(true) {
297 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
298 if (OK != lockRet)
300 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
301 curTuple_ = prevTuple;
302 rv = ErrLockTimeOut;
303 return NULL;
305 if (!status) break;
306 tries--;
307 if (tries == 0) break;
308 //os::select(0, 0, 0, 0, &timeout);
310 if (tries == 0)
312 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
313 curTuple_ = prevTuple;
314 rv = ErrLockTimeOut;
315 return NULL;
319 return curTuple_;
321 DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf, bool &noRec)
323 FieldInfo *info = new FieldInfo();
324 DbRetVal rv = getFieldInfo(fldName, info);
325 if (OK != rv) return rv;
326 bool res= false;
327 if (AGG_MIN == aType || AGG_MAX == aType) {
328 int pos =0;
329 IndexType iType = getIndexType((char*)fldName, &pos);
330 if(treeIndex == iType && pos >=0) {
331 if (AGG_MIN == aType) {
332 HashIndexInfo* hInfo = (HashIndexInfo*) idxInfo[pos];
333 CINDEX *iptr = (CINDEX*) hInfo->indexPtr;
334 TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_;
335 TreeIter *iter=NULL;
336 if(fstNode!=NULL){
337 TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode)));
338 iter = new TreeIter(start,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
339 }else{
340 iter = new TreeIter(NULL,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
342 char *tuple = (char*) iter->getFirstElement();
343 if (tuple != NULL) {
344 AllDataType::copyVal(buf,(void*)(tuple+info->offset),
345 info->type, info->length);
346 delete iter;
347 return OK;
349 delete iter; iter = NULL;
351 else if (AGG_MAX == aType) {
352 HashIndexInfo* hInfo = (HashIndexInfo*) idxInfo[pos];
353 CINDEX *iptr = (CINDEX*) hInfo->indexPtr;
354 TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_;
355 TreeIter *iter=NULL;
356 if(fstNode!=NULL){
357 TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode)));
358 iter = new TreeIter(start,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
359 }else{
360 iter = new TreeIter(NULL,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
362 char *tuple = (char*) iter->getLastElement();
363 if (tuple != NULL) {
364 AllDataType::copyVal(buf,(void*)(tuple+info->offset),
365 info->type, info->length);
366 delete iter; iter = NULL;
367 return OK;
369 delete iter; iter=NULL;
372 }else if (AGG_COUNT == aType) {
373 (*(int*)buf) = 0;
377 DataType type = info->type;
378 int length = info->length;
379 int offset = info->offset;
380 int colPos = fldList_.getFieldPosition(fldName);
381 bool isNullable= true;
382 if (info->isNull || info->isPrimary || info->isDefault || info->isAutoIncrement) {
383 isNullable = false;
385 int nullOffset = length_-4;
386 if (aType == AGG_COUNT) {
387 length = sizeof(int);
388 type = typeInt;
390 if (NULL == pred_ && typeInt == type && aType != AGG_AVG)
391 { //perf opt
392 ChunkIterator cIter = ((Chunk*)chunkPtr_)->getIterator();
393 char *tuple =(char*)cIter.nextElement();
394 if (NULL == tuple) {
395 *(int *) buf = 0;
396 noRec = true;
397 return OK;
399 int count =1;
400 if (isNullable) {
401 if (isIntUsedForNULL) {
402 if (BITSET(*(int*)(tuple+nullOffset), colPos-1)) count =0;
404 else {
405 curTuple_= tuple;
406 if(isFldNull(colPos)) count =0;
409 if (aType != AGG_COUNT)
410 AllDataType::copyVal(buf, (void*) (tuple+offset), type, length);
411 void *prev=NULL;
412 prev = curTuple_;
413 cIter.pageSize = PAGE_SIZE;
414 while(1)
416 tuple = (char*)cIter.nextElementInt();
417 if (NULL == tuple) break;
418 if (isNullable) {
419 if (isIntUsedForNULL) {
420 if (BITSET(*(int*)(tuple+nullOffset), colPos-1)) continue;
422 else {
423 curTuple_= tuple;
424 if(isFldNull(colPos)) continue;
427 if (aType == AGG_MIN)
429 if (*(int*)buf >= *((int*)(tuple+offset)))
430 *(int*)buf = *((int*)(tuple+offset));
432 else if (aType == AGG_MAX)
434 if (*(int*)buf <= *((int*)(tuple+offset)))
435 *(int*)buf = *((int*)(tuple+offset));
437 else if (aType == AGG_SUM)
439 *(int*)buf += *((int*)(tuple+offset));
441 else if (aType == AGG_AVG)
443 *(int*)buf = *(int*)buf + *((int*)(tuple+offset));
444 count++;
446 else if (aType == AGG_COUNT)
448 count++;
451 curTuple_= prev;
452 if( AGG_AVG == aType) AllDataType::divVal(buf, &count, type);
453 else if (AGG_COUNT == aType) (*(int*)buf) = count;
454 delete info;
455 return OK;
458 char *tuple = (char*) fetchNoBind(rv);
459 if ( NULL == tuple) { noRec = true; return OK; }
460 int count =1;
462 while(isFldNull(colPos)) {
463 tuple= (char*) fetchNoBind(rv);
464 if (aType == AGG_COUNT) count++;
465 if (tuple) break;
467 if ( NULL == tuple) { noRec = true; return OK; }
469 if (aType == AGG_AVG) {
470 AllDataType::convertToDouble(buf, (void*) (tuple+offset), type);
471 } else if (aType != AGG_COUNT) {
472 AllDataType::copyVal(buf, (void*) (tuple+offset), type, length);
474 while(1) {
475 tuple = (char*) fetchNoBind(rv);
476 if (NULL == tuple) break;
477 if (isNullable) {
478 if (isIntUsedForNULL) {
479 if (BITSET(*(int*)(tuple+nullOffset), colPos-1)) continue;
481 else {
482 curTuple_= tuple;
483 if(isFldNull(colPos)) continue;
486 switch(aType) {
487 case AGG_MIN:
489 res = AllDataType::compareVal(buf, (void*) (tuple+offset),
490 OpGreaterThanEquals,
491 type, length);
492 if (res) AllDataType::copyVal(buf, (void*) (tuple+offset),
493 type, length);
494 break;
496 case AGG_MAX:
498 res = AllDataType::compareVal(buf, (void*) (tuple+offset),
499 OpLessThanEquals,
500 type, length);
501 if (res) AllDataType::copyVal(buf, (void*) (tuple+offset),
502 type, length);
503 break;
505 case AGG_SUM:
507 AllDataType::addVal(buf, (void*) (tuple+offset),
508 type);
509 break;
511 case AGG_AVG:
513 double tmpBuf=0.0;
514 AllDataType::convertToDouble(&tmpBuf, (void*) (tuple+offset), type);
515 AllDataType::addVal(buf, &tmpBuf, typeDouble);
516 count++;
517 break;
519 case AGG_COUNT:
521 count++;
522 break;
526 switch(aType) {
527 case AGG_AVG:
529 AllDataType::divVal((double *)buf, count, type);
530 break;
532 case AGG_COUNT:
534 (*(int*)buf) = count;
535 break;
538 delete info;
539 return OK;
542 long TableImpl::numTuples()
544 return ((Chunk*)chunkPtr_)->getTotalDataNodes();
547 DbRetVal TableImpl::closeScan()
549 //do not throw scan not open error
550 //this function will be called by table handle
551 if (iter) {
552 iter->close();
554 return OK;
557 bool TableImpl::pushPredicate(Predicate *pred)
559 bool ret = false;
560 PredicateImpl *pImpl = (PredicateImpl*) pred;
561 char tableName[IDENTIFIER_LENGTH];
562 Table::getTableNameAlone(pImpl->getFldName1(), tableName);
563 //printf("predicate tbl name %s\n", tableName);
565 //if predicate is of form t1.f1=t2.f1 then do not push here
566 bool isAliasSet = (0 !=strcmp(getAliasName(),"")) ;
567 if (0 != strcmp(pImpl->getFldName2(),"")) return ret;
569 if (0 == strcmp(getName(), tableName) ||(isAliasSet && 0 == strcmp(getAliasName(), tableName)))
571 setPredicate(pred);
572 //printf("PRABA::pushed predicate in tablehdl %s\n", getName());
573 ret = true;
575 return ret;