From 5746e0f9d1ac5f81d3961a3b8d80f19303d3dac9 Mon Sep 17 00:00:00 2001 From: prabatuty Date: Thu, 26 Jun 2008 13:32:03 +0000 Subject: [PATCH] changes for join table and parser for aggregates --- include/AggTableImpl.h | 138 +++++++++++++++-- include/Parser.h | 13 +- include/Statement.h | 13 +- {src/sql => include}/dmlyacc.h | 7 + src/odbc/Makefile | 12 +- src/server/AggTableImpl.cxx | 325 ++++++++++++++++++++++++++++++++++++----- src/server/Makefile.am | 2 +- src/sql/ParsedData.cxx | 9 +- src/sql/Parser.h | 13 +- src/sql/SelStatement.cxx | 75 +++++++++- src/sql/dmllex.lxx | 7 + src/sql/dmlyacc.h | 7 + src/sql/dmlyacc.yxx | 43 +++++- tmptest/test.c | 153 +++++++++++++------ 14 files changed, 711 insertions(+), 106 deletions(-) copy {src/sql => include}/dmlyacc.h (89%) rewrite tmptest/test.c (97%) diff --git a/include/AggTableImpl.h b/include/AggTableImpl.h index 7064a022..4d02fbe5 100644 --- a/include/AggTableImpl.h +++ b/include/AggTableImpl.h @@ -13,8 +13,8 @@ * GNU General Public License for more details. * * * ***************************************************************************/ -#ifndef AGGTABLE_IMPL_H -#define AGGTABLE_IMPL_H +#ifndef JOINTABLE_IMPL_H +#define JOINTABLE_IMPL_H #include #include #include @@ -56,42 +56,35 @@ class AggFldDef } }; - class AggTableImpl:public Table { private: char tblName_[IDENTIFIER_LENGTH]; void *curTuple; //holds the current tuple ptr. moved during fetch() calls List fldList; - AggFldDef groupFld; + AggFldDef groupFld; Table *tableHdl; List aggNodes; //change this list to some other data structure ListIterator aggNodeIter; int aggNodeSize; DbRetVal copyValuesToBindBuffer(void *tuple); - public: AggTableImpl(); virtual ~AggTableImpl(); - DbRetVal getFieldInfo(const char *fieldName, FieldInfo *&info) { return ErrBadCall; } - bool isGroupSet() - { + { if (groupFld.type == typeUnknown) return false; else return true; } - void* insertOrGet(); - + void* insertOrGet(); void setTable(Table *impl){ tableHdl = impl;} + Table* getTableHdl(){ return tableHdl; } void closeScan(); - - //binding DbRetVal bindFld(const char *name, void *val); DbRetVal bindFld(const char *name, AggType aggType, void *val); DbRetVal setGroup(const char *name, void *val); - void setCondition(Condition *p){} void markFldNull(const char *name){} void markFldNull(int colpos){} @@ -112,7 +105,126 @@ class AggTableImpl:public Table void printSQLIndexString(){ }; char* getName() { return tableHdl->getName(); } List getFieldNameList(){ List list; return list;} + DbRetVal execute(); + void* fetch(); + void* fetch(DbRetVal &rv); + void* fetchNoBind(); + void* fetchNoBind(DbRetVal &rv); + DbRetVal close(); + long numTuples(); + void printInfo(); +}; + + + + + + +enum JoinType +{ + INNER_JOIN = 1, + RIGHT_JOIN, + LEFT_JOIN, + FULL_JOIN, + UNKNOWN_JOIN +}; +class JoinProjFieldInfo +{ + public: + char tableName[IDENTIFIER_LENGTH]; + char fieldName[IDENTIFIER_LENGTH]; + DataType type; + int length; + void *appBuf; + void *bindBuf; + JoinProjFieldInfo() + { + strcpy(tableName,""); strcpy(fieldName, ""); + type= typeUnknown; length =0; appBuf= NULL; bindBuf=NULL; + } +}; +class JoinCondition +{ + public: + char tableName1[IDENTIFIER_LENGTH]; + char tableName2[IDENTIFIER_LENGTH]; + char fieldName1[IDENTIFIER_LENGTH]; + char fieldName2[IDENTIFIER_LENGTH]; + DataType type1; + DataType type2; + int length1; + int length2; + void *bindBuf1; + void *bindBuf2; + bool alreadyBinded1; + bool alreadyBinded2; + ComparisionOp op; + JoinCondition() + { + strcpy(tableName1,""); strcpy(fieldName1, ""); + strcpy(tableName2,""); strcpy(fieldName2, ""); + type1= typeUnknown; length1 =0; bindBuf1=NULL; + type2= typeUnknown; length2 =0; bindBuf2=NULL; + alreadyBinded1=false; alreadyBinded2=false; + } + +}; +class JoinTableImpl:public Table +{ + private: + void *curTuple; //holds the current tuple ptr. moved during fetch() calls + List projList; + Table *leftTableHdl; + Table *rightTableHdl; + + JoinType jType; + ListIterator rsIter; + bool isNestedLoop; + bool rightExhausted; + DbRetVal copyValuesToBindBuffer(void *tuple); + JoinCondition jCondition; + + public: + JoinTableImpl(); + virtual ~JoinTableImpl(); + + DbRetVal getFieldInfo(const char *fieldName, FieldInfo *&info) + { return ErrBadCall; } + + void setTable(Table *left, Table *right) + { leftTableHdl = left; rightTableHdl = right; } + + void closeScan(); + void setJoinType(JoinType type) { jType = type; } + //binding + DbRetVal bindFld(const char *name, void *val); + DbRetVal setJoinCondition(const char *fldname1, ComparisionOp op, + const char *fldname2); + void getFieldNameAlone(char*, char*); + void getTableNameAlone(char*, char*); + + void setCondition(Condition *p){} + void markFldNull(const char *name){} + void markFldNull(int colpos){} + bool isFldNull(const char *name){return false;} + bool isFldNull(int colpos){return false;} + void clearFldNull(const char *name){} + void clearFldNull(int colpos){} + DbRetVal insertTuple() { return ErrBadCall; } + DbRetVal updateTuple() { return ErrBadCall; } + DbRetVal deleteTuple() { return ErrBadCall; } + int deleteWhere() { return ErrBadCall; } + int truncate() { return ErrBadCall; } + long spaceUsed() { return 0; } + int pagesUsed() { return 0; } + DbRetVal lock(bool shared) { return ErrBadCall; } + DbRetVal unlock(){ return ErrBadCall; } + DbRetVal setUndoLogging(bool flag) { return ErrBadCall; } + void printSQLIndexString(){ }; + List getFieldNameList(){ List list; return list;} + char* getName() { return NULL; } + bool evaluate(); DbRetVal execute(); void* fetch(); void* fetch(DbRetVal &rv); diff --git a/include/Parser.h b/include/Parser.h index ad6af89e..0b7f517c 100644 --- a/include/Parser.h +++ b/include/Parser.h @@ -20,6 +20,7 @@ #ifndef PARSER_H #define PARSER_H #include +#include #include #include enum StatementType @@ -58,6 +59,12 @@ struct ConditionValue struct FieldName { char fldName[IDENTIFIER_LENGTH]; + AggType aType; //used only in case of select projection + FieldName() + { + strcpy(fldName,""); + aType = AGG_UNKNOWN; + } }; struct UpdateFieldValue @@ -86,6 +93,8 @@ class ParsedData //also used to store primary or unique key fields in create statement List fieldNameList; + List groupFieldNameList; + //holds pointer to condition values. List conditionValueList; @@ -132,7 +141,8 @@ class ParsedData void** insertCondValueAndGetPtr(char *fName, char *value); void insertUpdateValue(char *fldName, char *value); - void insertField(char *fName); + void insertField(char *fName, AggType aggType= AGG_UNKNOWN); + void insertGroupField(char *fName); void clearFieldNameList(); @@ -150,6 +160,7 @@ class ParsedData void insertFieldValue(FieldValue *newVal) { fieldValueList.append(newVal); } List getFieldNameList() { return fieldNameList; } + List getGroupFieldNameList() { return groupFieldNameList; } List getConditionValueList() { return conditionValueList; } List getFieldValueList() { return fieldValueList; } List getInValueList() { return inValueList; } diff --git a/include/Statement.h b/include/Statement.h index bbd6c7a0..25511cc1 100644 --- a/include/Statement.h +++ b/include/Statement.h @@ -32,6 +32,7 @@ class Statement void setDbMgr(DatabaseManager *dbmgr) { dbMgr = dbmgr; } + virtual int noOfParamFields() { return 0; } virtual DbRetVal execute(int &rowsAffected)=0; virtual DbRetVal setParam(int paramNo, void *value)=0; @@ -84,6 +85,7 @@ class DmlStatement : public Statement virtual DbRetVal resolve()=0; + virtual void* getParamValuePtr( int pos )=0; virtual ~DmlStatement(){} }; @@ -106,7 +108,7 @@ class InsStatement : public DmlStatement DbRetVal setDateParam(int paramNo, Date value); DbRetVal setTimeParam(int paramNo, Time value); DbRetVal setTimeStampParam(int paramNo, TimeStamp value); - + void* getParamValuePtr( int ); DbRetVal resolve(); InsStatement(); ~InsStatement(); @@ -151,6 +153,11 @@ class SelStatement : public DmlStatement int noOfProjFields(); DbRetVal getProjFldInfo (int projpos, FieldInfo *&fInfo); DbRetVal getParamFldInfo(int paramPos, FieldInfo *&info); + + void *getParamValuePtr( int ); + DataType getFieldType( int ); + int getFieldLength( int ); + char* getFieldName( int ); void *fetch(); void *fetch(DbRetVal &rv); @@ -176,7 +183,7 @@ class UpdStatement : public DmlStatement DbRetVal setDateParam(int paramNo, Date value); DbRetVal setTimeParam(int paramNo, Time value); DbRetVal setTimeStampParam(int paramNo, TimeStamp value); - + void* getParamValuePtr(int); DbRetVal getParamFldInfo(int paramPos, FieldInfo *&info); @@ -207,7 +214,7 @@ class DelStatement : public DmlStatement DbRetVal setTimeStampParam(int paramNo, TimeStamp value); DbRetVal getParamFldInfo(int paramPos, FieldInfo *&info); - + void* getParamValuePtr(int); DbRetVal resolve(); DelStatement(); ~DelStatement(); diff --git a/src/sql/dmlyacc.h b/include/dmlyacc.h similarity index 89% copy from src/sql/dmlyacc.h copy to include/dmlyacc.h index 18230f71..57b29633 100644 --- a/src/sql/dmlyacc.h +++ b/include/dmlyacc.h @@ -43,6 +43,13 @@ #define BIGINT_TYPE 299 #define FLOAT_TYPE 300 #define TINYINT_TYPE 301 +#define MIN 302 +#define MAX 303 +#define AVG 304 +#define SUM 305 +#define COUNT 306 +#define GROUP 307 +#define BY 308 typedef union { char *stringval; diff --git a/src/odbc/Makefile b/src/odbc/Makefile index 2c3f9936..4c2c6834 100644 --- a/src/odbc/Makefile +++ b/src/odbc/Makefile @@ -23,7 +23,7 @@ pkglibdir = $(libdir)/csql pkgincludedir = $(includedir)/csql top_builddir = ../.. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = /usr/bin/ginstall -c +INSTALL = /usr/bin/install -c install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c @@ -94,7 +94,7 @@ CPPFLAGS = CXX = g++ CXXCPP = g++ -E CXXDEPMODE = depmode=gcc3 -CXXFLAGS = -g -I/home/csql/jdk1.5.0_14/include -I/home/csql/jdk1.5.0_14/include/linux +CXXFLAGS = -g -I/opt/java/jdk1.6.0_04/include -I/opt/java/jdk1.6.0_04/include/linux CYGPATH_W = echo DEFS = -DHAVE_CONFIG_H DEPDIR = .deps @@ -102,11 +102,11 @@ ECHO = echo ECHO_C = ECHO_N = -n ECHO_T = -EGREP = /usr/bin/grep -E +EGREP = /bin/grep -E EXEEXT = -F77 = g77 +F77 = gfortran FFLAGS = -g -O2 -GREP = /usr/bin/grep +GREP = /bin/grep INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} @@ -138,7 +138,7 @@ YACC = bison -y YFLAGS = ac_ct_CC = gcc ac_ct_CXX = g++ -ac_ct_F77 = g77 +ac_ct_F77 = gfortran am__fastdepCC_FALSE = # am__fastdepCC_TRUE = am__fastdepCXX_FALSE = # diff --git a/src/server/AggTableImpl.cxx b/src/server/AggTableImpl.cxx index 367751e0..44c12534 100644 --- a/src/server/AggTableImpl.cxx +++ b/src/server/AggTableImpl.cxx @@ -17,7 +17,6 @@ #include #include #include - AggTableImpl::AggTableImpl() { } @@ -43,18 +42,18 @@ DbRetVal AggTableImpl::bindFld(const char *fldname, AggType aggType, void *val) ListIterator iter = fldList.getIterator(); AggFldDef *elem; //If it is already binded, then use the same buffer which is binded. - //this code is to handle statements which have more aggregates on same field + //this code is to handle statements which have more aggregates on same field while (iter.hasElement()) { - elem = (AggFldDef*) iter.nextElement(); - if (strcmp(elem->fldName, fldname)==0) + elem = (AggFldDef*) iter.nextElement(); + if (strcmp(elem->fldName, fldname)==0) { def->bindBuf = elem->bindBuf; def->alreadyBinded = true; break; } } - if (!def->bindBuf) + if (!def->bindBuf) { def->bindBuf = AllDataType::alloc(def->type, def->length); tableHdl->bindFld(fldname, def->bindBuf); @@ -77,21 +76,20 @@ DbRetVal AggTableImpl::setGroup(const char *fldname, void *val) return OK; } - DbRetVal AggTableImpl::execute() { ListIterator iter = fldList.getIterator(); AggFldDef *def; if (isGroupSet()) aggNodeSize = AllDataType::size(groupFld.type, groupFld.length); - else + else aggNodeSize = 0; while (iter.hasElement()) { - def = (AggFldDef*) iter.nextElement(); + def = (AggFldDef*) iter.nextElement(); aggNodeSize = aggNodeSize + AllDataType::size(def->type, def->length); if (def->atype == AGG_AVG) aggNodeSize = aggNodeSize + sizeof(int);//for count - } + } void *tuple = NULL; int offset=0; tableHdl->execute(); @@ -106,23 +104,23 @@ DbRetVal AggTableImpl::execute() offset = 0; while (iter.hasElement()) { - def = (AggFldDef*) iter.nextElement(); + def = (AggFldDef*) iter.nextElement(); switch(def->atype) { case AGG_MIN: { - bool result = AllDataType::compareVal(buffer+offset, + bool result = AllDataType::compareVal(buffer+offset, def->bindBuf, OpGreaterThan, def->type, def->length); - if (result) + if (result) AllDataType::copyVal(buffer+offset, def->bindBuf, - def->type, def->length); + def->type, def->length); break; } case AGG_MAX: { - bool result = AllDataType::compareVal(buffer+offset, + bool result = AllDataType::compareVal(buffer+offset, def->bindBuf, OpLessThan, def->type, def->length); - if (result) + if (result) AllDataType::copyVal(buffer+offset, def->bindBuf, - def->type, def->length); + def->type, def->length); break; } case AGG_SUM: { @@ -140,14 +138,13 @@ DbRetVal AggTableImpl::execute() break; } offset = offset + AllDataType::size(def->type, def->length); - } - } - + } + } aggNodeIter = aggNodes.getIterator(); iter.reset(); char *element; while (iter.hasElement()) { - def = (AggFldDef*) iter.nextElement(); + def = (AggFldDef*) iter.nextElement(); if (isGroupSet()) offset = AllDataType::size(groupFld.type, groupFld.length); else @@ -157,8 +154,8 @@ DbRetVal AggTableImpl::execute() case AGG_AVG: { while (aggNodeIter.hasElement()) { element = (char*)aggNodeIter.nextElement(); - AllDataType::divVal(element+offset, - *(int*)(element+offset+AllDataType::size(def->type, def->length)), + AllDataType::divVal(element+offset, + *(int*)(element+offset+AllDataType::size(def->type, def->length)), def->type); offset = offset +sizeof(int); } @@ -166,7 +163,7 @@ DbRetVal AggTableImpl::execute() } offset = offset + AllDataType::size(def->type, def->length); } - aggNodeIter.reset(); + aggNodeIter.reset(); tableHdl->close(); return OK; } @@ -178,7 +175,7 @@ void* AggTableImpl::insertOrGet() element = (char*)aiter.nextElement(); if (!isGroupSet()) return element; - if (AllDataType::compareVal(element, groupFld.bindBuf, OpEquals, + if (AllDataType::compareVal(element, groupFld.bindBuf, OpEquals, groupFld.type, groupFld.length)) { return element; @@ -189,7 +186,7 @@ void* AggTableImpl::insertOrGet() AggFldDef *def; char *offset; if (isGroupSet()) { - AllDataType::copyVal(element, groupFld.bindBuf, groupFld.type, + AllDataType::copyVal(element, groupFld.bindBuf, groupFld.type, groupFld.length); offset = element + AllDataType::size(groupFld.type, groupFld.length); } @@ -198,21 +195,21 @@ void* AggTableImpl::insertOrGet() while (iter.hasElement()) { - def = (AggFldDef*) iter.nextElement(); + def = (AggFldDef*) iter.nextElement(); switch(def->atype) { case AGG_MIN: { *(int*)(offset)=INT_MAX; break; } case AGG_MAX: { *(int*)(offset)=INT_MIN; break; } case AGG_SUM: { *(int*)(offset)=0; break; } - case AGG_AVG: { - *(int*)(offset)=0; + case AGG_AVG: { + *(int*)(offset)=0; *(int*)(offset+AllDataType::size(def->type, def->length))=0; //count - offset = offset+ sizeof(int); - break; + offset = offset+ sizeof(int); + break; } case AGG_COUNT: { *(int*)(offset)=0; break; } - } + } offset = offset + AllDataType::size(def->type, def->length); - } + } aggNodes.append(element); return element; } @@ -225,13 +222,13 @@ void* AggTableImpl::fetch() copyValuesToBindBuffer(elem); return elem; } - else + else return NULL; } void* AggTableImpl::fetch(DbRetVal &rv) { - rv = OK; + rv = OK; return fetch(); } @@ -258,7 +255,7 @@ DbRetVal AggTableImpl::copyValuesToBindBuffer(void *elem) //Iterate through the bind list and copy the value here ListIterator fIter = fldList.getIterator(); AggFldDef *def; - AllDataType::copyVal(groupFld.appBuf, elem, groupFld.type, groupFld.length); + AllDataType::copyVal(groupFld.appBuf, elem, groupFld.type, groupFld.length); char *colPtr = (char*) elem + AllDataType::size(groupFld.type, groupFld.length); while (fIter.hasElement()) { @@ -287,6 +284,7 @@ void AggTableImpl::closeScan() } aggNodes.reset(); } + DbRetVal AggTableImpl::close() { //free memory allocated. make sure that field buffers are freed only once. @@ -302,3 +300,260 @@ DbRetVal AggTableImpl::close() fldList.reset(); return OK; } + + + + + + + +//----------------------------------------------------------- + +JoinTableImpl::JoinTableImpl() +{ + isNestedLoop= true; +} +JoinTableImpl::~JoinTableImpl() +{ +} +void JoinTableImpl::getFieldNameAlone(char *fname, char *name) { + bool dotFound= false; + char *fullname = fname; + while(*fullname != '\0') + { + if (*fullname == '.') { dotFound = true; break; } + fullname++; + } + if (dotFound) strcpy(name, ++fullname); else strcpy(name, fname); + +} +void JoinTableImpl::getTableNameAlone(char *fname, char *name) { + strcpy(name, fname); + while(*name != '\0') + { + if (*name == '.') { *name='\0'; break; } + name++; + } + return; +} +DbRetVal JoinTableImpl::bindFld(const char *fldname, void *val) +{ + FieldInfo *info = new FieldInfo(); + char tableName[IDENTIFIER_LENGTH]; + char fieldName[IDENTIFIER_LENGTH]; + getTableNameAlone((char*)fldname, tableName); + getFieldNameAlone((char*)fldname, fieldName); + printf("%s %s \n", tableName, fieldName); + + ListIterator iter = projList.getIterator(); + JoinProjFieldInfo *elem; + while (iter.hasElement()) + { + elem = (JoinProjFieldInfo*) iter.nextElement(); + if (strcmp(elem->fieldName, fieldName)==0 && + strcmp(elem->tableName, tableName) ==0) + { + printError(ErrBadCall, "Field already binded %s\n", fldname); + delete info; + return ErrBadCall; + } + } + JoinProjFieldInfo *def = new JoinProjFieldInfo(); + strcpy(def->tableName, tableName); + strcpy(def->fieldName, fieldName); + def->appBuf = val; + def->bindBuf = AllDataType::alloc(def->type, def->length); + + if (strcmp(tableName, leftTableHdl->getName()) == 0) + { + leftTableHdl->getFieldInfo(fieldName, info); + def->bindBuf = AllDataType::alloc(info->type, info->length); + leftTableHdl->bindFld(fieldName, def->bindBuf); + + }else if (strcmp(tableName, rightTableHdl->getName()) == 0) + { + rightTableHdl->getFieldInfo(fieldName, info); + def->bindBuf = AllDataType::alloc(info->type, info->length); + rightTableHdl->bindFld(fieldName, def->bindBuf); + }else + { + printError(ErrBadCall, "TableName is invalid\n"); + delete info; + return ErrBadCall; + } + def->type = info->type; + def->length= info->length; + projList.append(def); + delete info; + return OK; +} +DbRetVal JoinTableImpl::setJoinCondition(const char *fldname1, + ComparisionOp op, + const char *fldname2) +{ + getTableNameAlone((char*)fldname1, jCondition.tableName1); + getFieldNameAlone((char*)fldname1, jCondition.fieldName1); + getTableNameAlone((char*)fldname2, jCondition.tableName2); + getFieldNameAlone((char*)fldname2, jCondition.fieldName2); + + //check if it is already binded + ListIterator iter = projList.getIterator(); + JoinProjFieldInfo *elem; + jCondition.alreadyBinded1 = false; + jCondition.alreadyBinded2 = false; + jCondition.op = op; + while (iter.hasElement()) + { + elem = (JoinProjFieldInfo*) iter.nextElement(); + if (strcmp(elem->fieldName, jCondition.fieldName1)==0 && + strcmp(elem->tableName, jCondition.tableName1) ==0) + { + jCondition.alreadyBinded1 = true; + jCondition.bindBuf1 = elem->bindBuf; + jCondition.type1 = elem->type; + jCondition.length1 = elem->length; + } + if (strcmp(elem->fieldName, jCondition.fieldName2)==0 && + strcmp(elem->tableName, jCondition.tableName2) ==0) + { + jCondition.alreadyBinded2 = true; + jCondition.bindBuf2 = elem->bindBuf; + jCondition.type2 = elem->type; + jCondition.length2 = elem->length; + } + } + + FieldInfo *info = new FieldInfo(); + if (!jCondition.alreadyBinded1) { + if (strcmp(jCondition.tableName1, leftTableHdl->getName()) == 0) + { + leftTableHdl->getFieldInfo(jCondition.fieldName1, info); + jCondition.bindBuf1 = AllDataType::alloc(info->type, info->length); + leftTableHdl->bindFld(jCondition.fieldName1, jCondition.bindBuf1); + + }else if (strcmp(jCondition.tableName1, rightTableHdl->getName()) == 0) + { + rightTableHdl->getFieldInfo(jCondition.fieldName1, info); + jCondition.bindBuf1 = AllDataType::alloc(info->type, info->length); + rightTableHdl->bindFld(jCondition.fieldName1, jCondition.bindBuf1); + }else + { + printError(ErrBadCall, "TableName is invalid\n"); + delete info; + return ErrBadCall; + } + } + if (!jCondition.alreadyBinded2) { + if (strcmp(jCondition.tableName2, leftTableHdl->getName()) == 0) + { + leftTableHdl->getFieldInfo(jCondition.fieldName2, info); + jCondition.bindBuf2 = AllDataType::alloc(info->type, info->length); + leftTableHdl->bindFld(jCondition.fieldName2, jCondition.bindBuf2); + + }else if (strcmp(jCondition.tableName2, rightTableHdl->getName()) == 0) + { + rightTableHdl->getFieldInfo(jCondition.fieldName2, info); + jCondition.bindBuf2 = AllDataType::alloc(info->type, info->length); + rightTableHdl->bindFld(jCondition.fieldName2, jCondition.bindBuf2); + }else + { + printError(ErrBadCall, "TableName is invalid\n"); + delete info; + return ErrBadCall; + } + } + return OK; +} + + +DbRetVal JoinTableImpl::execute() +{ + isNestedLoop = true; + leftTableHdl->execute(); + rightTableHdl->execute(); + leftTableHdl->fetch(); + //TODO + //if join condition is not set then do nl + //if it is inner join, hen do nl + //nl cannot be done for outer join + return OK; +} + +void* JoinTableImpl::fetch() +{ + if (isNestedLoop) + { + void *rec = rightTableHdl->fetch(); + if (rec==NULL) + { + rightTableHdl->close(); + rightTableHdl->execute(); + rec = rightTableHdl->fetch(); + if (rec == NULL) return NULL; + rec = leftTableHdl->fetch(); + if (rec == NULL) return NULL; + bool result = evaluate(); + if (! result) return fetch(); + copyValuesToBindBuffer(NULL); + return rec; + } + else { + bool result = evaluate(); + if (! result) return fetch(); + copyValuesToBindBuffer(NULL); + return rec; + } + + } + return NULL; +} +bool JoinTableImpl::evaluate() +{ + if (!jCondition.bindBuf1 || !jCondition.bindBuf2) return true; + return AllDataType::compareVal(jCondition.bindBuf1, jCondition.bindBuf2, + jCondition.op, + jCondition.type1, jCondition.length1); +} +void* JoinTableImpl::fetch(DbRetVal &rv) +{ + rv = OK; + return fetch(); +} + +void* JoinTableImpl::fetchNoBind() +{ + return NULL; +} + +void* JoinTableImpl::fetchNoBind(DbRetVal &rv) +{ + rv = OK; + return fetchNoBind(); +} + +DbRetVal JoinTableImpl::copyValuesToBindBuffer(void *elem) +{ + //Iterate through the bind list and copy the value here + ListIterator fIter = projList.getIterator(); + JoinProjFieldInfo *def; + while (fIter.hasElement()) + { + def = (JoinProjFieldInfo*) fIter.nextElement(); + if (NULL != def->appBuf) { + AllDataType::copyVal(def->appBuf, def->bindBuf, def->type, def->length); + } + } + return OK; +} + +long JoinTableImpl::numTuples() +{ + return 0; +} +void JoinTableImpl::closeScan() +{ +} +DbRetVal JoinTableImpl::close() +{ + return OK; +} diff --git a/src/server/Makefile.am b/src/server/Makefile.am index 51e0f211..2ef1d092 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -6,7 +6,7 @@ libcsql_la_SOURCES = BucketIter.cxx BucketList.cxx CatalogTables.cxx Chunk.cxx \ ChunkIterator.cxx Condition.cxx Connection.cxx Database.cxx DatabaseManagerImpl.cxx DataType.cxx \ Debug.cxx FieldList.cxx Index.cxx LockListIter.cxx LockManager.cxx Logger.cxx Mutex.cxx os.cxx \ PageInfo.cxx PredicateImpl.cxx SessionImpl.cxx TableDef.cxx TableImpl.cxx Transaction.cxx \ - TransactionManager.cxx TupleIterator.cxx UserManagerImpl.cxx HashIndex.cxx Config.cxx Process.cxx AggTableImpl.cxx + TransactionManager.cxx TupleIterator.cxx UserManagerImpl.cxx HashIndex.cxx Config.cxx Process.cxx AggTableImpl.cxx JoinTableImpl.cxx #bin_PROGRAMS = csqlserver #csqlserver_SOURCES = Server.cxx #csqlserver_LDADD = $(top_builddir)/src/cache/libcacheload.la \ diff --git a/src/sql/ParsedData.cxx b/src/sql/ParsedData.cxx index 57e94328..3bc2e7aa 100644 --- a/src/sql/ParsedData.cxx +++ b/src/sql/ParsedData.cxx @@ -63,12 +63,19 @@ void** ParsedData::insertCondValueAndGetPtr(char *fldName, char *val) } -void ParsedData::insertField(char *fName) +void ParsedData::insertField(char *fName, AggType type) { FieldName *newVal = new FieldName(); strcpy(newVal->fldName , fName); + newVal->aType = type; fieldNameList.append(newVal); } +void ParsedData::insertGroupField(char *fName) +{ + FieldName *newVal = new FieldName(); + strcpy(newVal->fldName , fName); + groupFieldNameList.append(newVal); +} void ParsedData::insertUpdateValue(char *fName, char *val) { diff --git a/src/sql/Parser.h b/src/sql/Parser.h index ad6af89e..0b7f517c 100644 --- a/src/sql/Parser.h +++ b/src/sql/Parser.h @@ -20,6 +20,7 @@ #ifndef PARSER_H #define PARSER_H #include +#include #include #include enum StatementType @@ -58,6 +59,12 @@ struct ConditionValue struct FieldName { char fldName[IDENTIFIER_LENGTH]; + AggType aType; //used only in case of select projection + FieldName() + { + strcpy(fldName,""); + aType = AGG_UNKNOWN; + } }; struct UpdateFieldValue @@ -86,6 +93,8 @@ class ParsedData //also used to store primary or unique key fields in create statement List fieldNameList; + List groupFieldNameList; + //holds pointer to condition values. List conditionValueList; @@ -132,7 +141,8 @@ class ParsedData void** insertCondValueAndGetPtr(char *fName, char *value); void insertUpdateValue(char *fldName, char *value); - void insertField(char *fName); + void insertField(char *fName, AggType aggType= AGG_UNKNOWN); + void insertGroupField(char *fName); void clearFieldNameList(); @@ -150,6 +160,7 @@ class ParsedData void insertFieldValue(FieldValue *newVal) { fieldValueList.append(newVal); } List getFieldNameList() { return fieldNameList; } + List getGroupFieldNameList() { return groupFieldNameList; } List getConditionValueList() { return conditionValueList; } List getFieldValueList() { return fieldValueList; } List getInValueList() { return inValueList; } diff --git a/src/sql/SelStatement.cxx b/src/sql/SelStatement.cxx index 13efb0c3..870d38ff 100644 --- a/src/sql/SelStatement.cxx +++ b/src/sql/SelStatement.cxx @@ -250,6 +250,16 @@ DbRetVal SelStatement::resolve() FieldName *name = NULL; FieldInfo *fInfo = new FieldInfo(); DbRetVal rv = OK; + bool aggFlag = false; + AggTableImpl *aggTable = NULL; + //TODO::Projection should have only aggregates and field names in + // group by list only + int groupFieldListSize = parsedData->getGroupFieldNameList().size(); + if (groupFieldListSize !=0) { + aggTable = new AggTableImpl(); + aggTable->setTable(table); + } + bool isGroupFldInProjection = false; while (iter.hasElement()) { name = (FieldName*)iter.nextElement(); @@ -295,14 +305,46 @@ DbRetVal SelStatement::resolve() newVal->length = fInfo->length; newVal->value = AllDataType::alloc(fInfo->type, fInfo->length); parsedData->insertFieldValue(newVal); - table->bindFld(name->fldName, newVal->value); + if (name->aType == AGG_UNKNOWN) { + if (groupFieldListSize == 0) { + table->bindFld(name->fldName, newVal->value); + }else { + delete newVal; + FieldName *groupFldName = NULL; + ListIterator giter = parsedData->getGroupFieldNameList(). + getIterator(); + while (giter.hasElement()) + { + groupFldName = (FieldName*)giter.nextElement(); + if (strcmp(groupFldName->fldName, name->fldName) ==0) { + isGroupFldInProjection = true; + aggTable->setGroup(name->fldName, newVal->value); + } + } + if (!isGroupFldInProjection) + { + printError(ErrSyntax, "Projection should contain only group fields\n"); + delete fInfo; + dbMgr->closeTable(table); + table = NULL; + return ErrSyntax; + } + } + } else { + if (!aggFlag) { + aggTable = new AggTableImpl(); + aggTable->setTable(table); + aggFlag = true; + } + aggTable->bindFld(name->fldName, name->aType, newVal->value); + } } } - delete fInfo; rv = setBindFieldAndValues(); if (rv != OK) { + delete fInfo; dbMgr->closeTable(table); table = NULL; return rv; @@ -313,11 +355,40 @@ DbRetVal SelStatement::resolve() rv = resolveForCondition(); if (rv != OK) { + delete fInfo; //TODO::free memory allocated for params table->setCondition(NULL); dbMgr->closeTable(table); table = NULL; } + if(aggFlag && !isGroupFldInProjection) { + ListIterator giter = parsedData->getGroupFieldNameList().getIterator(); + while (giter.hasElement()) + { + name = (FieldName*)giter.nextElement(); + rv = table->getFieldInfo(name->fldName, fInfo); + if (ErrNotFound == rv) + { + dbMgr->closeTable(table); + table = NULL; + delete fInfo; + delete aggTable; + printError(ErrSyntaxError, "Field %s does not exist in table", + name->fldName); + return ErrSyntaxError; + } + FieldValue *newVal = new FieldValue(); + newVal->parsedString = NULL; + newVal->paramNo = 0; + newVal->type = fInfo->type; + newVal->length = fInfo->length; + newVal->value = AllDataType::alloc(fInfo->type, fInfo->length); + parsedData->insertFieldValue(newVal); + aggTable->setGroup(name->fldName, newVal->value); + } + table = aggTable; + } + delete fInfo; return rv; } DbRetVal SelStatement::resolveStar() diff --git a/src/sql/dmllex.lxx b/src/sql/dmllex.lxx index 09501a17..b8ddaa2a 100644 --- a/src/sql/dmllex.lxx +++ b/src/sql/dmllex.lxx @@ -129,6 +129,13 @@ operator "<"|">"|">="|"<="|"="|"\!="|"<>" if(strcasecmp(yytext,"BIGINT") ==0) token = BIGINT_TYPE; if(strcasecmp(yytext,"TINYINT") ==0) token = TINYINT_TYPE; if(strcasecmp(yytext,"FLOAT") ==0) token = FLOAT_TYPE; + if(strcasecmp(yytext,"MIN") ==0) token = MIN; + if(strcasecmp(yytext,"MAX") ==0) token = MAX; + if(strcasecmp(yytext,"SUM") ==0) token = SUM; + if(strcasecmp(yytext,"AVG") ==0) token = AVG; + if(strcasecmp(yytext,"COUNT") ==0) token = COUNT; + if(strcasecmp(yytext,"GROUP") ==0) token = GROUP; + if(strcasecmp(yytext,"BY") ==0) token = BY; if( token == FIELD ) yylval.stringval = strdup((const char*)yytext); diff --git a/src/sql/dmlyacc.h b/src/sql/dmlyacc.h index 18230f71..57b29633 100644 --- a/src/sql/dmlyacc.h +++ b/src/sql/dmlyacc.h @@ -43,6 +43,13 @@ #define BIGINT_TYPE 299 #define FLOAT_TYPE 300 #define TINYINT_TYPE 301 +#define MIN 302 +#define MAX 303 +#define AVG 304 +#define SUM 305 +#define COUNT 306 +#define GROUP 307 +#define BY 308 typedef union { char *stringval; diff --git a/src/sql/dmlyacc.yxx b/src/sql/dmlyacc.yxx index bdc0bd02..cc09de53 100644 --- a/src/sql/dmlyacc.yxx +++ b/src/sql/dmlyacc.yxx @@ -25,6 +25,7 @@ void yyerror(const char* Msg); %token DELETE UPDATE SET NULL_VALUE %token CREATE TABLE PRIMARY KEY DEFAULT INDEX ON HASH TREE UNIQUE DROP %token INT_TYPE LONG_TYPE SHORT_TYPE DOUBLE_TYPE TIMESTAMP_TYPE DATE_TYPE CHAR_TYPE TIME_TYPE BIGINT_TYPE FLOAT_TYPE TINYINT_TYPE +%token MIN MAX AVG SUM COUNT GROUP BY %token ';' ',' '(' ')' %type ident field value not_opt %type conditions condition @@ -37,7 +38,7 @@ command: select_statement { YYACCEPT; } | ddl_statement { YYACCEPT; } ; -select_statement: SELECT field_list FROM ident where_clause_opt semicolon_opt +select_statement: SELECT field_list FROM ident where_clause_opt group_by_opt semicolon_opt { parsedData->setStmtType(SelectStatement); parsedData->setTableName($4); @@ -127,7 +128,20 @@ assign_stmt: ident OPERATOR value where_clause_opt: WHERE conditions | ; - +group_by_opt: GROUP BY group_field_list + | + ; +group_field_list: group_field_list group_field_list_L + | group_field + ; +group_field_list_L: ',' group_field + ; +group_field: ident + { + parsedData->insertGroupField((char*)$1); + free( $1 ); + } + ; conditions: conditions AND conditions { Predicate *pred; @@ -226,6 +240,31 @@ field: ident parsedData->insertField((char*)$1); free( $1 ); } + | MIN '(' ident ')' + { + parsedData->insertField((char*)$3, AGG_MIN); + free( $1 ); + } + | MAX '(' ident ')' + { + parsedData->insertField((char*)$3, AGG_MAX); + free( $1 ); + } + | SUM '(' ident ')' + { + parsedData->insertField((char*)$3, AGG_SUM); + free( $1 ); + } + | AVG '(' ident ')' + { + parsedData->insertField((char*)$3, AGG_AVG); + free( $1 ); + } + | COUNT '(' ident ')' + { + parsedData->insertField((char*)$3, AGG_COUNT); + free( $1 ); + } | STAR { parsedData->insertField((char*)$1); diff --git a/tmptest/test.c b/tmptest/test.c dissimilarity index 97% index 5abe12e1..69b73bd9 100644 --- a/tmptest/test.c +++ b/tmptest/test.c @@ -1,41 +1,112 @@ -#include -#include -int main() -{ - DbRetVal rv = OK; - SqlConnection *con = new SqlConnection(); - con->connect("root", "manager"); - printf("Connected\n"); - SqlStatement *stmt = new SqlStatement(); - stmt->setConnection(con); - char statement[1024]; - //strcpy(statement, "INSERT INTO t1 (f1, f2) VALUES (100, 200);"); - strcpy(statement, "INSERT INTO t1 (f1, f2, f3) VALUES (?, ?, ?);"); - //strcpy(statement, "INSERT INTO t1 VALUES (100, 200);"); - //strcpy(statement, "INSERT INTO t1 "); - int rows =0; - rv = stmt->prepare(statement); - printf("Prepeared\n"); - int id1 =100, id2 = 100; - if (rv != OK) {delete stmt; delete con; return -1; } - NanoTimer timer; - for (int i = 0 ; i < 100000 ; i++) - { - timer.start(); - con->beginTrans(); - id1 = i; id2 = i; - stmt->setIntParam(1, id1); - stmt->setIntParam(2, id1); - stmt->setIntParam(3, id1); - - stmt->execute(rows); - timer.stop(); - con->commit(); - } -//{printf("Sleeping\n"); sleep(10);} - printf("Insert %lld %lld %lld\n", timer.min(), timer.max(), timer.avg()); - stmt->free(); - delete stmt; - delete con; - return 0; -} +/*************************************************************************** + * Copyright (C) 2007 by www.databasecache.com * + * Contact: praba_tuty@databasecache.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + **************************************************************************/ +#include +#include +int main() +{ + //connect to the database first + Connection conn; + char *tuple; + int ret; + int i; + int icount =0; + DbRetVal rv = conn.open("root", "manager"); + if (rv != OK) + { + printf("Error during connection %d\n", rv); + return -1; + } + + //get dbmgr to create table and index + DatabaseManager *dbMgr = conn.getDatabaseManager(); + if (dbMgr == NULL) { printf("Auth failed\n"); return -1;} +/* + //create table with two fields, f1 integer and f2 string + TableDef tabDef; + tabDef.addField("f1", typeInt, 0, NULL, true); + tabDef.addField("f2", typeInt); + rv = dbMgr->createTable("t1", tabDef); + if (rv != OK) { printf("Table creation failed\n"); return -1; } + printf("Table created\n"); + rv = dbMgr->createTable("t2", tabDef); + if (rv != OK) { printf("Table creation failed\n"); return -1; } +*/ + //open the table handle for doing DML operations + Table *table = dbMgr->openTable("t1"); + Table *table1 = dbMgr->openTable("t2"); +/* + if (table == NULL) { printf("Unable to open table\n"); return -1; } + int id1 = 0, id2=0; + table->bindFld("f1", &id1); + table1->bindFld("f1", &id1); + table->bindFld("f2", &id2); + table1->bindFld("f2", &id2); + + //insert 10 tuples into the table t1 + for(i = 0; i< 5; i++) + { + conn.startTransaction(); + id1= i; id2 = i %3; + ret = table->insertTuple(); + if (ret != 0) break; + ret = table1->insertTuple(); + if (ret != 0) break; + icount++; + conn.commit(); + } + char msgBuf[1024]; + sprintf(msgBuf,"Total rows inserted %d \n",icount); + os::write(1,msgBuf,strlen(msgBuf)); + dbMgr->closeTable(table); + dbMgr->closeTable(table1); + + table = dbMgr->openTable("t1"); + if (table == NULL) { printf("Unable to open table\n"); return -1; } + table1 = dbMgr->openTable("t2"); + if (table1 == NULL) { printf("Unable to open table\n"); return -1; } +*/ + + JoinTableImpl joinTable; + joinTable.setTable(table, table1); + int out1, out2, out3; + joinTable.bindFld("t1.f1", &out1); + joinTable.bindFld("t1.f2", &out2); + joinTable.bindFld("t2.f2", &out3); + + joinTable.setJoinCondition("t1.f2", OpEquals, "t2.f1"); + + conn.startTransaction(); + joinTable.execute(); + printf("Tuple values:\n"); + int cnt=0; + while(true) + { + tuple = (char*)joinTable.fetch() ; + if (tuple == NULL) { break; } + printf("Tuple %d: %d %d %d\n", cnt++, out1, out2, out3); + icount++; + } + joinTable.closeScan(); + conn.commit(); + joinTable.close(); + + dbMgr->closeTable(table); + dbMgr->closeTable(table1); + // dbMgr->dropTable("t1"); + printf("Table dropped\n"); + conn.close(); + return 0; +} -- 2.11.4.GIT