1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001 Brian Bruns
3 : * Copyright (C) 2002, 2003, 2004, 2005, 2006 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library 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 GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : /*
22 : * PROGRAMMER NAME CONTACT
23 : *==============================================================
24 : * BSB Brian Bruns camber@ais.org
25 : * PAH Peter Harvey pharvey@codebydesign.com
26 : * SMURPH Steve Murphree smurph@smcomp.com
27 : *
28 : ***************************************************************
29 : * DATE PROGRAMMER CHANGE
30 : *==============================================================
31 : * Original.
32 : * 03.FEB.02 PAH Started adding use of SQLGetPrivateProfileString().
33 : * 04.FEB.02 PAH Fixed small error preventing SQLBindParameter from being called
34 : */
35 :
36 : #if HAVE_CONFIG_H
37 : #include <config.h>
38 : #endif /* HAVE_CONFIG_H */
39 :
40 : #include <stdio.h>
41 :
42 : #if HAVE_STDLIB_H
43 : #include <stdlib.h>
44 : #endif /* HAVE_STDLIB_H */
45 :
46 : #if HAVE_STRING_H
47 : #include <string.h>
48 : #endif /* HAVE_STRING_H */
49 :
50 : #include <stdarg.h>
51 : #include <assert.h>
52 : #include <ctype.h>
53 :
54 : #include "tdsodbc.h"
55 : #include "tdsstring.h"
56 : #include "tdsconvert.h"
57 : #include "replacements.h"
58 :
59 : #ifdef DMALLOC
60 : #include <dmalloc.h>
61 : #endif
62 :
63 : TDS_RCSID(var, "$Id: odbc.c,v 1.402.2.6 2007/12/21 11:19:01 freddy77 Exp $");
64 :
65 : static SQLRETURN SQL_API _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);
66 : static SQLRETURN SQL_API _SQLAllocEnv(SQLHENV FAR * phenv);
67 : static SQLRETURN SQL_API _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt);
68 : static SQLRETURN SQL_API _SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phstmt);
69 : static SQLRETURN SQL_API _SQLFreeConnect(SQLHDBC hdbc);
70 : static SQLRETURN SQL_API _SQLFreeEnv(SQLHENV henv);
71 : static SQLRETURN SQL_API _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force);
72 : static SQLRETURN SQL_API _SQLFreeDesc(SQLHDESC hdesc);
73 : static SQLRETURN SQL_API _SQLExecute(TDS_STMT * stmt);
74 : static SQLRETURN SQL_API _SQLGetConnectAttr(SQLHDBC hdbc, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,
75 : SQLINTEGER * StringLength);
76 : static SQLRETURN SQL_API _SQLSetConnectAttr(SQLHDBC hdbc, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
77 : static SQLRETURN SQL_API _SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength);
78 : static SQLRETURN SQL_API _SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,
79 : SQLINTEGER * StringLength);
80 : static SQLRETURN SQL_API _SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,
81 : SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc);
82 : static SQLRETURN SQL_API _SQLFetch(TDS_STMT * stmt);
83 : static int query_timeout_cancel(void *param, unsigned int total_timeout);
84 : static SQLRETURN odbc_populate_ird(TDS_STMT * stmt);
85 : static int odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg);
86 : static void odbc_log_unimplemented_type(const char function_name[], int fType);
87 : static void odbc_upper_column_names(TDS_STMT * stmt);
88 : static void odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name);
89 : static SQLRETURN odbc_stat_execute(TDS_STMT * stmt, const char *begin, int nparams, ...);
90 : static SQLRETURN odbc_free_dynamic(TDS_STMT * stmt);
91 : static SQLSMALLINT odbc_swap_datetime_sql_type(SQLSMALLINT sql_type);
92 : static int odbc_process_tokens(TDS_STMT * stmt, unsigned flag);
93 :
94 : #if ENABLE_EXTRA_CHECKS
95 : static void odbc_ird_check(TDS_STMT * stmt);
96 :
97 : #define IRD_CHECK odbc_ird_check(stmt)
98 : #else
99 : #define IRD_CHECK
100 : #endif
101 :
102 : /**
103 : * \defgroup odbc_api ODBC API
104 : * Functions callable by \c ODBC client programs
105 : */
106 :
107 :
108 : /* utils to check handles */
109 : #define CHECK_HDBC if ( SQL_NULL_HDBC == hdbc || !IS_HDBC(hdbc) ) return SQL_INVALID_HANDLE;
110 : #define CHECK_HSTMT if ( SQL_NULL_HSTMT == hstmt || !IS_HSTMT(hstmt) ) return SQL_INVALID_HANDLE;
111 : #define CHECK_HENV if ( SQL_NULL_HENV == henv || !IS_HENV(henv) ) return SQL_INVALID_HANDLE;
112 : #define CHECK_HDESC if ( SQL_NULL_HDESC == hdesc || !IS_HDESC(hdesc) ) return SQL_INVALID_HANDLE;
113 :
114 : #define INIT_HSTMT \
115 : TDS_STMT *stmt = (TDS_STMT*)hstmt; \
116 : CHECK_HSTMT; \
117 : CHECK_STMT_EXTRA(stmt); \
118 : odbc_errs_reset(&stmt->errs); \
119 :
120 : #define INIT_HDBC \
121 : TDS_DBC *dbc = (TDS_DBC*)hdbc; \
122 : CHECK_HDBC; \
123 : CHECK_DBC_EXTRA(dbc); \
124 : odbc_errs_reset(&dbc->errs); \
125 :
126 : #define INIT_HENV \
127 : TDS_ENV *env = (TDS_ENV*)henv; \
128 : CHECK_HENV; \
129 : CHECK_ENV_EXTRA(env); \
130 : odbc_errs_reset(&env->errs); \
131 :
132 : #define INIT_HDESC \
133 : TDS_DESC *desc = (TDS_DESC*)hdesc; \
134 : CHECK_HDESC; \
135 : CHECK_DESC_EXTRA(desc); \
136 : odbc_errs_reset(&desc->errs); \
137 :
138 : #define IS_VALID_LEN(len) ((len) >= 0 || (len) == SQL_NTS || (len) == SQL_NULL_DATA)
139 :
140 : /*
141 : * Note: I *HATE* hungarian notation, it has to be the most idiotic thing
142 : * I've ever seen. So, you will note it is avoided other than in the function
143 : * declarations. "Gee, let's make our code totally hard to read and they'll
144 : * beg for GUI tools"
145 : * Bah!
146 : */
147 :
148 : static void
149 : odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name)
150 85 : {
151 : #if ENABLE_EXTRA_CHECKS
152 : TDSRESULTINFO *resinfo;
153 : #endif
154 :
155 85 : IRD_CHECK;
156 :
157 : #if ENABLE_EXTRA_CHECKS
158 85 : if (colpos > 0 && stmt->dbc->tds_socket != NULL && (resinfo = stmt->dbc->tds_socket->current_results) != NULL) {
159 85 : if (colpos <= resinfo->num_cols) {
160 : /* no overflow possible, name is always shorter */
161 85 : strcpy(resinfo->columns[colpos - 1]->column_name, name);
162 85 : resinfo->columns[colpos - 1]->column_namelen = strlen(name);
163 : }
164 : }
165 : #endif
166 :
167 85 : if (colpos > 0 && colpos <= stmt->ird->header.sql_desc_count) {
168 85 : --colpos;
169 85 : tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_label, name);
170 85 : tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_name, name);
171 : }
172 85 : }
173 :
174 : /* spinellia@acm.org : copied shamelessly from change_database */
175 : static SQLRETURN
176 : change_autocommit(TDS_DBC * dbc, int state)
177 22 : {
178 22 : TDSSOCKET *tds = dbc->tds_socket;
179 : char query[80];
180 :
181 : /*
182 : * We may not be connected yet and dbc->tds_socket
183 : * may not initialized.
184 : */
185 22 : if (tds) {
186 : /*
187 : * mssql: SET IMPLICIT_TRANSACTION ON
188 : * sybase: SET CHAINED ON
189 : */
190 :
191 : /* implicit transactions are on if autocommit is off :-| */
192 22 : if (TDS_IS_MSSQL(tds))
193 11 : sprintf(query, "SET IMPLICIT_TRANSACTIONS %s", (state == SQL_AUTOCOMMIT_ON) ? "OFF" : "ON");
194 : else {
195 : /* Sybase, do not use SET CHAINED but emulate for compatility */
196 11 : if (state == SQL_AUTOCOMMIT_ON)
197 4 : strcpy(query, "WHILE @@TRANCOUNT > 0 COMMIT");
198 : else
199 7 : strcpy(query, "BEGIN TRANSACTION");
200 : }
201 :
202 22 : tdsdump_log(TDS_DBG_INFO1, "change_autocommit: executing %s\n", query);
203 :
204 22 : if (tds_submit_query(tds, query) != TDS_SUCCEED) {
205 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
206 0 : ODBC_RETURN(dbc, SQL_ERROR);
207 : }
208 22 : if (tds_process_simple_query(tds) != TDS_SUCCEED) {
209 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
210 0 : ODBC_RETURN(dbc, SQL_ERROR);
211 : }
212 22 : dbc->attr.autocommit = state;
213 : }
214 22 : ODBC_RETURN_(dbc);
215 : }
216 :
217 : static SQLRETURN
218 : change_database(TDS_DBC * dbc, char *database, int database_len)
219 0 : {
220 0 : TDSSOCKET *tds = dbc->tds_socket;
221 :
222 : /*
223 : * We may not be connected yet and dbc->tds_socket
224 : * may not initialized.
225 : */
226 0 : if (tds) {
227 : /* build query */
228 0 : char *query = (char *) malloc(6 + tds_quote_id(tds, NULL, database, database_len));
229 :
230 0 : if (!query) {
231 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
232 0 : ODBC_RETURN(dbc, SQL_ERROR);
233 : }
234 0 : strcpy(query, "USE ");
235 0 : tds_quote_id(tds, query + 4, database, database_len);
236 :
237 :
238 0 : tdsdump_log(TDS_DBG_INFO1, "change_database: executing %s\n", query);
239 :
240 0 : if (tds_submit_query(tds, query) != TDS_SUCCEED) {
241 0 : free(query);
242 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
243 0 : ODBC_RETURN(dbc, SQL_ERROR);
244 : }
245 0 : free(query);
246 0 : if (tds_process_simple_query(tds) != TDS_SUCCEED) {
247 0 : odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
248 0 : ODBC_RETURN(dbc, SQL_ERROR);
249 : }
250 : }
251 0 : ODBC_RETURN_(dbc);
252 : }
253 :
254 : static void
255 : odbc_env_change(TDSSOCKET * tds, int type, char *oldval, char *newval)
256 410 : {
257 : TDS_DBC *dbc;
258 :
259 410 : if (tds == NULL) {
260 0 : return;
261 : }
262 410 : dbc = (TDS_DBC *) tds->parent;
263 410 : if (!dbc)
264 0 : return;
265 :
266 410 : switch (type) {
267 : case TDS_ENV_DATABASE:
268 226 : tds_dstr_copy(&dbc->attr.current_catalog, newval);
269 226 : break;
270 : case TDS_ENV_PACKSIZE:
271 92 : dbc->attr.packet_size = atoi(newval);
272 : break;
273 : }
274 : }
275 :
276 : static SQLRETURN
277 : odbc_connect(TDS_DBC * dbc, TDSCONNECTION * connection)
278 94 : {
279 94 : TDS_ENV *env = dbc->env;
280 : TDSSOCKET *tds;
281 :
282 94 : dbc->tds_socket = tds = tds_alloc_socket(env->tds_ctx, 512);
283 94 : if (!tds) {
284 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
285 0 : ODBC_RETURN(dbc, SQL_ERROR);
286 : }
287 94 : tds_set_parent(tds, (void *) dbc);
288 :
289 : /* Set up our environment change hook */
290 94 : tds->env_chg_func = odbc_env_change;
291 :
292 94 : tds_fix_connection(connection);
293 :
294 94 : connection->connect_timeout = dbc->attr.connection_timeout;
295 :
296 94 : tds->query_timeout_func = query_timeout_cancel;
297 94 : tds->query_timeout_param = dbc;
298 94 : tds->query_timeout = dbc->attr.connection_timeout;
299 :
300 94 : if (tds_connect(tds, connection) == TDS_FAIL) {
301 2 : tds_free_socket(tds);
302 2 : dbc->tds_socket = NULL;
303 2 : odbc_errs_add(&dbc->errs, "08001", NULL);
304 2 : ODBC_RETURN(dbc, SQL_ERROR);
305 : }
306 92 : tds->query_timeout_func = NULL;
307 92 : tds->query_timeout_param = NULL;
308 :
309 : /* this overwrite any error arrived (wanted behavior, Sybase return error for conversion errors) */
310 92 : ODBC_RETURN(dbc, SQL_SUCCESS);
311 : }
312 :
313 : SQLRETURN SQL_API
314 : SQLDriverConnect(SQLHDBC hdbc, SQLHWND hwnd, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,
315 : SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut, SQLUSMALLINT fDriverCompletion)
316 8 : {
317 : TDSCONNECTION *connection;
318 8 : int conlen = odbc_get_string_size(cbConnStrIn, szConnStrIn);
319 :
320 8 : INIT_HDBC;
321 :
322 : #ifdef TDS_NO_DM
323 : /* Check string length */
324 8 : if (!IS_VALID_LEN(conlen) || conlen == 0) {
325 0 : odbc_errs_add(&dbc->errs, "HY090", NULL);
326 0 : ODBC_RETURN(dbc, SQL_ERROR);
327 : }
328 :
329 : /* Check completion param */
330 8 : switch (fDriverCompletion) {
331 : case SQL_DRIVER_NOPROMPT:
332 : case SQL_DRIVER_COMPLETE:
333 : case SQL_DRIVER_PROMPT:
334 : case SQL_DRIVER_COMPLETE_REQUIRED:
335 : break;
336 : default:
337 0 : odbc_errs_add(&dbc->errs, "HY110", NULL);
338 0 : ODBC_RETURN(dbc, SQL_ERROR);
339 : }
340 : #endif
341 :
342 8 : connection = tds_alloc_connection(dbc->env->tds_ctx->locale);
343 8 : if (!connection) {
344 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
345 0 : ODBC_RETURN(dbc, SQL_ERROR);
346 : }
347 :
348 : /* parse the DSN string */
349 8 : odbc_parse_connect_string((const char *) szConnStrIn, (const char *) szConnStrIn + conlen, connection);
350 :
351 : /* add login info */
352 8 : if (hwnd) {
353 : #ifdef WIN32
354 : /* prompt for login information */
355 : if (!get_login_info(hwnd, connection)) {
356 : tds_free_connection(connection);
357 : odbc_errs_add(&dbc->errs, "08001", "User canceled login");
358 : ODBC_RETURN(dbc, SQL_ERROR);
359 : }
360 : #else
361 : /* we dont support a dialog box */
362 0 : odbc_errs_add(&dbc->errs, "HYC00", NULL);
363 : #endif
364 : }
365 :
366 : /* TODO what should be correct behavior for output string?? -- freddy77 */
367 8 : if (szConnStrOut)
368 8 : odbc_set_string(szConnStrOut, cbConnStrOutMax, pcbConnStrOut, (const char *) szConnStrIn, conlen);
369 :
370 8 : if (tds_dstr_isempty(&connection->server_name)) {
371 0 : tds_free_connection(connection);
372 0 : odbc_errs_add(&dbc->errs, "IM007", "Could not find Servername or server parameter");
373 0 : ODBC_RETURN(dbc, SQL_ERROR);
374 : }
375 :
376 8 : if (tds_dstr_isempty(&connection->user_name)) {
377 0 : tds_free_connection(connection);
378 0 : odbc_errs_add(&dbc->errs, "IM007", "Could not find UID parameter");
379 0 : ODBC_RETURN(dbc, SQL_ERROR);
380 : }
381 :
382 8 : if (odbc_connect(dbc, connection) != SQL_SUCCESS) {
383 2 : tds_free_connection(connection);
384 2 : ODBC_RETURN_(dbc);
385 : }
386 :
387 6 : tds_free_connection(connection);
388 6 : ODBC_RETURN_(dbc);
389 : }
390 :
391 : #if 0
392 : SQLRETURN SQL_API
393 : SQLBrowseConnect(SQLHDBC hdbc, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,
394 : SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut)
395 : {
396 : INIT_HDBC;
397 : odbc_errs_add(&dbc->errs, "HYC00", "SQLBrowseConnect: function not implemented");
398 : ODBC_RETURN(dbc, SQL_ERROR);
399 : }
400 : #endif
401 :
402 : SQLRETURN SQL_API
403 : SQLColumnPrivileges(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR FAR * szSchemaName,
404 : SQLSMALLINT cbSchemaName, SQLCHAR FAR * szTableName, SQLSMALLINT cbTableName, SQLCHAR FAR * szColumnName,
405 : SQLSMALLINT cbColumnName)
406 0 : {
407 : int retcode;
408 :
409 0 : INIT_HSTMT;
410 :
411 0 : retcode =
412 : odbc_stat_execute(stmt, "sp_column_privileges ", 4, "O@table_qualifier", szCatalogName, cbCatalogName,
413 : "O@table_owner", szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName,
414 : "P@column_name", szColumnName, cbColumnName);
415 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
416 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
417 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
418 : }
419 0 : ODBC_RETURN_(stmt);
420 : }
421 :
422 : #if 0
423 : SQLRETURN SQL_API
424 : SQLDescribeParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR * pfSqlType, SQLUINTEGER FAR * pcbParamDef,
425 : SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable)
426 : {
427 : INIT_HSTMT;
428 : odbc_errs_add(&stmt->errs, "HYC00", "SQLDescribeParam: function not implemented");
429 : ODBC_RETURN(stmt, SQL_ERROR);
430 : }
431 : #endif
432 :
433 : SQLRETURN SQL_API
434 : SQLExtendedFetch(SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLLEN irow, SQLULEN FAR * pcrow, SQLUSMALLINT FAR * rgfRowStatus)
435 0 : {
436 : SQLRETURN ret;
437 : SQLULEN * tmp_rows;
438 : SQLUSMALLINT * tmp_status;
439 : SQLULEN tmp_size;
440 : SQLLEN * tmp_offset;
441 :
442 0 : INIT_HSTMT;
443 :
444 : /* still we do not support cursors and scrolling */
445 : /* TODO cursors */
446 0 : if (fFetchType != SQL_FETCH_NEXT) {
447 0 : odbc_errs_add(&stmt->errs, "HY106", NULL);
448 0 : ODBC_RETURN(stmt, SQL_ERROR);
449 : }
450 :
451 : /* save and change IRD/ARD state */
452 0 : tmp_rows = stmt->ird->header.sql_desc_rows_processed_ptr;
453 0 : stmt->ird->header.sql_desc_rows_processed_ptr = pcrow;
454 0 : tmp_status = stmt->ird->header.sql_desc_array_status_ptr;
455 0 : stmt->ird->header.sql_desc_array_status_ptr = rgfRowStatus;
456 0 : tmp_size = stmt->ard->header.sql_desc_array_size;
457 0 : stmt->ard->header.sql_desc_array_size = stmt->sql_rowset_size;
458 0 : tmp_offset = stmt->ard->header.sql_desc_bind_offset_ptr;
459 0 : stmt->ard->header.sql_desc_bind_offset_ptr = NULL;
460 :
461 : /* TODO errors are sligthly different ... perhaps it's better to leave DM do this job ?? */
462 0 : ret = _SQLFetch(stmt);
463 :
464 : /* restore IRD/ARD */
465 0 : stmt->ird->header.sql_desc_rows_processed_ptr = tmp_rows;
466 0 : stmt->ird->header.sql_desc_array_status_ptr = tmp_status;
467 0 : stmt->ard->header.sql_desc_array_size = tmp_size;
468 0 : stmt->ard->header.sql_desc_bind_offset_ptr = tmp_offset;
469 :
470 0 : ODBC_RETURN(stmt, ret);
471 : }
472 :
473 : SQLRETURN SQL_API
474 : SQLForeignKeys(SQLHSTMT hstmt, SQLCHAR FAR * szPkCatalogName, SQLSMALLINT cbPkCatalogName, SQLCHAR FAR * szPkSchemaName,
475 : SQLSMALLINT cbPkSchemaName, SQLCHAR FAR * szPkTableName, SQLSMALLINT cbPkTableName, SQLCHAR FAR * szFkCatalogName,
476 : SQLSMALLINT cbFkCatalogName, SQLCHAR FAR * szFkSchemaName, SQLSMALLINT cbFkSchemaName, SQLCHAR FAR * szFkTableName,
477 : SQLSMALLINT cbFkTableName)
478 0 : {
479 : int retcode;
480 :
481 0 : INIT_HSTMT;
482 :
483 0 : retcode =
484 : odbc_stat_execute(stmt, "sp_fkeys ", 6, "O@pktable_qualifier", szPkCatalogName, cbPkCatalogName, "O@pktable_owner",
485 : szPkSchemaName, cbPkSchemaName, "O@pktable_name", szPkTableName, cbPkTableName,
486 : "O@fktable_qualifier", szFkCatalogName, cbFkCatalogName, "O@fktable_owner", szFkSchemaName,
487 : cbFkSchemaName, "O@fktable_name", szFkTableName, cbFkTableName);
488 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
489 0 : odbc_col_setname(stmt, 1, "PKTABLE_CAT");
490 0 : odbc_col_setname(stmt, 2, "PKTABLE_SCHEM");
491 0 : odbc_col_setname(stmt, 5, "FKTABLE_CAT");
492 0 : odbc_col_setname(stmt, 6, "FKTABLE_SCHEM");
493 : }
494 0 : ODBC_RETURN_(stmt);
495 : }
496 :
497 : SQLRETURN SQL_API
498 : SQLMoreResults(SQLHSTMT hstmt)
499 348 : {
500 : TDSSOCKET *tds;
501 : TDS_INT result_type;
502 : int tdsret;
503 348 : int in_row = 0;
504 : SQLUSMALLINT param_status;
505 : int token_flags;
506 :
507 348 : INIT_HSTMT;
508 :
509 348 : tds = stmt->dbc->tds_socket;
510 :
511 : /* we already readed all results... */
512 : /* TODO cursor */
513 348 : if (stmt->dbc->current_statement != stmt)
514 57 : ODBC_RETURN(stmt, SQL_NO_DATA);
515 :
516 291 : stmt->row_count = TDS_NO_COUNT;
517 291 : stmt->special_row = 0;
518 :
519 : /* TODO this code is TOO similar to _SQLExecute, merge it - freddy77 */
520 : /* try to go to the next recordset */
521 291 : if (stmt->row_status == IN_COMPUTE_ROW) {
522 : /* FIXME doesn't seem so fine ... - freddy77 */
523 4 : tds_process_tokens(stmt->dbc->tds_socket, &result_type, NULL, TDS_TOKEN_TRAILING);
524 4 : stmt->row_status = IN_COMPUTE_ROW;
525 4 : in_row = 1;
526 : }
527 :
528 291 : param_status = SQL_PARAM_SUCCESS;
529 291 : token_flags = (TDS_TOKEN_RESULTS & (~TDS_STOPAT_COMPUTE)) | TDS_RETURN_COMPUTE;
530 291 : if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
531 132 : token_flags |= TDS_RETURN_MSG;
532 : for (;;) {
533 357 : result_type = odbc_process_tokens(stmt, token_flags);
534 357 : switch (result_type) {
535 : case TDS_CMD_DONE:
536 207 : if (stmt->dbc->current_statement == stmt)
537 207 : stmt->dbc->current_statement = NULL;
538 : #if 1 /* !UNIXODBC */
539 207 : tds_free_all_results(tds);
540 : #endif
541 207 : odbc_populate_ird(stmt);
542 207 : if (stmt->row_count == TDS_NO_COUNT && !in_row) {
543 205 : stmt->row_status = NOT_IN_ROW;
544 205 : if (stmt->next_row_count != TDS_NO_COUNT) {
545 24 : stmt->row_count = stmt->next_row_count;
546 24 : stmt->row_status = PRE_NORMAL_ROW;
547 : }
548 : }
549 207 : stmt->next_row_count = TDS_NO_COUNT;
550 207 : if (stmt->row_count == TDS_NO_COUNT && (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO))
551 183 : ODBC_RETURN(stmt, SQL_NO_DATA);
552 24 : ODBC_RETURN_(stmt);
553 :
554 : case TDS_CMD_FAIL:
555 0 : ODBC_RETURN(stmt, SQL_ERROR);
556 :
557 : case TDS_COMPUTE_RESULT:
558 12 : switch (stmt->row_status) {
559 : /* skip this recordset */
560 : case IN_COMPUTE_ROW:
561 : /* TODO here we should set current_results to normal results */
562 0 : in_row = 1;
563 : /* fall throgh */
564 : /* in normal row, put in compute status */
565 : case AFTER_COMPUTE_ROW:
566 : case IN_NORMAL_ROW:
567 : case PRE_NORMAL_ROW:
568 12 : stmt->row_status = IN_COMPUTE_ROW;
569 12 : odbc_populate_ird(stmt);
570 12 : ODBC_RETURN_(stmt);
571 : case NOT_IN_ROW:
572 : /* this should never happen, protocol error */
573 0 : ODBC_RETURN(stmt, SQL_ERROR);
574 : break;
575 : }
576 0 : break;
577 :
578 : case TDS_ROW_RESULT:
579 33 : if (in_row || (stmt->row_status != IN_NORMAL_ROW && stmt->row_status != PRE_NORMAL_ROW)) {
580 23 : stmt->row_status = PRE_NORMAL_ROW;
581 23 : odbc_populate_ird(stmt);
582 23 : ODBC_RETURN_(stmt);
583 : }
584 : /* Skipping current result set's rows to access next resultset or proc's retval */
585 10 : tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_STOPAT_COMPUTE);
586 : /* TODO should we set in_row ?? */
587 10 : if (tdsret == TDS_FAIL || tdsret == TDS_CANCELLED)
588 0 : ODBC_RETURN(stmt, SQL_ERROR);
589 10 : break;
590 :
591 : case TDS_DONE_RESULT:
592 : case TDS_DONEPROC_RESULT:
593 : /* FIXME here ??? */
594 48 : if (!in_row)
595 34 : tds_free_all_results(tds);
596 48 : switch (stmt->errs.lastrc) {
597 : case SQL_ERROR:
598 10 : param_status = SQL_PARAM_ERROR;
599 10 : break;
600 : case SQL_SUCCESS_WITH_INFO:
601 2 : param_status = SQL_PARAM_SUCCESS_WITH_INFO;
602 : break;
603 : }
604 48 : if (stmt->curr_param_row < stmt->num_param_rows) {
605 8 : if (stmt->ipd->header.sql_desc_array_status_ptr)
606 8 : stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
607 8 : ++stmt->curr_param_row;
608 8 : if (stmt->ipd->header.sql_desc_rows_processed_ptr)
609 8 : *stmt->ipd->header.sql_desc_rows_processed_ptr = stmt->curr_param_row;
610 : }
611 48 : if (stmt->curr_param_row < stmt->num_param_rows) {
612 : #if 0
613 : if (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
614 : found_info = 1;
615 : if (stmt->errs.lastrc == SQL_ERROR)
616 : found_error = 1;
617 : #endif
618 7 : stmt->errs.lastrc = SQL_SUCCESS;
619 7 : param_status = SQL_PARAM_SUCCESS;
620 7 : break;
621 : }
622 41 : odbc_populate_ird(stmt);
623 41 : ODBC_RETURN_(stmt);
624 : break;
625 :
626 : /*
627 : * TODO test flags ? check error and change result ?
628 : * see also other DONEINPROC handle (below)
629 : */
630 : case TDS_DONEINPROC_RESULT:
631 6 : if (in_row) {
632 6 : odbc_populate_ird(stmt);
633 6 : ODBC_RETURN_(stmt);
634 : }
635 : /* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
636 0 : tds_free_all_results(tds);
637 0 : odbc_populate_ird(stmt);
638 0 : break;
639 :
640 : /* do not stop at metadata, an error can follow... */
641 : case TDS_ROWFMT_RESULT:
642 29 : if (in_row) {
643 2 : odbc_populate_ird(stmt);
644 2 : ODBC_RETURN_(stmt);
645 : }
646 27 : stmt->row = 0;
647 27 : stmt->row_count = TDS_NO_COUNT;
648 27 : stmt->next_row_count = TDS_NO_COUNT;
649 : /* we expect a row */
650 27 : stmt->row_status = PRE_NORMAL_ROW;
651 27 : in_row = 1;
652 27 : break;
653 :
654 : case TDS_MSG_RESULT:
655 22 : if (!in_row) {
656 12 : tds_free_all_results(tds);
657 12 : odbc_populate_ird(stmt);
658 : }
659 22 : in_row = 1;
660 : break;
661 : }
662 66 : }
663 : ODBC_RETURN(stmt, SQL_ERROR);
664 : }
665 :
666 : SQLRETURN SQL_API
667 : SQLNativeSql(SQLHDBC hdbc, SQLCHAR FAR * szSqlStrIn, SQLINTEGER cbSqlStrIn, SQLCHAR FAR * szSqlStr, SQLINTEGER cbSqlStrMax,
668 : SQLINTEGER FAR * pcbSqlStr)
669 0 : {
670 0 : SQLRETURN ret = SQL_SUCCESS;
671 : DSTR query;
672 :
673 0 : INIT_HDBC;
674 :
675 0 : tds_dstr_init(&query);
676 :
677 : #ifdef TDS_NO_DM
678 0 : if (!szSqlStrIn || !IS_VALID_LEN(cbSqlStrIn)) {
679 0 : odbc_errs_add(&dbc->errs, "HY009", NULL);
680 0 : ODBC_RETURN(dbc, SQL_ERROR);
681 : }
682 : #endif
683 :
684 0 : if (!tds_dstr_copyn(&query, (const char *) szSqlStrIn, odbc_get_string_size(cbSqlStrIn, szSqlStrIn))) {
685 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
686 0 : ODBC_RETURN(dbc, SQL_ERROR);
687 : }
688 :
689 : /* TODO support not null terminated in native_sql */
690 0 : native_sql(dbc, tds_dstr_cstr(&query));
691 :
692 0 : ret = odbc_set_string_i(szSqlStr, cbSqlStrMax, pcbSqlStr, tds_dstr_cstr(&query), -1);
693 :
694 0 : tds_dstr_free(&query);
695 :
696 0 : ODBC_RETURN(dbc, ret);
697 : }
698 :
699 : SQLRETURN SQL_API
700 : SQLNumParams(SQLHSTMT hstmt, SQLSMALLINT FAR * pcpar)
701 0 : {
702 0 : INIT_HSTMT;
703 0 : *pcpar = stmt->param_count;
704 0 : ODBC_RETURN_(stmt);
705 : }
706 :
707 : SQLRETURN SQL_API
708 : SQLParamOptions(SQLHSTMT hstmt, SQLULEN crow, SQLULEN FAR * pirow)
709 0 : {
710 : SQLRETURN res;
711 :
712 : /* emulate for ODBC 2 DM */
713 0 : res = _SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, pirow, 0);
714 0 : if (res != SQL_SUCCESS)
715 0 : return res;
716 : /* crow is converted back to SQLINTEGER in _SQLSetStmtAttr so the TDS_INTPTR cast is safe */
717 0 : return _SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crow, 0);
718 : }
719 :
720 : SQLRETURN SQL_API
721 : SQLPrimaryKeys(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR FAR * szSchemaName,
722 : SQLSMALLINT cbSchemaName, SQLCHAR FAR * szTableName, SQLSMALLINT cbTableName)
723 0 : {
724 : int retcode;
725 :
726 0 : INIT_HSTMT;
727 :
728 0 : retcode =
729 : odbc_stat_execute(stmt, "sp_pkeys ", 3, "O@table_qualifier", szCatalogName, cbCatalogName, "O@table_owner",
730 : szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName);
731 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
732 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
733 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
734 : }
735 0 : ODBC_RETURN_(stmt);
736 : }
737 :
738 : SQLRETURN SQL_API
739 : SQLProcedureColumns(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR FAR * szSchemaName,
740 : SQLSMALLINT cbSchemaName, SQLCHAR FAR * szProcName, SQLSMALLINT cbProcName, SQLCHAR FAR * szColumnName,
741 : SQLSMALLINT cbColumnName)
742 0 : {
743 : int retcode;
744 :
745 0 : INIT_HSTMT;
746 :
747 0 : retcode =
748 : odbc_stat_execute(stmt, "sp_sproc_columns ", 4, "O@procedure_qualifier", szCatalogName, cbCatalogName,
749 : "P@procedure_owner", szSchemaName, cbSchemaName, "P@procedure_name", szProcName, cbProcName,
750 : "P@column_name", szColumnName, cbColumnName);
751 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
752 0 : odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
753 0 : odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
754 0 : odbc_col_setname(stmt, 8, "COLUMN_SIZE");
755 0 : odbc_col_setname(stmt, 9, "BUFFER_LENGTH");
756 0 : odbc_col_setname(stmt, 10, "DECIMAL_DIGITS");
757 0 : odbc_col_setname(stmt, 11, "NUM_PREC_RADIX");
758 : }
759 0 : ODBC_RETURN_(stmt);
760 : }
761 :
762 : SQLRETURN SQL_API
763 : SQLProcedures(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR FAR * szSchemaName,
764 : SQLSMALLINT cbSchemaName, SQLCHAR FAR * szProcName, SQLSMALLINT cbProcName)
765 0 : {
766 : int retcode;
767 :
768 0 : INIT_HSTMT;
769 :
770 0 : retcode =
771 : odbc_stat_execute(stmt, "..sp_stored_procedures ", 3, "P@sp_name", szProcName, cbProcName, "P@sp_owner", szSchemaName,
772 : cbSchemaName, "O@sp_qualifier", szCatalogName, cbCatalogName);
773 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
774 0 : odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
775 0 : odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
776 : }
777 0 : ODBC_RETURN_(stmt);
778 : }
779 :
780 : #if 0
781 : SQLRETURN SQL_API
782 : SQLSetPos(SQLHSTMT hstmt, SQLUSMALLINT irow, SQLUSMALLINT fOption, SQLUSMALLINT fLock)
783 : {
784 : INIT_HSTMT;
785 : /* TODO cursors */
786 : odbc_errs_add(&stmt->errs, "HYC00", "SQLSetPos: function not implemented");
787 : ODBC_RETURN(stmt, SQL_ERROR);
788 : }
789 : #endif
790 :
791 : SQLRETURN SQL_API
792 : SQLTablePrivileges(SQLHSTMT hstmt, SQLCHAR FAR * szCatalogName, SQLSMALLINT cbCatalogName, SQLCHAR FAR * szSchemaName,
793 : SQLSMALLINT cbSchemaName, SQLCHAR FAR * szTableName, SQLSMALLINT cbTableName)
794 0 : {
795 : int retcode;
796 :
797 0 : INIT_HSTMT;
798 :
799 0 : retcode =
800 : odbc_stat_execute(stmt, "sp_table_privileges ", 3, "O@table_qualifier", szCatalogName, cbCatalogName,
801 : "P@table_owner", szSchemaName, cbSchemaName, "P@table_name", szTableName, cbTableName);
802 0 : if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
803 0 : odbc_col_setname(stmt, 1, "TABLE_CAT");
804 0 : odbc_col_setname(stmt, 2, "TABLE_SCHEM");
805 : }
806 0 : ODBC_RETURN_(stmt);
807 : }
808 :
809 : #if (ODBCVER >= 0x0300)
810 : SQLRETURN SQL_API
811 : SQLSetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength)
812 25 : {
813 25 : SQLINTEGER i_val = (SQLINTEGER) (TDS_INTPTR) Value;
814 :
815 25 : INIT_HENV;
816 :
817 25 : switch (Attribute) {
818 : case SQL_ATTR_CONNECTION_POOLING:
819 : case SQL_ATTR_CP_MATCH:
820 0 : odbc_errs_add(&env->errs, "HYC00", NULL);
821 0 : ODBC_RETURN(env, SQL_ERROR);
822 : break;
823 : case SQL_ATTR_ODBC_VERSION:
824 25 : switch (i_val) {
825 : case SQL_OV_ODBC3:
826 : case SQL_OV_ODBC2:
827 : break;
828 : default:
829 0 : odbc_errs_add(&env->errs, "HY024", NULL);
830 0 : ODBC_RETURN(env, SQL_ERROR);
831 : }
832 25 : env->attr.odbc_version = i_val;
833 25 : ODBC_RETURN_(env);
834 : break;
835 : case SQL_ATTR_OUTPUT_NTS:
836 0 : env->attr.output_nts = i_val;
837 : /* TODO - Make this really work */
838 0 : env->attr.output_nts = SQL_TRUE;
839 0 : ODBC_RETURN_(env);
840 : break;
841 : }
842 0 : odbc_errs_add(&env->errs, "HY092", NULL);
843 0 : ODBC_RETURN(env, SQL_ERROR);
844 : }
845 :
846 : SQLRETURN SQL_API
847 : SQLGetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
848 0 : {
849 : size_t size;
850 : void *src;
851 :
852 0 : INIT_HENV;
853 :
854 0 : switch (Attribute) {
855 : case SQL_ATTR_CONNECTION_POOLING:
856 0 : src = &env->attr.connection_pooling;
857 0 : size = sizeof(env->attr.connection_pooling);
858 0 : break;
859 : case SQL_ATTR_CP_MATCH:
860 0 : src = &env->attr.cp_match;
861 0 : size = sizeof(env->attr.cp_match);
862 0 : break;
863 : case SQL_ATTR_ODBC_VERSION:
864 0 : src = &env->attr.odbc_version;
865 0 : size = sizeof(env->attr.odbc_version);
866 0 : break;
867 : case SQL_ATTR_OUTPUT_NTS:
868 : /* TODO handle output_nts flags */
869 0 : env->attr.output_nts = SQL_TRUE;
870 0 : src = &env->attr.output_nts;
871 0 : size = sizeof(env->attr.output_nts);
872 0 : break;
873 : default:
874 0 : odbc_errs_add(&env->errs, "HY092", NULL);
875 0 : ODBC_RETURN(env, SQL_ERROR);
876 : break;
877 : }
878 :
879 0 : if (StringLength) {
880 0 : *StringLength = size;
881 : }
882 0 : memcpy(Value, src, size);
883 :
884 0 : ODBC_RETURN_(env);
885 : }
886 :
887 : #endif
888 :
889 : static SQLRETURN
890 : _SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
891 : SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
892 257 : {
893 : TDS_DESC *apd, *ipd;
894 : struct _drecord *drec;
895 : SQLSMALLINT orig_apd_size, orig_ipd_size;
896 257 : int is_numeric = 0;
897 :
898 257 : INIT_HSTMT;
899 :
900 : #ifdef TDS_NO_DM
901 : /* TODO - more error checking ... XXX smurph */
902 :
903 : /* Check param type */
904 257 : switch (fParamType) {
905 : case SQL_PARAM_INPUT:
906 : case SQL_PARAM_INPUT_OUTPUT:
907 : case SQL_PARAM_OUTPUT:
908 : break;
909 : default:
910 0 : odbc_errs_add(&stmt->errs, "HY105", NULL);
911 0 : ODBC_RETURN(stmt, SQL_ERROR);
912 : }
913 :
914 : /* Check max buffer length */
915 257 : if (cbValueMax < 0) {
916 0 : odbc_errs_add(&stmt->errs, "HY090", NULL);
917 0 : ODBC_RETURN(stmt, SQL_ERROR);
918 : }
919 : #endif
920 :
921 : /* check cbColDef and ibScale */
922 257 : if (fSqlType == SQL_DECIMAL || fSqlType == SQL_NUMERIC) {
923 8 : is_numeric = 1;
924 8 : if (cbColDef < 1 || cbColDef > 38) {
925 0 : odbc_errs_add(&stmt->errs, "HY104", "Invalid precision value");
926 0 : ODBC_RETURN(stmt, SQL_ERROR);
927 : }
928 8 : if (ibScale < 0 || ibScale > cbColDef) {
929 0 : odbc_errs_add(&stmt->errs, "HY104", "Invalid scale value");
930 0 : ODBC_RETURN(stmt, SQL_ERROR);
931 : }
932 : }
933 :
934 : /* Check parameter number */
935 257 : if (ipar <= 0 || ipar > 4000) {
936 0 : odbc_errs_add(&stmt->errs, "07009", NULL);
937 0 : ODBC_RETURN(stmt, SQL_ERROR);
938 : }
939 :
940 : /* fill APD related fields */
941 257 : apd = stmt->apd;
942 257 : orig_apd_size = apd->header.sql_desc_count;
943 257 : if (ipar > apd->header.sql_desc_count && desc_alloc_records(apd, ipar) != SQL_SUCCESS) {
944 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
945 0 : ODBC_RETURN(stmt, SQL_ERROR);
946 : }
947 257 : drec = &apd->records[ipar - 1];
948 :
949 257 : if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
950 14 : desc_alloc_records(apd, orig_apd_size);
951 14 : odbc_errs_add(&stmt->errs, "HY004", NULL);
952 14 : ODBC_RETURN(stmt, SQL_ERROR);
953 : }
954 :
955 243 : stmt->need_reprepare = 1;
956 :
957 : /* TODO other types ?? handle SQL_C_DEFAULT */
958 243 : if (drec->sql_desc_type == SQL_C_CHAR || drec->sql_desc_type == SQL_C_BINARY)
959 68 : drec->sql_desc_octet_length = cbValueMax;
960 243 : drec->sql_desc_indicator_ptr = pcbValue;
961 243 : drec->sql_desc_octet_length_ptr = pcbValue;
962 243 : drec->sql_desc_data_ptr = (char *) rgbValue;
963 :
964 : /* field IPD related fields */
965 243 : ipd = stmt->ipd;
966 243 : orig_ipd_size = ipd->header.sql_desc_count;
967 243 : if (ipar > ipd->header.sql_desc_count && desc_alloc_records(ipd, ipar) != SQL_SUCCESS) {
968 0 : desc_alloc_records(apd, orig_apd_size);
969 0 : odbc_errs_add(&stmt->errs, "HY001", NULL);
970 0 : ODBC_RETURN(stmt, SQL_ERROR);
971 : }
972 243 : drec = &ipd->records[ipar - 1];
973 :
974 243 : drec->sql_desc_parameter_type = fParamType;
975 243 : if (odbc_set_concise_sql_type(fSqlType, drec, 0) != SQL_SUCCESS) {
976 0 : desc_alloc_records(ipd, orig_ipd_size);
977 0 : desc_alloc_records(apd, orig_apd_size);
978 0 : odbc_errs_add(&stmt->errs, "HY004", NULL);
979 0 : ODBC_RETURN(stmt, SQL_ERROR);
980 : }
981 243 : if (is_numeric) {
982 8 : drec->sql_desc_precision = cbColDef;
983 8 : drec->sql_desc_scale = ibScale;
984 : } else {
985 235 : drec->sql_desc_length = cbColDef;
986 : }
987 :
988 243 : ODBC_RETURN_(stmt);
989 : }
990 :
991 : SQLRETURN SQL_API
992 : SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
993 : SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
994 257 : {
995 257 : return _SQLBindParameter(hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue);
996 : }
997 :
998 : /* compatibility with X/Open */
999 : SQLRETURN SQL_API
1000 : SQLBindParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale,
1001 : SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
1002 0 : {
1003 0 : return _SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT, fCType, fSqlType, cbColDef, ibScale, rgbValue, 0, pcbValue);
1004 : }
1005 :
1006 : #if (ODBCVER >= 0x0300)
1007 : SQLRETURN SQL_API
1008 : SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
1009 11 : {
1010 11 : switch (HandleType) {
1011 : case SQL_HANDLE_STMT:
1012 11 : return _SQLAllocStmt(InputHandle, OutputHandle);
1013 : break;
1014 : case SQL_HANDLE_DBC:
1015 0 : return _SQLAllocConnect(InputHandle, OutputHandle);
1016 : break;
1017 : case SQL_HANDLE_ENV:
1018 0 : return _SQLAllocEnv(OutputHandle);
1019 : break;
1020 : case SQL_HANDLE_DESC:
1021 0 : return _SQLAllocDesc(InputHandle, OutputHandle);
1022 : break;
1023 : }
1024 0 : return SQL_ERROR;
1025 : }
1026 : #endif
1027 :
1028 : static SQLRETURN SQL_API
1029 : _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1030 96 : {
1031 : TDS_DBC *dbc;
1032 :
1033 96 : INIT_HENV;
1034 :
1035 96 : dbc = (TDS_DBC *) malloc(sizeof(TDS_DBC));
1036 96 : if (!dbc) {
1037 0 : odbc_errs_add(&env->errs, "HY001", NULL);
1038 0 : ODBC_RETURN(env, SQL_ERROR);
1039 : }
1040 :
1041 96 : memset(dbc, '\0', sizeof(TDS_DBC));
1042 :
1043 96 : dbc->htype = SQL_HANDLE_DBC;
1044 96 : dbc->env = env;
1045 96 : tds_dstr_init(&dbc->server);
1046 96 : tds_dstr_init(&dbc->dsn);
1047 :
1048 96 : dbc->attr.access_mode = SQL_MODE_READ_WRITE;
1049 96 : dbc->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1050 96 : dbc->attr.auto_ipd = SQL_FALSE;
1051 : /*
1052 : * spinellia@acm.org
1053 : * after login is enabled autocommit
1054 : */
1055 96 : dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
1056 96 : dbc->attr.connection_dead = SQL_CD_TRUE; /* No connection yet */
1057 96 : dbc->attr.connection_timeout = 0;
1058 : /* This is set in the environment change function */
1059 96 : tds_dstr_init(&dbc->attr.current_catalog);
1060 96 : dbc->attr.login_timeout = 0; /* TODO */
1061 96 : dbc->attr.metadata_id = SQL_FALSE;
1062 96 : dbc->attr.odbc_cursors = SQL_CUR_USE_IF_NEEDED;
1063 96 : dbc->attr.packet_size = 0;
1064 96 : dbc->attr.quite_mode = NULL; /* We don't support GUI dialogs yet */
1065 : #ifdef TDS_NO_DM
1066 96 : dbc->attr.trace = SQL_OPT_TRACE_OFF;
1067 96 : tds_dstr_init(&dbc->attr.tracefile);
1068 : #endif
1069 96 : tds_dstr_init(&dbc->attr.translate_lib);
1070 96 : dbc->attr.translate_option = 0;
1071 96 : dbc->attr.txn_isolation = SQL_TXN_READ_COMMITTED;
1072 :
1073 96 : *phdbc = (SQLHDBC) dbc;
1074 :
1075 96 : ODBC_RETURN_(env);
1076 : }
1077 :
1078 : SQLRETURN SQL_API
1079 : SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1080 96 : {
1081 96 : odbc_errs_reset(&((TDS_ENV *) henv)->errs);
1082 96 : return _SQLAllocConnect(henv, phdbc);
1083 : }
1084 :
1085 : static SQLRETURN SQL_API
1086 : _SQLAllocEnv(SQLHENV FAR * phenv)
1087 96 : {
1088 : TDS_ENV *env;
1089 : TDSCONTEXT *ctx;
1090 :
1091 96 : env = (TDS_ENV *) malloc(sizeof(TDS_ENV));
1092 96 : if (!env)
1093 0 : return SQL_ERROR;
1094 :
1095 96 : memset(env, '\0', sizeof(TDS_ENV));
1096 :
1097 96 : env->htype = SQL_HANDLE_ENV;
1098 96 : env->attr.odbc_version = SQL_OV_ODBC2;
1099 : /* TODO use it */
1100 96 : env->attr.output_nts = SQL_TRUE;
1101 :
1102 96 : ctx = tds_alloc_context(env);
1103 96 : if (!ctx) {
1104 0 : free(env);
1105 0 : return SQL_ERROR;
1106 : }
1107 96 : env->tds_ctx = ctx;
1108 96 : ctx->msg_handler = odbc_errmsg_handler;
1109 96 : ctx->err_handler = odbc_errmsg_handler;
1110 :
1111 : /* ODBC has its own format */
1112 96 : if (ctx->locale->date_fmt)
1113 96 : free(ctx->locale->date_fmt);
1114 96 : ctx->locale->date_fmt = strdup("%Y-%m-%d %H:%M:%S.%z");
1115 :
1116 96 : *phenv = (SQLHENV) env;
1117 :
1118 96 : return SQL_SUCCESS;
1119 : }
1120 :
1121 : SQLRETURN SQL_API
1122 : SQLAllocEnv(SQLHENV FAR * phenv)
1123 96 : {
1124 96 : return _SQLAllocEnv(phenv);
1125 : }
1126 :
1127 : static SQLRETURN SQL_API
1128 : _SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc)
1129 0 : {
1130 : int i;
1131 :
1132 0 : INIT_HDBC;
1133 :
1134 0 : for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
1135 0 : if (dbc->uad[i] == NULL) {
1136 0 : TDS_DESC *desc = desc_alloc(dbc, DESC_ARD, SQL_DESC_ALLOC_USER);
1137 0 : if (desc == NULL) {
1138 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1139 0 : ODBC_RETURN(dbc, SQL_ERROR);
1140 : }
1141 0 : dbc->uad[i] = desc;
1142 0 : *phdesc = (SQLHDESC) desc;
1143 0 : ODBC_RETURN_(dbc);
1144 : }
1145 : }
1146 :
1147 0 : odbc_errs_add(&dbc->errs, "HY014", NULL);
1148 0 : ODBC_RETURN(dbc, SQL_ERROR);
1149 : }
1150 :
1151 : static SQLRETURN SQL_API
1152 : _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
1153 129 : {
1154 : TDS_STMT *stmt;
1155 : char *pstr;
1156 :
1157 129 : INIT_HDBC;
1158 :
1159 129 : stmt = (TDS_STMT *) malloc(sizeof(TDS_STMT));
1160 129 : if (!stmt) {
1161 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1162 0 : ODBC_RETURN(dbc, SQL_ERROR);
1163 : }
1164 129 : memset(stmt, '\0', sizeof(TDS_STMT));
1165 129 : tds_dstr_init(&stmt->cursor_name);
1166 :
1167 129 : stmt->htype = SQL_HANDLE_STMT;
1168 129 : stmt->dbc = dbc;
1169 129 : pstr = NULL;
1170 129 : if (asprintf(&pstr, "C%lx", (unsigned long) stmt) < 0 || !tds_dstr_set(&stmt->cursor_name, pstr)) {
1171 0 : free(stmt);
1172 0 : if (pstr != NULL)
1173 0 : free(pstr);
1174 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1175 0 : ODBC_RETURN(dbc, SQL_ERROR);
1176 : }
1177 : /* do not free pstr tds_dstr_set do it if necessary */
1178 :
1179 : /* allocate descriptors */
1180 129 : stmt->ird = desc_alloc(stmt, DESC_IRD, SQL_DESC_ALLOC_AUTO);
1181 129 : stmt->ard = desc_alloc(stmt, DESC_ARD, SQL_DESC_ALLOC_AUTO);
1182 129 : stmt->ipd = desc_alloc(stmt, DESC_IPD, SQL_DESC_ALLOC_AUTO);
1183 129 : stmt->apd = desc_alloc(stmt, DESC_APD, SQL_DESC_ALLOC_AUTO);
1184 129 : if (!stmt->ird || !stmt->ard || !stmt->ipd || !stmt->apd) {
1185 0 : tds_dstr_free(&stmt->cursor_name);
1186 0 : desc_free(stmt->ird);
1187 0 : desc_free(stmt->ard);
1188 0 : desc_free(stmt->ipd);
1189 0 : desc_free(stmt->apd);
1190 0 : free(stmt);
1191 0 : odbc_errs_add(&dbc->errs, "HY001", NULL);
1192 0 : ODBC_RETURN(dbc, SQL_ERROR);
1193 : }
1194 :
1195 : /* save original ARD and APD */
1196 129 : stmt->orig_apd = stmt->apd;
1197 |