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 50 : blk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer)
53 : {
54 : CS_BLKDESC *blkdesc;
55 :
56 50 : tdsdump_log(TDS_DBG_FUNC, "blk_alloc(%p, %d, %p)\n", connection, version, blk_pointer);
57 :
58 50 : if (!connection || !connection->tds_socket)
59 : return CS_FAIL;
60 :
61 50 : if (connection->tds_socket->conn->tds_version < 0x500)
62 : return CS_FAIL;
63 :
64 50 : blkdesc = (CS_BLKDESC *) tds_alloc_bcpinfo();
65 50 : if (!blkdesc)
66 : return CS_FAIL;
67 :
68 : /* so we know who we belong to */
69 50 : blkdesc->bcpinfo.parent = connection;
70 :
71 50 : *blk_pointer = blkdesc;
72 50 : return CS_SUCCEED;
73 : }
74 :
75 :
76 : CS_RETCODE
77 410 : 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 410 : tdsdump_log(TDS_DBG_FUNC, "blk_bind(%p, %d, %p, %p, %p, %p)\n", blkdesc, item, datafmt_arg, buffer, datalen, indicator);
86 :
87 410 : if (!blkdesc)
88 : return CS_FAIL;
89 :
90 410 : con = CONN(blkdesc);
91 :
92 410 : datafmt = _ct_datafmt_common(con->ctx, datafmt_arg);
93 :
94 410 : 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 410 : if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
114 0 : _ctclient_msg(NULL, 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 410 : 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 410 : 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 410 : bind_count = (datafmt->count == 0) ? 1 : datafmt->count;
142 :
143 : /* first bind for this result set */
144 :
145 410 : if (blkdesc->bcpinfo.bind_count == CS_UNUSED) {
146 130 : blkdesc->bcpinfo.bind_count = bind_count;
147 : } else {
148 : /* all subsequent binds for this result set - the bind counts must be the same */
149 280 : if (blkdesc->bcpinfo.bind_count != bind_count) {
150 0 : _ctclient_msg(NULL, 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 410 : colinfo = blkdesc->bcpinfo.bindinfo->columns[item - 1];
158 :
159 410 : colinfo->column_varaddr = (char *) buffer;
160 410 : colinfo->column_bindtype = datafmt->datatype;
161 410 : colinfo->column_bindfmt = datafmt->format;
162 410 : colinfo->column_bindlen = datafmt->maxlength;
163 410 : if (indicator) {
164 310 : colinfo->column_nullbind = indicator;
165 : }
166 410 : if (datalen) {
167 410 : 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 310 : 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 310 : tdsdump_log(TDS_DBG_FUNC, "blk_describe(%p, %d, %p)\n", blkdesc, item, datafmt_arg);
203 :
204 310 : if (!blkdesc)
205 : return CS_FAIL;
206 :
207 310 : datafmt = _ct_datafmt_conv_prepare(CONN(blkdesc)->ctx, datafmt_arg, &datafmt_buf);
208 :
209 310 : if (item < 1 || item > blkdesc->bcpinfo.bindinfo->num_cols) {
210 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_describe", 2, 5, 1, 141, "%s, %d", "colnum", item);
211 0 : return CS_FAIL;
212 : }
213 :
214 310 : curcol = blkdesc->bcpinfo.bindinfo->columns[item - 1];
215 : /* name is always null terminated */
216 620 : strlcpy(datafmt->name, tds_dstr_cstr(&curcol->column_name), sizeof(datafmt->name));
217 310 : datafmt->namelen = (CS_INT) strlen(datafmt->name);
218 : /* need to turn the SYBxxx into a CS_xxx_TYPE */
219 310 : datatype = _ct_get_client_type(curcol, true);
220 310 : if (datatype == CS_ILLEGAL_TYPE)
221 : return CS_FAIL;
222 310 : datafmt->datatype = datatype;
223 310 : 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 310 : datafmt->maxlength = curcol->column_size;
227 310 : datafmt->usertype = curcol->column_usertype;
228 310 : datafmt->precision = curcol->column_prec;
229 310 : 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 310 : status = 0;
236 310 : if (curcol->column_nullable)
237 140 : status |= CS_CANBENULL;
238 310 : if (curcol->column_identity)
239 0 : status |= CS_IDENTITY;
240 310 : datafmt->status = status;
241 :
242 310 : datafmt->count = 1;
243 310 : datafmt->locale = NULL;
244 :
245 310 : _ct_datafmt_conv_back(datafmt_arg, datafmt);
246 310 : return CS_SUCCEED;
247 : }
248 :
249 : CS_RETCODE
250 120 : blk_done(CS_BLKDESC * blkdesc, CS_INT type, CS_INT * outrow)
251 : {
252 : TDSSOCKET *tds;
253 : int rows_copied;
254 :
255 120 : tdsdump_log(TDS_DBG_FUNC, "blk_done(%p, %d, %p)\n", blkdesc, type, outrow);
256 :
257 120 : tds = CONN(blkdesc)->tds_socket;
258 :
259 120 : switch (type) {
260 0 : case CS_BLK_BATCH:
261 0 : if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
262 0 : _ctclient_msg(NULL, 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(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
271 0 : return CS_FAIL;
272 : }
273 : break;
274 :
275 120 : case CS_BLK_ALL:
276 120 : if (TDS_FAILED(tds_bcp_done(tds, &rows_copied))) {
277 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_done", 2, 5, 1, 140, "");
278 0 : return CS_FAIL;
279 : }
280 :
281 120 : if (outrow)
282 120 : *outrow = rows_copied;
283 :
284 : /* free allocated storage in blkdesc & initialise flags, etc. */
285 120 : tds_deinit_bcpinfo(&blkdesc->bcpinfo);
286 :
287 120 : blkdesc->bcpinfo.direction = 0;
288 120 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
289 120 : blkdesc->bcpinfo.xfer_init = false;
290 :
291 120 : break;
292 :
293 : }
294 :
295 : return CS_SUCCEED;
296 : }
297 :
298 : CS_RETCODE
299 50 : blk_drop(CS_BLKDESC * blkdesc)
300 : {
301 50 : tdsdump_log(TDS_DBG_FUNC, "blk_drop(%p)\n", blkdesc);
302 :
303 : /* this is possible as CS_BLKDESC contains just bcpinfo field */
304 50 : tds_free_bcpinfo(&blkdesc->bcpinfo);
305 :
306 50 : 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 160 : blk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen)
330 : {
331 160 : tdsdump_log(TDS_DBG_FUNC, "blk_init(%p, %d, %p, %d)\n", blkdesc, direction, tablename, tnamelen);
332 :
333 160 : if (!blkdesc) {
334 : return CS_FAIL;
335 : }
336 :
337 160 : if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) {
338 10 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 15, "");
339 10 : return CS_FAIL;
340 : }
341 :
342 150 : if (!tablename) {
343 10 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 6, "tblname");
344 10 : return CS_FAIL;
345 : }
346 140 : tnamelen = _ct_get_string_length(tablename, tnamelen);
347 140 : if (tnamelen < 0) {
348 10 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 4, "tblnamelen, %d", tnamelen);
349 10 : return CS_FAIL;
350 : }
351 :
352 : /* free allocated storage in blkdesc & initialise flags, etc. */
353 130 : tds_deinit_bcpinfo(&blkdesc->bcpinfo);
354 :
355 : /* string can be no-nul terminated so copy with memcpy */
356 130 : if (!tds_dstr_copyn(&blkdesc->bcpinfo.tablename, tablename, tnamelen)) {
357 : return CS_FAIL;
358 : }
359 :
360 130 : blkdesc->bcpinfo.direction = direction;
361 130 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
362 130 : blkdesc->bcpinfo.xfer_init = false;
363 :
364 130 : if (TDS_FAILED(tds_bcp_init(CONN(blkdesc)->tds_socket, &blkdesc->bcpinfo))) {
365 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 2, 5, 1, 140, "");
366 0 : return CS_FAIL;
367 : }
368 130 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
369 :
370 130 : return CS_SUCCEED;
371 : }
372 :
373 : CS_RETCODE
374 100 : blk_props(CS_BLKDESC * blkdesc, CS_INT action, CS_INT property, CS_VOID * buffer, CS_INT buflen, CS_INT * outlen)
375 : {
376 : int retval, intval;
377 :
378 100 : tdsdump_log(TDS_DBG_FUNC, "blk_props(%p, %d, %d, %p, %d, %p)\n", blkdesc, action, property, buffer, buflen, outlen);
379 :
380 100 : switch (property) {
381 0 : case BLK_IDENTITY:
382 0 : switch (action) {
383 0 : case CS_SET:
384 0 : if (buffer) {
385 0 : memcpy(&intval, buffer, sizeof(intval));
386 0 : if (intval == CS_TRUE)
387 0 : blkdesc->bcpinfo.identity_insert_on = true;
388 0 : if (intval == CS_FALSE)
389 0 : blkdesc->bcpinfo.identity_insert_on = false;
390 : }
391 : return CS_SUCCEED;
392 : break;
393 0 : case CS_GET:
394 0 : retval = blkdesc->bcpinfo.identity_insert_on ? CS_TRUE : CS_FALSE ;
395 0 : if (buffer) {
396 0 : memcpy (buffer, &retval, sizeof(retval));
397 0 : if (outlen)
398 0 : *outlen = sizeof(retval);
399 : }
400 : return CS_SUCCEED;
401 : break;
402 0 : default:
403 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "action", action);
404 : break;
405 : }
406 0 : break;
407 :
408 100 : case BLK_HINTS:
409 100 : return _ct_props_dstr(CONN(blkdesc), &blkdesc->bcpinfo.hint, action, buffer, buflen, outlen);
410 :
411 0 : default:
412 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "property", property);
413 0 : break;
414 : }
415 : return CS_FAIL;
416 : }
417 :
418 : CS_RETCODE
419 0 : blk_rowalloc(SRV_PROC * srvproc, CS_BLK_ROW ** row)
420 : {
421 0 : tdsdump_log(TDS_DBG_FUNC, "blk_rowalloc(%p, %p)\n", srvproc, row);
422 :
423 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowalloc()\n");
424 0 : return CS_FAIL;
425 : }
426 :
427 : CS_RETCODE
428 0 : blk_rowdrop(SRV_PROC * srvproc, CS_BLK_ROW * row)
429 : {
430 0 : tdsdump_log(TDS_DBG_FUNC, "blk_rowdrop(%p, %p)\n", srvproc, row);
431 :
432 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowdrop()\n");
433 0 : return CS_FAIL;
434 : }
435 :
436 : CS_RETCODE
437 300 : blk_rowxfer(CS_BLKDESC * blkdesc)
438 : {
439 300 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
440 :
441 300 : return blk_rowxfer_mult(blkdesc, NULL);
442 : }
443 :
444 : CS_RETCODE
445 330 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
446 : {
447 330 : CS_INT rows_to_xfer = 0;
448 330 : CS_INT rows_xferred = 0;
449 : CS_RETCODE ret;
450 :
451 330 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
452 :
453 330 : if (!row_count || *row_count == 0 )
454 310 : rows_to_xfer = blkdesc->bcpinfo.bind_count;
455 : else
456 : rows_to_xfer = *row_count;
457 :
458 330 : if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
459 300 : ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
460 : } else {
461 30 : ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
462 : }
463 330 : if (row_count)
464 30 : *row_count = rows_xferred;
465 330 : return ret;
466 :
467 : }
468 :
469 : CS_RETCODE
470 0 : blk_sendrow(CS_BLKDESC * blkdesc, CS_BLK_ROW * row)
471 : {
472 :
473 0 : tdsdump_log(TDS_DBG_FUNC, "blk_sendrow(%p, %p)\n", blkdesc, row);
474 :
475 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendrow()\n");
476 0 : return CS_FAIL;
477 : }
478 :
479 : CS_RETCODE
480 0 : blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT buflen)
481 : {
482 0 : tdsdump_log(TDS_DBG_FUNC, "blk_sendtext(%p, %p, %p, %d)\n", blkdesc, row, buffer, buflen);
483 :
484 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendtext()\n");
485 0 : return CS_FAIL;
486 : }
487 :
488 : CS_RETCODE
489 0 : blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
490 : {
491 0 : tdsdump_log(TDS_DBG_FUNC, "blk_srvinit(%p, %p)\n", srvproc, blkdescp);
492 :
493 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_srvinit()\n");
494 0 : return CS_FAIL;
495 : }
496 :
497 : CS_RETCODE
498 0 : blk_textxfer(CS_BLKDESC * blkdesc, CS_BYTE * buffer, CS_INT buflen, CS_INT * outlen)
499 : {
500 0 : tdsdump_log(TDS_DBG_FUNC, "blk_textxfer(%p, %p, %d, %p)\n", blkdesc, buffer, buflen, outlen);
501 :
502 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_textxfer()\n");
503 0 : return CS_FAIL;
504 : }
505 :
506 : static CS_RETCODE
507 30 : _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
508 : {
509 : TDSSOCKET *tds;
510 : TDS_INT result_type;
511 : TDSRET ret;
512 : TDS_INT temp_count;
513 :
514 30 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
515 :
516 30 : if (!blkdesc || !CONN(blkdesc))
517 : return CS_FAIL;
518 :
519 30 : tds = CONN(blkdesc)->tds_socket;
520 :
521 : /*
522 : * the first time blk_xfer called after blk_init()
523 : * do the query and get to the row data...
524 : */
525 :
526 30 : if (!blkdesc->bcpinfo.xfer_init) {
527 :
528 20 : if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&blkdesc->bcpinfo.tablename)))) {
529 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
530 0 : return CS_FAIL;
531 : }
532 :
533 20 : while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
534 20 : if (result_type == TDS_ROW_RESULT)
535 : break;
536 : }
537 :
538 10 : if (ret != TDS_SUCCESS || result_type != TDS_ROW_RESULT) {
539 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
540 0 : return CS_FAIL;
541 : }
542 :
543 10 : blkdesc->bcpinfo.xfer_init = true;
544 : }
545 :
546 30 : if (rows_xferred)
547 30 : *rows_xferred = 0;
548 :
549 50 : for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
550 :
551 60 : ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
552 :
553 60 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
554 :
555 60 : switch (ret) {
556 60 : case TDS_SUCCESS:
557 60 : if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
558 50 : if (result_type == TDS_ROW_RESULT) {
559 50 : if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
560 : return CS_ROW_FAIL;
561 50 : if (rows_xferred)
562 50 : *rows_xferred = *rows_xferred + 1;
563 : }
564 : break;
565 : }
566 : case TDS_NO_MORE_RESULTS:
567 : return CS_END_DATA;
568 : break;
569 :
570 0 : default:
571 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
572 0 : return CS_FAIL;
573 : break;
574 : }
575 : }
576 :
577 : return CS_SUCCEED;
578 : }
579 :
580 : static CS_RETCODE
581 300 : _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
582 : {
583 : TDSSOCKET *tds;
584 : TDS_INT each_row;
585 :
586 300 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
587 :
588 300 : if (!blkdesc)
589 : return CS_FAIL;
590 :
591 300 : tds = CONN(blkdesc)->tds_socket;
592 :
593 : /*
594 : * the first time blk_xfer called after blk_init()
595 : * do the query and get to the row data...
596 : */
597 :
598 300 : if (!blkdesc->bcpinfo.xfer_init) {
599 :
600 : /*
601 : * first call the start_copy function, which will
602 : * retrieve details of the database table columns
603 : */
604 :
605 120 : if (TDS_FAILED(tds_bcp_start_copy_in(tds, &blkdesc->bcpinfo))) {
606 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
607 0 : return CS_FAIL;
608 : }
609 :
610 120 : blkdesc->bcpinfo.xfer_init = true;
611 : }
612 :
613 300 : for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {
614 :
615 300 : if (tds_bcp_send_record(tds, &blkdesc->bcpinfo, _blk_get_col_data, _blk_null_error, each_row) == TDS_SUCCESS) {
616 : /* FIXME */
617 : }
618 : }
619 :
620 : return CS_SUCCEED;
621 : }
622 :
623 : static void
624 0 : _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset)
625 : {
626 0 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bcpinfo;
627 :
628 0 : tdsdump_log(TDS_DBG_FUNC, "_blk_null_error(%p, %d, %d)\n", bcpinfo, index, offset);
629 :
630 0 : _ctclient_msg(NULL, CONN(blkdesc), "blk_rowxfer", 2, 7, 1, 142, "%d, %d", index + 1, offset + 1);
631 0 : }
632 :
633 : static TDSRET
634 2900 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
635 : {
636 2900 : int result = 0;
637 2900 : bool null_column = false;
638 2900 : unsigned char *src = NULL;
639 :
640 2900 : CS_INT srctype = 0;
641 2900 : CS_INT srclen = 0;
642 2900 : CS_INT destlen = 0;
643 2900 : CS_SMALLINT *nullind = NULL;
644 2900 : CS_INT *datalen = NULL;
645 2900 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
646 2900 : CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
647 :
648 2900 : tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
649 :
650 : /*
651 : * Retrieve the initial bound column_varaddress
652 : * and increment it if offset specified
653 : */
654 :
655 2900 : src = (unsigned char *) bindcol->column_varaddr;
656 2900 : if (!src) {
657 0 : tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
658 : return TDS_FAIL;
659 : }
660 :
661 2900 : src += offset * bindcol->column_bindlen;
662 :
663 2900 : if (bindcol->column_nullbind) {
664 2800 : nullind = bindcol->column_nullbind;
665 2800 : nullind += offset;
666 : }
667 2900 : if (bindcol->column_lenbind) {
668 2900 : datalen = bindcol->column_lenbind;
669 2900 : datalen += offset;
670 : }
671 :
672 2900 : srctype = bindcol->column_bindtype; /* passes to cs_convert */
673 :
674 2900 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
675 2900 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
676 :
677 2900 : if (datalen) {
678 2900 : if (*datalen == CS_UNUSED) {
679 0 : switch (srctype) {
680 : case CS_LONG_TYPE: srclen = 8; break;
681 : case CS_FLOAT_TYPE: srclen = 8; break;
682 : case CS_MONEY_TYPE: srclen = 8; break;
683 : case CS_DATETIME_TYPE: srclen = 8; break;
684 0 : case CS_INT_TYPE: srclen = 4; break;
685 0 : case CS_UINT_TYPE: srclen = 4; break;
686 0 : case CS_REAL_TYPE: srclen = 4; break;
687 0 : case CS_MONEY4_TYPE: srclen = 4; break;
688 0 : case CS_DATETIME4_TYPE: srclen = 4; break;
689 0 : case CS_SMALLINT_TYPE: srclen = 2; break;
690 0 : case CS_USMALLINT_TYPE: srclen = 2; break;
691 0 : case CS_TINYINT_TYPE: srclen = 1; break;
692 0 : case CS_BIT_TYPE: srclen = 1; break;
693 : case CS_BIGINT_TYPE: srclen = 8; break;
694 : case CS_UBIGINT_TYPE: srclen = 8; break;
695 0 : case CS_UNIQUE_TYPE: srclen = 16; break;
696 0 : default:
697 0 : tdsdump_log(TDS_DBG_ERROR, "Not fixed length type (%d) and datalen not specified\n",
698 0 : bindcol->column_bindtype);
699 : return TDS_FAIL;
700 : }
701 :
702 : } else {
703 2900 : srclen = *datalen;
704 : }
705 : }
706 2900 : if (srclen == 0) {
707 1300 : if (nullind && *nullind == -1)
708 : null_column = true;
709 : }
710 :
711 : if (!null_column) {
712 : CS_DATAFMT_COMMON srcfmt, destfmt;
713 : CS_INT desttype;
714 1600 : TDS_SERVER_TYPE tds_desttype = TDS_INVALID_TYPE;
715 :
716 1600 : srcfmt.datatype = srctype;
717 1600 : srcfmt.maxlength = srclen;
718 :
719 1600 : desttype = _cs_convert_not_client(NULL, bindcol, NULL, NULL);
720 1600 : if (desttype == CS_ILLEGAL_TYPE)
721 1600 : desttype = _ct_get_client_type(bindcol, false);
722 : else
723 0 : tds_desttype = bindcol->column_type;
724 1600 : if (desttype == CS_ILLEGAL_TYPE)
725 0 : return TDS_FAIL;
726 :
727 1600 : destfmt.datatype = desttype;
728 1600 : destfmt.maxlength = bindcol->on_server.column_size;
729 1600 : destfmt.precision = bindcol->column_prec;
730 1600 : destfmt.scale = bindcol->column_scale;
731 1600 : destfmt.format = CS_FMT_UNUSED;
732 :
733 : /* if convert return FAIL mark error but process other columns */
734 1600 : result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
735 1600 : &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen, tds_desttype);
736 1600 : if (result != CS_SUCCEED) {
737 0 : tdsdump_log(TDS_DBG_ERROR, "conversion from srctype %d to desttype %d failed\n",
738 : srctype, desttype);
739 : return TDS_FAIL;
740 : }
741 : }
742 :
743 2900 : bindcol->bcp_column_data->datalen = destlen;
744 2900 : bindcol->bcp_column_data->is_null = null_column;
745 :
746 2900 : return TDS_SUCCESS;
747 : }
|