Update in sync with enterprise version.
[csql.git] / src / storage / AggTableImpl.cxx
blob12e1a9a8e26a7e6b5ea67e627bef4b3e5137e07a
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<AggTableImpl.h>
20 #include<PredicateImpl.h>
21 static char AggNames[][20] =
23 "MIN", "MAX", "SUM", "AVG", "COUNT", ""
26 AggTableImpl::AggTableImpl()
28 tableHdl = NULL;
29 curTuple = NULL;
30 havingPred = NULL;
31 groupSize = 0;
32 aggNodeSize = 0;
33 prjNullInfo = 0;
34 grpNullInfo = 0;
35 grpFldBuffer = NULL;
36 optGrpIntNoNull = false;
37 grpBindBuf = NULL;
39 AggTableImpl::~AggTableImpl()
41 //free memory allocated. make sure that field buffers are freed only once.
42 //for stmts which has more than one agg on same field needs to be handled safely
43 closeScan();
44 ListIterator iter = fldList.getIterator();
45 AggFldDef *elem;
46 while (iter.hasElement())
48 elem = (AggFldDef*) iter.nextElement();
49 if(!elem->alreadyBinded) free(elem->bindBuf);
50 //if(elem->bindBuf) { free(elem->bindBuf); elem->bindBuf =NULL; }
51 delete elem;
53 fldList.reset();
55 ListIterator giter = fldGroupList.getIterator();
56 while (giter.hasElement())
58 elem = (AggFldDef*) giter.nextElement();
59 if(!elem->alreadyBinded) free(elem->bindBuf);
60 //if(elem->bindBuf) { free(elem->bindBuf); elem->bindBuf =NULL; }
61 delete elem;
63 fldGroupList.reset();
64 if (tableHdl != NULL) tableHdl->close();
65 tableHdl = NULL;
66 ::free(grpFldBuffer);
68 void *AggTableImpl::getBindFldAddr(const char *name)
70 printError(ErrBadCall, "AggTableImpl getBindFldAdddr not implemented\n");
71 return NULL;
74 DbRetVal AggTableImpl::bindFld(const char *name, void *val)
76 printError(ErrBadCall, "AggTableImpl bindFld not implemented\n");
77 return ErrBadCall;
79 DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val)
81 FieldInfo *info = new FieldInfo();
82 DbRetVal rv = tableHdl->getFieldInfo(fldname, info);
83 if (OK != rv) { delete info; return rv; }
84 AggFldDef *def = new AggFldDef();
85 strcpy(def->fldName, fldname);
86 def->type = info->type;
87 def->length= info->length;
88 def->appBuf = val;
89 def->aType=aggType;
90 def->bindBuf = NULL;
91 def->alreadyBinded = false;
93 //if underlying tablehandle is TableImpl, then set isNullable
94 def->isNullable = true;
95 if (info->isNull || info->isPrimary ||
96 info->isDefault || info->isAutoIncrement) {
97 def->isNullable = false;
99 if (NULL == tableHdl->getName()) def->isNullable=true;
101 ListIterator iter = fldList.getIterator();
102 AggFldDef *elem;
103 //If it is already binded, then use the same buffer which is binded.
104 //this code is to handle statements which have more aggregates on same field
105 while (iter.hasElement())
107 elem = (AggFldDef*) iter.nextElement();
108 if (strcmp(elem->fldName, fldname)==0)
110 def->bindBuf = elem->bindBuf;
111 def->alreadyBinded = true;
112 break;
115 if (!def->bindBuf)
117 def->bindBuf = AllDataType::alloc(def->type, def->length);
118 rv = tableHdl->bindFld(fldname, def->bindBuf);
119 if (OK !=rv) {
120 delete info;
121 ::free(def->bindBuf);
122 delete def;
123 return rv;
125 def->alreadyBinded = true;
127 fldList.append(def);
128 delete info;
129 return OK;
131 DbRetVal AggTableImpl::setGroup(const char *fldname, void *val)
133 FieldInfo *info = new FieldInfo();
134 DbRetVal rv = tableHdl->getFieldInfo(fldname, info);
135 if (rv !=OK) { delete info; return rv; }
136 AggFldDef *groupFld=new AggFldDef();
137 strcpy(groupFld->fldName, fldname);
138 groupFld->type = info->type;
139 groupFld->length = info->length;
140 groupFld->appBuf = val;
141 groupFld->bindBuf = NULL;
143 groupFld->isNullable = true;
144 if (info->isNull || info->isPrimary ||
145 info->isDefault || info->isAutoIncrement) {
146 groupFld->isNullable = false;
148 if (NULL == tableHdl->getName()) groupFld->isNullable=true;
150 ListIterator iter = fldList.getIterator();
151 AggFldDef *elem;
153 while (iter.hasElement())
155 elem = (AggFldDef*) iter.nextElement();
156 if (strcmp(elem->fldName, fldname)==0)
158 groupFld->bindBuf = elem->bindBuf;
159 groupFld->alreadyBinded = true;
160 break;
163 if (!groupFld->bindBuf)
165 groupFld->bindBuf = AllDataType::alloc(groupFld->type, groupFld->length);
166 rv = tableHdl->bindFld(fldname, groupFld->bindBuf);
167 if (rv !=OK) {
168 delete info;
169 ::free(groupFld->bindBuf);
170 delete groupFld;
171 return rv;
175 fldGroupList.append(groupFld);
176 delete info;
177 return OK;
180 bool AggTableImpl::isFldPresentInGrp(char *fname)
182 ListIterator iter = fldGroupList.getIterator();
183 AggFldDef *grpFld=NULL;
184 while (iter.hasElement())
186 grpFld=(AggFldDef *)iter.nextElement();
187 if(0==strcmp(fname,grpFld->fldName)) return true;
189 return false;
191 int AggTableImpl::getAggOffset(char *fname, AggType aggType)
193 ListIterator iter = fldList.getIterator();
194 AggFldDef *projDef=NULL;
195 int offset = groupSize + sizeof(prjNullInfo);
196 while (iter.hasElement())
198 projDef=(AggFldDef *)iter.nextElement();
199 if(0==strcmp(fname, projDef->fldName) && aggType == projDef->aType)
201 return offset;
203 else {
204 if (projDef->aType == AGG_AVG)
205 offset = offset + sizeof (double)+ sizeof(int);
206 else if (projDef->aType == AGG_COUNT) offset = offset + sizeof(int);
207 else offset = offset + projDef->length;
210 printError(ErrSysFatal, "Aggregate condition not found in projection list %s", fname);
211 return offset;
214 int AggTableImpl::computeGrpNodeSize()
216 ListIterator iter = fldGroupList.getIterator();
217 AggFldDef *grpFld=NULL;
218 int totalGrpNodeSize=sizeof(int);
219 while (iter.hasElement())
221 grpFld=(AggFldDef *)iter.nextElement();
222 totalGrpNodeSize=totalGrpNodeSize + grpFld->length;
224 return totalGrpNodeSize;
227 DbRetVal AggTableImpl::copyValuesFromGrpBindBuf(char *buffer, char *fname)
229 ListIterator iter = fldGroupList.getIterator();
230 AggFldDef *grpFld=NULL;
231 while ((grpFld = (AggFldDef*)iter.nextElement()) != NULL)
233 //grpFld=(AggFldDef *)iter.nextElement();
234 if(0==strcmp(fname,grpFld->fldName))
236 AllDataType::copyVal(buffer, grpFld->bindBuf, grpFld->type,
237 grpFld->length);
238 break;
241 return OK;
243 DbRetVal AggTableImpl::optimize()
245 AggFldDef *grpFld=NULL;
246 optGrpIntNoNull= false;
247 if (groupSize == sizeof(int)+ sizeof(int))
249 ListIterator iter = fldGroupList.getIterator();
250 grpFld = (AggFldDef*)iter.nextElement();
251 if (!grpFld->isNullable && grpFld->type == typeInt)
253 optGrpIntNoNull=true;
254 grpBindBuf = grpFld->bindBuf;
255 aggNodeMap.setGrpIntNoNull();
258 return OK;
260 DbRetVal AggTableImpl::execute()
262 ListIterator iter = fldList.getIterator();
263 AggFldDef *def;
264 aggNodeSize = groupSize = computeGrpNodeSize();
265 aggNodeMap.setKeySize(groupSize);
266 optimize();
268 grpFldBuffer = (char*) ::malloc(groupSize);
269 aggNodeSize += sizeof(long long); // for proj field null Info
270 while (iter.hasElement())
272 def = (AggFldDef*) iter.nextElement();
273 if (def->aType == AGG_AVG) {
274 aggNodeSize += sizeof(double);
275 aggNodeSize += sizeof(int);//for count
277 else if (def->aType == AGG_COUNT) aggNodeSize += sizeof(int);
278 else aggNodeSize += def->length;
280 void *tuple = NULL;
281 int offset=0;
282 tableHdl->execute();
283 aggNodes.reset();
284 int groupOffset = groupSize;
285 while((tuple = tableHdl->fetch()) != NULL)
287 char *buffer = (char*)insertOrGetAggNode();
288 iter.reset();
289 offset = groupOffset;
290 char *nullInfo = buffer + offset;
291 prjNullInfo = *(long long *) nullInfo;
292 offset += sizeof(long long);
293 int colpos = 1;
294 while ((def = (AggFldDef*)iter.nextElement()) != NULL)
296 //def = (AggFldDef*) iter.nextElement();
297 if (def->isNullable && tableHdl->isFldNull(def->fldName)) {
298 if (def->aType == AGG_AVG)
299 offset = offset + sizeof(double) + sizeof(int);
300 else if (def->aType == AGG_COUNT) offset += sizeof(int);
301 else offset = offset + def->length;
302 colpos++;
303 continue;
305 bool result=false; bool isNull=false;
306 isNull = isFldNull(colpos);
307 switch(def->aType)
309 case AGG_MIN: {
310 if (!isNull) {
311 result = AllDataType::compareVal(buffer+offset,
312 def->bindBuf, OpGreaterThanEquals, def->type,
313 def->length);
315 if (result || isNull)
316 AllDataType::copyVal(buffer+offset, def->bindBuf,
317 def->type, def->length);
318 break;
320 case AGG_MAX: {
321 if (!isNull) {
322 result = AllDataType::compareVal(buffer+offset,
323 def->bindBuf, OpLessThanEquals, def->type,
324 def->length);
326 if (result || isNull)
327 AllDataType::copyVal(buffer+offset, def->bindBuf,
328 def->type, def->length);
329 break;
331 case AGG_SUM: {
332 AllDataType::addVal(buffer+offset, def->bindBuf, def->type);
333 break;
335 case AGG_AVG: {
336 double tmpBuf=0.0;
337 AllDataType::convertToDouble(&tmpBuf, def->bindBuf,
338 def->type);
339 AllDataType::addVal(buffer+offset, &tmpBuf, typeDouble);
340 (*(int*)(buffer+offset + sizeof(double)))++;
341 break;
343 case AGG_COUNT:
344 (*(int*)(buffer+offset))++;
345 break;
346 case AGG_UNKNOWN:
348 copyValuesFromGrpBindBuf(buffer+offset, def->fldName);
349 break;
352 clearFldNull(colpos);
353 if (def->aType == AGG_AVG)
354 offset = offset + sizeof(double) + sizeof(int);
355 else if (def->aType == AGG_COUNT) offset += sizeof(int);
356 else offset = offset + def->length;
357 colpos++;
359 memcpy(nullInfo, &prjNullInfo, sizeof(long long));
361 aggNodeIter = aggNodes.getIterator();
362 iter.reset();
363 char *element;
364 offset = groupOffset+sizeof(long long);
365 while (iter.hasElement()) {
366 def = (AggFldDef*) iter.nextElement();
367 if(def->aType == AGG_AVG) {
368 aggNodeIter.reset();
369 while (aggNodeIter.hasElement()) {
370 element = (char*)aggNodeIter.nextElement();
371 AllDataType::divVal((double *) (element+offset),
372 *(int *)(element+offset+ sizeof(double)), typeDouble);
374 offset = offset + sizeof(double) + sizeof(int);
375 continue;
377 else if (def->aType == AGG_COUNT) offset += sizeof(int);
378 else offset = offset + def->length;
380 aggNodeIter.reset();
381 tableHdl->closeScan();
382 return OK;
385 void* AggTableImpl::getGroupValueBuffer()
387 memset(grpFldBuffer, 0, groupSize);
388 AggFldDef *def;
389 char *offset= (char*)grpFldBuffer;
390 if (optGrpIntNoNull) {
391 *(int*)offset = *(int*)grpBindBuf;
392 return grpFldBuffer;
394 grpNullInfo = 0;
395 ListIterator giter = fldGroupList.getIterator();
396 int colpos = 1;
397 while((def = (AggFldDef*) giter.nextElement()) != NULL)
399 if (def->isNullable && tableHdl->isFldNull(def->fldName)) markFldNull(colpos);
400 else AllDataType::copyVal(offset, def->bindBuf, def->type, def->length);
401 offset = offset + def->length;
402 colpos++;
404 memcpy(offset, &grpNullInfo, sizeof(int));
405 return grpFldBuffer;
407 void* AggTableImpl::insertOrGetAggNode()
409 char *element;
410 if (0 == fldGroupList.size()) {
411 ListIterator aiter = aggNodes.getIterator();
412 if (aiter.hasElement()) return aiter.nextElement();
413 } else {
414 void *grpBuffer = getGroupValueBuffer();
415 element = (char*) aggNodeMap.find(grpBuffer);
416 if (element) return element;
419 element = (char*)malloc(aggNodeSize);
420 memset(element, 0, aggNodeSize);
421 ListIterator iter = fldList.getIterator();
422 AggFldDef *def;
423 char *offset = element;
424 grpNullInfo = 0;
425 //offset += sizeof(int);
426 ListIterator giter = fldGroupList.getIterator();
427 int colpos = 1;
428 while(giter.hasElement())
430 def = (AggFldDef*) giter.nextElement();
431 if(def->isNullable && tableHdl->isFldNull(def->fldName))
432 markFldNull(colpos);
433 else
434 AllDataType::copyVal(offset, def->bindBuf, def->type,def->length);
435 offset = offset + def->length;
436 colpos++;
438 memcpy(offset, &grpNullInfo, sizeof(int));
439 offset += sizeof(int);
440 memset(offset, 0xff, sizeof(long long));
441 offset += sizeof(long long);
442 while (iter.hasElement())
444 def = (AggFldDef*) iter.nextElement();
445 switch(def->aType) {
446 case AGG_MIN:
447 case AGG_MAX:
449 AllDataType::copyVal(offset, def->bindBuf, def->type,
450 def->length);
451 break;
453 case AGG_SUM:
455 AllDataType::copyZeroVal(offset, def->type, def->length);
456 break;
458 case AGG_AVG: {
459 *(double*)(offset)=0;
460 *(int*)(offset+ sizeof(double))=0; //count
461 break;
463 case AGG_COUNT: { *(int*)(offset)=0; break; }
465 if (def->aType == AGG_AVG)
466 offset = offset + sizeof(double) + sizeof(int);
467 else if (def->aType == AGG_COUNT) offset += sizeof(int);
468 else offset = offset + def->length;
470 aggNodes.append(element);
471 aggNodeMap.insert(element);
472 return element;
475 void* AggTableImpl::fetch()
477 while(aggNodeIter.hasElement())
479 void *elem = aggNodeIter.nextElement();
480 bool result=false;
481 if (havingPred) {
482 PredicateImpl *pImpl = (PredicateImpl*)havingPred;
483 pImpl->evaluateForHaving(result , this, elem);
484 if (!result) continue;
486 copyValuesToBindBuffer(elem);
487 return elem;
489 return NULL;
492 void* AggTableImpl::fetch(DbRetVal &rv)
494 rv = OK;
495 return fetch();
498 void* AggTableImpl::fetchNoBind()
500 if(aggNodeIter.hasElement())
502 void *elem = aggNodeIter.nextElement();
503 return elem;
505 else
506 return NULL;
509 void* AggTableImpl::fetchNoBind(DbRetVal &rv)
511 rv = OK;
512 return fetchNoBind();
515 DbRetVal AggTableImpl::copyValuesToBindBuffer(void *elem)
517 char *element = (char*)elem;
518 //Iterate through the bind list and copy the value here
519 ListIterator fIter = fldList.getIterator();
520 AggFldDef *def;
521 char *colPtr=element+groupSize;
522 prjNullInfo = *(long long *) colPtr;
523 colPtr += sizeof(long long);
524 int colpos = 1;
525 while (fIter.hasElement())
527 def = (AggFldDef*) fIter.nextElement();
528 if (isFldNull(colpos)) {
529 if (def->aType == AGG_AVG)
530 colPtr += sizeof(double) + sizeof(int);
531 else if (def->aType == AGG_COUNT) colPtr += sizeof(int);
532 else colPtr += def->length;
533 colpos++;
534 continue;
536 if (NULL != def->appBuf) {
537 if (def->aType == AGG_AVG) {
538 os::memcpy(def->appBuf, colPtr, sizeof(double));
539 colPtr = colPtr + sizeof(double) + sizeof(int);
541 else if (def->aType == AGG_COUNT) {
542 AllDataType::copyVal(def->appBuf, colPtr, typeInt, sizeof(int));
543 colPtr += sizeof(int);
545 else {
546 AllDataType::copyVal(def->appBuf, colPtr, def->type,
547 def->length);
548 colPtr = colPtr + def->length;
551 colpos++;
553 return OK;
556 long AggTableImpl::numTuples()
558 return aggNodes.size();
560 DbRetVal AggTableImpl::closeScan()
562 aggNodeIter.reset();
563 ListIterator aiter = aggNodes.getIterator();
564 char *element;
565 while (aiter.hasElement()) {
566 element = (char*)aiter.nextElement();
567 free(element);
569 aggNodes.reset();
570 aggNodeMap.removeAll();
571 if (tableHdl) tableHdl->closeScan();
572 return OK;
575 DbRetVal AggTableImpl::close()
577 havingPred = NULL;
578 delete this;
579 return OK;
582 bool AggTableImpl::isFldNull(const char *name)
584 ListIterator it = fldList.getIterator();
585 int colpos = 1;
586 char fldName[IDENTIFIER_LENGTH];
587 AggType atp = getAggType(name, fldName);
588 while (it.hasElement()) {
589 AggFldDef *def = (AggFldDef *) it.nextElement();
590 if (!def->isNullable) return false;
591 if (atp != AGG_UNKNOWN) {
592 if (strcmp(def->fldName, fldName)==0 && def->aType == atp) break;
594 else if (strcmp(def->fldName, name)==0) break;
595 colpos++;
597 return isFldNull(colpos);
599 void AggTableImpl::printPlan(int space)
601 char spaceBuf[IDENTIFIER_LENGTH];
602 memset(spaceBuf, 32, IDENTIFIER_LENGTH);
603 spaceBuf[space] = '\0';
604 PredicateImpl* predImpl = (PredicateImpl*) havingPred;
605 printf("%s <AGG-NODE>\n", spaceBuf);
606 printf("%s <PROJECTION>\n", spaceBuf);
607 AggFldDef *fldDef=NULL;
608 ListIterator iter = fldList.getIterator();
609 while ((fldDef = (AggFldDef*)iter.nextElement()) != NULL)
611 if (fldDef->aType == AGG_UNKNOWN)
612 printf("%s <FieldName> %s </FieldName>\n", spaceBuf,
613 fldDef->fldName);
614 else
615 printf("%s <FieldName> %s(%s) </FieldName>\n", spaceBuf,
616 AggNames[fldDef->aType -1], fldDef->fldName);
618 printf("%s </PROJECTION>\n", spaceBuf);
619 printf("%s <GROUPING>\n", spaceBuf);
620 ListIterator giter = fldGroupList.getIterator();
621 while ((fldDef = (AggFldDef*)giter.nextElement()) != NULL)
623 printf("%s <FieldName> %s </FieldName>\n", spaceBuf, fldDef->fldName);
625 printf("%s </GROUPING>\n", spaceBuf);
626 if (havingPred) predImpl->print(space);
627 printf("%s </AGG-NODE>\n", spaceBuf);
628 if (tableHdl) tableHdl->printPlan(space+2);
629 return;
632 AggType AggTableImpl::getAggType(const char *name, char *fldName)
634 char *ptr = (char *)name;
635 AggType atp = AGG_UNKNOWN;
636 if (strncmp(name, "COUNT", 5) == 0) {
637 ptr += strlen("COUNT(");
638 atp = AGG_COUNT;
639 } else if (strncmp(name, "MIN", 3) == 0) {
640 ptr += strlen("MIN(");
641 atp = AGG_MIN;
642 } else if (strncmp(name, "MAX", 3) == 0) {
643 ptr += strlen("MAX(");
644 atp = AGG_MAX;
645 } else if (strncmp(name, "SUM", 3) == 0) {
646 ptr += strlen("SUM(");
647 atp = AGG_SUM;
648 } else if (strncmp(name, "AVG", 3) == 0) {
649 ptr += strlen("AVG(");
650 atp = AGG_AVG;
652 if (atp == AGG_UNKNOWN) return atp;
653 strcpy(fldName, ptr);
654 ptr = fldName;
655 while (*ptr != ')') ptr++;
656 *ptr = '\0';
657 return atp;