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 : default:
406 0 : _ctclient_msg(CONN(blkdesc), "blk_props", 2, 5, 1, 141, "%s, %d", "property", property);
407 0 : break;
408 : }
409 : return CS_FAIL;
410 : }
411 :
412 : CS_RETCODE
413 0 : blk_rowalloc(SRV_PROC * srvproc, CS_BLK_ROW ** row)
414 : {
415 0 : tdsdump_log(TDS_DBG_FUNC, "blk_rowalloc(%p, %p)\n", srvproc, row);
416 :
417 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowalloc()\n");
418 0 : return CS_FAIL;
419 : }
420 :
421 : CS_RETCODE
422 0 : blk_rowdrop(SRV_PROC * srvproc, CS_BLK_ROW * row)
423 : {
424 0 : tdsdump_log(TDS_DBG_FUNC, "blk_rowdrop(%p, %p)\n", srvproc, row);
425 :
426 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_rowdrop()\n");
427 0 : return CS_FAIL;
428 : }
429 :
430 : CS_RETCODE
431 160 : blk_rowxfer(CS_BLKDESC * blkdesc)
432 : {
433 160 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
434 :
435 160 : return blk_rowxfer_mult(blkdesc, NULL);
436 : }
437 :
438 : CS_RETCODE
439 184 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
440 : {
441 184 : CS_INT rows_to_xfer = 0;
442 184 : CS_INT rows_xferred = 0;
443 : CS_RETCODE ret;
444 :
445 184 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
446 :
447 184 : if (!row_count || *row_count == 0 )
448 168 : rows_to_xfer = blkdesc->bcpinfo.bind_count;
449 : else
450 : rows_to_xfer = *row_count;
451 :
452 184 : if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
453 160 : ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
454 : } else {
455 24 : ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
456 : }
457 184 : if (row_count)
458 24 : *row_count = rows_xferred;
459 184 : return ret;
460 :
461 : }
462 :
463 : CS_RETCODE
464 0 : blk_sendrow(CS_BLKDESC * blkdesc, CS_BLK_ROW * row)
465 : {
466 :
467 0 : tdsdump_log(TDS_DBG_FUNC, "blk_sendrow(%p, %p)\n", blkdesc, row);
468 :
469 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendrow()\n");
470 0 : return CS_FAIL;
471 : }
472 :
473 : CS_RETCODE
474 0 : blk_sendtext(CS_BLKDESC * blkdesc, CS_BLK_ROW * row, CS_BYTE * buffer, CS_INT buflen)
475 : {
476 0 : tdsdump_log(TDS_DBG_FUNC, "blk_sendtext(%p, %p, %p, %d)\n", blkdesc, row, buffer, buflen);
477 :
478 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_sendtext()\n");
479 0 : return CS_FAIL;
480 : }
481 :
482 : CS_RETCODE
483 0 : blk_srvinit(SRV_PROC * srvproc, CS_BLKDESC * blkdescp)
484 : {
485 0 : tdsdump_log(TDS_DBG_FUNC, "blk_srvinit(%p, %p)\n", srvproc, blkdescp);
486 :
487 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_srvinit()\n");
488 0 : return CS_FAIL;
489 : }
490 :
491 : CS_RETCODE
492 0 : blk_textxfer(CS_BLKDESC * blkdesc, CS_BYTE * buffer, CS_INT buflen, CS_INT * outlen)
493 : {
494 0 : tdsdump_log(TDS_DBG_FUNC, "blk_textxfer(%p, %p, %d, %p)\n", blkdesc, buffer, buflen, outlen);
495 :
496 0 : tdsdump_log(TDS_DBG_FUNC, "UNIMPLEMENTED blk_textxfer()\n");
497 0 : return CS_FAIL;
498 : }
499 :
500 : static CS_RETCODE
501 24 : _blk_rowxfer_out(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
502 : {
503 : TDSSOCKET *tds;
504 : TDS_INT result_type;
505 : TDSRET ret;
506 : TDS_INT temp_count;
507 :
508 24 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
509 :
510 24 : if (!blkdesc || !CONN(blkdesc))
511 : return CS_FAIL;
512 :
513 24 : tds = CONN(blkdesc)->tds_socket;
514 :
515 : /*
516 : * the first time blk_xfer called after blk_init()
517 : * do the query and get to the row data...
518 : */
519 :
520 24 : if (blkdesc->bcpinfo.xfer_init == 0) {
521 :
522 16 : if (TDS_FAILED(tds_submit_queryf(tds, "select * from %s", tds_dstr_cstr(&blkdesc->bcpinfo.tablename)))) {
523 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
524 0 : return CS_FAIL;
525 : }
526 :
527 16 : while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
528 16 : if (result_type == TDS_ROW_RESULT)
529 : break;
530 : }
531 :
532 8 : if (ret != TDS_SUCCESS || result_type != TDS_ROW_RESULT) {
533 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
534 0 : return CS_FAIL;
535 : }
536 :
537 8 : blkdesc->bcpinfo.xfer_init = 1;
538 : }
539 :
540 24 : if (rows_xferred)
541 24 : *rows_xferred = 0;
542 :
543 40 : for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
544 :
545 48 : ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
546 :
547 48 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
548 :
549 48 : switch (ret) {
550 48 : case TDS_SUCCESS:
551 48 : if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
552 40 : if (result_type == TDS_ROW_RESULT) {
553 40 : if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
554 : return CS_ROW_FAIL;
555 40 : if (rows_xferred)
556 40 : *rows_xferred = *rows_xferred + 1;
557 : }
558 : break;
559 : }
560 : case TDS_NO_MORE_RESULTS:
561 : return CS_END_DATA;
562 : break;
563 :
564 0 : default:
565 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
566 0 : return CS_FAIL;
567 : break;
568 : }
569 : }
570 :
571 : return CS_SUCCEED;
572 : }
573 :
574 : static CS_RETCODE
575 160 : _blk_rowxfer_in(CS_BLKDESC * blkdesc, CS_INT rows_to_xfer, CS_INT * rows_xferred)
576 : {
577 : TDSSOCKET *tds;
578 : TDS_INT each_row;
579 :
580 160 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
581 :
582 160 : if (!blkdesc)
583 : return CS_FAIL;
584 :
585 160 : tds = CONN(blkdesc)->tds_socket;
586 :
587 : /*
588 : * the first time blk_xfer called after blk_init()
589 : * do the query and get to the row data...
590 : */
591 :
592 160 : if (blkdesc->bcpinfo.xfer_init == 0) {
593 :
594 : /*
595 : * first call the start_copy function, which will
596 : * retrieve details of the database table columns
597 : */
598 :
599 88 : if (TDS_FAILED(tds_bcp_start_copy_in(tds, &blkdesc->bcpinfo))) {
600 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 5, 1, 140, "");
601 0 : return CS_FAIL;
602 : }
603 :
604 88 : blkdesc->bcpinfo.xfer_init = 1;
605 : }
606 :
607 160 : for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {
608 :
609 160 : if (tds_bcp_send_record(tds, &blkdesc->bcpinfo, _blk_get_col_data, _blk_null_error, each_row) == TDS_SUCCESS) {
610 : /* FIXME */
611 : }
612 : }
613 :
614 : return CS_SUCCEED;
615 : }
616 :
617 : static void
618 0 : _blk_null_error(TDSBCPINFO *bcpinfo, int index, int offset)
619 : {
620 0 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bcpinfo;
621 :
622 0 : tdsdump_log(TDS_DBG_FUNC, "_blk_null_error(%p, %d, %d)\n", bcpinfo, index, offset);
623 :
624 0 : _ctclient_msg(CONN(blkdesc), "blk_rowxfer", 2, 7, 1, 142, "%d, %d", index + 1, offset + 1);
625 0 : }
626 :
627 : static TDSRET
628 2240 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
629 : {
630 2240 : int result = 0;
631 2240 : bool null_column = false;
632 2240 : unsigned char *src = NULL;
633 :
634 2240 : CS_INT srctype = 0;
635 2240 : CS_INT srclen = 0;
636 2240 : CS_INT destlen = 0;
637 2240 : CS_SMALLINT *nullind = NULL;
638 2240 : CS_INT *datalen = NULL;
639 2240 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
640 2240 : CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
641 :
642 2240 : tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
643 :
644 : /*
645 : * Retrieve the initial bound column_varaddress
646 : * and increment it if offset specified
647 : */
648 :
649 2240 : src = (unsigned char *) bindcol->column_varaddr;
650 2240 : if (!src) {
651 0 : tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
652 : return TDS_FAIL;
653 : }
654 :
655 2240 : src += offset * bindcol->column_bindlen;
656 :
657 2240 : if (bindcol->column_nullbind) {
658 2160 : nullind = bindcol->column_nullbind;
659 2160 : nullind += offset;
660 : }
661 2240 : if (bindcol->column_lenbind) {
662 2240 : datalen = bindcol->column_lenbind;
663 2240 : datalen += offset;
664 : }
665 :
666 2240 : srctype = bindcol->column_bindtype; /* passes to cs_convert */
667 :
668 2240 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
669 2240 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
670 :
671 2240 : if (datalen) {
672 2240 : if (*datalen == CS_UNUSED) {
673 0 : switch (srctype) {
674 : case CS_LONG_TYPE: srclen = 8; break;
675 : case CS_FLOAT_TYPE: srclen = 8; break;
676 : case CS_MONEY_TYPE: srclen = 8; break;
677 : case CS_DATETIME_TYPE: srclen = 8; break;
678 0 : case CS_INT_TYPE: srclen = 4; break;
679 0 : case CS_UINT_TYPE: srclen = 4; break;
680 0 : case CS_REAL_TYPE: srclen = 4; break;
681 0 : case CS_MONEY4_TYPE: srclen = 4; break;
682 0 : case CS_DATETIME4_TYPE: srclen = 4; break;
683 0 : case CS_SMALLINT_TYPE: srclen = 2; break;
684 0 : case CS_USMALLINT_TYPE: srclen = 2; break;
685 0 : case CS_TINYINT_TYPE: srclen = 1; break;
686 0 : case CS_BIT_TYPE: srclen = 1; break;
687 : case CS_BIGINT_TYPE: srclen = 8; break;
688 : case CS_UBIGINT_TYPE: srclen = 8; break;
689 0 : case CS_UNIQUE_TYPE: srclen = 16; break;
690 0 : default:
691 0 : printf("error not fixed length type (%d) and datalen not specified\n",
692 0 : bindcol->column_bindtype);
693 0 : return CS_FAIL;
694 : }
695 :
696 : } else {
697 2240 : srclen = *datalen;
698 : }
699 : }
700 2240 : if (srclen == 0) {
701 1040 : if (nullind && *nullind == -1)
702 : null_column = true;
703 : }
704 :
705 : if (!null_column) {
706 : CONV_RESULT convert_buffer;
707 : CS_DATAFMT_COMMON srcfmt, destfmt;
708 : CS_INT desttype;
709 :
710 1200 : srcfmt.datatype = srctype;
711 1200 : srcfmt.maxlength = srclen;
712 :
713 1200 : desttype = _cs_convert_not_client(ctx, bindcol, &convert_buffer, &src);
714 1200 : if (desttype == CS_ILLEGAL_TYPE)
715 1200 : desttype = _ct_get_client_type(bindcol, false);
716 1200 : if (desttype == CS_ILLEGAL_TYPE)
717 0 : return CS_FAIL;
718 1200 : destfmt.datatype = desttype;
719 1200 : destfmt.maxlength = bindcol->on_server.column_size;
720 1200 : destfmt.precision = bindcol->column_prec;
721 1200 : destfmt.scale = bindcol->column_scale;
722 1200 : destfmt.format = CS_FMT_UNUSED;
723 :
724 : /* if convert return FAIL mark error but process other columns */
725 1200 : if ((result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
726 1200 : &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen)) != CS_SUCCEED) {
727 0 : tdsdump_log(TDS_DBG_INFO1, "convert failed for %d \n", srctype);
728 : return CS_FAIL;
729 : }
730 : }
731 :
732 2240 : bindcol->bcp_column_data->datalen = destlen;
733 2240 : bindcol->bcp_column_data->is_null = null_column;
734 :
735 2240 : return TDS_SUCCESS;
736 : }
|