char size issue fix
[csql.git] / src / storage / AggTableImpl.cxx
blobac00be626f1336d8e23bff81b151eca86f6a4a66
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;
40 AggTableImpl::~AggTableImpl()
42 //free memory allocated. make sure that field buffers are freed only once.
43 //for stmts which has more than one agg on same field needs to be handled safely
44 closeScan();
45 ListIterator iter = fldList.getIterator();
46 AggFldDef *elem;
47 while (iter.hasElement())
49 elem = (AggFldDef*) iter.nextElement();
50 if(!elem->alreadyBinded) free(elem->bindBuf);
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 delete elem;
62 fldGroupList.reset();
63 if (tableHdl != NULL) tableHdl->close();
64 tableHdl = NULL;
65 ::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, bool dummy)
76 printError(ErrBadCall, "AggTableImpl bindFld not implemented\n");
77 return ErrBadCall;
80 DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val)
82 FieldInfo *info = new FieldInfo();
83 DbRetVal rv = tableHdl->getFieldInfo(fldname, info);
84 if (OK != rv) { delete info; return rv; }
85 AggFldDef *def = new AggFldDef();
86 strcpy(def->fldName, fldname);
87 def->type = info->type;
88 def->length= info->length;
89 def->appBuf = val;
90 def->aType=aggType;
91 def->bindBuf = NULL;
92 def->alreadyBinded = false;
94 //if underlying tablehandle is TableImpl, then set isNullable
95 def->isNullable = true;
96 if (info->isNull || info->isPrimary ||
97 info->isDefault || info->isAutoIncrement) {
98 def->isNullable = false;
100 if (NULL == tableHdl->getName()) def->isNullable=true;
102 ListIterator iter = fldList.getIterator();
103 AggFldDef *elem;
104 //If it is already binded, then use the same buffer which is binded.
105 //this code is to handle statements which have more aggregates on same field
106 while (iter.hasElement())
108 elem = (AggFldDef*) iter.nextElement();
109 if (strcmp(elem->fldName, fldname)==0)
111 def->bindBuf = elem->bindBuf;
112 def->alreadyBinded = true;
113 break;
116 if (!def->bindBuf)
118 def->bindBuf = AllDataType::alloc(def->type, def->length);
119 rv = tableHdl->bindFld(fldname, def->bindBuf);
120 if (OK !=rv) {
121 delete info;
122 ::free(def->bindBuf);
123 delete def;
124 return rv;
127 fldList.append(def);
128 delete info;
129 return OK;
132 DbRetVal AggTableImpl::setGroup(const char *fldname, void *val)
134 FieldInfo *info = new FieldInfo();
135 DbRetVal rv = tableHdl->getFieldInfo(fldname, info);
136 if (rv !=OK) { delete info; return rv; }
137 AggFldDef *groupFld=new AggFldDef();
138 strcpy(groupFld->fldName, fldname);
139 groupFld->type = info->type;
140 groupFld->length = info->length;
141 groupFld->appBuf = val;
142 groupFld->bindBuf = NULL;
144 groupFld->isNullable = true;
145 if (info->isNull || info->isPrimary ||
146 info->isDefault || info->isAutoIncrement) {
147 groupFld->isNullable = false;
149 if (NULL == tableHdl->getName()) groupFld->isNullable=true;
151 ListIterator iter = fldList.getIterator();
152 AggFldDef *elem;
154 while (iter.hasElement())
156 elem = (AggFldDef*) iter.nextElement();
157 if (strcmp(elem->fldName, fldname)==0)
159 groupFld->bindBuf = elem->bindBuf;
160 groupFld->alreadyBinded = true;
161 break;
164 if (!groupFld->bindBuf)
166 groupFld->bindBuf = AllDataType::alloc(groupFld->type, groupFld->length);
167 rv = tableHdl->bindFld(fldname, groupFld->bindBuf);
168 if (rv !=OK) {
169 delete info;
170 ::free(groupFld->bindBuf);
171 delete groupFld;
172 return rv;
176 fldGroupList.append(groupFld);
177 delete info;
178 return OK;
181 bool AggTableImpl::isFldPresentInGrp(char *fname)
183 ListIterator iter = fldGroupList.getIterator();
184 AggFldDef *grpFld=NULL;
185 while (iter.hasElement())
187 grpFld=(AggFldDef *)iter.nextElement();
188 if(0==strcmp(fname,grpFld->fldName)) return true;
190 return false;
193 int AggTableImpl::getAggOffset(char *fname, AggType aggType)
195 ListIterator iter = fldList.getIterator();
196 AggFldDef *projDef=NULL;
197 int offset = groupSize + sizeof(prjNullInfo);
198 while (iter.hasElement())
200 projDef=(AggFldDef *)iter.nextElement();
201 if(0==strcmp(fname, projDef->fldName) && aggType == projDef->aType)
203 return offset;
205 else {
206 if (projDef->aType == AGG_AVG)
207 offset = offset + sizeof (double)+ sizeof(int);
208 else if (projDef->aType == AGG_COUNT)
209 offset = offset + sizeof(int);
210 else
211 offset = offset + os::align(projDef->length);
214 printError(ErrSysFatal, "Aggregate condition not found in projection list %s", fname);
215 return offset;
218 int AggTableImpl::computeGrpNodeSize()
220 ListIterator iter = fldGroupList.getIterator();
221 AggFldDef *grpFld=NULL;
222 int totalGrpNodeSize=sizeof(int);
223 while (iter.hasElement())
225 grpFld=(AggFldDef *)iter.nextElement();
226 totalGrpNodeSize=totalGrpNodeSize + os::align(grpFld->length);
228 return totalGrpNodeSize;
231 DbRetVal AggTableImpl::copyValuesFromGrpBindBuf(char *buffer, char *fname)
233 ListIterator iter = fldGroupList.getIterator();
234 AggFldDef *grpFld=NULL;
235 while ((grpFld = (AggFldDef*)iter.nextElement()) != NULL)
237 //grpFld=(AggFldDef *)iter.nextElement();
238 if(0==strcmp(fname,grpFld->fldName))
240 AllDataType::copyVal(buffer, grpFld->bindBuf, grpFld->type,
241 grpFld->length);
242 break;
245 return OK;
248 DbRetVal AggTableImpl::optimize()
250 AggFldDef *grpFld=NULL;
251 optGrpIntNoNull= false;
252 if (groupSize == sizeof(int)+ sizeof(int))
254 ListIterator iter = fldGroupList.getIterator();
255 grpFld = (AggFldDef*)iter.nextElement();
256 if (!grpFld->isNullable && grpFld->type == typeInt)
258 optGrpIntNoNull=true;
259 grpBindBuf = grpFld->bindBuf;
260 aggNodeMap.setGrpIntNoNull();
263 return OK;
266 DbRetVal AggTableImpl::execute()
268 ListIterator iter = fldList.getIterator();
269 AggFldDef *def;
270 aggNodeSize = groupSize = computeGrpNodeSize();
271 aggNodeMap.setKeySize(groupSize);
272 optimize();
274 grpFldBuffer = (char*) ::malloc(groupSize);
275 aggNodeSize += sizeof(long long); // for proj field null Info
276 while (iter.hasElement())
278 def = (AggFldDef*) iter.nextElement();
279 if (def->aType == AGG_AVG) {
280 aggNodeSize += sizeof(double);
281 aggNodeSize += sizeof(int);//for count
283 else if (def->aType == AGG_COUNT) aggNodeSize += sizeof(int);
284 else aggNodeSize += os::align(def->length);
286 void *tuple = NULL;
287 int offset=0;
288 tableHdl->execute();
289 aggNodes.reset();
290 int groupOffset = groupSize;
291 while((tuple = tableHdl->fetch()) != NULL)
293 char *buffer = (char*)insertOrGetAggNode();
294 iter.reset();
295 offset = groupOffset;
296 char *nullInfo = buffer + offset;
297 prjNullInfo = *(long long *) nullInfo;
298 offset += sizeof(long long);
299 int colpos = 1;
300 while ((def = (AggFldDef*)iter.nextElement()) != NULL)
302 //def = (AggFldDef*) iter.nextElement();
303 if (def->isNullable && tableHdl->isFldNull(def->fldName)) {
304 if (def->aType == AGG_AVG)
305 offset = offset + sizeof(double) + sizeof(int);
306 else if (def->aType == AGG_COUNT) offset += sizeof(int);
307 else offset = offset + os::align(def->length);
308 colpos++;
309 continue;
311 bool result=false; bool isNull=false;
312 isNull = isFldNull(colpos);
313 switch(def->aType)
315 case AGG_MIN: {
316 if (!isNull) {
317 result = AllDataType::compareVal(buffer+offset,
318 def->bindBuf, OpGreaterThanEquals, def->type,
319 def->length);
321 if (result || isNull)
322 AllDataType::copyVal(buffer+offset, def->bindBuf,
323 def->type, def->length);
324 break;
326 case AGG_MAX: {
327 if (!isNull) {
328 result = AllDataType::compareVal(buffer+offset,
329 def->bindBuf, OpLessThanEquals, def->type,
330 def->length);
332 if (result || isNull)
333 AllDataType::copyVal(buffer+offset, def->bindBuf,
334 def->type, def->length);
335 break;
337 case AGG_SUM: {
338 AllDataType::addVal(buffer+offset, def->bindBuf, def->type);
339 break;
341 case AGG_AVG: {
342 double tmpBuf=0.0;
343 AllDataType::convertToDouble(&tmpBuf, def->bindBuf,
344 def->type);
345 AllDataType::addVal(buffer+offset, &tmpBuf, typeDouble);
346 (*(int*)(buffer+offset + sizeof(double)))++;
347 break;
349 case AGG_COUNT:
350 (*(int*)(buffer+offset))++;
351 break;
352 case AGG_UNKNOWN:
354 copyValuesFromGrpBindBuf(buffer+offset, def->fldName);
355 break;
358 clearFldNull(colpos);
359 if (def->aType == AGG_AVG)
360 offset = offset + sizeof(double) + sizeof(int);
361 else if (def->aType == AGG_COUNT)
362 offset += sizeof(int);
363 else
364 offset = offset + os::align(def->length);
365 colpos++;
367 memcpy(nullInfo, &prjNullInfo, sizeof(long long));
369 aggNodeIter = aggNodes.getIterator();
370 iter.reset();
371 char *element;
372 offset = groupOffset+sizeof(long long);
373 while (iter.hasElement()) {
374 def = (AggFldDef*) iter.nextElement();
375 if(def->aType == AGG_AVG) {
376 aggNodeIter.reset();
377 while (aggNodeIter.hasElement()) {
378 element = (char*)aggNodeIter.nextElement();
379 AllDataType::divVal((double *) (element+offset),
380 *(int *)(element+offset+ sizeof(double)), typeDouble);
382 offset = offset + sizeof(double) + sizeof(int);
383 continue;
385 else if (def->aType == AGG_COUNT)
386 offset += sizeof(int);
387 else
388 offset = offset + os::align(def->length);
390 aggNodeIter.reset();
391 tableHdl->closeScan();
392 return OK;
395 void* AggTableImpl::getGroupValueBuffer()
397 memset(grpFldBuffer, 0, groupSize);
398 AggFldDef *def;
399 char *offset= (char*)grpFldBuffer;
400 if (optGrpIntNoNull) {
401 *(int*)offset = *(int*)grpBindBuf;
402 return grpFldBuffer;
404 grpNullInfo = 0;
405 ListIterator giter = fldGroupList.getIterator();
406 int colpos = 1;
407 while((def = (AggFldDef*) giter.nextElement()) != NULL)
409 if (def->isNullable && tableHdl->isFldNull(def->fldName)) markFldNull(colpos);
410 else AllDataType::copyVal(offset, def->bindBuf, def->type, def->length);
411 offset = offset + os::align(def->length);
412 colpos++;
414 memcpy(offset, &grpNullInfo, sizeof(int));
415 return grpFldBuffer;
418 void* AggTableImpl::insertOrGetAggNode()
420 char *element;
421 if (0 == fldGroupList.size()) {
422 ListIterator aiter = aggNodes.getIterator();
423 if (aiter.hasElement()) return aiter.nextElement();
424 } else {
425 void *grpBuffer = getGroupValueBuffer();
426 element = (char*) aggNodeMap.find(grpBuffer);
427 if (element) return element;
430 element = (char*)malloc(aggNodeSize);
431 memset(element, 0, aggNodeSize);
432 ListIterator iter = fldList.getIterator();
433 AggFldDef *def;
434 char *offset = element;
435 grpNullInfo = 0;
436 //offset += sizeof(int);
437 ListIterator giter = fldGroupList.getIterator();
438 int colpos = 1;
439 while(giter.hasElement())
441 def = (AggFldDef*) giter.nextElement();
442 if(def->isNullable && tableHdl->isFldNull(def->fldName))
443 markFldNull(colpos);
444 else
445 AllDataType::copyVal(offset, def->bindBuf, def->type,def->length);
446 offset = offset + os::align(def->length);
447 colpos++;
449 memcpy(offset, &grpNullInfo, sizeof(int));
450 offset += sizeof(int);
451 memset(offset, 0xff, sizeof(long long));
452 offset += sizeof(long long);
453 while (iter.hasElement())
455 def = (AggFldDef*) iter.nextElement();
456 switch(def->aType) {
457 case AGG_MIN:
458 case AGG_MAX:
460 AllDataType::copyVal(offset, def->bindBuf, def->type,
461 def->length);
462 break;
464 case AGG_SUM:
466 AllDataType::copyZeroVal(offset, def->type, def->length);
467 break;
469 case AGG_AVG: {
470 *(double*)(offset)=0;
471 *(int*)(offset+ sizeof(double))=0; //count
472 break;
474 case AGG_COUNT: { *(int*)(offset)=0; break; }
476 if (def->aType == AGG_AVG)
477 offset = offset + sizeof(double) + sizeof(int);
478 else if (def->aType == AGG_COUNT)
479 offset += sizeof(int);
480 else
481 offset = offset + os::align(def->length);
483 aggNodes.append(element);
484 aggNodeMap.insert(element);
485 return element;
488 void* AggTableImpl::fetch()
490 while(aggNodeIter.hasElement())
492 void *elem = aggNodeIter.nextElement();
493 bool result=false;
494 if (havingPred) {
495 PredicateImpl *pImpl = (PredicateImpl*)havingPred;
496 pImpl->evaluateForHaving(result , this, elem);
497 if (!result) continue;
499 copyValuesToBindBuffer(elem);
500 return elem;
502 return NULL;
506 void* AggTableImpl::fetch(DbRetVal &rv)
508 rv = OK;
509 return fetch();
512 void* AggTableImpl::fetchNoBind()
514 if(aggNodeIter.hasElement())
516 void *elem = aggNodeIter.nextElement();
517 return elem;
519 else
520 return NULL;
523 void* AggTableImpl::fetchNoBind(DbRetVal &rv)
525 rv = OK;
526 return fetchNoBind();
529 DbRetVal AggTableImpl::copyValuesToBindBuffer(void *elem)
531 char *element = (char*)elem;
532 //Iterate through the bind list and copy the value here
533 ListIterator fIter = fldList.getIterator();
534 AggFldDef *def;
535 char *colPtr=element+groupSize;
536 prjNullInfo = *(long long *) colPtr;
537 colPtr += sizeof(long long);
538 int colpos = 1;
539 while (fIter.hasElement())
541 def = (AggFldDef*) fIter.nextElement();
542 if (isFldNull(colpos)) {
543 if (def->aType == AGG_AVG)
544 colPtr += sizeof(double) + sizeof(int);
545 else if (def->aType == AGG_COUNT)
546 colPtr += sizeof(int);
547 else
548 colPtr += os::align(def->length);
549 colpos++;
550 continue;
552 if (NULL != def->appBuf) {
553 if (def->aType == AGG_AVG) {
554 os::memcpy(def->appBuf, colPtr, sizeof(double));
555 colPtr = colPtr + sizeof(double) + sizeof(int);
557 else if (def->aType == AGG_COUNT) {
558 AllDataType::copyVal(def->appBuf, colPtr, typeInt, sizeof(int));
559 colPtr += sizeof(int);
561 else {
562 AllDataType::copyVal(def->appBuf, colPtr, def->type,
563 def->length);
564 colPtr = colPtr + os::align(def->length);
567 colpos++;
569 return OK;
572 long AggTableImpl::numTuples()
574 return aggNodes.size();
577 DbRetVal AggTableImpl::closeScan()
579 aggNodeIter.reset();
580 ListIterator aiter = aggNodes.getIterator();
581 char *element;
582 while (aiter.hasElement()) {
583 element = (char*)aiter.nextElement();
584 free(element);
586 aggNodes.reset();
587 aggNodeMap.removeAll();
588 if (tableHdl) tableHdl->closeScan();
589 return OK;
592 DbRetVal AggTableImpl::close()
594 havingPred = NULL;
595 delete this;
596 return OK;
599 bool AggTableImpl::isFldNull(const char *name)
601 ListIterator it = fldList.getIterator();
602 int colpos = 1;
603 char fldName[IDENTIFIER_LENGTH];
604 AggType atp = getAggType(name, fldName);
605 while (it.hasElement()) {
606 AggFldDef *def = (AggFldDef *) it.nextElement();
607 if (!def->isNullable) return false;
608 if (atp != AGG_UNKNOWN) {
609 if (strcmp(def->fldName, fldName)==0 && def->aType == atp) break;
611 else if (strcmp(def->fldName, name)==0) break;
612 colpos++;
614 return isFldNull(colpos);
617 void AggTableImpl::printPlan(int space)
619 char spaceBuf[IDENTIFIER_LENGTH];
620 memset(spaceBuf, 32, IDENTIFIER_LENGTH);
621 spaceBuf[space] = '\0';
622 PredicateImpl* predImpl = (PredicateImpl*) havingPred;
623 printf("%s <AGG-NODE>\n", spaceBuf);
624 printf("%s <PROJECTION>\n", spaceBuf);
625 AggFldDef *fldDef=NULL;
626 ListIterator iter = fldList.getIterator();
627 while ((fldDef = (AggFldDef*)iter.nextElement()) != NULL)
629 if (fldDef->aType == AGG_UNKNOWN)
630 printf("%s <FieldName> %s </FieldName>\n", spaceBuf,
631 fldDef->fldName);
632 else
633 printf("%s <FieldName> %s(%s) </FieldName>\n", spaceBuf,
634 AggNames[fldDef->aType -1], fldDef->fldName);
636 printf("%s </PROJECTION>\n", spaceBuf);
637 printf("%s <GROUPING>\n", spaceBuf);
638 ListIterator giter = fldGroupList.getIterator();
639 while ((fldDef = (AggFldDef*)giter.nextElement()) != NULL)
641 printf("%s <FieldName> %s </FieldName>\n", spaceBuf, fldDef->fldName);
643 printf("%s </GROUPING>\n", spaceBuf);
644 if (havingPred) predImpl->print(space);
645 printf("%s </AGG-NODE>\n", spaceBuf);
646 if (tableHdl) tableHdl->printPlan(space+2);
647 return;
650 AggType AggTableImpl::getAggType(const char *name, char *fldName)
652 char *ptr = (char *)name;
653 AggType atp = AGG_UNKNOWN;
654 if (strncmp(name, "COUNT", 5) == 0) {
655 ptr += strlen("COUNT(");
656 atp = AGG_COUNT;
657 } else if (strncmp(name, "MIN", 3) == 0) {
658 ptr += strlen("MIN(");
659 atp = AGG_MIN;
660 } else if (strncmp(name, "MAX", 3) == 0) {
661 ptr += strlen("MAX(");
662 atp = AGG_MAX;
663 } else if (strncmp(name, "SUM", 3) == 0) {
664 ptr += strlen("SUM(");
665 atp = AGG_SUM;
666 } else if (strncmp(name, "AVG", 3) == 0) {
667 ptr += strlen("AVG(");
668 atp = AGG_AVG;
670 if (atp == AGG_UNKNOWN) return atp;
671 strcpy(fldName, ptr);
672 ptr = fldName;
673 while (*ptr != ')') ptr++;
674 *ptr = '\0';
675 return atp;