performance fixes
[csql.git] / src / storage / JoinTableImpl.cxx
blob26505c61f07c6196ccd04d701afd5f986d3b892e
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()
32 close();
34 /* moved to Table class
35 * shall be removed
36 void JoinTableImpl::getFieldNameAlone(char *fname, char *name) {
37 bool dotFound= false;
38 char *fullname = fname;
39 while(*fullname != '\0')
41 if (*fullname == '.') { dotFound = true; break; }
42 fullname++;
44 if (dotFound) strcpy(name, ++fullname); else strcpy(name, fname);
47 void JoinTableImpl::getTableNameAlone(char *fname, char *name) {
48 strcpy(name, fname);
49 while(*name != '\0')
51 if (*name == '.') { *name='\0'; break; }
52 name++;
54 return;
57 DbRetVal JoinTableImpl::bindFld(const char *fldname, void *val)
59 FieldInfo *info = new FieldInfo();
60 char tableName[IDENTIFIER_LENGTH];
61 char fieldName[IDENTIFIER_LENGTH];
62 getTableNameAlone((char*)fldname, tableName);
63 getFieldNameAlone((char*)fldname, fieldName);
64 ListIterator iter = projList.getIterator();
65 JoinProjFieldInfo *elem;
66 while (iter.hasElement())
68 elem = (JoinProjFieldInfo*) iter.nextElement();
69 if (strcmp(elem->fieldName, fieldName)==0 &&
70 strcmp(elem->tableName, tableName) ==0)
72 printError(ErrBadCall, "Field already binded %s\n", fldname);
73 delete info;
74 return ErrBadCall;
77 JoinProjFieldInfo *def = new JoinProjFieldInfo();
78 strcpy(def->tableName, tableName);
79 strcpy(def->fieldName, fieldName);
80 strcpy(def->tabFieldName, fldname);
81 def->appBuf = val;
82 getFieldInfo(fldname, info);
83 def->bindBuf = AllDataType::alloc(info->type, info->length);
84 if (availableLeft)
85 leftTableHdl->bindFld(fldname, def->bindBuf);
86 else
87 rightTableHdl->bindFld(fldname, def->bindBuf);
88 def->type = info->type;
89 def->length= info->length;
90 projList.append(def);
91 delete info;
92 return OK;
95 DbRetVal JoinTableImpl::optimize()
97 PredicateImpl* predImpl = (PredicateImpl*) pred;
98 if (NULL != predImpl && !predImpl->isNotOrInvolved())
100 //printf("not or or not involved\n");
101 PredicateImpl *tblPred = NULL;
102 bool isPushed = false;
103 while (true)
105 tblPred = predImpl->getTablePredicate();
106 if (NULL == tblPred) break;
107 if (pred == tblPred)
109 pred = NULL;
110 isPushed = pushPredicate(tblPred);
111 if (!isPushed)
113 //printf("optimizer could not push table predicate\n");
115 break;
117 isPushed = pushPredicate(tblPred);
118 if (!isPushed)
120 //printf("optimizer could not push table predicate\n");
123 while (true)
125 tblPred = predImpl->getJoinPredicate();
126 if (pred == tblPred)
128 break;
130 if (NULL == tblPred) break;
131 isPushed = pushPredicate(tblPred);
132 if (!isPushed)
134 //printf("optimizer could not push join predicate\n");
138 if (pred != NULL)
140 //push predicates leave the predicate nodes empty
141 //here we remove all the unnecessary nodes
142 predImpl = (PredicateImpl*) pred;
143 predImpl->removeIfNotNecessary();
144 PredicateImpl *p = predImpl->getIfOneSidedPredicate();
145 if (NULL != p)
147 //TODO::fix this leak below..it dumps core if uncommented
148 //delete pred;
149 pred = p;
150 predImpl = p;
152 if (predImpl->isDummyPredicate())
154 //TODO::fix this leak below..it dumps core if uncommented
155 //delete pred;
156 pred = NULL;
159 DbRetVal rv = leftTableHdl->optimize();
160 if (OK != rv) {
161 printError(ErrUnknown, "Left handle optimize failed");
162 return rv;
164 rv = rightTableHdl->optimize();
165 if (OK != rv) {
166 printError(ErrUnknown, "Left handle optimize failed");
167 return rv;
169 optimizeRestrict();
170 return OK;
172 void JoinTableImpl::optimizeRestrict()
174 ScanType lType = leftTableHdl->getScanType();
175 ScanType rType = rightTableHdl->getScanType();
176 bool interChange = false;
177 if (lType == fullTableScan && rType != fullTableScan) interChange = true;
178 else if (lType != hashIndexScan && rType == treeIndexScan) interChange=true;
180 if (interChange) {
181 Table *tmp = leftTableHdl;
182 leftTableHdl=rightTableHdl;
183 rightTableHdl = tmp;
186 //get the predicate with right table handle name
187 //rightTableHdl->getIndexType();
188 return;
190 ScanType JoinTableImpl::getScanType()
192 ScanType lType = leftTableHdl->getScanType();
193 ScanType rType = rightTableHdl->getScanType();
194 if (lType == hashIndexScan || rType == hashIndexScan) return hashIndexScan;
195 if (lType == treeIndexScan || rType == treeIndexScan) return treeIndexScan;
196 return fullTableScan;
199 void JoinTableImpl::printPlan(int space)
201 char spaceBuf[IDENTIFIER_LENGTH];
202 memset(spaceBuf, 32, IDENTIFIER_LENGTH);
203 spaceBuf[space] = '\0';
204 PredicateImpl* predImpl = (PredicateImpl*) pred;
205 printf("%s <JOIN-NODE>\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 PredicateImpl* predImpl = (PredicateImpl*) pred;
218 isNestedLoop = true;
219 if (pred) predImpl->setProjectionList(&projList);
220 //push the table scan predicates
221 optimize();
222 leftTableHdl->execute();
223 leftTableHdl->fetch();
224 rightTableHdl->execute();
225 //TODO
226 //if join condition is not set then do nl
227 //if it is inner join, hen do nl
228 //nl cannot be done for outer join
229 return OK;
232 void* JoinTableImpl::fetch()
234 PredicateImpl* predImpl = (PredicateImpl*) pred;
235 DbRetVal rv = OK;
236 if (isNestedLoop)
238 void *rec = rightTableHdl->fetch();
239 if (rec==NULL)
241 rightTableHdl->closeScan();
242 rec = leftTableHdl->fetch();
243 if (rec == NULL) return NULL;
244 rightTableHdl->execute();
245 rec = rightTableHdl->fetch();
246 if (rec == NULL) return NULL;
247 bool result = true;
248 while (true) {
249 if (pred) rv = predImpl->evaluate(result);
250 if ( OK != rv) return NULL;
251 if (result) break;
252 rec = rightTableHdl->fetch();
253 if (rec == NULL) return fetch();
255 copyValuesToBindBuffer(NULL);
256 return rec;
258 else {
259 bool result = true;
260 while (true) {
261 if (pred) rv = predImpl->evaluate(result);
262 if ( rv !=OK) return NULL;
263 if (result) break;
264 rec = rightTableHdl->fetch();
265 if (rec == NULL) return fetch();
267 copyValuesToBindBuffer(NULL);
268 return rec;
272 return NULL;
274 void* JoinTableImpl::fetch(DbRetVal &rv)
276 rv = OK;
277 return fetch();
280 void* JoinTableImpl::fetchNoBind()
282 return NULL;
285 void* JoinTableImpl::fetchNoBind(DbRetVal &rv)
287 rv = OK;
288 return fetchNoBind();
291 DbRetVal JoinTableImpl::copyValuesToBindBuffer(void *elem)
293 //Iterate through the bind list and copy the value here
294 ListIterator fIter = projList.getIterator();
295 JoinProjFieldInfo *def;
296 while (fIter.hasElement())
298 def = (JoinProjFieldInfo*) fIter.nextElement();
299 if (NULL != def->appBuf) {
300 AllDataType::copyVal(def->appBuf, def->bindBuf, def->type, def->length);
303 return OK;
305 DbRetVal JoinTableImpl::getFieldInfo(const char* fldname, FieldInfo *&info)
307 DbRetVal retCode = OK;
308 retCode = leftTableHdl->getFieldInfo(fldname, info);
309 if (retCode ==OK)
311 availableLeft= true;
312 return OK;
314 retCode = rightTableHdl->getFieldInfo(fldname, info);
315 if (retCode ==OK)
317 availableLeft= false;
318 return OK;
320 return ErrNotExists;
323 long JoinTableImpl::numTuples()
325 return 0;
327 DbRetVal JoinTableImpl::closeScan()
329 if (leftTableHdl) leftTableHdl->closeScan();
330 if (rightTableHdl) rightTableHdl->closeScan();
331 return OK;
335 DbRetVal JoinTableImpl::close()
337 if (leftTableHdl) { leftTableHdl->close(); leftTableHdl = NULL; }
338 if (rightTableHdl) { rightTableHdl->close(); rightTableHdl = NULL; }
339 closeScan();
340 ListIterator iter = projList.getIterator();
341 JoinProjFieldInfo *elem;
342 while (iter.hasElement())
344 elem = (JoinProjFieldInfo*) iter.nextElement();
345 free(elem->bindBuf);
346 delete elem;
348 projList.reset();
349 return OK;
351 void* JoinTableImpl::getBindFldAddr(const char *name)
353 printf("PRABA::join getBindFldAddr not implemented\n");
354 return NULL;
356 List JoinTableImpl::getFieldNameList()
358 List fldNameList;
360 List leftList = leftTableHdl->getFieldNameList();
361 ListIterator lIter = leftList.getIterator();
362 while (lIter.hasElement())
364 Identifier *elem = (Identifier*) lIter.nextElement();
365 fldNameList.append(elem);
368 List rightList = rightTableHdl->getFieldNameList();
369 ListIterator rIter = rightList.getIterator();
370 while (rIter.hasElement())
372 Identifier *elem = (Identifier*) rIter.nextElement();
373 fldNameList.append(elem);
375 return fldNameList;
377 bool JoinTableImpl::isTableInvolved(char *tableName)
379 //printf("isTableInvolved called in join for %s\n", tableName);
380 bool isInvolved = leftTableHdl->isTableInvolved(tableName);
381 if (isInvolved) return true;
382 isInvolved = rightTableHdl->isTableInvolved(tableName);
383 return isInvolved;
385 void* JoinTableImpl::getBindedBuf(char* tName, char* fName)
387 ListIterator iter = projList.getIterator();
388 JoinProjFieldInfo *elem;
389 while (iter.hasElement())
391 elem = (JoinProjFieldInfo*) iter.nextElement();
392 if (strcmp(elem->fieldName, fName)==0 &&
393 strcmp(elem->tableName, tName) ==0)
395 return elem->bindBuf;
398 return NULL;
400 bool JoinTableImpl::pushPredicate(Predicate *pr)
402 //printf("PRABA::pushPredicate called\n");
403 PredicateImpl *pImpl = (PredicateImpl*) pr;
404 bool pushed = leftTableHdl->pushPredicate(pr);
405 if (!pushed)
407 pushed = rightTableHdl->pushPredicate(pr);
409 if (!pushed)
411 //printf("PRABA::unable to push the predicate\n");
412 //TODO::check if needs to be placed here
413 char *lTbl = leftTableHdl->getName();
414 char *rTbl = rightTableHdl->getName();
415 char fullName[IDENTIFIER_LENGTH];
416 char lTabName[IDENTIFIER_LENGTH];
417 char rTabName[IDENTIFIER_LENGTH];
418 char lFldName[IDENTIFIER_LENGTH];
419 char rFldName[IDENTIFIER_LENGTH];
420 strcpy(fullName, pImpl->getFldName1());
421 Table::getTableNameAlone(fullName, lTabName);
422 Table::getFieldNameAlone(fullName, lFldName);
423 strcpy(fullName, pImpl->getFldName2());
424 Table::getTableNameAlone(fullName, rTabName);
425 Table::getFieldNameAlone(fullName, rFldName);
427 if (NULL != lTbl && NULL != rTbl)
429 //both size TableImpl handles are there
430 if (0 == strcmp(lTbl, lTabName) || 0 == strcmp(lTbl, rTabName))
432 if (0 == strcmp(rTbl, lTabName) || 0 == strcmp(rTbl, rTabName))
434 //printf("PRABA::pushed join predicate here1\n");
435 //PRABA::START
436 ComparisionOp op = pImpl->getCompOp();
437 if (strcmp(rTbl, rTabName) ==0)
439 //bool ind = rightTableHdl->hasIndex(rFldName);
440 //if (ind) {
441 void *buf = getBindedBuf(lTabName, lFldName);
442 rightTableHdl->addPredicate(rFldName, op, buf);
443 pImpl->setDontEvaluate();
445 }else if (strcmp(rTbl, lTabName) ==0)
447 //bool ind = rightTableHdl->hasIndex(lFldName);
448 //if (ind) {
449 void *buf = getBindedBuf(rTabName, rFldName);
450 rightTableHdl->addPredicate(lFldName, op, buf);
451 pImpl->setDontEvaluate();
454 //PRABA::END
455 setPredicate(pr);
456 pushed = true;
459 }else{
460 if(isTableInvolved(lTabName) && isTableInvolved(rTabName))
462 //printf("PRABA::pushed join predicate here2\n");
463 //PRABA::START
464 ComparisionOp op = pImpl->getCompOp();
465 if (strcmp(rTbl, rTabName) ==0)
467 //bool ind = rightTableHdl->hasIndex(rFldName);
468 //if (ind) {
469 void *buf = getBindedBuf(lTabName, lFldName);
470 rightTableHdl->addPredicate(rFldName, op, buf);
471 pImpl->setDontEvaluate();
473 }else if (strcmp(rTbl, lTabName) ==0)
475 //bool ind = rightTableHdl->hasIndex(lFldName);
476 //if (ind) {
477 void *buf = getBindedBuf(rTabName, rFldName);
478 rightTableHdl->addPredicate(lFldName, op, buf);
479 pImpl->setDontEvaluate();
482 //PRABA::END
483 setPredicate(pr);
484 pushed = true;
488 return pushed;
490 void JoinTableImpl::setPredicate(Predicate *pr)
492 if (NULL == pred) { pred = pr; return; }
493 Predicate *curPred = pred;
494 PredicateImpl *newPred = new PredicateImpl();
495 newPred->setTerm(curPred, OpAnd, pr);
496 newPred->setProjectionList(&projList);
497 pred = newPred;
498 return;