1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3
4 #include <config.h>
5 #include <sqlrelay/sqlrclient.h>
6 #include <rudiments/memorypool.h>
7 #include <rudiments/file.h>
8 #include <rudiments/charstring.h>
9 #include <rudiments/permissions.h>
10 #include <rudiments/datetime.h>
11 #include <rudiments/bytestring.h>
12 #include <rudiments/character.h>
13 #include <rudiments/filesystem.h>
14 #include <rudiments/error.h>
15 #include <defines.h>
16 #define NEED_DATATYPESTRING 1
17 #include <datatypes.h>
18 #define NEED_BEFORE_BIND_VARIABLE 1
19 #define NEED_IS_BIND_DELIMITER 1
20 #define NEED_AFTER_BIND_VARIABLE 1
21 #define NEED_COUNT_BIND_VARIABLES 1
22 #include <bindvariables.h>
23
24 #ifndef MAXPATHLEN
25 #define MAXPATHLEN 256
26 #endif
27
28 // we're optimistic that the average query will contain 16 bind variables
29 #define OPTIMISTIC_BIND_COUNT 16
30
31 // we're optimistic that the average query will contain 16 columns whose data
32 // requires an average of 16 bytes to store
33 #define OPTIMISTIC_COLUMN_COUNT 16
34 #define OPTIMISTIC_AVERAGE_COLUMN_DATA_LENGTH 16
35 #define OPTIMISTIC_COLUMN_DATA_SIZE OPTIMISTIC_COLUMN_COUNT*\
36 OPTIMISTIC_AVERAGE_COLUMN_DATA_LENGTH
37
38 // we're also optimistic that if we need more space, that growing at a rate of
39 // 1 column at a time will work out well
40 #define OPTIMISTIC_COLUMN_DATA_GROWTH_SIZE OPTIMISTIC_COLUMN_DATA_SIZE
41
42 // we're optimistic that the average query will contain 16 rows whose fields
43 // average 16 characters in length
44 #define OPTIMISTIC_ROW_COUNT 16
45 #define OPTIMISTIC_AVERAGE_FIELD_LENGTH 16
46 #define OPTIMISTIC_RESULT_SET_SIZE OPTIMISTIC_COLUMN_COUNT*\
47 OPTIMISTIC_ROW_COUNT*\
48 OPTIMISTIC_AVERAGE_FIELD_LENGTH
49
50 // we're also optimistic that if we need more space, that growing at a rate of
51 // 4 rows at a time will work out well
52 #define OPTIMISTIC_RESULT_SET_GROWTH_SIZE OPTIMISTIC_COLUMN_COUNT*4*\
53 OPTIMISTIC_AVERAGE_FIELD_LENGTH
54
55
56
57 class sqlrclientrow {
58 friend class sqlrcursor;
59 private:
60 sqlrclientrow(uint32_t colcount);
61 ~sqlrclientrow();
62 void resize(uint32_t colcount);
63 void addField(uint32_t column,
64 const char *buffer, uint32_t length);
65
66 char *getField(uint32_t column) const;
67 uint32_t getFieldLength(uint32_t column) const;
68
69 sqlrclientrow *next;
70
71 char *fields[OPTIMISTIC_COLUMN_COUNT];
72 uint32_t fieldlengths[OPTIMISTIC_COLUMN_COUNT];
73 char **extrafields;
74 uint32_t *extrafieldlengths;
75
76 uint32_t colcount;
77 };
78
sqlrclientrow(uint32_t colcount)79 sqlrclientrow::sqlrclientrow(uint32_t colcount) {
80 this->colcount=colcount;
81 if (colcount>=OPTIMISTIC_COLUMN_COUNT) {
82 extrafields=new char *[colcount-OPTIMISTIC_COLUMN_COUNT];
83 extrafieldlengths=new uint32_t
84 [colcount-OPTIMISTIC_COLUMN_COUNT];
85 } else {
86 extrafields=NULL;
87 extrafieldlengths=NULL;
88 }
89 }
90
~sqlrclientrow()91 sqlrclientrow::~sqlrclientrow() {
92 delete[] extrafields;
93 delete[] extrafieldlengths;
94 }
95
resize(uint32_t colcount)96 void sqlrclientrow::resize(uint32_t colcount) {
97 this->colcount=colcount;
98 if (colcount>=OPTIMISTIC_COLUMN_COUNT) {
99 delete[] extrafields;
100 delete[] extrafieldlengths;
101 extrafields=new char *[colcount-OPTIMISTIC_COLUMN_COUNT];
102 extrafieldlengths=new uint32_t
103 [colcount-OPTIMISTIC_COLUMN_COUNT];
104 }
105 }
106
addField(uint32_t column,const char * buffer,uint32_t length)107 void sqlrclientrow::addField(uint32_t column,
108 const char *buffer, uint32_t length) {
109 if (column<OPTIMISTIC_COLUMN_COUNT) {
110 fields[column]=(char *)buffer;
111 fieldlengths[column]=length;
112 } else {
113 extrafields[column-OPTIMISTIC_COLUMN_COUNT]=(char *)buffer;
114 extrafieldlengths[column-OPTIMISTIC_COLUMN_COUNT]=length;
115 }
116 }
117
getField(uint32_t column) const118 char *sqlrclientrow::getField(uint32_t column) const {
119 if (column<OPTIMISTIC_COLUMN_COUNT) {
120 return fields[column];
121 } else {
122 return extrafields[column-OPTIMISTIC_COLUMN_COUNT];
123 }
124 }
125
getFieldLength(uint32_t column) const126 uint32_t sqlrclientrow::getFieldLength(uint32_t column) const {
127 if (column<OPTIMISTIC_COLUMN_COUNT) {
128 return fieldlengths[column];
129 } else {
130 return extrafieldlengths[column-OPTIMISTIC_COLUMN_COUNT];
131 }
132 }
133
134
135 class sqlrclientcolumn {
136 public:
137 char *name;
138 uint16_t type;
139 char *typestring;
140 uint16_t typestringlength;
141 uint32_t length;
142 uint32_t longest;
143 unsigned char longdatatype;
144 uint32_t precision;
145 uint32_t scale;
146 uint16_t nullable;
147 uint16_t primarykey;
148 uint16_t unique;
149 uint16_t partofkey;
150 uint16_t unsignednumber;
151 uint16_t zerofill;
152 uint16_t binary;
153 uint16_t autoincrement;
154 char *table;
155 };
156
157 enum columncase {
158 MIXED_CASE,
159 UPPER_CASE,
160 LOWER_CASE
161 };
162
163
164 class sqlrclientbindvar {
165 friend class sqlrcursor;
166 friend class sqlrcursorprivate;
167 private:
168 char *variable;
169 union {
170 char *stringval;
171 int64_t integerval;
172 struct {
173 double value;
174 uint32_t precision;
175 uint32_t scale;
176 } doubleval;
177 struct {
178 int16_t year;
179 int16_t month;
180 int16_t day;
181 int16_t hour;
182 int16_t minute;
183 int16_t second;
184 int32_t microsecond;
185 char *tz;
186 bool isnegative;
187 } dateval;
188 char *lobval;
189 uint16_t cursorid;
190 } value;
191 uint32_t valuesize;
192 uint32_t resultvaluesize;
193
194 sqlrclientbindvartype_t type;
195
196 bool send;
197
198 bool substituted;
199 bool donesubstituting;
200 };
201
202
203 class sqlrcursorprivate {
204 friend class sqlrcursor;
205 private:
206 sqlrclientbindvar *findVar(const char *variable,
207 dynamicarray<sqlrclientbindvar> *vars);
208
209 bool _resumed;
210 bool _cached;
211
212 // query
213 char *_querybuffer;
214 const char *_queryptr;
215 uint32_t _querylen;
216 char *_fullpath;
217 bool _reexecute;
218
219 // substitution variables
220 dynamicarray<sqlrclientbindvar> *_subvars;
221 bool _dirtysubs;
222
223 // bind variables
224 dynamicarray<sqlrclientbindvar> *_inbindvars;
225 dynamicarray<sqlrclientbindvar> *_outbindvars;
226 dynamicarray<sqlrclientbindvar> *_inoutbindvars;
227 bool _validatebinds;
228 bool _dirtybinds;
229 bool _clearbindsduringprepare;
230
231 // result set
232 bool _lazyfetch;
233 uint64_t _rsbuffersize;
234 uint16_t _sendcolumninfo;
235 uint16_t _sentcolumninfo;
236
237 uint16_t _suspendresultsetsent;
238 bool _endofresultset;
239
240 uint16_t _columntypeformat;
241 uint32_t _colcount;
242 uint32_t _previouscolcount;
243
244 columncase _colcase;
245
246 sqlrclientcolumn *_columns;
247 sqlrclientcolumn *_extracolumns;
248 memorypool *_colstorage;
249 char **_columnnamearray;
250
251 uint64_t _firstrowindex;
252 uint64_t _resumedlastrowindex;
253 uint64_t _rowcount;
254 uint16_t _knowsactualrows;
255 uint64_t _actualrows;
256 uint16_t _knowsaffectedrows;
257 uint64_t _affectedrows;
258
259 sqlrclientrow **_rows;
260 sqlrclientrow **_extrarows;
261 memorypool *_rowstorage;
262 sqlrclientrow *_firstextrarow;
263 char ***_fields;
264 uint32_t **_fieldlengths;
265
266 bool _returnnulls;
267
268 // result set caching
269 bool _cacheon;
270 int32_t _cachettl;
271 char *_cachedestname;
272 char *_cachedestindname;
273 file *_cachedest;
274 file *_cachedestind;
275 file *_cachesource;
276 file *_cachesourceind;
277
278 // error
279 int64_t _errorno;
280 char *_error;
281
282 // copy references flag
283 bool _copyrefs;
284
285 // parent connection
286 sqlrconnection *_sqlrc;
287
288 // next/previous pointers
289 sqlrcursor *_next;
290 sqlrcursor *_prev;
291
292 // cursor id
293 uint16_t _cursorid;
294 bool _havecursorid;
295
296 // query translation
297 char *_querytree;
298 char *_translatedquery;
299
300 // socket client
301 socketclient *_cs;
302 };
303
304 // This method is a member of sqlrcursorprivate, rather than sqlrcuror, because
305 // if it were a member of sqlrcursor, then it would have to be defined in the
306 // header file. If it were, then since it references a
307 // dynamicarray<sqlrclientbindvar>, older compilers would also require that
308 // sqlrclientbindvar be defined in the header file as well. To avoid all of
309 // that, it's part of sqlrcursorprivate.
findVar(const char * variable,dynamicarray<sqlrclientbindvar> * vars)310 sqlrclientbindvar *sqlrcursorprivate::findVar(const char *variable,
311 dynamicarray<sqlrclientbindvar> *vars) {
312 for (uint16_t i=0; i<vars->getLength(); i++) {
313 if (!charstring::compare((*vars)[i].variable,variable)) {
314 return &((*vars)[i]);
315 }
316 }
317 return NULL;
318 }
319
320
sqlrcursor(sqlrconnection * sqlrc,bool copyreferences)321 sqlrcursor::sqlrcursor(sqlrconnection *sqlrc, bool copyreferences) {
322 init(sqlrc,copyreferences);
323 }
324
sqlrcursor(sqlrconnection * sqlrc)325 sqlrcursor::sqlrcursor(sqlrconnection *sqlrc) {
326 init(sqlrc,false);
327 }
328
init(sqlrconnection * sqlrc,bool copyreferences)329 void sqlrcursor::init(sqlrconnection *sqlrc, bool copyreferences) {
330
331 pvt=new sqlrcursorprivate;
332
333 // copy references
334 pvt->_copyrefs=copyreferences;
335
336 pvt->_sqlrc=sqlrc;
337
338 // put self in connection's cursor list
339 if (pvt->_sqlrc->lastcursor()) {
340 pvt->_sqlrc->lastcursor()->pvt->_next=this;
341 pvt->_prev=pvt->_sqlrc->lastcursor();
342 } else {
343 pvt->_sqlrc->firstcursor(this);
344 pvt->_prev=NULL;
345 }
346 pvt->_sqlrc->lastcursor(this);
347 pvt->_next=NULL;
348
349 // session state
350 pvt->_cached=false;
351
352 // query
353 pvt->_querybuffer=NULL;
354 pvt->_fullpath=NULL;
355
356 // result set
357 pvt->_lazyfetch=false;
358 pvt->_rsbuffersize=0;
359
360 pvt->_firstrowindex=0;
361 pvt->_resumedlastrowindex=0;
362 pvt->_rowcount=0;
363 pvt->_actualrows=0;
364 pvt->_affectedrows=0;
365 pvt->_endofresultset=true;
366
367 pvt->_errorno=0;
368 pvt->_error=NULL;
369
370 pvt->_rows=NULL;
371 pvt->_extrarows=NULL;
372 pvt->_firstextrarow=NULL;
373 pvt->_rowstorage=new memorypool(OPTIMISTIC_RESULT_SET_SIZE,
374 OPTIMISTIC_RESULT_SET_GROWTH_SIZE,
375 5);
376 pvt->_fields=NULL;
377 pvt->_fieldlengths=NULL;
378
379 pvt->_colcount=0;
380 pvt->_previouscolcount=0;
381 pvt->_columns=NULL;
382 pvt->_extracolumns=NULL;
383 pvt->_colstorage=new memorypool(OPTIMISTIC_COLUMN_DATA_SIZE,
384 OPTIMISTIC_COLUMN_DATA_GROWTH_SIZE,
385 5);
386 pvt->_columnnamearray=NULL;
387
388 pvt->_returnnulls=false;
389
390 // cache file
391 pvt->_cachesource=NULL;
392 pvt->_cachesourceind=NULL;
393 pvt->_cachedestname=NULL;
394 pvt->_cachedestindname=NULL;
395 pvt->_cachedest=NULL;
396 pvt->_cachedestind=NULL;
397 pvt->_cacheon=false;
398
399 // options...
400 pvt->_sendcolumninfo=SEND_COLUMN_INFO;
401 pvt->_sentcolumninfo=SEND_COLUMN_INFO;
402 pvt->_columntypeformat=COLUMN_TYPE_IDS;
403 pvt->_colcase=MIXED_CASE;
404
405 // cursor id
406 pvt->_cursorid=0;
407 pvt->_havecursorid=false;
408
409 // query translation
410 pvt->_querytree=NULL;
411 pvt->_translatedquery=NULL;
412
413 // socket client
414 pvt->_cs=NULL;
415
416 // initialize all bind/substitution-related variables
417 pvt->_subvars=new dynamicarray<sqlrclientbindvar>(
418 OPTIMISTIC_BIND_COUNT,16);
419 pvt->_inbindvars=new dynamicarray<sqlrclientbindvar>(
420 OPTIMISTIC_BIND_COUNT,16);
421 pvt->_outbindvars=new dynamicarray<sqlrclientbindvar>(
422 OPTIMISTIC_BIND_COUNT,16);
423 pvt->_inoutbindvars=new dynamicarray<sqlrclientbindvar>(
424 OPTIMISTIC_BIND_COUNT,16);
425 pvt->_clearbindsduringprepare=true;
426 clearVariables();
427 }
428
~sqlrcursor()429 sqlrcursor::~sqlrcursor() {
430
431 // abort result set if necessary
432 if (pvt->_sqlrc && !pvt->_sqlrc->endsessionsent() &&
433 !pvt->_sqlrc->suspendsessionsent()) {
434 closeResultSet(true);
435 }
436
437 // deallocate copied references
438 deleteVariables();
439 delete pvt->_inoutbindvars;
440 delete pvt->_outbindvars;
441 delete pvt->_inbindvars;
442 delete pvt->_subvars;
443
444 // deallocate the query buffer
445 delete[] pvt->_querybuffer;
446
447 // deallocate the fullpath (used for file queries)
448 delete[] pvt->_fullpath;
449
450 clearResultSet();
451 delete[] pvt->_columns;
452 delete[] pvt->_extracolumns;
453 delete pvt->_colstorage;
454 if (pvt->_rows) {
455 for (uint32_t i=0; i<OPTIMISTIC_ROW_COUNT; i++) {
456 delete pvt->_rows[i];
457 }
458 delete[] pvt->_rows;
459 }
460 delete pvt->_rowstorage;
461
462 // it's possible for the connection to be deleted before the
463 // cursor is, in that case, don't do any of this stuff
464 if (pvt->_sqlrc) {
465
466 // remove self from connection's cursor list
467 if (!pvt->_next && !pvt->_prev) {
468 pvt->_sqlrc->firstcursor(NULL);
469 pvt->_sqlrc->lastcursor(NULL);
470 } else {
471 sqlrcursor *temp=pvt->_next;
472 if (pvt->_next) {
473 pvt->_next->pvt->_prev=pvt->_prev;
474 } else {
475 pvt->_sqlrc->lastcursor(pvt->_prev);
476 }
477 if (pvt->_prev) {
478 pvt->_prev->pvt->_next=temp;
479 } else {
480 pvt->_sqlrc->firstcursor(pvt->_next);
481 }
482 }
483
484 if (pvt->_sqlrc->debug()) {
485 pvt->_sqlrc->debugPreStart();
486 pvt->_sqlrc->debugPrint("Deallocated cursor\n");
487 pvt->_sqlrc->debugPreEnd();
488 }
489 }
490
491 if (pvt->_copyrefs && pvt->_cachedestname) {
492 delete[] pvt->_cachedestname;
493 }
494 delete[] pvt->_cachedestindname;
495
496 // query translation
497 delete[] pvt->_querytree;
498 delete[] pvt->_translatedquery;
499
500 delete pvt;
501 }
502
setResultSetBufferSize(uint64_t rows)503 void sqlrcursor::setResultSetBufferSize(uint64_t rows) {
504 pvt->_rsbuffersize=rows;
505 if (pvt->_sqlrc->debug()) {
506 pvt->_sqlrc->debugPreStart();
507 pvt->_sqlrc->debugPrint("Result Set Buffer Size: ");
508 pvt->_sqlrc->debugPrint((int64_t)rows);
509 pvt->_sqlrc->debugPrint("\n");
510 pvt->_sqlrc->debugPreEnd();
511 }
512 }
513
getResultSetBufferSize()514 uint64_t sqlrcursor::getResultSetBufferSize() {
515 return pvt->_rsbuffersize;
516 }
517
lazyFetch()518 void sqlrcursor::lazyFetch() {
519 pvt->_lazyfetch=true;
520 }
521
dontLazyFetch()522 void sqlrcursor::dontLazyFetch() {
523 pvt->_lazyfetch=false;
524 }
525
dontGetColumnInfo()526 void sqlrcursor::dontGetColumnInfo() {
527 pvt->_sendcolumninfo=DONT_SEND_COLUMN_INFO;
528 }
529
getColumnInfo()530 void sqlrcursor::getColumnInfo() {
531 pvt->_sendcolumninfo=SEND_COLUMN_INFO;
532 }
533
mixedCaseColumnNames()534 void sqlrcursor::mixedCaseColumnNames() {
535 pvt->_colcase=MIXED_CASE;
536 }
537
upperCaseColumnNames()538 void sqlrcursor::upperCaseColumnNames() {
539 pvt->_colcase=UPPER_CASE;
540 }
541
lowerCaseColumnNames()542 void sqlrcursor::lowerCaseColumnNames() {
543 pvt->_colcase=LOWER_CASE;
544 }
545
cacheToFile(const char * filename)546 void sqlrcursor::cacheToFile(const char *filename) {
547
548 pvt->_cacheon=true;
549 pvt->_cachettl=600;
550 if (pvt->_copyrefs) {
551 delete[] pvt->_cachedestname;
552 pvt->_cachedestname=charstring::duplicate(filename);
553 } else {
554 pvt->_cachedestname=(char *)filename;
555 }
556
557 // create the index name
558 delete[] pvt->_cachedestindname;
559 size_t cachedestindnamelen=charstring::length(filename)+5;
560 pvt->_cachedestindname=new char[cachedestindnamelen];
561 charstring::copy(pvt->_cachedestindname,filename);
562 charstring::append(pvt->_cachedestindname,".ind");
563 }
564
setCacheTtl(uint32_t ttl)565 void sqlrcursor::setCacheTtl(uint32_t ttl) {
566 pvt->_cachettl=ttl;
567 }
568
getCacheFileName()569 const char *sqlrcursor::getCacheFileName() {
570 return pvt->_cachedestname;
571 }
572
cacheOff()573 void sqlrcursor::cacheOff() {
574 pvt->_cacheon=false;
575 }
576
startCaching()577 void sqlrcursor::startCaching() {
578
579 if (!pvt->_resumed) {
580 if (pvt->_sqlrc->debug()) {
581 pvt->_sqlrc->debugPreStart();
582 pvt->_sqlrc->debugPrint("Caching data to ");
583 pvt->_sqlrc->debugPrint(pvt->_cachedestname);
584 pvt->_sqlrc->debugPrint("\n");
585 pvt->_sqlrc->debugPreEnd();
586 }
587 } else {
588 if (pvt->_sqlrc->debug()) {
589 pvt->_sqlrc->debugPreStart();
590 pvt->_sqlrc->debugPrint("Resuming caching data to ");
591 pvt->_sqlrc->debugPrint(pvt->_cachedestname);
592 pvt->_sqlrc->debugPrint("\n");
593 pvt->_sqlrc->debugPreEnd();
594 }
595 }
596
597 // create the cache file, truncate it unless we're
598 // resuming a previous session
599 pvt->_cachedest=new file();
600 pvt->_cachedestind=new file();
601 if (!pvt->_resumed) {
602 pvt->_cachedest->open(pvt->_cachedestname,
603 O_RDWR|O_TRUNC|O_CREAT,
604 permissions::ownerReadWrite());
605 pvt->_cachedestind->open(pvt->_cachedestindname,
606 O_RDWR|O_TRUNC|O_CREAT,
607 permissions::ownerReadWrite());
608 } else {
609 pvt->_cachedest->open(pvt->_cachedestname,
610 O_RDWR|O_CREAT|O_APPEND,
611 permissions::ownerReadWrite());
612 pvt->_cachedestind->open(pvt->_cachedestindname,
613 O_RDWR|O_CREAT|O_APPEND,
614 permissions::ownerReadWrite());
615 }
616
617 if (pvt->_cachedest && pvt->_cachedestind) {
618
619 // calculate and set write buffer size
620 // FIXME: I think rudiments bugs keep this from working...
621 /*filesystem fs;
622 if (fs.open(pvt->_cachedestname)) {
623 off64_t optblocksize=fs.getOptimumTransferBlockSize();
624 pvt->_cachedest->setWriteBufferSize(
625 (optblocksize)?optblocksize:1024);
626 pvt->_cachedestind->setWriteBufferSize(
627 (optblocksize)?optblocksize:1024);
628 }*/
629
630 if (!pvt->_resumed) {
631
632 // write "magic" identifier to head of files
633 pvt->_cachedest->write("SQLRELAYCACHE",13);
634 pvt->_cachedestind->write("SQLRELAYCACHE",13);
635
636 // write ttl to files
637 datetime dt;
638 dt.getSystemDateAndTime();
639 int64_t expiration=dt.getEpoch()+pvt->_cachettl;
640 pvt->_cachedest->write(expiration);
641 pvt->_cachedestind->write(expiration);
642 }
643
644 } else {
645
646 if (pvt->_sqlrc->debug()) {
647 pvt->_sqlrc->debugPreStart();
648 pvt->_sqlrc->debugPrint("Error caching data to ");
649 pvt->_sqlrc->debugPrint(pvt->_cachedestname);
650 pvt->_sqlrc->debugPrint("\n");
651 pvt->_sqlrc->debugPreEnd();
652 }
653
654 // in case of an error, clean up
655 clearCacheDest();
656 }
657 }
658
cacheError()659 void sqlrcursor::cacheError() {
660
661 if (pvt->_resumed || !pvt->_cachedest) {
662 return;
663 }
664
665 // write the number of returned rows, affected rows
666 // and a zero to terminate the column descriptions
667 pvt->_cachedest->write((uint16_t)NO_ACTUAL_ROWS);
668 pvt->_cachedest->write((uint16_t)NO_AFFECTED_ROWS);
669 pvt->_cachedest->write((uint16_t)END_COLUMN_INFO);
670 }
671
cacheNoError()672 void sqlrcursor::cacheNoError() {
673
674 if (pvt->_resumed || !pvt->_cachedest) {
675 return;
676 }
677
678 pvt->_cachedest->write((uint16_t)NO_ERROR_OCCURRED);
679 }
680
cacheColumnInfo()681 void sqlrcursor::cacheColumnInfo() {
682
683 if (pvt->_resumed || !pvt->_cachedest) {
684 return;
685 }
686
687 // write the number of returned rows
688 pvt->_cachedest->write(pvt->_knowsactualrows);
689 if (pvt->_knowsactualrows==ACTUAL_ROWS) {
690 pvt->_cachedest->write(pvt->_actualrows);
691 }
692
693 // write the number of affected rows
694 pvt->_cachedest->write(pvt->_knowsaffectedrows);
695 if (pvt->_knowsaffectedrows==AFFECTED_ROWS) {
696 pvt->_cachedest->write(pvt->_affectedrows);
697 }
698
699 // write whether or not the column info is is cached
700 pvt->_cachedest->write(pvt->_sentcolumninfo);
701
702 // write the column count
703 pvt->_cachedest->write(pvt->_colcount);
704
705 // write column descriptions to the cache file
706 if (pvt->_sendcolumninfo==SEND_COLUMN_INFO &&
707 pvt->_sentcolumninfo==SEND_COLUMN_INFO) {
708
709 // write column type format
710 pvt->_cachedest->write(pvt->_columntypeformat);
711
712 // write the columns themselves
713 uint16_t namelen;
714 uint16_t tablelen;
715 sqlrclientcolumn *whichcolumn;
716 for (uint32_t i=0; i<pvt->_colcount; i++) {
717
718 // get the column
719 whichcolumn=getColumnInternal(i);
720
721 // write the name
722 namelen=charstring::length(whichcolumn->name);
723 pvt->_cachedest->write(namelen);
724 pvt->_cachedest->write(whichcolumn->name,namelen);
725
726 // write the type
727 if (pvt->_columntypeformat==COLUMN_TYPE_IDS) {
728 pvt->_cachedest->write(whichcolumn->type);
729 } else {
730 pvt->_cachedest->write(
731 whichcolumn->typestringlength);
732 pvt->_cachedest->write(
733 whichcolumn->typestring,
734 whichcolumn->typestringlength);
735 }
736
737 // write the length, precision and scale
738 pvt->_cachedest->write(whichcolumn->length);
739 pvt->_cachedest->write(whichcolumn->precision);
740 pvt->_cachedest->write(whichcolumn->scale);
741
742 // write the flags
743 pvt->_cachedest->write(whichcolumn->nullable);
744 pvt->_cachedest->write(whichcolumn->primarykey);
745 pvt->_cachedest->write(whichcolumn->unique);
746 pvt->_cachedest->write(whichcolumn->partofkey);
747 pvt->_cachedest->write(whichcolumn->unsignednumber);
748 pvt->_cachedest->write(whichcolumn->zerofill);
749 pvt->_cachedest->write(whichcolumn->binary);
750 pvt->_cachedest->write(whichcolumn->autoincrement);
751
752 // write the table
753 tablelen=charstring::length(whichcolumn->table);
754 pvt->_cachedest->write(tablelen);
755 pvt->_cachedest->write(whichcolumn->table,tablelen);
756 }
757 }
758 }
759
cacheOutputBinds(uint32_t count)760 void sqlrcursor::cacheOutputBinds(uint32_t count) {
761
762 if (pvt->_resumed || !pvt->_cachedest) {
763 return;
764 }
765
766 // write the variable/value pairs to the cache file
767 uint16_t len;
768 for (uint32_t i=0; i<count; i++) {
769
770 pvt->_cachedest->write((uint16_t)(*pvt->_outbindvars)[i].type);
771
772 len=charstring::length((*pvt->_outbindvars)[i].variable);
773 pvt->_cachedest->write(len);
774 pvt->_cachedest->write((*pvt->_outbindvars)[i].variable,len);
775
776 len=(*pvt->_outbindvars)[i].resultvaluesize;
777 pvt->_cachedest->write(len);
778 if ((*pvt->_outbindvars)[i].type==
779 SQLRCLIENTBINDVARTYPE_STRING ||
780 (*pvt->_outbindvars)[i].type==
781 SQLRCLIENTBINDVARTYPE_BLOB ||
782 (*pvt->_outbindvars)[i].type==
783 SQLRCLIENTBINDVARTYPE_CLOB) {
784 pvt->_cachedest->write(
785 (*pvt->_outbindvars)[i].value.stringval,len);
786 pvt->_cachedest->write(
787 (*pvt->_outbindvars)[i].value.lobval,len);
788 } else if ((*pvt->_outbindvars)[i].type==
789 SQLRCLIENTBINDVARTYPE_INTEGER) {
790 pvt->_cachedest->write(
791 (*pvt->_outbindvars)[i].value.integerval);
792 } else if ((*pvt->_outbindvars)[i].type==
793 SQLRCLIENTBINDVARTYPE_DOUBLE) {
794 pvt->_cachedest->write(
795 (*pvt->_outbindvars)[i].value.
796 doubleval.value);
797 pvt->_cachedest->write(
798 (*pvt->_outbindvars)[i].value.
799 doubleval.precision);
800 pvt->_cachedest->write(
801 (*pvt->_outbindvars)[i].value.
802 doubleval.scale);
803 }
804 }
805
806 // terminate the list of output binds
807 pvt->_cachedest->write((uint16_t)END_BIND_VARS);
808 }
809
cacheInputOutputBinds(uint32_t count)810 void sqlrcursor::cacheInputOutputBinds(uint32_t count) {
811
812 if (pvt->_resumed || !pvt->_cachedest) {
813 return;
814 }
815
816 // FIXME: implement this
817
818 // terminate the list of output binds
819 pvt->_cachedest->write((uint16_t)END_BIND_VARS);
820 }
821
cacheData()822 void sqlrcursor::cacheData() {
823
824 if (!pvt->_cachedest) {
825 return;
826 }
827
828 // write the data to the cache file
829 uint32_t rowbuffercount=pvt->_rowcount-pvt->_firstrowindex;
830 for (uint32_t i=0; i<rowbuffercount; i++) {
831
832 // get the current offset in the cache destination file
833 int64_t position=pvt->_cachedest->getCurrentPosition();
834
835 // seek to the right place in the index file and write the
836 // destination file offset
837 pvt->_cachedestind->setPositionRelativeToBeginning(
838 13+sizeof(int64_t)+
839 ((pvt->_firstrowindex+i)*sizeof(int64_t)));
840 pvt->_cachedestind->write(position);
841
842 // write the row to the cache file
843 for (uint32_t j=0; j<pvt->_colcount; j++) {
844 uint16_t type;
845 int32_t len;
846 char *field=getFieldInternal(i,j);
847 if (field) {
848 type=STRING_DATA;
849 len=charstring::length(field);
850 pvt->_cachedest->write(type);
851 pvt->_cachedest->write(len);
852 if (len>0) {
853 pvt->_cachedest->write(field);
854 }
855 } else {
856 type=NULL_DATA;
857 pvt->_cachedest->write(type);
858 }
859 }
860 }
861
862 if (pvt->_endofresultset) {
863 finishCaching();
864 }
865 }
866
finishCaching()867 void sqlrcursor::finishCaching() {
868
869 if (!pvt->_cachedest) {
870 return;
871 }
872
873 if (pvt->_sqlrc->debug()) {
874 pvt->_sqlrc->debugPreStart();
875 pvt->_sqlrc->debugPrint("Finishing caching.\n");
876 pvt->_sqlrc->debugPreEnd();
877 }
878
879 // terminate the result set
880 pvt->_cachedest->write((uint16_t)END_RESULT_SET);
881 // FIXME: I think rudiments bugs keep this from working...
882 /*pvt->_cachedest->flushWriteBuffer(-1,-1);
883 pvt->_cachedestind->flushWriteBuffer(-1,-1);*/
884
885 // close the cache file and clean up
886 clearCacheDest();
887 }
888
clearCacheDest()889 void sqlrcursor::clearCacheDest() {
890
891 // close the cache file and clean up
892 if (pvt->_cachedest) {
893 pvt->_cachedest->close();
894 delete pvt->_cachedest;
895 pvt->_cachedest=NULL;
896 pvt->_cachedestind->close();
897 delete pvt->_cachedestind;
898 pvt->_cachedestind=NULL;
899 pvt->_cacheon=false;
900 }
901 }
902
getDatabaseList(const char * wild)903 bool sqlrcursor::getDatabaseList(const char *wild) {
904 return getDatabaseList(wild,SQLRCLIENTLISTFORMAT_MYSQL);
905 }
906
getDatabaseList(const char * wild,sqlrclientlistformat_t listformat)907 bool sqlrcursor::getDatabaseList(const char *wild,
908 sqlrclientlistformat_t listformat) {
909 if (pvt->_sqlrc->debug()) {
910 pvt->_sqlrc->debugPreStart();
911 pvt->_sqlrc->debugPrint("getting database list");
912 if (wild) {
913 pvt->_sqlrc->debugPrint("\"");
914 pvt->_sqlrc->debugPrint(wild);
915 pvt->_sqlrc->debugPrint("\"");
916 }
917 pvt->_sqlrc->debugPrint("\n");
918 pvt->_sqlrc->debugPreEnd();
919 }
920 return getList(GETDBLIST,listformat,NULL,wild,0);
921 }
922
getSchemaList(const char * wild)923 bool sqlrcursor::getSchemaList(const char *wild) {
924 return getSchemaList(wild,SQLRCLIENTLISTFORMAT_MYSQL);
925 }
926
getSchemaList(const char * wild,sqlrclientlistformat_t listformat)927 bool sqlrcursor::getSchemaList(const char *wild,
928 sqlrclientlistformat_t listformat) {
929 if (pvt->_sqlrc->debug()) {
930 pvt->_sqlrc->debugPreStart();
931 pvt->_sqlrc->debugPrint("getting schema list");
932 if (wild) {
933 pvt->_sqlrc->debugPrint("\"");
934 pvt->_sqlrc->debugPrint(wild);
935 pvt->_sqlrc->debugPrint("\"");
936 }
937 pvt->_sqlrc->debugPrint("\n");
938 pvt->_sqlrc->debugPreEnd();
939 }
940 return getList(GETSCHEMALIST,listformat,NULL,wild,0);
941 }
942
getTableList(const char * wild)943 bool sqlrcursor::getTableList(const char *wild) {
944 return getTableList(wild,SQLRCLIENTLISTFORMAT_MYSQL,
945 DB_OBJECT_TABLE|DB_OBJECT_VIEW|
946 DB_OBJECT_ALIAS|DB_OBJECT_SYNONYM);
947 }
948
getTableList(const char * wild,sqlrclientlistformat_t listformat,uint16_t objecttypes)949 bool sqlrcursor::getTableList(const char *wild,
950 sqlrclientlistformat_t listformat,
951 uint16_t objecttypes) {
952 if (pvt->_sqlrc->debug()) {
953 pvt->_sqlrc->debugPreStart();
954 pvt->_sqlrc->debugPrint("getting table list ");
955 if (wild) {
956 pvt->_sqlrc->debugPrint("\"");
957 pvt->_sqlrc->debugPrint(wild);
958 pvt->_sqlrc->debugPrint("\"");
959 }
960 pvt->_sqlrc->debugPrint("\n");
961 pvt->_sqlrc->debugPreEnd();
962 }
963 return getList(GETTABLELIST2,listformat,NULL,wild,objecttypes);
964 }
965
getTableTypeList(const char * wild)966 bool sqlrcursor::getTableTypeList(const char *wild) {
967 return getTableTypeList(wild,SQLRCLIENTLISTFORMAT_MYSQL);
968 }
969
getTableTypeList(const char * wild,sqlrclientlistformat_t listformat)970 bool sqlrcursor::getTableTypeList(const char *wild,
971 sqlrclientlistformat_t listformat) {
972 if (pvt->_sqlrc->debug()) {
973 pvt->_sqlrc->debugPreStart();
974 pvt->_sqlrc->debugPrint("getting table type list ");
975 if (wild) {
976 pvt->_sqlrc->debugPrint("\"");
977 pvt->_sqlrc->debugPrint(wild);
978 pvt->_sqlrc->debugPrint("\"");
979 }
980 pvt->_sqlrc->debugPrint("\n");
981 pvt->_sqlrc->debugPreEnd();
982 }
983 return getList(GETTABLETYPELIST,listformat,NULL,wild,0);
984 }
985
getColumnList(const char * table,const char * wild)986 bool sqlrcursor::getColumnList(const char *table, const char *wild) {
987 return getColumnList(table,wild,SQLRCLIENTLISTFORMAT_MYSQL);
988 }
989
getColumnList(const char * table,const char * wild,sqlrclientlistformat_t listformat)990 bool sqlrcursor::getColumnList(const char *table,
991 const char *wild,
992 sqlrclientlistformat_t listformat) {
993 if (pvt->_sqlrc->debug()) {
994 pvt->_sqlrc->debugPreStart();
995 pvt->_sqlrc->debugPrint("getting column list for: \"");
996 pvt->_sqlrc->debugPrint(table);
997 pvt->_sqlrc->debugPrint("\"");
998 if (wild) {
999 pvt->_sqlrc->debugPrint(" - \"");
1000 pvt->_sqlrc->debugPrint(wild);
1001 pvt->_sqlrc->debugPrint("\"");
1002 }
1003 pvt->_sqlrc->debugPrint("\n");
1004 pvt->_sqlrc->debugPreEnd();
1005 }
1006 return getList(GETCOLUMNLIST,listformat,(table)?table:"",wild,0);
1007 }
1008
getPrimaryKeysList(const char * table,const char * wild)1009 bool sqlrcursor::getPrimaryKeysList(const char *table, const char *wild) {
1010 return getPrimaryKeysList(table,wild,SQLRCLIENTLISTFORMAT_MYSQL);
1011 }
1012
getPrimaryKeysList(const char * table,const char * wild,sqlrclientlistformat_t listformat)1013 bool sqlrcursor::getPrimaryKeysList(const char *table,
1014 const char *wild,
1015 sqlrclientlistformat_t listformat) {
1016 if (pvt->_sqlrc->debug()) {
1017 pvt->_sqlrc->debugPreStart();
1018 pvt->_sqlrc->debugPrint("getting primary keys for: \"");
1019 pvt->_sqlrc->debugPrint(table);
1020 pvt->_sqlrc->debugPrint("\"");
1021 if (wild) {
1022 pvt->_sqlrc->debugPrint(" - \"");
1023 pvt->_sqlrc->debugPrint(wild);
1024 pvt->_sqlrc->debugPrint("\"");
1025 }
1026 pvt->_sqlrc->debugPrint("\n");
1027 pvt->_sqlrc->debugPreEnd();
1028 }
1029 return getList(GETPRIMARYKEYLIST,listformat,(table)?table:"",wild,0);
1030 }
1031
getKeyAndIndexList(const char * table,const char * qualifier)1032 bool sqlrcursor::getKeyAndIndexList(const char *table, const char *qualifier) {
1033 return getKeyAndIndexList(table,qualifier,SQLRCLIENTLISTFORMAT_MYSQL);
1034 }
1035
getKeyAndIndexList(const char * table,const char * qualifier,sqlrclientlistformat_t listformat)1036 bool sqlrcursor::getKeyAndIndexList(const char *table,
1037 const char *qualifier,
1038 sqlrclientlistformat_t listformat) {
1039 if (pvt->_sqlrc->debug()) {
1040 pvt->_sqlrc->debugPreStart();
1041 pvt->_sqlrc->debugPrint("getting keys and indexes for: \"");
1042 pvt->_sqlrc->debugPrint(table);
1043 pvt->_sqlrc->debugPrint("\"");
1044 if (qualifier) {
1045 pvt->_sqlrc->debugPrint(" - \"");
1046 pvt->_sqlrc->debugPrint(qualifier);
1047 pvt->_sqlrc->debugPrint("\"");
1048 }
1049 pvt->_sqlrc->debugPrint("\n");
1050 pvt->_sqlrc->debugPreEnd();
1051 }
1052 return getList(GETKEYANDINDEXLIST,listformat,
1053 (table)?table:"",qualifier,0);
1054 }
1055
getProcedureBindAndColumnList(const char * procedure,const char * wild)1056 bool sqlrcursor::getProcedureBindAndColumnList(
1057 const char *procedure,
1058 const char *wild) {
1059 return getProcedureBindAndColumnList(procedure,wild,
1060 SQLRCLIENTLISTFORMAT_MYSQL);
1061 }
1062
getProcedureBindAndColumnList(const char * procedure,const char * wild,sqlrclientlistformat_t listformat)1063 bool sqlrcursor::getProcedureBindAndColumnList(
1064 const char *procedure,
1065 const char *wild,
1066 sqlrclientlistformat_t listformat) {
1067 if (pvt->_sqlrc->debug()) {
1068 pvt->_sqlrc->debugPreStart();
1069 pvt->_sqlrc->debugPrint("getting procedure bind "
1070 "and column list for: \"");
1071 pvt->_sqlrc->debugPrint(procedure);
1072 pvt->_sqlrc->debugPrint("\"");
1073 if (wild) {
1074 pvt->_sqlrc->debugPrint(" - \"");
1075 pvt->_sqlrc->debugPrint(wild);
1076 pvt->_sqlrc->debugPrint("\"");
1077 }
1078 pvt->_sqlrc->debugPrint("\n");
1079 pvt->_sqlrc->debugPreEnd();
1080 }
1081 return getList(GETPROCEDUREBINDANDCOLUMNLIST,
1082 listformat,(procedure)?procedure:"",wild,0);
1083 }
1084
getTypeInfoList(const char * type,const char * wild)1085 bool sqlrcursor::getTypeInfoList(const char *type, const char *wild) {
1086 return getTypeInfoList(type,wild,SQLRCLIENTLISTFORMAT_MYSQL);
1087 }
1088
getTypeInfoList(const char * type,const char * wild,sqlrclientlistformat_t listformat)1089 bool sqlrcursor::getTypeInfoList(const char *type,
1090 const char *wild,
1091 sqlrclientlistformat_t listformat) {
1092 if (pvt->_sqlrc->debug()) {
1093 pvt->_sqlrc->debugPreStart();
1094 pvt->_sqlrc->debugPrint("getting type info for: \"");
1095 pvt->_sqlrc->debugPrint(type);
1096 pvt->_sqlrc->debugPrint("\"");
1097 if (wild) {
1098 pvt->_sqlrc->debugPrint(" - \"");
1099 pvt->_sqlrc->debugPrint(wild);
1100 pvt->_sqlrc->debugPrint("\"");
1101 }
1102 pvt->_sqlrc->debugPrint("\n");
1103 pvt->_sqlrc->debugPreEnd();
1104 }
1105 return getList(GETTYPEINFOLIST,listformat,(type)?type:"",wild,0);
1106 }
1107
getProcedureList(const char * wild)1108 bool sqlrcursor::getProcedureList(const char *wild) {
1109 return getProcedureList(wild,SQLRCLIENTLISTFORMAT_MYSQL);
1110 }
1111
getProcedureList(const char * wild,sqlrclientlistformat_t listformat)1112 bool sqlrcursor::getProcedureList(const char *wild,
1113 sqlrclientlistformat_t listformat) {
1114 if (pvt->_sqlrc->debug()) {
1115 pvt->_sqlrc->debugPreStart();
1116 pvt->_sqlrc->debugPrint("getting procedure list ");
1117 if (wild) {
1118 pvt->_sqlrc->debugPrint("\"");
1119 pvt->_sqlrc->debugPrint(wild);
1120 pvt->_sqlrc->debugPrint("\"");
1121 }
1122 pvt->_sqlrc->debugPrint("\n");
1123 pvt->_sqlrc->debugPreEnd();
1124 }
1125 return getList(GETPROCEDURELIST,listformat,NULL,wild,0);
1126 }
1127
getList(uint16_t command,sqlrclientlistformat_t listformat,const char * table,const char * wild,uint16_t objecttypes)1128 bool sqlrcursor::getList(uint16_t command, sqlrclientlistformat_t listformat,
1129 const char *table, const char *wild,
1130 uint16_t objecttypes) {
1131
1132 pvt->_reexecute=false;
1133 pvt->_validatebinds=false;
1134 pvt->_resumed=false;
1135 clearVariables();
1136
1137 if (!pvt->_endofresultset) {
1138 closeResultSet(false);
1139 }
1140 clearResultSet();
1141
1142 if (!pvt->_sqlrc->openSession()) {
1143 return false;
1144 }
1145
1146 pvt->_cached=false;
1147 pvt->_endofresultset=false;
1148
1149 // refresh socket client
1150 pvt->_cs=pvt->_sqlrc->cs();
1151
1152 // tell the server we want to get a list
1153 pvt->_cs->write(command);
1154
1155 // tell the server whether we'll need a cursor or not
1156 sendCursorStatus();
1157
1158 // send the list format
1159 pvt->_cs->write((uint16_t)listformat);
1160
1161 // send the wild parameter
1162 uint32_t len=charstring::length(wild);
1163 pvt->_cs->write(len);
1164 if (len) {
1165 pvt->_cs->write(wild,len);
1166 }
1167
1168 // send the table parameter
1169 if (table) {
1170 len=charstring::length(table);
1171 pvt->_cs->write(len);
1172 if (len) {
1173 pvt->_cs->write(table,len);
1174 }
1175 }
1176
1177 // send the objecttypes parameter
1178 if (command==GETTABLELIST2) {
1179 pvt->_cs->write(objecttypes);
1180 }
1181
1182 pvt->_sqlrc->flushWriteBuffer();
1183
1184 // process the initial result set
1185 bool retval=processInitialResultSet();
1186
1187 // set up not to re-execute the same query if executeQuery is called
1188 // again before calling prepareQuery on a new query
1189 pvt->_reexecute=false;
1190
1191 return retval;
1192 }
1193
sendQuery(const char * query)1194 bool sqlrcursor::sendQuery(const char *query) {
1195 prepareQuery(query);
1196 return executeQuery();
1197 }
1198
sendQuery(const char * query,uint32_t length)1199 bool sqlrcursor::sendQuery(const char *query, uint32_t length) {
1200 prepareQuery(query,length);
1201 return executeQuery();
1202 }
1203
sendFileQuery(const char * path,const char * filename)1204 bool sqlrcursor::sendFileQuery(const char *path, const char *filename) {
1205 return prepareFileQuery(path,filename) && executeQuery();
1206 }
1207
prepareQuery(const char * query)1208 void sqlrcursor::prepareQuery(const char *query) {
1209 prepareQuery(query,charstring::length(query));
1210 }
1211
prepareQuery(const char * query,uint32_t length)1212 void sqlrcursor::prepareQuery(const char *query, uint32_t length) {
1213 pvt->_reexecute=false;
1214 pvt->_validatebinds=false;
1215 pvt->_resumed=false;
1216 clearVariables(pvt->_clearbindsduringprepare);
1217 pvt->_querylen=length;
1218 if (pvt->_copyrefs) {
1219 initQueryBuffer(pvt->_querylen);
1220 charstring::copy(pvt->_querybuffer,query,pvt->_querylen);
1221 pvt->_querybuffer[pvt->_querylen]='\0';
1222 } else {
1223 pvt->_queryptr=query;
1224 }
1225 }
1226
prepareFileQuery(const char * path,const char * filename)1227 bool sqlrcursor::prepareFileQuery(const char *path, const char *filename) {
1228
1229 // init some variables
1230 pvt->_reexecute=false;
1231 pvt->_validatebinds=false;
1232 pvt->_resumed=false;
1233 clearVariables();
1234
1235 // init the fullpath buffer
1236 if (!pvt->_fullpath) {
1237 pvt->_fullpath=new char[MAXPATHLEN+1];
1238 }
1239
1240 // add the path to the fullpath
1241 uint32_t index=0;
1242 uint32_t counter=0;
1243 if (path) {
1244 while (path[index] && counter<MAXPATHLEN) {
1245 pvt->_fullpath[counter]=path[index];
1246 index++;
1247 counter++;
1248 }
1249
1250 // add the "/" to the fullpath
1251 if (counter<=MAXPATHLEN) {
1252 pvt->_fullpath[counter]='/';
1253 counter++;
1254 }
1255 }
1256
1257 // add the file to the fullpath
1258 index=0;
1259 while (filename[index] && counter<MAXPATHLEN) {
1260 pvt->_fullpath[counter]=filename[index];
1261 index++;
1262 counter++;
1263 }
1264
1265 // handle a filename that's too long
1266 if (counter>MAXPATHLEN) {
1267
1268 // sabotage the file name so it can't be opened
1269 pvt->_fullpath[0]='\0';
1270
1271 // debug info
1272 if (pvt->_sqlrc->debug()) {
1273 pvt->_sqlrc->debugPreStart();
1274 pvt->_sqlrc->debugPrint("File name ");
1275 if (path) {
1276 pvt->_sqlrc->debugPrint((char *)path);
1277 pvt->_sqlrc->debugPrint("/");
1278 }
1279 pvt->_sqlrc->debugPrint((char *)filename);
1280 pvt->_sqlrc->debugPrint(" is too long.");
1281 pvt->_sqlrc->debugPrint("\n");
1282 pvt->_sqlrc->debugPreEnd();
1283 }
1284
1285 } else {
1286
1287 // terminate the string
1288 pvt->_fullpath[counter]='\0';
1289
1290 // debug info
1291 if (pvt->_sqlrc->debug()) {
1292 pvt->_sqlrc->debugPreStart();
1293 pvt->_sqlrc->debugPrint("File: ");
1294 pvt->_sqlrc->debugPrint(pvt->_fullpath);
1295 pvt->_sqlrc->debugPrint("\n");
1296 pvt->_sqlrc->debugPreEnd();
1297 }
1298 }
1299
1300 // open the file
1301 file queryfile;
1302 if (!queryfile.open(pvt->_fullpath,O_RDONLY)) {
1303
1304 // set the error
1305 char *err=new char[32+charstring::length(pvt->_fullpath)];
1306 charstring::append(err,"The file ");
1307 charstring::append(err,pvt->_fullpath);
1308 charstring::append(err," could not be opened.\n");
1309 if (pvt->_sqlrc->debug()) {
1310 pvt->_sqlrc->debugPreStart();
1311 pvt->_sqlrc->debugPrint(err);
1312 pvt->_sqlrc->debugPreEnd();
1313 }
1314 setError(err);
1315
1316 // set queryptr to NULL so executeQuery won't try to do
1317 // anything with it in the event that it gets called
1318 pvt->_queryptr=NULL;
1319
1320 delete[] err;
1321
1322 return false;
1323 }
1324
1325 initQueryBuffer(queryfile.getSize());
1326
1327 // read the file into the query buffer
1328 pvt->_querylen=queryfile.getSize();
1329 queryfile.read((unsigned char *)pvt->_querybuffer,pvt->_querylen);
1330 pvt->_querybuffer[pvt->_querylen]='\0';
1331
1332 queryfile.close();
1333
1334 return true;
1335 }
1336
initQueryBuffer(uint32_t querylength)1337 void sqlrcursor::initQueryBuffer(uint32_t querylength) {
1338 delete[] pvt->_querybuffer;
1339 pvt->_querybuffer=new char[querylength+1];
1340 pvt->_queryptr=pvt->_querybuffer;
1341 }
1342
attachToBindCursor(uint16_t bindcursorid)1343 void sqlrcursor::attachToBindCursor(uint16_t bindcursorid) {
1344 prepareQuery("");
1345 pvt->_reexecute=true;
1346 pvt->_cursorid=bindcursorid;
1347 }
1348
countBindVariables() const1349 uint16_t sqlrcursor::countBindVariables() const {
1350 return ::countBindVariables(pvt->_queryptr,pvt->_querylen,
1351 pvt->_sqlrc->getBindVariableDelimiterQuestionMarkSupported(),
1352 pvt->_sqlrc->getBindVariableDelimiterColonSupported(),
1353 pvt->_sqlrc->getBindVariableDelimiterAtSignSupported(),
1354 pvt->_sqlrc->getBindVariableDelimiterDollarSignSupported());
1355 }
1356
clearVariables()1357 void sqlrcursor::clearVariables() {
1358 clearVariables(true);
1359 }
1360
clearVariables(bool clearbinds)1361 void sqlrcursor::clearVariables(bool clearbinds) {
1362 deleteSubstitutionVariables();
1363 pvt->_subvars->clear();
1364 pvt->_dirtysubs=false;
1365 if (clearbinds) {
1366 pvt->_dirtybinds=false;
1367 clearBinds();
1368 }
1369 }
1370
deleteVariables()1371 void sqlrcursor::deleteVariables() {
1372 deleteSubstitutionVariables();
1373 deleteInputBindVariables();
1374 deleteOutputBindVariables();
1375 deleteInputOutputBindVariables();
1376 }
1377
deleteSubstitutionVariables()1378 void sqlrcursor::deleteSubstitutionVariables() {
1379
1380 if (pvt->_copyrefs) {
1381 for (uint64_t i=0; i<pvt->_subvars->getLength(); i++) {
1382 delete[] (*pvt->_subvars)[i].variable;
1383 if ((*pvt->_subvars)[i].type==
1384 SQLRCLIENTBINDVARTYPE_STRING) {
1385 delete[] (*pvt->_subvars)[i].value.stringval;
1386 }
1387 if ((*pvt->_subvars)[i].type==
1388 SQLRCLIENTBINDVARTYPE_DATE) {
1389 delete[] (*pvt->_subvars)[i].value.dateval.tz;
1390 }
1391 }
1392 }
1393 }
1394
deleteInputBindVariables()1395 void sqlrcursor::deleteInputBindVariables() {
1396
1397 if (pvt->_copyrefs) {
1398 for (uint64_t i=0; i<pvt->_inbindvars->getLength(); i++) {
1399 delete[] (*pvt->_inbindvars)[i].variable;
1400 if ((*pvt->_inbindvars)[i].type==
1401 SQLRCLIENTBINDVARTYPE_STRING) {
1402 delete[] (*pvt->_inbindvars)[i].value.stringval;
1403 }
1404 if ((*pvt->_inbindvars)[i].type==
1405 SQLRCLIENTBINDVARTYPE_BLOB ||
1406 (*pvt->_inbindvars)[i].type==
1407 SQLRCLIENTBINDVARTYPE_CLOB) {
1408 delete[] (*pvt->_inbindvars)[i].value.lobval;
1409 }
1410 if ((*pvt->_inbindvars)[i].type==
1411 SQLRCLIENTBINDVARTYPE_DATE) {
1412 delete[] (*pvt->_inbindvars)[i].
1413 value.dateval.tz;
1414 }
1415 }
1416 }
1417 }
1418
deleteOutputBindVariables()1419 void sqlrcursor::deleteOutputBindVariables() {
1420
1421 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
1422 if (pvt->_copyrefs) {
1423 delete[] (*pvt->_outbindvars)[i].variable;
1424 }
1425 if ((*pvt->_outbindvars)[i].type==
1426 SQLRCLIENTBINDVARTYPE_STRING) {
1427 delete[] (*pvt->_outbindvars)[i].value.stringval;
1428 }
1429 if ((*pvt->_outbindvars)[i].type==
1430 SQLRCLIENTBINDVARTYPE_BLOB ||
1431 (*pvt->_outbindvars)[i].type==
1432 SQLRCLIENTBINDVARTYPE_CLOB) {
1433 delete[] (*pvt->_outbindvars)[i].value.lobval;
1434 }
1435 if ((*pvt->_outbindvars)[i].type==
1436 SQLRCLIENTBINDVARTYPE_DATE) {
1437 delete[] (*pvt->_outbindvars)[i].value.dateval.tz;
1438 }
1439 }
1440 }
1441
deleteInputOutputBindVariables()1442 void sqlrcursor::deleteInputOutputBindVariables() {
1443
1444 for (uint64_t i=0; i<pvt->_inoutbindvars->getLength(); i++) {
1445 if (pvt->_copyrefs) {
1446 delete[] (*pvt->_inoutbindvars)[i].variable;
1447 }
1448 if ((*pvt->_inoutbindvars)[i].type==
1449 SQLRCLIENTBINDVARTYPE_STRING) {
1450 delete[] (*pvt->_inoutbindvars)[i].value.stringval;
1451 }
1452 if ((*pvt->_inoutbindvars)[i].type==
1453 SQLRCLIENTBINDVARTYPE_BLOB ||
1454 (*pvt->_inoutbindvars)[i].type==
1455 SQLRCLIENTBINDVARTYPE_CLOB) {
1456 delete[] (*pvt->_inoutbindvars)[i].value.lobval;
1457 }
1458 if ((*pvt->_inoutbindvars)[i].type==
1459 SQLRCLIENTBINDVARTYPE_DATE) {
1460 delete[] (*pvt->_inoutbindvars)[i].value.dateval.tz;
1461 }
1462 }
1463 }
1464
substitution(const char * variable,const char * value)1465 void sqlrcursor::substitution(const char *variable, const char *value) {
1466 if (charstring::isNullOrEmpty(variable)) {
1467 return;
1468 }
1469 bool preexisting=true;
1470 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_subvars);
1471 if (!bv) {
1472 bv=&(*pvt->_subvars)[pvt->_subvars->getLength()];
1473 preexisting=false;
1474 }
1475 initVar(bv,variable,preexisting);
1476 stringVar(bv,variable,value);
1477 pvt->_dirtysubs=true;
1478 }
1479
substitution(const char * variable,int64_t value)1480 void sqlrcursor::substitution(const char *variable, int64_t value) {
1481 if (charstring::isNullOrEmpty(variable)) {
1482 return;
1483 }
1484 bool preexisting=true;
1485 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_subvars);
1486 if (!bv) {
1487 bv=&(*pvt->_subvars)[pvt->_subvars->getLength()];
1488 preexisting=false;
1489 }
1490 initVar(bv,variable,preexisting);
1491 integerVar(bv,variable,value);
1492 pvt->_dirtysubs=true;
1493 }
1494
substitution(const char * variable,double value,uint32_t precision,uint32_t scale)1495 void sqlrcursor::substitution(const char *variable, double value,
1496 uint32_t precision, uint32_t scale) {
1497 if (charstring::isNullOrEmpty(variable)) {
1498 return;
1499 }
1500 bool preexisting=true;
1501 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_subvars);
1502 if (!bv) {
1503 bv=&(*pvt->_subvars)[pvt->_subvars->getLength()];
1504 preexisting=false;
1505 }
1506 initVar(bv,variable,preexisting);
1507 doubleVar(bv,variable,value,precision,scale);
1508 pvt->_dirtysubs=true;
1509 }
1510
clearBinds()1511 void sqlrcursor::clearBinds() {
1512
1513 deleteInputBindVariables();
1514 pvt->_inbindvars->clear();
1515
1516 deleteOutputBindVariables();
1517 pvt->_outbindvars->clear();
1518
1519 deleteInputOutputBindVariables();
1520 pvt->_inoutbindvars->clear();
1521 }
1522
inputBindBlob(const char * variable,const char * value,uint32_t size)1523 void sqlrcursor::inputBindBlob(const char *variable, const char *value,
1524 uint32_t size) {
1525 if (charstring::isNullOrEmpty(variable)) {
1526 return;
1527 }
1528 bool preexisting=true;
1529 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1530 if (!bv) {
1531 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1532 preexisting=false;
1533 }
1534 initVar(bv,variable,preexisting);
1535 lobVar(bv,variable,value,size,SQLRCLIENTBINDVARTYPE_BLOB);
1536 bv->send=true;
1537 pvt->_dirtybinds=true;
1538 }
1539
inputBindClob(const char * variable,const char * value,uint32_t size)1540 void sqlrcursor::inputBindClob(const char *variable, const char *value,
1541 uint32_t size) {
1542 if (charstring::isNullOrEmpty(variable)) {
1543 return;
1544 }
1545 bool preexisting=true;
1546 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1547 if (!bv) {
1548 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1549 preexisting=false;
1550 }
1551 initVar(bv,variable,preexisting);
1552 lobVar(bv,variable,value,size,SQLRCLIENTBINDVARTYPE_CLOB);
1553 bv->send=true;
1554 pvt->_dirtybinds=true;
1555 }
1556
inputBind(const char * variable,const char * value)1557 void sqlrcursor::inputBind(const char *variable, const char *value) {
1558 if (charstring::isNullOrEmpty(variable)) {
1559 return;
1560 }
1561 bool preexisting=true;
1562 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1563 if (!bv) {
1564 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1565 preexisting=false;
1566 }
1567 initVar(bv,variable,preexisting);
1568 stringVar(bv,variable,value);
1569 bv->send=true;
1570 pvt->_dirtybinds=true;
1571 }
1572
inputBind(const char * variable,const char * value,uint32_t valuesize)1573 void sqlrcursor::inputBind(const char *variable, const char *value,
1574 uint32_t valuesize) {
1575 if (charstring::isNullOrEmpty(variable)) {
1576 return;
1577 }
1578 bool preexisting=true;
1579 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1580 if (!bv) {
1581 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1582 preexisting=false;
1583 }
1584 initVar(bv,variable,preexisting);
1585 stringVar(bv,variable,value,valuesize);
1586 bv->send=true;
1587 pvt->_dirtybinds=true;
1588 }
1589
inputBind(const char * variable,int64_t value)1590 void sqlrcursor::inputBind(const char *variable, int64_t value) {
1591 if (charstring::isNullOrEmpty(variable)) {
1592 return;
1593 }
1594 bool preexisting=true;
1595 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1596 if (!bv) {
1597 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1598 preexisting=false;
1599 }
1600 initVar(bv,variable,preexisting);
1601 integerVar(bv,variable,value);
1602 bv->send=true;
1603 pvt->_dirtybinds=true;
1604 }
1605
inputBind(const char * variable,double value,uint32_t precision,uint32_t scale)1606 void sqlrcursor::inputBind(const char *variable, double value,
1607 uint32_t precision, uint32_t scale) {
1608 if (charstring::isNullOrEmpty(variable)) {
1609 return;
1610 }
1611 bool preexisting=true;
1612 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1613 if (!bv) {
1614 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1615 preexisting=false;
1616 }
1617 initVar(bv,variable,preexisting);
1618 doubleVar(bv,variable,value,precision,scale);
1619 bv->send=true;
1620 pvt->_dirtybinds=true;
1621 }
1622
inputBind(const char * variable,int16_t year,int16_t month,int16_t day,int16_t hour,int16_t minute,int16_t second,int32_t microsecond,const char * tz,bool isnegative)1623 void sqlrcursor::inputBind(const char *variable,
1624 int16_t year, int16_t month, int16_t day,
1625 int16_t hour, int16_t minute, int16_t second,
1626 int32_t microsecond, const char *tz,
1627 bool isnegative) {
1628 if (charstring::isNullOrEmpty(variable)) {
1629 return;
1630 }
1631 bool preexisting=true;
1632 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inbindvars);
1633 if (!bv) {
1634 bv=&(*pvt->_inbindvars)[pvt->_inbindvars->getLength()];
1635 preexisting=false;
1636 }
1637 initVar(bv,variable,preexisting);
1638 dateVar(bv,variable,year,month,day,hour,
1639 minute,second,microsecond,tz,isnegative);
1640 bv->send=true;
1641 pvt->_dirtybinds=true;
1642 }
1643
substitutions(const char ** variables,const char ** values)1644 void sqlrcursor::substitutions(const char **variables, const char **values) {
1645 for (uint16_t i=0; variables[i]; i++) {
1646 substitution(variables[i],values[i]);
1647 }
1648 }
1649
substitutions(const char ** variables,const int64_t * values)1650 void sqlrcursor::substitutions(const char **variables, const int64_t *values) {
1651 for (uint16_t i=0; variables[i]; i++) {
1652 substitution(variables[i],values[i]);
1653 }
1654 }
1655
substitutions(const char ** variables,const double * values,const uint32_t * precisions,const uint32_t * scales)1656 void sqlrcursor::substitutions(const char **variables, const double *values,
1657 const uint32_t *precisions,
1658 const uint32_t *scales) {
1659 for (uint16_t i=0; variables[i]; i++) {
1660 substitution(variables[i],values[i],precisions[i],scales[i]);
1661 }
1662 }
1663
inputBinds(const char ** variables,const char ** values)1664 void sqlrcursor::inputBinds(const char **variables, const char **values) {
1665 for (uint16_t i=0; variables[i]; i++) {
1666 inputBind(variables[i],values[i]);
1667 }
1668 }
1669
inputBinds(const char ** variables,const int64_t * values)1670 void sqlrcursor::inputBinds(const char **variables, const int64_t *values) {
1671 for (uint16_t i=0; variables[i]; i++) {
1672 inputBind(variables[i],values[i]);
1673 }
1674 }
1675
inputBinds(const char ** variables,const double * values,const uint32_t * precisions,const uint32_t * scales)1676 void sqlrcursor::inputBinds(const char **variables, const double *values,
1677 const uint32_t *precisions,
1678 const uint32_t *scales) {
1679 for (uint16_t i=0; variables[i]; i++) {
1680 inputBind(variables[i],values[i],
1681 precisions[i],scales[i]);
1682 }
1683 }
1684
stringVar(sqlrclientbindvar * var,const char * variable,const char * value)1685 void sqlrcursor::stringVar(sqlrclientbindvar *var,
1686 const char *variable,
1687 const char *value) {
1688 stringVar(var,variable,value,charstring::length(value));
1689 }
1690
stringVar(sqlrclientbindvar * var,const char * variable,const char * value,uint32_t valuesize)1691 void sqlrcursor::stringVar(sqlrclientbindvar *var,
1692 const char *variable,
1693 const char *value,
1694 uint32_t valuesize) {
1695
1696 // store the value, handle NULL values too
1697 if (value) {
1698 if (pvt->_copyrefs) {
1699 var->value.stringval=charstring::duplicate(value);
1700 } else {
1701 var->value.stringval=(char *)value;
1702 }
1703 var->valuesize=valuesize;
1704 var->type=SQLRCLIENTBINDVARTYPE_STRING;
1705 } else {
1706 var->type=SQLRCLIENTBINDVARTYPE_NULL;
1707 }
1708 }
1709
integerVar(sqlrclientbindvar * var,const char * variable,int64_t value)1710 void sqlrcursor::integerVar(sqlrclientbindvar *var,
1711 const char *variable,
1712 int64_t value) {
1713 var->type=SQLRCLIENTBINDVARTYPE_INTEGER;
1714 var->value.integerval=value;
1715 }
1716
doubleVar(sqlrclientbindvar * var,const char * variable,double value,uint32_t precision,uint32_t scale)1717 void sqlrcursor::doubleVar(sqlrclientbindvar *var,
1718 const char *variable,
1719 double value,
1720 uint32_t precision,
1721 uint32_t scale) {
1722 var->type=SQLRCLIENTBINDVARTYPE_DOUBLE;
1723 var->value.doubleval.value=value;
1724 var->value.doubleval.precision=precision;
1725 var->value.doubleval.scale=scale;
1726 }
1727
dateVar(sqlrclientbindvar * var,const char * variable,int16_t year,int16_t month,int16_t day,int16_t hour,int16_t minute,int16_t second,int32_t microsecond,const char * tz,bool isnegative)1728 void sqlrcursor::dateVar(sqlrclientbindvar *var,
1729 const char *variable,
1730 int16_t year,
1731 int16_t month,
1732 int16_t day,
1733 int16_t hour,
1734 int16_t minute,
1735 int16_t second,
1736 int32_t microsecond,
1737 const char *tz,
1738 bool isnegative) {
1739 var->type=SQLRCLIENTBINDVARTYPE_DATE;
1740 var->value.dateval.year=year;
1741 var->value.dateval.month=month;
1742 var->value.dateval.day=day;
1743 var->value.dateval.hour=hour;
1744 var->value.dateval.minute=minute;
1745 var->value.dateval.second=second;
1746 var->value.dateval.microsecond=microsecond;
1747 var->value.dateval.isnegative=isnegative;
1748 if (pvt->_copyrefs) {
1749 var->value.dateval.tz=charstring::duplicate(tz);
1750 } else {
1751 var->value.dateval.tz=(char *)tz;
1752 }
1753 }
1754
lobVar(sqlrclientbindvar * var,const char * variable,const char * value,uint32_t size,sqlrclientbindvartype_t type)1755 void sqlrcursor::lobVar(sqlrclientbindvar *var,
1756 const char *variable,
1757 const char *value,
1758 uint32_t size,
1759 sqlrclientbindvartype_t type) {
1760
1761 // Store the value, handle NULL values too.
1762 // For LOB's empty strings are handled as NULL's as well, this is
1763 // probably not right, but I can't get empty string lob binds to work.
1764 if (value && size>0) {
1765 if (pvt->_copyrefs) {
1766 var->value.lobval=new char[size];
1767 bytestring::copy(var->value.lobval,value,size);
1768 } else {
1769 var->value.lobval=(char *)value;
1770 }
1771 var->valuesize=size;
1772 var->type=type;
1773 } else {
1774 var->type=SQLRCLIENTBINDVARTYPE_NULL;
1775 }
1776 }
1777
initVar(sqlrclientbindvar * var,const char * variable,bool preexisting)1778 void sqlrcursor::initVar(sqlrclientbindvar *var,
1779 const char *variable,
1780 bool preexisting) {
1781
1782 // clear any old variable name that was stored and assign the new
1783 // variable name also clear any old value that was stored in this
1784 // variable
1785 if (pvt->_copyrefs) {
1786 if (preexisting) {
1787 delete[] var->variable;
1788 if (var->type==SQLRCLIENTBINDVARTYPE_STRING) {
1789 delete[] var->value.stringval;
1790 } else if (var->type==SQLRCLIENTBINDVARTYPE_BLOB ||
1791 var->type==SQLRCLIENTBINDVARTYPE_CLOB) {
1792 delete[] var->value.lobval;
1793 }
1794 }
1795 var->variable=charstring::duplicate(variable);
1796 } else {
1797 var->variable=(char *)variable;
1798 }
1799
1800 var->substituted=false;
1801 var->donesubstituting=false;
1802 }
1803
defineOutputBindString(const char * variable,uint32_t length)1804 void sqlrcursor::defineOutputBindString(const char *variable,
1805 uint32_t length) {
1806 defineOutputBindGeneric(variable,
1807 SQLRCLIENTBINDVARTYPE_STRING,length);
1808 }
1809
defineOutputBindInteger(const char * variable)1810 void sqlrcursor::defineOutputBindInteger(const char *variable) {
1811 defineOutputBindGeneric(variable,
1812 SQLRCLIENTBINDVARTYPE_INTEGER,sizeof(int64_t));
1813 }
1814
defineOutputBindDouble(const char * variable)1815 void sqlrcursor::defineOutputBindDouble(const char *variable) {
1816 defineOutputBindGeneric(variable,
1817 SQLRCLIENTBINDVARTYPE_DOUBLE,sizeof(double));
1818 }
1819
defineOutputBindDate(const char * variable)1820 void sqlrcursor::defineOutputBindDate(const char *variable) {
1821 defineOutputBindGeneric(variable,
1822 SQLRCLIENTBINDVARTYPE_DATE,0);
1823 }
1824
defineOutputBindBlob(const char * variable)1825 void sqlrcursor::defineOutputBindBlob(const char *variable) {
1826 defineOutputBindGeneric(variable,
1827 SQLRCLIENTBINDVARTYPE_BLOB,0);
1828 }
1829
defineOutputBindClob(const char * variable)1830 void sqlrcursor::defineOutputBindClob(const char *variable) {
1831 defineOutputBindGeneric(variable,
1832 SQLRCLIENTBINDVARTYPE_CLOB,0);
1833 }
1834
defineOutputBindCursor(const char * variable)1835 void sqlrcursor::defineOutputBindCursor(const char *variable) {
1836 defineOutputBindGeneric(variable,
1837 SQLRCLIENTBINDVARTYPE_CURSOR,0);
1838 }
1839
defineOutputBindGeneric(const char * variable,sqlrclientbindvartype_t type,uint32_t valuesize)1840 void sqlrcursor::defineOutputBindGeneric(const char *variable,
1841 sqlrclientbindvartype_t type,
1842 uint32_t valuesize) {
1843
1844 if (charstring::isNullOrEmpty(variable)) {
1845 return;
1846 }
1847
1848 bool preexisting=true;
1849 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_outbindvars);
1850 if (!bv) {
1851 bv=&(*pvt->_outbindvars)[pvt->_outbindvars->getLength()];
1852 preexisting=false;
1853 pvt->_dirtybinds=true;
1854 }
1855
1856 // clean up old values and set new values
1857 if (preexisting) {
1858 if (bv->type==SQLRCLIENTBINDVARTYPE_STRING) {
1859 delete[] bv->value.stringval;
1860 } else if (bv->type==SQLRCLIENTBINDVARTYPE_BLOB ||
1861 bv->type==SQLRCLIENTBINDVARTYPE_CLOB) {
1862 delete[] bv->value.lobval;
1863 }
1864 }
1865 if (pvt->_copyrefs) {
1866 if (preexisting) {
1867 delete[] bv->variable;
1868 }
1869 bv->variable=charstring::duplicate(variable);
1870 } else {
1871 bv->variable=(char *)variable;
1872 }
1873 bv->type=type;
1874 if (bv->type==SQLRCLIENTBINDVARTYPE_STRING) {
1875 bv->value.stringval=NULL;
1876 } else if (bv->type==SQLRCLIENTBINDVARTYPE_BLOB ||
1877 bv->type==SQLRCLIENTBINDVARTYPE_CLOB) {
1878 bv->value.lobval=NULL;
1879 }
1880 bv->valuesize=valuesize;
1881 bv->resultvaluesize=0;
1882 bv->send=true;
1883 }
1884
defineInputOutputBindString(const char * variable,const char * value,uint32_t length)1885 void sqlrcursor::defineInputOutputBindString(const char *variable,
1886 const char *value,
1887 uint32_t length) {
1888 defineInputOutputBindGeneric(variable,
1889 SQLRCLIENTBINDVARTYPE_STRING,
1890 value,0,0.0,0,0,
1891 0,0,0,0,0,0,0,NULL,false,
1892 length);
1893 }
1894
defineInputOutputBindInteger(const char * variable,int64_t value)1895 void sqlrcursor::defineInputOutputBindInteger(const char *variable,
1896 int64_t value) {
1897 defineInputOutputBindGeneric(variable,
1898 SQLRCLIENTBINDVARTYPE_INTEGER,
1899 NULL,value,0.0,0,0,
1900 0,0,0,0,0,0,0,NULL,false,
1901 sizeof(int64_t));
1902 }
1903
defineInputOutputBindDouble(const char * variable,double value,uint32_t precision,uint32_t scale)1904 void sqlrcursor::defineInputOutputBindDouble(const char *variable,
1905 double value,
1906 uint32_t precision,
1907 uint32_t scale) {
1908 defineInputOutputBindGeneric(variable,
1909 SQLRCLIENTBINDVARTYPE_DOUBLE,
1910 NULL,0,value,precision,scale,
1911 0,0,0,0,0,0,0,NULL,false,
1912 sizeof(double));
1913 }
1914
defineInputOutputBindDate(const char * variable,int16_t year,int16_t month,int16_t day,int16_t hour,int16_t minute,int16_t second,int32_t microsecond,const char * tz,bool isnegative)1915 void sqlrcursor::defineInputOutputBindDate(const char *variable,
1916 int16_t year,
1917 int16_t month,
1918 int16_t day,
1919 int16_t hour,
1920 int16_t minute,
1921 int16_t second,
1922 int32_t microsecond,
1923 const char *tz,
1924 bool isnegative) {
1925 defineInputOutputBindGeneric(variable,
1926 SQLRCLIENTBINDVARTYPE_DATE,
1927 NULL,0,0.0,0,0,
1928 year,month,day,minute,
1929 hour,second,microsecond,
1930 tz,isnegative,
1931 0);
1932 }
1933
defineOutputBindBlob(const char * variable,const char * value,uint32_t size)1934 void sqlrcursor::defineOutputBindBlob(const char *variable,
1935 const char *value,
1936 uint32_t size) {
1937 // FIXME: implement this...
1938 }
1939
defineOutputBindClob(const char * variable,const char * value,uint32_t size)1940 void sqlrcursor::defineOutputBindClob(const char *variable,
1941 const char *value,
1942 uint32_t size) {
1943 // FIXME: implement this...
1944 }
1945
defineInputOutputBindGeneric(const char * variable,sqlrclientbindvartype_t type,const char * strvalue,int64_t intvalue,double doublevalue,uint32_t precision,uint32_t scale,int16_t year,int16_t month,int16_t day,int16_t hour,int16_t minute,int16_t second,int32_t microsecond,const char * tz,bool isnegative,uint32_t valuesize)1946 void sqlrcursor::defineInputOutputBindGeneric(const char *variable,
1947 sqlrclientbindvartype_t type,
1948 const char *strvalue,
1949 int64_t intvalue,
1950 double doublevalue,
1951 uint32_t precision,
1952 uint32_t scale,
1953 int16_t year,
1954 int16_t month,
1955 int16_t day,
1956 int16_t hour,
1957 int16_t minute,
1958 int16_t second,
1959 int32_t microsecond,
1960 const char *tz,
1961 bool isnegative,
1962 uint32_t valuesize) {
1963
1964 if (charstring::isNullOrEmpty(variable)) {
1965 return;
1966 }
1967
1968 bool preexisting=true;
1969 sqlrclientbindvar *bv=pvt->findVar(variable,pvt->_inoutbindvars);
1970 if (!bv) {
1971 bv=&(*pvt->_inoutbindvars)[pvt->_inoutbindvars->getLength()];
1972 preexisting=false;
1973 pvt->_dirtybinds=true;
1974 }
1975
1976 // clean up old values and set new values
1977 if (preexisting) {
1978 if (bv->type==SQLRCLIENTBINDVARTYPE_STRING) {
1979 delete[] bv->value.stringval;
1980 } else if (bv->type==SQLRCLIENTBINDVARTYPE_BLOB ||
1981 bv->type==SQLRCLIENTBINDVARTYPE_CLOB) {
1982 delete[] bv->value.lobval;
1983 }
1984 }
1985 if (pvt->_copyrefs) {
1986 if (preexisting) {
1987 delete[] bv->variable;
1988 }
1989 bv->variable=charstring::duplicate(variable);
1990 } else {
1991 bv->variable=(char *)variable;
1992 }
1993 bv->type=type;
1994 if (bv->type==SQLRCLIENTBINDVARTYPE_STRING) {
1995 bv->value.stringval=new char[valuesize+1];
1996 if (strvalue) {
1997 charstring::copy(bv->value.stringval,
1998 strvalue,valuesize);
1999 } else {
2000 bv->value.stringval[0]='\0';
2001 bv->type=SQLRCLIENTBINDVARTYPE_NULL;
2002 }
2003 } else if (bv->type==SQLRCLIENTBINDVARTYPE_INTEGER) {
2004 bv->value.integerval=intvalue;
2005 } else if (bv->type==SQLRCLIENTBINDVARTYPE_DOUBLE) {
2006 bv->value.doubleval.value=doublevalue;
2007 bv->value.doubleval.precision=precision;
2008 bv->value.doubleval.scale=scale;
2009 } else if (bv->type==SQLRCLIENTBINDVARTYPE_DATE) {
2010 bv->value.dateval.year=year;
2011 bv->value.dateval.month=month;
2012 bv->value.dateval.day=day;
2013 bv->value.dateval.hour=hour;
2014 bv->value.dateval.minute=minute;
2015 bv->value.dateval.second=second;
2016 bv->value.dateval.microsecond=microsecond;
2017 bv->value.dateval.tz=(char *)tz;
2018 bv->value.dateval.isnegative=isnegative;
2019 } else if (bv->type==SQLRCLIENTBINDVARTYPE_BLOB ||
2020 bv->type==SQLRCLIENTBINDVARTYPE_CLOB) {
2021 // FIXME: initialize....
2022 bv->value.lobval=NULL;
2023 }
2024 bv->valuesize=valuesize;
2025 bv->resultvaluesize=0;
2026 bv->send=true;
2027 }
2028
getOutputBindString(const char * variable)2029 const char *sqlrcursor::getOutputBindString(const char *variable) {
2030
2031 if (variable) {
2032 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2033 if (!charstring::compare(
2034 (*pvt->_outbindvars)[i].variable,variable) &&
2035 ((*pvt->_outbindvars)[i].type==
2036 SQLRCLIENTBINDVARTYPE_STRING ||
2037 (*pvt->_outbindvars)[i].type==
2038 SQLRCLIENTBINDVARTYPE_NULL)) {
2039 return (*pvt->_outbindvars)[i].value.stringval;
2040 }
2041 }
2042 }
2043 return NULL;
2044 }
2045
getOutputBindLength(const char * variable)2046 uint32_t sqlrcursor::getOutputBindLength(const char *variable) {
2047
2048 if (variable) {
2049 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2050 if (!charstring::compare(
2051 (*pvt->_outbindvars)[i].variable,variable)) {
2052 return (*pvt->_outbindvars)[i].resultvaluesize;
2053 }
2054 }
2055 }
2056 return 0;
2057 }
2058
getOutputBindBlob(const char * variable)2059 const char *sqlrcursor::getOutputBindBlob(const char *variable) {
2060
2061 if (variable) {
2062 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2063 if (!charstring::compare(
2064 (*pvt->_outbindvars)[i].variable,variable) &&
2065 (*pvt->_outbindvars)[i].type==
2066 SQLRCLIENTBINDVARTYPE_BLOB) {
2067 return (*pvt->_outbindvars)[i].value.lobval;
2068 }
2069 }
2070 }
2071 return NULL;
2072 }
2073
getOutputBindClob(const char * variable)2074 const char *sqlrcursor::getOutputBindClob(const char *variable) {
2075
2076 if (variable) {
2077 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2078 if (!charstring::compare(
2079 (*pvt->_outbindvars)[i].variable,variable) &&
2080 (*pvt->_outbindvars)[i].type==
2081 SQLRCLIENTBINDVARTYPE_CLOB) {
2082 return (*pvt->_outbindvars)[i].value.lobval;
2083 }
2084 }
2085 }
2086 return NULL;
2087 }
2088
getOutputBindInteger(const char * variable)2089 int64_t sqlrcursor::getOutputBindInteger(const char *variable) {
2090
2091 if (variable) {
2092 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2093 if (!charstring::compare(
2094 (*pvt->_outbindvars)[i].variable,variable) &&
2095 (*pvt->_outbindvars)[i].type==
2096 SQLRCLIENTBINDVARTYPE_INTEGER) {
2097 return (*pvt->_outbindvars)[i].value.integerval;
2098 }
2099 }
2100 }
2101 return -1;
2102 }
2103
getOutputBindDouble(const char * variable)2104 double sqlrcursor::getOutputBindDouble(const char *variable) {
2105
2106 if (variable) {
2107 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2108 if (!charstring::compare(
2109 (*pvt->_outbindvars)[i].variable,variable) &&
2110 (*pvt->_outbindvars)[i].type==
2111 SQLRCLIENTBINDVARTYPE_DOUBLE) {
2112 return (*pvt->_outbindvars)[i].
2113 value.doubleval.value;
2114 }
2115 }
2116 }
2117 return -1.0;
2118 }
2119
getOutputBindDate(const char * variable,int16_t * year,int16_t * month,int16_t * day,int16_t * hour,int16_t * minute,int16_t * second,int32_t * microsecond,const char ** tz,bool * isnegative)2120 bool sqlrcursor::getOutputBindDate(const char *variable,
2121 int16_t *year, int16_t *month, int16_t *day,
2122 int16_t *hour, int16_t *minute, int16_t *second,
2123 int32_t *microsecond, const char **tz,
2124 bool *isnegative) {
2125
2126 if (variable) {
2127 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2128 if (!charstring::compare(
2129 (*pvt->_outbindvars)[i].variable,variable) &&
2130 (*pvt->_outbindvars)[i].type==
2131 SQLRCLIENTBINDVARTYPE_DATE) {
2132 *year=(*pvt->_outbindvars)[i].
2133 value.dateval.year;
2134 *month=(*pvt->_outbindvars)[i].
2135 value.dateval.month;
2136 *day=(*pvt->_outbindvars)[i].
2137 value.dateval.day;
2138 *hour=(*pvt->_outbindvars)[i].
2139 value.dateval.hour;
2140 *minute=(*pvt->_outbindvars)[i].
2141 value.dateval.minute;
2142 *second=(*pvt->_outbindvars)[i].
2143 value.dateval.second;
2144 *microsecond=(*pvt->_outbindvars)[i].
2145 value.dateval.microsecond;
2146 *tz=(*pvt->_outbindvars)[i].
2147 value.dateval.tz;
2148 *isnegative=(*pvt->_outbindvars)[i].
2149 value.dateval.isnegative;
2150 return true;
2151 }
2152 }
2153 }
2154 return false;
2155 }
2156
getOutputBindCursor(const char * variable)2157 sqlrcursor *sqlrcursor::getOutputBindCursor(const char *variable) {
2158 return getOutputBindCursor(variable,false);
2159 }
2160
getOutputBindCursor(const char * variable,bool copyrefs)2161 sqlrcursor *sqlrcursor::getOutputBindCursor(const char *variable,
2162 bool copyrefs) {
2163
2164 if (!outputBindCursorIdIsValid(variable)) {
2165 return NULL;
2166 }
2167 uint16_t bindcursorid=getOutputBindCursorId(variable);
2168 sqlrcursor *bindcursor=new sqlrcursor(pvt->_sqlrc,copyrefs);
2169 bindcursor->attachToBindCursor(bindcursorid);
2170 return bindcursor;
2171 }
2172
getInputOutputBindString(const char * variable)2173 const char *sqlrcursor::getInputOutputBindString(const char *variable) {
2174
2175 if (variable) {
2176 for (uint64_t i=0; i<pvt->_inoutbindvars->getLength(); i++) {
2177 if (!charstring::compare(
2178 (*pvt->_inoutbindvars)[i].variable,variable) &&
2179 ((*pvt->_inoutbindvars)[i].type==
2180 SQLRCLIENTBINDVARTYPE_STRING ||
2181 (*pvt->_inoutbindvars)[i].type==
2182 SQLRCLIENTBINDVARTYPE_NULL)) {
2183 return (*pvt->_inoutbindvars)[i].
2184 value.stringval;
2185 }
2186 }
2187 }
2188 return NULL;
2189 }
2190
getInputOutputBindLength(const char * variable)2191 uint32_t sqlrcursor::getInputOutputBindLength(const char *variable) {
2192
2193 if (variable) {
2194 for (uint64_t i=0; i<pvt->_inoutbindvars->getLength(); i++) {
2195 if (!charstring::compare(
2196 (*pvt->_inoutbindvars)[i].variable,variable)) {
2197 return (*pvt->_inoutbindvars)[i].
2198 resultvaluesize;
2199 }
2200 }
2201 }
2202 return 0;
2203 }
2204
getInputOutputBindInteger(const char * variable)2205 int64_t sqlrcursor::getInputOutputBindInteger(const char *variable) {
2206
2207 if (variable) {
2208 for (uint64_t i=0; i<pvt->_inoutbindvars->getLength(); i++) {
2209 if (!charstring::compare(
2210 (*pvt->_inoutbindvars)[i].variable,variable) &&
2211 (*pvt->_inoutbindvars)[i].type==
2212 SQLRCLIENTBINDVARTYPE_INTEGER) {
2213 return (*pvt->_inoutbindvars)[i].
2214 value.integerval;
2215 }
2216 }
2217 }
2218 return -1;
2219 }
2220
getInputOutputBindDouble(const char * variable)2221 double sqlrcursor::getInputOutputBindDouble(const char *variable) {
2222
2223 if (variable) {
2224 for (uint64_t i=0; i<pvt->_inoutbindvars->getLength(); i++) {
2225 if (!charstring::compare(
2226 (*pvt->_inoutbindvars)[i].variable,variable) &&
2227 (*pvt->_inoutbindvars)[i].type==
2228 SQLRCLIENTBINDVARTYPE_DOUBLE) {
2229 return (*pvt->_inoutbindvars)[i].
2230 value.doubleval.value;
2231 }
2232 }
2233 }
2234 return -1.0;
2235 }
2236
getInputOutputBindDate(const char * variable,int16_t * year,int16_t * month,int16_t * day,int16_t * hour,int16_t * minute,int16_t * second,int32_t * microsecond,const char ** tz,bool * isnegative)2237 bool sqlrcursor::getInputOutputBindDate(const char *variable,
2238 int16_t *year, int16_t *month, int16_t *day,
2239 int16_t *hour, int16_t *minute, int16_t *second,
2240 int32_t *microsecond, const char **tz,
2241 bool *isnegative) {
2242
2243 if (variable) {
2244 for (uint64_t i=0; i<pvt->_inoutbindvars->getLength(); i++) {
2245 if (!charstring::compare(
2246 (*pvt->_inoutbindvars)[i].variable,variable) &&
2247 (*pvt->_inoutbindvars)[i].type==
2248 SQLRCLIENTBINDVARTYPE_DATE) {
2249 *year=(*pvt->_inoutbindvars)[i].
2250 value.dateval.year;
2251 *month=(*pvt->_inoutbindvars)[i].
2252 value.dateval.month;
2253 *day=(*pvt->_inoutbindvars)[i].
2254 value.dateval.day;
2255 *hour=(*pvt->_inoutbindvars)[i].
2256 value.dateval.hour;
2257 *minute=(*pvt->_inoutbindvars)[i].
2258 value.dateval.minute;
2259 *second=(*pvt->_inoutbindvars)[i].
2260 value.dateval.second;
2261 *microsecond=(*pvt->_inoutbindvars)[i].
2262 value.dateval.microsecond;
2263 *tz=(*pvt->_inoutbindvars)[i].
2264 value.dateval.tz;
2265 *isnegative=(*pvt->_inoutbindvars)[i].
2266 value.dateval.isnegative;
2267 return true;
2268 }
2269 }
2270 }
2271 return false;
2272 }
2273
getInputOutputBindBlob(const char * variable)2274 const char *sqlrcursor::getInputOutputBindBlob(const char *variable) {
2275 // FIXME: implement this
2276 return NULL;
2277 }
2278
getInputOutputBindClob(const char * variable)2279 const char *sqlrcursor::getInputOutputBindClob(const char *variable) {
2280 // FIXME: implement this
2281 return NULL;
2282 }
2283
outputBindCursorIdIsValid(const char * variable)2284 bool sqlrcursor::outputBindCursorIdIsValid(const char *variable) {
2285 if (variable) {
2286 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2287 if (!charstring::compare(
2288 (*pvt->_outbindvars)[i].variable,variable)) {
2289 return true;
2290 }
2291 }
2292 }
2293 return false;
2294 }
2295
getOutputBindCursorId(const char * variable)2296 uint16_t sqlrcursor::getOutputBindCursorId(const char *variable) {
2297
2298 if (variable) {
2299 for (uint64_t i=0; i<pvt->_outbindvars->getLength(); i++) {
2300 if (!charstring::compare(
2301 (*pvt->_outbindvars)[i].variable,variable)) {
2302 return (*pvt->_outbindvars)[i].value.cursorid;
2303 }
2304 }
2305 }
2306 return 0;
2307 }
2308
validateBinds()2309 void sqlrcursor::validateBinds() {
2310 pvt->_validatebinds=true;
2311 }
2312
validBind(const char * variable)2313 bool sqlrcursor::validBind(const char *variable) {
2314 performSubstitutions();
2315 validateBindsInternal();
2316 for (uint64_t in=0; in<pvt->_inbindvars->getLength(); in++) {
2317 if (!charstring::compare(
2318 (*pvt->_inbindvars)[in].variable,variable)) {
2319 return (*pvt->_inbindvars)[in].send;
2320 }
2321 }
2322 for (uint64_t out=0; out<pvt->_outbindvars->getLength(); out++) {
2323 if (!charstring::compare(
2324 (*pvt->_outbindvars)[out].variable,variable)) {
2325 return (*pvt->_outbindvars)[out].send;
2326 }
2327 }
2328 for (uint64_t out=0; out<pvt->_inoutbindvars->getLength(); out++) {
2329 if (!charstring::compare(
2330 (*pvt->_inoutbindvars)[out].variable,variable)) {
2331 return (*pvt->_inoutbindvars)[out].send;
2332 }
2333 }
2334 return false;
2335 }
2336
executeQuery()2337 bool sqlrcursor::executeQuery() {
2338
2339 if (!pvt->_queryptr) {
2340 setError("No query to execute.");
2341 return false;
2342 }
2343
2344 performSubstitutions();
2345
2346 // validate the bind variables
2347 if (pvt->_validatebinds) {
2348 validateBindsInternal();
2349 }
2350
2351 // run the query
2352 bool retval=runQuery();
2353
2354 // set up to re-execute the same query if executeQuery is called
2355 // again before calling prepareQuery
2356 pvt->_reexecute=true;
2357
2358 return retval;
2359 }
2360
performSubstitutions()2361 void sqlrcursor::performSubstitutions() {
2362
2363 if (!pvt->_subvars->getLength() || !pvt->_dirtysubs) {
2364 return;
2365 }
2366
2367 // perform substitutions
2368 stringbuffer container;
2369 const char *ptr=pvt->_queryptr;
2370 const char *endptr=pvt->_queryptr+pvt->_querylen;
2371 bool found=false;
2372 bool inquotes=false;
2373 bool inbraces=false;
2374 int len=0;
2375 stringbuffer *braces=NULL;
2376
2377 // iterate through the string
2378 while (ptr<endptr) {
2379
2380 // figure out whether we're inside a quoted
2381 // string or not
2382 if (*ptr=='\'' && *(ptr-1)!='\\') {
2383 inquotes=!inquotes;
2384 }
2385
2386 // if we find an open-brace then start
2387 // sending to a new buffer
2388 if (*ptr=='[' && !inbraces && !inquotes) {
2389 braces=new stringbuffer();
2390 inbraces=true;
2391 ptr++;
2392 }
2393
2394 // if we find a close-brace then process
2395 // the brace buffer
2396 if (*ptr==']' && inbraces && !inquotes) {
2397
2398 // look for an = sign, skipping whitespace
2399 const char *bptr=braces->getString();
2400 while (*bptr && (*bptr==' ' ||
2401 *bptr==' ' || *bptr=='\n')) {
2402 bptr++;
2403 }
2404
2405 if (*bptr=='=') {
2406 // if we find an equals sign first
2407 // then process the rest of the buffer
2408 bptr++;
2409
2410 // skip whitespace
2411 while (*bptr && (*bptr==' ' ||
2412 *bptr==' ' ||
2413 *bptr=='\n')) {
2414 bptr++;
2415 }
2416
2417 // if the remaining contents of the
2418 // buffer are '' or nothing then we
2419 // must have an ='' or just an = with
2420 // some whitespace, replace this
2421 // with "is NULL" otherwise, just write
2422 // out the contents of the buffer
2423 if (!bptr ||
2424 (bptr &&
2425 !charstring::compare(bptr,
2426 "''"))) {
2427 container.append(" is NULL ");
2428 } else {
2429 container.append(
2430 braces->getString());
2431 }
2432 } else {
2433 // if we don't find an equals sign,
2434 // then write the contents out directly
2435 container.append(braces->getString());
2436 }
2437 delete braces;
2438 inbraces=false;
2439 ptr++;
2440 }
2441
2442 // if we encounter $(....) then replace the
2443 // variable within
2444 if ((*ptr)=='$' && (*(ptr+1))=='(') {
2445
2446 // first iterate through the arrays passed in
2447 found=false;
2448 for (uint64_t i=0;
2449 i<pvt->_subvars->getLength() && !found; i++) {
2450
2451
2452 // if we find a match, write the
2453 // value to the container and skip
2454 // past the $(variable)
2455 len=charstring::length(
2456 (*pvt->_subvars)[i].variable);
2457 if (!(*pvt->_subvars)[i].donesubstituting &&
2458 !charstring::compare((ptr+2),
2459 (*pvt->_subvars)[i].
2460 variable,len) &&
2461 (*(ptr+2+len))==')') {
2462
2463 if (inbraces) {
2464 performSubstitution(
2465 braces,i);
2466 } else {
2467 performSubstitution(
2468 &container,i);
2469 }
2470 ptr=ptr+3+len;
2471 found=true;
2472 }
2473 }
2474
2475 // if the variable wasn't found, then
2476 // just write the $(
2477 if (!found) {
2478 if (inbraces) {
2479 braces->append("$(");
2480 } else {
2481 container.append("$(");
2482 }
2483 ptr=ptr+2;
2484 }
2485
2486 } else {
2487
2488 // print out the current character and proceed
2489 if (inbraces) {
2490 braces->append(*ptr);
2491 } else {
2492 container.append(*ptr);
2493 }
2494 ptr++;
2495 }
2496 }
2497
2498 // mark all vars that were substituted in as "done" so the next time
2499 // this method gets called, they won't be processed.
2500 for (uint64_t i=0; i<pvt->_subvars->getLength(); i++) {
2501 (*pvt->_subvars)[i].donesubstituting=
2502 (*pvt->_subvars)[i].substituted;
2503 }
2504
2505 delete[] pvt->_querybuffer;
2506 pvt->_querylen=container.getSize();
2507 pvt->_querybuffer=container.detachString();
2508 pvt->_queryptr=pvt->_querybuffer;
2509
2510 pvt->_dirtysubs=false;
2511 }
2512
validateBindsInternal()2513 void sqlrcursor::validateBindsInternal() {
2514
2515 if (!pvt->_dirtybinds) {
2516 return;
2517 }
2518
2519 // check each input bind
2520 for (uint64_t in=0; in<pvt->_inbindvars->getLength(); in++) {
2521
2522 // don't check bind-by-position variables
2523 if (charstring::isInteger(
2524 (*pvt->_inbindvars)[in].variable)) {
2525 continue;
2526 }
2527
2528 (*pvt->_inbindvars)[in].send=
2529 validateBind((*pvt->_inbindvars)[in].variable);
2530 }
2531
2532 // check each output bind
2533 for (uint64_t out=0; out<pvt->_outbindvars->getLength(); out++) {
2534
2535 // don't check bind-by-position variables
2536 if (charstring::isInteger(
2537 (*pvt->_outbindvars)[out].variable)) {
2538 continue;
2539 }
2540
2541 (*pvt->_outbindvars)[out].send=
2542 validateBind((*pvt->_outbindvars)[out].variable);
2543 }
2544
2545 // check each input/output bind
2546 for (uint64_t inout=0;
2547 inout<pvt->_inoutbindvars->getLength(); inout++) {
2548
2549 // don't check bind-by-position variables
2550 if (charstring::isInteger(
2551 (*pvt->_inoutbindvars)[inout].variable)) {
2552 continue;
2553 }
2554
2555 (*pvt->_inoutbindvars)[inout].send=
2556 validateBind((*pvt->_inoutbindvars)[inout].variable);
2557 }
2558 }
2559
validateBind(const char * variable)2560 bool sqlrcursor::validateBind(const char *variable) {
2561
2562 queryparsestate_t parsestate=IN_QUERY;
2563 stringbuffer currentbind;
2564
2565 size_t len=charstring::length(variable);
2566
2567 // run through the querybuffer...
2568 const char *ptr=pvt->_queryptr;
2569 const char *endptr=pvt->_queryptr+pvt->_querylen;
2570 char prev='\0';
2571 do {
2572
2573 // if we're in the query...
2574 if (parsestate==IN_QUERY) {
2575
2576 // if we find a quote, we're in quotes
2577 if (*ptr=='\'') {
2578 parsestate=IN_QUOTES;
2579 }
2580
2581 // if we find whitespace or a couple of other things
2582 // then the next thing could be a bind variable
2583 if (beforeBindVariable(ptr)) {
2584 parsestate=BEFORE_BIND;
2585 }
2586
2587 // move on
2588 if (*ptr=='\\' && prev=='\\') {
2589 prev='\0';
2590 } else {
2591 prev=*ptr;
2592 }
2593 ptr++;
2594 continue;
2595 }
2596
2597 // copy anything in quotes verbatim
2598 if (parsestate==IN_QUOTES) {
2599
2600 // if we find a quote, but not an escaped quote,
2601 // then we're back in the query
2602 // (or we're in between one of these: '...''...'
2603 // which is functionally the same)
2604 if (*ptr=='\'' && prev!='\\') {
2605 parsestate=IN_QUERY;
2606 }
2607
2608 // move on
2609 if (*ptr=='\\' && prev=='\\') {
2610 prev='\0';
2611 } else {
2612 prev=*ptr;
2613 }
2614 ptr++;
2615 continue;
2616 }
2617
2618 if (parsestate==BEFORE_BIND) {
2619
2620 // if we find a bind variable...
2621 if (isBindDelimiter(ptr,
2622 pvt->_sqlrc->getBindVariableDelimiterQuestionMarkSupported(),
2623 pvt->_sqlrc->getBindVariableDelimiterColonSupported(),
2624 pvt->_sqlrc->getBindVariableDelimiterAtSignSupported(),
2625 pvt->_sqlrc->getBindVariableDelimiterDollarSignSupported())) {
2626 parsestate=IN_BIND;
2627 currentbind.clear();
2628 continue;
2629 }
2630
2631 // if we didn't find a bind variable then we're just
2632 // back in the query
2633 parsestate=IN_QUERY;
2634 continue;
2635 }
2636
2637 // if we're in a bind variable...
2638 if (parsestate==IN_BIND) {
2639
2640 // If we find whitespace or a few other things
2641 // then we're done with the bind variable. Process it.
2642 // Otherwise get the variable itself in another buffer.
2643 bool endofbind=afterBindVariable(ptr);
2644 if (endofbind || ptr==endptr-1) {
2645
2646 // special case...
2647 // last character in the query
2648 if (!endofbind && ptr==endptr-1) {
2649 currentbind.append(*ptr);
2650 if (*ptr=='\\' && prev=='\\') {
2651 prev='\0';
2652 } else {
2653 prev=*ptr;
2654 }
2655 ptr++;
2656 }
2657
2658 // check variable against currentbind
2659 if (len==currentbind.getStringLength()-1 &&
2660 !charstring::compare(
2661 variable,
2662 currentbind.getString()+1,
2663 len)) {
2664 return true;
2665 }
2666
2667 parsestate=IN_QUERY;
2668
2669 } else {
2670
2671 // move on
2672 currentbind.append(*ptr);
2673 if (*ptr=='\\' && prev=='\\') {
2674 prev='\0';
2675 } else {
2676 prev=*ptr;
2677 }
2678 ptr++;
2679 }
2680 continue;
2681 }
2682
2683 } while (ptr<endptr);
2684
2685 return false;
2686 }
2687
performSubstitution(stringbuffer * buffer,uint16_t which)2688 void sqlrcursor::performSubstitution(stringbuffer *buffer, uint16_t which) {
2689
2690 if ((*pvt->_subvars)[which].type==
2691 SQLRCLIENTBINDVARTYPE_STRING) {
2692 buffer->append((*pvt->_subvars)[which].value.stringval);
2693 } else if ((*pvt->_subvars)[which].type==
2694 SQLRCLIENTBINDVARTYPE_INTEGER) {
2695 buffer->append((*pvt->_subvars)[which].value.integerval);
2696 } else if ((*pvt->_subvars)[which].type==
2697 SQLRCLIENTBINDVARTYPE_DOUBLE) {
2698 buffer->append((*pvt->_subvars)[which].value.doubleval.value,
2699 (*pvt->_subvars)[which].value.doubleval.precision,
2700 (*pvt->_subvars)[which].value.doubleval.scale);
2701 }
2702 (*pvt->_subvars)[which].substituted=true;
2703 }
2704
runQuery()2705 bool sqlrcursor::runQuery() {
2706
2707 // send the query
2708 if (sendQueryInternal()) {
2709
2710 sendInputBinds();
2711 sendOutputBinds();
2712 sendInputOutputBinds();
2713 sendGetColumnInfo();
2714
2715 pvt->_sqlrc->flushWriteBuffer();
2716
2717 if (processInitialResultSet()) {
2718 return true;
2719 }
2720 }
2721 return false;
2722 }
2723
sendQueryInternal()2724 bool sqlrcursor::sendQueryInternal() {
2725
2726 // if the first 8 characters of the query are "-- debug" followed
2727 // by a return, then set debugging on
2728 if (!charstring::compare(pvt->_queryptr,"-- debug\n",9)) {
2729 pvt->_sqlrc->debugOn();
2730 }
2731
2732 if (!pvt->_endofresultset) {
2733 closeResultSet(false);
2734 }
2735 clearResultSet();
2736
2737 if (!pvt->_sqlrc->openSession()) {
2738 return false;
2739 }
2740
2741 pvt->_cached=false;
2742 pvt->_endofresultset=false;
2743
2744 // refresh socket client
2745 pvt->_cs=pvt->_sqlrc->cs();
2746
2747 // send the query to the server.
2748 if (!pvt->_reexecute) {
2749
2750 // tell the server we're sending a query
2751 pvt->_cs->write((uint16_t)NEW_QUERY);
2752
2753 // tell the server whether we'll need a cursor or not
2754 sendCursorStatus();
2755
2756 if (pvt->_sqlrc->debug()) {
2757 pvt->_sqlrc->debugPreStart();
2758 pvt->_sqlrc->debugPrint("Sending Client Info:");
2759 pvt->_sqlrc->debugPrint("\n");
2760 pvt->_sqlrc->debugPrint("Length: ");
2761 pvt->_sqlrc->debugPrint(
2762 (int64_t)pvt->_sqlrc->clientinfolen());
2763 pvt->_sqlrc->debugPrint("\n");
2764 pvt->_sqlrc->debugPrint(pvt->_sqlrc->clientinfo());
2765 pvt->_sqlrc->debugPrint("\n");
2766 pvt->_sqlrc->debugPreEnd();
2767 }
2768
2769 // send the client info
2770 // FIXME: arguably this should be its own command
2771 pvt->_cs->write(pvt->_sqlrc->clientinfolen());
2772 pvt->_cs->write(pvt->_sqlrc->clientinfo(),
2773 pvt->_sqlrc->clientinfolen());
2774
2775 if (pvt->_sqlrc->debug()) {
2776 pvt->_sqlrc->debugPreStart();
2777 pvt->_sqlrc->debugPrint("Sending Query:");
2778 pvt->_sqlrc->debugPrint("\n");
2779 pvt->_sqlrc->debugPrint("Length: ");
2780 pvt->_sqlrc->debugPrint((int64_t)pvt->_querylen);
2781 pvt->_sqlrc->debugPrint("\n");
2782 pvt->_sqlrc->debugPrint(pvt->_queryptr);
2783 pvt->_sqlrc->debugPrint("\n");
2784 pvt->_sqlrc->debugPreEnd();
2785 }
2786
2787 // send the query
2788 pvt->_cs->write(pvt->_querylen);
2789 pvt->_cs->write(pvt->_queryptr,pvt->_querylen);
2790
2791 } else {
2792
2793 if (pvt->_sqlrc->debug()) {
2794 pvt->_sqlrc->debugPreStart();
2795 pvt->_sqlrc->debugPrint("Requesting re-execution of ");
2796 pvt->_sqlrc->debugPrint("previous query.");
2797 pvt->_sqlrc->debugPrint("\n");
2798 pvt->_sqlrc->debugPrint("Requesting Cursor: ");
2799 pvt->_sqlrc->debugPrint((int64_t)pvt->_cursorid);
2800 pvt->_sqlrc->debugPrint("\n");
2801 pvt->_sqlrc->debugPreEnd();
2802 }
2803
2804 // tell the server we're sending a query
2805 pvt->_cs->write((uint16_t)REEXECUTE_QUERY);
2806
2807 // send the cursor id to the server
2808 pvt->_cs->write(pvt->_cursorid);
2809 }
2810
2811 return true;
2812 }
2813
sendCursorStatus()2814 void sqlrcursor::sendCursorStatus() {
2815
2816 if (pvt->_havecursorid) {
2817
2818 // tell the server we already have a cursor
2819 pvt->_cs->write((uint16_t)DONT_NEED_NEW_CURSOR);
2820
2821 // send the cursor id to the server
2822 pvt->_cs->write(pvt->_cursorid);
2823
2824 if (pvt->_sqlrc->debug()) {
2825 pvt->_sqlrc->debugPreStart();
2826 pvt->_sqlrc->debugPrint("Requesting Cursor: ");
2827 pvt->_sqlrc->debugPrint((int64_t)pvt->_cursorid);
2828 pvt->_sqlrc->debugPrint("\n");
2829 pvt->_sqlrc->debugPreEnd();
2830 }
2831
2832 } else {
2833
2834 // tell the server we need a cursor
2835 pvt->_cs->write((uint16_t)NEED_NEW_CURSOR);
2836
2837 if (pvt->_sqlrc->debug()) {
2838 pvt->_sqlrc->debugPreStart();
2839 pvt->_sqlrc->debugPrint("Requesting a new cursor.\n");
2840 pvt->_sqlrc->debugPreEnd();
2841 }
2842 }
2843 }
2844
sendInputBinds()2845 void sqlrcursor::sendInputBinds() {
2846
2847 // index
2848 uint16_t i=0;
2849
2850 // count number of vars to send
2851 uint16_t count=pvt->_inbindvars->getLength();
2852 for (i=0; i<count; i++) {
2853 if (!(*pvt->_inbindvars)[i].send) {
2854 count--;
2855 }
2856 }
2857
2858 if (pvt->_sqlrc->debug()) {
2859 pvt->_sqlrc->debugPreStart();
2860 pvt->_sqlrc->debugPrint("Sending ");
2861 pvt->_sqlrc->debugPrint((int64_t)count);
2862 pvt->_sqlrc->debugPrint(" Input Bind Variables:\n");
2863 pvt->_sqlrc->debugPreEnd();
2864 }
2865
2866 // write the input bind variables/values to the server.
2867 pvt->_cs->write(count);
2868 uint16_t size;
2869 i=0;
2870 while (i<count) {
2871
2872 // don't send anything if the send flag is turned off
2873 if (!(*pvt->_inbindvars)[i].send) {
2874 continue;
2875 }
2876
2877 // send the variable
2878 size=charstring::length((*pvt->_inbindvars)[i].variable);
2879 pvt->_cs->write(size);
2880 pvt->_cs->write((*pvt->_inbindvars)[i].variable,(size_t)size);
2881 if (pvt->_sqlrc->debug()) {
2882 pvt->_sqlrc->debugPreStart();
2883 pvt->_sqlrc->debugPrint(
2884 (*pvt->_inbindvars)[i].variable);
2885 pvt->_sqlrc->debugPrint("(");
2886 pvt->_sqlrc->debugPrint((int64_t)size);
2887 }
2888
2889 // send the type
2890 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].type);
2891
2892 // send the value
2893 if ((*pvt->_inbindvars)[i].type==
2894 SQLRCLIENTBINDVARTYPE_NULL) {
2895
2896 if (pvt->_sqlrc->debug()) {
2897 pvt->_sqlrc->debugPrint(":NULL)\n");
2898 pvt->_sqlrc->debugPreEnd();
2899 }
2900
2901 } else if ((*pvt->_inbindvars)[i].type==
2902 SQLRCLIENTBINDVARTYPE_STRING) {
2903
2904 pvt->_cs->write((*pvt->_inbindvars)[i].valuesize);
2905 if ((*pvt->_inbindvars)[i].valuesize>0) {
2906 pvt->_cs->write(
2907 (*pvt->_inbindvars)[i].value.stringval,
2908 (size_t)(*pvt->_inbindvars)[i].
2909 valuesize);
2910 }
2911
2912 if (pvt->_sqlrc->debug()) {
2913 pvt->_sqlrc->debugPrint(":STRING)=");
2914 pvt->_sqlrc->debugPrint(
2915 (*pvt->_inbindvars)[i].value.stringval);
2916 pvt->_sqlrc->debugPrint("(");
2917 pvt->_sqlrc->debugPrint(
2918 (int64_t)(*pvt->_inbindvars)[i].
2919 valuesize);
2920 pvt->_sqlrc->debugPrint(")");
2921 pvt->_sqlrc->debugPrint("\n");
2922 pvt->_sqlrc->debugPreEnd();
2923 }
2924
2925 } else if ((*pvt->_inbindvars)[i].type==
2926 SQLRCLIENTBINDVARTYPE_INTEGER) {
2927
2928 pvt->_cs->write((uint64_t)(*pvt->_inbindvars)[i].
2929 value.integerval);
2930
2931 if (pvt->_sqlrc->debug()) {
2932 pvt->_sqlrc->debugPrint(":LONG)=");
2933 pvt->_sqlrc->debugPrint(
2934 (int64_t)(*pvt->_inbindvars)[i].
2935 value.integerval);
2936 pvt->_sqlrc->debugPrint("\n");
2937 pvt->_sqlrc->debugPreEnd();
2938 }
2939
2940 } else if ((*pvt->_inbindvars)[i].type==
2941 SQLRCLIENTBINDVARTYPE_DOUBLE) {
2942
2943 pvt->_cs->write((*pvt->_inbindvars)[i].value.
2944 doubleval.value);
2945 pvt->_cs->write((*pvt->_inbindvars)[i].value.
2946 doubleval.precision);
2947 pvt->_cs->write((*pvt->_inbindvars)[i].value.
2948 doubleval.scale);
2949
2950 if (pvt->_sqlrc->debug()) {
2951 pvt->_sqlrc->debugPrint(":DOUBLE)=");
2952 pvt->_sqlrc->debugPrint(
2953 (*pvt->_inbindvars)[i].value.
2954 doubleval.value);
2955 pvt->_sqlrc->debugPrint(":");
2956 pvt->_sqlrc->debugPrint(
2957 (int64_t)(*pvt->_inbindvars)[i].
2958 value.doubleval.precision);
2959 pvt->_sqlrc->debugPrint(",");
2960 pvt->_sqlrc->debugPrint(
2961 (int64_t)(*pvt->_inbindvars)[i].
2962 value.doubleval.scale);
2963 pvt->_sqlrc->debugPrint("\n");
2964 pvt->_sqlrc->debugPreEnd();
2965 }
2966
2967 } else if ((*pvt->_inbindvars)[i].type==
2968 SQLRCLIENTBINDVARTYPE_DATE) {
2969
2970 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].
2971 value.dateval.year);
2972 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].
2973 value.dateval.month);
2974 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].
2975 value.dateval.day);
2976 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].
2977 value.dateval.hour);
2978 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].
2979 value.dateval.minute);
2980 pvt->_cs->write((uint16_t)(*pvt->_inbindvars)[i].
2981 value.dateval.second);
2982 pvt->_cs->write((uint32_t)(*pvt->_inbindvars)[i].
2983 value.dateval.microsecond);
2984 pvt->_cs->write((uint16_t)charstring::length(
2985 (*pvt->_inbindvars)[i].
2986 value.dateval.tz));
2987 pvt->_cs->write((*pvt->_inbindvars)[i].
2988 value.dateval.tz);
2989 pvt->_cs->write((*pvt->_inbindvars)[i].
2990 value.dateval.isnegative);
2991
2992 if (pvt->_sqlrc->debug()) {
2993 pvt->_sqlrc->debugPrint(":DATE)=");
2994 pvt->_sqlrc->debugPrint((int64_t)
2995 (*pvt->_inbindvars)[i].
2996 value.dateval.year);
2997 pvt->_sqlrc->debugPrint("-");
2998 pvt->_sqlrc->debugPrint((int64_t)
2999 (*pvt->_inbindvars)[i].
3000 value.dateval.month);
3001 pvt->_sqlrc->debugPrint("-");
3002 pvt->_sqlrc->debugPrint((int64_t)
3003 (*pvt->_inbindvars)[i].
3004 value.dateval.day);
3005 pvt->_sqlrc->debugPrint(" ");
3006 if ((*pvt->_inbindvars)[i].
3007 value.dateval.isnegative) {
3008 pvt->_sqlrc->debugPrint("-");
3009 }
3010 pvt->_sqlrc->debugPrint((int64_t)
3011 (*pvt->_inbindvars)[i].
3012 value.dateval.hour);
3013 pvt->_sqlrc->debugPrint(":");
3014 pvt->_sqlrc->debugPrint((int64_t)
3015 (*pvt->_inbindvars)[i].
3016 value.dateval.minute);
3017 pvt->_sqlrc->debugPrint(":");
3018 pvt->_sqlrc->debugPrint((int64_t)
3019 (*pvt->_inbindvars)[i].
3020 value.dateval.second);
3021 pvt->_sqlrc->debugPrint(".");
3022 pvt->_sqlrc->debugPrint((int64_t)
3023 (*pvt->_inbindvars)[i].value.
3024 dateval.microsecond);
3025 pvt->_sqlrc->debugPrint(" ");
3026 pvt->_sqlrc->debugPrint(
3027 (*pvt->_inbindvars)[i].
3028 value.dateval.tz);
3029 pvt->_sqlrc->debugPrint("\n");
3030 pvt->_sqlrc->debugPreEnd();
3031 }
3032
3033 } else if ((*pvt->_inbindvars)[i].type==
3034 SQLRCLIENTBINDVARTYPE_BLOB ||
3035 (*pvt->_inbindvars)[i].type==
3036 SQLRCLIENTBINDVARTYPE_CLOB) {
3037
3038 pvt->_cs->write((*pvt->_inbindvars)[i].valuesize);
3039 if ((*pvt->_inbindvars)[i].valuesize>0) {
3040 pvt->_cs->write((*pvt->_inbindvars)[i].value.lobval,
3041 (size_t)(*pvt->_inbindvars)[i].
3042 valuesize);
3043 }
3044
3045 if (pvt->_sqlrc->debug()) {
3046 if ((*pvt->_inbindvars)[i].type==
3047 SQLRCLIENTBINDVARTYPE_BLOB) {
3048 pvt->_sqlrc->debugPrint(":BLOB)=");
3049 pvt->_sqlrc->debugPrintBlob(
3050 (*pvt->_inbindvars)[i].
3051 value.lobval,
3052 (*pvt->_inbindvars)[i].
3053 valuesize);
3054 } else if ((*pvt->_inbindvars)[i].type==
3055 SQLRCLIENTBINDVARTYPE_CLOB) {
3056 pvt->_sqlrc->debugPrint(":CLOB)=");
3057 pvt->_sqlrc->debugPrintClob(
3058 (*pvt->_inbindvars)[i].
3059 value.lobval,
3060 (*pvt->_inbindvars)[i].
3061 valuesize);
3062 }
3063 pvt->_sqlrc->debugPrint("(");
3064 pvt->_sqlrc->debugPrint((int64_t)
3065 (*pvt->_inbindvars)[i].
3066 valuesize);
3067 pvt->_sqlrc->debugPrint(")");
3068 pvt->_sqlrc->debugPrint("\n");
3069 pvt->_sqlrc->debugPreEnd();
3070 }
3071 }
3072
3073 i++;
3074 }
3075 }
3076
sendOutputBinds()3077 void sqlrcursor::sendOutputBinds() {
3078
3079 // index
3080 uint16_t i=0;
3081
3082 // count number of vars to send
3083 uint16_t count=pvt->_outbindvars->getLength();
3084 for (i=0; i<count; i++) {
3085 if (!(*pvt->_outbindvars)[i].send) {
3086 count--;
3087 }
3088 }
3089
3090 if (pvt->_sqlrc->debug()) {
3091 pvt->_sqlrc->debugPreStart();
3092 pvt->_sqlrc->debugPrint("Sending ");
3093 pvt->_sqlrc->debugPrint((int64_t)count);
3094 pvt->_sqlrc->debugPrint(" Output Bind Variables:\n");
3095 pvt->_sqlrc->debugPreEnd();
3096 }
3097
3098 // write the output bind variables to the server.
3099 pvt->_cs->write(count);
3100 uint16_t size;
3101 i=0;
3102 while (i<count) {
3103
3104 // don't send anything if the send flag is turned off
3105 if (!(*pvt->_outbindvars)[i].send) {
3106 continue;
3107 }
3108
3109 // send the variable, type and size that the buffer needs to be
3110 size=charstring::length((*pvt->_outbindvars)[i].variable);
3111 pvt->_cs->write(size);
3112 pvt->_cs->write((*pvt->_outbindvars)[i].variable,(size_t)size);
3113 pvt->_cs->write((uint16_t)(*pvt->_outbindvars)[i].type);
3114 if ((*pvt->_outbindvars)[i].type==
3115 SQLRCLIENTBINDVARTYPE_STRING ||
3116 (*pvt->_outbindvars)[i].type==
3117 SQLRCLIENTBINDVARTYPE_BLOB ||
3118 (*pvt->_outbindvars)[i].type==
3119 SQLRCLIENTBINDVARTYPE_CLOB ||
3120 (*pvt->_outbindvars)[i].type==
3121 SQLRCLIENTBINDVARTYPE_NULL) {
3122 pvt->_cs->write((*pvt->_outbindvars)[i].valuesize);
3123 }
3124
3125 if (pvt->_sqlrc->debug()) {
3126 pvt->_sqlrc->debugPreStart();
3127 pvt->_sqlrc->debugPrint(
3128 (*pvt->_outbindvars)[i].variable);
3129 const char *bindtype=NULL;
3130 switch ((*pvt->_outbindvars)[i].type) {
3131 case SQLRCLIENTBINDVARTYPE_NULL:
3132 bindtype="(NULL)";
3133 break;
3134 case SQLRCLIENTBINDVARTYPE_STRING:
3135 bindtype="(STRING)";
3136 break;
3137 case SQLRCLIENTBINDVARTYPE_INTEGER:
3138 bindtype="(INTEGER)";
3139 break;
3140 case SQLRCLIENTBINDVARTYPE_DOUBLE:
3141 bindtype="(DOUBLE)";
3142 break;
3143 case SQLRCLIENTBINDVARTYPE_DATE:
3144 bindtype="(DATE)";
3145 break;
3146 case SQLRCLIENTBINDVARTYPE_BLOB:
3147 bindtype="(BLOB)";
3148 break;
3149 case SQLRCLIENTBINDVARTYPE_CLOB:
3150 bindtype="(CLOB)";
3151 break;
3152 case SQLRCLIENTBINDVARTYPE_CURSOR:
3153 bindtype="(CURSOR)";
3154 break;
3155 }
3156 pvt->_sqlrc->debugPrint(bindtype);
3157 if ((*pvt->_outbindvars)[i].type==
3158 SQLRCLIENTBINDVARTYPE_STRING ||
3159 (*pvt->_outbindvars)[i].type==
3160 SQLRCLIENTBINDVARTYPE_BLOB ||
3161 (*pvt->_outbindvars)[i].type==
3162 SQLRCLIENTBINDVARTYPE_CLOB ||
3163 (*pvt->_outbindvars)[i].type==
3164 SQLRCLIENTBINDVARTYPE_NULL) {
3165 pvt->_sqlrc->debugPrint("(");
3166 pvt->_sqlrc->debugPrint((int64_t)
3167 (*pvt->_outbindvars)[i].valuesize);
3168 pvt->_sqlrc->debugPrint(")");
3169 }
3170 pvt->_sqlrc->debugPrint("\n");
3171 pvt->_sqlrc->debugPreEnd();
3172 }
3173
3174 i++;
3175 }
3176 }
3177
sendInputOutputBinds()3178 void sqlrcursor::sendInputOutputBinds() {
3179
3180 // index
3181 uint16_t i=0;
3182
3183 // count number of vars to send
3184 uint16_t count=pvt->_inoutbindvars->getLength();
3185 for (i=0; i<count; i++) {
3186 if (!(*pvt->_inoutbindvars)[i].send) {
3187 count--;
3188 }
3189 }
3190
3191 if (pvt->_sqlrc->debug()) {
3192 pvt->_sqlrc->debugPreStart();
3193 pvt->_sqlrc->debugPrint("Sending ");
3194 pvt->_sqlrc->debugPrint((int64_t)count);
3195 pvt->_sqlrc->debugPrint(" Input/Output Bind Variables:\n");
3196 pvt->_sqlrc->debugPreEnd();
3197 }
3198
3199 // write the input/output bind variables to the server.
3200 pvt->_cs->write(count);
3201 uint16_t size;
3202 i=0;
3203 while (i<count) {
3204
3205 // don't send anything if the send flag is turned off
3206 if (!(*pvt->_inoutbindvars)[i].send) {
3207 continue;
3208 }
3209
3210 // send the variable, type, size that the buffer needs to be,
3211 // and value
3212 size=charstring::length((*pvt->_inoutbindvars)[i].variable);
3213 pvt->_cs->write(size);
3214 pvt->_cs->write((*pvt->_inoutbindvars)[i].variable,
3215 (size_t)size);
3216 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].type);
3217 if ((*pvt->_inoutbindvars)[i].type==
3218 SQLRCLIENTBINDVARTYPE_NULL) {
3219 pvt->_cs->write((*pvt->_inoutbindvars)[i].valuesize);
3220 } else if ((*pvt->_inoutbindvars)[i].type==
3221 SQLRCLIENTBINDVARTYPE_STRING ||
3222 (*pvt->_inoutbindvars)[i].type==
3223 SQLRCLIENTBINDVARTYPE_BLOB ||
3224 (*pvt->_inoutbindvars)[i].type==
3225 SQLRCLIENTBINDVARTYPE_CLOB) {
3226 pvt->_cs->write((*pvt->_inoutbindvars)[i].valuesize);
3227 if ((*pvt->_inoutbindvars)[i].valuesize>0) {
3228 pvt->_cs->write(
3229 (*pvt->_inoutbindvars)[i].
3230 value.stringval,
3231 (size_t)(*pvt->_inoutbindvars)[i].
3232 valuesize);
3233 }
3234 } else if ((*pvt->_inoutbindvars)[i].type==
3235 SQLRCLIENTBINDVARTYPE_INTEGER) {
3236 pvt->_cs->write((uint64_t)(*pvt->_inoutbindvars)[i].
3237 value.integerval);
3238 } else if ((*pvt->_inoutbindvars)[i].type==
3239 SQLRCLIENTBINDVARTYPE_DOUBLE) {
3240 pvt->_cs->write((*pvt->_inoutbindvars)[i].
3241 value.doubleval.value);
3242 pvt->_cs->write((*pvt->_inoutbindvars)[i].
3243 value.doubleval.precision);
3244 pvt->_cs->write((*pvt->_inoutbindvars)[i].
3245 value.doubleval.scale);
3246 } else if ((*pvt->_inoutbindvars)[i].type==
3247 SQLRCLIENTBINDVARTYPE_DATE) {
3248 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].
3249 value.dateval.year);
3250 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].
3251 value.dateval.month);
3252 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].
3253 value.dateval.day);
3254 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].
3255 value.dateval.hour);
3256 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].
3257 value.dateval.minute);
3258 pvt->_cs->write((uint16_t)(*pvt->_inoutbindvars)[i].
3259 value.dateval.second);
3260 pvt->_cs->write((uint32_t)(*pvt->_inoutbindvars)[i].
3261 value.dateval.microsecond);
3262 pvt->_cs->write((uint16_t)charstring::length(
3263 (*pvt->_inoutbindvars)[i].
3264 value.dateval.tz));
3265 pvt->_cs->write((*pvt->_inoutbindvars)[i].
3266 value.dateval.tz);
3267 pvt->_cs->write((*pvt->_inoutbindvars)[i].
3268 value.dateval.isnegative);
3269 }
3270
3271 if (pvt->_sqlrc->debug()) {
3272
3273 pvt->_sqlrc->debugPreStart();
3274 pvt->_sqlrc->debugPrint(
3275 (*pvt->_inoutbindvars)[i].variable);
3276 const char *bindtype=NULL;
3277 switch ((*pvt->_inoutbindvars)[i].type) {
3278 case SQLRCLIENTBINDVARTYPE_NULL:
3279 bindtype="(NULL)";
3280 break;
3281 case SQLRCLIENTBINDVARTYPE_STRING:
3282 bindtype="(STRING)";
3283 break;
3284 case SQLRCLIENTBINDVARTYPE_INTEGER:
3285 bindtype="(INTEGER)";
3286 break;
3287 case SQLRCLIENTBINDVARTYPE_DOUBLE:
3288 bindtype="(DOUBLE)";
3289 break;
3290 case SQLRCLIENTBINDVARTYPE_DATE:
3291 bindtype="(DATE)";
3292 break;
3293 case SQLRCLIENTBINDVARTYPE_BLOB:
3294 bindtype="(BLOB)";
3295 break;
3296 case SQLRCLIENTBINDVARTYPE_CLOB:
3297 bindtype="(CLOB)";
3298 break;
3299 case SQLRCLIENTBINDVARTYPE_CURSOR:
3300 bindtype="(CURSOR)";
3301 break;
3302 }
3303 pvt->_sqlrc->debugPrint(bindtype);
3304
3305 if ((*pvt->_inoutbindvars)[i].type==
3306 SQLRCLIENTBINDVARTYPE_STRING ||
3307 (*pvt->_inoutbindvars)[i].type==
3308 SQLRCLIENTBINDVARTYPE_BLOB ||
3309 (*pvt->_inoutbindvars)[i].type==
3310 SQLRCLIENTBINDVARTYPE_CLOB ||
3311 (*pvt->_inoutbindvars)[i].type==
3312 SQLRCLIENTBINDVARTYPE_NULL) {
3313
3314 pvt->_sqlrc->debugPrint("=");
3315 pvt->_sqlrc->debugPrint(
3316 (*pvt->_inoutbindvars)[i].
3317 value.stringval);
3318 pvt->_sqlrc->debugPrint("(");
3319 pvt->_sqlrc->debugPrint((int64_t)
3320 (*pvt->_inoutbindvars)[i].valuesize);
3321 pvt->_sqlrc->debugPrint(")");
3322
3323 } else if ((*pvt->_inoutbindvars)[i].type==
3324 SQLRCLIENTBINDVARTYPE_INTEGER) {
3325
3326 pvt->_sqlrc->debugPrint("=");
3327 pvt->_sqlrc->debugPrint(
3328 (int64_t)(*pvt->_inoutbindvars)[i].
3329 value.integerval);
3330 pvt->_sqlrc->debugPrint("\n");
3331 pvt->_sqlrc->debugPreEnd();
3332
3333 } else if ((*pvt->_inoutbindvars)[i].type==
3334 SQLRCLIENTBINDVARTYPE_DOUBLE) {
3335
3336 if (pvt->_sqlrc->debug()) {
3337 pvt->_sqlrc->debugPrint("=");
3338 pvt->_sqlrc->debugPrint(
3339 (*pvt->_inoutbindvars)[i].
3340 value.doubleval.value);
3341 pvt->_sqlrc->debugPrint(":");
3342 pvt->_sqlrc->debugPrint(
3343 (int64_t)
3344 (*pvt->_inoutbindvars)[i].
3345 value.doubleval.precision);
3346 pvt->_sqlrc->debugPrint(",");
3347 pvt->_sqlrc->debugPrint(
3348 (int64_t)
3349 (*pvt->_inoutbindvars)[i].
3350 value.doubleval.scale);
3351 pvt->_sqlrc->debugPrint("\n");
3352 pvt->_sqlrc->debugPreEnd();
3353 }
3354
3355 } else if ((*pvt->_inoutbindvars)[i].type==
3356 SQLRCLIENTBINDVARTYPE_DATE) {
3357
3358 if (pvt->_sqlrc->debug()) {
3359 pvt->_sqlrc->debugPrint("=");
3360 pvt->_sqlrc->debugPrint((int64_t)
3361 (*pvt->_inoutbindvars)[i].
3362 value.dateval.year);
3363 pvt->_sqlrc->debugPrint("-");
3364 pvt->_sqlrc->debugPrint((int64_t)
3365 (*pvt->_inoutbindvars)[i].
3366 value.dateval.month);
3367 pvt->_sqlrc->debugPrint("-");
3368 pvt->_sqlrc->debugPrint((int64_t)
3369 (*pvt->_inoutbindvars)[i].
3370 value.dateval.day);
3371 pvt->_sqlrc->debugPrint(" ");
3372 if ((*pvt->_inoutbindvars)[i].
3373 value.dateval.isnegative) {
3374 pvt->_sqlrc->debugPrint("-");
3375 }
3376 pvt->_sqlrc->debugPrint((int64_t)
3377 (*pvt->_inoutbindvars)[i].
3378 value.dateval.hour);
3379 pvt->_sqlrc->debugPrint(":");
3380 pvt->_sqlrc->debugPrint((int64_t)
3381 (*pvt->_inoutbindvars)[i].
3382 value.dateval.minute);
3383 pvt->_sqlrc->debugPrint(":");
3384 pvt->_sqlrc->debugPrint((int64_t)
3385 (*pvt->_inoutbindvars)[i].
3386 value.dateval.second);
3387 pvt->_sqlrc->debugPrint(".");
3388 pvt->_sqlrc->debugPrint((int64_t)
3389 (*pvt->_inoutbindvars)[i].value.
3390 dateval.microsecond);
3391 pvt->_sqlrc->debugPrint(" ");
3392 pvt->_sqlrc->debugPrint(
3393 (*pvt->_inoutbindvars)[i].
3394 value.dateval.tz);
3395 pvt->_sqlrc->debugPrint("\n");
3396 pvt->_sqlrc->debugPreEnd();
3397 }
3398 }
3399 pvt->_sqlrc->debugPrint("\n");
3400 pvt->_sqlrc->debugPreEnd();
3401 }
3402
3403 // set this to NULL here because it will be deleted in
3404 // deleteInputOutputVariables, and it needs to be NULL in case
3405 // the query fails and parseInputOutputVariables (which
3406 // allocates a buffer for it) is never called
3407 (*pvt->_inoutbindvars)[i].value.dateval.tz=NULL;
3408
3409 i++;
3410 }
3411 }
3412
sendGetColumnInfo()3413 void sqlrcursor::sendGetColumnInfo() {
3414
3415 if (pvt->_sendcolumninfo==SEND_COLUMN_INFO) {
3416 if (pvt->_sqlrc->debug()) {
3417 pvt->_sqlrc->debugPreStart();
3418 pvt->_sqlrc->debugPrint("Send Column Info: yes\n");
3419 pvt->_sqlrc->debugPreEnd();
3420 }
3421 pvt->_cs->write((uint16_t)SEND_COLUMN_INFO);
3422 } else {
3423 if (pvt->_sqlrc->debug()) {
3424 pvt->_sqlrc->debugPreStart();
3425 pvt->_sqlrc->debugPrint("Send Column Info: no\n");
3426 pvt->_sqlrc->debugPreEnd();
3427 }
3428 pvt->_cs->write((uint16_t)DONT_SEND_COLUMN_INFO);
3429 }
3430 }
3431
processInitialResultSet()3432 bool sqlrcursor::processInitialResultSet() {
3433
3434 if (pvt->_sqlrc->debug()) {
3435 pvt->_sqlrc->debugPreStart();
3436 pvt->_sqlrc->debugPrint("Fetching initial rows...\n");
3437 pvt->_sqlrc->debugPreEnd();
3438 }
3439
3440 // start caching the result set
3441 if (pvt->_cacheon) {
3442 startCaching();
3443 }
3444
3445 // parse the columninfo and data
3446 bool success=true;
3447
3448 // Skip and fetch here if we're not reading from a cached result set.
3449 // This way, everything gets done in 1 round trip.
3450 if (!pvt->_cachesource) {
3451 success=skipAndFetch(true,0);
3452 }
3453
3454 // check for an error
3455 if (success) {
3456
3457 uint16_t err=getErrorStatus();
3458 if (err!=NO_ERROR_OCCURRED) {
3459
3460 // if there was a timeout, then end
3461 // the session and bail immediately
3462 if (err==TIMEOUT_GETTING_ERROR_STATUS) {
3463 pvt->_sqlrc->endSession();
3464 return false;
3465 }
3466
3467 // otherwise, get the error from the server
3468 getErrorFromServer();
3469
3470 // don't get the cursor if the error was that there
3471 // were no cursors available
3472 if (pvt->_errorno!=SQLR_ERROR_NOCURSORS) {
3473 getCursorId();
3474 }
3475
3476 // if we need to disconnect then end the session
3477 if (err==ERROR_OCCURRED_DISCONNECT) {
3478 pvt->_sqlrc->endSession();
3479 }
3480 return false;
3481 }
3482 }
3483
3484 // get data from the server/cache
3485 if (success && ((pvt->_cachesource && pvt->_cachesourceind) ||
3486 ((!pvt->_cachesource && !pvt->_cachesourceind) &&
3487 (success=getCursorId()) &&
3488 (success=getSuspended()))) &&
3489 (success=parseColumnInfo()) &&
3490 (success=parseOutputBinds()) &&
3491 (success=parseInputOutputBinds())) {
3492
3493 // skip and fetch here if we're reading from a cached result set
3494 if (pvt->_cachesource) {
3495 success=skipAndFetch(true,0);
3496 }
3497
3498 // parse the data
3499 if (success) {
3500
3501 if (!pvt->_lazyfetch) {
3502
3503 success=parseResults();
3504
3505 } else {
3506
3507 // If we just resumed a result set, (or more
3508 // precisely, if we did, and any rows had been
3509 // fetched from it prior to suspension) then
3510 // rowcount and firstrowindex need to be set
3511 // here. If we were't lazy-fetching then they
3512 // would have been set inside of parseResults().
3513 if (pvt->_resumedlastrowindex) {
3514 pvt->_rowcount=
3515 pvt->_resumedlastrowindex+1;
3516 pvt->_firstrowindex=pvt->_rowcount;
3517 }
3518 }
3519 }
3520 }
3521
3522 if (!success) {
3523 // some kind of network error occurred, end the session
3524 clearResultSet();
3525 pvt->_sqlrc->endSession();
3526 }
3527 return success;
3528 }
3529
skipAndFetch(bool initial,uint64_t rowstoskip)3530 bool sqlrcursor::skipAndFetch(bool initial, uint64_t rowstoskip) {
3531
3532 if (!skipRows(initial,rowstoskip)) {
3533 return false;
3534 }
3535
3536 fetchRows();
3537
3538 pvt->_sqlrc->flushWriteBuffer();
3539 return true;
3540 }
3541
skipRows(bool initial,uint64_t rowstoskip)3542 bool sqlrcursor::skipRows(bool initial, uint64_t rowstoskip) {
3543
3544 if (pvt->_sqlrc->debug()) {
3545 pvt->_sqlrc->debugPreStart();
3546 pvt->_sqlrc->debugPrint("Skipping ");
3547 pvt->_sqlrc->debugPrint((int64_t)rowstoskip);
3548 pvt->_sqlrc->debugPrint(" rows\n");
3549 pvt->_sqlrc->debugPreEnd();
3550 }
3551
3552 // bump the rowcount
3553 pvt->_rowcount+=rowstoskip;
3554
3555 // skip manually if we're reading from a cached result set
3556 if (pvt->_cachesource && pvt->_cachesourceind) {
3557
3558 // bail if we don't need to skip
3559 if (!rowstoskip) {
3560 return true;
3561 }
3562
3563 // get the row offset from the index
3564 pvt->_cachesourceind->setPositionRelativeToBeginning(
3565 13+sizeof(int64_t)+
3566 (pvt->_rowcount*sizeof(int64_t)));
3567 int64_t rowoffset;
3568 if (pvt->_cachesourceind->read(&rowoffset)!=sizeof(int64_t)) {
3569 setError("The cache file index appears to be corrupt.");
3570 return false;
3571 }
3572
3573 // skip to that offset in the cache file
3574 pvt->_cachesource->setPositionRelativeToBeginning(rowoffset);
3575 return true;
3576 }
3577
3578 if (initial) {
3579
3580 // If this is the initial fetch, then rowstoskip will always
3581 // be 0, and prior to 1.2, we would always send a 0 here.
3582 //
3583 // In 1.2+ we need a way to send some flags to the server, so
3584 // we'll repurpose these 8 bytes as flags.
3585 //
3586 // For now, the only flag is whether or not to do lazy fetches.
3587
3588 uint64_t flags=0;
3589 if (pvt->_lazyfetch) {
3590 flags=1;
3591 }
3592
3593 if (pvt->_sqlrc->debug()) {
3594 pvt->_sqlrc->debugPreStart();
3595 if (pvt->_lazyfetch) {
3596 pvt->_sqlrc->debugPrint("Lazy fetching\n");
3597 } else {
3598 pvt->_sqlrc->debugPrint("Eager fetching\n");
3599 }
3600 pvt->_sqlrc->debugPreEnd();
3601 }
3602
3603 pvt->_cs->write(flags);
3604
3605 } else {
3606 // otherwise send the server the number of rows to skip
3607 pvt->_cs->write(rowstoskip);
3608 }
3609 return true;
3610 }
3611
fetchRows()3612 void sqlrcursor::fetchRows() {
3613
3614 if (pvt->_sqlrc->debug()) {
3615 pvt->_sqlrc->debugPreStart();
3616 pvt->_sqlrc->debugPrint("Fetching ");
3617 pvt->_sqlrc->debugPrint((int64_t)pvt->_rsbuffersize);
3618 pvt->_sqlrc->debugPrint(" rows\n");
3619 pvt->_sqlrc->debugPreEnd();
3620 }
3621
3622 // bail if we're reading from a cached result set
3623 if (pvt->_cachesource && pvt->_cachesourceind) {
3624 return;
3625 }
3626
3627 // otherwise send the server the number of rows to fetch
3628 pvt->_cs->write(pvt->_rsbuffersize);
3629 }
3630
getErrorStatus()3631 uint16_t sqlrcursor::getErrorStatus() {
3632
3633 if (pvt->_sqlrc->debug()) {
3634 pvt->_sqlrc->debugPreStart();
3635 pvt->_sqlrc->debugPrint("Checking For An Error...\n");
3636 pvt->_sqlrc->debugPreEnd();
3637 }
3638
3639 // get a flag indicating whether there's been an error or not
3640 uint16_t err;
3641 int32_t result=getShort(&err,pvt->_sqlrc->responsetimeoutsec(),
3642 pvt->_sqlrc->responsetimeoutusec());
3643 if (result==RESULT_TIMEOUT) {
3644 setError("Timeout while determining whether "
3645 "an error occurred or not.\n");
3646 return TIMEOUT_GETTING_ERROR_STATUS;
3647 } else if (result!=sizeof(uint16_t)) {
3648 setError("Failed to determine whether an "
3649 "error occurred or not.\n "
3650 "A network error may have occurred.");
3651 return ERROR_OCCURRED;
3652 }
3653
3654 if (err==NO_ERROR_OCCURRED) {
3655 if (pvt->_sqlrc->debug()) {
3656 pvt->_sqlrc->debugPreStart();
3657 pvt->_sqlrc->debugPrint(" none.\n");
3658 pvt->_sqlrc->debugPreEnd();
3659 }
3660 cacheNoError();
3661 return NO_ERROR_OCCURRED;
3662 }
3663
3664 if (pvt->_sqlrc->debug()) {
3665 pvt->_sqlrc->debugPreStart();
3666 pvt->_sqlrc->debugPrint(" error!!!\n");
3667 pvt->_sqlrc->debugPreEnd();
3668 }
3669 return err;
3670 }
3671
getCursorId()3672 bool sqlrcursor::getCursorId() {
3673
3674 if (pvt->_sqlrc->debug()) {
3675 pvt->_sqlrc->debugPreStart();
3676 pvt->_sqlrc->debugPrint("Getting Cursor ID...\n");
3677 pvt->_sqlrc->debugPreEnd();
3678 }
3679 if (pvt->_cs->read(&pvt->_cursorid)!=sizeof(uint16_t)) {
3680 if (!pvt->_error) {
3681 char *err=error::getErrorString();
3682 stringbuffer errstr;
3683 errstr.append("Failed to get a cursor id.\n "
3684 "A network error may have occurred. ");
3685 errstr.append(err);
3686 setError(errstr.getString());
3687 delete[] err;
3688 }
3689 return false;
3690 }
3691 pvt->_havecursorid=true;
3692 if (pvt->_sqlrc->debug()) {
3693 pvt->_sqlrc->debugPreStart();
3694 pvt->_sqlrc->debugPrint("Cursor ID: ");
3695 pvt->_sqlrc->debugPrint((int64_t)pvt->_cursorid);
3696 pvt->_sqlrc->debugPrint("\n");
3697 pvt->_sqlrc->debugPreEnd();
3698 }
3699 return true;
3700 }
3701
getSuspended()3702 bool sqlrcursor::getSuspended() {
3703
3704 // see if the result set of that cursor is actually suspended
3705 uint16_t suspendedresultset;
3706 if (pvt->_cs->read(&suspendedresultset)!=sizeof(uint16_t)) {
3707 setError("Failed to determine whether "
3708 "the session was suspended or not.\n "
3709 "A network error may have occurred.");
3710 return false;
3711 }
3712
3713 if (suspendedresultset==SUSPENDED_RESULT_SET) {
3714
3715 // If it was suspended the server will send the index of the
3716 // last row from the previous result set.
3717 if (pvt->_cs->read(&pvt->_resumedlastrowindex)!=
3718 sizeof(uint64_t)) {
3719 setError("Failed to get the index of the "
3720 "last row of a previously suspended result "
3721 "set.\n A network error may have occurred.");
3722 return false;
3723 }
3724
3725 if (pvt->_sqlrc->debug()) {
3726 pvt->_sqlrc->debugPreStart();
3727 pvt->_sqlrc->debugPrint("Result set was ");
3728 pvt->_sqlrc->debugPrint("suspended at row index: ");
3729 pvt->_sqlrc->debugPrint(
3730 (int64_t)pvt->_resumedlastrowindex);
3731 pvt->_sqlrc->debugPrint("\n");
3732 pvt->_sqlrc->debugPreEnd();
3733 }
3734
3735 } else {
3736
3737 if (pvt->_sqlrc->debug()) {
3738 pvt->_sqlrc->debugPreStart();
3739 pvt->_sqlrc->debugPrint("Previous result set was ");
3740 pvt->_sqlrc->debugPrint("not suspended.\n");
3741 pvt->_sqlrc->debugPreEnd();
3742 }
3743 }
3744 return true;
3745 }
3746
parseColumnInfo()3747 bool sqlrcursor::parseColumnInfo() {
3748
3749 if (pvt->_sqlrc->debug()) {
3750 pvt->_sqlrc->debugPreStart();
3751 pvt->_sqlrc->debugPrint("Parsing Column Info\n");
3752 pvt->_sqlrc->debugPrint(" Actual row count: ");
3753 pvt->_sqlrc->debugPreEnd();
3754 }
3755
3756 // first get whether the server knows the total number of rows or not
3757 if (getShort(&pvt->_knowsactualrows)!=sizeof(uint16_t)) {
3758 setError("Failed to get whether the server knows "
3759 "the number of actual rows or not.\n"
3760 "A network error may have occurred.");
3761 return false;
3762 }
3763
3764 // get the number of rows returned by the query
3765 if (pvt->_knowsactualrows==ACTUAL_ROWS) {
3766 if (getLongLong(&pvt->_actualrows)!=sizeof(uint64_t)) {
3767 setError("Failed to get the number of actual rows.\n"
3768 "A network error may have occurred.");
3769 return false;
3770 }
3771 if (pvt->_sqlrc->debug()) {
3772 pvt->_sqlrc->debugPreStart();
3773 pvt->_sqlrc->debugPrint((int64_t)pvt->_actualrows);
3774 pvt->_sqlrc->debugPreEnd();
3775 }
3776 } else {
3777 if (pvt->_sqlrc->debug()) {
3778 pvt->_sqlrc->debugPreStart();
3779 pvt->_sqlrc->debugPrint("unknown");
3780 pvt->_sqlrc->debugPreEnd();
3781 }
3782 }
3783
3784 if (pvt->_sqlrc->debug()) {
3785 pvt->_sqlrc->debugPreStart();
3786 pvt->_sqlrc->debugPrint("\n");
3787 pvt->_sqlrc->debugPrint(" Affected row count: ");
3788 pvt->_sqlrc->debugPreEnd();
3789 }
3790
3791 // get whether the server knows the number of affected rows or not
3792 if (getShort(&pvt->_knowsaffectedrows)!=sizeof(uint16_t)) {
3793 setError("Failed to get whether the server knows "
3794 "the number of affected rows or not.\n"
3795 "A network error may have occurred.");
3796 return false;
3797 }
3798
3799 // get the number of rows affected by the query
3800 if (pvt->_knowsaffectedrows==AFFECTED_ROWS) {
3801 if (getLongLong(&pvt->_affectedrows)!=sizeof(uint64_t)) {
3802 setError("Failed to get the number of affected rows.\n"
3803 "A network error may have occurred.");
3804 return false;
3805 }
3806 if (pvt->_sqlrc->debug()) {
3807 pvt->_sqlrc->debugPreStart();
3808 pvt->_sqlrc->debugPrint((int64_t)pvt->_affectedrows);
3809 pvt->_sqlrc->debugPreEnd();
3810 }
3811 } else {
3812 if (pvt->_sqlrc->debug()) {
3813 pvt->_sqlrc->debugPreStart();
3814 pvt->_sqlrc->debugPrint("unknown");
3815 pvt->_sqlrc->debugPreEnd();
3816 }
3817 }
3818
3819 if (pvt->_sqlrc->debug()) {
3820 pvt->_sqlrc->debugPreStart();
3821 pvt->_sqlrc->debugPrint("\n");
3822 pvt->_sqlrc->debugPreEnd();
3823 }
3824
3825 // get whether the server is sending column info or not
3826 if (getShort(&pvt->_sentcolumninfo)!=sizeof(uint16_t)) {
3827 setError("Failed to get whether the server "
3828 "is sending column info or not.\n"
3829 "A network error may have occurred.");
3830 return false;
3831 }
3832
3833 // get column count
3834 if (getLong(&pvt->_colcount)!=sizeof(uint32_t)) {
3835 setError("Failed to get the column count.\n"
3836 "A network error may have occurred.");
3837 return false;
3838 }
3839 if (pvt->_sqlrc->debug()) {
3840 pvt->_sqlrc->debugPreStart();
3841 pvt->_sqlrc->debugPrint(" Column count: ");
3842 pvt->_sqlrc->debugPrint((int64_t)pvt->_colcount);
3843 pvt->_sqlrc->debugPrint("\n");
3844 pvt->_sqlrc->debugPreEnd();
3845 }
3846
3847 // we have to do this here even if we're not getting the column
3848 // descriptions because we are going to use the longdatatype member
3849 // variable no matter what
3850 createColumnBuffers();
3851
3852 if (pvt->_sendcolumninfo==SEND_COLUMN_INFO &&
3853 pvt->_sentcolumninfo==SEND_COLUMN_INFO) {
3854
3855 // get whether column types will be predefined id's or strings
3856 if (getShort(&pvt->_columntypeformat)!=sizeof(uint16_t)) {
3857 setError("Failed to whether column types will be "
3858 "predefined id's or strings.\n"
3859 "A network error may have occurred.");
3860 return false;
3861 }
3862
3863 // some useful variables
3864 uint16_t length;
3865 sqlrclientcolumn *currentcol;
3866
3867 // get the columninfo segment
3868 for (uint32_t i=0; i<pvt->_colcount; i++) {
3869
3870 // get the column name length
3871 if (getShort(&length)!=sizeof(uint16_t)) {
3872 setError("Failed to get the column name "
3873 "length.\n"
3874 "A network error may have occurred.");
3875 return false;
3876 }
3877
3878 // which column to use
3879 currentcol=getColumnInternal(i);
3880
3881 // get the column name
3882 currentcol->name=
3883 (char *)pvt->_colstorage->allocate(length+1);
3884 if (getString(currentcol->name,length)!=length) {
3885 setError("Failed to get the column name.\n "
3886 "A network error may have occurred.");
3887 return false;
3888 }
3889 currentcol->name[length]='\0';
3890
3891 // upper/lowercase column name if necessary
3892 if (pvt->_colcase==UPPER_CASE) {
3893 charstring::upper(currentcol->name);
3894 } else if (pvt->_colcase==LOWER_CASE) {
3895 charstring::lower(currentcol->name);
3896 }
3897
3898 if (pvt->_columntypeformat==COLUMN_TYPE_IDS) {
3899
3900 // get the column type
3901 if (getShort(¤tcol->type)!=
3902 sizeof(uint16_t)) {
3903 setError("Failed to get the column "
3904 "type.\n"
3905 "A network error may have "
3906 "occurred.");
3907 return false;
3908 }
3909
3910 // sanity check
3911 if (currentcol->type>=END_DATATYPE) {
3912 currentcol->type=UNKNOWN_DATATYPE;
3913 }
3914
3915 } else {
3916
3917 // get the column type length
3918 if (getShort(¤tcol->typestringlength)!=
3919 sizeof(uint16_t)) {
3920 setError("Failed to get the column "
3921 "type length.\n"
3922 "A network error may have "
3923 "occurred.");
3924 return false;
3925 }
3926
3927 // get the column type
3928 currentcol->typestring=new
3929 char[currentcol->typestringlength+1];
3930 currentcol->typestring[
3931 currentcol->typestringlength]='\0';
3932 if (getString(currentcol->typestring,
3933 currentcol->typestringlength)!=
3934 currentcol->typestringlength) {
3935 setError("Failed to get the column "
3936 "type.\n"
3937 "A network error may have "
3938 "occurred.");
3939 return false;
3940 }
3941 }
3942
3943 // get the column length
3944 // get the column precision
3945 // get the column scale
3946 // get whether the column is nullable
3947 // get whether the column is a primary key
3948 // get whether the column is unique
3949 // get whether the column is part of a key
3950 // get whether the column is unsigned
3951 // get whether the column is zero-filled
3952 // get whether the column is binary
3953 // get whether the column is auto-incremented
3954 if (getLong(¤tcol->length)!=
3955 sizeof(uint32_t) ||
3956 getLong(¤tcol->precision)!=
3957 sizeof(uint32_t) ||
3958 getLong(¤tcol->scale)!=
3959 sizeof(uint32_t) ||
3960 getShort(¤tcol->nullable)!=
3961 sizeof(uint16_t) ||
3962 getShort(¤tcol->primarykey)!=
3963 sizeof(uint16_t) ||
3964 getShort(¤tcol->unique)!=
3965 sizeof(uint16_t) ||
3966 getShort(¤tcol->partofkey)!=
3967 sizeof(uint16_t) ||
3968 getShort(¤tcol->unsignednumber)!=
3969 sizeof(uint16_t) ||
3970 getShort(¤tcol->zerofill)!=
3971 sizeof(uint16_t) ||
3972 getShort(¤tcol->binary)!=
3973 sizeof(uint16_t) ||
3974 getShort(¤tcol->autoincrement)!=
3975 sizeof(uint16_t)) {
3976 setError("Failed to get column info.\n"
3977 "A network error may have occurred.");
3978 return false;
3979 }
3980
3981 // get the table length
3982 if (getShort(&length)!=sizeof(uint16_t)) {
3983 setError("Failed to get the table length.\n"
3984 "A network error may have occurred.");
3985 return false;
3986 }
3987
3988 // get the table
3989 currentcol->table=
3990 (char *)pvt->_colstorage->allocate(length+1);
3991 if (getString(currentcol->table,length)!=length) {
3992 setError("Failed to get the table.\n "
3993 "A network error may have occurred.");
3994 return false;
3995 }
3996 currentcol->table[length]='\0';
3997
3998
3999 // initialize the longest value
4000 currentcol->longest=0;
4001
4002 if (pvt->_sqlrc->debug()) {
4003 pvt->_sqlrc->debugPreStart();
4004 pvt->_sqlrc->debugPrint(" ");
4005 pvt->_sqlrc->debugPrint("\"");
4006 pvt->_sqlrc->debugPrint(currentcol->table);
4007 pvt->_sqlrc->debugPrint("\".");
4008 pvt->_sqlrc->debugPrint("\"");
4009 pvt->_sqlrc->debugPrint(currentcol->name);
4010 pvt->_sqlrc->debugPrint("\",");
4011 pvt->_sqlrc->debugPrint("\"");
4012 if (pvt->_columntypeformat!=COLUMN_TYPE_IDS) {
4013 pvt->_sqlrc->debugPrint(
4014 currentcol->typestring);
4015 } else {
4016 pvt->_sqlrc->debugPrint(
4017 datatypestring[
4018 currentcol->type]);
4019 }
4020 pvt->_sqlrc->debugPrint("\", ");
4021 pvt->_sqlrc->debugPrint((int64_t)
4022 currentcol->length);
4023 pvt->_sqlrc->debugPrint(" (");
4024 pvt->_sqlrc->debugPrint((int64_t)
4025 currentcol->precision);
4026 pvt->_sqlrc->debugPrint(",");
4027 pvt->_sqlrc->debugPrint((int64_t)
4028 currentcol->scale);
4029 pvt->_sqlrc->debugPrint(") ");
4030 if (!currentcol->nullable) {
4031 pvt->_sqlrc->debugPrint(
4032 "NOT NULL ");
4033 }
4034 if (currentcol->primarykey) {
4035 pvt->_sqlrc->debugPrint(
4036 "Primary Key ");
4037 }
4038 if (currentcol->unique) {
4039 pvt->_sqlrc->debugPrint(
4040 "Unique ");
4041 }
4042 if (currentcol->partofkey) {
4043 pvt->_sqlrc->debugPrint(
4044 "Part of a Key ");
4045 }
4046 if (currentcol->unsignednumber) {
4047 pvt->_sqlrc->debugPrint(
4048 "Unsigned ");
4049 }
4050 if (currentcol->zerofill) {
4051 pvt->_sqlrc->debugPrint(
4052 "Zero Filled ");
4053 }
4054 if (currentcol->binary) {
4055 pvt->_sqlrc->debugPrint(
4056 "Binary ");
4057 }
4058 if (currentcol->autoincrement) {
4059 pvt->_sqlrc->debugPrint(
4060 "Auto-Increment ");
4061 }
4062 pvt->_sqlrc->debugPrint("\n");
4063 pvt->_sqlrc->debugPreEnd();
4064 }
4065
4066 }
4067 }
4068
4069 // cache the column definitions
4070 cacheColumnInfo();
4071
4072 return true;
4073 }
4074
createColumnBuffers()4075 void sqlrcursor::createColumnBuffers() {
4076
4077 // we could get really sophisticated here and keep stats on the number
4078 // of columns that previous queries returned and adjust the size of
4079 // "columns" periodically, but for now, we'll just use a static size
4080
4081 // create the standard set of columns, this will hang around until
4082 // the cursor is deleted
4083 if (!pvt->_columns) {
4084 pvt->_columns=new sqlrclientcolumn[OPTIMISTIC_COLUMN_COUNT];
4085 }
4086
4087 // if there are more columns than our static column buffer
4088 // can handle, create extra columns, these will be deleted after each
4089 // query
4090 if (pvt->_colcount>OPTIMISTIC_COLUMN_COUNT &&
4091 pvt->_colcount>pvt->_previouscolcount) {
4092 delete[] pvt->_extracolumns;
4093 pvt->_extracolumns=
4094 new sqlrclientcolumn[
4095 pvt->_colcount-OPTIMISTIC_COLUMN_COUNT];
4096 }
4097 }
4098
parseOutputBinds()4099 bool sqlrcursor::parseOutputBinds() {
4100
4101 if (pvt->_sqlrc->debug()) {
4102 pvt->_sqlrc->debugPreStart();
4103 pvt->_sqlrc->debugPrint("Receiving Output Bind Values: \n");
4104 pvt->_sqlrc->debugPreEnd();
4105 }
4106
4107 // useful variables
4108 uint16_t type;
4109 uint32_t length;
4110 uint16_t count=0;
4111
4112 // get the bind values
4113 for (;;) {
4114
4115 if (pvt->_sqlrc->debug()) {
4116 pvt->_sqlrc->debugPreStart();
4117 pvt->_sqlrc->debugPrint(" getting type...\n");
4118 pvt->_sqlrc->debugPreEnd();
4119 }
4120
4121 // get the data type
4122 if (getShort(&type)!=sizeof(uint16_t)) {
4123 setError("Failed to get data type.\n "
4124 "A network error may have occurred.");
4125
4126 return false;
4127 }
4128
4129 if (pvt->_sqlrc->debug()) {
4130 pvt->_sqlrc->debugPreStart();
4131 pvt->_sqlrc->debugPrint(" done getting type: ");
4132 pvt->_sqlrc->debugPrint((int64_t)type);
4133 pvt->_sqlrc->debugPrint("\n");
4134 pvt->_sqlrc->debugPreEnd();
4135 }
4136
4137 // check for end of bind values
4138 if (type==END_BIND_VARS) {
4139
4140 break;
4141
4142 } else if (type==NULL_DATA) {
4143
4144 if (pvt->_sqlrc->debug()) {
4145 pvt->_sqlrc->debugPreStart();
4146 pvt->_sqlrc->debugPrint(
4147 " NULL output bind\n");
4148 pvt->_sqlrc->debugPreEnd();
4149 }
4150
4151 // handle a null value
4152 (*pvt->_outbindvars)[count].resultvaluesize=0;
4153 if ((*pvt->_outbindvars)[count].type==
4154 SQLRCLIENTBINDVARTYPE_STRING) {
4155 if (pvt->_returnnulls) {
4156 (*pvt->_outbindvars)[count].value.
4157 stringval=NULL;
4158 } else {
4159 (*pvt->_outbindvars)[count].value.
4160 stringval=new char[1];
4161 (*pvt->_outbindvars)[count].value.
4162 stringval[0]='\0';
4163 }
4164 } else if ((*pvt->_outbindvars)[count].type==
4165 SQLRCLIENTBINDVARTYPE_INTEGER) {
4166 (*pvt->_outbindvars)[count].value.integerval=0;
4167 } else if ((*pvt->_outbindvars)[count].type==
4168 SQLRCLIENTBINDVARTYPE_DOUBLE) {
4169 (*pvt->_outbindvars)[count].
4170 value.doubleval.value=0;
4171 (*pvt->_outbindvars)[count].
4172 value.doubleval.precision=0;
4173 (*pvt->_outbindvars)[count].
4174 value.doubleval.scale=0;
4175 } else if ((*pvt->_outbindvars)[count].type==
4176 SQLRCLIENTBINDVARTYPE_DATE) {
4177 (*pvt->_outbindvars)[count].
4178 value.dateval.year=0;
4179 (*pvt->_outbindvars)[count].
4180 value.dateval.month=0;
4181 (*pvt->_outbindvars)[count].
4182 value.dateval.day=0;
4183 (*pvt->_outbindvars)[count].
4184 value.dateval.hour=0;
4185 (*pvt->_outbindvars)[count].
4186 value.dateval.minute=0;
4187 (*pvt->_outbindvars)[count].
4188 value.dateval.second=0;
4189 (*pvt->_outbindvars)[count].
4190 value.dateval.microsecond=0;
4191 if (pvt->_returnnulls) {
4192 (*pvt->_outbindvars)[count].
4193 value.dateval.tz=NULL;
4194 } else {
4195 (*pvt->_outbindvars)[count].
4196 value.dateval.tz=new char[1];
4197 (*pvt->_outbindvars)[count].
4198 value.dateval.tz[0]='\0';
4199 }
4200 }
4201
4202 if (pvt->_sqlrc->debug()) {
4203 pvt->_sqlrc->debugPrint(" ");
4204 pvt->_sqlrc->debugPrint("done fetching.\n");
4205 }
4206
4207 } else if (type==STRING_DATA) {
4208
4209 if (pvt->_sqlrc->debug()) {
4210 pvt->_sqlrc->debugPreStart();
4211 pvt->_sqlrc->debugPrint(
4212 " STRING output bind\n");
4213 pvt->_sqlrc->debugPreEnd();
4214 }
4215
4216 // get the value length
4217 if (getLong(&length)!=sizeof(uint32_t)) {
4218 setError("Failed to get string value length.\n "
4219 "A network error may have occurred.");
4220 return false;
4221 }
4222 (*pvt->_outbindvars)[count].resultvaluesize=length;
4223 (*pvt->_outbindvars)[count].value.stringval=
4224 new char[length+1];
4225
4226 if (pvt->_sqlrc->debug()) {
4227 pvt->_sqlrc->debugPreStart();
4228 pvt->_sqlrc->debugPrint(
4229 " length=");
4230 pvt->_sqlrc->debugPrint((int64_t)length);
4231 pvt->_sqlrc->debugPrint("\n");
4232 pvt->_sqlrc->debugPreEnd();
4233 }
4234
4235 // get the value
4236 if ((uint32_t)getString(
4237 (*pvt->_outbindvars)[count].value.
4238 stringval,length)!=length) {
4239 setError("Failed to get string value.\n "
4240 "A network error may have occurred.");
4241 return false;
4242 }
4243 (*pvt->_outbindvars)[count].
4244 value.stringval[length]='\0';
4245
4246 if (pvt->_sqlrc->debug()) {
4247 pvt->_sqlrc->debugPreStart();
4248 pvt->_sqlrc->debugPrint(" ");
4249 pvt->_sqlrc->debugPrint("done fetching\n");
4250 pvt->_sqlrc->debugPreEnd();
4251 }
4252
4253 } else if (type==INTEGER_DATA) {
4254
4255 if (pvt->_sqlrc->debug()) {
4256 pvt->_sqlrc->debugPreStart();
4257 pvt->_sqlrc->debugPrint(
4258 " INTEGER output bind\n");
4259 pvt->_sqlrc->debugPreEnd();
4260 }
4261
4262 // get the value
4263 if (getLongLong((uint64_t *)
4264 &(*pvt->_outbindvars)[count].value.
4265 integerval)!=sizeof(uint64_t)) {
4266 setError("Failed to get integer value.\n "
4267 "A network error may have occurred.");
4268 return false;
4269 }
4270
4271 if (pvt->_sqlrc->debug()) {
4272 pvt->_sqlrc->debugPreStart();
4273 pvt->_sqlrc->debugPrint(" ");
4274 pvt->_sqlrc->debugPrint("done fetching\n");
4275 pvt->_sqlrc->debugPreEnd();
4276 }
4277
4278 } else if (type==DOUBLE_DATA) {
4279
4280 if (pvt->_sqlrc->debug()) {
4281 pvt->_sqlrc->debugPreStart();
4282 pvt->_sqlrc->debugPrint(
4283 " DOUBLE output bind\n");
4284 pvt->_sqlrc->debugPreEnd();
4285 }
4286
4287 // get the value
4288 if (getDouble(&(*pvt->_outbindvars)[count].value.
4289 doubleval.value)!=
4290 sizeof(double)) {
4291 setError("Failed to get double value.\n "
4292 "A network error may have occurred.");
4293 return false;
4294 }
4295
4296 // get the precision
4297 if (getLong(&(*pvt->_outbindvars)[count].value.
4298 doubleval.precision)!=
4299 sizeof(uint32_t)) {
4300 setError("Failed to get precision.\n "
4301 "A network error may have occurred.");
4302 return false;
4303 }
4304
4305 // get the scale
4306 if (getLong(&(*pvt->_outbindvars)[count].value.
4307 doubleval.scale)!=
4308 sizeof(uint32_t)) {
4309 setError("Failed to get scale.\n "
4310 "A network error may have occurred.");
4311 return false;
4312 }
4313
4314 if (pvt->_sqlrc->debug()) {
4315 pvt->_sqlrc->debugPreStart();
4316 pvt->_sqlrc->debugPrint(" ");
4317 pvt->_sqlrc->debugPrint("done fetching\n");
4318 pvt->_sqlrc->debugPreEnd();
4319 }
4320
4321 } else if (type==DATE_DATA) {
4322
4323 if (pvt->_sqlrc->debug()) {
4324 pvt->_sqlrc->debugPreStart();
4325 pvt->_sqlrc->debugPrint(
4326 " DATE output bind\n");
4327 pvt->_sqlrc->debugPreEnd();
4328 }
4329
4330 uint16_t temp;
4331
4332 // get the year
4333 if (getShort(&temp)!=sizeof(uint16_t)) {
4334 setError("Failed to get long value.\n "
4335 "A network error may have occurred.");
4336 return false;
4337 }
4338 (*pvt->_outbindvars)[count].
4339 value.dateval.year=(int16_t)temp;
4340
4341 // get the month
4342 if (getShort(&temp)!=sizeof(uint16_t)) {
4343 setError("Failed to get long value.\n "
4344 "A network error may have occurred.");
4345 return false;
4346 }
4347 (*pvt->_outbindvars)[count].
4348 value.dateval.month=(int16_t)temp;
4349
4350 // get the day
4351 if (getShort(&temp)!=sizeof(uint16_t)) {
4352 setError("Failed to get long value.\n "
4353 "A network error may have occurred.");
4354 return false;
4355 }
4356 (*pvt->_outbindvars)[count].
4357 value.dateval.day=(int16_t)temp;
4358
4359 // get the hour
4360 if (getShort(&temp)!=sizeof(uint16_t)) {
4361 setError("Failed to get long value.\n "
4362 "A network error may have occurred.");
4363 return false;
4364 }
4365 (*pvt->_outbindvars)[count].
4366 value.dateval.hour=(int16_t)temp;
4367
4368 // get the minute
4369 if (getShort(&temp)!=sizeof(uint16_t)) {
4370 setError("Failed to get long value.\n "
4371 "A network error may have occurred.");
4372 return false;
4373 }
4374 (*pvt->_outbindvars)[count].
4375 value.dateval.minute=(int16_t)temp;
4376
4377 // get the second
4378 if (getShort(&temp)!=sizeof(uint16_t)) {
4379 setError("Failed to get long value.\n "
4380 "A network error may have occurred.");
4381 return false;
4382 }
4383 (*pvt->_outbindvars)[count].
4384 value.dateval.second=(int16_t)temp;
4385
4386 // get the microsecond
4387 uint32_t temp32;
4388 if (getLong(&temp32)!=sizeof(uint32_t)) {
4389 setError("Failed to get long value.\n "
4390 "A network error may have occurred.");
4391 return false;
4392 }
4393 (*pvt->_outbindvars)[count].value.
4394 dateval.microsecond=(int32_t)temp32;
4395
4396 // get the timezone length
4397 uint16_t length;
4398 if (getShort(&length)!=sizeof(uint16_t)) {
4399 setError("Failed to get timezone length.\n "
4400 "A network error may have occurred.");
4401 return false;
4402 }
4403 (*pvt->_outbindvars)[count].
4404 value.dateval.tz=new char[length+1];
4405
4406 // get the timezone
4407 if ((uint16_t)getString(
4408 (*pvt->_outbindvars)[count].value.
4409 dateval.tz,length)!=length) {
4410 setError("Failed to get timezone.\n "
4411 "A network error may have occurred.");
4412 return false;
4413 }
4414 (*pvt->_outbindvars)[count].
4415 value.dateval.tz[length]='\0';
4416
4417 // get the isnegative flag
4418 bool tempbool;
4419 if (getBool(&tempbool)!=sizeof(bool)) {
4420 setError("Failed to get bool value.\n "
4421 "A network error may have occurred.");
4422 return false;
4423 }
4424 (*pvt->_outbindvars)[count].value.
4425 dateval.isnegative=tempbool;
4426
4427 if (pvt->_sqlrc->debug()) {
4428 pvt->_sqlrc->debugPreStart();
4429 pvt->_sqlrc->debugPrint(" ");
4430 pvt->_sqlrc->debugPrint("done fetching\n");
4431 pvt->_sqlrc->debugPreEnd();
4432 }
4433
4434 } else if (type==CURSOR_DATA) {
4435
4436 if (pvt->_sqlrc->debug()) {
4437 pvt->_sqlrc->debugPreStart();
4438 pvt->_sqlrc->debugPrint(
4439 " CURSOR output bind\n");
4440 pvt->_sqlrc->debugPreEnd();
4441 }
4442
4443 // get the cursor id
4444 if (getShort((uint16_t *)
4445 &((*pvt->_outbindvars)[count].value.cursorid))!=
4446 sizeof(uint16_t)) {
4447 setError("Failed to get cursor id.\n "
4448 "A network error may have occurred.");
4449 return false;
4450 }
4451
4452 if (pvt->_sqlrc->debug()) {
4453 pvt->_sqlrc->debugPreStart();
4454 pvt->_sqlrc->debugPrint(" ");
4455 pvt->_sqlrc->debugPrint("done fetching\n");
4456 pvt->_sqlrc->debugPreEnd();
4457 }
4458
4459 } else {
4460
4461 if (pvt->_sqlrc->debug()) {
4462 pvt->_sqlrc->debugPreStart();
4463 pvt->_sqlrc->debugPrint(" LOB/CLOB ");
4464 pvt->_sqlrc->debugPrint("output bind\n");
4465 pvt->_sqlrc->debugPreEnd();
4466 }
4467
4468 // must be START_LONG_DATA...
4469 // get the total length of the long data
4470 uint64_t totallength;
4471 if (getLongLong(&totallength)!=sizeof(uint64_t)) {
4472 setError("Failed to get total length.\n "
4473 "A network error may have occurred.");
4474 return false;
4475 }
4476
4477 if (pvt->_sqlrc->debug()) {
4478 pvt->_sqlrc->debugPreStart();
4479 pvt->_sqlrc->debugPrint(
4480 " length=");
4481 pvt->_sqlrc->debugPrint((int64_t)totallength);
4482 pvt->_sqlrc->debugPrint("\n");
4483 pvt->_sqlrc->debugPreEnd();
4484 }
4485
4486 // create a buffer to hold the data
4487 char *buffer=new char[totallength+1];
4488
4489 uint64_t offset=0;
4490 uint32_t length;
4491 for (;;) {
4492
4493 if (pvt->_sqlrc->debug()) {
4494 pvt->_sqlrc->debugPreStart();
4495 pvt->_sqlrc->debugPrint(
4496 " ");
4497 pvt->_sqlrc->debugPrint(
4498 "fetching...\n");
4499 pvt->_sqlrc->debugPreEnd();
4500 }
4501
4502 // get the type of the chunk
4503 if (getShort(&type)!=sizeof(uint16_t)) {
4504 delete[] buffer;
4505 setError("Failed to get chunk type.\n "
4506 "A network error may have "
4507 "occurred.");
4508 return false;
4509 }
4510
4511 // check to see if we're done
4512 if (type==END_LONG_DATA) {
4513 break;
4514 }
4515
4516 // get the length of the chunk
4517 if (getLong(&length)!=sizeof(uint32_t)) {
4518 delete[] buffer;
4519 setError("Failed to get chunk length.\n"
4520 " A network error may have "
4521 "occurred.");
4522 return false;
4523 }
4524
4525 // get the chunk of data
4526 if ((uint32_t)getString(buffer+offset,
4527 length)!=length) {
4528 delete[] buffer;
4529 setError("Failed to get chunk data.\n "
4530 "A network error may have "
4531 "occurred.");
4532 return false;
4533 }
4534
4535 offset=offset+length;
4536 }
4537
4538 if (pvt->_sqlrc->debug()) {
4539 pvt->_sqlrc->debugPreStart();
4540 pvt->_sqlrc->debugPrint(" ");
4541 pvt->_sqlrc->debugPrint("done fetching.\n");
4542 pvt->_sqlrc->debugPreEnd();
4543 }
4544
4545 // NULL terminate the buffer. This makes
4546 // certain operations safer and won't hurt
4547 // since the actual length (which doesn't
4548 // include the NULL) is available from
4549 // getOutputBindLength.
4550 buffer[totallength]='\0';
4551 (*pvt->_outbindvars)[count].value.lobval=buffer;
4552 (*pvt->_outbindvars)[count].resultvaluesize=totallength;
4553 }
4554
4555 if (pvt->_sqlrc->debug()) {
4556 pvt->_sqlrc->debugPreStart();
4557 pvt->_sqlrc->debugPrint(
4558 (*pvt->_outbindvars)[count].variable);
4559 pvt->_sqlrc->debugPrint("=");
4560 if ((*pvt->_outbindvars)[count].type==
4561 SQLRCLIENTBINDVARTYPE_BLOB) {
4562 pvt->_sqlrc->debugPrintBlob(
4563 (*pvt->_outbindvars)[count].
4564 value.lobval,
4565 (*pvt->_outbindvars)[count].
4566 resultvaluesize);
4567 } else if ((*pvt->_outbindvars)[count].type==
4568 SQLRCLIENTBINDVARTYPE_CLOB) {
4569 pvt->_sqlrc->debugPrintClob(
4570 (*pvt->_outbindvars)[count].
4571 value.lobval,
4572 (*pvt->_outbindvars)[count].
4573 resultvaluesize);
4574 } else if ((*pvt->_outbindvars)[count].type==
4575 SQLRCLIENTBINDVARTYPE_CURSOR) {
4576 pvt->_sqlrc->debugPrint((int64_t)
4577 (*pvt->_outbindvars)[count].
4578 value.cursorid);
4579 } else if ((*pvt->_outbindvars)[count].type==
4580 SQLRCLIENTBINDVARTYPE_INTEGER) {
4581 pvt->_sqlrc->debugPrint(
4582 (*pvt->_outbindvars)[count].
4583 value.integerval);
4584 } else if ((*pvt->_outbindvars)[count].type==
4585 SQLRCLIENTBINDVARTYPE_DOUBLE) {
4586 pvt->_sqlrc->debugPrint(
4587 (*pvt->_outbindvars)[count].
4588 value.doubleval.value);
4589 pvt->_sqlrc->debugPrint("(");
4590 pvt->_sqlrc->debugPrint((int64_t)
4591 (*pvt->_outbindvars)[count].
4592 value.doubleval.
4593 precision);
4594 pvt->_sqlrc->debugPrint(",");
4595 pvt->_sqlrc->debugPrint((int64_t)
4596 (*pvt->_outbindvars)[count].
4597 value.doubleval.
4598 scale);
4599 pvt->_sqlrc->debugPrint(")");
4600 } else if ((*pvt->_outbindvars)[count].type==
4601 SQLRCLIENTBINDVARTYPE_DATE) {
4602 pvt->_sqlrc->debugPrint((int64_t)
4603 (*pvt->_outbindvars)[count].
4604 value.dateval.year);
4605 pvt->_sqlrc->debugPrint("-");
4606 pvt->_sqlrc->debugPrint((int64_t)
4607 (*pvt->_outbindvars)[count].
4608 value.dateval.month);
4609 pvt->_sqlrc->debugPrint("-");
4610 pvt->_sqlrc->debugPrint((int64_t)
4611 (*pvt->_outbindvars)[count].
4612 value.dateval.day);
4613 pvt->_sqlrc->debugPrint(" ");
4614 pvt->_sqlrc->debugPrint((int64_t)
4615 (*pvt->_outbindvars)[count].
4616 value.dateval.hour);
4617 pvt->_sqlrc->debugPrint(":");
4618 pvt->_sqlrc->debugPrint((int64_t)
4619 (*pvt->_outbindvars)[count].
4620 value.dateval.minute);
4621 pvt->_sqlrc->debugPrint(":");
4622 pvt->_sqlrc->debugPrint((int64_t)
4623 (*pvt->_outbindvars)[count].
4624 value.dateval.second);
4625 pvt->_sqlrc->debugPrint(".");
4626 pvt->_sqlrc->debugPrint((int64_t)
4627 (*pvt->_inoutbindvars)[count].
4628 value.dateval.microsecond);
4629 pvt->_sqlrc->debugPrint(" ");
4630 pvt->_sqlrc->debugPrint(
4631 (*pvt->_outbindvars)[count].
4632 value.dateval.tz);
4633 } else {
4634 pvt->_sqlrc->debugPrint(
4635 (*pvt->_outbindvars)[count].
4636 value.stringval);
4637 }
4638 pvt->_sqlrc->debugPrint("\n");
4639 pvt->_sqlrc->debugPreEnd();
4640 }
4641
4642 count++;
4643 }
4644
4645 // cache the output binds
4646 cacheOutputBinds(count);
4647
4648 return true;
4649 }
4650
parseInputOutputBinds()4651 bool sqlrcursor::parseInputOutputBinds() {
4652
4653 if (pvt->_sqlrc->debug()) {
4654 pvt->_sqlrc->debugPreStart();
4655 pvt->_sqlrc->debugPrint("Receiving Input/Output "
4656 "Bind Values: \n");
4657 pvt->_sqlrc->debugPreEnd();
4658 }
4659
4660 // useful variables
4661 uint16_t type;
4662 uint32_t length;
4663 uint16_t count=0;
4664
4665 // get the bind values
4666 for (;;) {
4667
4668 if (pvt->_sqlrc->debug()) {
4669 pvt->_sqlrc->debugPreStart();
4670 pvt->_sqlrc->debugPrint(" getting type...\n");
4671 pvt->_sqlrc->debugPreEnd();
4672 }
4673
4674 // get the data type
4675 if (getShort(&type)!=sizeof(uint16_t)) {
4676 setError("Failed to get data type.\n "
4677 "A network error may have occurred.");
4678
4679 return false;
4680 }
4681
4682 if (pvt->_sqlrc->debug()) {
4683 pvt->_sqlrc->debugPreStart();
4684 pvt->_sqlrc->debugPrint(" done getting type: ");
4685 pvt->_sqlrc->debugPrint((int64_t)type);
4686 pvt->_sqlrc->debugPrint("\n");
4687 pvt->_sqlrc->debugPreEnd();
4688 }
4689
4690 // check for end of bind values
4691 if (type==END_BIND_VARS) {
4692
4693 break;
4694
4695 } else if (type==NULL_DATA) {
4696
4697 if (pvt->_sqlrc->debug()) {
4698 pvt->_sqlrc->debugPreStart();
4699 pvt->_sqlrc->debugPrint(
4700 " NULL output bind\n");
4701 pvt->_sqlrc->debugPreEnd();
4702 }
4703
4704 if ((*pvt->_inoutbindvars)[count].type==
4705 SQLRCLIENTBINDVARTYPE_NULL) {
4706 (*pvt->_inoutbindvars)[count].type=
4707 SQLRCLIENTBINDVARTYPE_STRING;
4708 }
4709
4710 // handle a null value
4711 (*pvt->_inoutbindvars)[count].resultvaluesize=0;
4712 if ((*pvt->_inoutbindvars)[count].type==
4713 SQLRCLIENTBINDVARTYPE_STRING) {
4714 if (pvt->_returnnulls) {
4715 delete[] (*pvt->_inoutbindvars)[count].
4716 value.stringval;
4717 (*pvt->_inoutbindvars)[count].value.
4718 stringval=NULL;
4719 } else {
4720 (*pvt->_inoutbindvars)[count].value.
4721 stringval[0]='\0';
4722 }
4723 } else if ((*pvt->_inoutbindvars)[count].type==
4724 SQLRCLIENTBINDVARTYPE_INTEGER) {
4725 (*pvt->_inoutbindvars)[count].value.
4726 integerval=0;
4727 } else if ((*pvt->_inoutbindvars)[count].type==
4728 SQLRCLIENTBINDVARTYPE_DOUBLE) {
4729 (*pvt->_inoutbindvars)[count].
4730 value.doubleval.value=0;
4731 (*pvt->_inoutbindvars)[count].
4732 value.doubleval.precision=0;
4733 (*pvt->_inoutbindvars)[count].
4734 value.doubleval.scale=0;
4735 } else if ((*pvt->_inoutbindvars)[count].type==
4736 SQLRCLIENTBINDVARTYPE_DATE) {
4737 (*pvt->_inoutbindvars)[count].
4738 value.dateval.year=0;
4739 (*pvt->_inoutbindvars)[count].
4740 value.dateval.month=0;
4741 (*pvt->_inoutbindvars)[count].
4742 value.dateval.day=0;
4743 (*pvt->_inoutbindvars)[count].
4744 value.dateval.hour=0;
4745 (*pvt->_inoutbindvars)[count].
4746 value.dateval.minute=0;
4747 (*pvt->_inoutbindvars)[count].
4748 value.dateval.second=0;
4749 (*pvt->_inoutbindvars)[count].
4750 value.dateval.microsecond=0;
4751 (*pvt->_inoutbindvars)[count].
4752 value.dateval.tz=new char[1];
4753 (*pvt->_inoutbindvars)[count].
4754 value.dateval.tz[0]='\0';
4755 }
4756
4757 if (pvt->_sqlrc->debug()) {
4758 pvt->_sqlrc->debugPrint(" ");
4759 pvt->_sqlrc->debugPrint("done fetching.\n");
4760 }
4761
4762 } else if (type==STRING_DATA) {
4763
4764 if (pvt->_sqlrc->debug()) {
4765 pvt->_sqlrc->debugPreStart();
4766 pvt->_sqlrc->debugPrint(
4767 " STRING input/output "
4768 "bind\n");
4769 pvt->_sqlrc->debugPreEnd();
4770 }
4771
4772 // get the value length
4773 if (getLong(&length)!=sizeof(uint32_t)) {
4774 setError("Failed to get string value length.\n "
4775 "A network error may have occurred.");
4776 return false;
4777 }
4778 (*pvt->_inoutbindvars)[count].resultvaluesize=length;
4779 // FIXME: verify that resultvaluesize <= size of buffer
4780
4781 if (pvt->_sqlrc->debug()) {
4782 pvt->_sqlrc->debugPreStart();
4783 pvt->_sqlrc->debugPrint(
4784 " length=");
4785 pvt->_sqlrc->debugPrint((int64_t)length);
4786 pvt->_sqlrc->debugPrint("\n");
4787 pvt->_sqlrc->debugPreEnd();
4788 }
4789
4790 // get the value
4791 if ((uint32_t)getString(
4792 (*pvt->_inoutbindvars)[count].value.
4793 stringval,length)!=length) {
4794 setError("Failed to get string value.\n "
4795 "A network error may have occurred.");
4796 return false;
4797 }
4798 (*pvt->_inoutbindvars)[count].
4799 value.stringval[length]='\0';
4800
4801 if (pvt->_sqlrc->debug()) {
4802 pvt->_sqlrc->debugPreStart();
4803 pvt->_sqlrc->debugPrint(" ");
4804 pvt->_sqlrc->debugPrint("done fetching\n");
4805 pvt->_sqlrc->debugPreEnd();
4806 }
4807
4808 } else if (type==INTEGER_DATA) {
4809
4810 if (pvt->_sqlrc->debug()) {
4811 pvt->_sqlrc->debugPreStart();
4812 pvt->_sqlrc->debugPrint(
4813 " INTEGER input/output "
4814 "bind\n");
4815 pvt->_sqlrc->debugPreEnd();
4816 }
4817
4818 // get the value
4819 if (getLongLong((uint64_t *)
4820 &(*pvt->_inoutbindvars)[count].value.
4821 integerval)!=sizeof(uint64_t)) {
4822 setError("Failed to get integer value.\n "
4823 "A network error may have occurred.");
4824 return false;
4825 }
4826
4827 if (pvt->_sqlrc->debug()) {
4828 pvt->_sqlrc->debugPreStart();
4829 pvt->_sqlrc->debugPrint(" ");
4830 pvt->_sqlrc->debugPrint("done fetching\n");
4831 pvt->_sqlrc->debugPreEnd();
4832 }
4833
4834 } else if (type==DOUBLE_DATA) {
4835
4836 if (pvt->_sqlrc->debug()) {
4837 pvt->_sqlrc->debugPreStart();
4838 pvt->_sqlrc->debugPrint(
4839 " DOUBLE input/output bind\n");
4840 pvt->_sqlrc->debugPreEnd();
4841 }
4842
4843 // get the value
4844 if (getDouble(&(*pvt->_inoutbindvars)[count].value.
4845 doubleval.value)!=
4846 sizeof(double)) {
4847 setError("Failed to get double value.\n "
4848 "A network error may have occurred.");
4849 return false;
4850 }
4851
4852 // get the precision
4853 if (getLong(&(*pvt->_inoutbindvars)[count].value.
4854 doubleval.precision)!=
4855 sizeof(uint32_t)) {
4856 setError("Failed to get precision.\n "
4857 "A network error may have occurred.");
4858 return false;
4859 }
4860
4861 // get the scale
4862 if (getLong(&(*pvt->_inoutbindvars)[count].value.
4863 doubleval.scale)!=
4864 sizeof(uint32_t)) {
4865 setError("Failed to get scale.\n "
4866 "A network error may have occurred.");
4867 return false;
4868 }
4869
4870 if (pvt->_sqlrc->debug()) {
4871 pvt->_sqlrc->debugPreStart();
4872 pvt->_sqlrc->debugPrint(" ");
4873 pvt->_sqlrc->debugPrint("done fetching\n");
4874 pvt->_sqlrc->debugPreEnd();
4875 }
4876
4877 } else if (type==DATE_DATA) {
4878
4879 if (pvt->_sqlrc->debug()) {
4880 pvt->_sqlrc->debugPreStart();
4881 pvt->_sqlrc->debugPrint(
4882 " DATE input/output bind\n");
4883 pvt->_sqlrc->debugPreEnd();
4884 }
4885
4886 uint16_t temp;
4887
4888 // get the year
4889 if (getShort(&temp)!=sizeof(uint16_t)) {
4890 setError("Failed to get long value.\n "
4891 "A network error may have occurred.");
4892 return false;
4893 }
4894 (*pvt->_inoutbindvars)[count].
4895 value.dateval.year=(int16_t)temp;
4896
4897 // get the month
4898 if (getShort(&temp)!=sizeof(uint16_t)) {
4899 setError("Failed to get long value.\n "
4900 "A network error may have occurred.");
4901 return false;
4902 }
4903 (*pvt->_inoutbindvars)[count].
4904 value.dateval.month=(int16_t)temp;
4905
4906 // get the day
4907 if (getShort(&temp)!=sizeof(uint16_t)) {
4908 setError("Failed to get long value.\n "
4909 "A network error may have occurred.");
4910 return false;
4911 }
4912 (*pvt->_inoutbindvars)[count].
4913 value.dateval.day=(int16_t)temp;
4914
4915 // get the hour
4916 if (getShort(&temp)!=sizeof(uint16_t)) {
4917 setError("Failed to get long value.\n "
4918 "A network error may have occurred.");
4919 return false;
4920 }
4921 (*pvt->_inoutbindvars)[count].
4922 value.dateval.hour=(int16_t)temp;
4923
4924 // get the minute
4925 if (getShort(&temp)!=sizeof(uint16_t)) {
4926 setError("Failed to get long value.\n "
4927 "A network error may have occurred.");
4928 return false;
4929 }
4930 (*pvt->_inoutbindvars)[count].
4931 value.dateval.minute=(int16_t)temp;
4932
4933 // get the second
4934 if (getShort(&temp)!=sizeof(uint16_t)) {
4935 setError("Failed to get long value.\n "
4936 "A network error may have occurred.");
4937 return false;
4938 }
4939 (*pvt->_inoutbindvars)[count].
4940 value.dateval.second=(int16_t)temp;
4941
4942 // get the microsecond
4943 uint32_t temp32;
4944 if (getLong(&temp32)!=sizeof(uint32_t)) {
4945 setError("Failed to get long value.\n "
4946 "A network error may have occurred.");
4947 return false;
4948 }
4949 (*pvt->_inoutbindvars)[count].value.
4950 dateval.microsecond=(int32_t)temp32;
4951
4952 // get the timezone length
4953 uint16_t length;
4954 if (getShort(&length)!=sizeof(uint16_t)) {
4955 setError("Failed to get timezone length.\n "
4956 "A network error may have occurred.");
4957 return false;
4958 }
4959 (*pvt->_inoutbindvars)[count].value.
4960 dateval.tz=new char[length+1];
4961
4962 // get the timezone
4963 if ((uint16_t)getString(
4964 (*pvt->_inoutbindvars)[count].value.
4965 dateval.tz,length)!=length) {
4966 setError("Failed to get timezone.\n "
4967 "A network error may have occurred.");
4968 return false;
4969 }
4970 (*pvt->_inoutbindvars)[count].
4971 value.dateval.tz[length]='\0';
4972
4973 // get the isnegative flag
4974 bool tempbool;
4975 if (getBool(&tempbool)!=sizeof(bool)) {
4976 setError("Failed to get bool value.\n "
4977 "A network error may have occurred.");
4978 return false;
4979 }
4980 (*pvt->_inoutbindvars)[count].value.
4981 dateval.isnegative=tempbool;
4982
4983 if (pvt->_sqlrc->debug()) {
4984 pvt->_sqlrc->debugPreStart();
4985 pvt->_sqlrc->debugPrint(" ");
4986 pvt->_sqlrc->debugPrint("done fetching\n");
4987 pvt->_sqlrc->debugPreEnd();
4988 }
4989
4990 } else {
4991
4992 if (pvt->_sqlrc->debug()) {
4993 pvt->_sqlrc->debugPreStart();
4994 pvt->_sqlrc->debugPrint(" LOB/CLOB ");
4995 pvt->_sqlrc->debugPrint("input/output bind\n");
4996 pvt->_sqlrc->debugPreEnd();
4997 }
4998
4999 // must be START_LONG_DATA...
5000 // get the total length of the long data
5001 uint64_t totallength;
5002 if (getLongLong(&totallength)!=sizeof(uint64_t)) {
5003 setError("Failed to get total length.\n "
5004 "A network error may have occurred.");
5005 return false;
5006 }
5007
5008 if (pvt->_sqlrc->debug()) {
5009 pvt->_sqlrc->debugPreStart();
5010 pvt->_sqlrc->debugPrint(
5011 " length=");
5012 pvt->_sqlrc->debugPrint((int64_t)totallength);
5013 pvt->_sqlrc->debugPrint("\n");
5014 pvt->_sqlrc->debugPreEnd();
5015 }
5016
5017 // create a buffer to hold the data
5018 // FIXME: this should be pre-allocated or something...
5019 char *buffer=new char[totallength+1];
5020
5021 uint64_t offset=0;
5022 uint32_t length;
5023 for (;;) {
5024
5025 if (pvt->_sqlrc->debug()) {
5026 pvt->_sqlrc->debugPreStart();
5027 pvt->_sqlrc->debugPrint(
5028 " ");
5029 pvt->_sqlrc->debugPrint(
5030 "fetching...\n");
5031 pvt->_sqlrc->debugPreEnd();
5032 }
5033
5034 // get the type of the chunk
5035 if (getShort(&type)!=sizeof(uint16_t)) {
5036 delete[] buffer;
5037 setError("Failed to get chunk type.\n "
5038 "A network error may have "
5039 "occurred.");
5040 return false;
5041 }
5042
5043 // check to see if we're done
5044 if (type==END_LONG_DATA) {
5045 break;
5046 }
5047
5048 // get the length of the chunk
5049 if (getLong(&length)!=sizeof(uint32_t)) {
5050 delete[] buffer;
5051 setError("Failed to get chunk length.\n"
5052 " A network error may have "
5053 "occurred.");
5054 return false;
5055 }
5056
5057 // get the chunk of data
5058 if ((uint32_t)getString(buffer+offset,
5059 length)!=length) {
5060 delete[] buffer;
5061 setError("Failed to get chunk data.\n "
5062 "A network error may have "
5063 "occurred.");
5064 return false;
5065 }
5066
5067 offset=offset+length;
5068 }
5069
5070 if (pvt->_sqlrc->debug()) {
5071 pvt->_sqlrc->debugPreStart();
5072 pvt->_sqlrc->debugPrint(" ");
5073 pvt->_sqlrc->debugPrint("done fetching.\n");
5074 pvt->_sqlrc->debugPreEnd();
5075 }
5076
5077 // NULL terminate the buffer. This makes
5078 // certain operations safer and won't hurt
5079 // since the actual length (which doesn't
5080 // include the NULL) is available from
5081 // getOutputBindLength.
5082 buffer[totallength]='\0';
5083 (*pvt->_inoutbindvars)[count].value.lobval=buffer;
5084 (*pvt->_inoutbindvars)[count].resultvaluesize=
5085 totallength;
5086 }
5087
5088 if (pvt->_sqlrc->debug()) {
5089 pvt->_sqlrc->debugPreStart();
5090 pvt->_sqlrc->debugPrint(
5091 (*pvt->_inoutbindvars)[count].variable);
5092 pvt->_sqlrc->debugPrint("=");
5093 if ((*pvt->_inoutbindvars)[count].type==
5094 SQLRCLIENTBINDVARTYPE_BLOB) {
5095 pvt->_sqlrc->debugPrintBlob(
5096 (*pvt->_inoutbindvars)[count].
5097 value.lobval,
5098 (*pvt->_inoutbindvars)[count].
5099 resultvaluesize);
5100 } else if ((*pvt->_inoutbindvars)[count].type==
5101 SQLRCLIENTBINDVARTYPE_CLOB) {
5102 pvt->_sqlrc->debugPrintClob(
5103 (*pvt->_inoutbindvars)[count].
5104 value.lobval,
5105 (*pvt->_inoutbindvars)[count].
5106 resultvaluesize);
5107 } else if ((*pvt->_inoutbindvars)[count].type==
5108 SQLRCLIENTBINDVARTYPE_CURSOR) {
5109 pvt->_sqlrc->debugPrint((int64_t)
5110 (*pvt->_inoutbindvars)[count].
5111 value.cursorid);
5112 } else if ((*pvt->_inoutbindvars)[count].type==
5113 SQLRCLIENTBINDVARTYPE_INTEGER) {
5114 pvt->_sqlrc->debugPrint(
5115 (*pvt->_inoutbindvars)[count].
5116 value.integerval);
5117 } else if ((*pvt->_inoutbindvars)[count].type==
5118 SQLRCLIENTBINDVARTYPE_DOUBLE) {
5119 pvt->_sqlrc->debugPrint(
5120 (*pvt->_inoutbindvars)[count].
5121 value.doubleval.value);
5122 pvt->_sqlrc->debugPrint("(");
5123 pvt->_sqlrc->debugPrint((int64_t)
5124 (*pvt->_inoutbindvars)[count].
5125 value.doubleval.
5126 precision);
5127 pvt->_sqlrc->debugPrint(",");
5128 pvt->_sqlrc->debugPrint((int64_t)
5129 (*pvt->_inoutbindvars)[count].
5130 value.doubleval.
5131 scale);
5132 pvt->_sqlrc->debugPrint(")");
5133 } else if ((*pvt->_inoutbindvars)[count].type==
5134 SQLRCLIENTBINDVARTYPE_DATE) {
5135 pvt->_sqlrc->debugPrint((int64_t)
5136 (*pvt->_inoutbindvars)[count].
5137 value.dateval.year);
5138 pvt->_sqlrc->debugPrint("-");
5139 pvt->_sqlrc->debugPrint((int64_t)
5140 (*pvt->_inoutbindvars)[count].
5141 value.dateval.month);
5142 pvt->_sqlrc->debugPrint("-");
5143 pvt->_sqlrc->debugPrint((int64_t)
5144 (*pvt->_inoutbindvars)[count].
5145 value.dateval.day);
5146 pvt->_sqlrc->debugPrint(" ");
5147 pvt->_sqlrc->debugPrint((int64_t)
5148 (*pvt->_inoutbindvars)[count].
5149 value.dateval.hour);
5150 pvt->_sqlrc->debugPrint(":");
5151 pvt->_sqlrc->debugPrint((int64_t)
5152 (*pvt->_inoutbindvars)[count].
5153 value.dateval.minute);
5154 pvt->_sqlrc->debugPrint(":");
5155 pvt->_sqlrc->debugPrint((int64_t)
5156 (*pvt->_inoutbindvars)[count].
5157 value.dateval.second);
5158 pvt->_sqlrc->debugPrint(".");
5159 pvt->_sqlrc->debugPrint((int64_t)
5160 (*pvt->_inoutbindvars)[count].
5161 value.dateval.microsecond);
5162 pvt->_sqlrc->debugPrint(" ");
5163 pvt->_sqlrc->debugPrint(
5164 (*pvt->_inoutbindvars)[count].
5165 value.dateval.tz);
5166 } else {
5167 pvt->_sqlrc->debugPrint(
5168 (*pvt->_inoutbindvars)[count].
5169 value.stringval);
5170 }
5171 pvt->_sqlrc->debugPrint("\n");
5172 pvt->_sqlrc->debugPreEnd();
5173 }
5174
5175 count++;
5176 }
5177
5178 // cache the input/output binds
5179 cacheInputOutputBinds(count);
5180
5181 return true;
5182 }
5183
parseResults()5184 bool sqlrcursor::parseResults() {
5185
5186 if (pvt->_sqlrc->debug()) {
5187 pvt->_sqlrc->debugPreStart();
5188 pvt->_sqlrc->debugPrint("Parsing Results\n");
5189 pvt->_sqlrc->debugPreEnd();
5190 }
5191
5192 // if we're already at the end of the result set, then just return
5193 if (pvt->_endofresultset) {
5194 if (pvt->_sqlrc->debug()) {
5195 pvt->_sqlrc->debugPreStart();
5196 pvt->_sqlrc->debugPrint(
5197 "Already at the end of the result set\n");
5198 pvt->_sqlrc->debugPreEnd();
5199 }
5200 return true;
5201 }
5202
5203 // if we just resumed a result set, then reset the rowcount
5204 if (!pvt->_rowcount && pvt->_resumedlastrowindex) {
5205 pvt->_rowcount=pvt->_resumedlastrowindex+1;
5206 }
5207
5208 // set firstrowindex to the index of the first row in the block of rows
5209 pvt->_firstrowindex=pvt->_rowcount;
5210
5211 // useful variables
5212 uint16_t type;
5213 uint32_t length;
5214 char *buffer=NULL;
5215 uint32_t colindex=0;
5216 sqlrclientcolumn *currentcol;
5217 sqlrclientrow *currentrow=NULL;
5218 bool firstrow=true;
5219
5220 // in the block of rows, keep track of
5221 // how many rows are actually populated
5222 uint64_t rowblockcount=0;
5223
5224 // get rows
5225 for (;;) {
5226
5227 // get the type of the field
5228 if (getShort(&type)!=sizeof(uint16_t)) {
5229 setError("Failed to get the field type.\n"
5230 "A network error may have occurred");
5231 return false;
5232 }
5233
5234 // check for an error
5235 if (type==FETCH_ERROR) {
5236
5237 if (pvt->_sqlrc->debug()) {
5238 pvt->_sqlrc->debugPreStart();
5239 pvt->_sqlrc->debugPrint(
5240 "Got fetch error.\n");
5241 pvt->_sqlrc->debugPreEnd();
5242 }
5243 pvt->_endofresultset=true;
5244
5245 // if we were stepping through a cached result set
5246 // then we need to close the file
5247 clearCacheSource();
5248
5249 uint16_t err=getErrorStatus();
5250 if (err==TIMEOUT_GETTING_ERROR_STATUS) {
5251 // The pattern here is that we bail
5252 // immediately. Error status has
5253 // already been set.
5254 pvt->_sqlrc->endSession();
5255 return false;
5256 }
5257 getErrorFromServer();
5258 if (err==ERROR_OCCURRED_DISCONNECT) {
5259 pvt->_sqlrc->endSession();
5260 return false;
5261 }
5262 break;
5263 }
5264
5265 // check for the end of the result set
5266 if (type==END_RESULT_SET) {
5267
5268 if (pvt->_sqlrc->debug()) {
5269 pvt->_sqlrc->debugPreStart();
5270 pvt->_sqlrc->debugPrint(
5271 "Got end of result set.\n");
5272 pvt->_sqlrc->debugPreEnd();
5273 }
5274 pvt->_endofresultset=true;
5275
5276 // if we were stepping through a cached result set
5277 // then we need to close the file
5278 clearCacheSource();
5279 break;
5280 }
5281
5282 // if we're on the first column, start a new row,
5283 // reset the column pointer, and increment the
5284 // buffer counter and total row counter
5285 if (colindex==0) {
5286
5287 if (rowblockcount<OPTIMISTIC_ROW_COUNT) {
5288 if (!pvt->_rows) {
5289 createRowBuffers();
5290 }
5291 currentrow=pvt->_rows[rowblockcount];
5292 } else {
5293 if (pvt->_sqlrc->debug()) {
5294 pvt->_sqlrc->debugPreStart();
5295 pvt->_sqlrc->debugPrint(
5296 "Creating extra rows.\n");
5297 pvt->_sqlrc->debugPreEnd();
5298 }
5299 if (!pvt->_firstextrarow) {
5300 currentrow=new sqlrclientrow(
5301 pvt->_colcount);
5302 pvt->_firstextrarow=currentrow;
5303 } else {
5304 currentrow->next=new sqlrclientrow(
5305 pvt->_colcount);
5306 currentrow=currentrow->next;
5307 }
5308 }
5309 if (pvt->_colcount>currentrow->colcount) {
5310 currentrow->resize(pvt->_colcount);
5311 }
5312
5313 rowblockcount++;
5314 pvt->_rowcount++;
5315 }
5316
5317 if (type==NULL_DATA) {
5318
5319 // handle null data
5320 if (pvt->_returnnulls) {
5321 buffer=NULL;
5322 } else {
5323 buffer=(char *)pvt->_rowstorage->allocate(1);
5324 buffer[0]='\0';
5325 }
5326 length=0;
5327
5328 } else if (type==STRING_DATA) {
5329
5330 // handle non-null data
5331 if (getLong(&length)!=sizeof(uint32_t)) {
5332 setError("Failed to get the field length.\n"
5333 "A network error may have occurred");
5334 return false;
5335 }
5336
5337 // for non-long, non-NULL datatypes...
5338 // get the field into a buffer
5339 buffer=(char *)pvt->_rowstorage->allocate(length+1);
5340 if ((uint32_t)getString(buffer,length)!=length) {
5341 setError("Failed to get the field data.\n"
5342 "A network error may have occurred");
5343 return false;
5344 }
5345 buffer[length]='\0';
5346
5347 } else if (type==START_LONG_DATA) {
5348
5349 uint64_t totallength;
5350 if (getLongLong(&totallength)!=sizeof(uint64_t)) {
5351 setError("Failed to get total length.\n"
5352 "A network error may have occurred");
5353 return false;
5354 }
5355
5356 // create a buffer to hold the data
5357 if (totallength) {
5358 buffer=new char[totallength+1];
5359 } else {
5360 buffer=(char *)pvt->_rowstorage->allocate(1);
5361 }
5362
5363 // handle a long datatype
5364 uint64_t offset=0;
5365 for (;;) {
5366
5367 // get the type of the chunk
5368 if (getShort(&type)!=sizeof(uint16_t)) {
5369 delete[] buffer;
5370 setError("Failed to get chunk type.\n"
5371 "A network error may have "
5372 "occurred");
5373 return false;
5374 }
5375
5376 // check to see if we're done
5377 if (type==END_LONG_DATA) {
5378 break;
5379 }
5380
5381 // get the length of the chunk
5382 if (getLong(&length)!=sizeof(uint32_t)) {
5383 delete[] buffer;
5384 setError("Failed to get chunk length.\n"
5385 "A network error may have "
5386 "occurred");
5387 return false;
5388 }
5389
5390 // Oracle in particular has a function that
5391 // returns the number of characters in a CLOB,
5392 // but not the number of bytes. Since
5393 // varying-width character data can be stored
5394 // in a CLOB, characters may be less than bytes.
5395 // AFAIK, there's no way to get the number of
5396 // bytes. So, we use the number of characters
5397 // as a starting point, and extend buffer if
5398 // necessary.
5399 if (offset+length>totallength) {
5400 char *newbuffer=
5401 new char[offset+length+1];
5402 bytestring::copy(
5403 newbuffer,buffer,offset);
5404 if (totallength) {
5405 delete[] buffer;
5406 }
5407 buffer=newbuffer;
5408 totallength=offset+length;
5409 }
5410
5411 // get the chunk of data
5412 if ((uint32_t)getString(buffer+offset,
5413 length)!=length) {
5414 delete[] buffer;
5415 setError("Failed to get chunk data.\n"
5416 "A network error may have "
5417 "occurred");
5418 return false;
5419 }
5420
5421 offset=offset+length;
5422 }
5423 // NULL terminate the buffer. This makes
5424 // certain operations safer and won't hurt
5425 // since the actual length (which doesn't
5426 // include the NULL) is available from
5427 // getFieldLength.
5428 buffer[totallength]='\0';
5429 length=totallength;
5430 }
5431
5432 // add the buffer to the current row
5433 currentrow->addField(colindex,buffer,length);
5434
5435 if (pvt->_sqlrc->debug()) {
5436 pvt->_sqlrc->debugPreStart();
5437 if (buffer) {
5438 if (type==END_LONG_DATA) {
5439 pvt->_sqlrc->debugPrint("\nLOB data:");
5440 pvt->_sqlrc->debugPrintBlob(
5441 buffer,length);
5442 } else {
5443 pvt->_sqlrc->debugPrint("\"");
5444 pvt->_sqlrc->debugPrint(buffer);
5445 pvt->_sqlrc->debugPrint("\",");
5446 }
5447 } else {
5448 pvt->_sqlrc->debugPrint(buffer);
5449 pvt->_sqlrc->debugPrint(",");
5450 }
5451 pvt->_sqlrc->debugPreEnd();
5452 }
5453
5454 // tag the column as a long data type or not
5455 currentcol=getColumnInternal(colindex);
5456
5457 // set whether this column is a "long type" or not
5458 // (unless it's already set)
5459 if (firstrow || !currentcol->longdatatype) {
5460 currentcol->longdatatype=(type==END_LONG_DATA)?1:0;
5461 }
5462
5463 if (pvt->_sendcolumninfo==SEND_COLUMN_INFO &&
5464 pvt->_sentcolumninfo==SEND_COLUMN_INFO) {
5465
5466 // keep track of the longest field
5467 if (length>currentcol->longest) {
5468 currentcol->longest=length;
5469 }
5470 }
5471
5472 // move to the next column, handle end of row
5473 colindex++;
5474 if (colindex==pvt->_colcount) {
5475
5476 colindex=0;
5477
5478 if (pvt->_sqlrc->debug()) {
5479 pvt->_sqlrc->debugPreStart();
5480 pvt->_sqlrc->debugPrint("\n");
5481 pvt->_sqlrc->debugPreEnd();
5482 }
5483
5484 // check to see if we've gotten enough rows
5485 if (pvt->_rsbuffersize &&
5486 rowblockcount==pvt->_rsbuffersize) {
5487 break;
5488 }
5489
5490 firstrow=false;
5491 }
5492 }
5493
5494 // terminate the row list
5495 if (rowblockcount>=OPTIMISTIC_ROW_COUNT && currentrow) {
5496 currentrow->next=NULL;
5497 createExtraRowArray();
5498 }
5499
5500 // cache the rows
5501 cacheData();
5502
5503 return true;
5504 }
5505
createRowBuffers()5506 void sqlrcursor::createRowBuffers() {
5507
5508 // rows will hang around from now until the cursor is deleted,
5509 // getting reused with each query
5510 pvt->_rows=new sqlrclientrow *[OPTIMISTIC_ROW_COUNT];
5511 for (uint64_t i=0; i<OPTIMISTIC_ROW_COUNT; i++) {
5512 pvt->_rows[i]=new sqlrclientrow(pvt->_colcount);
5513 }
5514 }
5515
createExtraRowArray()5516 void sqlrcursor::createExtraRowArray() {
5517
5518 // create the arrays
5519 uint64_t howmany=pvt->_rowcount-
5520 pvt->_firstrowindex-
5521 OPTIMISTIC_ROW_COUNT;
5522 pvt->_extrarows=new sqlrclientrow *[howmany];
5523
5524 // populate the arrays
5525 sqlrclientrow *currentrow=pvt->_firstextrarow;
5526 for (uint64_t i=0; i<howmany; i++) {
5527 pvt->_extrarows[i]=currentrow;
5528 currentrow=currentrow->next;
5529 }
5530 }
5531
getErrorFromServer()5532 void sqlrcursor::getErrorFromServer() {
5533
5534 if (pvt->_sqlrc->debug()) {
5535 pvt->_sqlrc->debugPreStart();
5536 pvt->_sqlrc->debugPrint("Getting Error From Server\n");
5537 pvt->_sqlrc->debugPreEnd();
5538 }
5539
5540 bool networkerror=true;
5541
5542 // get the error code
5543 if (getLongLong((uint64_t *)&pvt->_errorno)==sizeof(uint64_t)) {
5544
5545 // get the length of the error string
5546 uint16_t length;
5547 if (getShort(&length)==sizeof(uint16_t)) {
5548
5549 // get the error string
5550 pvt->_error=new char[length+1];
5551 pvt->_cs->read(pvt->_error,length);
5552 pvt->_error[length]='\0';
5553
5554 networkerror=false;
5555 }
5556 }
5557
5558 if (networkerror) {
5559 setError("There was an error, but the connection"
5560 " died trying to retrieve it. Sorry.");
5561 }
5562
5563 handleError();
5564 }
5565
setError(const char * err)5566 void sqlrcursor::setError(const char *err) {
5567
5568 if (pvt->_sqlrc->debug()) {
5569 pvt->_sqlrc->debugPreStart();
5570 pvt->_sqlrc->debugPrint("Setting Error\n");
5571 pvt->_sqlrc->debugPreEnd();
5572 }
5573 pvt->_error=charstring::duplicate(err);
5574 handleError();
5575 }
5576
handleError()5577 void sqlrcursor::handleError() {
5578
5579 if (pvt->_sqlrc->debug()) {
5580 pvt->_sqlrc->debugPreStart();
5581 pvt->_sqlrc->debugPrint((int64_t)pvt->_errorno);
5582 pvt->_sqlrc->debugPrint(":\n");
5583 pvt->_sqlrc->debugPrint(pvt->_error);
5584 pvt->_sqlrc->debugPrint("\n");
5585 pvt->_sqlrc->debugPreEnd();
5586 }
5587
5588 pvt->_endofresultset=true;
5589
5590 cacheError();
5591 finishCaching();
5592 }
5593
fetchRowIntoBuffer(uint64_t row,uint64_t * rowbufferindex)5594 bool sqlrcursor::fetchRowIntoBuffer(uint64_t row, uint64_t *rowbufferindex) {
5595
5596 // bail if the requested row is before the current block of rows
5597 if (row<pvt->_firstrowindex) {
5598 return false;
5599 }
5600
5601 // if the requested row is in the current block of rows
5602 // then return the row buffer index
5603 if (row>=pvt->_firstrowindex && row<pvt->_rowcount) {
5604 *rowbufferindex=row-pvt->_firstrowindex;
5605 return true;
5606 }
5607
5608 // bail if the requested row is past the end of the result set
5609 if (pvt->_endofresultset) {
5610 return false;
5611 }
5612
5613 // bail if we lost our data source
5614 if (!pvt->_sqlrc->connected() &&
5615 !(pvt->_cachesource && pvt->_cachesourceind)) {
5616 return false;
5617 }
5618
5619 // otherwise, fetch additional rows...
5620
5621 if (pvt->_sqlrc->debug()) {
5622 pvt->_sqlrc->debugPreStart();
5623 pvt->_sqlrc->debugPrint("Fetching additional rows...\n");
5624 pvt->_sqlrc->debugPreEnd();
5625 }
5626
5627 // skip to the block of rows containing the requested row,
5628 // fetch that block of rows, and process what we get back...
5629 do {
5630
5631 // clear the row buffers
5632 clearRows();
5633
5634 // if we're not fetching from a cached result set,
5635 // then tell the server to send some rows
5636 if (!pvt->_cachesource && !pvt->_cachesourceind) {
5637 pvt->_cs->write((uint16_t)FETCH_RESULT_SET);
5638 pvt->_cs->write(pvt->_cursorid);
5639 }
5640
5641 // calculate how many rows to actually skip
5642 // if we're caching the result set, then we shouldn't skip any
5643 // (thus the outer loop)
5644 // also, if we're fetching all rows then we shouldn't skip any
5645 uint64_t rowstoskip=0;
5646 if (!pvt->_cachedest && pvt->_rsbuffersize) {
5647 rowstoskip=
5648 row-((pvt->_rsbuffersize)?(row%pvt->_rsbuffersize):0)-
5649 pvt->_rowcount;
5650 }
5651
5652 if (!skipAndFetch(false,rowstoskip) || !parseResults()) {
5653 return false;
5654 }
5655
5656 } while (!pvt->_endofresultset && pvt->_rowcount<=row);
5657
5658 // bail if the requested row is still past the end of the result set
5659 if (row>=pvt->_rowcount) {
5660 return false;
5661 }
5662
5663 // the requested row must be in the current block of rows,
5664 // return the row buffer index
5665 *rowbufferindex=(pvt->_rsbuffersize)?(row%pvt->_rsbuffersize):row;
5666 return true;
5667 }
5668
getBool(bool * boolean)5669 int32_t sqlrcursor::getBool(bool *boolean) {
5670
5671 // if the result set is coming from a cache file, read from
5672 // the file, if not, read from the server
5673 if (pvt->_cachesource && pvt->_cachesourceind) {
5674 return pvt->_cachesource->read(boolean);
5675 } else {
5676 return pvt->_cs->read(boolean);
5677 }
5678 }
5679
getShort(uint16_t * integer,int32_t timeoutsec,int32_t timeoutusec)5680 int32_t sqlrcursor::getShort(uint16_t *integer,
5681 int32_t timeoutsec, int32_t timeoutusec) {
5682
5683 // if the result set is coming from a cache file, read from
5684 // the file, if not, read from the server
5685 if (pvt->_cachesource && pvt->_cachesourceind) {
5686 return pvt->_cachesource->read(integer);
5687 } else {
5688 return pvt->_cs->read(integer,timeoutsec,timeoutusec);
5689 }
5690 }
5691
getShort(uint16_t * integer)5692 int32_t sqlrcursor::getShort(uint16_t *integer) {
5693
5694 // if the result set is coming from a cache file, read from
5695 // the file, if not, read from the server
5696 if (pvt->_cachesource && pvt->_cachesourceind) {
5697 return pvt->_cachesource->read(integer);
5698 } else {
5699 return pvt->_cs->read(integer);
5700 }
5701 }
5702
getLong(uint32_t * integer)5703 int32_t sqlrcursor::getLong(uint32_t *integer) {
5704
5705 // if the result set is coming from a cache file, read from
5706 // the file, if not, read from the server
5707 if (pvt->_cachesource && pvt->_cachesourceind) {
5708 return pvt->_cachesource->read(integer);
5709 } else {
5710 return pvt->_cs->read(integer);
5711 }
5712 }
5713
getLongLong(uint64_t * integer)5714 int32_t sqlrcursor::getLongLong(uint64_t *integer) {
5715
5716 // if the result set is coming from a cache file, read from
5717 // the file, if not, read from the server
5718 if (pvt->_cachesource && pvt->_cachesourceind) {
5719 return pvt->_cachesource->read(integer);
5720 } else {
5721 return pvt->_cs->read(integer);
5722 }
5723 }
5724
getString(char * string,int32_t size)5725 int32_t sqlrcursor::getString(char *string, int32_t size) {
5726
5727 // if the result set is coming from a cache file, read from
5728 // the file, if not, read from the server
5729 if (pvt->_cachesource && pvt->_cachesourceind) {
5730 return pvt->_cachesource->read(string,size);
5731 } else {
5732 return pvt->_cs->read(string,size);
5733 }
5734 }
5735
getDouble(double * value)5736 int32_t sqlrcursor::getDouble(double *value) {
5737
5738 // if the result set is coming from a cache file, read from
5739 // the file, if not, read from the server
5740 if (pvt->_cachesource && pvt->_cachesourceind) {
5741 return pvt->_cachesource->read(value);
5742 } else {
5743 return pvt->_cs->read(value);
5744 }
5745 }
5746
fetchFromBindCursor()5747 bool sqlrcursor::fetchFromBindCursor() {
5748
5749 if (!pvt->_endofresultset || !pvt->_sqlrc->connected()) {
5750 return false;
5751 }
5752
5753 // FIXME: should these be here?
5754 clearVariables();
5755 clearResultSet();
5756
5757 pvt->_cached=false;
5758 pvt->_endofresultset=false;
5759
5760 // refresh socket client
5761 pvt->_cs=pvt->_sqlrc->cs();
5762
5763 // tell the server we're fetching from a bind cursor
5764 pvt->_cs->write((uint16_t)FETCH_FROM_BIND_CURSOR);
5765
5766 // send the cursor id to the server
5767 pvt->_cs->write((uint16_t)pvt->_cursorid);
5768
5769 sendGetColumnInfo();
5770
5771 pvt->_sqlrc->flushWriteBuffer();
5772
5773 return processInitialResultSet();
5774 }
5775
openCachedResultSet(const char * filename)5776 bool sqlrcursor::openCachedResultSet(const char *filename) {
5777
5778 if (pvt->_sqlrc->debug()) {
5779 pvt->_sqlrc->debugPreStart();
5780 pvt->_sqlrc->debugPrint("Opening cached result set: ");
5781 pvt->_sqlrc->debugPrint(filename);
5782 pvt->_sqlrc->debugPrint("\n");
5783 pvt->_sqlrc->debugPreEnd();
5784 }
5785
5786 if (!pvt->_endofresultset) {
5787 closeResultSet(true);
5788 }
5789 clearResultSet();
5790
5791 pvt->_cached=true;
5792 pvt->_endofresultset=false;
5793
5794 // create the index file name
5795 size_t indexfilenamelen=charstring::length(filename)+5;
5796 char *indexfilename=new char[indexfilenamelen];
5797 charstring::copy(indexfilename,filename);
5798 charstring::append(indexfilename,".ind");
5799
5800 // open the file
5801 pvt->_cachesource=new file();
5802 pvt->_cachesourceind=new file();
5803 if ((pvt->_cachesource->open(filename,O_RDWR)) &&
5804 (pvt->_cachesourceind->open(indexfilename,O_RDWR))) {
5805
5806 delete[] indexfilename;
5807
5808 // make sure it's a cache file and skip the ttl
5809 char magicid[13];
5810 uint64_t ttl;
5811 if (getString(magicid,13)==13 &&
5812 !charstring::compare(magicid,"SQLRELAYCACHE",13) &&
5813 getLongLong(&ttl)==sizeof(uint64_t)) {
5814
5815 // process the result set
5816 return processInitialResultSet();
5817 } else {
5818
5819 // if the test above failed, the file is either not
5820 // a cache file or is corrupt
5821 stringbuffer errstr;
5822 errstr.append("File ");
5823 errstr.append(filename);
5824 errstr.append(" is either corrupt");
5825 errstr.append(" or not a cache file.");
5826 setError(errstr.getString());
5827 }
5828
5829 } else {
5830
5831 // if we couldn't open the file, set the error message
5832 stringbuffer errstr;
5833 errstr.append("Couldn't open ");
5834 errstr.append(filename);
5835 errstr.append(" and ");
5836 errstr.append(indexfilename);
5837 setError(errstr.getString());
5838
5839 delete[] indexfilename;
5840 }
5841
5842 // if we fell through to here, then an error has occurred
5843 clearCacheSource();
5844 return false;
5845 }
5846
clearCacheSource()5847 void sqlrcursor::clearCacheSource() {
5848 if (pvt->_cachesource) {
5849 pvt->_cachesource->close();
5850 delete pvt->_cachesource;
5851 pvt->_cachesource=NULL;
5852 }
5853 if (pvt->_cachesourceind) {
5854 pvt->_cachesourceind->close();
5855 delete pvt->_cachesourceind;
5856 pvt->_cachesourceind=NULL;
5857 }
5858 }
5859
colCount()5860 uint32_t sqlrcursor::colCount() {
5861 return pvt->_colcount;
5862 }
5863
getColumn(uint32_t index)5864 sqlrclientcolumn *sqlrcursor::getColumn(uint32_t index) {
5865 if (pvt->_sendcolumninfo==SEND_COLUMN_INFO &&
5866 pvt->_sentcolumninfo==SEND_COLUMN_INFO &&
5867 pvt->_colcount && index<pvt->_colcount) {
5868 return getColumnInternal(index);
5869 }
5870 return NULL;
5871 }
5872
getColumn(const char * name)5873 sqlrclientcolumn *sqlrcursor::getColumn(const char *name) {
5874 if (pvt->_sendcolumninfo==SEND_COLUMN_INFO &&
5875 pvt->_sentcolumninfo==SEND_COLUMN_INFO) {
5876 sqlrclientcolumn *whichcolumn;
5877 for (uint32_t i=0; i<pvt->_colcount; i++) {
5878 whichcolumn=getColumnInternal(i);
5879 if (!charstring::compare(whichcolumn->name,name)) {
5880 return whichcolumn;
5881 }
5882 }
5883 }
5884 return NULL;
5885 }
5886
getColumnInternal(uint32_t index)5887 sqlrclientcolumn *sqlrcursor::getColumnInternal(uint32_t index) {
5888 if (index<OPTIMISTIC_COLUMN_COUNT) {
5889 return &pvt->_columns[index];
5890 }
5891 return &pvt->_extracolumns[index-OPTIMISTIC_COLUMN_COUNT];
5892 }
5893
getColumnNames()5894 const char * const *sqlrcursor::getColumnNames() {
5895
5896 if (pvt->_sendcolumninfo==DONT_SEND_COLUMN_INFO ||
5897 pvt->_sentcolumninfo==DONT_SEND_COLUMN_INFO) {
5898 return NULL;
5899 }
5900
5901 if (!pvt->_columnnamearray) {
5902 if (pvt->_sqlrc->debug()) {
5903 pvt->_sqlrc->debugPreStart();
5904 pvt->_sqlrc->debugPrint("Creating Column Arrays...\n");
5905 pvt->_sqlrc->debugPreEnd();
5906 }
5907
5908 // build a 2d array of pointers to the column names
5909 pvt->_columnnamearray=new char *[pvt->_colcount+1];
5910 pvt->_columnnamearray[pvt->_colcount]=NULL;
5911 for (uint32_t i=0; i<pvt->_colcount; i++) {
5912 pvt->_columnnamearray[i]=getColumnInternal(i)->name;
5913 }
5914 }
5915 return pvt->_columnnamearray;
5916 }
5917
getColumnName(uint32_t col)5918 const char *sqlrcursor::getColumnName(uint32_t col) {
5919 sqlrclientcolumn *whichcol=getColumn(col);
5920 return (whichcol)?whichcol->name:NULL;
5921 }
5922
getColumnType(uint32_t col)5923 const char *sqlrcursor::getColumnType(uint32_t col) {
5924 sqlrclientcolumn *whichcol=getColumn(col);
5925 if (whichcol) {
5926 if (pvt->_columntypeformat!=COLUMN_TYPE_IDS) {
5927 return whichcol->typestring;
5928 } else {
5929 return datatypestring[whichcol->type];
5930 }
5931 }
5932 return NULL;
5933 }
5934
getColumnLength(uint32_t col)5935 uint32_t sqlrcursor::getColumnLength(uint32_t col) {
5936 sqlrclientcolumn *whichcol=getColumn(col);
5937 return (whichcol)?whichcol->length:0;
5938 }
5939
getColumnPrecision(uint32_t col)5940 uint32_t sqlrcursor::getColumnPrecision(uint32_t col) {
5941 sqlrclientcolumn *whichcol=getColumn(col);
5942 return (whichcol)?whichcol->precision:0;
5943 }
5944
getColumnScale(uint32_t col)5945 uint32_t sqlrcursor::getColumnScale(uint32_t col) {
5946 sqlrclientcolumn *whichcol=getColumn(col);
5947 return (whichcol)?whichcol->scale:0;
5948 }
5949
getColumnIsNullable(uint32_t col)5950 bool sqlrcursor::getColumnIsNullable(uint32_t col) {
5951 sqlrclientcolumn *whichcol=getColumn(col);
5952 return (whichcol)?(whichcol->nullable!=0):false;
5953 }
5954
getColumnIsPrimaryKey(uint32_t col)5955 bool sqlrcursor::getColumnIsPrimaryKey(uint32_t col) {
5956 sqlrclientcolumn *whichcol=getColumn(col);
5957 return (whichcol)?(whichcol->primarykey!=0):false;
5958 }
5959
getColumnIsUnique(uint32_t col)5960 bool sqlrcursor::getColumnIsUnique(uint32_t col) {
5961 sqlrclientcolumn *whichcol=getColumn(col);
5962 return (whichcol)?(whichcol->unique!=0):false;
5963 }
5964
getColumnIsPartOfKey(uint32_t col)5965 bool sqlrcursor::getColumnIsPartOfKey(uint32_t col) {
5966 sqlrclientcolumn *whichcol=getColumn(col);
5967 return (whichcol)?(whichcol->partofkey!=0):false;
5968 }
5969
getColumnIsUnsigned(uint32_t col)5970 bool sqlrcursor::getColumnIsUnsigned(uint32_t col) {
5971 sqlrclientcolumn *whichcol=getColumn(col);
5972 return (whichcol)?(whichcol->unsignednumber!=0):false;
5973 }
5974
getColumnIsZeroFilled(uint32_t col)5975 bool sqlrcursor::getColumnIsZeroFilled(uint32_t col) {
5976 sqlrclientcolumn *whichcol=getColumn(col);
5977 return (whichcol)?(whichcol->zerofill!=0):false;
5978 }
5979
getColumnIsBinary(uint32_t col)5980 bool sqlrcursor::getColumnIsBinary(uint32_t col) {
5981 sqlrclientcolumn *whichcol=getColumn(col);
5982 return (whichcol)?(whichcol->binary!=0):false;
5983 }
5984
getColumnIsAutoIncrement(uint32_t col)5985 bool sqlrcursor::getColumnIsAutoIncrement(uint32_t col) {
5986 sqlrclientcolumn *whichcol=getColumn(col);
5987 return (whichcol)?(whichcol->autoincrement!=0):false;
5988 }
5989
getColumnTable(uint32_t col)5990 const char *sqlrcursor::getColumnTable(uint32_t col) {
5991 sqlrclientcolumn *whichcol=getColumn(col);
5992 return (whichcol)?whichcol->table:NULL;
5993 }
5994
getLongest(uint32_t col)5995 uint32_t sqlrcursor::getLongest(uint32_t col) {
5996 sqlrclientcolumn *whichcol=getColumn(col);
5997 return (whichcol)?whichcol->longest:0;
5998 }
5999
getColumnType(const char * col)6000 const char *sqlrcursor::getColumnType(const char *col) {
6001 sqlrclientcolumn *whichcol=getColumn(col);
6002 if (whichcol) {
6003 if (pvt->_columntypeformat!=COLUMN_TYPE_IDS) {
6004 return whichcol->typestring;
6005 } else {
6006 return datatypestring[whichcol->type];
6007 }
6008 }
6009 return NULL;
6010 }
6011
getColumnLength(const char * col)6012 uint32_t sqlrcursor::getColumnLength(const char *col) {
6013 sqlrclientcolumn *whichcol=getColumn(col);
6014 return (whichcol)?whichcol->length:0;
6015 }
6016
getColumnPrecision(const char * col)6017 uint32_t sqlrcursor::getColumnPrecision(const char *col) {
6018 sqlrclientcolumn *whichcol=getColumn(col);
6019 return (whichcol)?whichcol->precision:0;
6020 }
6021
getColumnScale(const char * col)6022 uint32_t sqlrcursor::getColumnScale(const char *col) {
6023 sqlrclientcolumn *whichcol=getColumn(col);
6024 return (whichcol)?whichcol->scale:0;
6025 }
6026
getColumnIsNullable(const char * col)6027 bool sqlrcursor::getColumnIsNullable(const char *col) {
6028 sqlrclientcolumn *whichcol=getColumn(col);
6029 return (whichcol)?(whichcol->nullable!=0):false;
6030 }
6031
getColumnIsPrimaryKey(const char * col)6032 bool sqlrcursor::getColumnIsPrimaryKey(const char *col) {
6033 sqlrclientcolumn *whichcol=getColumn(col);
6034 return (whichcol)?(whichcol->primarykey!=0):false;
6035 }
6036
getColumnIsUnique(const char * col)6037 bool sqlrcursor::getColumnIsUnique(const char *col) {
6038 sqlrclientcolumn *whichcol=getColumn(col);
6039 return (whichcol)?(whichcol->unique!=0):false;
6040 }
6041
getColumnIsPartOfKey(const char * col)6042 bool sqlrcursor::getColumnIsPartOfKey(const char *col) {
6043 sqlrclientcolumn *whichcol=getColumn(col);
6044 return (whichcol)?(whichcol->partofkey!=0):false;
6045 }
6046
getColumnIsUnsigned(const char * col)6047 bool sqlrcursor::getColumnIsUnsigned(const char *col) {
6048 sqlrclientcolumn *whichcol=getColumn(col);
6049 return (whichcol)?(whichcol->unsignednumber!=0):false;
6050 }
6051
getColumnIsZeroFilled(const char * col)6052 bool sqlrcursor::getColumnIsZeroFilled(const char *col) {
6053 sqlrclientcolumn *whichcol=getColumn(col);
6054 return (whichcol)?(whichcol->zerofill!=0):false;
6055 }
6056
getColumnIsBinary(const char * col)6057 bool sqlrcursor::getColumnIsBinary(const char *col) {
6058 sqlrclientcolumn *whichcol=getColumn(col);
6059 return (whichcol)?(whichcol->binary!=0):false;
6060 }
6061
getColumnIsAutoIncrement(const char * col)6062 bool sqlrcursor::getColumnIsAutoIncrement(const char *col) {
6063 sqlrclientcolumn *whichcol=getColumn(col);
6064 return (whichcol)?(whichcol->autoincrement!=0):false;
6065 }
6066
getColumnTable(const char * col)6067 const char *sqlrcursor::getColumnTable(const char *col) {
6068 sqlrclientcolumn *whichcol=getColumn(col);
6069 return (whichcol)?whichcol->table:NULL;
6070 }
6071
6072
getLongest(const char * col)6073 uint32_t sqlrcursor::getLongest(const char *col) {
6074 sqlrclientcolumn *whichcol=getColumn(col);
6075 return (whichcol)?whichcol->longest:0;
6076 }
6077
firstRowIndex()6078 uint64_t sqlrcursor::firstRowIndex() {
6079 return pvt->_firstrowindex;
6080 }
6081
endOfResultSet()6082 bool sqlrcursor::endOfResultSet() {
6083 return pvt->_endofresultset;
6084 }
6085
rowCount()6086 uint64_t sqlrcursor::rowCount() {
6087 return pvt->_rowcount;
6088 }
6089
affectedRows()6090 uint64_t sqlrcursor::affectedRows() {
6091 if (pvt->_knowsaffectedrows==AFFECTED_ROWS) {
6092 return pvt->_affectedrows;
6093 }
6094 return 0;
6095 }
6096
totalRows()6097 uint64_t sqlrcursor::totalRows() {
6098 if (pvt->_knowsactualrows==ACTUAL_ROWS) {
6099 return pvt->_actualrows;
6100 }
6101 return 0;
6102 }
6103
errorNumber()6104 int64_t sqlrcursor::errorNumber() {
6105 // if we have a code then we should have a message too,
6106 // the codes could be any number, including 0, so check
6107 // the message to see which code to return
6108 if (pvt->_error) {
6109 return pvt->_errorno;
6110 } else if (pvt->_sqlrc->error()) {
6111 return pvt->_sqlrc->errorno();
6112 }
6113 return 0;
6114 }
6115
errorMessage()6116 const char *sqlrcursor::errorMessage() {
6117 if (pvt->_error) {
6118 return pvt->_error;
6119 } else if (pvt->_sqlrc->error()) {
6120 return pvt->_sqlrc->error();
6121 }
6122 return NULL;
6123 }
6124
getNullsAsEmptyStrings()6125 void sqlrcursor::getNullsAsEmptyStrings() {
6126 pvt->_returnnulls=false;
6127 }
6128
getNullsAsNulls()6129 void sqlrcursor::getNullsAsNulls() {
6130 pvt->_returnnulls=true;
6131 }
6132
getFieldInternal(uint64_t row,uint32_t col)6133 char *sqlrcursor::getFieldInternal(uint64_t row, uint32_t col) {
6134 if (row<OPTIMISTIC_ROW_COUNT) {
6135 return pvt->_rows[row]->getField(col);
6136 }
6137 return pvt->_extrarows[row-OPTIMISTIC_ROW_COUNT]->getField(col);
6138 }
6139
getFieldLengthInternal(uint64_t row,uint32_t col)6140 uint32_t sqlrcursor::getFieldLengthInternal(uint64_t row, uint32_t col) {
6141 if (row<OPTIMISTIC_ROW_COUNT) {
6142 return pvt->_rows[row]->getFieldLength(col);
6143 }
6144 return pvt->_extrarows[row-OPTIMISTIC_ROW_COUNT]->getFieldLength(col);
6145 }
6146
getField(uint64_t row,uint32_t col)6147 const char *sqlrcursor::getField(uint64_t row, uint32_t col) {
6148
6149 // bail if the requested column is invalid
6150 if (col>=pvt->_colcount) {
6151 return NULL;
6152 }
6153
6154 // fetch and return the field
6155 uint64_t rowbufferindex;
6156 if (fetchRowIntoBuffer(row,&rowbufferindex)) {
6157 return getFieldInternal(rowbufferindex,col);
6158 }
6159 return NULL;
6160 }
6161
getFieldAsInteger(uint64_t row,uint32_t col)6162 int64_t sqlrcursor::getFieldAsInteger(uint64_t row, uint32_t col) {
6163 const char *field=getField(row,col);
6164 return (field)?charstring::toInteger(field):0;
6165 }
6166
getFieldAsDouble(uint64_t row,uint32_t col)6167 double sqlrcursor::getFieldAsDouble(uint64_t row, uint32_t col) {
6168 const char *field=getField(row,col);
6169 return (field)?charstring::toFloatC(field):0.0;
6170 }
6171
getField(uint64_t row,const char * col)6172 const char *sqlrcursor::getField(uint64_t row, const char *col) {
6173
6174 // bail if no column info was sent
6175 if (pvt->_sendcolumninfo!=SEND_COLUMN_INFO ||
6176 pvt->_sentcolumninfo!=SEND_COLUMN_INFO) {
6177 return NULL;
6178 }
6179
6180 // get the column index, by name
6181 for (uint32_t i=0; i<pvt->_colcount; i++) {
6182 if (!charstring::compare(getColumnInternal(i)->name,col)) {
6183
6184 // fetch and return the field
6185 uint64_t rowbufferindex;
6186 if (fetchRowIntoBuffer(row,&rowbufferindex)) {
6187 return getFieldInternal(rowbufferindex,i);
6188 }
6189 return NULL;
6190 }
6191 }
6192 return NULL;
6193 }
6194
getFieldAsInteger(uint64_t row,const char * col)6195 int64_t sqlrcursor::getFieldAsInteger(uint64_t row, const char *col) {
6196 const char *field=getField(row,col);
6197 return (field)?charstring::toInteger(field):0;
6198 }
6199
getFieldAsDouble(uint64_t row,const char * col)6200 double sqlrcursor::getFieldAsDouble(uint64_t row, const char *col) {
6201 const char *field=getField(row,col);
6202 return (field)?charstring::toFloatC(field):0.0;
6203 }
6204
getFieldLength(uint64_t row,uint32_t col)6205 uint32_t sqlrcursor::getFieldLength(uint64_t row, uint32_t col) {
6206
6207 // bail if the requested column is invalid
6208 if (col>=pvt->_colcount) {
6209 return 0;
6210 }
6211
6212 // fetch and return the field length
6213 uint64_t rowbufferindex;
6214 if (fetchRowIntoBuffer(row,&rowbufferindex)) {
6215 return getFieldLengthInternal(rowbufferindex,col);
6216 }
6217 return 0;
6218 }
6219
getFieldLength(uint64_t row,const char * col)6220 uint32_t sqlrcursor::getFieldLength(uint64_t row, const char *col) {
6221
6222 // bail if no column info was sent
6223 if (pvt->_sendcolumninfo!=SEND_COLUMN_INFO ||
6224 pvt->_sentcolumninfo!=SEND_COLUMN_INFO) {
6225 return 0;
6226 }
6227
6228 // get the column index, by name
6229 for (uint32_t i=0; i<pvt->_colcount; i++) {
6230 if (!charstring::compare(getColumnInternal(i)->name,col)) {
6231
6232 // fetch and return the field length
6233 uint64_t rowbufferindex;
6234 if (fetchRowIntoBuffer(row,&rowbufferindex)) {
6235 return getFieldLengthInternal(rowbufferindex,i);
6236 }
6237 return 0;
6238 }
6239 }
6240 return 0;
6241 }
6242
getRow(uint64_t row)6243 const char * const *sqlrcursor::getRow(uint64_t row) {
6244
6245 // fetch and return the row
6246 uint64_t rowbufferindex;
6247 if (fetchRowIntoBuffer(row,&rowbufferindex)) {
6248 if (!pvt->_fields) {
6249 createFields();
6250 }
6251 return pvt->_fields[rowbufferindex];
6252 }
6253 return NULL;
6254 }
6255
createFields()6256 void sqlrcursor::createFields() {
6257 // lets say that rowcount=5 and firstrowindex=3,
6258 // the fields array will contain 2 elements:
6259 // fields[0] (corresponding to row 3) and
6260 // fields[1] (corresponding to row 4)
6261 uint64_t rowbuffercount=pvt->_rowcount-pvt->_firstrowindex;
6262 pvt->_fields=new char **[rowbuffercount+1];
6263 pvt->_fields[rowbuffercount]=(char **)NULL;
6264 for (uint64_t i=0; i<rowbuffercount; i++) {
6265 pvt->_fields[i]=new char *[pvt->_colcount+1];
6266 pvt->_fields[i][pvt->_colcount]=(char *)NULL;
6267 for (uint32_t j=0; j<pvt->_colcount; j++) {
6268 pvt->_fields[i][j]=getFieldInternal(i,j);
6269 }
6270 }
6271 }
6272
getRowLengths(uint64_t row)6273 uint32_t *sqlrcursor::getRowLengths(uint64_t row) {
6274
6275 // fetch and return the row lengths
6276 uint64_t rowbufferindex;
6277 if (fetchRowIntoBuffer(row,&rowbufferindex)) {
6278 if (!pvt->_fieldlengths) {
6279 createFieldLengths();
6280 }
6281 return pvt->_fieldlengths[rowbufferindex];
6282 }
6283 return NULL;
6284 }
6285
createFieldLengths()6286 void sqlrcursor::createFieldLengths() {
6287 // lets say that rowcount=5 and firstrowindex=3,
6288 // the fieldlengths array will contain 2 elements:
6289 // fieldlengths[0] (corresponding to row 3) and
6290 // fieldlengths[1] (corresponding to row 4)
6291 uint64_t rowbuffercount=pvt->_rowcount-pvt->_firstrowindex;
6292 pvt->_fieldlengths=new uint32_t *[rowbuffercount+1];
6293 pvt->_fieldlengths[rowbuffercount]=0;
6294 for (uint64_t i=0; i<rowbuffercount; i++) {
6295 pvt->_fieldlengths[i]=new uint32_t[pvt->_colcount+1];
6296 pvt->_fieldlengths[i][pvt->_colcount]=0;
6297 for (uint32_t j=0; j<pvt->_colcount; j++) {
6298 pvt->_fieldlengths[i][j]=getFieldLengthInternal(i,j);
6299 }
6300 }
6301 }
6302
suspendResultSet()6303 void sqlrcursor::suspendResultSet() {
6304
6305 if (pvt->_sqlrc->debug()) {
6306 pvt->_sqlrc->debugPreStart();
6307 pvt->_sqlrc->debugPrint("Suspending Result Set\n");
6308 pvt->_sqlrc->debugPreEnd();
6309 }
6310
6311 if (pvt->_sqlrc->connected() && !pvt->_cached) {
6312
6313 // refresh socket client
6314 pvt->_cs=pvt->_sqlrc->cs();
6315
6316 pvt->_cs->write((uint16_t)SUSPEND_RESULT_SET);
6317 pvt->_cs->write(pvt->_cursorid);
6318
6319 pvt->_sqlrc->flushWriteBuffer();
6320 }
6321
6322 clearCacheDest();
6323 pvt->_suspendresultsetsent=1;
6324 }
6325
getResultSetId()6326 uint16_t sqlrcursor::getResultSetId() {
6327 return pvt->_cursorid;
6328 }
6329
resumeResultSet(uint16_t id)6330 bool sqlrcursor::resumeResultSet(uint16_t id) {
6331 return resumeCachedResultSet(id,NULL);
6332 }
6333
resumeCachedResultSet(uint16_t id,const char * filename)6334 bool sqlrcursor::resumeCachedResultSet(uint16_t id, const char *filename) {
6335
6336 if (!pvt->_endofresultset && !pvt->_suspendresultsetsent) {
6337 closeResultSet(false);
6338 }
6339 clearResultSet();
6340
6341 if (!pvt->_sqlrc->connected()) {
6342 return false;
6343 }
6344
6345 pvt->_cached=false;
6346 pvt->_resumed=true;
6347 pvt->_endofresultset=false;
6348
6349 if (pvt->_sqlrc->debug()) {
6350 pvt->_sqlrc->debugPreStart();
6351 pvt->_sqlrc->debugPrint("Resuming Result Set of Cursor: ");
6352 pvt->_sqlrc->debugPrint((int64_t)id);
6353 pvt->_sqlrc->debugPrint("\n");
6354 pvt->_sqlrc->debugPreEnd();
6355 }
6356
6357 // refresh socket client
6358 pvt->_cs=pvt->_sqlrc->cs();
6359
6360 // tell the server we want to resume the result set
6361 pvt->_cs->write((uint16_t)RESUME_RESULT_SET);
6362
6363 // send the id of the cursor we want to
6364 // resume the result set of to the server
6365 pvt->_cs->write(id);
6366
6367 // process the result set
6368 if (!charstring::isNullOrEmpty(filename)) {
6369 cacheToFile(filename);
6370 }
6371 return processInitialResultSet();
6372 }
6373
nextResultSet()6374 bool sqlrcursor::nextResultSet() {
6375
6376 // One could imagine an optimization where the availability of a next
6377 // result set could be returned along with every result set..
6378
6379 if (!pvt->_queryptr) {
6380 setError("No query being executed: _queryptr");
6381 return false;
6382 }
6383 if (!pvt->_reexecute) {
6384 setError("No query being executed: _rexecute");
6385 return false;
6386 }
6387
6388 if (!pvt->_sqlrc->openSession()) {
6389 return false;
6390 }
6391
6392 // refresh socket client
6393 pvt->_cs=pvt->_sqlrc->cs();
6394
6395 if (pvt->_sqlrc->debug()) {
6396 pvt->_sqlrc->debugPreStart();
6397 pvt->_sqlrc->debugPrint("Requesting nextResultSet");
6398 pvt->_sqlrc->debugPrint("\n");
6399 pvt->_sqlrc->debugPrint("Requesting Cursor: ");
6400 pvt->_sqlrc->debugPrint((int64_t)pvt->_cursorid);
6401 pvt->_sqlrc->debugPrint("\n");
6402 pvt->_sqlrc->debugPreEnd();
6403 }
6404 pvt->_cs->write((uint16_t)NEXT_RESULT_SET);
6405 pvt->_cs->write(pvt->_cursorid);
6406 pvt->_sqlrc->flushWriteBuffer();
6407
6408 uint16_t err=getErrorStatus();
6409 if (err!=NO_ERROR_OCCURRED) {
6410 if (err==TIMEOUT_GETTING_ERROR_STATUS) {
6411 // the pattern here is that we bail immediately.
6412 // error status has already been set.
6413 pvt->_sqlrc->endSession();
6414 return false;
6415 }
6416 getErrorFromServer();
6417 if (err==ERROR_OCCURRED_DISCONNECT) {
6418 pvt->_sqlrc->endSession();
6419 }
6420 return false;
6421 }
6422 bool resultbool;
6423 if (getBool(&resultbool)!=sizeof(bool)) {
6424 setError("Failed to get bool value.\n "
6425 "A network error may have occurred.");
6426 return false;
6427 }
6428 return resultbool;
6429 }
6430
closeResultSet()6431 void sqlrcursor::closeResultSet() {
6432 closeResultSet(true);
6433 }
6434
closeResultSet(bool closeremote)6435 void sqlrcursor::closeResultSet(bool closeremote) {
6436
6437 // If the end of the previous result set was never reached, abort it.
6438 // If we're caching data to a local file, get the rest of the data; we
6439 // won't have to abort the result set in that case, the server will
6440 // do it.
6441
6442 // refresh socket client
6443 pvt->_cs=pvt->_sqlrc->cs();
6444
6445 if (pvt->_sqlrc->connected() || pvt->_cached) {
6446 if (pvt->_cachedest && pvt->_cachedestind) {
6447 if (pvt->_sqlrc->debug()) {
6448 pvt->_sqlrc->debugPreStart();
6449 pvt->_sqlrc->debugPrint(
6450 "Getting the rest of the result set, "
6451 "since this is a cached result set.\n");
6452 pvt->_sqlrc->debugPreEnd();
6453 }
6454 while (!pvt->_endofresultset) {
6455 clearRows();
6456
6457 // if we're not fetching from a cached result
6458 // set, then tell the server to send one
6459 if (!pvt->_cachesource &&
6460 !pvt->_cachesourceind) {
6461 pvt->_cs->write(
6462 (uint16_t)FETCH_RESULT_SET);
6463 pvt->_cs->write(pvt->_cursorid);
6464 }
6465
6466 // parseResults should call finishCaching when
6467 // it hits the end of the result set, but
6468 // if it or skipAndFetch return a -1 (network
6469 // error) we'll have to call it ourselves.
6470 if (!skipAndFetch(false,0) || !parseResults()) {
6471 finishCaching();
6472 return;
6473 }
6474 }
6475 } else if (closeremote && pvt->_havecursorid) {
6476
6477 if (pvt->_sqlrc->debug()) {
6478 pvt->_sqlrc->debugPreStart();
6479 pvt->_sqlrc->debugPrint("Aborting Result "
6480 "Set For Cursor: ");
6481 pvt->_sqlrc->debugPrint(
6482 (int64_t)pvt->_cursorid);
6483 pvt->_sqlrc->debugPrint("\n");
6484 pvt->_sqlrc->debugPreEnd();
6485 }
6486
6487 pvt->_cs->write((uint16_t)ABORT_RESULT_SET);
6488 pvt->_cs->write((uint16_t)DONT_NEED_NEW_CURSOR);
6489 pvt->_cs->write(pvt->_cursorid);
6490 pvt->_sqlrc->flushWriteBuffer();
6491 }
6492 }
6493 }
6494
clearResultSet()6495 void sqlrcursor::clearResultSet() {
6496
6497 clearCacheDest();
6498 clearCacheSource();
6499 clearError();
6500
6501 // columns is cleared after rows because colcount is used in
6502 // clearRows() and set to 0 in clearColumns()
6503 clearRows();
6504 clearColumns();
6505
6506 // clear row counters, since fetchRowIntoBuffer() and clearResultSet()
6507 // are the only methods that call clearRows() and fetchRowIntoBuffer()
6508 // needs these values not to be cleared, we'll clear them here...
6509 pvt->_firstrowindex=0;
6510 pvt->_resumedlastrowindex=0;
6511 pvt->_rowcount=0;
6512 pvt->_actualrows=0;
6513 pvt->_affectedrows=0;
6514 pvt->_endofresultset=true;
6515 pvt->_suspendresultsetsent=0;
6516 }
6517
clearError()6518 void sqlrcursor::clearError() {
6519 delete[] pvt->_error;
6520 pvt->_error=NULL;
6521 pvt->_errorno=0;
6522 if (pvt->_sqlrc) {
6523 pvt->_sqlrc->clearError();
6524 }
6525 }
6526
clearRows()6527 void sqlrcursor::clearRows() {
6528
6529 // delete data in rows for long datatypes
6530 uint32_t rowbuffercount=pvt->_rowcount-pvt->_firstrowindex;
6531 for (uint32_t i=0; i<rowbuffercount; i++) {
6532 for (uint32_t j=0; j<pvt->_colcount; j++) {
6533 if (getColumnInternal(j)->longdatatype) {
6534 char *field=getFieldInternal(i,j);
6535 uint32_t len=getFieldLengthInternal(i,j);
6536 // Null lobs might be stored as a NULL or as
6537 // an empty string. In either case (and in no
6538 // other case) the length will be 0. In the
6539 // case of a NULL there's nothing to delete.
6540 // In the case of an empty string, the memory
6541 // will be allocated from the rowstorage pool
6542 // and shouldn't be deallocated here.
6543 if (len) {
6544 delete[] field;
6545 }
6546 }
6547 }
6548 }
6549
6550 // delete linked list storing extra result set fields
6551 sqlrclientrow *currentrow;
6552 if (pvt->_firstextrarow) {
6553 currentrow=pvt->_firstextrarow;
6554 while (currentrow) {
6555 pvt->_firstextrarow=currentrow->next;
6556 delete currentrow;
6557 currentrow=pvt->_firstextrarow;
6558 }
6559 pvt->_firstextrarow=NULL;
6560 }
6561 currentrow=NULL;
6562
6563 // delete array pointing to linked list items
6564 delete[] pvt->_extrarows;
6565 pvt->_extrarows=NULL;
6566
6567 // delete arrays of fields and field lengths
6568 if (pvt->_fields) {
6569 for (uint32_t i=0; i<rowbuffercount; i++) {
6570 delete[] pvt->_fields[i];
6571 }
6572 delete[] pvt->_fields;
6573 pvt->_fields=NULL;
6574 }
6575 if (pvt->_fieldlengths) {
6576 for (uint32_t i=0; i<rowbuffercount; i++) {
6577 delete[] pvt->_fieldlengths[i];
6578 }
6579 delete[] pvt->_fieldlengths;
6580 pvt->_fieldlengths=NULL;
6581 }
6582
6583 // reset the row storage pool
6584 pvt->_rowstorage->clear();
6585 }
6586
clearColumns()6587 void sqlrcursor::clearColumns() {
6588
6589 // delete the column type strings (if necessary)
6590 if (pvt->_sentcolumninfo==SEND_COLUMN_INFO &&
6591 pvt->_columntypeformat!=COLUMN_TYPE_IDS) {
6592 for (uint32_t i=0; i<pvt->_colcount; i++) {
6593 delete[] getColumnInternal(i)->typestring;
6594 }
6595 }
6596
6597 // reset the column storage pool
6598 pvt->_colstorage->clear();
6599
6600 // reset the column count
6601 pvt->_previouscolcount=pvt->_colcount;
6602 pvt->_colcount=0;
6603
6604 // delete array pointing to each column name
6605 delete[] pvt->_columnnamearray;
6606 pvt->_columnnamearray=NULL;
6607 }
6608
getQueryTree()6609 const char *sqlrcursor::getQueryTree() {
6610
6611 delete[] pvt->_querytree;
6612 pvt->_querytree=NULL;
6613
6614 pvt->_reexecute=false;
6615 pvt->_validatebinds=false;
6616 pvt->_resumed=false;
6617 clearVariables();
6618
6619 if (!pvt->_endofresultset) {
6620 closeResultSet(false);
6621 }
6622 clearResultSet();
6623
6624 if (!pvt->_sqlrc->openSession()) {
6625 return NULL;
6626 }
6627
6628 pvt->_cached=false;
6629 pvt->_endofresultset=false;
6630
6631 // refresh socket client
6632 pvt->_cs=pvt->_sqlrc->cs();
6633
6634 // tell the server we want to get a query tree
6635 pvt->_cs->write((uint16_t)GET_QUERY_TREE);
6636
6637 // tell the server whether we'll need a cursor or not
6638 sendCursorStatus();
6639
6640 pvt->_sqlrc->flushWriteBuffer();
6641
6642 uint16_t err=getErrorStatus();
6643 if (err!=NO_ERROR_OCCURRED) {
6644 if (err==TIMEOUT_GETTING_ERROR_STATUS) {
6645 pvt->_sqlrc->endSession();
6646 return NULL;
6647 }
6648 getErrorFromServer();
6649 if (err==ERROR_OCCURRED_DISCONNECT) {
6650 pvt->_sqlrc->endSession();
6651 }
6652 return NULL;
6653 }
6654
6655 // get the size of the tree
6656 uint64_t len;
6657 if (pvt->_cs->read(&len)!=sizeof(uint64_t)) {
6658 return NULL;
6659 }
6660
6661 // get the tree itself
6662 pvt->_querytree=new char[len+1];
6663 if ((uint64_t)pvt->_cs->read(pvt->_querytree,len)!=len) {
6664 delete[] pvt->_querytree;
6665 pvt->_querytree=NULL;
6666 return NULL;
6667 }
6668 pvt->_querytree[len]='\0';
6669
6670 return pvt->_querytree;
6671 }
6672
getTranslatedQuery()6673 const char *sqlrcursor::getTranslatedQuery() {
6674
6675 delete[] pvt->_translatedquery;
6676 pvt->_translatedquery=NULL;
6677
6678 pvt->_reexecute=false;
6679 pvt->_validatebinds=false;
6680 pvt->_resumed=false;
6681 clearVariables();
6682
6683 if (!pvt->_endofresultset) {
6684 closeResultSet(false);
6685 }
6686 clearResultSet();
6687
6688 if (!pvt->_sqlrc->openSession()) {
6689 return NULL;
6690 }
6691
6692 pvt->_cached=false;
6693 pvt->_endofresultset=false;
6694
6695 // refresh socket client
6696 pvt->_cs=pvt->_sqlrc->cs();
6697
6698 // tell the server we want to get a translated query
6699 pvt->_cs->write((uint16_t)GET_TRANSLATED_QUERY);
6700
6701 // tell the server whether we'll need a cursor or not
6702 sendCursorStatus();
6703
6704 pvt->_sqlrc->flushWriteBuffer();
6705
6706 uint16_t err=getErrorStatus();
6707 if (err!=NO_ERROR_OCCURRED) {
6708 if (err==TIMEOUT_GETTING_ERROR_STATUS) {
6709 pvt->_sqlrc->endSession();
6710 return NULL;
6711 }
6712 getErrorFromServer();
6713 if (err==ERROR_OCCURRED_DISCONNECT) {
6714 pvt->_sqlrc->endSession();
6715 }
6716 return NULL;
6717 }
6718
6719 // get the size of the query
6720 uint64_t len;
6721 if (pvt->_cs->read(&len)!=sizeof(uint64_t)) {
6722 return NULL;
6723 }
6724
6725 // get the query itself
6726 pvt->_translatedquery=new char[len+1];
6727 if ((uint64_t)pvt->_cs->read(pvt->_translatedquery,len)!=len) {
6728 delete[] pvt->_translatedquery;
6729 pvt->_translatedquery=NULL;
6730 return NULL;
6731 }
6732 pvt->_translatedquery[len]='\0';
6733
6734 return pvt->_translatedquery;
6735 }
6736
endofresultset()6737 bool sqlrcursor::endofresultset() {
6738 return pvt->_endofresultset;
6739 }
6740
sqlrc(sqlrconnection * sqlrc)6741 void sqlrcursor::sqlrc(sqlrconnection *sqlrc) {
6742 pvt->_sqlrc=sqlrc;
6743 }
6744
next()6745 sqlrcursor *sqlrcursor::next() {
6746 return pvt->_next;
6747 }
6748
havecursorid(bool havecursorid)6749 void sqlrcursor::havecursorid(bool havecursorid) {
6750 pvt->_havecursorid=havecursorid;
6751 }
6752
clearBindsDuringPrepare()6753 void sqlrcursor::clearBindsDuringPrepare() {
6754 pvt->_clearbindsduringprepare=true;
6755 }
6756
dontClearBindsDuringPrepare()6757 void sqlrcursor::dontClearBindsDuringPrepare() {
6758 pvt->_clearbindsduringprepare=false;
6759 }
6760