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
);
50 //if(elem->bindBuf) { free(elem->bindBuf); elem->bindBuf =NULL; }
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; }
64 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
)
76 printError(ErrBadCall
, "AggTableImpl bindFld not implemented\n");
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
;
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();
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;
117 def
->bindBuf
= AllDataType::alloc(def
->type
, def
->length
);
118 rv
= tableHdl
->bindFld(fldname
, def
->bindBuf
);
121 ::free(def
->bindBuf
);
125 def
->alreadyBinded
= true;
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();
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;
163 if (!groupFld
->bindBuf
)
165 groupFld
->bindBuf
= AllDataType::alloc(groupFld
->type
, groupFld
->length
);
166 rv
= tableHdl
->bindFld(fldname
, groupFld
->bindBuf
);
169 ::free(groupFld
->bindBuf
);
175 fldGroupList
.append(groupFld
);
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;
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
)
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
);
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
,
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();
260 DbRetVal
AggTableImpl::execute()
262 ListIterator iter
= fldList
.getIterator();
264 aggNodeSize
= groupSize
= computeGrpNodeSize();
265 aggNodeMap
.setKeySize(groupSize
);
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
;
284 int groupOffset
= groupSize
;
285 while((tuple
= tableHdl
->fetch()) != NULL
)
287 char *buffer
= (char*)insertOrGetAggNode();
289 offset
= groupOffset
;
290 char *nullInfo
= buffer
+ offset
;
291 prjNullInfo
= *(long long *) nullInfo
;
292 offset
+= sizeof(long long);
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
;
305 bool result
=false; bool isNull
=false;
306 isNull
= isFldNull(colpos
);
311 result
= AllDataType::compareVal(buffer
+offset
,
312 def
->bindBuf
, OpGreaterThanEquals
, def
->type
,
315 if (result
|| isNull
)
316 AllDataType::copyVal(buffer
+offset
, def
->bindBuf
,
317 def
->type
, def
->length
);
322 result
= AllDataType::compareVal(buffer
+offset
,
323 def
->bindBuf
, OpLessThanEquals
, def
->type
,
326 if (result
|| isNull
)
327 AllDataType::copyVal(buffer
+offset
, def
->bindBuf
,
328 def
->type
, def
->length
);
332 AllDataType::addVal(buffer
+offset
, def
->bindBuf
, def
->type
);
337 AllDataType::convertToDouble(&tmpBuf
, def
->bindBuf
,
339 AllDataType::addVal(buffer
+offset
, &tmpBuf
, typeDouble
);
340 (*(int*)(buffer
+offset
+ sizeof(double)))++;
344 (*(int*)(buffer
+offset
))++;
348 copyValuesFromGrpBindBuf(buffer
+offset
, def
->fldName
);
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
;
359 memcpy(nullInfo
, &prjNullInfo
, sizeof(long long));
361 aggNodeIter
= aggNodes
.getIterator();
364 offset
= groupOffset
+sizeof(long long);
365 while (iter
.hasElement()) {
366 def
= (AggFldDef
*) iter
.nextElement();
367 if(def
->aType
== AGG_AVG
) {
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);
377 else if (def
->aType
== AGG_COUNT
) offset
+= sizeof(int);
378 else offset
= offset
+ def
->length
;
381 tableHdl
->closeScan();
385 void* AggTableImpl::getGroupValueBuffer()
387 memset(grpFldBuffer
, 0, groupSize
);
389 char *offset
= (char*)grpFldBuffer
;
390 if (optGrpIntNoNull
) {
391 *(int*)offset
= *(int*)grpBindBuf
;
395 ListIterator giter
= fldGroupList
.getIterator();
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
;
404 memcpy(offset
, &grpNullInfo
, sizeof(int));
407 void* AggTableImpl::insertOrGetAggNode()
410 if (0 == fldGroupList
.size()) {
411 ListIterator aiter
= aggNodes
.getIterator();
412 if (aiter
.hasElement()) return aiter
.nextElement();
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();
423 char *offset
= element
;
425 //offset += sizeof(int);
426 ListIterator giter
= fldGroupList
.getIterator();
428 while(giter
.hasElement())
430 def
= (AggFldDef
*) giter
.nextElement();
431 if(def
->isNullable
&& tableHdl
->isFldNull(def
->fldName
))
434 AllDataType::copyVal(offset
, def
->bindBuf
, def
->type
,def
->length
);
435 offset
= offset
+ def
->length
;
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();
449 AllDataType::copyVal(offset
, def
->bindBuf
, def
->type
,
455 AllDataType::copyZeroVal(offset
, def
->type
, def
->length
);
459 *(double*)(offset
)=0;
460 *(int*)(offset
+ sizeof(double))=0; //count
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
);
475 void* AggTableImpl::fetch()
477 while(aggNodeIter
.hasElement())
479 void *elem
= aggNodeIter
.nextElement();
482 PredicateImpl
*pImpl
= (PredicateImpl
*)havingPred
;
483 pImpl
->evaluateForHaving(result
, this, elem
);
484 if (!result
) continue;
486 copyValuesToBindBuffer(elem
);
492 void* AggTableImpl::fetch(DbRetVal
&rv
)
498 void* AggTableImpl::fetchNoBind()
500 if(aggNodeIter
.hasElement())
502 void *elem
= aggNodeIter
.nextElement();
509 void* AggTableImpl::fetchNoBind(DbRetVal
&rv
)
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();
521 char *colPtr
=element
+groupSize
;
522 prjNullInfo
= *(long long *) colPtr
;
523 colPtr
+= sizeof(long long);
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
;
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);
546 AllDataType::copyVal(def
->appBuf
, colPtr
, def
->type
,
548 colPtr
= colPtr
+ def
->length
;
556 long AggTableImpl::numTuples()
558 return aggNodes
.size();
560 DbRetVal
AggTableImpl::closeScan()
563 ListIterator aiter
= aggNodes
.getIterator();
565 while (aiter
.hasElement()) {
566 element
= (char*)aiter
.nextElement();
570 aggNodeMap
.removeAll();
571 if (tableHdl
) tableHdl
->closeScan();
575 DbRetVal
AggTableImpl::close()
582 bool AggTableImpl::isFldNull(const char *name
)
584 ListIterator it
= fldList
.getIterator();
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;
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
,
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);
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(");
639 } else if (strncmp(name
, "MIN", 3) == 0) {
640 ptr
+= strlen("MIN(");
642 } else if (strncmp(name
, "MAX", 3) == 0) {
643 ptr
+= strlen("MAX(");
645 } else if (strncmp(name
, "SUM", 3) == 0) {
646 ptr
+= strlen("SUM(");
648 } else if (strncmp(name
, "AVG", 3) == 0) {
649 ptr
+= strlen("AVG(");
652 if (atp
== AGG_UNKNOWN
) return atp
;
653 strcpy(fldName
, ptr
);
655 while (*ptr
!= ')') ptr
++;