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