1 /***************************************************************************
2 * Copyright (C) 2007 by Prabakaran Thirumalai *
3 * praba_tuty@yahoo.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 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include <SqlOdbcStatement.h>
21 //Important Note: MySQL Bug
22 //Bug #1382 SQLDescribeParam returns the same type information for any type
23 //as varchar of length 255. To avoid this, this class converts every data type
24 //to varchar by using appropriate conversion functions.
26 DbRetVal
SqlOdbcStatement::prepare(char *stmtstr
)
29 if (innerStmt
) rv
= ErrBadCall
;
30 if (rv
!= OK
) return rv
;
33 SqlOdbcConnection
*conn
= (SqlOdbcConnection
*)con
;
34 retValue
=SQLAllocHandle (SQL_HANDLE_STMT
, conn
->dbHdl
, &hstmt
);
35 if (retValue
) return ErrBadCall
;
36 retValue
= SQLPrepare (hstmt
, (unsigned char *) stmtstr
, SQL_NTS
);
37 if (retValue
) return ErrBadCall
;
40 retValue
= SQLNumResultCols (hstmt
, &totalFields
);
41 if (retValue
) return ErrBadCall
;
42 BindSqlProjectField
*bindProjField
= NULL
;
44 UCHAR colName
[IDENTIFIER_LENGTH
];
51 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
52 while (icol
<= totalFields
)
54 retValue
= SQLDescribeCol(hstmt
, icol
, colName
, colNameMax
,
55 &nameLength
, &colType
, &colLength
,
57 if (retValue
) return ErrBadCall
;
59 bindProjField
= new BindSqlProjectField();
60 strncpy(bindProjField
->fName
, (char*)colName
, IDENTIFIER_LENGTH
);
61 bindProjField
->fName
[IDENTIFIER_LENGTH
] = '\0';
62 bindProjField
->type
= AllDataType::convertFromSQLType(colType
);
63 bindProjField
->length
= colLength
;
64 bindProjField
->value
= NULL
;
65 bindProjField
->targetvalue
= NULL
;
67 switch(bindProjField
->type
)
70 fieldsize
= colLength
;
71 bindProjField
->targetvalue
= malloc(fieldsize
);
74 fieldsize
= sizeof(DATE_STRUCT
);
75 bindProjField
->targetvalue
= malloc(sizeof(DATE_STRUCT
));
78 fieldsize
= sizeof(TIME_STRUCT
);
79 bindProjField
->targetvalue
= malloc(sizeof(TIME_STRUCT
));
82 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
83 bindProjField
->targetvalue
= malloc(sizeof(TIMESTAMP_STRUCT
));
86 bindProjField
->targetvalue
= AllDataType::alloc(bindProjField
->type
, bindProjField
->length
);
88 retValue
= SQLBindCol(hstmt
, icol
,
89 AllDataType::convertToSQLType(bindProjField
->type
),
90 bindProjField
->targetvalue
, fieldsize
, NULL
);
91 if (retValue
) return ErrBadCall
;
92 bindList
.append(bindProjField
);
97 BindSqlField
*bindField
;
98 retValue
= SQLNumParams (hstmt
, &totalFields
);
99 if (retValue
) return ErrBadCall
;
100 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
103 while (icol
<= totalFields
)
105 retValue
= SQLDescribeParam(hstmt
, icol
, &cType
, &cLength
,
108 //Bug #1382 SQLDescribeParam returns the same type information
110 if (retValue
) return ErrBadCall
;
112 bindField
= new BindSqlField();
113 bindField
->type
= AllDataType::convertFromSQLType(cType
);
114 bindField
->length
= cLength
;
115 bindField
->value
= AllDataType::alloc(bindField
->type
, cLength
);
116 bindField
->targetvalue
= NULL
;
118 switch(bindField
->type
)
122 bindField
->targetvalue
= malloc(fieldsize
);
125 fieldsize
= sizeof(DATE_STRUCT
);
126 bindField
->targetvalue
= malloc(sizeof(DATE_STRUCT
));
129 fieldsize
= sizeof(TIME_STRUCT
);
130 bindField
->targetvalue
= malloc(sizeof(TIME_STRUCT
));
133 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
134 bindField
->targetvalue
= malloc(sizeof(TIMESTAMP_STRUCT
));
137 bindField
->targetvalue
= AllDataType::alloc(bindField
->type
, cLength
);
141 retValue
= SQLBindParameter(hstmt
, icol
, SQL_PARAM_INPUT
,
142 AllDataType::convertToSQL_C_Type(bindField
->type
),
143 cType
, fieldsize
, scale
, bindField
->targetvalue
,
145 if (retValue
) return ErrBadCall
;
146 paramList
.append(bindField
);
149 //TODO::deallocate memory and remove elements from list in case of any
150 //failure in any of the above ODBC functions
154 bool SqlOdbcStatement::isSelect()
160 DbRetVal
SqlOdbcStatement::execute(int &rowsAffected
)
163 if (!isPrepared
) return OK
;
164 ListIterator iter
= paramList
.getIterator();
165 BindSqlField
*bindField
= NULL
;
166 while (iter
.hasElement())
168 bindField
= (BindSqlField
*)iter
.nextElement();
169 switch(bindField
->type
)
172 Date
*dtCSQL
= (Date
*) bindField
->value
;
173 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
174 dtTarget
->year
= dtCSQL
->year();
175 dtTarget
->month
= dtCSQL
->month();
176 dtTarget
->day
= dtCSQL
->dayOfMonth();
180 Time
*dtCSQL
= (Time
*) bindField
->value
;
181 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
182 dtTarget
->hour
= dtCSQL
->hours();
183 dtTarget
->minute
= dtCSQL
->minutes();
184 dtTarget
->second
= dtCSQL
->seconds();
187 case typeTimeStamp
: {
188 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
189 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
190 dtTarget
->year
= dtCSQL
->year();
191 dtTarget
->month
= dtCSQL
->month();
192 dtTarget
->day
= dtCSQL
->dayOfMonth();
193 dtTarget
->hour
= dtCSQL
->hours();
194 dtTarget
->minute
= dtCSQL
->minutes();
195 dtTarget
->second
= dtCSQL
->seconds();
199 AllDataType::copyVal(bindField
->targetvalue
, bindField
->value
,
200 bindField
->type
, bindField
->length
);
205 int retValue
= SQLExecute (hstmt
);
206 if (retValue
) return ErrBadCall
;
210 DbRetVal
SqlOdbcStatement::bindParam(int pos
, void* value
)
213 printError(ErrWarning
, "Deprecated. Use setParamXXX instead\n");
217 DbRetVal
SqlOdbcStatement::bindField(int pos
, void* value
)
219 if (!isPrepared
) return OK
;
220 BindSqlProjectField
*bindField
= (BindSqlProjectField
*)bindList
.get(pos
);
221 if (NULL
== bindField
)
223 printError(ErrBadArg
, "Could not get the projection list. Should be called only for SELECT statement");
226 bindField
->value
= value
;
229 void* SqlOdbcStatement::fetch()
231 if (!isPrepared
) return NULL
;
232 int retValue
= SQLFetch (hstmt
);
233 if (retValue
) return NULL
;
234 ListIterator iter
= bindList
.getIterator();
235 BindSqlProjectField
*bindField
= NULL
;
236 void *ptrToFirstField
= NULL
;
237 while (iter
.hasElement())
239 bindField
= (BindSqlProjectField
*)iter
.nextElement();
240 switch(bindField
->type
)
243 Date
*dtCSQL
= (Date
*) bindField
->value
;
244 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
245 dtCSQL
->set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
249 Time
*dtCSQL
= (Time
*) bindField
->value
;
250 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
251 dtCSQL
->set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
254 case typeTimeStamp
: {
255 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
256 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
257 dtCSQL
->setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
258 dtCSQL
->setTime(dtTarget
->hour
,dtTarget
->minute
,
259 dtTarget
->second
, dtTarget
->fraction
);
263 AllDataType::copyVal(bindField
->value
, bindField
->targetvalue
,
264 bindField
->type
, bindField
->length
);
268 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->value
;
270 return ptrToFirstField
;
273 void* SqlOdbcStatement::fetchAndPrint(bool SQL
)
275 if (!isPrepared
) return NULL
;
276 int retValue
= SQLFetch (hstmt
);
277 if (retValue
) return NULL
;
278 ListIterator iter
= bindList
.getIterator();
279 BindSqlProjectField
*bindField
= NULL
;
280 void *ptrToFirstField
= NULL
;
281 while (iter
.hasElement())
283 bindField
= (BindSqlProjectField
*)iter
.nextElement();
284 switch(bindField
->type
)
288 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
289 dtCSQL
.set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
290 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
295 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
296 dtCSQL
.set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
297 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
300 case typeTimeStamp
: {
302 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
303 dtCSQL
.setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
304 dtCSQL
.setTime(dtTarget
->hour
,dtTarget
->minute
,
305 dtTarget
->second
, dtTarget
->fraction
);
306 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
310 AllDataType::printVal(bindField
->targetvalue
,
311 bindField
->type
, bindField
->length
);
315 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->targetvalue
;
318 return ptrToFirstField
;
321 void* SqlOdbcStatement::next()
326 DbRetVal
SqlOdbcStatement::close()
328 if (!isPrepared
) return OK
;
329 SQLCloseCursor(hstmt
);
333 void* SqlOdbcStatement::getFieldValuePtr( int pos
)
338 int SqlOdbcStatement::noOfProjFields()
340 if (!isPrepared
) return 0;
341 return bindList
.size();
344 int SqlOdbcStatement::noOfParamFields()
346 if (!isPrepared
) return 0;
347 return paramList
.size();
350 DbRetVal
SqlOdbcStatement::getProjFldInfo (int projpos
, FieldInfo
*&fInfo
)
352 ListIterator biter
= bindList
.getIterator();
353 BindSqlProjectField
*elem
= NULL
;
355 while (biter
.hasElement())
357 elem
= (BindSqlProjectField
*) biter
.nextElement();
358 if (count
== projpos
)
360 strcpy(fInfo
->fldName
, elem
->fName
);
361 fInfo
->length
= elem
->length
;
362 fInfo
->type
=elem
->type
;
370 DbRetVal
SqlOdbcStatement::getParamFldInfo (int parampos
, FieldInfo
*&fInfo
)
372 ListIterator biter
= paramList
.getIterator();
373 BindSqlField
*elem
= NULL
;
375 while (biter
.hasElement())
377 elem
= (BindSqlField
*) biter
.nextElement();
378 if (count
== parampos
)
380 fInfo
->length
= elem
->length
;
381 fInfo
->type
=elem
->type
;
389 DbRetVal
SqlOdbcStatement::free()
392 ListIterator biter
= bindList
.getIterator();
393 BindSqlProjectField
*elem
= NULL
;
394 while (biter
.hasElement())
396 elem
= (BindSqlProjectField
*) biter
.nextElement();
397 ::free(elem
->targetvalue
);
401 ListIterator piter
= paramList
.getIterator();
402 BindSqlField
*bindField
= NULL
;
403 while (piter
.hasElement())
405 bindField
= (BindSqlField
*) piter
.nextElement();
406 ::free(bindField
->value
);
407 ::free(bindField
->targetvalue
);
412 SQLFreeHandle (SQL_HANDLE_STMT
, hstmt
);
415 void SqlOdbcStatement::setShortParam(int paramPos
, short value
)
417 if (!isPrepared
) return ;
418 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
419 if (bindField
->type
!= typeShort
) return;
420 *(short*)(bindField
->value
) = value
;
423 void SqlOdbcStatement::setIntParam(int paramPos
, int value
)
425 if (!isPrepared
) return ;
426 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
427 /*if (bindField->type != typeInt) return;
428 *(int*)(bindField->value) = value;
432 //Bug #1382 SQLDescribeParam returns the same type information, varchar
433 AllDataType::convertToString(bindField
->value
, &value
, typeInt
);
438 void SqlOdbcStatement::setLongParam(int paramPos
, long value
)
440 if (!isPrepared
) return ;
441 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
442 //if (bindField->type != typeLong) return;
443 //*(long*)(bindField->value) = value;
445 //Bug #1382 SQLDescribeParam returns the same type information, varchar
446 AllDataType::convertToString(bindField
->value
, &value
, typeLong
);
450 void SqlOdbcStatement::setLongLongParam(int paramPos
, long long value
)
452 if (!isPrepared
) return ;
453 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
454 //if (bindField->type != typeLongLong) return;
455 //*(long long*)(bindField->value) = value;
456 AllDataType::convertToString(bindField
->value
, &value
, typeLongLong
);
459 void SqlOdbcStatement::setByteIntParam(int paramPos
, ByteInt value
)
461 if (!isPrepared
) return ;
462 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
463 //if (bindField->type != typeByteInt) return;
464 //*(char*)(bindField->value) = value;
465 AllDataType::convertToString(bindField
->value
, &value
, typeByteInt
);
468 void SqlOdbcStatement::setFloatParam(int paramPos
, float value
)
470 if (!isPrepared
) return ;
471 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
472 //if (bindField->type != typeFloat) return;
473 //*(float*)(bindField->value) = value;
474 AllDataType::convertToString(bindField
->value
, &value
, typeFloat
);
476 void SqlOdbcStatement::setDoubleParam(int paramPos
, double value
)
478 if (!isPrepared
) return ;
479 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
480 //if (bindField->type != typeDouble) return;
481 //*(double*)(bindField->value) = value;
482 AllDataType::convertToString(bindField
->value
, &value
, typeDouble
);
485 void SqlOdbcStatement::setStringParam(int paramPos
, char *value
)
487 if (!isPrepared
) return ;
488 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
489 if (bindField
->type
!= typeString
) return;
490 char *dest
= (char*)bindField
->value
;
491 strncpy(dest
, value
, bindField
->length
);
492 dest
[ bindField
->length
- 1] ='\0';
495 void SqlOdbcStatement::setDateParam(int paramPos
, Date value
)
497 if (!isPrepared
) return ;
498 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
499 //if (bindField->type != typeDate) return;
500 //*(Date*)(bindField->value) = value;
501 AllDataType::convertToString(bindField
->value
, &value
, typeDate
);
504 void SqlOdbcStatement::setTimeParam(int paramPos
, Time value
)
506 if (!isPrepared
) return ;
507 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
508 //if (bindField->type != typeTime) return;
509 //*(Time*)(bindField->value) = value;
510 AllDataType::convertToString(bindField
->value
, &value
, typeTime
);
513 void SqlOdbcStatement::setTimeStampParam(int paramPos
, TimeStamp value
)
515 if (!isPrepared
) return ;
516 BindSqlField
*bindField
= (BindSqlField
*) paramList
.get(paramPos
);
517 //if (bindField->type != typeTimeStamp) return;
518 //*(TimeStamp*)(bindField->value) = value;
519 AllDataType::convertToString(bindField
->value
, &value
, typeTimeStamp
);