code reorg
[csql.git] / src / relational / table / TableImplReadOp.cxx
blob7060d423711c3d8153aa6aaaa12d4a0f931ac5b6
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_;
191 void* TableImpl::fetch(DbRetVal &rv)
193 fetchNoBind(rv);
194 if (NULL == curTuple_) return curTuple_;
195 copyValuesToBindBuffer(curTuple_);
196 return curTuple_;
199 void* TableImpl::fetchNoBind()
201 if (NULL == iter)
203 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
204 return NULL;
206 void *prevTuple = curTuple_;
207 curTuple_ = iter->next();
208 if (NULL == curTuple_)
210 return NULL;
212 DbRetVal lockRet = OK;
213 if (!loadFlag) {
214 if ((*trans)->isoLevel_ == READ_COMMITTED)
216 //if iso level is read committed, operation duration lock is sufficent
217 //so release it here itself.
218 int tries = Conf::config.getMutexRetries();
219 struct timeval timeout, timeval;
220 timeout.tv_sec = Conf::config.getMutexSecs();
221 timeout.tv_usec = Conf::config.getMutexUSecs();
223 bool status = false;
224 while(true) {
225 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
226 if (OK != lockRet)
228 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
229 curTuple_ = prevTuple;
230 return NULL;
232 if (!status) break;
233 tries--;
234 if (tries == 0) break;
235 timeval.tv_sec = timeout.tv_sec;
236 timeval.tv_usec = timeout.tv_usec;
237 os::select(0, 0, 0, 0, &timeval);
239 if (tries == 0)
241 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
242 curTuple_ = prevTuple;
243 return NULL;
246 else if ((*trans)->isoLevel_ == READ_REPEATABLE) {
247 if (OK != trySharedLock(curTuple_, trans))
249 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
250 curTuple_ = prevTuple;
251 return NULL;
256 return curTuple_;
259 void* TableImpl::fetchNoBind(DbRetVal &rv)
261 rv = OK;
262 if (NULL == iter)
264 printError(ErrNotOpen,"Scan not open or Scan is closed\n");
265 rv = ErrNotOpen;
266 return NULL;
268 void *prevTuple = curTuple_;
269 curTuple_ = iter->next();
270 if (NULL == curTuple_)
272 return NULL;
274 DbRetVal lockRet = OK;
275 if (!loadFlag) {
276 if ((*trans)->isoLevel_ == READ_REPEATABLE) {
277 lockRet = lMgr_->getSharedLock(curTuple_, trans);
278 if (OK != lockRet)
280 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
281 rv = ErrLockTimeOut;
282 curTuple_ = prevTuple;
283 return NULL;
287 else if ((*trans)->isoLevel_ == READ_COMMITTED)
289 //if iso level is read committed, operation duration lock is sufficent
290 //so release it here itself.
291 int tries = Conf::config.getMutexRetries();
292 //struct timeval timeout;
293 //timeout.tv_sec = Conf::config.getMutexSecs();
294 //timeout.tv_usec = Conf::config.getMutexUSecs();
296 bool status = false;
297 while(true) {
298 lockRet = lMgr_->isExclusiveLocked( curTuple_, trans, status);
299 if (OK != lockRet)
301 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
302 curTuple_ = prevTuple;
303 rv = ErrLockTimeOut;
304 return NULL;
306 if (!status) break;
307 tries--;
308 if (tries == 0) break;
309 //os::select(0, 0, 0, 0, &timeout);
311 if (tries == 0)
313 printError(lockRet, "Unable to get the lock for the tuple %x", curTuple_);
314 curTuple_ = prevTuple;
315 rv = ErrLockTimeOut;
316 return NULL;
320 return curTuple_;
323 DbRetVal TableImpl::fetchAgg(const char * fldName, AggType aType, void *buf, bool &noRec)
325 FieldInfo *info = new FieldInfo();
326 DbRetVal rv = getFieldInfo(fldName, info);
327 if (OK != rv) return rv;
328 bool res= false;
329 if (AGG_MIN == aType || AGG_MAX == aType) {
330 int pos =0;
331 IndexType iType = getIndexType((char*)fldName, &pos);
332 if(treeIndex == iType && pos >=0) {
333 if (AGG_MIN == aType) {
334 HashIndexInfo* hInfo = (HashIndexInfo*) idxInfo[pos];
335 CINDEX *iptr = (CINDEX*) hInfo->indexPtr;
336 TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_;
337 TreeIter *iter=NULL;
338 if(fstNode!=NULL){
339 TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode)));
340 iter = new TreeIter(start,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
341 }else{
342 iter = new TreeIter(NULL,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
344 char *tuple = (char*) iter->getFirstElement();
345 if (tuple != NULL) {
346 AllDataType::copyVal(buf,(void*)(tuple+info->offset),
347 info->type, info->length);
348 delete iter;
349 return OK;
351 delete iter; iter = NULL;
353 else if (AGG_MAX == aType) {
354 HashIndexInfo* hInfo = (HashIndexInfo*) idxInfo[pos];
355 CINDEX *iptr = (CINDEX*) hInfo->indexPtr;
356 TreeNode *fstNode=(TreeNode *)iptr->hashNodeChunk_;
357 TreeIter *iter=NULL;
358 if(fstNode!=NULL){
359 TreeNode *start = (TreeNode *)*((char**)((char*)fstNode + sizeof(TreeNode)));
360 iter = new TreeIter(start,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
361 }else{
362 iter = new TreeIter(NULL,(TreeNode*)iptr->hashNodeChunk_,sysDB_->procSlot);
364 char *tuple = (char*) iter->getLastElement();
365 if (tuple != NULL) {
366 AllDataType::copyVal(buf,(void*)(tuple+info->offset),
367 info->type, info->length);
368 delete iter; iter = NULL;
369 return OK;
371 delete iter; iter=NULL;
374 }else if (AGG_COUNT == aType) {
375 (*(int*)buf) = 0;
379 DataType type = info->type;
380 int length = info->length;
381 int offset = info->offset;
382 int colPos = fldList_.getFieldPosition(fldName);
383 bool isNullable= true;
384 if (info->isNull || info->isPrimary || info->isDefault || info->isAutoIncrement) {
385 isNullable = false;
387 int nullOffset = length_-4;
388 if (aType == AGG_COUNT) {
389 length = sizeof(int);
390 type = typeInt;
392 if (NULL == pred_ && typeInt == type && aType != AGG_AVG)
393 { //perf opt
394 ChunkIterator cIter = ((Chunk*)chunkPtr_)->getIterator();
395 char *tuple =(char*)cIter.nextElement();
396 if (NULL == tuple) {
397 *(int *) buf = 0;
398 noRec = true;
399 return OK;
401 int count =1;
402 if (isNullable) {
403 if (isIntUsedForNULL) {
404 if (BITSET(*(int*)(tuple+nullOffset), colPos-1)) count =0;
406 else {
407 curTuple_= tuple;
408 if(isFldNull(colPos)) count =0;
411 if (aType != AGG_COUNT)
412 AllDataType::copyVal(buf, (void*) (tuple+offset), type, length);
413 void *prev=NULL;
414 prev = curTuple_;
415 cIter.pageSize = PAGE_SIZE;
416 while(1)
418 tuple = (char*)cIter.nextElementInt();
419 if (NULL == tuple) break;
420 if (isNullable) {
421 if (isIntUsedForNULL) {
422 if (BITSET(*(int*)(tuple+nullOffset), colPos-1)) continue;
424 else {
425 curTuple_= tuple;
426 if(isFldNull(colPos)) continue;
429 if (aType == AGG_MIN)
431 if (*(int*)buf >= *((int*)(tuple+offset)))
432 *(int*)buf = *((int*)(tuple+offset));
434 else if (aType == AGG_MAX)
436 if (*(int*)buf <= *((int*)(tuple+offset)))
437 *(int*)buf = *((int*)(tuple+offset));
439 else if (aType == AGG_SUM)
441 *(int*)buf += *((int*)(tuple+offset));
443 else if (aType == AGG_AVG)
445 *(int*)buf = *(int*)buf + *((int*)(tuple+offset));
446 count++;
448 else if (aType == AGG_COUNT)
450 count++;
453 curTuple_= prev;
454 if( AGG_AVG == aType) AllDataType::divVal(buf, &count, type);
455 else if (AGG_COUNT == aType) (*(int*)buf) = count;
456 delete info;
457 return OK;
460 char *tuple = (char*) fetchNoBind(rv);
461 if ( NULL == tuple) { noRec = true; return OK; }
462 int count =1;
464 while(isFldNull(colPos)) {
465 tuple= (char*) fetchNoBind(rv);
466 if (aType == AGG_COUNT) count++;
467 if (tuple) break;
469 if ( NULL == tuple) { noRec = true; return OK; }
471 if (aType == AGG_AVG) {
472 AllDataType::convertToDouble(buf, (void*) (tuple+offset), type);
473 } else if (aType != AGG_COUNT) {
474 AllDataType::copyVal(buf, (void*) (tuple+offset), type, length);
476 while(1) {
477 tuple = (char*) fetchNoBind(rv);
478 if (NULL == tuple) break;
479 if (isNullable) {
480 if (isIntUsedForNULL) {
481 if (BITSET(*(int*)(tuple+nullOffset), colPos-1)) continue;
483 else {
484 curTuple_= tuple;
485 if(isFldNull(colPos)) continue;
488 switch(aType) {
489 case AGG_MIN:
491 res = AllDataType::compareVal(buf, (void*) (tuple+offset),
492 OpGreaterThanEquals,
493 type, length);
494 if (res) AllDataType::copyVal(buf, (void*) (tuple+offset),
495 type, length);
496 break;
498 case AGG_MAX:
500 res = AllDataType::compareVal(buf, (void*) (tuple+offset),
501 OpLessThanEquals,
502 type, length);
503 if (res) AllDataType::copyVal(buf, (void*) (tuple+offset),
504 type, length);
505 break;
507 case AGG_SUM:
509 AllDataType::addVal(buf, (void*) (tuple+offset),
510 type);
511 break;
513 case AGG_AVG:
515 double tmpBuf=0.0;
516 AllDataType::convertToDouble(&tmpBuf, (void*) (tuple+offset), type);
517 AllDataType::addVal(buf, &tmpBuf, typeDouble);
518 count++;
519 break;
521 case AGG_COUNT:
523 count++;
524 break;
528 switch(aType) {
529 case AGG_AVG:
531 AllDataType::divVal((double *)buf, count, type);
532 break;
534 case AGG_COUNT:
536 (*(int*)buf) = count;
537 break;
540 delete info;
541 return OK;
544 long TableImpl::numTuples()
546 return ((Chunk*)chunkPtr_)->getTotalDataNodes();
549 DbRetVal TableImpl::closeScan()
551 //do not throw scan not open error
552 //this function will be called by table handle
553 if (iter) {
554 iter->close();
556 return OK;
559 bool TableImpl::pushPredicate(Predicate *pred)
561 bool ret = false;
562 PredicateImpl *pImpl = (PredicateImpl*) pred;
563 char tableName[IDENTIFIER_LENGTH];
564 Table::getTableNameAlone(pImpl->getFldName1(), tableName);
565 //printf("predicate tbl name %s\n", tableName);
567 //if predicate is of form t1.f1=t2.f1 then do not push here
568 bool isAliasSet = (0 !=strcmp(getAliasName(),"")) ;
569 if (0 != strcmp(pImpl->getFldName2(),"")) return ret;
571 if (0 == strcmp(getName(), tableName) ||(isAliasSet && 0 == strcmp(getAliasName(), tableName)))
573 setPredicate(pred);
574 //printf("PRABA::pushed predicate in tablehdl %s\n", getName());
575 ret = true;
577 return ret;