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