src/adapter/SqlOdbcStatement.cxx

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007 by Prabakaran Thirumalai   *
00003  *   praba_tuty@yahoo.com   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 #include <SqlOdbcStatement.h>
00021 //Important Note: MySQL Bug
00022 //Bug #1382     SQLDescribeParam returns the same type information for any type
00023 //as varchar of length 255. To avoid this, this class converts every data type
00024 //to varchar by using appropriate conversion functions.
00025 
00026 DbRetVal SqlOdbcStatement::prepare(char *stmtstr)
00027 {
00028     DbRetVal rv = OK;
00029     if (innerStmt) rv = ErrBadCall;
00030     if (rv != OK) return rv;
00031     int retValue;
00032     isPrepared = false;
00033     SqlOdbcConnection *conn = (SqlOdbcConnection*)con;
00034     retValue=SQLAllocHandle (SQL_HANDLE_STMT, conn->dbHdl, &hstmt);
00035     if (retValue) return ErrBadCall;
00036     retValue = SQLPrepare (hstmt, (unsigned char *) stmtstr, SQL_NTS);
00037     if (retValue) return ErrBadCall;
00038     isPrepared = true;
00039     short totalFields=0;
00040     retValue = SQLNumResultCols (hstmt, &totalFields);
00041     if (retValue) return ErrBadCall;
00042     BindSqlProjectField *bindProjField = NULL;
00043     UWORD                   icol;
00044     UCHAR                   colName[IDENTIFIER_LENGTH];
00045     SWORD                   colNameMax;
00046     SWORD                   nameLength;
00047     SWORD                   colType;
00048     SQLULEN                 colLength;
00049     SWORD                   scale;
00050     SWORD                   nullable;
00051     icol = 1; colNameMax = IDENTIFIER_LENGTH;
00052     while (icol <= totalFields)
00053     {
00054         retValue = SQLDescribeCol(hstmt, icol, colName, colNameMax,
00055                    &nameLength, &colType, &colLength,
00056                    &scale, &nullable);
00057         if (retValue) return ErrBadCall;
00058         
00059         bindProjField = new BindSqlProjectField();
00060         strncpy(bindProjField->fName, (char*)colName, IDENTIFIER_LENGTH);
00061         bindProjField->fName[IDENTIFIER_LENGTH] = '\0';
00062         bindProjField->type = AllDataType::convertFromSQLType(colType);
00063         bindProjField->length = colLength +1;
00064         bindProjField->value = NULL;
00065         bindProjField->targetvalue = NULL;
00066         int fieldsize =0;
00067         switch(bindProjField->type)
00068         {
00069             case typeString:
00070                 fieldsize = colLength+1;
00071                 bindProjField->targetvalue = malloc(fieldsize); 
00072                 break;
00073             case typeDate:
00074                 fieldsize = sizeof(DATE_STRUCT);
00075                 bindProjField->targetvalue = malloc(sizeof(DATE_STRUCT));
00076                 break;
00077             case typeTime:
00078                 fieldsize = sizeof(TIME_STRUCT);
00079                 bindProjField->targetvalue = malloc(sizeof(TIME_STRUCT));
00080                 break;
00081             case typeTimeStamp:
00082                 fieldsize = sizeof(TIMESTAMP_STRUCT);
00083                 bindProjField->targetvalue = malloc(sizeof(TIMESTAMP_STRUCT));
00084                 break;
00085             default:
00086                 bindProjField->targetvalue = AllDataType::alloc(bindProjField->type, bindProjField->length);
00087         }
00088         retValue = SQLBindCol(hstmt, icol, 
00089                               AllDataType::convertToSQLType(bindProjField->type),
00090                               bindProjField->targetvalue, fieldsize, NULL);
00091         if (retValue) return ErrBadCall; 
00092         bindList.append(bindProjField);
00093         icol++;
00094        
00095     }
00096     totalFields =0;
00097     BindSqlField *bindField;
00098     retValue = SQLNumParams (hstmt, &totalFields);
00099     if (retValue) return ErrBadCall;
00100     icol = 1; colNameMax = IDENTIFIER_LENGTH;
00101     SWORD                   cType=0;
00102     SQLULEN                 cLength=0;
00103     while (icol <= totalFields)
00104     {
00105         retValue = SQLDescribeParam(hstmt, icol, &cType, &cLength,
00106                    &scale, &nullable);
00107         //Note: MySQL Bug
00108         //Bug #1382     SQLDescribeParam returns the same type information
00109 
00110         if (retValue) return ErrBadCall;
00111         
00112         bindField = new BindSqlField();
00113         bindField->type = AllDataType::convertFromSQLType(cType);
00114         bindField->length = cLength;
00115         bindField->value =  AllDataType::alloc(bindField->type, cLength);
00116         bindField->targetvalue = NULL;
00117         int fieldsize =0;
00118         switch(bindField->type)
00119         {
00120             case typeString:
00121                 fieldsize = cLength;
00122                 bindField->targetvalue = malloc(fieldsize);
00123                 break;
00124             case typeDate:
00125                 fieldsize = sizeof(DATE_STRUCT);
00126                 bindField->targetvalue = malloc(sizeof(DATE_STRUCT));
00127                 break;
00128             case typeTime:
00129                 fieldsize = sizeof(TIME_STRUCT);
00130                 bindField->targetvalue = malloc(sizeof(TIME_STRUCT));
00131                 break;
00132             case typeTimeStamp:
00133                 fieldsize = sizeof(TIMESTAMP_STRUCT);
00134                 bindField->targetvalue = malloc(sizeof(TIMESTAMP_STRUCT));
00135                 break;
00136             default:
00137                 bindField->targetvalue = AllDataType::alloc(bindField->type, cLength);
00138                 break;
00139 
00140         }
00141         retValue = SQLBindParameter(hstmt, icol, SQL_PARAM_INPUT, 
00142                       AllDataType::convertToSQL_C_Type(bindField->type), 
00143                       cType, fieldsize, scale, bindField->targetvalue, 
00144                       fieldsize, NULL);
00145         if (retValue) return ErrBadCall;
00146         paramList.append(bindField);
00147         icol++;
00148     }
00149     //TODO::deallocate memory and remove elements from list in case of any
00150     //failure in any of the above ODBC functions
00151     return OK;
00152 }
00153 
00154 bool SqlOdbcStatement::isSelect()
00155 {
00156     //TODO
00157     return false;
00158 }
00159 
00160 DbRetVal SqlOdbcStatement::execute(int &rowsAffected)
00161 {
00162     DbRetVal rv = OK;
00163     if (!isPrepared) return OK;
00164     ListIterator iter = paramList.getIterator();
00165     BindSqlField *bindField = NULL;
00166     while (iter.hasElement())
00167     {
00168         bindField = (BindSqlField*)iter.nextElement();
00169         switch(bindField->type)
00170         {
00171             case typeDate: {
00172                 Date *dtCSQL = (Date*) bindField->value;
00173                 DATE_STRUCT *dtTarget = (DATE_STRUCT*) bindField->targetvalue;
00174                 dtTarget->year= dtCSQL->year();
00175                 dtTarget->month= dtCSQL->month();
00176                 dtTarget->day = dtCSQL->dayOfMonth();
00177                 break;
00178             }
00179             case typeTime: {
00180                 Time *dtCSQL = (Time*) bindField->value;
00181                 TIME_STRUCT *dtTarget = (TIME_STRUCT*) bindField->targetvalue;
00182                 dtTarget->hour = dtCSQL->hours();
00183                 dtTarget->minute = dtCSQL->minutes();
00184                 dtTarget->second = dtCSQL->seconds();
00185                 break;
00186             }
00187             case typeTimeStamp: {
00188                 TimeStamp *dtCSQL = (TimeStamp*) bindField->value;
00189                 TIMESTAMP_STRUCT *dtTarget = (TIMESTAMP_STRUCT*) bindField->targetvalue;
00190                 dtTarget->year= dtCSQL->year();
00191                 dtTarget->month= dtCSQL->month();
00192                 dtTarget->day = dtCSQL->dayOfMonth();
00193                 dtTarget->hour = dtCSQL->hours();
00194                 dtTarget->minute = dtCSQL->minutes();
00195                 dtTarget->second = dtCSQL->seconds();
00196                 break;
00197             }
00198             default: {
00199                 AllDataType::copyVal(bindField->targetvalue, bindField->value,
00200                                      bindField->type, bindField->length);
00201                 break;
00202             }
00203         }
00204     }
00205     int retValue = SQLExecute (hstmt);
00206     if (retValue) return ErrBadCall;
00207     return rv;
00208 }
00209 
00210 DbRetVal SqlOdbcStatement::bindParam(int pos, void* value)
00211 {
00212     DbRetVal rv = OK;
00213     printError(ErrWarning, "Deprecated. Use setParamXXX instead\n");
00214     return rv;
00215 }
00216 
00217 DbRetVal SqlOdbcStatement::bindField(int pos, void* value)
00218 {
00219     if (!isPrepared) return OK;
00220     BindSqlProjectField *bindField = (BindSqlProjectField*)bindList.get(pos);
00221     if (NULL == bindField) 
00222     {
00223         printError(ErrBadArg, "Could not get the projection list. Should be called only for SELECT statement");
00224         return ErrBadArg;
00225     }
00226     bindField->value = value;
00227     return OK;
00228 }
00229 void* SqlOdbcStatement::fetch()
00230 {
00231     if (!isPrepared) return NULL;
00232     int retValue = SQLFetch (hstmt);
00233     if (retValue) return NULL;
00234     ListIterator iter = bindList.getIterator();
00235     BindSqlProjectField *bindField = NULL;
00236     void *ptrToFirstField = NULL;
00237     while (iter.hasElement())
00238     {
00239         bindField = (BindSqlProjectField*)iter.nextElement();
00240         switch(bindField->type)
00241         {
00242             case typeDate: {
00243                 Date *dtCSQL = (Date*) bindField->value;
00244                 DATE_STRUCT *dtTarget = (DATE_STRUCT*) bindField->targetvalue;
00245                 dtCSQL->set(dtTarget->year,dtTarget->month,dtTarget->day);
00246                 break;
00247             }
00248             case typeTime: {
00249                 Time *dtCSQL = (Time*) bindField->value;
00250                 TIME_STRUCT *dtTarget = (TIME_STRUCT*) bindField->targetvalue;
00251                 dtCSQL->set(dtTarget->hour,dtTarget->minute,dtTarget->second);
00252                 break;
00253             }
00254             case typeTimeStamp: {
00255                 TimeStamp *dtCSQL = (TimeStamp*) bindField->value;
00256                 TIMESTAMP_STRUCT *dtTarget = (TIMESTAMP_STRUCT*) bindField->targetvalue;
00257                 dtCSQL->setDate(dtTarget->year,dtTarget->month,dtTarget->day);
00258                 dtCSQL->setTime(dtTarget->hour,dtTarget->minute,
00259                                 dtTarget->second, dtTarget->fraction);
00260                 break;
00261             }
00262             default: {
00263                 AllDataType::copyVal(bindField->value, bindField->targetvalue,
00264                                      bindField->type, bindField->length);
00265                 break;
00266             }
00267         } 
00268         if (ptrToFirstField == NULL) ptrToFirstField=bindField->value;
00269     }
00270     return ptrToFirstField;
00271 }
00272 
00273 void* SqlOdbcStatement::fetchAndPrint(bool SQL)
00274 {
00275     if (!isPrepared) return NULL;
00276     int retValue = SQLFetch (hstmt);
00277     if (retValue) return NULL;
00278     ListIterator iter = bindList.getIterator();
00279     BindSqlProjectField *bindField = NULL;
00280     void *ptrToFirstField = NULL;
00281     while (iter.hasElement())
00282     {
00283         bindField = (BindSqlProjectField*)iter.nextElement();
00284         switch(bindField->type)
00285         {
00286             case typeDate: {
00287                 Date dtCSQL;
00288                 DATE_STRUCT *dtTarget = (DATE_STRUCT*) bindField->targetvalue;
00289                 dtCSQL.set(dtTarget->year,dtTarget->month,dtTarget->day);
00290                 AllDataType::printVal(&dtCSQL, bindField->type, bindField->length);
00291                 break;
00292             }
00293             case typeTime: {
00294                 Time dtCSQL;
00295                 TIME_STRUCT *dtTarget = (TIME_STRUCT*) bindField->targetvalue;
00296                 dtCSQL.set(dtTarget->hour,dtTarget->minute,dtTarget->second);
00297                 AllDataType::printVal(&dtCSQL, bindField->type, bindField->length);
00298                 break;
00299             }
00300             case typeTimeStamp: {
00301                 TimeStamp dtCSQL;
00302                 TIMESTAMP_STRUCT *dtTarget = (TIMESTAMP_STRUCT*) bindField->targetvalue;
00303                 dtCSQL.setDate(dtTarget->year,dtTarget->month,dtTarget->day);
00304                 dtCSQL.setTime(dtTarget->hour,dtTarget->minute,
00305                                 dtTarget->second, dtTarget->fraction);
00306                 AllDataType::printVal(&dtCSQL, bindField->type, bindField->length);
00307                 break;
00308             }
00309             default: {
00310                 AllDataType::printVal(bindField->targetvalue,
00311                                      bindField->type, bindField->length);
00312                 break;
00313             }
00314         }
00315         if (ptrToFirstField == NULL) ptrToFirstField=bindField->targetvalue;
00316         printf("\t");
00317     }
00318 
00319     return ptrToFirstField;
00320 }
00321 
00322 void* SqlOdbcStatement::next()
00323 {
00324     return fetch();
00325 }
00326 
00327 DbRetVal SqlOdbcStatement::close()
00328 {
00329     if (!isPrepared) return OK;
00330     SQLCloseCursor(hstmt);
00331     return OK;
00332 }
00333 
00334 void* SqlOdbcStatement::getFieldValuePtr( int pos )
00335 {
00336     return NULL;
00337 }
00338 
00339 int SqlOdbcStatement::noOfProjFields()
00340 {
00341     if (!isPrepared) return 0;
00342     return bindList.size();
00343 }
00344 
00345 int SqlOdbcStatement::noOfParamFields()
00346 {
00347     if (!isPrepared) return 0;
00348     return paramList.size();
00349 }
00350 
00351 DbRetVal SqlOdbcStatement::getProjFldInfo (int projpos, FieldInfo *&fInfo)
00352 {
00353     ListIterator biter = bindList.getIterator();
00354     BindSqlProjectField *elem = NULL;
00355     int count =0;
00356     while (biter.hasElement())
00357     {
00358         elem = (BindSqlProjectField*) biter.nextElement();
00359         if (count == projpos) 
00360         {
00361             strcpy(fInfo->fldName, elem->fName);
00362             fInfo->length = elem->length;
00363             fInfo->type =elem->type;
00364             return OK;
00365         }
00366         count++;
00367     }
00368     return ErrNotFound;
00369 }
00370 
00371 DbRetVal SqlOdbcStatement::getParamFldInfo (int parampos, FieldInfo *&fInfo)
00372 {
00373     ListIterator biter = paramList.getIterator();
00374     BindSqlField *elem = NULL;
00375     int count =0;
00376     while (biter.hasElement())
00377     {
00378         elem = (BindSqlField*) biter.nextElement();
00379         if (count == parampos) 
00380         {
00381             fInfo->length = elem->length;
00382             fInfo->type =elem->type;
00383             return OK;
00384         }
00385         count++;
00386     }
00387     return ErrNotFound;
00388 }
00389 
00390 DbRetVal SqlOdbcStatement::free()
00391 {
00392     isPrepared = false;
00393     ListIterator biter = bindList.getIterator();
00394     BindSqlProjectField *elem = NULL;
00395     while (biter.hasElement())
00396     {
00397         elem = (BindSqlProjectField*) biter.nextElement();
00398         ::free(elem->targetvalue); 
00399         delete elem;
00400     }
00401     bindList.reset();
00402     ListIterator piter = paramList.getIterator();
00403     BindSqlField *bindField = NULL;
00404     while (piter.hasElement())
00405     {
00406         bindField = (BindSqlField*) piter.nextElement();
00407         ::free(bindField->value);
00408         ::free(bindField->targetvalue);
00409         delete bindField; 
00410     }
00411     paramList.reset();
00412 
00413     SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
00414     return OK;
00415 }
00416 void SqlOdbcStatement::setShortParam(int paramPos, short value)
00417 {
00418     if (!isPrepared) return ;
00419     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00420     if (bindField->type != typeShort) return;
00421     *(short*)(bindField->value) = value;
00422     return;
00423 }
00424 void SqlOdbcStatement::setIntParam(int paramPos, int value)
00425 {
00426     if (!isPrepared) return ;
00427     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00428     /*if (bindField->type != typeInt) return;
00429     *(int*)(bindField->value) = value;
00430     */
00431 
00432      //Note: MySQL Bug
00433      //Bug #1382     SQLDescribeParam returns the same type information, varchar
00434     AllDataType::convertToString(bindField->value, &value, typeInt);
00435 
00436     return;
00437 
00438 }
00439 void SqlOdbcStatement::setLongParam(int paramPos, long value)
00440 {
00441     if (!isPrepared) return ;
00442     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00443     //if (bindField->type != typeLong) return;
00444     //*(long*)(bindField->value) = value;
00445      //Note: MySQL Bug
00446      //Bug #1382     SQLDescribeParam returns the same type information, varchar
00447     AllDataType::convertToString(bindField->value, &value, typeLong);
00448     return;
00449 
00450 }
00451 void SqlOdbcStatement::setLongLongParam(int paramPos, long long value)
00452 {
00453     if (!isPrepared) return ;
00454     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00455     //if (bindField->type != typeLongLong) return;
00456     //*(long long*)(bindField->value) = value;
00457     AllDataType::convertToString(bindField->value, &value, typeLongLong);
00458     return;
00459 }
00460 void SqlOdbcStatement::setByteIntParam(int paramPos, ByteInt value)
00461 {
00462     if (!isPrepared) return ;
00463     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00464     //if (bindField->type != typeByteInt) return;
00465     //*(char*)(bindField->value) = value;
00466     AllDataType::convertToString(bindField->value, &value, typeByteInt);
00467 
00468 }
00469 void SqlOdbcStatement::setFloatParam(int paramPos, float value)
00470 {
00471     if (!isPrepared) return ;
00472     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00473     //if (bindField->type != typeFloat) return;
00474     //*(float*)(bindField->value) = value;
00475     AllDataType::convertToString(bindField->value, &value, typeFloat);
00476 }
00477 void SqlOdbcStatement::setDoubleParam(int paramPos, double value)
00478 {
00479     if (!isPrepared) return ;
00480     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00481     //if (bindField->type != typeDouble) return;
00482     //*(double*)(bindField->value) = value;
00483     AllDataType::convertToString(bindField->value, &value, typeDouble);
00484 
00485 }
00486 void SqlOdbcStatement::setStringParam(int paramPos, char *value)
00487 {
00488     if (!isPrepared) return ;
00489     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00490     if (bindField->type != typeString) return;
00491     char *dest = (char*)bindField->value;
00492     strncpy(dest, value, bindField->length);
00493     dest[ bindField->length - 1] ='\0';
00494     return;
00495 }
00496 void SqlOdbcStatement::setDateParam(int paramPos, Date value)
00497 {
00498     if (!isPrepared) return ;
00499     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00500     //if (bindField->type != typeDate) return;
00501     //*(Date*)(bindField->value) = value;
00502     AllDataType::convertToString(bindField->value, &value, typeDate);
00503 
00504 }
00505 void SqlOdbcStatement::setTimeParam(int paramPos, Time value)
00506 {
00507     if (!isPrepared) return ;
00508     BindSqlField *bindField = (BindSqlField*)paramList.get(paramPos);
00509     //if (bindField->type != typeTime) return;
00510     //*(Time*)(bindField->value) = value;
00511     AllDataType::convertToString(bindField->value, &value, typeTime);
00512 
00513 }
00514 void SqlOdbcStatement::setTimeStampParam(int paramPos, TimeStamp value)
00515 {
00516     if (!isPrepared) return ;
00517     BindSqlField *bindField = (BindSqlField*) paramList.get(paramPos);
00518     //if (bindField->type != typeTimeStamp) return;
00519     //*(TimeStamp*)(bindField->value) = value;
00520     AllDataType::convertToString(bindField->value, &value, typeTimeStamp);
00521 }
00522 
00523 void SqlOdbcStatement::getPrimaryKeyFieldName(char *tablename, char *pkfieldname)
00524 {
00525     if (pkfieldname == NULL) return;
00526     SqlOdbcConnection *conn = (SqlOdbcConnection*)con;
00527     int retValue=SQLAllocHandle (SQL_HANDLE_STMT, conn->dbHdl, &hstmt);
00528     if (retValue) return ;
00529     char columnName[128];
00530     SQLINTEGER cbData;     // Output length of data
00531     SQLPrimaryKeys(hstmt, NULL, 0, NULL, 0, (SQLCHAR*) tablename, SQL_NTS);
00532     SQLFetch(hstmt);
00533     SQLGetData(hstmt, 4, SQL_C_CHAR, (SQLCHAR*) columnName, sizeof(columnName),&cbData);
00534     strcpy(pkfieldname, columnName);
00535     SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
00536     return;
00537 }

Generated on Mon Jun 9 22:37:14 2008 for csql by  doxygen 1.4.7