commiting changes from enterprise version for V2.4
[csql.git] / src / storage / JoinTableImpl.cxx
blob234ff1401640c03aecba81c4ead2443b341aa2fe
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;
30 JoinTableImpl::~JoinTableImpl() {}
31 /* moved to Table class
32 * shall be removed
33 void JoinTableImpl::getFieldNameAlone(char *fname, char *name) {
34 bool dotFound= false;
35 char *fullname = fname;
36 while(*fullname != '\0')
38 if (*fullname == '.') { dotFound = true; break; }
39 fullname++;
41 if (dotFound) strcpy(name, ++fullname); else strcpy(name, fname);
44 void JoinTableImpl::getTableNameAlone(char *fname, char *name) {
45 strcpy(name, fname);
46 while(*name != '\0')
48 if (*name == '.') { *name='\0'; break; }
49 name++;
51 return;
54 DbRetVal JoinTableImpl::bindFld(const char *fldname, void *val)
56 FieldInfo *info = new FieldInfo();
57 char tableName[IDENTIFIER_LENGTH];
58 char fieldName[IDENTIFIER_LENGTH];
59 getTableNameAlone((char*)fldname, tableName);
60 getFieldNameAlone((char*)fldname, fieldName);
61 ListIterator iter = projList.getIterator();
62 JoinProjFieldInfo *elem;
63 while (iter.hasElement())
65 elem = (JoinProjFieldInfo*) iter.nextElement();
66 if (strcmp(elem->fieldName, fieldName)==0 &&
67 strcmp(elem->tableName, tableName) ==0)
69 printError(ErrBadCall, "Field already binded %s\n", fldname);
70 delete info;
71 return ErrBadCall;
74 JoinProjFieldInfo *def = new JoinProjFieldInfo();
75 strcpy(def->tableName, tableName);
76 strcpy(def->fieldName, fieldName);
77 strcpy(def->tabFieldName, fldname);
78 def->appBuf = val;
79 getFieldInfo(fldname, info);
80 def->bindBuf = AllDataType::alloc(info->type, info->length);
81 if (availableLeft)
82 leftTableHdl->bindFld(fldname, def->bindBuf);
83 else
84 rightTableHdl->bindFld(fldname, def->bindBuf);
85 def->type = info->type;
86 def->length= info->length;
87 projList.append(def);
88 delete info;
89 return OK;
92 DbRetVal JoinTableImpl::optimize()
94 PredicateImpl* predImpl = (PredicateImpl*) pred;
95 if (NULL != predImpl && !predImpl->isNotOrInvolved())
97 //printf("not or or not involved\n");
98 PredicateImpl *tblPred = NULL;
99 bool isPushed = false;
100 while (true)
102 tblPred = predImpl->getTablePredicate();
103 if (NULL == tblPred) break;
104 if (pred == tblPred)
106 pred = NULL;
107 isPushed = pushPredicate(tblPred);
108 if (!isPushed)
110 //printf("optimizer could not push table predicate\n");
112 break;
114 isPushed = pushPredicate(tblPred);
115 if (!isPushed)
117 //printf("optimizer could not push table predicate\n");
120 while (true)
122 tblPred = predImpl->getJoinPredicate();
123 if (pred == tblPred)
125 break;
127 if (NULL == tblPred) break;
128 isPushed = pushPredicate(tblPred);
129 if (!isPushed)
131 //printf("optimizer could not push join predicate\n");
135 if (pred != NULL)
137 //push predicates leave the predicate nodes empty
138 //here we remove all the unnecessary nodes
139 predImpl = (PredicateImpl*) pred;
140 predImpl->removeIfNotNecessary();
141 PredicateImpl *p = predImpl->getIfOneSidedPredicate();
142 if (NULL != p)
144 //TODO::fix this leak below..it dumps core if uncommented
145 //delete pred;
146 pred = p;
147 predImpl = p;
149 if (predImpl->isDummyPredicate())
151 //TODO::fix this leak below..it dumps core if uncommented
152 //delete pred;
153 pred = NULL;
156 DbRetVal rv = leftTableHdl->optimize();
157 if (OK != rv) {
158 printError(ErrUnknown, "Left handle optimize failed");
159 return rv;
161 rv = rightTableHdl->optimize();
162 if (OK != rv) {
163 printError(ErrUnknown, "Left handle optimize failed");
164 return rv;
166 optimizeRestrict();
167 return OK;
169 void JoinTableImpl::optimizeRestrict()
171 ScanType lType = leftTableHdl->getScanType();
172 ScanType rType = rightTableHdl->getScanType();
173 bool interChange = false;
174 if (lType == fullTableScan && rType != fullTableScan) interChange = true;
175 else if (lType != hashIndexScan && rType == treeIndexScan) interChange=true;
177 if (interChange) {
178 Table *tmp = leftTableHdl;
179 leftTableHdl=rightTableHdl;
180 rightTableHdl = tmp;
183 //get the predicate with right table handle name
184 //rightTableHdl->getIndexType();
185 return;
187 ScanType JoinTableImpl::getScanType()
189 ScanType lType = leftTableHdl->getScanType();
190 ScanType rType = rightTableHdl->getScanType();
191 if (lType == hashIndexScan || rType == hashIndexScan) return hashIndexScan;
192 if (lType == treeIndexScan || rType == treeIndexScan) return treeIndexScan;
193 return fullTableScan;
196 void JoinTableImpl::printPlan(int space)
198 char spaceBuf[IDENTIFIER_LENGTH];
199 memset(spaceBuf, 32, IDENTIFIER_LENGTH);
200 spaceBuf[space] = '\0';
201 PredicateImpl* predImpl = (PredicateImpl*) pred;
202 printf("%s <JOIN-NODE>\n", spaceBuf);
203 if (predImpl) predImpl->print(space);
204 printf("%s <LEFT>\n", spaceBuf);
205 leftTableHdl->printPlan(space+2);
206 printf("%s </LEFT>\n", spaceBuf);
207 printf("%s <RIGHT>\n", spaceBuf);
208 rightTableHdl->printPlan(space+2);
209 printf("%s </RIGHT>\n", spaceBuf);
210 printf("%s </JOIN-NODE>\n", spaceBuf);
212 DbRetVal JoinTableImpl::execute()
214 PredicateImpl* predImpl = (PredicateImpl*) pred;
215 isNestedLoop = true;
216 if (pred) predImpl->setProjectionList(&projList);
217 //push the table scan predicates
218 optimize();
219 leftTableHdl->execute();
220 leftTableHdl->fetch();
221 rightTableHdl->execute();
222 //TODO
223 //if join condition is not set then do nl
224 //if it is inner join, hen do nl
225 //nl cannot be done for outer join
226 return OK;
229 void* JoinTableImpl::fetch()
231 PredicateImpl* predImpl = (PredicateImpl*) pred;
232 DbRetVal rv = OK;
233 if (isNestedLoop)
235 void *rec = rightTableHdl->fetch();
236 if (rec==NULL)
238 rightTableHdl->closeScan();
239 rec = leftTableHdl->fetch();
240 if (rec == NULL) return NULL;
241 rightTableHdl->execute();
242 rec = rightTableHdl->fetch();
243 if (rec == NULL) return NULL;
244 bool result = true;
245 while (true) {
246 if (pred) rv = predImpl->evaluate(result);
247 if ( OK != rv) return NULL;
248 if (result) break;
249 rec = rightTableHdl->fetch();
250 if (rec == NULL) return fetch();
252 copyValuesToBindBuffer(NULL);
253 return rec;
255 else {
256 bool result = true;
257 while (true) {
258 if (pred) rv = predImpl->evaluate(result);
259 if ( rv !=OK) return NULL;
260 if (result) break;
261 rec = rightTableHdl->fetch();
262 if (rec == NULL) return fetch();
264 copyValuesToBindBuffer(NULL);
265 return rec;
269 return NULL;
271 void* JoinTableImpl::fetch(DbRetVal &rv)
273 rv = OK;
274 return fetch();
277 void* JoinTableImpl::fetchNoBind()
279 return NULL;
282 void* JoinTableImpl::fetchNoBind(DbRetVal &rv)
284 rv = OK;
285 return fetchNoBind();
288 DbRetVal JoinTableImpl::copyValuesToBindBuffer(void *elem)
290 //Iterate through the bind list and copy the value here
291 ListIterator fIter = projList.getIterator();
292 JoinProjFieldInfo *def;
293 while (fIter.hasElement())
295 def = (JoinProjFieldInfo*) fIter.nextElement();
296 if (NULL != def->appBuf) {
297 AllDataType::copyVal(def->appBuf, def->bindBuf, def->type, def->length);
300 return OK;
302 DbRetVal JoinTableImpl::getFieldInfo(const char* fldname, FieldInfo *&info)
304 DbRetVal retCode = OK;
305 retCode = leftTableHdl->getFieldInfo(fldname, info);
306 if (retCode ==OK)
308 availableLeft= true;
309 return OK;
311 retCode = rightTableHdl->getFieldInfo(fldname, info);
312 if (retCode ==OK)
314 availableLeft= false;
315 return OK;
317 return ErrNotExists;
320 long JoinTableImpl::numTuples()
322 return 0;
324 DbRetVal JoinTableImpl::closeScan()
326 if (leftTableHdl) leftTableHdl->closeScan();
327 if (rightTableHdl) rightTableHdl->closeScan();
328 return OK;
332 DbRetVal JoinTableImpl::close()
334 if (leftTableHdl) { leftTableHdl->close(); leftTableHdl = NULL; }
335 if (rightTableHdl) { rightTableHdl->close(); rightTableHdl = NULL; }
336 closeScan();
337 ListIterator iter = projList.getIterator();
338 JoinProjFieldInfo *elem;
339 while (iter.hasElement())
341 elem = (JoinProjFieldInfo*) iter.nextElement();
342 free(elem->bindBuf);
343 delete elem;
345 projList.reset();
346 delete pred;
347 delete this;
348 return OK;
350 void* JoinTableImpl::getBindFldAddr(const char *name)
352 printf("PRABA::join getBindFldAddr not implemented\n");
353 return NULL;
355 List JoinTableImpl::getFieldNameList()
357 List fldNameList;
359 List leftList = leftTableHdl->getFieldNameList();
360 ListIterator lIter = leftList.getIterator();
361 while (lIter.hasElement())
363 Identifier *elem = (Identifier*) lIter.nextElement();
364 fldNameList.append(elem);
367 List rightList = rightTableHdl->getFieldNameList();
368 ListIterator rIter = rightList.getIterator();
369 while (rIter.hasElement())
371 Identifier *elem = (Identifier*) rIter.nextElement();
372 fldNameList.append(elem);
374 leftList.reset();
375 rightList.reset();
376 return fldNameList;
378 bool JoinTableImpl::isTableInvolved(char *tableName)
380 //printf("isTableInvolved called in join for %s\n", tableName);
381 bool isInvolved = leftTableHdl->isTableInvolved(tableName);
382 if (isInvolved) return true;
383 isInvolved = rightTableHdl->isTableInvolved(tableName);
384 return isInvolved;
386 void* JoinTableImpl::getBindedBuf(char* tName, char* fName)
388 ListIterator iter = projList.getIterator();
389 JoinProjFieldInfo *elem;
390 while (iter.hasElement())
392 elem = (JoinProjFieldInfo*) iter.nextElement();
393 if (strcmp(elem->fieldName, fName)==0 &&
394 strcmp(elem->tableName, tName) ==0)
396 return elem->bindBuf;
399 return NULL;
401 bool JoinTableImpl::pushPredicate(Predicate *pr)
403 //printf("PRABA::pushPredicate called\n");
404 PredicateImpl *pImpl = (PredicateImpl*) pr;
405 bool pushed = leftTableHdl->pushPredicate(pr);
406 if (!pushed)
408 pushed = rightTableHdl->pushPredicate(pr);
410 if (!pushed)
412 //printf("PRABA::unable to push the predicate\n");
413 //TODO::check if needs to be placed here
414 char *lTbl = leftTableHdl->getName();
415 char *rTbl = rightTableHdl->getName();
416 char fullName[IDENTIFIER_LENGTH];
417 char lTabName[IDENTIFIER_LENGTH];
418 char rTabName[IDENTIFIER_LENGTH];
419 char lFldName[IDENTIFIER_LENGTH];
420 char rFldName[IDENTIFIER_LENGTH];
421 strcpy(fullName, pImpl->getFldName1());
422 Table::getTableNameAlone(fullName, lTabName);
423 Table::getFieldNameAlone(fullName, lFldName);
424 strcpy(fullName, pImpl->getFldName2());
425 Table::getTableNameAlone(fullName, rTabName);
426 Table::getFieldNameAlone(fullName, rFldName);
428 if (NULL != lTbl && NULL != rTbl)
430 //both size TableImpl handles are there
431 if (0 == strcmp(lTbl, lTabName) || 0 == strcmp(lTbl, rTabName))
433 if (0 == strcmp(rTbl, lTabName) || 0 == strcmp(rTbl, rTabName))
435 //printf("PRABA::pushed join predicate here1\n");
436 //PRABA::START
437 ComparisionOp op = pImpl->getCompOp();
438 if (strcmp(rTbl, rTabName) ==0)
440 //bool ind = rightTableHdl->hasIndex(rFldName);
441 //if (ind) {
442 void *buf = getBindedBuf(lTabName, lFldName);
443 rightTableHdl->addPredicate(rFldName, op, buf);
444 pImpl->setDontEvaluate();
446 }else if (strcmp(rTbl, lTabName) ==0)
448 //bool ind = rightTableHdl->hasIndex(lFldName);
449 //if (ind) {
450 void *buf = getBindedBuf(rTabName, rFldName);
451 rightTableHdl->addPredicate(lFldName, op, buf);
452 pImpl->setDontEvaluate();
455 //PRABA::END
456 setPredicate(pr);
457 pushed = true;
460 }else{
461 if(isTableInvolved(lTabName) && isTableInvolved(rTabName))
463 //printf("PRABA::pushed join predicate here2\n");
464 //PRABA::START
465 ComparisionOp op = pImpl->getCompOp();
466 if (strcmp(rTbl, rTabName) ==0)
468 //bool ind = rightTableHdl->hasIndex(rFldName);
469 //if (ind) {
470 void *buf = getBindedBuf(lTabName, lFldName);
471 rightTableHdl->addPredicate(rFldName, op, buf);
472 pImpl->setDontEvaluate();
474 }else if (strcmp(rTbl, lTabName) ==0)
476 //bool ind = rightTableHdl->hasIndex(lFldName);
477 //if (ind) {
478 void *buf = getBindedBuf(rTabName, rFldName);
479 rightTableHdl->addPredicate(lFldName, op, buf);
480 pImpl->setDontEvaluate();
483 //PRABA::END
484 setPredicate(pr);
485 pushed = true;
489 return pushed;
491 void JoinTableImpl::setPredicate(Predicate *pr)
493 if (NULL == pred) { pred = pr; return; }
494 Predicate *curPred = pred;
495 PredicateImpl *newPred = new PredicateImpl();
496 newPred->setTerm(curPred, OpAnd, pr);
497 newPred->setProjectionList(&projList);
498 pred = newPred;
499 return;
501 bool JoinTableImpl::isFldNull(const char *name)
503 bool ret = false;
504 if(NULL==leftTableHdl->getName())
506 ret = leftTableHdl->isFldNull(name);
507 if(ret==true) return true;
509 else
511 char tableName[IDENTIFIER_LENGTH];
512 Table::getTableNameAlone((char*)name, tableName);
513 if(0 == strcmp(tableName,leftTableHdl->getName()))
515 return leftTableHdl->isFldNull(name);
518 if(NULL==rightTableHdl->getName())
520 ret = rightTableHdl->isFldNull(name);
521 if(ret==true) return true;
523 else{
524 char tableName[IDENTIFIER_LENGTH];
525 Table::getTableNameAlone((char*)name, tableName);
526 if(0==strcmp(tableName,rightTableHdl->getName()))
528 return rightTableHdl->isFldNull(name);
531 return ret;