*** empty log message ***
[csql.git] / src / relational / relop / JoinTableImpl.cxx
blob1312472ab4d3f5836105480c267fa634b53bc2e9
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<Debug.h>
17 #include<Table.h>
18 #include<TableImpl.h>
19 #include<JoinTableImpl.h>
20 #include<PredicateImpl.h>
22 JoinTableImpl::JoinTableImpl()
24 isNestedLoop= true;
25 pred = NULL;
26 curTuple = NULL;
27 leftTableHdl = NULL;
28 rightTableHdl = NULL;
29 isLeftRecOver = false;
30 isFirstCall = true;
31 availableLeft = true;
32 isFirstFetch = true;
33 isReturnNull = false;
34 //isOuterJoin = false;
35 isOptimized = false;
36 leftSideFail = false;
37 jType = INNER_JOIN;
38 isNestedLoop = true;
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);
59 delete info;
60 return ErrBadCall;
62 if (strcmp(elem->fieldName, fieldName)==0 &&
63 strcmp(elem->tableName, "") ==0)
65 printError(ErrBadCall, "Field already binded %s\n", fldname);
66 delete info;
67 return ErrBadCall;
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);
76 def->appBuf = val;
77 DbRetVal rv = getFieldInfo(fldname, info);
78 if ( OK != rv) {
79 printError(ErrBadCall, "Field not found or unqualified field name %s", fldname);
80 delete def;
81 delete info;
82 return ErrSyntaxError;
84 def->bindBuf = AllDataType::alloc(info->type, info->length);
85 if (availableLeft)
86 leftTableHdl->bindFld(fldname, def->bindBuf);
87 else
88 rightTableHdl->bindFld(fldname, def->bindBuf);
89 def->type = info->type;
90 def->length= info->length;
91 projList.append(def);
92 delete info;
93 return OK;
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;
104 while (true)
106 tblPred = predImpl->getTablePredicate();
107 if (NULL == tblPred) break;
108 if (pred == tblPred)
110 pred = NULL;
111 isPushed = pushPredicate(tblPred);
112 if (!isPushed)
114 //printf("optimizer could not push table predicate\n");
116 break;
118 isPushed = pushPredicate(tblPred);
119 if (!isPushed)
121 //printf("optimizer could not push table predicate\n");
124 while (true)
126 tblPred = predImpl->getJoinPredicate();
127 if (pred == tblPred)
129 break;
131 if (NULL == tblPred) break;
132 isPushed = pushPredicate(tblPred);
133 if (!isPushed)
135 //printf("optimizer could not push join predicate\n");
139 if (pred != NULL)
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();
146 if (NULL != p)
148 //TODO::fix this leak below..it dumps core if uncommented
149 //delete pred;
150 pred = p;
151 predImpl = p;
153 if (predImpl->isDummyPredicate())
155 //TODO::fix this leak below..it dumps core if uncommented
156 //delete pred;
157 pred = NULL;
160 DbRetVal rv = leftTableHdl->optimize();
161 if (OK != rv) {
162 printError(ErrUnknown, "Left handle optimize failed");
163 return rv;
165 rv = rightTableHdl->optimize();
166 if (OK != rv) {
167 printError(ErrUnknown, "Left handle optimize failed");
168 return rv;
170 optimizeRestrict();
171 return OK;
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;
181 if (interChange) {
182 Table *tmp = leftTableHdl;
183 leftTableHdl=rightTableHdl;
184 rightTableHdl = tmp;
187 //get the predicate with right table handle name
188 //rightTableHdl->getIndexType();
189 return;
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;
230 isNestedLoop = true;
231 if (pred)
233 predImpl->setProjectionList(&projList);
234 predImpl->solveForProjList(this);
236 //push the table scan predicates
237 //PRABA::TEMP:
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);
250 isFirstCall = false;
252 rightTableHdl->execute();
253 TableImpl *tImpl = (TableImpl*) rightTableHdl;
254 //isOuterJoin= true;
255 isFirstFetch = true;
256 return OK;
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)
268 isFirstFetch= false;
269 isReturnNull = true;
270 copyValuesToBindBuffer(NULL);
271 //if (!leftTableHdl->getName()) printf("rec value is 0x1\n");
272 return (void*)0x1;
274 isReturnNull = false;
275 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
276 return rec;
279 void* JoinTableImpl::fetchInt()
281 PredicateImpl* predImpl = (PredicateImpl*) pred;
282 DbRetVal rv = OK;
283 if (isNestedLoop)
285 void *rec = rightTableHdl->fetch();
286 if (rec==NULL)
288 return fetchRightFail();
290 else {
291 if (jType == LEFT_JOIN && leftSideFail
292 && !leftTableHdl->getName()
293 && !isFirstFetch) return fetchRightFail();
295 bool result = true;
296 while (true) {
297 if (pred) rv = predImpl->evaluate(result);
298 if ( rv !=OK && rv !=ErrNullValues ) return NULL;
299 if (result) break;
300 rec = rightTableHdl->fetch();
301 if (rec == NULL) {
302 if (jType == LEFT_JOIN && isFirstFetch) return NULL;
303 return fetchInt();
306 copyValuesToBindBuffer(NULL);
307 isFirstFetch = false;
308 return rec;
311 return NULL;
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;
319 DbRetVal rv = OK;
320 rightTableHdl->closeScan();
321 void *rec = leftTableHdl->fetch();
322 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
323 leftSideFail= false;
324 if (rec == NULL) {isLeftRecOver= true; return NULL;}
325 else if (rec == (char*)0x1) { leftSideFail = true;}
326 rightTableHdl->execute();
327 isFirstFetch = true;
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();
336 bool result = true;
337 isReturnNull = false;
338 while (true) {
339 if (pred) rv = predImpl->evaluate(result);
340 if ( OK != rv) return NULL;
341 if (result) { break; }
342 rec = rightTableHdl->fetch();
343 if (rec == NULL) {
344 if (jType == LEFT_JOIN) {
345 //return from here so that null values for rhs table will be set
346 return (void*) NULL;
348 return fetchInt();
351 isFirstFetch = false;
352 copyValuesToBindBuffer(NULL);
353 return rec;
356 void* JoinTableImpl::fetch(DbRetVal &rv)
358 rv = OK;
359 return fetchInt();
362 void* JoinTableImpl::fetchNoBind()
364 printError(ErrBadCall, "fetchNoBind not implemented for JoinTableImpl");
365 return NULL;
368 void* JoinTableImpl::fetchNoBind(DbRetVal &rv)
370 rv = OK;
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);
386 return OK;
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);
394 return OK;
397 DbRetVal JoinTableImpl::getFieldInfo(const char* fldname, FieldInfo *&info)
399 DbRetVal retCode = OK, retCode1 =OK;
400 availableLeft = false;
401 retCode = leftTableHdl->getFieldInfo(fldname, info);
402 if (retCode ==OK)
404 availableLeft= true;
405 //return OK;
407 retCode1 = rightTableHdl->getFieldInfo(fldname, info);
408 if (retCode1 ==OK)
410 if (availableLeft) return ErrSyntaxError;
411 return OK;
413 return retCode;
416 long JoinTableImpl::numTuples()
418 return 0;
421 DbRetVal JoinTableImpl::closeScan()
423 //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan();
424 if (leftTableHdl) leftTableHdl->closeScan();
425 if (rightTableHdl) rightTableHdl->closeScan();
426 isLeftRecOver = false;
427 isFirstCall = true;
428 return OK;
432 DbRetVal JoinTableImpl::close()
434 closeScan();
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();
442 free(elem->bindBuf);
443 delete elem;
445 projList.reset();
446 //delete pred;
447 ListIterator pIter = predList.getIterator();
448 while(pIter.hasElement())
450 PredicateImpl *pImpl = (PredicateImpl*) pIter.nextElement();
451 delete pImpl;
453 predList.reset();
454 delete this;
455 return OK;
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()
467 List fldNameList;
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);
484 leftList.reset();
485 rightList.reset();
486 return fldNameList;
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);
495 return isInvolved;
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;
511 return NULL;
514 bool JoinTableImpl::pushPredicate(Predicate *pr)
516 //printf("PRABA::pushPredicate called\n");
517 PredicateImpl *pImpl = (PredicateImpl*) pr;
518 bool pushed = leftTableHdl->pushPredicate(pr);
519 if (!pushed)
521 pushed = rightTableHdl->pushPredicate(pr);
523 if (!pushed)
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");
552 //PRABA::START
553 ComparisionOp op = pImpl->getCompOp();
554 if (0 == strcmp(rTbl, rTabName) ||(isAliasSet && 0 == strcmp(rAliasTbl, rTabName)))
556 //bool ind = rightTableHdl->hasIndex(rFldName);
557 if (OpEquals ==op) {
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);
565 if (OpEquals ==op) {
566 void *buf = getBindedBuf(rTabName, rFldName);
567 rightTableHdl->addPredicate(lFldName, op, buf);
568 pImpl->setDontEvaluate();
571 //PRABA::END
572 setPredicate(pr);
573 pushed = true;
576 }else{
577 if(isTableInvolved(lTabName) && isTableInvolved(rTabName))
579 //printf("PRABA::pushed join predicate here2\n");
580 //PRABA::START
581 ComparisionOp op = pImpl->getCompOp();
582 if (strcmp(rTbl, rTabName) ==0)
584 //bool ind = rightTableHdl->hasIndex(rFldName);
585 if (OpEquals ==op) {
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);
593 if (OpEquals ==op) {
594 void *buf = getBindedBuf(rTabName, rFldName);
595 rightTableHdl->addPredicate(lFldName, op, buf);
596 pImpl->setDontEvaluate();
599 //PRABA::END
600 setPredicate(pr);
601 pushed = true;
605 return pushed;
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);
616 pred = newPred;
617 return;
620 bool JoinTableImpl::isFldNull(const char *name)
622 bool ret = false;
623 if(NULL==leftTableHdl->getName())
625 ret = leftTableHdl->isFldNull(name);
626 if(ret==true) return true;
628 else
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;
643 else{
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);
652 return ret;
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)
659 bool ret = false;
660 if(NULL==leftTableHdl->getName())
662 ret = leftTableHdl->isFldNull(name);
663 if(ret==true) return true;
665 else
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;
679 else{
680 char tableName[IDENTIFIER_LENGTH];
681 Table::getTableNameAlone((char*)name, tableName);
682 if(0==strcmp(tableName,rightTableHdl->getName()))
684 return rightTableHdl->isFldNull(name);
687 return ret;