1 /*--------
2 * Module: options.c
3 *
4 * Description: This module contains routines for getting/setting
5 * connection and statement options.
6 *
7 * Classes: n/a
8 *
9 * API functions: SQLSetConnectOption, SQLSetStmtOption, SQLGetConnectOption,
10 * SQLGetStmtOption
11 *
12 * Comments: See "readme.txt" for copyright and license information.
13 *--------
14 */
15
16 #include "psqlodbc.h"
17 #include "unicode_support.h"
18 #include <string.h>
19
20 #include "misc.h"
21 #include "environ.h"
22 #include "connection.h"
23 #include "statement.h"
24 #include "qresult.h"
25 #include "pgapifunc.h"
26
27 static RETCODE
set_statement_option(ConnectionClass * conn,StatementClass * stmt,SQLUSMALLINT fOption,SQLULEN vParam)28 set_statement_option(ConnectionClass *conn,
29 StatementClass *stmt,
30 SQLUSMALLINT fOption,
31 SQLULEN vParam)
32 {
33 CSTR func = "set_statement_option";
34 char changed = FALSE;
35 ConnInfo *ci = NULL;
36 SQLULEN setval;
37
38 if (conn)
39 ci = &(conn->connInfo);
40 else
41 ci = &(SC_get_conn(stmt)->connInfo);
42 switch (fOption)
43 {
44 case SQL_ASYNC_ENABLE: /* ignored */
45 break;
46
47 case SQL_BIND_TYPE:
48 /* now support multi-column and multi-row binding */
49 if (conn)
50 conn->ardOptions.bind_size = (SQLUINTEGER) vParam;
51 if (stmt)
52 SC_get_ARDF(stmt)->bind_size = (SQLUINTEGER) vParam;
53 break;
54
55 case SQL_CONCURRENCY:
56 /*
57 * positioned update isn't supported so cursor concurrency is
58 * read-only
59 */
60 MYLOG(0, "SQL_CONCURRENCY = " FORMAT_LEN " ", vParam);
61 setval = SQL_CONCUR_READ_ONLY;
62 if (SQL_CONCUR_READ_ONLY == vParam)
63 ;
64 else if (ci->drivers.lie)
65 setval = vParam;
66 else if (0 != ci->updatable_cursors)
67 setval = SQL_CONCUR_ROWVER;
68 if (conn)
69 conn->stmtOptions.scroll_concurrency = (SQLUINTEGER) setval;
70 else if (stmt)
71 {
72 if (SC_get_Result(stmt))
73 {
74 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.", func);
75 return SQL_ERROR;
76 }
77 stmt->options.scroll_concurrency =
78 stmt->options_orig.scroll_concurrency = (SQLUINTEGER) setval;
79 }
80 if (setval != vParam)
81 changed = TRUE;
82 MYPRINTF(0, "-> " FORMAT_LEN "\n", setval);
83 break;
84
85 case SQL_CURSOR_TYPE:
86 /*
87 * if declare/fetch, then type can only be forward. otherwise,
88 * it can only be forward or static.
89 */
90 MYLOG(0, "SQL_CURSOR_TYPE = " FORMAT_LEN " ", vParam);
91 setval = SQL_CURSOR_FORWARD_ONLY;
92 if (ci->drivers.lie)
93 setval = vParam;
94 else if (SQL_CURSOR_STATIC == vParam)
95 setval = vParam;
96 else if (SQL_CURSOR_KEYSET_DRIVEN == vParam)
97 {
98 if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
99 setval = vParam;
100 else
101 setval = SQL_CURSOR_STATIC; /* at least scrollable */
102 }
103 else if (SQL_CURSOR_DYNAMIC == vParam)
104 {
105 if (0 != (ci->updatable_cursors & ALLOW_DYNAMIC_CURSORS))
106 setval = vParam;
107 else if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
108 setval = SQL_CURSOR_KEYSET_DRIVEN;
109 else
110 setval = SQL_CURSOR_STATIC; /* at least scrollable */
111 }
112 if (conn)
113 conn->stmtOptions.cursor_type = (SQLUINTEGER) setval;
114 else if (stmt)
115 {
116 if (SC_get_Result(stmt))
117 {
118 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The attr can't be changed because the cursor is open.", func);
119 return SQL_ERROR;
120 }
121 stmt->options_orig.cursor_type =
122 stmt->options.cursor_type = (SQLUINTEGER) setval;
123 }
124 if (setval != vParam)
125 changed = TRUE;
126 MYPRINTF(0, "-> " FORMAT_LEN "\n", setval);
127 break;
128
129 case SQL_KEYSET_SIZE: /* ignored, but saved and returned */
130 MYLOG(0, "SQL_KEYSET_SIZE, vParam = " FORMAT_LEN "\n", vParam);
131
132 if (conn)
133 conn->stmtOptions.keyset_size = vParam;
134 if (stmt)
135 {
136 stmt->options_orig.keyset_size = vParam;
137 if (!SC_get_Result(stmt))
138 stmt->options.keyset_size = vParam;
139 if (stmt->options.keyset_size != (SQLLEN) vParam)
140 changed = TRUE;
141 }
142
143 break;
144
145 case SQL_MAX_LENGTH: /* ignored, but saved */
146 MYLOG(0, "SQL_MAX_LENGTH, vParam = " FORMAT_LEN "\n", vParam);
147 if (conn)
148 conn->stmtOptions.maxLength = vParam;
149 if (stmt)
150 {
151 stmt->options_orig.maxLength = vParam;
152 if (!SC_get_Result(stmt))
153 stmt->options.maxLength = vParam;
154 if (stmt->options.maxLength != (SQLLEN) vParam)
155 changed = TRUE;
156 }
157 break;
158
159 case SQL_MAX_ROWS: /* ignored, but saved */
160 MYLOG(0, "SQL_MAX_ROWS, vParam = " FORMAT_LEN "\n", vParam);
161 if (conn)
162 conn->stmtOptions.maxRows = vParam;
163 if (stmt)
164 {
165 stmt->options_orig.maxRows = vParam;
166 if (!SC_get_Result(stmt))
167 stmt->options.maxRows = vParam;
168 if (stmt->options.maxRows != (SQLLEN)vParam)
169 changed = TRUE;
170 }
171 break;
172
173 case SQL_NOSCAN: /* ignored */
174 MYLOG(0, "SQL_NOSCAN, vParam = " FORMAT_LEN "\n", vParam);
175 break;
176
177 case SQL_QUERY_TIMEOUT: /* ignored */
178 MYLOG(0, "SQL_QUERY_TIMEOUT, vParam = " FORMAT_LEN "\n", vParam);
179 if (conn)
180 conn->stmtOptions.stmt_timeout = (SQLULEN) vParam;
181 if (stmt)
182 stmt->options.stmt_timeout = (SQLULEN) vParam;
183 break;
184
185 case SQL_RETRIEVE_DATA:
186 MYLOG(0, "SQL_RETRIEVE_DATA, vParam = " FORMAT_LEN "\n", vParam);
187 if (conn)
188 conn->stmtOptions.retrieve_data = (SQLUINTEGER) vParam;
189 if (stmt)
190 stmt->options.retrieve_data = (SQLUINTEGER) vParam;
191 break;
192
193 case SQL_ROWSET_SIZE:
194 MYLOG(0, "SQL_ROWSET_SIZE, vParam = " FORMAT_LEN "\n", vParam);
195
196 if (vParam < 1)
197 {
198 vParam = 1;
199 changed = TRUE;
200 }
201
202 if (conn)
203 conn->ardOptions.size_of_rowset_odbc2 = vParam;
204 if (stmt)
205 SC_get_ARDF(stmt)->size_of_rowset_odbc2 = vParam;
206 break;
207
208 case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
209 if (stmt)
210 {
211 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported. Use the cursor library.", func);
212 }
213 if (conn)
214 {
215 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Simulated positioned update/delete not supported. Use the cursor library.", func);
216 }
217 return SQL_ERROR;
218
219 case SQL_USE_BOOKMARKS:
220 if (stmt)
221 {
222 MYLOG(0, "USE_BOOKMARKS %s\n", (vParam == SQL_UB_OFF) ? "off" : ((vParam == SQL_UB_VARIABLE) ? "variable" : "fixed"));
223 setval = vParam;
224 stmt->options.use_bookmarks = (SQLUINTEGER) setval;
225 }
226 if (conn)
227 conn->stmtOptions.use_bookmarks = (SQLUINTEGER) vParam;
228 break;
229
230 case 1204: /* SQL_COPT_SS_PRESERVE_CURSORS ? */
231 if (stmt)
232 {
233 SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
234 }
235 else if (conn)
236 {
237 CC_set_error(conn, CONN_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
238 }
239 return SQL_ERROR;
240 case 1227: /* SQL_SOPT_SS_HIDDEN_COLUMNS ? */
241 case 1228: /* SQL_SOPT_SS_NOBROWSETABLE ? */
242 if (stmt)
243 {
244 #ifndef NOT_USED
245 if (0 != vParam)
246 changed = TRUE;
247 break;
248 #else
249 SC_set_error(stmt, STMT_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
250 #endif /* NOT_USED */
251 }
252 else if (conn)
253 {
254 CC_set_error(conn, CONN_OPTION_NOT_FOR_THE_DRIVER, "The option may be for MS SQL Server(Set)", func);
255 }
256 return SQL_ERROR;
257 default:
258 {
259 char option[64];
260
261 if (stmt)
262 {
263 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)", func);
264 SPRINTF_FIXED(option, "fOption=%d, vParam=" FORMAT_ULEN, fOption, vParam);
265 SC_log_error(func, option, stmt);
266 }
267 if (conn)
268 {
269 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Set)", func);
270 SPRINTF_FIXED(option, "fOption=%d, vParam=" FORMAT_ULEN, fOption, vParam);
271 CC_log_error(func, option, conn);
272 }
273
274 return SQL_ERROR;
275 }
276 }
277
278 if (changed)
279 {
280 if (stmt)
281 {
282 SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "Requested value changed.", func);
283 }
284 if (conn)
285 {
286 CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.", func);
287 }
288 return SQL_SUCCESS_WITH_INFO;
289 }
290 else
291 return SQL_SUCCESS;
292 }
293
294
295 /* Implements only SQL_AUTOCOMMIT */
296 RETCODE SQL_API
PGAPI_SetConnectOption(HDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam)297 PGAPI_SetConnectOption(HDBC hdbc,
298 SQLUSMALLINT fOption,
299 SQLULEN vParam)
300 {
301 CSTR func = "PGAPI_SetConnectOption";
302 ConnectionClass *conn = (ConnectionClass *) hdbc;
303 char changed = FALSE;
304 RETCODE retval;
305 BOOL autocomm_on;
306
307 MYLOG(0, "entering fOption = %d vParam = " FORMAT_LEN "\n", fOption, vParam);
308 if (!conn)
309 {
310 CC_log_error(func, "", NULL);
311 return SQL_INVALID_HANDLE;
312 }
313
314 switch (fOption)
315 {
316 /*
317 * Statement Options (apply to all stmts on the connection and
318 * become defaults for new stmts)
319 */
320 case SQL_ASYNC_ENABLE:
321 case SQL_BIND_TYPE:
322 case SQL_CONCURRENCY:
323 case SQL_CURSOR_TYPE:
324 case SQL_KEYSET_SIZE:
325 case SQL_MAX_LENGTH:
326 case SQL_MAX_ROWS:
327 case SQL_NOSCAN:
328 case SQL_QUERY_TIMEOUT:
329 case SQL_RETRIEVE_DATA:
330 case SQL_ROWSET_SIZE:
331 case SQL_SIMULATE_CURSOR:
332 case SQL_USE_BOOKMARKS:
333 /*
334 * Become the default for all future statements on this
335 * connection
336 */
337 retval = set_statement_option(conn, NULL, fOption, vParam);
338
339 if (retval == SQL_SUCCESS_WITH_INFO)
340 changed = TRUE;
341 else if (retval == SQL_ERROR)
342 return SQL_ERROR;
343
344 break;
345
346 /*
347 * Connection Options
348 */
349
350 case SQL_ACCESS_MODE: /* ignored */
351 break;
352
353 case SQL_AUTOCOMMIT:
354 switch (vParam)
355 {
356 case SQL_AUTOCOMMIT_ON:
357 autocomm_on = TRUE;
358 break;
359 case SQL_AUTOCOMMIT_OFF:
360 autocomm_on = FALSE;
361 break;
362 default:
363 CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "Illegal parameter value for SQL_AUTOCOMMIT", func);
364 return SQL_ERROR;
365 }
366 if (autocomm_on && SQL_AUTOCOMMIT_OFF != conn->autocommit_public)
367 break;
368 else if (!autocomm_on && SQL_AUTOCOMMIT_OFF == conn->autocommit_public)
369 break;
370 conn->autocommit_public = (autocomm_on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
371 MYLOG(0, "AUTOCOMMIT: transact_status=%d, vparam=" FORMAT_LEN "\n", conn->transact_status, vParam);
372
373 #ifdef _HANDLE_ENLIST_IN_DTC_
374 if (CC_is_in_global_trans(conn))
375 {
376 CC_set_error(conn, CONN_ILLEGAL_TRANSACT_STATE, "Don't change AUTOCOMMIT mode in a distributed transaction", func);
377 return SQL_ERROR;
378 }
379 #endif /* _HANDLE_ENLIST_IN_DTC_ */
380 CC_set_autocommit(conn, autocomm_on);
381 break;
382
383 case SQL_CURRENT_QUALIFIER: /* ignored */
384 break;
385
386 case SQL_LOGIN_TIMEOUT:
387 conn->login_timeout = (SQLUINTEGER) vParam;
388 break;
389
390 case SQL_PACKET_SIZE: /* ignored */
391 break;
392
393 case SQL_QUIET_MODE: /* ignored */
394 break;
395
396 case SQL_TXN_ISOLATION:
397 if (conn->isolation == vParam)
398 break;
399 /*
400 * If the connection is not established, just record the setting to
401 * reflect it upon connection.
402 */
403 if (CC_not_connected(conn))
404 {
405 conn->isolation = (UInt4) vParam;
406 break;
407 }
408
409 /* The ODBC spec prohibits changing the isolation level while in manual transaction. */
410 if (CC_is_in_trans(conn))
411 {
412 if (CC_does_autocommit(conn) && !CC_is_in_error_trans(conn))
413 CC_commit(conn);
414 else
415 {
416 CC_set_error(conn, CONN_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress", func);
417 return SQL_ERROR;
418 }
419 }
420
421 if (!CC_set_transact(conn, (UInt4) vParam))
422 return SQL_ERROR;
423
424 conn->isolation = (UInt4) vParam;
425 break;
426
427 /* These options should be handled by driver manager */
428 case SQL_ODBC_CURSORS:
429 case SQL_OPT_TRACE:
430 case SQL_OPT_TRACEFILE:
431 case SQL_TRANSLATE_DLL:
432 case SQL_TRANSLATE_OPTION:
433 CC_log_error(func, "This connect option (Set) is only used by the Driver Manager", conn);
434 break;
435
436 default:
437 {
438 char option[64];
439
440 CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Set)", func);
441 SPRINTF_FIXED(option, "fOption=%d, vParam=" FORMAT_LEN, fOption, vParam);
442 #ifdef WIN32
443 if (fOption == 30002 && vParam)
444 {
445 int cmp;
446 #ifdef UNICODE_SUPPORT
447 if (CC_is_in_unicode_driver(conn))
448 {
449 char *asPara = ucs2_to_utf8((SQLWCHAR *) vParam, SQL_NTS, NULL, FALSE);
450 cmp = strcmp(asPara, "Microsoft Jet");
451 free(asPara);
452 }
453 else
454 #endif /* UNICODE_SUPPORT */
455 cmp = strncmp((char *) vParam, "Microsoft Jet", 13);
456 if (0 == cmp)
457 {
458 MYLOG(0, "Microsoft Jet !!!!\n");
459 CC_set_errornumber(conn, 0);
460 conn->ms_jet = 1;
461 return SQL_SUCCESS;
462 }
463 }
464 #endif /* WIN32 */
465 CC_log_error(func, option, conn);
466 return SQL_ERROR;
467 }
468 }
469
470 if (changed)
471 {
472 CC_set_error(conn, CONN_OPTION_VALUE_CHANGED, "Requested value changed.", func);
473 return SQL_SUCCESS_WITH_INFO;
474 }
475 else
476 return SQL_SUCCESS;
477 }
478
479
480 /* This function just can tell you whether you are in Autcommit mode or not */
481 RETCODE SQL_API
PGAPI_GetConnectOption(HDBC hdbc,SQLUSMALLINT fOption,PTR pvParam,SQLINTEGER * StringLength,SQLINTEGER BufferLength)482 PGAPI_GetConnectOption(HDBC hdbc,
483 SQLUSMALLINT fOption,
484 PTR pvParam,
485 SQLINTEGER *StringLength,
486 SQLINTEGER BufferLength)
487 {
488 CSTR func = "PGAPI_GetConnectOption";
489 ConnectionClass *conn = (ConnectionClass *) hdbc;
490 const char *p = NULL;
491 SQLLEN len = sizeof(SQLINTEGER);
492 SQLRETURN result = SQL_SUCCESS;
493
494 MYLOG(0, "entering...\n");
495
496 if (!conn)
497 {
498 CC_log_error(func, "", NULL);
499 return SQL_INVALID_HANDLE;
500 }
501
502 switch (fOption)
503 {
504 case SQL_ACCESS_MODE: /* NOT SUPPORTED */
505 *((SQLUINTEGER *) pvParam) = SQL_MODE_READ_WRITE;
506 break;
507
508 case SQL_AUTOCOMMIT:
509 *((SQLUINTEGER *) pvParam) = conn->autocommit_public;
510 break;
511
512 case SQL_CURRENT_QUALIFIER: /* don't use qualifiers */
513 len = 0;
514 p = CurrCatString(conn);
515 break;
516
517 case SQL_LOGIN_TIMEOUT:
518 *((SQLUINTEGER *) pvParam) = conn->login_timeout;
519 break;
520
521 case SQL_PACKET_SIZE: /* NOT SUPPORTED */
522 *((SQLUINTEGER *) pvParam) = 4096;
523 break;
524
525 case SQL_QUERY_TIMEOUT:
526 *((SQLULEN *) pvParam) = conn->stmtOptions.stmt_timeout;
527 break;
528
529 case SQL_QUIET_MODE: /* NOT SUPPORTED */
530 *((SQLULEN *) pvParam) = 0;
531 break;
532
533 case SQL_TXN_ISOLATION:
534 if (conn->isolation == 0)
535 {
536 if (CC_not_connected(conn))
537 return SQL_NO_DATA;
538 conn->isolation = CC_get_isolation(conn);
539 }
540 *((SQLUINTEGER *) pvParam) = conn->isolation;
541 break;
542
543 #ifdef SQL_ATTR_CONNECTION_DEAD
544 case SQL_ATTR_CONNECTION_DEAD:
545 #else
546 case 1209:
547 #endif /* SQL_ATTR_CONNECTION_DEAD */
548 MYLOG(0, "CONNECTION_DEAD status=%d", conn->status);
549 *((SQLUINTEGER *) pvParam) = CC_not_connected(conn);
550 MYPRINTF(0, " val=" FORMAT_UINTEGER "\n", *((SQLUINTEGER *) pvParam));
551 break;
552
553 case SQL_ATTR_ANSI_APP:
554 *((SQLUINTEGER *) pvParam) = CC_is_in_ansi_app(conn);
555 MYLOG(0, "ANSI_APP val=" FORMAT_UINTEGER "\n", *((SQLUINTEGER *) pvParam));
556 break;
557
558 /* These options should be handled by driver manager */
559 case SQL_ODBC_CURSORS:
560 case SQL_OPT_TRACE:
561 case SQL_OPT_TRACEFILE:
562 case SQL_TRANSLATE_DLL:
563 case SQL_TRANSLATE_OPTION:
564 CC_log_error(func, "This connect option (Get) is only used by the Driver Manager", conn);
565 break;
566
567 default:
568 {
569 char option[64];
570
571 CC_set_error(conn, CONN_UNSUPPORTED_OPTION, "Unknown connect option (Get)", func);
572 SPRINTF_FIXED(option, "fOption=%d", fOption);
573 CC_log_error(func, option, conn);
574 return SQL_ERROR;
575 break;
576 }
577 }
578
579 if (NULL != p && 0 == len)
580 {
581 /* char/binary data */
582 len = strlen(p);
583
584 if (pvParam)
585 {
586 #ifdef UNICODE_SUPPORT
587 if (CC_is_in_unicode_driver(conn))
588 {
589 len = utf8_to_ucs2(p, len, (SQLWCHAR *) pvParam , BufferLength / WCLEN);
590 len *= WCLEN;
591 }
592 else
593 #endif /* UNICODE_SUPPORT */
594 strncpy_null((char *) pvParam, p, (size_t) BufferLength);
595
596 if (len >= BufferLength)
597 {
598 result = SQL_SUCCESS_WITH_INFO;
599 CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the pvParam.", func);
600 }
601 }
602 }
603 if (StringLength)
604 *StringLength = (SQLINTEGER) len;
605 return result;
606 }
607
608
609 RETCODE SQL_API
PGAPI_SetStmtOption(HSTMT hstmt,SQLUSMALLINT fOption,SQLULEN vParam)610 PGAPI_SetStmtOption(HSTMT hstmt,
611 SQLUSMALLINT fOption,
612 SQLULEN vParam)
613 {
614 CSTR func = "PGAPI_SetStmtOption";
615 StatementClass *stmt = (StatementClass *) hstmt;
616 RETCODE retval;
617
618 MYLOG(0, " entering...\n");
619
620 /*
621 * Though we could fake Access out by just returning SQL_SUCCESS all
622 * the time, but it tries to set a huge value for SQL_MAX_LENGTH and
623 * expects the driver to reduce it to the real value.
624 */
625 if (!stmt)
626 {
627 SC_log_error(func, "", NULL);
628 return SQL_INVALID_HANDLE;
629 }
630
631 /* StartRollbackState(stmt); */
632 retval = set_statement_option(NULL, stmt, fOption, vParam);
633 return retval;
634 }
635
636
637 RETCODE SQL_API
PGAPI_GetStmtOption(HSTMT hstmt,SQLUSMALLINT fOption,PTR pvParam,SQLINTEGER * StringLength,SQLINTEGER BufferLength)638 PGAPI_GetStmtOption(HSTMT hstmt,
639 SQLUSMALLINT fOption,
640 PTR pvParam,
641 SQLINTEGER *StringLength,
642 SQLINTEGER BufferLength)
643 {
644 CSTR func = "PGAPI_GetStmtOption";
645 StatementClass *stmt = (StatementClass *) hstmt;
646 QResultClass *res;
647 SQLLEN ridx;
648 SQLINTEGER len = sizeof(SQLINTEGER);
649 Int4 bookmark;
650
651 MYLOG(0, "entering...\n");
652
653 /*
654 * thought we could fake Access out by just returning SQL_SUCCESS all
655 * the time, but it tries to set a huge value for SQL_MAX_LENGTH and
656 * expects the driver to reduce it to the real value
657 */
658 if (!stmt)
659 {
660 SC_log_error(func, "", NULL);
661 return SQL_INVALID_HANDLE;
662 }
663
664 switch (fOption)
665 {
666 case SQL_GET_BOOKMARK:
667 case SQL_ROW_NUMBER:
668
669 res = SC_get_Curres(stmt);
670 if (!res)
671 {
672 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor has no result.", func);
673 return SQL_ERROR;
674 }
675
676 ridx = GIdx2CacheIdx(stmt->currTuple, stmt, res);
677 if (!SC_is_fetchcursor(stmt))
678 {
679 /* make sure we're positioned on a valid row */
680 if ((ridx < 0) ||
681 (((SQLULEN) ridx) >= QR_get_num_cached_tuples(res)))
682 {
683 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.", func);
684 return SQL_ERROR;
685 }
686 }
687 else
688 {
689 if (stmt->currTuple < 0 || !res->tupleField)
690 {
691 SC_set_error(stmt, STMT_INVALID_CURSOR_STATE_ERROR, "Not positioned on a valid row.", func);
692 return SQL_ERROR;
693 }
694 }
695
696 if (fOption == SQL_GET_BOOKMARK && stmt->options.use_bookmarks == SQL_UB_OFF)
697 {
698 SC_set_error(stmt, STMT_OPERATION_INVALID, "Operation invalid because use bookmarks not enabled.", func);
699 return SQL_ERROR;
700 }
701
702 bookmark = SC_make_int4_bookmark(stmt->currTuple);
703 memcpy(pvParam, &bookmark, sizeof(UInt4));
704
705 break;
706
707 case SQL_ASYNC_ENABLE: /* NOT SUPPORTED */
708 *((SQLINTEGER *) pvParam) = SQL_ASYNC_ENABLE_OFF;
709 break;
710
711 case SQL_BIND_TYPE:
712 *((SQLINTEGER *) pvParam) = SC_get_ARDF(stmt)->bind_size;
713 break;
714
715 case SQL_CONCURRENCY: /* NOT REALLY SUPPORTED */
716 MYLOG(0, "SQL_CONCURRENCY " FORMAT_INTEGER "\n", stmt->options.scroll_concurrency);
717 *((SQLINTEGER *) pvParam) = stmt->options.scroll_concurrency;
718 break;
719
720 case SQL_CURSOR_TYPE: /* PARTIAL SUPPORT */
721 MYLOG(0, "SQL_CURSOR_TYPE " FORMAT_INTEGER "\n", stmt->options.cursor_type);
722 *((SQLINTEGER *) pvParam) = stmt->options.cursor_type;
723 break;
724
725 case SQL_KEYSET_SIZE: /* NOT SUPPORTED, but saved */
726 MYLOG(0, "SQL_KEYSET_SIZE\n");
727 *((SQLLEN *) pvParam) = stmt->options.keyset_size;
728 break;
729
730 case SQL_MAX_LENGTH: /* NOT SUPPORTED, but saved */
731 *((SQLLEN *) pvParam) = stmt->options.maxLength;
732 break;
733
734 case SQL_MAX_ROWS: /* NOT SUPPORTED, but saved */
735 *((SQLLEN *) pvParam) = stmt->options.maxRows;
736 MYLOG(0, "MAX_ROWS, returning " FORMAT_LEN "\n", stmt->options.maxRows);
737 break;
738
739 case SQL_NOSCAN: /* NOT SUPPORTED */
740 *((SQLINTEGER *) pvParam) = SQL_NOSCAN_ON;
741 break;
742
743 case SQL_QUERY_TIMEOUT: /* NOT SUPPORTED */
744 *((SQLULEN *) pvParam) = stmt->options.stmt_timeout;
745 break;
746
747 case SQL_RETRIEVE_DATA:
748 *((SQLINTEGER *) pvParam) = stmt->options.retrieve_data;
749 break;
750
751 case SQL_ROWSET_SIZE:
752 *((SQLLEN *) pvParam) = SC_get_ARDF(stmt)->size_of_rowset_odbc2;
753 break;
754
755 case SQL_SIMULATE_CURSOR: /* NOT SUPPORTED */
756 *((SQLINTEGER *) pvParam) = SQL_SC_NON_UNIQUE;
757 break;
758
759 case SQL_USE_BOOKMARKS:
760 *((SQLINTEGER *) pvParam) = stmt->options.use_bookmarks;
761 break;
762 case 1227: /* SQL_SOPT_SS_HIDDEN_COLUMNS ? */
763 case 1228: /* SQL_SOPT_SS_NOBROWSETABLE ? */
764 *((SQLINTEGER *) pvParam) = 0;
765 break;
766
767 default:
768 {
769 char option[64];
770
771 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Unknown statement option (Get)", func);
772 SPRINTF_FIXED(option, "fOption=%d", fOption);
773 SC_log_error(func, option, stmt);
774 return SQL_ERROR;
775 }
776 }
777 if (StringLength)
778 *StringLength = len;
779
780 return SQL_SUCCESS;
781 }
782