Line data Source code
1 : /* Test SQLDescribeParam */
2 :
3 : #include "common.h"
4 :
5 : static void
6 82 : check_int(bool cond, long int value, const char *msg, int line)
7 : {
8 82 : if (cond)
9 82 : return;
10 0 : fprintf(stderr, "Invalid value %ld at line %d, check: %s\n", value, line, msg);
11 0 : exit(1);
12 : }
13 :
14 : #define check_int(value, cond, expected) \
15 : check_int(value cond expected, value, #value " " #cond " " #expected, __LINE__)
16 :
17 : static void
18 32 : check_type(bool cond, SQLSMALLINT value, const char *msg, int line)
19 : {
20 32 : if (cond)
21 32 : return;
22 0 : fprintf(stderr, "Invalid value %d(%s) at line %d, check: %s\n",
23 : value, odbc_lookup_value(value, odbc_sql_types, "???"), line, msg);
24 0 : exit(1);
25 : }
26 :
27 : #define check_type(value, cond, expected) \
28 : check_type(value cond expected, value, #value " " #cond " " #expected, __LINE__)
29 :
30 10 : TEST_MAIN()
31 : {
32 : SQLSMALLINT num_params;
33 : SQLSMALLINT sql_type;
34 : SQLULEN size;
35 : SQLSMALLINT digits, scale, nullable, count;
36 : SQLHDESC ipd, apd;
37 : SQLINTEGER ind;
38 10 : SQLLEN sql_nts = SQL_NTS;
39 : SQLINTEGER id;
40 : const char *env;
41 :
42 10 : odbc_use_version3 = 1;
43 10 : odbc_connect();
44 :
45 10 : if (!odbc_db_is_microsoft() || odbc_db_version_int() < 0x0b000000u) {
46 8 : odbc_disconnect();
47 8 : printf("SQLDescribeParam implementation requires MSSQL 2012+\n");
48 8 : odbc_test_skipped();
49 0 : return 0;
50 : }
51 :
52 2 : odbc_command("IF OBJECT_ID('describe') IS NOT NULL DROP TABLE describe");
53 2 : odbc_command("CREATE TABLE describe(i int NOT NULL, vc VARCHAR(100) NULL, "
54 : "vb VARBINARY(100) NULL, num NUMERIC(17,5) NULL)");
55 2 : odbc_reset_statement();
56 :
57 2 : CHKPrepare(T("INSERT INTO describe(i, vc, num) VALUES(?, ?, ?)"), SQL_NTS, "S");
58 :
59 : /* we prepared a query with 3 parameters, we should have 3 parameters */
60 2 : CHKNumParams(&num_params, "S");
61 2 : check_int(num_params, ==, 3);
62 :
63 2 : CHKGetStmtAttr(SQL_ATTR_IMP_PARAM_DESC, &ipd, sizeof(ipd), &ind, "S");
64 2 : CHKGetStmtAttr(SQL_ATTR_APP_PARAM_DESC, &apd, sizeof(apd), &ind, "S");
65 :
66 : /* check we have no parameters on IPD and APD */
67 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
68 2 : check_int(count, ==, 0);
69 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
70 2 : check_int(count, ==, 0);
71 :
72 : /* get some parameters */
73 2 : CHKDescribeParam(0, &sql_type, &size, &digits, &nullable, "E");
74 2 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
75 2 : check_type(sql_type, ==, SQL_INTEGER);
76 2 : check_int(size, ==, 10);
77 2 : check_int(digits, ==, 0);
78 2 : check_int(nullable, ==, SQL_NULLABLE);
79 2 : CHKGetDescField(ipd, 1, SQL_DESC_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
80 2 : check_type(sql_type, ==, SQL_INTEGER);
81 2 : CHKGetDescField(ipd, 1, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
82 2 : check_type(sql_type, ==, SQL_INTEGER);
83 2 : CHKGetDescField(ipd, 1, SQL_DESC_LENGTH, &size, sizeof(SQLULEN), &ind, "S");
84 2 : check_int(size, ==, 10);
85 2 : CHKGetDescField(ipd, 1, SQL_DESC_PRECISION, &digits, sizeof(SQLSMALLINT), &ind, "S");
86 : /* TODO sligthly difference with MS driver about descriptor handling */
87 2 : if (!odbc_driver_is_freetds())
88 0 : check_int(digits, ==, 10);
89 2 : CHKGetDescField(ipd, 1, SQL_DESC_SCALE, &scale, sizeof(SQLSMALLINT), &ind, "S");
90 2 : check_int(scale, ==, 0);
91 :
92 2 : CHKDescribeParam(2, &sql_type, &size, &digits, &nullable, "S");
93 2 : check_type(sql_type, ==, SQL_VARCHAR);
94 2 : check_int(size, ==, 100);
95 2 : check_int(digits, ==, 0);
96 2 : check_int(nullable, ==, SQL_NULLABLE);
97 2 : CHKGetDescField(ipd, 2, SQL_DESC_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
98 2 : check_type(sql_type, ==, SQL_VARCHAR);
99 2 : CHKGetDescField(ipd, 2, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
100 2 : check_type(sql_type, ==, SQL_VARCHAR);
101 2 : CHKGetDescField(ipd, 2, SQL_DESC_LENGTH, &size, sizeof(SQLULEN), &ind, "S");
102 2 : check_int(size, ==, 100);
103 2 : CHKGetDescField(ipd, 2, SQL_DESC_PRECISION, &digits, sizeof(SQLSMALLINT), &ind, "S");
104 2 : if (!odbc_driver_is_freetds())
105 0 : check_int(digits, ==, 100);
106 2 : CHKGetDescField(ipd, 2, SQL_DESC_SCALE, &scale, sizeof(SQLSMALLINT), &ind, "S");
107 2 : check_int(scale, ==, 0);
108 :
109 2 : CHKDescribeParam(3, &sql_type, &size, &digits, &nullable, "S");
110 2 : check_type(sql_type, ==, SQL_NUMERIC);
111 2 : check_int(size, ==, 17);
112 2 : check_int(digits, ==, 5);
113 2 : check_int(nullable, ==, SQL_NULLABLE);
114 2 : CHKGetDescField(ipd, 3, SQL_DESC_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
115 2 : check_type(sql_type, ==, SQL_NUMERIC);
116 2 : CHKGetDescField(ipd, 3, SQL_DESC_CONCISE_TYPE, &sql_type, sizeof(SQLSMALLINT), &ind, "S");
117 2 : check_type(sql_type, ==, SQL_NUMERIC);
118 2 : CHKGetDescField(ipd, 3, SQL_DESC_LENGTH, &size, sizeof(SQLULEN), &ind, "S");
119 2 : check_int(size, ==, 17);
120 2 : CHKGetDescField(ipd, 3, SQL_DESC_PRECISION, &digits, sizeof(SQLSMALLINT), &ind, "S");
121 2 : check_int(digits, ==, 17);
122 2 : CHKGetDescField(ipd, 3, SQL_DESC_SCALE, &scale, sizeof(SQLSMALLINT), &ind, "S");
123 2 : check_int(scale, ==, 5);
124 :
125 2 : CHKDescribeParam(4, &sql_type, &size, &digits, &nullable, "E");
126 :
127 : /* check parameters were filled on IPD */
128 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
129 2 : check_int(count, ==, 3);
130 : /* APD is not filled */
131 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
132 2 : check_int(count, ==, 0);
133 :
134 : /*****************************************************************/
135 :
136 : /* preparing another query */
137 2 : CHKPrepare(T("INSERT INTO describe(i) VALUES(?)"), SQL_NTS, "S");
138 :
139 : /* we prepared a query with 1 parameter, we should have 1 parameter */
140 2 : CHKNumParams(&num_params, "S");
141 2 : check_int(num_params, ==, 1);
142 :
143 2 : CHKPrepare(T("INSERT INTO describe(i, vc) VALUES(?, ?)"), SQL_NTS, "S");
144 :
145 : /* check we have no parameters on IPD and APD */
146 : /* SQLPrepare should clear them */
147 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
148 2 : check_int(count, ==, 0);
149 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
150 2 : check_int(count, ==, 0);
151 :
152 2 : CHKNumParams(&num_params, "S");
153 :
154 : /* check we have no parameters on IPD and APD */
155 : /* SQLNumParams does not affect them */
156 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
157 2 : check_int(count, ==, 0);
158 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
159 2 : check_int(count, ==, 0);
160 :
161 2 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
162 2 : check_type(sql_type, ==, SQL_INTEGER);
163 :
164 : /* check parameters were filled on IPD */
165 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
166 2 : check_int(count, ==, 2);
167 : /* APD is not filled */
168 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
169 2 : check_int(count, ==, 0);
170 :
171 : /*****************************************************************/
172 :
173 : /* bind a parameter, see if affects SQLDescribeParam */
174 2 : CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_FLOAT, 10, 0, &id, 0, &sql_nts, "S");
175 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
176 2 : check_int(count, ==, 1);
177 :
178 : /* what happens preparing another query ? */
179 2 : CHKPrepare(T("INSERT INTO describe(vc, i, vb) VALUES(?, ?, ?)"), SQL_NTS, "S");
180 :
181 : /* type do not change, set one stays */
182 2 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
183 2 : check_type(sql_type, ==, SQL_FLOAT);
184 : /* even this parameter remains */
185 2 : CHKDescribeParam(2, &sql_type, &size, &digits, &nullable, "S");
186 2 : check_type(sql_type, ==, SQL_VARCHAR);
187 : /* additional parameter are not read from server */
188 : /* "SQL error 07009 -- [Microsoft][ODBC Driver 18 for SQL Server]Invalid Descriptor Index" */
189 2 : CHKDescribeParam(3, &sql_type, &size, &digits, &nullable, "E");
190 :
191 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
192 2 : check_int(count, ==, 2);
193 : /* APD remains */
194 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
195 2 : check_int(count, ==, 1);
196 :
197 : /*****************************************************************/
198 :
199 : /* try to reset APD */
200 2 : CHKSetDescField(apd, 1, SQL_DESC_COUNT, (SQLPOINTER) 0, SQL_IS_SMALLINT, "S");
201 :
202 2 : CHKPrepare(T("INSERT INTO describe(i) VALUES(?)"), SQL_NTS, "S");
203 :
204 : /* parameter is not overridden */
205 2 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
206 2 : check_type(sql_type, ==, SQL_FLOAT);
207 :
208 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
209 2 : check_int(count, ==, 2);
210 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
211 2 : check_int(count, ==, 0);
212 :
213 : /*****************************************************************/
214 :
215 : /* try to reset parameters */
216 2 : CHKFreeStmt(SQL_RESET_PARAMS, "S");
217 :
218 2 : CHKPrepare(T("INSERT INTO describe(i) VALUES(?)"), SQL_NTS, "S");
219 :
220 : /* parameter is overridden */
221 2 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
222 2 : check_type(sql_type, ==, SQL_INTEGER);
223 :
224 2 : CHKGetDescField(ipd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
225 2 : check_int(count, ==, 1);
226 2 : CHKGetDescField(apd, 0, SQL_DESC_COUNT, &count, sizeof(count), &ind, "S");
227 2 : check_int(count, ==, 0);
228 :
229 : /*****************************************************************/
230 :
231 : /* check what happens if connection is busy (no MARS, pending data) */
232 2 : env = getenv("ODBC_MARS");
233 3 : if (!env || atoi(env) == 0) {
234 : SQLHSTMT stmt;
235 :
236 1 : CHKAllocStmt(&stmt, "S");
237 :
238 1 : SWAP_STMT(stmt);
239 1 : CHKExecDirect(T("SELECT * FROM sysobjects"), SQL_NTS, "S");
240 :
241 1 : SWAP_STMT(stmt);
242 1 : CHKPrepare(T("INSERT INTO describe(vc) VALUES(?)"), SQL_NTS, "S");
243 :
244 1 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "E");
245 1 : odbc_read_error();
246 1 : if (strcmp(odbc_sqlstate, "07009") != 0) {
247 0 : fprintf(stderr, "Unexpected sql state returned: %s\n", odbc_sqlstate);
248 0 : odbc_disconnect();
249 0 : exit(1);
250 : }
251 :
252 1 : SWAP_STMT(stmt);
253 1 : CHKMoreResults("SNo");
254 1 : CHKMoreResults("No");
255 1 : CHKFreeStmt(SQL_DROP, "S");
256 :
257 1 : SWAP_STMT(stmt);
258 : }
259 :
260 : /*****************************************************************/
261 :
262 : /* prepare a stored procedure */
263 2 : CHKPrepare(T("{?=call sp_tables(?)}"), SQL_NTS, "S");
264 :
265 2 : CHKDescribeParam(1, &sql_type, &size, &digits, &nullable, "S");
266 2 : check_type(sql_type, ==, SQL_INTEGER);
267 2 : check_int(size, ==, 10);
268 2 : check_int(digits, ==, 0);
269 2 : check_int(nullable, ==, SQL_NULLABLE);
270 2 : CHKDescribeParam(2, &sql_type, &size, &digits, &nullable, "S");
271 2 : check_type(sql_type, ==, SQL_WVARCHAR);
272 2 : check_int(size, ==, 384);
273 2 : check_int(digits, ==, 0);
274 2 : check_int(nullable, ==, SQL_NULLABLE);
275 :
276 : /*****************************************************************/
277 :
278 : /* cleanup */
279 2 : odbc_command("DROP TABLE describe");
280 :
281 2 : odbc_disconnect();
282 2 : return 0;
283 : }
|