1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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. *
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. *
15 ***************************************************************************/
19 #include<AggTableImpl.h>
20 #include<PredicateImpl.h>
21 static char AggNames
[][20] =
23 "MIN", "MAX", "SUM", "AVG", "COUNT", ""
26 AggTableImpl::AggTableImpl()
36 optGrpIntNoNull
= false;
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
44 ListIterator iter
= fldList
.getIterator();
46 while (iter
.hasElement())
48 elem
= (AggFldDef
*) iter
.nextElement();
49 if(!elem
->alreadyBinded
) free(elem
->bindBuf
);
54 ListIterator giter
= fldGroupList
.getIterator();
55 while (giter
.hasElement())
57 elem
= (AggFldDef
*) giter
.nextElement();
58 if(!elem
->alreadyBinded
) free(elem
->bindBuf
);
62 if (tableHdl
!= NULL
) tableHdl
->close();
66 void *AggTableImpl::getBindFldAddr(const char *name
)
68 printError(ErrBadCall
, "AggTableImpl getBindFldAdddr not implemented\n");
72 DbRetVal
AggTableImpl::bindFld(const char *name
, void *val
, bool dummy
)
74 printError(ErrBadCall
, "AggTableImpl bindFld not implemented\n");
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
;
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();
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;
115 def
->bindBuf
= AllDataType::alloc(def
->type
, def
->length
);
116 rv
= tableHdl
->bindFld(fldname
, def
->bindBuf
);
119 ::free(def
->bindBuf
);
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();
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;
160 if (!groupFld
->bindBuf
)
162 groupFld
->bindBuf
= AllDataType::alloc(groupFld
->type
, groupFld
->length
);
163 rv
= tableHdl
->bindFld(fldname
, groupFld
->bindBuf
);
166 ::free(groupFld
->bindBuf
);
172 fldGroupList
.append(groupFld
);
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;
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
)
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
);
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
,
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();
257 DbRetVal
AggTableImpl::execute()
259 ListIterator iter
= fldList
.getIterator();
261 aggNodeSize
= groupSize
= computeGrpNodeSize();
262 aggNodeMap
.setKeySize(groupSize
);
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
;
281 int groupOffset
= groupSize
;
282 while((tuple
= tableHdl
->fetch()) != NULL
)
284 char *buffer
= (char*)insertOrGetAggNode();
286 offset
= groupOffset
;
287 char *nullInfo
= buffer
+ offset
;
288 prjNullInfo
= *(long long *) nullInfo
;
289 offset
+= sizeof(long long);
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
;
302 bool result
=false; bool isNull
=false;
303 isNull
= isFldNull(colpos
);
308 result
= AllDataType::compareVal(buffer
+offset
,
309 def
->bindBuf
, OpGreaterThanEquals
, def
->type
,
312 if (result
|| isNull
)
313 AllDataType::copyVal(buffer
+offset
, def
->bindBuf
,
314 def
->type
, def
->length
);
319 result
= AllDataType::compareVal(buffer
+offset
,
320 def
->bindBuf
, OpLessThanEquals
, def
->type
,
323 if (result
|| isNull
)
324 AllDataType::copyVal(buffer
+offset
, def
->bindBuf
,
325 def
->type
, def
->length
);
329 AllDataType::addVal(buffer
+offset
, def
->bindBuf
, def
->type
);
334 AllDataType::convertToDouble(&tmpBuf
, def
->bindBuf
,
336 AllDataType::addVal(buffer
+offset
, &tmpBuf
, typeDouble
);
337 (*(int*)(buffer
+offset
+ sizeof(double)))++;
341 (*(int*)(buffer
+offset
))++;
345 copyValuesFromGrpBindBuf(buffer
+offset
, def
->fldName
);
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
;
356 memcpy(nullInfo
, &prjNullInfo
, sizeof(long long));
358 aggNodeIter
= aggNodes
.getIterator();
361 offset
= groupOffset
+sizeof(long long);
362 while (iter
.hasElement()) {
363 def
= (AggFldDef
*) iter
.nextElement();
364 if(def
->aType
== AGG_AVG
) {
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);
374 else if (def
->aType
== AGG_COUNT
) offset
+= sizeof(int);
375 else offset
= offset
+ def
->length
;
378 tableHdl
->closeScan();
382 void* AggTableImpl::getGroupValueBuffer()
384 memset(grpFldBuffer
, 0, groupSize
);
386 char *offset
= (char*)grpFldBuffer
;
387 if (optGrpIntNoNull
) {
388 *(int*)offset
= *(int*)grpBindBuf
;
392 ListIterator giter
= fldGroupList
.getIterator();
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
;
401 memcpy(offset
, &grpNullInfo
, sizeof(int));
404 void* AggTableImpl::insertOrGetAggNode()
407 if (0 == fldGroupList
.size()) {
408 ListIterator aiter
= aggNodes
.getIterator();
409 if (aiter
.hasElement()) return aiter
.nextElement();
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();
420 char *offset
= element
;
422 //offset += sizeof(int);
423 ListIterator giter
= fldGroupList
.getIterator();
425 while(giter
.hasElement())
427 def
= (AggFldDef
*) giter
.nextElement();
428 if(def
->isNullable
&& tableHdl
->isFldNull(def
->fldName
))
431 AllDataType::copyVal(offset
, def
->bindBuf
, def
->type
,def
->length
);
432 offset
= offset
+ def
->length
;
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();
446 AllDataType::copyVal(offset
, def
->bindBuf
, def
->type
,
452 AllDataType::copyZeroVal(offset
, def
->type
, def
->length
);
456 *(double*)(offset
)=0;
457 *(int*)(offset
+ sizeof(double))=0; //count
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
);
472 void* AggTableImpl::fetch()
474 while(aggNodeIter
.hasElement())
476 void *elem
= aggNodeIter
.nextElement();
479 PredicateImpl
*pImpl
= (PredicateImpl
*)havingPred
;
480 pImpl
->evaluateForHaving(result
, this, elem
);
481 if (!result
) continue;
483 copyValuesToBindBuffer(elem
);
489 void* AggTableImpl::fetch(DbRetVal
&rv
)
495 void* AggTableImpl::fetchNoBind()
497 if(aggNodeIter
.hasElement())
499 void *elem
= aggNodeIter
.nextElement();
506 void* AggTableImpl::fetchNoBind(DbRetVal
&rv
)
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();
518 char *colPtr
=element
+groupSize
;
519 prjNullInfo
= *(long long *) colPtr
;
520 colPtr
+= sizeof(long long);
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
;
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);
543 AllDataType::copyVal(def
->appBuf
, colPtr
, def
->type
,
545 colPtr
= colPtr
+ def
->length
;
553 long AggTableImpl::numTuples()
555 return aggNodes
.size();
557 DbRetVal
AggTableImpl::closeScan()
560 ListIterator aiter
= aggNodes
.getIterator();
562 while (aiter
.hasElement()) {
563 element
= (char*)aiter
.nextElement();
567 aggNodeMap
.removeAll();
568 if (tableHdl
) tableHdl
->closeScan();
572 DbRetVal
AggTableImpl::close()
579 bool AggTableImpl::isFldNull(const char *name
)
581 ListIterator it
= fldList
.getIterator();
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;
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
,
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);
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(");
636 } else if (strncmp(name
, "MIN", 3) == 0) {
637 ptr
+= strlen("MIN(");
639 } else if (strncmp(name
, "MAX", 3) == 0) {
640 ptr
+= strlen("MAX(");
642 } else if (strncmp(name
, "SUM", 3) == 0) {
643 ptr
+= strlen("SUM(");
645 } else if (strncmp(name
, "AVG", 3) == 0) {
646 ptr
+= strlen("AVG(");
649 if (atp
== AGG_UNKNOWN
) return atp
;
650 strcpy(fldName
, ptr
);
652 while (*ptr
!= ')') ptr
++;