static void test_with_conversions(void) { SQLLEN ind, ind2, ind3; char out2[30]; /* * test from Bower, Wayne * Cfr ML 2012-03-02 "[freetds] [unixODBC][Driver Manager]Function sequence error (SQL-HY010)" */ odbc_use_version3 = 1; odbc_connect(); odbc_command("IF OBJECT_ID('TMP_SP_Test_ODBC') IS NOT NULL DROP PROC TMP_SP_Test_ODBC"); odbc_command("create proc TMP_SP_Test_ODBC @i int,\n@o int output\nas\nset nocount on\nselect @o = 55\nreturn 9\n"); odbc_reset_statement(); CHKPrepare(T("{ ? = call TMP_SP_Test_ODBC (?, ?) }"), SQL_NTS, "S"); ind2 = 2; CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 80, 0, "10", 2, &ind2, "S"); ind3 = SQL_NULL_DATA; strcpy(out2, " "); CHKBindParameter(3, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind3, "S"); ind = 1; CHKBindParameter(1, SQL_PARAM_INPUT_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 1, out2, 29, &ind, "S"); /* mssql returns SUCCESS */ CHKExecute("No"); ODBC_CHECK_COLS(0); odbc_reset_statement(); odbc_command("drop proc TMP_SP_Test_ODBC"); odbc_disconnect(); }
static int test(int odbc3) { SQLLEN cnamesize; const char *query; odbc_use_version3 = odbc3; odbc_connect(); /* issue print statement and test message returned */ output[0] = 0; query = "print 'START' select count(*) from sysobjects where name='sysobjects' print 'END'"; odbc_command2(query, "I"); odbc_read_error(); if (!strstr(odbc_err, "START")) { printf("Message invalid\n"); return 1; } odbc_err[0] = 0; if (odbc3) { ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(-1); CHKFetch("E"); CHKMoreResults("S"); } ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); CHKFetch("S"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(-1); /* check no data */ CHKFetch("No"); ODBC_CHECK_COLS(1); ODBC_CHECK_ROWS(1); /* SQLMoreResults return NO DATA or SUCCESS WITH INFO ... */ if (tds_no_dm && !odbc3) CHKMoreResults("No"); else if (odbc3) CHKMoreResults("I"); else CHKMoreResults("INo"); /* * ... but read error * (unixODBC till 2.2.11 do not read errors on NO DATA, skip test) */ if (tds_no_dm || odbc3) { odbc_read_error(); if (!strstr(odbc_err, "END")) { printf("Message invalid\n"); return 1; } odbc_err[0] = 0; } if (odbc3) { ODBC_CHECK_COLS(0); ODBC_CHECK_ROWS(-1); CHKMoreResults("No"); } /* issue invalid command and test error */ odbc_command2("SELECT donotexistsfield FROM donotexiststable", "E"); odbc_read_error(); /* test no data returned */ CHKFetch("E"); odbc_read_error(); CHKGetData(1, SQL_C_CHAR, output, sizeof(output), &cnamesize, "E"); odbc_read_error(); odbc_disconnect(); 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(); }
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; }