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 32 : blk_alloc(CS_CONNECTION * connection, CS_INT version, CS_BLKDESC ** blk_pointer)
53 : {
54 : CS_BLKDESC *blkdesc;
55 :
56 32 : tdsdump_log(TDS_DBG_FUNC, "blk_alloc(%p, %d, %p)\n", connection, version, blk_pointer);
57 :
58 32 : if (!connection || !connection->tds_socket)
59 : return CS_FAIL;
60 :
61 32 : if (connection->tds_socket->conn->tds_version < 0x500)
62 : return CS_FAIL;
63 :
64 32 : blkdesc = (CS_BLKDESC *) tds_alloc_bcpinfo();
65 32 : if (!blkdesc)
66 : return CS_FAIL;
67 :
68 : /* so we know who we belong to */
69 32 : blkdesc->bcpinfo.parent = connection;
70 :
71 32 : *blk_pointer = blkdesc;
72 32 : 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(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 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(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 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(NULL, 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(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 88 : case CS_BLK_ALL:
276 88 : 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 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 32 : blk_drop(CS_BLKDESC * blkdesc)
300 : {
301 32 : tdsdump_log(TDS_DBG_FUNC, "blk_drop(%p)\n", blkdesc);
302 :
303 : /* this is possible as CS_BLKDESC contains just bcpinfo field */
304 32 : tds_free_bcpinfo(&blkdesc->bcpinfo);
305 :
306 32 : 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 120 : blk_init(CS_BLKDESC * blkdesc, CS_INT direction, CS_CHAR * tablename, CS_INT tnamelen)
330 : {
331 120 : tdsdump_log(TDS_DBG_FUNC, "blk_init(%p, %d, %p, %d)\n", blkdesc, direction, tablename, tnamelen);
332 :
333 120 : if (!blkdesc) {
334 : return CS_FAIL;
335 : }
336 :
337 120 : if (direction != CS_BLK_IN && direction != CS_BLK_OUT ) {
338 8 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 15, "");
339 8 : return CS_FAIL;
340 : }
341 :
342 112 : if (!tablename) {
343 8 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 6, "tblname");
344 8 : return CS_FAIL;
345 : }
346 104 : tnamelen = _ct_get_string_length(tablename, tnamelen);
347 104 : if (tnamelen < 0) {
348 8 : _ctclient_msg(NULL, CONN(blkdesc), "blk_init", 1, 1, 1, 4, "tblnamelen, %d", tnamelen);
349 8 : return CS_FAIL;
350 : }
351 :
352 : /* free allocated storage in blkdesc & initialise flags, etc. */
353 96 : tds_deinit_bcpinfo(&blkdesc->bcpinfo);
354 :
355 : /* string can be no-nul terminated so copy with memcpy */
356 96 : if (!tds_dstr_copyn(&blkdesc->bcpinfo.tablename, tablename, tnamelen)) {
357 : return CS_FAIL;
358 : }
359 :
360 96 : blkdesc->bcpinfo.direction = direction;
361 96 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
362 96 : blkdesc->bcpinfo.xfer_init = 0;
363 :
364 96 : 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 96 : blkdesc->bcpinfo.bind_count = CS_UNUSED;
369 :
370 96 : return CS_SUCCEED;
371 : }
372 :
373 : CS_RETCODE
374 80 : 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 80 : tdsdump_log(TDS_DBG_FUNC, "blk_props(%p, %d, %d, %p, %d, %p)\n", blkdesc, action, property, buffer, buflen, outlen);
379 :
380 80 : 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 = 1;
388 0 : if (intval == CS_FALSE)
389 0 : blkdesc->bcpinfo.identity_insert_on = 0;
390 : }
391 : return CS_SUCCEED;
392 : break;
393 0 : case CS_GET:
394 0 : retval = blkdesc->bcpinfo.identity_insert_on == 1 ? 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 80 : case BLK_HINTS:
409 80 : 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 160 : blk_rowxfer(CS_BLKDESC * blkdesc)
438 : {
439 160 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer(%p)\n", blkdesc);
440 :
441 160 : return blk_rowxfer_mult(blkdesc, NULL);
442 : }
443 :
444 : CS_RETCODE
445 184 : blk_rowxfer_mult(CS_BLKDESC * blkdesc, CS_INT * row_count)
446 : {
447 184 : CS_INT rows_to_xfer = 0;
448 184 : CS_INT rows_xferred = 0;
449 : CS_RETCODE ret;
450 :
451 184 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_mult(%p, %p)\n", blkdesc, row_count);
452 :
453 184 : if (!row_count || *row_count == 0 )
454 168 : rows_to_xfer = blkdesc->bcpinfo.bind_count;
455 : else
456 : rows_to_xfer = *row_count;
457 :
458 184 : if (blkdesc->bcpinfo.direction == CS_BLK_IN) {
459 160 : ret = _blk_rowxfer_in(blkdesc, rows_to_xfer, &rows_xferred);
460 : } else {
461 24 : ret = _blk_rowxfer_out(blkdesc, rows_to_xfer, &rows_xferred);
462 : }
463 184 : if (row_count)
464 24 : *row_count = rows_xferred;
465 184 : 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 24 : _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 24 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_out(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
515 :
516 24 : if (!blkdesc || !CONN(blkdesc))
517 : return CS_FAIL;
518 :
519 24 : 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 24 : if (blkdesc->bcpinfo.xfer_init == 0) {
527 :
528 16 : 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 16 : while ((ret = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
534 16 : if (result_type == TDS_ROW_RESULT)
535 : break;
536 : }
537 :
538 8 : 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 8 : blkdesc->bcpinfo.xfer_init = 1;
544 : }
545 :
546 24 : if (rows_xferred)
547 24 : *rows_xferred = 0;
548 :
549 40 : for (temp_count = 0; temp_count < rows_to_xfer; temp_count++) {
550 :
551 48 : ret = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_STOPAT_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
552 :
553 48 : tdsdump_log(TDS_DBG_FUNC, "blk_rowxfer_out() process_row_tokens returned %d\n", ret);
554 :
555 48 : switch (ret) {
556 48 : case TDS_SUCCESS:
557 48 : if (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT) {
558 40 : if (result_type == TDS_ROW_RESULT) {
559 40 : if (_ct_bind_data( CONN(blkdesc)->ctx, tds->current_results, blkdesc->bcpinfo.bindinfo, temp_count))
560 : return CS_ROW_FAIL;
561 40 : if (rows_xferred)
562 40 : *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 160 : _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 160 : tdsdump_log(TDS_DBG_FUNC, "_blk_rowxfer_in(%p, %d, %p)\n", blkdesc, rows_to_xfer, rows_xferred);
587 :
588 160 : if (!blkdesc)
589 : return CS_FAIL;
590 :
591 160 : 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 160 : if (blkdesc->bcpinfo.xfer_init == 0) {
599 :
600 : /*
601 : * first call the start_copy function, which will
602 : * retrieve details of the database table columns
603 : */
604 :
605 88 : 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 88 : blkdesc->bcpinfo.xfer_init = 1;
611 : }
612 :
613 160 : for (each_row = 0; each_row < rows_to_xfer; each_row++ ) {
614 :
615 160 : 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 TDS_INT _blk_to_not_client(CS_CONTEXT *ctx, TDSCOLUMN *col, const CS_DATAFMT_COMMON * srcfmt, CS_VOID * srcdata);
634 :
635 : static TDSRET
636 2240 : _blk_get_col_data(TDSBCPINFO *bulk, TDSCOLUMN *bindcol, int offset)
637 : {
638 2240 : int result = 0;
639 2240 : bool null_column = false;
640 2240 : unsigned char *src = NULL;
641 :
642 2240 : CS_INT srctype = 0;
643 2240 : CS_INT srclen = 0;
644 2240 : CS_INT destlen = 0;
645 2240 : CS_SMALLINT *nullind = NULL;
646 2240 : CS_INT *datalen = NULL;
647 2240 : CS_BLKDESC *blkdesc = (CS_BLKDESC *) bulk;
648 2240 : CS_CONTEXT *ctx = CONN(blkdesc)->ctx;
649 :
650 2240 : tdsdump_log(TDS_DBG_FUNC, "_blk_get_col_data(%p, %p, %d)\n", bulk, bindcol, offset);
651 :
652 : /*
653 : * Retrieve the initial bound column_varaddress
654 : * and increment it if offset specified
655 : */
656 :
657 2240 : src = (unsigned char *) bindcol->column_varaddr;
658 2240 : if (!src) {
659 0 : tdsdump_log(TDS_DBG_ERROR, "error source field not addressable\n");
660 : return TDS_FAIL;
661 : }
662 :
663 2240 : src += offset * bindcol->column_bindlen;
664 :
665 2240 : if (bindcol->column_nullbind) {
666 2160 : nullind = bindcol->column_nullbind;
667 2160 : nullind += offset;
668 : }
669 2240 : if (bindcol->column_lenbind) {
670 2240 : datalen = bindcol->column_lenbind;
671 2240 : datalen += offset;
672 : }
673 :
674 2240 : srctype = bindcol->column_bindtype; /* passes to cs_convert */
675 :
676 2240 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data srctype = %d\n", srctype);
677 2240 : tdsdump_log(TDS_DBG_INFO1, "blk_get_col_data datalen = %d\n", datalen ? *datalen : -1);
678 :
679 2240 : if (datalen) {
680 2240 : if (*datalen == CS_UNUSED) {
681 0 : switch (srctype) {
682 : case CS_LONG_TYPE: srclen = 8; break;
683 : case CS_FLOAT_TYPE: srclen = 8; break;
684 : case CS_MONEY_TYPE: srclen = 8; break;
685 : case CS_DATETIME_TYPE: srclen = 8; break;
686 0 : case CS_INT_TYPE: srclen = 4; break;
687 0 : case CS_UINT_TYPE: srclen = 4; break;
688 0 : case CS_REAL_TYPE: srclen = 4; break;
689 0 : case CS_MONEY4_TYPE: srclen = 4; break;
690 0 : case CS_DATETIME4_TYPE: srclen = 4; break;
691 0 : case CS_SMALLINT_TYPE: srclen = 2; break;
692 0 : case CS_USMALLINT_TYPE: srclen = 2; break;
693 0 : case CS_TINYINT_TYPE: srclen = 1; break;
694 0 : case CS_BIT_TYPE: srclen = 1; break;
695 : case CS_BIGINT_TYPE: srclen = 8; break;
696 : case CS_UBIGINT_TYPE: srclen = 8; break;
697 0 : case CS_UNIQUE_TYPE: srclen = 16; break;
698 0 : default:
699 0 : tdsdump_log(TDS_DBG_ERROR, "Not fixed length type (%d) and datalen not specified\n",
700 0 : bindcol->column_bindtype);
701 : return TDS_FAIL;
702 : }
703 :
704 : } else {
705 2240 : srclen = *datalen;
706 : }
707 : }
708 2240 : if (srclen == 0) {
709 1040 : if (nullind && *nullind == -1)
710 : null_column = true;
711 : }
712 :
713 : if (!null_column) {
714 : CS_DATAFMT_COMMON srcfmt, destfmt;
715 : CS_INT desttype;
716 : TDS_INT outlen;
717 :
718 1200 : srcfmt.datatype = srctype;
719 1200 : srcfmt.maxlength = srclen;
720 :
721 1200 : outlen = _blk_to_not_client(ctx, bindcol, &srcfmt, src);
722 1200 : if (outlen != TDS_CONVERT_NOAVAIL)
723 0 : return outlen > 0 ? TDS_SUCCESS : TDS_FAIL;
724 :
725 1200 : desttype = _ct_get_client_type(bindcol, false);
726 1200 : if (desttype == CS_ILLEGAL_TYPE)
727 : return TDS_FAIL;
728 1200 : destfmt.datatype = desttype;
729 1200 : destfmt.maxlength = bindcol->on_server.column_size;
730 1200 : destfmt.precision = bindcol->column_prec;
731 1200 : destfmt.scale = bindcol->column_scale;
732 1200 : destfmt.format = CS_FMT_UNUSED;
733 :
734 : /* if convert return FAIL mark error but process other columns */
735 1200 : if ((result = _cs_convert(ctx, &srcfmt, (CS_VOID *) src,
736 1200 : &destfmt, (CS_VOID *) bindcol->bcp_column_data->data, &destlen)) != 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 2240 : bindcol->bcp_column_data->datalen = destlen;
744 2240 : bindcol->bcp_column_data->is_null = null_column;
745 :
746 2240 : return TDS_SUCCESS;
747 : }
748 :
749 : static TDS_INT
750 1200 : _blk_to_not_client(CS_CONTEXT *ctx, TDSCOLUMN *col, const CS_DATAFMT_COMMON * srcfmt, CS_VOID * srcdata)
751 : {
752 1200 : TDS_SERVER_TYPE desttype = col->on_server.column_type, srctype;
753 : CS_INT datatype, src_len;
754 : TDS_INT out_len;
755 :
756 1200 : switch (desttype) {
757 : case SYBMSDATE:
758 : case SYBMSTIME:
759 : case SYBMSDATETIME2:
760 : case SYBMSDATETIMEOFFSET:
761 : break;
762 : default:
763 : return TDS_CONVERT_NOAVAIL;
764 : }
765 :
766 0 : datatype = srcfmt->datatype;
767 0 : srctype = _ct_get_server_type(NULL, datatype);
768 0 : if (srctype == TDS_INVALID_TYPE)
769 : return TDS_CONVERT_FAIL;
770 :
771 0 : src_len = srcfmt->maxlength;
772 0 : if (datatype == CS_VARCHAR_TYPE || datatype == CS_VARBINARY_TYPE) {
773 0 : CS_VARCHAR *vc = (CS_VARCHAR *) srcdata;
774 0 : src_len = vc->len;
775 0 : srcdata = vc->str;
776 : }
777 :
778 0 : out_len = tds_convert(ctx->tds_ctx, srctype, srcdata,
779 0 : src_len, desttype, (CONV_RESULT *) col->bcp_column_data->data);
780 0 : if (out_len < 0)
781 : return out_len;
782 :
783 0 : col->bcp_column_data->datalen = out_len;
784 0 : col->bcp_column_data->is_null = false;
785 :
786 : return out_len;
787 : }
|