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
;
39 isSelStmt
=chechStmtType(stmtstr
);
42 retValue
= SQLNumResultCols (hstmt
, &totalFields
);
43 if (retValue
) return ErrBadCall
;
44 BindSqlProjectField
*bindProjField
= NULL
;
46 UCHAR colName
[IDENTIFIER_LENGTH
];
53 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
54 while (icol
<= totalFields
)
56 retValue
= SQLDescribeCol(hstmt
, icol
, colName
, colNameMax
,
57 &nameLength
, &colType
, &colLength
,
59 if (retValue
) return ErrBadCall
;
61 bindProjField
= new BindSqlProjectField();
62 strncpy(bindProjField
->fName
, (char*)colName
, IDENTIFIER_LENGTH
);
63 bindProjField
->fName
[IDENTIFIER_LENGTH
] = '\0';
64 bindProjField
->type
= AllDataType::convertFromSQLType(colType
);
65 bindProjField
->length
= colLength
+1;
66 bindProjField
->value
= NULL
;
67 bindProjField
->targetvalue
= NULL
;
69 switch(bindProjField
->type
)
72 fieldsize
= colLength
+1;
73 bindProjField
->targetvalue
= malloc(fieldsize
);
76 fieldsize
= sizeof(DATE_STRUCT
);
77 bindProjField
->targetvalue
= malloc(sizeof(DATE_STRUCT
));
80 fieldsize
= sizeof(TIME_STRUCT
);
81 bindProjField
->targetvalue
= malloc(sizeof(TIME_STRUCT
));
84 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
85 bindProjField
->targetvalue
= malloc(sizeof(TIMESTAMP_STRUCT
));
88 bindProjField
->targetvalue
= AllDataType::alloc(bindProjField
->type
, bindProjField
->length
);
90 retValue
= SQLBindCol(hstmt
, icol
,
91 AllDataType::convertToSQLType(bindProjField
->type
),
92 bindProjField
->targetvalue
, fieldsize
, &len
[icol
]);
93 if (retValue
) return ErrBadCall
;
94 bindList
.append(bindProjField
);
98 totalFld
= totalFields
;
100 BindSqlField
*bindField
;
101 retValue
= SQLNumParams (hstmt
, &totalFields
);
102 if (retValue
) return ErrBadCall
;
103 icol
= 1; colNameMax
= IDENTIFIER_LENGTH
;
106 while (icol
<= totalFields
)
108 retValue
= SQLDescribeParam(hstmt
, icol
, &cType
, &cLength
,
111 //Bug #1382 SQLDescribeParam returns the same type information
113 if (retValue
) return ErrBadCall
;
115 bindField
= new BindSqlField();
116 bindField
->type
= AllDataType::convertFromSQLType(cType
);
117 bindField
->length
= cLength
;
118 bindField
->value
= AllDataType::alloc(bindField
->type
, cLength
);
119 bindField
->targetvalue
= NULL
;
121 switch(bindField
->type
)
125 bindField
->targetvalue
= malloc(fieldsize
);
128 fieldsize
= sizeof(DATE_STRUCT
);
129 bindField
->targetvalue
= malloc(sizeof(DATE_STRUCT
));
132 fieldsize
= sizeof(TIME_STRUCT
);
133 bindField
->targetvalue
= malloc(sizeof(TIME_STRUCT
));
136 fieldsize
= sizeof(TIMESTAMP_STRUCT
);
137 bindField
->targetvalue
= malloc(sizeof(TIMESTAMP_STRUCT
));
140 bindField
->targetvalue
= AllDataType::alloc(bindField
->type
, cLength
);
144 retValue
= SQLBindParameter(hstmt
, icol
, SQL_PARAM_INPUT
,
145 AllDataType::convertToSQL_C_Type(bindField
->type
),
146 cType
, fieldsize
, scale
, bindField
->targetvalue
,
148 if (retValue
) return ErrBadCall
;
149 paramList
.append(bindField
);
152 //TODO::deallocate memory and remove elements from list in case of any
153 //failure in any of the above ODBC functions
157 bool SqlOdbcStatement::isSelect()
163 DbRetVal
SqlOdbcStatement::execute(int &rowsAffected
)
166 if (!isPrepared
) return ErrNotPrepared
;
167 ListIterator iter
= paramList
.getIterator();
168 BindSqlField
*bindField
= NULL
;
169 while (iter
.hasElement())
171 bindField
= (BindSqlField
*)iter
.nextElement();
172 switch(bindField
->type
)
175 Date
*dtCSQL
= (Date
*) bindField
->value
;
176 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
177 dtTarget
->year
= dtCSQL
->year();
178 dtTarget
->month
= dtCSQL
->month();
179 dtTarget
->day
= dtCSQL
->dayOfMonth();
183 Time
*dtCSQL
= (Time
*) bindField
->value
;
184 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
185 dtTarget
->hour
= dtCSQL
->hours();
186 dtTarget
->minute
= dtCSQL
->minutes();
187 dtTarget
->second
= dtCSQL
->seconds();
190 case typeTimeStamp
: {
191 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
192 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
193 dtTarget
->year
= dtCSQL
->year();
194 dtTarget
->month
= dtCSQL
->month();
195 dtTarget
->day
= dtCSQL
->dayOfMonth();
196 dtTarget
->hour
= dtCSQL
->hours();
197 dtTarget
->minute
= dtCSQL
->minutes();
198 dtTarget
->second
= dtCSQL
->seconds();
202 AllDataType::copyVal(bindField
->targetvalue
, bindField
->value
,
203 bindField
->type
, bindField
->length
);
208 int retValue
= SQLExecute (hstmt
);
209 if (retValue
) return ErrBadCall
;
210 retValue
=SQLRowCount(hstmt
,(SQLINTEGER
*)&rowsAffected
);
211 if(isSelStmt
) rowsAffected
= 0;
215 DbRetVal
SqlOdbcStatement::bindParam(int pos
, void* value
)
218 printError(ErrWarning
, "Deprecated. Use setParamXXX instead\n");
222 DbRetVal
SqlOdbcStatement::bindField(int pos
, void* value
)
224 if (!isPrepared
) return OK
;
225 BindSqlProjectField
*bindField
= (BindSqlProjectField
*)bindList
.get(pos
);
226 if (NULL
== bindField
)
228 printError(ErrBadArg
, "Could not get the projection list. Should be called only for SELECT statement");
231 bindField
->value
= value
;
235 void SqlOdbcStatement::setNullInfo(Table
*table
)
238 table
->resetNullinfo();
239 while(fldpos
< totalFld
)
241 if(len
[++fldpos
] == SQL_NULL_DATA
)
243 table
->markFldNull(fldpos
);
248 void* SqlOdbcStatement::fetch()
250 if (!isPrepared
) return NULL
;
251 int retValue
= SQLFetch (hstmt
);
252 if (retValue
) return NULL
;
253 ListIterator iter
= bindList
.getIterator();
254 BindSqlProjectField
*bindField
= NULL
;
255 void *ptrToFirstField
= NULL
;
257 while (iter
.hasElement())
259 bindField
= (BindSqlProjectField
*)iter
.nextElement();
260 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->value
;
261 if(len
[++icol
] == SQL_NULL_DATA
)
263 AllDataType::memoryset(bindField
->value
,bindField
->type
);
266 if( isSelStmt
&& NULL
== bindField
->value
)
268 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->targetvalue
;
271 switch(bindField
->type
)
274 Date
*dtCSQL
= (Date
*) bindField
->value
;
275 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
276 dtCSQL
->set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
280 Time
*dtCSQL
= (Time
*) bindField
->value
;
281 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
282 dtCSQL
->set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
285 case typeTimeStamp
: {
286 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
287 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
288 dtCSQL
->setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
289 dtCSQL
->setTime(dtTarget
->hour
,dtTarget
->minute
,
290 dtTarget
->second
, dtTarget
->fraction
);
294 AllDataType::copyVal(bindField
->value
, bindField
->targetvalue
,
295 bindField
->type
, bindField
->length
);
300 return ptrToFirstField
;
303 void* SqlOdbcStatement::fetch(DbRetVal
&rv
)
305 if (!isPrepared
) return NULL
;
306 int retValue
= SQLFetch (hstmt
);
307 if (retValue
) { rv
= OK
; return NULL
; }
308 ListIterator iter
= bindList
.getIterator();
309 BindSqlProjectField
*bindField
= NULL
;
310 void *ptrToFirstField
= NULL
;
312 while (iter
.hasElement())
314 bindField
= (BindSqlProjectField
*)iter
.nextElement();
315 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->value
;
316 if(len
[++icol
] == SQL_NULL_DATA
)
318 AllDataType::memoryset(bindField
->value
,bindField
->type
);
321 if( isSelStmt
&& NULL
== bindField
->value
)
323 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->targetvalue
;
326 switch(bindField
->type
)
329 Date
*dtCSQL
= (Date
*) bindField
->value
;
330 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
331 dtCSQL
->set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
335 Time
*dtCSQL
= (Time
*) bindField
->value
;
336 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
337 dtCSQL
->set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
340 case typeTimeStamp
: {
341 TimeStamp
*dtCSQL
= (TimeStamp
*) bindField
->value
;
342 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
343 dtCSQL
->setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
344 dtCSQL
->setTime(dtTarget
->hour
,dtTarget
->minute
,
345 dtTarget
->second
, dtTarget
->fraction
);
349 AllDataType::copyVal(bindField
->value
, bindField
->targetvalue
,
350 bindField
->type
, bindField
->length
);
355 return ptrToFirstField
;
358 void* SqlOdbcStatement::fetchAndPrint(bool SQL
)
360 if (!isPrepared
) return NULL
;
361 int retValue
= SQLFetch (hstmt
);
362 if (retValue
) return NULL
;
363 ListIterator iter
= bindList
.getIterator();
364 BindSqlProjectField
*bindField
= NULL
;
365 void *ptrToFirstField
= NULL
;
367 while (iter
.hasElement())
370 bindField
= (BindSqlProjectField
*)iter
.nextElement();
371 if (ptrToFirstField
== NULL
) ptrToFirstField
=bindField
->targetvalue
;
372 if(len
[icol
++] == SQL_NULL_DATA
)
377 switch(bindField
->type
)
381 DATE_STRUCT
*dtTarget
= (DATE_STRUCT
*) bindField
->targetvalue
;
382 dtCSQL
.set(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
383 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
388 TIME_STRUCT
*dtTarget
= (TIME_STRUCT
*) bindField
->targetvalue
;
389 dtCSQL
.set(dtTarget
->hour
,dtTarget
->minute
,dtTarget
->second
);
390 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
393 case typeTimeStamp
: {
395 TIMESTAMP_STRUCT
*dtTarget
= (TIMESTAMP_STRUCT
*) bindField
->targetvalue
;
396 dtCSQL
.setDate(dtTarget
->year
,dtTarget
->month
,dtTarget
->day
);
397 dtCSQL
.setTime(dtTarget
->hour
,dtTarget
->minute
,
398 dtTarget
->second
, dtTarget
->fraction
);
399 AllDataType::printVal(&dtCSQL
, bindField
->type
, bindField
->length
);
403 AllDataType::printVal(bindField
->targetvalue
,
404 bindField
->type
, bindField
->length
);
410 return ptrToFirstField
;
413 void* SqlOdbcStatement::next()
418 DbRetVal
SqlOdbcStatement::close()
420 if (!isPrepared
) return OK
;
421 SQLCloseCursor(hstmt
);
424 bool SqlOdbcStatement::chechStmtType(char *buf
)
433 if (strncasecmp (buf
, "SELECT", 6) == 0) { return true;}
436 void* SqlOdbcStatement::getFieldValuePtr( int pos
)
439 ListIterator biter
= bindList
.getIterator();
440 BindSqlProjectField
*elem
= NULL
;
442 while (biter
.hasElement())
444 elem
= (BindSqlProjectField
*) biter
.nextElement();
447 return elem
->targetvalue
;
455 int SqlOdbcStatement::noOfProjFields()
457 if (!isPrepared
) return 0;
458 return bindList
.size();
461 int SqlOdbcStatement::noOfParamFields()
463 if (!isPrepared
) return 0;
464 return paramList
.size();
467 DbRetVal
SqlOdbcStatement::getProjFldInfo (int projpos
, FieldInfo
*&fInfo
)
469 ListIterator biter
= bindList
.getIterator();
470 BindSqlProjectField
*elem
= NULL
;
472 while (biter
.hasElement())
474 elem
= (BindSqlProjectField
*) biter
.nextElement();
475 if (count
== projpos
-1)
477 strcpy(fInfo
->fldName
, elem
->fName
);
478 fInfo
->length
= elem
->length
;
479 fInfo
->type
=elem
->type
;
487 DbRetVal
SqlOdbcStatement::getParamFldInfo (int parampos
, FieldInfo
*&fInfo
)
489 ListIterator biter
= paramList
.getIterator();
490 BindSqlField
*elem
= NULL
;
492 while (biter
.hasElement())
494 elem
= (BindSqlField
*) biter
.nextElement();
495 if (count
== parampos
)
497 fInfo
->length
= elem
->length
;
498 fInfo
->type
=elem
->type
;
506 DbRetVal
SqlOdbcStatement::free()
509 ListIterator biter
= bindList
.getIterator();
510 BindSqlProjectField
*elem
= NULL
;
511 while (biter
.hasElement())
513 elem
= (BindSqlProjectField
*) biter
.nextElement();
514 ::free(elem
->targetvalue
);
518 ListIterator piter
= paramList
.getIterator();
519 BindSqlField
*bindField
= NULL
;
520 while (piter
.hasElement())
522 bindField
= (BindSqlField
*) piter
.nextElement();
523 ::free(bindField
->value
);
524 ::free(bindField
->targetvalue
);
529 SQLFreeHandle (SQL_HANDLE_STMT
, hstmt
);
532 void SqlOdbcStatement::setShortParam(int paramPos
, short value
)
534 if (!isPrepared
) return ;
535 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
536 //if (bindField->type != typeShort) return;
537 //*(short*)(bindField->value) = value;
538 AllDataType::convertToString(bindField
->value
, &value
, typeShort
);
541 void SqlOdbcStatement::setIntParam(int paramPos
, int value
)
543 if (!isPrepared
) return ;
544 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
545 /*if (bindField->type != typeInt) return;
546 *(int*)(bindField->value) = value;
550 //Bug #1382 SQLDescribeParam returns the same type information, varchar
551 AllDataType::convertToString(bindField
->value
, &value
, typeInt
);
555 void SqlOdbcStatement::setLongParam(int paramPos
, long value
)
557 if (!isPrepared
) return ;
558 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
559 //if (bindField->type != typeLong) return;
560 //*(long*)(bindField->value) = value;
562 //Bug #1382 SQLDescribeParam returns the same type information, varchar
563 AllDataType::convertToString(bindField
->value
, &value
, typeLong
);
567 void SqlOdbcStatement::setLongLongParam(int paramPos
, long long value
)
569 if (!isPrepared
) return ;
570 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
571 //if (bindField->type != typeLongLong) return;
572 //*(long long*)(bindField->value) = value;
573 AllDataType::convertToString(bindField
->value
, &value
, typeLongLong
);
576 void SqlOdbcStatement::setByteIntParam(int paramPos
, ByteInt value
)
578 if (!isPrepared
) return ;
579 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
580 //if (bindField->type != typeByteInt) return;
581 //*(char*)(bindField->value) = value;
582 AllDataType::convertToString(bindField
->value
, &value
, typeByteInt
);
585 void SqlOdbcStatement::setFloatParam(int paramPos
, float value
)
587 if (!isPrepared
) return ;
588 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
589 //if (bindField->type != typeFloat) return;
590 //*(float*)(bindField->value) = value;
591 AllDataType::convertToString(bindField
->value
, &value
, typeFloat
);
593 void SqlOdbcStatement::setDoubleParam(int paramPos
, double value
)
595 if (!isPrepared
) return ;
596 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
597 //if (bindField->type != typeDouble) return;
598 //*(double*)(bindField->value) = value;
599 AllDataType::convertToString(bindField
->value
, &value
, typeDouble
);
602 void SqlOdbcStatement::setStringParam(int paramPos
, char *value
)
604 if (!isPrepared
) return ;
605 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
606 if (bindField
->type
!= typeString
) return;
607 char *dest
= (char*)bindField
->value
;
608 strncpy(dest
, value
, bindField
->length
);
609 dest
[ bindField
->length
- 1] ='\0';
612 void SqlOdbcStatement::setDateParam(int paramPos
, Date value
)
614 if (!isPrepared
) return ;
615 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
616 //if (bindField->type != typeDate) return;
617 //*(Date*)(bindField->value) = value;
618 AllDataType::convertToString(bindField
->value
, &value
, typeDate
);
621 void SqlOdbcStatement::setTimeParam(int paramPos
, Time value
)
623 if (!isPrepared
) return ;
624 BindSqlField
*bindField
= (BindSqlField
*)paramList
.get(paramPos
);
625 //if (bindField->type != typeTime) return;
626 //*(Time*)(bindField->value) = value;
627 AllDataType::convertToString(bindField
->value
, &value
, typeTime
);
630 void SqlOdbcStatement::setTimeStampParam(int paramPos
, TimeStamp value
)
632 if (!isPrepared
) return ;
633 BindSqlField
*bindField
= (BindSqlField
*) paramList
.get(paramPos
);
634 //if (bindField->type != typeTimeStamp) return;
635 //*(TimeStamp*)(bindField->value) = value;
636 AllDataType::convertToString(bindField
->value
, &value
, typeTimeStamp
);
638 void SqlOdbcStatement::setBinaryParam(int paramPos
, void *value
, int length
)
640 if (!isPrepared
) return;
641 BindSqlField
*bindField
= (BindSqlField
*) paramList
.get(paramPos
);
642 //if (bindField->type != typeTimeStamp) return;
643 // *(TimeStamp*)(bindField->value) = value;
644 AllDataType::convertToString(bindField
->value
, value
, typeBinary
, bindField
->length
);
647 void SqlOdbcStatement::getPrimaryKeyFieldName(char *tablename
, char *pkfieldname
)
649 if (pkfieldname
== NULL
) return;
650 SqlOdbcConnection
*conn
= (SqlOdbcConnection
*)con
;
651 int retValue
=SQLAllocHandle (SQL_HANDLE_STMT
, conn
->dbHdl
, &hstmt
);
652 if (retValue
) return ;
653 char columnName
[128];
654 columnName
[0] = '\0';
655 SQLINTEGER cbData
; // Output length of data
656 SQLPrimaryKeys(hstmt
, NULL
, 0, NULL
, 0, (SQLCHAR
*) tablename
, SQL_NTS
);
658 SQLGetData(hstmt
, 4, SQL_C_CHAR
, (SQLCHAR
*) columnName
, sizeof(columnName
),&cbData
);
659 strcpy(pkfieldname
, columnName
);
660 SQLFreeHandle (SQL_HANDLE_STMT
, hstmt
);
664 bool SqlOdbcStatement::isFldNull(int pos
)
666 if( len
[pos
] == SQL_NULL_DATA
)
672 bool SqlOdbcStatement::isFldNull(char *name
)
674 ListIterator iter
= bindList
.getIterator();
675 BindSqlProjectField
*bindField
= NULL
;
677 while (iter
.hasElement())
679 bindField
= (BindSqlProjectField
*)iter
.nextElement();
680 if(strcmp(name
,bindField
->fName
)==0)
686 if( len
[pos
] == SQL_NULL_DATA
)
692 void SqlOdbcStatement::setNull(int pos
)
694 len
[pos
] = SQL_NULL_DATA
;