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; }
static void Test(int use_sql) { odbc_command_with_result(odbc_stmt, "DROP TABLE #a"); odbc_command("CREATE TABLE #a(x int)"); odbc_command("INSERT INTO #a VALUES(123)"); Test0(use_sql, "CREATE TABLE #test(i int, c varchar(6))", "INSERT INTO #test(c, i) VALUES('%s', %d)", "SELECT x AS i, c FROM #test, #a"); Test0(use_sql, "CREATE TABLE #test(i int, c varchar(6))", "INSERT INTO #test(c, i) VALUES('%s', %d)", "SELECT i, c FROM #test"); if (odbc_db_is_microsoft()) { Test0(use_sql, "CREATE TABLE #test(i int identity(1,1), c varchar(6))", "INSERT INTO #test(c) VALUES('%s')", "SELECT i, c FROM #test"); Test0(use_sql, "CREATE TABLE #test(i int primary key, c varchar(6))", "INSERT INTO #test(c, i) VALUES('%s', %d)", "SELECT i, c FROM #test"); } Test0(use_sql, "CREATE TABLE #test(i int, c varchar(6))", "INSERT INTO #test(c, i) VALUES('%s', %d)", "SELECT i, c, c + 'xxx' FROM #test"); }
int main(int argc, char **argv) { odbc_connect(); odbc_command_with_result(odbc_stmt, "DROP TABLE test"); odbc_command("CREATE TABLE test(i int, c varchar(40))"); insert_test_man(); odbc_command("DELETE FROM test"); insert_test_auto(); odbc_command("DROP TABLE test"); odbc_disconnect(); return 0; }
int main(int argc, char *argv[]) { char output[256]; SQLLEN dataSize; odbc_connect(); odbc_command_with_result(odbc_stmt, "drop proc sp_norowset_test"); odbc_command("create proc sp_norowset_test as begin declare @i int end"); odbc_command("exec sp_norowset_test"); /* note, mssql 2005 seems to not return row for tempdb, use always master */ odbc_command("select name from master..sysobjects where name = 'sysobjects'"); CHKFetch("S"); CHKGetData(1, SQL_C_CHAR, output, sizeof(output), &dataSize, "S"); if (strcmp(output, "sysobjects") != 0) { printf("Unexpected result\n"); exit(1); } CHKFetch("No"); CHKMoreResults("No"); odbc_command("drop proc sp_norowset_test"); odbc_disconnect(); printf("Done.\n"); return 0; }
int main(int argc, char *argv[]) { #define TEST_FILE "describecol.in" const char *in_file = FREETDS_SRCDIR "/" TEST_FILE; FILE *f; char buf[256]; SQLINTEGER i; SQLLEN len; check_attr_t check_attr_p = check_attr_none; odbc_connect(); odbc_command("SET TEXTSIZE 4096"); SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len); f = fopen(in_file, "r"); if (!f) fopen(TEST_FILE, "r"); if (!f) { fprintf(stderr, "error opening test file\n"); exit(1); } line_num = 0; while (fgets(buf, sizeof(buf), f)) { char *p = buf, *cmd; ++line_num; while (isspace((unsigned char) *p)) ++p; cmd = strtok(p, SEP); /* skip comments */ if (!cmd || cmd[0] == '#' || cmd[0] == 0 || cmd[0] == '\n') continue; if (strcmp(cmd, "odbc") == 0) { int odbc3 = get_int(strtok(NULL, SEP)) == 3 ? 1 : 0; if (odbc_use_version3 != odbc3) { odbc_use_version3 = odbc3; odbc_disconnect(); odbc_connect(); odbc_command("SET TEXTSIZE 4096"); SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len); } } /* select type */ if (strcmp(cmd, "select") == 0) { const char *type = strtok(NULL, SEP); const char *value = strtok(NULL, SEP); char sql[sizeof(buf) + 40]; SQLMoreResults(odbc_stmt); odbc_reset_statement(); sprintf(sql, "SELECT CONVERT(%s, %s) AS col", type, value); /* ignore error, we only need precision of known types */ check_attr_p = check_attr_none; if (odbc_command_with_result(odbc_stmt, sql) != SQL_SUCCESS) { odbc_reset_statement(); SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len); continue; } CHKFetch("SI"); SQLBindCol(odbc_stmt, 1, SQL_C_SLONG, &i, sizeof(i), &len); check_attr_p = check_attr_ird; } /* set attribute */ if (strcmp(cmd, "set") == 0) { const struct attribute *attr = lookup_attr(strtok(NULL, SEP)); char *value = strtok(NULL, SEP); SQLHDESC desc; SQLRETURN ret; SQLINTEGER ind; if (!value) fatal("Line %u: value not defined\n", line_num); /* get ARD */ SQLGetStmtAttr(odbc_stmt, SQL_ATTR_APP_ROW_DESC, &desc, sizeof(desc), &ind); ret = SQL_ERROR; switch (attr->type) { case type_INTEGER: ret = SQLSetDescField(desc, 1, attr->value, int2ptr(lookup(value, attr->lookup)), sizeof(SQLINTEGER)); break; case type_SMALLINT: ret = SQLSetDescField(desc, 1, attr->value, int2ptr(lookup(value, attr->lookup)), sizeof(SQLSMALLINT)); break; case type_LEN: ret = SQLSetDescField(desc, 1, attr->value, int2ptr(lookup(value, attr->lookup)), sizeof(SQLLEN)); break; case type_CHARP: ret = SQLSetDescField(desc, 1, attr->value, (SQLPOINTER) value, SQL_NTS); break; } if (!SQL_SUCCEEDED(ret)) fatal("Line %u: failure not expected setting ARD attribute\n", line_num); check_attr_p = check_attr_ard; } /* test attribute */ if (strcmp(cmd, "attr") == 0) { const struct attribute *attr = lookup_attr(strtok(NULL, SEP)); char *expected = strtok(NULL, SEP); if (!expected) fatal("Line %u: value not defined\n", line_num); check_attr_p(attr, expected); } } fclose(f); odbc_disconnect(); printf("Done.\n"); return g_result; }
static void Test(int level) { SQLRETURN result; SQLSMALLINT InParam = level; SQLSMALLINT OutParam = 1; SQLLEN cbReturnCode = 0, cbInParam = 0, cbOutParam = 0; SQLLEN cbOutString = SQL_NTS; char sql[80]; printf("ODBC %d nocount %s select %s level %d\n", odbc_use_version3 ? 3 : 2, g_nocount ? "yes" : "no", g_second_select ? "yes" : "no", level); ReturnCode = INVALID_RETURN; memset(&OutString, 0, sizeof(OutString)); /* test with SQLExecDirect */ sprintf(sql, "RAISERROR('An error occurred.', %d, 1)", level); result = odbc_command_with_result(odbc_stmt, sql); TestResult(result, level, "SQLExecDirect"); /* test with SQLPrepare/SQLExecute */ if (!SQL_SUCCEEDED(SQLPrepare(odbc_stmt, T(SP_TEXT), strlen(SP_TEXT)))) { fprintf(stderr, "SQLPrepare failure!\n"); exit(1); } SQLBindParameter(odbc_stmt, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &ReturnCode, 0, &cbReturnCode); SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &InParam, 0, &cbInParam); SQLBindParameter(odbc_stmt, 3, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &OutParam, 0, &cbOutParam); strcpy(OutString, "Invalid!"); SQLBindParameter(odbc_stmt, 4, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, OUTSTRING_LEN, 0, OutString, OUTSTRING_LEN, &cbOutString); CHKExecute("S"); /* first select, check data are returned. * SET statements before does not affect results */ CheckData(""); CHKFetch("S"); CheckData("Here is the first row"); result = SQLFetch(odbc_stmt); if (odbc_use_version3) { SQLTCHAR SqlState[6]; SQLINTEGER NativeError; SQLTCHAR MessageText[1000]; SQLSMALLINT TextLength; SQLRETURN expected; SQLLEN rows; if (result != SQL_NO_DATA) ODBC_REPORT_ERROR("SQLFetch should return NO DATA"); CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, 1, SqlState, &NativeError, MessageText, ODBC_VECTOR_SIZE(MessageText), &TextLength, "No"); result = SQLMoreResults(odbc_stmt); expected = level > 10 ? SQL_ERROR : SQL_SUCCESS_WITH_INFO; if (result != expected) ODBC_REPORT_ERROR("SQLMoreResults returned unexpected result"); if (!g_second_select && g_nocount) { if (ReturnCode == INVALID_RETURN) { result = SQLMoreResults(odbc_stmt); } else { CheckReturnCode(result, 0); ReturnCode = INVALID_RETURN; TestResult(result, level, "SQLMoreResults"); ReturnCode = 0; } } else { TestResult(result, level, "SQLMoreResults"); } /* a recordset with only warnings/errors do not contains rows */ if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1) ODBC_REPORT_ERROR("SQLRowCount returned some rows"); } else { /* in ODBC 2 errors/warnings are not handled as different recordset */ TestResult(result, level, "SQLFetch"); } if (odbc_driver_is_freetds()) CheckData(""); if (!g_second_select) { SQLLEN rows; if (CHKRowCount(&rows, "SE") == SQL_SUCCESS && rows != -1) ODBC_REPORT_ERROR("SQLRowCount returned some rows"); CheckReturnCode(result, g_nocount ? 0 : INVALID_RETURN); result = SQLMoreResults(odbc_stmt); #ifdef ENABLE_DEVELOPING if (result != SQL_NO_DATA) ODBC_REPORT_ERROR("SQLMoreResults should return NO DATA"); ODBC_CHECK_ROWS(-2); #endif CheckReturnCode(result, 0); return; } if (!odbc_use_version3 || !g_nocount) { /* mssql 2008 return SUCCESS_WITH_INFO with previous error */ CHKMoreResults("S"); result = SQL_SUCCESS; } CheckReturnCode(result, INVALID_RETURN); CheckData(""); if (g_nocount && odbc_use_version3 && g_second_select && level >= 10) { if (CHKFetch("SE") == SQL_ERROR) { SQLMoreResults(odbc_stmt); CHKFetch("S"); } } else { CHKFetch("S"); } CheckData("Here is the last row"); CHKFetch("No"); CheckData(""); if (!odbc_use_version3 || g_nocount) CheckReturnCode(result, 0); #ifdef ENABLE_DEVELOPING else CheckReturnCode(result, INVALID_RETURN); #endif /* FIXME how to handle return in store procedure ?? */ result = SQLMoreResults(odbc_stmt); #ifdef ENABLE_DEVELOPING if (result != SQL_NO_DATA) ODBC_REPORT_ERROR("SQLMoreResults return other data"); #endif CheckReturnCode(result, 0); CheckData(""); ODBC_FREE(); }
static void DoTest(int version3) { char name[128], params[128]; SQLSMALLINT type, is_unsigned; SQLINTEGER col_size, min_scale; SQLLEN ind1, ind2, ind3, ind4, ind5, ind6; int date_time_supported = 0; int name_version3; odbc_use_version3 = version3; name_version3 = version3; odbc_connect(); printf("Using ODBC version %d\n", version3 ? 3 : 2); /* test column name */ /* MS ODBC use always ODBC 3 names even in ODBC 2 mode */ if (!odbc_driver_is_freetds()) name_version3 = 1; CHKGetTypeInfo(SQL_ALL_TYPES, "SI"); TestName(1, "TYPE_NAME"); TestName(2, "DATA_TYPE"); TestName(3, name_version3 ? "COLUMN_SIZE" : "PRECISION"); TestName(4, "LITERAL_PREFIX"); TestName(5, "LITERAL_SUFFIX"); TestName(6, "CREATE_PARAMS"); TestName(7, "NULLABLE"); TestName(8, "CASE_SENSITIVE"); TestName(9, "SEARCHABLE"); TestName(10, "UNSIGNED_ATTRIBUTE"); TestName(11, name_version3 ? "FIXED_PREC_SCALE" : "MONEY"); TestName(12, name_version3 ? "AUTO_UNIQUE_VALUE" : "AUTO_INCREMENT"); TestName(13, "LOCAL_TYPE_NAME"); TestName(14, "MINIMUM_SCALE"); TestName(15, "MAXIMUM_SCALE"); /* TODO test these column for ODBC 3 */ /* ODBC 3.0 SQL_DATA_TYPE SQL_DATETIME_SUB NUM_PREC_RADIX INTERVAL_PRECISION */ Flushodbc_stmt(); /* TODO test if SQL_ALL_TYPES returns right numeric type for timestamp */ /* numeric type for data */ /* test for date/time support */ if (odbc_command_with_result(odbc_stmt, "select cast(getdate() as date)") == SQL_SUCCESS) date_time_supported = 1; SQLCloseCursor(odbc_stmt); #define CHECK_TYPE(in,out) CheckType(in, out, #in, __LINE__) /* under Sybase this type require extra handling, check it */ CHECK_TYPE(SQL_VARCHAR, SQL_VARCHAR); CHECK_TYPE(SQL_DATE, date_time_supported && !version3 ? SQL_DATE : SQL_UNKNOWN_TYPE); CHECK_TYPE(SQL_TIME, date_time_supported && !version3 ? SQL_TIME : SQL_UNKNOWN_TYPE); /* MS ODBC returns S1004 (HY004), TODO support it */ if (odbc_driver_is_freetds() || version3) { CHECK_TYPE(SQL_TYPE_DATE, date_time_supported && version3 ? SQL_TYPE_DATE : SQL_UNKNOWN_TYPE); CHECK_TYPE(SQL_TYPE_TIME, date_time_supported && version3 ? SQL_TYPE_TIME : SQL_UNKNOWN_TYPE); } /* TODO MS ODBC handle SQL_TIMESTAMP even for ODBC 3 */ if (odbc_driver_is_freetds()) CHECK_TYPE(SQL_TIMESTAMP, version3 ? SQL_UNKNOWN_TYPE : SQL_TIMESTAMP); else CHECK_TYPE(SQL_TIMESTAMP, version3 ? SQL_TYPE_TIMESTAMP : SQL_TIMESTAMP); /* MS ODBC returns S1004 (HY004), TODO support it */ if (odbc_driver_is_freetds() || version3) { CHECK_TYPE(SQL_TYPE_TIMESTAMP, version3 ? SQL_TYPE_TIMESTAMP : SQL_UNKNOWN_TYPE); } /* TODO implement this part of test */ /* varchar/nvarchar before sysname */ /* test binding (not all column, required for Oracle) */ CHKGetTypeInfo(SQL_ALL_TYPES, "SI"); CHKBindCol(1, SQL_C_CHAR, name, sizeof(name), &ind1, "SI"); CHKBindCol(2, SQL_C_SSHORT, &type, 0, &ind2, "SI"); CHKBindCol(3, SQL_C_SLONG, &col_size, 0, &ind3, "SI"); CHKBindCol(6, SQL_C_CHAR, params, sizeof(params), &ind4, "SI"); CHKBindCol(10, SQL_C_SSHORT, &is_unsigned, 0, &ind5, "SI"); CHKBindCol(14, SQL_C_SSHORT, &min_scale, 0, &ind6, "SI"); while (CHKFetch("SNo") == SQL_SUCCESS) ; SQLFreeStmt(odbc_stmt, SQL_UNBIND); Flushodbc_stmt(); /* check WVARCHAR for no pending data */ if (odbc_db_is_microsoft() || strncmp(odbc_db_version(), "15.00.", 6) >= 0) { CHKGetTypeInfo(SQL_WVARCHAR, "SI"); CHKFetch("S"); if (odbc_db_is_microsoft()) CHKFetch("S"); CHKFetch("No"); CHKGetTypeInfo(SQL_BINARY, "SI"); } odbc_disconnect(); }
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 void query_test(int prepare, SQLRETURN expected, const char *expected_status) { #define DESC_LEN 51 #define ARRAY_SIZE 10 SQLUINTEGER *ids = XMALLOC_N(SQLUINTEGER,ARRAY_SIZE); typedef SQLCHAR desc_t[DESC_LEN]; desc_t *descs = XMALLOC_N(desc_t, ARRAY_SIZE); SQLLEN *id_lens = XMALLOC_N(SQLLEN,ARRAY_SIZE), *desc_lens = XMALLOC_N(SQLLEN,ARRAY_SIZE); SQLUSMALLINT i, *statuses = XMALLOC_N(SQLUSMALLINT,ARRAY_SIZE); unsigned *num_errors = XMALLOC_N(unsigned, ARRAY_SIZE); SQLULEN processed; RETCODE ret; char status[20]; SQLTCHAR *err = ODBC_GET(sizeof(odbc_err)*sizeof(SQLTCHAR)); SQLTCHAR *state = ODBC_GET(sizeof(odbc_sqlstate)*sizeof(SQLTCHAR)); assert(odbc_stmt != SQL_NULL_HSTMT); odbc_reset_statement(); odbc_command_with_result(odbc_stmt, "drop table #tmp1"); odbc_command("create table #tmp1 (id tinyint, value char(20))"); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAMSET_SIZE, (void *) ARRAY_SIZE, 0); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAM_STATUS_PTR, statuses, 0); SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &processed, 0); SQLBindParameter(odbc_stmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0, ids, 0, id_lens); SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, DESC_LEN - 1, 0, descs, DESC_LEN, desc_lens); processed = ARRAY_SIZE + 1; for (i = 0; i < ARRAY_SIZE; i++) { statuses[i] = SQL_PARAM_DIAG_UNAVAILABLE; ids[i] = (i + 1) * multiply; sprintf((char *) descs[i], "data %d", i * 7); id_lens[i] = 0; desc_lens[i] = SQL_NTS; num_errors[i] = 0; } multiply = 90; if (!prepare) { ret = SQLExecDirect(odbc_stmt, test_query, SQL_NTS); } else { SQLPrepare(odbc_stmt, test_query, SQL_NTS); ret = SQLExecute(odbc_stmt); } if (processed > ARRAY_SIZE) { char buf[256]; sprintf(buf, "Invalid processed number: %d", (int) processed); ODBC_REPORT_ERROR(buf); } for (i = 1; CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, i, state, NULL, err, sizeof(odbc_err), NULL, "SINo") != SQL_NO_DATA; ++i) { SQLINTEGER row; strcpy(odbc_err, C(err)); strcpy(odbc_sqlstate, C(state)); CHKGetDiagField(SQL_HANDLE_STMT, odbc_stmt, i, SQL_DIAG_ROW_NUMBER, &row, sizeof(row), NULL, "S"); if (row == SQL_ROW_NUMBER_UNKNOWN) continue; if (row < 1 || row > ARRAY_SIZE) { fprintf(stderr, "invalid row %d returned reading error number %d\n", (int) row, i); exit(1); } ++num_errors[row-1]; printf("for row %2d returned '%s' %s\n", (int) row, odbc_sqlstate, odbc_err); } for (i = 0; i < processed; ++i) { int has_diag = 0; switch (statuses[i]) { case SQL_PARAM_SUCCESS_WITH_INFO: has_diag = 1; case SQL_PARAM_SUCCESS: status[i] = 'V'; break; case SQL_PARAM_ERROR: has_diag = 1; status[i] = '!'; break; case SQL_PARAM_UNUSED: status[i] = ' '; break; case SQL_PARAM_DIAG_UNAVAILABLE: status[i] = '?'; break; default: fprintf(stderr, "Invalid status returned %d\n", statuses[i]); exit(1); } if (has_diag) { if (!num_errors[i]) { fprintf(stderr, "Diagnostics not returned for status %d\n", i); failure = 1; } } else { if (num_errors[i]) { fprintf(stderr, "Diagnostics returned for status %d\n", i); failure = 1; } } } status[i] = 0; if (ret != expected || strcmp(expected_status, status) != 0) { fprintf(stderr, "Invalid result: got %d \"%s\" expected %d \"%s\" processed %d\n", ret, status, expected, expected_status, (int) processed); if (ret != SQL_SUCCESS) odbc_read_error(); failure = 1; odbc_reset_statement(); return; } odbc_reset_statement(); }