1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001  Brian Bruns
3  * Copyright (C) 2002-2012  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 #include <config.h>
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 
26 #if HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif /* HAVE_STDLIB_H */
29 
30 #if HAVE_STRING_H
31 #include <string.h>
32 #endif /* HAVE_STRING_H */
33 
34 #include <assert.h>
35 #include <ctype.h>
36 
37 #include <freetds/odbc.h>
38 #include <freetds/iconv.h>
39 #include <freetds/string.h>
40 #include <freetds/convert.h>
41 #include "replacements.h"
42 #include "sqlwparams.h"
43 
44 /* Include odbcss.h with all bcp functions */
45 /* The define trick is to make inline functions calls internal
46  * _SQLSetConnectAttr instead of SQLSetConnectAttr */
47 ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE));
48 #define TDSODBC_BCP
49 #undef SQLSetConnectAttr
50 #define SQLSetConnectAttr(h, n, p, t) _SQLSetConnectAttr(h, n, p, t _wide0)
51 #include <odbcss.h>
52 #undef SQLSetConnectAttr
53 
54 static SQLRETURN _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc);
55 static SQLRETURN _SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version);
56 static SQLRETURN _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt);
57 static SQLRETURN _SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc);
58 static SQLRETURN _SQLFreeConnect(SQLHDBC hdbc);
59 static SQLRETURN _SQLFreeEnv(SQLHENV henv);
60 static SQLRETURN _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force);
61 static SQLRETURN _SQLFreeDesc(SQLHDESC hdesc);
62 static SQLRETURN _SQLExecute(TDS_STMT * stmt);
63 static SQLRETURN _SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE);
64 static SQLRETURN _SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength,
65 					 SQLINTEGER * StringLength WIDE);
66 static SQLRETURN _SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc,
67 					  SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE);
68 static SQLRETURN _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset);
69 static SQLRETURN odbc_populate_ird(TDS_STMT * stmt);
70 static int odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg);
71 static void odbc_log_unimplemented_type(const char function_name[], int fType);
72 static void odbc_upper_column_names(TDS_STMT * stmt);
73 static void odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name);
74 static SQLRETURN odbc_stat_execute(TDS_STMT * stmt _WIDE, const char *begin, int nparams, ...);
75 static SQLRETURN odbc_free_dynamic(TDS_STMT * stmt);
76 static SQLRETURN odbc_free_cursor(TDS_STMT * stmt);
77 static SQLRETURN odbc_update_ird(TDS_STMT *stmt, TDS_ERRS *errs);
78 static SQLRETURN odbc_prepare(TDS_STMT *stmt);
79 static SQLSMALLINT odbc_swap_datetime_sql_type(SQLSMALLINT sql_type, int version);
80 static int odbc_process_tokens(TDS_STMT * stmt, unsigned flag);
81 static int odbc_lock_statement(TDS_STMT* stmt);
82 static void odbc_unlock_statement(TDS_STMT* stmt);
83 
84 #if ENABLE_EXTRA_CHECKS
85 static void odbc_ird_check(TDS_STMT * stmt);
86 
87 #define IRD_CHECK odbc_ird_check(stmt)
88 #else
89 #define IRD_CHECK
90 #endif
91 
92 /**
93  * \defgroup odbc_api ODBC API
94  * Functions callable by \c ODBC client programs
95  */
96 
97 
98 /* utils to check handles */
99 #define INIT_HANDLE(t, n) \
100 	TDS_##t *n = (TDS_##t*)h##n; \
101 	if (SQL_NULL_H##t  == h##n || !IS_H##t(h##n)) return SQL_INVALID_HANDLE; \
102 	tds_mutex_lock(&n->mtx); \
103 	CHECK_##t##_EXTRA(n); \
104 	odbc_errs_reset(&n->errs);
105 
106 #define ODBC_ENTER_HSTMT INIT_HANDLE(STMT, stmt)
107 #define ODBC_ENTER_HDBC  INIT_HANDLE(DBC,  dbc)
108 #define ODBC_ENTER_HENV  INIT_HANDLE(ENV,  env)
109 #define ODBC_ENTER_HDESC INIT_HANDLE(DESC, desc)
110 
111 #define IS_VALID_LEN(len) ((len) >= 0 || (len) == SQL_NTS || (len) == SQL_NULL_DATA)
112 
113 #define ODBC_SAFE_ERROR(stmt) \
114 	do { \
115 		if (!stmt->errs.num_errors) \
116 			odbc_errs_add(&stmt->errs, "HY000", "Unknown error"); \
117 	} while(0)
118 
119 #define DEFAULT_QUERY_TIMEOUT (~((SQLUINTEGER) 0))
120 
121 /*
122  * Note: I *HATE* hungarian notation, it has to be the most idiotic thing
123  * I've ever seen. So, you will note it is avoided other than in the function
124  * declarations. "Gee, let's make our code totally hard to read and they'll
125  * beg for GUI tools"
126  * Bah!
127  */
128 
129 static const char *
odbc_prret(SQLRETURN ret,char * unknown,size_t unknown_size)130 odbc_prret(SQLRETURN ret, char *unknown, size_t unknown_size)
131 {
132 	switch (ret) {
133 	case SQL_ERROR:			return "SQL_ERROR";
134 	case SQL_INVALID_HANDLE:	return "SQL_INVALID_HANDLE";
135 	case SQL_SUCCESS:		return "SQL_SUCCESS";
136 	case SQL_SUCCESS_WITH_INFO:	return "SQL_SUCCESS_WITH_INFO";
137 #if ODBCVER >= 0x0300
138 	case SQL_NO_DATA:		return "SQL_NO_DATA";
139 #endif
140 	case SQL_STILL_EXECUTING:	return "SQL_STILL_EXECUTING";
141 	case SQL_NEED_DATA:		return "SQL_NEED_DATA";
142 	}
143 
144 	snprintf(unknown, unknown_size, "unknown: %d", (int)ret);
145 
146 	return unknown;
147 }
148 #define ODBC_PRRET_BUF	char unknown_prret_buf[24]
149 #define odbc_prret(ret) odbc_prret(ret, unknown_prret_buf, sizeof(unknown_prret_buf))
150 
151 static void
odbc_col_setname(TDS_STMT * stmt,int colpos,const char * name)152 odbc_col_setname(TDS_STMT * stmt, int colpos, const char *name)
153 {
154 #if ENABLE_EXTRA_CHECKS
155 	TDSRESULTINFO *resinfo;
156 #endif
157 
158 	IRD_CHECK;
159 
160 #if ENABLE_EXTRA_CHECKS
161 	if (colpos > 0 && stmt->tds != NULL && (resinfo = stmt->tds->current_results) != NULL) {
162 		if (colpos <= resinfo->num_cols) {
163 			/* no overflow possible, name is always shorter */
164 			if (!tds_dstr_copy(&resinfo->columns[colpos - 1]->column_name, name))
165 				odbc_errs_add(&stmt->errs, "HY001", NULL);
166 			tds_dstr_empty(&resinfo->columns[colpos - 1]->table_column_name);
167 		}
168 	}
169 #endif
170 
171 	if (colpos > 0 && colpos <= stmt->ird->header.sql_desc_count) {
172 		--colpos;
173 		if (!tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_label, name)
174 		    || !tds_dstr_copy(&stmt->ird->records[colpos].sql_desc_name, name))
175 			odbc_errs_add(&stmt->errs, "HY001", NULL);
176 	}
177 }
178 
179 /* spinellia@acm.org : copied shamelessly from change_database */
180 static SQLRETURN
change_autocommit(TDS_DBC * dbc,int state)181 change_autocommit(TDS_DBC * dbc, int state)
182 {
183 	TDSSOCKET *tds = dbc->tds_socket;
184 	TDSRET ret;
185 
186 	if (dbc->attr.autocommit == state)
187 		return SQL_SUCCESS;
188 
189 	/*
190 	 * We may not be connected yet and dbc->tds_socket
191 	 * may not initialized.
192 	 */
193 	if (tds) {
194 		/* TODO better idle check, not thread safe */
195 		if (tds->state == TDS_IDLE)
196 			tds->query_timeout = dbc->default_query_timeout;
197 
198 		if (state == SQL_AUTOCOMMIT_ON)
199 			ret = tds_submit_rollback(tds, 0);
200 		else
201 			ret = tds_submit_begin_tran(tds);
202 
203 		if (TDS_FAILED(ret)) {
204 			odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
205 			return SQL_ERROR;
206 		}
207 		if (TDS_FAILED(tds_process_simple_query(tds))) {
208 			odbc_errs_add(&dbc->errs, "HY000", "Could not change transaction status");
209 			return SQL_ERROR;
210 		}
211 		dbc->attr.autocommit = state;
212 	} else {
213 		/* if not connected we will change auto-commit after login */
214 		dbc->attr.autocommit = state;
215 	}
216 	ODBC_RETURN_(dbc);
217 }
218 
219 static SQLRETURN
change_database(TDS_DBC * dbc,const char * database,size_t database_len)220 change_database(TDS_DBC * dbc, const char *database, size_t database_len)
221 {
222 	TDSSOCKET *tds = dbc->tds_socket;
223 
224 	/*
225 	 * We may not be connected yet and dbc->tds_socket
226 	 * may not initialized.
227 	 */
228 	if (tds) {
229 		/* build query */
230 		char *query = tds_new(char, 6 + tds_quote_id(tds, NULL, database, database_len));
231 
232 		if (!query) {
233 			odbc_errs_add(&dbc->errs, "HY001", NULL);
234 			return SQL_ERROR;
235 		}
236 		strcpy(query, "USE ");
237 		tds_quote_id(tds, query + 4, database, database_len);
238 
239 
240 		tdsdump_log(TDS_DBG_INFO1, "change_database: executing %s\n", query);
241 
242 		/* TODO better idle check, not thread safe */
243 		if (tds->state == TDS_IDLE)
244 			tds->query_timeout = dbc->default_query_timeout;
245 		if (TDS_FAILED(tds_submit_query(tds, query))) {
246 			free(query);
247 			odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
248 			return SQL_ERROR;
249 		}
250 		free(query);
251 		if (TDS_FAILED(tds_process_simple_query(tds))) {
252 			odbc_errs_add(&dbc->errs, "HY000", "Could not change database");
253 			return SQL_ERROR;
254 		}
255 	} else {
256 		if (!tds_dstr_copyn(&dbc->attr.current_catalog, database, database_len)) {
257 			odbc_errs_add(&dbc->errs, "HY001", NULL);
258 			return SQL_ERROR;
259 		}
260 	}
261 	ODBC_RETURN_(dbc);
262 }
263 
264 static SQLRETURN
change_txn(TDS_DBC * dbc,SQLUINTEGER txn_isolation)265 change_txn(TDS_DBC * dbc, SQLUINTEGER txn_isolation)
266 {
267 	char query[64];
268 	const char *level;
269 	TDSSOCKET *tds = dbc->tds_socket;
270 
271 	switch (txn_isolation) {
272 	case SQL_TXN_READ_COMMITTED:
273 		level = "READ COMMITTED";
274 		break;
275 	case SQL_TXN_READ_UNCOMMITTED:
276 		level = "READ UNCOMMITTED";
277 		break;
278 	case SQL_TXN_REPEATABLE_READ:
279 		level = "REPEATABLE READ";
280 		break;
281 	case SQL_TXN_SERIALIZABLE:
282 		level = "SERIALIZABLE";
283 		break;
284 	default:
285 		odbc_errs_add(&dbc->errs, "HY024", NULL);
286 		return SQL_ERROR;
287 	}
288 
289 	/* if not connected return success, will be set after connection */
290 	if (!tds)
291 		return SQL_SUCCESS;
292 
293 	if (tds->state != TDS_IDLE) {
294 		odbc_errs_add(&dbc->errs, "HY011", NULL);
295 		return SQL_ERROR;
296 	}
297 
298 	tds->query_timeout = dbc->default_query_timeout;
299 	sprintf(query, "SET TRANSACTION ISOLATION LEVEL %s", level);
300 	if (TDS_FAILED(tds_submit_query(tds, query))) {
301 		ODBC_SAFE_ERROR(dbc);
302 		return SQL_ERROR;
303 	}
304 	if (TDS_FAILED(tds_process_simple_query(tds))) {
305 		ODBC_SAFE_ERROR(dbc);
306 		return SQL_ERROR;
307 	}
308 
309 	return SQL_SUCCESS;
310 }
311 
312 static TDS_DBC*
odbc_get_dbc(TDSSOCKET * tds)313 odbc_get_dbc(TDSSOCKET *tds)
314 {
315 	TDS_CHK *chk = (TDS_CHK *) tds_get_parent(tds);
316 	if (!chk)
317 		return NULL;
318 	if (chk->htype == SQL_HANDLE_DBC)
319 		return (TDS_DBC *) chk;
320 	assert(chk->htype == SQL_HANDLE_STMT);
321 	return ((TDS_STMT *) chk)->dbc;
322 }
323 
324 static TDS_STMT*
odbc_get_stmt(TDSSOCKET * tds)325 odbc_get_stmt(TDSSOCKET *tds)
326 {
327 	TDS_CHK *chk = (TDS_CHK *) tds_get_parent(tds);
328 	if (!chk || chk->htype != SQL_HANDLE_STMT)
329 		return NULL;
330 	return (TDS_STMT *) chk;
331 }
332 
333 
334 static void
odbc_env_change(TDSSOCKET * tds,int type,char * oldval,char * newval)335 odbc_env_change(TDSSOCKET * tds, int type, char *oldval, char *newval)
336 {
337 	TDS_DBC *dbc;
338 
339 	assert(tds);
340 
341 	dbc = odbc_get_dbc(tds);
342 	if (!dbc)
343 		return;
344 
345 	switch (type) {
346 	case TDS_ENV_DATABASE:
347 		tds_dstr_copy(&dbc->attr.current_catalog, newval);
348 		break;
349 	case TDS_ENV_PACKSIZE:
350 		dbc->attr.packet_size = atoi(newval);
351 		break;
352 	}
353 }
354 
355 static SQLRETURN
odbc_connect(TDS_DBC * dbc,TDSLOGIN * login)356 odbc_connect(TDS_DBC * dbc, TDSLOGIN * login)
357 {
358 	TDS_ENV *env = dbc->env;
359 
360 #ifdef ENABLE_ODBC_WIDE
361 	dbc->mb_conv = NULL;
362 #endif
363 	dbc->tds_socket = tds_alloc_socket(env->tds_ctx, 512);
364 	if (!dbc->tds_socket)
365 		goto memory_error;
366 
367 	dbc->tds_socket->conn->use_iconv = 0;
368 	tds_set_parent(dbc->tds_socket, (void *) dbc);
369 
370 	/* Set up our environment change hook */
371 	dbc->tds_socket->env_chg_func = odbc_env_change;
372 
373 	tds_fix_login(login);
374 
375 	/* use connection timeout if set */
376 	if (dbc->attr.connection_timeout)
377 		login->connect_timeout = dbc->attr.connection_timeout;
378 
379 	if (dbc->attr.mars_enabled != SQL_MARS_ENABLED_NO)
380 		login->mars = 1;
381 	if (dbc->attr.bulk_enabled != SQL_BCP_OFF)
382 		tds_set_bulk(login, 1);
383 
384 #ifdef ENABLE_ODBC_WIDE
385 	/* force utf-8 in order to support wide characters */
386 	if (!tds_dstr_dup(&dbc->original_charset, &login->client_charset)
387 	    || !tds_dstr_copy(&login->client_charset, "UTF-8"))
388 		goto memory_error;
389 #endif
390 
391 	/* replace password with old one */
392 	if (dbc->use_oldpwd) {
393 		if (!tds_dstr_dup(&login->new_password, &login->password)
394 		    || !tds_dstr_dup(&login->password, &dbc->oldpwd))
395 			goto memory_error;
396 		login->use_new_password = 1;
397 	}
398 
399 	if (TDS_FAILED(tds_connect_and_login(dbc->tds_socket, login))) {
400 		tds_free_socket(dbc->tds_socket);
401 		dbc->tds_socket = NULL;
402 		odbc_errs_add(&dbc->errs, "08001", NULL);
403 		return SQL_ERROR;
404 	}
405 #ifdef ENABLE_ODBC_WIDE
406 	dbc->mb_conv = tds_iconv_get(dbc->tds_socket->conn, tds_dstr_cstr(&dbc->original_charset), "UTF-8");
407 #endif
408 
409 	dbc->default_query_timeout = dbc->tds_socket->query_timeout;
410 
411 	if (IS_TDS7_PLUS(dbc->tds_socket->conn))
412 		dbc->cursor_support = 1;
413 
414 #if ENABLE_ODBC_MARS
415 	/* check if mars is enabled */
416 	if (!IS_TDS72_PLUS(dbc->tds_socket->conn) || !dbc->tds_socket->conn->mars)
417 		dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
418 #else
419 	dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
420 #endif
421 
422 	if (dbc->attr.txn_isolation != SQL_TXN_READ_COMMITTED) {
423 		if (!SQL_SUCCEEDED(change_txn(dbc, dbc->attr.txn_isolation)))
424 			ODBC_RETURN_(dbc);
425 	}
426 
427 	if (dbc->attr.autocommit != SQL_AUTOCOMMIT_ON) {
428 		dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
429 		if (!SQL_SUCCEEDED(change_autocommit(dbc, SQL_AUTOCOMMIT_OFF)))
430 			ODBC_RETURN_(dbc);
431 	}
432 
433 	/* this overwrite any error arrived (wanted behavior, Sybase return error for conversion errors) */
434 	ODBC_RETURN(dbc, SQL_SUCCESS);
435 
436 memory_error:
437 	tds_free_socket(dbc->tds_socket);
438 	dbc->tds_socket = NULL;
439 	odbc_errs_add(&dbc->errs, "HY001", NULL);
440 	ODBC_RETURN_(dbc);
441 }
442 
443 static SQLRETURN
odbc_update_ird(TDS_STMT * stmt,TDS_ERRS * errs)444 odbc_update_ird(TDS_STMT *stmt, TDS_ERRS *errs)
445 {
446 	SQLRETURN res;
447 
448 	if (!stmt->need_reprepare || stmt->prepared_query_is_rpc
449 	    || !stmt->dbc || !IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
450 		stmt->need_reprepare = 0;
451 		return SQL_SUCCESS;
452 	}
453 
454 	/* FIXME where error are put ?? on stmt... */
455 	if (!odbc_lock_statement(stmt))
456 		ODBC_RETURN_(stmt);
457 
458 	/* FIXME error */
459 	res = start_parse_prepared_query(stmt, 0);
460 	if (res != SQL_SUCCESS) {
461 		/* prepare with dummy parameters just to fill IRD */
462 		tds_free_param_results(stmt->params);
463 		stmt->params = NULL;
464 		stmt->param_num = 0;
465 		/*
466 		 * TODO
467 		 * we need to prepare again with parameters but need_reprepare
468 		 * flag is reset by odbc_prepare... perhaps should be checked
469 		 * later, not calling describeCol or similar
470 		 * we need prepare to get dynamic and cause we change parameters
471 		 */
472 	}
473 
474 	return odbc_prepare(stmt);
475 }
476 
477 static SQLRETURN
odbc_prepare(TDS_STMT * stmt)478 odbc_prepare(TDS_STMT *stmt)
479 {
480 	TDSSOCKET *tds = stmt->tds;
481 	int in_row = 0;
482 
483 	if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
484 		ODBC_SAFE_ERROR(stmt);
485 		return SQL_ERROR;
486 	}
487 
488 	/* try to go to the next recordset */
489 	/* TODO merge with similar code */
490 	desc_free_records(stmt->ird);
491 	stmt->row_status = PRE_NORMAL_ROW;
492 	for (;;) {
493 		TDS_INT result_type;
494 		int done_flags;
495 
496 		switch (tds_process_tokens(tds, &result_type, &done_flags, TDS_RETURN_ROWFMT|TDS_RETURN_DONE)) {
497 		case TDS_SUCCESS:
498 			switch (result_type) {
499 			case TDS_DONE_RESULT:
500 			case TDS_DONEPROC_RESULT:
501 			case TDS_DONEINPROC_RESULT:
502 				stmt->row_count = tds->rows_affected;
503 				if (done_flags & TDS_DONE_ERROR && !stmt->dyn->emulated)
504 					stmt->errs.lastrc = SQL_ERROR;
505 				/* FIXME this row is used only as a flag for update binding, should be cleared if binding/result changed */
506 				stmt->row = 0;
507 				break;
508 
509 			case TDS_ROWFMT_RESULT:
510 				/* store first row informations */
511 				if (!in_row)
512 					odbc_populate_ird(stmt);
513 				stmt->row = 0;
514 				stmt->row_count = TDS_NO_COUNT;
515 				stmt->row_status = PRE_NORMAL_ROW;
516 				in_row = 1;
517 				break;
518 			}
519 			continue;
520 		case TDS_NO_MORE_RESULTS:
521 			break;
522 		case TDS_CANCELLED:
523 			odbc_errs_add(&stmt->errs, "HY008", NULL);
524 		default:
525 			stmt->errs.lastrc = SQL_ERROR;
526 			break;
527 		}
528 		break;
529 	}
530 
531 	if (stmt->errs.lastrc == SQL_ERROR && !stmt->dyn->emulated) {
532 		tds_release_dynamic(&stmt->dyn);
533 	}
534 	odbc_unlock_statement(stmt);
535 	stmt->need_reprepare = 0;
536 	ODBC_RETURN_(stmt);
537 }
538 
539 ODBC_FUNC(SQLDriverConnect, (P(SQLHDBC,hdbc), P(SQLHWND,hwnd), PCHARIN(ConnStrIn,SQLSMALLINT),
540 	PCHAROUT(ConnStrOut,SQLSMALLINT), P(SQLUSMALLINT,fDriverCompletion) WIDE))
541 {
542 	TDSLOGIN *login;
543 	TDS_PARSED_PARAM params[ODBC_PARAM_SIZE];
544 	DSTR conn_str = DSTR_INITIALIZER;
545 
546 	ODBC_ENTER_HDBC;
547 
548 #ifdef TDS_NO_DM
549 	/* Check string length */
550 	if (!IS_VALID_LEN(cbConnStrIn) || cbConnStrIn == 0) {
551 		odbc_errs_add(&dbc->errs, "HY090", NULL);
552 		ODBC_EXIT_(dbc);
553 	}
554 
555 	/* Check completion param */
556 	switch (fDriverCompletion) {
557 	case SQL_DRIVER_NOPROMPT:
558 	case SQL_DRIVER_COMPLETE:
559 	case SQL_DRIVER_PROMPT:
560 	case SQL_DRIVER_COMPLETE_REQUIRED:
561 		break;
562 	default:
563 		odbc_errs_add(&dbc->errs, "HY110", NULL);
564 		ODBC_EXIT_(dbc);
565 	}
566 #endif
567 
568 	if (!odbc_dstr_copy(dbc, &conn_str, cbConnStrIn, szConnStrIn)) {
569 		odbc_errs_add(&dbc->errs, "HY001", NULL);
570 		ODBC_EXIT_(dbc);
571 	}
572 
573 	login = tds_alloc_login(0);
574 	if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale)) {
575 		tds_free_login(login);
576 		tds_dstr_free(&conn_str);
577 		odbc_errs_add(&dbc->errs, "HY001", NULL);
578 		ODBC_EXIT_(dbc);
579 	}
580 
581 	if (!tds_dstr_isempty(&dbc->attr.current_catalog))
582 		if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog)) {
583 			tds_free_login(login);
584 			tds_dstr_free(&conn_str);
585 			odbc_errs_add(&dbc->errs, "HY001", NULL);
586 			ODBC_EXIT_(dbc);
587 		}
588 
589 	/* parse the DSN string */
590 	if (!odbc_parse_connect_string(&dbc->errs, tds_dstr_buf(&conn_str), tds_dstr_buf(&conn_str) + tds_dstr_len(&conn_str),
591 				       login, params)) {
592 		tds_dstr_free(&conn_str);
593 		ODBC_EXIT_(dbc);
594 	}
595 
596 	odbc_set_string(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, tds_dstr_buf(&conn_str), tds_dstr_len(&conn_str));
597 	tds_dstr_free(&conn_str);
598 
599 	/* add login info */
600 	if (hwnd && fDriverCompletion != SQL_DRIVER_NOPROMPT
601 	    && (fDriverCompletion == SQL_DRIVER_PROMPT || (!params[ODBC_PARAM_UID].p && !params[ODBC_PARAM_Trusted_Connection].p)
602 		|| tds_dstr_isempty(&login->server_name))) {
603 #ifdef _WIN32
604 		char *out = NULL;
605 
606 		/* prompt for login information */
607 		if (!get_login_info(hwnd, login)) {
608 			tds_free_login(login);
609 			odbc_errs_add(&dbc->errs, "08001", "User canceled login");
610 			ODBC_EXIT_(dbc);
611 		}
612 		if (tds_dstr_isempty(&login->user_name)) {
613 			params[ODBC_PARAM_UID].p = NULL;
614 			params[ODBC_PARAM_PWD].p = NULL;
615 			params[ODBC_PARAM_Trusted_Connection].p = "Yes";
616 			params[ODBC_PARAM_Trusted_Connection].len = 3;
617 		} else {
618 			params[ODBC_PARAM_UID].p   = tds_dstr_cstr(&login->user_name);
619 			params[ODBC_PARAM_UID].len = tds_dstr_len(&login->user_name);
620 			params[ODBC_PARAM_PWD].p   = tds_dstr_cstr(&login->password);
621 			params[ODBC_PARAM_PWD].len = tds_dstr_len(&login->password);
622 			params[ODBC_PARAM_Trusted_Connection].p = NULL;
623 		}
624 		if (!odbc_build_connect_string(&dbc->errs, params, &out))
625 			ODBC_EXIT_(dbc);
626 
627 		odbc_set_string(dbc, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, out, -1);
628 		tdsdump_log(TDS_DBG_INFO1, "connection string is now: %s\n", out);
629 		free(out);
630 #else
631 		/* we dont support a dialog box */
632 		odbc_errs_add(&dbc->errs, "HYC00", NULL);
633 #endif
634 	}
635 
636 	if (tds_dstr_isempty(&login->server_name)) {
637 		tds_free_login(login);
638 		odbc_errs_add(&dbc->errs, "IM007", "Could not find Servername or server parameter");
639 		ODBC_EXIT_(dbc);
640 	}
641 
642 	odbc_connect(dbc, login);
643 
644 	tds_free_login(login);
645 	ODBC_EXIT_(dbc);
646 }
647 
648 #if 0
649 SQLRETURN ODBC_API
650 SQLBrowseConnect(SQLHDBC hdbc, SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut,
651 		 SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut)
652 {
653 	tdsdump_log(TDS_DBG_FUNC, "SQLBrowseConnect(%p, %s, %d, %p, %d, %p)\n",
654 			hdbc, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
655 	ODBC_ENTER_HDBC;
656 	odbc_errs_add(&dbc->errs, "HYC00", "SQLBrowseConnect: function not implemented");
657 	ODBC_EXIT_(dbc);
658 }
659 #endif
660 
661 
662 ODBC_FUNC(SQLColumnPrivileges, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT), PCHARIN(SchemaName,SQLSMALLINT),
663 	PCHARIN(TableName,SQLSMALLINT), PCHARIN(ColumnName,SQLSMALLINT) WIDE))
664 {
665 	int retcode;
666 
667 	ODBC_ENTER_HSTMT;
668 
669 	retcode =
670 		odbc_stat_execute(stmt _wide, "sp_column_privileges", 4, "O@table_qualifier", szCatalogName, cbCatalogName,
671 				  "O@table_owner", szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName,
672 				  "P@column_name", szColumnName, cbColumnName);
673 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
674 		odbc_col_setname(stmt, 1, "TABLE_CAT");
675 		odbc_col_setname(stmt, 2, "TABLE_SCHEM");
676 	}
677 	ODBC_EXIT_(stmt);
678 }
679 
680 #if 0
681 SQLRETURN ODBC_API
682 SQLDescribeParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR * pfSqlType, SQLUINTEGER FAR * pcbParamDef,
683 		 SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable)
684 {
685 	tdsdump_log(TDS_DBG_FUNC, "SQLDescribeParam(%p, %d, %p, %p, %p, %p)\n",
686 			hstmt, ipar, pfSqlType, pcbParamDef, pibScale, pfNullable);
687 	ODBC_ENTER_HSTMT;
688 	odbc_errs_add(&stmt->errs, "HYC00", "SQLDescribeParam: function not implemented");
689 	ODBC_EXIT_(stmt);
690 }
691 #endif
692 
693 
694 SQLRETURN ODBC_PUBLIC ODBC_API
SQLExtendedFetch(SQLHSTMT hstmt,SQLUSMALLINT fFetchType,SQLROWOFFSET irow,SQLROWSETSIZE FAR * pcrow,SQLUSMALLINT FAR * rgfRowStatus)695 SQLExtendedFetch(SQLHSTMT hstmt, SQLUSMALLINT fFetchType, SQLROWOFFSET irow, SQLROWSETSIZE FAR * pcrow, SQLUSMALLINT FAR * rgfRowStatus)
696 {
697 	SQLRETURN ret;
698 	SQLULEN * tmp_rows;
699 	SQLUSMALLINT * tmp_status;
700 	SQLULEN tmp_size;
701 	SQLLEN * tmp_offset;
702 	SQLPOINTER tmp_bookmark;
703 	SQLULEN bookmark;
704 	SQLULEN out_len = 0;
705 
706 	ODBC_ENTER_HSTMT;
707 
708 	tdsdump_log(TDS_DBG_FUNC, "SQLExtendedFetch(%p, %d, %d, %p, %p)\n",
709 			hstmt, fFetchType, (int)irow, pcrow, rgfRowStatus);
710 
711 	if (fFetchType != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
712 		odbc_errs_add(&stmt->errs, "HY106", NULL);
713 		ODBC_EXIT_(stmt);
714 	}
715 
716 	/* save and change IRD/ARD state */
717 	tmp_rows = stmt->ird->header.sql_desc_rows_processed_ptr;
718 	stmt->ird->header.sql_desc_rows_processed_ptr = &out_len;
719 	tmp_status = stmt->ird->header.sql_desc_array_status_ptr;
720 	stmt->ird->header.sql_desc_array_status_ptr = rgfRowStatus;
721 	tmp_size = stmt->ard->header.sql_desc_array_size;
722 	stmt->ard->header.sql_desc_array_size = stmt->sql_rowset_size;
723 	tmp_offset = stmt->ard->header.sql_desc_bind_offset_ptr;
724 	stmt->ard->header.sql_desc_bind_offset_ptr = NULL;
725 	tmp_bookmark = stmt->attr.fetch_bookmark_ptr;
726 
727 	/* SQL_FETCH_BOOKMARK different */
728 	if (fFetchType == SQL_FETCH_BOOKMARK) {
729 		bookmark = irow;
730 		irow = 0;
731 		stmt->attr.fetch_bookmark_ptr = &bookmark;
732 	}
733 
734 	/* TODO errors are sligthly different ... perhaps it's better to leave DM do this job ?? */
735 	/* TODO check fFetchType can be converted to USMALLINT */
736 	ret = _SQLFetch(stmt, fFetchType, irow);
737 
738 	/* restore IRD/ARD */
739 	stmt->ird->header.sql_desc_rows_processed_ptr = tmp_rows;
740 	if (pcrow)
741 		*pcrow = out_len;
742 	stmt->ird->header.sql_desc_array_status_ptr = tmp_status;
743 	stmt->ard->header.sql_desc_array_size = tmp_size;
744 	stmt->ard->header.sql_desc_bind_offset_ptr = tmp_offset;
745 	stmt->attr.fetch_bookmark_ptr = tmp_bookmark;
746 
747 	ODBC_EXIT(stmt, ret);
748 }
749 
750 ODBC_FUNC(SQLForeignKeys, (P(SQLHSTMT,hstmt), PCHARIN(PkCatalogName,SQLSMALLINT),
751 	PCHARIN(PkSchemaName,SQLSMALLINT), PCHARIN(PkTableName,SQLSMALLINT),
752 	PCHARIN(FkCatalogName,SQLSMALLINT), PCHARIN(FkSchemaName,SQLSMALLINT),
753 	PCHARIN(FkTableName,SQLSMALLINT) WIDE))
754 {
755 	int retcode;
756 
757 	ODBC_ENTER_HSTMT;
758 
759 	retcode =
760 		odbc_stat_execute(stmt _wide, "sp_fkeys", 6, "O@pktable_qualifier", szPkCatalogName, cbPkCatalogName, "O@pktable_owner",
761 				  szPkSchemaName, cbPkSchemaName, "O@pktable_name", szPkTableName, cbPkTableName,
762 				  "O@fktable_qualifier", szFkCatalogName, cbFkCatalogName, "O@fktable_owner", szFkSchemaName,
763 				  cbFkSchemaName, "O@fktable_name", szFkTableName, cbFkTableName);
764 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
765 		odbc_col_setname(stmt, 1, "PKTABLE_CAT");
766 		odbc_col_setname(stmt, 2, "PKTABLE_SCHEM");
767 		odbc_col_setname(stmt, 5, "FKTABLE_CAT");
768 		odbc_col_setname(stmt, 6, "FKTABLE_SCHEM");
769 	}
770 	ODBC_EXIT_(stmt);
771 }
772 
773 static int
odbc_lock_statement(TDS_STMT * stmt)774 odbc_lock_statement(TDS_STMT* stmt)
775 {
776 #if ENABLE_ODBC_MARS
777 	TDSSOCKET *tds = stmt->tds;
778 
779 
780 	/* we already own a socket, just use it */
781 	if (!tds) {
782 		/* try with one saved into DBC */
783 		TDSSOCKET *dbc_tds = stmt->dbc->tds_socket;
784 		tds_mutex_lock(&stmt->dbc->mtx);
785 
786 		if (stmt->dbc->current_statement == NULL
787 		    || stmt->dbc->current_statement == stmt) {
788 			tds = dbc_tds;
789 			stmt->dbc->current_statement = stmt;
790 		}
791 
792 		/* try to grab current locked one */
793 		if (!tds && dbc_tds->state == TDS_IDLE) {
794 			stmt->dbc->current_statement->tds = NULL;
795 			tds = dbc_tds;
796 			stmt->dbc->current_statement = stmt;
797 		}
798 		tds_mutex_unlock(&stmt->dbc->mtx);
799 
800 		/* try with MARS */
801 		if (!tds)
802 			tds = tds_alloc_additional_socket(dbc_tds->conn);
803 	}
804 	if (tds) {
805 		tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
806 			stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
807 		tds_set_parent(tds, stmt);
808 		stmt->tds = tds;
809 		return 1;
810 	}
811 	odbc_errs_add(&stmt->errs, "24000", NULL);
812 	return 0;
813 #else
814 	TDSSOCKET *tds = stmt->dbc->tds_socket;
815 
816 	tds_mutex_lock(&stmt->dbc->mtx);
817 	if (stmt->dbc->current_statement != NULL
818 	    && stmt->dbc->current_statement != stmt) {
819 		if (!tds || tds->state != TDS_IDLE) {
820 			tds_mutex_unlock(&stmt->dbc->mtx);
821 			odbc_errs_add(&stmt->errs, "24000", NULL);
822 			return 0;
823 		}
824 		stmt->dbc->current_statement->tds = NULL;
825 	}
826 	stmt->dbc->current_statement = stmt;
827 	if (tds) {
828 		tds->query_timeout = (stmt->attr.query_timeout != DEFAULT_QUERY_TIMEOUT) ?
829 			stmt->attr.query_timeout : stmt->dbc->default_query_timeout;
830 		tds_set_parent(tds, stmt);
831 		stmt->tds = tds;
832 	}
833 	tds_mutex_unlock(&stmt->dbc->mtx);
834 	return 1;
835 #endif
836 }
837 
838 static void
odbc_unlock_statement(TDS_STMT * stmt)839 odbc_unlock_statement(TDS_STMT* stmt)
840 {
841 	TDSSOCKET * tds;
842 
843 	tds_mutex_lock(&stmt->dbc->mtx);
844 	tds = stmt->tds;
845 	if (stmt->dbc->current_statement == stmt) {
846 		assert(tds == stmt->dbc->tds_socket);
847 		if (tds->state == TDS_IDLE) {
848 			stmt->dbc->current_statement = NULL;
849 			tds_set_parent(tds, stmt->dbc);
850 			stmt->tds = NULL;
851 		}
852 #if ENABLE_ODBC_MARS
853 	} else if (tds) {
854 		if (tds->state == TDS_IDLE || tds->state == TDS_DEAD) {
855 			assert(tds != stmt->dbc->tds_socket);
856 			tds_free_socket(tds);
857 			stmt->tds = NULL;
858 		}
859 #endif
860 	}
861 	tds_mutex_unlock(&stmt->dbc->mtx);
862 }
863 
864 SQLRETURN ODBC_PUBLIC ODBC_API
SQLMoreResults(SQLHSTMT hstmt)865 SQLMoreResults(SQLHSTMT hstmt)
866 {
867 	TDSSOCKET *tds;
868 	TDS_INT result_type;
869 	TDSRET tdsret;
870 	int in_row = 0;
871 	SQLUSMALLINT param_status;
872 	int token_flags;
873 
874 	ODBC_ENTER_HSTMT;
875 
876 	tdsdump_log(TDS_DBG_FUNC, "SQLMoreResults(%p)\n", hstmt);
877 
878 	tds = stmt->tds;
879 
880 	/* We already read all results... */
881 	if (!tds)
882 		ODBC_EXIT(stmt, SQL_NO_DATA);
883 
884 	stmt->row_count = TDS_NO_COUNT;
885 	stmt->special_row = ODBC_SPECIAL_NONE;
886 
887 	/* TODO this code is TOO similar to _SQLExecute, merge it - freddy77 */
888 	/* try to go to the next recordset */
889 	if (stmt->row_status == IN_COMPUTE_ROW) {
890 		/* FIXME doesn't seem so fine ... - freddy77 */
891 		tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
892 		stmt->row_status = IN_COMPUTE_ROW;
893 		in_row = 1;
894 	}
895 
896 	param_status = SQL_PARAM_SUCCESS;
897 	token_flags = (TDS_TOKEN_RESULTS & (~TDS_STOPAT_COMPUTE)) | TDS_RETURN_COMPUTE;
898 	if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
899 		token_flags |= TDS_RETURN_MSG;
900 	for (;;) {
901 		result_type = odbc_process_tokens(stmt, token_flags);
902 		tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: result_type=%d, row_count=%" PRId64 ", lastrc=%d\n",
903 						result_type, stmt->row_count, stmt->errs.lastrc);
904 		switch (result_type) {
905 		case TDS_CMD_DONE:
906 #if 1 /* !UNIXODBC */
907 			tds_free_all_results(tds);
908 #endif
909 			odbc_populate_ird(stmt);
910 			odbc_unlock_statement(stmt);
911 			if (stmt->row_count == TDS_NO_COUNT && !in_row) {
912 				stmt->row_status = NOT_IN_ROW;
913 				tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_status=%d\n", stmt->row_status);
914 			}
915 			tdsdump_log(TDS_DBG_INFO1, "SQLMoreResults: row_count=%" PRId64 ", lastrc=%d\n", stmt->row_count, stmt->errs.lastrc);
916 			if (stmt->row_count == TDS_NO_COUNT) {
917 				if (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
918 					ODBC_EXIT(stmt, SQL_NO_DATA);
919 			}
920 			ODBC_EXIT_(stmt);
921 
922 		case TDS_CMD_FAIL:
923 			ODBC_SAFE_ERROR(stmt);
924 			ODBC_EXIT_(stmt);
925 
926 		case TDS_COMPUTE_RESULT:
927 			switch (stmt->row_status) {
928 			/* skip this recordset */
929 			case IN_COMPUTE_ROW:
930 				/* TODO here we should set current_results to normal results */
931 				in_row = 1;
932 				/* fall through */
933 			/* in normal row, put in compute status */
934 			case AFTER_COMPUTE_ROW:
935 			case IN_NORMAL_ROW:
936 			case PRE_NORMAL_ROW:
937 				stmt->row_status = IN_COMPUTE_ROW;
938 				odbc_populate_ird(stmt);
939 				ODBC_EXIT_(stmt);
940 			case NOT_IN_ROW:
941 				/* this should never happen, protocol error */
942 				ODBC_SAFE_ERROR(stmt);
943 				ODBC_EXIT_(stmt);
944 				break;
945 			}
946 			break;
947 
948 		case TDS_ROW_RESULT:
949 			if (in_row || (stmt->row_status != IN_NORMAL_ROW && stmt->row_status != PRE_NORMAL_ROW)) {
950 				stmt->row_status = PRE_NORMAL_ROW;
951 				odbc_populate_ird(stmt);
952 				ODBC_EXIT_(stmt);
953 			}
954 			/* Skipping current result set's rows to access next resultset or proc's retval */
955 			tdsret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_STOPAT_COMPUTE);
956 			/* TODO should we set in_row ?? */
957 			switch (tdsret) {
958 			case TDS_CANCELLED:
959 				odbc_errs_add(&stmt->errs, "HY008", NULL);
960 			default:
961 				if (TDS_FAILED(tdsret)) {
962 					ODBC_SAFE_ERROR(stmt);
963 					ODBC_EXIT_(stmt);
964 				}
965 			}
966 			break;
967 
968 		case TDS_DONE_RESULT:
969 		case TDS_DONEPROC_RESULT:
970 			/* FIXME here ??? */
971 			if (!in_row)
972 				tds_free_all_results(tds);
973 			switch (stmt->errs.lastrc) {
974 			case SQL_ERROR:
975 				param_status = SQL_PARAM_ERROR;
976 				break;
977 			case SQL_SUCCESS_WITH_INFO:
978 				param_status = SQL_PARAM_SUCCESS_WITH_INFO;
979 				break;
980 			}
981 			if (stmt->curr_param_row < stmt->num_param_rows) {
982 				if (stmt->ipd->header.sql_desc_array_status_ptr)
983 					stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
984 				++stmt->curr_param_row;
985 				if (stmt->ipd->header.sql_desc_rows_processed_ptr)
986 					*stmt->ipd->header.sql_desc_rows_processed_ptr = stmt->curr_param_row;
987 			}
988 			if (stmt->curr_param_row < stmt->num_param_rows) {
989 #if 0
990 				if (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO)
991 					found_info = 1;
992 				if (stmt->errs.lastrc == SQL_ERROR)
993 					found_error = 1;
994 #endif
995 				stmt->errs.lastrc = SQL_SUCCESS;
996 				param_status = SQL_PARAM_SUCCESS;
997 				break;
998 			}
999 			odbc_populate_ird(stmt);
1000 			ODBC_EXIT_(stmt);
1001 			break;
1002 
1003 			/*
1004 			 * TODO test flags ? check error and change result ?
1005 			 * see also other DONEINPROC handle (below)
1006 			 */
1007 		case TDS_DONEINPROC_RESULT:
1008 			if (in_row) {
1009 				odbc_populate_ird(stmt);
1010 				ODBC_EXIT_(stmt);
1011 			}
1012 			/* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
1013 			tds_free_all_results(tds);
1014 			odbc_populate_ird(stmt);
1015 			break;
1016 
1017 			/* do not stop at metadata, an error can follow... */
1018 		case TDS_ROWFMT_RESULT:
1019 			if (in_row) {
1020 				odbc_populate_ird(stmt);
1021 				ODBC_EXIT_(stmt);
1022 			}
1023 			stmt->row = 0;
1024 			stmt->row_count = TDS_NO_COUNT;
1025 			/* we expect a row */
1026 			stmt->row_status = PRE_NORMAL_ROW;
1027 			in_row = 1;
1028 			break;
1029 
1030 		case TDS_MSG_RESULT:
1031 			if (!in_row) {
1032 				tds_free_all_results(tds);
1033 				odbc_populate_ird(stmt);
1034 			}
1035 			in_row = 1;
1036 			break;
1037 		}
1038 	}
1039 	ODBC_EXIT(stmt, SQL_ERROR);
1040 }
1041 
1042 ODBC_FUNC(SQLNativeSql, (P(SQLHDBC,hdbc), PCHARIN(SqlStrIn,SQLINTEGER),
1043 	PCHAROUT(SqlStr,SQLINTEGER) WIDE))
1044 {
1045 	SQLRETURN ret = SQL_SUCCESS;
1046 	DSTR query = DSTR_INITIALIZER;
1047 
1048 	ODBC_ENTER_HDBC;
1049 
1050 #ifdef TDS_NO_DM
1051 	if (!szSqlStrIn || !IS_VALID_LEN(cbSqlStrIn)) {
1052 		odbc_errs_add(&dbc->errs, "HY009", NULL);
1053 		ODBC_EXIT_(dbc);
1054 	}
1055 #endif
1056 
1057 	if (!odbc_dstr_copy(dbc, &query, cbSqlStrIn, szSqlStrIn)) {
1058 		odbc_errs_add(&dbc->errs, "HY001", NULL);
1059 		ODBC_EXIT_(dbc);
1060 	}
1061 
1062 	native_sql(dbc, &query);
1063 
1064 	/* FIXME if error set some kind of error */
1065 	ret = odbc_set_string(dbc, szSqlStr, cbSqlStrMax, pcbSqlStr, tds_dstr_cstr(&query), -1);
1066 
1067 	tds_dstr_free(&query);
1068 
1069 	ODBC_EXIT(dbc, ret);
1070 }
1071 
1072 SQLRETURN ODBC_PUBLIC ODBC_API
SQLNumParams(SQLHSTMT hstmt,SQLSMALLINT FAR * pcpar)1073 SQLNumParams(SQLHSTMT hstmt, SQLSMALLINT FAR * pcpar)
1074 {
1075 	ODBC_ENTER_HSTMT;
1076 	tdsdump_log(TDS_DBG_FUNC, "SQLNumParams(%p, %p)\n", hstmt, pcpar);
1077 	*pcpar = stmt->param_count;
1078 	ODBC_EXIT_(stmt);
1079 }
1080 
1081 SQLRETURN ODBC_PUBLIC ODBC_API
SQLParamOptions(SQLHSTMT hstmt,SQLULEN crow,SQLULEN FAR * pirow)1082 SQLParamOptions(SQLHSTMT hstmt, SQLULEN crow, SQLULEN FAR * pirow)
1083 {
1084 	SQLRETURN res;
1085 
1086 	tdsdump_log(TDS_DBG_FUNC, "SQLParamOptions(%p, %lu, %p)\n", hstmt, (unsigned long int)crow, pirow);
1087 
1088 	/* emulate for ODBC 2 DM */
1089 	res = _SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, pirow, 0 _wide0);
1090 	if (res != SQL_SUCCESS)
1091 		return res;
1092 	return _SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crow, 0 _wide0);
1093 }
1094 
1095 ODBC_FUNC(SQLPrimaryKeys, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1096 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT) WIDE))
1097 {
1098 	int retcode;
1099 
1100 	ODBC_ENTER_HSTMT;
1101 
1102 	retcode =
1103 		odbc_stat_execute(stmt _wide, "sp_pkeys", 3, "O@table_qualifier", szCatalogName, cbCatalogName, "O@table_owner",
1104 				  szSchemaName, cbSchemaName, "O@table_name", szTableName, cbTableName);
1105 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1106 		odbc_col_setname(stmt, 1, "TABLE_CAT");
1107 		odbc_col_setname(stmt, 2, "TABLE_SCHEM");
1108 	}
1109 	ODBC_EXIT_(stmt);
1110 }
1111 
1112 ODBC_FUNC(SQLProcedureColumns, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1113 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(ProcName,SQLSMALLINT), PCHARIN(ColumnName,SQLSMALLINT) WIDE))
1114 {
1115 	int retcode;
1116 
1117 	ODBC_ENTER_HSTMT;
1118 
1119 	retcode =
1120 		odbc_stat_execute(stmt _wide, "sp_sproc_columns", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4,
1121 				  "O@procedure_qualifier", szCatalogName, cbCatalogName,
1122 				  "P@procedure_owner", szSchemaName, cbSchemaName, "P@procedure_name", szProcName, cbProcName,
1123 				  "P@column_name", szColumnName, cbColumnName, "V@ODBCVer", (char*) NULL, 0);
1124 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1125 		odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
1126 		odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
1127 		odbc_col_setname(stmt, 8, "COLUMN_SIZE");
1128 		odbc_col_setname(stmt, 9, "BUFFER_LENGTH");
1129 		odbc_col_setname(stmt, 10, "DECIMAL_DIGITS");
1130 		odbc_col_setname(stmt, 11, "NUM_PREC_RADIX");
1131 		if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
1132 			stmt->special_row = ODBC_SPECIAL_PROCEDURECOLUMNS;
1133 	}
1134 	ODBC_EXIT_(stmt);
1135 }
1136 
1137 ODBC_FUNC(SQLProcedures, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1138 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(ProcName,SQLSMALLINT) WIDE))
1139 {
1140 	int retcode;
1141 
1142 	ODBC_ENTER_HSTMT;
1143 
1144 	retcode =
1145 		odbc_stat_execute(stmt _wide, "..sp_stored_procedures", 3, "P@sp_name", szProcName, cbProcName, "P@sp_owner", szSchemaName,
1146 				  cbSchemaName, "O@sp_qualifier", szCatalogName, cbCatalogName);
1147 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1148 		odbc_col_setname(stmt, 1, "PROCEDURE_CAT");
1149 		odbc_col_setname(stmt, 2, "PROCEDURE_SCHEM");
1150 	}
1151 	ODBC_EXIT_(stmt);
1152 }
1153 
1154 static TDSPARAMINFO*
odbc_build_update_params(TDS_STMT * stmt,SQLSETPOSIROW n_row)1155 odbc_build_update_params(TDS_STMT * stmt, SQLSETPOSIROW n_row)
1156 {
1157         SQLSMALLINT n;
1158 	TDSPARAMINFO * params = NULL;
1159 	struct _drecord *drec_ird;
1160 
1161 	for (n = 0; n < stmt->ird->header.sql_desc_count && n < stmt->ard->header.sql_desc_count; ++n) {
1162 		TDSPARAMINFO *temp_params;
1163 		TDSCOLUMN *curcol;
1164 
1165 		drec_ird = &stmt->ird->records[n];
1166 
1167 		if (drec_ird->sql_desc_updatable == SQL_FALSE)
1168 			continue;
1169 
1170 		/* we have certainly a parameter */
1171 		if (!(temp_params = tds_alloc_param_result(params)))
1172 			goto memory_error;
1173                 params = temp_params;
1174 
1175 		curcol = params->columns[params->num_cols - 1];
1176 		if (!tds_dstr_dup(&curcol->column_name, &drec_ird->sql_desc_name))
1177 			goto memory_error;
1178 
1179 		/* TODO use all infos... */
1180 		if (!tds_dstr_dup(&curcol->table_name, &drec_ird->sql_desc_base_table_name))
1181 			goto memory_error;
1182 
1183 		switch (odbc_sql2tds(stmt, drec_ird, &stmt->ard->records[n], curcol, 1, stmt->ard, n_row)) {
1184 		case SQL_NEED_DATA:
1185 			goto memory_error;
1186 		case SQL_ERROR:
1187 			tds_free_param_results(params);
1188 			return NULL;
1189 		}
1190 	}
1191 	return params;
1192 
1193 memory_error:
1194 	tds_free_param_results(params);
1195 	odbc_errs_add(&stmt->errs, "HY001", NULL);
1196 	return NULL;
1197 }
1198 
1199 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetPos(SQLHSTMT hstmt,SQLSETPOSIROW irow,SQLUSMALLINT fOption,SQLUSMALLINT fLock)1200 SQLSetPos(SQLHSTMT hstmt, SQLSETPOSIROW irow, SQLUSMALLINT fOption, SQLUSMALLINT fLock)
1201 {
1202 	TDSRET ret;
1203 	TDSSOCKET *tds;
1204 	TDS_CURSOR_OPERATION op;
1205 	TDSPARAMINFO *params = NULL;
1206 	ODBC_ENTER_HSTMT;
1207 
1208 	tdsdump_log(TDS_DBG_FUNC, "SQLSetPos(%p, %ld, %d, %d)\n",
1209 			hstmt, (long) irow, fOption, fLock);
1210 
1211 	if (!stmt->dbc->cursor_support) {
1212 		odbc_errs_add(&stmt->errs, "HYC00", "SQLSetPos: function not implemented");
1213 		ODBC_EXIT_(stmt);
1214 	}
1215 
1216 	/* TODO handle irow == 0 (all rows) */
1217 
1218 	if (!stmt->cursor) {
1219 		odbc_errs_add(&stmt->errs, "HY109", NULL);
1220 		ODBC_EXIT_(stmt);
1221 	}
1222 
1223 	switch (fOption) {
1224 	case SQL_POSITION:
1225 		op = TDS_CURSOR_POSITION;
1226 		break;
1227 	/* TODO cursor support */
1228 	case SQL_REFRESH:
1229 	default:
1230 		odbc_errs_add(&stmt->errs, "HY092", NULL);
1231 		ODBC_EXIT_(stmt);
1232 		break;
1233 	case SQL_UPDATE:
1234 		op = TDS_CURSOR_UPDATE;
1235 		/* prepare paremeters for update */
1236 		/* scan all columns and build parameter list */
1237 		params = odbc_build_update_params(stmt, irow >= 1 ? irow - 1 : 0);
1238 		if (!params) {
1239 			ODBC_SAFE_ERROR(stmt);
1240 			ODBC_EXIT_(stmt);
1241 		}
1242 		break;
1243 	case SQL_DELETE:
1244 		op = TDS_CURSOR_DELETE;
1245 		break;
1246 	case SQL_ADD:
1247 		op = TDS_CURSOR_INSERT;
1248 		break;
1249 	}
1250 
1251 	if (!odbc_lock_statement(stmt)) {
1252 		tds_free_param_results(params);
1253 		ODBC_EXIT_(stmt);
1254 	}
1255 
1256 	tds = stmt->tds;
1257 
1258 	if (TDS_FAILED(tds_cursor_update(tds, stmt->cursor, op, irow, params))) {
1259 		tds_free_param_results(params);
1260 		ODBC_SAFE_ERROR(stmt);
1261 		ODBC_EXIT_(stmt);
1262 	}
1263 	tds_free_param_results(params);
1264 	params = NULL;
1265 
1266 	ret = tds_process_simple_query(tds);
1267 	odbc_unlock_statement(stmt);
1268 	if (TDS_FAILED(ret)) {
1269 		ODBC_SAFE_ERROR(stmt);
1270 		ODBC_EXIT_(stmt);
1271 	}
1272 
1273 	ODBC_EXIT_(stmt);
1274 }
1275 
1276 ODBC_FUNC(SQLTablePrivileges, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
1277 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT) WIDE))
1278 {
1279 	int retcode;
1280 
1281 	ODBC_ENTER_HSTMT;
1282 
1283 	retcode =
1284 		odbc_stat_execute(stmt _wide, "sp_table_privileges", 3, "O@table_qualifier", szCatalogName, cbCatalogName,
1285 				  "P@table_owner", szSchemaName, cbSchemaName, "P@table_name", szTableName, cbTableName);
1286 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
1287 		odbc_col_setname(stmt, 1, "TABLE_CAT");
1288 		odbc_col_setname(stmt, 2, "TABLE_SCHEM");
1289 	}
1290 	ODBC_EXIT_(stmt);
1291 }
1292 
1293 #if (ODBCVER >= 0x0300)
1294 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetEnvAttr(SQLHENV henv,SQLINTEGER Attribute,SQLPOINTER Value,SQLINTEGER StringLength)1295 SQLSetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength)
1296 {
1297 	SQLINTEGER i_val = (SQLINTEGER) (TDS_INTPTR) Value;
1298 
1299 	ODBC_ENTER_HENV;
1300 
1301 	tdsdump_log(TDS_DBG_FUNC, "SQLSetEnvAttr(%p, %d, %p, %d)\n", henv, (int)Attribute, Value, (int)StringLength);
1302 
1303 	switch (Attribute) {
1304 	case SQL_ATTR_CONNECTION_POOLING:
1305 	case SQL_ATTR_CP_MATCH:
1306 		odbc_errs_add(&env->errs, "HYC00", NULL);
1307 		break;
1308 	case SQL_ATTR_ODBC_VERSION:
1309 		switch (i_val) {
1310 		case SQL_OV_ODBC3:
1311 		case SQL_OV_ODBC2:
1312 			env->attr.odbc_version = i_val;
1313 			break;
1314 		default:
1315 			odbc_errs_add(&env->errs, "HY024", NULL);
1316 			break;
1317 		}
1318 		break;
1319 	case SQL_ATTR_OUTPUT_NTS:
1320 		/* TODO - Make this really work */
1321                 env->attr.output_nts = i_val;
1322                 /* env->attr.output_nts = SQL_TRUE; */
1323 		break;
1324 	default:
1325 		odbc_errs_add(&env->errs, "HY092", NULL);
1326 		break;
1327 	}
1328 	ODBC_EXIT_(env);
1329 }
1330 
1331 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetEnvAttr(SQLHENV henv,SQLINTEGER Attribute,SQLPOINTER Value,SQLINTEGER BufferLength,SQLINTEGER * StringLength)1332 SQLGetEnvAttr(SQLHENV henv, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
1333 {
1334         SQLINTEGER size;
1335 	void *src;
1336 
1337 	ODBC_ENTER_HENV;
1338 
1339 	tdsdump_log(TDS_DBG_FUNC, "SQLGetEnvAttr(%p, %d, %p, %d, %p)\n",
1340 			henv, (int)Attribute, Value, (int)BufferLength, StringLength);
1341 
1342 	switch (Attribute) {
1343 	case SQL_ATTR_CONNECTION_POOLING:
1344 		src = &env->attr.connection_pooling;
1345 		size = sizeof(env->attr.connection_pooling);
1346 		break;
1347 	case SQL_ATTR_CP_MATCH:
1348 		src = &env->attr.cp_match;
1349 		size = sizeof(env->attr.cp_match);
1350 		break;
1351 	case SQL_ATTR_ODBC_VERSION:
1352 		src = &env->attr.odbc_version;
1353 		size = sizeof(env->attr.odbc_version);
1354 		break;
1355 	case SQL_ATTR_OUTPUT_NTS:
1356 		/* TODO handle output_nts flags */
1357 		env->attr.output_nts = SQL_TRUE;
1358 		src = &env->attr.output_nts;
1359 		size = sizeof(env->attr.output_nts);
1360 		break;
1361 	default:
1362 		odbc_errs_add(&env->errs, "HY092", NULL);
1363 		ODBC_EXIT_(env);
1364 		break;
1365 	}
1366 
1367 	if (StringLength) {
1368 		*StringLength = size;
1369 	}
1370 	memcpy(Value, src, size);
1371 
1372 	ODBC_EXIT_(env);
1373 }
1374 
1375 #endif
1376 
1377 #define IRD_UPDATE(desc, errs, exit) \
1378 	do { \
1379 		if (desc->type == DESC_IRD && ((TDS_STMT*)desc->parent)->need_reprepare && \
1380 		    odbc_update_ird((TDS_STMT*)desc->parent, errs) != SQL_SUCCESS) \
1381 			exit; \
1382 	} while(0)
1383 
1384 static SQLRETURN
_SQLBindParameter(SQLHSTMT hstmt,SQLUSMALLINT ipar,SQLSMALLINT fParamType,SQLSMALLINT fCType,SQLSMALLINT fSqlType,SQLULEN cbColDef,SQLSMALLINT ibScale,SQLPOINTER rgbValue,SQLLEN cbValueMax,SQLLEN FAR * pcbValue)1385 _SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1386 		  SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1387 {
1388 	TDS_DESC *apd, *ipd;
1389 	struct _drecord *drec;
1390 	SQLSMALLINT orig_apd_size, orig_ipd_size;
1391 	int is_numeric = 0;
1392 
1393 	ODBC_ENTER_HSTMT;
1394 
1395 	tdsdump_log(TDS_DBG_FUNC, "_SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1396 			hstmt, (unsigned short)ipar, (int)fParamType, (int)fCType, (int)fSqlType, (unsigned int)cbColDef,
1397 			(int)ibScale, rgbValue, (int)cbValueMax, pcbValue);
1398 
1399 #ifdef TDS_NO_DM
1400 	/* TODO - more error checking ...  XXX smurph */
1401 
1402 	/* Check param type */
1403 	switch (fParamType) {
1404 	case SQL_PARAM_INPUT:
1405 	case SQL_PARAM_INPUT_OUTPUT:
1406 	case SQL_PARAM_OUTPUT:
1407 		break;
1408 	default:
1409 		odbc_errs_add(&stmt->errs, "HY105", NULL);
1410 		ODBC_EXIT_(stmt);
1411 	}
1412 
1413 	/* Check max buffer length */
1414 	if (cbValueMax < 0) {
1415 		odbc_errs_add(&stmt->errs, "HY090", NULL);
1416 		ODBC_EXIT_(stmt);
1417 	}
1418 #endif
1419 
1420 	/* check cbColDef and ibScale */
1421 	if (fSqlType == SQL_DECIMAL || fSqlType == SQL_NUMERIC) {
1422 		is_numeric = 1;
1423 		if (cbColDef < 1 || cbColDef > 38) {
1424 			odbc_errs_add(&stmt->errs, "HY104", "Invalid precision value");
1425 			ODBC_EXIT_(stmt);
1426 		}
1427                 if (ibScale < 0 || (SQLULEN)ibScale > cbColDef) {
1428 			odbc_errs_add(&stmt->errs, "HY104", "Invalid scale value");
1429 			ODBC_EXIT_(stmt);
1430 		}
1431 	}
1432 
1433 	/* Check parameter number */
1434 	if (ipar <= 0 || ipar > 4000) {
1435 		odbc_errs_add(&stmt->errs, "07009", NULL);
1436 		ODBC_EXIT_(stmt);
1437 	}
1438 
1439 	/* fill APD related fields */
1440 	apd = stmt->apd;
1441 	orig_apd_size = apd->header.sql_desc_count;
1442 	if (ipar > apd->header.sql_desc_count && desc_alloc_records(apd, ipar) != SQL_SUCCESS) {
1443 		odbc_errs_add(&stmt->errs, "HY001", NULL);
1444 		ODBC_EXIT_(stmt);
1445 	}
1446 	drec = &apd->records[ipar - 1];
1447 
1448 	if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1449 		desc_alloc_records(apd, orig_apd_size);
1450 		odbc_errs_add(&stmt->errs, "HY004", NULL);
1451 		ODBC_EXIT_(stmt);
1452 	}
1453 
1454 	stmt->need_reprepare = 1;
1455 
1456 	/* TODO other types ?? handle SQL_C_DEFAULT */
1457 	if (drec->sql_desc_type == SQL_C_CHAR || drec->sql_desc_type == SQL_C_WCHAR || drec->sql_desc_type == SQL_C_BINARY)
1458 		drec->sql_desc_octet_length = cbValueMax;
1459 	drec->sql_desc_indicator_ptr = pcbValue;
1460 	drec->sql_desc_octet_length_ptr = pcbValue;
1461 	drec->sql_desc_data_ptr = (char *) rgbValue;
1462 
1463 	/* field IPD related fields */
1464 	ipd = stmt->ipd;
1465 	orig_ipd_size = ipd->header.sql_desc_count;
1466 	if (ipar > ipd->header.sql_desc_count && desc_alloc_records(ipd, ipar) != SQL_SUCCESS) {
1467 		desc_alloc_records(apd, orig_apd_size);
1468 		odbc_errs_add(&stmt->errs, "HY001", NULL);
1469 		ODBC_EXIT_(stmt);
1470 	}
1471 	drec = &ipd->records[ipar - 1];
1472 
1473 	drec->sql_desc_parameter_type = fParamType;
1474 	if (odbc_set_concise_sql_type(fSqlType, drec, 0) != SQL_SUCCESS) {
1475 		desc_alloc_records(ipd, orig_ipd_size);
1476 		desc_alloc_records(apd, orig_apd_size);
1477 		odbc_errs_add(&stmt->errs, "HY004", NULL);
1478 		ODBC_EXIT_(stmt);
1479 	}
1480 	if (is_numeric) {
1481                 drec->sql_desc_precision = (SQLSMALLINT) cbColDef;
1482 		drec->sql_desc_scale = ibScale;
1483 	} else {
1484 		drec->sql_desc_length = cbColDef;
1485 	}
1486 
1487 	ODBC_EXIT_(stmt);
1488 }
1489 
1490 SQLRETURN ODBC_PUBLIC ODBC_API
SQLBindParameter(SQLHSTMT hstmt,SQLUSMALLINT ipar,SQLSMALLINT fParamType,SQLSMALLINT fCType,SQLSMALLINT fSqlType,SQLULEN cbColDef,SQLSMALLINT ibScale,SQLPOINTER rgbValue,SQLLEN cbValueMax,SQLLEN FAR * pcbValue)1491 SQLBindParameter(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fParamType, SQLSMALLINT fCType, SQLSMALLINT fSqlType,
1492 		 SQLULEN cbColDef, SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1493 {
1494 	tdsdump_log(TDS_DBG_FUNC, "SQLBindParameter(%p, %u, %d, %d, %d, %u, %d, %p, %d, %p)\n",
1495 			hstmt, (unsigned)ipar, fParamType, fCType, (int)fSqlType, (unsigned)cbColDef, ibScale, rgbValue, (int)cbValueMax, pcbValue);
1496 	return _SQLBindParameter(hstmt, ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, cbValueMax, pcbValue);
1497 }
1498 
1499 
1500 /* compatibility with X/Open */
1501 SQLRETURN ODBC_PUBLIC ODBC_API
SQLBindParam(SQLHSTMT hstmt,SQLUSMALLINT ipar,SQLSMALLINT fCType,SQLSMALLINT fSqlType,SQLULEN cbColDef,SQLSMALLINT ibScale,SQLPOINTER rgbValue,SQLLEN FAR * pcbValue)1502 SQLBindParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbColDef, SQLSMALLINT ibScale,
1503 	     SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
1504 {
1505 	tdsdump_log(TDS_DBG_FUNC, "SQLBindParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
1506 			hstmt, ipar, fCType, fSqlType, (unsigned)cbColDef, ibScale, rgbValue, pcbValue);
1507 	return _SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT, fCType, fSqlType, cbColDef, ibScale, rgbValue, 0, pcbValue);
1508 }
1509 
1510 #if (ODBCVER >= 0x0300)
1511 SQLRETURN ODBC_PUBLIC ODBC_API
SQLAllocHandle(SQLSMALLINT HandleType,SQLHANDLE InputHandle,SQLHANDLE * OutputHandle)1512 SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle)
1513 {
1514 	tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(%d, %p, %p)\n", HandleType, InputHandle, OutputHandle);
1515 
1516 	switch (HandleType) {
1517 	case SQL_HANDLE_STMT:
1518 		return _SQLAllocStmt(InputHandle, OutputHandle);
1519 		break;
1520 	case SQL_HANDLE_DBC:
1521 		return _SQLAllocConnect(InputHandle, OutputHandle);
1522 		break;
1523 	case SQL_HANDLE_ENV:
1524 		return _SQLAllocEnv(OutputHandle, SQL_OV_ODBC3);
1525 		break;
1526 	case SQL_HANDLE_DESC:
1527 		return _SQLAllocDesc(InputHandle, OutputHandle);
1528 		break;
1529 	}
1530 
1531 	/*
1532 	 * As the documentation puts it,
1533 	 *	"There is no handle with which to associate additional diagnostic information."
1534 	 *
1535 	 * The DM must catch HY092 because the driver has no valid handle at this early stage in which
1536 	 * to store the error for later retrieval by the application.
1537 	 */
1538 	tdsdump_log(TDS_DBG_FUNC, "SQLAllocHandle(): invalid HandleType, error HY092: should be caught by DM\n");
1539 	return SQL_ERROR;
1540 }
1541 #endif
1542 
1543 static SQLRETURN
_SQLAllocConnect(SQLHENV henv,SQLHDBC FAR * phdbc)1544 _SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1545 {
1546 	TDS_DBC *dbc;
1547 
1548 	ODBC_ENTER_HENV;
1549 
1550 	tdsdump_log(TDS_DBG_FUNC, "_SQLAllocConnect(%p, %p)\n", henv, phdbc);
1551 
1552 	dbc = tds_new0(TDS_DBC, 1);
1553 	if (!dbc) {
1554 		odbc_errs_add(&env->errs, "HY001", NULL);
1555 		ODBC_EXIT_(env);
1556 	}
1557 
1558 	dbc->htype = SQL_HANDLE_DBC;
1559 	dbc->env = env;
1560 	tds_dstr_init(&dbc->dsn);
1561 
1562 	dbc->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1563 	dbc->attr.access_mode = SQL_MODE_READ_WRITE;
1564 	dbc->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1565 	dbc->attr.auto_ipd = SQL_FALSE;
1566 	/*
1567 	 * spinellia@acm.org
1568 	 * after login is enabled autocommit
1569 	 */
1570 	dbc->attr.autocommit = SQL_AUTOCOMMIT_ON;
1571 	dbc->attr.connection_dead = SQL_CD_TRUE;	/* No connection yet */
1572 	dbc->attr.connection_timeout = 0;
1573 	/* This is set in the environment change function */
1574 	tds_dstr_init(&dbc->attr.current_catalog);
1575 	dbc->attr.login_timeout = 0;	/* TODO */
1576 	dbc->attr.metadata_id = SQL_FALSE;
1577 	dbc->attr.odbc_cursors = SQL_CUR_USE_IF_NEEDED;
1578 	dbc->attr.packet_size = 0;
1579 	dbc->attr.quite_mode = NULL;	/* We don't support GUI dialogs yet */
1580 #ifdef TDS_NO_DM
1581 	dbc->attr.trace = SQL_OPT_TRACE_OFF;
1582 	tds_dstr_init(&dbc->attr.tracefile);
1583 #endif
1584 	tds_dstr_init(&dbc->attr.translate_lib);
1585 #ifdef ENABLE_ODBC_WIDE
1586 	tds_dstr_init(&dbc->original_charset);
1587 #endif
1588 	tds_dstr_init(&dbc->oldpwd);
1589 	dbc->attr.translate_option = 0;
1590 	dbc->attr.txn_isolation = SQL_TXN_READ_COMMITTED;
1591 	dbc->attr.mars_enabled = SQL_MARS_ENABLED_NO;
1592 	dbc->attr.bulk_enabled = SQL_BCP_OFF;
1593 
1594 	tds_mutex_init(&dbc->mtx);
1595 	*phdbc = (SQLHDBC) dbc;
1596 
1597 	ODBC_EXIT_(env);
1598 }
1599 
1600 SQLRETURN ODBC_PUBLIC ODBC_API
SQLAllocConnect(SQLHENV henv,SQLHDBC FAR * phdbc)1601 SQLAllocConnect(SQLHENV henv, SQLHDBC FAR * phdbc)
1602 {
1603 	tdsdump_log(TDS_DBG_FUNC, "SQLAllocConnect(%p, %p)\n", henv, phdbc);
1604 
1605 	return _SQLAllocConnect(henv, phdbc);
1606 }
1607 
1608 static SQLRETURN
_SQLAllocEnv(SQLHENV FAR * phenv,SQLINTEGER odbc_version)1609 _SQLAllocEnv(SQLHENV FAR * phenv, SQLINTEGER odbc_version)
1610 {
1611 	TDS_ENV *env;
1612 	TDSCONTEXT *ctx;
1613 
1614 	tdsdump_log(TDS_DBG_FUNC, "_SQLAllocEnv(%p, %d)\n",
1615 			phenv, (int) odbc_version);
1616 
1617 	env = tds_new0(TDS_ENV, 1);
1618 	if (!env)
1619 		return SQL_ERROR;
1620 
1621 	env->htype = SQL_HANDLE_ENV;
1622 	env->attr.odbc_version = odbc_version;
1623 	/* TODO use it */
1624 	env->attr.output_nts = SQL_TRUE;
1625 
1626 	ctx = tds_alloc_context(env);
1627 	if (!ctx) {
1628 		free(env);
1629 		return SQL_ERROR;
1630 	}
1631 	env->tds_ctx = ctx;
1632 	ctx->msg_handler = odbc_errmsg_handler;
1633 	ctx->err_handler = odbc_errmsg_handler;
1634 
1635 	/* ODBC has its own format */
1636 	free(ctx->locale->date_fmt);
1637 	ctx->locale->date_fmt = strdup("%Y-%m-%d %H:%M:%S.%z");
1638 
1639 	tds_mutex_init(&env->mtx);
1640 	*phenv = (SQLHENV) env;
1641 
1642 	return SQL_SUCCESS;
1643 }
1644 
1645 SQLRETURN ODBC_PUBLIC ODBC_API
SQLAllocEnv(SQLHENV FAR * phenv)1646 SQLAllocEnv(SQLHENV FAR * phenv)
1647 {
1648 	tdsdump_log(TDS_DBG_FUNC, "SQLAllocEnv(%p)\n", phenv);
1649 
1650 	return _SQLAllocEnv(phenv, SQL_OV_ODBC2);
1651 }
1652 
1653 static SQLRETURN
_SQLAllocDesc(SQLHDBC hdbc,SQLHDESC FAR * phdesc)1654 _SQLAllocDesc(SQLHDBC hdbc, SQLHDESC FAR * phdesc)
1655 {
1656 	int i;
1657 
1658 	ODBC_ENTER_HDBC;
1659 
1660 	tdsdump_log(TDS_DBG_FUNC, "_SQLAllocDesc(%p, %p)\n", hdbc, phdesc);
1661 
1662 	for (i = 0; ; ++i) {
1663 		if (i >= TDS_MAX_APP_DESC) {
1664 			odbc_errs_add(&dbc->errs, "HY014", NULL);
1665 			break;
1666 		}
1667 		if (dbc->uad[i] == NULL) {
1668 			TDS_DESC *desc = desc_alloc(dbc, DESC_ARD, SQL_DESC_ALLOC_USER);
1669 			if (desc == NULL) {
1670 				odbc_errs_add(&dbc->errs, "HY001", NULL);
1671 				break;
1672 			}
1673 			dbc->uad[i] = desc;
1674 			*phdesc = (SQLHDESC) desc;
1675 			break;
1676 		}
1677 	}
1678 	ODBC_EXIT_(dbc);
1679 }
1680 
1681 static SQLRETURN
_SQLAllocStmt(SQLHDBC hdbc,SQLHSTMT FAR * phstmt)1682 _SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
1683 {
1684 	TDS_STMT *stmt;
1685 	char *pstr;
1686 
1687 	ODBC_ENTER_HDBC;
1688 
1689 	tdsdump_log(TDS_DBG_FUNC, "_SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1690 
1691 	stmt = tds_new0(TDS_STMT, 1);
1692 	if (!stmt) {
1693 		odbc_errs_add(&dbc->errs, "HY001", NULL);
1694 		ODBC_EXIT_(dbc);
1695 	}
1696 	tds_dstr_init(&stmt->cursor_name);
1697 	tds_dstr_init(&stmt->query);
1698 
1699 	stmt->htype = SQL_HANDLE_STMT;
1700 	stmt->dbc = dbc;
1701 	stmt->num_param_rows = 1;
1702 	pstr = NULL;
1703 	/* TODO test initial cursor ... */
1704         if (asprintf(&pstr, "SQL_CUR%p", stmt) < 0
1705             ||  !tds_dstr_set(&stmt->cursor_name, pstr)) {
1706 		free(stmt);
1707 		free(pstr);
1708 		odbc_errs_add(&dbc->errs, "HY001", NULL);
1709 		ODBC_EXIT_(dbc);
1710 	}
1711 	/* do not free pstr tds_dstr_set do it if necessary */
1712 
1713 	/* allocate descriptors */
1714 	stmt->ird = desc_alloc(stmt, DESC_IRD, SQL_DESC_ALLOC_AUTO);
1715 	stmt->ard = desc_alloc(stmt, DESC_ARD, SQL_DESC_ALLOC_AUTO);
1716 	stmt->ipd = desc_alloc(stmt, DESC_IPD, SQL_DESC_ALLOC_AUTO);
1717 	stmt->apd = desc_alloc(stmt, DESC_APD, SQL_DESC_ALLOC_AUTO);
1718 	if (!stmt->ird || !stmt->ard || !stmt->ipd || !stmt->apd) {
1719 		tds_dstr_free(&stmt->cursor_name);
1720 		desc_free(stmt->ird);
1721 		desc_free(stmt->ard);
1722 		desc_free(stmt->ipd);
1723 		desc_free(stmt->apd);
1724 		free(stmt);
1725 		odbc_errs_add(&dbc->errs, "HY001", NULL);
1726 		ODBC_EXIT_(dbc);
1727 	}
1728 
1729 	/* save original ARD and APD */
1730 	stmt->orig_apd = stmt->apd;
1731 	stmt->orig_ard = stmt->ard;
1732 
1733 	/* set the default statement attributes */
1734 /*	stmt->attr.app_param_desc = stmt->apd; */
1735 /*	stmt->attr.app_row_desc = stmt->ard; */
1736 	stmt->attr.async_enable = SQL_ASYNC_ENABLE_OFF;
1737 	stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
1738 	stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
1739 	stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
1740 	stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
1741 	/* TODO ?? why two attributes */
1742 	stmt->attr.enable_auto_ipd = dbc->attr.auto_ipd = SQL_FALSE;
1743 	stmt->attr.fetch_bookmark_ptr = NULL;
1744 /*	stmt->attr.imp_param_desc = stmt->ipd; */
1745 /*	stmt->attr.imp_row_desc = stmt->ird; */
1746 	stmt->attr.keyset_size = 0;
1747 	stmt->attr.max_length = 0;
1748 	stmt->attr.max_rows = 0;
1749 	stmt->attr.metadata_id = dbc->attr.metadata_id;
1750 	/* TODO check this flag in prepare_call */
1751 	stmt->attr.noscan = SQL_NOSCAN_OFF;
1752 	assert(stmt->apd->header.sql_desc_bind_offset_ptr == NULL);
1753 	assert(stmt->apd->header.sql_desc_bind_type == SQL_PARAM_BIND_BY_COLUMN);
1754 	assert(stmt->apd->header.sql_desc_array_status_ptr == NULL);
1755 	assert(stmt->ipd->header.sql_desc_array_status_ptr == NULL);
1756 	assert(stmt->ipd->header.sql_desc_rows_processed_ptr == NULL);
1757 	assert(stmt->apd->header.sql_desc_array_size == 1);
1758 	stmt->attr.query_timeout = DEFAULT_QUERY_TIMEOUT;
1759 	stmt->attr.retrieve_data = SQL_RD_ON;
1760 	assert(stmt->ard->header.sql_desc_array_size == 1);
1761 	assert(stmt->ard->header.sql_desc_bind_offset_ptr == NULL);
1762 	assert(stmt->ard->header.sql_desc_bind_type == SQL_BIND_BY_COLUMN);
1763 	stmt->attr.row_number = 0;
1764 	assert(stmt->ard->header.sql_desc_array_status_ptr == NULL);
1765 	assert(stmt->ird->header.sql_desc_array_status_ptr == NULL);
1766 	assert(stmt->ird->header.sql_desc_rows_processed_ptr == NULL);
1767 	stmt->attr.simulate_cursor = SQL_SC_NON_UNIQUE;
1768 	stmt->attr.use_bookmarks = SQL_UB_OFF;
1769 	tds_dstr_init(&stmt->attr.qn_msgtext);
1770 	tds_dstr_init(&stmt->attr.qn_options);
1771 	stmt->attr.qn_timeout = 432000;
1772 
1773 	stmt->sql_rowset_size = 1;
1774 
1775 	stmt->row_count = TDS_NO_COUNT;
1776 	stmt->row_status = NOT_IN_ROW;
1777 
1778 	/* insert into list */
1779 	stmt->next = dbc->stmt_list;
1780 	if (dbc->stmt_list)
1781 		dbc->stmt_list->prev = stmt;
1782 	dbc->stmt_list = stmt;
1783 
1784 	tds_mutex_init(&stmt->mtx);
1785 	*phstmt = (SQLHSTMT) stmt;
1786 
1787 	if (dbc->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY)
1788 		_SQLSetStmtAttr(stmt, SQL_CURSOR_TYPE, (SQLPOINTER) (TDS_INTPTR) dbc->attr.cursor_type, SQL_IS_INTEGER _wide0);
1789 
1790 	ODBC_EXIT_(dbc);
1791 }
1792 
1793 SQLRETURN ODBC_PUBLIC ODBC_API
SQLAllocStmt(SQLHDBC hdbc,SQLHSTMT FAR * phstmt)1794 SQLAllocStmt(SQLHDBC hdbc, SQLHSTMT FAR * phstmt)
1795 {
1796 	tdsdump_log(TDS_DBG_FUNC, "SQLAllocStmt(%p, %p)\n", hdbc, phstmt);
1797 
1798 	return _SQLAllocStmt(hdbc, phstmt);
1799 }
1800 
1801 SQLRETURN ODBC_PUBLIC ODBC_API
SQLBindCol(SQLHSTMT hstmt,SQLUSMALLINT icol,SQLSMALLINT fCType,SQLPOINTER rgbValue,SQLLEN cbValueMax,SQLLEN FAR * pcbValue)1802 SQLBindCol(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
1803 {
1804 	TDS_DESC *ard;
1805 	struct _drecord *drec;
1806 	SQLSMALLINT orig_ard_size;
1807 
1808 	ODBC_ENTER_HSTMT;
1809 
1810 	tdsdump_log(TDS_DBG_FUNC, "SQLBindCol(%p, %d, %d, %p, %d, %p)\n",
1811 			hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
1812 
1813 	/* TODO - More error checking XXX smurph */
1814 
1815 #ifdef TDS_NO_DM
1816 	/* check conversion type */
1817 	switch (fCType) {
1818 	case SQL_C_CHAR:
1819 	case SQL_C_WCHAR:
1820 	case SQL_C_BINARY:
1821 	case SQL_C_DEFAULT:
1822 		/* check max buffer length */
1823 		if (!IS_VALID_LEN(cbValueMax)) {
1824 			odbc_errs_add(&stmt->errs, "HY090", NULL);
1825 			ODBC_EXIT_(stmt);
1826 		}
1827 		break;
1828 	}
1829 #endif
1830 
1831 	if (icol <= 0 || icol > 4000) {
1832 		odbc_errs_add(&stmt->errs, "07009", NULL);
1833 		ODBC_EXIT_(stmt);
1834 	}
1835 
1836 	ard = stmt->ard;
1837 	orig_ard_size = ard->header.sql_desc_count;
1838 	if (icol > ard->header.sql_desc_count && desc_alloc_records(ard, icol) != SQL_SUCCESS) {
1839 		odbc_errs_add(&stmt->errs, "HY001", NULL);
1840 		ODBC_EXIT_(stmt);
1841 	}
1842 
1843 	drec = &ard->records[icol - 1];
1844 
1845 	if (odbc_set_concise_c_type(fCType, drec, 0) != SQL_SUCCESS) {
1846 		desc_alloc_records(ard, orig_ard_size);
1847 		odbc_errs_add(&stmt->errs, "HY003", NULL);
1848 		ODBC_EXIT_(stmt);
1849 	}
1850 	drec->sql_desc_octet_length = cbValueMax;
1851 	drec->sql_desc_octet_length_ptr = pcbValue;
1852 	drec->sql_desc_indicator_ptr = pcbValue;
1853 	drec->sql_desc_data_ptr = rgbValue;
1854 
1855 	/* force rebind */
1856 	stmt->row = 0;
1857 
1858 	ODBC_EXIT_(stmt);
1859 }
1860 
1861 SQLRETURN ODBC_PUBLIC ODBC_API
SQLCancel(SQLHSTMT hstmt)1862 SQLCancel(SQLHSTMT hstmt)
1863 {
1864 	TDSSOCKET *tds;
1865 
1866 	/*
1867 	 * FIXME this function can be called from other thread, do not free
1868 	 * errors for this function
1869 	 * If function is called from another thread errors are not touched
1870 	 */
1871 	/* TODO some tests required */
1872 	TDS_STMT *stmt = (TDS_STMT*)hstmt;
1873 	if (SQL_NULL_HSTMT == hstmt || !IS_HSTMT(hstmt))
1874 		return SQL_INVALID_HANDLE;
1875 
1876 	tdsdump_log(TDS_DBG_FUNC, "SQLCancel(%p)\n", hstmt);
1877 
1878         tds_mutex_lock(&stmt->dbc->mtx);
1879 	tds = stmt->tds;
1880         tds_mutex_unlock(&stmt->dbc->mtx);
1881 
1882 	/* cancelling an inactive statement ?? */
1883 	if (!tds) {
1884 		ODBC_SAFE_ERROR(stmt);
1885 		ODBC_EXIT_(stmt);
1886 	}
1887 	if (tds_mutex_trylock(&stmt->mtx) == 0) {
1888 		CHECK_STMT_EXTRA(stmt);
1889 		odbc_errs_reset(&stmt->errs);
1890 
1891 		/* FIXME test current statement */
1892 		/* FIXME here we are unlocked */
1893 
1894 		if (TDS_FAILED(tds_send_cancel(tds))) {
1895 			ODBC_SAFE_ERROR(stmt);
1896 			ODBC_EXIT_(stmt);
1897 		}
1898 
1899 		if (TDS_FAILED(tds_process_cancel(tds))) {
1900 			ODBC_SAFE_ERROR(stmt);
1901 			ODBC_EXIT_(stmt);
1902 		}
1903 
1904 		/* only if we processed cancel reset statement */
1905 		if (tds->state == TDS_IDLE)
1906 			odbc_unlock_statement(stmt);
1907 
1908 		ODBC_EXIT_(stmt);
1909 	}
1910 
1911 	/* don't access error here, just return error */
1912 	if (TDS_FAILED(tds_send_cancel(tds)))
1913 		return SQL_ERROR;
1914 	return SQL_SUCCESS;
1915 }
1916 
1917 ODBC_FUNC(SQLConnect, (P(SQLHDBC,hdbc), PCHARIN(DSN,SQLSMALLINT), PCHARIN(UID,SQLSMALLINT),
1918 	PCHARIN(AuthStr,SQLSMALLINT) WIDE))
1919 {
1920 	TDSLOGIN *login;
1921 	DSTR *s;
1922 
1923 	ODBC_ENTER_HDBC;
1924 
1925 #ifdef TDS_NO_DM
1926 	if (szDSN && !IS_VALID_LEN(cbDSN)) {
1927 		odbc_errs_add(&dbc->errs, "HY090", "Invalid DSN buffer length");
1928 		ODBC_EXIT_(dbc);
1929 	}
1930 
1931 	if (szUID && !IS_VALID_LEN(cbUID)) {
1932 		odbc_errs_add(&dbc->errs, "HY090", "Invalid UID buffer length");
1933 		ODBC_EXIT_(dbc);
1934 	}
1935 
1936 	if (szAuthStr && !IS_VALID_LEN(cbAuthStr)) {
1937 		odbc_errs_add(&dbc->errs, "HY090", "Invalid PWD buffer length");
1938 		ODBC_EXIT_(dbc);
1939 	}
1940 #endif
1941 
1942 	login = tds_alloc_login(0);
1943 	if (!login || !tds_init_login(login, dbc->env->tds_ctx->locale))
1944 		goto memory_error;
1945 
1946 	/* data source name */
1947 	if (odbc_get_string_size(cbDSN, szDSN _wide))
1948 		s = odbc_dstr_copy(dbc, &dbc->dsn, cbDSN, szDSN);
1949 	else
1950 		s = tds_dstr_copy(&dbc->dsn, "DEFAULT");
1951 	if (!s)
1952 		goto memory_error;
1953 
1954 
1955 	if (!odbc_get_dsn_info(&dbc->errs, tds_dstr_cstr(&dbc->dsn), login)) {
1956 		tds_free_login(login);
1957 		ODBC_EXIT_(dbc);
1958 	}
1959 
1960 	if (!tds_dstr_isempty(&dbc->attr.current_catalog))
1961 		if (!tds_dstr_dup(&login->database, &dbc->attr.current_catalog))
1962 			goto memory_error;
1963 
1964 	/*
1965 	 * username/password are never saved to ini file,
1966 	 * so you do not check in ini file
1967 	 */
1968 	/* user id */
1969 	if (odbc_get_string_size(cbUID, szUID _wide)) {
1970 		if (!odbc_dstr_copy(dbc, &login->user_name, cbUID, szUID))
1971 			goto memory_error;
1972 	}
1973 
1974 	/* password */
1975 	if (szAuthStr && !tds_dstr_isempty(&login->user_name)) {
1976 		if (!odbc_dstr_copy(dbc, &login->password, cbAuthStr, szAuthStr))
1977 			goto memory_error;
1978 	}
1979 
1980 	/* DO IT */
1981 	odbc_connect(dbc, login);
1982 
1983 	tds_free_login(login);
1984 	ODBC_EXIT_(dbc);
1985 
1986 memory_error:
1987 	tds_free_login(login);
1988 	odbc_errs_add(&dbc->errs, "HY001", NULL);
1989 	ODBC_EXIT_(dbc);
1990 }
1991 
1992 ODBC_FUNC(SQLDescribeCol, (P(SQLHSTMT,hstmt), P(SQLUSMALLINT,icol), PCHAROUT(ColName,SQLSMALLINT),
1993 	P(SQLSMALLINT FAR *,pfSqlType), P(SQLULEN FAR *,pcbColDef),
1994 	P(SQLSMALLINT FAR *,pibScale), P(SQLSMALLINT FAR *,pfNullable) WIDE))
1995 {
1996 	TDS_DESC *ird;
1997 	struct _drecord *drec;
1998 	SQLRETURN result;
1999 
2000 	ODBC_ENTER_HSTMT;
2001 
2002 	ird = stmt->ird;
2003 	IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2004 
2005 	if (icol <= 0 || icol > ird->header.sql_desc_count) {
2006 		odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2007 		ODBC_EXIT_(stmt);
2008 	}
2009 	/* check name length */
2010 	if (cbColNameMax < 0) {
2011 		odbc_errs_add(&stmt->errs, "HY090", NULL);
2012 		ODBC_EXIT_(stmt);
2013 	}
2014 	drec = &ird->records[icol - 1];
2015 
2016 	/* cbColNameMax can be 0 (to retrieve name length) */
2017 	if (szColName == NULL)
2018 		cbColNameMax = 0;
2019 
2020 	/* straight copy column name up to cbColNameMax */
2021 	result = odbc_set_string(stmt->dbc, szColName, cbColNameMax, pcbColName, tds_dstr_cstr(&drec->sql_desc_label), -1);
2022 	if (szColName && result == SQL_SUCCESS_WITH_INFO)
2023 		odbc_errs_add(&stmt->errs, "01004", NULL);
2024 
2025 	if (pfSqlType) {
2026 		/* TODO sure ? check documentation for date and intervals */
2027 		*pfSqlType = drec->sql_desc_concise_type;
2028 	}
2029 
2030 	if (pcbColDef) {
2031 		if (drec->sql_desc_type == SQL_NUMERIC || drec->sql_desc_type == SQL_DECIMAL) {
2032 			*pcbColDef = drec->sql_desc_precision;
2033 		} else {
2034 			*pcbColDef = drec->sql_desc_length;
2035 		}
2036 	}
2037 	if (pibScale) {
2038 		*pibScale = drec->sql_desc_scale;
2039 	}
2040 	if (pfNullable) {
2041 		*pfNullable = drec->sql_desc_nullable;
2042 	}
2043 	ODBC_EXIT_(stmt);
2044 }
2045 
2046 static SQLRETURN
_SQLColAttribute(SQLHSTMT hstmt,SQLUSMALLINT icol,SQLUSMALLINT fDescType,SQLPOINTER rgbDesc,SQLSMALLINT cbDescMax,SQLSMALLINT FAR * pcbDesc,SQLLEN FAR * pfDesc _WIDE)2047 _SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax,
2048 		 SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc _WIDE)
2049 {
2050 	TDS_DESC *ird;
2051 	struct _drecord *drec;
2052 	SQLRETURN result = SQL_SUCCESS;
2053 
2054 	ODBC_ENTER_HSTMT;
2055 
2056 	tdsdump_log(TDS_DBG_FUNC, "_SQLColAttribute(%p, %u, %u, %p, %d, %p, %p)\n",
2057 			hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2058 
2059 	ird = stmt->ird;
2060 
2061 #define COUT(src) result = odbc_set_string_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, src ? src : "", -1);
2062 #define SOUT(src) result = odbc_set_string_oct(stmt->dbc, rgbDesc, cbDescMax, pcbDesc, tds_dstr_cstr(&src), -1);
2063 
2064 /* SQLColAttribute returns always attributes using SQLINTEGER */
2065 #if ENABLE_EXTRA_CHECKS
2066 #define IOUT(type, src) do { \
2067 	/* trick warning if type wrong */ \
2068 	type *p_test = &src; p_test = p_test; \
2069 	*pfDesc = src; } while(0)
2070 #else
2071 #define IOUT(type, src) *pfDesc = src
2072 #endif
2073 
2074 	IRD_UPDATE(ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
2075 
2076 	/* dont check column index for these */
2077 	switch (fDescType) {
2078 #if SQL_COLUMN_COUNT != SQL_DESC_COUNT
2079 	case SQL_COLUMN_COUNT:
2080 #endif
2081 	case SQL_DESC_COUNT:
2082 		IOUT(SQLSMALLINT, ird->header.sql_desc_count);
2083 		ODBC_EXIT(stmt, SQL_SUCCESS);
2084 		break;
2085 	}
2086 
2087 	if (!ird->header.sql_desc_count) {
2088 		odbc_errs_add(&stmt->errs, "07005", NULL);
2089 		ODBC_EXIT_(stmt);
2090 	}
2091 
2092 	if (icol <= 0 || icol > ird->header.sql_desc_count) {
2093 		odbc_errs_add(&stmt->errs, "07009", "Column out of range");
2094 		ODBC_EXIT_(stmt);
2095 	}
2096 	drec = &ird->records[icol - 1];
2097 
2098 	tdsdump_log(TDS_DBG_INFO1, "SQLColAttribute: fDescType is %d\n", fDescType);
2099 
2100 	switch (fDescType) {
2101 	case SQL_DESC_AUTO_UNIQUE_VALUE:
2102 		IOUT(SQLUINTEGER, drec->sql_desc_auto_unique_value);
2103 		break;
2104 	case SQL_DESC_BASE_COLUMN_NAME:
2105 		SOUT(drec->sql_desc_base_column_name);
2106 		break;
2107 	case SQL_DESC_BASE_TABLE_NAME:
2108 		SOUT(drec->sql_desc_base_table_name);
2109 		break;
2110 	case SQL_DESC_CASE_SENSITIVE:
2111 		IOUT(SQLINTEGER, drec->sql_desc_case_sensitive);
2112 		break;
2113 	case SQL_DESC_CATALOG_NAME:
2114 		SOUT(drec->sql_desc_catalog_name);
2115 		break;
2116 #if SQL_COLUMN_TYPE != SQL_DESC_CONCISE_TYPE
2117 	case SQL_COLUMN_TYPE:
2118 #endif
2119 	case SQL_DESC_CONCISE_TYPE:
2120 		/* special case, get ODBC 2 type, not ODBC 3 SQL_DESC_CONCISE_TYPE (different for datetime) */
2121 		if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
2122 			IOUT(SQLSMALLINT, drec->sql_desc_concise_type);
2123 			break;
2124 		}
2125 
2126 		/* get type and convert it to ODBC 2 type */
2127 		{
2128 			SQLSMALLINT type = drec->sql_desc_concise_type;
2129 
2130 			switch (type) {
2131 			case SQL_TYPE_DATE:
2132 				type = SQL_DATE;
2133 				break;
2134 			case SQL_TYPE_TIME:
2135 				type = SQL_TIME;
2136 				break;
2137 			case SQL_TYPE_TIMESTAMP:
2138 				type = SQL_TIMESTAMP;
2139 				break;
2140 			}
2141 			IOUT(SQLSMALLINT, type);
2142 		}
2143 		break;
2144 	case SQL_DESC_DISPLAY_SIZE:
2145 		IOUT(SQLLEN, drec->sql_desc_display_size);
2146 		break;
2147 	case SQL_DESC_FIXED_PREC_SCALE:
2148 		IOUT(SQLSMALLINT, drec->sql_desc_fixed_prec_scale);
2149 		break;
2150 	case SQL_DESC_LABEL:
2151 		SOUT(drec->sql_desc_label);
2152 		break;
2153 		/* FIXME special cases for SQL_COLUMN_LENGTH */
2154 	case SQL_COLUMN_LENGTH:
2155 		IOUT(SQLLEN, drec->sql_desc_octet_length);
2156 		break;
2157 	case SQL_DESC_LENGTH:
2158 		IOUT(SQLULEN, drec->sql_desc_length);
2159 		break;
2160 	case SQL_DESC_LITERAL_PREFIX:
2161 		COUT(drec->sql_desc_literal_prefix);
2162 		break;
2163 	case SQL_DESC_LITERAL_SUFFIX:
2164 		COUT(drec->sql_desc_literal_suffix);
2165 		break;
2166 	case SQL_DESC_LOCAL_TYPE_NAME:
2167 		SOUT(drec->sql_desc_local_type_name);
2168 		break;
2169 #if SQL_COLUMN_NAME != SQL_DESC_NAME
2170 	case SQL_COLUMN_NAME:
2171 #endif
2172 	case SQL_DESC_NAME:
2173 		SOUT(drec->sql_desc_name);
2174 		break;
2175 #if SQL_COLUMN_NULLABLE != SQL_DESC_NULLABLE
2176 	case SQL_COLUMN_NULLABLE:
2177 #endif
2178 	case SQL_DESC_NULLABLE:
2179 		IOUT(SQLSMALLINT, drec->sql_desc_nullable);
2180 		break;
2181 	case SQL_DESC_NUM_PREC_RADIX:
2182 		IOUT(SQLINTEGER, drec->sql_desc_num_prec_radix);
2183 		break;
2184 	case SQL_DESC_OCTET_LENGTH:
2185 		IOUT(SQLLEN, drec->sql_desc_octet_length);
2186 		break;
2187 		/* FIXME special cases for SQL_COLUMN_PRECISION */
2188 	case SQL_COLUMN_PRECISION:
2189 		if (drec->sql_desc_concise_type == SQL_REAL) {
2190 			*pfDesc = 7;
2191 			break;
2192 		}
2193 		if (drec->sql_desc_concise_type == SQL_DOUBLE) {
2194 			*pfDesc = 15;
2195 			break;
2196 		}
2197 		if (drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP || drec->sql_desc_concise_type == SQL_TIMESTAMP) {
2198 			*pfDesc = drec->sql_desc_precision ? 23 : 16;
2199 			break;
2200 		}
2201 	case SQL_DESC_PRECISION:	/* this section may be wrong */
2202 		if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2203 		    || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2204 		    || drec->sql_desc_concise_type == SQL_TYPE_DATE
2205 		    || drec->sql_desc_concise_type == SQL_TIMESTAMP
2206 		    || drec->sql_desc_concise_type == SQL_SS_TIME2
2207 		    || drec->sql_desc_concise_type == SQL_SS_TIMESTAMPOFFSET)
2208 			IOUT(SQLSMALLINT, drec->sql_desc_precision);
2209 		else
2210 			*pfDesc = drec->sql_desc_length;
2211 		break;
2212 		/* FIXME special cases for SQL_COLUMN_SCALE */
2213 	case SQL_COLUMN_SCALE:
2214 	case SQL_DESC_SCALE:	/* this section may be wrong */
2215 		if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2216 		    || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2217 		    || drec->sql_desc_concise_type == SQL_TYPE_DATE
2218 		    || drec->sql_desc_concise_type == SQL_TIMESTAMP
2219 		    || drec->sql_desc_concise_type == SQL_FLOAT
2220 		    || drec->sql_desc_concise_type == SQL_SS_TIME2
2221 		    || drec->sql_desc_concise_type == SQL_SS_TIMESTAMPOFFSET)
2222 			IOUT(SQLSMALLINT, drec->sql_desc_scale);
2223 		else
2224 			*pfDesc = 0;
2225 		break;
2226 	case SQL_DESC_SCHEMA_NAME:
2227 		SOUT(drec->sql_desc_schema_name);
2228 		break;
2229 	case SQL_DESC_SEARCHABLE:
2230 		IOUT(SQLSMALLINT, drec->sql_desc_searchable);
2231 		break;
2232 	case SQL_DESC_TABLE_NAME:
2233 		SOUT(drec->sql_desc_table_name);
2234 		break;
2235 	case SQL_DESC_TYPE:
2236 		IOUT(SQLSMALLINT, drec->sql_desc_type);
2237 		break;
2238 	case SQL_DESC_TYPE_NAME:
2239 		COUT(drec->sql_desc_type_name);
2240 		break;
2241 	case SQL_DESC_UNNAMED:
2242 		IOUT(SQLSMALLINT, drec->sql_desc_unnamed);
2243 		break;
2244 	case SQL_DESC_UNSIGNED:
2245 		IOUT(SQLSMALLINT, drec->sql_desc_unsigned);
2246 		break;
2247 	case SQL_DESC_UPDATABLE:
2248 		IOUT(SQLSMALLINT, drec->sql_desc_updatable);
2249 		break;
2250 	default:
2251 		tdsdump_log(TDS_DBG_INFO2, "SQLColAttribute: fDescType %d not catered for...\n", fDescType);
2252 		odbc_errs_add(&stmt->errs, "HY091", NULL);
2253 		ODBC_EXIT_(stmt);
2254 		break;
2255 	}
2256 
2257 	if (result == SQL_SUCCESS_WITH_INFO)
2258 		odbc_errs_add(&stmt->errs, "01004", NULL);
2259 
2260 	ODBC_EXIT(stmt, result);
2261 
2262 #undef COUT
2263 #undef SOUT
2264 #undef IOUT
2265 }
2266 
2267 SQLRETURN ODBC_PUBLIC ODBC_API
SQLColAttributes(SQLHSTMT hstmt,SQLUSMALLINT icol,SQLUSMALLINT fDescType,SQLPOINTER rgbDesc,SQLSMALLINT cbDescMax,SQLSMALLINT FAR * pcbDesc,SQLLEN FAR * pfDesc)2268 SQLColAttributes(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2269 		 SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc)
2270 {
2271 	tdsdump_log(TDS_DBG_FUNC, "SQLColAttributes(%p, %d, %d, %p, %d, %p, %p)\n",
2272 			hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2273 
2274 	return _SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc _wide0);
2275 }
2276 
2277 #if (ODBCVER >= 0x0300)
2278 SQLRETURN ODBC_PUBLIC ODBC_API
SQLColAttribute(SQLHSTMT hstmt,SQLUSMALLINT icol,SQLUSMALLINT fDescType,SQLPOINTER rgbDesc,SQLSMALLINT cbDescMax,SQLSMALLINT FAR * pcbDesc,SQLLEN FAR * pfDesc)2279 SQLColAttribute(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2280 		SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2281 #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2282 		SQLLEN FAR * pfDesc
2283 #else
2284 		SQLPOINTER pfDesc
2285 #endif
2286 	)
2287 {
2288 
2289         return _SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax,
2290                                 pcbDesc, (SQLLEN*) pfDesc _wide0);
2291 }
2292 
2293 #ifdef ENABLE_ODBC_WIDE
2294 SQLRETURN ODBC_PUBLIC ODBC_API
SQLColAttributeW(SQLHSTMT hstmt,SQLUSMALLINT icol,SQLUSMALLINT fDescType,SQLPOINTER rgbDesc,SQLSMALLINT cbDescMax,SQLSMALLINT FAR * pcbDesc,SQLLEN FAR * pfDesc)2295 SQLColAttributeW(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType,
2296 		SQLPOINTER rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc,
2297 #ifdef TDS_SQLCOLATTRIBUTE_SQLLEN
2298 		SQLLEN FAR * pfDesc
2299 #else
2300 		SQLPOINTER pfDesc
2301 #endif
2302 	)
2303 {
2304 	tdsdump_log(TDS_DBG_FUNC, "SQLColAttributeW(%p, %u, %u, %p, %d, %p, %p)\n",
2305 			hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
2306 
2307 	return _SQLColAttribute(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc, 1);
2308 }
2309 #endif
2310 #endif
2311 
2312 SQLRETURN ODBC_PUBLIC ODBC_API
SQLDisconnect(SQLHDBC hdbc)2313 SQLDisconnect(SQLHDBC hdbc)
2314 {
2315 	int i;
2316         struct _hstmt *stmt, *next;
2317 
2318 	ODBC_ENTER_HDBC;
2319 
2320 	tdsdump_log(TDS_DBG_FUNC, "SQLDisconnect(%p)\n", hdbc);
2321 
2322 	/* free all associated statements */
2323         for (stmt = dbc->stmt_list;  stmt != NULL;  stmt = next) {
2324                 next = stmt->next;
2325 		tds_mutex_unlock(&dbc->mtx);
2326 		_SQLFreeStmt(stmt, SQL_DROP, 1);
2327 		tds_mutex_lock(&dbc->mtx);
2328 	}
2329 
2330 	/* free all associated descriptors */
2331 	for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
2332 		if (dbc->uad[i]) {
2333 			desc_free(dbc->uad[i]);
2334 			dbc->uad[i] = NULL;
2335 		}
2336 	}
2337 
2338 #ifdef ENABLE_ODBC_WIDE
2339 	dbc->mb_conv = NULL;
2340 #endif
2341 	tds_close_socket(dbc->tds_socket);
2342 	tds_free_socket(dbc->tds_socket);
2343 	dbc->tds_socket = NULL;
2344 	dbc->cursor_support = 0;
2345 
2346 	ODBC_EXIT_(dbc);
2347 }
2348 
2349 static int
odbc_errmsg_handler(const TDSCONTEXT * ctx,TDSSOCKET * tds,TDSMESSAGE * msg)2350 odbc_errmsg_handler(const TDSCONTEXT * ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
2351 {
2352 	struct _sql_errors *errs = NULL;
2353 	TDS_DBC *dbc = NULL;
2354 	TDS_STMT *stmt = NULL;
2355 
2356 	tdsdump_log(TDS_DBG_INFO1, "msgno %d %d\n", (int) msg->msgno, TDSETIME);
2357 
2358 	if (msg->msgno == TDSETIME) {
2359 
2360 		tdsdump_log(TDS_DBG_INFO1, "in timeout\n");
2361 		if (!tds)
2362 			return TDS_INT_CANCEL;
2363 
2364 		if ((stmt = odbc_get_stmt(tds)) != NULL) {
2365 			/* first time, try to send a cancel */
2366 			if (!tds->in_cancel) {
2367 				odbc_errs_add(&stmt->errs, "HYT00", "Timeout expired");
2368 				tdsdump_log(TDS_DBG_INFO1, "returning from timeout\n");
2369 				return TDS_INT_TIMEOUT;
2370 			}
2371 		} else if ((dbc = odbc_get_dbc(tds)) != NULL) {
2372 			odbc_errs_add(&dbc->errs, "HYT00", "Timeout expired");
2373 		}
2374 
2375 		tds_close_socket(tds);
2376 		tdsdump_log(TDS_DBG_INFO1, "returning cancel from timeout\n");
2377 		return TDS_INT_CANCEL;
2378 	}
2379 
2380 	if (tds && (dbc = odbc_get_dbc(tds)) != NULL) {
2381 		errs = &dbc->errs;
2382 		stmt = odbc_get_stmt(tds);
2383 		if (stmt)
2384 			errs = &stmt->errs;
2385 	} else if (ctx->parent) {
2386 		errs = &((TDS_ENV *) ctx->parent)->errs;
2387 	}
2388 	if (errs) {
2389 		int severity = msg->severity;
2390 		const char * state = msg->sql_state;
2391 
2392 		/* fix severity for Sybase */
2393 		if (severity <= 10 && dbc && !TDS_IS_MSSQL(dbc->tds_socket) && msg->sql_state && msg->sql_state[0]
2394 		    && strncmp(msg->sql_state, "00", 2) != 0) {
2395 			if (strncmp(msg->sql_state, "01", 2) != 0 && strncmp(msg->sql_state, "IM", 2) != 0)
2396 				severity = 11;
2397 		}
2398 
2399 		/* compute state if not available */
2400 		if (!state)
2401 			state = severity <= 10 ? "01000" : "42000";
2402 		/* add error, do not overwrite connection timeout error */
2403 		if (msg->msgno != TDSEFCON || errs->lastrc != SQL_ERROR || errs->num_errors < 1)
2404 			odbc_errs_add_rdbms(errs, msg->msgno, state, msg->message, msg->line_number, msg->severity,
2405 					    msg->server, stmt ? stmt->curr_param_row + 1 : 0);
2406 
2407 		/* set lastc according */
2408 		if (severity <= 10) {
2409 			if (errs->lastrc == SQL_SUCCESS)
2410 				errs->lastrc = SQL_SUCCESS_WITH_INFO;
2411 		} else {
2412 			errs->lastrc = SQL_ERROR;
2413 		}
2414 	}
2415 	return TDS_INT_CANCEL;
2416 }
2417 
2418 /* TODO optimize, change only if some data change (set same value should not set this flag) */
2419 #define DESC_SET_NEED_REPREPARE \
2420 	do {\
2421 		if (desc->type == DESC_IPD) {\
2422 			assert(IS_HSTMT(desc->parent));\
2423 			((TDS_STMT *) desc->parent)->need_reprepare = 1;\
2424 		 }\
2425 	} while(0)
2426 
2427 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetDescRec(SQLHDESC hdesc,SQLSMALLINT nRecordNumber,SQLSMALLINT nType,SQLSMALLINT nSubType,SQLLEN nLength,SQLSMALLINT nPrecision,SQLSMALLINT nScale,SQLPOINTER pData,SQLLEN FAR * pnStringLength,SQLLEN FAR * pnIndicator)2428 SQLSetDescRec(SQLHDESC hdesc, SQLSMALLINT nRecordNumber, SQLSMALLINT nType, SQLSMALLINT nSubType, SQLLEN nLength,
2429 	      SQLSMALLINT nPrecision, SQLSMALLINT nScale, SQLPOINTER pData, SQLLEN FAR * pnStringLength, SQLLEN FAR * pnIndicator)
2430 {
2431 	struct _drecord *drec;
2432 	SQLSMALLINT concise_type;
2433 
2434 	ODBC_ENTER_HDESC;
2435 
2436 	tdsdump_log(TDS_DBG_FUNC, "SQLSetDescRec(%p, %d, %d, %d, %d, %d, %d, %p, %p, %p)\n",
2437 			hdesc, nRecordNumber, nType, nSubType, (int)nLength, nPrecision, nScale, pData, pnStringLength, pnIndicator);
2438 
2439 	if (desc->type == DESC_IRD) {
2440 		odbc_errs_add(&desc->errs, "HY016", NULL);
2441 		ODBC_EXIT_(desc);
2442 	}
2443 
2444 	if (nRecordNumber > desc->header.sql_desc_count || nRecordNumber <= 0) {
2445 		odbc_errs_add(&desc->errs, "07009", NULL);
2446 		ODBC_EXIT_(desc);
2447 	}
2448 
2449 	drec = &desc->records[nRecordNumber - 1];
2450 
2451 	/* check for valid types and return "HY021" if not */
2452 	if (desc->type == DESC_IPD) {
2453 		DESC_SET_NEED_REPREPARE;
2454 		concise_type = odbc_get_concise_sql_type(nType, nSubType);
2455 	} else {
2456 		concise_type = odbc_get_concise_c_type(nType, nSubType);
2457 	}
2458 	if (nType == SQL_INTERVAL || nType == SQL_DATETIME) {
2459 		if (!concise_type) {
2460 			odbc_errs_add(&desc->errs, "HY021", NULL);
2461 			ODBC_EXIT_(desc);
2462 		}
2463 	} else {
2464 		if (concise_type != nType) {
2465 			odbc_errs_add(&desc->errs, "HY021", NULL);
2466 			ODBC_EXIT_(desc);
2467 		}
2468 		nSubType = 0;
2469 	}
2470 	drec->sql_desc_concise_type = concise_type;
2471 	drec->sql_desc_type = nType;
2472 	drec->sql_desc_datetime_interval_code = nSubType;
2473 
2474 	drec->sql_desc_octet_length = nLength;
2475 	drec->sql_desc_precision = nPrecision;
2476 	drec->sql_desc_scale = nScale;
2477 	drec->sql_desc_data_ptr = pData;
2478 	drec->sql_desc_octet_length_ptr = pnStringLength;
2479 	drec->sql_desc_indicator_ptr = pnIndicator;
2480 
2481 	ODBC_EXIT_(desc);
2482 }
2483 
2484 ODBC_FUNC(SQLGetDescRec, (P(SQLHDESC,hdesc), P(SQLSMALLINT,RecordNumber), PCHAROUT(Name,SQLSMALLINT),
2485 	P(SQLSMALLINT *,Type), P(SQLSMALLINT *,SubType), P(SQLLEN FAR *,Length),
2486 	P(SQLSMALLINT *,Precision), P(SQLSMALLINT *,Scale), P(SQLSMALLINT *,Nullable) WIDE))
2487 {
2488 	struct _drecord *drec = NULL;
2489 	SQLRETURN rc = SQL_SUCCESS;
2490 
2491 	ODBC_ENTER_HDESC;
2492 
2493 	if (RecordNumber <= 0) {
2494 		odbc_errs_add(&desc->errs, "07009", NULL);
2495 		ODBC_EXIT_(desc);
2496 	}
2497 
2498 	IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2499 	if (RecordNumber > desc->header.sql_desc_count)
2500 		ODBC_EXIT(desc, SQL_NO_DATA);
2501 
2502 	if (desc->type == DESC_IRD && !desc->header.sql_desc_count) {
2503 		odbc_errs_add(&desc->errs, "HY007", NULL);
2504 		ODBC_EXIT_(desc);
2505 	}
2506 
2507 	drec = &desc->records[RecordNumber - 1];
2508 
2509 	if ((rc = odbc_set_string(desc_get_dbc(desc), szName, cbNameMax, pcbName, tds_dstr_cstr(&drec->sql_desc_name), -1)) != SQL_SUCCESS)
2510 		odbc_errs_add(&desc->errs, "01004", NULL);
2511 
2512 	if (Type)
2513 		*Type = drec->sql_desc_type;
2514 	if (Length)
2515 		*Length = drec->sql_desc_octet_length;
2516 	if (Precision)
2517 		*Precision = drec->sql_desc_precision;
2518 	if (Scale)
2519 		*Scale = drec->sql_desc_scale;
2520 	if (SubType)
2521 		*SubType = drec->sql_desc_datetime_interval_code;
2522 	if (Nullable)
2523 		*Nullable = drec->sql_desc_nullable;
2524 
2525 	ODBC_EXIT(desc, rc);
2526 }
2527 
2528 ODBC_FUNC(SQLGetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType), P(SQLPOINTER,Value),
2529 	P(SQLINTEGER,BufferLength), P(SQLINTEGER *,StringLength) WIDE))
2530 {
2531 	struct _drecord *drec;
2532 	SQLRETURN result = SQL_SUCCESS;
2533 
2534 	ODBC_ENTER_HDESC;
2535 
2536 #define COUT(src) result = odbc_set_string_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, src, -1);
2537 #define SOUT(src) result = odbc_set_string_oct(desc_get_dbc(desc), Value, BufferLength, StringLength, tds_dstr_cstr(&src), -1);
2538 
2539 #if ENABLE_EXTRA_CHECKS
2540 #define IOUT(type, src) do { \
2541 	/* trick warning if type wrong */ \
2542 	type *p_test = &src; p_test = p_test; \
2543 	*((type *)Value) = src; } while(0)
2544 #else
2545 #define IOUT(type, src) *((type *)Value) = src
2546 #endif
2547 
2548 	/* dont check column index for these */
2549 	switch (fDescType) {
2550 	case SQL_DESC_ALLOC_TYPE:
2551 		IOUT(SQLSMALLINT, desc->header.sql_desc_alloc_type);
2552 		ODBC_EXIT_(desc);
2553 		break;
2554 	case SQL_DESC_ARRAY_SIZE:
2555 		IOUT(SQLULEN, desc->header.sql_desc_array_size);
2556 		ODBC_EXIT_(desc);
2557 		break;
2558 	case SQL_DESC_ARRAY_STATUS_PTR:
2559 		IOUT(SQLUSMALLINT *, desc->header.sql_desc_array_status_ptr);
2560 		ODBC_EXIT_(desc);
2561 		break;
2562 	case SQL_DESC_BIND_OFFSET_PTR:
2563 		IOUT(SQLLEN *, desc->header.sql_desc_bind_offset_ptr);
2564 		ODBC_EXIT_(desc);
2565 		break;
2566 	case SQL_DESC_BIND_TYPE:
2567 		IOUT(SQLINTEGER, desc->header.sql_desc_bind_type);
2568 		ODBC_EXIT_(desc);
2569 		break;
2570 	case SQL_DESC_COUNT:
2571 		IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2572 		IOUT(SQLSMALLINT, desc->header.sql_desc_count);
2573 		ODBC_EXIT_(desc);
2574 		break;
2575 	case SQL_DESC_ROWS_PROCESSED_PTR:
2576 		IOUT(SQLULEN *, desc->header.sql_desc_rows_processed_ptr);
2577 		ODBC_EXIT_(desc);
2578 		break;
2579 	}
2580 
2581 	IRD_UPDATE(desc, &desc->errs, ODBC_EXIT(desc, SQL_ERROR));
2582 	if (!desc->header.sql_desc_count) {
2583 		odbc_errs_add(&desc->errs, "07005", NULL);
2584 		ODBC_EXIT_(desc);
2585 	}
2586 
2587 	if (icol < 1) {
2588 		odbc_errs_add(&desc->errs, "07009", "Column out of range");
2589 		ODBC_EXIT_(desc);
2590 	}
2591 	if (icol > desc->header.sql_desc_count)
2592 		ODBC_EXIT(desc, SQL_NO_DATA);
2593 	drec = &desc->records[icol - 1];
2594 
2595 	tdsdump_log(TDS_DBG_INFO1, "SQLGetDescField: fDescType is %d\n", fDescType);
2596 
2597 	switch (fDescType) {
2598 	case SQL_DESC_AUTO_UNIQUE_VALUE:
2599 		IOUT(SQLUINTEGER, drec->sql_desc_auto_unique_value);
2600 		break;
2601 	case SQL_DESC_BASE_COLUMN_NAME:
2602 		SOUT(drec->sql_desc_base_column_name);
2603 		break;
2604 	case SQL_DESC_BASE_TABLE_NAME:
2605 		SOUT(drec->sql_desc_base_table_name);
2606 		break;
2607 	case SQL_DESC_CASE_SENSITIVE:
2608 		IOUT(SQLINTEGER, drec->sql_desc_case_sensitive);
2609 		break;
2610 	case SQL_DESC_CATALOG_NAME:
2611 		SOUT(drec->sql_desc_catalog_name);
2612 		break;
2613 	case SQL_DESC_CONCISE_TYPE:
2614 		IOUT(SQLSMALLINT, drec->sql_desc_concise_type);
2615 		break;
2616 	case SQL_DESC_DATA_PTR:
2617 		IOUT(SQLPOINTER, drec->sql_desc_data_ptr);
2618 		break;
2619 	case SQL_DESC_DATETIME_INTERVAL_CODE:
2620 		IOUT(SQLSMALLINT, drec->sql_desc_datetime_interval_code);
2621 		break;
2622 	case SQL_DESC_DATETIME_INTERVAL_PRECISION:
2623 		IOUT(SQLINTEGER, drec->sql_desc_datetime_interval_precision);
2624 		break;
2625 	case SQL_DESC_DISPLAY_SIZE:
2626 		IOUT(SQLLEN, drec->sql_desc_display_size);
2627 		break;
2628 	case SQL_DESC_FIXED_PREC_SCALE:
2629 		IOUT(SQLSMALLINT, drec->sql_desc_fixed_prec_scale);
2630 		break;
2631 	case SQL_DESC_INDICATOR_PTR:
2632 		IOUT(SQLLEN *, drec->sql_desc_indicator_ptr);
2633 		break;
2634 	case SQL_DESC_LABEL:
2635 		SOUT(drec->sql_desc_label);
2636 		break;
2637 	case SQL_DESC_LENGTH:
2638 		IOUT(SQLULEN, drec->sql_desc_length);
2639 		break;
2640 	case SQL_DESC_LITERAL_PREFIX:
2641 		COUT(drec->sql_desc_literal_prefix);
2642 		break;
2643 	case SQL_DESC_LITERAL_SUFFIX:
2644 		COUT(drec->sql_desc_literal_suffix);
2645 		break;
2646 	case SQL_DESC_LOCAL_TYPE_NAME:
2647 		SOUT(drec->sql_desc_local_type_name);
2648 		break;
2649 	case SQL_DESC_NAME:
2650 		SOUT(drec->sql_desc_name);
2651 		break;
2652 	case SQL_DESC_NULLABLE:
2653 		IOUT(SQLSMALLINT, drec->sql_desc_nullable);
2654 		break;
2655 	case SQL_DESC_NUM_PREC_RADIX:
2656 		IOUT(SQLINTEGER, drec->sql_desc_num_prec_radix);
2657 		break;
2658 	case SQL_DESC_OCTET_LENGTH:
2659 		IOUT(SQLLEN, drec->sql_desc_octet_length);
2660 		break;
2661 	case SQL_DESC_OCTET_LENGTH_PTR:
2662 		IOUT(SQLLEN *, drec->sql_desc_octet_length_ptr);
2663 		break;
2664 	case SQL_DESC_PARAMETER_TYPE:
2665 		IOUT(SQLSMALLINT, drec->sql_desc_parameter_type);
2666 		break;
2667 	case SQL_DESC_PRECISION:
2668 		if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2669 		    || drec->sql_desc_concise_type == SQL_TIMESTAMP
2670 		    || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP)
2671 			IOUT(SQLSMALLINT, drec->sql_desc_precision);
2672 		else
2673 			/* TODO support date/time */
2674 			*((SQLSMALLINT *) Value) = 0;
2675 		break;
2676 #ifdef SQL_DESC_ROWVER
2677 	case SQL_DESC_ROWVER:
2678 		IOUT(SQLSMALLINT, drec->sql_desc_rowver);
2679 		break;
2680 #endif
2681 	case SQL_DESC_SCALE:
2682 		if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL
2683 		    || drec->sql_desc_concise_type == SQL_TYPE_TIMESTAMP
2684 		    || drec->sql_desc_concise_type == SQL_TIMESTAMP
2685 		    || drec->sql_desc_concise_type == SQL_FLOAT)
2686 			IOUT(SQLSMALLINT, drec->sql_desc_scale);
2687 		else
2688 			*((SQLSMALLINT *) Value) = 0;
2689 		break;
2690 	case SQL_DESC_SCHEMA_NAME:
2691 		SOUT(drec->sql_desc_schema_name);
2692 		break;
2693 	case SQL_DESC_SEARCHABLE:
2694 		IOUT(SQLSMALLINT, drec->sql_desc_searchable);
2695 		break;
2696 	case SQL_DESC_TABLE_NAME:
2697 		SOUT(drec->sql_desc_table_name);
2698 		break;
2699 	case SQL_DESC_TYPE:
2700 		IOUT(SQLSMALLINT, drec->sql_desc_type);
2701 		break;
2702 	case SQL_DESC_TYPE_NAME:
2703 		COUT(drec->sql_desc_type_name);
2704 		break;
2705 	case SQL_DESC_UNNAMED:
2706 		IOUT(SQLSMALLINT, drec->sql_desc_unnamed);
2707 		break;
2708 	case SQL_DESC_UNSIGNED:
2709 		IOUT(SQLSMALLINT, drec->sql_desc_unsigned);
2710 		break;
2711 	case SQL_DESC_UPDATABLE:
2712 		IOUT(SQLSMALLINT, drec->sql_desc_updatable);
2713 		break;
2714 	default:
2715 		odbc_errs_add(&desc->errs, "HY091", NULL);
2716 		ODBC_EXIT_(desc);
2717 		break;
2718 	}
2719 
2720 	if (result == SQL_SUCCESS_WITH_INFO)
2721 		odbc_errs_add(&desc->errs, "01004", NULL);
2722 
2723 	ODBC_EXIT(desc, result);
2724 
2725 #undef COUT
2726 #undef SOUT
2727 #undef IOUT
2728 }
2729 
2730 ODBC_FUNC(SQLSetDescField, (P(SQLHDESC,hdesc), P(SQLSMALLINT,icol), P(SQLSMALLINT,fDescType),
2731 	P(SQLPOINTER,Value), P(SQLINTEGER,BufferLength) WIDE))
2732 {
2733 	struct _drecord *drec;
2734 	SQLRETURN result = SQL_SUCCESS;
2735 
2736 	ODBC_ENTER_HDESC;
2737 
2738 #if ENABLE_EXTRA_CHECKS
2739 #define IIN(type, dest) do { \
2740 	/* trick warning if type wrong */ \
2741 	type *p_test = &dest; p_test = p_test; \
2742 	dest = (type)(TDS_INTPTR)Value; } while(0)
2743 #define PIN(type, dest) do { \
2744 	/* trick warning if type wrong */ \
2745 	type *p_test = &dest; p_test = p_test; \
2746 	dest = (type)Value; } while(0)
2747 #else
2748 #define IIN(type, dest) dest = (type)(TDS_INTPTR)Value
2749 #define PIN(type, dest) dest = (type)Value
2750 #endif
2751 
2752 	/* special case for IRD */
2753 	if (desc->type == DESC_IRD && fDescType != SQL_DESC_ARRAY_STATUS_PTR && fDescType != SQL_DESC_ROWS_PROCESSED_PTR) {
2754 		odbc_errs_add(&desc->errs, "HY016", NULL);
2755 		ODBC_EXIT_(desc);
2756 	}
2757 
2758 	/* dont check column index for these */
2759 	switch (fDescType) {
2760 	case SQL_DESC_ALLOC_TYPE:
2761 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2762 		ODBC_EXIT_(desc);
2763 		break;
2764 	case SQL_DESC_ARRAY_SIZE:
2765 		IIN(SQLULEN, desc->header.sql_desc_array_size);
2766 		ODBC_EXIT_(desc);
2767 		break;
2768 	case SQL_DESC_ARRAY_STATUS_PTR:
2769 		PIN(SQLUSMALLINT *, desc->header.sql_desc_array_status_ptr);
2770 		ODBC_EXIT_(desc);
2771 		break;
2772 	case SQL_DESC_ROWS_PROCESSED_PTR:
2773 		PIN(SQLULEN *, desc->header.sql_desc_rows_processed_ptr);
2774 		ODBC_EXIT_(desc);
2775 		break;
2776 	case SQL_DESC_BIND_TYPE:
2777 		IIN(SQLINTEGER, desc->header.sql_desc_bind_type);
2778 		ODBC_EXIT_(desc);
2779 		break;
2780 	case SQL_DESC_COUNT:
2781 		{
2782 			int n = (int) (TDS_INTPTR) Value;
2783 
2784 			if (n <= 0 || n > 4000) {
2785 				odbc_errs_add(&desc->errs, "07009", NULL);
2786 				ODBC_EXIT_(desc);
2787 			}
2788 			result = desc_alloc_records(desc, n);
2789 			if (result == SQL_ERROR)
2790 				odbc_errs_add(&desc->errs, "HY001", NULL);
2791 			ODBC_EXIT(desc, result);
2792 		}
2793 		break;
2794 	}
2795 
2796 	if (!desc->header.sql_desc_count) {
2797 		odbc_errs_add(&desc->errs, "07005", NULL);
2798 		ODBC_EXIT_(desc);
2799 	}
2800 
2801 	if (icol <= 0 || icol > desc->header.sql_desc_count) {
2802 		odbc_errs_add(&desc->errs, "07009", "Column out of range");
2803 		ODBC_EXIT_(desc);
2804 	}
2805 	drec = &desc->records[icol - 1];
2806 
2807 	tdsdump_log(TDS_DBG_INFO1, "SQLColAttributes: fDescType is %d\n", fDescType);
2808 
2809 	switch (fDescType) {
2810 	case SQL_DESC_AUTO_UNIQUE_VALUE:
2811 	case SQL_DESC_BASE_COLUMN_NAME:
2812 	case SQL_DESC_BASE_TABLE_NAME:
2813 	case SQL_DESC_CASE_SENSITIVE:
2814 	case SQL_DESC_CATALOG_NAME:
2815 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2816 		result = SQL_ERROR;
2817 		break;
2818 	case SQL_DESC_CONCISE_TYPE:
2819 		DESC_SET_NEED_REPREPARE;
2820 		if (desc->type == DESC_IPD)
2821 			result = odbc_set_concise_sql_type((SQLSMALLINT) (TDS_INTPTR) Value, drec, 0);
2822 		else
2823 			result = odbc_set_concise_c_type((SQLSMALLINT) (TDS_INTPTR) Value, drec, 0);
2824 		if (result != SQL_SUCCESS)
2825 			odbc_errs_add(&desc->errs, "HY021", NULL);
2826 		break;
2827 	case SQL_DESC_DATA_PTR:
2828 		PIN(SQLPOINTER, drec->sql_desc_data_ptr);
2829 		break;
2830 		/* TODO SQL_DESC_DATETIME_INTERVAL_CODE remember to check sql_desc_type */
2831 		/* TODO SQL_DESC_DATETIME_INTERVAL_PRECISION */
2832 	case SQL_DESC_DISPLAY_SIZE:
2833 	case SQL_DESC_FIXED_PREC_SCALE:
2834 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2835 		result = SQL_ERROR;
2836 		break;
2837 	case SQL_DESC_INDICATOR_PTR:
2838 		PIN(SQLLEN *, drec->sql_desc_indicator_ptr);
2839 		break;
2840 	case SQL_DESC_LABEL:
2841 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2842 		result = SQL_ERROR;
2843 		break;
2844 	case SQL_DESC_LENGTH:
2845 		DESC_SET_NEED_REPREPARE;
2846 		IIN(SQLULEN, drec->sql_desc_length);
2847 		break;
2848 	case SQL_DESC_LITERAL_PREFIX:
2849 	case SQL_DESC_LITERAL_SUFFIX:
2850 	case SQL_DESC_LOCAL_TYPE_NAME:
2851 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2852 		result = SQL_ERROR;
2853 		break;
2854 	case SQL_DESC_NAME:
2855 		if (!odbc_dstr_copy_oct(desc_get_dbc(desc), &drec->sql_desc_name, BufferLength, (ODBC_CHAR*) Value)) {
2856 			odbc_errs_add(&desc->errs, "HY001", NULL);
2857 			result = SQL_ERROR;
2858 		}
2859 		break;
2860 	case SQL_DESC_NULLABLE:
2861 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2862 		result = SQL_ERROR;
2863 		break;
2864 	case SQL_DESC_NUM_PREC_RADIX:
2865 		IIN(SQLINTEGER, drec->sql_desc_num_prec_radix);
2866 		break;
2867 	case SQL_DESC_OCTET_LENGTH:
2868 		DESC_SET_NEED_REPREPARE;
2869 		IIN(SQLLEN, drec->sql_desc_octet_length);
2870 		break;
2871 	case SQL_DESC_OCTET_LENGTH_PTR:
2872 		PIN(SQLLEN *, drec->sql_desc_octet_length_ptr);
2873 		break;
2874 	case SQL_DESC_PARAMETER_TYPE:
2875 		DESC_SET_NEED_REPREPARE;
2876 		IIN(SQLSMALLINT, drec->sql_desc_parameter_type);
2877 		break;
2878 	case SQL_DESC_PRECISION:
2879 		DESC_SET_NEED_REPREPARE;
2880 		/* TODO correct ?? */
2881 		if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL)
2882 			IIN(SQLSMALLINT, drec->sql_desc_precision);
2883 		else
2884 			IIN(SQLULEN, drec->sql_desc_length);
2885 		break;
2886 #ifdef SQL_DESC_ROWVER
2887 	case SQL_DESC_ROWVER:
2888 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2889 		result = SQL_ERROR;
2890 		break;
2891 #endif
2892 	case SQL_DESC_SCALE:
2893 		DESC_SET_NEED_REPREPARE;
2894 		if (drec->sql_desc_concise_type == SQL_NUMERIC || drec->sql_desc_concise_type == SQL_DECIMAL)
2895 			IIN(SQLSMALLINT, drec->sql_desc_scale);
2896 		else
2897 			/* TODO even for datetime/money ?? */
2898 			drec->sql_desc_scale = 0;
2899 		break;
2900 	case SQL_DESC_SCHEMA_NAME:
2901 	case SQL_DESC_SEARCHABLE:
2902 	case SQL_DESC_TABLE_NAME:
2903 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2904 		result = SQL_ERROR;
2905 		break;
2906 	case SQL_DESC_TYPE:
2907 		DESC_SET_NEED_REPREPARE;
2908 		IIN(SQLSMALLINT, drec->sql_desc_type);
2909 		/* FIXME what happen for interval/datetime ?? */
2910 		drec->sql_desc_concise_type = drec->sql_desc_type;
2911 		break;
2912 	case SQL_DESC_TYPE_NAME:
2913 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2914 		result = SQL_ERROR;
2915 		break;
2916 	case SQL_DESC_UNNAMED:
2917 		IIN(SQLSMALLINT, drec->sql_desc_unnamed);
2918 		break;
2919 	case SQL_DESC_UNSIGNED:
2920 	case SQL_DESC_UPDATABLE:
2921 		odbc_errs_add(&desc->errs, "HY091", "Descriptor type read only");
2922 		result = SQL_ERROR;
2923 		break;
2924 	default:
2925 		odbc_errs_add(&desc->errs, "HY091", NULL);
2926 		ODBC_EXIT_(desc);
2927 		break;
2928 	}
2929 
2930 #undef IIN
2931 
2932 	ODBC_EXIT(desc, result);
2933 }
2934 
2935 SQLRETURN ODBC_PUBLIC ODBC_API
SQLCopyDesc(SQLHDESC hsrc,SQLHDESC hdesc)2936 SQLCopyDesc(SQLHDESC hsrc, SQLHDESC hdesc)
2937 {
2938 	TDS_DESC *src;
2939 
2940 	ODBC_ENTER_HDESC;
2941 
2942 	tdsdump_log(TDS_DBG_FUNC, "SQLCopyDesc(%p, %p)\n",
2943 			hsrc, hdesc);
2944 
2945 	if (SQL_NULL_HDESC == hsrc || !IS_HDESC(hsrc))
2946 		return SQL_INVALID_HANDLE;
2947 	src = (TDS_DESC *) hsrc;
2948 	CHECK_DESC_EXTRA(src);
2949 
2950 	/* do not write on IRD */
2951 	if (desc->type == DESC_IRD) {
2952 		odbc_errs_add(&desc->errs, "HY016", NULL);
2953 		ODBC_EXIT_(desc);
2954 	}
2955 	IRD_UPDATE(src, &src->errs, ODBC_EXIT(desc, SQL_ERROR));
2956 
2957 	ODBC_EXIT(desc, desc_copy(desc, src));
2958 }
2959 
2960 #if ENABLE_EXTRA_CHECKS
2961 static void
odbc_ird_check(TDS_STMT * stmt)2962 odbc_ird_check(TDS_STMT * stmt)
2963 {
2964 #if !ENABLE_ODBC_MARS
2965 	TDS_DESC *ird = stmt->ird;
2966 	TDSRESULTINFO *res_info = NULL;
2967 	int cols = 0, i;
2968 
2969 	if (!stmt->tds)
2970 		return;
2971 	if (stmt->tds->current_results) {
2972 		res_info = stmt->tds->current_results;
2973 		cols = res_info->num_cols;
2974 	}
2975 	if (stmt->cursor != NULL)
2976 		return;
2977 
2978 	/* check columns number */
2979 	assert(ird->header.sql_desc_count <= cols || ird->header.sql_desc_count == 0);
2980 
2981 
2982 	/* check all columns */
2983 	for (i = 0; i < ird->header.sql_desc_count; ++i) {
2984 		struct _drecord *drec = &ird->records[i];
2985 		TDSCOLUMN *col = res_info->columns[i];
2986 
2987 		assert(strcmp(tds_dstr_cstr(&drec->sql_desc_label), tds_dstr_cstr(&col->column_name)) == 0);
2988 	}
2989 #endif
2990 }
2991 #endif
2992 
2993 static void
odbc_unquote(char * buf,size_t buf_len,const char * start,const char * end)2994 odbc_unquote(char *buf, size_t buf_len, const char *start, const char *end)
2995 {
2996 	char quote;
2997 	assert(buf_len > 0);
2998 
2999 	/* empty string */
3000 	if (start >= end) {
3001 		buf[0] = 0;
3002 		return;
3003 	}
3004 
3005 	/* not quoted */
3006 	if (*start != '[' && *start != '\"') {
3007 		--buf_len;
3008                 if (end < start + buf_len)
3009 			buf_len = end - start;
3010 		memcpy(buf, start, buf_len);
3011 		buf[buf_len] = 0;
3012 		return;
3013 	}
3014 
3015 	/* quoted... unquote */
3016 	quote = (*start == '[') ? ']' : *start;
3017 	++start;
3018 	while (buf_len > 0 && start < end) {
3019 		if (*start == quote)
3020 			if (++start >= end)
3021 				break;
3022 		*buf++ = *start++;
3023 		--buf_len;
3024 	}
3025 	*buf = 0;
3026 }
3027 
3028 /* FIXME check result !!! */
3029 static SQLRETURN
odbc_populate_ird(TDS_STMT * stmt)3030 odbc_populate_ird(TDS_STMT * stmt)
3031 {
3032 	TDS_DESC *ird = stmt->ird;
3033 	struct _drecord *drec;
3034 	TDSCOLUMN *col;
3035 	TDSRESULTINFO *res_info;
3036 	int num_cols;
3037 	int i;
3038 
3039 	desc_free_records(ird);
3040 	if (!stmt->tds || !(res_info = stmt->tds->current_results))
3041 		return SQL_SUCCESS;
3042 	if (res_info == stmt->tds->param_info)
3043 		return SQL_SUCCESS;
3044 	num_cols = res_info->num_cols;
3045 
3046 	/* ignore hidden columns... TODO correct? */
3047 	while (num_cols > 0 && res_info->columns[num_cols - 1]->column_hidden == 1)
3048 		--num_cols;
3049 
3050 	if (desc_alloc_records(ird, num_cols) != SQL_SUCCESS)
3051 		goto memory_error;
3052 
3053 	for (i = 0; i < num_cols; i++) {
3054 		drec = &ird->records[i];
3055 		col = res_info->columns[i];
3056 		drec->sql_desc_auto_unique_value = col->column_identity ? SQL_TRUE : SQL_FALSE;
3057 		/* TODO SQL_FALSE ?? */
3058 		drec->sql_desc_case_sensitive = SQL_TRUE;
3059 
3060 		/*
3061 		 * TODO how to handle when in datetime we change precision ??
3062 		 * should we change display size too ??
3063 		 * is formatting function correct ??
3064 		 * we should not convert to string with invalid precision!
3065 		 */
3066 		odbc_set_sql_type_info(col, drec, stmt->dbc->env->attr.odbc_version);
3067 
3068 		drec->sql_desc_fixed_prec_scale = (col->column_prec && col->column_scale) ? SQL_TRUE : SQL_FALSE;
3069 		if (!tds_dstr_dup(&drec->sql_desc_label, &col->column_name))
3070 			goto memory_error;
3071 
3072 		if (tds_dstr_isempty(&col->table_column_name)) {
3073 			if (!tds_dstr_dup(&drec->sql_desc_name, &col->column_name))
3074 				goto memory_error;
3075 		} else {
3076 			if (!tds_dstr_dup(&drec->sql_desc_name, &col->table_column_name))
3077 				goto memory_error;
3078 			if (!tds_dstr_dup(&drec->sql_desc_base_column_name, &col->table_column_name))
3079 				goto memory_error;
3080 		}
3081 
3082 		/* extract sql_desc_(catalog/schema/base_table)_name */
3083 		/* TODO extract them dinamically (when needed) ? */
3084 		/* TODO store in libTDS in different way (separately) ? */
3085 		if (!tds_dstr_isempty(&col->table_name)) {
3086 			struct {
3087 				const char *start;
3088 				const char *end;
3089 			} partials[4];
3090 			const char *p;
3091 			char buf[256];
3092 			int i;
3093 
3094 			p = tds_dstr_cstr(&col->table_name);
3095 			for (i = 0; ; ++i) {
3096 				const char *pend;
3097 
3098 				if (*p == '[' || *p == '\"') {
3099 					pend = tds_skip_quoted(p);
3100 				} else {
3101 					pend = strchr(p, '.');
3102 					if (!pend)
3103 						pend = strchr(p, 0);
3104 				}
3105 				partials[i].start = p;
3106 				partials[i].end = pend;
3107 				p = pend;
3108 				if (i == 3 || *p != '.')
3109 					break;
3110 				++p;
3111 			}
3112 
3113 			/* here i points to last element */
3114 			odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3115 			if (!tds_dstr_copy(&drec->sql_desc_base_table_name, buf))
3116 				goto memory_error;
3117 
3118 			--i;
3119 			if (i >= 0) {
3120 				odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3121 				if (!tds_dstr_copy(&drec->sql_desc_schema_name, buf))
3122 					goto memory_error;
3123 			}
3124 
3125 			--i;
3126 			if (i >= 0) {
3127 				odbc_unquote(buf, sizeof(buf), partials[i].start, partials[i].end);
3128 				if (!tds_dstr_copy(&drec->sql_desc_catalog_name, buf))
3129 					goto memory_error;
3130 			}
3131 		}
3132 
3133 		drec->sql_desc_unnamed = tds_dstr_isempty(&drec->sql_desc_name) ? SQL_UNNAMED : SQL_NAMED;
3134 		/* TODO use is_nullable_type ?? */
3135 		drec->sql_desc_nullable = col->column_nullable ? SQL_TRUE : SQL_FALSE;
3136 
3137 		drec->sql_desc_octet_length_ptr = NULL;
3138 		/* TODO test timestamp from db, FOR BROWSE query */
3139 		drec->sql_desc_rowver = SQL_FALSE;
3140 		/* TODO seem not correct */
3141 		drec->sql_desc_searchable = (drec->sql_desc_unnamed == SQL_NAMED) ? SQL_PRED_SEARCHABLE : SQL_UNSEARCHABLE;
3142 		drec->sql_desc_updatable = col->column_writeable && !col->column_identity ? SQL_TRUE : SQL_FALSE;
3143 	}
3144 	return SQL_SUCCESS;
3145 
3146 memory_error:
3147 	odbc_errs_add(&stmt->errs, "HY001", NULL);
3148 	return SQL_ERROR;
3149 }
3150 
3151 static TDSRET
odbc_cursor_execute(TDS_STMT * stmt)3152 odbc_cursor_execute(TDS_STMT * stmt)
3153 {
3154 	TDSSOCKET *tds = stmt->tds;
3155 	int send = 0, i;
3156 	TDSRET ret;
3157 	TDSCURSOR *cursor;
3158 	TDSPARAMINFO *params = stmt->params;
3159 
3160 	assert(tds);
3161 	assert(stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY);
3162 
3163 	tds_release_cursor(&stmt->cursor);
3164 	cursor = tds_alloc_cursor(tds, tds_dstr_cstr(&stmt->cursor_name), tds_dstr_len(&stmt->cursor_name),
3165 			tds_dstr_cstr(&stmt->query), tds_dstr_len(&stmt->query));
3166 	if (!cursor) {
3167 		odbc_unlock_statement(stmt);
3168 
3169 		odbc_errs_add(&stmt->errs, "HY001", NULL);
3170 		return TDS_FAIL;
3171 	}
3172 	stmt->cursor = cursor;
3173 
3174 	/* TODO cursor add enums for tds7 */
3175 	switch (stmt->attr.cursor_type) {
3176 	default:
3177 	case SQL_CURSOR_FORWARD_ONLY:
3178 		i = TDS_CUR_TYPE_FORWARD;
3179 		break;
3180 	case SQL_CURSOR_STATIC:
3181 		i = TDS_CUR_TYPE_STATIC;
3182 		break;
3183 	case SQL_CURSOR_KEYSET_DRIVEN:
3184 		i = TDS_CUR_TYPE_KEYSET;
3185 		break;
3186 	case SQL_CURSOR_DYNAMIC:
3187 		i = TDS_CUR_TYPE_DYNAMIC;
3188 		break;
3189 	}
3190 	cursor->type = i;
3191 
3192 	switch (stmt->attr.concurrency) {
3193 	default:
3194 	case SQL_CONCUR_READ_ONLY:
3195 		i = TDS_CUR_CONCUR_READ_ONLY;
3196 		break;
3197 	case SQL_CONCUR_LOCK:
3198 		i = TDS_CUR_CONCUR_SCROLL_LOCKS;
3199 		break;
3200 	case SQL_CONCUR_ROWVER:
3201 		i = TDS_CUR_CONCUR_OPTIMISTIC;
3202 		break;
3203 	case SQL_CONCUR_VALUES:
3204 		i = TDS_CUR_CONCUR_OPTIMISTIC_VALUES;
3205 		break;
3206 	}
3207 	cursor->concurrency = 0x2000 | i;
3208 
3209 	ret = tds_cursor_declare(tds, cursor, params, &send);
3210 	if (TDS_FAILED(ret))
3211 		return ret;
3212 	ret = tds_cursor_open(tds, cursor, params, &send);
3213 	if (TDS_FAILED(ret))
3214 		return ret;
3215 	/* TODO read results, set row count, check type and scroll returned */
3216 	ret = tds_flush_packet(tds);
3217 	tds_set_state(tds, TDS_PENDING);
3218 	/* set cursor name for TDS7+ */
3219 	if (TDS_SUCCEED(ret) && IS_TDS7_PLUS(tds->conn) && !tds_dstr_isempty(&stmt->cursor_name)) {
3220 		ret = odbc_process_tokens(stmt, TDS_RETURN_DONE|TDS_STOPAT_ROW|TDS_STOPAT_COMPUTE);
3221 		stmt->row_count = tds->rows_affected;
3222 		if (ret == TDS_CMD_DONE && cursor->cursor_id != 0) {
3223 			ret = tds_cursor_setname(tds, cursor);
3224 			tds_set_state(tds, TDS_PENDING);
3225 		} else {
3226 			ret = (ret == TDS_CMD_FAIL) ? TDS_FAIL : TDS_SUCCESS;
3227 		}
3228 		if (!cursor->cursor_id) {
3229 			tds_cursor_dealloc(tds, cursor);
3230 			tds_release_cursor(&stmt->cursor);
3231 		}
3232 	}
3233 	return ret;
3234 }
3235 
3236 static TDSHEADERS *
odbc_init_headers(TDS_STMT * stmt,TDSHEADERS * head)3237 odbc_init_headers(TDS_STMT * stmt, TDSHEADERS * head)
3238 {
3239 	if (tds_dstr_isempty(&stmt->attr.qn_msgtext) || tds_dstr_isempty(&stmt->attr.qn_options))
3240 		return NULL;
3241 
3242 	memset(head, 0, sizeof(*head));
3243 	head->qn_timeout = stmt->attr.qn_timeout;
3244 	head->qn_msgtext = tds_dstr_cstr(&stmt->attr.qn_msgtext);
3245 	head->qn_options = tds_dstr_cstr(&stmt->attr.qn_options);
3246 	return head;
3247 }
3248 
3249 static SQLRETURN
_SQLExecute(TDS_STMT * stmt)3250 _SQLExecute(TDS_STMT * stmt)
3251 {
3252 	TDSRET ret;
3253 	TDSSOCKET *tds;
3254 	TDS_INT result_type;
3255 	TDS_INT done = 0;
3256 	int in_row = 0;
3257 	SQLUSMALLINT param_status;
3258 	int found_info = 0, found_error = 0;
3259 	TDS_INT8 total_rows = TDS_NO_COUNT;
3260 	TDSHEADERS head;
3261 
3262 	tdsdump_log(TDS_DBG_FUNC, "_SQLExecute(%p)\n",
3263 			stmt);
3264 
3265 	stmt->row = 0;
3266 
3267 
3268 	/* check parameters are all OK */
3269         if (stmt->params && stmt->param_num <= (int) stmt->param_count) {
3270 		/* TODO what error ?? */
3271 		ODBC_SAFE_ERROR(stmt);
3272 		return SQL_ERROR;
3273 	}
3274 
3275 	if (!odbc_lock_statement(stmt))
3276 		return SQL_ERROR;
3277 
3278 	tds = stmt->tds;
3279 	tdsdump_log(TDS_DBG_FUNC, "_SQLExecute() starting with state %d\n", tds->state);
3280 
3281 	if (tds->state != TDS_IDLE) {
3282 		if (tds->state == TDS_DEAD) {
3283 			odbc_errs_add(&stmt->errs, "08S01", NULL);
3284 		} else {
3285 			odbc_errs_add(&stmt->errs, "24000", NULL);
3286 		}
3287 		return SQL_ERROR;
3288 	}
3289 
3290 	stmt->curr_param_row = 0;
3291 	stmt->num_param_rows = ODBC_MAX(1, stmt->apd->header.sql_desc_array_size);
3292 
3293 	stmt->row_count = TDS_NO_COUNT;
3294 
3295 	if (stmt->prepared_query_is_rpc) {
3296 		/* TODO support stmt->apd->header.sql_desc_array_size for RPC */
3297 		/* get rpc name */
3298 		/* TODO change method */
3299 		/* TODO cursor change way of calling */
3300 		char *name = tds_dstr_buf(&stmt->query);
3301 		char *end, tmp;
3302 
3303 		end = name;
3304 		end = (char *) odbc_skip_rpc_name(end);
3305 		stmt->prepared_pos = end;
3306 		tmp = *end;
3307 		*end = 0;
3308 		ret = tds_submit_rpc(tds, name, stmt->params, odbc_init_headers(stmt, &head));
3309 		*end = tmp;
3310 	} else if (stmt->attr.cursor_type != SQL_CURSOR_FORWARD_ONLY || stmt->attr.concurrency != SQL_CONCUR_READ_ONLY) {
3311 		ret = odbc_cursor_execute(stmt);
3312 	} else if (!stmt->is_prepared_query) {
3313 		/* not prepared query */
3314 		/* TODO cursor change way of calling */
3315 		/* SQLExecDirect */
3316 		if (stmt->num_param_rows <= 1) {
3317 			if (!stmt->params) {
3318 				ret = tds_submit_query_params(tds, tds_dstr_cstr(&stmt->query), NULL, odbc_init_headers(stmt, &head));
3319 			} else {
3320 				ret = tds_submit_execdirect(tds, tds_dstr_cstr(&stmt->query), stmt->params, odbc_init_headers(stmt, &head));
3321 			}
3322 		} else {
3323 			/* pack multiple submit using language */
3324 			TDSMULTIPLE multiple;
3325 
3326 			ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_QUERY, odbc_init_headers(stmt, &head));
3327 			for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3328 				/* submit a query */
3329 				ret = tds_multiple_query(tds, &multiple, tds_dstr_cstr(&stmt->query), stmt->params);
3330 				if (++stmt->curr_param_row >= stmt->num_param_rows)
3331 					break;
3332 				/* than process others parameters */
3333 				/* TODO handle all results*/
3334 				if (start_parse_prepared_query(stmt, 1) != SQL_SUCCESS)
3335 					break;
3336 			}
3337 			if (TDS_SUCCEED(ret))
3338 				ret = tds_multiple_done(tds, &multiple);
3339 		}
3340 	} else if (stmt->num_param_rows <= 1 && IS_TDS71_PLUS(tds->conn) && (!stmt->dyn || stmt->need_reprepare)) {
3341 			if (stmt->dyn) {
3342 				if (odbc_free_dynamic(stmt) != SQL_SUCCESS)
3343 					ODBC_RETURN(stmt, SQL_ERROR);
3344 			}
3345 			stmt->need_reprepare = 0;
3346 			ret = tds71_submit_prepexec(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params);
3347 	} else {
3348 		/* TODO cursor change way of calling */
3349 		/* SQLPrepare */
3350 		TDSDYNAMIC *dyn;
3351 
3352 		/* prepare dynamic query (only for first SQLExecute call) */
3353 		if (!stmt->dyn || (stmt->need_reprepare && !stmt->dyn->emulated && IS_TDS7_PLUS(tds->conn))) {
3354 
3355 			/* free previous prepared statement */
3356 			if (stmt->dyn) {
3357 				if (odbc_free_dynamic(stmt) != SQL_SUCCESS)
3358 					ODBC_RETURN(stmt, SQL_ERROR);
3359 			}
3360 			stmt->need_reprepare = 0;
3361 
3362 			tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
3363 			/* TODO use tds_submit_prepexec (mssql2k, tds71) */
3364 			if (TDS_FAILED(tds_submit_prepare(tds, tds_dstr_cstr(&stmt->query), NULL, &stmt->dyn, stmt->params))) {
3365 				/* TODO ?? tds_free_param_results(params); */
3366 				ODBC_SAFE_ERROR(stmt);
3367 				return SQL_ERROR;
3368 			}
3369 			if (TDS_FAILED(tds_process_simple_query(tds))) {
3370 				tds_release_dynamic(&stmt->dyn);
3371 				/* TODO ?? tds_free_param_results(params); */
3372 				ODBC_SAFE_ERROR(stmt);
3373 				return SQL_ERROR;
3374 			}
3375 		}
3376 		stmt->row_count = TDS_NO_COUNT;
3377 		if (stmt->num_param_rows <= 1) {
3378 			dyn = stmt->dyn;
3379 			tds_free_input_params(dyn);
3380 			dyn->params = stmt->params;
3381 			/* prevent double free */
3382 			stmt->params = NULL;
3383 			tdsdump_log(TDS_DBG_INFO1, "End prepare, execute\n");
3384 			/* TODO return error to client */
3385 			ret = tds_submit_execute(tds, dyn);
3386 		} else {
3387 			TDSMULTIPLE multiple;
3388 
3389 			ret = tds_multiple_init(tds, &multiple, TDS_MULTIPLE_EXECUTE, NULL);
3390 			for (stmt->curr_param_row = 0; TDS_SUCCEED(ret); ) {
3391 				dyn = stmt->dyn;
3392 				tds_free_input_params(dyn);
3393 				dyn->params = stmt->params;
3394 				/* prevent double free */
3395 				stmt->params = NULL;
3396 				ret = tds_multiple_execute(tds, &multiple, dyn);
3397 				if (++stmt->curr_param_row >= stmt->num_param_rows)
3398 					break;
3399 				/* than process others parameters */
3400 				/* TODO handle all results*/
3401 				if (start_parse_prepared_query(stmt, 1) != SQL_SUCCESS)
3402 					break;
3403 			}
3404 			if (TDS_SUCCEED(ret))
3405 				ret = tds_multiple_done(tds, &multiple);
3406 		}
3407 	}
3408 	if (TDS_FAILED(ret)) {
3409 		ODBC_SAFE_ERROR(stmt);
3410 		return SQL_ERROR;
3411 	}
3412 	/* catch all errors */
3413 	if (!odbc_lock_statement(stmt))
3414 		ODBC_RETURN_(stmt);
3415 
3416 	stmt->row_status = PRE_NORMAL_ROW;
3417 
3418 	stmt->curr_param_row = 0;
3419 	param_status = SQL_PARAM_SUCCESS;
3420 
3421 	/* TODO review this, ODBC return parameter in other way, for compute I don't know */
3422 	/* TODO perhaps we should return SQL_NO_DATA if no data available... see old SQLExecute code */
3423 	for (;;) {
3424 		result_type = odbc_process_tokens(stmt, TDS_TOKEN_RESULTS);
3425 		tdsdump_log(TDS_DBG_FUNC, "_SQLExecute: odbc_process_tokens returned result_type %d\n", result_type);
3426 		switch (result_type) {
3427 		case TDS_CMD_FAIL:
3428 		case TDS_CMD_DONE:
3429 		case TDS_COMPUTE_RESULT:
3430 		case TDS_ROW_RESULT:
3431 			done = 1;
3432 			break;
3433 
3434 		case TDS_DONE_RESULT:
3435 		case TDS_DONEPROC_RESULT:
3436 			switch (stmt->errs.lastrc) {
3437 			case SQL_ERROR:
3438 				found_error = 1;
3439 				param_status = SQL_PARAM_ERROR;
3440 				break;
3441 			case SQL_SUCCESS_WITH_INFO:
3442 				found_info = 1;
3443 				param_status = SQL_PARAM_SUCCESS_WITH_INFO;
3444 				break;
3445 			}
3446 			if (stmt->curr_param_row < stmt->num_param_rows && stmt->ipd->header.sql_desc_array_status_ptr)
3447 				stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3448 			param_status = SQL_PARAM_SUCCESS;
3449 			++stmt->curr_param_row;
3450 			/* actually is quite strange, if prepared always success with info or success
3451 			 * if not prepared return last one
3452 			 */
3453 			if (stmt->curr_param_row < stmt->num_param_rows || result_type == TDS_DONEPROC_RESULT)
3454 				stmt->errs.lastrc = SQL_SUCCESS;
3455 			if (total_rows == TDS_NO_COUNT)
3456 				total_rows = stmt->row_count;
3457 			else if (stmt->row_count != TDS_NO_COUNT)
3458 				total_rows += stmt->row_count;
3459 			stmt->row_count = TDS_NO_COUNT;
3460 			if (stmt->curr_param_row >= stmt->num_param_rows) {
3461 				done = 1;
3462 				break;
3463 			}
3464 			break;
3465 
3466 		case TDS_DONEINPROC_RESULT:
3467 			if (in_row)
3468 				done = 1;
3469 			break;
3470 
3471 			/* ignore metadata, stop at done or row */
3472 		case TDS_ROWFMT_RESULT:
3473 			if (in_row) {
3474 				done = 1;
3475 				break;
3476 			}
3477 			stmt->row = 0;
3478 			stmt->row_count = TDS_NO_COUNT;
3479 			stmt->row_status = PRE_NORMAL_ROW;
3480 			in_row = 1;
3481 			break;
3482 		}
3483 		if (done)
3484 			break;
3485 	}
3486 	if ((found_info || found_error) && stmt->errs.lastrc != SQL_ERROR)
3487 		stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3488 	if (tds_dstr_isempty(&stmt->attr.qn_msgtext) != tds_dstr_isempty(&stmt->attr.qn_options)) {
3489 		odbc_errs_add(&stmt->errs, "HY000", "Attribute ignored");
3490 		stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3491 	}
3492 	if (found_error && stmt->num_param_rows <= 1)
3493 		stmt->errs.lastrc = SQL_ERROR;
3494 	if (stmt->curr_param_row < stmt->num_param_rows) {
3495 		if (stmt->ipd->header.sql_desc_array_status_ptr)
3496 			stmt->ipd->header.sql_desc_array_status_ptr[stmt->curr_param_row] = param_status;
3497 		++stmt->curr_param_row;
3498 		if (total_rows == TDS_NO_COUNT)
3499 			total_rows = stmt->row_count;
3500 		else if (stmt->row_count != TDS_NO_COUNT)
3501 			total_rows += stmt->row_count;
3502 		stmt->row_count = TDS_NO_COUNT;
3503 	}
3504 	if (stmt->ipd->header.sql_desc_rows_processed_ptr)
3505 		*stmt->ipd->header.sql_desc_rows_processed_ptr = ODBC_MIN(stmt->curr_param_row, stmt->num_param_rows);
3506 
3507 	if (total_rows != TDS_NO_COUNT)
3508 		stmt->row_count = total_rows;
3509 
3510 	odbc_populate_ird(stmt);
3511 	switch (result_type) {
3512 	case TDS_CMD_DONE:
3513 		odbc_unlock_statement(stmt);
3514 		if (stmt->errs.lastrc == SQL_SUCCESS && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3
3515 		    && stmt->row_count == TDS_NO_COUNT && !stmt->cursor)
3516 			ODBC_RETURN(stmt, SQL_NO_DATA);
3517 		break;
3518 
3519 	case TDS_CMD_FAIL:
3520 		/* TODO test what happened, report correct error to client */
3521 		tdsdump_log(TDS_DBG_INFO1, "SQLExecute: bad results\n");
3522 		ODBC_SAFE_ERROR(stmt);
3523 		return SQL_ERROR;
3524 	}
3525 	ODBC_RETURN_(stmt);
3526 }
3527 
3528 ODBC_FUNC(SQLExecDirect, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE))
3529 {
3530 	SQLRETURN res;
3531 
3532 	ODBC_ENTER_HSTMT;
3533 
3534 	if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide)) {
3535 		odbc_errs_add(&stmt->errs, "HY001", NULL);
3536 		ODBC_EXIT_(stmt);
3537 	}
3538 
3539 	/* count placeholders */
3540 	/* note: szSqlStr can be no-null terminated, so first we set query and then count placeholders */
3541 	stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
3542 	stmt->param_data_called = 0;
3543 
3544 	if (SQL_SUCCESS != prepare_call(stmt)) {
3545 		/* TODO return another better error, prepare_call should set error ?? */
3546 		odbc_errs_add(&stmt->errs, "HY000", "Could not prepare call");
3547 		ODBC_EXIT_(stmt);
3548 	}
3549 
3550 	res = start_parse_prepared_query(stmt, 1);
3551 	if (SQL_SUCCESS != res)
3552 		ODBC_EXIT(stmt, res);
3553 
3554 	ODBC_EXIT(stmt, _SQLExecute(stmt));
3555 }
3556 
3557 SQLRETURN ODBC_PUBLIC ODBC_API
SQLExecute(SQLHSTMT hstmt)3558 SQLExecute(SQLHSTMT hstmt)
3559 {
3560 	ODBC_PRRET_BUF;
3561 	SQLRETURN res;
3562 
3563 	ODBC_ENTER_HSTMT;
3564 
3565 	tdsdump_log(TDS_DBG_FUNC, "SQLExecute(%p)\n", hstmt);
3566 
3567 	if (!stmt->is_prepared_query) {
3568 		/* TODO error report, only without DM ?? */
3569 		tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns SQL_ERROR (not prepared)\n");
3570 		ODBC_EXIT(stmt, SQL_ERROR);
3571 	}
3572 
3573 	/* TODO rebuild should be done for every bindings change, not every time */
3574 	/* TODO free previous parameters */
3575 	/* build parameters list */
3576 	stmt->param_data_called = 0;
3577 	stmt->curr_param_row = 0;
3578 	if ((res = start_parse_prepared_query(stmt, 1)) != SQL_SUCCESS) {
3579 		tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s (start_parse_prepared_query failed)\n", odbc_prret(res));
3580 		ODBC_EXIT(stmt, res);
3581 	}
3582 
3583 	/* TODO test if two SQLPrepare on a statement */
3584 	/* TODO test unprepare on statement free or connection close */
3585 
3586 	res = _SQLExecute(stmt);
3587 
3588 	tdsdump_log(TDS_DBG_FUNC, "SQLExecute returns %s\n", odbc_prret(res));
3589 
3590 	ODBC_EXIT(stmt, res);
3591 }
3592 
3593 static int
odbc_process_tokens(TDS_STMT * stmt,unsigned flag)3594 odbc_process_tokens(TDS_STMT * stmt, unsigned flag)
3595 {
3596 	TDS_INT result_type;
3597         int done_flags = 0;
3598 	TDSSOCKET * tds = stmt->tds;
3599 
3600 	flag |= TDS_RETURN_DONE | TDS_RETURN_PROC;
3601 	for (;;) {
3602 		TDSRET retcode = tds_process_tokens(tds, &result_type, &done_flags, flag);
3603 		tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: tds_process_tokens returned %d\n", retcode);
3604 		tdsdump_log(TDS_DBG_FUNC, "    result_type=%d, TDS_DONE_COUNT=%x, TDS_DONE_ERROR=%x\n",
3605 						result_type, (done_flags & TDS_DONE_COUNT), (done_flags & TDS_DONE_ERROR));
3606 		switch (retcode) {
3607 		case TDS_SUCCESS:
3608 			break;
3609 		case TDS_NO_MORE_RESULTS:
3610 			return TDS_CMD_DONE;
3611 		case TDS_CANCELLED:
3612 			odbc_errs_add(&stmt->errs, "HY008", NULL);
3613 		default:
3614 			return TDS_CMD_FAIL;
3615 		}
3616 
3617 		switch (result_type) {
3618 		case TDS_STATUS_RESULT:
3619 			odbc_set_return_status(stmt, ODBC_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3620 			break;
3621 		case TDS_PARAM_RESULT:
3622 			odbc_set_return_params(stmt, ODBC_MIN(stmt->curr_param_row, stmt->num_param_rows - 1));
3623 			break;
3624 
3625 		case TDS_DONE_RESULT:
3626 		case TDS_DONEPROC_RESULT:
3627 			if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3628 				flag |= TDS_STOPAT_MSG;
3629 			if (done_flags & TDS_DONE_COUNT) {
3630 				/* correct ?? overwrite ?? */
3631 				if (stmt->row_count == TDS_NO_COUNT)
3632 					stmt->row_count = tds->rows_affected;
3633 			}
3634 			if (done_flags & TDS_DONE_ERROR)
3635 				stmt->errs.lastrc = SQL_ERROR;
3636 			/* test for internal_sp not very fine, used for param set  -- freddy77 */
3637 			if ((done_flags & (TDS_DONE_COUNT|TDS_DONE_ERROR)) != 0
3638 			    || (stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3639 			    || (result_type == TDS_DONEPROC_RESULT && tds->current_op == TDS_OP_EXECUTE)) {
3640 				/* FIXME this row is used only as a flag for update binding, should be cleared if binding/result changed */
3641 				stmt->row = 0;
3642 #if 0
3643 				tds_free_all_results(tds);
3644 				odbc_populate_ird(stmt);
3645 #endif
3646 				tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: row_count=%" PRId64 "\n", stmt->row_count);
3647 				return result_type;
3648 			}
3649 			tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed %s\n",
3650 					result_type==TDS_DONE_RESULT? "TDS_DONE_RESULT" : "TDS_DONEPROC_RESULT");
3651 			break;
3652 
3653 		/*
3654 		 * TODO test flags ? check error and change result ?
3655 		 * see also other DONEINPROC handle (below)
3656 		 */
3657 		case TDS_DONEINPROC_RESULT:
3658 			if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3)
3659 				flag |= TDS_STOPAT_MSG;
3660 			if (done_flags & TDS_DONE_COUNT) {
3661 				stmt->row_count = tds->rows_affected;
3662 			}
3663 			if (done_flags & TDS_DONE_ERROR)
3664 				stmt->errs.lastrc = SQL_ERROR;
3665 			/* TODO perhaps it can be a problem if SET NOCOUNT ON, test it */
3666 #if 0
3667 			tds_free_all_results(tds);
3668 			odbc_populate_ird(stmt);
3669 #endif
3670 			tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: processed TDS_DONEINPROC_RESULT\n");
3671 			if (stmt->row_status == PRE_NORMAL_ROW)
3672 				return result_type;
3673 			break;
3674 
3675 		default:
3676 			tdsdump_log(TDS_DBG_FUNC, "odbc_process_tokens: returning result_type %d\n", result_type);
3677 			return result_type;
3678 		}
3679 	}
3680 }
3681 
3682 static void
odbc_fix_data_type_col(TDS_STMT * stmt,int idx)3683 odbc_fix_data_type_col(TDS_STMT *stmt, int idx)
3684 {
3685 	TDSSOCKET *tds = stmt->tds;
3686 	TDSRESULTINFO *resinfo;
3687 	TDSCOLUMN *colinfo;
3688 
3689 	if (!tds)
3690 		return;
3691 
3692 	resinfo = tds->current_results;
3693 	if (!resinfo || resinfo->num_cols <= idx)
3694 		return;
3695 
3696 	colinfo = resinfo->columns[idx];
3697 	if (colinfo->column_cur_size < 0)
3698 		return;
3699 
3700 	switch (tds_get_conversion_type(colinfo->column_type, colinfo->column_size)) {
3701 	case SYBINT2: {
3702 		TDS_SMALLINT *data = (TDS_SMALLINT *) colinfo->column_data;
3703 		*data = odbc_swap_datetime_sql_type(*data, 0);
3704 		}
3705 		break;
3706 	case SYBINT4: {
3707 		TDS_INT *data = (TDS_INT *) colinfo->column_data;
3708 		*data = odbc_swap_datetime_sql_type(*data, 0);
3709 		}
3710 		break;
3711         default:
3712                 break;
3713 	}
3714 }
3715 
3716 /*
3717  * - handle correctly SQLGetData (for forward cursors accept only row_size == 1
3718  *   for other types application must use SQLSetPos)
3719  * - handle correctly results (SQL_SUCCESS_WITH_INFO if error on some rows,
3720  *   SQL_ERROR for all rows, see doc)
3721  */
3722 static SQLRETURN
_SQLFetch(TDS_STMT * stmt,SQLSMALLINT FetchOrientation,SQLLEN FetchOffset)3723 _SQLFetch(TDS_STMT * stmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
3724 {
3725 	TDSSOCKET *tds;
3726 	TDSRESULTINFO *resinfo;
3727 	TDSCOLUMN *colinfo;
3728 	int i;
3729 	SQLULEN curr_row, num_rows;
3730         SQLLEN len = 0;
3731 	TDS_CHAR *src;
3732 	int srclen;
3733 	struct _drecord *drec_ard;
3734 	TDS_DESC *ard;
3735 	SQLULEN dummy, *fetched_ptr;
3736 	SQLUSMALLINT *status_ptr, row_status;
3737 	TDS_INT result_type;
3738 	int truncated = 0;
3739 
3740 #define AT_ROW(ptr, type) (row_offset ? (type*)(((char*)(ptr)) + row_offset) : &ptr[curr_row])
3741 	SQLLEN row_offset = 0;
3742 
3743 	tdsdump_log(TDS_DBG_FUNC, "_SQLFetch(%p, %d, %d)\n", stmt, (int)FetchOrientation, (int)FetchOffset);
3744 
3745 	if (stmt->ard->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN && stmt->ard->header.sql_desc_bind_offset_ptr)
3746 		row_offset = *stmt->ard->header.sql_desc_bind_offset_ptr;
3747 
3748 	ard = stmt->ard;
3749 
3750 	tds = stmt->tds;
3751 	num_rows = ard->header.sql_desc_array_size;
3752 
3753 	/* TODO cursor check also type of cursor (scrollable, not forward) */
3754 	if (FetchOrientation != SQL_FETCH_NEXT && (!stmt->cursor || !stmt->dbc->cursor_support)) {
3755 		odbc_errs_add(&stmt->errs, "HY106", NULL);
3756 		return SQL_ERROR;
3757 	}
3758 
3759 	/* handle cursors, fetch wanted rows */
3760 	if (stmt->cursor && odbc_lock_statement(stmt)) {
3761 		TDSCURSOR *cursor = stmt->cursor;
3762 		TDS_CURSOR_FETCH fetch_type = TDS_CURSOR_FETCH_NEXT;
3763 
3764 		tds = stmt->tds;
3765 
3766 		switch (FetchOrientation) {
3767 		case SQL_FETCH_NEXT:
3768 			break;
3769 		case SQL_FETCH_FIRST:
3770 			fetch_type = TDS_CURSOR_FETCH_FIRST;
3771 			break;
3772 		case SQL_FETCH_LAST:
3773 			fetch_type = TDS_CURSOR_FETCH_LAST;
3774 			break;
3775 		case SQL_FETCH_PRIOR:
3776 			fetch_type = TDS_CURSOR_FETCH_PREV;
3777 			break;
3778 		case SQL_FETCH_ABSOLUTE:
3779 			fetch_type = TDS_CURSOR_FETCH_ABSOLUTE;
3780 			break;
3781 		case SQL_FETCH_RELATIVE:
3782 			fetch_type = TDS_CURSOR_FETCH_RELATIVE;
3783 			break;
3784 		/* TODO cursor bookmark */
3785 		default:
3786 			odbc_errs_add(&stmt->errs, "HYC00", NULL);
3787 			return SQL_ERROR;
3788 		}
3789 
3790 		if (cursor->cursor_rows != num_rows) {
3791 			int send = 0;
3792 			cursor->cursor_rows = num_rows;
3793 			/* TODO handle change rows (tds5) */
3794 			/*
3795 			 * TODO curerntly we support cursors only using tds7+
3796 			 * so this function can't fail but remember to add error
3797 			 * check when tds5 will be supported
3798 			 */
3799 			tds_cursor_setrows(tds, cursor, &send);
3800 		}
3801 
3802 		if (TDS_FAILED(tds_cursor_fetch(tds, cursor, fetch_type, FetchOffset))) {
3803 			/* TODO what kind of error ?? */
3804 			ODBC_SAFE_ERROR(stmt);
3805 			return SQL_ERROR;
3806 		}
3807 
3808 		/* TODO handle errors in a better way */
3809 		odbc_process_tokens(stmt, TDS_RETURN_ROW|TDS_STOPAT_COMPUTE|TDS_STOPAT_ROW);
3810 		stmt->row_status = PRE_NORMAL_ROW;
3811 	}
3812 
3813 	if (!tds || stmt->row_status == NOT_IN_ROW) {
3814 		odbc_errs_add(&stmt->errs, "24000", NULL);
3815 		return SQL_ERROR;
3816 	}
3817 	IRD_CHECK;
3818 
3819 	if (stmt->ird->header.sql_desc_count <= 0) {
3820 		odbc_errs_add(&stmt->errs, "24000", NULL);
3821 		return SQL_ERROR;
3822 	}
3823 
3824 	stmt->row++;
3825 
3826 	fetched_ptr = &dummy;
3827 	if (stmt->ird->header.sql_desc_rows_processed_ptr)
3828 		fetched_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
3829 	*fetched_ptr = 0;
3830 
3831 	status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
3832 	if (status_ptr) {
3833                 for (i = 0; (SQLULEN) i < num_rows; ++i)
3834 			*status_ptr++ = SQL_ROW_NOROW;
3835 		status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
3836 	}
3837 
3838 	curr_row = 0;
3839 	do {
3840 		row_status = SQL_ROW_SUCCESS;
3841 
3842 		/* do not get compute row if we are not expecting a compute row */
3843 		switch (stmt->row_status) {
3844 		case AFTER_COMPUTE_ROW:
3845 			/* handle done if needed */
3846 			/* FIXME doesn't seem so fine ... - freddy77 */
3847 			tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
3848 			goto all_done;
3849 
3850 		case IN_COMPUTE_ROW:
3851 			/* compute recorset contains only a row */
3852 			/* we already fetched compute row in SQLMoreResults so do not fetch another one */
3853 			num_rows = 1;
3854 			stmt->row_status = AFTER_COMPUTE_ROW;
3855 			break;
3856 
3857 		default:
3858 			/* FIXME stmt->row_count set correctly ?? TDS_DONE_COUNT not checked */
3859 			switch (odbc_process_tokens(stmt, TDS_STOPAT_ROWFMT|TDS_RETURN_ROW|TDS_STOPAT_COMPUTE)) {
3860 			case TDS_ROW_RESULT:
3861 				break;
3862 			default:
3863 #if 0
3864 				stmt->row_count = tds->rows_affected;
3865 #endif
3866 				/*
3867 				 * NOTE do not set row_status to NOT_IN_ROW,
3868 				 * if compute tds_process_tokens above returns TDS_NO_MORE_RESULTS
3869 				 */
3870 				stmt->row_status = PRE_NORMAL_ROW;
3871 				stmt->special_row = ODBC_SPECIAL_NONE;
3872 #if 0
3873 				odbc_populate_ird(stmt);
3874 #endif
3875 				tdsdump_log(TDS_DBG_INFO1, "SQLFetch: NO_DATA_FOUND\n");
3876 				goto all_done;
3877 				break;
3878 			case TDS_CMD_FAIL:
3879 				ODBC_SAFE_ERROR(stmt);
3880 				return SQL_ERROR;
3881 				break;
3882 			}
3883 
3884 			stmt->row_status = IN_NORMAL_ROW;
3885 
3886 			/* handle special row */
3887 			switch (stmt->special_row) {
3888 			case ODBC_SPECIAL_GETTYPEINFO:
3889 				odbc_fix_data_type_col(stmt, 1);
3890 				break;
3891 			case ODBC_SPECIAL_COLUMNS:
3892 				odbc_fix_data_type_col(stmt, 4);
3893 				odbc_fix_data_type_col(stmt, 13); /* TODO sure ?? */
3894 				break;
3895 			case ODBC_SPECIAL_PROCEDURECOLUMNS:
3896 				odbc_fix_data_type_col(stmt, 5);
3897 				odbc_fix_data_type_col(stmt, 14); /* TODO sure ?? */
3898 				break;
3899 			case ODBC_SPECIAL_SPECIALCOLUMNS:
3900 				odbc_fix_data_type_col(stmt, 2);
3901 				break;
3902 			case ODBC_SPECIAL_NONE:
3903 				break;
3904 			}
3905 		}
3906 
3907 		resinfo = tds->current_results;
3908 		if (!resinfo) {
3909 			tdsdump_log(TDS_DBG_INFO1, "SQLFetch: !resinfo\n");
3910 			break;
3911 		}
3912 
3913 		/* we got a row, return a row readed even if error (for ODBC specifications) */
3914 		++(*fetched_ptr);
3915 		for (i = 0; i < resinfo->num_cols; i++) {
3916 			colinfo = resinfo->columns[i];
3917 			colinfo->column_text_sqlgetdatapos = 0;
3918 			drec_ard = (i < ard->header.sql_desc_count) ? &ard->records[i] : NULL;
3919 			if (!drec_ard)
3920 				continue;
3921 			if (colinfo->column_cur_size < 0) {
3922 				if (drec_ard->sql_desc_indicator_ptr) {
3923 					*AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = SQL_NULL_DATA;
3924 				} else if (drec_ard->sql_desc_data_ptr) {
3925 					odbc_errs_add(&stmt->errs, "22002", NULL);
3926 					row_status = SQL_ROW_ERROR;
3927 					break;
3928 				}
3929 				continue;
3930 			}
3931 			/* set indicator to 0 if data is not null */
3932 			if (drec_ard->sql_desc_indicator_ptr)
3933 				*AT_ROW(drec_ard->sql_desc_indicator_ptr, SQLLEN) = 0;
3934 
3935 			/* TODO what happen to length if no data is returned (drec->sql_desc_data_ptr == NULL) ?? */
3936 			len = 0;
3937 			if (drec_ard->sql_desc_data_ptr) {
3938 				int c_type;
3939 				TDS_CHAR *data_ptr = (TDS_CHAR *) drec_ard->sql_desc_data_ptr;
3940 
3941 				src = (TDS_CHAR *) colinfo->column_data;
3942 				srclen = colinfo->column_cur_size;
3943 				colinfo->column_text_sqlgetdatapos = 0;
3944 				c_type = drec_ard->sql_desc_concise_type;
3945 				if (c_type == SQL_C_DEFAULT)
3946 					c_type = odbc_sql_to_c_type_default(stmt->ird->records[i].sql_desc_concise_type);
3947 				if (row_offset || curr_row == 0) {
3948 					data_ptr += row_offset;
3949 				} else {
3950 					data_ptr += odbc_get_octet_len(c_type, drec_ard) * curr_row;
3951 				}
3952 				len = odbc_tds2sql(stmt, colinfo, tds_get_conversion_type(colinfo->on_server.column_type, colinfo->on_server.column_size),
3953 						      src, srclen, c_type, data_ptr, drec_ard->sql_desc_octet_length, drec_ard);
3954 				if (len == SQL_NULL_DATA) {
3955 					row_status = SQL_ROW_ERROR;
3956 					break;
3957 				}
3958 				if ((c_type == SQL_C_CHAR && len >= drec_ard->sql_desc_octet_length)
3959 				    || (c_type == SQL_C_BINARY && len > drec_ard->sql_desc_octet_length)) {
3960 					truncated = 1;
3961 					stmt->errs.lastrc = SQL_SUCCESS_WITH_INFO;
3962 				}
3963 			}
3964 			if (drec_ard->sql_desc_octet_length_ptr)
3965 				*AT_ROW(drec_ard->sql_desc_octet_length_ptr, SQLLEN) = len;
3966 		}
3967 
3968 		if (status_ptr)
3969 			*status_ptr++ = truncated ? SQL_ROW_ERROR : row_status;
3970 		if (row_status == SQL_ROW_ERROR) {
3971 			stmt->errs.lastrc = SQL_ERROR;
3972 			break;
3973 		}
3974 #if SQL_BIND_BY_COLUMN != 0
3975 		if (stmt->ard->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN)
3976 #endif
3977 			row_offset += stmt->ard->header.sql_desc_bind_type;
3978 	} while (++curr_row < num_rows);
3979 
3980 	if (truncated)
3981 		odbc_errs_add(&stmt->errs, "01004", NULL);
3982 
3983       all_done:
3984 	/* TODO cursor correct ?? */
3985 	if (stmt->cursor) {
3986 		tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_TRAILING);
3987 		odbc_unlock_statement(stmt);
3988 	}
3989 	if (*fetched_ptr == 0 && (stmt->errs.lastrc == SQL_SUCCESS || stmt->errs.lastrc == SQL_SUCCESS_WITH_INFO))
3990 		ODBC_RETURN(stmt, SQL_NO_DATA);
3991 	if (stmt->errs.lastrc == SQL_ERROR && (*fetched_ptr > 1 || (*fetched_ptr == 1 && row_status != SQL_ROW_ERROR)))
3992 		ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
3993 	ODBC_RETURN_(stmt);
3994 }
3995 
3996 SQLRETURN ODBC_PUBLIC ODBC_API
SQLFetch(SQLHSTMT hstmt)3997 SQLFetch(SQLHSTMT hstmt)
3998 {
3999 	SQLRETURN ret;
4000 	struct {
4001 		SQLULEN  array_size;
4002 		SQLULEN *rows_processed_ptr;
4003 		SQLUSMALLINT *array_status_ptr;
4004 	} keep;
4005 
4006 	ODBC_ENTER_HSTMT;
4007 
4008 	tdsdump_log(TDS_DBG_FUNC, "SQLFetch(%p)\n", hstmt);
4009 
4010 	keep.array_size = stmt->ard->header.sql_desc_array_size;
4011 	keep.rows_processed_ptr = stmt->ird->header.sql_desc_rows_processed_ptr;
4012 	keep.array_status_ptr = stmt->ird->header.sql_desc_array_status_ptr;
4013 
4014 	if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4015 		stmt->ard->header.sql_desc_array_size = 1;
4016 		stmt->ird->header.sql_desc_rows_processed_ptr = NULL;
4017 		stmt->ird->header.sql_desc_array_status_ptr = NULL;
4018 	}
4019 
4020 	ret = _SQLFetch(stmt, SQL_FETCH_NEXT, 0);
4021 
4022 	if (stmt->dbc->env->attr.odbc_version != SQL_OV_ODBC3) {
4023 		stmt->ard->header.sql_desc_array_size = keep.array_size;
4024 		stmt->ird->header.sql_desc_rows_processed_ptr = keep.rows_processed_ptr;
4025 		stmt->ird->header.sql_desc_array_status_ptr = keep.array_status_ptr;
4026 	}
4027 
4028 	ODBC_EXIT(stmt, ret);
4029 }
4030 
4031 #if (ODBCVER >= 0x0300)
4032 SQLRETURN ODBC_PUBLIC ODBC_API
SQLFetchScroll(SQLHSTMT hstmt,SQLSMALLINT FetchOrientation,SQLLEN FetchOffset)4033 SQLFetchScroll(SQLHSTMT hstmt, SQLSMALLINT FetchOrientation, SQLLEN FetchOffset)
4034 {
4035 	ODBC_ENTER_HSTMT;
4036 
4037 	tdsdump_log(TDS_DBG_FUNC, "SQLFetchScroll(%p, %d, %d)\n", hstmt, FetchOrientation, (int)FetchOffset);
4038 
4039 	if (FetchOrientation != SQL_FETCH_NEXT && !stmt->dbc->cursor_support) {
4040 		odbc_errs_add(&stmt->errs, "HY106", NULL);
4041 		ODBC_EXIT_(stmt);
4042 	}
4043 
4044 	ODBC_EXIT(stmt, _SQLFetch(stmt, FetchOrientation, FetchOffset));
4045 }
4046 #endif
4047 
4048 
4049 #if (ODBCVER >= 0x0300)
4050 SQLRETURN ODBC_PUBLIC ODBC_API
SQLFreeHandle(SQLSMALLINT HandleType,SQLHANDLE Handle)4051 SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle)
4052 {
4053 	tdsdump_log(TDS_DBG_INFO1, "SQLFreeHandle(%d, %p)\n", HandleType, (void *) Handle);
4054 
4055 	switch (HandleType) {
4056 	case SQL_HANDLE_STMT:
4057 		return _SQLFreeStmt(Handle, SQL_DROP, 0);
4058 		break;
4059 	case SQL_HANDLE_DBC:
4060 		return _SQLFreeConnect(Handle);
4061 		break;
4062 	case SQL_HANDLE_ENV:
4063 		return _SQLFreeEnv(Handle);
4064 		break;
4065 	case SQL_HANDLE_DESC:
4066 		return _SQLFreeDesc(Handle);
4067 		break;
4068 	}
4069 	return SQL_ERROR;
4070 }
4071 
4072 static SQLRETURN
_SQLFreeConnect(SQLHDBC hdbc)4073 _SQLFreeConnect(SQLHDBC hdbc)
4074 {
4075 	int i;
4076 
4077 	ODBC_ENTER_HDBC;
4078 
4079 	tdsdump_log(TDS_DBG_FUNC, "_SQLFreeConnect(%p)\n",
4080 			hdbc);
4081 
4082 	tds_close_socket(dbc->tds_socket);
4083 
4084 	/* TODO if connected return error */
4085 	tds_free_socket(dbc->tds_socket);
4086 
4087 	odbc_bcp_free_storage(dbc);
4088 	/* free attributes */
4089 #ifdef TDS_NO_DM
4090 	tds_dstr_free(&dbc->attr.tracefile);
4091 #endif
4092 	tds_dstr_free(&dbc->attr.current_catalog);
4093 	tds_dstr_free(&dbc->attr.translate_lib);
4094 	tds_dstr_zero(&dbc->oldpwd);
4095 	tds_dstr_free(&dbc->oldpwd);
4096 
4097 #ifdef ENABLE_ODBC_WIDE
4098 	tds_dstr_free(&dbc->original_charset);
4099 #endif
4100 	tds_dstr_free(&dbc->dsn);
4101 
4102 	for (i = 0; i < TDS_MAX_APP_DESC; i++) {
4103 		if (dbc->uad[i]) {
4104 			desc_free(dbc->uad[i]);
4105 		}
4106 	}
4107 	odbc_errs_reset(&dbc->errs);
4108 	tds_mutex_unlock(&dbc->mtx);
4109 	tds_mutex_free(&dbc->mtx);
4110 
4111 	free(dbc);
4112 
4113 	return SQL_SUCCESS;
4114 }
4115 
4116 SQLRETURN ODBC_PUBLIC ODBC_API
SQLFreeConnect(SQLHDBC hdbc)4117 SQLFreeConnect(SQLHDBC hdbc)
4118 {
4119 	tdsdump_log(TDS_DBG_INFO2, "SQLFreeConnect(%p)\n", hdbc);
4120 	return _SQLFreeConnect(hdbc);
4121 }
4122 #endif
4123 
4124 static SQLRETURN
_SQLFreeEnv(SQLHENV henv)4125 _SQLFreeEnv(SQLHENV henv)
4126 {
4127 	ODBC_ENTER_HENV;
4128 
4129 	tdsdump_log(TDS_DBG_FUNC, "_SQLFreeEnv(%p)\n",
4130 			henv);
4131 
4132 	odbc_errs_reset(&env->errs);
4133 	tds_free_context(env->tds_ctx);
4134 	tds_mutex_unlock(&env->mtx);
4135 	tds_mutex_free(&env->mtx);
4136 	free(env);
4137 
4138 	return SQL_SUCCESS;
4139 }
4140 
4141 SQLRETURN ODBC_PUBLIC ODBC_API
SQLFreeEnv(SQLHENV henv)4142 SQLFreeEnv(SQLHENV henv)
4143 {
4144 	tdsdump_log(TDS_DBG_FUNC, "SQLFreeEnv(%p)\n", henv);
4145 
4146 	return _SQLFreeEnv(henv);
4147 }
4148 
4149 static SQLRETURN
_SQLFreeStmt(SQLHSTMT hstmt,SQLUSMALLINT fOption,int force)4150 _SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption, int force)
4151 {
4152 	TDSSOCKET *tds;
4153 
4154 	ODBC_ENTER_HSTMT;
4155 
4156 	tdsdump_log(TDS_DBG_FUNC, "_SQLFreeStmt(%p, %d, %d)\n", hstmt, fOption, force);
4157 
4158 	/* check if option correct */
4159 	if (fOption != SQL_DROP && fOption != SQL_CLOSE && fOption != SQL_UNBIND && fOption != SQL_RESET_PARAMS) {
4160 		tdsdump_log(TDS_DBG_ERROR, "SQLFreeStmt: Unknown option %d\n", fOption);
4161 		odbc_errs_add(&stmt->errs, "HY092", NULL);
4162 		ODBC_EXIT_(stmt);
4163 	}
4164 
4165 	/* if we have bound columns, free the temporary list */
4166 	if (fOption == SQL_DROP || fOption == SQL_UNBIND) {
4167 		desc_free_records(stmt->ard);
4168 	}
4169 
4170 	/* do the same for bound parameters */
4171 	if (fOption == SQL_DROP || fOption == SQL_RESET_PARAMS) {
4172 		desc_free_records(stmt->apd);
4173 		desc_free_records(stmt->ipd);
4174 	}
4175 
4176 	/* close statement */
4177 	if (fOption == SQL_DROP || fOption == SQL_CLOSE) {
4178 		SQLRETURN retcode;
4179 
4180 		tds = stmt->tds;
4181 		/*
4182 		 * FIXME -- otherwise make sure the current statement is complete
4183 		 */
4184 		/* do not close other running query ! */
4185 		if (tds && tds->state != TDS_IDLE && tds->state != TDS_DEAD) {
4186 			if (TDS_SUCCEED(tds_send_cancel(tds)))
4187 				tds_process_cancel(tds);
4188 		}
4189 
4190 		/* free cursor */
4191 		retcode = odbc_free_cursor(stmt);
4192 		if (!force && retcode != SQL_SUCCESS)
4193 			ODBC_EXIT(stmt, retcode);
4194 	}
4195 
4196 	/* free it */
4197 	if (fOption == SQL_DROP) {
4198 		SQLRETURN retcode;
4199 
4200 		/* close prepared statement or add to connection */
4201 		retcode = odbc_free_dynamic(stmt);
4202 		if (!force && retcode != SQL_SUCCESS)
4203 			ODBC_EXIT(stmt, retcode);
4204 
4205 		/* detatch from list */
4206 		tds_mutex_lock(&stmt->dbc->mtx);
4207 		if (stmt->next)
4208 			stmt->next->prev = stmt->prev;
4209 		if (stmt->prev)
4210 			stmt->prev->next = stmt->next;
4211 		if (stmt->dbc->stmt_list == stmt)
4212 			stmt->dbc->stmt_list = stmt->next;
4213 		tds_mutex_unlock(&stmt->dbc->mtx);
4214 
4215 		tds_dstr_free(&stmt->query);
4216 		tds_free_param_results(stmt->params);
4217 		odbc_errs_reset(&stmt->errs);
4218 		odbc_unlock_statement(stmt);
4219 		tds_dstr_free(&stmt->cursor_name);
4220 		tds_dstr_free(&stmt->attr.qn_msgtext);
4221 		tds_dstr_free(&stmt->attr.qn_options);
4222 		desc_free(stmt->ird);
4223 		desc_free(stmt->ipd);
4224 		desc_free(stmt->orig_ard);
4225 		desc_free(stmt->orig_apd);
4226 		tds_mutex_unlock(&stmt->mtx);
4227 		tds_mutex_free(&stmt->mtx);
4228 		free(stmt);
4229 
4230 		/* NOTE we freed stmt, do not use ODBC_EXIT */
4231 		return SQL_SUCCESS;
4232 	}
4233 	ODBC_EXIT_(stmt);
4234 }
4235 
4236 SQLRETURN ODBC_PUBLIC ODBC_API
SQLFreeStmt(SQLHSTMT hstmt,SQLUSMALLINT fOption)4237 SQLFreeStmt(SQLHSTMT hstmt, SQLUSMALLINT fOption)
4238 {
4239 	tdsdump_log(TDS_DBG_FUNC, "SQLFreeStmt(%p, %d)\n", hstmt, fOption);
4240 	return _SQLFreeStmt(hstmt, fOption, 0);
4241 }
4242 
4243 
4244 SQLRETURN ODBC_PUBLIC ODBC_API
SQLCloseCursor(SQLHSTMT hstmt)4245 SQLCloseCursor(SQLHSTMT hstmt)
4246 {
4247 	/* TODO cursors */
4248 	/*
4249 	 * Basic implementation for when no driver manager is present.
4250 	 *  - according to ODBC documentation SQLCloseCursor is more or less
4251 	 *    equivalent to SQLFreeStmt(..., SQL_CLOSE).
4252 	 *  - indeed that is what the DM does if it can't find the function
4253 	 *    in the driver, so this is pretty close.
4254 	 */
4255 	/* TODO remember to close cursors really when get implemented */
4256 	/* TODO read all results and discard them or use cancellation ?? test behaviour */
4257 
4258 	tdsdump_log(TDS_DBG_FUNC, "SQLCloseCursor(%p)\n", hstmt);
4259 	return _SQLFreeStmt(hstmt, SQL_CLOSE, 0);
4260 }
4261 
4262 static SQLRETURN
_SQLFreeDesc(SQLHDESC hdesc)4263 _SQLFreeDesc(SQLHDESC hdesc)
4264 {
4265 	ODBC_ENTER_HDESC;
4266 
4267 	tdsdump_log(TDS_DBG_FUNC, "_SQLFreeDesc(%p)\n",
4268 			hdesc);
4269 
4270 	if (desc->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
4271 		odbc_errs_add(&desc->errs, "HY017", NULL);
4272 		ODBC_EXIT_(desc);
4273 	}
4274 
4275 	if (IS_HDBC(desc->parent)) {
4276 		TDS_DBC *dbc = (TDS_DBC *) desc->parent;
4277 		TDS_STMT *stmt;
4278 		int i;
4279 
4280 		/* freeing descriptors associated to statements revert state of statements */
4281 		tds_mutex_lock(&dbc->mtx);
4282 		for (stmt = dbc->stmt_list; stmt != NULL; stmt = stmt->next) {
4283 			if (stmt->ard == desc)
4284 				stmt->ard = stmt->orig_ard;
4285 			if (stmt->apd == desc)
4286 				stmt->apd = stmt->orig_apd;
4287 		}
4288 		tds_mutex_unlock(&dbc->mtx);
4289 
4290 		for (i = 0; i < TDS_MAX_APP_DESC; ++i) {
4291 			if (dbc->uad[i] == desc) {
4292 				dbc->uad[i] = NULL;
4293 				tds_mutex_unlock(&desc->mtx);
4294 				desc_free(desc);
4295 				break;
4296 			}
4297 		}
4298 	}
4299 	return SQL_SUCCESS;
4300 }
4301 
4302 static SQLRETURN
_SQLGetStmtAttr(SQLHSTMT hstmt,SQLINTEGER Attribute,SQLPOINTER Value,SQLINTEGER BufferLength,SQLINTEGER * StringLength WIDE)4303 _SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength WIDE)
4304 {
4305 	void *src;
4306         SQLINTEGER size;
4307 
4308 	ODBC_ENTER_HSTMT;
4309 
4310 	/* TODO assign directly, use macro for size */
4311 	switch (Attribute) {
4312 	case SQL_ATTR_APP_PARAM_DESC:
4313 		size = sizeof(stmt->apd);
4314 		src = &stmt->apd;
4315 		break;
4316 	case SQL_ATTR_APP_ROW_DESC:
4317 		size = sizeof(stmt->ard);
4318 		src = &stmt->ard;
4319 		break;
4320 	case SQL_ATTR_ASYNC_ENABLE:
4321 		size = sizeof(stmt->attr.async_enable);
4322 		src = &stmt->attr.async_enable;
4323 		break;
4324 	case SQL_ATTR_CONCURRENCY:
4325 		size = sizeof(stmt->attr.concurrency);
4326 		src = &stmt->attr.concurrency;
4327 		break;
4328 	case SQL_ATTR_CURSOR_TYPE:
4329 		size = sizeof(stmt->attr.cursor_type);
4330 		src = &stmt->attr.cursor_type;
4331 		break;
4332 	case SQL_ATTR_ENABLE_AUTO_IPD:
4333 		size = sizeof(stmt->attr.enable_auto_ipd);
4334 		src = &stmt->attr.enable_auto_ipd;
4335 		break;
4336 	case SQL_ATTR_FETCH_BOOKMARK_PTR:
4337 		size = sizeof(stmt->attr.fetch_bookmark_ptr);
4338 		src = &stmt->attr.fetch_bookmark_ptr;
4339 		break;
4340 	case SQL_ATTR_KEYSET_SIZE:
4341 		size = sizeof(stmt->attr.keyset_size);
4342 		src = &stmt->attr.keyset_size;
4343 		break;
4344 	case SQL_ATTR_MAX_LENGTH:
4345 		size = sizeof(stmt->attr.max_length);
4346 		src = &stmt->attr.max_length;
4347 		break;
4348 	case SQL_ATTR_MAX_ROWS:
4349 		size = sizeof(stmt->attr.max_rows);
4350 		src = &stmt->attr.max_rows;
4351 		break;
4352 	case SQL_ATTR_METADATA_ID:
4353 		size = sizeof(stmt->attr.metadata_id);
4354 		src = &stmt->attr.noscan;
4355 		break;
4356 	case SQL_ATTR_NOSCAN:
4357 		size = sizeof(stmt->attr.noscan);
4358 		src = &stmt->attr.noscan;
4359 		break;
4360 	case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
4361 		size = sizeof(stmt->apd->header.sql_desc_bind_offset_ptr);
4362 		src = &stmt->apd->header.sql_desc_bind_offset_ptr;
4363 		break;
4364 	case SQL_ATTR_PARAM_BIND_TYPE:
4365 		size = sizeof(stmt->apd->header.sql_desc_bind_type);
4366 		src = &stmt->apd->header.sql_desc_bind_type;
4367 		break;
4368 	case SQL_ATTR_PARAM_OPERATION_PTR:
4369 		size = sizeof(stmt->apd->header.sql_desc_array_status_ptr);
4370 		src = &stmt->apd->header.sql_desc_array_status_ptr;
4371 		break;
4372 	case SQL_ATTR_PARAM_STATUS_PTR:
4373 		size = sizeof(stmt->ipd->header.sql_desc_array_status_ptr);
4374 		src = &stmt->ipd->header.sql_desc_array_status_ptr;
4375 		break;
4376 	case SQL_ATTR_PARAMS_PROCESSED_PTR:
4377 		size = sizeof(stmt->ipd->header.sql_desc_rows_processed_ptr);
4378 		src = &stmt->ipd->header.sql_desc_rows_processed_ptr;
4379 		break;
4380 	case SQL_ATTR_PARAMSET_SIZE:
4381 		size = sizeof(stmt->apd->header.sql_desc_array_size);
4382 		src = &stmt->apd->header.sql_desc_array_size;
4383 		break;
4384 	case SQL_ATTR_QUERY_TIMEOUT:
4385 		size = sizeof(stmt->attr.query_timeout);
4386 		src = &stmt->attr.query_timeout;
4387 		break;
4388 	case SQL_ATTR_RETRIEVE_DATA:
4389 		size = sizeof(stmt->attr.retrieve_data);
4390 		src = &stmt->attr.retrieve_data;
4391 		break;
4392 	case SQL_ATTR_ROW_BIND_OFFSET_PTR:
4393 		size = sizeof(stmt->ard->header.sql_desc_bind_offset_ptr);
4394 		src = &stmt->ard->header.sql_desc_bind_offset_ptr;
4395 		break;
4396 #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
4397 	case SQL_BIND_TYPE:	/* although this is ODBC2 we must support this attribute */
4398 #endif
4399 	case SQL_ATTR_ROW_BIND_TYPE:
4400 		size = sizeof(stmt->ard->header.sql_desc_bind_type);
4401 		src = &stmt->ard->header.sql_desc_bind_type;
4402 		break;
4403 	case SQL_ATTR_ROW_NUMBER:
4404 		/* TODO do not get info every time, cache somewhere */
4405 		if (stmt->cursor && odbc_lock_statement(stmt)) {
4406 			TDS_UINT row_number, row_count;
4407 
4408 			tds_cursor_get_cursor_info(stmt->tds, stmt->cursor, &row_number, &row_count);
4409 			stmt->attr.row_number = row_number;
4410 		}
4411 		size = sizeof(stmt->attr.row_number);
4412 		src = &stmt->attr.row_number;
4413 		break;
4414 	case SQL_ATTR_ROW_OPERATION_PTR:
4415 		size = sizeof(stmt->ard->header.sql_desc_array_status_ptr);
4416 		src = &stmt->ard->header.sql_desc_array_status_ptr;
4417 		break;
4418 	case SQL_ATTR_ROW_STATUS_PTR:
4419 		size = sizeof(stmt->ird->header.sql_desc_array_status_ptr);
4420 		src = &stmt->ird->header.sql_desc_array_status_ptr;
4421 		break;
4422 	case SQL_ATTR_ROWS_FETCHED_PTR:
4423 		size = sizeof(stmt->ird->header.sql_desc_rows_processed_ptr);
4424 		src = &stmt->ird->header.sql_desc_rows_processed_ptr;
4425 		break;
4426 	case SQL_ATTR_ROW_ARRAY_SIZE:
4427 		size = sizeof(stmt->ard->header.sql_desc_array_size);
4428 		src = &stmt->ard->header.sql_desc_array_size;
4429 		break;
4430 	case SQL_ATTR_SIMULATE_CURSOR:
4431 		size = sizeof(stmt->attr.simulate_cursor);
4432 		src = &stmt->attr.simulate_cursor;
4433 		break;
4434 	case SQL_ATTR_USE_BOOKMARKS:
4435 		size = sizeof(stmt->attr.use_bookmarks);
4436 		src = &stmt->attr.use_bookmarks;
4437 		break;
4438 	case SQL_ATTR_CURSOR_SCROLLABLE:
4439 		size = sizeof(stmt->attr.cursor_scrollable);
4440 		src = &stmt->attr.cursor_scrollable;
4441 		break;
4442 	case SQL_ATTR_CURSOR_SENSITIVITY:
4443 		size = sizeof(stmt->attr.cursor_sensitivity);
4444 		src = &stmt->attr.cursor_sensitivity;
4445 		break;
4446 	case SQL_ATTR_IMP_ROW_DESC:
4447 		size = sizeof(stmt->ird);
4448 		src = &stmt->ird;
4449 		break;
4450 	case SQL_ATTR_IMP_PARAM_DESC:
4451 		size = sizeof(stmt->ipd);
4452 		src = &stmt->ipd;
4453 		break;
4454 	case SQL_ROWSET_SIZE:	/* although this is ODBC2 we must support this attribute */
4455 		size = sizeof(stmt->sql_rowset_size);
4456 		src = &stmt->sql_rowset_size;
4457 		break;
4458 	case SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT:
4459 		size = sizeof(stmt->attr.qn_timeout);
4460 		src = &stmt->attr.qn_timeout;
4461 		break;
4462 	case SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT:
4463 		{
4464 			SQLRETURN rc = odbc_set_string_oct(stmt->dbc, Value, BufferLength, StringLength, tds_dstr_cstr(&stmt->attr.qn_msgtext), tds_dstr_len(&stmt->attr.qn_msgtext));
4465 			ODBC_EXIT(stmt, rc);
4466 		}
4467 	case SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS:
4468 		{
4469 			SQLRETURN rc = odbc_set_string_oct(stmt->dbc, Value, BufferLength, StringLength, tds_dstr_cstr(&stmt->attr.qn_options), tds_dstr_len(&stmt->attr.qn_options));
4470 			ODBC_EXIT(stmt, rc);
4471 		}
4472 		/* TODO SQL_COLUMN_SEARCHABLE, although ODBC2 */
4473 	default:
4474 		odbc_errs_add(&stmt->errs, "HY092", NULL);
4475 		ODBC_EXIT_(stmt);
4476 	}
4477 
4478 	memcpy(Value, src, size);
4479 	if (StringLength)
4480 		*StringLength = size;
4481 
4482 	ODBC_EXIT_(stmt);
4483 }
4484 
4485 #if (ODBCVER >= 0x0300)
4486 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetStmtAttr(SQLHSTMT hstmt,SQLINTEGER Attribute,SQLPOINTER Value,SQLINTEGER BufferLength,SQLINTEGER * StringLength)4487 SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4488 {
4489 	tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4490 			hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4491 
4492 	return _SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength _wide0);
4493 }
4494 
4495 #ifdef ENABLE_ODBC_WIDE
4496 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetStmtAttrW(SQLHSTMT hstmt,SQLINTEGER Attribute,SQLPOINTER Value,SQLINTEGER BufferLength,SQLINTEGER * StringLength)4497 SQLGetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER BufferLength, SQLINTEGER * StringLength)
4498 {
4499 	tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtAttr(%p, %d, %p, %d, %p)\n",
4500 			hstmt, (int)Attribute, Value, (int)BufferLength, StringLength);
4501 
4502 	return _SQLGetStmtAttr(hstmt, Attribute, Value, BufferLength, StringLength, 1);
4503 }
4504 #endif
4505 #endif
4506 
4507 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetStmtOption(SQLHSTMT hstmt,SQLUSMALLINT fOption,SQLPOINTER pvParam)4508 SQLGetStmtOption(SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4509 {
4510 	tdsdump_log(TDS_DBG_FUNC, "SQLGetStmtOption(%p, %d, %p)\n",
4511 			hstmt, fOption, pvParam);
4512 
4513 	return _SQLGetStmtAttr(hstmt, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
4514 }
4515 
4516 SQLRETURN ODBC_PUBLIC ODBC_API
SQLNumResultCols(SQLHSTMT hstmt,SQLSMALLINT FAR * pccol)4517 SQLNumResultCols(SQLHSTMT hstmt, SQLSMALLINT FAR * pccol)
4518 {
4519 	ODBC_ENTER_HSTMT;
4520 
4521 	tdsdump_log(TDS_DBG_FUNC, "SQLNumResultCols(%p, %p)\n",
4522 			hstmt, pccol);
4523 
4524 	/*
4525 	 * 3/15/2001 bsb - DBD::ODBC calls SQLNumResultCols on non-result
4526 	 * generating queries such as 'drop table'
4527 	 */
4528 #if 0
4529 	if (stmt->row_status == NOT_IN_ROW) {
4530 		odbc_errs_add(&stmt->errs, "24000", NULL);
4531 		ODBC_EXIT_(stmt);
4532 	}
4533 #endif
4534 	IRD_UPDATE(stmt->ird, &stmt->errs, ODBC_EXIT(stmt, SQL_ERROR));
4535 	*pccol = stmt->ird->header.sql_desc_count;
4536 	ODBC_EXIT_(stmt);
4537 }
4538 
4539 ODBC_FUNC(SQLPrepare, (P(SQLHSTMT,hstmt), PCHARIN(SqlStr,SQLINTEGER) WIDE))
4540 {
4541 	SQLRETURN retcode;
4542 
4543 	ODBC_ENTER_HSTMT;
4544 
4545 	/* try to free dynamic associated */
4546 	retcode = odbc_free_dynamic(stmt);
4547 	if (retcode != SQL_SUCCESS)
4548 		ODBC_EXIT(stmt, retcode);
4549 
4550 	if (SQL_SUCCESS != odbc_set_stmt_query(stmt, szSqlStr, cbSqlStr _wide))
4551 		ODBC_EXIT(stmt, SQL_ERROR);
4552 	stmt->is_prepared_query = 1;
4553 
4554 	/* count parameters */
4555 	stmt->param_count = tds_count_placeholders(tds_dstr_cstr(&stmt->query));
4556 
4557 	/* trasform to native (one time, not for every SQLExecute) */
4558 	if (SQL_SUCCESS != prepare_call(stmt))
4559 		ODBC_EXIT(stmt, SQL_ERROR);
4560 
4561 	/* TODO needed ?? */
4562 	tds_release_dynamic(&stmt->dyn);
4563 
4564 	/* try to prepare query */
4565 	/* TODO support getting info for RPC */
4566 	if (!stmt->prepared_query_is_rpc
4567 		 && (stmt->attr.cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->attr.concurrency == SQL_CONCUR_READ_ONLY)) {
4568 
4569 		tds_free_param_results(stmt->params);
4570 		stmt->params = NULL;
4571 		stmt->param_num = 0;
4572 		stmt->need_reprepare = 0;
4573 		/*
4574 		 * using TDS7+ we need parameters to prepare a query so try
4575 		 * to get them
4576 		 * TDS5 do not need parameters type and we have always to
4577 		 * prepare sepatarely so this is not an issue
4578 		 */
4579 		if (IS_TDS7_PLUS(stmt->dbc->tds_socket->conn)) {
4580 			stmt->need_reprepare = 1;
4581 			ODBC_EXIT_(stmt);
4582 		}
4583 
4584 		tdsdump_log(TDS_DBG_INFO1, "Creating prepared statement\n");
4585 		if (odbc_lock_statement(stmt))
4586 			odbc_prepare(stmt);
4587 	}
4588 
4589 	ODBC_EXIT_(stmt);
4590 }
4591 
4592 /* TDS_NO_COUNT must be -1 for SQLRowCount to return -1 when there is no rowcount */
4593 #if TDS_NO_COUNT != -1
4594 # error TDS_NO_COUNT != -1
4595 #endif
4596 
4597 SQLRETURN
_SQLRowCount(SQLHSTMT hstmt,SQLLEN FAR * pcrow)4598 _SQLRowCount(SQLHSTMT hstmt, SQLLEN FAR * pcrow)
4599 {
4600 	ODBC_ENTER_HSTMT;
4601 
4602 	tdsdump_log(TDS_DBG_FUNC, "_SQLRowCount(%p, %p),  %ld rows \n", hstmt, pcrow, (long)stmt->row_count);
4603 
4604 	*pcrow = stmt->row_count;
4605 
4606 	ODBC_EXIT_(stmt);
4607 }
4608 
4609 SQLRETURN ODBC_PUBLIC ODBC_API
SQLRowCount(SQLHSTMT hstmt,SQLLEN FAR * pcrow)4610 SQLRowCount(SQLHSTMT hstmt, SQLLEN FAR * pcrow)
4611 {
4612 	SQLRETURN rc = _SQLRowCount(hstmt, pcrow);
4613 	tdsdump_log(TDS_DBG_INFO1, "SQLRowCount returns %d, row count %ld\n", rc, (long int) *pcrow);
4614 	return rc;
4615 }
4616 
4617 ODBC_FUNC(SQLSetCursorName, (P(SQLHSTMT,hstmt), PCHARIN(Cursor,SQLSMALLINT) WIDE))
4618 {
4619 	ODBC_ENTER_HSTMT;
4620 
4621 	/* cursor already present, we cannot set name */
4622 	if (stmt->cursor) {
4623 		odbc_errs_add(&stmt->errs, "24000", NULL);
4624 		ODBC_EXIT_(stmt);
4625 	}
4626 
4627 	if (!odbc_dstr_copy(stmt->dbc, &stmt->cursor_name, cbCursor, szCursor)) {
4628 		odbc_errs_add(&stmt->errs, "HY001", NULL);
4629 		ODBC_EXIT_(stmt);
4630 	}
4631 	ODBC_EXIT_(stmt);
4632 }
4633 
4634 ODBC_FUNC(SQLGetCursorName, (P(SQLHSTMT,hstmt), PCHAROUT(Cursor,SQLSMALLINT) WIDE))
4635 {
4636 	SQLRETURN rc;
4637 
4638 	ODBC_ENTER_HSTMT;
4639 
4640 	if ((rc = odbc_set_string(stmt->dbc, szCursor, cbCursorMax, pcbCursor, tds_dstr_cstr(&stmt->cursor_name), -1)))
4641 		odbc_errs_add(&stmt->errs, "01004", NULL);
4642 
4643 	ODBC_EXIT(stmt, rc);
4644 }
4645 
4646 /*
4647  * spinellia@acm.org : copied shamelessly from change_database
4648  * transaction support
4649  * 1 = commit, 0 = rollback
4650  */
4651 static SQLRETURN
change_transaction(TDS_DBC * dbc,int state)4652 change_transaction(TDS_DBC * dbc, int state)
4653 {
4654 	TDSSOCKET *tds = dbc->tds_socket;
4655 	int cont;
4656 	TDSRET ret;
4657 
4658 	tdsdump_log(TDS_DBG_INFO1, "change_transaction(0x%p,%d)\n", dbc, state);
4659 
4660 	if (dbc->attr.autocommit == SQL_AUTOCOMMIT_ON)
4661 		cont = 0;
4662 	else
4663 		cont = 1;
4664 
4665 	/* if pending drop all recordset, don't issue cancel */
4666 	if (tds->state == TDS_PENDING && dbc->current_statement != NULL) {
4667 		/* TODO what happen on multiple errors ?? discard all ?? */
4668 		if (TDS_FAILED(tds_process_simple_query(tds)))
4669 			return SQL_ERROR;
4670 	}
4671 
4672 	/* TODO better idle check, not thread safe */
4673 	if (tds->state == TDS_IDLE)
4674 		tds->query_timeout = dbc->default_query_timeout;
4675 
4676 	if (state)
4677 		ret = tds_submit_commit(tds, cont);
4678 	else
4679 		ret = tds_submit_rollback(tds, cont);
4680 
4681 	if (TDS_FAILED(ret)) {
4682 		odbc_errs_add(&dbc->errs, "HY000", "Could not perform COMMIT or ROLLBACK");
4683 		return SQL_ERROR;
4684 	}
4685 
4686 	if (TDS_FAILED(tds_process_simple_query(tds)))
4687 		return SQL_ERROR;
4688 
4689 	/* TODO some query can collect errors so perhaps it's better to return SUCCES_WITH_INFO in such case... */
4690 	return SQL_SUCCESS;
4691 }
4692 
4693 static SQLRETURN
_SQLTransact(SQLHENV henv,SQLHDBC hdbc,SQLUSMALLINT fType)4694 _SQLTransact(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType)
4695 {
4696 	int op = (fType == SQL_COMMIT ? 1 : 0);
4697 
4698 	/* I may live without a HENV */
4699 	/*     CHECK_HENV; */
4700 	/* ..but not without a HDBC! */
4701 	ODBC_ENTER_HDBC;
4702 
4703 	tdsdump_log(TDS_DBG_FUNC, "_SQLTransact(%p, %p, %d)\n",
4704 			henv, hdbc, fType);
4705 
4706 	ODBC_EXIT(dbc, change_transaction(dbc, op));
4707 }
4708 
4709 SQLRETURN ODBC_PUBLIC ODBC_API
SQLTransact(SQLHENV henv,SQLHDBC hdbc,SQLUSMALLINT fType)4710 SQLTransact(SQLHENV henv, SQLHDBC hdbc, SQLUSMALLINT fType)
4711 {
4712 	tdsdump_log(TDS_DBG_FUNC, "SQLTransact(%p, %p, %d)\n", henv, hdbc, fType);
4713 
4714 	return _SQLTransact(henv, hdbc, fType);
4715 }
4716 
4717 #if ODBCVER >= 0x300
4718 SQLRETURN ODBC_PUBLIC ODBC_API
SQLEndTran(SQLSMALLINT handleType,SQLHANDLE handle,SQLSMALLINT completionType)4719 SQLEndTran(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT completionType)
4720 {
4721 	/*
4722 	 * Do not call the exported SQLTransact(),
4723 	 * because we may wind up calling a function with the same name implemented by the DM.
4724 	 */
4725 	tdsdump_log(TDS_DBG_FUNC, "SQLEndTran(%d, %p, %d)\n", handleType, handle, completionType);
4726 
4727 	switch (handleType) {
4728 	case SQL_HANDLE_ENV:
4729 		return _SQLTransact(handle, NULL, completionType);
4730 	case SQL_HANDLE_DBC:
4731 		return _SQLTransact(NULL, handle, completionType);
4732 	}
4733 	return SQL_ERROR;
4734 }
4735 #endif
4736 
4737 /* end of transaction support */
4738 
4739 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetParam(SQLHSTMT hstmt,SQLUSMALLINT ipar,SQLSMALLINT fCType,SQLSMALLINT fSqlType,SQLULEN cbParamDef,SQLSMALLINT ibScale,SQLPOINTER rgbValue,SQLLEN FAR * pcbValue)4740 SQLSetParam(SQLHSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT fCType, SQLSMALLINT fSqlType, SQLULEN cbParamDef,
4741 	    SQLSMALLINT ibScale, SQLPOINTER rgbValue, SQLLEN FAR * pcbValue)
4742 {
4743 	tdsdump_log(TDS_DBG_FUNC, "SQLSetParam(%p, %d, %d, %d, %u, %d, %p, %p)\n",
4744 			hstmt, ipar, fCType, fSqlType, (unsigned)cbParamDef, ibScale, rgbValue, pcbValue);
4745 
4746 	return _SQLBindParameter(hstmt, ipar, SQL_PARAM_INPUT_OUTPUT, fCType, fSqlType, cbParamDef, ibScale, rgbValue,
4747 				 SQL_SETPARAM_VALUE_MAX, pcbValue);
4748 }
4749 
4750 /**
4751  * SQLColumns
4752  *
4753  * Return column information for a table or view. This is
4754  * mapped to a call to sp_columns which - lucky for us - returns
4755  * the exact result set we need.
4756  *
4757  * exec sp_columns [ @table_name = ] object
4758  *                 [ , [ @table_owner = ] owner ]
4759  *                 [ , [ @table_qualifier = ] qualifier ]
4760  *                 [ , [ @column_name = ] column ]
4761  *                 [ , [ @ODBCVer = ] ODBCVer ]
4762  *
4763  */
4764 ODBC_FUNC(SQLColumns, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),	/* object_qualifier */
4765 	PCHARIN(SchemaName,SQLSMALLINT),	/* object_owner */
4766 	PCHARIN(TableName,SQLSMALLINT),	/* object_name */
4767 	PCHARIN(ColumnName,SQLSMALLINT)	/* column_name */
4768 	WIDE))
4769 {
4770 	int retcode;
4771 
4772 	ODBC_ENTER_HSTMT;
4773 
4774 	retcode =
4775 		odbc_stat_execute(stmt _wide, "sp_columns", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4,
4776 				  "P@table_name", szTableName, cbTableName, "P@table_owner", szSchemaName,
4777 				  cbSchemaName, "O@table_qualifier", szCatalogName, cbCatalogName, "P@column_name", szColumnName,
4778 				  cbColumnName, "V@ODBCVer", (char*) NULL, 0);
4779 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
4780 		odbc_col_setname(stmt, 1, "TABLE_CAT");
4781 		odbc_col_setname(stmt, 2, "TABLE_SCHEM");
4782 		odbc_col_setname(stmt, 7, "COLUMN_SIZE");
4783 		odbc_col_setname(stmt, 8, "BUFFER_LENGTH");
4784 		odbc_col_setname(stmt, 9, "DECIMAL_DIGITS");
4785 		odbc_col_setname(stmt, 10, "NUM_PREC_RADIX");
4786 		if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
4787 			stmt->special_row = ODBC_SPECIAL_COLUMNS;
4788 	}
4789 	ODBC_EXIT_(stmt);
4790 }
4791 
4792 ODBC_FUNC(SQLGetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,Value), P(SQLINTEGER,BufferLength),
4793 	P(SQLINTEGER *,StringLength) WIDE))
4794 {
4795 	const char *p = NULL;
4796 
4797 	ODBC_ENTER_HDBC;
4798 
4799 	tdsdump_log(TDS_DBG_FUNC, "_SQLGetConnectAttr(%p, %d, %p, %d, %p)\n",
4800 			hdbc, (int)Attribute, Value, (int)BufferLength, StringLength);
4801 
4802 	switch (Attribute) {
4803 	case SQL_ATTR_AUTOCOMMIT:
4804 		*((SQLUINTEGER *) Value) = dbc->attr.autocommit;
4805 		break;
4806 #if defined(SQL_ATTR_CONNECTION_DEAD) && defined(SQL_CD_TRUE)
4807 	case SQL_ATTR_CONNECTION_DEAD:
4808 		*((SQLUINTEGER *) Value) = IS_TDSDEAD(dbc->tds_socket) ? SQL_CD_TRUE : SQL_CD_FALSE;
4809 		break;
4810 #endif
4811 	case SQL_ATTR_CONNECTION_TIMEOUT:
4812 		*((SQLUINTEGER *) Value) = dbc->attr.connection_timeout;
4813 		break;
4814 	case SQL_ATTR_ACCESS_MODE:
4815 		*((SQLUINTEGER *) Value) = dbc->attr.access_mode;
4816 		break;
4817 	case SQL_ATTR_CURRENT_CATALOG:
4818 		p = tds_dstr_cstr(&dbc->attr.current_catalog);
4819 		break;
4820 	case SQL_ATTR_LOGIN_TIMEOUT:
4821 		*((SQLUINTEGER *) Value) = dbc->attr.login_timeout;
4822 		break;
4823 	case SQL_ATTR_ODBC_CURSORS:
4824 		*((SQLUINTEGER *) Value) = dbc->attr.odbc_cursors;
4825 		break;
4826 	case SQL_ATTR_PACKET_SIZE:
4827 		*((SQLUINTEGER *) Value) = dbc->attr.packet_size;
4828 		break;
4829 	case SQL_ATTR_QUIET_MODE:
4830 		*((SQLHWND *) Value) = dbc->attr.quite_mode;
4831 		break;
4832 #ifdef TDS_NO_DM
4833 	case SQL_ATTR_TRACE:
4834 		*((SQLUINTEGER *) Value) = dbc->attr.trace;
4835 		break;
4836 	case SQL_ATTR_TRACEFILE:
4837 		p = tds_dstr_cstr(&dbc->attr.tracefile);
4838 		break;
4839 #endif
4840 	case SQL_ATTR_TXN_ISOLATION:
4841 		*((SQLUINTEGER *) Value) = dbc->attr.txn_isolation;
4842 		break;
4843 	case SQL_COPT_SS_MARS_ENABLED:
4844 		*((SQLUINTEGER *) Value) = dbc->attr.mars_enabled;
4845 		break;
4846 	case SQL_ATTR_TRANSLATE_LIB:
4847 	case SQL_ATTR_TRANSLATE_OPTION:
4848 		odbc_errs_add(&dbc->errs, "HYC00", NULL);
4849 		break;
4850 	case SQL_COPT_SS_BCP:
4851 		*((SQLUINTEGER *) Value) = dbc->attr.bulk_enabled;
4852 		break;
4853 	default:
4854 		odbc_errs_add(&dbc->errs, "HY092", NULL);
4855 		break;
4856 	}
4857 
4858 	if (p) {
4859 		SQLRETURN rc = odbc_set_string_oct(dbc, Value, BufferLength, StringLength, p, -1);
4860 		ODBC_EXIT(dbc, rc);
4861 	}
4862 	ODBC_EXIT_(dbc);
4863 }
4864 
4865 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetConnectOption(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLPOINTER pvParam)4866 SQLGetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4867 {
4868 	tdsdump_log(TDS_DBG_FUNC, "SQLGetConnectOption(%p, %u, %p)\n", hdbc, fOption, pvParam);
4869 
4870 	return _SQLGetConnectAttr(hdbc, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL _wide0);
4871 }
4872 
4873 #ifdef ENABLE_ODBC_WIDE
4874 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetConnectOptionW(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLPOINTER pvParam)4875 SQLGetConnectOptionW(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
4876 {
4877 	tdsdump_log(TDS_DBG_FUNC, "SQLGetConnectOptionW(%p, %u, %p)\n", hdbc, fOption, pvParam);
4878 
4879 	return _SQLGetConnectAttr(hdbc, (SQLINTEGER) fOption, pvParam, SQL_MAX_OPTION_STRING_LENGTH, NULL, 1);
4880 }
4881 #endif
4882 
4883 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetData(SQLHSTMT hstmt,SQLUSMALLINT icol,SQLSMALLINT fCType,SQLPOINTER rgbValue,SQLLEN cbValueMax,SQLLEN FAR * pcbValue)4884 SQLGetData(SQLHSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, SQLPOINTER rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue)
4885 {
4886 	/* TODO cursors fetch row if needed ?? */
4887 	TDSCOLUMN *colinfo;
4888 	TDSRESULTINFO *resinfo;
4889 	SQLLEN dummy_cb;
4890 
4891 	ODBC_ENTER_HSTMT;
4892 
4893 	tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n",
4894 			hstmt, icol, fCType, rgbValue, (int)cbValueMax, pcbValue);
4895 
4896 	if (cbValueMax < 0) {
4897 		odbc_errs_add(&stmt->errs, "HY090", NULL);
4898 		ODBC_EXIT_(stmt);
4899 	}
4900 
4901 	/* read data from TDS only if current statement */
4902 	if ((stmt->cursor == NULL && !stmt->tds)
4903 		|| stmt->row_status == PRE_NORMAL_ROW
4904 		|| stmt->row_status == NOT_IN_ROW)
4905 	{
4906 		odbc_errs_add(&stmt->errs, "24000", NULL);
4907 		ODBC_EXIT_(stmt);
4908 	}
4909 
4910 	IRD_CHECK;
4911 
4912 	if (!pcbValue)
4913 		pcbValue = &dummy_cb;
4914 
4915 	resinfo = stmt->cursor ? stmt->cursor->res_info : stmt->tds->current_results;
4916 	if (!resinfo) {
4917 		odbc_errs_add(&stmt->errs, "HY010", NULL);
4918 		ODBC_EXIT_(stmt);
4919 	}
4920 	if (icol <= 0 || icol > resinfo->num_cols) {
4921 		odbc_errs_add(&stmt->errs, "07009", "Column out of range");
4922 		ODBC_EXIT_(stmt);
4923 	}
4924 	colinfo = resinfo->columns[icol - 1];
4925 
4926 	if (colinfo->column_cur_size < 0) {
4927 		/* TODO check what should happen if pcbValue was NULL */
4928 		*pcbValue = SQL_NULL_DATA;
4929 	} else {
4930 		TDS_CHAR *src;
4931 		int srclen;
4932 		int nSybType;
4933 
4934 		if (colinfo->column_text_sqlgetdatapos > 0
4935 		    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
4936 			ODBC_EXIT(stmt, SQL_NO_DATA);
4937 
4938 		src = (TDS_CHAR *) colinfo->column_data;
4939 		srclen = colinfo->column_cur_size;
4940 		if (!is_variable_type(colinfo->column_type))
4941 			colinfo->column_text_sqlgetdatapos = 0;
4942 
4943 		nSybType = tds_get_conversion_type(colinfo->on_server.column_type, colinfo->on_server.column_size);
4944 		if (fCType == SQL_C_DEFAULT)
4945 			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
4946 		if (fCType == SQL_ARD_TYPE) {
4947 			if (icol > stmt->ard->header.sql_desc_count) {
4948 				odbc_errs_add(&stmt->errs, "07009", NULL);
4949 				ODBC_EXIT_(stmt);
4950 			}
4951 			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
4952 		}
4953 		assert(fCType);
4954 
4955 		*pcbValue = odbc_tds2sql(stmt, colinfo, nSybType, src, srclen, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
4956 		if (*pcbValue == SQL_NULL_DATA)
4957 			ODBC_EXIT(stmt, SQL_ERROR);
4958 
4959 		if (is_variable_type(colinfo->column_type) && (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR || fCType == SQL_C_BINARY)) {
4960 			/* avoid infinite SQL_SUCCESS on empty strings */
4961 			if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
4962 				++colinfo->column_text_sqlgetdatapos;
4963 
4964 			if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size) {	/* not all read ?? */
4965 				odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
4966 				ODBC_EXIT_(stmt);
4967 			}
4968 		} else {
4969 			colinfo->column_text_sqlgetdatapos = colinfo->column_cur_size;
4970 			if (is_fixed_type(nSybType) && (fCType == SQL_C_CHAR || fCType == SQL_C_WCHAR || fCType == SQL_C_BINARY)
4971 			    && cbValueMax < *pcbValue) {
4972 				odbc_errs_add(&stmt->errs, "22003", NULL);
4973 				ODBC_EXIT_(stmt);
4974 			}
4975 		}
4976 	}
4977 	ODBC_EXIT_(stmt);
4978 }
4979 
4980 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetFunctions(SQLHDBC hdbc,SQLUSMALLINT fFunction,SQLUSMALLINT FAR * pfExists)4981 SQLGetFunctions(SQLHDBC hdbc, SQLUSMALLINT fFunction, SQLUSMALLINT FAR * pfExists)
4982 {
4983 	int i;
4984 
4985 	ODBC_ENTER_HDBC;
4986 
4987 	tdsdump_log(TDS_DBG_FUNC, "SQLGetFunctions: fFunction is %d\n", fFunction);
4988 	switch (fFunction) {
4989 #if (ODBCVER >= 0x0300)
4990 	case SQL_API_ODBC3_ALL_FUNCTIONS:
4991 		for (i = 0; i < SQL_API_ODBC3_ALL_FUNCTIONS_SIZE; ++i) {
4992 			pfExists[i] = 0;
4993 		}
4994 
4995 		/*
4996 		 * every api available are contained in a macro
4997 		 * all these macro begin with API followed by 2 letter
4998 		 * first letter mean pre ODBC 3 (_) or ODBC 3 (3)
4999 		 * second letter mean implemented (X) or unimplemented (_)
5000 		 * You should copy these macro 3 times... not very good
5001 		 * but works. Perhaps best method is build the bit array statically
5002 		 * and then use it but I don't know how to build it...
5003 		 */
5004 #undef ODBC_ALL_API
5005 #undef ODBC_COLATTRIBUTE
5006 
5007 #if SQL_API_SQLCOLATTRIBUTE != SQL_API_SQLCOLATTRIBUTES
5008 #define ODBC_COLATTRIBUTE(s) s
5009 #else
5010 #define ODBC_COLATTRIBUTE(s)
5011 #endif
5012 
5013 #define ODBC_ALL_API \
5014 	API_X(SQL_API_SQLALLOCCONNECT);\
5015 	API_X(SQL_API_SQLALLOCENV);\
5016 	API3X(SQL_API_SQLALLOCHANDLE);\
5017 	API_X(SQL_API_SQLALLOCSTMT);\
5018 	API_X(SQL_API_SQLBINDCOL);\
5019 	API_X(SQL_API_SQLBINDPARAM);\
5020 	API_X(SQL_API_SQLBINDPARAMETER);\
5021 	API__(SQL_API_SQLBROWSECONNECT);\
5022 	API3_(SQL_API_SQLBULKOPERATIONS);\
5023 	API_X(SQL_API_SQLCANCEL);\
5024 	API3X(SQL_API_SQLCLOSECURSOR);\
5025 	ODBC_COLATTRIBUTE(API3X(SQL_API_SQLCOLATTRIBUTE);)\
5026 	API_X(SQL_API_SQLCOLATTRIBUTES);\
5027 	API_X(SQL_API_SQLCOLUMNPRIVILEGES);\
5028 	API_X(SQL_API_SQLCOLUMNS);\
5029 	API_X(SQL_API_SQLCONNECT);\
5030 	API3X(SQL_API_SQLCOPYDESC);\
5031 	API_X(SQL_API_SQLDESCRIBECOL);\
5032 	API__(SQL_API_SQLDESCRIBEPARAM);\
5033 	API_X(SQL_API_SQLDISCONNECT);\
5034 	API_X(SQL_API_SQLDRIVERCONNECT);\
5035 	API3X(SQL_API_SQLENDTRAN);\
5036 	API_X(SQL_API_SQLERROR);\
5037 	API_X(SQL_API_SQLEXECDIRECT);\
5038 	API_X(SQL_API_SQLEXECUTE);\
5039 	API_X(SQL_API_SQLEXTENDEDFETCH);\
5040 	API_X(SQL_API_SQLFETCH);\
5041 	API3X(SQL_API_SQLFETCHSCROLL);\
5042 	API_X(SQL_API_SQLFOREIGNKEYS);\
5043 	API_X(SQL_API_SQLFREECONNECT);\
5044 	API_X(SQL_API_SQLFREEENV);\
5045 	API3X(SQL_API_SQLFREEHANDLE);\
5046 	API_X(SQL_API_SQLFREESTMT);\
5047 	API3X(SQL_API_SQLGETCONNECTATTR);\
5048 	API_X(SQL_API_SQLGETCONNECTOPTION);\
5049 	API_X(SQL_API_SQLGETCURSORNAME);\
5050 	API_X(SQL_API_SQLGETDATA);\
5051 	API3X(SQL_API_SQLGETDESCFIELD);\
5052 	API3X(SQL_API_SQLGETDESCREC);\
5053 	API3X(SQL_API_SQLGETDIAGFIELD);\
5054 	API3X(SQL_API_SQLGETDIAGREC);\
5055 	API3X(SQL_API_SQLGETENVATTR);\
5056 	API_X(SQL_API_SQLGETFUNCTIONS);\
5057 	API_X(SQL_API_SQLGETINFO);\
5058 	API3X(SQL_API_SQLGETSTMTATTR);\
5059 	API_X(SQL_API_SQLGETSTMTOPTION);\
5060 	API_X(SQL_API_SQLGETTYPEINFO);\
5061 	API_X(SQL_API_SQLMORERESULTS);\
5062 	API_X(SQL_API_SQLNATIVESQL);\
5063 	API_X(SQL_API_SQLNUMPARAMS);\
5064 	API_X(SQL_API_SQLNUMRESULTCOLS);\
5065 	API_X(SQL_API_SQLPARAMDATA);\
5066 	API_X(SQL_API_SQLPARAMOPTIONS);\
5067 	API_X(SQL_API_SQLPREPARE);\
5068 	API_X(SQL_API_SQLPRIMARYKEYS);\
5069 	API_X(SQL_API_SQLPROCEDURECOLUMNS);\
5070 	API_X(SQL_API_SQLPROCEDURES);\
5071 	API_X(SQL_API_SQLPUTDATA);\
5072 	API_X(SQL_API_SQLROWCOUNT);\
5073 	API3X(SQL_API_SQLSETCONNECTATTR);\
5074 	API_X(SQL_API_SQLSETCONNECTOPTION);\
5075 	API_X(SQL_API_SQLSETCURSORNAME);\
5076 	API3X(SQL_API_SQLSETDESCFIELD);\
5077 	API3X(SQL_API_SQLSETDESCREC);\
5078 	API3X(SQL_API_SQLSETENVATTR);\
5079 	API_X(SQL_API_SQLSETPARAM);\
5080 	API_X(SQL_API_SQLSETPOS);\
5081 	API_X(SQL_API_SQLSETSCROLLOPTIONS);\
5082 	API3X(SQL_API_SQLSETSTMTATTR);\
5083 	API_X(SQL_API_SQLSETSTMTOPTION);\
5084 	API_X(SQL_API_SQLSPECIALCOLUMNS);\
5085 	API_X(SQL_API_SQLSTATISTICS);\
5086 	API_X(SQL_API_SQLTABLEPRIVILEGES);\
5087 	API_X(SQL_API_SQLTABLES);\
5088 	API_X(SQL_API_SQLTRANSACT);
5089 
5090 #define API_X(n) if (n >= 0 && n < (16*SQL_API_ODBC3_ALL_FUNCTIONS_SIZE)) pfExists[n/16] |= (1 << n%16);
5091 #define API__(n)
5092 #define API3X(n) if (n >= 0 && n < (16*SQL_API_ODBC3_ALL_FUNCTIONS_SIZE)) pfExists[n/16] |= (1 << n%16);
5093 #define API3_(n)
5094 		ODBC_ALL_API
5095 #undef API_X
5096 #undef API__
5097 #undef API3X
5098 #undef API3_
5099 		break;
5100 #endif
5101 
5102 	case SQL_API_ALL_FUNCTIONS:
5103 		tdsdump_log(TDS_DBG_FUNC, "SQLGetFunctions: " "fFunction is SQL_API_ALL_FUNCTIONS\n");
5104 		for (i = 0; i < 100; ++i) {
5105 			pfExists[i] = SQL_FALSE;
5106 		}
5107 
5108 #define API_X(n) if (n >= 0 && n < 100) pfExists[n] = SQL_TRUE;
5109 #define API__(n)
5110 #define API3X(n)
5111 #define API3_(n)
5112 		ODBC_ALL_API
5113 #undef API_X
5114 #undef API__
5115 #undef API3X
5116 #undef API3_
5117 		break;
5118 #define API_X(n) case n:
5119 #define API__(n)
5120 #if (ODBCVER >= 0x300)
5121 #define API3X(n) case n:
5122 #else
5123 #define API3X(n)
5124 #endif
5125 #define API3_(n)
5126 		ODBC_ALL_API
5127 #undef API_X
5128 #undef API__
5129 #undef API3X
5130 #undef API3_
5131 		*pfExists = SQL_TRUE;
5132 		break;
5133 	default:
5134 		*pfExists = SQL_FALSE;
5135 		break;
5136 	}
5137 	ODBC_EXIT(dbc, SQL_SUCCESS);
5138 #undef ODBC_ALL_API
5139 }
5140 
5141 
5142 static SQLRETURN
_SQLGetInfo(TDS_DBC * dbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT FAR * pcbInfoValue _WIDE)5143 _SQLGetInfo(TDS_DBC * dbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax,
5144 	    SQLSMALLINT FAR * pcbInfoValue _WIDE)
5145 {
5146 	const char *p = NULL;
5147 	char buf[32];
5148 	TDSSOCKET *tds;
5149 	int is_ms = -1;
5150 	unsigned int smajor = 6;
5151 	SQLUINTEGER mssql7plus_mask = 0;
5152 	int out_len = -1;
5153 
5154 	tdsdump_log(TDS_DBG_FUNC, "_SQLGetInfo(%p, %u, %p, %d, %p)\n",
5155 			dbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
5156 
5157 #define SIVAL out_len = sizeof(SQLSMALLINT), *((SQLSMALLINT *) rgbInfoValue)
5158 #define USIVAL out_len = sizeof(SQLUSMALLINT), *((SQLUSMALLINT *) rgbInfoValue)
5159 #define IVAL out_len = sizeof(SQLINTEGER), *((SQLINTEGER *) rgbInfoValue)
5160 #define UIVAL out_len = sizeof(SQLUINTEGER), *((SQLUINTEGER *) rgbInfoValue)
5161 #define ULVAL out_len = sizeof(SQLULEN), *((SQLULEN *) rgbInfoValue)
5162 
5163 	if ((tds = dbc->tds_socket) != NULL) {
5164 		is_ms = TDS_IS_MSSQL(tds);
5165 		smajor = (tds->conn->product_version >> 24) & 0x7F;
5166 		if (is_ms && smajor >= 7)
5167 			mssql7plus_mask = ~((SQLUINTEGER) 0);
5168 	}
5169 
5170 	switch (fInfoType) {
5171 	case SQL_ACCESSIBLE_PROCEDURES:
5172 	case SQL_ACCESSIBLE_TABLES:
5173 		p = "Y";
5174 		break;
5175 		/* SQL_ACTIVE_CONNECTIONS renamed to SQL_MAX_DRIVER_CONNECTIONS */
5176 #if (ODBCVER >= 0x0300)
5177 	case SQL_ACTIVE_ENVIRONMENTS:
5178 		UIVAL = 0;
5179 		break;
5180 #endif /* ODBCVER >= 0x0300 */
5181 #if (ODBCVER >= 0x0300)
5182 	case SQL_AGGREGATE_FUNCTIONS:
5183 		UIVAL = SQL_AF_ALL;
5184 		break;
5185 	case SQL_ALTER_DOMAIN:
5186 		UIVAL = 0;
5187 		break;
5188 #endif /* ODBCVER >= 0x0300 */
5189 	case SQL_ALTER_TABLE:
5190 		UIVAL = SQL_AT_ADD_COLUMN | SQL_AT_ADD_COLUMN_DEFAULT | SQL_AT_ADD_COLUMN_SINGLE | SQL_AT_ADD_CONSTRAINT |
5191 			SQL_AT_ADD_TABLE_CONSTRAINT | SQL_AT_CONSTRAINT_NAME_DEFINITION | SQL_AT_DROP_COLUMN_RESTRICT;
5192 		break;
5193 #if (ODBCVER >= 0x0300)
5194 	case SQL_ASYNC_MODE:
5195 		/* TODO we hope so in a not-too-far future */
5196 		/* UIVAL = SQL_AM_STATEMENT; */
5197 		UIVAL = SQL_AM_NONE;
5198 		break;
5199 	case SQL_BATCH_ROW_COUNT:
5200 		UIVAL = SQL_BRC_EXPLICIT;
5201 		break;
5202 	case SQL_BATCH_SUPPORT:
5203 		UIVAL = SQL_BS_ROW_COUNT_EXPLICIT | SQL_BS_ROW_COUNT_PROC | SQL_BS_SELECT_EXPLICIT | SQL_BS_SELECT_PROC;
5204 		break;
5205 #endif /* ODBCVER >= 0x0300 */
5206 	case SQL_BOOKMARK_PERSISTENCE:
5207 		/* TODO ??? */
5208 		UIVAL = SQL_BP_DELETE | SQL_BP_SCROLL | SQL_BP_UPDATE;
5209 		break;
5210 	case SQL_CATALOG_LOCATION:
5211 		SIVAL = SQL_CL_START;
5212 		break;
5213 #if (ODBCVER >= 0x0300)
5214 	case SQL_CATALOG_NAME:
5215 		p = "Y";
5216 		break;
5217 #endif /* ODBCVER >= 0x0300 */
5218 	case SQL_CATALOG_NAME_SEPARATOR:
5219 		p = ".";
5220 		break;
5221 	case SQL_CATALOG_TERM:
5222 		p = "database";
5223 		break;
5224 	case SQL_CATALOG_USAGE:
5225 		UIVAL = SQL_CU_DML_STATEMENTS | SQL_CU_PROCEDURE_INVOCATION | SQL_CU_TABLE_DEFINITION;
5226 		break;
5227 		/* TODO */
5228 #if 0
5229 	case SQL_COLLATION_SEQ:
5230 		break;
5231 #endif
5232 	case SQL_COLUMN_ALIAS:
5233 		p = "Y";
5234 		break;
5235 	case SQL_CONCAT_NULL_BEHAVIOR:
5236 		if (is_ms == -1)
5237 			return SQL_ERROR;
5238 		/* TODO a bit more complicate for mssql2k.. */
5239 		SIVAL = (!is_ms || smajor < 7) ? SQL_CB_NON_NULL : SQL_CB_NULL;
5240 		break;
5241 		/* TODO SQL_CONVERT_BIGINT SQL_CONVERT_GUID SQL_CONVERT_DATE SQL_CONVERT_TIME */
5242 		/* For Sybase/MSSql6.x we return 0 cause NativeSql is not so implemented */
5243 	case SQL_CONVERT_BINARY:
5244 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_VARCHAR |
5245 			 SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_TINYINT | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR |
5246 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5247 		break;
5248 	case SQL_CONVERT_BIT:
5249 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5250 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5251 			 SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5252 		break;
5253 	case SQL_CONVERT_CHAR:
5254 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5255 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5256 			 SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5257 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5258 		break;
5259 	case SQL_CONVERT_DECIMAL:
5260 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5261 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5262 			 SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5263 		break;
5264 	case SQL_CONVERT_FLOAT:
5265 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5266 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) &
5267 			mssql7plus_mask;
5268 		break;
5269 	case SQL_CONVERT_INTEGER:
5270 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5271 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5272 			 SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5273 		break;
5274 	case SQL_CONVERT_LONGVARCHAR:
5275 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5276 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5277 		break;
5278 	case SQL_CONVERT_NUMERIC:
5279 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5280 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5281 			 SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5282 		break;
5283 	case SQL_CONVERT_REAL:
5284 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5285 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BIT | SQL_CVT_TINYINT | SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) &
5286 			mssql7plus_mask;
5287 		break;
5288 	case SQL_CONVERT_SMALLINT:
5289 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5290 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5291 			 SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5292 		break;
5293 	case SQL_CONVERT_TIMESTAMP:
5294 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_TIMESTAMP | SQL_CVT_WCHAR |
5295 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5296 		break;
5297 	case SQL_CONVERT_TINYINT:
5298 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5299 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT | SQL_CVT_TINYINT |
5300 			 SQL_CVT_WCHAR | SQL_CVT_WVARCHAR) & mssql7plus_mask;
5301 		break;
5302 	case SQL_CONVERT_VARBINARY:
5303 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_VARCHAR |
5304 			 SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_TINYINT | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR |
5305 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5306 		break;
5307 	case SQL_CONVERT_VARCHAR:
5308 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5309 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5310 			 SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5311 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5312 		break;
5313 	case SQL_CONVERT_LONGVARBINARY:
5314 		UIVAL = (SQL_CVT_BINARY | SQL_CVT_LONGVARBINARY | SQL_CVT_VARBINARY) & mssql7plus_mask;
5315 		break;
5316 	case SQL_CONVERT_WLONGVARCHAR:
5317 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5318 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5319 		break;
5320 #if (ODBCVER >= 0x0300)
5321 	case SQL_CONVERT_WCHAR:
5322 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5323 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5324 			 SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5325 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5326 		break;
5327 	case SQL_CONVERT_WVARCHAR:
5328 		UIVAL = (SQL_CVT_CHAR | SQL_CVT_NUMERIC | SQL_CVT_DECIMAL | SQL_CVT_INTEGER | SQL_CVT_SMALLINT | SQL_CVT_FLOAT |
5329 			 SQL_CVT_REAL | SQL_CVT_VARCHAR | SQL_CVT_LONGVARCHAR | SQL_CVT_BINARY | SQL_CVT_VARBINARY | SQL_CVT_BIT |
5330 			 SQL_CVT_TINYINT | SQL_CVT_TIMESTAMP | SQL_CVT_LONGVARBINARY | SQL_CVT_WCHAR | SQL_CVT_WLONGVARCHAR |
5331 			 SQL_CVT_WVARCHAR) & mssql7plus_mask;
5332 		break;
5333 #endif /* ODBCVER >= 0x0300 */
5334 	case SQL_CONVERT_FUNCTIONS:
5335 		/* TODO no CAST for Sybase ?? */
5336 		UIVAL = SQL_FN_CVT_CONVERT | SQL_FN_CVT_CAST;
5337 		break;
5338 #if (ODBCVER >= 0x0300)
5339 	case SQL_CREATE_ASSERTION:
5340 	case SQL_CREATE_CHARACTER_SET:
5341 	case SQL_CREATE_COLLATION:
5342 	case SQL_CREATE_DOMAIN:
5343 		UIVAL = 0;
5344 		break;
5345 	case SQL_CREATE_SCHEMA:
5346 		UIVAL = SQL_CS_AUTHORIZATION | SQL_CS_CREATE_SCHEMA;
5347 		break;
5348 	case SQL_CREATE_TABLE:
5349 		UIVAL = SQL_CT_CREATE_TABLE;
5350 		break;
5351 	case SQL_CREATE_TRANSLATION:
5352 		UIVAL = 0;
5353 		break;
5354 	case SQL_CREATE_VIEW:
5355 		UIVAL = SQL_CV_CHECK_OPTION | SQL_CV_CREATE_VIEW;
5356 		break;
5357 #endif /* ODBCVER >= 0x0300 */
5358 	case SQL_CORRELATION_NAME:
5359 		USIVAL = SQL_CN_ANY;
5360 		break;
5361 	case SQL_CURSOR_COMMIT_BEHAVIOR:
5362 		/* currently cursors are not supported however sql server close automaticly cursors on commit */
5363 		/* TODO cursors test what happen if rollback, cursors get properly deleted ?? */
5364 		USIVAL = SQL_CB_CLOSE;
5365 		break;
5366 	case SQL_CURSOR_ROLLBACK_BEHAVIOR:
5367 		USIVAL = SQL_CB_CLOSE;
5368 		break;
5369 	case SQL_CURSOR_SENSITIVITY:
5370 		UIVAL = SQL_SENSITIVE;
5371 		break;
5372 	case SQL_DATABASE_NAME:
5373 		p = tds_dstr_cstr(&dbc->attr.current_catalog);
5374 		break;
5375 	case SQL_DATA_SOURCE_NAME:
5376 		p = tds_dstr_cstr(&dbc->dsn);
5377 		break;
5378 	case SQL_DATA_SOURCE_READ_ONLY:
5379 		/*
5380 		 * TODO: determine the right answer from connection
5381 		 * attribute SQL_ATTR_ACCESS_MODE
5382 		 */
5383 		p = "N";	/* false, writable */
5384 		break;
5385 #if (ODBCVER >= 0x0300)
5386 	case SQL_DATETIME_LITERALS:
5387 		/* TODO ok ?? */
5388 		UIVAL = 0;
5389 		break;
5390 #endif /* ODBCVER >= 0x0300 */
5391 	case SQL_DBMS_NAME:
5392 		p = tds ? tds->conn->product_name : NULL;
5393 		break;
5394 	case SQL_DBMS_VER:
5395 		if (!dbc->tds_socket)
5396 			return SQL_ERROR;
5397 		odbc_rdbms_version(dbc->tds_socket, buf);
5398 		p = buf;
5399 		break;
5400 #if (ODBCVER >= 0x0300)
5401 	case SQL_DDL_INDEX:
5402 		UIVAL = 0;
5403 		break;
5404 #endif /* ODBCVER >= 0x0300 */
5405 	case SQL_DEFAULT_TXN_ISOLATION:
5406 		UIVAL = SQL_TXN_READ_COMMITTED;
5407 		break;
5408 #if (ODBCVER >= 0x0300)
5409 	case SQL_DESCRIBE_PARAMETER:
5410 		/* TODO */
5411 		p = "N";
5412 		break;
5413 #endif /* ODBCVER >= 0x0300 */
5414 #ifdef TDS_NO_DM
5415 	case SQL_DRIVER_HDBC:
5416 		ULVAL = (SQLULEN) dbc;
5417 		break;
5418 	case SQL_DRIVER_HENV:
5419 		ULVAL = (SQLULEN) dbc->env;
5420 		break;
5421 	case SQL_DRIVER_HSTMT:
5422 		ULVAL = (SQLULEN) dbc->current_statement;
5423 		break;
5424 #endif
5425 	case SQL_DRIVER_NAME:	/* ODBC 2.0 */
5426 		p = "libtdsodbc.so";
5427 		break;
5428 	case SQL_DRIVER_ODBC_VER:
5429 		p = "03.50";
5430 		break;
5431 	case SQL_DRIVER_VER:
5432 		sprintf(buf, "%02d.%02d.%04d", TDS_VERSION_MAJOR,
5433 			TDS_VERSION_MINOR, TDS_VERSION_SUBVERSION);
5434 		p = buf;
5435 		break;
5436 #if (ODBCVER >= 0x0300)
5437 	case SQL_DROP_ASSERTION:
5438 	case SQL_DROP_CHARACTER_SET:
5439 	case SQL_DROP_COLLATION:
5440 	case SQL_DROP_DOMAIN:
5441 	case SQL_DROP_SCHEMA:
5442 		UIVAL = 0;
5443 		break;
5444 	case SQL_DROP_TABLE:
5445 		UIVAL = SQL_DT_DROP_TABLE;
5446 		break;
5447 	case SQL_DROP_TRANSLATION:
5448 		UIVAL = 0;
5449 		break;
5450 	case SQL_DROP_VIEW:
5451 		UIVAL = SQL_DV_DROP_VIEW;
5452 		break;
5453 	case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
5454 		if (dbc->cursor_support)
5455 			/* TODO cursor SQL_CA1_BULK_ADD SQL_CA1_POS_REFRESH SQL_CA1_SELECT_FOR_UPDATE */
5456 			UIVAL = SQL_CA1_ABSOLUTE | SQL_CA1_NEXT | SQL_CA1_RELATIVE |
5457 				SQL_CA1_LOCK_NO_CHANGE |
5458 				SQL_CA1_POS_DELETE | SQL_CA1_POS_POSITION | SQL_CA1_POS_UPDATE |
5459 				SQL_CA1_POSITIONED_UPDATE | SQL_CA1_POSITIONED_DELETE;
5460 		else
5461 			UIVAL = 0;
5462 		break;
5463 	case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
5464 		/* TODO cursors */
5465 		/* Cursors not supported yet */
5466 		/*
5467 		 * Should be SQL_CA2_LOCK_CONCURRENCY SQL_CA2_MAX_ROWS_CATALOG SQL_CA2_MAX_ROWS_DELETE
5468  		 * SQL_CA2_MAX_ROWS_INSERT SQL_CA2_MAX_ROWS_SELECT SQL_CA2_MAX_ROWS_UPDATE SQL_CA2_OPT_ROWVER_CONCURRENCY
5469  		 * SQL_CA2_OPT_VALUES_CONCURRENCY SQL_CA2_READ_ONLY_CONCURRENCY SQL_CA2_SENSITIVITY_ADDITIONS
5470  		 * SQL_CA2_SENSITIVITY_UPDATES SQL_CA2_SIMULATE_UNIQUE
5471 		 */
5472 		UIVAL = 0;
5473 		break;
5474 #endif /* ODBCVER >= 0x0300 */
5475 	case SQL_EXPRESSIONS_IN_ORDERBY:
5476 		p = "Y";
5477 		break;
5478 	case SQL_FILE_USAGE:
5479 		USIVAL = SQL_FILE_NOT_SUPPORTED;
5480 		break;
5481 	case SQL_FETCH_DIRECTION:
5482 		if (dbc->cursor_support)
5483 			/* TODO cursors SQL_FD_FETCH_BOOKMARK */
5484 			UIVAL = SQL_FD_FETCH_ABSOLUTE|SQL_FD_FETCH_FIRST|SQL_FD_FETCH_LAST|SQL_FD_FETCH_NEXT|SQL_FD_FETCH_PRIOR|SQL_FD_FETCH_RELATIVE;
5485 		else
5486 			UIVAL = 0;
5487 		break;
5488 #if (ODBCVER >= 0x0300)
5489 	case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
5490 		if (dbc->cursor_support)
5491 			/* TODO cursors SQL_CA1_SELECT_FOR_UPDATE */
5492 			UIVAL = SQL_CA1_NEXT|SQL_CA1_POSITIONED_DELETE|SQL_CA1_POSITIONED_UPDATE;
5493 		else
5494 			UIVAL = 0;
5495 		break;
5496 	case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
5497 		/* TODO cursors */
5498 		/* Cursors not supported yet */
5499 		/*
5500 		 * Should be SQL_CA2_LOCK_CONCURRENCY SQL_CA2_MAX_ROWS_CATALOG SQL_CA2_MAX_ROWS_DELETE
5501  		 * SQL_CA2_MAX_ROWS_INSERT SQL_CA2_MAX_ROWS_SELECT SQL_CA2_MAX_ROWS_UPDATE SQL_CA2_OPT_ROWVER_CONCURRENCY
5502  		 * SQL_CA2_OPT_VALUES_CONCURRENCY SQL_CA2_READ_ONLY_CONCURRENCY
5503 		 */
5504 		UIVAL = 0;
5505 		break;
5506 #endif /* ODBCVER >= 0x0300 */
5507 	case SQL_GETDATA_EXTENSIONS:
5508 		/* TODO FreeTDS support more ?? */
5509 		UIVAL = SQL_GD_BLOCK;
5510 		break;
5511 	case SQL_GROUP_BY:
5512 		USIVAL = SQL_GB_GROUP_BY_CONTAINS_SELECT;
5513 		break;
5514 	case SQL_IDENTIFIER_CASE:
5515 		/* TODO configuration dependend */
5516 		USIVAL = SQL_IC_MIXED;
5517 		break;
5518 	case SQL_IDENTIFIER_QUOTE_CHAR:
5519 		p = "\"";
5520 		/* TODO workaround for Sybase, use SET QUOTED_IDENTIFIER ON and fix unwanted quote */
5521 		if (!is_ms)
5522 			p = "";
5523 		break;
5524 #if (ODBCVER >= 0x0300)
5525 	case SQL_INDEX_KEYWORDS:
5526 		UIVAL = SQL_IK_ASC | SQL_IK_DESC;
5527 		break;
5528 #endif /* ODBCVER >= 0x0300 */
5529 	case SQL_INFO_SCHEMA_VIEWS:
5530 		/* TODO finish */
5531 		UIVAL = 0;
5532 		break;
5533 	case SQL_INSERT_STATEMENT:
5534 		UIVAL = 0;
5535 		break;
5536 		/* renamed from SQL_ODBC_SQL_OPT_IEF */
5537 	case SQL_INTEGRITY:
5538 		p = "Y";
5539 		break;
5540 	case SQL_KEYSET_CURSOR_ATTRIBUTES1:
5541 	case SQL_KEYSET_CURSOR_ATTRIBUTES2:
5542 		/* TODO cursors */
5543 		UIVAL = 0;
5544 		break;
5545 	case SQL_KEYWORDS:
5546 		/* TODO ok for Sybase ? */
5547 		p = "BREAK,BROWSE,BULK,CHECKPOINT,CLUSTERED,"
5548 			"COMMITTED,COMPUTE,CONFIRM,CONTROLROW,DATABASE,"
5549 			"DBCC,DISK,DISTRIBUTED,DUMMY,DUMP,ERRLVL,"
5550 			"ERROREXIT,EXIT,FILE,FILLFACTOR,FLOPPY,HOLDLOCK,"
5551 			"IDENTITY_INSERT,IDENTITYCOL,IF,KILL,LINENO,"
5552 			"LOAD,MIRROREXIT,NONCLUSTERED,OFF,OFFSETS,ONCE,"
5553 			"OVER,PERCENT,PERM,PERMANENT,PLAN,PRINT,PROC,"
5554 			"PROCESSEXIT,RAISERROR,READ,READTEXT,RECONFIGURE,"
5555 			"REPEATABLE,RETURN,ROWCOUNT,RULE,SAVE,SERIALIZABLE,"
5556 			"SETUSER,SHUTDOWN,STATISTICS,TAPE,TEMP,TEXTSIZE,"
5557 			"TRAN,TRIGGER,TRUNCATE,TSEQUEL,UNCOMMITTED," "UPDATETEXT,USE,WAITFOR,WHILE,WRITETEXT";
5558 		break;
5559 	case SQL_LIKE_ESCAPE_CLAUSE:
5560 		p = "Y";
5561 		break;
5562 	case SQL_LOCK_TYPES:
5563 		if (dbc->cursor_support)
5564 			IVAL = SQL_LCK_NO_CHANGE;
5565 		else
5566 			IVAL = 0;
5567 		break;
5568 #if (ODBCVER >= 0x0300)
5569 	case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS:
5570 		UIVAL = 1;
5571 		break;
5572 #endif /* ODBCVER >= 0x0300 */
5573 		/* TODO same limits for Sybase ? */
5574 	case SQL_MAX_BINARY_LITERAL_LEN:
5575 		UIVAL = 131072;
5576 		break;
5577 	case SQL_MAX_CHAR_LITERAL_LEN:
5578 		UIVAL = 131072;
5579 		break;
5580 	case SQL_MAX_CONCURRENT_ACTIVITIES:
5581 		USIVAL = 1;
5582 		break;
5583 	case SQL_MAX_COLUMNS_IN_GROUP_BY:
5584 	case SQL_MAX_COLUMNS_IN_INDEX:
5585 	case SQL_MAX_COLUMNS_IN_ORDER_BY:
5586 		/* TODO Sybase ? */
5587 		USIVAL = 16;
5588 		break;
5589 	case SQL_MAX_COLUMNS_IN_SELECT:
5590 		/* TODO Sybase ? */
5591 		USIVAL = 4000;
5592 		break;
5593 	case SQL_MAX_COLUMNS_IN_TABLE:
5594 		/* TODO Sybase ? */
5595 		USIVAL = 250;
5596 		break;
5597 	case SQL_MAX_DRIVER_CONNECTIONS:
5598 		USIVAL = 0;
5599 		break;
5600 	case SQL_MAX_IDENTIFIER_LEN:
5601 		if (is_ms == -1)
5602 			return SQL_ERROR;
5603 		USIVAL = (!is_ms || smajor < 7) ? 30 : 128;
5604 		break;
5605 	case SQL_MAX_INDEX_SIZE:
5606 		UIVAL = 127;
5607 		break;
5608 	case SQL_MAX_PROCEDURE_NAME_LEN:
5609 		if (is_ms == -1)
5610 			return SQL_ERROR;
5611 		/* TODO Sybase ? */
5612 		USIVAL = (is_ms && smajor >= 7) ? 134 : 36;
5613 		break;
5614 	case SQL_MAX_ROW_SIZE:
5615 		if (is_ms == -1)
5616 			return SQL_ERROR;
5617 		/* TODO Sybase ? */
5618 		UIVAL = (is_ms && smajor >= 7) ? 8062 : 1962;
5619 		break;
5620 	case SQL_MAX_ROW_SIZE_INCLUDES_LONG:
5621 		p = "N";
5622 		break;
5623 	case SQL_MAX_STATEMENT_LEN:
5624 		/* TODO Sybase ? */
5625 		UIVAL = 131072;
5626 		break;
5627 	case SQL_MAX_TABLES_IN_SELECT:
5628 		/* TODO Sybase ? */
5629 		USIVAL = 16;
5630 		break;
5631 	case SQL_MAX_USER_NAME_LEN:
5632 		/* TODO Sybase ? */
5633 		if (is_ms == -1)
5634 			return SQL_ERROR;
5635 		USIVAL = (is_ms && smajor >= 7) ? 128 : 30;
5636 		break;
5637 	case SQL_MAX_COLUMN_NAME_LEN:
5638 	case SQL_MAX_CURSOR_NAME_LEN:
5639 	case SQL_MAX_SCHEMA_NAME_LEN:
5640 	case SQL_MAX_CATALOG_NAME_LEN:
5641 	case SQL_MAX_TABLE_NAME_LEN:
5642 		/* TODO Sybase ? */
5643 		if (is_ms == -1)
5644 			return SQL_ERROR;
5645 		USIVAL = (is_ms && smajor >= 7) ? 128 : 30;
5646 		break;
5647 	case SQL_MULT_RESULT_SETS:
5648 		p = "Y";
5649 		break;
5650 	case SQL_MULTIPLE_ACTIVE_TXN:
5651 		p = "Y";
5652 		break;
5653 	case SQL_NEED_LONG_DATA_LEN:
5654 		/* current implementation do not require length, however future will, so is correct to return yes */
5655 		p = "Y";
5656 		break;
5657 	case SQL_NON_NULLABLE_COLUMNS:
5658 		USIVAL = SQL_NNC_NON_NULL;
5659 		break;
5660 	case SQL_NULL_COLLATION:
5661 		USIVAL = SQL_NC_LOW;
5662 		break;
5663 	case SQL_NUMERIC_FUNCTIONS:
5664 		UIVAL = (SQL_FN_NUM_ABS | SQL_FN_NUM_ACOS | SQL_FN_NUM_ASIN | SQL_FN_NUM_ATAN | SQL_FN_NUM_ATAN2 |
5665 			 SQL_FN_NUM_CEILING | SQL_FN_NUM_COS | SQL_FN_NUM_COT | SQL_FN_NUM_DEGREES | SQL_FN_NUM_EXP |
5666 			 SQL_FN_NUM_FLOOR | SQL_FN_NUM_LOG | SQL_FN_NUM_LOG10 | SQL_FN_NUM_MOD | SQL_FN_NUM_PI | SQL_FN_NUM_POWER |
5667 			 SQL_FN_NUM_RADIANS | SQL_FN_NUM_RAND | SQL_FN_NUM_ROUND | SQL_FN_NUM_SIGN | SQL_FN_NUM_SIN |
5668 			 SQL_FN_NUM_SQRT | SQL_FN_NUM_TAN) & mssql7plus_mask;
5669 		break;
5670 	case SQL_ODBC_API_CONFORMANCE:
5671 		SIVAL = SQL_OAC_LEVEL2;
5672 		break;
5673 #if (ODBCVER >= 0x0300)
5674 	case SQL_ODBC_INTERFACE_CONFORMANCE:
5675 		UIVAL = SQL_OAC_LEVEL2;
5676 		break;
5677 #endif /* ODBCVER >= 0x0300 */
5678 	case SQL_ODBC_SAG_CLI_CONFORMANCE:
5679 		SIVAL = SQL_OSCC_NOT_COMPLIANT;
5680 		break;
5681 	case SQL_ODBC_SQL_CONFORMANCE:
5682 		SIVAL = SQL_OSC_CORE;
5683 		break;
5684 #ifdef TDS_NO_DM
5685 	case SQL_ODBC_VER:
5686 		/* TODO check format ##.##.0000 */
5687 		p = VERSION;
5688 		break;
5689 #endif
5690 #if (ODBCVER >= 0x0300)
5691 	case SQL_OJ_CAPABILITIES:
5692 		UIVAL = SQL_OJ_ALL_COMPARISON_OPS | SQL_OJ_FULL | SQL_OJ_INNER | SQL_OJ_LEFT | SQL_OJ_NESTED | SQL_OJ_NOT_ORDERED |
5693 			SQL_OJ_RIGHT;
5694 		break;
5695 #endif /* ODBCVER >= 0x0300 */
5696 	case SQL_ORDER_BY_COLUMNS_IN_SELECT:
5697 		p = "N";
5698 		break;
5699 	case SQL_OUTER_JOINS:
5700 		p = "Y";
5701 		break;
5702 #if (ODBCVER >= 0x0300)
5703 	case SQL_PARAM_ARRAY_ROW_COUNTS:
5704 		UIVAL = SQL_PARC_BATCH;
5705 		break;
5706 	case SQL_PARAM_ARRAY_SELECTS:
5707 		UIVAL = SQL_PAS_BATCH;
5708 		break;
5709 #endif /* ODBCVER >= 0x0300 */
5710 	case SQL_POS_OPERATIONS:
5711 		if (dbc->cursor_support)
5712 			/* TODO cursors SQL_POS_ADD SQL_POS_REFRESH */
5713 			/* test REFRESH, ADD under mssql, under Sybase I don't know how to do it but dblib do */
5714 			IVAL = SQL_POS_DELETE | SQL_POS_POSITION | SQL_POS_UPDATE;
5715 		else
5716 			IVAL = 0;
5717 		break;
5718 	case SQL_POSITIONED_STATEMENTS:
5719 		/* TODO cursors SQL_PS_SELECT_FOR_UPDATE */
5720 		IVAL = SQL_PS_POSITIONED_DELETE | SQL_PS_POSITIONED_UPDATE;
5721 		break;
5722 	case SQL_PROCEDURE_TERM:
5723 		p = "stored procedure";
5724 		break;
5725 	case SQL_PROCEDURES:
5726 		p = "Y";
5727 		break;
5728 	case SQL_QUOTED_IDENTIFIER_CASE:
5729 		/* TODO usually insensitive */
5730 		USIVAL = SQL_IC_MIXED;
5731 		break;
5732 	case SQL_ROW_UPDATES:
5733 		p = "N";
5734 		break;
5735 #if (ODBCVER >= 0x0300)
5736 	case SQL_SCHEMA_TERM:
5737 		p = "owner";
5738 		break;
5739 	case SQL_SCHEMA_USAGE:
5740 		UIVAL = SQL_OU_DML_STATEMENTS | SQL_OU_INDEX_DEFINITION | SQL_OU_PRIVILEGE_DEFINITION | SQL_OU_PROCEDURE_INVOCATION
5741 			| SQL_OU_TABLE_DEFINITION;
5742 		break;
5743 #endif /* ODBCVER >= 0x0300 */
5744 	case SQL_SCROLL_CONCURRENCY:
5745 		if (dbc->cursor_support)
5746 			/* TODO cursors test them, Sybase support all ?  */
5747 			IVAL = SQL_SCCO_LOCK | SQL_SCCO_OPT_ROWVER | SQL_SCCO_OPT_VALUES | SQL_SCCO_READ_ONLY;
5748 		else
5749 			IVAL = SQL_SCCO_READ_ONLY;
5750 		break;
5751 	case SQL_SCROLL_OPTIONS:
5752 		if (dbc->cursor_support)
5753 			/* TODO cursors test them, Sybase support all ?? */
5754 			UIVAL = SQL_SO_DYNAMIC | SQL_SO_FORWARD_ONLY | SQL_SO_KEYSET_DRIVEN | SQL_SO_STATIC;
5755 		else
5756 			UIVAL = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
5757 		break;
5758 	case SQL_SEARCH_PATTERN_ESCAPE:
5759 		p = "\\";
5760 		break;
5761 	case SQL_SERVER_NAME:
5762 		p = dbc->tds_socket->conn->server;
5763 		break;
5764 	case SQL_SPECIAL_CHARACTERS:
5765 		/* TODO others ?? */
5766 		p = "\'\"[]{}";
5767 		break;
5768 #if (ODBCVER >= 0x0300)
5769 	case SQL_SQL_CONFORMANCE:
5770 		UIVAL = SQL_SC_SQL92_ENTRY;
5771 		break;
5772 	case SQL_SQL92_DATETIME_FUNCTIONS:
5773 	case SQL_SQL92_FOREIGN_KEY_DELETE_RULE:
5774 	case SQL_SQL92_FOREIGN_KEY_UPDATE_RULE:
5775 		UIVAL = 0;
5776 		break;
5777 	case SQL_SQL92_GRANT:
5778 		UIVAL = SQL_SG_WITH_GRANT_OPTION;
5779 		break;
5780 	case SQL_SQL92_NUMERIC_VALUE_FUNCTIONS:
5781 		UIVAL = 0;
5782 		break;
5783 	case SQL_SQL92_PREDICATES:
5784 		/* TODO Sybase ?? */
5785 		UIVAL = SQL_SP_EXISTS | SQL_SP_ISNOTNULL | SQL_SP_ISNULL;
5786 		break;
5787 	case SQL_SQL92_RELATIONAL_JOIN_OPERATORS:
5788 		/* TODO Sybase ?? */
5789 		UIVAL = SQL_SRJO_CROSS_JOIN | SQL_SRJO_FULL_OUTER_JOIN | SQL_SRJO_INNER_JOIN | SQL_SRJO_LEFT_OUTER_JOIN |
5790 			SQL_SRJO_RIGHT_OUTER_JOIN | SQL_SRJO_UNION_JOIN;
5791 		break;
5792 	case SQL_SQL92_REVOKE:
5793 		UIVAL = SQL_SR_GRANT_OPTION_FOR;
5794 		break;
5795 	case SQL_SQL92_ROW_VALUE_CONSTRUCTOR:
5796 		UIVAL = SQL_SRVC_DEFAULT | SQL_SRVC_NULL | SQL_SRVC_ROW_SUBQUERY | SQL_SRVC_VALUE_EXPRESSION;
5797 		break;
5798 	case SQL_SQL92_STRING_FUNCTIONS:
5799 		UIVAL = SQL_SSF_LOWER | SQL_SSF_UPPER;
5800 		break;
5801 	case SQL_SQL92_VALUE_EXPRESSIONS:
5802 		/* TODO Sybase ? CAST supported ? */
5803 		UIVAL = SQL_SVE_CASE | SQL_SVE_CAST | SQL_SVE_COALESCE | SQL_SVE_NULLIF;
5804 		break;
5805 	case SQL_STANDARD_CLI_CONFORMANCE:
5806 		UIVAL = SQL_SCC_ISO92_CLI;
5807 		break;
5808 	case SQL_STATIC_SENSITIVITY:
5809 		IVAL = 0;
5810 		break;
5811 	case SQL_STATIC_CURSOR_ATTRIBUTES1:
5812 		if (dbc->cursor_support)
5813 			/* TODO cursors SQL_CA1_BOOKMARK SQL_CA1_BULK_FETCH_BY_BOOKMARK SQL_CA1_POS_REFRESH */
5814 			UIVAL = SQL_CA1_ABSOLUTE | SQL_CA1_LOCK_NO_CHANGE | SQL_CA1_NEXT | SQL_CA1_POS_POSITION | SQL_CA1_RELATIVE;
5815 		else
5816 			UIVAL = 0;
5817 		break;
5818 	case SQL_STATIC_CURSOR_ATTRIBUTES2:
5819 		/* TODO cursors */
5820 		UIVAL = 0;
5821 		break;
5822 #endif /* ODBCVER >= 0x0300 */
5823 	case SQL_STRING_FUNCTIONS:
5824 		UIVAL = (SQL_FN_STR_ASCII | SQL_FN_STR_BIT_LENGTH | SQL_FN_STR_CHAR | SQL_FN_STR_CONCAT | SQL_FN_STR_DIFFERENCE |
5825 			 SQL_FN_STR_INSERT | SQL_FN_STR_LCASE | SQL_FN_STR_LEFT | SQL_FN_STR_LENGTH | SQL_FN_STR_LOCATE_2 |
5826 			 SQL_FN_STR_LTRIM | SQL_FN_STR_OCTET_LENGTH | SQL_FN_STR_REPEAT | SQL_FN_STR_RIGHT | SQL_FN_STR_RTRIM |
5827 			 SQL_FN_STR_SOUNDEX | SQL_FN_STR_SPACE | SQL_FN_STR_SUBSTRING | SQL_FN_STR_UCASE) & mssql7plus_mask;
5828 		break;
5829 	case SQL_SUBQUERIES:
5830 		UIVAL = SQL_SQ_COMPARISON | SQL_SQ_CORRELATED_SUBQUERIES | SQL_SQ_EXISTS | SQL_SQ_IN | SQL_SQ_QUANTIFIED;
5831 		break;
5832 	case SQL_SYSTEM_FUNCTIONS:
5833 		UIVAL = SQL_FN_SYS_DBNAME | SQL_FN_SYS_IFNULL | SQL_FN_SYS_USERNAME;
5834 		break;
5835 	case SQL_TABLE_TERM:
5836 		p = "table";
5837 		break;
5838 	case SQL_TIMEDATE_ADD_INTERVALS:
5839 		UIVAL = (SQL_FN_TSI_DAY | SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_HOUR | SQL_FN_TSI_MINUTE | SQL_FN_TSI_MONTH |
5840 			 SQL_FN_TSI_QUARTER | SQL_FN_TSI_SECOND | SQL_FN_TSI_WEEK | SQL_FN_TSI_YEAR) & mssql7plus_mask;
5841 		break;
5842 	case SQL_TIMEDATE_DIFF_INTERVALS:
5843 		UIVAL = (SQL_FN_TSI_DAY | SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_HOUR | SQL_FN_TSI_MINUTE | SQL_FN_TSI_MONTH |
5844 			 SQL_FN_TSI_QUARTER | SQL_FN_TSI_SECOND | SQL_FN_TSI_WEEK | SQL_FN_TSI_YEAR) & mssql7plus_mask;
5845 		break;
5846 	case SQL_TIMEDATE_FUNCTIONS:
5847 		UIVAL = (SQL_FN_TD_CURDATE | SQL_FN_TD_CURRENT_DATE | SQL_FN_TD_CURRENT_TIME | SQL_FN_TD_CURRENT_TIMESTAMP |
5848 			 SQL_FN_TD_CURTIME | SQL_FN_TD_DAYNAME | SQL_FN_TD_DAYOFMONTH | SQL_FN_TD_DAYOFWEEK | SQL_FN_TD_DAYOFYEAR |
5849 			 SQL_FN_TD_EXTRACT | SQL_FN_TD_HOUR | SQL_FN_TD_MINUTE | SQL_FN_TD_MONTH | SQL_FN_TD_MONTHNAME |
5850 			 SQL_FN_TD_NOW | SQL_FN_TD_QUARTER | SQL_FN_TD_SECOND | SQL_FN_TD_TIMESTAMPADD | SQL_FN_TD_TIMESTAMPDIFF |
5851 			 SQL_FN_TD_WEEK | SQL_FN_TD_YEAR) & mssql7plus_mask;
5852 		break;
5853 	case SQL_TXN_CAPABLE:
5854 		/* transaction for DML and DDL */
5855 		SIVAL = SQL_TC_ALL;
5856 		break;
5857 	case SQL_TXN_ISOLATION_OPTION:
5858 		UIVAL = SQL_TXN_READ_COMMITTED | SQL_TXN_READ_UNCOMMITTED | SQL_TXN_REPEATABLE_READ | SQL_TXN_SERIALIZABLE;
5859 		break;
5860 	case SQL_UNION:
5861 		UIVAL = SQL_U_UNION | SQL_U_UNION_ALL;
5862 		break;
5863 		/* TODO finish */
5864 	case SQL_USER_NAME:
5865 		/* TODO this is not correct username */
5866 		/* p = tds_dstr_cstr(&dbc->tds_login->user_name); */
5867 		/* make OpenOffice happy :) */
5868 		p = "";
5869 		break;
5870 	case SQL_XOPEN_CLI_YEAR:
5871 		/* TODO check specifications */
5872 		p = "1995";
5873 		break;
5874 	case SQL_INFO_FREETDS_TDS_VERSION:
5875 		if (!dbc->tds_socket)
5876 			return SQL_ERROR;
5877 		UIVAL = TDS_MAJOR(dbc->tds_socket->conn) << 16 | TDS_MINOR(dbc->tds_socket->conn);
5878 		break;
5879 	default:
5880 		odbc_log_unimplemented_type("SQLGetInfo", fInfoType);
5881 		odbc_errs_add(&dbc->errs, "HY092", "Option not supported");
5882 		return SQL_ERROR;
5883 	}
5884 
5885 	/* char data */
5886 	if (p) {
5887 		return odbc_set_string_oct(dbc, rgbInfoValue, cbInfoValueMax, pcbInfoValue, p, -1);
5888 	} else {
5889 		if (out_len > 0 && pcbInfoValue)
5890 			*pcbInfoValue = out_len;
5891 	}
5892 
5893 	return SQL_SUCCESS;
5894 #undef SIVAL
5895 #undef USIVAL
5896 #undef IVAL
5897 #undef UIVAL
5898 }
5899 
5900 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetInfo(SQLHDBC hdbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT FAR * pcbInfoValue)5901 SQLGetInfo(SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax,
5902 	   SQLSMALLINT FAR * pcbInfoValue)
5903 {
5904 	ODBC_ENTER_HDBC;
5905 
5906 	tdsdump_log(TDS_DBG_FUNC, "SQLGetInfo(%p, %d, %p, %d, %p)\n",
5907 			hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
5908 
5909 	ODBC_EXIT(dbc, _SQLGetInfo(dbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue _wide0));
5910 }
5911 
5912 #ifdef ENABLE_ODBC_WIDE
5913 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetInfoW(SQLHDBC hdbc,SQLUSMALLINT fInfoType,SQLPOINTER rgbInfoValue,SQLSMALLINT cbInfoValueMax,SQLSMALLINT FAR * pcbInfoValue)5914 SQLGetInfoW(SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax,
5915 	   SQLSMALLINT FAR * pcbInfoValue)
5916 {
5917 	ODBC_ENTER_HDBC;
5918 
5919 	tdsdump_log(TDS_DBG_FUNC, "SQLGetInfoW(%p, %d, %p, %d, %p)\n",
5920 			hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
5921 
5922 	ODBC_EXIT(dbc, _SQLGetInfo(dbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue, 1));
5923 }
5924 #endif
5925 
5926 static void
tds_ascii_strupr(char * s)5927 tds_ascii_strupr(char *s)
5928 {
5929 	for (; *s; ++s)
5930 		if ('a' <= *s && *s <= 'z')
5931 			*s = *s & (~0x20);
5932 }
5933 
5934 static void
odbc_upper_column_names(TDS_STMT * stmt)5935 odbc_upper_column_names(TDS_STMT * stmt)
5936 {
5937 #if ENABLE_EXTRA_CHECKS
5938 	TDSRESULTINFO *resinfo;
5939 	TDSSOCKET *tds;
5940 #endif
5941 	int icol;
5942 	TDS_DESC *ird;
5943 
5944 	IRD_CHECK;
5945 
5946 #if ENABLE_EXTRA_CHECKS
5947 	tds = stmt->dbc->tds_socket;
5948 	if (!tds || !tds->current_results)
5949 		return;
5950 
5951 	resinfo = tds->current_results;
5952 	for (icol = 0; icol < resinfo->num_cols; ++icol) {
5953 		TDSCOLUMN *colinfo = resinfo->columns[icol];
5954 		char *p = tds_dstr_buf(&colinfo->column_name);
5955                 size_t n, len = tds_dstr_len(&colinfo->column_name);
5956 
5957 		/* upper case */
5958 		/* TODO procedure */
5959 		for (n = 0; n < len; ++n, ++p)
5960 			if ('a' <= *p && *p <= 'z')
5961 				*p = *p & (~0x20);
5962 	}
5963 #endif
5964 
5965 	ird = stmt->ird;
5966 	for (icol = ird->header.sql_desc_count; --icol >= 0;) {
5967 		struct _drecord *drec = &ird->records[icol];
5968 
5969 		/* upper case */
5970 		tds_ascii_strupr(tds_dstr_buf(&drec->sql_desc_label));
5971 		tds_ascii_strupr(tds_dstr_buf(&drec->sql_desc_name));
5972 	}
5973 }
5974 
5975 /**
5976  * Change sql datatype to a specific version
5977  * \param sql_type sql data type to change (any type)
5978  * \param version  ODBC version to change to, 2 for ODBC 2, 3 for ODBC 3, 0 swap
5979  */
5980 static SQLSMALLINT
odbc_swap_datetime_sql_type(SQLSMALLINT sql_type,int version)5981 odbc_swap_datetime_sql_type(SQLSMALLINT sql_type, int version)
5982 {
5983 	switch (sql_type) {
5984 	case SQL_TYPE_TIMESTAMP:
5985 		if (version != 3)
5986 			sql_type = SQL_TIMESTAMP;
5987 		break;
5988 	case SQL_TIMESTAMP:
5989 		if (version != 2)
5990 			sql_type = SQL_TYPE_TIMESTAMP;
5991 		break;
5992 	case SQL_TYPE_DATE:
5993 		if (version != 3)
5994 			sql_type = SQL_DATE;
5995 		break;
5996 	case SQL_DATE:
5997 		if (version != 2)
5998 			sql_type = SQL_TYPE_DATE;
5999 		break;
6000 	case SQL_TYPE_TIME:
6001 		if (version != 3)
6002 			sql_type = SQL_TIME;
6003 		break;
6004 	case SQL_TIME:
6005 		if (version != 2)
6006 			sql_type = SQL_TYPE_TIME;
6007 		break;
6008 	}
6009 	return sql_type;
6010 }
6011 
6012 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetTypeInfo(SQLHSTMT hstmt,SQLSMALLINT fSqlType)6013 SQLGetTypeInfo(SQLHSTMT hstmt, SQLSMALLINT fSqlType)
6014 {
6015 	SQLRETURN res;
6016 	TDSSOCKET *tds;
6017 	TDS_INT result_type;
6018 	TDS_INT compute_id;
6019 	int varchar_pos = -1, n;
6020 	static const char sql_templ_default[] = "sp_datatype_info %d";
6021 	const char *sql_templ = sql_templ_default;
6022 	char sql[sizeof(sql_templ_default) + 36];
6023 	int odbc3;
6024 
6025 	ODBC_ENTER_HSTMT;
6026 
6027 	tdsdump_log(TDS_DBG_FUNC, "SQLGetTypeInfo(%p, %d)\n", hstmt, fSqlType);
6028 
6029 	tds = stmt->dbc->tds_socket;
6030 	odbc3 = (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3);
6031 
6032 	if (IS_TDS73_PLUS(tds->conn))
6033 		sql_templ = "sp_datatype_info_100 %d";
6034 	else if (IS_TDS72_PLUS(tds->conn))
6035 		sql_templ = "sp_datatype_info_90 %d";
6036 
6037 	/* For MSSQL6.5 and Sybase 11.9 sp_datatype_info work */
6038 	/* TODO what about early Sybase products ? */
6039 	/* TODO Does Sybase return all ODBC3 columns? Add them if not */
6040 	/* TODO ODBC3 convert type to ODBC version 2 (date) */
6041 	if (odbc3) {
6042 		if (TDS_IS_SYBASE(tds)) {
6043 			sprintf(sql, sql_templ, odbc_swap_datetime_sql_type(fSqlType, 0));
6044 			stmt->special_row = ODBC_SPECIAL_GETTYPEINFO;
6045 		} else {
6046 			sprintf(sql, sql_templ, fSqlType);
6047 			strcat(sql, ",3");
6048 		}
6049 	} else {
6050 		/* MS ODBC translate SQL_TIMESTAMP to SQL_TYPE_TIMESTAMP even for ODBC 2 apps
6051 		 * other DM just pass value straight.
6052 		 * Convert always to version 2 to make version 2 datatype works with all DMs
6053 		 */
6054 		sprintf(sql, sql_templ, odbc_swap_datetime_sql_type(fSqlType, 2));
6055 	}
6056 	if (SQL_SUCCESS != odbc_set_stmt_query(stmt, (ODBC_CHAR*) sql, strlen(sql) _wide0))
6057 		ODBC_EXIT(stmt, SQL_ERROR);
6058 
6059       redo:
6060 	res = _SQLExecute(stmt);
6061 
6062 	odbc_upper_column_names(stmt);
6063 	if (odbc3) {
6064 		odbc_col_setname(stmt, 3, "COLUMN_SIZE");
6065 		odbc_col_setname(stmt, 11, "FIXED_PREC_SCALE");
6066 		odbc_col_setname(stmt, 12, "AUTO_UNIQUE_VALUE");
6067 	}
6068 
6069 	/* workaround for a mispelled column name in Sybase */
6070 	if (TDS_IS_SYBASE(stmt->dbc->tds_socket) && !odbc3)
6071 		odbc_col_setname(stmt, 3, "PRECISION");
6072 
6073 	if (TDS_IS_MSSQL(stmt->dbc->tds_socket) || fSqlType != SQL_VARCHAR || res != SQL_SUCCESS)
6074 		ODBC_EXIT(stmt, res);
6075 
6076 	/*
6077 	 * Sybase return first nvarchar for char... and without length !!!
6078 	 * Some program use first entry so we discard all entry before varchar
6079 	 */
6080 	n = 0;
6081 	while (tds->current_results) {
6082 		TDSRESULTINFO *resinfo;
6083 		TDSCOLUMN *colinfo;
6084 		char *name;
6085 
6086 		/* if next is varchar leave next for SQLFetch */
6087 		if (n == (varchar_pos - 1))
6088 			break;
6089 
6090 		switch (tds_process_tokens(stmt->dbc->tds_socket, &result_type, &compute_id, TDS_STOPAT_ROWFMT|TDS_RETURN_ROW)) {
6091 		case TDS_SUCCESS:
6092 			if (result_type == TDS_ROW_RESULT)
6093 				break;
6094 		case TDS_NO_MORE_RESULTS:
6095 			/* discard other tokens */
6096 			tds_process_simple_query(tds);
6097 			if (n >= varchar_pos && varchar_pos > 0)
6098 				goto redo;
6099 			break;
6100 		case TDS_CANCELLED:
6101 			odbc_errs_add(&stmt->errs, "HY008", NULL);
6102 			res = SQL_ERROR;
6103 			break;
6104 		}
6105 		if (!tds->current_results)
6106 			break;
6107 		++n;
6108 
6109 		resinfo = tds->current_results;
6110 		colinfo = resinfo->columns[0];
6111 		name = (char *) colinfo->column_data;
6112 		if (is_blob_col(colinfo))
6113 			name = (char*) ((TDSBLOB *) name)->textvalue;
6114 		/* skip nvarchar and sysname */
6115 		if (colinfo->column_cur_size == 7 && memcmp("varchar", name, 7) == 0) {
6116 			varchar_pos = n;
6117 		}
6118 	}
6119 	ODBC_EXIT(stmt, res);
6120 }
6121 
6122 #ifdef ENABLE_ODBC_WIDE
6123 SQLRETURN ODBC_PUBLIC ODBC_API
SQLGetTypeInfoW(SQLHSTMT hstmt,SQLSMALLINT fSqlType)6124 SQLGetTypeInfoW(SQLHSTMT hstmt, SQLSMALLINT fSqlType)
6125 {
6126 	return SQLGetTypeInfo(hstmt, fSqlType);
6127 }
6128 #endif
6129 
6130 static SQLRETURN
_SQLParamData(SQLHSTMT hstmt,SQLPOINTER FAR * prgbValue)6131 _SQLParamData(SQLHSTMT hstmt, SQLPOINTER FAR * prgbValue)
6132 {
6133 	ODBC_ENTER_HSTMT;
6134 
6135 	tdsdump_log(TDS_DBG_FUNC, "SQLParamData(%p, %p) [param_num %d, param_data_called = %d]\n",
6136 					hstmt, prgbValue, stmt->param_num, stmt->param_data_called);
6137 
6138         if (stmt->params
6139             &&  (unsigned int) stmt->param_num <= stmt->param_count) {
6140 		SQLRETURN res;
6141 
6142 		if (stmt->param_num <= 0 || stmt->param_num > stmt->apd->header.sql_desc_count) {
6143 			tdsdump_log(TDS_DBG_FUNC, "SQLParamData: logic_error: parameter out of bounds: 0 <= %d < %d\n",
6144 						   stmt->param_num, stmt->apd->header.sql_desc_count);
6145 			ODBC_EXIT(stmt, SQL_ERROR);
6146 		}
6147 
6148 		/*
6149 		 * TODO compute output value with this formula:
6150 		 * Bound Address + Binding Offset + ((Row Number - 1) x Element Size)
6151 		 * (see SQLParamData documentation)
6152 		 * This is needed for updates using SQLBulkOperation (not currently supported)
6153 		 */
6154 		if (!stmt->param_data_called) {
6155 			stmt->param_data_called = 1;
6156 			*prgbValue = stmt->apd->records[stmt->param_num - 1].sql_desc_data_ptr;
6157 			ODBC_EXIT(stmt, SQL_NEED_DATA);
6158 		}
6159 		++stmt->param_num;
6160 		switch (res = parse_prepared_query(stmt, 1)) {
6161 		case SQL_NEED_DATA:
6162 			*prgbValue = stmt->apd->records[stmt->param_num - 1].sql_desc_data_ptr;
6163 			ODBC_EXIT(stmt, SQL_NEED_DATA);
6164 		case SQL_SUCCESS:
6165 			ODBC_EXIT(stmt, _SQLExecute(stmt));
6166 		}
6167 		ODBC_EXIT(stmt, res);
6168 	}
6169 
6170 	odbc_errs_add(&stmt->errs, "HY010", NULL);
6171 	ODBC_EXIT_(stmt);
6172 }
6173 
6174 SQLRETURN ODBC_PUBLIC ODBC_API
SQLParamData(SQLHSTMT hstmt,SQLPOINTER FAR * prgbValue)6175 SQLParamData(SQLHSTMT hstmt, SQLPOINTER FAR * prgbValue)
6176 {
6177 	ODBC_PRRET_BUF;
6178 	SQLRETURN ret = _SQLParamData(hstmt, prgbValue);
6179 
6180 	tdsdump_log(TDS_DBG_FUNC, "SQLParamData returns %s\n", odbc_prret(ret));
6181 
6182 	return ret;
6183 }
6184 
6185 SQLRETURN ODBC_PUBLIC ODBC_API
SQLPutData(SQLHSTMT hstmt,SQLPOINTER rgbValue,SQLLEN cbValue)6186 SQLPutData(SQLHSTMT hstmt, SQLPOINTER rgbValue, SQLLEN cbValue)
6187 {
6188 	ODBC_PRRET_BUF;
6189 	ODBC_ENTER_HSTMT;
6190 
6191 	tdsdump_log(TDS_DBG_FUNC, "SQLPutData(%p, %p, %i)\n", hstmt, rgbValue, (int)cbValue);
6192 
6193 	if (stmt->is_prepared_query || stmt->prepared_query_is_rpc) {
6194 		SQLRETURN ret;
6195 		const TDSCOLUMN *curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
6196 		/* TODO do some more tests before setting this flag */
6197 		stmt->param_data_called = 1;
6198 		ret = continue_parse_prepared_query(stmt, rgbValue, cbValue);
6199 		tdsdump_log(TDS_DBG_FUNC, "SQLPutData returns %s, %d bytes left\n",
6200 					  odbc_prret(ret), curcol->column_size - curcol->column_cur_size);
6201 		ODBC_EXIT(stmt, ret);
6202 	}
6203 
6204 	odbc_errs_add(&stmt->errs, "HY010", NULL);
6205 	ODBC_EXIT_(stmt);
6206 }
6207 
6208 
6209 ODBC_FUNC(SQLSetConnectAttr, (P(SQLHDBC,hdbc), P(SQLINTEGER,Attribute), P(SQLPOINTER,ValuePtr), P(SQLINTEGER,StringLength) WIDE))
6210 {
6211 	SQLULEN u_value = (SQLULEN) (TDS_INTPTR) ValuePtr;
6212 
6213 	ODBC_ENTER_HDBC;
6214 
6215 	tdsdump_log(TDS_DBG_FUNC, "_SQLSetConnectAttr(%p, %d, %p, %d)\n", hdbc, (int)Attribute, ValuePtr, (int)StringLength);
6216 
6217 	switch (Attribute) {
6218 	case SQL_ATTR_AUTOCOMMIT:
6219 		/* spinellia@acm.org */
6220                 change_autocommit(dbc, (int) u_value);
6221 		break;
6222 	case SQL_ATTR_CONNECTION_TIMEOUT:
6223                 dbc->attr.connection_timeout = (SQLUINTEGER) u_value;
6224 		break;
6225 	case SQL_ATTR_ACCESS_MODE:
6226                 dbc->attr.access_mode = (SQLUINTEGER) u_value;
6227 		break;
6228 	case SQL_ATTR_CURRENT_CATALOG:
6229 		if (!IS_VALID_LEN(StringLength)) {
6230 			odbc_errs_add(&dbc->errs, "HY090", NULL);
6231 			break;
6232 		}
6233 		{
6234 			DSTR s = DSTR_INITIALIZER;
6235 
6236 			if (!odbc_dstr_copy_oct(dbc, &s, StringLength, (ODBC_CHAR*) ValuePtr)) {
6237 				odbc_errs_add(&dbc->errs, "HY001", NULL);
6238 				break;
6239 			}
6240 			change_database(dbc, tds_dstr_cstr(&s), tds_dstr_len(&s));
6241 			tds_dstr_free(&s);
6242 		}
6243 		break;
6244 	case SQL_ATTR_CURSOR_TYPE:
6245 		if (dbc->cursor_support)
6246                         dbc->attr.cursor_type = (SQLUINTEGER) u_value;
6247 		break;
6248 	case SQL_ATTR_LOGIN_TIMEOUT:
6249                 dbc->attr.login_timeout = (SQLUINTEGER) u_value;
6250 		break;
6251 	case SQL_ATTR_ODBC_CURSORS:
6252 		/* TODO cursors */
6253                 dbc->attr.odbc_cursors = (SQLUINTEGER) u_value;
6254 		break;
6255 	case SQL_ATTR_PACKET_SIZE:
6256                 dbc->attr.packet_size = (SQLUINTEGER) u_value;
6257 		break;
6258 	case SQL_ATTR_QUIET_MODE:
6259 		dbc->attr.quite_mode = (SQLHWND) (TDS_INTPTR) ValuePtr;
6260 		break;
6261 #ifdef TDS_NO_DM
6262 	case SQL_ATTR_TRACE:
6263                 dbc->attr.trace = (SQLUINTEGER) u_value;
6264 		break;
6265 	case SQL_ATTR_TRACEFILE:
6266 		if (!IS_VALID_LEN(StringLength)) {
6267 			odbc_errs_add(&dbc->errs, "HY090", NULL);
6268 			break;
6269 		}
6270 		if (!odbc_dstr_copy(dbc, &dbc->attr.tracefile, StringLength, (ODBC_CHAR *) ValuePtr))
6271 			odbc_errs_add(&dbc->errs, "HY001", NULL);
6272 		break;
6273 #endif
6274 	case SQL_ATTR_TXN_ISOLATION:
6275 		if (u_value != dbc->attr.txn_isolation) {
6276                         if (change_txn(dbc, (SQLUINTEGER) u_value)
6277                             == SQL_SUCCESS)
6278                                 dbc->attr.txn_isolation = (SQLUINTEGER)u_value;
6279 		}
6280 		break;
6281 	case SQL_COPT_SS_MARS_ENABLED:
6282                 dbc->attr.mars_enabled = (SQLUINTEGER) u_value;
6283 		break;
6284 	case SQL_ATTR_TRANSLATE_LIB:
6285 	case SQL_ATTR_TRANSLATE_OPTION:
6286 		odbc_errs_add(&dbc->errs, "HYC00", NULL);
6287 		break;
6288 	case SQL_COPT_SS_OLDPWD:
6289 		if (!IS_VALID_LEN(StringLength)) {
6290 			odbc_errs_add(&dbc->errs, "HY090", NULL);
6291 			break;
6292 		}
6293 		if (!odbc_dstr_copy(dbc, &dbc->oldpwd, StringLength, (ODBC_CHAR *) ValuePtr))
6294 			odbc_errs_add(&dbc->errs, "HY001", NULL);
6295 		else
6296 			dbc->use_oldpwd = 1;
6297 		break;
6298 	case SQL_COPT_SS_BCP:
6299                 dbc->attr.bulk_enabled = (SQLUINTEGER) u_value;
6300 		break;
6301 	case SQL_COPT_TDSODBC_IMPL_BCP_INITA:
6302 		if (!ValuePtr)
6303 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6304 		else {
6305 			const struct tdsodbc_impl_bcp_init_params *params = (const struct tdsodbc_impl_bcp_init_params*)ValuePtr;
6306 			odbc_bcp_init(dbc, (const ODBC_CHAR *) params->tblname, (const ODBC_CHAR *) params->hfile,
6307 				      (const ODBC_CHAR *) params->errfile, params->direction _wide0);
6308 		}
6309 		break;
6310 #ifdef ENABLE_ODBC_WIDE
6311 	case SQL_COPT_TDSODBC_IMPL_BCP_INITW:
6312 		if (!ValuePtr)
6313 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6314 		else {
6315 			const struct tdsodbc_impl_bcp_init_params *params = (const struct tdsodbc_impl_bcp_init_params*)ValuePtr;
6316 			odbc_bcp_init(dbc, (const ODBC_CHAR *) params->tblname, (const ODBC_CHAR *) params->hfile,
6317 				      (const ODBC_CHAR *) params->errfile, params->direction, 1);
6318 		}
6319 		break;
6320 #endif
6321 	case SQL_COPT_TDSODBC_IMPL_BCP_CONTROL:
6322 		if (!ValuePtr)
6323 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6324 		else {
6325 			const struct tdsodbc_impl_bcp_control_params *params = (const struct tdsodbc_impl_bcp_control_params*)ValuePtr;
6326 			odbc_bcp_control(dbc, params->field, params->value);
6327 		}
6328 		break;
6329 	case SQL_COPT_TDSODBC_IMPL_BCP_COLPTR:
6330 		if (!ValuePtr)
6331 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6332 		else {
6333 			const struct tdsodbc_impl_bcp_colptr_params *params = (const struct tdsodbc_impl_bcp_colptr_params*)ValuePtr;
6334 			odbc_bcp_colptr(dbc, params->colptr, params->table_column);
6335 		}
6336 		break;
6337 	case SQL_COPT_TDSODBC_IMPL_BCP_SENDROW:
6338 		if (ValuePtr)
6339 			odbc_errs_add(&dbc->errs, "HY000", NULL);
6340 		else
6341 			odbc_bcp_sendrow(dbc);
6342 		break;
6343 	case SQL_COPT_TDSODBC_IMPL_BCP_BATCH:
6344 		if (!ValuePtr)
6345 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6346 		else {
6347 			struct tdsodbc_impl_bcp_batch_params *params = (struct tdsodbc_impl_bcp_batch_params*)ValuePtr;
6348 			params->rows = odbc_bcp_batch(dbc);
6349 		}
6350 		break;
6351 	case SQL_COPT_TDSODBC_IMPL_BCP_DONE:
6352 		if (!ValuePtr)
6353 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6354 		else {
6355 			struct tdsodbc_impl_bcp_done_params *params = (struct tdsodbc_impl_bcp_done_params*)ValuePtr;
6356 			params->rows = odbc_bcp_done(dbc);
6357 		}
6358 		break;
6359 	case SQL_COPT_TDSODBC_IMPL_BCP_BIND:
6360 		if (!ValuePtr)
6361 			odbc_errs_add(&dbc->errs, "HY009", NULL);
6362 		else {
6363 			const struct tdsodbc_impl_bcp_bind_params *params = (const struct tdsodbc_impl_bcp_bind_params*)ValuePtr;
6364 			odbc_bcp_bind(dbc, params->varaddr, params->prefixlen, params->varlen, params->terminator, params->termlen, params->vartype, params->table_column);
6365 		}
6366 		break;
6367 	default:
6368 		odbc_errs_add(&dbc->errs, "HY092", NULL);
6369 		break;
6370 	}
6371 	ODBC_EXIT_(dbc);
6372 }
6373 
6374 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetConnectOption(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam)6375 SQLSetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
6376 {
6377 	tdsdump_log(TDS_DBG_FUNC, "SQLSetConnectOption(%p, %d, %u)\n", hdbc, fOption, (unsigned)vParam);
6378 	/* XXX: Lost precision */
6379 	return _SQLSetConnectAttr(hdbc, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS _wide0);
6380 }
6381 
6382 #ifdef ENABLE_ODBC_WIDE
6383 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetConnectOptionW(SQLHDBC hdbc,SQLUSMALLINT fOption,SQLULEN vParam)6384 SQLSetConnectOptionW(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
6385 {
6386 	tdsdump_log(TDS_DBG_FUNC, "SQLSetConnectOptionW(%p, %d, %u)\n", hdbc, fOption, (unsigned)vParam);
6387 	/* XXX: Lost precision */
6388 	return _SQLSetConnectAttr(hdbc, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS, 1);
6389 }
6390 #endif
6391 
6392 static SQLRETURN
_SQLSetStmtAttr(SQLHSTMT hstmt,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength WIDE)6393 _SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength WIDE)
6394 {
6395 	SQLULEN ui = (SQLULEN) (TDS_INTPTR) ValuePtr;
6396 	SQLUSMALLINT *usip = (SQLUSMALLINT *) ValuePtr;
6397 	SQLLEN *lp = (SQLLEN *) ValuePtr;
6398 	SQLULEN *ulp = (SQLULEN *) ValuePtr;
6399 
6400 	ODBC_ENTER_HSTMT;
6401 
6402 	tdsdump_log(TDS_DBG_FUNC, "_SQLSetStmtAttr(%p, %d, %p, %d)\n", hstmt, (int)Attribute, ValuePtr, (int)StringLength);
6403 
6404 	/* TODO - error checking and real functionality :-) */
6405 	/* TODO some setting set also other attribute, see documentation */
6406 	switch (Attribute) {
6407 		/* TODO check SQLFreeHandle on descriptor. Is possible to free an associated descriptor ? */
6408 	case SQL_ATTR_APP_PARAM_DESC:
6409 	case SQL_ATTR_APP_ROW_DESC:
6410 		{
6411 			TDS_DESC *orig;
6412 			TDS_DESC **curr;
6413 			TDS_DESC *val = (TDS_DESC *) ValuePtr;
6414 
6415 			if (Attribute == SQL_ATTR_APP_PARAM_DESC) {
6416 				orig = stmt->orig_apd;
6417 				curr = &stmt->apd;
6418 			} else {
6419 				orig = stmt->orig_ard;
6420 				curr = &stmt->ard;
6421 			}
6422 			/* if ValuePtr is NULL or original descriptor set original */
6423 			if (!val || val == orig) {
6424 				*curr = orig;
6425 				break;
6426 			}
6427 
6428 			/* must be allocated by user, not implicit ones */
6429 			if (val->header.sql_desc_alloc_type != SQL_DESC_ALLOC_USER) {
6430 				odbc_errs_add(&stmt->errs, "HY017", NULL);
6431 				break;
6432 			}
6433 			/* TODO check HDESC (not associated, from DBC HY024) */
6434 			*curr = val;
6435 		}
6436 		break;
6437 	case SQL_ATTR_ASYNC_ENABLE:
6438 		if (stmt->attr.async_enable != ui) {
6439 			odbc_errs_add(&stmt->errs, "HYC00", NULL);
6440 			break;
6441 		}
6442                 stmt->attr.async_enable = (SQLUINTEGER) ui;
6443 		break;
6444 	case SQL_ATTR_CONCURRENCY:
6445 		if (stmt->attr.concurrency != ui && !stmt->dbc->cursor_support) {
6446 			odbc_errs_add(&stmt->errs, "01S02", NULL);
6447 			break;
6448 		}
6449 
6450 		if (stmt->cursor) {
6451 			odbc_errs_add(&stmt->errs, "24000", NULL);
6452 			break;
6453 		}
6454 
6455 		switch (ui) {
6456 		case SQL_CONCUR_READ_ONLY:
6457 			stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
6458 			break;
6459 		case SQL_CONCUR_LOCK:
6460 		case SQL_CONCUR_ROWVER:
6461 		case SQL_CONCUR_VALUES:
6462 			stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
6463 			break;
6464 		default:
6465 			odbc_errs_add(&stmt->errs, "HY092", NULL);
6466 			ODBC_EXIT_(stmt);
6467 		}
6468                 stmt->attr.concurrency = (SQLUINTEGER) ui;
6469 		break;
6470 	case SQL_ATTR_CURSOR_SCROLLABLE:
6471 		if (stmt->attr.cursor_scrollable != ui && !stmt->dbc->cursor_support) {
6472 			odbc_errs_add(&stmt->errs, "HYC00", NULL);
6473 			break;
6474 		}
6475 
6476 		switch (ui) {
6477 		case SQL_SCROLLABLE:
6478 			stmt->attr.cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
6479 			break;
6480 		case SQL_NONSCROLLABLE:
6481 			stmt->attr.cursor_type = SQL_CURSOR_FORWARD_ONLY;
6482 			break;
6483 		default:
6484 			odbc_errs_add(&stmt->errs, "HY092", NULL);
6485 			ODBC_EXIT_(stmt);
6486 		}
6487                 stmt->attr.cursor_scrollable = (SQLUINTEGER) ui;
6488 		break;
6489 	case SQL_ATTR_CURSOR_SENSITIVITY:
6490 		/* don't change anything */
6491 		if (ui == SQL_UNSPECIFIED)
6492 			break;
6493 		if (stmt->attr.cursor_sensitivity != ui && !stmt->dbc->cursor_support) {
6494 			odbc_errs_add(&stmt->errs, "HYC00", NULL);
6495 			break;
6496 		}
6497 		switch (ui) {
6498 		case SQL_INSENSITIVE:
6499 			stmt->attr.concurrency = SQL_CONCUR_READ_ONLY;
6500 			stmt->attr.cursor_type = SQL_CURSOR_STATIC;
6501 			break;
6502 		case SQL_SENSITIVE:
6503 			stmt->attr.concurrency = SQL_CONCUR_ROWVER;
6504 			break;
6505 		}
6506                 stmt->attr.cursor_sensitivity = (SQLUINTEGER) ui;
6507 		break;
6508 	case SQL_ATTR_CURSOR_TYPE:
6509 		if (stmt->attr.cursor_type != ui && !stmt->dbc->cursor_support) {
6510 			odbc_errs_add(&stmt->errs, "01S02", NULL);
6511 			break;
6512 		}
6513 
6514 		if (stmt->cursor) {
6515 			odbc_errs_add(&stmt->errs, "24000", NULL);
6516 			break;
6517 		}
6518 
6519 		switch (ui) {
6520 		case SQL_CURSOR_DYNAMIC:
6521 		case SQL_CURSOR_KEYSET_DRIVEN:
6522 			if (stmt->attr.concurrency != SQL_CONCUR_READ_ONLY)
6523 				stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
6524 			stmt->attr.cursor_scrollable = SQL_SCROLLABLE;
6525 			break;
6526 		case SQL_CURSOR_STATIC:
6527 			if (stmt->attr.concurrency != SQL_CONCUR_READ_ONLY)
6528 				stmt->attr.cursor_sensitivity = SQL_SENSITIVE;
6529 			else
6530 				stmt->attr.cursor_sensitivity = SQL_INSENSITIVE;
6531 			stmt->attr.cursor_scrollable = SQL_SCROLLABLE;
6532 			break;
6533 		case SQL_CURSOR_FORWARD_ONLY:
6534 			stmt->attr.cursor_scrollable = SQL_NONSCROLLABLE;
6535 			break;
6536 		default:
6537 			odbc_errs_add(&stmt->errs, "HY092", NULL);
6538 			ODBC_EXIT_(stmt);
6539 		}
6540                 stmt->attr.cursor_type = (SQLUINTEGER) ui;
6541 		break;
6542 	case SQL_ATTR_ENABLE_AUTO_IPD:
6543 		if (stmt->attr.enable_auto_ipd != ui) {
6544 			odbc_errs_add(&stmt->errs, "HYC00", NULL);
6545 			break;
6546 		}
6547                 stmt->attr.enable_auto_ipd = (SQLUINTEGER) ui;
6548 		break;
6549 	case SQL_ATTR_FETCH_BOOKMARK_PTR:
6550 		stmt->attr.fetch_bookmark_ptr = ValuePtr;
6551 		break;
6552 	case SQL_ATTR_IMP_ROW_DESC:
6553 	case SQL_ATTR_IMP_PARAM_DESC:
6554 		odbc_errs_add(&stmt->errs, "HY017", NULL);
6555 		break;
6556 		/* TODO what's is this ??? */
6557 	case SQL_ATTR_KEYSET_SIZE:
6558 		stmt->attr.keyset_size = ui;
6559 		break;
6560 		/* TODO max length of data returned. Use SQL TEXTSIZE or just truncate ?? */
6561 	case SQL_ATTR_MAX_LENGTH:
6562 		if (stmt->attr.max_length != ui) {
6563 			odbc_errs_add(&stmt->errs, "01S02", NULL);
6564 			break;
6565 		}
6566 		stmt->attr.max_length = ui;
6567 		break;
6568 		/* TODO max row returned. Use SET ROWCOUNT */
6569 	case SQL_ATTR_MAX_ROWS:
6570 		if (stmt->attr.max_rows != ui) {
6571 			odbc_errs_add(&stmt->errs, "01S02", NULL);
6572 			break;
6573 		}
6574 		stmt->attr.max_rows = ui;
6575 		break;
6576 	case SQL_ATTR_METADATA_ID:
6577                 stmt->attr.metadata_id = (SQLUINTEGER) ui;
6578 		break;
6579 		/* TODO use it !!! */
6580 	case SQL_ATTR_NOSCAN:
6581                 stmt->attr.noscan = (SQLUINTEGER) ui;
6582 		break;
6583 	case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
6584 		stmt->apd->header.sql_desc_bind_offset_ptr = lp;
6585 		break;
6586 	case SQL_ATTR_PARAM_BIND_TYPE:
6587                 stmt->apd->header.sql_desc_bind_type = (SQLUINTEGER) ui;
6588 		break;
6589 	case SQL_ATTR_PARAM_OPERATION_PTR:
6590 		stmt->apd->header.sql_desc_array_status_ptr = usip;
6591 		break;
6592 	case SQL_ATTR_PARAM_STATUS_PTR:
6593 		stmt->ipd->header.sql_desc_array_status_ptr = usip;
6594 		break;
6595 	case SQL_ATTR_PARAMS_PROCESSED_PTR:
6596 		stmt->ipd->header.sql_desc_rows_processed_ptr = ulp;
6597 		break;
6598 		/* allow to exec procedure multiple time */
6599 	case SQL_ATTR_PARAMSET_SIZE:
6600 		stmt->apd->header.sql_desc_array_size = ui;
6601 		break;
6602 	case SQL_ATTR_QUERY_TIMEOUT:
6603                 stmt->attr.query_timeout = (SQLUINTEGER) ui;
6604 		break;
6605 		/* retrieve data after positioning the cursor */
6606 	case SQL_ATTR_RETRIEVE_DATA:
6607 		/* TODO cursors */
6608 		if (stmt->attr.retrieve_data != ui) {
6609 			odbc_errs_add(&stmt->errs, "01S02", NULL);
6610 			break;
6611 		}
6612                 stmt->attr.retrieve_data = (SQLUINTEGER) ui;
6613 		break;
6614 	case SQL_ATTR_ROW_ARRAY_SIZE:
6615 		stmt->ard->header.sql_desc_array_size = ui;
6616 		break;
6617 	case SQL_ATTR_ROW_BIND_OFFSET_PTR:
6618 		/* TODO test what happen with column-wise and row-wise bindings and SQLGetData */
6619 		stmt->ard->header.sql_desc_bind_offset_ptr = lp;
6620 		break;
6621 #if SQL_BIND_TYPE != SQL_ATTR_ROW_BIND_TYPE
6622 	case SQL_BIND_TYPE:	/* although this is ODBC2 we must support this attribute */
6623 #endif
6624 	case SQL_ATTR_ROW_BIND_TYPE:
6625                 stmt->ard->header.sql_desc_bind_type = (SQLUINTEGER) ui;
6626 		break;
6627 	case SQL_ATTR_ROW_NUMBER:
6628 		odbc_errs_add(&stmt->errs, "HY092", NULL);
6629 		break;
6630 	case SQL_ATTR_ROW_OPERATION_PTR:
6631 		stmt->ard->header.sql_desc_array_status_ptr = usip;
6632 		break;
6633 	case SQL_ATTR_ROW_STATUS_PTR:
6634 		stmt->ird->header.sql_desc_array_status_ptr = usip;
6635 		break;
6636 	case SQL_ATTR_ROWS_FETCHED_PTR:
6637 		stmt->ird->header.sql_desc_rows_processed_ptr = ulp;
6638 		break;
6639 	case SQL_ATTR_SIMULATE_CURSOR:
6640 		/* TODO cursors */
6641 		if (stmt->cursor) {
6642 			odbc_errs_add(&stmt->errs, "24000", NULL);
6643 			break;
6644 		}
6645 		if (stmt->attr.simulate_cursor != ui) {
6646 			odbc_errs_add(&stmt->errs, "01S02", NULL);
6647 			break;
6648 		}
6649                 stmt->attr.simulate_cursor = (SQLUINTEGER) ui;
6650 		break;
6651 	case SQL_ATTR_USE_BOOKMARKS:
6652 		if (stmt->cursor) {
6653 			odbc_errs_add(&stmt->errs, "24000", NULL);
6654 			break;
6655 		}
6656                 stmt->attr.use_bookmarks = (SQLUINTEGER) ui;
6657 		break;
6658 	case SQL_ROWSET_SIZE:	/* although this is ODBC2 we must support this attribute */
6659 		if (((TDS_INTPTR) ValuePtr) < 1) {
6660 			odbc_errs_add(&stmt->errs, "HY024", NULL);
6661 			break;
6662 		}
6663 		stmt->sql_rowset_size = ui;
6664 		break;
6665 	case SQL_SOPT_SS_QUERYNOTIFICATION_TIMEOUT:
6666 		if (ui < 1) {
6667 			odbc_errs_add(&stmt->errs, "HY024", NULL);
6668 			break;
6669 		}
6670 		stmt->attr.qn_timeout = ui;
6671 		break;
6672 	case SQL_SOPT_SS_QUERYNOTIFICATION_MSGTEXT:
6673 		if (!IS_VALID_LEN(StringLength)) {
6674 			odbc_errs_add(&stmt->errs, "HY090", NULL);
6675 			break;
6676 		}
6677 		if (!odbc_dstr_copy_oct(stmt->dbc, &stmt->attr.qn_msgtext, StringLength, (ODBC_CHAR*) ValuePtr)) {
6678 			odbc_errs_add(&stmt->errs, "HY001", NULL);
6679 			break;
6680 		}
6681 		break;
6682 	case SQL_SOPT_SS_QUERYNOTIFICATION_OPTIONS:
6683 		if (!IS_VALID_LEN(StringLength)) {
6684 			odbc_errs_add(&stmt->errs, "HY090", NULL);
6685 			break;
6686 		}
6687 		if (!odbc_dstr_copy_oct(stmt->dbc, &stmt->attr.qn_options, StringLength, (ODBC_CHAR*) ValuePtr)) {
6688 			odbc_errs_add(&stmt->errs, "HY001", NULL);
6689 			break;
6690 		}
6691 		break;
6692 	default:
6693 		odbc_errs_add(&stmt->errs, "HY092", NULL);
6694 		break;
6695 	}
6696 	ODBC_EXIT_(stmt);
6697 }
6698 
6699 #if (ODBCVER >= 0x0300)
6700 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetStmtAttr(SQLHSTMT hstmt,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength)6701 SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
6702 {
6703 	tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtAttr(%p, %d, %p, %d)\n",
6704 			hstmt, (int)Attribute, ValuePtr, (int)StringLength);
6705 
6706 	return _SQLSetStmtAttr(hstmt, Attribute, ValuePtr, StringLength _wide0);
6707 }
6708 
6709 #ifdef ENABLE_ODBC_WIDE
6710 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetStmtAttrW(SQLHSTMT hstmt,SQLINTEGER Attribute,SQLPOINTER ValuePtr,SQLINTEGER StringLength)6711 SQLSetStmtAttrW(SQLHSTMT hstmt, SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
6712 {
6713 	tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtAttr(%p, %d, %p, %d)\n",
6714 			hstmt, (int)Attribute, ValuePtr, (int)StringLength);
6715 
6716 	return _SQLSetStmtAttr(hstmt, Attribute, ValuePtr, StringLength, 1);
6717 }
6718 #endif
6719 #endif
6720 
6721 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetStmtOption(SQLHSTMT hstmt,SQLUSMALLINT fOption,SQLULEN vParam)6722 SQLSetStmtOption(SQLHSTMT hstmt, SQLUSMALLINT fOption, SQLULEN vParam)
6723 {
6724 	tdsdump_log(TDS_DBG_FUNC, "SQLSetStmtOption(%p, %u, %u)\n", hstmt, fOption, (unsigned)vParam);
6725 
6726 	/* XXX: Lost precision */
6727 	return _SQLSetStmtAttr(hstmt, (SQLINTEGER) fOption, (SQLPOINTER) (TDS_INTPTR) vParam, SQL_NTS _wide0);
6728 }
6729 
6730 ODBC_FUNC(SQLSpecialColumns, (P(SQLHSTMT,hstmt), P(SQLUSMALLINT,fColType), PCHARIN(CatalogName,SQLSMALLINT),
6731 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT),
6732 	P(SQLUSMALLINT,fScope), P(SQLUSMALLINT,fNullable) WIDE))
6733 {
6734 	int retcode;
6735 	char nullable, scope, col_type;
6736 
6737 	ODBC_ENTER_HSTMT;
6738 
6739 	tdsdump_log(TDS_DBG_FUNC, "SQLSpecialColumns(%p, %d, %p, %d, %p, %d, %p, %d, %d, %d)\n",
6740 			hstmt, fColType, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, fScope, fNullable);
6741 
6742 #ifdef TDS_NO_DM
6743 	/* Check column type */
6744 	if (fColType != SQL_BEST_ROWID && fColType != SQL_ROWVER) {
6745 		odbc_errs_add(&stmt->errs, "HY097", NULL);
6746 		ODBC_EXIT_(stmt);
6747 	}
6748 
6749 	/* check our buffer lengths */
6750 	if (!IS_VALID_LEN(cbCatalogName) || !IS_VALID_LEN(cbSchemaName) || !IS_VALID_LEN(cbTableName)) {
6751 		odbc_errs_add(&stmt->errs, "HY090", NULL);
6752 		ODBC_EXIT_(stmt);
6753 	}
6754 
6755 	/* Check nullable */
6756 	if (fNullable != SQL_NO_NULLS && fNullable != SQL_NULLABLE) {
6757 		odbc_errs_add(&stmt->errs, "HY099", NULL);
6758 		ODBC_EXIT_(stmt);
6759 	}
6760 
6761 	if (!odbc_get_string_size(cbTableName, szTableName _wide)) {
6762 		odbc_errs_add(&stmt->errs, "HY009", "SQLSpecialColumns: The table name parameter is required");
6763 		ODBC_EXIT_(stmt);
6764 	}
6765 
6766 	switch (fScope) {
6767 	case SQL_SCOPE_CURROW:
6768 	case SQL_SCOPE_TRANSACTION:
6769 	case SQL_SCOPE_SESSION:
6770 		break;
6771 	default:
6772 		odbc_errs_add(&stmt->errs, "HY098", NULL);
6773 		ODBC_EXIT_(stmt);
6774 	}
6775 #endif
6776 
6777 	if (fNullable == SQL_NO_NULLS)
6778 		nullable = 'O';
6779 	else
6780 		nullable = 'U';
6781 
6782 	if (fScope == SQL_SCOPE_CURROW)
6783 		scope = 'C';
6784 	else
6785 		scope = 'T';
6786 
6787 	if (fColType == SQL_BEST_ROWID)
6788 		col_type = 'R';
6789 	else
6790 		col_type = 'V';
6791 
6792 	retcode =
6793 		odbc_stat_execute(stmt _wide, "sp_special_columns", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 7 : 4, "O", szTableName,
6794 				  cbTableName, "O", szSchemaName, cbSchemaName, "O@qualifier", szCatalogName, cbCatalogName,
6795 				  "!@col_type", &col_type, 1, "!@scope", &scope, 1, "!@nullable", &nullable, 1,
6796 				  "V@ODBCVer", (char*) NULL, 0);
6797 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
6798 		odbc_col_setname(stmt, 5, "COLUMN_SIZE");
6799 		odbc_col_setname(stmt, 6, "BUFFER_LENGTH");
6800 		odbc_col_setname(stmt, 7, "DECIMAL_DIGITS");
6801 		if (TDS_IS_SYBASE(stmt->dbc->tds_socket))
6802 			stmt->special_row = ODBC_SPECIAL_SPECIALCOLUMNS;
6803 	}
6804 	ODBC_EXIT_(stmt);
6805 }
6806 
6807 ODBC_FUNC(SQLStatistics, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
6808 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT), P(SQLUSMALLINT,fUnique),
6809 	P(SQLUSMALLINT,fAccuracy) WIDE))
6810 {
6811 	int retcode;
6812 	char unique, accuracy;
6813 
6814 	ODBC_ENTER_HSTMT;
6815 
6816 	tdsdump_log(TDS_DBG_FUNC, "SQLStatistics(%p, %p, %d, %p, %d, %p, %d, %d, %d)\n",
6817 			hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, fUnique, fAccuracy);
6818 
6819 #ifdef TDS_NO_DM
6820 	/* check our buffer lengths */
6821 	if (!IS_VALID_LEN(cbCatalogName) || !IS_VALID_LEN(cbSchemaName) || !IS_VALID_LEN(cbTableName)) {
6822 		odbc_errs_add(&stmt->errs, "HY090", NULL);
6823 		ODBC_EXIT_(stmt);
6824 	}
6825 
6826 	/* check our uniqueness value */
6827 	if (fUnique != SQL_INDEX_UNIQUE && fUnique != SQL_INDEX_ALL) {
6828 		odbc_errs_add(&stmt->errs, "HY100", NULL);
6829 		ODBC_EXIT_(stmt);
6830 	}
6831 
6832 	/* check our accuracy value */
6833 	if (fAccuracy != SQL_QUICK && fAccuracy != SQL_ENSURE) {
6834 		odbc_errs_add(&stmt->errs, "HY101", NULL);
6835 		ODBC_EXIT_(stmt);
6836 	}
6837 
6838 	if (!odbc_get_string_size(cbTableName, szTableName _wide)) {
6839 		odbc_errs_add(&stmt->errs, "HY009", NULL);
6840 		ODBC_EXIT_(stmt);
6841 	}
6842 #endif
6843 
6844 	if (fAccuracy == SQL_ENSURE)
6845 		accuracy = 'E';
6846 	else
6847 		accuracy = 'Q';
6848 
6849 	if (fUnique == SQL_INDEX_UNIQUE)
6850 		unique = 'Y';
6851 	else
6852 		unique = 'N';
6853 
6854 	retcode =
6855 		odbc_stat_execute(stmt _wide, "sp_statistics", TDS_IS_MSSQL(stmt->dbc->tds_socket) ? 5 : 4, "O@table_qualifier",
6856 				  szCatalogName, cbCatalogName, "O@table_owner", szSchemaName, cbSchemaName, "O@table_name",
6857 				  szTableName, cbTableName, "!@is_unique", &unique, 1, "!@accuracy", &accuracy, 1);
6858 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
6859 		odbc_col_setname(stmt, 1, "TABLE_CAT");
6860 		odbc_col_setname(stmt, 2, "TABLE_SCHEM");
6861 		odbc_col_setname(stmt, 8, "ORDINAL_POSITION");
6862 		odbc_col_setname(stmt, 10, "ASC_OR_DESC");
6863 	}
6864 	ODBC_EXIT_(stmt);
6865 }
6866 
6867 ODBC_FUNC(SQLTables, (P(SQLHSTMT,hstmt), PCHARIN(CatalogName,SQLSMALLINT),
6868 	PCHARIN(SchemaName,SQLSMALLINT), PCHARIN(TableName,SQLSMALLINT), PCHARIN(TableType,SQLSMALLINT) WIDE))
6869 {
6870 	int retcode;
6871 	const char *proc = NULL;
6872 	int wildcards;
6873 	TDSSOCKET *tds;
6874 	DSTR schema_name  = DSTR_INITIALIZER;
6875 	DSTR catalog_name = DSTR_INITIALIZER;
6876 	DSTR table_name   = DSTR_INITIALIZER;
6877 	DSTR table_type   = DSTR_INITIALIZER;
6878 
6879 	ODBC_ENTER_HSTMT;
6880 
6881 	tdsdump_log(TDS_DBG_FUNC, "SQLTables(%p, %p, %d, %p, %d, %p, %d, %p, %d)\n",
6882 			hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, szTableType, cbTableType);
6883 
6884 	tds = stmt->dbc->tds_socket;
6885 
6886 	if (!odbc_dstr_copy(stmt->dbc, &catalog_name, cbCatalogName, szCatalogName)
6887 	    || !odbc_dstr_copy(stmt->dbc, &schema_name, cbSchemaName, szSchemaName)
6888 	    || !odbc_dstr_copy(stmt->dbc, &table_name, cbTableName, szTableName)
6889 	    || !odbc_dstr_copy(stmt->dbc, &table_type, cbTableType, szTableType))
6890 		goto memory_error;
6891 
6892 	if (cbTableName == SQL_NTS)
6893 		cbTableName = tds_dstr_len(&table_name);
6894 	if (cbSchemaName == SQL_NTS)
6895 		cbSchemaName = tds_dstr_len(&schema_name);
6896 
6897 	/* support wildcards on catalog (only odbc 3) */
6898 	wildcards = 0;
6899 	if (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3 && stmt->dbc->attr.metadata_id == SQL_FALSE &&
6900 	    (strchr(tds_dstr_cstr(&catalog_name), '%') || strchr(tds_dstr_cstr(&catalog_name), '_')))
6901 		wildcards = 1;
6902 
6903 	proc = "sp_tables";
6904 	if (!tds_dstr_isempty(&catalog_name)) {
6905 		if (wildcards) {
6906 			/* if catalog specified and wildcards use sp_tableswc under mssql2k */
6907 			if (TDS_IS_MSSQL(tds) && tds->conn->product_version >= TDS_MS_VER(8,0,0)) {
6908 				proc = "sp_tableswc";
6909 				if (tds_dstr_isempty(&schema_name))
6910 					if (!tds_dstr_copy(&schema_name, "%"))
6911 						goto memory_error;
6912 			}
6913 			/*
6914 			 * TODO support wildcards on catalog even for Sybase
6915 			 * first execute a select name from master..sysdatabases where name like catalog quoted
6916 			 * build a db1..sp_tables args db2..sp_tables args ... query
6917 			 * collapse results in a single recordset (how??)
6918 			 */
6919 		} else {
6920 			/* if catalog specified and not wildcards use catatog on name (catalog..sp_tables) */
6921 			proc = "..sp_tables";
6922 		}
6923 	}
6924 
6925 	/* fix type if needed quoting it */
6926 	if (!tds_dstr_isempty(&table_type)) {
6927 		int to_fix = 0;
6928 		int elements = 0;
6929 		const char *p = tds_dstr_cstr(&table_type);
6930 		const char *const end = p + tds_dstr_len(&table_type);
6931 
6932 		for (;;) {
6933 			const char *begin = p;
6934 
6935 			p = (const char*) memchr(p, ',', end - p);
6936 			if (!p)
6937 				p = end;
6938 			++elements;
6939 			if ((p - begin) < 2 || begin[0] != '\'' || p[-1] != '\'')
6940 				to_fix = 1;
6941 			if (p >= end)
6942 				break;
6943 			++p;
6944 		}
6945 		/* fix it */
6946 		tdsdump_log(TDS_DBG_INFO1, "to_fix %d elements %d\n", to_fix, elements);
6947 		if (to_fix) {
6948 			char *dst, *type;
6949 
6950 			tdsdump_log(TDS_DBG_INFO1, "fixing type elements\n");
6951 			type = tds_new(char, tds_dstr_len(&table_type) + elements * 2 + 3);
6952 			if (!type)
6953 				goto memory_error;
6954 
6955 			p = tds_dstr_cstr(&table_type);
6956 			dst = type;
6957 			for (;;) {
6958 				const char *begin = p;
6959 
6960 				p = (const char*) memchr(p, ',', end - p);
6961 				if (!p)
6962 					p = end;
6963 				if ((p - begin) < 2 || begin[0] != '\'' || p[-1] != '\'') {
6964 					*dst++ = '\'';
6965 					memcpy(dst, begin, p - begin);
6966 					dst += p - begin;
6967 					*dst++ = '\'';
6968 				} else {
6969 					memcpy(dst, begin, p - begin);
6970 					dst += p - begin;
6971 				}
6972 				if (p >= end)
6973 					break;
6974 				*dst++ = *p++;
6975 			}
6976 			*dst = 0;
6977 			if (!tds_dstr_set(&table_type, type)) {
6978 				free(type);
6979 				goto memory_error;
6980 			}
6981 		}
6982 	}
6983 
6984 	/* special case for catalog list */
6985 	if (strcmp(tds_dstr_cstr(&catalog_name), "%") == 0 && cbTableName <= 0 && cbSchemaName <= 0) {
6986 		retcode =
6987 			odbc_stat_execute(stmt _wide, "sp_tables", 3, "$!P@table_name", "", 0,
6988 					  "$!P@table_owner", "", 0, "!P@table_qualifier", "%", 1);
6989 	} else {
6990 		retcode =
6991 			odbc_stat_execute(stmt _wide, proc, 4,
6992 				"!P@table_name", tds_dstr_cstr(&table_name), tds_dstr_len(&table_name),
6993 				"!P@table_owner", tds_dstr_cstr(&schema_name), tds_dstr_len(&schema_name),
6994 				"!P@table_qualifier", tds_dstr_cstr(&catalog_name), tds_dstr_len(&catalog_name),
6995 				"!@table_type", tds_dstr_cstr(&table_type), tds_dstr_len(&table_type));
6996 	}
6997 	tds_dstr_free(&schema_name);
6998 	tds_dstr_free(&catalog_name);
6999 	tds_dstr_free(&table_name);
7000 	tds_dstr_free(&table_type);
7001 	if (SQL_SUCCEEDED(retcode) && stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) {
7002 		odbc_col_setname(stmt, 1, "TABLE_CAT");
7003 		odbc_col_setname(stmt, 2, "TABLE_SCHEM");
7004 	}
7005 	ODBC_EXIT_(stmt);
7006 
7007 memory_error:
7008 	tds_dstr_free(&schema_name);
7009 	tds_dstr_free(&catalog_name);
7010 	tds_dstr_free(&table_name);
7011 	tds_dstr_free(&table_type);
7012 	odbc_errs_add(&stmt->errs, "HY001", NULL);
7013 	ODBC_EXIT_(stmt);
7014 }
7015 
7016 /**
7017  * Log a useful message about unimplemented options
7018  * Defying belief, Microsoft defines mutually exclusive options that
7019  * some ODBC implementations #define as duplicate values (meaning, of course,
7020  * that they couldn't be implemented in the same function because they're
7021  * indistinguishable.
7022  *
7023  * Those duplicates are commented out below.
7024  */
7025 static void
odbc_log_unimplemented_type(const char function_name[],int fType)7026 odbc_log_unimplemented_type(const char function_name[], int fType)
7027 {
7028 	const char *name, *category;
7029 
7030 	switch (fType) {
7031 #ifdef SQL_ALTER_SCHEMA
7032 	case SQL_ALTER_SCHEMA:
7033 		name = "SQL_ALTER_SCHEMA";
7034 		category = "Supported SQL";
7035 		break;
7036 #endif
7037 #ifdef SQL_ANSI_SQL_DATETIME_LITERALS
7038 	case SQL_ANSI_SQL_DATETIME_LITERALS:
7039 		name = "SQL_ANSI_SQL_DATETIME_LITERALS";
7040 		category = "Supported SQL";
7041 		break;
7042 #endif
7043 	case SQL_COLLATION_SEQ:
7044 		name = "SQL_COLLATION_SEQ";
7045 		category = "Data Source Information";
7046 		break;
7047 	case SQL_CONVERT_BIGINT:
7048 		name = "SQL_CONVERT_BIGINT";
7049 		category = "Conversion Information";
7050 		break;
7051 	case SQL_CONVERT_DATE:
7052 		name = "SQL_CONVERT_DATE";
7053 		category = "Conversion Information";
7054 		break;
7055 	case SQL_CONVERT_DOUBLE:
7056 		name = "SQL_CONVERT_DOUBLE";
7057 		category = "Conversion Information";
7058 		break;
7059 	case SQL_CONVERT_INTERVAL_DAY_TIME:
7060 		name = "SQL_CONVERT_INTERVAL_DAY_TIME";
7061 		category = "Conversion Information";
7062 		break;
7063 	case SQL_CONVERT_INTERVAL_YEAR_MONTH:
7064 		name = "SQL_CONVERT_INTERVAL_YEAR_MONTH";
7065 		category = "Conversion Information";
7066 		break;
7067 	case SQL_DM_VER:
7068 		name = "SQL_DM_VER";
7069 		category = "Added for ODBC 3.x";
7070 		break;
7071 	case SQL_DRIVER_HDESC:
7072 		name = "SQL_DRIVER_HDESC";
7073 		category = "Driver Information";
7074 		break;
7075 	case SQL_DRIVER_HLIB:
7076 		name = "SQL_DRIVER_HLIB";
7077 		category = "Driver Information";
7078 		break;
7079 #ifdef SQL_ODBC_STANDARD_CLI_CONFORMANCE
7080 	case SQL_ODBC_STANDARD_CLI_CONFORMANCE:
7081 		name = "SQL_ODBC_STANDARD_CLI_CONFORMANCE";
7082 		category = "Driver Information";
7083 		break;
7084 #endif
7085 	case SQL_USER_NAME:
7086 		name = "SQL_USER_NAME";
7087 		category = "Data Source Information";
7088 		break;
7089 	/* TODO extension SQL_INFO_SS_NETLIB_NAME ?? */
7090 	default:
7091 		name = "unknown";
7092 		category = "unknown";
7093 		break;
7094 	}
7095 
7096 	tdsdump_log(TDS_DBG_INFO1, "not implemented: %s: option/type %d(%s) [category %s]\n", function_name, fType, name,
7097 		    category);
7098 
7099 	return;
7100 }
7101 
7102 static size_t
odbc_quote_metadata(TDS_DBC * dbc,char type,char * dest,DSTR * dstr)7103 odbc_quote_metadata(TDS_DBC * dbc, char type, char *dest, DSTR * dstr)
7104 {
7105 	int unquote = 0;
7106 	char prev, buf[1200], *dst;
7107 	const char *s = tds_dstr_cstr(dstr);
7108         ssize_t len = tds_dstr_len(dstr);
7109 
7110 	/* limit string/id lengths */
7111 	if (len > 384)
7112 		len = 384;
7113 
7114 	if (!type || (type == 'O' && dbc->attr.metadata_id == SQL_FALSE)) {
7115 		if (dest)
7116 			memcpy(dest, s, len);
7117 		return len;
7118 	}
7119 
7120 	/* where we can have ID or PV */
7121 	assert(type == 'P' || (type == 'O' && dbc->attr.metadata_id != SQL_FALSE));
7122 
7123 	/* ID ? */
7124 	if (dbc->attr.metadata_id != SQL_FALSE) {
7125 		/* strip leading and trailing spaces */
7126 		while (len > 0 && *s == ' ')
7127 			++s, --len;
7128 		while (len > 0 && s[len - 1] == ' ')
7129 			--len;
7130 		/* unquote if necessary */
7131 		if (len > 2 && *s == '\"' && s[len - 1] == '\"') {
7132 			++s, len -= 2;
7133 			unquote = 1;
7134 		}
7135 	}
7136 
7137 	if (!dest)
7138 		dest = buf;
7139 	dst = dest;
7140 
7141 	/*
7142 	 * handle patterns
7143 	 * "'" -> "''" (normal string quoting)
7144 	 *
7145 	 * if metadata_id is FALSE
7146 	 * "\_" -> "[_]"
7147 	 * "\%" -> "[%]"
7148 	 * "[" -> "[[]"
7149 	 *
7150 	 * if metadata_id is TRUE
7151 	 * "\"\"" -> "\"" (if unquote id)
7152 	 * "_" -> "[_]"
7153 	 * "%" -> "[%]"
7154 	 * "[" -> "[[]"
7155 	 */
7156 	prev = 0;
7157 	for (; --len >= 0; ++s) {
7158 		switch (*s) {
7159 		case '\"':
7160 			if (unquote && prev == '\"') {
7161 				prev = 0;	/* avoid "\"\"\"" -> "\"" */
7162 				--dst;
7163 				continue;
7164 			}
7165 			break;
7166 		case '_':
7167 		case '%':
7168 			if (dbc->attr.metadata_id == SQL_FALSE) {
7169 				if (prev != '\\')
7170 					break;
7171 				--dst;
7172 			}
7173 		case '[':
7174 			if (type != 'P')
7175 				break;
7176 			/* quote search string */
7177 			*dst++ = '[';
7178 			*dst++ = *s;
7179 			*dst++ = ']';
7180 			prev = 0;
7181 			continue;
7182 		}
7183 		*dst++ = prev = *s;
7184 	}
7185 	return dst - dest;
7186 }
7187 
7188 static TDSPARAMINFO*
odbc_add_char_param(TDSSOCKET * tds,TDSPARAMINFO * params,const char * name,const char * value,TDS_INT len)7189 odbc_add_char_param(TDSSOCKET *tds, TDSPARAMINFO *params, const char *name,
7190                     const char *value, TDS_INT len)
7191 {
7192 	TDSCOLUMN *col;
7193 
7194 	params = tds_alloc_param_result(params);
7195 	if (!params)
7196 		return NULL;
7197 
7198 	col = params->columns[params->num_cols-1];
7199 	if (!tds_dstr_copy(&col->column_name, name))
7200 		return NULL;
7201 	tds_set_param_type(tds->conn, col, IS_TDS7_PLUS(tds->conn) ? XSYBNVARCHAR : SYBVARCHAR);
7202 
7203 	col->column_size = len;
7204 	if (!tds_alloc_param_data(col))
7205 		return NULL;
7206 
7207 	memcpy(col->column_data, value, len);
7208 	col->column_cur_size = len;
7209 
7210 	return params;
7211 }
7212 
7213 static TDSPARAMINFO*
odbc_add_int_param(TDSSOCKET * tds,TDSPARAMINFO * params,const char * name,int value)7214 odbc_add_int_param(TDSSOCKET *tds, TDSPARAMINFO *params, const char *name, int value)
7215 {
7216 	TDSCOLUMN *col;
7217 
7218 	params = tds_alloc_param_result(params);
7219 	if (!params)
7220 		return NULL;
7221 
7222 	col = params->columns[params->num_cols-1];
7223 	if (!tds_dstr_copy(&col->column_name, name))
7224 		return NULL;
7225 	tds_set_param_type(tds->conn, col, SYBINT4);
7226 
7227 	if (!tds_alloc_param_data(col))
7228 		return NULL;
7229 
7230 	*((TDS_INT*) col->column_data) = value;
7231 	col->column_cur_size = sizeof(TDS_INT);
7232 
7233 	return params;
7234 }
7235 
7236 
7237 static SQLRETURN
odbc_stat_execute(TDS_STMT * stmt _WIDE,const char * begin,int nparams,...)7238 odbc_stat_execute(TDS_STMT * stmt _WIDE, const char *begin, int nparams, ...)
7239 {
7240         int i, param_qualifier = -1;
7241         size_t len;
7242 	char *proc = NULL, *p;
7243 	SQLRETURN retcode;
7244 	va_list marker;
7245 	DSTR qualifier = DSTR_INITIALIZER, value = DSTR_INITIALIZER;
7246 	TDSPARAMINFO *params;
7247 
7248 	/* read all params and calc len required */
7249 	va_start(marker, nparams);
7250 	len = strlen(begin) + 3;
7251 	params = tds_alloc_results(0);
7252 	if (!params)
7253 		goto mem_error;
7254 	for (i = 0; i < nparams; ++i) {
7255 		int param_len;
7256 		bool convert = true;
7257 		bool add_always = false;
7258 		DSTR *out;
7259 		const char *name;
7260 		char type;
7261 
7262 		p = va_arg(marker, char *);
7263 
7264 		for (; ; ++p) {
7265 			switch (*p) {
7266 			case '$':
7267 				add_always = true;
7268 				continue;
7269 			case '!':
7270 				convert = 0;
7271 				continue;
7272 			case 'V':	/* ODBC version */
7273 			case 'O':	/* ordinary arguments */
7274 			case 'P':	/* pattern value arguments */
7275 				type = *p++;
7276 				break;
7277 			default:
7278 				type = 0;	/* ordinary type */
7279 				break;
7280 			}
7281 			break;
7282 		}
7283 		name = p;
7284 
7285 		p = va_arg(marker, char *);
7286 		param_len = va_arg(marker, int);
7287 
7288 		if (type == 'V') {
7289 			int ver = (stmt->dbc->env->attr.odbc_version == SQL_OV_ODBC3) ? 3: 2;
7290 			if (!odbc_add_int_param(stmt->dbc->tds_socket, params, name, ver))
7291 				goto mem_error;
7292 			continue;
7293 		}
7294 
7295 #ifdef ENABLE_ODBC_WIDE
7296 		if (!convert)
7297 			out = tds_dstr_copyn(&value, p, param_len);
7298 		else
7299 			out = odbc_dstr_copy(stmt->dbc, &value, param_len, (ODBC_CHAR *) p);
7300 #else
7301 		out = odbc_dstr_copy(stmt->dbc, &value, param_len, (ODBC_CHAR *) p);
7302 #endif
7303 		if (!out)
7304 			goto mem_error;
7305 
7306 		if (add_always || !tds_dstr_isempty(&value)) {
7307 			char buf[1200];
7308 			int l;
7309 
7310                         l = (int) odbc_quote_metadata(stmt->dbc, type, buf, &value);
7311 			if (!odbc_add_char_param(stmt->dbc->tds_socket, params, name, buf, l))
7312 				goto mem_error;
7313 
7314 			if (begin[0] == '.' && strstr(name, "qualifier")) {
7315 				if (!tds_dstr_dup(&qualifier, &value))
7316 					goto mem_error;
7317 				len += tds_quote_id(stmt->dbc->tds_socket, NULL,
7318 						    tds_dstr_cstr(&qualifier), tds_dstr_len(&qualifier));
7319 				param_qualifier = i;
7320 			}
7321 		}
7322 	}
7323 	tds_dstr_free(&value);
7324 
7325 	/* proc is neither mb or wide, is always utf encoded */
7326 	retcode = odbc_set_stmt_query(stmt, (ODBC_CHAR *) "-", 1 _wide0);
7327 	if (retcode != SQL_SUCCESS)
7328 		goto error;
7329 	stmt->prepared_query_is_rpc = 1;
7330 
7331 	/* set params */
7332 	tds_free_param_results(stmt->params);
7333 	stmt->param_count = params->num_cols;
7334 	stmt->param_num = 1 + stmt->param_count;
7335 	stmt->params = params;
7336 	params = NULL;
7337 
7338 	/* allocate space for string */
7339 	if (!tds_dstr_alloc(&stmt->query, len))
7340 		goto mem_error;
7341 	proc = tds_dstr_buf(&stmt->query);
7342 
7343 	/* build query string */
7344 	p = proc;
7345 	if (param_qualifier >= 0)
7346 		p += tds_quote_id(stmt->dbc->tds_socket, p, tds_dstr_cstr(&qualifier), tds_dstr_len(&qualifier));
7347 	tds_dstr_free(&qualifier);
7348 	strcpy(p, begin);
7349 	p += strlen(begin);
7350 	tds_dstr_setlen(&stmt->query, p - proc);
7351         assert(p + 1 <= proc + len);
7352 
7353 	/* execute it */
7354 	retcode = _SQLExecute(stmt);
7355 	if (SQL_SUCCEEDED(retcode))
7356 		odbc_upper_column_names(stmt);
7357 
7358 	va_end(marker);
7359 	ODBC_RETURN(stmt, retcode);
7360 
7361 mem_error:
7362 	odbc_errs_add(&stmt->errs, "HY001", NULL);
7363 
7364 error:
7365 	tds_dstr_free(&value);
7366 	tds_dstr_free(&qualifier);
7367 	tds_free_results(params);
7368 	va_end(marker);
7369 	return SQL_ERROR;
7370 }
7371 
7372 static SQLRETURN
odbc_free_dynamic(TDS_STMT * stmt)7373 odbc_free_dynamic(TDS_STMT * stmt)
7374 {
7375 	TDSSOCKET *tds;
7376 
7377 	if (!stmt->dyn)
7378 		return TDS_SUCCESS;
7379 
7380 	tds = stmt->dbc->tds_socket;
7381 	if (!tds_needs_unprepare(tds->conn, stmt->dyn)) {
7382 		tds_release_dynamic(&stmt->dyn);
7383 		return SQL_SUCCESS;
7384 	}
7385 
7386 	if (odbc_lock_statement(stmt)) {
7387 		if (TDS_SUCCEED(tds_submit_unprepare(stmt->tds, stmt->dyn))
7388 		    && TDS_SUCCEED(tds_process_simple_query(stmt->tds))) {
7389 			odbc_unlock_statement(stmt);
7390 			tds_release_dynamic(&stmt->dyn);
7391 			return SQL_SUCCESS;
7392 		}
7393 	}
7394 
7395 	if (TDS_SUCCEED(tds_deferred_unprepare(tds->conn, stmt->dyn))) {
7396 		tds_release_dynamic(&stmt->dyn);
7397 		return SQL_SUCCESS;
7398 	}
7399 
7400 	ODBC_SAFE_ERROR(stmt);
7401 	return SQL_ERROR;
7402 }
7403 
7404 /**
7405  * Close server cursors
7406  */
7407 static SQLRETURN
odbc_free_cursor(TDS_STMT * stmt)7408 odbc_free_cursor(TDS_STMT * stmt)
7409 {
7410 	TDSCURSOR *cursor = stmt->cursor;
7411 	TDSSOCKET *tds;
7412 
7413 	if (!cursor)
7414 		return SQL_SUCCESS;
7415 
7416 	/* if possible deallocate now */
7417 	if (odbc_lock_statement(stmt)) {
7418 		tds = stmt->tds;
7419 
7420 		cursor->status.dealloc   = TDS_CURSOR_STATE_REQUESTED;
7421 		if (TDS_SUCCEED(tds_cursor_close(tds, cursor))) {
7422 			if (TDS_SUCCEED(tds_process_simple_query(tds))) {
7423 				/* TODO check error */
7424 				tds_cursor_dealloc(tds, cursor);
7425 				tds_release_cursor(&stmt->cursor);
7426 				return SQL_SUCCESS;
7427 			}
7428 		}
7429 	}
7430 
7431 	tds = stmt->dbc->tds_socket;
7432 	if (TDS_SUCCEED(tds_deferred_cursor_dealloc(tds->conn, cursor))) {
7433 		tds_release_cursor(&stmt->cursor);
7434 		return SQL_SUCCESS;
7435 	}
7436 
7437 	ODBC_SAFE_ERROR(stmt);
7438 	return SQL_ERROR;
7439 }
7440 
7441 SQLRETURN ODBC_PUBLIC ODBC_API
SQLSetScrollOptions(SQLHSTMT hstmt,SQLUSMALLINT fConcurrency,SQLLEN crowKeyset,SQLUSMALLINT crowRowset)7442 SQLSetScrollOptions(SQLHSTMT hstmt, SQLUSMALLINT fConcurrency, SQLLEN crowKeyset, SQLUSMALLINT crowRowset)
7443 {
7444 	SQLUSMALLINT info;
7445 	SQLUINTEGER value, check;
7446 	SQLUINTEGER cursor_type;
7447 
7448 	ODBC_ENTER_HSTMT;
7449 
7450 	tdsdump_log(TDS_DBG_FUNC, "SQLSetScrollOptions(%p, %u, %ld, %u)\n",
7451 			hstmt, fConcurrency, (long int) crowKeyset, crowRowset);
7452 
7453 	if (!stmt->dbc->cursor_support) {
7454 		odbc_errs_add(&stmt->errs, "HYC00", NULL);
7455 		ODBC_EXIT_(stmt);
7456 	}
7457 
7458 	if (stmt->cursor) {
7459 		odbc_errs_add(&stmt->errs, "24000", NULL);
7460 		ODBC_EXIT_(stmt);
7461 	}
7462 
7463 	switch (crowKeyset) {
7464 	case SQL_SCROLL_FORWARD_ONLY:
7465 		info = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2;
7466 		cursor_type = SQL_CURSOR_FORWARD_ONLY;
7467 		break;
7468 	case SQL_SCROLL_STATIC:
7469 		info = SQL_STATIC_CURSOR_ATTRIBUTES2;
7470 		cursor_type = SQL_CURSOR_STATIC;
7471 		break;
7472 	case SQL_SCROLL_KEYSET_DRIVEN:
7473 		info = SQL_KEYSET_CURSOR_ATTRIBUTES2;
7474 		cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
7475 		break;
7476 	case SQL_SCROLL_DYNAMIC:
7477 		info = SQL_DYNAMIC_CURSOR_ATTRIBUTES2;
7478 		cursor_type = SQL_CURSOR_DYNAMIC;
7479 		break;
7480 	default:
7481 		if (crowKeyset > crowRowset) {
7482 			info = SQL_KEYSET_CURSOR_ATTRIBUTES2;
7483 			cursor_type = SQL_CURSOR_KEYSET_DRIVEN;
7484 			break;
7485 		}
7486 
7487 		odbc_errs_add(&stmt->errs, "HY107", NULL);
7488 		ODBC_EXIT_(stmt);
7489 	}
7490 
7491 	switch (fConcurrency) {
7492 	case SQL_CONCUR_READ_ONLY:
7493 		check = SQL_CA2_READ_ONLY_CONCURRENCY;
7494 		break;
7495 	case SQL_CONCUR_LOCK:
7496 		check = SQL_CA2_LOCK_CONCURRENCY;
7497 		break;
7498 	case SQL_CONCUR_ROWVER:
7499 		check = SQL_CA2_OPT_ROWVER_CONCURRENCY;
7500 		break;
7501 	case SQL_CONCUR_VALUES:
7502 		check = SQL_CA2_OPT_VALUES_CONCURRENCY;
7503 		break;
7504 	default:
7505 		odbc_errs_add(&stmt->errs, "HY108", NULL);
7506 		ODBC_EXIT_(stmt);
7507 	}
7508 
7509 	value = 0;
7510 	_SQLGetInfo(stmt->dbc, info, &value, sizeof(value), NULL _wide0);
7511 
7512 	if ((value & check) == 0) {
7513 		odbc_errs_add(&stmt->errs, "HYC00", NULL);
7514 		ODBC_EXIT_(stmt);
7515 	}
7516 
7517 	_SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) (TDS_INTPTR) cursor_type, 0 _wide0);
7518 	_SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) (TDS_INTPTR) fConcurrency, 0 _wide0);
7519 	_SQLSetStmtAttr(hstmt, SQL_ATTR_KEYSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crowKeyset, 0 _wide0);
7520 	_SQLSetStmtAttr(hstmt, SQL_ROWSET_SIZE, (SQLPOINTER) (TDS_INTPTR) crowRowset, 0 _wide0);
7521 
7522 	ODBC_EXIT_(stmt);
7523 }
7524 
7525 #include "odbc_export.h"
7526 
7527 /* Under Windows driver exports functions */
7528 /* The win_ prefix is to avoid clash with inline function.
7529  * The prefix is removed from exported functions using definition file.
7530  */
7531 #ifdef _WIN32
7532 RETCODE SQL_API win_bcp_initA(HDBC hdbc, const char *tblname, const char *hfile,
7533 	const char *errfile, int direction);
7534 RETCODE SQL_API win_bcp_initW(HDBC hdbc, const SQLWCHAR *tblname, const SQLWCHAR *hfile,
7535 	const SQLWCHAR *errfile, int direction);
7536 RETCODE SQL_API win_bcp_control(HDBC hdbc, int field, void *value);
7537 RETCODE SQL_API win_bcp_colptr(HDBC hdbc, const unsigned char * colptr, int table_column);
7538 RETCODE SQL_API win_bcp_sendrow(HDBC hdbc);
7539 int SQL_API win_bcp_batch(HDBC hdbc);
7540 int SQL_API win_bcp_done(HDBC hdbc);
7541 RETCODE SQL_API win_bcp_bind(HDBC hdbc, const unsigned char * varaddr, int prefixlen, int varlen,
7542 	const unsigned char * terminator, int termlen, int vartype, int table_column);
7543 
7544 RETCODE SQL_API
win_bcp_initA(HDBC hdbc,const char * tblname,const char * hfile,const char * errfile,int direction)7545 win_bcp_initA(HDBC hdbc, const char *tblname, const char *hfile, const char *errfile, int direction)
7546 {
7547 	return bcp_initA(hdbc, tblname, hfile, errfile, direction);
7548 }
7549 
7550 #ifdef ENABLE_ODBC_WIDE
7551 RETCODE SQL_API
win_bcp_initW(HDBC hdbc,const SQLWCHAR * tblname,const SQLWCHAR * hfile,const SQLWCHAR * errfile,int direction)7552 win_bcp_initW(HDBC hdbc, const SQLWCHAR *tblname, const SQLWCHAR *hfile, const SQLWCHAR *errfile, int direction)
7553 {
7554 	return bcp_initW(hdbc, tblname, hfile, errfile, direction);
7555 }
7556 #endif
7557 
7558 RETCODE SQL_API
win_bcp_control(HDBC hdbc,int field,void * value)7559 win_bcp_control(HDBC hdbc, int field, void *value)
7560 {
7561 	return bcp_control(hdbc, field, value);
7562 }
7563 
7564 RETCODE SQL_API
win_bcp_colptr(HDBC hdbc,const unsigned char * colptr,int table_column)7565 win_bcp_colptr(HDBC hdbc, const unsigned char * colptr, int table_column)
7566 {
7567 	return bcp_colptr(hdbc, colptr, table_column);
7568 }
7569 
7570 RETCODE SQL_API
win_bcp_sendrow(HDBC hdbc)7571 win_bcp_sendrow(HDBC hdbc)
7572 {
7573 	return bcp_sendrow(hdbc);
7574 }
7575 
7576 int SQL_API
win_bcp_batch(HDBC hdbc)7577 win_bcp_batch(HDBC hdbc)
7578 {
7579 	return bcp_batch(hdbc);
7580 }
7581 
7582 int SQL_API
win_bcp_done(HDBC hdbc)7583 win_bcp_done(HDBC hdbc)
7584 {
7585 	return bcp_done(hdbc);
7586 }
7587 
7588 RETCODE SQL_API
win_bcp_bind(HDBC hdbc,const unsigned char * varaddr,int prefixlen,int varlen,const unsigned char * terminator,int termlen,int vartype,int table_column)7589 win_bcp_bind(HDBC hdbc, const unsigned char * varaddr, int prefixlen, int varlen,
7590 	const unsigned char * terminator, int termlen, int vartype, int table_column)
7591 {
7592 	return bcp_bind(hdbc, varaddr, prefixlen, varlen, terminator, termlen, vartype, table_column);
7593 }
7594 #endif
7595 
7596