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>
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
34 PredicateImpl
*pred
= (PredicateImpl
*) pred_
;
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
; }
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
);
48 printError(ErrSysFatal
,"Unable to create tuple iterator");
56 DbRetVal
TableImpl::execute()
58 if (iter
&& !iter
->isIterClosed())
60 //printError(ErrAlready,"Scan already open:Close and re execute");
64 if (!isPlanCreated
) ret
= optimize();
67 printError(ErrSysInternal
,"Unable to create the plan");
68 return ErrSysInternal
;
73 printError(ret
,"Unable to open the iterator");
80 DbRetVal
TableImpl::createPlan()
83 //will do early return here. plan is generated only when setPredicate is called.
84 if (scanType_
== unknownScan
) return ErrSysFatal
; //this should never happen
91 FieldIterator fIter
= fldList_
.getIterator();
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 *));
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_
)
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;
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();
132 while(iter
.hasElement())
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
;
145 scanType_
= treeIndexScan
;
149 else if (pred
->isBetweenInvolved(def
->fldName_
))
151 if (treeIndex
== info
->indType
)
153 scanType_
= treeIndexScan
;
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
;
166 break; //no composite index for tree index
167 } else isAllFldPointLookup
=false;
170 isAllFldPointLookup
= false;
173 }//while iter.hasElement()
174 if( noOfIfld
== 1 && useIndex_
!= -1)return OK
;
175 if (!isAllFldPointLookup
&& useIndex_
!= -1) return OK
;
179 scanType_
= fullTableScan
;
183 void* TableImpl::fetch()
186 if (NULL
== curTuple_
) return curTuple_
;
187 copyValuesToBindBuffer(curTuple_
);
191 void* TableImpl::fetch(DbRetVal
&rv
)
194 if (NULL
== curTuple_
) return curTuple_
;
195 copyValuesToBindBuffer(curTuple_
);
199 void* TableImpl::fetchNoBind()
203 printError(ErrNotOpen
,"Scan not open or Scan is closed\n");
206 void *prevTuple
= curTuple_
;
207 curTuple_
= iter
->next();
208 if (NULL
== curTuple_
)
212 DbRetVal lockRet
= OK
;
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();
225 lockRet
= lMgr_
->isExclusiveLocked( curTuple_
, trans
, status
);
228 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
229 curTuple_
= prevTuple
;
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
);
241 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
242 curTuple_
= prevTuple
;
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
;
259 void* TableImpl::fetchNoBind(DbRetVal
&rv
)
264 printError(ErrNotOpen
,"Scan not open or Scan is closed\n");
268 void *prevTuple
= curTuple_
;
269 curTuple_
= iter
->next();
270 if (NULL
== curTuple_
)
274 DbRetVal lockRet
= OK
;
276 if ((*trans
)->isoLevel_
== READ_REPEATABLE
) {
277 lockRet
= lMgr_
->getSharedLock(curTuple_
, trans
);
280 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
282 curTuple_
= prevTuple
;
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();
298 lockRet
= lMgr_
->isExclusiveLocked( curTuple_
, trans
, status
);
301 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
302 curTuple_
= prevTuple
;
308 if (tries
== 0) break;
309 //os::select(0, 0, 0, 0, &timeout);
313 printError(lockRet
, "Unable to get the lock for the tuple %x", curTuple_
);
314 curTuple_
= prevTuple
;
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
;
329 if (AGG_MIN
== aType
|| AGG_MAX
== aType
) {
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_
;
339 TreeNode
*start
= (TreeNode
*)*((char**)((char*)fstNode
+ sizeof(TreeNode
)));
340 iter
= new TreeIter(start
,(TreeNode
*)iptr
->hashNodeChunk_
,sysDB_
->procSlot
);
342 iter
= new TreeIter(NULL
,(TreeNode
*)iptr
->hashNodeChunk_
,sysDB_
->procSlot
);
344 char *tuple
= (char*) iter
->getFirstElement();
346 AllDataType::copyVal(buf
,(void*)(tuple
+info
->offset
),
347 info
->type
, info
->length
);
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_
;
359 TreeNode
*start
= (TreeNode
*)*((char**)((char*)fstNode
+ sizeof(TreeNode
)));
360 iter
= new TreeIter(start
,(TreeNode
*)iptr
->hashNodeChunk_
,sysDB_
->procSlot
);
362 iter
= new TreeIter(NULL
,(TreeNode
*)iptr
->hashNodeChunk_
,sysDB_
->procSlot
);
364 char *tuple
= (char*) iter
->getLastElement();
366 AllDataType::copyVal(buf
,(void*)(tuple
+info
->offset
),
367 info
->type
, info
->length
);
368 delete iter
; iter
= NULL
;
371 delete iter
; iter
=NULL
;
374 }else if (AGG_COUNT
== aType
) {
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
) {
387 int nullOffset
= length_
-4;
388 if (aType
== AGG_COUNT
) {
389 length
= sizeof(int);
392 if (NULL
== pred_
&& typeInt
== type
&& aType
!= AGG_AVG
)
394 ChunkIterator cIter
= ((Chunk
*)chunkPtr_
)->getIterator();
395 char *tuple
=(char*)cIter
.nextElement();
403 if (isIntUsedForNULL
) {
404 if (BITSET(*(int*)(tuple
+nullOffset
), colPos
-1)) count
=0;
408 if(isFldNull(colPos
)) count
=0;
411 if (aType
!= AGG_COUNT
)
412 AllDataType::copyVal(buf
, (void*) (tuple
+offset
), type
, length
);
415 cIter
.pageSize
= PAGE_SIZE
;
418 tuple
= (char*)cIter
.nextElementInt();
419 if (NULL
== tuple
) break;
421 if (isIntUsedForNULL
) {
422 if (BITSET(*(int*)(tuple
+nullOffset
), colPos
-1)) continue;
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
));
448 else if (aType
== AGG_COUNT
)
454 if( AGG_AVG
== aType
) AllDataType::divVal(buf
, &count
, type
);
455 else if (AGG_COUNT
== aType
) (*(int*)buf
) = count
;
460 char *tuple
= (char*) fetchNoBind(rv
);
461 if ( NULL
== tuple
) { noRec
= true; return OK
; }
464 while(isFldNull(colPos
)) {
465 tuple
= (char*) fetchNoBind(rv
);
466 if (aType
== AGG_COUNT
) count
++;
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
);
477 tuple
= (char*) fetchNoBind(rv
);
478 if (NULL
== tuple
) break;
480 if (isIntUsedForNULL
) {
481 if (BITSET(*(int*)(tuple
+nullOffset
), colPos
-1)) continue;
485 if(isFldNull(colPos
)) continue;
491 res
= AllDataType::compareVal(buf
, (void*) (tuple
+offset
),
494 if (res
) AllDataType::copyVal(buf
, (void*) (tuple
+offset
),
500 res
= AllDataType::compareVal(buf
, (void*) (tuple
+offset
),
503 if (res
) AllDataType::copyVal(buf
, (void*) (tuple
+offset
),
509 AllDataType::addVal(buf
, (void*) (tuple
+offset
),
516 AllDataType::convertToDouble(&tmpBuf
, (void*) (tuple
+offset
), type
);
517 AllDataType::addVal(buf
, &tmpBuf
, typeDouble
);
531 AllDataType::divVal((double *)buf
, count
, type
);
536 (*(int*)buf
) = count
;
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
559 bool TableImpl::pushPredicate(Predicate
*pred
)
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
)))
574 //printf("PRABA::pushed predicate in tablehdl %s\n", getName());