modified to accept hostname and connect to the network
[csql.git] / src / adapter / SqlOdbcStatement.cxx
blobf9b640a11e75c5b9e022db329340455402388c4b
1 /***************************************************************************
2 * Copyright (C) 2007 by Prabakaran Thirumalai *
3 * praba_tuty@yahoo.com *
4 * *
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. *
9 * *
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. *
14 * *
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)
28 DbRetVal rv = OK;
29 if (innerStmt) rv = ErrBadCall;
30 if (rv != OK) return rv;
31 int retValue =0;
32 isPrepared = false;
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);
40 isPrepared = true;
41 short totalFields=0;
42 retValue = SQLNumResultCols (hstmt, &totalFields);
43 if (retValue) return ErrBadCall;
44 BindSqlProjectField *bindProjField = NULL;
45 UWORD icol;
46 UCHAR colName[IDENTIFIER_LENGTH];
47 SWORD colNameMax;
48 SWORD nameLength;
49 SWORD colType;
50 SQLULEN colLength;
51 SWORD scale;
52 SWORD nullable;
53 icol = 1; colNameMax = IDENTIFIER_LENGTH;
54 while (icol <= totalFields)
56 retValue = SQLDescribeCol(hstmt, icol, colName, colNameMax,
57 &nameLength, &colType, &colLength,
58 &scale, &nullable);
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;
68 int fieldsize =0;
69 switch(bindProjField->type)
71 case typeString:
72 fieldsize = colLength+1;
73 bindProjField->targetvalue = malloc(fieldsize);
74 break;
75 case typeDate:
76 fieldsize = sizeof(DATE_STRUCT);
77 bindProjField->targetvalue = malloc(sizeof(DATE_STRUCT));
78 break;
79 case typeTime:
80 fieldsize = sizeof(TIME_STRUCT);
81 bindProjField->targetvalue = malloc(sizeof(TIME_STRUCT));
82 break;
83 case typeTimeStamp:
84 fieldsize = sizeof(TIMESTAMP_STRUCT);
85 bindProjField->targetvalue = malloc(sizeof(TIMESTAMP_STRUCT));
86 break;
87 default:
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);
95 icol++;
98 totalFld = totalFields;
99 totalFields =0;
100 BindSqlField *bindField;
101 retValue = SQLNumParams (hstmt, &totalFields);
102 if (retValue) return ErrBadCall;
103 icol = 1; colNameMax = IDENTIFIER_LENGTH;
104 SWORD cType=0;
105 SQLULEN cLength=0;
106 while (icol <= totalFields)
108 retValue = SQLDescribeParam(hstmt, icol, &cType, &cLength,
109 &scale, &nullable);
110 //Note: MySQL Bug
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;
120 int fieldsize =0;
121 switch(bindField->type)
123 case typeString:
124 fieldsize = cLength;
125 bindField->targetvalue = malloc(fieldsize);
126 break;
127 case typeDate:
128 fieldsize = sizeof(DATE_STRUCT);
129 bindField->targetvalue = malloc(sizeof(DATE_STRUCT));
130 break;
131 case typeTime:
132 fieldsize = sizeof(TIME_STRUCT);
133 bindField->targetvalue = malloc(sizeof(TIME_STRUCT));
134 break;
135 case typeTimeStamp:
136 fieldsize = sizeof(TIMESTAMP_STRUCT);
137 bindField->targetvalue = malloc(sizeof(TIMESTAMP_STRUCT));
138 break;
139 default:
140 bindField->targetvalue = AllDataType::alloc(bindField->type, cLength);
141 break;
144 retValue = SQLBindParameter(hstmt, icol, SQL_PARAM_INPUT,
145 AllDataType::convertToSQL_C_Type(bindField->type),
146 cType, fieldsize, scale, bindField->targetvalue,
147 fieldsize, NULL);
148 if (retValue) return ErrBadCall;
149 paramList.append(bindField);
150 icol++;
152 //TODO::deallocate memory and remove elements from list in case of any
153 //failure in any of the above ODBC functions
154 return OK;
157 bool SqlOdbcStatement::isSelect()
159 //TODO
160 return isSelStmt;
163 DbRetVal SqlOdbcStatement::execute(int &rowsAffected)
165 DbRetVal rv = OK;
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)
174 case typeDate: {
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();
180 break;
182 case typeTime: {
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();
188 break;
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();
199 break;
201 default: {
202 AllDataType::copyVal(bindField->targetvalue, bindField->value,
203 bindField->type, bindField->length);
204 break;
208 int retValue = SQLExecute (hstmt);
209 if (retValue) return ErrBadCall;
210 retValue=SQLRowCount(hstmt,(SQLINTEGER*)&rowsAffected);
211 if(isSelStmt) rowsAffected = 0;
212 return rv;
215 DbRetVal SqlOdbcStatement::bindParam(int pos, void* value)
217 DbRetVal rv = OK;
218 printError(ErrWarning, "Deprecated. Use setParamXXX instead\n");
219 return rv;
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");
229 return ErrBadArg;
231 bindField->value = value;
232 return OK;
235 void SqlOdbcStatement::setNullInfo(Table *table)
237 int fldpos=0;
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;
256 int icol=0;
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);
264 continue;
266 if( isSelStmt && NULL == bindField->value )
268 if (ptrToFirstField == NULL) ptrToFirstField=bindField->targetvalue;
269 continue;
271 switch(bindField->type)
273 case typeDate: {
274 Date *dtCSQL = (Date*) bindField->value;
275 DATE_STRUCT *dtTarget = (DATE_STRUCT*) bindField->targetvalue;
276 dtCSQL->set(dtTarget->year,dtTarget->month,dtTarget->day);
277 break;
279 case typeTime: {
280 Time *dtCSQL = (Time*) bindField->value;
281 TIME_STRUCT *dtTarget = (TIME_STRUCT*) bindField->targetvalue;
282 dtCSQL->set(dtTarget->hour,dtTarget->minute,dtTarget->second);
283 break;
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);
291 break;
293 default: {
294 AllDataType::copyVal(bindField->value, bindField->targetvalue,
295 bindField->type, bindField->length);
296 break;
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;
311 int icol=0;
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);
319 continue;
321 if( isSelStmt && NULL == bindField->value )
323 if (ptrToFirstField == NULL) ptrToFirstField=bindField->targetvalue;
324 continue;
326 switch(bindField->type)
328 case typeDate: {
329 Date *dtCSQL = (Date*) bindField->value;
330 DATE_STRUCT *dtTarget = (DATE_STRUCT*) bindField->targetvalue;
331 dtCSQL->set(dtTarget->year,dtTarget->month,dtTarget->day);
332 break;
334 case typeTime: {
335 Time *dtCSQL = (Time*) bindField->value;
336 TIME_STRUCT *dtTarget = (TIME_STRUCT*) bindField->targetvalue;
337 dtCSQL->set(dtTarget->hour,dtTarget->minute,dtTarget->second);
338 break;
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);
346 break;
348 default: {
349 AllDataType::copyVal(bindField->value, bindField->targetvalue,
350 bindField->type, bindField->length);
351 break;
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;
366 int icol=1;
367 while (iter.hasElement())
370 bindField = (BindSqlProjectField*)iter.nextElement();
371 if (ptrToFirstField == NULL) ptrToFirstField=bindField->targetvalue;
372 if(len[icol++] == SQL_NULL_DATA)
374 printf("NULL");
375 continue;
377 switch(bindField->type)
379 case typeDate: {
380 Date dtCSQL;
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);
384 break;
386 case typeTime: {
387 Time dtCSQL;
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);
391 break;
393 case typeTimeStamp: {
394 TimeStamp dtCSQL;
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);
400 break;
402 default: {
403 AllDataType::printVal(bindField->targetvalue,
404 bindField->type, bindField->length);
405 break;
408 printf("\t");
410 return ptrToFirstField;
413 void* SqlOdbcStatement::next()
415 return fetch();
418 DbRetVal SqlOdbcStatement::close()
420 if (!isPrepared) return OK;
421 SQLCloseCursor(hstmt);
422 return OK;
424 bool SqlOdbcStatement::chechStmtType(char *buf)
426 char c;
427 while(1)
429 c=*buf;
430 if(c !=' ') break;
431 buf++;
433 if (strncasecmp (buf, "SELECT", 6) == 0) { return true;}
434 return false;
436 void* SqlOdbcStatement::getFieldValuePtr( int pos )
439 ListIterator biter = bindList.getIterator();
440 BindSqlProjectField *elem = NULL;
441 int count =0;
442 while (biter.hasElement())
444 elem = (BindSqlProjectField*) biter.nextElement();
445 if (count == pos)
447 return elem->targetvalue;
449 count++;
451 return NULL;
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;
471 int count =0;
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;
480 return OK;
482 count++;
484 return ErrNotFound;
487 DbRetVal SqlOdbcStatement::getParamFldInfo (int parampos, FieldInfo *&fInfo)
489 ListIterator biter = paramList.getIterator();
490 BindSqlField *elem = NULL;
491 int count =0;
492 while (biter.hasElement())
494 elem = (BindSqlField*) biter.nextElement();
495 if (count == parampos)
497 fInfo->length = elem->length;
498 fInfo->type =elem->type;
499 return OK;
501 count++;
503 return ErrNotFound;
506 DbRetVal SqlOdbcStatement::free()
508 isPrepared = false;
509 ListIterator biter = bindList.getIterator();
510 BindSqlProjectField *elem = NULL;
511 while (biter.hasElement())
513 elem = (BindSqlProjectField*) biter.nextElement();
514 ::free(elem->targetvalue);
515 delete elem;
517 bindList.reset();
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);
525 delete bindField;
527 paramList.reset();
529 SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
530 return OK;
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);
539 return;
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;
549 //Note: MySQL Bug
550 //Bug #1382 SQLDescribeParam returns the same type information, varchar
551 AllDataType::convertToString(bindField->value, &value, typeInt);
552 return;
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;
561 //Note: MySQL Bug
562 //Bug #1382 SQLDescribeParam returns the same type information, varchar
563 AllDataType::convertToString(bindField->value, &value, typeLong);
564 return;
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);
574 return;
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';
610 return;
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)
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);
657 SQLFetch(hstmt);
658 SQLGetData(hstmt, 4, SQL_C_CHAR, (SQLCHAR*) columnName, sizeof(columnName),&cbData);
659 strcpy(pkfieldname, columnName);
660 SQLFreeHandle (SQL_HANDLE_STMT, hstmt);
661 return;
664 bool SqlOdbcStatement::isFldNull(int pos)
666 if( len[pos] == SQL_NULL_DATA )
667 return true;
668 else
669 return false;
671 void SqlOdbcStatement::setNull(int pos)
673 len[pos] == SQL_NULL_DATA ;