Line data Source code
1 : #include "common.h"
2 : #include <assert.h>
3 :
4 : /* Test using array binding */
5 :
6 : static SQLTCHAR *test_query = NULL;
7 : static int multiply = 90;
8 : static int failure = 0;
9 :
10 : #define XMALLOC_N(t, n) (t*) ODBC_GET(n*sizeof(t))
11 :
12 : enum {
13 : FLAG_PREPARE = 1,
14 : FLAG_NO_STAT = 2
15 : };
16 :
17 : static void
18 114 : query_test(int flags, SQLRETURN expected, const char *expected_status)
19 : {
20 : #define DESC_LEN 51
21 : #define ARRAY_SIZE 10
22 :
23 114 : SQLUINTEGER *ids = XMALLOC_N(SQLUINTEGER,ARRAY_SIZE);
24 : typedef SQLCHAR desc_t[DESC_LEN];
25 114 : desc_t *descs = XMALLOC_N(desc_t, ARRAY_SIZE);
26 114 : SQLLEN *id_lens = XMALLOC_N(SQLLEN,ARRAY_SIZE), *desc_lens = XMALLOC_N(SQLLEN,ARRAY_SIZE);
27 114 : SQLUSMALLINT i, *statuses = XMALLOC_N(SQLUSMALLINT,ARRAY_SIZE);
28 114 : unsigned *num_errors = XMALLOC_N(unsigned, ARRAY_SIZE);
29 : SQLULEN processed;
30 : RETCODE ret;
31 : char status[20];
32 114 : SQLTCHAR *err = (SQLTCHAR *) ODBC_GET(sizeof(odbc_err)*sizeof(SQLTCHAR));
33 114 : SQLTCHAR *state = (SQLTCHAR *) ODBC_GET(sizeof(odbc_sqlstate)*sizeof(SQLTCHAR));
34 :
35 114 : assert(odbc_stmt != SQL_NULL_HSTMT);
36 114 : odbc_reset_statement();
37 :
38 114 : odbc_command("create table #tmp1 (id tinyint, value char(20))");
39 :
40 114 : SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);
41 114 : SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAMSET_SIZE, (void *) ARRAY_SIZE, 0);
42 114 : if (!(flags & FLAG_NO_STAT)) {
43 82 : SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAM_STATUS_PTR, statuses, 0);
44 : }
45 114 : SQLSetStmtAttr(odbc_stmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &processed, 0);
46 114 : SQLBindParameter(odbc_stmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0, ids, 0, id_lens);
47 114 : SQLBindParameter(odbc_stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, DESC_LEN - 1, 0, descs, DESC_LEN, desc_lens);
48 :
49 114 : processed = ARRAY_SIZE + 1;
50 1254 : for (i = 0; i < ARRAY_SIZE; i++) {
51 1140 : statuses[i] = SQL_PARAM_DIAG_UNAVAILABLE;
52 1140 : ids[i] = (i + 1) * multiply;
53 1140 : sprintf((char *) descs[i], "data %d \xf4", i * 7);
54 1140 : id_lens[i] = 0;
55 1140 : desc_lens[i] = SQL_NTS;
56 1140 : num_errors[i] = 0;
57 : }
58 114 : multiply = 90;
59 :
60 114 : if (!(flags & FLAG_PREPARE)) {
61 58 : ret = SQLExecDirect(odbc_stmt, test_query, SQL_NTS);
62 : } else {
63 56 : SQLPrepare(odbc_stmt, test_query, SQL_NTS);
64 56 : ret = SQLExecute(odbc_stmt);
65 : }
66 :
67 114 : if (processed > ARRAY_SIZE) {
68 : char buf[256];
69 :
70 0 : sprintf(buf, "Invalid processed number: %d", (int) processed);
71 0 : ODBC_REPORT_ERROR(buf);
72 : }
73 :
74 114 : if (!(flags & FLAG_NO_STAT)) {
75 976 : for (i = 1; CHKGetDiagRec(SQL_HANDLE_STMT, odbc_stmt, i, state, NULL, err, sizeof(odbc_err), NULL, "SINo") != SQL_NO_DATA; ++i) {
76 976 : SQLINTEGER row = 0;
77 :
78 976 : strcpy(odbc_err, C(err));
79 976 : strcpy(odbc_sqlstate, C(state));
80 976 : CHKGetDiagField(SQL_HANDLE_STMT, odbc_stmt, i, SQL_DIAG_ROW_NUMBER, &row, sizeof(row), NULL, "S");
81 :
82 976 : if (row == SQL_ROW_NUMBER_UNKNOWN) continue;
83 976 : if (row < 1 || row > ARRAY_SIZE) {
84 0 : fprintf(stderr, "invalid row %d returned reading error number %d\n", (int) row, i);
85 0 : exit(1);
86 : }
87 976 : ++num_errors[row-1];
88 976 : printf("for row %2d returned '%s' %s\n", (int) row, odbc_sqlstate, odbc_err);
89 : }
90 : }
91 :
92 1140 : for (i = 0; i < processed; ++i) {
93 1140 : int has_diag = 0;
94 :
95 1140 : switch (statuses[i]) {
96 0 : case SQL_PARAM_SUCCESS_WITH_INFO:
97 0 : has_diag = 1;
98 332 : case SQL_PARAM_SUCCESS:
99 332 : status[i] = 'V';
100 332 : break;
101 :
102 488 : case SQL_PARAM_ERROR:
103 488 : has_diag = 1;
104 488 : status[i] = '!';
105 488 : break;
106 :
107 0 : case SQL_PARAM_UNUSED:
108 0 : status[i] = ' ';
109 0 : break;
110 :
111 320 : case SQL_PARAM_DIAG_UNAVAILABLE:
112 320 : status[i] = '?';
113 320 : break;
114 0 : default:
115 0 : fprintf(stderr, "Invalid status returned %d\n", statuses[i]);
116 0 : exit(1);
117 : }
118 :
119 : /* can't check status values if we hadn't asked for them */
120 1140 : if (flags & FLAG_NO_STAT)
121 320 : continue;
122 :
123 820 : if (has_diag) {
124 488 : if (!num_errors[i]) {
125 0 : fprintf(stderr, "Diagnostics not returned for status %d\n", i);
126 0 : failure = 1;
127 : }
128 : } else {
129 332 : if (num_errors[i]) {
130 0 : fprintf(stderr, "Diagnostics returned for status %d\n", i);
131 0 : failure = 1;
132 : }
133 : }
134 : }
135 114 : status[i] = 0;
136 :
137 114 : if (ret != expected || strcmp(expected_status, status) != 0) {
138 0 : fprintf(stderr, "Invalid result: got %d \"%s\" expected %d \"%s\" processed %d\n",
139 : ret, status, expected, expected_status, (int) processed);
140 0 : if (ret != SQL_SUCCESS)
141 0 : odbc_read_error();
142 0 : failure = 1;
143 : }
144 :
145 114 : odbc_reset_statement();
146 :
147 114 : odbc_command_with_result(odbc_stmt, "drop table #tmp1");
148 114 : }
149 :
150 : int
151 10 : main(void)
152 : {
153 10 : odbc_use_version3 = 1;
154 10 : odbc_conn_additional_params = "ClientCharset=ISO-8859-1;";
155 10 : odbc_connect();
156 :
157 10 : if (odbc_db_is_microsoft()) {
158 : /* all successes */
159 8 : test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
160 8 : multiply = 1;
161 8 : query_test(0, SQL_SUCCESS, "VVVVVVVVVV");
162 8 : multiply = 1;
163 8 : query_test(FLAG_PREPARE, SQL_SUCCESS, "VVVVVVVVVV");
164 :
165 : /* all errors */
166 8 : test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
167 8 : multiply = 257;
168 8 : query_test(0, SQL_SUCCESS_WITH_INFO, "!!!!!!!!!!");
169 8 : multiply = 257;
170 8 : query_test(FLAG_PREPARE, SQL_SUCCESS_WITH_INFO, "!!!!!!!!!!");
171 :
172 8 : test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
173 8 : query_test(0, SQL_SUCCESS_WITH_INFO, "VV!!!!!!!!");
174 8 : query_test(FLAG_PREPARE, SQL_SUCCESS_WITH_INFO, "VV!!!!!!!!");
175 :
176 8 : test_query = T("INSERT INTO #tmp1 (id, value) VALUES (900-?, ?)");
177 8 : query_test(0, SQL_SUCCESS_WITH_INFO, "!!!!!!!VVV");
178 8 : query_test(FLAG_PREPARE, SQL_SUCCESS_WITH_INFO, "!!!!!!!VVV");
179 :
180 8 : test_query = T("INSERT INTO #tmp1 (id) VALUES (?) UPDATE #tmp1 SET value = ?");
181 8 : query_test(0, SQL_SUCCESS_WITH_INFO, odbc_driver_is_freetds() ? "VVVV!V!V!V" : "VV!!!!!!!!");
182 8 : query_test(FLAG_PREPARE, SQL_SUCCESS_WITH_INFO, "VV!!!!!!!!");
183 :
184 : /* test what happens when not using status array */
185 8 : test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?, ?)");
186 8 : multiply = 1;
187 8 : query_test(FLAG_NO_STAT, SQL_SUCCESS, "??????????");
188 8 : multiply = 1;
189 8 : query_test(FLAG_NO_STAT | FLAG_PREPARE, SQL_SUCCESS, "??????????");
190 :
191 8 : query_test(FLAG_NO_STAT, SQL_ERROR, "??????????");
192 8 : query_test(FLAG_NO_STAT | FLAG_PREPARE, SQL_ERROR, "??????????");
193 :
194 : #ifdef ENABLE_DEVELOPING
195 : /* with result, see how SQLMoreResult work */
196 : test_query = T("INSERT INTO #tmp1 (id) VALUES (?) SELECT * FROM #tmp1 UPDATE #tmp1 SET value = ?");
197 : /* IMHO our driver is better here -- freddy77 */
198 : query_test(0, SQL_SUCCESS, odbc_driver_is_freetds() ? "VVVVV!V!V!" : "VVVVVV!VVV");
199 : query_test(FLAG_PREPARE, SQL_SUCCESS, "VVVVVVVVVV");
200 : #endif
201 : } else {
202 : /* Sybase test for conversions before executing */
203 2 : test_query = T("INSERT INTO #tmp1 (id, value) VALUES (?/8, ?)");
204 2 : query_test(0, SQL_SUCCESS, "VVVVVVVVVV");
205 : }
206 :
207 : /* TODO record binding, array fetch, sqlputdata */
208 :
209 10 : odbc_disconnect();
210 :
211 10 : printf(failure ? "Failed :(\n" : "Success!\n");
212 10 : return failure;
213 : }
214 :
|