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 ***************************************************************************/
19 #include<JoinTableImpl.h>
20 #include<PredicateImpl.h>
22 JoinTableImpl::JoinTableImpl()
29 isLeftRecOver
= false;
34 //isOuterJoin = false;
39 rightExhausted
= false;
41 JoinTableImpl::~JoinTableImpl() {}
43 DbRetVal
JoinTableImpl::bindFld(const char *fldname
, void *val
, bool dummy
)
45 FieldInfo
*info
= new FieldInfo();
46 char tableName
[IDENTIFIER_LENGTH
];
47 char fieldName
[IDENTIFIER_LENGTH
];
48 getTableNameAlone((char*)fldname
, tableName
);
49 getFieldNameAlone((char*)fldname
, fieldName
);
50 ListIterator iter
= projList
.getIterator();
51 JoinProjFieldInfo
*elem
;
52 while (iter
.hasElement())
54 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
55 if (strcmp(elem
->fieldName
, fieldName
)==0 &&
56 strcmp(elem
->tableName
, tableName
) ==0)
58 printError(ErrBadCall
, "Field already binded %s\n", fldname
);
62 if (strcmp(elem
->fieldName
, fieldName
)==0 &&
63 strcmp(elem
->tableName
, "") ==0)
65 printError(ErrBadCall
, "Field already binded %s\n", fldname
);
70 JoinProjFieldInfo
*def
= new JoinProjFieldInfo();
71 strcpy(def
->tableName
, tableName
);
72 strcpy(def
->fieldName
, fieldName
);
73 strcpy(def
->tabFieldName
, fldname
);
74 if (strcmp (tableName
, "") == 0)
75 getQualifiedName(fldname
, def
->tabFieldName
);
77 DbRetVal rv
= getFieldInfo(fldname
, info
);
79 printError(ErrBadCall
, "Field not found or unqualified field name %s", fldname
);
82 return ErrSyntaxError
;
84 def
->bindBuf
= AllDataType::alloc(info
->type
, info
->length
);
86 leftTableHdl
->bindFld(fldname
, def
->bindBuf
);
88 rightTableHdl
->bindFld(fldname
, def
->bindBuf
);
89 def
->type
= info
->type
;
90 def
->length
= info
->length
;
96 DbRetVal
JoinTableImpl::optimize()
98 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
99 if (NULL
!= predImpl
&& !predImpl
->isNotOrInvolved())
101 //printf("not or or not involved\n");
102 PredicateImpl
*tblPred
= NULL
;
103 bool isPushed
= false;
106 tblPred
= predImpl
->getTablePredicate();
107 if (NULL
== tblPred
) break;
111 isPushed
= pushPredicate(tblPred
);
114 //printf("optimizer could not push table predicate\n");
118 isPushed
= pushPredicate(tblPred
);
121 //printf("optimizer could not push table predicate\n");
126 tblPred
= predImpl
->getJoinPredicate();
131 if (NULL
== tblPred
) break;
132 isPushed
= pushPredicate(tblPred
);
135 //printf("optimizer could not push join predicate\n");
141 //push predicates leave the predicate nodes empty
142 //here we remove all the unnecessary nodes
143 predImpl
= (PredicateImpl
*) pred
;
144 predImpl
->removeIfNotNecessary();
145 PredicateImpl
*p
= predImpl
->getIfOneSidedPredicate();
148 //TODO::fix this leak below..it dumps core if uncommented
153 if (predImpl
->isDummyPredicate())
155 //TODO::fix this leak below..it dumps core if uncommented
160 DbRetVal rv
= leftTableHdl
->optimize();
162 printError(ErrUnknown
, "Left handle optimize failed");
165 rv
= rightTableHdl
->optimize();
167 printError(ErrUnknown
, "Left handle optimize failed");
173 void JoinTableImpl::optimizeRestrict()
175 ScanType lType
= leftTableHdl
->getScanType();
176 ScanType rType
= rightTableHdl
->getScanType();
177 bool interChange
= false;
178 if (lType
== fullTableScan
&& rType
!= fullTableScan
) interChange
= true;
179 else if (lType
!= hashIndexScan
&& rType
== treeIndexScan
) interChange
=true;
182 Table *tmp = leftTableHdl;
183 leftTableHdl=rightTableHdl;
187 //get the predicate with right table handle name
188 //rightTableHdl->getIndexType();
191 ScanType
JoinTableImpl::getScanType()
193 ScanType lType
= leftTableHdl
->getScanType();
194 ScanType rType
= rightTableHdl
->getScanType();
195 if (lType
== hashIndexScan
|| rType
== hashIndexScan
) return hashIndexScan
;
196 if (lType
== treeIndexScan
|| rType
== treeIndexScan
) return treeIndexScan
;
197 return fullTableScan
;
200 void JoinTableImpl::printPlan(int space
)
202 char spaceBuf
[IDENTIFIER_LENGTH
];
203 memset(spaceBuf
, 32, IDENTIFIER_LENGTH
);
204 spaceBuf
[space
] = '\0';
205 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
206 printf("%s <JOIN-NODE>\n", spaceBuf
);
207 if (jType
== INNER_JOIN
)
208 printf("%s <TYPE> INNER_JOIN </TYPE>\n", spaceBuf
);
209 else if (jType
== LEFT_JOIN
)
210 printf("%s <TYPE> LEFT_JOIN </TYPE>\n", spaceBuf
);
211 else if (jType
== RIGHT_JOIN
)
212 printf("%s <TYPE> RIGHT_JOIN </TYPE>\n", spaceBuf
);
213 else if (jType
== FULL_JOIN
)
214 printf("%s <TYPE> FULL_JOIN </TYPE>\n", spaceBuf
);
216 if (predImpl
) predImpl
->print(space
);
217 printf("%s <LEFT>\n", spaceBuf
);
218 leftTableHdl
->printPlan(space
+2);
219 printf("%s </LEFT>\n", spaceBuf
);
220 printf("%s <RIGHT>\n", spaceBuf
);
221 rightTableHdl
->printPlan(space
+2);
222 printf("%s </RIGHT>\n", spaceBuf
);
223 printf("%s </JOIN-NODE>\n", spaceBuf
);
226 DbRetVal
JoinTableImpl::execute()
228 //if (!leftTableHdl->getName()) printf("execute called with isFirstCall %d\n", isFirstCall);
229 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
233 predImpl
->setProjectionList(&projList
);
234 predImpl
->solveForProjList(this);
236 //push the table scan predicates
238 //if( jType != LEFT_JOIN) optimize();
239 if (leftTableHdl
->getName()) {
240 //printf("left execute call %s", leftTableHdl->getName());
241 if (!isOptimized
) { optimize(); isOptimized
= true; }
242 leftTableHdl
->execute();
243 leftTableHdl
->fetch();
244 }else if (isFirstCall
) {
245 //printf("First call");
246 if (!isOptimized
) { optimize(); isOptimized
= true; }
247 leftTableHdl
->execute();
248 void *rec
= leftTableHdl
->fetch();
249 //printf("rec value is %x\n", rec);
252 rightTableHdl
->execute();
253 TableImpl
*tImpl
= (TableImpl
*) rightTableHdl
;
259 void* JoinTableImpl::fetch()
261 //if (!leftTableHdl->getName()) printf("fetch called\n");
262 if (isLeftRecOver
) return NULL
;
263 void * rec
= fetchInt();
264 //if (!leftTableHdl->getName()) printf("rec got %x\n", rec);
266 if (rec
== NULL
&& jType
== LEFT_JOIN
&& isFirstFetch
)
270 copyValuesToBindBuffer(NULL
);
271 //if (!leftTableHdl->getName()) printf("rec value is 0x1\n");
274 isReturnNull
= false;
275 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
279 void* JoinTableImpl::fetchInt()
281 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
285 void *rec
= rightTableHdl
->fetch();
288 return fetchRightFail();
291 if (jType
== LEFT_JOIN
&& leftSideFail
292 && !leftTableHdl
->getName()
293 && !isFirstFetch
) return fetchRightFail();
297 if (pred
) rv
= predImpl
->evaluate(result
);
298 if ( rv
!=OK
&& rv
!=ErrNullValues
) return NULL
;
300 rec
= rightTableHdl
->fetch();
302 if (jType
== LEFT_JOIN
&& isFirstFetch
) return NULL
;
306 copyValuesToBindBuffer(NULL
);
307 isFirstFetch
= false;
314 void* JoinTableImpl::fetchRightFail()
316 if (jType
== LEFT_JOIN
&& isFirstFetch
) { return NULL
;}
317 //if (!leftTableHdl->getName()) printf("fetch right fail called\n");
318 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
320 rightTableHdl
->closeScan();
321 void *rec
= leftTableHdl
->fetch();
322 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
324 if (rec
== NULL
) {isLeftRecOver
= true; return NULL
;}
325 else if (rec
== (char*)0x1) { leftSideFail
= true;}
326 rightTableHdl
->execute();
328 rec
= rightTableHdl
->fetch();
329 if (rec
== NULL
|| leftSideFail
) {
330 //if(!leftTableHdl->getName()) printf("RIGHT FETCH returns NULL\n");
331 //if join condition(pred) is set and if it is pushed to tablehdl
332 //when there is index, it returns no record
333 if (jType
== LEFT_JOIN
&& pred
) return NULL
;
334 return fetchRightFail();
337 isReturnNull
= false;
339 if (pred
) rv
= predImpl
->evaluate(result
);
340 if ( OK
!= rv
) return NULL
;
341 if (result
) { break; }
342 rec
= rightTableHdl
->fetch();
344 if (jType
== LEFT_JOIN
) {
345 //return from here so that null values for rhs table will be set
351 isFirstFetch
= false;
352 copyValuesToBindBuffer(NULL
);
356 void* JoinTableImpl::fetch(DbRetVal
&rv
)
362 void* JoinTableImpl::fetchNoBind()
364 printError(ErrBadCall
, "fetchNoBind not implemented for JoinTableImpl");
368 void* JoinTableImpl::fetchNoBind(DbRetVal
&rv
)
371 return fetchNoBind();
374 DbRetVal
JoinTableImpl::copyValuesToBindBuffer(void *elem
)
376 //Iterate through the bind list and copy the value here
377 ListIterator fIter
= projList
.getIterator();
378 JoinProjFieldInfo
*def
;
379 while (fIter
.hasElement())
381 def
= (JoinProjFieldInfo
*) fIter
.nextElement();
382 if (NULL
!= def
->appBuf
) {
383 AllDataType::copyVal(def
->appBuf
, def
->bindBuf
, def
->type
, def
->length
);
388 DbRetVal
JoinTableImpl::getQualifiedName(const char *fldname
, char *qualName
)
390 if (leftTableHdl
!= NULL
)
391 leftTableHdl
->getQualifiedName(fldname
, qualName
);
392 if (rightTableHdl
!= NULL
)
393 rightTableHdl
->getQualifiedName(fldname
, qualName
);
397 DbRetVal
JoinTableImpl::getFieldInfo(const char* fldname
, FieldInfo
*&info
)
399 DbRetVal retCode
= OK
, retCode1
=OK
;
400 availableLeft
= false;
401 retCode
= leftTableHdl
->getFieldInfo(fldname
, info
);
407 retCode1
= rightTableHdl
->getFieldInfo(fldname
, info
);
410 if (availableLeft
) return ErrSyntaxError
;
416 long JoinTableImpl::numTuples()
421 DbRetVal
JoinTableImpl::closeScan()
423 //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan();
424 if (leftTableHdl
) leftTableHdl
->closeScan();
425 if (rightTableHdl
) rightTableHdl
->closeScan();
426 isLeftRecOver
= false;
432 DbRetVal
JoinTableImpl::close()
435 if (leftTableHdl
) { leftTableHdl
->close(); leftTableHdl
= NULL
; }
436 if (rightTableHdl
) { rightTableHdl
->close(); rightTableHdl
= NULL
; }
437 ListIterator iter
= projList
.getIterator();
438 JoinProjFieldInfo
*elem
;
439 while (iter
.hasElement())
441 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
447 ListIterator pIter
= predList
.getIterator();
448 while(pIter
.hasElement())
450 PredicateImpl
*pImpl
= (PredicateImpl
*) pIter
.nextElement();
458 void* JoinTableImpl::getBindFldAddr(const char *name
)
460 void* bindAddr
= leftTableHdl
->getBindFldAddr(name
);
461 if (bindAddr
) return bindAddr
;
462 return rightTableHdl
->getBindFldAddr(name
);
465 List
JoinTableImpl::getFieldNameList()
469 List leftList
= leftTableHdl
->getFieldNameList();
470 ListIterator lIter
= leftList
.getIterator();
471 while (lIter
.hasElement())
473 Identifier
*elem
= (Identifier
*) lIter
.nextElement();
474 fldNameList
.append(elem
);
477 List rightList
= rightTableHdl
->getFieldNameList();
478 ListIterator rIter
= rightList
.getIterator();
479 while (rIter
.hasElement())
481 Identifier
*elem
= (Identifier
*) rIter
.nextElement();
482 fldNameList
.append(elem
);
489 bool JoinTableImpl::isTableInvolved(char *tableName
)
491 //printf("isTableInvolved called in join for %s\n", tableName);
492 bool isInvolved
= leftTableHdl
->isTableInvolved(tableName
);
493 if (isInvolved
) return true;
494 isInvolved
= rightTableHdl
->isTableInvolved(tableName
);
498 void* JoinTableImpl::getBindedBuf(char* tName
, char* fName
)
500 ListIterator iter
= projList
.getIterator();
501 JoinProjFieldInfo
*elem
;
502 while (iter
.hasElement())
504 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
505 if (strcmp(elem
->fieldName
, fName
)==0 &&
506 strcmp(elem
->tableName
, tName
) ==0)
508 return elem
->bindBuf
;
514 bool JoinTableImpl::pushPredicate(Predicate
*pr
)
516 //printf("PRABA::pushPredicate called\n");
517 PredicateImpl
*pImpl
= (PredicateImpl
*) pr
;
518 bool pushed
= leftTableHdl
->pushPredicate(pr
);
521 pushed
= rightTableHdl
->pushPredicate(pr
);
525 //printf("PRABA::unable to push the predicate\n");
526 //TODO::check if needs to be placed here
527 char *lTbl
= leftTableHdl
->getName();
528 char *rTbl
= rightTableHdl
->getName();
529 char *lAliasTbl
= leftTableHdl
->getAliasName();
530 char *rAliasTbl
= rightTableHdl
->getAliasName();
531 bool isAliasSet
= lAliasTbl
&& rAliasTbl
&& (!(strcmp(lAliasTbl
,"") == 0 && strcmp(rAliasTbl
,"") == 0 ));
532 char fullName
[IDENTIFIER_LENGTH
];
533 char lTabName
[IDENTIFIER_LENGTH
];
534 char rTabName
[IDENTIFIER_LENGTH
];
535 char lFldName
[IDENTIFIER_LENGTH
];
536 char rFldName
[IDENTIFIER_LENGTH
];
537 strcpy(fullName
, pImpl
->getFldName1());
538 Table::getTableNameAlone(fullName
, lTabName
);
539 Table::getFieldNameAlone(fullName
, lFldName
);
540 strcpy(fullName
, pImpl
->getFldName2());
541 Table::getTableNameAlone(fullName
, rTabName
);
542 Table::getFieldNameAlone(fullName
, rFldName
);
544 if (NULL
!= lTbl
&& NULL
!= rTbl
)
546 //both size TableImpl handles are there
547 if (0 == strcmp(lTbl
, lTabName
) || 0 == strcmp(lTbl
, rTabName
) || ( isAliasSet
&& (0 == strcmp(lAliasTbl
, lTabName
) ||0 == strcmp(lAliasTbl
,rTabName
))) )
549 if (0 == strcmp(rTbl
, lTabName
) || 0 == strcmp(rTbl
, rTabName
)|| (isAliasSet
&& (0 == strcmp(rAliasTbl
, lTabName
) ||0 == strcmp(rAliasTbl
,rTabName
))))
551 //printf("PRABA::pushed join predicate here1\n");
553 ComparisionOp op
= pImpl
->getCompOp();
554 if (0 == strcmp(rTbl
, rTabName
) ||(isAliasSet
&& 0 == strcmp(rAliasTbl
, rTabName
)))
556 //bool ind = rightTableHdl->hasIndex(rFldName);
558 void *buf
= getBindedBuf(lTabName
, lFldName
);
559 rightTableHdl
->addPredicate(rFldName
, op
, buf
);
560 pImpl
->setDontEvaluate();
562 }else if (0==strcmp(rTbl
, lTabName
) || (isAliasSet
&& 0== strcmp(rAliasTbl
, lTabName
)))
564 //bool ind = rightTableHdl->hasIndex(lFldName);
566 void *buf
= getBindedBuf(rTabName
, rFldName
);
567 rightTableHdl
->addPredicate(lFldName
, op
, buf
);
568 pImpl
->setDontEvaluate();
577 if(isTableInvolved(lTabName
) && isTableInvolved(rTabName
))
579 //printf("PRABA::pushed join predicate here2\n");
581 ComparisionOp op
= pImpl
->getCompOp();
582 if (strcmp(rTbl
, rTabName
) ==0)
584 //bool ind = rightTableHdl->hasIndex(rFldName);
586 void *buf
= getBindedBuf(lTabName
, lFldName
);
587 rightTableHdl
->addPredicate(rFldName
, op
, buf
);
588 pImpl
->setDontEvaluate();
590 }else if (strcmp(rTbl
, lTabName
) ==0)
592 //bool ind = rightTableHdl->hasIndex(lFldName);
594 void *buf
= getBindedBuf(rTabName
, rFldName
);
595 rightTableHdl
->addPredicate(lFldName
, op
, buf
);
596 pImpl
->setDontEvaluate();
608 void JoinTableImpl::setPredicate(Predicate
*pr
)
610 if (NULL
== pred
) { pred
= pr
; return; }
611 Predicate
*curPred
= pred
;
612 PredicateImpl
*newPred
= new PredicateImpl();
613 newPred
->setTerm(curPred
, OpAnd
, pr
);
614 newPred
->setProjectionList(&projList
);
615 predList
.append(newPred
);
620 bool JoinTableImpl::isFldNull(const char *name
)
623 if(NULL
==leftTableHdl
->getName())
625 ret
= leftTableHdl
->isFldNull(name
);
626 if(ret
==true) return true;
630 char tableName
[IDENTIFIER_LENGTH
];
631 Table::getTableNameAlone((char*)name
, tableName
);
632 if(0 == strcmp(tableName
,leftTableHdl
->getName()))
634 return leftTableHdl
->isFldNull(name
);
637 if(NULL
==rightTableHdl
->getName())
639 if (isReturnNull
) return true;
640 ret
= rightTableHdl
->isFldNull(name
);
641 if(ret
==true) return true;
644 char tableName
[IDENTIFIER_LENGTH
];
645 Table::getTableNameAlone((char*)name
, tableName
);
646 if(0==strcmp(tableName
,rightTableHdl
->getName()))
648 if (isReturnNull
) return true;
649 return rightTableHdl
->isFldNull(name
);
655 //same as above expect it does not check for isRecordFound flag
656 //as it is set only after predicate evaluate
657 bool JoinTableImpl::isFldNullInt(const char *name
)
660 if(NULL
==leftTableHdl
->getName())
662 ret
= leftTableHdl
->isFldNull(name
);
663 if(ret
==true) return true;
667 char tableName
[IDENTIFIER_LENGTH
];
668 Table::getTableNameAlone((char*)name
, tableName
);
669 if(0 == strcmp(tableName
,leftTableHdl
->getName()))
671 return leftTableHdl
->isFldNull(name
);
674 if(NULL
==rightTableHdl
->getName())
676 ret
= rightTableHdl
->isFldNull(name
);
677 if(ret
==true) return true;
680 char tableName
[IDENTIFIER_LENGTH
];
681 Table::getTableNameAlone((char*)name
, tableName
);
682 if(0==strcmp(tableName
,rightTableHdl
->getName()))
684 return rightTableHdl
->isFldNull(name
);