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
);
63 JoinProjFieldInfo
*def
= new JoinProjFieldInfo();
64 strcpy(def
->tableName
, tableName
);
65 strcpy(def
->fieldName
, fieldName
);
66 strcpy(def
->tabFieldName
, fldname
);
68 DbRetVal rv
= getFieldInfo(fldname
, info
);
70 printError(ErrBadCall
, "Field not found or unqualified field name %s", fldname
);
73 return ErrSyntaxError
;
75 def
->bindBuf
= AllDataType::alloc(info
->type
, info
->length
);
77 leftTableHdl
->bindFld(fldname
, def
->bindBuf
);
79 rightTableHdl
->bindFld(fldname
, def
->bindBuf
);
80 def
->type
= info
->type
;
81 def
->length
= info
->length
;
87 DbRetVal
JoinTableImpl::optimize()
89 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
90 if (NULL
!= predImpl
&& !predImpl
->isNotOrInvolved())
92 //printf("not or or not involved\n");
93 PredicateImpl
*tblPred
= NULL
;
94 bool isPushed
= false;
97 tblPred
= predImpl
->getTablePredicate();
98 if (NULL
== tblPred
) break;
102 isPushed
= pushPredicate(tblPred
);
105 //printf("optimizer could not push table predicate\n");
109 isPushed
= pushPredicate(tblPred
);
112 //printf("optimizer could not push table predicate\n");
117 tblPred
= predImpl
->getJoinPredicate();
122 if (NULL
== tblPred
) break;
123 isPushed
= pushPredicate(tblPred
);
126 //printf("optimizer could not push join predicate\n");
132 //push predicates leave the predicate nodes empty
133 //here we remove all the unnecessary nodes
134 predImpl
= (PredicateImpl
*) pred
;
135 predImpl
->removeIfNotNecessary();
136 PredicateImpl
*p
= predImpl
->getIfOneSidedPredicate();
139 //TODO::fix this leak below..it dumps core if uncommented
144 if (predImpl
->isDummyPredicate())
146 //TODO::fix this leak below..it dumps core if uncommented
151 DbRetVal rv
= leftTableHdl
->optimize();
153 printError(ErrUnknown
, "Left handle optimize failed");
156 rv
= rightTableHdl
->optimize();
158 printError(ErrUnknown
, "Left handle optimize failed");
164 void JoinTableImpl::optimizeRestrict()
166 ScanType lType
= leftTableHdl
->getScanType();
167 ScanType rType
= rightTableHdl
->getScanType();
168 bool interChange
= false;
169 if (lType
== fullTableScan
&& rType
!= fullTableScan
) interChange
= true;
170 else if (lType
!= hashIndexScan
&& rType
== treeIndexScan
) interChange
=true;
173 Table *tmp = leftTableHdl;
174 leftTableHdl=rightTableHdl;
178 //get the predicate with right table handle name
179 //rightTableHdl->getIndexType();
182 ScanType
JoinTableImpl::getScanType()
184 ScanType lType
= leftTableHdl
->getScanType();
185 ScanType rType
= rightTableHdl
->getScanType();
186 if (lType
== hashIndexScan
|| rType
== hashIndexScan
) return hashIndexScan
;
187 if (lType
== treeIndexScan
|| rType
== treeIndexScan
) return treeIndexScan
;
188 return fullTableScan
;
191 void JoinTableImpl::printPlan(int space
)
193 char spaceBuf
[IDENTIFIER_LENGTH
];
194 memset(spaceBuf
, 32, IDENTIFIER_LENGTH
);
195 spaceBuf
[space
] = '\0';
196 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
197 printf("%s <JOIN-NODE>\n", spaceBuf
);
198 if (jType
== INNER_JOIN
)
199 printf("%s <TYPE> INNER_JOIN </TYPE>\n", spaceBuf
);
200 else if (jType
== LEFT_JOIN
)
201 printf("%s <TYPE> LEFT_JOIN </TYPE>\n", spaceBuf
);
202 else if (jType
== RIGHT_JOIN
)
203 printf("%s <TYPE> RIGHT_JOIN </TYPE>\n", spaceBuf
);
204 else if (jType
== FULL_JOIN
)
205 printf("%s <TYPE> FULL_JOIN </TYPE>\n", spaceBuf
);
207 if (predImpl
) predImpl
->print(space
);
208 printf("%s <LEFT>\n", spaceBuf
);
209 leftTableHdl
->printPlan(space
+2);
210 printf("%s </LEFT>\n", spaceBuf
);
211 printf("%s <RIGHT>\n", spaceBuf
);
212 rightTableHdl
->printPlan(space
+2);
213 printf("%s </RIGHT>\n", spaceBuf
);
214 printf("%s </JOIN-NODE>\n", spaceBuf
);
216 DbRetVal
JoinTableImpl::execute()
218 //if (!leftTableHdl->getName()) printf("execute called with isFirstCall %d\n", isFirstCall);
219 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
223 predImpl
->setProjectionList(&projList
);
224 predImpl
->solveForProjList(this);
226 //push the table scan predicates
228 //if( jType != LEFT_JOIN) optimize();
229 if (leftTableHdl
->getName()) {
230 //printf("left execute call %s", leftTableHdl->getName());
231 if (!isOptimized
) { optimize(); isOptimized
= true; }
232 leftTableHdl
->execute();
233 leftTableHdl
->fetch();
234 }else if (isFirstCall
) {
235 //printf("First call");
236 if (!isOptimized
) { optimize(); isOptimized
= true; }
237 leftTableHdl
->execute();
238 void *rec
= leftTableHdl
->fetch();
239 //printf("rec value is %x\n", rec);
242 rightTableHdl
->execute();
243 TableImpl
*tImpl
= (TableImpl
*) rightTableHdl
;
248 void* JoinTableImpl::fetch()
250 //if (!leftTableHdl->getName()) printf("fetch called\n");
251 if (isLeftRecOver
) return NULL
;
252 void * rec
= fetchInt();
253 //if (!leftTableHdl->getName()) printf("rec got %x\n", rec);
255 if (rec
== NULL
&& jType
== LEFT_JOIN
&& isFirstFetch
)
259 copyValuesToBindBuffer(NULL
);
260 //if (!leftTableHdl->getName()) printf("rec value is 0x1\n");
263 isReturnNull
= false;
264 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
267 void* JoinTableImpl::fetchInt()
269 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
273 void *rec
= rightTableHdl
->fetch();
276 return fetchRightFail();
279 if (jType
== LEFT_JOIN
&& leftSideFail
280 && !leftTableHdl
->getName()
281 && !isFirstFetch
) return fetchRightFail();
285 if (pred
) rv
= predImpl
->evaluate(result
);
286 if ( rv
!=OK
&& rv
!=ErrNullValues
) return NULL
;
288 rec
= rightTableHdl
->fetch();
290 if (jType
== LEFT_JOIN
&& isFirstFetch
) return NULL
;
294 copyValuesToBindBuffer(NULL
);
295 isFirstFetch
= false;
302 void* JoinTableImpl::fetchRightFail()
304 if (jType
== LEFT_JOIN
&& isFirstFetch
) { return NULL
;}
305 //if (!leftTableHdl->getName()) printf("fetch right fail called\n");
306 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
308 rightTableHdl
->closeScan();
309 void *rec
= leftTableHdl
->fetch();
310 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
312 if (rec
== NULL
) {isLeftRecOver
= true; return NULL
;}
313 else if (rec
== (char*)0x1) { leftSideFail
= true;}
314 rightTableHdl
->execute();
316 rec
= rightTableHdl
->fetch();
317 if (rec
== NULL
|| leftSideFail
) {
318 //if(!leftTableHdl->getName()) printf("RIGHT FETCH returns NULL\n");
319 //if join condition(pred) is set and if it is pushed to tablehdl
320 //when there is index, it returns no record
321 if (jType
== LEFT_JOIN
&& pred
) return NULL
;
322 return fetchRightFail();
325 isReturnNull
= false;
327 if (pred
) rv
= predImpl
->evaluate(result
);
328 if ( OK
!= rv
) return NULL
;
329 if (result
) { break; }
330 rec
= rightTableHdl
->fetch();
332 if (jType
== LEFT_JOIN
) {
333 //return from here so that null values for rhs table will be set
339 isFirstFetch
= false;
340 copyValuesToBindBuffer(NULL
);
343 void* JoinTableImpl::fetch(DbRetVal
&rv
)
349 void* JoinTableImpl::fetchNoBind()
351 printError(ErrBadCall
, "fetchNoBind not implemented for JoinTableImpl");
355 void* JoinTableImpl::fetchNoBind(DbRetVal
&rv
)
358 return fetchNoBind();
361 DbRetVal
JoinTableImpl::copyValuesToBindBuffer(void *elem
)
363 //Iterate through the bind list and copy the value here
364 ListIterator fIter
= projList
.getIterator();
365 JoinProjFieldInfo
*def
;
366 while (fIter
.hasElement())
368 def
= (JoinProjFieldInfo
*) fIter
.nextElement();
369 if (NULL
!= def
->appBuf
) {
370 AllDataType::copyVal(def
->appBuf
, def
->bindBuf
, def
->type
, def
->length
);
375 DbRetVal
JoinTableImpl::getFieldInfo(const char* fldname
, FieldInfo
*&info
)
377 DbRetVal retCode
= OK
, retCode1
=OK
;
378 availableLeft
= false;
379 retCode
= leftTableHdl
->getFieldInfo(fldname
, info
);
385 retCode1
= rightTableHdl
->getFieldInfo(fldname
, info
);
388 if (availableLeft
) return ErrSyntaxError
;
394 long JoinTableImpl::numTuples()
398 DbRetVal
JoinTableImpl::closeScan()
400 //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan();
401 if (leftTableHdl
) leftTableHdl
->closeScan();
402 if (rightTableHdl
) rightTableHdl
->closeScan();
403 isLeftRecOver
= false;
409 DbRetVal
JoinTableImpl::close()
412 if (leftTableHdl
) { leftTableHdl
->close(); leftTableHdl
= NULL
; }
413 if (rightTableHdl
) { rightTableHdl
->close(); rightTableHdl
= NULL
; }
414 ListIterator iter
= projList
.getIterator();
415 JoinProjFieldInfo
*elem
;
416 while (iter
.hasElement())
418 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
424 ListIterator pIter
= predList
.getIterator();
425 while(pIter
.hasElement())
427 PredicateImpl
*pImpl
= (PredicateImpl
*) pIter
.nextElement();
434 void* JoinTableImpl::getBindFldAddr(const char *name
)
436 void* bindAddr
= leftTableHdl
->getBindFldAddr(name
);
437 if (bindAddr
) return bindAddr
;
438 return rightTableHdl
->getBindFldAddr(name
);
440 List
JoinTableImpl::getFieldNameList()
444 List leftList
= leftTableHdl
->getFieldNameList();
445 ListIterator lIter
= leftList
.getIterator();
446 while (lIter
.hasElement())
448 Identifier
*elem
= (Identifier
*) lIter
.nextElement();
449 fldNameList
.append(elem
);
452 List rightList
= rightTableHdl
->getFieldNameList();
453 ListIterator rIter
= rightList
.getIterator();
454 while (rIter
.hasElement())
456 Identifier
*elem
= (Identifier
*) rIter
.nextElement();
457 fldNameList
.append(elem
);
463 bool JoinTableImpl::isTableInvolved(char *tableName
)
465 //printf("isTableInvolved called in join for %s\n", tableName);
466 bool isInvolved
= leftTableHdl
->isTableInvolved(tableName
);
467 if (isInvolved
) return true;
468 isInvolved
= rightTableHdl
->isTableInvolved(tableName
);
471 void* JoinTableImpl::getBindedBuf(char* tName
, char* fName
)
473 ListIterator iter
= projList
.getIterator();
474 JoinProjFieldInfo
*elem
;
475 while (iter
.hasElement())
477 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
478 if (strcmp(elem
->fieldName
, fName
)==0 &&
479 strcmp(elem
->tableName
, tName
) ==0)
481 return elem
->bindBuf
;
486 bool JoinTableImpl::pushPredicate(Predicate
*pr
)
488 //printf("PRABA::pushPredicate called\n");
489 PredicateImpl
*pImpl
= (PredicateImpl
*) pr
;
490 bool pushed
= leftTableHdl
->pushPredicate(pr
);
493 pushed
= rightTableHdl
->pushPredicate(pr
);
497 //printf("PRABA::unable to push the predicate\n");
498 //TODO::check if needs to be placed here
499 char *lTbl
= leftTableHdl
->getName();
500 char *rTbl
= rightTableHdl
->getName();
501 char *lAliasTbl
= leftTableHdl
->getAliasName();
502 char *rAliasTbl
= rightTableHdl
->getAliasName();
503 bool isAliasSet
= lAliasTbl
&& rAliasTbl
&& (!(strcmp(lAliasTbl
,"") == 0 && strcmp(rAliasTbl
,"") == 0 ));
504 char fullName
[IDENTIFIER_LENGTH
];
505 char lTabName
[IDENTIFIER_LENGTH
];
506 char rTabName
[IDENTIFIER_LENGTH
];
507 char lFldName
[IDENTIFIER_LENGTH
];
508 char rFldName
[IDENTIFIER_LENGTH
];
509 strcpy(fullName
, pImpl
->getFldName1());
510 Table::getTableNameAlone(fullName
, lTabName
);
511 Table::getFieldNameAlone(fullName
, lFldName
);
512 strcpy(fullName
, pImpl
->getFldName2());
513 Table::getTableNameAlone(fullName
, rTabName
);
514 Table::getFieldNameAlone(fullName
, rFldName
);
516 if (NULL
!= lTbl
&& NULL
!= rTbl
)
518 //both size TableImpl handles are there
519 if (0 == strcmp(lTbl
, lTabName
) || 0 == strcmp(lTbl
, rTabName
) || ( isAliasSet
&& (0 == strcmp(lAliasTbl
, lTabName
) ||0 == strcmp(lAliasTbl
,rTabName
))) )
521 if (0 == strcmp(rTbl
, lTabName
) || 0 == strcmp(rTbl
, rTabName
)|| (isAliasSet
&& (0 == strcmp(rAliasTbl
, lTabName
) ||0 == strcmp(rAliasTbl
,rTabName
))))
523 //printf("PRABA::pushed join predicate here1\n");
525 ComparisionOp op
= pImpl
->getCompOp();
526 if (0 == strcmp(rTbl
, rTabName
) ||(isAliasSet
&& 0 == strcmp(rAliasTbl
, rTabName
)))
528 //bool ind = rightTableHdl->hasIndex(rFldName);
530 void *buf
= getBindedBuf(lTabName
, lFldName
);
531 rightTableHdl
->addPredicate(rFldName
, op
, buf
);
532 pImpl
->setDontEvaluate();
534 }else if (0==strcmp(rTbl
, lTabName
) || (isAliasSet
&& 0== strcmp(rAliasTbl
, lTabName
)))
536 //bool ind = rightTableHdl->hasIndex(lFldName);
538 void *buf
= getBindedBuf(rTabName
, rFldName
);
539 rightTableHdl
->addPredicate(lFldName
, op
, buf
);
540 pImpl
->setDontEvaluate();
549 if(isTableInvolved(lTabName
) && isTableInvolved(rTabName
))
551 //printf("PRABA::pushed join predicate here2\n");
553 ComparisionOp op
= pImpl
->getCompOp();
554 if (strcmp(rTbl
, rTabName
) ==0)
556 //bool ind = rightTableHdl->hasIndex(rFldName);
558 void *buf
= getBindedBuf(lTabName
, lFldName
);
559 rightTableHdl
->addPredicate(rFldName
, op
, buf
);
560 pImpl
->setDontEvaluate();
562 }else if (strcmp(rTbl
, lTabName
) ==0)
564 //bool ind = rightTableHdl->hasIndex(lFldName);
566 void *buf
= getBindedBuf(rTabName
, rFldName
);
567 rightTableHdl
->addPredicate(lFldName
, op
, buf
);
568 pImpl
->setDontEvaluate();
579 void JoinTableImpl::setPredicate(Predicate
*pr
)
581 if (NULL
== pred
) { pred
= pr
; return; }
582 Predicate
*curPred
= pred
;
583 PredicateImpl
*newPred
= new PredicateImpl();
584 newPred
->setTerm(curPred
, OpAnd
, pr
);
585 newPred
->setProjectionList(&projList
);
586 predList
.append(newPred
);
590 bool JoinTableImpl::isFldNull(const char *name
)
593 if(NULL
==leftTableHdl
->getName())
595 ret
= leftTableHdl
->isFldNull(name
);
596 if(ret
==true) return true;
600 char tableName
[IDENTIFIER_LENGTH
];
601 Table::getTableNameAlone((char*)name
, tableName
);
602 if(0 == strcmp(tableName
,leftTableHdl
->getName()))
604 return leftTableHdl
->isFldNull(name
);
607 if(NULL
==rightTableHdl
->getName())
609 if (isReturnNull
) return true;
610 ret
= rightTableHdl
->isFldNull(name
);
611 if(ret
==true) return true;
614 char tableName
[IDENTIFIER_LENGTH
];
615 Table::getTableNameAlone((char*)name
, tableName
);
616 if(0==strcmp(tableName
,rightTableHdl
->getName()))
618 if (isReturnNull
) return true;
619 return rightTableHdl
->isFldNull(name
);
624 //same as above expect it does not check for isRecordFound flag
625 //as it is set only after predicate evaluate
626 bool JoinTableImpl::isFldNullInt(const char *name
)
629 if(NULL
==leftTableHdl
->getName())
631 ret
= leftTableHdl
->isFldNull(name
);
632 if(ret
==true) return true;
636 char tableName
[IDENTIFIER_LENGTH
];
637 Table::getTableNameAlone((char*)name
, tableName
);
638 if(0 == strcmp(tableName
,leftTableHdl
->getName()))
640 return leftTableHdl
->isFldNull(name
);
643 if(NULL
==rightTableHdl
->getName())
645 ret
= rightTableHdl
->isFldNull(name
);
646 if(ret
==true) return true;
649 char tableName
[IDENTIFIER_LENGTH
];
650 Table::getTableNameAlone((char*)name
, tableName
);
651 if(0==strcmp(tableName
,rightTableHdl
->getName()))
653 return rightTableHdl
->isFldNull(name
);