*** empty log message ***
[csql.git] / src / storage / AggTableImpl.cxx
blobef063489f5c7dbe8557cca6b1451509759dceaab
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 delete elem;
52 fldList.reset();
54 ListIterator giter = fldGroupList.getIterator();
55 while (giter.hasElement())
57 elem = (AggFldDef*) giter.nextElement();
58 if(!elem->alreadyBinded) free(elem->bindBuf);
59 delete elem;
61 fldGroupList.reset();
62 if (tableHdl != NULL) tableHdl->close();
63 tableHdl = NULL;
64 ::free(grpFldBuffer);
66 void *AggTableImpl::getBindFldAddr(const char *name)
68 printError(ErrBadCall, "AggTableImpl getBindFldAdddr not implemented\n");
69 return NULL;
72 DbRetVal AggTableImpl::bindFld(const char *name, void *val, bool dummy)
74 printError(ErrBadCall, "AggTableImpl bindFld not implemented\n");
75 return ErrBadCall;
77 DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val)
79 FieldInfo *info = new FieldInfo();
80 DbRetVal rv = tableHdl->getFieldInfo(fldname, info);
81 if (OK != rv) { delete info; return rv; }
82 AggFldDef *def = new AggFldDef();
83 strcpy(def->fldName, fldname);
84 def->type = info->type;
85 def->length= info->length;
86 def->appBuf = val;
87 def->aType=aggType;
88 def->bindBuf = NULL;
89 def->alreadyBinded = false;
91 //if underlying tablehandle is TableImpl, then set isNullable
92 def->isNullable = true;
93 if (info->isNull || info->isPrimary ||
94 info->isDefault || info->isAutoIncrement) {
95 def->isNullable = false;
97 if (NULL == tableHdl->getName()) def->isNullable=true;
99 ListIterator iter = fldList.getIterator();
100 AggFldDef *elem;
101 //If it is already binded, then use the same buffer which is binded.
102 //this code is to handle statements which have more aggregates on same field
103 while (iter.hasElement())
105 elem = (AggFldDef*) iter.nextElement();
106 if (strcmp(elem->fldName, fldname)==0)
108 def->bindBuf = elem->bindBuf;
109 def->alreadyBinded = true;
110 break;
113 if (!def->bindBuf)
115 def->bindBuf = AllDataType::alloc(def->type, def->length);
116 rv = tableHdl->bindFld(fldname, def->bindBuf);
117 if (OK !=rv) {
118 delete info;
119 ::free(def->bindBuf);
120 delete def;
121 return rv;
124 fldList.append(def);
125 delete info;
126 return OK;
128 DbRetVal AggTableImpl::setGroup(const char *fldname, void *val)
130 FieldInfo *info = new FieldInfo();
131 DbRetVal rv = tableHdl->getFieldInfo(fldname, info);
132 if (rv !=OK) { delete info; return rv; }
133 AggFldDef *groupFld=new AggFldDef();
134 strcpy(groupFld->fldName, fldname);
135 groupFld->type = info->type;
136 groupFld->length = info->length;
137 groupFld->appBuf = val;
138 groupFld->bindBuf = NULL;
140 groupFld->isNullable = true;
141 if (info->isNull || info->isPrimary ||
142 info->isDefault || info->isAutoIncrement) {
143 groupFld->isNullable = false;
145 if (NULL == tableHdl->getName()) groupFld->isNullable=true;
147 ListIterator iter = fldList.getIterator();
148 AggFldDef *elem;
150 while (iter.hasElement())
152 elem = (AggFldDef*) iter.nextElement();
153 if (strcmp(elem->fldName, fldname)==0)
155 groupFld->bindBuf = elem->bindBuf;
156 groupFld->alreadyBinded = true;
157 break;
160 if (!groupFld->bindBuf)
162 groupFld->bindBuf = AllDataType::alloc(groupFld->type, groupFld->length);
163 rv = tableHdl->bindFld(fldname, groupFld->bindBuf);
164 if (rv !=OK) {
165 delete info;
166 ::free(groupFld->bindBuf);
167 delete groupFld;
168 return rv;
172 fldGroupList.append(groupFld);
173 delete info;
174 return OK;
177 bool AggTableImpl::isFldPresentInGrp(char *fname)
179 ListIterator iter = fldGroupList.getIterator();
180 AggFldDef *grpFld=NULL;
181 while (iter.hasElement())
183 grpFld=(AggFldDef *)iter.nextElement();
184 if(0==strcmp(fname,grpFld->fldName)) return true;
186 return false;
188 int AggTableImpl::getAggOffset(char *fname, AggType aggType)
190 ListIterator iter = fldList.getIterator();
191 AggFldDef *projDef=NULL;
192 int offset = groupSize + sizeof(prjNullInfo);
193 while (iter.hasElement())
195 projDef=(AggFldDef *)iter.nextElement();
196 if(0==strcmp(fname, projDef->fldName) && aggType == projDef->aType)
198 return offset;
200 else {
201 if (projDef->aType == AGG_AVG)
202 offset = offset + sizeof (double)+ sizeof(int);
203 else if (projDef->aType == AGG_COUNT) offset = offset + sizeof(int);
204 else offset = offset + projDef->length;
207 printError(ErrSysFatal, "Aggregate condition not found in projection list %s", fname);
208 return offset;
211 int AggTableImpl::computeGrpNodeSize()
213 ListIterator iter = fldGroupList.getIterator();
214 AggFldDef *grpFld=NULL;
215 int totalGrpNodeSize=sizeof(int);
216 while (iter.hasElement())
218 grpFld=(AggFldDef *)iter.nextElement();
219 totalGrpNodeSize=totalGrpNodeSize + grpFld->length;
221 return totalGrpNodeSize;
224 DbRetVal AggTableImpl::copyValuesFromGrpBindBuf(char *buffer, char *fname)
226 ListIterator iter = fldGroupList.getIterator();
227 AggFldDef *grpFld=NULL;
228 while ((grpFld = (AggFldDef*)iter.nextElement()) != NULL)
230 //grpFld=(AggFldDef *)iter.nextElement();
231 if(0==strcmp(fname,grpFld->fldName))
233 AllDataType::copyVal(buffer, grpFld->bindBuf, grpFld->type,
234 grpFld->length);
235 break;
238 return OK;
240 DbRetVal AggTableImpl::optimize()
242 AggFldDef *grpFld=NULL;
243 optGrpIntNoNull= false;
244 if (groupSize == sizeof(int)+ sizeof(int))
246 ListIterator iter = fldGroupList.getIterator();
247 grpFld = (AggFldDef*)iter.nextElement();
248 if (!grpFld->isNullable && grpFld->type == typeInt)
250 optGrpIntNoNull=true;
251 grpBindBuf = grpFld->bindBuf;
252 aggNodeMap.setGrpIntNoNull();
255 return OK;
257 DbRetVal AggTableImpl::execute()
259 ListIterator iter = fldList.getIterator();
260 AggFldDef *def;
261 aggNodeSize = groupSize = computeGrpNodeSize();
262 aggNodeMap.setKeySize(groupSize);
263 optimize();
265 grpFldBuffer = (char*) ::malloc(groupSize);
266 aggNodeSize += sizeof(long long); // for proj field null Info
267 while (iter.hasElement())
269 def = (AggFldDef*) iter.nextElement();
270 if (def->aType == AGG_AVG) {
271 aggNodeSize += sizeof(double);
272 aggNodeSize += sizeof(int);//for count
274 else if (def->aType == AGG_COUNT) aggNodeSize += sizeof(int);
275 else aggNodeSize += def->length;
277 void *tuple = NULL;
278 int offset=0;
279 tableHdl->execute();
280 aggNodes.reset();
281 int groupOffset = groupSize;
282 while((tuple = tableHdl->fetch()) != NULL)
284 char *buffer = (char*)insertOrGetAggNode();
285 iter.reset();
286 offset = groupOffset;
287 char *nullInfo = buffer + offset;
288 prjNullInfo = *(long long *) nullInfo;
289 offset += sizeof(long long);
290 int colpos = 1;
291 while ((def = (AggFldDef*)iter.nextElement()) != NULL)
293 //def = (AggFldDef*) iter.nextElement();
294 if (def->isNullable && tableHdl->isFldNull(def->fldName)) {
295 if (def->aType == AGG_AVG)
296 offset = offset + sizeof(double) + sizeof(int);
297 else if (def->aType == AGG_COUNT) offset += sizeof(int);
298 else offset = offset + def->length;
299 colpos++;
300 continue;
302 bool result=false; bool isNull=false;
303 isNull = isFldNull(colpos);
304 switch(def->aType)
306 case AGG_MIN: {
307 if (!isNull) {
308 result = AllDataType::compareVal(buffer+offset,
309 def->bindBuf, OpGreaterThanEquals, def->type,
310 def->length);
312 if (result || isNull)
313 AllDataType::copyVal(buffer+offset, def->bindBuf,
314 def->type, def->length);
315 break;
317 case AGG_MAX: {
318 if (!isNull) {
319 result = AllDataType::compareVal(buffer+offset,
320 def->bindBuf, OpLessThanEquals, def->type,
321 def->length);
323 if (result || isNull)
324 AllDataType::copyVal(buffer+offset, def->bindBuf,
325 def->type, def->length);
326 break;
328 case AGG_SUM: {
329 AllDataType::addVal(buffer+offset, def->bindBuf, def->type);
330 break;
332 case AGG_AVG: {
333 double tmpBuf=0.0;
334 AllDataType::convertToDouble(&tmpBuf, def->bindBuf,
335 def->type);
336 AllDataType::addVal(buffer+offset, &tmpBuf, typeDouble);
337 (*(int*)(buffer+offset + sizeof(double)))++;
338 break;
340 case AGG_COUNT:
341 (*(int*)(buffer+offset))++;
342 break;
343 case AGG_UNKNOWN:
345 copyValuesFromGrpBindBuf(buffer+offset, def->fldName);
346 break;
349 clearFldNull(colpos);
350 if (def->aType == AGG_AVG)
351 offset = offset + sizeof(double) + sizeof(int);
352 else if (def->aType == AGG_COUNT) offset += sizeof(int);
353 else offset = offset + def->length;
354 colpos++;
356 memcpy(nullInfo, &prjNullInfo, sizeof(long long));
358 aggNodeIter = aggNodes.getIterator();
359 iter.reset();
360 char *element;
361 offset = groupOffset+sizeof(long long);
362 while (iter.hasElement()) {
363 def = (AggFldDef*) iter.nextElement();
364 if(def->aType == AGG_AVG) {
365 aggNodeIter.reset();
366 while (aggNodeIter.hasElement()) {
367 element = (char*)aggNodeIter.nextElement();
368 AllDataType::divVal((double *) (element+offset),
369 *(int *)(element+offset+ sizeof(double)), typeDouble);
371 offset = offset + sizeof(double) + sizeof(int);
372 continue;
374 else if (def->aType == AGG_COUNT) offset += sizeof(int);
375 else offset = offset + def->length;
377 aggNodeIter.reset();
378 tableHdl->closeScan();
379 return OK;
382 void* AggTableImpl::getGroupValueBuffer()
384 memset(grpFldBuffer, 0, groupSize);
385 AggFldDef *def;
386 char *offset= (char*)grpFldBuffer;
387 if (optGrpIntNoNull) {
388 *(int*)offset = *(int*)grpBindBuf;
389 return grpFldBuffer;
391 grpNullInfo = 0;
392 ListIterator giter = fldGroupList.getIterator();
393 int colpos = 1;
394 while((def = (AggFldDef*) giter.nextElement()) != NULL)
396 if (def->isNullable && tableHdl->isFldNull(def->fldName)) markFldNull(colpos);
397 else AllDataType::copyVal(offset, def->bindBuf, def->type, def->length);
398 offset = offset + def->length;
399 colpos++;
401 memcpy(offset, &grpNullInfo, sizeof(int));
402 return grpFldBuffer;
404 void* AggTableImpl::insertOrGetAggNode()
406 char *element;
407 if (0 == fldGroupList.size()) {
408 ListIterator aiter = aggNodes.getIterator();
409 if (aiter.hasElement()) return aiter.nextElement();
410 } else {
411 void *grpBuffer = getGroupValueBuffer();
412 element = (char*) aggNodeMap.find(grpBuffer);
413 if (element) return element;
416 element = (char*)malloc(aggNodeSize);
417 memset(element, 0, aggNodeSize);
418 ListIterator iter = fldList.getIterator();
419 AggFldDef *def;
420 char *offset = element;
421 grpNullInfo = 0;
422 //offset += sizeof(int);
423 ListIterator giter = fldGroupList.getIterator();
424 int colpos = 1;
425 while(giter.hasElement())
427 def = (AggFldDef*) giter.nextElement();
428 if(def->isNullable && tableHdl->isFldNull(def->fldName))
429 markFldNull(colpos);
430 else
431 AllDataType::copyVal(offset, def->bindBuf, def->type,def->length);
432 offset = offset + def->length;
433 colpos++;
435 memcpy(offset, &grpNullInfo, sizeof(int));
436 offset += sizeof(int);
437 memset(offset, 0xff, sizeof(long long));
438 offset += sizeof(long long);
439 while (iter.hasElement())
441 def = (AggFldDef*) iter.nextElement();
442 switch(def->aType) {
443 case AGG_MIN:
444 case AGG_MAX:
446 AllDataType::copyVal(offset, def->bindBuf, def->type,
447 def->length);
448 break;
450 case AGG_SUM:
452 AllDataType::copyZeroVal(offset, def->type, def->length);
453 break;
455 case AGG_AVG: {
456 *(double*)(offset)=0;
457 *(int*)(offset+ sizeof(double))=0; //count
458 break;
460 case AGG_COUNT: { *(int*)(offset)=0; break; }
462 if (def->aType == AGG_AVG)
463 offset = offset + sizeof(double) + sizeof(int);
464 else if (def->aType == AGG_COUNT) offset += sizeof(int);
465 else offset = offset + def->length;
467 aggNodes.append(element);
468 aggNodeMap.insert(element);
469 return element;
472 void* AggTableImpl::fetch()
474 while(aggNodeIter.hasElement())
476 void *elem = aggNodeIter.nextElement();
477 bool result=false;
478 if (havingPred) {
479 PredicateImpl *pImpl = (PredicateImpl*)havingPred;
480 pImpl->evaluateForHaving(result , this, elem);
481 if (!result) continue;
483 copyValuesToBindBuffer(elem);
484 return elem;
486 return NULL;
489 void* AggTableImpl::fetch(DbRetVal &rv)
491 rv = OK;
492 return fetch();
495 void* AggTableImpl::fetchNoBind()
497 if(aggNodeIter.hasElement())
499 void *elem = aggNodeIter.nextElement();
500 return elem;
502 else
503 return NULL;
506 void* AggTableImpl::fetchNoBind(DbRetVal &rv)
508 rv = OK;
509 return fetchNoBind();
512 DbRetVal AggTableImpl::copyValuesToBindBuffer(void *elem)
514 char *element = (char*)elem;
515 //Iterate through the bind list and copy the value here
516 ListIterator fIter = fldList.getIterator();
517 AggFldDef *def;
518 char *colPtr=element+groupSize;
519 prjNullInfo = *(long long *) colPtr;
520 colPtr += sizeof(long long);
521 int colpos = 1;
522 while (fIter.hasElement())
524 def = (AggFldDef*) fIter.nextElement();
525 if (isFldNull(colpos)) {
526 if (def->aType == AGG_AVG)
527 colPtr += sizeof(double) + sizeof(int);
528 else if (def->aType == AGG_COUNT) colPtr += sizeof(int);
529 else colPtr += def->length;
530 colpos++;
531 continue;
533 if (NULL != def->appBuf) {
534 if (def->aType == AGG_AVG) {
535 os::memcpy(def->appBuf, colPtr, sizeof(double));
536 colPtr = colPtr + sizeof(double) + sizeof(int);
538 else if (def->aType == AGG_COUNT) {
539 AllDataType::copyVal(def->appBuf, colPtr, typeInt, sizeof(int));
540 colPtr += sizeof(int);
542 else {
543 AllDataType::copyVal(def->appBuf, colPtr, def->type,
544 def->length);
545 colPtr = colPtr + def->length;
548 colpos++;
550 return OK;
553 long AggTableImpl::numTuples()
555 return aggNodes.size();
557 DbRetVal AggTableImpl::closeScan()
559 aggNodeIter.reset();
560 ListIterator aiter = aggNodes.getIterator();
561 char *element;
562 while (aiter.hasElement()) {
563 element = (char*)aiter.nextElement();
564 free(element);
566 aggNodes.reset();
567 aggNodeMap.removeAll();
568 if (tableHdl) tableHdl->closeScan();
569 return OK;
572 DbRetVal AggTableImpl::close()
574 havingPred = NULL;
575 delete this;
576 return OK;
579 bool AggTableImpl::isFldNull(const char *name)
581 ListIterator it = fldList.getIterator();
582 int colpos = 1;
583 char fldName[IDENTIFIER_LENGTH];
584 AggType atp = getAggType(name, fldName);
585 while (it.hasElement()) {
586 AggFldDef *def = (AggFldDef *) it.nextElement();
587 if (!def->isNullable) return false;
588 if (atp != AGG_UNKNOWN) {
589 if (strcmp(def->fldName, fldName)==0 && def->aType == atp) break;
591 else if (strcmp(def->fldName, name)==0) break;
592 colpos++;
594 return isFldNull(colpos);
596 void AggTableImpl::printPlan(int space)
598 char spaceBuf[IDENTIFIER_LENGTH];
599 memset(spaceBuf, 32, IDENTIFIER_LENGTH);
600 spaceBuf[space] = '\0';
601 PredicateImpl* predImpl = (PredicateImpl*) havingPred;
602 printf("%s <AGG-NODE>\n", spaceBuf);
603 printf("%s <PROJECTION>\n", spaceBuf);
604 AggFldDef *fldDef=NULL;
605 ListIterator iter = fldList.getIterator();
606 while ((fldDef = (AggFldDef*)iter.nextElement()) != NULL)
608 if (fldDef->aType == AGG_UNKNOWN)
609 printf("%s <FieldName> %s </FieldName>\n", spaceBuf,
610 fldDef->fldName);
611 else
612 printf("%s <FieldName> %s(%s) </FieldName>\n", spaceBuf,
613 AggNames[fldDef->aType -1], fldDef->fldName);
615 printf("%s </PROJECTION>\n", spaceBuf);
616 printf("%s <GROUPING>\n", spaceBuf);
617 ListIterator giter = fldGroupList.getIterator();
618 while ((fldDef = (AggFldDef*)giter.nextElement()) != NULL)
620 printf("%s <FieldName> %s </FieldName>\n", spaceBuf, fldDef->fldName);
622 printf("%s </GROUPING>\n", spaceBuf);
623 if (havingPred) predImpl->print(space);
624 printf("%s </AGG-NODE>\n", spaceBuf);
625 if (tableHdl) tableHdl->printPlan(space+2);
626 return;
629 AggType AggTableImpl::getAggType(const char *name, char *fldName)
631 char *ptr = (char *)name;
632 AggType atp = AGG_UNKNOWN;
633 if (strncmp(name, "COUNT", 5) == 0) {
634 ptr += strlen("COUNT(");
635 atp = AGG_COUNT;
636 } else if (strncmp(name, "MIN", 3) == 0) {
637 ptr += strlen("MIN(");
638 atp = AGG_MIN;
639 } else if (strncmp(name, "MAX", 3) == 0) {
640 ptr += strlen("MAX(");
641 atp = AGG_MAX;
642 } else if (strncmp(name, "SUM", 3) == 0) {
643 ptr += strlen("SUM(");
644 atp = AGG_SUM;
645 } else if (strncmp(name, "AVG", 3) == 0) {
646 ptr += strlen("AVG(");
647 atp = AGG_AVG;
649 if (atp == AGG_UNKNOWN) return atp;
650 strcpy(fldName, ptr);
651 ptr = fldName;
652 while (*ptr != ')') ptr++;
653 *ptr = '\0';
654 return atp;