int main(int argc, char *argv[]) { int result; int retcode = 0; Connect(); /* create table */ CommandWithResult(Statement, "DROP TABLE TestTransaction"); result = CommandWithResult(Statement, "CREATE TABLE TestTransaction ( value INT )"); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't create table TestTransaction"); retcode = 1; goto cleanup; } if (!retcode) retcode = Test(1); if (!retcode) retcode = Test(0); cleanup: /* drop table */ CommandWithResult(Statement, "DROP TABLE TestTransaction"); Disconnect(); printf("Done.\n"); return retcode; }
static void AutoCommit(int onoff) { SQLRETURN ret; ret = SQLSetConnectAttr(Connection, SQL_ATTR_AUTOCOMMIT, int2ptr(onoff), 0); if (ret != SQL_SUCCESS) ODBC_REPORT_ERROR("Enabling AutoCommit"); }
static void EndTransaction(SQLSMALLINT type) { SQLRETURN ret; ret = SQLEndTran(SQL_HANDLE_DBC, Connection, type); if (ret != SQL_SUCCESS) ODBC_REPORT_ERROR("Can't commit transaction"); }
int main(int argc, char *argv[]) { 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; odbc_connect(); /* create table to hold data */ 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 */ CHKPrepare(T("INSERT INTO #putdata(c) VALUES(?)"), SQL_NTS, "S"); CHKExecute("Ne"); p = test_text; n = 5; CHKParamData(&ptr, "Ne"); if (ptr != (SQLPOINTER) 123) 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 (;;) { 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); RetCode = CHKExecute("Ne"); 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 (;;) { 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; RetCode = CHKExecute("Ne"); 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 */ odbc_disconnect(); printf("Done.\n"); return 0; }
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(); }
int main(int argc, char *argv[]) { HENV env; HDBC dbc; HSTMT stmt; SQLRETURN ret; SQLINTEGER i; Connect(); /* here we can't use temporary table cause we use two connection */ CommandWithResult(Statement, "drop table test_timeout"); Command(Statement, "create table test_timeout(n numeric(18,0) primary key, t varchar(30))"); AutoCommit(SQL_AUTOCOMMIT_OFF); Command(Statement, "insert into test_timeout(n, t) values(1, 'initial')"); EndTransaction(SQL_COMMIT); Command(Statement, "update test_timeout set t = 'second' where n = 1"); /* save this connection and do another */ env = Environment; dbc = Connection; stmt = Statement; Environment = SQL_NULL_HENV; Connection = SQL_NULL_HDBC; Statement = SQL_NULL_HSTMT; Connect(); AutoCommit(SQL_AUTOCOMMIT_OFF); ret = SQLSetStmtAttr(Statement, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER) 2, 0); if (ret != SQL_SUCCESS) ODBC_REPORT_ERROR("Error setting timeout"); i = 1; ret = SQLBindParameter(Statement, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &i, 0, NULL); if (ret != SQL_SUCCESS) ODBC_REPORT_ERROR("SQLBindParameter failure"); if (SQLPrepare(Statement, (SQLCHAR *) "update test_timeout set t = 'bad' where n = ?", SQL_NTS) != SQL_SUCCESS) ODBC_REPORT_ERROR("SQLPrepare failure"); ret = SQLExecute(Statement); if (ret != SQL_ERROR) ODBC_REPORT_ERROR("SQLExecute success ??"); EndTransaction(SQL_ROLLBACK); /* TODO should return error S1T00 Timeout expired, test error message */ ret = CommandWithResult(Statement, "update test_timeout set t = 'bad' where n = 1"); if (ret != SQL_ERROR) ODBC_REPORT_ERROR("SQLExecDirect success ??"); EndTransaction(SQL_ROLLBACK); Disconnect(); Environment = env; Connection = dbc; Statement = stmt; EndTransaction(SQL_COMMIT); /* Sybase do not accept DROP TABLE during a transaction */ AutoCommit(SQL_AUTOCOMMIT_ON); Command(Statement, "drop table test_timeout"); Disconnect(); return 0; }
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(); }
int main(int argc, char *argv[]) { char tmp[2048]; SQLSMALLINT len; int succeeded = 0; int is_freetds = 1; SQLRETURN rc; if (odbc_read_login_info()) exit(1); /* * prepare our odbcinst.ini * is better to do it before connect cause uniODBC cache INIs * the name must be odbcinst.ini cause unixODBC accept only this name */ if (odbc_driver[0]) { FILE *f = fopen("odbcinst.ini", "w"); if (f) { fprintf(f, "[FreeTDS]\nDriver = %s\n", odbc_driver); fclose(f); /* force iODBC */ setenv("ODBCINSTINI", "./odbcinst.ini", 1); setenv("SYSODBCINSTINI", "./odbcinst.ini", 1); /* force unixODBC (only directory) */ setenv("ODBCSYSINI", ".", 1); } } printf("SQLConnect connect..\n"); odbc_connect(); if (!odbc_driver_is_freetds()) is_freetds = 0; odbc_disconnect(); ++succeeded; if (!is_freetds) { printf("Driver is not FreeTDS, exiting\n"); return 0; } /* try connect string with using DSN */ printf("connect string DSN connect..\n"); init_connect(); sprintf(tmp, "DSN=%s;UID=%s;PWD=%s;DATABASE=%s;", odbc_server, odbc_user, odbc_password, odbc_database); CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SI"); odbc_disconnect(); ++succeeded; /* try connect string using old SERVERNAME specification */ printf("connect string SERVERNAME connect..\n"); printf("odbcinst.ini must be configured with FreeTDS driver..\n"); /* this is expected to work with unixODBC */ init_connect(); sprintf(tmp, "DRIVER=FreeTDS;SERVERNAME=%s;UID=%s;PWD=%s;DATABASE=%s;", odbc_server, odbc_user, odbc_password, odbc_database); rc = CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SIE"); if (rc == SQL_ERROR) { printf("Unable to open data source (ret=%d)\n", rc); } else { ++succeeded; } odbc_disconnect(); /* this is expected to work with iODBC */ init_connect(); sprintf(tmp, "DRIVER=%s;SERVERNAME=%s;UID=%s;PWD=%s;DATABASE=%s;", odbc_driver, odbc_server, odbc_user, odbc_password, odbc_database); rc = CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SIE"); if (rc == SQL_ERROR) { printf("Unable to open data source (ret=%d)\n", rc); } else { ++succeeded; } odbc_disconnect(); #ifdef _WIN32 if (get_entry("SERVER")) { init_connect(); sprintf(tmp, "DRIVER=FreeTDS;SERVER=%s;UID=%s;PWD=%s;DATABASE=%s;", entry, odbc_user, odbc_password, odbc_database); if (get_entry("TDS_Version")) sprintf(strchr(tmp, 0), "TDS_Version=%s;", entry); rc = CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SIE"); if (rc == SQL_ERROR) { printf("Unable to open data source (ret=%d)\n", rc); } else { ++succeeded; } odbc_disconnect(); } #endif /* at least one should success.. */ if (succeeded < 3) { ODBC_REPORT_ERROR("Too few successes"); exit(1); } printf("Done.\n"); return 0; }
static int Test(int discard_test) { SQLINTEGER out_buf; SQLLEN out_len; int result = 0; SQLLEN rows; int retcode = 0; char buf[512]; unsigned char sqlstate[6]; const char *createErrorProcedure = "CREATE PROCEDURE testerror AS\n" "SELECT value FROM TestTransaction\n" "SELECT value / (value-value) FROM TestTransaction\n"; /* select after insert is required to test data discarding */ char createProcedure[512]; sprintf(createProcedure, "CREATE PROCEDURE testinsert @value INT AS\n" "INSERT INTO TestTransaction VALUES ( @value )\n%s", discard_test ? "SELECT * FROM TestTransaction\n" : ""); /* create stored proc */ CommandWithResult(Statement, "DROP PROCEDURE testinsert"); result = CommandWithResult(Statement, createProcedure); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't create proc testinsert"); retcode = 1; goto cleanup; } /* create stored proc that generates an error */ CommandWithResult(Statement, "DROP PROCEDURE testerror"); result = CommandWithResult(Statement, createErrorProcedure); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't create proc testerror"); retcode = 1; goto cleanup; } /* Start transaction */ result = SQLSetConnectAttr(Connection, SQL_ATTR_AUTOCOMMIT, (void *) SQL_AUTOCOMMIT_OFF, 0); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't start transaction"); retcode = 1; goto cleanup; } /* Insert a value */ Command(Statement, "EXEC testinsert 1"); /* we should be able to read row count */ if (SQLRowCount(Statement, &rows) != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't get row counts"); retcode = 1; goto cleanup; } /* Commit transaction */ result = SQLEndTran(SQL_HANDLE_DBC, Connection, SQL_COMMIT); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't commit transaction"); retcode = 1; goto cleanup; } SQLCloseCursor(Statement); /* Start transaction */ result = SQLSetConnectAttr(Connection, SQL_ATTR_AUTOCOMMIT, (void *) SQL_AUTOCOMMIT_OFF, 0); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't start transaction"); retcode = 1; goto cleanup; } /* Insert another value */ Command(Statement, "EXEC testinsert 2"); /* Roll back transaction */ result = SQLEndTran(SQL_HANDLE_DBC, Connection, SQL_ROLLBACK); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't roll back transaction"); retcode = 1; goto cleanup; } /* TODO test row inserted */ result = SQLSetConnectAttr(Connection, SQL_ATTR_AUTOCOMMIT, (void *) SQL_AUTOCOMMIT_ON, 0); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("Can't stop transaction"); retcode = 1; goto cleanup; } /* generate an error */ result = CommandWithResult(Statement, "EXEC testerror"); if (result != SQL_SUCCESS) { ODBC_REPORT_ERROR("error: SQLExecDirect: testerror"); retcode = 1; goto cleanup; } if (SQLBindCol(Statement, 1, SQL_C_SLONG, &out_buf, sizeof(out_buf), &out_len) != SQL_SUCCESS) { ODBC_REPORT_ERROR("error: SQLBindCol: testerror"); retcode = 1; goto cleanup; } while ((result = SQLFetch(Statement)) == SQL_SUCCESS) { printf("\t%ld\n", (long int) out_buf); if (out_buf != 1) { printf("error: expected to select 1 got %ld\n", (long int) out_buf); retcode = 1; goto cleanup; } } if (result != SQL_NO_DATA) { ODBC_REPORT_ERROR("error: SQLFetch: testerror"); goto cleanup; } result = SQLMoreResults(Statement); printf("SQLMoreResults returned %d\n", result); if (result != SQL_ERROR) { printf("SQLMoreResults should return error\n"); retcode = 1; goto cleanup; } result = SQLGetDiagRec(SQL_HANDLE_STMT, Statement, 1, sqlstate, NULL, (SQLCHAR *)buf, sizeof(buf), NULL); if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { fprintf(stderr, "Error not set (line %d)\n", __LINE__); retcode = 1; goto cleanup; } printf("err=%s\n", buf); result = SQLMoreResults(Statement); printf("SQLMoreResults returned %d\n", result); if (result != SQL_NO_DATA) { printf("SQLMoreResults should return error"); retcode = 1; goto cleanup; } cleanup: /* drop table */ CommandWithResult(Statement, "DROP PROCEDURE testinsert"); CommandWithResult(Statement, "DROP PROCEDURE testerror"); return retcode; }
static void DoTest(int n) { int res; SQLCHAR output[256]; SQLSMALLINT colType; SQLULEN colSize; SQLSMALLINT colScale, colNullable; SQLLEN dataSize; TIMESTAMP_STRUCT ts; if (CommandWithResult(Statement, "select convert(datetime, '2002-12-27 18:43:21')") != SQL_SUCCESS) ODBC_REPORT_ERROR("Unable to execute statement"); res = SQLFetch(Statement); if (res != SQL_SUCCESS && res != SQL_SUCCESS_WITH_INFO) ODBC_REPORT_ERROR("Unable to fetch row"); if (SQLDescribeCol(Statement, 1, output, sizeof(output), NULL, &colType, &colSize, &colScale, &colNullable) != SQL_SUCCESS) ODBC_REPORT_ERROR("Error getting data"); if (n == 0) { memset(&ts, 0, sizeof(ts)); if (SQLGetData(Statement, 1, SQL_C_TIMESTAMP, &ts, sizeof(ts), &dataSize) != SQL_SUCCESS) { printf("Unable to get data col %d\n", 1); CheckReturn(); exit(1); } sprintf((char *) output, "%04d-%02d-%02d %02d:%02d:%02d.000", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second); } else { if (SQLGetData(Statement, 1, SQL_C_CHAR, output, sizeof(output), &dataSize) != SQL_SUCCESS) { printf("Unable to get data col %d\n", 1); CheckReturn(); exit(1); } } printf("Date returned: %s\n", output); if (strcmp((char *) output, "2002-12-27 18:43:21.000") != 0) { printf("Invalid returned date\n"); exit(1); } res = SQLFetch(Statement); if (res != SQL_NO_DATA) ODBC_REPORT_ERROR("Unable to fetch row"); res = SQLCloseCursor(Statement); if (!SQL_SUCCEEDED(res)) ODBC_REPORT_ERROR("Unable to close cursor"); }