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(&currentcol->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(&currentcol->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(&currentcol->length)!=
3955 						sizeof(uint32_t) ||
3956 				getLong(&currentcol->precision)!=
3957 						sizeof(uint32_t) ||
3958 				getLong(&currentcol->scale)!=
3959 						sizeof(uint32_t) ||
3960 				getShort(&currentcol->nullable)!=
3961 						sizeof(uint16_t) ||
3962 				getShort(&currentcol->primarykey)!=
3963 						sizeof(uint16_t) ||
3964 				getShort(&currentcol->unique)!=
3965 						sizeof(uint16_t) ||
3966 				getShort(&currentcol->partofkey)!=
3967 						sizeof(uint16_t) ||
3968 				getShort(&currentcol->unsignednumber)!=
3969 						sizeof(uint16_t) ||
3970 				getShort(&currentcol->zerofill)!=
3971 						sizeof(uint16_t) ||
3972 				getShort(&currentcol->binary)!=
3973 						sizeof(uint16_t) ||
3974 				getShort(&currentcol->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