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;
38 rightExhausted
= false;
40 JoinTableImpl::~JoinTableImpl() {}
42 DbRetVal
JoinTableImpl::bindFld(const char *fldname
, void *val
, bool dummy
)
44 FieldInfo
*info
= new FieldInfo();
45 char tableName
[IDENTIFIER_LENGTH
];
46 char fieldName
[IDENTIFIER_LENGTH
];
47 getTableNameAlone((char*)fldname
, tableName
);
48 getFieldNameAlone((char*)fldname
, fieldName
);
49 ListIterator iter
= projList
.getIterator();
50 JoinProjFieldInfo
*elem
;
51 while (iter
.hasElement())
53 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
54 if (strcmp(elem
->fieldName
, fieldName
)==0 &&
55 strcmp(elem
->tableName
, tableName
) ==0)
57 printError(ErrBadCall
, "Field already binded %s\n", fldname
);
62 JoinProjFieldInfo
*def
= new JoinProjFieldInfo();
63 strcpy(def
->tableName
, tableName
);
64 strcpy(def
->fieldName
, fieldName
);
65 strcpy(def
->tabFieldName
, fldname
);
67 DbRetVal rv
= getFieldInfo(fldname
, info
);
69 printError(ErrBadCall
, "Field not found or unqualified field name %s", fldname
);
72 return ErrSyntaxError
;
74 def
->bindBuf
= AllDataType::alloc(info
->type
, info
->length
);
76 leftTableHdl
->bindFld(fldname
, def
->bindBuf
);
78 rightTableHdl
->bindFld(fldname
, def
->bindBuf
);
79 def
->type
= info
->type
;
80 def
->length
= info
->length
;
86 DbRetVal
JoinTableImpl::optimize()
88 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
89 if (NULL
!= predImpl
&& !predImpl
->isNotOrInvolved())
91 //printf("not or or not involved\n");
92 PredicateImpl
*tblPred
= NULL
;
93 bool isPushed
= false;
96 tblPred
= predImpl
->getTablePredicate();
97 if (NULL
== tblPred
) break;
101 isPushed
= pushPredicate(tblPred
);
104 //printf("optimizer could not push table predicate\n");
108 isPushed
= pushPredicate(tblPred
);
111 //printf("optimizer could not push table predicate\n");
116 tblPred
= predImpl
->getJoinPredicate();
121 if (NULL
== tblPred
) break;
122 isPushed
= pushPredicate(tblPred
);
125 //printf("optimizer could not push join predicate\n");
131 //push predicates leave the predicate nodes empty
132 //here we remove all the unnecessary nodes
133 predImpl
= (PredicateImpl
*) pred
;
134 predImpl
->removeIfNotNecessary();
135 PredicateImpl
*p
= predImpl
->getIfOneSidedPredicate();
138 //TODO::fix this leak below..it dumps core if uncommented
143 if (predImpl
->isDummyPredicate())
145 //TODO::fix this leak below..it dumps core if uncommented
150 DbRetVal rv
= leftTableHdl
->optimize();
152 printError(ErrUnknown
, "Left handle optimize failed");
155 rv
= rightTableHdl
->optimize();
157 printError(ErrUnknown
, "Left handle optimize failed");
163 void JoinTableImpl::optimizeRestrict()
165 ScanType lType
= leftTableHdl
->getScanType();
166 ScanType rType
= rightTableHdl
->getScanType();
167 bool interChange
= false;
168 if (lType
== fullTableScan
&& rType
!= fullTableScan
) interChange
= true;
169 else if (lType
!= hashIndexScan
&& rType
== treeIndexScan
) interChange
=true;
172 Table *tmp = leftTableHdl;
173 leftTableHdl=rightTableHdl;
177 //get the predicate with right table handle name
178 //rightTableHdl->getIndexType();
181 ScanType
JoinTableImpl::getScanType()
183 ScanType lType
= leftTableHdl
->getScanType();
184 ScanType rType
= rightTableHdl
->getScanType();
185 if (lType
== hashIndexScan
|| rType
== hashIndexScan
) return hashIndexScan
;
186 if (lType
== treeIndexScan
|| rType
== treeIndexScan
) return treeIndexScan
;
187 return fullTableScan
;
190 void JoinTableImpl::printPlan(int space
)
192 char spaceBuf
[IDENTIFIER_LENGTH
];
193 memset(spaceBuf
, 32, IDENTIFIER_LENGTH
);
194 spaceBuf
[space
] = '\0';
195 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
196 printf("%s <JOIN-NODE>\n", spaceBuf
);
197 if (jType
== INNER_JOIN
)
198 printf("%s <TYPE> INNER_JOIN </TYPE>\n", spaceBuf
);
199 else if (jType
== LEFT_JOIN
)
200 printf("%s <TYPE> LEFT_JOIN </TYPE>\n", spaceBuf
);
201 else if (jType
== RIGHT_JOIN
)
202 printf("%s <TYPE> RIGHT_JOIN </TYPE>\n", spaceBuf
);
203 else if (jType
== FULL_JOIN
)
204 printf("%s <TYPE> FULL_JOIN </TYPE>\n", spaceBuf
);
206 if (predImpl
) predImpl
->print(space
);
207 printf("%s <LEFT>\n", spaceBuf
);
208 leftTableHdl
->printPlan(space
+2);
209 printf("%s </LEFT>\n", spaceBuf
);
210 printf("%s <RIGHT>\n", spaceBuf
);
211 rightTableHdl
->printPlan(space
+2);
212 printf("%s </RIGHT>\n", spaceBuf
);
213 printf("%s </JOIN-NODE>\n", spaceBuf
);
215 DbRetVal
JoinTableImpl::execute()
217 //if (!leftTableHdl->getName()) printf("execute called with isFirstCall %d\n", isFirstCall);
218 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
222 predImpl
->setProjectionList(&projList
);
223 predImpl
->solveForProjList(this);
225 //push the table scan predicates
227 //if( jType != LEFT_JOIN) optimize();
228 if (leftTableHdl
->getName()) {
229 //printf("left execute call %s", leftTableHdl->getName());
231 leftTableHdl
->execute();
232 leftTableHdl
->fetch();
233 }else if (isFirstCall
) {
234 //printf("First call");
236 leftTableHdl
->execute();
237 void *rec
= leftTableHdl
->fetch();
238 //printf("rec value is %x\n", rec);
241 rightTableHdl
->execute();
242 TableImpl
*tImpl
= (TableImpl
*) rightTableHdl
;
247 void* JoinTableImpl::fetch()
249 //if (!leftTableHdl->getName()) printf("fetch called\n");
250 if (isLeftRecOver
) return NULL
;
251 void * rec
= fetchInt();
252 //if (!leftTableHdl->getName()) printf("rec got %x\n", rec);
254 if (rec
== NULL
&& jType
== LEFT_JOIN
&& isFirstFetch
)
258 copyValuesToBindBuffer(NULL
);
259 //if (!leftTableHdl->getName()) printf("rec value is 0x1\n");
262 isReturnNull
= false;
263 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
266 void* JoinTableImpl::fetchInt()
268 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
272 void *rec
= rightTableHdl
->fetch();
275 return fetchRightFail();
278 if (jType
== LEFT_JOIN
&& leftSideFail
279 && !leftTableHdl
->getName()
280 && !isFirstFetch
) return fetchRightFail();
284 if (pred
) rv
= predImpl
->evaluate(result
);
285 if ( rv
!=OK
) return NULL
;
287 rec
= rightTableHdl
->fetch();
289 if (jType
== LEFT_JOIN
&& isFirstFetch
) return NULL
;
293 copyValuesToBindBuffer(NULL
);
294 isFirstFetch
= false;
301 void* JoinTableImpl::fetchRightFail()
303 if (jType
== LEFT_JOIN
&& isFirstFetch
) { return NULL
;}
304 //if (!leftTableHdl->getName()) printf("fetch right fail called\n");
305 PredicateImpl
* predImpl
= (PredicateImpl
*) pred
;
307 rightTableHdl
->closeScan();
308 void *rec
= leftTableHdl
->fetch();
309 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
311 if (rec
== NULL
) {isLeftRecOver
= true; return NULL
;}
312 else if (rec
== (char*)0x1) { leftSideFail
= true;}
313 rightTableHdl
->execute();
315 rec
= rightTableHdl
->fetch();
316 if (rec
== NULL
|| leftSideFail
) {
317 //if(!leftTableHdl->getName()) printf("RIGHT FETCH returns NULL\n");
318 //if join condition(pred) is set and if it is pushed to tablehdl
319 //when there is index, it returns no record
320 if (jType
== LEFT_JOIN
&& pred
) return NULL
;
321 return fetchRightFail();
324 isReturnNull
= false;
326 if (pred
) rv
= predImpl
->evaluate(result
);
327 if ( OK
!= rv
) return NULL
;
328 if (result
) { break; }
329 rec
= rightTableHdl
->fetch();
331 if (jType
== LEFT_JOIN
) {
332 //return from here so that null values for rhs table will be set
338 isFirstFetch
= false;
339 copyValuesToBindBuffer(NULL
);
342 void* JoinTableImpl::fetch(DbRetVal
&rv
)
348 void* JoinTableImpl::fetchNoBind()
350 printError(ErrBadCall
, "fetchNoBind not implemented for JoinTableImpl");
354 void* JoinTableImpl::fetchNoBind(DbRetVal
&rv
)
357 return fetchNoBind();
360 DbRetVal
JoinTableImpl::copyValuesToBindBuffer(void *elem
)
362 //Iterate through the bind list and copy the value here
363 ListIterator fIter
= projList
.getIterator();
364 JoinProjFieldInfo
*def
;
365 while (fIter
.hasElement())
367 def
= (JoinProjFieldInfo
*) fIter
.nextElement();
368 if (NULL
!= def
->appBuf
) {
369 AllDataType::copyVal(def
->appBuf
, def
->bindBuf
, def
->type
, def
->length
);
374 DbRetVal
JoinTableImpl::getFieldInfo(const char* fldname
, FieldInfo
*&info
)
376 DbRetVal retCode
= OK
, retCode1
=OK
;
377 availableLeft
= false;
378 retCode
= leftTableHdl
->getFieldInfo(fldname
, info
);
384 retCode1
= rightTableHdl
->getFieldInfo(fldname
, info
);
387 if (availableLeft
) return ErrSyntaxError
;
393 long JoinTableImpl::numTuples()
397 DbRetVal
JoinTableImpl::closeScan()
399 //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan();
400 if (leftTableHdl
) leftTableHdl
->closeScan();
401 if (rightTableHdl
) rightTableHdl
->closeScan();
402 isLeftRecOver
= false;
408 DbRetVal
JoinTableImpl::close()
411 if (leftTableHdl
) { leftTableHdl
->close(); leftTableHdl
= NULL
; }
412 if (rightTableHdl
) { rightTableHdl
->close(); rightTableHdl
= NULL
; }
413 ListIterator iter
= projList
.getIterator();
414 JoinProjFieldInfo
*elem
;
415 while (iter
.hasElement())
417 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
423 ListIterator pIter
= predList
.getIterator();
424 while(pIter
.hasElement())
426 PredicateImpl
*pImpl
= (PredicateImpl
*) pIter
.nextElement();
433 void* JoinTableImpl::getBindFldAddr(const char *name
)
435 void* bindAddr
= leftTableHdl
->getBindFldAddr(name
);
436 if (bindAddr
) return bindAddr
;
437 return rightTableHdl
->getBindFldAddr(name
);
439 List
JoinTableImpl::getFieldNameList()
443 List leftList
= leftTableHdl
->getFieldNameList();
444 ListIterator lIter
= leftList
.getIterator();
445 while (lIter
.hasElement())
447 Identifier
*elem
= (Identifier
*) lIter
.nextElement();
448 fldNameList
.append(elem
);
451 List rightList
= rightTableHdl
->getFieldNameList();
452 ListIterator rIter
= rightList
.getIterator();
453 while (rIter
.hasElement())
455 Identifier
*elem
= (Identifier
*) rIter
.nextElement();
456 fldNameList
.append(elem
);
462 bool JoinTableImpl::isTableInvolved(char *tableName
)
464 //printf("isTableInvolved called in join for %s\n", tableName);
465 bool isInvolved
= leftTableHdl
->isTableInvolved(tableName
);
466 if (isInvolved
) return true;
467 isInvolved
= rightTableHdl
->isTableInvolved(tableName
);
470 void* JoinTableImpl::getBindedBuf(char* tName
, char* fName
)
472 ListIterator iter
= projList
.getIterator();
473 JoinProjFieldInfo
*elem
;
474 while (iter
.hasElement())
476 elem
= (JoinProjFieldInfo
*) iter
.nextElement();
477 if (strcmp(elem
->fieldName
, fName
)==0 &&
478 strcmp(elem
->tableName
, tName
) ==0)
480 return elem
->bindBuf
;
485 bool JoinTableImpl::pushPredicate(Predicate
*pr
)
487 //printf("PRABA::pushPredicate called\n");
488 PredicateImpl
*pImpl
= (PredicateImpl
*) pr
;
489 bool pushed
= leftTableHdl
->pushPredicate(pr
);
492 pushed
= rightTableHdl
->pushPredicate(pr
);
496 //printf("PRABA::unable to push the predicate\n");
497 //TODO::check if needs to be placed here
498 char *lTbl
= leftTableHdl
->getName();
499 char *rTbl
= rightTableHdl
->getName();
500 char *lAliasTbl
= leftTableHdl
->getAliasName();
501 char *rAliasTbl
= rightTableHdl
->getAliasName();
502 bool isAliasSet
= lAliasTbl
&& rAliasTbl
&& (!(strcmp(lAliasTbl
,"") == 0 && strcmp(rAliasTbl
,"") == 0 ));
503 char fullName
[IDENTIFIER_LENGTH
];
504 char lTabName
[IDENTIFIER_LENGTH
];
505 char rTabName
[IDENTIFIER_LENGTH
];
506 char lFldName
[IDENTIFIER_LENGTH
];
507 char rFldName
[IDENTIFIER_LENGTH
];
508 strcpy(fullName
, pImpl
->getFldName1());
509 Table::getTableNameAlone(fullName
, lTabName
);
510 Table::getFieldNameAlone(fullName
, lFldName
);
511 strcpy(fullName
, pImpl
->getFldName2());
512 Table::getTableNameAlone(fullName
, rTabName
);
513 Table::getFieldNameAlone(fullName
, rFldName
);
515 if (NULL
!= lTbl
&& NULL
!= rTbl
)
517 //both size TableImpl handles are there
518 if (0 == strcmp(lTbl
, lTabName
) || 0 == strcmp(lTbl
, rTabName
) || ( isAliasSet
&& (0 == strcmp(lAliasTbl
, lTabName
) ||0 == strcmp(lAliasTbl
,rTabName
))) )
520 if (0 == strcmp(rTbl
, lTabName
) || 0 == strcmp(rTbl
, rTabName
)|| (isAliasSet
&& (0 == strcmp(rAliasTbl
, lTabName
) ||0 == strcmp(rAliasTbl
,rTabName
))))
522 //printf("PRABA::pushed join predicate here1\n");
524 ComparisionOp op
= pImpl
->getCompOp();
525 if (0 == strcmp(rTbl
, rTabName
) ||(isAliasSet
&& 0 == strcmp(rAliasTbl
, rTabName
)))
527 //bool ind = rightTableHdl->hasIndex(rFldName);
529 void *buf
= getBindedBuf(lTabName
, lFldName
);
530 rightTableHdl
->addPredicate(rFldName
, op
, buf
);
531 pImpl
->setDontEvaluate();
533 }else if (0==strcmp(rTbl
, lTabName
) || (isAliasSet
&& 0== strcmp(rAliasTbl
, lTabName
)))
535 //bool ind = rightTableHdl->hasIndex(lFldName);
537 void *buf
= getBindedBuf(rTabName
, rFldName
);
538 rightTableHdl
->addPredicate(lFldName
, op
, buf
);
539 pImpl
->setDontEvaluate();
548 if(isTableInvolved(lTabName
) && isTableInvolved(rTabName
))
550 //printf("PRABA::pushed join predicate here2\n");
552 ComparisionOp op
= pImpl
->getCompOp();
553 if (strcmp(rTbl
, rTabName
) ==0)
555 //bool ind = rightTableHdl->hasIndex(rFldName);
557 void *buf
= getBindedBuf(lTabName
, lFldName
);
558 rightTableHdl
->addPredicate(rFldName
, op
, buf
);
559 pImpl
->setDontEvaluate();
561 }else if (strcmp(rTbl
, lTabName
) ==0)
563 //bool ind = rightTableHdl->hasIndex(lFldName);
565 void *buf
= getBindedBuf(rTabName
, rFldName
);
566 rightTableHdl
->addPredicate(lFldName
, op
, buf
);
567 pImpl
->setDontEvaluate();
578 void JoinTableImpl::setPredicate(Predicate
*pr
)
580 if (NULL
== pred
) { pred
= pr
; return; }
581 Predicate
*curPred
= pred
;
582 PredicateImpl
*newPred
= new PredicateImpl();
583 newPred
->setTerm(curPred
, OpAnd
, pr
);
584 newPred
->setProjectionList(&projList
);
585 predList
.append(newPred
);
589 bool JoinTableImpl::isFldNull(const char *name
)
592 if(NULL
==leftTableHdl
->getName())
594 ret
= leftTableHdl
->isFldNull(name
);
595 if(ret
==true) return true;
599 char tableName
[IDENTIFIER_LENGTH
];
600 Table::getTableNameAlone((char*)name
, tableName
);
601 if(0 == strcmp(tableName
,leftTableHdl
->getName()))
603 return leftTableHdl
->isFldNull(name
);
606 if(NULL
==rightTableHdl
->getName())
608 if (isReturnNull
) return true;
609 ret
= rightTableHdl
->isFldNull(name
);
610 if(ret
==true) return true;
613 char tableName
[IDENTIFIER_LENGTH
];
614 Table::getTableNameAlone((char*)name
, tableName
);
615 if(0==strcmp(tableName
,rightTableHdl
->getName()))
617 if (isReturnNull
) return true;
618 return rightTableHdl
->isFldNull(name
);
623 //same as above expect it does not check for isRecordFound flag
624 //as it is set only after predicate evaluate
625 bool JoinTableImpl::isFldNullInt(const char *name
)
628 if(NULL
==leftTableHdl
->getName())
630 ret
= leftTableHdl
->isFldNull(name
);
631 if(ret
==true) return true;
635 char tableName
[IDENTIFIER_LENGTH
];
636 Table::getTableNameAlone((char*)name
, tableName
);
637 if(0 == strcmp(tableName
,leftTableHdl
->getName()))
639 return leftTableHdl
->isFldNull(name
);
642 if(NULL
==rightTableHdl
->getName())
644 ret
= rightTableHdl
->isFldNull(name
);
645 if(ret
==true) return true;
648 char tableName
[IDENTIFIER_LENGTH
];
649 Table::getTableNameAlone((char*)name
, tableName
);
650 if(0==strcmp(tableName
,rightTableHdl
->getName()))
652 return rightTableHdl
->isFldNull(name
);