Line data Source code
1 : #include "common.h"
2 : #define TDSODBC_BCP
3 : #include <odbcss.h>
4 : #include <assert.h>
5 :
6 : #ifdef UNICODE
7 : typedef SQLWCHAR bcp_init_char_t;
8 : #else
9 : typedef char bcp_init_char_t;
10 : #endif
11 :
12 : struct prefixed_int {
13 : ODBCINT64 prefix;
14 : int value;
15 : };
16 : struct prefixed_str {
17 : ODBCINT64 prefix;
18 : char value[64];
19 : };
20 :
21 : /*
22 : * Static data for insertion
23 : */
24 : static struct prefixed_int not_null_bit = {4, 1};
25 : static struct prefixed_str not_null_char = {64, "a char"};
26 : static struct prefixed_str not_null_varchar = {64, "a varchar"};
27 : static struct prefixed_str not_null_datetime = {64, "2003-12-17 15:44:00.000"};
28 : static struct prefixed_str not_null_smalldatetime = {64, "2003-12-17 15:44:00"};
29 : static struct prefixed_str not_null_money = {64, "12.341"};
30 : static struct prefixed_str not_null_smallmoney = {64, "12.34"};
31 : static struct prefixed_str not_null_float = {64, "12.34"};
32 : static struct prefixed_str not_null_real = {64, "12.34"};
33 : static struct prefixed_str not_null_decimal = {64, "12.34"};
34 : static struct prefixed_str not_null_numeric = {64, "12.34"};
35 : static struct prefixed_int not_null_int = {4, 1234};
36 : static struct prefixed_int not_null_smallint = {4, 1234};
37 : static struct prefixed_int not_null_tinyint = {4, 123};
38 : static struct prefixed_str not_null_nvarchar = {64, "a wide var"};
39 : static ODBCINT64 null_prefix = -1;
40 :
41 : static const char *expected[] = {
42 : "1",
43 : "a char ","a varchar","2003-12-17 15:44:00.000","2003-12-17 15:44:00",
44 : "12.3410","12.3400","12.34","12.3400002","12.34","12.34",
45 : "1234","1234","123",
46 : "a wide var",
47 : };
48 : static const int total_cols = 29;
49 :
50 : static const char *expected_special[] = {
51 : "2015-03-14 15:26:53.000",
52 : "2015-03-14 15:26:53.589793",
53 : "3.141593000",
54 : "3.141593", /* MS driver has "3141593" here. Bug? Should we be bug-compatible? */
55 : "",
56 : };
57 :
58 : static int tds_version;
59 :
60 : static void
61 16 : cleanup(void)
62 : {
63 16 : odbc_command("if exists (select 1 from sysobjects where type = 'U' and name = 'all_types_bcp_unittest') drop table all_types_bcp_unittest");
64 16 : odbc_command("if exists (select 1 from sysobjects where type = 'U' and name = 'special_types_bcp_unittest') drop table special_types_bcp_unittest");
65 16 : }
66 :
67 : static void
68 8 : init(void)
69 : {
70 8 : cleanup();
71 :
72 8 : odbc_command("CREATE TABLE all_types_bcp_unittest ("
73 : " not_null_bit bit NOT NULL"
74 : ""
75 : ", not_null_char char(10) NOT NULL"
76 : ", not_null_varchar varchar(10) NOT NULL"
77 : ""
78 : ", not_null_datetime datetime NOT NULL"
79 : ", not_null_smalldatetime smalldatetime NOT NULL"
80 : ""
81 : ", not_null_money money NOT NULL"
82 : ", not_null_smallmoney smallmoney NOT NULL"
83 : ""
84 : ", not_null_float float NOT NULL"
85 : ", not_null_real real NOT NULL"
86 : ""
87 : ", not_null_decimal decimal(5,2) NOT NULL"
88 : ", not_null_numeric numeric(5,2) NOT NULL"
89 : ""
90 : ", not_null_int int NOT NULL"
91 : ", not_null_smallint smallint NOT NULL"
92 : ", not_null_tinyint tinyint NOT NULL"
93 : ", not_null_nvarchar nvarchar(10) NOT NULL"
94 : ""
95 : ", nullable_char char(10) NULL"
96 : ", nullable_varchar varchar(10) NULL"
97 : ""
98 : ", nullable_datetime datetime NULL"
99 : ", nullable_smalldatetime smalldatetime NULL"
100 : ""
101 : ", nullable_money money NULL"
102 : ", nullable_smallmoney smallmoney NULL"
103 : ""
104 : ", nullable_float float NULL"
105 : ", nullable_real real NULL"
106 : ""
107 : ", nullable_decimal decimal(5,2) NULL"
108 : ", nullable_numeric numeric(5,2) NULL"
109 : ""
110 : ", nullable_int int NULL"
111 : ", nullable_smallint smallint NULL"
112 : ", nullable_tinyint tinyint NULL"
113 : ", nullable_nvarchar nvarchar(10) NULL"
114 : ")");
115 :
116 8 : if (tds_version < 0x703)
117 : return;
118 :
119 : /* Excludes:
120 : * binary
121 : * image
122 : * uniqueidentifier
123 : * varbinary
124 : * text
125 : * timestamp
126 : * nchar
127 : * ntext
128 : * nvarchar
129 : */
130 2 : odbc_command("CREATE TABLE special_types_bcp_unittest ("
131 : "dt datetime not null,"
132 : "dt2 datetime2(6) not null,"
133 : "num decimal(19,9) not null,"
134 : "numstr varchar(64) not null,"
135 : "empty varchar(64) not null,"
136 : "bitnull bit null"
137 : ")");
138 : }
139 :
140 : #define VARCHAR_BIND(x) \
141 : bcp_bind( odbc_conn, (unsigned char *) (prefixlen == 0 ? (void*)&x.value : &x), prefixlen, strlen(x.value), NULL, termlen, BCP_TYPE_SQLVARCHAR, col++ )
142 :
143 : #define INT_BIND(x) \
144 : bcp_bind( odbc_conn, (unsigned char *) (prefixlen == 0 ? (void*)&x.value : &x), prefixlen, SQL_VARLEN_DATA, NULL, termlen, BCP_TYPE_SQLINT4, col++ )
145 :
146 : #define NULL_BIND(x, type) \
147 : bcp_bind( odbc_conn, (unsigned char *) (prefixlen == 0 ? (void*)&x.value : &null_prefix), prefixlen, prefixlen == 0 ? SQL_NULL_DATA : SQL_VARLEN_DATA, NULL, termlen, type, col++ )
148 :
149 : static void
150 16 : test_bind(int prefixlen)
151 : {
152 : enum { termlen = 0 };
153 :
154 : RETCODE fOK;
155 16 : int col=1;
156 :
157 : /* non nulls */
158 32 : fOK = INT_BIND(not_null_bit);
159 16 : assert(fOK == SUCCEED);
160 :
161 32 : fOK = VARCHAR_BIND(not_null_char);
162 16 : assert(fOK == SUCCEED);
163 32 : fOK = VARCHAR_BIND(not_null_varchar);
164 16 : assert(fOK == SUCCEED);
165 :
166 32 : fOK = VARCHAR_BIND(not_null_datetime);
167 16 : assert(fOK == SUCCEED);
168 32 : fOK = VARCHAR_BIND(not_null_smalldatetime);
169 16 : assert(fOK == SUCCEED);
170 :
171 32 : fOK = VARCHAR_BIND(not_null_money);
172 16 : assert(fOK == SUCCEED);
173 32 : fOK = VARCHAR_BIND(not_null_smallmoney);
174 16 : assert(fOK == SUCCEED);
175 :
176 32 : fOK = VARCHAR_BIND(not_null_float);
177 16 : assert(fOK == SUCCEED);
178 32 : fOK = VARCHAR_BIND(not_null_real);
179 16 : assert(fOK == SUCCEED);
180 :
181 32 : fOK = VARCHAR_BIND(not_null_decimal);
182 16 : assert(fOK == SUCCEED);
183 32 : fOK = VARCHAR_BIND(not_null_numeric);
184 16 : assert(fOK == SUCCEED);
185 :
186 32 : fOK = INT_BIND(not_null_int);
187 16 : assert(fOK == SUCCEED);
188 32 : fOK = INT_BIND(not_null_smallint);
189 16 : assert(fOK == SUCCEED);
190 32 : fOK = INT_BIND(not_null_tinyint);
191 16 : assert(fOK == SUCCEED);
192 32 : fOK = VARCHAR_BIND(not_null_nvarchar);
193 16 : assert(fOK == SUCCEED);
194 :
195 : /* nulls */
196 : assert(fOK == SUCCEED);
197 32 : fOK = NULL_BIND(not_null_char, BCP_TYPE_SQLVARCHAR);
198 16 : assert(fOK == SUCCEED);
199 32 : fOK = NULL_BIND(not_null_varchar, BCP_TYPE_SQLVARCHAR);
200 16 : assert(fOK == SUCCEED);
201 :
202 32 : fOK = NULL_BIND(not_null_datetime, BCP_TYPE_SQLVARCHAR);
203 16 : assert(fOK == SUCCEED);
204 32 : fOK = NULL_BIND(not_null_smalldatetime, BCP_TYPE_SQLVARCHAR);
205 16 : assert(fOK == SUCCEED);
206 :
207 32 : fOK = NULL_BIND(not_null_money, BCP_TYPE_SQLVARCHAR);
208 16 : assert(fOK == SUCCEED);
209 32 : fOK = NULL_BIND(not_null_smallmoney, BCP_TYPE_SQLVARCHAR);
210 16 : assert(fOK == SUCCEED);
211 :
212 32 : fOK = NULL_BIND(not_null_float, BCP_TYPE_SQLVARCHAR);
213 16 : assert(fOK == SUCCEED);
214 32 : fOK = NULL_BIND(not_null_real, BCP_TYPE_SQLVARCHAR);
215 16 : assert(fOK == SUCCEED);
216 :
217 32 : fOK = NULL_BIND(not_null_decimal, BCP_TYPE_SQLVARCHAR);
218 16 : assert(fOK == SUCCEED);
219 32 : fOK = NULL_BIND(not_null_numeric, BCP_TYPE_SQLVARCHAR);
220 16 : assert(fOK == SUCCEED);
221 :
222 32 : fOK = NULL_BIND(not_null_int, BCP_TYPE_SQLINT4);
223 16 : assert(fOK == SUCCEED);
224 32 : fOK = NULL_BIND(not_null_smallint, BCP_TYPE_SQLINT4);
225 16 : assert(fOK == SUCCEED);
226 32 : fOK = NULL_BIND(not_null_tinyint, BCP_TYPE_SQLINT4);
227 16 : assert(fOK == SUCCEED);
228 32 : fOK = NULL_BIND(not_null_nvarchar, BCP_TYPE_SQLVARCHAR);
229 16 : assert(fOK == SUCCEED);
230 :
231 16 : }
232 :
233 : static void
234 8 : set_attr(void)
235 : {
236 8 : SQLSetConnectAttr(odbc_conn, SQL_COPT_SS_BCP, (SQLPOINTER)SQL_BCP_ON, 0);
237 8 : }
238 :
239 : static void
240 : report_bcp_error(const char *errmsg, int line, const char *file)
241 : {
242 0 : odbc_stmt = NULL;
243 0 : odbc_report_error(errmsg, line, file);
244 : }
245 :
246 : static void normal_inserts(int prefixlen);
247 : static void normal_select(void);
248 : static void special_inserts(void);
249 : static void special_select(void);
250 :
251 : static const char table_name[] = "all_types_bcp_unittest";
252 :
253 : int
254 8 : main(int argc, char *argv[])
255 : {
256 : const char *s;
257 :
258 8 : odbc_set_conn_attr = set_attr;
259 8 : odbc_connect();
260 :
261 8 : tds_version = odbc_tds_version();
262 :
263 8 : init();
264 :
265 8 : normal_inserts(0);
266 8 : if (tds_version >= 0x703)
267 2 : special_inserts();
268 8 : normal_select();
269 8 : if (tds_version >= 0x703)
270 2 : special_select();
271 :
272 8 : odbc_command("delete from all_types_bcp_unittest");
273 8 : normal_inserts(8);
274 8 : normal_select();
275 :
276 8 : if ((s = getenv("BCP")) != NULL && 0 == strcmp(s, "nodrop")) {
277 0 : printf("BCP=nodrop: '%s' kept\n", table_name);
278 : } else {
279 8 : printf("Dropping table %s\n", table_name);
280 8 : odbc_command("drop table all_types_bcp_unittest");
281 8 : if (tds_version >= 0x703)
282 2 : odbc_command("drop table special_types_bcp_unittest");
283 : }
284 :
285 8 : cleanup();
286 :
287 8 : odbc_disconnect();
288 :
289 8 : printf("Done.\n");
290 : return 0;
291 : }
292 :
293 16 : static void normal_inserts(int prefixlen)
294 : {
295 : int i;
296 : int rows_sent;
297 :
298 : /* set up and send the bcp */
299 16 : printf("preparing to insert into %s ... ", table_name);
300 32 : if (bcp_init(odbc_conn, (bcp_init_char_t *) T(table_name), NULL, NULL, BCP_DIRECTION_IN) == FAIL)
301 : report_bcp_error("bcp_init", __LINE__, __FILE__);
302 16 : printf("OK\n");
303 :
304 16 : test_bind(prefixlen);
305 :
306 16 : printf("Sending same row 10 times... \n");
307 176 : for (i=0; i<10; i++)
308 320 : if (bcp_sendrow(odbc_conn) == FAIL)
309 : report_bcp_error("bcp_sendrow", __LINE__, __FILE__);
310 :
311 : #if 1
312 16 : rows_sent = bcp_batch(odbc_conn);
313 16 : if (rows_sent == -1)
314 : report_bcp_error("bcp_batch", __LINE__, __FILE__);
315 : #endif
316 :
317 16 : printf("OK\n");
318 :
319 : /* end bcp. */
320 16 : rows_sent = bcp_done(odbc_conn);
321 16 : if (rows_sent != 0)
322 : report_bcp_error("bcp_done", __LINE__, __FILE__);
323 : else
324 16 : printf("%d rows copied.\n", rows_sent);
325 :
326 16 : printf("done\n");
327 16 : }
328 :
329 2 : static void special_inserts(void)
330 : {
331 : int rows_sent;
332 : SQL_TIMESTAMP_STRUCT timestamp;
333 : DBDATETIME datetime;
334 : SQL_NUMERIC_STRUCT numeric;
335 :
336 2 : printf("sending special types\n");
337 2 : rows_sent = 0;
338 :
339 4 : if (bcp_init(odbc_conn, (bcp_init_char_t *) T("special_types_bcp_unittest"), NULL, NULL, BCP_DIRECTION_IN) == FAIL)
340 : report_bcp_error("bcp_init", __LINE__, __FILE__);
341 2 : printf("OK\n");
342 :
343 2 : datetime.dtdays = 42075;
344 2 : datetime.dttime = 16683900;
345 2 : timestamp.year = 2015;
346 2 : timestamp.month = 3;
347 2 : timestamp.day = 14;
348 2 : timestamp.hour = 15;
349 2 : timestamp.minute = 26;
350 2 : timestamp.second = 53;
351 2 : timestamp.fraction = 589793238;
352 2 : memset(&numeric, 0, sizeof(numeric));
353 2 : numeric.precision = 19;
354 2 : numeric.scale = 6;
355 2 : numeric.sign = 1;
356 2 : numeric.val[0] = 0xd9;
357 2 : numeric.val[1] = 0xef;
358 2 : numeric.val[2] = 0x2f;
359 4 : bcp_bind(odbc_conn, (unsigned char *) &datetime, 0, sizeof(datetime), NULL, 0, BCP_TYPE_SQLDATETIME, 1);
360 4 : bcp_bind(odbc_conn, (unsigned char *) ×tamp, 0, sizeof(timestamp), NULL, 0, BCP_TYPE_SQLDATETIME2, 2);
361 4 : bcp_bind(odbc_conn, (unsigned char *) &numeric, 0, sizeof(numeric), NULL, 0, BCP_TYPE_SQLDECIMAL, 3);
362 4 : bcp_bind(odbc_conn, (unsigned char *) &numeric, 0, sizeof(numeric), NULL, 0, BCP_TYPE_SQLDECIMAL, 4);
363 4 : bcp_bind(odbc_conn, (unsigned char *) "", 0, 0, NULL, 0, BCP_TYPE_SQLVARCHAR, 5);
364 4 : bcp_bind(odbc_conn, (unsigned char *) ¬_null_bit, 0, SQL_NULL_DATA, NULL, 0, BCP_TYPE_SQLINT4, 6);
365 :
366 4 : if (bcp_sendrow(odbc_conn) == FAIL)
367 : report_bcp_error("bcp_sendrow", __LINE__, __FILE__);
368 :
369 2 : rows_sent = bcp_batch(odbc_conn);
370 2 : if (rows_sent != 1)
371 : report_bcp_error("bcp_batch", __LINE__, __FILE__);
372 :
373 2 : printf("OK\n");
374 :
375 : /* end bcp. */
376 :
377 2 : rows_sent = bcp_done(odbc_conn);
378 2 : if (rows_sent != 0)
379 : report_bcp_error("bcp_done", __LINE__, __FILE__);
380 : else
381 2 : printf("%d rows copied.\n", rows_sent);
382 :
383 2 : printf("done\n");
384 2 : }
385 :
386 16 : static void normal_select(void)
387 : {
388 16 : int ok = 1, i;
389 :
390 16 : odbc_command("select * from all_types_bcp_unittest");
391 16 : CHKFetch("SI");
392 :
393 : /* first columns have values */
394 256 : for (i = 0; i < TDS_VECTOR_SIZE(expected); ++i) {
395 : char output[128];
396 : SQLLEN dataSize;
397 240 : CHKGetData(i + 1, SQL_C_CHAR, output, sizeof(output), &dataSize, "S");
398 240 : if (strcmp(output, expected[i]) || dataSize <= 0) {
399 0 : fprintf(stderr, "Invalid returned col %d: '%s'!='%s'\n", i, expected[i], output);
400 0 : ok = 0;
401 : }
402 : }
403 : /* others are NULL */
404 224 : for (; i < total_cols; ++i) {
405 : char output[128];
406 : SQLLEN dataSize;
407 224 : CHKGetData(i + 1, SQL_C_CHAR, output, sizeof(output), &dataSize, "S");
408 224 : if (dataSize != SQL_NULL_DATA) {
409 0 : fprintf(stderr, "Invalid returned col %d: should be NULL'\n", i);
410 0 : ok = 0;
411 : }
412 : }
413 16 : if (!ok)
414 0 : exit(1);
415 16 : CHKCloseCursor("SI");
416 16 : }
417 :
418 2 : static void special_select(void)
419 : {
420 2 : int ok = 1, i;
421 :
422 2 : odbc_command("select top 1 * from special_types_bcp_unittest");
423 2 : CHKFetch("SI");
424 12 : for (i = 0; i < TDS_VECTOR_SIZE(expected_special); ++i) {
425 : char output[128];
426 : SQLLEN dataSize;
427 10 : CHKGetData(i + 1, SQL_C_CHAR, output, sizeof(output), &dataSize, "S");
428 10 : if (strcmp(output, expected_special[i]) || (dataSize <= 0 && expected_special[i][0] != '\0')) {
429 0 : fprintf(stderr, "Invalid returned col %d: '%s'!='%s'\n", i, expected_special[i], output);
430 0 : ok = 0;
431 : }
432 : }
433 2 : if (!ok)
434 0 : exit(1);
435 2 : CHKCloseCursor("SI");
436 2 : }
|