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