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 SQLCHAR
* sstr
= (SQLCHAR
*)stmtstr
;
37 retValue
= SQLPrepare (hstmt
, sstr
, SQL_NTS
);
38 if (retValue
) return ErrBadCall
;
41 retValue
= SQLNumResultCols (hstmt
, &totalFields
);
42 if (retValue
) return ErrBadCall
;
43 BindSqlProjectField
*bindProjField
= NULL
;
45 UCHAR colName
[IDENTIFIER_LENGTH
];
52 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
53 while (icol
<= totalFields
)
55 retValue
= SQLDescribeCol(hstmt
, icol
, colName
, colNameMax
,
56 &nameLength
, &colType
, &colLength
,
58 if (retValue
) return ErrBadCall
;
60 bindProjField
= new BindSqlProjectField();
61 strncpy(bindProjField
->fName
, (char*)colName
, IDENTIFIER_LENGTH
);
62 bindProjField
->fName
[IDENTIFIER_LENGTH
] = '\0';
63 bindProjField
->type
= AllDataType::convertFromSQLType(colType
);
64 bindProjField
->length
= colLength
+1;
65 bindProjField
->value
= NULL
;
66 bindProjField
->targetvalue
= NULL
;
68 switch(bindProjField
->type
)
71 fieldsize
= colLength
+1;
72 bindProjField
->targetvalue
= malloc(fieldsize
);
75 fieldsize
= sizeof(DATE_STRUCT
);
76 bindProjField
->targetvalue
= malloc(sizeof(DATE_STRUCT
));
79 fieldsize
= sizeof(TIME_STRUCT
);
80 bindProjField
->targetvalue
= malloc(sizeof(TIME_STRUCT
));
83 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
84 bindProjField
->targetvalue
= malloc(sizeof(TIMESTAMP_STRUCT
));
87 bindProjField
->targetvalue
= AllDataType::alloc(bindProjField
->type
, bindProjField
->length
);
89 retValue
= SQLBindCol(hstmt
, icol
,
90 AllDataType::convertToSQLType(bindProjField
->type
),
91 bindProjField
->targetvalue
, fieldsize
, NULL
);
92 if (retValue
) return ErrBadCall
;
93 bindList
.append(bindProjField
);
98 BindSqlField
*bindField
;
99 retValue
= SQLNumParams (hstmt
, &totalFields
);
100 if (retValue
) return ErrBadCall
;
101 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
104 while (icol
<= totalFields
)
106 retValue
= SQLDescribeParam(hstmt
, icol
, &cType
, &cLength
,
109 //Bug #1382 SQLDescribeParam returns the same type information
111 if (retValue
) return ErrBadCall
;
113 bindField
= new BindSqlField();
114 bindField
->type
= AllDataType::convertFromSQLType(cType
);
115 bindField
->length
= cLength
;
116 bindField
->value
= AllDataType::alloc(bindField
->type
, cLength
);
117 bindField
->targetvalue
= NULL
;
119 switch(bindField
->type
)
123 bindField
->targetvalue
= malloc(fieldsize
);
126 fieldsize
= sizeof(DATE_STRUCT
);
127 bindField
->targetvalue
= malloc(sizeof(DATE_STRUCT
));
130 fieldsize
= sizeof(TIME_STRUCT
);
131 bindField
->targetvalue
= malloc(sizeof(TIME_STRUCT
));
134 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
135 bindField
->targetvalue
= malloc(sizeof(TIMESTAMP_STRUCT
));
138 bindField
->targetvalue
= AllDataType::alloc(bindField
->type
, cLength
);
142 retValue
= SQLBindParameter(hstmt
, icol
, SQL_PARAM_INPUT
,
143 AllDataType::convertToSQL_C_Type(bindField
->type
),
144 cType
, fieldsize
, scale
, bindField
->targetvalue
,
146 if (retValue
) return ErrBadCall
;
147 paramList
.append(bindField
);
150 //TODO::deallocate memory and remove elements from list in case of any
151 //failure in any of the above ODBC functions
155 bool SqlOdbcStatement::isSelect()
161 DbRetVal
SqlOdbcStatement::execute(int &rowsAffected
)
164 if (!isPrepared
) return ErrNotPrepared
;
165 ListIterator iter
= paramList
.getIterator();
166 BindSqlField
*bindField
= NULL
;
167 while (iter
.hasElement())
169 bindField
= (BindSqlField
*)iter
.nextElement();
170 switch(bindField
->type
)
173 Date
*dtCSQL
= (Date
*) bindField
->value
;
174 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
175 dtTarget
->year
= dtCSQL
->year();
176 dtTarget
->month
= dtCSQL
->month();
177 dtTarget
->day
= dtCSQL
->dayOfMonth();
181 Time
*dtCSQL
= (Time
*) bindField
->value
;
182 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
183 dtTarget
->hour
= dtCSQL
->hours();
184 dtTarget
->minute
= dtCSQL
->minutes();
185 dtTarget
->second
= dtCSQL
->seconds();
188 case typeTimeStamp
: {
189 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
190 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
191 dtTarget
->year
= dtCSQL
->year();
192 dtTarget
->month
= dtCSQL
->month();
193 dtTarget
->day
= dtCSQL
->dayOfMonth();
194 dtTarget
->hour
= dtCSQL
->hours();
195 dtTarget
->minute
= dtCSQL
->minutes();
196 dtTarget
->second
= dtCSQL
->seconds();
200 AllDataType::copyVal(bindField
->targetvalue
, bindField
->value
,
201 bindField
->type
, bindField
->length
);
206 int retValue
= SQLExecute (hstmt
);
207 if (retValue
) return ErrBadCall
;
211 DbRetVal
SqlOdbcStatement::bindParam(int pos
, void* value
)
214 printError(ErrWarning
, "Deprecated. Use setParamXXX instead\n");
218 DbRetVal
SqlOdbcStatement::bindField(int pos
, void* value
)
220 if (!isPrepared
) return OK
;
221 BindSqlProjectField
*bindField
= (BindSqlProjectField
*)bindList
.get(pos
);
222 if (NULL
== bindField
)
224 printError(ErrBadArg
, "Could not get the projection list. Should be called only for SELECT statement");
227 bindField
->value
= value
;
230 void* SqlOdbcStatement::fetch()
232 if (!isPrepared
) return NULL
;
233 int retValue
= SQLFetch (hstmt
);
234 if (retValue
) return NULL
;
235 ListIterator iter
= bindList
.getIterator();
236 BindSqlProjectField
*bindField
= NULL
;
237 void *ptrToFirstField
= NULL
;
238 while (iter
.hasElement())
240 bindField
= (BindSqlProjectField
*)iter
.nextElement();
241 switch(bindField
->type
)
244 Date
*dtCSQL
= (Date
*) bindField
->value
;
245 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
246 dtCSQL
->set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
250 Time
*dtCSQL
= (Time
*) bindField
->value
;
251 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
252 dtCSQL
->set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
255 case typeTimeStamp
: {
256 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
257 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
258 dtCSQL
->setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
259 dtCSQL
->setTime(dtTarget
->hour
,dtTarget
->minute
,
260 dtTarget
->second
, dtTarget
->fraction
);
264 AllDataType::copyVal(bindField
->value
, bindField
->targetvalue
,
265 bindField
->type
, bindField
->length
);
269 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->value
;
271 return ptrToFirstField
;
274 void* SqlOdbcStatement::fetchAndPrint(bool SQL
)
276 if (!isPrepared
) return NULL
;
277 int retValue
= SQLFetch (hstmt
);
278 if (retValue
) return NULL
;
279 ListIterator iter
= bindList
.getIterator();
280 BindSqlProjectField
*bindField
= NULL
;
281 void *ptrToFirstField
= NULL
;
282 while (iter
.hasElement())
284 bindField
= (BindSqlProjectField
*)iter
.nextElement();
285 switch(bindField
->type
)
289 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
290 dtCSQL
.set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
291 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
296 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
297 dtCSQL
.set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
298 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
301 case typeTimeStamp
: {
303 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
304 dtCSQL
.setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
305 dtCSQL
.setTime(dtTarget
->hour
,dtTarget
->minute
,
306 dtTarget
->second
, dtTarget
->fraction
);
307 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
311 AllDataType::printVal(bindField
->targetvalue
,
312 bindField
->type
, bindField
->length
);
316 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->targetvalue
;
320 return ptrToFirstField
;
323 void* SqlOdbcStatement::next()
328 DbRetVal
SqlOdbcStatement::close()
330 if (!isPrepared
) return OK
;
331 SQLCloseCursor(hstmt
);
335 void* SqlOdbcStatement::getFieldValuePtr( int pos
)
340 int SqlOdbcStatement::noOfProjFields()
342 if (!isPrepared
) return 0;
343 return bindList
.size();
346 int SqlOdbcStatement::noOfParamFields()
348 if (!isPrepared
) return 0;
349 return paramList
.size();
352 DbRetVal
SqlOdbcStatement::getProjFldInfo (int projpos
, FieldInfo
*&fInfo
)
354 ListIterator biter
= bindList
.getIterator();
355 BindSqlProjectField
*elem
= NULL
;
357 while (biter
.hasElement())
359 elem
= (BindSqlProjectField
*) biter
.nextElement();
360 if (count
== projpos
)
362 strcpy(fInfo
->fldName
, elem
->fName
);
363 fInfo
->length
= elem
->length
;
364 fInfo
->type
=elem
->type
;
372 DbRetVal
SqlOdbcStatement::getParamFldInfo (int parampos
, FieldInfo
*&fInfo
)
374 ListIterator biter
= paramList
.getIterator();
375 BindSqlField
*elem
= NULL
;
377 while (biter
.hasElement())
379 elem
= (BindSqlField
*) biter
.nextElement();
380 if (count
== parampos
)
382 fInfo
->length
= elem
->length
;
383 fInfo
->type
=elem
->type
;
391 DbRetVal
SqlOdbcStatement::free()
394 ListIterator biter
= bindList
.getIterator();
395 BindSqlProjectField
*elem
= NULL
;
396 while (biter
.hasElement())
398 elem
= (BindSqlProjectField
*) biter
.nextElement();
399 ::free(elem
->targetvalue
);
403 ListIterator piter
= paramList
.getIterator();
404 BindSqlField
*bindField
= NULL
;
405 while (piter
.hasElement())
407 bindField
= (BindSqlField
*) piter
.nextElement();
408 ::free(bindField
->value
);
409 ::free(bindField
->targetvalue
);
414 SQLFreeHandle (SQL_HANDLE_STMT
, hstmt
);
417 void SqlOdbcStatement::setShortParam(int paramPos
, short value
)
419 if (!isPrepared
) return ;
420 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
421 //if (bindField->type != typeShort) return;
422 //*(short*)(bindField->value) = value;
423 AllDataType::convertToString(bindField
->value
, &value
, typeShort
);
426 void SqlOdbcStatement::setIntParam(int paramPos
, int value
)
428 if (!isPrepared
) return ;
429 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
430 /*if (bindField->type != typeInt) return;
431 *(int*)(bindField->value) = value;
435 //Bug #1382 SQLDescribeParam returns the same type information, varchar
436 AllDataType::convertToString(bindField
->value
, &value
, typeInt
);
441 void SqlOdbcStatement::setLongParam(int paramPos
, long value
)
443 if (!isPrepared
) return ;
444 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
445 //if (bindField->type != typeLong) return;
446 //*(long*)(bindField->value) = value;
448 //Bug #1382 SQLDescribeParam returns the same type information, varchar
449 AllDataType::convertToString(bindField
->value
, &value
, typeLong
);
453 void SqlOdbcStatement::setLongLongParam(int paramPos
, long long value
)
455 if (!isPrepared
) return ;
456 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
457 //if (bindField->type != typeLongLong) return;
458 //*(long long*)(bindField->value) = value;
459 AllDataType::convertToString(bindField
->value
, &value
, typeLongLong
);
462 void SqlOdbcStatement::setByteIntParam(int paramPos
, ByteInt value
)
464 if (!isPrepared
) return ;
465 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
466 //if (bindField->type != typeByteInt) return;
467 //*(char*)(bindField->value) = value;
468 AllDataType::convertToString(bindField
->value
, &value
, typeByteInt
);
471 void SqlOdbcStatement::setFloatParam(int paramPos
, float value
)
473 if (!isPrepared
) return ;
474 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
475 //if (bindField->type != typeFloat) return;
476 //*(float*)(bindField->value) = value;
477 AllDataType::convertToString(bindField
->value
, &value
, typeFloat
);
479 void SqlOdbcStatement::setDoubleParam(int paramPos
, double value
)
481 if (!isPrepared
) return ;
482 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
483 //if (bindField->type != typeDouble) return;
484 //*(double*)(bindField->value) = value;
485 AllDataType::convertToString(bindField
->value
, &value
, typeDouble
);
488 void SqlOdbcStatement::setStringParam(int paramPos
, char *value
)
490 if (!isPrepared
) return ;
491 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
492 if (bindField
->type
!= typeString
) return;
493 char *dest
= (char*)bindField
->value
;
494 strncpy(dest
, value
, bindField
->length
);
495 dest
[ bindField
->length
- 1] ='\0';
498 void SqlOdbcStatement::setDateParam(int paramPos
, Date value
)
500 if (!isPrepared
) return ;
501 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
502 //if (bindField->type != typeDate) return;
503 //*(Date*)(bindField->value) = value;
504 AllDataType::convertToString(bindField
->value
, &value
, typeDate
);
507 void SqlOdbcStatement::setTimeParam(int paramPos
, Time value
)
509 if (!isPrepared
) return ;
510 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
511 //if (bindField->type != typeTime) return;
512 //*(Time*)(bindField->value) = value;
513 AllDataType::convertToString(bindField
->value
, &value
, typeTime
);
516 void SqlOdbcStatement::setTimeStampParam(int paramPos
, TimeStamp value
)
518 if (!isPrepared
) return ;
519 BindSqlField
*bindField
= (BindSqlField
*) paramList
.get(paramPos
);
520 //if (bindField->type != typeTimeStamp) return;
521 //*(TimeStamp*)(bindField->value) = value;
522 AllDataType::convertToString(bindField
->value
, &value
, typeTimeStamp
);
525 void SqlOdbcStatement::getPrimaryKeyFieldName(char *tablename
, char *pkfieldname
)
527 if (pkfieldname
== NULL
) return;
528 SqlOdbcConnection
*conn
= (SqlOdbcConnection
*)con
;
529 int retValue
=SQLAllocHandle (SQL_HANDLE_STMT
, conn
->dbHdl
, &hstmt
);
530 if (retValue
) return ;
531 char columnName
[128];
532 columnName
[0] = '\0';
533 SQLINTEGER cbData
; // Output length of data
534 SQLPrimaryKeys(hstmt
, NULL
, 0, NULL
, 0, (SQLCHAR
*) tablename
, SQL_NTS
);
536 SQLGetData(hstmt
, 4, SQL_C_CHAR
, (SQLCHAR
*) columnName
, sizeof(columnName
),&cbData
);
537 strcpy(pkfieldname
, columnName
);
538 SQLFreeHandle (SQL_HANDLE_STMT
, hstmt
);