Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998-2004, 2005, 2010 Brian Bruns, Bill Thompson
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdarg.h>
23 : #include <stdio.h>
24 :
25 : #if HAVE_STDLIB_H
26 : #include <stdlib.h>
27 : #endif /* HAVE_STDLIB_H */
28 :
29 : #if HAVE_STRING_H
30 : #include <string.h>
31 : #endif /* HAVE_STRING_H */
32 :
33 : #include <freetds/utils.h>
34 : #include <freetds/replacements.h>
35 :
36 : #include "bkpublic.h"
37 :
38 : #include "ctpublic.h"
39 : #include "ctlib.h"
40 :
41 : static void _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset);
42 : static TDSRET _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bcpcol, int offset);
43 : static CS_RETCODE _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);
44 : static CS_RETCODE _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred);
45 :
46 : #define CONN(bulk) ((CS_CONNECTION *) (bulk)->bcpinfo.parent)
47 :
48 : TDS_COMPILE_CHECK(same_size, sizeof(CS_BLKDESC) == sizeof(TDSBCPINFO));
49 : TDS_COMPILE_CHECK(nested_type, TDS_OFFSET(CS_BLKDESC, bcpinfo) == 0);
50 :
51 : CS_RETCODE
52 24 : blk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer)
53 : {
54 : CS_BLKDESC *blkdesc;
55 :
56 24 : tdsdump_log(TDS_DBG_FUNC, "blk_alloc(%p, %d, %p)\n", connection, version, blk_pointer);
57 :
58 24 : if (!connection || !connection->tds_socket)
59 : return CS_FAIL;
60 :
61 24 : if (connection->tds_socket->conn->tds_version < 0x500)
62 : return CS_FAIL;
63 :
64 24 : blkdesc = (CS_BLKDESC *) tds_alloc_bcpinfo();
65 24 : if (!blkdesc)
66 : return CS_FAIL;
67 :
68 : /* so we know who we belong to */
69 24 : blkdesc->bcpinfo.parent = connection;
70 :
71 24 : *blk_pointer = blkdesc;
72 24 : return CS_SUCCEED;
73 : }
74 :
75 :
76 : CS_RETCODE
77 320 : blk_bind(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt_arg, CS_VOID * buffer, CS_INT * datalen, CS_SMALLINT * indicator)
78 : {
79 : TDSCOLUMN *colinfo;
80 : CS_CONNECTION *con;
81 : CS_INT bind_count;
82 : const CS_DATAFMT_COMMON * datafmt;
83 : int i;
84 :
85 320 : tdsdump_log(TDS_DBG_FUNC, "blk_bind(%p, %d, %p, %p, %p, %p)\n", blkdesc, item, datafmt_arg, buffer, datalen, indicator);
86 :
87 320 : if (!blkdesc)
88 : return CS_FAIL;
89 :
90 320 : con = CONN(blkdesc);
91 :
92 320 : datafmt = _ct_datafmt_common(con->ctx, datafmt_arg);
93 :
94 320 : if (item == CS_UNUSED) {
95 : /* clear all bindings */
96 0 : if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) {
97 0 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
98 0 : for (i = 0; i < blkdesc->bcpinfo.bindinfo->num_cols; i++ ) {
99 0 : colinfo = blkdesc->bcpinfo.bindinfo->columns[i];
100 0 : colinfo->column_varaddr = NULL;
101 0 : colinfo->column_bindtype = 0;
102 0 : colinfo->column_bindfmt = 0;
103 0 : colinfo->column_bindlen = 0;
104 0 : colinfo->column_nullbind = NULL;
105 0 : colinfo->column_lenbind = NULL;
106 : }
107 : }
108 : return CS_SUCCEED;
109 : }
110 :
111 : /* check item value */
112 :
113 320 : if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
114 0 : _ctclient_msg(con, "blk_bind", 2, 5, 1, 141, "%s, %d", "colnum", item);
115 0 : return CS_FAIL;
116 : }
117 :
118 : /* clear bindings for this column */
119 :
120 320 : if (datafmt == NULL && buffer == NULL && datalen == NULL && indicator == NULL ) {
121 :
122 0 : colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
123 0 : colinfo->column_varaddr = NULL;
124 0 : colinfo->column_bindtype = 0;
125 0 : colinfo->column_bindfmt = 0;
126 0 : colinfo->column_bindlen = 0;
127 0 : colinfo->column_nullbind = NULL;
128 0 : colinfo->column_lenbind = NULL;
129 :
130 0 : return CS_SUCCEED;
131 : }
132 :
133 320 : if (datafmt == NULL)
134 : return CS_FAIL;
135 :
136 : /*
137 : * check whether the request is for array binding and ensure that user
138 : * supplies the same datafmt->count to the subsequent ct_bind calls
139 : */
140 :
141 320 : bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
142 :
143 : /* first bind for this result set */
144 :
145 320 : if (blkdesc->bcpinfo.bind_count == CS_UNUSED) {
146 96 : blkdesc->bcpinfo.bind_count = bind_count;
147 : } else {
148 : /* all subsequent binds for this result set - the bind counts must be the same */
149 224 : if (blkdesc->bcpinfo.bind_count != bind_count) {
150 0 : _ctclient_msg(con, "blk_bind", 1, 1, 1, 137, "%d, %d", bind_count, blkdesc->bcpinfo.bind_count);
151 0 : return CS_FAIL;
152 : }
153 : }
154 :
155 : /* bind the column_varaddr to the address of the buffer */
156 :
157 320 : colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
158 :
159 320 : colinfo->column_varaddr = (char *) buffer;
160 320 : colinfo->column_bindtype = datafmt->datatype;
161 320 : colinfo->column_bindfmt = datafmt->format;
162 320 : colinfo->column_bindlen = datafmt->maxlength;
163 320 : if (indicator) {
164 240 : colinfo->column_nullbind = indicator;
165 : }
166 320 : if (datalen) {
167 320 : colinfo->column_lenbind = datalen;
168 : }
169 : return CS_SUCCEED;
170 : }
171 :
172 : CS_RETCODE
173 0 : blk_colval(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT colnum, CS_VOID * valuep, CS_INT valuelen,
174 : CS_INT * outlenp)
175 : {
176 :
177 0 : tdsdump_log(TDS_DBG_FUNC, "blk_colval(%p, %p, %p, %d, %p, %d, %p)\n",
178 : srvproc, blkdescp, rowp, colnum, valuep, valuelen, outlenp);
179 :
180 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_colval()\n");
181 0 : return CS_FAIL;
182 : }
183 :
184 : CS_RETCODE
185 0 : blk_default(CS_BLKDESC * blkdesc, CS_INT colnum, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
186 : {
187 :
188 0 : tdsdump_log(TDS_DBG_FUNC, "blk_default(%p, %d, %p, %d, %p)\n", blkdesc, colnum, buffer, buflen, outlen);
189 :
190 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_default()\n");
191 0 : return CS_FAIL;
192 : }
193 :
194 : CS_RETCODE
195 240 : blk_describe(CS_BLKDESC * blkdesc, CS_INT item, CS_DATAFMT * datafmt_arg)
196 : {
197 : TDSCOLUMN *curcol;
198 : CS_INT status, datatype;
199 : CS_DATAFMT_LARGE *datafmt;
200 : CS_DATAFMT_LARGE datafmt_buf;
201 :
202 240 : tdsdump_log(TDS_DBG_FUNC, "blk_describe(%p, %d, %p)\n", blkdesc, item, datafmt_arg);
203 :
204 240 : if (!blkdesc)
205 : return CS_FAIL;
206 :
207 240 : datafmt = _ct_datafmt_conv_prepare(CONN(blkdesc)->ctx, datafmt_arg, &datafmt_buf);
208 :
209 240 : if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
210 0 : _ctclient_msg(CONN(blkdesc), "blk_describe", 2, 5, 1, 141, "%s, %d", "colnum", item);
211 0 : return CS_FAIL;
212 : }
213 :
214 240 : curcol = blkdesc->bcpinfo.bindinfo->columns[item - 1];
215 : /* name is always null terminated */
216 480 : strlcpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), sizeof(datafmt->name));
217 240 : datafmt->namelen = strlen(datafmt->name);
218 : /* need to turn the SYBxxx into a CS_xxx_TYPE */
219 240 : datatype = _ct_get_client_type(curcol, true);
220 240 : if (datatype == CS_ILLEGAL_TYPE)
221 : return CS_FAIL;
222 240 : datafmt->datatype = datatype;
223 240 : tdsdump_log(TDS_DBG_INFO1, "blk_describe() datafmt->datatype = %d server type %d\n", datatype,
224 0 : curcol->column_type);
225 : /* FIXME is ok this value for numeric/decimal? */
226 240 : datafmt->maxlength = curcol->column_size;
227 240 : datafmt->usertype = curcol->column_usertype;
228 240 : datafmt->precision = curcol->column_prec;
229 240 : datafmt->scale = curcol->column_scale;
230 :
231 : /*
232 : * There are other options that can be returned, but these are the
233 : * only two being noted via the TDS layer.
234 : */
235 240 : status = 0;
236 240 : if (curcol->column_nullable)
237 112 : status |= CS_CANBENULL;
238 240 : if (curcol->column_identity)
239 0 : status |= CS_IDENTITY;
240 240 : datafmt->status = status;
241 :
242 240 : datafmt->count = 1;
243 240 : datafmt->locale = NULL;
244 :
245 240 : _ct_datafmt_conv_back(datafmt_arg, datafmt);
246 240 : return CS_SUCCEED;
247 : }
248 :
249 : CS_RETCODE
250 88 : blk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow)
251 : {
252 : TDSSOCKET *tds;
253 : int rows_copied;
254 :
255 88 : tdsdump_log(TDS_DBG_FUNC, "blk_done(%p, %d, %p)\n", blkdesc, type, outrow);
256 :
257 88 : tds = CONN(blkdesc)->tds_socket;
258 :
259 88 : switch (type) {
260 0 : case CS_BLK_BATCH:
261 0 : if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
262 0 : _ctclient_msg(CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
263 0 : return CS_FAIL;
264 : }
265 :
266 0 : if (outrow)
267 0 : *outrow = rows_copied;
268 :
269 0 : if (TDS_FAILED(tds_bcp_start(tds, &blkdesc->bcpinfo))) {
270 0 : _ctclient_msg(CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
271 0 : return CS_FAIL;
272 : }
273 : break;
274 :
275 88 : case CS_BLK_ALL:
276 88 : if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
277 0 : _ctclient_msg(CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
278 0 : return CS_FAIL;
279 : }
280 :
281 88 : if (outrow)
282 88 : *outrow = rows_copied;
283 :
284 : /* free allocated storage in blkdesc & initialise flags, etc. */
285 88 : tds_deinit_bcpinfo(&blkdesc->bcpinfo);
286 :
287 88 : blkdesc->bcpinfo.direction = 0;
288 88 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
289 88 : blkdesc->bcpinfo.xfer_init = 0;
290 :
291 88 : break;
292 :
293 : }
294 :
295 : return CS_SUCCEED;
296 : }
297 :
298 : CS_RETCODE
299 24 : blk_drop(CS_BLKDESC * blkdesc)
300 : {
301 24 : tdsdump_log(TDS_DBG_FUNC, "blk_drop(%p)\n", blkdesc);
302 :
303 : /* this is possible as CS_BLKDESC contains just bcpinfo field */
304 24 : tds_free_bcpinfo(&blkdesc->bcpinfo);
305 :
306 24 : return CS_SUCCEED;
307 : }
308 :
309 : CS_RETCODE
310 0 : blk_getrow(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp)
311 : {
312 0 : tdsdump_log(TDS_DBG_FUNC, "blk_getrow(%p, %p, %p)\n", srvproc, blkdescp, rowp);
313 :
314 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_getrow()\n");
315 0 : return CS_FAIL;
316 : }
317 :
318 : CS_RETCODE
319 0 : blk_gettext(SRV_PROC * srvproc, CS_BLKDESC * blkdescp, CS_BLK_ROW * rowp, CS_INT bufsize, CS_INT * outlenp)
320 : {
321 :
322 0 : tdsdump_log(TDS_DBG_FUNC, "blk_gettext(%p, %p, %p, %d, %p)\n", srvproc, blkdescp, rowp, bufsize, outlenp);
323 :
324 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_gettext()\n");
325 0 : return CS_FAIL;
326 : }
327 :
328 : CS_RETCODE
329 96 : blk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen)
330 : {
331 96 : tdsdump_log(TDS_DBG_FUNC, "blk_init(%p, %d, %p, %d)\n", blkdesc, direction, tablename, tnamelen);
332 :
333 96 : if (!blkdesc) {
334 : return CS_FAIL;
335 : }
336 :
337 96 : if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) {
338 0 : _ctclient_msg(CONN(blkdesc), "blk_init", 2, 6, 1, 138, "");
339 0 : return CS_FAIL;
340 : }
341 :
342 96 : if (!tablename) {
343 0 : _ctclient_msg(CONN(blkdesc), "blk_init", 2, 6, 1, 139, "");
344 0 : return CS_FAIL;
345 : }
346 96 : if (tnamelen == CS_NULLTERM)
347 96 : tnamelen = strlen(tablename);
348 :
349 : /* free allocated storage in blkdesc & initialise flags, etc. */
350 96 : tds_deinit_bcpinfo(&blkdesc->bcpinfo);
351 :
352 : /* string can be no-nul terminated so copy with memcpy */
353 96 : if (!tds_dstr_copyn(&blkdesc->bcpinfo.tablename, tablename, tnamelen)) {
354 : return CS_FAIL;
355 : }
356 :
357 96 : blkdesc->bcpinfo.direction = direction;
358 96 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
359 96 : blkdesc->bcpinfo.xfer_init = 0;
360 :
361 96 : if (TDS_FAILED(tds_bcp_init(CONN(blkdesc)->tds_socket, &blkdesc->bcpinfo))) {
362 0 : _ctclient_msg(CONN(blkdesc), "blk_init", 2, 5, 1, 140, "");
363 0 : return CS_FAIL;
364 : }
365 96 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
366 :
367 96 : return CS_SUCCEED;
368 : }
369 :
370 : CS_RETCODE
371 0 : blk_props(CS_BLKDESC * blkdesc, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
372 : {
373 : int retval, intval;
374 :
375 0 : tdsdump_log(TDS_DBG_FUNC, "blk_props(%p, %d, %d, %p, %d, %p)\n", blkdesc, action, property, buffer, buflen, outlen);
376 :
377 0 : switch (property) {
378 0 : case BLK_IDENTITY:
379 0 : switch (action) {
380 0 : case CS_SET:
381 0 : if (buffer) {
382 0 : memcpy(&intval, buffer, sizeof(intval));
383 0 : if (intval == CS_TRUE)
384 0 : blkdesc->bcpinfo.identity_insert_on = 1;
385 0 : if (intval == CS_FALSE)
386 0 : blkdesc->bcpinfo.identity_insert_on = 0;
387 : }
388 : return CS_SUCCEED;
389 : break;
390 0 : case CS_GET:
391 0 : retval = blkdesc->bcpinfo.identity_insert_on == 1 ? CS_TRUE : CS_FALSE ;
392 0 : if (buffer) {
393 0 : memcpy (buffer, &retval, sizeof(retval));
394 0 : if (outlen)
395 0 : *outlen = sizeof(retval);
396 : }
397 : return CS_SUCCEED;
398 : break;
399 0 : default:
400 0 : _ctclient_msg(CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "action", action);
401 : break;
402 : }
403 0 : break;
404 :
405 0 : case BLK_HINTS:
406 0 : return _ct_props_dstr(CONN(blkdesc), &blkdesc->bcpinfo.hint, action, buffer, buflen, outlen);
407 :
408 0 : default:
409 0 : _ctclient_msg(CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "property", property);
410 0 : break;
411 : }
412 : return CS_FAIL;
413 : }
414 :
415 : CS_RETCODE
416 0 : blk_rowalloc(SRV_PROC * srvproc, CS_BLK_ROW ** row)
417 : {
418 0 : tdsdump_log(TDS_DBG_FUNC, "blk_rowalloc(%p, %p)\n", srvproc, row);
419 :
420 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowalloc()\n");
421 0 : return CS_FAIL;
422 : }
423 :
424 : CS_RETCODE
425 0 : blk_rowdrop(SRV_PROC * srvproc, CS_BLK_ROW * row)
426 : {
427 0 : tdsdump_log(TDS_DBG_FUNC, "blk_rowdrop(%p, %p)\n", srvproc, row);
428 :
429 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowdrop()\n");
430 0 : return CS_FAIL;
431 : }
432 :
433 : CS_RETCODE
434 160 : blk_rowxfer(CS_BLKDESC * blkdesc)
435 : {
436 160 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
437 :
438 160 : return blk_rowxfer_mult(blkdesc, NULL);
439 : }
440 :
441 : CS_RETCODE
442 184 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
443 : {
444 184 : CS_INT rows_to_xfer = 0;
445 184 : CS_INT rows_xferred = 0;
446 : CS_RETCODE ret;
447 :
448 184 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
449 :
450 184 : if (!row_count || *row_count == 0 )
451 168 : rows_to_xfer = blkdesc->bcpinfo.bind_count;
452 : else
453 : rows_to_xfer = *row_count;
454 :
455 184 : if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
456 160 : ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
457 : } else {
458 24 : ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
459 : }
460 184 : if (row_count)
461 24 : *row_count = rows_xferred;
462 184 : return ret;
463 :
464 : }
465 :
466 : CS_RETCODE
467 0 : blk_sendrow(CS_BLKDESC * blkdesc, CS_BLK_ROW * row)
468 : {
469 :
470 0 : tdsdump_log(TDS_DBG_FUNC, "blk_sendrow(%p, %p)\n", blkdesc, row);
471 :
472 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendrow()\n");
473 0 : return CS_FAIL;
474 : }
475 :
476 : CS_RETCODE
477 0 : blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT buflen)
478 : {
479 0 : tdsdump_log(TDS_DBG_FUNC, "blk_sendtext(%p, %p, %p, %d)\n", blkdesc, row, buffer, buflen);
480 :
481 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendtext()\n");
482 0 : return CS_FAIL;
483 : }
484 :
485 : CS_RETCODE
486 0 : blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
487 : {
488 0 : tdsdump_log(TDS_DBG_FUNC, "blk_srvinit(%p, %p)\n", srvproc, blkdescp);
489 :
490 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_srvinit()\n");
491 0 : return CS_FAIL;
492 : }
493 :
494 : CS_RETCODE
495 0 : blk_textxfer(CS_BLKDESC * blkdesc, CS_BYTE * buffer, CS_INT buflen, CS_INT * outlen)
496 : {
497 0 : tdsdump_log(TDS_DBG_FUNC, "blk_textxfer(%p, %p, %d, %p)\n", blkdesc, buffer, buflen, outlen);
498 :
499 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_textxfer()\n");
500 0 : return CS_FAIL;
501 : }
502 :
503 : static CS_RETCODE
504 24 : _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
505 : {
506 : TDSSOCKET *tds;
507 : TDS_INT result_type;
508 : TDSRET ret;
509 : TDS_INT temp_count;
510 :
511 24 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
512 :
513 24 : if (!blkdesc || !CONN(blkdesc))
514 : return CS_FAIL;
515 :
516 24 : tds = CONN(blkdesc)->tds_socket;
517 :
518 : /*
519 : * the first time blk_xfer called after blk_init()
520 : * do the query and get to the row data...
521 : */
522 :
523 24 : if (blkdesc->bcpinfo.xfer_init == 0) {
524 :
525 16 : if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&blkdesc->bcpinfo.tablename)))) {
526 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
527 0 : return CS_FAIL;
528 : }
529 :
530 16 : while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
531 16 : if (result_type == TDS_ROW_RESULT)
532 : break;
533 : }
534 :
535 8 : if (ret != TDS_SUCCESS || result_type != TDS_ROW_RESULT) {
536 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
537 0 : return CS_FAIL;
538 : }
539 :
540 8 : blkdesc->bcpinfo.xfer_init = 1;
541 : }
542 :
543 24 : if (rows_xferred)
544 24 : *rows_xferred = 0;
545 :
546 40 : for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
547 :
548 48 : ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
549 :
550 48 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
551 :
552 48 : switch (ret) {
553 48 : case TDS_SUCCESS:
554 48 : if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
555 40 : if (result_type == TDS_ROW_RESULT) {
556 40 : if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
557 : return CS_ROW_FAIL;
558 40 : if (rows_xferred)
559 40 : *rows_xferred = *rows_xferred + 1;
560 : }
561 : break;
562 : }
563 : case TDS_NO_MORE_RESULTS:
564 : return CS_END_DATA;
565 : break;
566 :
567 0 : default:
568 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
569 0 : return CS_FAIL;
570 : break;
571 : }
572 : }
573 :
574 : return CS_SUCCEED;
575 : }
576 :
577 : static CS_RETCODE
578 160 : _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
579 : {
580 : TDSSOCKET *tds;
581 : TDS_INT each_row;
582 :
583 160 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
584 :
585 160 : if (!blkdesc)
586 : return CS_FAIL;
587 :
588 160 : tds = CONN(blkdesc)->tds_socket;
589 :
590 : /*
591 : * the first time blk_xfer called after blk_init()
592 : * do the query and get to the row data...
593 : */
594 :
595 160 : if (blkdesc->bcpinfo.xfer_init == 0) {
596 :
597 : /*
598 : * first call the start_copy function, which will
599 : * retrieve details of the database table columns
600 : */
601 :
602 88 : if (TDS_FAILED(tds_bcp_start_copy_in(tds, &blkdesc->bcpinfo))) {
603 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
604 0 : return CS_FAIL;
605 : }
606 :
607 88 : blkdesc->bcpinfo.xfer_init = 1;
608 : }
609 :
610 160 : for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {
611 :
612 160 : if (tds_bcp_send_record(tds, &blkdesc->bcpinfo, _blk_get_col_data, _blk_null_error, each_row) == TDS_SUCCESS) {
613 : /* FIXME */
614 : }
615 : }
616 :
617 : return CS_SUCCEED;
618 : }
619 :
620 : static void
621 0 : _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset)
622 : {
623 0 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bcpinfo;
624 :
625 0 : tdsdump_log(TDS_DBG_FUNC, "_blk_null_error(%p, %d, %d)\n", bcpinfo, index, offset);
626 :
627 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 7, 1, 142, "%d, %d", index + 1, offset + 1);
628 0 : }
629 :
630 : static TDSRET
631 2240 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
632 : {
633 2240 : int result = 0;
634 2240 : bool null_column = false;
635 2240 : unsigned char *src = NULL;
636 :
637 2240 : CS_INT srctype = 0;
638 2240 : CS_INT srclen = 0;
639 2240 : CS_INT destlen = 0;
640 2240 : CS_SMALLINT *nullind = NULL;
641 2240 : CS_INT *datalen = NULL;
642 2240 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
643 2240 : CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
644 :
645 2240 : tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
646 :
647 : /*
648 : * Retrieve the initial bound column_varaddress
649 : * and increment it if offset specified
650 : */
651 :
652 2240 : src = (unsigned char *) bindcol->column_varaddr;
653 2240 : if (!src) {
654 0 : tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
655 : return TDS_FAIL;
656 : }
657 :
658 2240 : src += offset * bindcol->column_bindlen;
659 :
660 2240 : if (bindcol->column_nullbind) {
661 2160 : nullind = bindcol->column_nullbind;
662 2160 : nullind += offset;
663 : }
664 2240 : if (bindcol->column_lenbind) {
665 2240 : datalen = bindcol->column_lenbind;
666 2240 : datalen += offset;
667 : }
668 :
669 2240 : srctype = bindcol->column_bindtype; /* passes to cs_convert */
670 :
671 2240 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
672 2240 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
673 :
674 2240 : if (datalen) {
675 2240 : if (*datalen == CS_UNUSED) {
676 0 : switch (srctype) {
677 : case CS_LONG_TYPE: srclen = 8; break;
678 : case CS_FLOAT_TYPE: srclen = 8; break;
679 : case CS_MONEY_TYPE: srclen = 8; break;
680 : case CS_DATETIME_TYPE: srclen = 8; break;
681 0 : case CS_INT_TYPE: srclen = 4; break;
682 0 : case CS_UINT_TYPE: srclen = 4; break;
683 0 : case CS_REAL_TYPE: srclen = 4; break;
684 0 : case CS_MONEY4_TYPE: srclen = 4; break;
685 0 : case CS_DATETIME4_TYPE: srclen = 4; break;
686 0 : case CS_SMALLINT_TYPE: srclen = 2; break;
687 0 : case CS_USMALLINT_TYPE: srclen = 2; break;
688 0 : case CS_TINYINT_TYPE: srclen = 1; break;
689 0 : case CS_BIT_TYPE: srclen = 1; break;
690 : case CS_BIGINT_TYPE: srclen = 8; break;
691 : case CS_UBIGINT_TYPE: srclen = 8; break;
692 0 : case CS_UNIQUE_TYPE: srclen = 16; break;
693 0 : default:
694 0 : printf("error not fixed length type (%d) and datalen not specified\n",
695 0 : bindcol->column_bindtype);
696 0 : return TDS_FAIL;
697 : }
698 :
699 : } else {
700 2240 : srclen = *datalen;
701 : }
702 : }
703 2240 : if (srclen == 0) {
704 1040 : if (nullind && *nullind == -1)
705 : null_column = true;
706 : }
707 :
708 : if (!null_column) {
709 : CONV_RESULT convert_buffer;
710 : CS_DATAFMT_COMMON srcfmt, destfmt;
711 : CS_INT desttype;
712 :
713 1200 : srcfmt.datatype = srctype;
714 1200 : srcfmt.maxlength = srclen;
715 :
716 1200 : desttype = _cs_convert_not_client(ctx, bindcol, &convert_buffer, &src);
717 1200 : if (desttype == CS_ILLEGAL_TYPE)
718 1200 : desttype = _ct_get_client_type(bindcol, false);
719 1200 : if (desttype == CS_ILLEGAL_TYPE)
720 0 : return TDS_FAIL;
721 1200 : destfmt.datatype = desttype;
722 1200 : destfmt.maxlength = bindcol->on_server.column_size;
723 1200 : destfmt.precision = bindcol->column_prec;
724 1200 : destfmt.scale = bindcol->column_scale;
725 1200 : destfmt.format = CS_FMT_UNUSED;
726 :
727 : /* if convert return FAIL mark error but process other columns */
728 1200 : if ((result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
729 1200 : &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen)) != CS_SUCCEED) {
730 0 : tdsdump_log(TDS_DBG_INFO1, "convert failed for %d \n", srctype);
731 : return TDS_FAIL;
732 : }
733 : }
734 :
735 2240 : bindcol->bcp_column_data->datalen = destlen;
736 2240 : bindcol->bcp_column_data->is_null = null_column;
737 :
738 2240 : return TDS_SUCCESS;
739 : }
|