1 #include <string.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 #include "common.h"
6
7 void
printCurrentRow(HSTMT hstmt)8 printCurrentRow(HSTMT hstmt)
9 {
10 char buf[40];
11 int col;
12 SQLLEN ind;
13 int rc;
14
15 for (col = 1; col <= 2; col++)
16 {
17 rc = SQLGetData(hstmt, col, SQL_C_CHAR, buf, sizeof(buf), &ind);
18 if (!SQL_SUCCEEDED(rc))
19 {
20 print_diag("SQLGetData failed", SQL_HANDLE_STMT, hstmt);
21 exit(1);
22 }
23 if (ind == SQL_NULL_DATA)
24 strcpy(buf, "NULL");
25 printf("%s%s", (col > 1) ? "\t" : "", buf);
26 }
27 printf("\n");
28 }
29
main(int argc,char ** argv)30 int main(int argc, char **argv)
31 {
32 int rc;
33 HSTMT hstmt = SQL_NULL_HSTMT;
34 int i;
35 SQLUINTEGER cursor_type;
36 SQLINTEGER colvalue;
37 SQLLEN indColvalue;
38
39 test_connect();
40
41 rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
42 if (!SQL_SUCCEEDED(rc))
43 {
44 print_diag("failed to allocate stmt handle", SQL_HANDLE_DBC, conn);
45 exit(1);
46 }
47
48 /*
49 * Initialize a table with some test data.
50 */
51 printf("Creating test table pos_update_test\n");
52 rc = SQLExecDirect(hstmt, (SQLCHAR *) "CREATE TEMPORARY TABLE pos_update_test(i int4, orig int4 primary key)", SQL_NTS);
53 CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
54 rc = SQLExecDirect(hstmt, (SQLCHAR *) "INSERT INTO pos_update_test SELECT g, g FROM generate_series(1, 10) g", SQL_NTS);
55 CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
56
57 rc = SQLFreeStmt(hstmt, SQL_CLOSE);
58 CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
59
60 printf("Opening a cursor for update, and fetching 10 rows\n");
61
62 rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY,
63 (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
64 CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt);
65 rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE,
66 (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0);
67 CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt);
68
69 rc = SQLBindCol(hstmt, 1, SQL_C_LONG, &colvalue, 0, &indColvalue);
70 CHECK_STMT_RESULT(rc, "SQLBindCol failed", hstmt);
71
72 rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM pos_update_test ORDER BY orig", SQL_NTS);
73 CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
74
75 rc = SQLGetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) &cursor_type, 0, NULL);
76 printf("exec cursor_type=%d\n", cursor_type);
77
78 for (i = 0; i < 5; i++)
79 {
80 rc = SQLFetch(hstmt);
81 if (rc == SQL_NO_DATA)
82 break;
83 if (rc == SQL_SUCCESS)
84 {
85
86 printCurrentRow(hstmt);
87 }
88 else
89 {
90 print_diag("SQLFetch failed", SQL_HANDLE_STMT, hstmt);
91 exit(1);
92 }
93 }
94
95 /* Do a positioned update and delete */
96 printf("\nUpdating result set\n");
97 colvalue += 50;
98 rc = SQLSetPos(hstmt, 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
99 CHECK_STMT_RESULT(rc, "SQLSetPos 1st UPDATE failed", hstmt);
100 colvalue += 50;
101 rc = SQLSetPos(hstmt, 1, SQL_UPDATE, SQL_LOCK_NO_CHANGE);
102 CHECK_STMT_RESULT(rc, "SQLSetPos 2nd UPDATE failed", hstmt);
103
104 rc = SQLFetch(hstmt);
105 CHECK_STMT_RESULT(rc, "SQLFetch failed", hstmt);
106
107 rc = SQLSetPos(hstmt, 1, SQL_REFRESH, SQL_LOCK_NO_CHANGE);
108 CHECK_STMT_RESULT(rc, "SQLSetPos REFRESH failed", hstmt);
109
110 rc = SQLSetPos(hstmt, 1, SQL_DELETE, SQL_LOCK_NO_CHANGE);
111 CHECK_STMT_RESULT(rc, "SQLSetPos DELETE failed", hstmt);
112
113
114 /**** See if the updates are reflected in the still-open result set ***/
115 printf("\nRe-fetching the rows in the result set\n");
116
117 rc = SQLFetchScroll(hstmt, SQL_FETCH_RELATIVE, 0);
118 CHECK_STMT_RESULT(rc, "SQLFetchScroll failed", hstmt);
119 printCurrentRow(hstmt);
120
121 rc = SQLFetchScroll(hstmt, SQL_FETCH_PRIOR, -1);
122 CHECK_STMT_RESULT(rc, "SQLFetchScroll failed", hstmt);
123 printCurrentRow(hstmt);
124
125 rc = SQLFetchScroll(hstmt, SQL_FETCH_PRIOR, -1);
126 CHECK_STMT_RESULT(rc, "SQLFetchScroll failed", hstmt);
127 printCurrentRow(hstmt);
128
129 rc = SQLFreeStmt(hstmt, SQL_CLOSE);
130 CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
131
132
133 /**** See if the updates really took effect ****/
134 printf("\nQuerying the table again\n");
135 rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM pos_update_test ORDER BY orig", SQL_NTS);
136 CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
137 print_result(hstmt);
138
139 rc = SQLFreeStmt(hstmt, SQL_CLOSE);
140 CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
141
142 /*** Check that the code can deal with large keysets correctly.
143 *
144 * There was a bug in the reallocation in old driver versions.
145 */
146 rc = SQLExecDirect(hstmt, (SQLCHAR *) "INSERT INTO pos_update_test SELECT g, g FROM generate_series(100, 5000) g", SQL_NTS);
147
148 CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
149
150 rc = SQLFreeStmt(hstmt, SQL_CLOSE);
151 CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
152
153 /*
154 * Set Fetch option, and create a new statement to reflect the new
155 * setting.
156 */
157 {
158 SQLINTEGER fetch_val = 10000;
159 rc = SQLSetConnectAttr(conn,
160 65541, /* SQL_ATTR_PGOPT_FETCH */
161 &fetch_val,
162 SQL_IS_INTEGER);
163 CHECK_STMT_RESULT(rc, "SQLSetConnectAttr failed", hstmt);
164 }
165
166 rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
167 CHECK_CONN_RESULT(rc, "SQLAllocHandle failed", conn);
168
169 printf("\nOpening a cursor for update, and fetching 5000 rows\n");
170
171 rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY,
172 (SQLPOINTER) SQL_CONCUR_ROWVER, 0);
173 CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt);
174 rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE,
175 (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0);
176 CHECK_STMT_RESULT(rc, "SQLSetStmtAttr failed", hstmt);
177
178 rc = SQLBindCol(hstmt, 1, SQL_C_LONG, &colvalue, 0, &indColvalue);
179 CHECK_STMT_RESULT(rc, "SQLBindCol failed", hstmt);
180
181 rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT * FROM pos_update_test ORDER BY orig", SQL_NTS);
182 CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
183
184 /* Clean up */
185 test_disconnect();
186
187 return 0;
188 }
189