#include #include #include #include "common.h" void printCurrentRow(HSTMT hstmt) { char buf[40]; int col; SQLLEN ind; int rc; for (col = 1; col <= 2; col++) { rc = SQLGetData(hstmt, col, SQL_C_CHAR, buf, sizeof(buf), &ind); if (!SQL_SUCCEEDED(rc)) { print_diag("SQLGetData failed", SQL_HANDLE_STMT, hstmt); exit(1); } if (ind == SQL_NULL_DATA) strcpy(buf, "NULL"); printf("%s%s", (col > 1) ? "\t" : "", buf); } printf("\n"); } int main(int argc, char **argv) { int rc; HSTMT hstmt = SQL_NULL_HSTMT; int i; SQLUINTEGER cursor_type; SQLINTEGER colvalue; SQLLEN indColvalue; test_connect(); rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt); if (!SQL_SUCCEEDED(rc)) { print_diag("failed to allocate stmt handle", SQL_HANDLE_DBC, conn); exit(1); } /* * Initialize a table with some test data. */ printf("Creating test table pos_update_test\n"); rc = SQLExecDirect(hstmt, (SQLCHAR *) "CREATE TEMPORARY TABLE pos_update_test(i int4, orig int4 primary key)", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt); rc = SQLExecDirect(hstmt, (SQLCHAR *) "INSERT INTO pos_update_test SELECT g, g FROM generate_series(1, 10) g", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); printf("Opening a cursor for update, and fetching 10 rows\n"); rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0); CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt); rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0); CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt); rc = SQLBindCol(hstmt, 1, SQL_C_LONG, &colvalue, 0, &indColvalue); CHECK_STMT_RESULT(rc, "SQLBindCol failed", hstmt); rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM pos_update_test ORDER BY orig", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt); rc = SQLGetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) &cursor_type, 0, NULL); printf("exec cursor_type=%d\n", cursor_type); for (i = 0; i < 5; i++) { rc = SQLFetch(hstmt); if (rc == SQL_NO_DATA) break; if (rc == SQL_SUCCESS) { printCurrentRow(hstmt); } else { print_diag("SQLFetch failed", SQL_HANDLE_STMT, hstmt); exit(1); } } /* Do a positioned update and delete */ printf("\nUpdating result set\n"); colvalue += 50; rc = SQLSetPos(hstmt, 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE); CHECK_STMT_RESULT(rc, "SQLSetPos 1st UPDATE failed", hstmt); colvalue += 50; rc = SQLSetPos(hstmt, 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE); CHECK_STMT_RESULT(rc, "SQLSetPos 2nd UPDATE failed", hstmt); rc = SQLFetch(hstmt); CHECK_STMT_RESULT(rc, "SQLFetch failed", hstmt); rc = SQLSetPos(hstmt, 1, SQL_REFRESH, SQL_LOCK_NO_CHANGE); CHECK_STMT_RESULT(rc, "SQLSetPos REFRESH failed", hstmt); rc = SQLSetPos(hstmt, 1, SQL_DELETE, SQL_LOCK_NO_CHANGE); CHECK_STMT_RESULT(rc, "SQLSetPos DELETE failed", hstmt); /**** See if the updates are reflected in the still-open result set ***/ printf("\nRe-fetching the rows in the result set\n"); rc = SQLFetchScroll(hstmt, SQL_FETCH_RELATIVE, 0); CHECK_STMT_RESULT(rc, "SQLFetchScroll failed", hstmt); printCurrentRow(hstmt); rc = SQLFetchScroll(hstmt, SQL_FETCH_PRIOR, -1); CHECK_STMT_RESULT(rc, "SQLFetchScroll failed", hstmt); printCurrentRow(hstmt); rc = SQLFetchScroll(hstmt, SQL_FETCH_PRIOR, -1); CHECK_STMT_RESULT(rc, "SQLFetchScroll failed", hstmt); printCurrentRow(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /**** See if the updates really took effect ****/ printf("\nQuerying the table again\n"); rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM pos_update_test ORDER BY orig", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt); print_result(hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /*** Check that the code can deal with large keysets correctly. * * There was a bug in the reallocation in old driver versions. */ rc = SQLExecDirect(hstmt, (SQLCHAR *) "INSERT INTO pos_update_test SELECT g, g FROM generate_series(100, 5000) g", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt); rc = SQLFreeStmt(hstmt, SQL_CLOSE); CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt); /* * Set Fetch option, and create a new statement to reflect the new * setting. */ { SQLINTEGER fetch_val = 10000; rc = SQLSetConnectAttr(conn, 65541, /* SQL_ATTR_PGOPT_FETCH */ &fetch_val, SQL_IS_INTEGER); CHECK_STMT_RESULT(rc, "SQLSetConnectAttr failed", hstmt); } rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt); CHECK_CONN_RESULT(rc, "SQLAllocHandle failed", conn); printf("\nOpening a cursor for update, and fetching 5000 rows\n"); rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_ROWVER, 0); CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt); rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0); CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt); rc = SQLBindCol(hstmt, 1, SQL_C_LONG, &colvalue, 0, &indColvalue); CHECK_STMT_RESULT(rc, "SQLBindCol failed", hstmt); rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM pos_update_test ORDER BY orig", SQL_NTS); CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt); /* Clean up */ test_disconnect(); return 0; }