code reorg
[csql.git] / src / storage / JoinTableImpl.cxx
blob339da28408605b125f7ec2487c33d5afc5dd312e
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;
63 JoinProjFieldInfo *def = new JoinProjFieldInfo();
64 strcpy(def->tableName, tableName);
65 strcpy(def->fieldName, fieldName);
66 strcpy(def->tabFieldName, fldname);
67 def->appBuf = val;
68 DbRetVal rv = getFieldInfo(fldname, info);
69 if ( OK != rv) {
70 printError(ErrBadCall, "Field not found or unqualified field name %s", fldname);
71 delete def;
72 delete info;
73 return ErrSyntaxError;
75 def->bindBuf = AllDataType::alloc(info->type, info->length);
76 if (availableLeft)
77 leftTableHdl->bindFld(fldname, def->bindBuf);
78 else
79 rightTableHdl->bindFld(fldname, def->bindBuf);
80 def->type = info->type;
81 def->length= info->length;
82 projList.append(def);
83 delete info;
84 return OK;
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;
95 while (true)
97 tblPred = predImpl->getTablePredicate();
98 if (NULL == tblPred) break;
99 if (pred == tblPred)
101 pred = NULL;
102 isPushed = pushPredicate(tblPred);
103 if (!isPushed)
105 //printf("optimizer could not push table predicate\n");
107 break;
109 isPushed = pushPredicate(tblPred);
110 if (!isPushed)
112 //printf("optimizer could not push table predicate\n");
115 while (true)
117 tblPred = predImpl->getJoinPredicate();
118 if (pred == tblPred)
120 break;
122 if (NULL == tblPred) break;
123 isPushed = pushPredicate(tblPred);
124 if (!isPushed)
126 //printf("optimizer could not push join predicate\n");
130 if (pred != NULL)
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();
137 if (NULL != p)
139 //TODO::fix this leak below..it dumps core if uncommented
140 //delete pred;
141 pred = p;
142 predImpl = p;
144 if (predImpl->isDummyPredicate())
146 //TODO::fix this leak below..it dumps core if uncommented
147 //delete pred;
148 pred = NULL;
151 DbRetVal rv = leftTableHdl->optimize();
152 if (OK != rv) {
153 printError(ErrUnknown, "Left handle optimize failed");
154 return rv;
156 rv = rightTableHdl->optimize();
157 if (OK != rv) {
158 printError(ErrUnknown, "Left handle optimize failed");
159 return rv;
161 optimizeRestrict();
162 return OK;
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;
172 if (interChange) {
173 Table *tmp = leftTableHdl;
174 leftTableHdl=rightTableHdl;
175 rightTableHdl = tmp;
178 //get the predicate with right table handle name
179 //rightTableHdl->getIndexType();
180 return;
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;
220 isNestedLoop = true;
221 if (pred)
223 predImpl->setProjectionList(&projList);
224 predImpl->solveForProjList(this);
226 //push the table scan predicates
227 //PRABA::TEMP:
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);
240 isFirstCall = false;
242 rightTableHdl->execute();
243 TableImpl *tImpl = (TableImpl*) rightTableHdl;
244 //isOuterJoin= true;
245 isFirstFetch = true;
246 return OK;
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)
257 isFirstFetch= false;
258 isReturnNull = true;
259 copyValuesToBindBuffer(NULL);
260 //if (!leftTableHdl->getName()) printf("rec value is 0x1\n");
261 return (void*)0x1;
263 isReturnNull = false;
264 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
265 return rec;
267 void* JoinTableImpl::fetchInt()
269 PredicateImpl* predImpl = (PredicateImpl*) pred;
270 DbRetVal rv = OK;
271 if (isNestedLoop)
273 void *rec = rightTableHdl->fetch();
274 if (rec==NULL)
276 return fetchRightFail();
278 else {
279 if (jType == LEFT_JOIN && leftSideFail
280 && !leftTableHdl->getName()
281 && !isFirstFetch) return fetchRightFail();
283 bool result = true;
284 while (true) {
285 if (pred) rv = predImpl->evaluate(result);
286 if ( rv !=OK && rv !=ErrNullValues ) return NULL;
287 if (result) break;
288 rec = rightTableHdl->fetch();
289 if (rec == NULL) {
290 if (jType == LEFT_JOIN && isFirstFetch) return NULL;
291 return fetchInt();
294 copyValuesToBindBuffer(NULL);
295 isFirstFetch = false;
296 return rec;
299 return NULL;
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;
307 DbRetVal rv = OK;
308 rightTableHdl->closeScan();
309 void *rec = leftTableHdl->fetch();
310 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
311 leftSideFail= false;
312 if (rec == NULL) {isLeftRecOver= true; return NULL;}
313 else if (rec == (char*)0x1) { leftSideFail = true;}
314 rightTableHdl->execute();
315 isFirstFetch = true;
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();
324 bool result = true;
325 isReturnNull = false;
326 while (true) {
327 if (pred) rv = predImpl->evaluate(result);
328 if ( OK != rv) return NULL;
329 if (result) { break; }
330 rec = rightTableHdl->fetch();
331 if (rec == NULL) {
332 if (jType == LEFT_JOIN) {
333 //return from here so that null values for rhs table will be set
334 return (void*) NULL;
336 return fetchInt();
339 isFirstFetch = false;
340 copyValuesToBindBuffer(NULL);
341 return rec;
343 void* JoinTableImpl::fetch(DbRetVal &rv)
345 rv = OK;
346 return fetchInt();
349 void* JoinTableImpl::fetchNoBind()
351 printError(ErrBadCall, "fetchNoBind not implemented for JoinTableImpl");
352 return NULL;
355 void* JoinTableImpl::fetchNoBind(DbRetVal &rv)
357 rv = OK;
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);
373 return OK;
375 DbRetVal JoinTableImpl::getFieldInfo(const char* fldname, FieldInfo *&info)
377 DbRetVal retCode = OK, retCode1 =OK;
378 availableLeft = false;
379 retCode = leftTableHdl->getFieldInfo(fldname, info);
380 if (retCode ==OK)
382 availableLeft= true;
383 //return OK;
385 retCode1 = rightTableHdl->getFieldInfo(fldname, info);
386 if (retCode1 ==OK)
388 if (availableLeft) return ErrSyntaxError;
389 return OK;
391 return retCode;
394 long JoinTableImpl::numTuples()
396 return 0;
398 DbRetVal JoinTableImpl::closeScan()
400 //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan();
401 if (leftTableHdl) leftTableHdl->closeScan();
402 if (rightTableHdl) rightTableHdl->closeScan();
403 isLeftRecOver = false;
404 isFirstCall = true;
405 return OK;
409 DbRetVal JoinTableImpl::close()
411 closeScan();
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();
419 free(elem->bindBuf);
420 delete elem;
422 projList.reset();
423 //delete pred;
424 ListIterator pIter = predList.getIterator();
425 while(pIter.hasElement())
427 PredicateImpl *pImpl = (PredicateImpl*) pIter.nextElement();
428 delete pImpl;
430 predList.reset();
431 delete this;
432 return OK;
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()
442 List fldNameList;
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);
459 leftList.reset();
460 rightList.reset();
461 return fldNameList;
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);
469 return isInvolved;
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;
484 return NULL;
486 bool JoinTableImpl::pushPredicate(Predicate *pr)
488 //printf("PRABA::pushPredicate called\n");
489 PredicateImpl *pImpl = (PredicateImpl*) pr;
490 bool pushed = leftTableHdl->pushPredicate(pr);
491 if (!pushed)
493 pushed = rightTableHdl->pushPredicate(pr);
495 if (!pushed)
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");
524 //PRABA::START
525 ComparisionOp op = pImpl->getCompOp();
526 if (0 == strcmp(rTbl, rTabName) ||(isAliasSet && 0 == strcmp(rAliasTbl, rTabName)))
528 //bool ind = rightTableHdl->hasIndex(rFldName);
529 if (OpEquals ==op) {
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);
537 if (OpEquals ==op) {
538 void *buf = getBindedBuf(rTabName, rFldName);
539 rightTableHdl->addPredicate(lFldName, op, buf);
540 pImpl->setDontEvaluate();
543 //PRABA::END
544 setPredicate(pr);
545 pushed = true;
548 }else{
549 if(isTableInvolved(lTabName) && isTableInvolved(rTabName))
551 //printf("PRABA::pushed join predicate here2\n");
552 //PRABA::START
553 ComparisionOp op = pImpl->getCompOp();
554 if (strcmp(rTbl, rTabName) ==0)
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 (strcmp(rTbl, lTabName) ==0)
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;
577 return pushed;
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);
587 pred = newPred;
588 return;
590 bool JoinTableImpl::isFldNull(const char *name)
592 bool ret = false;
593 if(NULL==leftTableHdl->getName())
595 ret = leftTableHdl->isFldNull(name);
596 if(ret==true) return true;
598 else
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;
613 else{
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);
622 return ret;
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)
628 bool ret = false;
629 if(NULL==leftTableHdl->getName())
631 ret = leftTableHdl->isFldNull(name);
632 if(ret==true) return true;
634 else
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;
648 else{
649 char tableName[IDENTIFIER_LENGTH];
650 Table::getTableNameAlone((char*)name, tableName);
651 if(0==strcmp(tableName,rightTableHdl->getName()))
653 return rightTableHdl->isFldNull(name);
656 return ret;