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