int main(int argc, char *argv[]) { SQLLEN cb = SQL_NTS; odbc_use_version3 = 1; odbc_connect(); odbc_command_with_result(odbc_stmt, "drop proc sp_paramcore_test"); odbc_command("create proc sp_paramcore_test @s varchar(100) output as select @s = '12345'"); /* here we pass a NULL buffer for input SQL_NTS */ CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, OUTSTRING_LEN, 0, NULL, OUTSTRING_LEN, &cb, "S"); cb = SQL_NTS; CHKExecDirect(T(SP_TEXT), SQL_NTS, "E"); odbc_reset_statement(); /* here we pass a NULL buffer for input */ CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_VARCHAR, 18, 0, NULL, OUTSTRING_LEN, &cb, "S"); cb = 1; CHKExecDirect(T(SP_TEXT), SQL_NTS, "E"); odbc_reset_statement(); odbc_command("drop proc sp_paramcore_test"); odbc_command("create proc sp_paramcore_test @s numeric(10,2) output as select @s = 12345.6"); odbc_reset_statement(); #if 0 /* this fails even on native platforms */ /* here we pass a NULL buffer for output */ cb = sizeof(SQL_NUMERIC_STRUCT); SQLBindParameter(odbc_stmt, 1, SQL_PARAM_OUTPUT, SQL_C_NUMERIC, SQL_NUMERIC, 18, 0, NULL, OUTSTRING_LEN, &cb); odbc_read_error(); cb = 1; odbc_command_with_result(odbc_stmt, SP_TEXT); odbc_read_error(); odbc_reset_statement(); #endif odbc_command("drop proc sp_paramcore_test"); odbc_disconnect(); printf("Done successfully!\n"); return 0; }
int main(void) { int i; char cmd[128 + 110*10]; printf("SQLWCHAR size is: %d\n", (int) sizeof(SQLWCHAR)); odbc_use_version3 = 1; odbc_connect(); /* this test do not work with Sybase */ if (!odbc_db_is_microsoft()) { odbc_disconnect(); return 0; } strcpy(cmd, "create procedure #proc_longerror as\nbegin\nraiserror('"); for (i = 0; i < 110; ++i) strcat(cmd, "reallylong"); strcat(cmd, " error', 16, 1)\nend\n"); odbc_command(cmd); CHKExecDirect(T("{CALL #proc_longerror}"), SQL_NTS, "E"); extract_error(odbc_stmt, SQL_HANDLE_STMT); odbc_disconnect(); return 0; }
static int Test(int direct) { SQLTCHAR buf[256]; SQLTCHAR sqlstate[6]; odbc_connect(); if (!close_last_socket()) { fprintf(stderr, "Error closing connection\n"); return 1; } /* force disconnection closing socket */ if (direct) { CHKExecDirect(T("SELECT 1"), SQL_NTS, "E"); } else { SQLSMALLINT cols; /* use prepare, force dialog with server */ if (CHKPrepare(T("SELECT 1"), SQL_NTS, "SE") == SQL_SUCCESS) CHKNumResultCols(&cols, "E"); } CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, buf, ODBC_VECTOR_SIZE(buf), NULL, "SI"); sqlstate[5] = 0; printf("state=%s err=%s\n", C(sqlstate), C(buf)); odbc_disconnect(); printf("Done.\n"); return 0; }
static int test_select(void *buf, SQLINTEGER buflen, SQLLEN * bytes_returned) { SQLHSTMT odbc_stmt = SQL_NULL_HSTMT; SQLLEN strlen_or_ind = 0; const char *qstr = "select * from " TEST_TABLE_NAME; assert(odbc_conn); assert(odbc_env); /* allocate new statement handle */ CHKAllocHandle(SQL_HANDLE_STMT, odbc_conn, &odbc_stmt, "SI"); /* execute query */ CHKExecDirect(T(qstr), SQL_NTS, "SINo"); /* fetch first page of first result row of unbound column */ CHKFetch("S"); strlen_or_ind = 0; CHKGetData(1, SQL_C_BINARY, buf, buflen, &strlen_or_ind, "SINo"); *bytes_returned = ((strlen_or_ind > buflen || (strlen_or_ind == SQL_NO_TOTAL)) ? buflen : strlen_or_ind); /* ensure that this was the only row */ CHKFetch("No"); SQLFreeHandle(SQL_HANDLE_STMT, odbc_stmt); ODBC_FREE(); return 0; }
int main(int argc, char **argv) { char buff[64]; SQLLEN ind; odbc_use_version3 = 1; odbc_connect(); odbc_check_cursor(); exec_direct("CREATE TABLE #t1 ( k INT, c VARCHAR(20))"); exec_direct("INSERT INTO #t1 VALUES (1, 'aaa')"); odbc_reset_statement(); CHKSetStmtAttr(SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_LOCK, SQL_IS_UINTEGER, "S"); CHKSetCursorName(T("c112"), SQL_NTS, "S"); CHKSetConnectAttr(SQL_ATTR_AUTOCOMMIT, int2ptr(SQL_AUTOCOMMIT_OFF), 0, "S"); CHKPrepare(T("SELECT * FROM #t1 FOR UPDATE"), SQL_NTS, "S"); CHKExecute("S"); CHKFetch("S"); exec_direct("UPDATE #t1 SET c = 'xxx' WHERE CURRENT OF c112"); CHKCloseCursor("SI"); CHKEndTran(SQL_HANDLE_DBC, odbc_conn, SQL_COMMIT, "S"); CHKSetConnectAttr(SQL_ATTR_AUTOCOMMIT, int2ptr(SQL_AUTOCOMMIT_ON), 0, "S"); CHKExecDirect(T("SELECT c FROM #t1 WHERE k = 1"), SQL_NTS, "S"); CHKFetch("S"); CHKGetData(1, SQL_C_CHAR, buff, sizeof(buff), &ind, "S"); printf(">> New value after update = [%s] (should be [xxx]) \n", buff); CHKFreeHandle(SQL_HANDLE_STMT, (SQLHANDLE) odbc_stmt, "S"); odbc_stmt = SQL_NULL_HSTMT; odbc_disconnect(); return 0; }
static int Test(int direct) { SQLTCHAR buf[256]; SQLTCHAR sqlstate[6]; time_t start_time, end_time; odbc_mark_sockets_opened(); odbc_connect(); if (!shutdown_last_socket()) { fprintf(stderr, "Error shutting down connection\n"); return 1; } CHKSetStmtAttr(SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER) 10, SQL_IS_UINTEGER, "S"); alarm(30); start_time = time(NULL); if (direct) { CHKExecDirect(T("SELECT 1"), SQL_NTS, "E"); } else { SQLSMALLINT cols; /* force dialog with server */ if (CHKPrepare(T("SELECT 1"), SQL_NTS, "SE") == SQL_SUCCESS) CHKNumResultCols(&cols, "E"); } end_time = time(NULL); alarm(0); memset(sqlstate, 'X', sizeof(sqlstate)); CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, buf, ODBC_VECTOR_SIZE(buf), NULL, "SI"); sqlstate[5] = 0; printf("Message: %s - %s\n", C(sqlstate), C(buf)); if (strcmp(C(sqlstate), "HYT00") || !strstr(C(buf), "Timeout")) { fprintf(stderr, "Invalid timeout message\n"); return 1; } if (end_time - start_time < 10 || end_time - start_time > 26) { fprintf(stderr, "Unexpected connect timeout (%d)\n", (int) (end_time - start_time)); return 1; } odbc_disconnect(); if (end_socket >= 0) close(end_socket); printf("Done.\n"); return 0; }
/* stripped down version of TestInput for NULLs */ static void NullInput(SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *param_type) { char sbuf[1024]; SQLLEN out_len = SQL_NULL_DATA; odbc_reset_statement(); /* create a table with a column of that type */ odbc_reset_statement(); sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s NULL)", param_type); odbc_command(sbuf); if (use_cursors) { odbc_reset_statement(); CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S"); CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S"); } /* insert data using prepared statements */ sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)"); if (exec_direct) { CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S"); CHKExecDirect(T(sbuf), SQL_NTS, "SNo"); } else { if (prepare_before) CHKPrepare(T(sbuf), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, NULL, 1, &out_len, "S"); if (!prepare_before) CHKPrepare(T(sbuf), SQL_NTS, "S"); CHKExecute("SNo"); } /* check if row is present */ odbc_reset_statement(); if (!odbc_db_is_microsoft() && strcmp(param_type, "TEXT") == 0) odbc_command("SELECT * FROM #tmp_insert WHERE col LIKE ''"); else odbc_command("SELECT * FROM #tmp_insert WHERE col IS NULL"); CHKFetch("S"); CHKFetch("No"); CHKMoreResults("No"); odbc_command("DROP TABLE #tmp_insert"); ODBC_FREE(); }
static void Test(int use_threads, int return_data) { tds_thread wait_thread; #if !HAVE_ALARM if (!use_threads) return; #endif printf("testing with %s\n", use_threads ? "threads" : "signals"); printf(">> Wait 5 minutes...\n"); if (!use_threads) { alarm(4); signal(SIGALRM, sigalrm_handler); } else { int err; exit_thread = 0; err = tds_thread_create(&wait_thread, wait_thread_proc, NULL); if (err != 0) { perror("tds_thread_create"); exit(1); } } if (!return_data) CHKExecDirect(T("WAITFOR DELAY '000:05:00'"), SQL_NTS, "E"); else odbc_command2("SELECT MAX(p1.k) FROM tab1 p1, tab1 p2, tab1 p3, tab1 p4", "E"); tds_mutex_lock(&mtx); exit_thread = 1; tds_mutex_unlock(&mtx); if (!use_threads) { alarm(0); } else { tds_thread_join(wait_thread, NULL); } getErrorInfo(SQL_HANDLE_STMT, odbc_stmt); if (strcmp(C(sqlstate), "HY008") != 0) { fprintf(stderr, "Unexpected sql state returned\n"); odbc_disconnect(); exit(1); } odbc_reset_statement(); odbc_command("SELECT name FROM sysobjects WHERE 0=1"); }
int odbc_connect(void) { ODBC_BUF *odbc_buf = NULL; char command[512]; const char *p; if (odbc_read_login_info()) exit(1); if (odbc_use_version3) { CHKAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &odbc_env, "S"); SQLSetEnvAttr(odbc_env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) (SQL_OV_ODBC3), SQL_IS_UINTEGER); CHKAllocHandle(SQL_HANDLE_DBC, odbc_env, &odbc_conn, "S"); } else { CHKAllocEnv(&odbc_env, "S"); CHKAllocConnect(&odbc_conn, "S"); } printf("odbctest\n--------\n\n"); printf("connection parameters:\nserver: '%s'\nuser: '******'\npassword: '******'\ndatabase: '%s'\n", odbc_server, odbc_user, "????" /* odbc_password */ , odbc_database); p = getenv("ODBC_MARS"); if (p && atoi(p) != 0) SQLSetConnectAttr(odbc_conn, 1224 /*SQL_COPT_SS_MARS_ENABLED*/, (SQLPOINTER) 1 /*SQL_MARS_ENABLED_YES*/, SQL_IS_UINTEGER); if (odbc_set_conn_attr) (*odbc_set_conn_attr)(); CHKConnect(T(odbc_server), SQL_NTS, T(odbc_user), SQL_NTS, T(odbc_password), SQL_NTS, "SI"); CHKAllocStmt(&odbc_stmt, "S"); sprintf(command, "use %s", odbc_database); printf("%s\n", command); CHKExecDirect(T(command), SQL_NTS, "SI"); #ifndef TDS_NO_DM /* unixODBC seems to require it */ SQLMoreResults(odbc_stmt); #endif ODBC_FREE(); return 0; }
static void CheckNoRow(const char *query) { SQLRETURN rc; rc = CHKExecDirect(T(query), SQL_NTS, "SINo"); if (rc == SQL_NO_DATA) return; do { SQLSMALLINT cols; CHKNumResultCols(&cols, "S"); if (cols != 0) { fprintf(stderr, "Data not expected here, query:\n\t%s\n", query); exit(1); } } while (CHKMoreResults("SNo") == SQL_SUCCESS); }
int odbc_connect(void) { char command[512]; if (odbc_read_login_info()) exit(1); if (odbc_use_version3) { CHKAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &odbc_env, "S"); SQLSetEnvAttr(odbc_env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) (SQL_OV_ODBC3), SQL_IS_UINTEGER); CHKAllocHandle(SQL_HANDLE_DBC, odbc_env, &odbc_conn, "S"); } else { CHKAllocEnv(&odbc_env, "S"); CHKAllocConnect(&odbc_conn, "S"); } printf("odbctest\n--------\n\n"); printf("connection parameters:\nserver: '%s'\nuser: '******'\npassword: '******'\ndatabase: '%s'\n", odbc_server, odbc_user, "????" /* odbc_password */ , odbc_database); if (odbc_set_conn_attr) (*odbc_set_conn_attr)(); CHKR(SQLConnect, (odbc_conn, (SQLCHAR *) odbc_server, SQL_NTS, (SQLCHAR *) odbc_user, SQL_NTS, (SQLCHAR *) odbc_password, SQL_NTS), "SI"); CHKAllocStmt(&odbc_stmt, "S"); sprintf(command, "use %s", odbc_database); printf("%s\n", command); CHKExecDirect((SQLCHAR *) command, SQL_NTS, "SI"); #ifndef TDS_NO_DM /* unixODBC seems to require it */ SQLMoreResults(odbc_stmt); #endif return 0; }
static void Test(int direct) { SQLLEN ind; int len = strlen(test_text), n, i; const char *p; char *pp; SQLPOINTER ptr; unsigned char buf[256], *pb; SQLRETURN RetCode; int type, lc, sql_type; /* create table to hold data */ odbc_command_with_result(odbc_stmt, "DROP TABLE #putdata"); odbc_command("CREATE TABLE #putdata (c TEXT NULL, b IMAGE NULL)"); sql_type = SQL_LONGVARCHAR; type = SQL_C_CHAR; lc = 1; for (;;) { CHKBindParameter(1, SQL_PARAM_INPUT, type, sql_type, 0, 0, (SQLPOINTER) 123, 0, &ind, "S"); /* length required */ ind = SQL_LEN_DATA_AT_EXEC(len * lc); /* * test for char */ if (!direct) { CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKExecute("Ne"); } else { CHKExecDirect(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "Ne"); } p = test_text; n = 5; ptr = ((char*)0) + 0xdeadbeef; CHKParamData(&ptr, "Ne"); if (ptr != (SQLPOINTER) 123) { fprintf(stderr, "%p\n", ptr); ODBC_REPORT_ERROR("Wrong pointer from SQLParamData"); } while (*p) { int l = strlen(p); if (l < n) n = l; if (type == SQL_C_CHAR) { CHKPutData((char *) p, n, "S"); } else { SQLWCHAR buf[256]; CHKPutData((char *) buf, to_sqlwchar(buf, p, n), "S"); } p += n; n *= 2; } CHKParamData(&ptr, "S"); CHKParamData(&ptr, "E"); /* check state and reset some possible buffers */ odbc_command("DECLARE @i INT"); /* use server ntext if available */ if (sql_type == SQL_LONGVARCHAR && odbc_db_is_microsoft() && odbc_db_version_int() >= 0x08000000u) { sql_type = SQL_WLONGVARCHAR; continue; } if (type != SQL_C_CHAR) break; sql_type = SQL_LONGVARCHAR; type = SQL_C_WCHAR; lc = sizeof(SQLWCHAR); } /* update row setting binary field */ for (i = 0; i < 255; ++i) buf[i] = BYTE_AT(i); /* * test for binary */ CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER) 4567, 0, &ind, "S"); ind = SQL_LEN_DATA_AT_EXEC(254); CHKPrepare(T("UPDATE #putdata SET b = ?"), SQL_NTS, "S"); CHKExecute("Ne"); pb = buf; n = 7; CHKParamData(&ptr, "Ne"); if (ptr != (SQLPOINTER) 4567) ODBC_REPORT_ERROR("Wrong pointer from SQLParamData"); while (pb != (buf + 254)) { int l = buf + 254 - pb; if (l < n) n = l; CHKPutData((char *) pb, n, "S"); pb += n; n *= 2; } CHKParamData(&ptr, "S"); CHKParamData(&ptr, "E"); /* check state and reset some possible buffers */ odbc_command("DECLARE @i2 INT"); CHKFreeStmt(SQL_RESET_PARAMS, "S"); /* check inserts ... there should be all equal rows */ strcpy(sql, "IF EXISTS(SELECT * FROM #putdata WHERE CONVERT(VARBINARY(255),b) <> 0x"); /* append binary */ for (i = 0; i < 254; ++i) sprintf(strchr(sql, 0), "%02x", buf[i]); strcat(sql, " OR CONVERT(VARCHAR(255),c) <> '"); /* append string */ pp = strchr(sql, 0); p = test_text; do { *pp++ = *p; if (*p == '\'') *pp++ = *p; } while(*p++); strcat(sql, "') SELECT 1"); odbc_check_no_row(sql); odbc_command("DELETE FROM #putdata"); /* test len == 0 case from ML */ type = SQL_C_CHAR; for (;;) { if (!direct) CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, type, SQL_LONGVARCHAR, 0, 0, (PTR) 2, 0, &ind, "S"); ind = SQL_LEN_DATA_AT_EXEC(0); if (!direct) CHKExecute("Ne"); else CHKExecDirect(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "Ne"); RetCode = SQL_NEED_DATA; while (RetCode == SQL_NEED_DATA) { RetCode = SQLParamData(odbc_stmt, &ptr); if (RetCode == SQL_NEED_DATA) { if (type == SQL_C_CHAR) { CHKPutData("abc", 3, "S"); } else { SQLWCHAR buf[10]; CHKPutData(buf, to_sqlwchar(buf, "abc", 3), "S"); } } } if (type != SQL_C_CHAR) break; type = SQL_C_WCHAR; odbc_reset_statement(); } /* check inserts ... */ odbc_check_no_row("IF EXISTS(SELECT * FROM #putdata WHERE c NOT LIKE 'abc') SELECT 1"); odbc_command("DELETE FROM #putdata"); /* test putting 0 bytes from Sebastien Flaesch */ if (odbc_db_is_microsoft()) { type = SQL_C_CHAR; for (;;) { if (!direct) CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, type, SQL_LONGVARCHAR, 10, 0, (PTR) 2, 10, &ind, "S"); ind = SQL_DATA_AT_EXEC; if (!direct) CHKExecute("Ne"); else CHKExecDirect(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "Ne"); RetCode = SQL_NEED_DATA; while (RetCode == SQL_NEED_DATA) { RetCode = SQLParamData(odbc_stmt, &ptr); if (RetCode == SQL_NEED_DATA) CHKPutData("", 0, "S"); } if (type != SQL_C_CHAR) break; type = SQL_C_WCHAR; odbc_reset_statement(); } /* check inserts ... */ odbc_check_no_row("IF EXISTS(SELECT * FROM #putdata WHERE c NOT LIKE '') SELECT 1"); } /* TODO test cancel inside SQLExecute */ }
static int TestOutput(const char *type, const char *value_to_convert, SQLSMALLINT out_c_type, SQLSMALLINT out_sql_type, const char *expected) { char sbuf[1024]; unsigned char out_buf[256]; SQLLEN out_len = 0; const char *sep; odbc_reset_statement(); /* build store procedure to test */ odbc_command("IF OBJECT_ID('spTestProc') IS NOT NULL DROP PROC spTestProc"); sep = "'"; if (strncmp(value_to_convert, "0x", 2) == 0) sep = ""; sprintf(sbuf, "CREATE PROC spTestProc @i %s OUTPUT AS SELECT @i = CONVERT(%s, %s%s%s)", type, type, sep, value_to_convert, sep); odbc_command(sbuf); memset(out_buf, 0, sizeof(out_buf)); if (use_cursors) { odbc_reset_statement(); CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S"); CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S"); } /* bind parameter */ if (exec_direct) { CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf, sizeof(out_buf), &out_len, "S"); /* call store procedure */ CHKExecDirect(T("{call spTestProc(?)}"), SQL_NTS, "S"); } else { if (prepare_before) CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_OUTPUT, out_c_type, out_sql_type, precision, 0, out_buf, sizeof(out_buf), &out_len, "S"); if (!prepare_before) CHKPrepare(T("{call spTestProc(?)}"), SQL_NTS, "S"); CHKExecute("S"); } /* * MS OBDC requires it cause first recordset is a recordset with a * warning caused by the way it execute RPC (via EXEC statement) */ if (use_cursors && !odbc_driver_is_freetds()) SQLMoreResults(odbc_stmt); /* test results */ odbc_c2string(sbuf, out_c_type, out_buf, out_len); if (strcmp(sbuf, expected) != 0) { if (only_test) { odbc_command("drop proc spTestProc"); ODBC_FREE(); return 1; } fprintf(stderr, "Wrong result\n Got: %s\n Expected: %s\n", sbuf, expected); exit(1); } only_test = 0; odbc_command("drop proc spTestProc"); ODBC_FREE(); return 0; }
static void TestInput(SQLSMALLINT out_c_type, const char *type, SQLSMALLINT out_sql_type, const char *param_type, const char *value_to_convert) { char sbuf[1024]; unsigned char out_buf[256]; SQLLEN out_len = 0; const char *expected = value_to_convert; size_t value_len = strlen(value_to_convert); const char *p; const char *sep = "'"; odbc_reset_statement(); /* execute a select to get data as wire */ if ((p = strstr(value_to_convert, " -> ")) != NULL) { value_len = p - value_to_convert; expected = p + 4; } if (value_len >= 2 && strncmp(value_to_convert, "0x", 2) == 0) sep = ""; sprintf(sbuf, "SELECT CONVERT(%s, %s%.*s%s)", type, sep, (int) value_len, value_to_convert, sep); odbc_command(sbuf); SQLBindCol(odbc_stmt, 1, out_c_type, out_buf, sizeof(out_buf), &out_len); CHKFetch("SI"); CHKFetch("No"); CHKMoreResults("No"); if (use_nts) { out_len = SQL_NTS; use_nts = 0; } /* create a table with a column of that type */ odbc_reset_statement(); sprintf(sbuf, "CREATE TABLE #tmp_insert (col %s)", param_type); odbc_command(sbuf); if (use_cursors) { odbc_reset_statement(); CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S"); CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S"); } /* insert data using prepared statements */ sprintf(sbuf, "INSERT INTO #tmp_insert VALUES(?)"); if (exec_direct) { CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S"); if (check_truncation) CHKExecDirect(T(sbuf), SQL_NTS, "E"); else CHKExecDirect(T(sbuf), SQL_NTS, "SNo"); } else { if (prepare_before) CHKPrepare(T(sbuf), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, out_c_type, out_sql_type, 20, 0, out_buf, sizeof(out_buf), &out_len, "S"); if (!prepare_before) CHKPrepare(T(sbuf), SQL_NTS, "S"); if (check_truncation) CHKExecute("E"); else CHKExecute("SNo"); } /* check if row is present */ if (!check_truncation) { odbc_reset_statement(); sep = "'"; if (strncmp(expected, "0x", 2) == 0) sep = ""; if (strcmp(param_type, "TEXT") == 0) sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE CONVERT(VARCHAR(255), col) = CONVERT(VARCHAR(255), %s%s%s)", sep, expected, sep); else if (strcmp(param_type, "NTEXT") == 0) sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE CONVERT(NVARCHAR(2000), col) = CONVERT(NVARCHAR(2000), %s%s%s)", sep, expected, sep); else if (strcmp(param_type, "IMAGE") == 0) sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE CONVERT(VARBINARY(255), col) = CONVERT(VARBINARY(255), %s%s%s)", sep, expected, sep); else sprintf(sbuf, "SELECT * FROM #tmp_insert WHERE col = CONVERT(%s, %s%s%s)", param_type, sep, expected, sep); odbc_command(sbuf); CHKFetch("S"); CHKFetch("No"); CHKMoreResults("No"); } check_truncation = 0; odbc_command("DROP TABLE #tmp_insert"); ODBC_FREE(); }
static void query_test(const char* expected, const char *expected_status) { #define ARRAY_SIZE 10 ODBC_BUF *odbc_buf = NULL; SQLUINTEGER *ids; SQLCHAR *descs; SQLLEN *id_lens, *desc_lens; SQLULEN processed; SQLUSMALLINT i, statuses[ARRAY_SIZE]; int desc_len = trunc ? 4 : 51; int rec_size = 0; Record *rec = NULL; char status[20]; assert(odbc_stmt != SQL_NULL_HSTMT); odbc_reset_statement(); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_STATUS_PTR, statuses, 0); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_ARRAY_SIZE, (void *) ARRAY_SIZE, 0); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROWS_FETCHED_PTR, &processed, 0); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0); if (!record_bind) { ids = (SQLUINTEGER *) ODBC_GET(sizeof(SQLUINTEGER) * ARRAY_SIZE); descs = ODBC_GET(sizeof(SQLCHAR) * ARRAY_SIZE * desc_len); desc_lens = (SQLLEN *) ODBC_GET(sizeof(SQLLEN) * ARRAY_SIZE); id_lens = (SQLLEN *) ODBC_GET(sizeof(SQLLEN) * ARRAY_SIZE); assert(descs && ids && desc_lens && id_lens); } else { rec_size = (sizeof(Record) + (sizeof(SQLCHAR) * desc_len + sizeof(SQLLEN) - 1)) & ~(sizeof(SQLLEN) - 1); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_ROW_BIND_TYPE, int2ptr(rec_size), 0); rec = (Record *) ODBC_GET(rec_size * ARRAY_SIZE); ids = &rec->id; id_lens = &rec->id_len; desc_lens = &rec->desc_len; descs = (SQLCHAR *) (((char *) rec) + sizeof(Record)); } #define REC(f,n) (((char*)f)+rec_size*(n)) #define DESCS(n) (rec ? (SQLCHAR*)REC(descs,n): (descs+(n)*desc_len)) #define IDS(n) *(rec ? (SQLUINTEGER*)REC(ids,n) : &ids[n]) #define ID_LENS(n) *(rec ? (SQLLEN*)REC(id_lens,n) : &id_lens[n]) #define DESC_LENS(n) *(rec ? (SQLLEN*)REC(desc_lens,n) : &desc_lens[n]) processed = ARRAY_SIZE + 1; for (i = 0; i < ARRAY_SIZE; i++) { statuses[i] = SQL_ROW_UPDATED; IDS(i) = i * 132; sprintf((char *) DESCS(i), "aaa"); ID_LENS(i) = 0; DESC_LENS(i) = -i; } SQLBindCol(odbc_stmt, 1, SQL_C_ULONG, &IDS(0), 0, &ID_LENS(0)); SQLBindCol(odbc_stmt, 2, SQL_C_CHAR, DESCS(0), desc_len, &DESC_LENS(0)); CHKExecDirect(T(test_query), SQL_NTS, "S"); CHKFetch(expected); assert(processed <= ARRAY_SIZE); for (i = 0; i < processed; ++i) { char buf[128]; sprintf(buf, "%crow number %d", 'a' + i, i * 13); if (trunc) buf[3] = 0; if (IDS(i) != i + 1 || strcmp((char *) DESCS(i), buf) != 0) { fprintf(stderr, "Invalid result\n\tgot '%d|%s'\n\texpected '%d|%s'\n", (int) IDS(i), DESCS(i), i + 1, buf); exit(1); } switch (statuses[i]) { case SQL_ROW_SUCCESS: status[i] = 'V'; break; case SQL_ROW_SUCCESS_WITH_INFO: status[i] = 'v'; break; case SQL_ROW_ERROR: status[i] = '!'; break; case SQL_ROW_NOROW: status[i] = ' '; break; default: fprintf(stderr, "Invalid status returned\n"); exit(1); } } status[i] = 0; if (expected_status && strcmp(expected_status, status) != 0) { fprintf(stderr, "Invalid status\n\tgot '%s'\n\texpected '%s'\n", status, expected_status); exit(1); } ODBC_FREE(); }
/* Detect protocol version using queries * This to make possible protocol discovery on drivers like MS */ static int odbc_tds_version_long(void) { SQLRETURN ret; SQLSMALLINT scale, nullable, type; SQLULEN prec; ODBC_BUF *odbc_buf = NULL; /* statement must be in a consistent state to do the check */ CHKExecDirect(T("select 1"), SQL_NTS, "S"); odbc_reset_statement(); /* select cast(123 as sql_variant) -> nvarchar('123') is 7.0 failure query is 5.0 ?? */ ret = CHKExecDirect(T("select cast('123' as sql_variant)"), SQL_NTS, "SNoE"); odbc_reset_statement(); if (ret == SQL_ERROR) { ODBC_FREE(); return 0x500; } /* see how bigint is returned, numeric means 7.0 */ CHKExecDirect(T("select cast('123' as bigint)"), SQL_NTS, "S"); CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S"); odbc_reset_statement(); if (type == SQL_NUMERIC || type == SQL_DECIMAL) { ODBC_FREE(); return 0x700; } if (type != SQL_BIGINT) { fprintf(stderr, "Strange type returned trying to detect protocol version\n"); odbc_disconnect(); ODBC_FREE(); exit(1); } /* select cast('123' as varchar(max)) -> ??? SQL_VARCHAR is 7.2 ?? */ ret = CHKExecDirect(T("select cast('123' as varchar(max))"), SQL_NTS, "SE"); if (ret == SQL_ERROR) { odbc_reset_statement(); ODBC_FREE(); return 0x701; } CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S"); odbc_reset_statement(); if (type == SQL_LONGVARCHAR) { ODBC_FREE(); return 0x701; } if (type != SQL_VARCHAR) { fprintf(stderr, "Strange type returned trying to detect protocol version\n"); odbc_disconnect(); ODBC_FREE(); exit(1); } /* select cast('12:13:14.1234' as time(4)) -> NVARCHAR('12:13:14.1234') is 7.2 else 7.3 */ ret = CHKExecDirect(T("select cast('12:13:14.1234' as time(4))"), SQL_NTS, "SE"); if (ret == SQL_ERROR) { odbc_reset_statement(); ODBC_FREE(); return 0x702; } CHKDescribeCol(1, NULL, 0, NULL, &type, &prec, &scale, &nullable, "S"); odbc_reset_statement(); if (scale == 4) return 0x703; if (scale != 0 || type != SQL_WVARCHAR) { fprintf(stderr, "Strange type or scale returned trying to detect protocol version\n"); odbc_disconnect(); ODBC_FREE(); exit(1); } ODBC_FREE(); return 0x702; }
static void Test0(int use_sql, const char *create_sql, const char *insert_sql, const char *select_sql) { #define ROWS 4 #define C_LEN 10 SQLUINTEGER n[ROWS]; char c[ROWS][C_LEN]; SQLLEN c_len[ROWS], n_len[ROWS]; SQLUSMALLINT statuses[ROWS]; SQLUSMALLINT i; SQLULEN num_row; SQLHSTMT stmt2; /* create test table */ odbc_command("IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test"); odbc_command(create_sql); for (i = 1; i <= 6; ++i) { char sql_buf[80], data[10]; memset(data, 'a' + (i - 1), sizeof(data)); data[i] = 0; sprintf(sql_buf, insert_sql, data, i); odbc_command(sql_buf); } /* set cursor options */ odbc_reset_statement(); CHKSetStmtAttr(SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0, "S"); CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S"); CHKSetStmtAttr(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0, "S"); CHKSetStmtAttr(SQL_ATTR_ROW_STATUS_PTR, (SQLPOINTER) statuses, 0, "S"); CHKSetStmtAttr(SQL_ATTR_ROWS_FETCHED_PTR, &num_row, 0, "S"); CHKSetCursorName(T("C1"), SQL_NTS, "S"); /* */ CHKExecDirect(T(select_sql), SQL_NTS, "S"); /* bind some rows at a time */ CHKBindCol(1, SQL_C_ULONG, n, 0, n_len, "S"); CHKBindCol(2, SQL_C_CHAR, c, C_LEN, c_len, "S"); /* allocate an additional statement */ CHKAllocStmt(&stmt2, "S"); while (CHKFetchScroll(SQL_FETCH_NEXT, 0, "SNo") == SQL_SUCCESS) { /* print, just for debug */ for (i = 0; i < num_row; ++i) printf("row %d i %d c %s\n", (int) (i + 1), (int) n[i], c[i]); printf("---\n"); /* delete a row */ i = 1; if (i > 0 && i <= num_row) { if (mssql2005) CHKSetPos(i, use_sql ? SQL_POSITION : SQL_DELETE, SQL_LOCK_NO_CHANGE, "SI"); else CHKSetPos(i, use_sql ? SQL_POSITION : SQL_DELETE, SQL_LOCK_NO_CHANGE, "S"); if (use_sql) { SWAP_STMT(stmt2); CHKPrepare(T("DELETE FROM #test WHERE CURRENT OF C1"), SQL_NTS, "S"); CHKExecute("S"); SWAP_STMT(stmt2); } } /* update another row */ i = 2; if (i > 0 && i <= num_row) { strcpy(c[i - 1], "foo"); c_len[i - 1] = 3; if (strstr(select_sql, "#a") == NULL || use_sql) { CHKSetPos(i, use_sql ? SQL_POSITION : SQL_UPDATE, SQL_LOCK_NO_CHANGE, "S"); } else { SQLTCHAR sqlstate[6]; SQLTCHAR msg[256]; n[i - 1] = 321; CHKSetPos(i, use_sql ? SQL_POSITION : SQL_UPDATE, SQL_LOCK_NO_CHANGE, "E"); CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, sqlstate, NULL, msg, ODBC_VECTOR_SIZE(msg), NULL, "S"); if (strstr(C(msg), "Invalid column name 'c'") == NULL) { fprintf(stderr, "Expected message not found at line %d\n", __LINE__); exit(1); } } if (use_sql) { SWAP_STMT(stmt2); CHKPrepare(T("UPDATE #test SET c=? WHERE CURRENT OF C1"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, C_LEN, 0, c[i - 1], 0, NULL, "S"); CHKExecute("S"); /* FIXME this is not necessary for mssql driver */ SQLMoreResults(odbc_stmt); SWAP_STMT(stmt2); } } } SWAP_STMT(stmt2); CHKFreeStmt(SQL_DROP, "S"); SWAP_STMT(stmt2); odbc_reset_statement(); /* test values */ CheckNoRow("IF (SELECT COUNT(*) FROM #test) <> 4 SELECT 1"); CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 3 AND c = 'ccc') SELECT 1"); CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 4 AND c = 'dddd') SELECT 1"); if (strstr(select_sql, "#a") == NULL || use_sql) { CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 2 AND c = 'foo') SELECT 1"); CheckNoRow("IF NOT EXISTS(SELECT * FROM #test WHERE i = 6 AND c = 'foo') SELECT 1"); } }
int main(int argc, char *argv[]) { SQLINTEGER input, output; SQLLEN ind, ind2, ind3, ind4; SQLINTEGER out1; char out2[30]; odbc_connect(); odbc_command("IF OBJECT_ID('simpleresult') IS NOT NULL DROP PROC simpleresult"); odbc_command("create proc simpleresult @i int as begin return @i end"); CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S"); CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S"); CHKPrepare(T("{ \n?\t\r= call simpleresult(?)}"), SQL_NTS, "S"); input = 123; ind2 = sizeof(input); output = 0xdeadbeef; CHKExecute("S"); if (output != 123) { printf("Invalid result\n"); exit(1); } /* should return "Invalid cursor state" */ if (SQLFetch(odbc_stmt) != SQL_ERROR) { printf("Data not expected\n"); exit(1); } ODBC_CHECK_COLS(0); /* just to reset some possible buffers */ odbc_command("DECLARE @i INT"); /* same test but with SQLExecDirect and same bindings */ input = 567; ind2 = sizeof(input); output = 0xdeadbeef; CHKExecDirect(T("{?=call simpleresult(?)}"), SQL_NTS, "S"); if (output != 567) { fprintf(stderr, "Invalid result\n"); exit(1); } /* should return "Invalid cursor state" */ CHKFetch("E"); odbc_command("drop proc simpleresult"); odbc_command("IF OBJECT_ID('simpleresult2') IS NOT NULL DROP PROC simpleresult2"); /* force cursor close */ SQLCloseCursor(odbc_stmt); /* test output parameter */ odbc_command("create proc simpleresult2 @i int, @x int output, @y varchar(20) output as begin select @x = 6789 select @y = 'test foo' return @i end"); CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S"); CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S"); CHKBindParameter(3, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &out1, 0, &ind3, "S"); CHKBindParameter(4, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 20, 0, out2, sizeof(out2), &ind4, "S"); CHKPrepare(T("{ \n?\t\r= call simpleresult2(?,?,?)}"), SQL_NTS, "S"); input = 987; ind2 = sizeof(input); out1 = 888; output = 0xdeadbeef; ind3 = SQL_DATA_AT_EXEC; ind4 = SQL_DEFAULT_PARAM; strcpy(out2, "bad!"); CHKExecute("S"); if (output != 987 || ind3 <= 0 || ind4 <= 0 || out1 != 6789 || strcmp(out2, "test foo") != 0) { printf("ouput = %d ind3 = %d ind4 = %d out1 = %d out2 = %s\n", (int) output, (int) ind3, (int) ind4, (int) out1, out2); printf("Invalid result\n"); exit(1); } /* should return "Invalid cursor state" */ CHKFetch("E"); ODBC_CHECK_COLS(0); odbc_command("drop proc simpleresult2"); /* * test from shiv kumar * Cfr ML 2006-11-21 "specifying a 0 for the StrLen_or_IndPtr in the * SQLBindParameter call is not working on AIX" */ odbc_command("IF OBJECT_ID('rpc_read') IS NOT NULL DROP PROC rpc_read"); odbc_reset_statement(); odbc_command("create proc rpc_read @i int, @x timestamp as begin select 1 return 1234 end"); SQLCloseCursor(odbc_stmt); CHKPrepare(T("{ ? = CALL rpc_read ( ?, ? ) }"), SQL_NTS, "S"); ind = 0; CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S"); ind2 = 0; CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &input, 0, &ind2, "S"); ind3 = 8; CHKBindParameter(3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, 8, 0, out2, 8, &ind3, "S"); CHKExecute("S"); CHKFetch("S"); CHKFetch("No"); odbc_reset_statement(); odbc_command("drop proc rpc_read"); /* * Test from Joao Amaral * This test SQLExecute where a store procedure returns no result * This seems similar to a previous one but use set instead of select * (with is supported only by mssql and do not return all stuff as * select does) */ if (odbc_db_is_microsoft()) { odbc_reset_statement(); odbc_command("IF OBJECT_ID('sp_test') IS NOT NULL DROP PROC sp_test"); odbc_command("create proc sp_test @res int output as set @res = 456"); odbc_reset_statement(); CHKPrepare(T("{ call sp_test(?)}"), SQL_NTS, "S"); CHKBindParameter(1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &output, 0, &ind, "S"); output = 0xdeadbeef; CHKExecute("S"); if (output != 456) { fprintf(stderr, "Invalid result %d(%x)\n", (int) output, (int) output); return 1; } odbc_command("drop proc sp_test"); } odbc_disconnect(); if (odbc_db_is_microsoft()) test_with_conversions(); printf("Done.\n"); return 0; }
int main(int argc, char *argv[]) { #define ROWS 3 #define C_LEN 10 SQLUINTEGER n[ROWS]; char c[ROWS][C_LEN]; SQLLEN c_len[ROWS], n_len[ROWS]; SQLUSMALLINT statuses[ROWS]; SQLUSMALLINT i; SQLULEN num_row; int i_test; typedef struct _test { SQLUSMALLINT type; SQLINTEGER irow; int start; int num; } TEST; static const TEST tests[] = { {SQL_FETCH_NEXT, 0, 1, 3}, {SQL_FETCH_NEXT, 0, 4, 2}, {SQL_FETCH_PRIOR, 0, 1, 3}, {SQL_FETCH_NEXT, 0, 4, 2}, {SQL_FETCH_NEXT, 0, -1, -1}, {SQL_FETCH_FIRST, 0, 1, 3}, {SQL_FETCH_ABSOLUTE, 3, 3, 3}, {SQL_FETCH_RELATIVE, 1, 4, 2}, {SQL_FETCH_LAST, 0, 3, 3} }; const int num_tests = sizeof(tests) / sizeof(TEST); odbc_use_version3 = 1; odbc_connect(); odbc_check_cursor(); /* create test table */ odbc_command("IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test"); odbc_command("CREATE TABLE #test(i int, c varchar(6))"); odbc_command("INSERT INTO #test(i, c) VALUES(1, 'a')"); odbc_command("INSERT INTO #test(i, c) VALUES(2, 'bb')"); odbc_command("INSERT INTO #test(i, c) VALUES(3, 'ccc')"); odbc_command("INSERT INTO #test(i, c) VALUES(4, 'dddd')"); odbc_command("INSERT INTO #test(i, c) VALUES(5, 'eeeee')"); /* set cursor options */ odbc_reset_statement(); CHKSetStmtAttr(SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0, "S"); CHKSetStmtAttr(SQL_ATTR_CURSOR_SCROLLABLE, (SQLPOINTER) SQL_SCROLLABLE, 0, "S"); CHKSetStmtAttr(SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_DYNAMIC, 0, "S"); CHKSetStmtAttr(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) ROWS, 0, "S"); CHKSetStmtAttr(SQL_ATTR_ROW_STATUS_PTR, (SQLPOINTER) statuses, 0, "S"); CHKSetStmtAttr(SQL_ATTR_ROWS_FETCHED_PTR, &num_row, 0, "S"); /* */ CHKExecDirect(T("SELECT i, c FROM #test"), SQL_NTS, "S"); /* bind some rows at a time */ CHKBindCol(1, SQL_C_ULONG, n, 0, n_len, "S"); CHKBindCol(2, SQL_C_CHAR, c, C_LEN, c_len, "S"); for (i_test = 0; i_test < num_tests; ++i_test) { const TEST *t = &tests[i_test]; printf("Test %d\n", i_test + 1); if (t->start == -1) { CHKFetchScroll(t->type, t->irow, "No"); } else { CHKFetchScroll(t->type, t->irow, "S"); if (t->start < 1) { fprintf(stderr, "Rows not expected\n"); exit(1); } /* print, just for debug */ for (i = 0; i < num_row; ++i) printf("row %d i %d c %s\n", (int) (i + 1), (int) n[i], c[i]); printf("---\n"); if (num_row != t->num) { fprintf(stderr, "Expected %d rows, got %d\n", t->num, (int) num_row); exit(1); } for (i = 0; i < num_row; ++i) { char name[10]; memset(name, 0, sizeof(name)); memset(name, 'a' - 1 + i + t->start, i + t->start); if (n[i] != i + t->start || c_len[i] != strlen(name) || strcmp(c[i], name) != 0) { fprintf(stderr, "Wrong row returned\n"); fprintf(stderr, "\tn %d %d\n", (int) n[i], i + t->start); fprintf(stderr, "\tc len %d %d\n", (int) c_len[i], (int) strlen(name)); fprintf(stderr, "\tc %s %s\n", c[i], name); exit(1); } } } } odbc_reset_statement(); odbc_disconnect(); return 0; }
int main(int argc, char *argv[]) { int i; SQLLEN len; #ifdef HAVE_SQLROWSETSIZE SQLROWSETSIZE row_count; #else SQLULEN row_count; #endif SQLUSMALLINT statuses[10]; char buf[32]; odbc_use_version3 = 1; odbc_connect(); /* initial value should be 1 */ CHKGetStmtAttr(SQL_ROWSET_SIZE, &len, sizeof(len), NULL, "S"); if (len != 1) { fprintf(stderr, "len should be 1\n"); odbc_disconnect(); return 1; } /* check invalid parameter values */ test_err(-123); test_err(-1); test_err(0); odbc_check_cursor(); /* set some correct values */ CHKSetStmtAttr(SQL_ROWSET_SIZE, (SQLPOINTER) int2ptr(2), 0, "S"); CHKSetStmtAttr(SQL_ROWSET_SIZE, (SQLPOINTER) int2ptr(1), 0, "S"); /* now check that SQLExtendedFetch works as expected */ odbc_command("CREATE TABLE #rowset(n INTEGER, c VARCHAR(20))"); for (i = 0; i < 10; ++i) { char s[10]; char sql[128]; memset(s, 'a' + i, 9); s[9] = 0; sprintf(sql, "INSERT INTO #rowset(n,c) VALUES(%d,'%s')", i+1, s); odbc_command(sql); } odbc_reset_statement(); CHKSetStmtOption(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_DYNAMIC, "S"); CHKExecDirect((SQLCHAR *) "SELECT * FROM #rowset ORDER BY n", SQL_NTS, "SI"); CHKBindCol(2, SQL_C_CHAR, buf, sizeof(buf), &len, "S"); row_count = 0xdeadbeef; memset(statuses, 0x55, sizeof(statuses)); CHKExtendedFetch(SQL_FETCH_NEXT, 1, &row_count, statuses, "S"); if (row_count != 1 || statuses[0] != SQL_ROW_SUCCESS || strcmp(buf, "aaaaaaaaa") != 0) { fprintf(stderr, "Invalid result\n"); odbc_disconnect(); return 1; } odbc_disconnect(); printf("Done.\n"); return 0; }
static void DoTest(int prepare) { int n = 0; static const char query[] = /* on prepared this recordset should be skipped */ "DECLARE @b INT SELECT @b = 25 " "SELECT * FROM #tmp1 WHERE i <= 3 " /* on prepare we cannot distinguish these recordset */ "INSERT INTO #tmp2 SELECT * FROM #tmp1 WHERE i = 1 " "INSERT INTO #tmp2 SELECT * FROM #tmp1 WHERE i <= 3 " "SELECT * FROM #tmp1 WHERE i = 1 " /* but FreeTDS can detect last recordset */ "UPDATE #tmp1 SET i=i+1 WHERE i >= 2"; if (prepare) { CHKPrepare(T(query), SQL_NTS, "S"); CHKExecute("S"); } else { /* execute a batch command select insert insert select and check rows */ CHKExecDirect(T(query), SQL_NTS, "S"); } if (!prepare) { printf("Result %d\n", ++n); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(1); CHKMoreResults("S"); } printf("Result %d\n", ++n); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("S"); CHKFetch("S"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("No"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(2); CHKMoreResults("S"); if (!prepare) { printf("Result %d\n", ++n); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(1); CHKMoreResults("S"); printf("Result %d\n", ++n); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(2); CHKMoreResults("S"); } printf("Result %d\n", ++n); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("S"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("No"); ODBC_CHECK_COLS(1); if (prepare) { /* collapse 2 recordset... after a lot of testing this is the behavior! */ if (odbc_driver_is_freetds()) ODBC_CHECK_ROWS(2); } else { ODBC_CHECK_ROWS(1); CHKMoreResults("S"); ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(2); } CHKMoreResults("No"); #ifndef TDS_NO_DM if (!prepare) ODBC_CHECK_COLS(-1); ODBC_CHECK_ROWS(-2); #endif ODBC_FREE(); }