code reorg
[csql.git] / src / server / AggTableImpl.cxx
blob2a39da2503ff757df9f922a44f90af4cc61ed091
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 AggTableImpl::AggTableImpl()
23 AggTableImpl::~AggTableImpl()
26 DbRetVal AggTableImpl::bindFld(const char *name, void *val)
28 return ErrBadCall;
30 DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val)
32 FieldInfo *info = new FieldInfo();
33 tableHdl->getFieldInfo(fldname, info);
34 AggFldDef *def = new AggFldDef();
35 strcpy(def->fldName, fldname);
36 def->type = info->type;
37 def->length= info->length;
38 def->appBuf = val;
39 def->atype=aggType;
40 def->bindBuf = NULL;
41 def->alreadyBinded = false;
42 ListIterator iter = fldList.getIterator();
43 AggFldDef *elem;
44 //If it is already binded, then use the same buffer which is binded.
45 //this code is to handle statements which have more aggregates on same field
46 while (iter.hasElement())
48 elem = (AggFldDef*) iter.nextElement();
49 if (strcmp(elem->fldName, fldname)==0)
51 def->bindBuf = elem->bindBuf;
52 def->alreadyBinded = true;
53 break;
56 if (!def->bindBuf)
58 def->bindBuf = AllDataType::alloc(def->type, def->length);
59 tableHdl->bindFld(fldname, def->bindBuf);
61 fldList.append(def);
62 delete info;
63 return OK;
65 DbRetVal AggTableImpl::setGroup(const char *fldname, void *val)
67 FieldInfo *info = new FieldInfo();
68 tableHdl->getFieldInfo(fldname, info);
69 strcpy(groupFld.fldName, fldname);
70 groupFld.type = info->type;
71 groupFld.length = info->length;
72 groupFld.appBuf = val;
73 groupFld.bindBuf = AllDataType::alloc(info->type, info->length);
74 tableHdl->bindFld(fldname, groupFld.bindBuf);
75 delete info;
76 return OK;
79 DbRetVal AggTableImpl::execute()
81 ListIterator iter = fldList.getIterator();
82 AggFldDef *def;
83 if (isGroupSet())
84 aggNodeSize = AllDataType::size(groupFld.type, groupFld.length);
85 else
86 aggNodeSize = 0;
87 while (iter.hasElement())
89 def = (AggFldDef*) iter.nextElement();
90 aggNodeSize = aggNodeSize + AllDataType::size(def->type, def->length);
91 if (def->atype == AGG_AVG) aggNodeSize = aggNodeSize + sizeof(int);//for count
93 void *tuple = NULL;
94 int offset=0;
95 tableHdl->execute();
96 aggNodes.reset();
97 while((tuple = tableHdl->fetch()) != NULL)
99 char *buffer = (char*)insertOrGet();
100 iter.reset();
101 if (isGroupSet())
102 offset = AllDataType::size(groupFld.type, groupFld.length);
103 else
104 offset = 0;
105 while (iter.hasElement())
107 def = (AggFldDef*) iter.nextElement();
108 switch(def->atype)
110 case AGG_MIN: {
111 bool result = AllDataType::compareVal(buffer+offset,
112 def->bindBuf, OpGreaterThanEquals, def->type, def->length);
113 if (result)
114 AllDataType::copyVal(buffer+offset, def->bindBuf,
115 def->type, def->length);
116 break;
118 case AGG_MAX: {
119 bool result = AllDataType::compareVal(buffer+offset,
120 def->bindBuf, OpLessThanEquals, def->type, def->length);
121 if (result)
122 AllDataType::copyVal(buffer+offset, def->bindBuf,
123 def->type, def->length);
124 break;
126 case AGG_SUM: {
127 AllDataType::addVal(buffer+offset, def->bindBuf, def->type);
128 break;
130 case AGG_AVG: {
131 AllDataType::addVal(buffer+offset, def->bindBuf, def->type);
132 (*(int*)(buffer+offset + AllDataType::size(def->type, def->length)))++;
133 offset = offset +sizeof(int); //->count
134 break;
136 case AGG_COUNT:
137 (*(int*)(buffer+offset))++;
138 break;
140 offset = offset + AllDataType::size(def->type, def->length);
143 aggNodeIter = aggNodes.getIterator();
144 iter.reset();
145 char *element;
146 while (iter.hasElement()) {
147 def = (AggFldDef*) iter.nextElement();
148 if (isGroupSet())
149 offset = AllDataType::size(groupFld.type, groupFld.length);
150 else
151 offset = 0;
152 switch(def->atype)
154 case AGG_AVG: {
155 while (aggNodeIter.hasElement()) {
156 element = (char*)aggNodeIter.nextElement();
157 AllDataType::divVal(element+offset,
158 *(int*)(element+offset+AllDataType::size(def->type, def->length)),
159 def->type);
161 offset = offset +sizeof(int);
164 offset = offset + AllDataType::size(def->type, def->length);
166 aggNodeIter.reset();
167 tableHdl->close();
168 return OK;
170 void* AggTableImpl::insertOrGet()
172 ListIterator aiter = aggNodes.getIterator();
173 char *element;
174 while (aiter.hasElement()) {
175 element = (char*)aiter.nextElement();
177 if (!isGroupSet()) return element;
178 if (AllDataType::compareVal(element, groupFld.bindBuf, OpEquals,
179 groupFld.type, groupFld.length))
181 return element;
184 element = (char*)malloc(aggNodeSize);
185 ListIterator iter = fldList.getIterator();
186 AggFldDef *def;
187 char *offset;
188 if (isGroupSet()) {
189 AllDataType::copyVal(element, groupFld.bindBuf, groupFld.type,
190 groupFld.length);
191 offset = element + AllDataType::size(groupFld.type, groupFld.length);
193 else
194 offset = element;
196 while (iter.hasElement())
198 def = (AggFldDef*) iter.nextElement();
199 switch(def->atype) {
200 case AGG_MIN: { *(int*)(offset)=INT_MAX; break; }
201 case AGG_MAX: { *(int*)(offset)=INT_MIN; break; }
202 case AGG_SUM: { *(int*)(offset)=0; break; }
203 case AGG_AVG: {
204 *(int*)(offset)=0;
205 *(int*)(offset+AllDataType::size(def->type, def->length))=0; //count
206 offset = offset+ sizeof(int);
207 break;
209 case AGG_COUNT: { *(int*)(offset)=0; break; }
211 offset = offset + AllDataType::size(def->type, def->length);
213 aggNodes.append(element);
214 return element;
217 void* AggTableImpl::fetch()
219 if(aggNodeIter.hasElement())
221 void *elem = aggNodeIter.nextElement();
222 copyValuesToBindBuffer(elem);
223 return elem;
225 else
226 return NULL;
229 void* AggTableImpl::fetch(DbRetVal &rv)
231 rv = OK;
232 return fetch();
235 void* AggTableImpl::fetchNoBind()
237 if(aggNodeIter.hasElement())
239 void *elem = aggNodeIter.nextElement();
240 return elem;
242 else
243 return NULL;
246 void* AggTableImpl::fetchNoBind(DbRetVal &rv)
248 rv = OK;
249 return fetchNoBind();
252 DbRetVal AggTableImpl::copyValuesToBindBuffer(void *elem)
254 char *element = (char*)elem;
255 //Iterate through the bind list and copy the value here
256 ListIterator fIter = fldList.getIterator();
257 AggFldDef *def;
258 AllDataType::copyVal(groupFld.appBuf, elem, groupFld.type, groupFld.length);
259 char *colPtr = (char*) elem + AllDataType::size(groupFld.type, groupFld.length);
260 while (fIter.hasElement())
262 def = (AggFldDef*) fIter.nextElement();
263 if (NULL != def->appBuf) {
264 AllDataType::copyVal(def->appBuf, colPtr, def->type, def->length);
266 colPtr = colPtr + os::align(AllDataType::size(def->type, def->length));
267 if(def->atype == AGG_AVG) colPtr = colPtr + sizeof(int);
269 return OK;
272 long AggTableImpl::numTuples()
274 return aggNodes.size();
276 void AggTableImpl::closeScan()
278 aggNodeIter.reset();
279 ListIterator aiter = aggNodes.getIterator();
280 char *element;
281 while (aiter.hasElement()) {
282 element = (char*)aiter.nextElement();
283 free(element);
285 aggNodes.reset();
288 DbRetVal AggTableImpl::close()
290 //free memory allocated. make sure that field buffers are freed only once.
291 //for stmts which has more than one agg on same field needs to be handled safely
292 free(groupFld.bindBuf);
293 ListIterator iter = fldList.getIterator();
294 AggFldDef *elem;
295 while (iter.hasElement())
297 elem = (AggFldDef*) iter.nextElement();
298 if(!elem->alreadyBinded) free(elem->bindBuf);
300 fldList.reset();
301 return OK;
310 //-----------------------------------------------------------
312 JoinTableImpl::JoinTableImpl()
314 isNestedLoop= true;
316 JoinTableImpl::~JoinTableImpl()
319 void JoinTableImpl::getFieldNameAlone(char *fname, char *name) {
320 bool dotFound= false;
321 char *fullname = fname;
322 while(*fullname != '\0')
324 if (*fullname == '.') { dotFound = true; break; }
325 fullname++;
327 if (dotFound) strcpy(name, ++fullname); else strcpy(name, fname);
330 void JoinTableImpl::getTableNameAlone(char *fname, char *name) {
331 strcpy(name, fname);
332 while(*name != '\0')
334 if (*name == '.') { *name='\0'; break; }
335 name++;
337 return;
339 DbRetVal JoinTableImpl::bindFld(const char *fldname, void *val)
341 FieldInfo *info = new FieldInfo();
342 char tableName[IDENTIFIER_LENGTH];
343 char fieldName[IDENTIFIER_LENGTH];
344 getTableNameAlone((char*)fldname, tableName);
345 getFieldNameAlone((char*)fldname, fieldName);
346 printf("%s %s \n", tableName, fieldName);
348 ListIterator iter = projList.getIterator();
349 JoinProjFieldInfo *elem;
350 while (iter.hasElement())
352 elem = (JoinProjFieldInfo*) iter.nextElement();
353 if (strcmp(elem->fieldName, fieldName)==0 &&
354 strcmp(elem->tableName, tableName) ==0)
356 printError(ErrBadCall, "Field already binded %s\n", fldname);
357 delete info;
358 return ErrBadCall;
361 JoinProjFieldInfo *def = new JoinProjFieldInfo();
362 strcpy(def->tableName, tableName);
363 strcpy(def->fieldName, fieldName);
364 def->appBuf = val;
365 def->bindBuf = AllDataType::alloc(def->type, def->length);
367 if (strcmp(tableName, leftTableHdl->getName()) == 0)
369 leftTableHdl->getFieldInfo(fieldName, info);
370 def->bindBuf = AllDataType::alloc(info->type, info->length);
371 leftTableHdl->bindFld(fieldName, def->bindBuf);
373 }else if (strcmp(tableName, rightTableHdl->getName()) == 0)
375 rightTableHdl->getFieldInfo(fieldName, info);
376 def->bindBuf = AllDataType::alloc(info->type, info->length);
377 rightTableHdl->bindFld(fieldName, def->bindBuf);
378 }else
380 printError(ErrBadCall, "TableName is invalid\n");
381 delete info;
382 return ErrBadCall;
384 def->type = info->type;
385 def->length= info->length;
386 projList.append(def);
387 delete info;
388 return OK;
390 DbRetVal JoinTableImpl::setJoinCondition(const char *fldname1,
391 ComparisionOp op,
392 const char *fldname2)
394 getTableNameAlone((char*)fldname1, jCondition.tableName1);
395 getFieldNameAlone((char*)fldname1, jCondition.fieldName1);
396 getTableNameAlone((char*)fldname2, jCondition.tableName2);
397 getFieldNameAlone((char*)fldname2, jCondition.fieldName2);
399 //check if it is already binded
400 ListIterator iter = projList.getIterator();
401 JoinProjFieldInfo *elem;
402 jCondition.alreadyBinded1 = false;
403 jCondition.alreadyBinded2 = false;
404 jCondition.op = op;
405 while (iter.hasElement())
407 elem = (JoinProjFieldInfo*) iter.nextElement();
408 if (strcmp(elem->fieldName, jCondition.fieldName1)==0 &&
409 strcmp(elem->tableName, jCondition.tableName1) ==0)
411 jCondition.alreadyBinded1 = true;
412 jCondition.bindBuf1 = elem->bindBuf;
413 jCondition.type1 = elem->type;
414 jCondition.length1 = elem->length;
416 if (strcmp(elem->fieldName, jCondition.fieldName2)==0 &&
417 strcmp(elem->tableName, jCondition.tableName2) ==0)
419 jCondition.alreadyBinded2 = true;
420 jCondition.bindBuf2 = elem->bindBuf;
421 jCondition.type2 = elem->type;
422 jCondition.length2 = elem->length;
426 FieldInfo *info = new FieldInfo();
427 if (!jCondition.alreadyBinded1) {
428 if (strcmp(jCondition.tableName1, leftTableHdl->getName()) == 0)
430 leftTableHdl->getFieldInfo(jCondition.fieldName1, info);
431 jCondition.bindBuf1 = AllDataType::alloc(info->type, info->length);
432 leftTableHdl->bindFld(jCondition.fieldName1, jCondition.bindBuf1);
434 }else if (strcmp(jCondition.tableName1, rightTableHdl->getName()) == 0)
436 rightTableHdl->getFieldInfo(jCondition.fieldName1, info);
437 jCondition.bindBuf1 = AllDataType::alloc(info->type, info->length);
438 rightTableHdl->bindFld(jCondition.fieldName1, jCondition.bindBuf1);
439 }else
441 printError(ErrBadCall, "TableName is invalid\n");
442 delete info;
443 return ErrBadCall;
446 if (!jCondition.alreadyBinded2) {
447 if (strcmp(jCondition.tableName2, leftTableHdl->getName()) == 0)
449 leftTableHdl->getFieldInfo(jCondition.fieldName2, info);
450 jCondition.bindBuf2 = AllDataType::alloc(info->type, info->length);
451 leftTableHdl->bindFld(jCondition.fieldName2, jCondition.bindBuf2);
453 }else if (strcmp(jCondition.tableName2, rightTableHdl->getName()) == 0)
455 rightTableHdl->getFieldInfo(jCondition.fieldName2, info);
456 jCondition.bindBuf2 = AllDataType::alloc(info->type, info->length);
457 rightTableHdl->bindFld(jCondition.fieldName2, jCondition.bindBuf2);
458 }else
460 printError(ErrBadCall, "TableName is invalid\n");
461 delete info;
462 return ErrBadCall;
465 return OK;
469 DbRetVal JoinTableImpl::execute()
471 isNestedLoop = true;
472 leftTableHdl->execute();
473 rightTableHdl->execute();
474 leftTableHdl->fetch();
475 //TODO
476 //if join condition is not set then do nl
477 //if it is inner join, hen do nl
478 //nl cannot be done for outer join
479 return OK;
482 void* JoinTableImpl::fetch()
484 if (isNestedLoop)
486 void *rec = rightTableHdl->fetch();
487 if (rec==NULL)
489 rightTableHdl->close();
490 rightTableHdl->execute();
491 rec = rightTableHdl->fetch();
492 if (rec == NULL) return NULL;
493 rec = leftTableHdl->fetch();
494 if (rec == NULL) return NULL;
495 bool result = evaluate();
496 if (! result) return fetch();
497 copyValuesToBindBuffer(NULL);
498 return rec;
500 else {
501 bool result = evaluate();
502 if (! result) return fetch();
503 copyValuesToBindBuffer(NULL);
504 return rec;
508 return NULL;
510 bool JoinTableImpl::evaluate()
512 if (!jCondition.bindBuf1 || !jCondition.bindBuf2) return true;
513 return AllDataType::compareVal(jCondition.bindBuf1, jCondition.bindBuf2,
514 jCondition.op,
515 jCondition.type1, jCondition.length1);
517 void* JoinTableImpl::fetch(DbRetVal &rv)
519 rv = OK;
520 return fetch();
523 void* JoinTableImpl::fetchNoBind()
525 return NULL;
528 void* JoinTableImpl::fetchNoBind(DbRetVal &rv)
530 rv = OK;
531 return fetchNoBind();
534 DbRetVal JoinTableImpl::copyValuesToBindBuffer(void *elem)
536 //Iterate through the bind list and copy the value here
537 ListIterator fIter = projList.getIterator();
538 JoinProjFieldInfo *def;
539 while (fIter.hasElement())
541 def = (JoinProjFieldInfo*) fIter.nextElement();
542 if (NULL != def->appBuf) {
543 AllDataType::copyVal(def->appBuf, def->bindBuf, def->type, def->length);
546 return OK;
549 long JoinTableImpl::numTuples()
551 return 0;
553 void JoinTableImpl::closeScan()
556 DbRetVal JoinTableImpl::close()
558 return OK;