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;
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
45 ListIterator iter
= fldList
.getIterator();
47 while (iter
.hasElement())
49 elem
= (AggFldDef
*) iter
.nextElement();
50 if(!elem
->alreadyBinded
) free(elem
->bindBuf
);
55 ListIterator giter
= fldGroupList
.getIterator();
56 while (giter
.hasElement())
58 elem
= (AggFldDef
*) giter
.nextElement();
59 if(!elem
->alreadyBinded
) free(elem
->bindBuf
);
63 if (tableHdl
!= NULL
) tableHdl
->close();
68 void *AggTableImpl::getBindFldAddr(const char *name
)
70 printError(ErrBadCall
, "AggTableImpl getBindFldAdddr not implemented\n");
74 DbRetVal
AggTableImpl::bindFld(const char *name
, void *val
, bool dummy
)
76 printError(ErrBadCall
, "AggTableImpl bindFld not implemented\n");
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
;
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();
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;
118 def
->bindBuf
= AllDataType::alloc(def
->type
, def
->length
);
119 rv
= tableHdl
->bindFld(fldname
, def
->bindBuf
);
122 ::free(def
->bindBuf
);
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();
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;
164 if (!groupFld
->bindBuf
)
166 groupFld
->bindBuf
= AllDataType::alloc(groupFld
->type
, groupFld
->length
);
167 rv
= tableHdl
->bindFld(fldname
, groupFld
->bindBuf
);
170 ::free(groupFld
->bindBuf
);
176 fldGroupList
.append(groupFld
);
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;
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
)
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);
211 offset
= offset
+ os::align(projDef
->length
);
214 printError(ErrSysFatal
, "Aggregate condition not found in projection list %s", fname
);
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
,
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();
266 DbRetVal
AggTableImpl::execute()
268 ListIterator iter
= fldList
.getIterator();
270 aggNodeSize
= groupSize
= computeGrpNodeSize();
271 aggNodeMap
.setKeySize(groupSize
);
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
);
290 int groupOffset
= groupSize
;
291 while((tuple
= tableHdl
->fetch()) != NULL
)
293 char *buffer
= (char*)insertOrGetAggNode();
295 offset
= groupOffset
;
296 char *nullInfo
= buffer
+ offset
;
297 prjNullInfo
= *(long long *) nullInfo
;
298 offset
+= sizeof(long long);
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
);
311 bool result
=false; bool isNull
=false;
312 isNull
= isFldNull(colpos
);
317 result
= AllDataType::compareVal(buffer
+offset
,
318 def
->bindBuf
, OpGreaterThanEquals
, def
->type
,
321 if (result
|| isNull
)
322 AllDataType::copyVal(buffer
+offset
, def
->bindBuf
,
323 def
->type
, def
->length
);
328 result
= AllDataType::compareVal(buffer
+offset
,
329 def
->bindBuf
, OpLessThanEquals
, def
->type
,
332 if (result
|| isNull
)
333 AllDataType::copyVal(buffer
+offset
, def
->bindBuf
,
334 def
->type
, def
->length
);
338 AllDataType::addVal(buffer
+offset
, def
->bindBuf
, def
->type
);
343 AllDataType::convertToDouble(&tmpBuf
, def
->bindBuf
,
345 AllDataType::addVal(buffer
+offset
, &tmpBuf
, typeDouble
);
346 (*(int*)(buffer
+offset
+ sizeof(double)))++;
350 (*(int*)(buffer
+offset
))++;
354 copyValuesFromGrpBindBuf(buffer
+offset
, def
->fldName
);
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);
364 offset
= offset
+ os::align(def
->length
);
367 memcpy(nullInfo
, &prjNullInfo
, sizeof(long long));
369 aggNodeIter
= aggNodes
.getIterator();
372 offset
= groupOffset
+sizeof(long long);
373 while (iter
.hasElement()) {
374 def
= (AggFldDef
*) iter
.nextElement();
375 if(def
->aType
== AGG_AVG
) {
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);
385 else if (def
->aType
== AGG_COUNT
)
386 offset
+= sizeof(int);
388 offset
= offset
+ os::align(def
->length
);
391 tableHdl
->closeScan();
395 void* AggTableImpl::getGroupValueBuffer()
397 memset(grpFldBuffer
, 0, groupSize
);
399 char *offset
= (char*)grpFldBuffer
;
400 if (optGrpIntNoNull
) {
401 *(int*)offset
= *(int*)grpBindBuf
;
405 ListIterator giter
= fldGroupList
.getIterator();
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
);
414 memcpy(offset
, &grpNullInfo
, sizeof(int));
418 void* AggTableImpl::insertOrGetAggNode()
421 if (0 == fldGroupList
.size()) {
422 ListIterator aiter
= aggNodes
.getIterator();
423 if (aiter
.hasElement()) return aiter
.nextElement();
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();
434 char *offset
= element
;
436 //offset += sizeof(int);
437 ListIterator giter
= fldGroupList
.getIterator();
439 while(giter
.hasElement())
441 def
= (AggFldDef
*) giter
.nextElement();
442 if(def
->isNullable
&& tableHdl
->isFldNull(def
->fldName
))
445 AllDataType::copyVal(offset
, def
->bindBuf
, def
->type
,def
->length
);
446 offset
= offset
+ os::align(def
->length
);
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();
460 AllDataType::copyVal(offset
, def
->bindBuf
, def
->type
,
466 AllDataType::copyZeroVal(offset
, def
->type
, def
->length
);
470 *(double*)(offset
)=0;
471 *(int*)(offset
+ sizeof(double))=0; //count
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);
481 offset
= offset
+ os::align(def
->length
);
483 aggNodes
.append(element
);
484 aggNodeMap
.insert(element
);
488 void* AggTableImpl::fetch()
490 while(aggNodeIter
.hasElement())
492 void *elem
= aggNodeIter
.nextElement();
495 PredicateImpl
*pImpl
= (PredicateImpl
*)havingPred
;
496 pImpl
->evaluateForHaving(result
, this, elem
);
497 if (!result
) continue;
499 copyValuesToBindBuffer(elem
);
506 void* AggTableImpl::fetch(DbRetVal
&rv
)
512 void* AggTableImpl::fetchNoBind()
514 if(aggNodeIter
.hasElement())
516 void *elem
= aggNodeIter
.nextElement();
523 void* AggTableImpl::fetchNoBind(DbRetVal
&rv
)
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();
535 char *colPtr
=element
+groupSize
;
536 prjNullInfo
= *(long long *) colPtr
;
537 colPtr
+= sizeof(long long);
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);
548 colPtr
+= os::align(def
->length
);
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);
562 AllDataType::copyVal(def
->appBuf
, colPtr
, def
->type
,
564 colPtr
= colPtr
+ os::align(def
->length
);
572 long AggTableImpl::numTuples()
574 return aggNodes
.size();
577 DbRetVal
AggTableImpl::closeScan()
580 ListIterator aiter
= aggNodes
.getIterator();
582 while (aiter
.hasElement()) {
583 element
= (char*)aiter
.nextElement();
587 aggNodeMap
.removeAll();
588 if (tableHdl
) tableHdl
->closeScan();
592 DbRetVal
AggTableImpl::close()
599 bool AggTableImpl::isFldNull(const char *name
)
601 ListIterator it
= fldList
.getIterator();
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;
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
,
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);
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(");
657 } else if (strncmp(name
, "MIN", 3) == 0) {
658 ptr
+= strlen("MIN(");
660 } else if (strncmp(name
, "MAX", 3) == 0) {
661 ptr
+= strlen("MAX(");
663 } else if (strncmp(name
, "SUM", 3) == 0) {
664 ptr
+= strlen("SUM(");
666 } else if (strncmp(name
, "AVG", 3) == 0) {
667 ptr
+= strlen("AVG(");
670 if (atp
== AGG_UNKNOWN
) return atp
;
671 strcpy(fldName
, ptr
);
673 while (*ptr
!= ')') ptr
++;