statement caching modifications and cache stmt display
[csql.git] / src / storage / JoinTableImpl.cxx
blob06ba071173bf9e5c626a37667557b1621d90ffaa
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 leftSideFail = false;
36 jType = INNER_JOIN;
37 isNestedLoop = true;
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);
58 delete info;
59 return ErrBadCall;
62 JoinProjFieldInfo *def = new JoinProjFieldInfo();
63 strcpy(def->tableName, tableName);
64 strcpy(def->fieldName, fieldName);
65 strcpy(def->tabFieldName, fldname);
66 def->appBuf = val;
67 DbRetVal rv = getFieldInfo(fldname, info);
68 if ( OK != rv) {
69 printError(ErrBadCall, "Field not found or unqualified field name %s", fldname);
70 delete def;
71 delete info;
72 return ErrSyntaxError;
74 def->bindBuf = AllDataType::alloc(info->type, info->length);
75 if (availableLeft)
76 leftTableHdl->bindFld(fldname, def->bindBuf);
77 else
78 rightTableHdl->bindFld(fldname, def->bindBuf);
79 def->type = info->type;
80 def->length= info->length;
81 projList.append(def);
82 delete info;
83 return OK;
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;
94 while (true)
96 tblPred = predImpl->getTablePredicate();
97 if (NULL == tblPred) break;
98 if (pred == tblPred)
100 pred = NULL;
101 isPushed = pushPredicate(tblPred);
102 if (!isPushed)
104 //printf("optimizer could not push table predicate\n");
106 break;
108 isPushed = pushPredicate(tblPred);
109 if (!isPushed)
111 //printf("optimizer could not push table predicate\n");
114 while (true)
116 tblPred = predImpl->getJoinPredicate();
117 if (pred == tblPred)
119 break;
121 if (NULL == tblPred) break;
122 isPushed = pushPredicate(tblPred);
123 if (!isPushed)
125 //printf("optimizer could not push join predicate\n");
129 if (pred != NULL)
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();
136 if (NULL != p)
138 //TODO::fix this leak below..it dumps core if uncommented
139 //delete pred;
140 pred = p;
141 predImpl = p;
143 if (predImpl->isDummyPredicate())
145 //TODO::fix this leak below..it dumps core if uncommented
146 //delete pred;
147 pred = NULL;
150 DbRetVal rv = leftTableHdl->optimize();
151 if (OK != rv) {
152 printError(ErrUnknown, "Left handle optimize failed");
153 return rv;
155 rv = rightTableHdl->optimize();
156 if (OK != rv) {
157 printError(ErrUnknown, "Left handle optimize failed");
158 return rv;
160 optimizeRestrict();
161 return OK;
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;
171 if (interChange) {
172 Table *tmp = leftTableHdl;
173 leftTableHdl=rightTableHdl;
174 rightTableHdl = tmp;
177 //get the predicate with right table handle name
178 //rightTableHdl->getIndexType();
179 return;
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;
219 isNestedLoop = true;
220 if (pred)
222 predImpl->setProjectionList(&projList);
223 predImpl->solveForProjList(this);
225 //push the table scan predicates
226 //PRABA::TEMP:
227 //if( jType != LEFT_JOIN) optimize();
228 if (leftTableHdl->getName()) {
229 //printf("left execute call %s", leftTableHdl->getName());
230 optimize();
231 leftTableHdl->execute();
232 leftTableHdl->fetch();
233 }else if (isFirstCall) {
234 //printf("First call");
235 optimize();
236 leftTableHdl->execute();
237 void *rec = leftTableHdl->fetch();
238 //printf("rec value is %x\n", rec);
239 isFirstCall = false;
241 rightTableHdl->execute();
242 TableImpl *tImpl = (TableImpl*) rightTableHdl;
243 isOuterJoin= true;
244 isFirstFetch = true;
245 return OK;
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)
256 isFirstFetch= false;
257 isReturnNull = true;
258 copyValuesToBindBuffer(NULL);
259 //if (!leftTableHdl->getName()) printf("rec value is 0x1\n");
260 return (void*)0x1;
262 isReturnNull = false;
263 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
264 return rec;
266 void* JoinTableImpl::fetchInt()
268 PredicateImpl* predImpl = (PredicateImpl*) pred;
269 DbRetVal rv = OK;
270 if (isNestedLoop)
272 void *rec = rightTableHdl->fetch();
273 if (rec==NULL)
275 return fetchRightFail();
277 else {
278 if (jType == LEFT_JOIN && leftSideFail
279 && !leftTableHdl->getName()
280 && !isFirstFetch) return fetchRightFail();
282 bool result = true;
283 while (true) {
284 if (pred) rv = predImpl->evaluate(result);
285 if ( rv !=OK) return NULL;
286 if (result) break;
287 rec = rightTableHdl->fetch();
288 if (rec == NULL) {
289 if (jType == LEFT_JOIN && isFirstFetch) return NULL;
290 return fetchInt();
293 copyValuesToBindBuffer(NULL);
294 isFirstFetch = false;
295 return rec;
298 return NULL;
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;
306 DbRetVal rv = OK;
307 rightTableHdl->closeScan();
308 void *rec = leftTableHdl->fetch();
309 //if (!leftTableHdl->getName()) printf("rec value is %x\n", rec);
310 leftSideFail= false;
311 if (rec == NULL) {isLeftRecOver= true; return NULL;}
312 else if (rec == (char*)0x1) { leftSideFail = true;}
313 rightTableHdl->execute();
314 isFirstFetch = true;
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();
323 bool result = true;
324 isReturnNull = false;
325 while (true) {
326 if (pred) rv = predImpl->evaluate(result);
327 if ( OK != rv) return NULL;
328 if (result) { break; }
329 rec = rightTableHdl->fetch();
330 if (rec == NULL) {
331 if (jType == LEFT_JOIN) {
332 //return from here so that null values for rhs table will be set
333 return (void*) NULL;
335 return fetchInt();
338 isFirstFetch = false;
339 copyValuesToBindBuffer(NULL);
340 return rec;
342 void* JoinTableImpl::fetch(DbRetVal &rv)
344 rv = OK;
345 return fetchInt();
348 void* JoinTableImpl::fetchNoBind()
350 printError(ErrBadCall, "fetchNoBind not implemented for JoinTableImpl");
351 return NULL;
354 void* JoinTableImpl::fetchNoBind(DbRetVal &rv)
356 rv = OK;
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);
372 return OK;
374 DbRetVal JoinTableImpl::getFieldInfo(const char* fldname, FieldInfo *&info)
376 DbRetVal retCode = OK, retCode1 =OK;
377 availableLeft = false;
378 retCode = leftTableHdl->getFieldInfo(fldname, info);
379 if (retCode ==OK)
381 availableLeft= true;
382 //return OK;
384 retCode1 = rightTableHdl->getFieldInfo(fldname, info);
385 if (retCode1 ==OK)
387 if (availableLeft) return ErrSyntaxError;
388 return OK;
390 return retCode;
393 long JoinTableImpl::numTuples()
395 return 0;
397 DbRetVal JoinTableImpl::closeScan()
399 //if (leftTableHdl && leftTableHdl->getName()) leftTableHdl->closeScan();
400 if (leftTableHdl) leftTableHdl->closeScan();
401 if (rightTableHdl) rightTableHdl->closeScan();
402 isLeftRecOver = false;
403 isFirstCall = true;
404 return OK;
408 DbRetVal JoinTableImpl::close()
410 closeScan();
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();
418 free(elem->bindBuf);
419 delete elem;
421 projList.reset();
422 //delete pred;
423 ListIterator pIter = predList.getIterator();
424 while(pIter.hasElement())
426 PredicateImpl *pImpl = (PredicateImpl*) pIter.nextElement();
427 delete pImpl;
429 predList.reset();
430 delete this;
431 return OK;
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()
441 List fldNameList;
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);
458 leftList.reset();
459 rightList.reset();
460 return fldNameList;
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);
468 return isInvolved;
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;
483 return NULL;
485 bool JoinTableImpl::pushPredicate(Predicate *pr)
487 //printf("PRABA::pushPredicate called\n");
488 PredicateImpl *pImpl = (PredicateImpl*) pr;
489 bool pushed = leftTableHdl->pushPredicate(pr);
490 if (!pushed)
492 pushed = rightTableHdl->pushPredicate(pr);
494 if (!pushed)
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");
523 //PRABA::START
524 ComparisionOp op = pImpl->getCompOp();
525 if (0 == strcmp(rTbl, rTabName) ||(isAliasSet && 0 == strcmp(rAliasTbl, rTabName)))
527 //bool ind = rightTableHdl->hasIndex(rFldName);
528 if (OpEquals ==op) {
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);
536 if (OpEquals ==op) {
537 void *buf = getBindedBuf(rTabName, rFldName);
538 rightTableHdl->addPredicate(lFldName, op, buf);
539 pImpl->setDontEvaluate();
542 //PRABA::END
543 setPredicate(pr);
544 pushed = true;
547 }else{
548 if(isTableInvolved(lTabName) && isTableInvolved(rTabName))
550 //printf("PRABA::pushed join predicate here2\n");
551 //PRABA::START
552 ComparisionOp op = pImpl->getCompOp();
553 if (strcmp(rTbl, rTabName) ==0)
555 //bool ind = rightTableHdl->hasIndex(rFldName);
556 if (OpEquals ==op) {
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);
564 if (OpEquals ==op) {
565 void *buf = getBindedBuf(rTabName, rFldName);
566 rightTableHdl->addPredicate(lFldName, op, buf);
567 pImpl->setDontEvaluate();
570 //PRABA::END
571 setPredicate(pr);
572 pushed = true;
576 return pushed;
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);
586 pred = newPred;
587 return;
589 bool JoinTableImpl::isFldNull(const char *name)
591 bool ret = false;
592 if(NULL==leftTableHdl->getName())
594 ret = leftTableHdl->isFldNull(name);
595 if(ret==true) return true;
597 else
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;
612 else{
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);
621 return ret;
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)
627 bool ret = false;
628 if(NULL==leftTableHdl->getName())
630 ret = leftTableHdl->isFldNull(name);
631 if(ret==true) return true;
633 else
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;
647 else{
648 char tableName[IDENTIFIER_LENGTH];
649 Table::getTableNameAlone((char*)name, tableName);
650 if(0==strcmp(tableName,rightTableHdl->getName()))
652 return rightTableHdl->isFldNull(name);
655 return ret;