1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3 
4 #include <config.h>
5 
6 #include <sqlrelay/sqlrserver.h>
7 
8 #include <rudiments/stringbuffer.h>
9 #include <rudiments/memorypool.h>
10 #include <rudiments/datetime.h>
11 #include <rudiments/userentry.h>
12 #include <rudiments/process.h>
13 #include <rudiments/file.h>
14 //#define DEBUG_MESSAGES 1
15 #include <rudiments/debugprint.h>
16 
17 #include <datatypes.h>
18 #include <defaults.h>
19 #include <defines.h>
20 
21 enum sqlrclientquerytype_t {
22 	SQLRCLIENTQUERYTYPE_QUERY=0,
23 	SQLRCLIENTQUERYTYPE_DATABASE_LIST,
24 	SQLRCLIENTQUERYTYPE_SCHEMA_LIST,
25 	SQLRCLIENTQUERYTYPE_TABLE_LIST,
26 	SQLRCLIENTQUERYTYPE_TABLE_LIST_2,
27 	SQLRCLIENTQUERYTYPE_TABLE_TYPE_LIST,
28 	SQLRCLIENTQUERYTYPE_COLUMN_LIST,
29 	SQLRCLIENTQUERYTYPE_PRIMARY_KEY_LIST,
30 	SQLRCLIENTQUERYTYPE_KEY_AND_INDEX_LIST,
31 	SQLRCLIENTQUERYTYPE_PROCEDURE_BIND_AND_COLUMN_LIST,
32 	SQLRCLIENTQUERYTYPE_TYPE_INFO_LIST,
33 	SQLRCLIENTQUERYTYPE_PROCEDURE_LIST
34 };
35 
36 class SQLRSERVER_DLLSPEC sqlrprotocol_sqlrclient : public sqlrprotocol {
37 	public:
38 			sqlrprotocol_sqlrclient(sqlrservercontroller *cont,
39 							sqlrprotocols *ps,
40 							domnode *parameters);
41 		virtual	~sqlrprotocol_sqlrclient();
42 
43 		clientsessionexitstatus_t	clientSession(
44 							filedescriptor *cs);
45 
46 		gsscontext	*getGSSContext();
47 		tlscontext	*getTLSContext();
48 
49 	private:
50 		bool	acceptSecurityContext();
51 		bool	getCommand(uint16_t *command);
52 		sqlrservercursor	*getCursor(uint16_t command);
53 		void	noAvailableCursors(uint16_t command);
54 		bool	authCommand();
55 		bool	getUserFromClient();
56 		bool	getPasswordFromClient();
57 		void	suspendSessionCommand();
58 		void	pingCommand();
59 		void	identifyCommand();
60 		void	autoCommitCommand();
61 		void	beginCommand();
62 		void	commitCommand();
63 		void	rollbackCommand();
64 		void	dbVersionCommand();
65 		void	bindFormatCommand();
66 		void	serverVersionCommand();
67 		void	selectDatabaseCommand();
68 		void	getCurrentDatabaseCommand();
69 		void	getCurrentSchemaCommand();
70 		void	getLastInsertIdCommand();
71 		void	dbHostNameCommand();
72 		void	dbIpAddressCommand();
73 		bool	newQueryCommand(sqlrservercursor *cursor);
74 		bool	reExecuteQueryCommand(sqlrservercursor *cursor);
75 		bool	fetchFromBindCursorCommand(sqlrservercursor *cursor);
76 		bool	processQueryOrBindCursor(sqlrservercursor *cursor,
77 					sqlrclientquerytype_t querytype,
78 					sqlrserverlistformat_t listformat,
79 					bool reexecute,
80 					bool bindcursor);
81 		bool	getClientInfo(sqlrservercursor *cursor);
82 		bool	getQuery(sqlrservercursor *cursor);
83 		bool	getInputBinds(sqlrservercursor *cursor);
84 		bool	getOutputBinds(sqlrservercursor *cursor);
85 		bool	getInputOutputBinds(sqlrservercursor *cursor);
86 		bool	getBindVarCount(sqlrservercursor *cursor,
87 						uint16_t *count);
88 		bool	getBindVarName(sqlrservercursor *cursor,
89 						sqlrserverbindvar *bv,
90 						memorypool *bindpool);
91 		bool	getBindVarType(sqlrserverbindvar *bv);
92 		bool	getBindSize(sqlrservercursor *cursor,
93 						sqlrserverbindvar *bv,
94 						uint32_t *maxsize);
95 		void	getNullBind(sqlrserverbindvar *bv,
96 						memorypool *bindpool);
97 		bool	getStringBind(sqlrservercursor *cursor,
98 						sqlrserverbindvar *bv,
99 						memorypool *bindpool);
100 		bool	getIntegerBind(sqlrserverbindvar *bv);
101 		bool	getDoubleBind(sqlrserverbindvar *bv);
102 		bool	getDateBind(sqlrserverbindvar *bv,
103 						memorypool *bindpool);
104 		bool	getLobBind(sqlrservercursor *cursor,
105 						sqlrserverbindvar *bv,
106 						memorypool *bindpool);
107 		bool	getSendColumnInfo();
108 		bool	getSkipAndFetch(bool initial, sqlrservercursor *cursor);
109 		void	returnResultSetHeader(sqlrservercursor *cursor);
110 		void	returnColumnInfo(sqlrservercursor *cursor,
111 							uint16_t format);
112 		uint16_t	protocolAppropriateColumnType(uint16_t coltype);
113 		void	sendRowCounts(bool knowsactual, uint64_t actual,
114 					bool knowsaffected, uint64_t affected);
115 		void	returnOutputBindValues(sqlrservercursor *cursor);
116 		void	returnOutputBindBlob(sqlrservercursor *cursor,
117 							uint16_t index);
118 		void	returnOutputBindClob(sqlrservercursor *cursor,
119 							uint16_t index);
120 		void	sendLobOutputBind(sqlrservercursor *cursor,
121 							uint16_t index);
122 		void	returnInputOutputBindValues(sqlrservercursor *cursor);
123 		void	sendColumnDefinition(const char *name,
124 						uint16_t namelen,
125 						uint16_t type,
126 						uint32_t size,
127 						uint32_t precision,
128 						uint32_t scale,
129 						uint16_t nullable,
130 						uint16_t primarykey,
131 						uint16_t unique,
132 						uint16_t partofkey,
133 						uint16_t unsignednumber,
134 						uint16_t zerofill,
135 						uint16_t binary,
136 						uint16_t autoincrement,
137 						const char *table,
138 						uint16_t tablelength);
139 		void	sendColumnDefinitionString(const char *name,
140 						uint16_t namelen,
141 						const char *type,
142 						uint16_t typelen,
143 						uint32_t size,
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 						const char *table,
155 						uint16_t tablelength);
156 		bool	returnResultSetData(sqlrservercursor *cursor,
157 						bool getskipandfetch,
158 						bool overridelazyfetch);
159 		void	returnFetchError(sqlrservercursor *cursor);
160 		void	returnRow(sqlrservercursor *cursor);
161 		void	sendField(const char *data, uint32_t size);
162 		void	sendNullField();
163 		void	sendLobField(sqlrservercursor *cursor, uint32_t col);
164 		void	startSendingLong(uint64_t longlength);
165 		void	sendLongSegment(const char *data, uint32_t size);
166 		void	endSendingLong();
167 		void	returnError(bool forcedisconnect);
168 		void	returnError(sqlrservercursor *cursor,
169 						bool forcedisconnect);
170 		bool	fetchResultSetCommand(sqlrservercursor *cursor);
171 		void	abortResultSetCommand(sqlrservercursor *cursor);
172 		void	suspendResultSetCommand(sqlrservercursor *cursor);
173 		bool	resumeResultSetCommand(sqlrservercursor *cursor);
174 		bool	getDatabaseListCommand(sqlrservercursor *cursor);
175 		bool	getSchemaListCommand(sqlrservercursor *cursor);
176 		bool	getTableListCommand(sqlrservercursor *cursor);
177 		bool	getTableList2Command(sqlrservercursor *cursor);
178 		bool	getTableTypeListCommand(sqlrservercursor *cursor);
179 		bool	getColumnListCommand(sqlrservercursor *cursor);
180 		bool	getPrimaryKeyListCommand(sqlrservercursor *cursor);
181 		bool	getKeyAndIndexListCommand(sqlrservercursor *cursor);
182 		bool	getProcedureBindAndColumnListCommand(
183 						sqlrservercursor *cursor);
184 		bool	getTypeInfoListCommand(sqlrservercursor *cursor);
185 		bool	getProcedureListCommand(sqlrservercursor *cursor);
186 		bool	getListCommand(sqlrservercursor *cursor,
187 					sqlrclientquerytype_t querytype,
188 					bool getobject);
189 		bool	getListByApiCall(sqlrservercursor *cursor,
190 					sqlrclientquerytype_t querytype,
191 					const char *object,
192 					const char *wild,
193 					sqlrserverlistformat_t listformat,
194 					uint16_t objecttypes);
195 		bool	getListByQuery(sqlrservercursor *cursor,
196 					sqlrclientquerytype_t querytype,
197 					const char *object,
198 					const char *wild,
199 					sqlrserverlistformat_t listformat,
200 					uint16_t objecttypes);
201 		bool	buildListQuery(sqlrservercursor *cursor,
202 						const char *query,
203 						const char *wild,
204 						const char *object);
205 		void	escapeParameter(stringbuffer *buffer,
206 						const char *parameter);
207 		bool	getQueryTreeCommand(sqlrservercursor *cursor);
208 		bool	getTranslatedQueryCommand(sqlrservercursor *cursor);
209 		bool	nextResultSetCommand(sqlrservercursor *cursor);
210 
211 		stringbuffer	debugstr;
212 
213 		filedescriptor	*clientsock;
214 
215 		securitycontext	*ctx;
216 		bool		usekrb;
217 		bool		usetls;
218 
219 		gsscredentials	gcred;
220 		gssmechanism	gmech;
221 		gsscontext	gctx;
222 		tlscontext	tctx;
223 
224 		int32_t		idleclienttimeout;
225 
226 		uint64_t	maxclientinfolength;
227 		uint32_t	maxquerysize;
228 		uint16_t	maxbindcount;
229 		uint16_t	maxbindnamelength;
230 		uint32_t	maxstringbindvaluelength;
231 		uint32_t	maxlobbindvaluelength;
232 		uint32_t	maxerrorlength;
233 		bool		waitfordowndb;
234 
235 		char		userbuffer[USERSIZE];
236 		char		passwordbuffer[USERSIZE];
237 
238 		char		*clientinfo;
239 		uint64_t	clientinfolen;
240 
241 		uint64_t	skip;
242 		uint64_t	fetch;
243 		bool		lazyfetch;
244 
245 		char		lobbuffer[32768];
246 
247 		uint16_t	protocolversion;
248 		uint16_t	endresultset;
249 };
250 
sqlrprotocol_sqlrclient(sqlrservercontroller * cont,sqlrprotocols * ps,domnode * parameters)251 sqlrprotocol_sqlrclient::sqlrprotocol_sqlrclient(
252 					sqlrservercontroller *cont,
253 					sqlrprotocols *ps,
254 					domnode *parameters) :
255 					sqlrprotocol(cont,ps,parameters) {
256 	debugFunction();
257 
258 	idleclienttimeout=cont->getConfig()->getIdleClientTimeout();
259 	maxclientinfolength=cont->getConfig()->getMaxClientInfoLength();
260 	maxquerysize=cont->getConfig()->getMaxQuerySize();
261 	maxbindcount=cont->getConfig()->getMaxBindCount();
262 	maxbindnamelength=cont->getConfig()->getMaxBindNameLength();
263 	maxstringbindvaluelength=
264 			cont->getConfig()->getMaxStringBindValueLength();
265 	maxlobbindvaluelength=cont->getConfig()->getMaxLobBindValueLength();
266 	lazyfetch=false;
267 	maxerrorlength=cont->getConfig()->getMaxErrorLength();
268 	waitfordowndb=cont->getConfig()->getWaitForDownDatabase();
269 	clientinfo=new char[maxclientinfolength+1];
270 	clientsock=NULL;
271 	ctx=NULL;
272 	usekrb=charstring::isYes(parameters->getAttributeValue("krb"));
273 	usetls=charstring::isYes(parameters->getAttributeValue("tls"));
274 
275 	if (usekrb) {
276 		if (gss::supported()) {
277 
278 			// set the keytab file to use
279 			const char	*keytab=
280 				parameters->getAttributeValue("krbkeytab");
281 			if (!charstring::isNullOrEmpty(keytab)) {
282 				gcred.setKeytab(keytab);
283 			}
284 
285 			// set the service to use
286 			const char	*service=
287 				parameters->getAttributeValue("krbservice");
288 			if (charstring::isNullOrEmpty(service)) {
289 				service=DEFAULT_KRBSERVICE;
290 			}
291 
292 			// acquire service credentials
293 			if (!gcred.acquireForService(service)) {
294 				const char	*status=
295 					gcred.getMechanismMinorStatus();
296 				stderror.printf("kerberos acquire-"
297 						"service %s failed:\n%s",
298 						service,status);
299 				if (charstring::contains(status,
300 							"Permission denied")) {
301 					char	*user=userentry::getName(
302 							process::getUserId());
303 					stderror.printf("(keytab file likely "
304 							"not readable by user "
305 							"%s)\n",user);
306 					delete[] user;
307 				}
308 			}
309 
310 			// initialize the gss context
311 			gmech.initialize(
312 				parameters->getAttributeValue("krbmech"));
313 			gctx.setDesiredMechanism(&gmech);
314 			gctx.setDesiredFlags(
315 				parameters->getAttributeValue("krbflags"));
316 			gctx.setCredentials(&gcred);
317 
318 			// use the gss context
319 			ctx=&gctx;
320 
321 		} else {
322 			stderror.printf("Warning: kerberos support requested "
323 					"but platform doesn't support "
324 					"kerberos\n");
325 		}
326 	} else if (usetls) {
327 		if (tls::supported()) {
328 
329 			// get the protocol version to use
330 			tctx.setProtocolVersion(
331 				parameters->getAttributeValue("tlsversion"));
332 
333 			// get the certificate chain file to use
334 			const char	*tlscert=
335 				parameters->getAttributeValue("tlscert");
336 			if (file::readable(tlscert)) {
337 				tctx.setCertificateChainFile(tlscert);
338 			} else if (!charstring::isNullOrEmpty(tlscert)) {
339 				stderror.printf("Warning: TLS certificate "
340 						"file %s is not readable.\n",
341 						tlscert);
342 			}
343 
344 			// get the private key file to use
345 			const char	*tlskey=
346 				parameters->getAttributeValue("tlskey");
347 			if (file::readable(tlskey)) {
348 				tctx.setPrivateKeyFile(tlskey);
349 			} else if (!charstring::isNullOrEmpty(tlskey)) {
350 				stderror.printf("Warning: TLS private key "
351 						"file %s is not readable.\n",
352 						tlskey);
353 			}
354 
355 			// get the private key password to use
356 			tctx.setPrivateKeyPassword(
357 				parameters->getAttributeValue("tlspassword"));
358 
359 			// get whether to validate
360 			tctx.setValidatePeer(
361 				charstring::isYes(
362 				parameters->getAttributeValue("tlsvalidate")));
363 
364 			// get the certificate authority file to use
365 			// FIXME: not-found warning
366 			tctx.setCertificateAuthority(
367 				parameters->getAttributeValue("tlsca"));
368 
369 			// get the cipher list to use
370 			tctx.setCiphers(
371 				parameters->getAttributeValue("tlsciphers"));
372 
373 			// get the validation depth
374 			tctx.setValidationDepth(
375 				charstring::toUnsignedInteger(
376 				parameters->getAttributeValue("tlsdepth")));
377 
378 			// use the tls context
379 			ctx=&tctx;
380 
381 		} else {
382 			stderror.printf("Warning: TLS support requested "
383 					"but platform doesn't support "
384 					"TLS\n");
385 		}
386 	}
387 
388 	protocolversion=0;
389 	endresultset=END_RESULT_SET;
390 }
391 
~sqlrprotocol_sqlrclient()392 sqlrprotocol_sqlrclient::~sqlrprotocol_sqlrclient() {
393 	debugFunction();
394 	delete[] clientinfo;
395 }
396 
clientSession(filedescriptor * cs)397 clientsessionexitstatus_t sqlrprotocol_sqlrclient::clientSession(
398 							filedescriptor *cs) {
399 	debugFunction();
400 
401 	clientsock=cs;
402 
403 	// set up the socket
404 	clientsock->translateByteOrder();
405 	clientsock->dontUseNaglesAlgorithm();
406 	clientsock->setSocketReadBufferSize(65536);
407 	clientsock->setSocketWriteBufferSize(65536);
408 	clientsock->setReadBufferSize(65536);
409 	clientsock->setWriteBufferSize(65536);
410 	//clientsock->useAsyncWrite();
411 
412 	clientsessionexitstatus_t	status=CLIENTSESSIONEXITSTATUS_ERROR;
413 
414 	// accept security context, if necessary
415 	if (!acceptSecurityContext()) {
416 		return status;
417 	}
418 
419 	// During each session, the client will send a series of commands.
420 	// The session ends when the client ends it or when certain commands
421 	// fail.
422 	bool			loop=true;
423 	bool			endsession=true;
424 	uint16_t		command;
425 	do {
426 
427 		// handle disabled instance
428 		// FIXME: push up?
429 		if (cont->getInstanceDisabled()) {
430 			endsession=true;
431 			break;
432 		}
433 
434 		// get a command from the client
435 		if (!getCommand(&command)) {
436 			break;
437 		}
438 
439 		// get the command start time
440 		datetime	dt;
441 		dt.getSystemDateAndTime();
442 
443 		// handle client protocol version as a command, for now
444 		if (command==PROTOCOLVERSION) {
445 			if (clientsock->read(&protocolversion,
446 						idleclienttimeout,0)==
447 						sizeof(uint16_t)) {
448 				// END_RESULT_SET was 3 in protocol version 1,
449 				// but changed in version 2
450 				endresultset=(protocolversion==1)?
451 							3:END_RESULT_SET;
452 				continue;
453 			}
454 			endsession=false;
455 			break;
456 		} else
457 
458 		// these commands are all handled at the connection level
459 		if (command==AUTH) {
460 			cont->incrementAuthCount();
461 			if (authCommand()) {
462 				cont->beginSession();
463 				continue;
464 			}
465 			endsession=false;
466 			break;
467 		} else if (command==SUSPEND_SESSION) {
468 			cont->incrementSuspendSessionCount();
469 			suspendSessionCommand();
470 			status=CLIENTSESSIONEXITSTATUS_SUSPENDED_SESSION;
471 			endsession=false;
472 			break;
473 		} else if (command==END_SESSION) {
474 			cont->incrementEndSessionCount();
475 			status=CLIENTSESSIONEXITSTATUS_ENDED_SESSION;
476 			break;
477 		} else if (command==PING) {
478 			cont->incrementPingCount();
479 			pingCommand();
480 			continue;
481 		} else if (command==IDENTIFY) {
482 			cont->incrementIdentifyCount();
483 			identifyCommand();
484 			continue;
485 		} else if (command==AUTOCOMMIT) {
486 			cont->incrementAutocommitCount();
487 			autoCommitCommand();
488 			continue;
489 		} else if (command==BEGIN) {
490 			cont->incrementBeginCount();
491 			beginCommand();
492 			continue;
493 		} else if (command==COMMIT) {
494 			cont->incrementCommitCount();
495 			commitCommand();
496 			continue;
497 		} else if (command==ROLLBACK) {
498 			cont->incrementRollbackCount();
499 			rollbackCommand();
500 			continue;
501 		} else if (command==DBVERSION) {
502 			cont->incrementDbVersionCount();
503 			dbVersionCommand();
504 			continue;
505 		} else if (command==BINDFORMAT) {
506 			cont->incrementBindFormatCount();
507 			bindFormatCommand();
508 			continue;
509 		} else if (command==SERVERVERSION) {
510 			cont->incrementServerVersionCount();
511 			serverVersionCommand();
512 			continue;
513 		} else if (command==SELECT_DATABASE) {
514 			cont->incrementSelectDatabaseCount();
515 			selectDatabaseCommand();
516 			continue;
517 		} else if (command==GET_CURRENT_DATABASE) {
518 			cont->incrementGetCurrentDatabaseCount();
519 			getCurrentDatabaseCommand();
520 			continue;
521 		} else if (command==GET_CURRENT_SCHEMA) {
522 			//cont->incrementGetCurrentSchemaCount();
523 			getCurrentSchemaCommand();
524 			continue;
525 		} else if (command==GET_LAST_INSERT_ID) {
526 			cont->incrementGetLastInsertIdCount();
527 			getLastInsertIdCommand();
528 			continue;
529 		} else if (command==DBHOSTNAME) {
530 			cont->incrementDbHostNameCount();
531 			dbHostNameCommand();
532 			continue;
533 		} else if (command==DBIPADDRESS) {
534 			cont->incrementDbIpAddressCount();
535 			dbIpAddressCommand();
536 			continue;
537 		}
538 
539 		// For the rest of the commands,
540 		// the client will request a cursor
541 		sqlrservercursor	*cursor=getCursor(command);
542 		if (!cursor) {
543 			// Don't worry about reporting that a cursor wasn't
544 			// available for abort-result-set commands. Those
545 			// commands don't look for a response from the server
546 			// and it doesn't matter if a non-existent result set
547 			// was aborted.
548 			if (command!=ABORT_RESULT_SET) {
549 				noAvailableCursors(command);
550 			}
551 			continue;
552 		}
553 
554 		// set the command start-time
555 		cont->setCommandStart(cursor,
556 				dt.getSeconds(),dt.getMicroseconds());
557 
558 		// these commands are all handled at the cursor level
559 		if (command==NEW_QUERY) {
560 			cont->incrementNewQueryCount();
561 			loop=newQueryCommand(cursor);
562 		} else if (command==REEXECUTE_QUERY) {
563 			cont->incrementReexecuteQueryCount();
564 			loop=reExecuteQueryCommand(cursor);
565 		} else if (command==FETCH_FROM_BIND_CURSOR) {
566 			cont->incrementFetchFromBindCursorCount();
567 			loop=fetchFromBindCursorCommand(cursor);
568 		} else if (command==FETCH_RESULT_SET) {
569 			cont->incrementFetchResultSetCount();
570 			loop=fetchResultSetCommand(cursor);
571 		} else if (command==ABORT_RESULT_SET) {
572 			cont->incrementAbortResultSetCount();
573 			abortResultSetCommand(cursor);
574 		} else if (command==SUSPEND_RESULT_SET) {
575 			cont->incrementSuspendResultSetCount();
576 			suspendResultSetCommand(cursor);
577 		} else if (command==RESUME_RESULT_SET) {
578 			cont->incrementResumeResultSetCount();
579 			loop=resumeResultSetCommand(cursor);
580 		} else if (command==GETDBLIST) {
581 			cont->incrementGetDbListCount();
582 			loop=getDatabaseListCommand(cursor);
583 		} else if (command==GETSCHEMALIST) {
584 			//cont->incrementGetSchemaListCount();
585 			loop=getSchemaListCommand(cursor);
586 		} else if (command==GETTABLELIST) {
587 			cont->incrementGetTableListCount();
588 			loop=getTableListCommand(cursor);
589 		} else if (command==GETTABLELIST2) {
590 			cont->incrementGetTableListCount();
591 			loop=getTableList2Command(cursor);
592 		} else if (command==GETTABLETYPELIST) {
593 			//cont->incrementGetTableTypeListCount();
594 			loop=getTableTypeListCommand(cursor);
595 		} else if (command==GETCOLUMNLIST) {
596 			cont->incrementGetColumnListCount();
597 			loop=getColumnListCommand(cursor);
598 		} else if (command==GETPRIMARYKEYLIST) {
599 			//cont->incrementGetPrimaryKeyListCount();
600 			loop=getPrimaryKeyListCommand(cursor);
601 		} else if (command==GETKEYANDINDEXLIST) {
602 			//cont->incrementGetKeyAndIndexListCount();
603 			loop=getKeyAndIndexListCommand(cursor);
604 		} else if (command==GETPROCEDUREBINDANDCOLUMNLIST) {
605 			//cont->incrementGetProcedureBindAndColumnListCount();
606 			loop=getProcedureBindAndColumnListCommand(cursor);
607 		} else if (command==GETTYPEINFOLIST) {
608 			//cont->incrementGetTypeInfoListCount();
609 			loop=getTypeInfoListCommand(cursor);
610 		} else if (command==GETPROCEDURELIST) {
611 			//cont->incrementGetProcedureListCount();
612 			loop=getProcedureListCommand(cursor);
613 		} else if (command==GET_QUERY_TREE) {
614 			cont->incrementGetQueryTreeCount();
615 			loop=getQueryTreeCommand(cursor);
616 		} else if (command==GET_TRANSLATED_QUERY) {
617 			//cont->incrementGetTranslatedQueryCount();
618 			loop=getTranslatedQueryCommand(cursor);
619 		} else if (command==NEXT_RESULT_SET) {
620 			loop=nextResultSetCommand(cursor);
621 		} else {
622 			loop=false;
623 		}
624 
625 		// set the command end-time
626 		dt.getSystemDateAndTime();
627 		cont->setCommandEnd(cursor,
628 				dt.getSeconds(),dt.getMicroseconds());
629 
630 		// free memory used by binds...
631 		// FIXME: can we move this inside of processQueryOrBindCursor?
632 		// verify that log/notification modules activated by
633 		// raise*Event calls don't still need the bind values
634 		cont->getBindPool(cursor)->clear();
635 
636 	} while (loop);
637 
638 	// close the client connection
639 	//
640 	// If an error occurred, the client could still be sending an entire
641 	// session's worth of data before it reads the error and closes the
642 	// socket.  We have to absorb all of that data.  We shouldn't just loop
643 	// forever though, that would provide a point of entry for a DOS attack.
644 	// We'll read the maximum number of bytes that could be sent.
645 	cont->closeClientConnection(
646 				// sending auth
647 				(sizeof(uint16_t)+
648 				// user/password
649 				2*(sizeof(uint32_t)+USERSIZE)+
650 				// sending query
651 				sizeof(uint16_t)+
652 				// need a cursor
653 				sizeof(uint16_t)+
654 				// executing new query
655 				sizeof(uint16_t)+
656 				// query size and query
657 				sizeof(uint32_t)+maxquerysize+
658 				// input bind var count
659 				sizeof(uint16_t)+
660 				// input bind vars
661 				maxbindcount*(2*sizeof(uint16_t)+
662 						maxbindnamelength)+
663 				// output bind var count
664 				sizeof(uint16_t)+
665 				// output bind vars
666 				maxbindcount*(2*sizeof(uint16_t)+
667 						maxbindnamelength)+
668 				// get column info
669 				sizeof(uint16_t)+
670 				// skip/fetch
671 				2*sizeof(uint32_t)
672 				// divide by two because we're
673 				// reading 2 bytes at a time
674 				)/2);
675 
676 	// end the session if necessary
677 	if (endsession) {
678 		cont->endSession();
679 	}
680 
681 	// return the exit status
682 	return status;
683 }
684 
acceptSecurityContext()685 bool sqlrprotocol_sqlrclient::acceptSecurityContext() {
686 
687 	if (!usekrb && !usetls) {
688 		return true;
689 	}
690 
691 	cont->raiseDebugMessageEvent("accepting security context");
692 
693 	if (usekrb && !gss::supported()) {
694 		cont->raiseInternalErrorEvent(NULL,
695 				"failed to accept gss security "
696 				"context (kerberos requested but "
697 				"not supported)");
698 		return false;
699 	} else if (usetls && !tls::supported()) {
700 		cont->raiseInternalErrorEvent(NULL,
701 				"failed to accept tls security "
702 				"context (tls requested but "
703 				"not supported)");
704 		return false;
705 	}
706 
707 	// attach the context and file descriptor to each other
708 	clientsock->setSecurityContext(ctx);
709 	ctx->setFileDescriptor(clientsock);
710 
711 	// accept the security context
712 	bool	retval=ctx->accept();
713 	if (!retval) {
714 		cont->raiseInternalErrorEvent(NULL,
715 			"failed to accept security context");
716 	}
717 
718 	cont->raiseDebugMessageEvent("done accepting security context");
719 	return retval;
720 }
721 
getCommand(uint16_t * command)722 bool sqlrprotocol_sqlrclient::getCommand(uint16_t *command) {
723 	debugFunction();
724 
725 	cont->raiseDebugMessageEvent("getting command...");
726 
727 	cont->setState(GET_COMMAND);
728 
729 	// get the command
730 	ssize_t	result=clientsock->read(command,idleclienttimeout,0);
731 	if (result!=sizeof(uint16_t)) {
732 
733 		// Return false but don't consider it an error if we get a
734 		// timeout or a 0 (meaning that the client closed the socket)
735 		// as either would be natural to do here.
736 		if (result!=RESULT_TIMEOUT && result!=0) {
737 			cont->raiseClientProtocolErrorEvent(
738 				NULL,"get command failed",result);
739 		}
740 
741 		*command=NO_COMMAND;
742 		return false;
743 	}
744 
745 	debugstr.clear();
746 	debugstr.append("command: ")->append(*command);
747 	cont->raiseDebugMessageEvent(debugstr.getString());
748 
749 	cont->raiseDebugMessageEvent("done getting command");
750 	return true;
751 }
752 
getCursor(uint16_t command)753 sqlrservercursor *sqlrprotocol_sqlrclient::getCursor(uint16_t command) {
754 	debugFunction();
755 
756 	cont->raiseDebugMessageEvent("getting a cursor...");
757 
758 	// does the client need a cursor or does it already have one
759 	uint16_t	neednewcursor=DONT_NEED_NEW_CURSOR;
760 	if (command==NEW_QUERY ||
761 		command==GETDBLIST ||
762 		command==GETSCHEMALIST ||
763 		command==GETTABLELIST ||
764 		command==GETTABLELIST2 ||
765 		command==GETTABLETYPELIST ||
766 		command==GETCOLUMNLIST ||
767 		command==GETPRIMARYKEYLIST ||
768 		command==GETKEYANDINDEXLIST ||
769 		command==GETPROCEDUREBINDANDCOLUMNLIST ||
770 		command==GETTYPEINFOLIST ||
771 		command==GETPROCEDURELIST ||
772 		command==ABORT_RESULT_SET ||
773 		command==GET_QUERY_TREE ||
774 		command==GET_TRANSLATED_QUERY) {
775 		ssize_t	result=clientsock->read(&neednewcursor,
776 						idleclienttimeout,0);
777 		if (result!=sizeof(uint16_t)) {
778 			cont->raiseClientProtocolErrorEvent(NULL,
779 					"get cursor failed: "
780 					"failed to get whether client "
781 					"needs  new cursor or not",result);
782 			return NULL;
783 		}
784 	}
785 
786 	sqlrservercursor	*cursor=NULL;
787 
788 	if (neednewcursor==DONT_NEED_NEW_CURSOR) {
789 
790 		// which cursor is the client requesting?
791 		uint16_t	id;
792 		ssize_t		result=clientsock->read(&id,
793 						idleclienttimeout,0);
794 		if (result!=sizeof(uint16_t)) {
795 			cont->raiseClientProtocolErrorEvent(NULL,
796 					"get cursor failed: "
797 					"failed to get cursor id",result);
798 			return NULL;
799 		}
800 
801 		// get the requested cursor
802 		cursor=cont->getCursor(id);
803 
804 	} else {
805 
806 		// find an available cursor
807 		cursor=cont->getCursor();
808 	}
809 
810 	cont->raiseDebugMessageEvent("done getting a cursor");
811 	return cursor;
812 }
813 
noAvailableCursors(uint16_t command)814 void sqlrprotocol_sqlrclient::noAvailableCursors(uint16_t command) {
815 	debugFunction();
816 
817 	// If no cursor was available, the client
818 	// cound send an entire query and bind vars
819 	// before it reads the error and closes the
820 	// socket.  We have to absorb all of that
821 	// data.  We shouldn't just loop forever
822 	// though, that would provide a point of entry
823 	// for a DOS attack.  We'll read the maximum
824 	// number of bytes that could be sent.
825 	uint32_t	size=(
826 				// query size and query
827 				sizeof(uint32_t)+maxquerysize+
828 				// input bind var count
829 				sizeof(uint16_t)+
830 				// input bind vars
831 				maxbindcount*(2*sizeof(uint16_t)+
832 						maxbindnamelength)+
833 				// output bind var count
834 				sizeof(uint16_t)+
835 				// output bind vars
836 				maxbindcount*(2*sizeof(uint16_t)+
837 						maxbindnamelength)+
838 				// get column info
839 				sizeof(uint16_t)+
840 				// skip/fetch
841 				2*sizeof(uint32_t));
842 
843 	clientsock->useNonBlockingMode();
844 	unsigned char	*dummy=new unsigned char[size];
845 	clientsock->read(dummy,size,idleclienttimeout,0);
846 	clientsock->useBlockingMode();
847 	delete[] dummy;
848 
849 	// indicate that an error has occurred
850 	clientsock->write((uint16_t)ERROR_OCCURRED);
851 
852 	// send the error code
853 	clientsock->write((uint64_t)SQLR_ERROR_NOCURSORS);
854 
855 	// send the error itself
856 	uint16_t	len=charstring::length(SQLR_ERROR_NOCURSORS_STRING);
857 	clientsock->write(len);
858 	clientsock->write(SQLR_ERROR_NOCURSORS_STRING,len);
859 	clientsock->flushWriteBuffer(-1,-1);
860 }
861 
authCommand()862 bool sqlrprotocol_sqlrclient::authCommand() {
863 	debugFunction();
864 
865 	cont->raiseDebugMessageEvent("auth");
866 
867 	// get the user/password from the client
868 	if (!getUserFromClient() || !getPasswordFromClient()) {
869 		return false;
870 	}
871 
872 	// build credentials...
873 	sqlrcredentials	*cred=cont->getCredentials(
874 					userbuffer,passwordbuffer,
875 					usekrb,usetls);
876 
877 	// auth
878 	bool	success=cont->auth(cred);
879 
880 	// clean up
881 	delete cred;
882 
883 	// success
884 	if (success) {
885 		return true;
886 	}
887 
888 	// indicate that an error has occurred
889 	clientsock->write((uint16_t)ERROR_OCCURRED_DISCONNECT);
890 	clientsock->write((uint64_t)SQLR_ERROR_AUTHENTICATIONERROR);
891 	clientsock->write((uint16_t)charstring::length(
892 				SQLR_ERROR_AUTHENTICATIONERROR_STRING));
893 	clientsock->write(SQLR_ERROR_AUTHENTICATIONERROR_STRING);
894 	clientsock->flushWriteBuffer(-1,-1);
895 	return false;
896 }
897 
getUserFromClient()898 bool sqlrprotocol_sqlrclient::getUserFromClient() {
899 	debugFunction();
900 	uint32_t	size=0;
901 	ssize_t		result=clientsock->read(&size,idleclienttimeout,0);
902 	if (result!=sizeof(uint32_t)) {
903 		cont->raiseClientProtocolErrorEvent(NULL,
904 			"authentication failed: "
905 			"failed to get user size",result);
906 		return false;
907 	}
908 	if (size>=sizeof(userbuffer)) {
909 		debugstr.clear();
910 		debugstr.append("authentication failed: user size too long: ");
911 		debugstr.append(size);
912 		cont->raiseClientConnectionRefusedEvent(debugstr.getString());
913 		return false;
914 	}
915 	result=clientsock->read(userbuffer,size,idleclienttimeout,0);
916 	if ((uint32_t)result!=size) {
917 		cont->raiseClientProtocolErrorEvent(NULL,
918 			"authentication failed: "
919 			"failed to get user",result);
920 		return false;
921 	}
922 	userbuffer[size]='\0';
923 	return true;
924 }
925 
getPasswordFromClient()926 bool sqlrprotocol_sqlrclient::getPasswordFromClient() {
927 	debugFunction();
928 	uint32_t	size=0;
929 	ssize_t		result=clientsock->read(&size,idleclienttimeout,0);
930 	if (result!=sizeof(uint32_t)) {
931 		cont->raiseClientProtocolErrorEvent(NULL,
932 			"authentication failed: "
933 			"failed to get password size",result);
934 		return false;
935 	}
936 	if (size>=sizeof(passwordbuffer)) {
937 		debugstr.clear();
938 		debugstr.append("authentication failed: "
939 				"password size too long: ");
940 		debugstr.append(size);
941 		cont->raiseClientConnectionRefusedEvent(debugstr.getString());
942 		return false;
943 	}
944 	result=clientsock->read(passwordbuffer,size,idleclienttimeout,0);
945 	if ((uint32_t)result!=size) {
946 		cont->raiseClientProtocolErrorEvent(NULL,
947 			"authentication failed: "
948 			"failed to get password",result);
949 		return false;
950 	}
951 	passwordbuffer[size]='\0';
952 	return true;
953 }
954 
suspendSessionCommand()955 void sqlrprotocol_sqlrclient::suspendSessionCommand() {
956 	debugFunction();
957 
958 	cont->raiseDebugMessageEvent("suspending session...");
959 
960 	// suspend the session
961 	const char	*unixsocketname=NULL;
962 	uint16_t	inetportnumber=0;
963 	cont->suspendSession(&unixsocketname,&inetportnumber);
964 	uint16_t	unixsocketsize=charstring::length(unixsocketname);
965 
966 	// pass the socket info to the client
967 	cont->raiseDebugMessageEvent("passing socket info to client...");
968 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
969 	clientsock->write(unixsocketsize);
970 	if (unixsocketsize) {
971 		clientsock->write(unixsocketname,unixsocketsize);
972 	}
973 	clientsock->write(inetportnumber);
974 	clientsock->flushWriteBuffer(-1,-1);
975 	cont->raiseDebugMessageEvent("done passing socket info to client");
976 
977 	cont->raiseDebugMessageEvent("done suspending session");
978 }
979 
pingCommand()980 void sqlrprotocol_sqlrclient::pingCommand() {
981 	debugFunction();
982 	cont->raiseDebugMessageEvent("ping");
983 	bool	pingresult=cont->ping();
984 	if (pingresult) {
985 		cont->raiseDebugMessageEvent("ping succeeded");
986 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
987 		clientsock->flushWriteBuffer(-1,-1);
988 	} else {
989 		cont->raiseDebugMessageEvent("ping failed");
990 		returnError(false);
991 	}
992 	if (!pingresult) {
993 		cont->reLogIn();
994 	}
995 }
996 
identifyCommand()997 void sqlrprotocol_sqlrclient::identifyCommand() {
998 	debugFunction();
999 
1000 	cont->raiseDebugMessageEvent("identify");
1001 
1002 	// get the identification
1003 	const char	*ident=cont->identify();
1004 
1005 	// send it to the client
1006 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1007 	uint16_t	idlen=charstring::length(ident);
1008 	clientsock->write(idlen);
1009 	clientsock->write(ident,idlen);
1010 	clientsock->flushWriteBuffer(-1,-1);
1011 }
1012 
autoCommitCommand()1013 void sqlrprotocol_sqlrclient::autoCommitCommand() {
1014 	debugFunction();
1015 	cont->raiseDebugMessageEvent("autocommit...");
1016 	bool	on;
1017 	ssize_t	result=clientsock->read(&on,idleclienttimeout,0);
1018 	if (result!=sizeof(bool)) {
1019 		cont->raiseClientProtocolErrorEvent(NULL,
1020 				"get autocommit failed: "
1021 				"failed to get autocommit setting",result);
1022 		return;
1023 	}
1024 	bool	success=false;
1025 	if (on) {
1026 		cont->raiseDebugMessageEvent("autocommit on");
1027 		success=cont->autoCommitOn();
1028 	} else {
1029 		cont->raiseDebugMessageEvent("autocommit off");
1030 		success=cont->autoCommitOff();
1031 	}
1032 	if (success) {
1033 		cont->raiseDebugMessageEvent("succeeded");
1034 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1035 		clientsock->flushWriteBuffer(-1,-1);
1036 	} else {
1037 		cont->raiseDebugMessageEvent("failed");
1038 		returnError(false);
1039 	}
1040 }
1041 
beginCommand()1042 void sqlrprotocol_sqlrclient::beginCommand() {
1043 	debugFunction();
1044 	cont->raiseDebugMessageEvent("begin...");
1045 	if (cont->begin()) {
1046 		cont->raiseDebugMessageEvent("succeeded");
1047 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1048 		clientsock->flushWriteBuffer(-1,-1);
1049 	} else {
1050 		cont->raiseDebugMessageEvent("failed");
1051 		returnError(false);
1052 	}
1053 }
1054 
commitCommand()1055 void sqlrprotocol_sqlrclient::commitCommand() {
1056 	debugFunction();
1057 	cont->raiseDebugMessageEvent("commit...");
1058 	if (cont->commit()) {
1059 		cont->raiseDebugMessageEvent("succeeded");
1060 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1061 		clientsock->flushWriteBuffer(-1,-1);
1062 	} else {
1063 		cont->raiseDebugMessageEvent("failed");
1064 		returnError(false);
1065 	}
1066 }
1067 
rollbackCommand()1068 void sqlrprotocol_sqlrclient::rollbackCommand() {
1069 	debugFunction();
1070 	cont->raiseDebugMessageEvent("rollback...");
1071 	if (cont->rollback()) {
1072 		cont->raiseDebugMessageEvent("succeeded");
1073 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1074 		clientsock->flushWriteBuffer(-1,-1);
1075 	} else {
1076 		cont->raiseDebugMessageEvent("failed");
1077 		returnError(false);
1078 	}
1079 }
1080 
dbVersionCommand()1081 void sqlrprotocol_sqlrclient::dbVersionCommand() {
1082 	debugFunction();
1083 
1084 	cont->raiseDebugMessageEvent("db version");
1085 
1086 	// get the db version
1087 	const char	*dbversion=cont->dbVersion();
1088 
1089 	// send it to the client
1090 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1091 	uint16_t	dbvlen=charstring::length(dbversion);
1092 	clientsock->write(dbvlen);
1093 	clientsock->write(dbversion,dbvlen);
1094 	clientsock->flushWriteBuffer(-1,-1);
1095 }
1096 
bindFormatCommand()1097 void sqlrprotocol_sqlrclient::bindFormatCommand() {
1098 	debugFunction();
1099 
1100 	cont->raiseDebugMessageEvent("bind format");
1101 
1102 	// get the bind format
1103 	const char	*bf=cont->bindFormat();
1104 
1105 	// send it to the client
1106 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1107 	uint16_t	bflen=charstring::length(bf);
1108 	clientsock->write(bflen);
1109 	clientsock->write(bf,bflen);
1110 	clientsock->flushWriteBuffer(-1,-1);
1111 }
1112 
serverVersionCommand()1113 void sqlrprotocol_sqlrclient::serverVersionCommand() {
1114 	debugFunction();
1115 
1116 	cont->raiseDebugMessageEvent("server version");
1117 
1118 	// get the server version
1119 	const char	*svrversion=SQLR_VERSION;
1120 
1121 	// send it to the client
1122 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1123 	uint16_t	svrvlen=charstring::length(svrversion);
1124 	clientsock->write(svrvlen);
1125 	clientsock->write(svrversion,svrvlen);
1126 	clientsock->flushWriteBuffer(-1,-1);
1127 }
1128 
selectDatabaseCommand()1129 void sqlrprotocol_sqlrclient::selectDatabaseCommand() {
1130 	debugFunction();
1131 
1132 	cont->raiseDebugMessageEvent("select database");
1133 
1134 	// get length of db parameter
1135 	uint32_t	dblen;
1136 	ssize_t		result=clientsock->read(&dblen,idleclienttimeout,0);
1137 	if (result!=sizeof(uint32_t)) {
1138 		clientsock->write(false);
1139 		cont->raiseClientProtocolErrorEvent(NULL,
1140 				"select database failed: "
1141 				"failed to get db length",result);
1142 		return;
1143 	}
1144 
1145 	// bounds checking
1146 	if (dblen>maxquerysize) {
1147 		clientsock->write(false);
1148 		debugstr.clear();
1149 		debugstr.append("select database failed: "
1150 				"client sent bad db length: ");
1151 		debugstr.append(dblen);
1152 		cont->raiseClientProtocolErrorEvent(NULL,debugstr.getString(),1);
1153 		return;
1154 	}
1155 
1156 	// read the db parameter into the buffer
1157 	char	*db=new char[dblen+1];
1158 	if (dblen) {
1159 		result=clientsock->read(db,dblen,idleclienttimeout,0);
1160 		if ((uint32_t)result!=dblen) {
1161 			clientsock->write(false);
1162 			clientsock->flushWriteBuffer(-1,-1);
1163 			delete[] db;
1164 			cont->raiseClientProtocolErrorEvent(NULL,
1165 				"select database failed: "
1166 				"failed to get database name",result);
1167 			return;
1168 		}
1169 	}
1170 	db[dblen]='\0';
1171 
1172 	// Select the db and send back the result.
1173 	if (cont->selectDatabase(db)) {
1174 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1175 		clientsock->flushWriteBuffer(-1,-1);
1176 	} else {
1177 		returnError(false);
1178 	}
1179 
1180 	delete[] db;
1181 
1182 	return;
1183 }
1184 
getCurrentDatabaseCommand()1185 void sqlrprotocol_sqlrclient::getCurrentDatabaseCommand() {
1186 	debugFunction();
1187 
1188 	cont->raiseDebugMessageEvent("get current database");
1189 
1190 	// get the current database
1191 	char	*currentdb=cont->getCurrentDatabase();
1192 
1193 	// send it to the client
1194 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1195 	uint16_t	currentdbsize=charstring::length(currentdb);
1196 	clientsock->write(currentdbsize);
1197 	clientsock->write(currentdb,currentdbsize);
1198 	clientsock->flushWriteBuffer(-1,-1);
1199 
1200 	// clean up
1201 	delete[] currentdb;
1202 }
1203 
getCurrentSchemaCommand()1204 void sqlrprotocol_sqlrclient::getCurrentSchemaCommand() {
1205 	debugFunction();
1206 
1207 	cont->raiseDebugMessageEvent("get current schema");
1208 
1209 	// get the current schema
1210 	char	*currentschema=cont->getCurrentSchema();
1211 
1212 	// send it to the client
1213 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1214 	uint16_t	currentschemasize=charstring::length(currentschema);
1215 	clientsock->write(currentschemasize);
1216 	clientsock->write(currentschema,currentschemasize);
1217 	clientsock->flushWriteBuffer(-1,-1);
1218 
1219 	// clean up
1220 	delete[] currentschema;
1221 }
1222 
getLastInsertIdCommand()1223 void sqlrprotocol_sqlrclient::getLastInsertIdCommand() {
1224 	debugFunction();
1225 	cont->raiseDebugMessageEvent("getting last insert id...");
1226 	uint64_t	id;
1227 	if (cont->getLastInsertId(&id)) {
1228 		cont->raiseDebugMessageEvent("get last insert id succeeded");
1229 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1230 		clientsock->write(id);
1231 		clientsock->flushWriteBuffer(-1,-1);
1232 	} else {
1233 		cont->raiseDebugMessageEvent("get last insert id failed");
1234 		returnError(false);
1235 	}
1236 }
1237 
dbHostNameCommand()1238 void sqlrprotocol_sqlrclient::dbHostNameCommand() {
1239 	debugFunction();
1240 
1241 	cont->raiseDebugMessageEvent("getting db host name");
1242 
1243 	const char	*hostname=cont->dbHostName();
1244 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1245 	uint16_t	hostnamelen=charstring::length(hostname);
1246 	clientsock->write(hostnamelen);
1247 	clientsock->write(hostname,hostnamelen);
1248 	clientsock->flushWriteBuffer(-1,-1);
1249 }
1250 
dbIpAddressCommand()1251 void sqlrprotocol_sqlrclient::dbIpAddressCommand() {
1252 	debugFunction();
1253 
1254 	cont->raiseDebugMessageEvent("getting db host name");
1255 
1256 	const char	*ipaddress=cont->dbIpAddress();
1257 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1258 	uint16_t	ipaddresslen=charstring::length(ipaddress);
1259 	clientsock->write(ipaddresslen);
1260 	clientsock->write(ipaddress,ipaddresslen);
1261 	clientsock->flushWriteBuffer(-1,-1);
1262 }
1263 
newQueryCommand(sqlrservercursor * cursor)1264 bool sqlrprotocol_sqlrclient::newQueryCommand(sqlrservercursor *cursor) {
1265 	debugFunction();
1266 
1267 	cont->raiseDebugMessageEvent("new query");
1268 
1269 	// if we're using a custom cursor then close it
1270 	// FIXME: push up?
1271 	sqlrservercursor	*customcursor=cursor->getCustomQueryCursor();
1272 	if (customcursor) {
1273 		customcursor->close();
1274 		cursor->clearCustomQueryCursor();
1275 	}
1276 
1277 	// get the client info and query from the client
1278 	bool	success=(getClientInfo(cursor) && getQuery(cursor));
1279 
1280 	// do we need to use a custom query handler for this query?
1281 	if (success) {
1282 		cursor=cont->useCustomQueryCursor(cursor);
1283 	}
1284 
1285 	// get binds and whether to get column info
1286 	if (success) {
1287 		success=(getInputBinds(cursor) &&
1288 				getOutputBinds(cursor) &&
1289 				getInputOutputBinds(cursor) &&
1290 				getSendColumnInfo());
1291 	}
1292 
1293 	if (success) {
1294 		return processQueryOrBindCursor(cursor,
1295 				SQLRCLIENTQUERYTYPE_QUERY,
1296 				SQLRSERVERLISTFORMAT_NULL,
1297 				false,false);
1298 	}
1299 
1300 	// The client is apparently sending us something we
1301 	// can't handle.  Return an error if there was one,
1302 	// instruct the client to disconnect and return false
1303 	// to end the session on this side.
1304 	if (cont->getErrorNumber(cursor)) {
1305 		returnError(cursor,true);
1306 	}
1307 	cont->raiseDebugMessageEvent("new query failed");
1308 	return false;
1309 }
1310 
reExecuteQueryCommand(sqlrservercursor * cursor)1311 bool sqlrprotocol_sqlrclient::reExecuteQueryCommand(sqlrservercursor *cursor) {
1312 	debugFunction();
1313 
1314 	cont->raiseDebugMessageEvent("rexecute query");
1315 
1316 	// if we're using a custom cursor then operate on it
1317 	// FIXME: push up?
1318 	sqlrservercursor	*customcursor=cursor->getCustomQueryCursor();
1319 	if (customcursor) {
1320 		cursor=customcursor;
1321 	}
1322 
1323 	// get binds and whether to get column info
1324 	if (getInputBinds(cursor) &&
1325 			getOutputBinds(cursor) &&
1326 			getInputOutputBinds(cursor) &&
1327 			getSendColumnInfo()) {
1328 		return processQueryOrBindCursor(cursor,
1329 				SQLRCLIENTQUERYTYPE_QUERY,
1330 				SQLRSERVERLISTFORMAT_NULL,
1331 				true,false);
1332 	}
1333 
1334 	// The client is apparently sending us something we
1335 	// can't handle.  Return an error if there was one,
1336 	// instruct the client to disconnect and return false
1337 	// to end the session on this side.
1338 	if (cont->getErrorNumber(cursor)) {
1339 		returnError(cursor,true);
1340 	}
1341 	cont->raiseDebugMessageEvent("reexecute query failed");
1342 	return false;
1343 }
1344 
nextResultSetCommand(sqlrservercursor * cursor)1345 bool sqlrprotocol_sqlrclient::nextResultSetCommand(sqlrservercursor *cursor) {
1346 	debugFunction();
1347 
1348 	cont->raiseDebugMessageEvent("nextResultSet");
1349 
1350 	// if we're using a custom cursor then operate on it
1351 	// FIXME: push up?
1352 	sqlrservercursor	*customcursor=cursor->getCustomQueryCursor();
1353 	if (customcursor) {
1354 		cursor=customcursor;
1355 	}
1356 
1357 	bool nextresultsetavailable;
1358 	if (cont->nextResultSet(cursor,&nextresultsetavailable)) {
1359 		cont->raiseDebugMessageEvent("nextResultSet succeeded");
1360 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1361 		clientsock->write(nextresultsetavailable);
1362 		clientsock->flushWriteBuffer(-1,-1);
1363 		if (nextresultsetavailable) {
1364 			cont->incrementNextResultSetAvailableCount();
1365 		}
1366 		cont->incrementNextResultSetCount();
1367 		return true;
1368 	}
1369 
1370 	cont->raiseDebugMessageEvent("nextResultSet failed");
1371 	returnError(!cont->getLiveConnection());
1372 	cont->incrementNextResultSetCount();
1373 	return false;
1374 }
1375 
fetchFromBindCursorCommand(sqlrservercursor * cursor)1376 bool sqlrprotocol_sqlrclient::fetchFromBindCursorCommand(
1377 					sqlrservercursor *cursor) {
1378 	debugFunction();
1379 
1380 	cont->raiseDebugMessageEvent("fetch from bind cursor");
1381 
1382 	// if we're using a custom cursor then close it
1383 	// FIXME: push up?
1384 	sqlrservercursor	*customcursor=cursor->getCustomQueryCursor();
1385 	if (customcursor) {
1386 		customcursor->close();
1387 		cursor->clearCustomQueryCursor();
1388 	}
1389 
1390 	// get whether to get column info
1391 	if (getSendColumnInfo()) {
1392 		return processQueryOrBindCursor(cursor,
1393 				SQLRCLIENTQUERYTYPE_QUERY,
1394 				SQLRSERVERLISTFORMAT_NULL,
1395 				false,true);
1396 	}
1397 
1398 	// The client is apparently sending us something we
1399 	// can't handle.  Return an error if there was one,
1400 	// instruct the client to disconnect and return false
1401 	// to end the session on this side.
1402 	if (cont->getErrorNumber(cursor)) {
1403 		returnError(cursor,true);
1404 	}
1405 	cont->raiseDebugMessageEvent("failed to fetch from bind cursor");
1406 	return false;
1407 }
1408 
processQueryOrBindCursor(sqlrservercursor * cursor,sqlrclientquerytype_t querytype,sqlrserverlistformat_t listformat,bool reexecute,bool bindcursor)1409 bool sqlrprotocol_sqlrclient::processQueryOrBindCursor(
1410 					sqlrservercursor *cursor,
1411 					sqlrclientquerytype_t querytype,
1412 					sqlrserverlistformat_t listformat,
1413 					bool reexecute,
1414 					bool bindcursor) {
1415 	debugFunction();
1416 
1417 	// loop here to handle down databases
1418 	for (;;) {
1419 
1420 		// process the query or bind cursor...
1421 		bool	success=false;
1422 		if (bindcursor) {
1423 			success=cont->fetchFromBindCursor(cursor);
1424 		} else if (reexecute) {
1425 			success=cont->executeQuery(cursor,true,true,true,true);
1426 		} else {
1427 			success=(cont->prepareQuery(cursor,
1428 					cont->getQueryBuffer(cursor),
1429 					cont->getQueryLength(cursor),
1430 					true,true,true) &&
1431 				cont->executeQuery(cursor,true,true,true,true));
1432 		}
1433 
1434 		// get the skip and fetch parameters here so everything can be
1435 		// done in one round trip without relying on buffering
1436 		if (success) {
1437 			success=getSkipAndFetch(true,cursor);
1438 		}
1439 
1440 		if (success) {
1441 
1442 			// success...
1443 
1444 			cont->raiseDebugMessageEvent("process query succeeded");
1445 
1446 			// indicate that no error has occurred
1447 			clientsock->write((uint16_t)NO_ERROR_OCCURRED);
1448 
1449 			// send the client the id of the cursor
1450 			// that it's going to use so it can request
1451 			// it again later for re-execute
1452 			clientsock->write(cont->getId(cursor));
1453 
1454 			// tell the client that this is not a
1455 			// suspended result set
1456 			clientsock->write((uint16_t)NO_SUSPENDED_RESULT_SET);
1457 
1458 			// remap columns
1459 			switch (querytype) {
1460 				case SQLRCLIENTQUERYTYPE_DATABASE_LIST:
1461 					cont->setDatabaseListColumnMap(
1462 								listformat);
1463 					break;
1464 				case SQLRCLIENTQUERYTYPE_SCHEMA_LIST:
1465 					cont->setSchemaListColumnMap(
1466 								listformat);
1467 					break;
1468 				case SQLRCLIENTQUERYTYPE_TABLE_LIST:
1469 				case SQLRCLIENTQUERYTYPE_TABLE_LIST_2:
1470 					cont->setTableListColumnMap(
1471 								listformat);
1472 					break;
1473 				case SQLRCLIENTQUERYTYPE_TABLE_TYPE_LIST:
1474 					cont->setTableListColumnMap(
1475 								listformat);
1476 					break;
1477 				case SQLRCLIENTQUERYTYPE_COLUMN_LIST:
1478 					cont->setColumnListColumnMap(
1479 								listformat);
1480 					break;
1481 				case SQLRCLIENTQUERYTYPE_PRIMARY_KEY_LIST:
1482 					cont->setPrimaryKeyListColumnMap(
1483 								listformat);
1484 					break;
1485 				case SQLRCLIENTQUERYTYPE_KEY_AND_INDEX_LIST:
1486 					cont->setKeyAndIndexListColumnMap(
1487 								listformat);
1488 					break;
1489 				case SQLRCLIENTQUERYTYPE_PROCEDURE_BIND_AND_COLUMN_LIST:
1490 					cont->setProcedureBindAndColumnListColumnMap(
1491 								listformat);
1492 					break;
1493 				case SQLRCLIENTQUERYTYPE_TYPE_INFO_LIST:
1494 					cont->setTypeInfoListColumnMap(
1495 								listformat);
1496 					break;
1497 				case SQLRCLIENTQUERYTYPE_PROCEDURE_LIST:
1498 					cont->setProcedureListColumnMap(
1499 								listformat);
1500 					break;
1501 				default:
1502 					break;
1503 			}
1504 
1505 			// send a result set header
1506 			returnResultSetHeader(cursor);
1507 
1508 			// return the result set
1509 			return returnResultSetData(cursor,false,false);
1510 
1511 		} else {
1512 
1513 			// an error occurred...
1514 
1515 			// is the db still up?
1516 			bool	dbup=cont->getLiveConnection(cursor);
1517 
1518 			// if the db is still up, or if we're not configured
1519 			// to wait for them if they're down, then return the
1520 			// error
1521 			if (dbup || !waitfordowndb) {
1522 
1523 				// return the error
1524 				returnError(cursor,false);
1525 			}
1526 
1527 			// if the error was a dead connection
1528 			// then re-establish the connection
1529 			if (!dbup) {
1530 
1531 				cont->raiseDebugMessageEvent(
1532 						"database is down...");
1533 
1534 				cont->raiseDbErrorEvent(cursor,
1535 						cont->getErrorBuffer(cursor));
1536 
1537 				cont->reLogIn();
1538 
1539 				// if we're waiting for down databases then
1540 				// loop back and try the query again
1541 				if (waitfordowndb) {
1542 					continue;
1543 				}
1544 			}
1545 			return true;
1546 		}
1547 	}
1548 }
1549 
getClientInfo(sqlrservercursor * cursor)1550 bool sqlrprotocol_sqlrclient::getClientInfo(sqlrservercursor *cursor) {
1551 	debugFunction();
1552 
1553 	cont->raiseDebugMessageEvent("getting client info...");
1554 
1555 	// init
1556 	clientinfo[0]='\0';
1557 	clientinfolen=0;
1558 
1559 	// get the length of the client info
1560 	ssize_t	result=clientsock->read(&clientinfolen);
1561 	if (result!=sizeof(uint64_t)) {
1562 		cont->raiseClientProtocolErrorEvent(cursor,
1563 				"get client info failed: "
1564 				"failed to get clientinfo length",result);
1565 		return false;
1566 	}
1567 
1568 	// bounds checking
1569 	if (clientinfolen>maxclientinfolength) {
1570 
1571 		stringbuffer	err;
1572 		err.append(SQLR_ERROR_MAXCLIENTINFOLENGTH_STRING);
1573 		err.append(" (")->append(clientinfolen)->append('>');
1574 		err.append(maxclientinfolength)->append(')');
1575 		cont->setError(cursor,err.getString(),
1576 				SQLR_ERROR_MAXCLIENTINFOLENGTH,true);
1577 
1578 		debugstr.clear();
1579 		debugstr.append("get client info failed: "
1580 				"client sent bad client info size: ");
1581 		debugstr.append(clientinfolen);
1582 		cont->raiseClientProtocolErrorEvent(cursor,debugstr.getString(),1);
1583 		return false;
1584 	}
1585 
1586 	// read the client info into the buffer
1587 	result=clientsock->read(clientinfo,clientinfolen);
1588 	if ((uint64_t)result!=clientinfolen) {
1589 		cont->raiseClientProtocolErrorEvent(cursor,
1590 				"get client info failed: "
1591 				"failed to get client info",result);
1592 		return false;
1593 	}
1594 	clientinfo[clientinfolen]='\0';
1595 
1596 	if (cont->logEnabled() || cont->notificationsEnabled()) {
1597 		debugstr.clear();
1598 		debugstr.append("clientinfolen: ")->append(clientinfolen);
1599 		cont->raiseDebugMessageEvent(debugstr.getString());
1600 		debugstr.clear();
1601 		debugstr.append("clientinfo: ")->append(clientinfo);
1602 		cont->raiseDebugMessageEvent(debugstr.getString());
1603 		cont->raiseDebugMessageEvent("getting clientinfo succeeded");
1604 	}
1605 
1606 	// FIXME: push up?
1607 	// update the stats with the client info
1608 	cont->setClientInfo(clientinfo,clientinfolen);
1609 
1610 	return true;
1611 }
1612 
getQuery(sqlrservercursor * cursor)1613 bool sqlrprotocol_sqlrclient::getQuery(sqlrservercursor *cursor) {
1614 	debugFunction();
1615 
1616 	cont->raiseDebugMessageEvent("getting query...");
1617 
1618 	// init
1619 	uint32_t	querylength=0;
1620 	char		*querybuffer=cont->getQueryBuffer(cursor);
1621 	querybuffer[0]='\0';
1622 	cont->setQueryLength(cursor,0);
1623 
1624 	// get the length of the query
1625 	ssize_t	result=clientsock->read(&querylength,idleclienttimeout,0);
1626 	if (result!=sizeof(uint32_t)) {
1627 		cont->raiseClientProtocolErrorEvent(cursor,
1628 				"get query failed: "
1629 				"failed to get query length",result);
1630 		return false;
1631 	}
1632 
1633 	// bounds checking
1634 	if (querylength>maxquerysize) {
1635 
1636 		stringbuffer	err;
1637 		err.append(SQLR_ERROR_MAXQUERYLENGTH_STRING);
1638 		err.append(" (")->append(querylength)->append('>');
1639 		err.append(maxquerysize)->append(')');
1640 		cont->setError(cursor,err.getString(),
1641 				SQLR_ERROR_MAXQUERYLENGTH,true);
1642 
1643 		debugstr.clear();
1644 		debugstr.append("get query failed: "
1645 				"client sent bad query length: ");
1646 		debugstr.append(querylength);
1647 		cont->raiseClientProtocolErrorEvent(cursor,
1648 						debugstr.getString(),1);
1649 
1650 		return false;
1651 	}
1652 
1653 	// read the query into the buffer
1654 	result=clientsock->read(querybuffer,querylength,idleclienttimeout,0);
1655 	if ((uint32_t)result!=querylength) {
1656 
1657 		querybuffer[0]='\0';
1658 
1659 		cont->raiseClientProtocolErrorEvent(cursor,
1660 				"get query failed: "
1661 				"failed to get query",result);
1662 		return false;
1663 	}
1664 
1665 	// update query buffer and length
1666 	querybuffer[querylength]='\0';
1667 	cont->setQueryLength(cursor,querylength);
1668 
1669 	if (cont->logEnabled() || cont->notificationsEnabled()) {
1670 		debugstr.clear();
1671 		debugstr.append("querylength: ")->append(querylength);
1672 		cont->raiseDebugMessageEvent(debugstr.getString());
1673 		debugstr.clear();
1674 		debugstr.append("query: ")->append(querybuffer);
1675 		cont->raiseDebugMessageEvent(debugstr.getString());
1676 		cont->raiseDebugMessageEvent("getting query succeeded");
1677 	}
1678 
1679 	// FIXME: push up?
1680 	// update the stats with the current query
1681 	cont->setCurrentQuery(querybuffer,querylength);
1682 
1683 	return true;
1684 }
1685 
getInputBinds(sqlrservercursor * cursor)1686 bool sqlrprotocol_sqlrclient::getInputBinds(sqlrservercursor *cursor) {
1687 	debugFunction();
1688 
1689 	cont->raiseDebugMessageEvent("getting input binds...");
1690 
1691 	// get the number of input bind variable/values
1692 	uint16_t	inbindcount=0;
1693 	if (!getBindVarCount(cursor,&inbindcount)) {
1694 		return false;
1695 	}
1696 	cont->setInputBindCount(cursor,inbindcount);
1697 
1698 	// get the input bind buffers
1699 	memorypool		*bindpool=cont->getBindPool(cursor);
1700 	sqlrserverbindvar	*inbinds=cont->getInputBinds(cursor);
1701 
1702 	// fill the buffers
1703 	for (uint16_t i=0; i<inbindcount && i<maxbindcount; i++) {
1704 
1705 		sqlrserverbindvar	*bv=&(inbinds[i]);
1706 
1707 		// get the variable name and type
1708 		if (!(getBindVarName(cursor,bv,bindpool) &&
1709 					getBindVarType(bv))) {
1710 			return false;
1711 		}
1712 
1713 		// get the value
1714 		if (bv->type==SQLRSERVERBINDVARTYPE_NULL) {
1715 			getNullBind(bv,bindpool);
1716 		} else if (bv->type==SQLRSERVERBINDVARTYPE_STRING) {
1717 			if (!getStringBind(cursor,bv,bindpool)) {
1718 				return false;
1719 			}
1720 		} else if (bv->type==SQLRSERVERBINDVARTYPE_INTEGER) {
1721 			if (!getIntegerBind(bv)) {
1722 				return false;
1723 			}
1724 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DOUBLE) {
1725 			if (!getDoubleBind(bv)) {
1726 				return false;
1727 			}
1728 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DATE) {
1729 			if (!getDateBind(bv,bindpool)) {
1730 				return false;
1731 			}
1732 		} else if (bv->type==SQLRSERVERBINDVARTYPE_BLOB) {
1733 			if (!getLobBind(cursor,bv,bindpool)) {
1734 				return false;
1735 			}
1736 		} else if (bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
1737 			if (!getLobBind(cursor,bv,bindpool)) {
1738 				return false;
1739 			}
1740 		}
1741 	}
1742 
1743 	cont->raiseDebugMessageEvent("done getting input binds");
1744 	return true;
1745 }
1746 
getOutputBinds(sqlrservercursor * cursor)1747 bool sqlrprotocol_sqlrclient::getOutputBinds(sqlrservercursor *cursor) {
1748 	debugFunction();
1749 
1750 	cont->raiseDebugMessageEvent("getting output binds...");
1751 
1752 	// get the number of output bind variable/values
1753 	uint16_t	outbindcount=0;
1754 	if (!getBindVarCount(cursor,&outbindcount)) {
1755 		return false;
1756 	}
1757 	cont->setOutputBindCount(cursor,outbindcount);
1758 
1759 	// get the output bind buffers
1760 	memorypool		*bindpool=cont->getBindPool(cursor);
1761 	sqlrserverbindvar	*outbinds=cont->getOutputBinds(cursor);
1762 
1763 	// fill the buffers
1764 	for (uint16_t i=0; i<outbindcount && i<maxbindcount; i++) {
1765 
1766 		sqlrserverbindvar	*bv=&(outbinds[i]);
1767 
1768 		// get the variable name and type
1769 		if (!(getBindVarName(cursor,bv,bindpool) &&
1770 					getBindVarType(bv))) {
1771 			return false;
1772 		}
1773 
1774 		// get the size of the value
1775 		if (bv->type==SQLRSERVERBINDVARTYPE_STRING) {
1776 			bv->value.stringval=NULL;
1777 			if (!getBindSize(cursor,bv,&maxstringbindvaluelength)) {
1778 				return false;
1779 			}
1780 			// This must be a allocated and zeroed because oracle
1781 			// gets angry if these aren't initialized to NULL's.
1782 			// It's possible that just the first character needs to
1783 			// be NULL, but for now I'm just going to go ahead and
1784 			// allocate/zero.
1785 			bv->value.stringval=
1786 				(char *)bindpool->allocate(bv->valuesize+1);
1787 			bytestring::zero(bv->value.stringval,bv->valuesize+1);
1788 			cont->raiseDebugMessageEvent("STRING");
1789 		} else if (bv->type==SQLRSERVERBINDVARTYPE_INTEGER) {
1790 			cont->raiseDebugMessageEvent("INTEGER");
1791 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DOUBLE) {
1792 			cont->raiseDebugMessageEvent("DOUBLE");
1793 			// these don't typically get set, but they get used
1794 			// when building debug strings, so we need to
1795 			// initialize them
1796 			bv->value.doubleval.precision=0;
1797 			bv->value.doubleval.scale=0;
1798 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DATE) {
1799 			cont->raiseDebugMessageEvent("DATE");
1800 			bv->value.dateval.year=0;
1801 			bv->value.dateval.month=0;
1802 			bv->value.dateval.day=0;
1803 			bv->value.dateval.hour=0;
1804 			bv->value.dateval.minute=0;
1805 			bv->value.dateval.second=0;
1806 			bv->value.dateval.microsecond=0;
1807 			bv->value.dateval.tz=NULL;
1808 			bv->value.dateval.isnegative=false;
1809 			// allocate enough space to store the date/time string
1810 			// or whatever buffer a child might need to store a
1811 			// date 512 bytes ought to be enough
1812 			bv->value.dateval.buffersize=512;
1813 			bv->value.dateval.buffer=
1814 				(char *)bindpool->
1815 					allocate(bv->value.dateval.buffersize);
1816 		} else if (bv->type==SQLRSERVERBINDVARTYPE_BLOB ||
1817 					bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
1818 			if (!getBindSize(cursor,bv,&maxlobbindvaluelength)) {
1819 				return false;
1820 			}
1821 			if (bv->type==SQLRSERVERBINDVARTYPE_BLOB) {
1822 				cont->raiseDebugMessageEvent("BLOB");
1823 			} else if (bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
1824 				cont->raiseDebugMessageEvent("CLOB");
1825 			}
1826 		} else if (bv->type==SQLRSERVERBINDVARTYPE_CURSOR) {
1827 			cont->raiseDebugMessageEvent("CURSOR");
1828 			sqlrservercursor	*curs=cont->getCursor();
1829 			if (!curs) {
1830 				// FIXME: set error here
1831 				return false;
1832 			}
1833 			cont->setState(curs,SQLRCURSORSTATE_BUSY);
1834 			bv->value.cursorid=cont->getId(curs);
1835 		}
1836 
1837 		// init the null indicator
1838 		bv->isnull=cont->nonNullBindValue();
1839 	}
1840 
1841 	cont->raiseDebugMessageEvent("done getting output binds");
1842 	return true;
1843 }
1844 
getInputOutputBinds(sqlrservercursor * cursor)1845 bool sqlrprotocol_sqlrclient::getInputOutputBinds(sqlrservercursor *cursor) {
1846 	debugFunction();
1847 
1848 	if (protocolversion<2) {
1849 		cont->raiseDebugMessageEvent("not getting input/output binds "
1850 						"(client protocol too old)");
1851 		return true;
1852 	}
1853 
1854 	cont->raiseDebugMessageEvent("getting input/output binds...");
1855 
1856 	// get the number of input/output bind variable/values
1857 	uint16_t	inoutbindcount=0;
1858 	if (!getBindVarCount(cursor,&inoutbindcount)) {
1859 		return false;
1860 	}
1861 	cont->setInputOutputBindCount(cursor,inoutbindcount);
1862 
1863 	// get the input/output bind buffers
1864 	memorypool		*bindpool=cont->getBindPool(cursor);
1865 	sqlrserverbindvar	*inoutbinds=cont->getInputOutputBinds(cursor);
1866 
1867 	// fill the buffers
1868 	for (uint16_t i=0; i<inoutbindcount && i<maxbindcount; i++) {
1869 
1870 		sqlrserverbindvar	*bv=&(inoutbinds[i]);
1871 
1872 		// get the variable name and type
1873 		if (!(getBindVarName(cursor,bv,bindpool) &&
1874 					getBindVarType(bv))) {
1875 			return false;
1876 		}
1877 
1878 		// get the size of the value
1879 		if (bv->type==SQLRSERVERBINDVARTYPE_NULL) {
1880 			bv->type=SQLRSERVERBINDVARTYPE_STRING;
1881 			bv->value.stringval=NULL;
1882 			if (!getBindSize(cursor,bv,&maxstringbindvaluelength)) {
1883 				return false;
1884 			}
1885 			// This must be a allocated and zeroed because oracle
1886 			// gets angry if these aren't initialized to NULL's.
1887 			// It's possible that just the first character needs to
1888 			// be NULL, but for now I'm just going to go ahead and
1889 			// allocate/zero.
1890 			bv->value.stringval=
1891 				(char *)bindpool->allocate(bv->valuesize+1);
1892 			bytestring::zero(bv->value.stringval,bv->valuesize+1);
1893 			bv->isnull=cont->nullBindValue();
1894 			cont->raiseDebugMessageEvent("NULL");
1895 		} else if (bv->type==SQLRSERVERBINDVARTYPE_STRING) {
1896 			bv->value.stringval=NULL;
1897 			if (!getBindSize(cursor,bv,&maxstringbindvaluelength)) {
1898 				return false;
1899 			}
1900 			// This must be a allocated and zeroed because oracle
1901 			// gets angry if these aren't initialized to NULL's.
1902 			// It's possible that just the first character needs to
1903 			// be NULL, but for now I'm just going to go ahead and
1904 			// allocate/zero.
1905 			bv->value.stringval=
1906 				(char *)bindpool->allocate(bv->valuesize+1);
1907 			bytestring::zero(bv->value.stringval,bv->valuesize+1);
1908 
1909 			// get the bind value
1910 			ssize_t	result=clientsock->read(bv->value.stringval,
1911 							bv->valuesize,
1912 							idleclienttimeout,0);
1913 			if ((uint32_t)result!=(uint32_t)(bv->valuesize)) {
1914 				bv->value.stringval[0]='\0';
1915 				const char	*info="get binds failed: "
1916 							"failed to get bind "
1917 							"value";
1918 				cont->raiseClientProtocolErrorEvent(
1919 							cursor,info,result);
1920 				return false;
1921 			}
1922 			bv->value.stringval[bv->valuesize]='\0';
1923 			bv->isnull=cont->nonNullBindValue();
1924 			cont->raiseDebugMessageEvent("STRING");
1925 		} else if (bv->type==SQLRSERVERBINDVARTYPE_INTEGER) {
1926 
1927 			// get the bind value
1928 			ssize_t	result=clientsock->read(&(bv->value.integerval),
1929 							idleclienttimeout,0);
1930 			if (result!=sizeof(uint64_t)) {
1931 				const char	*info="get binds failed: "
1932 							"failed to get bind "
1933 							"value";
1934 				cont->raiseClientProtocolErrorEvent(
1935 							cursor,info,result);
1936 				return false;
1937 			}
1938 			bv->isnull=cont->nonNullBindValue();
1939 			cont->raiseDebugMessageEvent("INTEGER");
1940 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DOUBLE) {
1941 
1942 			// get the bind value
1943 			ssize_t	result=clientsock->read(
1944 					&(bv->value.doubleval.value),
1945 					idleclienttimeout,0);
1946 			if ((uint32_t)result!=(uint32_t)sizeof(double)) {
1947 				const char	*info="get binds failed: "
1948 							"failed to get bind "
1949 							"value";
1950 				cont->raiseClientProtocolErrorEvent(
1951 							cursor,info,result);
1952 				return false;
1953 			}
1954 
1955 			// get the precision
1956 			result=clientsock->read(
1957 					&(bv->value.doubleval.precision),
1958 					idleclienttimeout,0);
1959 			if ((uint32_t)result!=(uint32_t)sizeof(uint32_t)) {
1960 				const char	*info="get binds failed: "
1961 							"failed to get "
1962 							"precision";
1963 				cont->raiseClientProtocolErrorEvent(
1964 							cursor,info,result);
1965 				return false;
1966 			}
1967 
1968 			// get the scale
1969 			result=clientsock->read(
1970 					&(bv->value.doubleval.scale),
1971 					idleclienttimeout,0);
1972 			if ((uint32_t)result!=(uint32_t)sizeof(uint32_t)) {
1973 				const char	*info="get binds failed: "
1974 							"failed to get "
1975 							"scale";
1976 				cont->raiseClientProtocolErrorEvent(
1977 							cursor,info,result);
1978 				return false;
1979 			}
1980 
1981 			bv->isnull=cont->nonNullBindValue();
1982 			cont->raiseDebugMessageEvent("DOUBLE");
1983 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DATE) {
1984 
1985 			// get the year
1986 			ssize_t	result=clientsock->read(
1987 					&(bv->value.dateval.year),
1988 					idleclienttimeout,0);
1989 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
1990 				const char	*info="get binds failed: "
1991 							"failed to get bind "
1992 							"year";
1993 				cont->raiseClientProtocolErrorEvent(
1994 							cursor,info,result);
1995 				return false;
1996 			}
1997 
1998 			// get the month
1999 			result=clientsock->read(
2000 					&(bv->value.dateval.month),
2001 					idleclienttimeout,0);
2002 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
2003 				const char	*info="get binds failed: "
2004 							"failed to get bind "
2005 							"month";
2006 				cont->raiseClientProtocolErrorEvent(
2007 							cursor,info,result);
2008 				return false;
2009 			}
2010 
2011 			// get the day
2012 			result=clientsock->read(
2013 					&(bv->value.dateval.day),
2014 					idleclienttimeout,0);
2015 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
2016 				const char	*info="get binds failed: "
2017 							"failed to get bind "
2018 							"day";
2019 				cont->raiseClientProtocolErrorEvent(
2020 							cursor,info,result);
2021 				return false;
2022 			}
2023 
2024 			// get the hour
2025 			result=clientsock->read(
2026 					&(bv->value.dateval.hour),
2027 					idleclienttimeout,0);
2028 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
2029 				const char	*info="get binds failed: "
2030 							"failed to get bind "
2031 							"hour";
2032 				cont->raiseClientProtocolErrorEvent(
2033 							cursor,info,result);
2034 				return false;
2035 			}
2036 
2037 			// get the minute
2038 			result=clientsock->read(
2039 					&(bv->value.dateval.minute),
2040 					idleclienttimeout,0);
2041 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
2042 				const char	*info="get binds failed: "
2043 							"failed to get bind "
2044 							"minute";
2045 				cont->raiseClientProtocolErrorEvent(
2046 							cursor,info,result);
2047 				return false;
2048 			}
2049 
2050 			// get the second
2051 			result=clientsock->read(
2052 					&(bv->value.dateval.second),
2053 					idleclienttimeout,0);
2054 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
2055 				const char	*info="get binds failed: "
2056 							"failed to get bind "
2057 							"second";
2058 				cont->raiseClientProtocolErrorEvent(
2059 							cursor,info,result);
2060 				return false;
2061 			}
2062 
2063 			// get the microsecond
2064 			result=clientsock->read(
2065 					&(bv->value.dateval.microsecond),
2066 					idleclienttimeout,0);
2067 			if ((uint32_t)result!=(uint32_t)sizeof(uint32_t)) {
2068 				const char	*info="get binds failed: "
2069 							"failed to get bind "
2070 							"microsecond";
2071 				cont->raiseClientProtocolErrorEvent(
2072 							cursor,info,result);
2073 				return false;
2074 			}
2075 
2076 			// get the tz length
2077 			uint16_t	tzlen=0;
2078 			result=clientsock->read(&tzlen,idleclienttimeout,0);
2079 			if ((uint32_t)result!=(uint32_t)sizeof(uint16_t)) {
2080 				const char	*info="get binds failed: "
2081 							"failed to get bind "
2082 							"tz length";
2083 				cont->raiseClientProtocolErrorEvent(
2084 							cursor,info,result);
2085 				return false;
2086 			}
2087 
2088 			// get the tz
2089 			bv->value.dateval.tz=(char *)bindpool->allocate(tzlen);
2090 			result=clientsock->read(bv->value.dateval.tz,tzlen,
2091 						idleclienttimeout,0);
2092 			if ((uint32_t)result!=(uint32_t)tzlen) {
2093 				bv->value.dateval.tz[0]='\0';
2094 				const char	*info="get binds failed: "
2095 							"failed to get bind "
2096 							"tz";
2097 				cont->raiseClientProtocolErrorEvent(
2098 							cursor,info,result);
2099 				return false;
2100 			}
2101 
2102 			// get the is-negative flag
2103 			result=clientsock->read(&bv->value.dateval.isnegative,
2104 							idleclienttimeout,0);
2105 			if (result!=sizeof(bool)) {
2106 				const char	*info="get binds failed: "
2107 							"failed to get "
2108 							"is-negative flag";
2109 				cont->raiseClientProtocolErrorEvent(
2110 							cursor,info,result);
2111 				return false;
2112 			}
2113 
2114 			// allocate enough space to store the date/time string
2115 			// or whatever buffer a child might need to store a
2116 			// date 512 bytes ought to be enough
2117 			bv->value.dateval.buffersize=512;
2118 			bv->value.dateval.buffer=
2119 				(char *)bindpool->allocate(
2120 						bv->value.dateval.buffersize);
2121 
2122 			bv->isnull=cont->nonNullBindValue();
2123 			cont->raiseDebugMessageEvent("DATE");
2124 		} /*else if (bv->type==SQLRSERVERBINDVARTYPE_BLOB ||
2125 					bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
2126 			if (!getBindSize(cursor,bv,&maxlobbindvaluelength)) {
2127 				return false;
2128 			}
2129 			if (bv->type==SQLRSERVERBINDVARTYPE_BLOB) {
2130 				cont->raiseDebugMessageEvent("BLOB");
2131 			} else if (bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
2132 				cont->raiseDebugMessageEvent("CLOB");
2133 			}
2134 			bv->isnull=cont->nonNullBindValue();
2135 		}*/
2136 	}
2137 
2138 	cont->raiseDebugMessageEvent("done getting input/output binds");
2139 	return true;
2140 }
2141 
getBindVarCount(sqlrservercursor * cursor,uint16_t * count)2142 bool sqlrprotocol_sqlrclient::getBindVarCount(sqlrservercursor *cursor,
2143 							uint16_t *count) {
2144 	debugFunction();
2145 
2146 	// init
2147 	*count=0;
2148 
2149 	// get the number of input bind variable/values
2150 	ssize_t	result=clientsock->read(count,idleclienttimeout,0);
2151 	if (result!=sizeof(uint16_t)) {
2152 		cont->raiseClientProtocolErrorEvent(cursor,
2153 				"get binds failed: "
2154 				"failed to get bind count",result);
2155 		*count=0;
2156 		return false;
2157 	}
2158 
2159 	// bounds checking
2160 	if (*count>maxbindcount) {
2161 
2162 		stringbuffer	err;
2163 		err.append(SQLR_ERROR_MAXBINDCOUNT_STRING);
2164 		err.append(" (")->append(*count)->append('>');
2165 		err.append(maxbindcount)->append(')');
2166 		cont->setError(cursor,err.getString(),
2167 				SQLR_ERROR_MAXBINDCOUNT,true);
2168 
2169 		debugstr.clear();
2170 		debugstr.append("get binds failed: "
2171 				"client tried to send too many binds: ");
2172 		debugstr.append(*count);
2173 		cont->raiseClientProtocolErrorEvent(cursor,debugstr.getString(),1);
2174 
2175 		*count=0;
2176 		return false;
2177 	}
2178 
2179 	return true;
2180 }
2181 
getBindVarName(sqlrservercursor * cursor,sqlrserverbindvar * bv,memorypool * bindpool)2182 bool sqlrprotocol_sqlrclient::getBindVarName(sqlrservercursor *cursor,
2183 						sqlrserverbindvar *bv,
2184 						memorypool *bindpool) {
2185 	debugFunction();
2186 
2187 	// init
2188 	bv->variablesize=0;
2189 	bv->variable=NULL;
2190 
2191 	// get the variable name size
2192 	uint16_t	bindnamesize;
2193 	ssize_t		result=clientsock->read(&bindnamesize,
2194 						idleclienttimeout,0);
2195 	if (result!=sizeof(uint16_t)) {
2196 		cont->raiseClientProtocolErrorEvent(cursor,
2197 				"get binds failed: "
2198 				"failed to get variable name length",result);
2199 		return false;
2200 	}
2201 
2202 	// bounds checking
2203 	if (bindnamesize>maxbindnamelength) {
2204 
2205 		stringbuffer	err;
2206 		err.append(SQLR_ERROR_MAXBINDNAMELENGTH_STRING);
2207 		err.append(" (")->append(bindnamesize)->append('>');
2208 		err.append(maxbindnamelength)->append(')');
2209 		cont->setError(cursor,err.getString(),
2210 					SQLR_ERROR_MAXBINDNAMELENGTH,true);
2211 
2212 		debugstr.clear();
2213 		debugstr.append("get binds failed: bad variable name length: ");
2214 		debugstr.append(bindnamesize);
2215 		cont->raiseClientProtocolErrorEvent(cursor,debugstr.getString(),1);
2216 		return false;
2217 	}
2218 
2219 	// get the variable name
2220 	bv->variablesize=bindnamesize+1;
2221 	bv->variable=(char *)bindpool->allocate(bindnamesize+2);
2222 	bv->variable[0]=cont->bindFormat()[0];
2223 	result=clientsock->read(bv->variable+1,bindnamesize,
2224 					idleclienttimeout,0);
2225 	if (result!=bindnamesize) {
2226 		bv->variablesize=0;
2227 		bv->variable[0]='\0';
2228 		cont->raiseClientProtocolErrorEvent(cursor,
2229 				"get binds failed: "
2230 				"failed to get variable name",result);
2231 		return false;
2232 	}
2233 	bv->variable[bindnamesize+1]='\0';
2234 
2235 	cont->raiseDebugMessageEvent(bv->variable);
2236 
2237 	return true;
2238 }
2239 
getBindVarType(sqlrserverbindvar * bv)2240 bool sqlrprotocol_sqlrclient::getBindVarType(sqlrserverbindvar *bv) {
2241 	debugFunction();
2242 
2243 	// get the type
2244 	uint16_t	type;
2245 	ssize_t	result=clientsock->read(&type,idleclienttimeout,0);
2246 	if (result!=sizeof(uint16_t)) {
2247 		cont->raiseClientProtocolErrorEvent(NULL,
2248 				"get binds failed: "
2249 				"failed to get type",result);
2250 		return false;
2251 	}
2252 	bv->type=(sqlrserverbindvartype_t)type;
2253 	return true;
2254 }
2255 
getBindSize(sqlrservercursor * cursor,sqlrserverbindvar * bv,uint32_t * maxsize)2256 bool sqlrprotocol_sqlrclient::getBindSize(sqlrservercursor *cursor,
2257 						sqlrserverbindvar *bv,
2258 						uint32_t *maxsize) {
2259 	debugFunction();
2260 
2261 	// init
2262 	bv->valuesize=0;
2263 
2264 	// get the size of the value
2265 	ssize_t	result=clientsock->read(&(bv->valuesize),idleclienttimeout,0);
2266 	if (result!=sizeof(uint32_t)) {
2267 		bv->valuesize=0;
2268 		cont->raiseClientProtocolErrorEvent(cursor,
2269 				"get binds failed: "
2270 				"failed to get bind value length",result);
2271 		return false;
2272 	}
2273 
2274 	// bounds checking
2275 	if (bv->valuesize>*maxsize) {
2276 		if (maxsize==&maxstringbindvaluelength) {
2277 			stringbuffer	err;
2278 			err.append(SQLR_ERROR_MAXSTRINGBINDVALUELENGTH_STRING);
2279 			err.append(" (")->append(bv->valuesize)->append('>');
2280 			err.append(*maxsize)->append(')');
2281 			cont->setError(cursor,err.getString(),
2282 				SQLR_ERROR_MAXSTRINGBINDVALUELENGTH,true);
2283 		} else {
2284 			stringbuffer	err;
2285 			err.append(SQLR_ERROR_MAXLOBBINDVALUELENGTH_STRING);
2286 			err.append(" (")->append(bv->valuesize)->append('>');
2287 			err.append(*maxsize)->append(')');
2288 			cont->setError(cursor,err.getString(),
2289 				SQLR_ERROR_MAXLOBBINDVALUELENGTH,true);
2290 		}
2291 		debugstr.clear();
2292 		debugstr.append("get binds failed: bad value length: ");
2293 		debugstr.append(bv->valuesize);
2294 		cont->raiseClientProtocolErrorEvent(
2295 				cursor,debugstr.getString(),1);
2296 		return false;
2297 	}
2298 
2299 	return true;
2300 }
2301 
getNullBind(sqlrserverbindvar * bv,memorypool * bindpool)2302 void sqlrprotocol_sqlrclient::getNullBind(sqlrserverbindvar *bv,
2303 						memorypool *bindpool) {
2304 	debugFunction();
2305 
2306 	cont->raiseDebugMessageEvent("NULL");
2307 
2308 	bv->value.stringval=(char *)bindpool->allocate(1);
2309 	bv->value.stringval[0]='\0';
2310 	bv->valuesize=0;
2311 	bv->isnull=cont->nullBindValue();
2312 }
2313 
getStringBind(sqlrservercursor * cursor,sqlrserverbindvar * bv,memorypool * bindpool)2314 bool sqlrprotocol_sqlrclient::getStringBind(sqlrservercursor *cursor,
2315 						sqlrserverbindvar *bv,
2316 						memorypool *bindpool) {
2317 	debugFunction();
2318 
2319 	cont->raiseDebugMessageEvent("STRING");
2320 
2321 	// init
2322 	bv->value.stringval=NULL;
2323 
2324 	// get the size of the value
2325 	if (!getBindSize(cursor,bv,&maxstringbindvaluelength)) {
2326 		return false;
2327 	}
2328 
2329 	// allocate space to store the value
2330 	bv->value.stringval=(char *)bindpool->allocate(bv->valuesize+1);
2331 
2332 	// get the bind value
2333 	ssize_t	result=clientsock->read(bv->value.stringval,
2334 					bv->valuesize,
2335 					idleclienttimeout,0);
2336 	if ((uint32_t)result!=(uint32_t)(bv->valuesize)) {
2337 		bv->value.stringval[0]='\0';
2338 		const char	*info="get binds failed: "
2339 					"failed to get bind value";
2340 		cont->raiseClientProtocolErrorEvent(cursor,info,result);
2341 		return false;
2342 	}
2343 	bv->value.stringval[bv->valuesize]='\0';
2344 
2345 	bv->isnull=cont->nonNullBindValue();
2346 
2347 	cont->raiseDebugMessageEvent(bv->value.stringval);
2348 
2349 	return true;
2350 }
2351 
getIntegerBind(sqlrserverbindvar * bv)2352 bool sqlrprotocol_sqlrclient::getIntegerBind(sqlrserverbindvar *bv) {
2353 	debugFunction();
2354 
2355 	cont->raiseDebugMessageEvent("INTEGER");
2356 
2357 	// get the value itself
2358 	uint64_t	value;
2359 	ssize_t		result=clientsock->read(&value,idleclienttimeout,0);
2360 	if (result!=sizeof(uint64_t)) {
2361 		cont->raiseClientProtocolErrorEvent(NULL,
2362 				"get binds failed: "
2363 				"failed to get bind value",result);
2364 		return false;
2365 	}
2366 
2367 	// set the value
2368 	bv->value.integerval=(int64_t)value;
2369 
2370 	char	*intval=charstring::parseNumber(bv->value.integerval);
2371 	cont->raiseDebugMessageEvent(intval);
2372 	delete[] intval;
2373 
2374 	return true;
2375 }
2376 
getDoubleBind(sqlrserverbindvar * bv)2377 bool sqlrprotocol_sqlrclient::getDoubleBind(sqlrserverbindvar *bv) {
2378 	debugFunction();
2379 
2380 	cont->raiseDebugMessageEvent("DOUBLE");
2381 
2382 	// get the value
2383 	ssize_t	result=clientsock->read(&(bv->value.doubleval.value),
2384 						idleclienttimeout,0);
2385 	if (result!=sizeof(double)) {
2386 		cont->raiseClientProtocolErrorEvent(NULL,
2387 				"get binds failed: "
2388 				"failed to get bind value",result);
2389 		return false;
2390 	}
2391 
2392 	// get the precision
2393 	result=clientsock->read(&(bv->value.doubleval.precision),
2394 						idleclienttimeout,0);
2395 	if (result!=sizeof(uint32_t)) {
2396 		cont->raiseClientProtocolErrorEvent(NULL,
2397 				"get binds failed: "
2398 				"failed to get precision",result);
2399 		return false;
2400 	}
2401 
2402 	// get the scale
2403 	result=clientsock->read(&(bv->value.doubleval.scale),
2404 						idleclienttimeout,0);
2405 	if (result!=sizeof(uint32_t)) {
2406 		cont->raiseClientProtocolErrorEvent(NULL,
2407 				"get binds failed: "
2408 				"failed to get scale",result);
2409 		return false;
2410 	}
2411 
2412 	char	*doubleval=charstring::parseNumber(bv->value.doubleval.value);
2413 	cont->raiseDebugMessageEvent(doubleval);
2414 	delete[] doubleval;
2415 
2416 	return true;
2417 }
2418 
getDateBind(sqlrserverbindvar * bv,memorypool * bindpool)2419 bool sqlrprotocol_sqlrclient::getDateBind(sqlrserverbindvar *bv,
2420 						memorypool *bindpool) {
2421 	debugFunction();
2422 
2423 	cont->raiseDebugMessageEvent("DATE");
2424 
2425 	// init
2426 	bv->value.dateval.tz=NULL;
2427 
2428 	uint16_t	temp;
2429 
2430 	// get the year
2431 	ssize_t	result=clientsock->read(&temp,idleclienttimeout,0);
2432 	if (result!=sizeof(uint16_t)) {
2433 		cont->raiseClientProtocolErrorEvent(NULL,
2434 				"get binds failed: "
2435 				"failed to get year",result);
2436 		return false;
2437 	}
2438 	bv->value.dateval.year=(int16_t)temp;
2439 
2440 	// get the month
2441 	result=clientsock->read(&temp,idleclienttimeout,0);
2442 	if (result!=sizeof(uint16_t)) {
2443 		cont->raiseClientProtocolErrorEvent(NULL,
2444 				"get binds failed: "
2445 				"failed to get month",result);
2446 		return false;
2447 	}
2448 	bv->value.dateval.month=(int16_t)temp;
2449 
2450 	// get the day
2451 	result=clientsock->read(&temp,idleclienttimeout,0);
2452 	if (result!=sizeof(uint16_t)) {
2453 		cont->raiseClientProtocolErrorEvent(NULL,
2454 				"get binds failed: "
2455 				"failed to get day",result);
2456 		return false;
2457 	}
2458 	bv->value.dateval.day=(int16_t)temp;
2459 
2460 	// get the hour
2461 	result=clientsock->read(&temp,idleclienttimeout,0);
2462 	if (result!=sizeof(uint16_t)) {
2463 		cont->raiseClientProtocolErrorEvent(NULL,
2464 				"get binds failed: "
2465 				"failed to get hour",result);
2466 		return false;
2467 	}
2468 	bv->value.dateval.hour=(int16_t)temp;
2469 
2470 	// get the minute
2471 	result=clientsock->read(&temp,idleclienttimeout,0);
2472 	if (result!=sizeof(uint16_t)) {
2473 		cont->raiseClientProtocolErrorEvent(NULL,
2474 				"get binds failed: "
2475 				"failed to get minute",result);
2476 		return false;
2477 	}
2478 	bv->value.dateval.minute=(int16_t)temp;
2479 
2480 	// get the second
2481 	result=clientsock->read(&temp,idleclienttimeout,0);
2482 	if (result!=sizeof(uint16_t)) {
2483 		cont->raiseClientProtocolErrorEvent(NULL,
2484 				"get binds failed: "
2485 				"failed to get second",result);
2486 		return false;
2487 	}
2488 	bv->value.dateval.second=(int16_t)temp;
2489 
2490 	// get the microsecond
2491 	uint32_t	temp32;
2492 	result=clientsock->read(&temp32,idleclienttimeout,0);
2493 	if (result!=sizeof(uint32_t)) {
2494 		cont->raiseClientProtocolErrorEvent(NULL,
2495 				"get binds failed: "
2496 				"failed to get microsecond",result);
2497 		return false;
2498 	}
2499 	bv->value.dateval.microsecond=(int32_t)temp32;
2500 
2501 	// get the size of the time zone
2502 	uint16_t	length;
2503 	result=clientsock->read(&length,idleclienttimeout,0);
2504 	if (result!=sizeof(uint16_t)) {
2505 		cont->raiseClientProtocolErrorEvent(NULL,
2506 				"get binds failed: "
2507 				"failed to get timezone size",result);
2508 		return false;
2509 	}
2510 
2511 	// FIXME: do bounds checking here
2512 
2513 	// allocate space to store the time zone
2514 	bv->value.dateval.tz=(char *)bindpool->allocate(length+1);
2515 
2516 	// get the time zone
2517 	result=clientsock->read(bv->value.dateval.tz,length,
2518 					idleclienttimeout,0);
2519 	if ((uint16_t)result!=length) {
2520 		bv->value.dateval.tz[0]='\0';
2521 		cont->raiseClientProtocolErrorEvent(NULL,
2522 				"get binds failed: "
2523 				"failed to get timezone",result);
2524 		return false;
2525 	}
2526 	bv->value.dateval.tz[length]='\0';
2527 
2528 	// get the is-negative flag
2529 	bool	tempbool;
2530 	result=clientsock->read(&tempbool,idleclienttimeout,0);
2531 	if (result!=sizeof(bool)) {
2532 		cont->raiseClientProtocolErrorEvent(NULL,
2533 				"get binds failed: "
2534 				"failed to get is-negative flag",result);
2535 		return false;
2536 	}
2537 	bv->value.dateval.isnegative=tempbool;
2538 
2539 	// allocate enough space to store the date/time string
2540 	// 64 bytes ought to be enough
2541 	bv->value.dateval.buffersize=64;
2542 	bv->value.dateval.buffer=(char *)bindpool->
2543 					allocate(bv->value.dateval.buffersize);
2544 
2545 	bv->isnull=cont->nonNullBindValue();
2546 
2547 	debugstr.clear();
2548 	debugstr.append(bv->value.dateval.year)->append('-');
2549 	debugstr.append(bv->value.dateval.month)->append('-');
2550 	debugstr.append(bv->value.dateval.day)->append(' ');
2551 	if (bv->value.dateval.isnegative) {
2552 		debugstr.append('-');
2553 	}
2554 	debugstr.append(bv->value.dateval.hour)->append(':');
2555 	debugstr.append(bv->value.dateval.minute)->append(':');
2556 	debugstr.append(bv->value.dateval.second)->append(':');
2557 	debugstr.append(bv->value.dateval.microsecond)->append(' ');
2558 	debugstr.append(bv->value.dateval.tz);
2559 	cont->raiseDebugMessageEvent(debugstr.getString());
2560 
2561 	return true;
2562 }
2563 
getLobBind(sqlrservercursor * cursor,sqlrserverbindvar * bv,memorypool * bindpool)2564 bool sqlrprotocol_sqlrclient::getLobBind(sqlrservercursor *cursor,
2565 						sqlrserverbindvar *bv,
2566 						memorypool *bindpool) {
2567 	debugFunction();
2568 
2569 	// init
2570 	bv->value.stringval=NULL;
2571 
2572 	if (bv->type==SQLRSERVERBINDVARTYPE_BLOB) {
2573 		cont->raiseDebugMessageEvent("BLOB");
2574 	}
2575 	if (bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
2576 		cont->raiseDebugMessageEvent("CLOB");
2577 	}
2578 
2579 	// get the size of the value
2580 	if (!getBindSize(cursor,bv,&maxlobbindvaluelength)) {
2581 		return false;
2582 	}
2583 
2584 	// allocate space to store the value
2585 	// (the +1 is to store the NULL-terminator for CLOBS)
2586 	bv->value.stringval=(char *)bindpool->allocate(bv->valuesize+1);
2587 
2588 	// get the bind value
2589 	ssize_t	result=clientsock->read(bv->value.stringval,
2590 					bv->valuesize,
2591 					idleclienttimeout,0);
2592 	if ((uint32_t)result!=(uint32_t)(bv->valuesize)) {
2593 		bv->value.stringval[0]='\0';
2594 		cont->raiseClientProtocolErrorEvent(cursor,
2595 				"get binds failed: bad value",result);
2596 		return false;
2597 	}
2598 
2599 	// It shouldn't hurt to NULL-terminate the lob because the actual size
2600 	// (which doesn't include the NULL terminator) should be used when
2601 	// binding.
2602 	bv->value.stringval[bv->valuesize]='\0';
2603 
2604 	bv->isnull=cont->nonNullBindValue();
2605 
2606 	return true;
2607 }
2608 
getSendColumnInfo()2609 bool sqlrprotocol_sqlrclient::getSendColumnInfo() {
2610 	debugFunction();
2611 
2612 	cont->raiseDebugMessageEvent("get send column info...");
2613 
2614 	uint16_t	sendcolumninfo;
2615 	ssize_t	result=clientsock->read(&sendcolumninfo,idleclienttimeout,0);
2616 	if (result!=sizeof(uint16_t)) {
2617 		cont->raiseClientProtocolErrorEvent(NULL,
2618 				"get send column info failed",result);
2619 		return false;
2620 	}
2621 
2622 	if (sendcolumninfo==SEND_COLUMN_INFO) {
2623 		cont->raiseDebugMessageEvent("send column info");
2624 	} else {
2625 		cont->raiseDebugMessageEvent("don't send column info");
2626 	}
2627 	cont->raiseDebugMessageEvent("done getting send column info...");
2628 
2629 	cont->setSendColumnInfo(sendcolumninfo);
2630 
2631 	return true;
2632 }
2633 
getSkipAndFetch(bool initial,sqlrservercursor * cursor)2634 bool sqlrprotocol_sqlrclient::getSkipAndFetch(bool initial,
2635 						sqlrservercursor *cursor) {
2636 	debugFunction();
2637 
2638 	ssize_t	result=0;
2639 	if (initial) {
2640 
2641 		// get some flags
2642 		uint64_t	flags=0;
2643 		result=clientsock->read(&flags,idleclienttimeout,0);
2644 		if (result!=sizeof(uint64_t)) {
2645 			cont->raiseClientProtocolErrorEvent(cursor,
2646 					"return result set data failed: "
2647 					"failed to get flags",result);
2648 			return false;
2649 		}
2650 
2651 		// for now the only flag is whether or not to do lazy fetches
2652 		lazyfetch=flags;
2653 
2654 		// in this situation, skip should always be 0
2655 		skip=0;
2656 
2657 	} else {
2658 
2659 		// get the number of rows to skip
2660 		result=clientsock->read(&skip,idleclienttimeout,0);
2661 		if (result!=sizeof(uint64_t)) {
2662 			cont->raiseClientProtocolErrorEvent(cursor,
2663 					"return result set data failed: "
2664 					"failed to get rows to skip",result);
2665 			return false;
2666 		}
2667 	}
2668 
2669 	// get the number of rows to fetch
2670 	result=clientsock->read(&fetch,idleclienttimeout,0);
2671 	if (result!=sizeof(uint64_t)) {
2672 		cont->raiseClientProtocolErrorEvent(cursor,
2673 				"return result set data failed: "
2674 				"failed to get rows to fetch",result);
2675 		return false;
2676 	}
2677 	return true;
2678 }
2679 
returnResultSetHeader(sqlrservercursor * cursor)2680 void sqlrprotocol_sqlrclient::returnResultSetHeader(sqlrservercursor *cursor) {
2681 	debugFunction();
2682 
2683 	cont->raiseDebugMessageEvent("returning result set header...");
2684 
2685 	// return the row counts
2686 	cont->raiseDebugMessageEvent("returning row counts...");
2687 	sendRowCounts(cont->knowsRowCount(cursor),
2688 			cont->rowCount(cursor),
2689 			cont->knowsAffectedRows(cursor),
2690 			cont->affectedRows(cursor));
2691 	cont->raiseDebugMessageEvent("done returning row counts");
2692 
2693 	// tell the client whether or not the column information will be sent
2694 	uint16_t	sendcolumninfo=cont->getSendColumnInfo();
2695 	clientsock->write(sendcolumninfo);
2696 	cont->raiseDebugMessageEvent((sendcolumninfo==SEND_COLUMN_INFO)?
2697 					"column info will be sent":
2698 					"column info will not be sent");
2699 
2700 	// return the column count
2701 	cont->raiseDebugMessageEvent("returning column counts...");
2702 	clientsock->write(cont->colCount(cursor));
2703 	cont->raiseDebugMessageEvent("done returning column counts");
2704 
2705 	if (sendcolumninfo==SEND_COLUMN_INFO) {
2706 
2707 		// return the column type format
2708 		cont->raiseDebugMessageEvent("sending column type format...");
2709 		uint16_t	format=cont->columnTypeFormat(cursor);
2710 		cont->raiseDebugMessageEvent((format==COLUMN_TYPE_IDS)?
2711 							"id's":"names");
2712 		clientsock->write(format);
2713 		cont->raiseDebugMessageEvent("done sending column type format");
2714 
2715 		// return the column info
2716 		cont->raiseDebugMessageEvent("returning column info...");
2717 		returnColumnInfo(cursor,format);
2718 		cont->raiseDebugMessageEvent("done returning column info");
2719 	}
2720 
2721 	// return the output bind vars
2722 	returnOutputBindValues(cursor);
2723 	returnInputOutputBindValues(cursor);
2724 
2725 	cont->raiseDebugMessageEvent("done returning result set header");
2726 }
2727 
returnColumnInfo(sqlrservercursor * cursor,uint16_t format)2728 void sqlrprotocol_sqlrclient::returnColumnInfo(sqlrservercursor *cursor,
2729 							uint16_t format) {
2730 	debugFunction();
2731 
2732 	for (uint32_t i=0; i<cont->colCount(cursor); i++) {
2733 
2734 		const char	*name=cont->getColumnName(cursor,i);
2735 		uint16_t	namelen=cont->getColumnNameLength(cursor,i);
2736 		uint32_t	length=cont->getColumnLength(cursor,i);
2737 		uint32_t	precision=cont->getColumnPrecision(cursor,i);
2738 		uint32_t	scale=cont->getColumnScale(cursor,i);
2739 		uint16_t	nullable=cont->getColumnIsNullable(cursor,i);
2740 		uint16_t	primarykey=
2741 				cont->getColumnIsPrimaryKey(cursor,i);
2742 		uint16_t	unique=cont->getColumnIsUnique(cursor,i);
2743 		uint16_t	partofkey=cont->getColumnIsPartOfKey(cursor,i);
2744 		uint16_t	unsignednumber=
2745 				cont->getColumnIsUnsigned(cursor,i);
2746 		uint16_t	zerofill=cont->getColumnIsZeroFilled(cursor,i);
2747 		uint16_t	binary=cont->getColumnIsBinary(cursor,i);
2748 		uint16_t	autoincrement=
2749 				cont->getColumnIsAutoIncrement(cursor,i);
2750 		const char	*table=cont->getColumnTable(cursor,i);
2751 		uint16_t	tablelen=cont->getColumnTableLength(cursor,i);
2752 
2753 		if (format==COLUMN_TYPE_IDS) {
2754 			sendColumnDefinition(name,namelen,
2755 					protocolAppropriateColumnType(
2756 						cont->getColumnType(cursor,i)),
2757 					length,precision,scale,
2758 					nullable,primarykey,unique,partofkey,
2759 					unsignednumber,zerofill,binary,
2760 					autoincrement,table,tablelen);
2761 		} else {
2762 			sendColumnDefinitionString(name,namelen,
2763 					cont->getColumnTypeName(cursor,i),
2764 					cont->getColumnTypeNameLength(cursor,i),
2765 					length,precision,scale,
2766 					nullable,primarykey,unique,partofkey,
2767 					unsignednumber,zerofill,binary,
2768 					autoincrement,table,tablelen);
2769 		}
2770 	}
2771 }
2772 
protocolAppropriateColumnType(uint16_t coltype)2773 uint16_t sqlrprotocol_sqlrclient::protocolAppropriateColumnType(
2774 							uint16_t coltype) {
2775 
2776 	if (protocolversion>=2) {
2777 		return coltype;
2778 	}
2779 
2780 	// these types didn't exist in earlier protocol verions
2781 	switch (coltype) {
2782 		// also added by mysql
2783 		case TINYTEXT_DATATYPE:
2784 			return TINY_BLOB_DATATYPE;
2785 		case MEDIUMTEXT_DATATYPE:
2786 			return MEDIUM_BLOB_DATATYPE;
2787 		case LONGTEXT_DATATYPE:
2788 			return LONG_BLOB_DATATYPE;
2789 		case JSON_DATATYPE:
2790 			return UNKNOWN_DATATYPE;
2791 		case GEOMETRY_DATATYPE:
2792 			return UNKNOWN_DATATYPE;
2793 		// also added by oracle
2794 		case SDO_GEOMETRY_DATATYPE:
2795 			return BLOB_DATATYPE;
2796 		// added by mssql
2797 		case NCHAR_DATATYPE:
2798 			return CHAR_DATATYPE;
2799 		case NVARCHAR_DATATYPE:
2800 			return VARCHAR_DATATYPE;
2801 		case NTEXT_DATATYPE:
2802 			return TEXT_DATATYPE;
2803 		case XML_DATATYPE:
2804 			return VARCHAR_DATATYPE;
2805 		case DATETIMEOFFSET_DATATYPE:
2806 			return DATETIME_DATATYPE;
2807 		default:
2808 			return coltype;
2809 	}
2810 }
2811 
sendRowCounts(bool knowsactual,uint64_t actual,bool knowsaffected,uint64_t affected)2812 void sqlrprotocol_sqlrclient::sendRowCounts(bool knowsactual,
2813 						uint64_t actual,
2814 						bool knowsaffected,
2815 						uint64_t affected) {
2816 	debugFunction();
2817 
2818 	cont->raiseDebugMessageEvent("sending row counts...");
2819 
2820 	// send actual rows, if that is known
2821 	if (knowsactual) {
2822 
2823 		char	string[30];
2824 		charstring::printf(string,sizeof(string),
2825 				"actual rows: %lld",(long long)actual);
2826 		cont->raiseDebugMessageEvent(string);
2827 
2828 		clientsock->write((uint16_t)ACTUAL_ROWS);
2829 		clientsock->write(actual);
2830 
2831 	} else {
2832 
2833 		cont->raiseDebugMessageEvent("actual rows unknown");
2834 
2835 		clientsock->write((uint16_t)NO_ACTUAL_ROWS);
2836 	}
2837 
2838 
2839 	// send affected rows, if that is known
2840 	if (knowsaffected) {
2841 
2842 		char	string[46];
2843 		charstring::printf(string,46,
2844 				"affected rows: %lld",(long long)affected);
2845 		cont->raiseDebugMessageEvent(string);
2846 
2847 		clientsock->write((uint16_t)AFFECTED_ROWS);
2848 		clientsock->write(affected);
2849 
2850 	} else {
2851 
2852 		cont->raiseDebugMessageEvent("affected rows unknown");
2853 
2854 		clientsock->write((uint16_t)NO_AFFECTED_ROWS);
2855 	}
2856 
2857 	cont->raiseDebugMessageEvent("done sending row counts");
2858 }
2859 
returnOutputBindValues(sqlrservercursor * cursor)2860 void sqlrprotocol_sqlrclient::returnOutputBindValues(sqlrservercursor *cursor) {
2861 	debugFunction();
2862 
2863 	if (cont->logEnabled() || cont->notificationsEnabled()) {
2864 		debugstr.clear();
2865 		debugstr.append("returning ");
2866 		debugstr.append(cont->getOutputBindCount(cursor));
2867 		debugstr.append(" output bind values: ");
2868 		cont->raiseDebugMessageEvent(debugstr.getString());
2869 	}
2870 
2871 	// run through the output bind values, sending them back
2872 	for (uint16_t i=0; i<cont->getOutputBindCount(cursor); i++) {
2873 
2874 		sqlrserverbindvar	*bv=&(cont->getOutputBinds(cursor)[i]);
2875 
2876 		if (cont->logEnabled() || cont->notificationsEnabled()) {
2877 			debugstr.clear();
2878 			debugstr.append(i);
2879 			debugstr.append(":");
2880 		}
2881 
2882 		if (cont->bindValueIsNull(bv->isnull)) {
2883 
2884 			if (cont->logEnabled() ||
2885 				cont->notificationsEnabled()) {
2886 				debugstr.append("NULL");
2887 			}
2888 
2889 			clientsock->write((uint16_t)NULL_DATA);
2890 
2891 		} else if (bv->type==SQLRSERVERBINDVARTYPE_BLOB) {
2892 
2893 			if (cont->logEnabled() ||
2894 				cont->notificationsEnabled()) {
2895 				debugstr.append("BLOB:");
2896 			}
2897 
2898 			returnOutputBindBlob(cursor,i);
2899 
2900 		} else if (bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
2901 
2902 			if (cont->logEnabled() ||
2903 				cont->notificationsEnabled()) {
2904 				debugstr.append("CLOB:");
2905 			}
2906 
2907 			returnOutputBindClob(cursor,i);
2908 
2909 		} else if (bv->type==SQLRSERVERBINDVARTYPE_STRING) {
2910 
2911 			if (cont->logEnabled() ||
2912 				cont->notificationsEnabled()) {
2913 				debugstr.append("STRING:");
2914 				debugstr.append(bv->value.stringval);
2915 			}
2916 
2917 			clientsock->write((uint16_t)STRING_DATA);
2918 			bv->valuesize=charstring::length(
2919 						(char *)bv->value.stringval);
2920 			clientsock->write(bv->valuesize);
2921 			clientsock->write(bv->value.stringval,bv->valuesize);
2922 
2923 		} else if (bv->type==SQLRSERVERBINDVARTYPE_INTEGER) {
2924 
2925 			if (cont->logEnabled() ||
2926 				cont->notificationsEnabled()) {
2927 				debugstr.append("INTEGER:");
2928 				debugstr.append(bv->value.integerval);
2929 			}
2930 
2931 			clientsock->write((uint16_t)INTEGER_DATA);
2932 			clientsock->write((uint64_t)bv->value.integerval);
2933 
2934 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DOUBLE) {
2935 
2936 			if (cont->logEnabled() ||
2937 				cont->notificationsEnabled()) {
2938 				debugstr.append("DOUBLE:");
2939 				debugstr.append(bv->value.doubleval.value);
2940 				debugstr.append("(");
2941 				debugstr.append(bv->value.doubleval.precision);
2942 				debugstr.append(",");
2943 				debugstr.append(bv->value.doubleval.scale);
2944 				debugstr.append(")");
2945 			}
2946 
2947 			clientsock->write((uint16_t)DOUBLE_DATA);
2948 			clientsock->write(bv->value.doubleval.value);
2949 			clientsock->write((uint32_t)bv->value.
2950 						doubleval.precision);
2951 			clientsock->write((uint32_t)bv->value.
2952 						doubleval.scale);
2953 
2954 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DATE) {
2955 
2956 			if (cont->logEnabled() ||
2957 				cont->notificationsEnabled()) {
2958 				debugstr.append("DATE:");
2959 				debugstr.append(bv->value.dateval.year);
2960 				debugstr.append("-");
2961 				debugstr.append(bv->value.dateval.month);
2962 				debugstr.append("-");
2963 				debugstr.append(bv->value.dateval.day);
2964 				debugstr.append(" ");
2965 				if (bv->value.dateval.isnegative) {
2966 					debugstr.append('-');
2967 				}
2968 				debugstr.append(bv->value.dateval.hour);
2969 				debugstr.append(":");
2970 				debugstr.append(bv->value.dateval.minute);
2971 				debugstr.append(":");
2972 				debugstr.append(bv->value.dateval.second);
2973 				debugstr.append(":");
2974 				debugstr.append(bv->value.dateval.microsecond);
2975 				debugstr.append(" ");
2976 				debugstr.append(bv->value.dateval.tz);
2977 			}
2978 
2979 			clientsock->write((uint16_t)DATE_DATA);
2980 			clientsock->write((uint16_t)bv->value.dateval.year);
2981 			clientsock->write((uint16_t)bv->value.dateval.month);
2982 			clientsock->write((uint16_t)bv->value.dateval.day);
2983 			clientsock->write((uint16_t)bv->value.dateval.hour);
2984 			clientsock->write((uint16_t)bv->value.dateval.minute);
2985 			clientsock->write((uint16_t)bv->value.dateval.second);
2986 			clientsock->write((uint32_t)bv->value.
2987 							dateval.microsecond);
2988 			uint16_t	length=charstring::length(
2989 							bv->value.dateval.tz);
2990 			clientsock->write(length);
2991 			clientsock->write(bv->value.dateval.tz,length);
2992 			clientsock->write((bool)bv->value.dateval.isnegative);
2993 
2994 		} else if (bv->type==SQLRSERVERBINDVARTYPE_CURSOR) {
2995 
2996 			if (cont->logEnabled() ||
2997 				cont->notificationsEnabled()) {
2998 				debugstr.append("CURSOR:");
2999 				debugstr.append(bv->value.cursorid);
3000 			}
3001 
3002 			clientsock->write((uint16_t)CURSOR_DATA);
3003 			clientsock->write(bv->value.cursorid);
3004 		}
3005 
3006 		if (cont->logEnabled() || cont->notificationsEnabled()) {
3007 			cont->raiseDebugMessageEvent(debugstr.getString());
3008 		}
3009 	}
3010 
3011 	// terminate the bind vars
3012 	clientsock->write((uint16_t)END_BIND_VARS);
3013 
3014 	cont->raiseDebugMessageEvent("done returning output bind values");
3015 }
3016 
returnOutputBindBlob(sqlrservercursor * cursor,uint16_t index)3017 void sqlrprotocol_sqlrclient::returnOutputBindBlob(sqlrservercursor *cursor,
3018 							uint16_t index) {
3019 	debugFunction();
3020 	sendLobOutputBind(cursor,index);
3021 	cont->closeLobOutputBind(cursor,index);
3022 }
3023 
returnOutputBindClob(sqlrservercursor * cursor,uint16_t index)3024 void sqlrprotocol_sqlrclient::returnOutputBindClob(sqlrservercursor *cursor,
3025 							uint16_t index) {
3026 	debugFunction();
3027 	sendLobOutputBind(cursor,index);
3028 	cont->closeLobOutputBind(cursor,index);
3029 }
3030 
3031 #define MAX_BYTES_PER_CHAR	4
3032 
sendLobOutputBind(sqlrservercursor * cursor,uint16_t index)3033 void sqlrprotocol_sqlrclient::sendLobOutputBind(sqlrservercursor *cursor,
3034 							uint16_t index) {
3035 	debugFunction();
3036 
3037 	// Get lob length.  If this fails, send a NULL field.
3038 	uint64_t	loblength;
3039 	if (!cont->getLobOutputBindLength(cursor,index,&loblength)) {
3040 		sendNullField();
3041 		return;
3042 	}
3043 
3044 	// for lobs of 0 length
3045 	if (!loblength) {
3046 		startSendingLong(0);
3047 		sendLongSegment("",0);
3048 		endSendingLong();
3049 		return;
3050 	}
3051 
3052 	// initialize sizes and status
3053 	uint64_t	charstoread=sizeof(lobbuffer)/MAX_BYTES_PER_CHAR;
3054 	uint64_t	charsread=0;
3055 	uint64_t	offset=0;
3056 	bool		start=true;
3057 
3058 	for (;;) {
3059 
3060 		// read a segment from the lob
3061 		if (!cont->getLobOutputBindSegment(cursor,index,
3062 					lobbuffer,sizeof(lobbuffer),
3063 					offset,charstoread,&charsread) ||
3064 					!charsread) {
3065 
3066 			// if we fail to get a segment or got nothing...
3067 			// if we haven't started sending yet, then send a NULL,
3068 			// otherwise just end normally
3069 			if (start) {
3070 				sendNullField();
3071 			} else {
3072 				endSendingLong();
3073 			}
3074 			return;
3075 
3076 		} else {
3077 
3078 			// if we haven't started sending yet, then do that now
3079 			if (start) {
3080 				startSendingLong(loblength);
3081 				start=false;
3082 			}
3083 
3084 			// send the segment we just got
3085 			sendLongSegment(lobbuffer,charsread);
3086 
3087 			// FIXME: or should this be charsread?
3088 			offset=offset+charstoread;
3089 		}
3090 	}
3091 }
3092 
returnInputOutputBindValues(sqlrservercursor * cursor)3093 void sqlrprotocol_sqlrclient::returnInputOutputBindValues(
3094 						sqlrservercursor *cursor) {
3095 	debugFunction();
3096 
3097 	if (protocolversion<2) {
3098 		cont->raiseDebugMessageEvent("not returning input/output binds "
3099 						"(client protocol too old)");
3100 		return;
3101 	}
3102 
3103 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3104 		debugstr.clear();
3105 		debugstr.append("returning ");
3106 		debugstr.append(cont->getInputOutputBindCount(cursor));
3107 		debugstr.append(" input/output bind values: ");
3108 		cont->raiseDebugMessageEvent(debugstr.getString());
3109 	}
3110 
3111 	// run through the input/output bind values, sending them back
3112 	for (uint16_t i=0; i<cont->getInputOutputBindCount(cursor); i++) {
3113 
3114 		sqlrserverbindvar	*bv=
3115 				&(cont->getInputOutputBinds(cursor)[i]);
3116 
3117 		if (cont->logEnabled() || cont->notificationsEnabled()) {
3118 			debugstr.clear();
3119 			debugstr.append(i);
3120 			debugstr.append(":");
3121 		}
3122 
3123 		if (cont->bindValueIsNull(bv->isnull)) {
3124 
3125 			if (cont->logEnabled() ||
3126 				cont->notificationsEnabled()) {
3127 				debugstr.append("NULL");
3128 			}
3129 
3130 			clientsock->write((uint16_t)NULL_DATA);
3131 
3132 		} else /*if (bv->type==SQLRSERVERBINDVARTYPE_BLOB) {
3133 
3134 			if (cont->logEnabled() ||
3135 				cont->notificationsEnabled()) {
3136 				debugstr.append("BLOB:");
3137 			}
3138 
3139 			returnInputOutputBindBlob(cursor,i);
3140 
3141 		} else if (bv->type==SQLRSERVERBINDVARTYPE_CLOB) {
3142 
3143 			if (cont->logEnabled() ||
3144 				cont->notificationsEnabled()) {
3145 				debugstr.append("CLOB:");
3146 			}
3147 
3148 			returnInputOutputBindClob(cursor,i);
3149 
3150 		} else*/ if (bv->type==SQLRSERVERBINDVARTYPE_STRING) {
3151 
3152 			if (cont->logEnabled() ||
3153 				cont->notificationsEnabled()) {
3154 				debugstr.append("STRING:");
3155 				debugstr.append(bv->value.stringval);
3156 			}
3157 
3158 			clientsock->write((uint16_t)STRING_DATA);
3159 			bv->valuesize=charstring::length(
3160 						(char *)bv->value.stringval);
3161 			clientsock->write(bv->valuesize);
3162 			clientsock->write(bv->value.stringval,bv->valuesize);
3163 
3164 		} else if (bv->type==SQLRSERVERBINDVARTYPE_INTEGER) {
3165 
3166 			if (cont->logEnabled() ||
3167 				cont->notificationsEnabled()) {
3168 				debugstr.append("INTEGER:");
3169 				debugstr.append(bv->value.integerval);
3170 			}
3171 
3172 			clientsock->write((uint16_t)INTEGER_DATA);
3173 			clientsock->write((uint64_t)bv->value.integerval);
3174 
3175 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DOUBLE) {
3176 
3177 			if (cont->logEnabled() ||
3178 				cont->notificationsEnabled()) {
3179 				debugstr.append("DOUBLE:");
3180 				debugstr.append(bv->value.doubleval.value);
3181 				debugstr.append("(");
3182 				debugstr.append(bv->value.doubleval.precision);
3183 				debugstr.append(",");
3184 				debugstr.append(bv->value.doubleval.scale);
3185 				debugstr.append(")");
3186 			}
3187 
3188 			clientsock->write((uint16_t)DOUBLE_DATA);
3189 			clientsock->write(bv->value.doubleval.value);
3190 			clientsock->write((uint32_t)bv->value.
3191 						doubleval.precision);
3192 			clientsock->write((uint32_t)bv->value.
3193 						doubleval.scale);
3194 
3195 		} else if (bv->type==SQLRSERVERBINDVARTYPE_DATE) {
3196 
3197 			if (cont->logEnabled() ||
3198 				cont->notificationsEnabled()) {
3199 				debugstr.append("DATE:");
3200 				debugstr.append(bv->value.dateval.year);
3201 				debugstr.append("-");
3202 				debugstr.append(bv->value.dateval.month);
3203 				debugstr.append("-");
3204 				debugstr.append(bv->value.dateval.day);
3205 				debugstr.append(" ");
3206 				if (bv->value.dateval.isnegative) {
3207 					debugstr.append('-');
3208 				}
3209 				debugstr.append(bv->value.dateval.hour);
3210 				debugstr.append(":");
3211 				debugstr.append(bv->value.dateval.minute);
3212 				debugstr.append(":");
3213 				debugstr.append(bv->value.dateval.second);
3214 				debugstr.append(":");
3215 				debugstr.append(bv->value.dateval.microsecond);
3216 				debugstr.append(" ");
3217 				debugstr.append(bv->value.dateval.tz);
3218 			}
3219 
3220 			clientsock->write((uint16_t)DATE_DATA);
3221 			clientsock->write((uint16_t)bv->value.dateval.year);
3222 			clientsock->write((uint16_t)bv->value.dateval.month);
3223 			clientsock->write((uint16_t)bv->value.dateval.day);
3224 			clientsock->write((uint16_t)bv->value.dateval.hour);
3225 			clientsock->write((uint16_t)bv->value.dateval.minute);
3226 			clientsock->write((uint16_t)bv->value.dateval.second);
3227 			clientsock->write((uint32_t)bv->value.
3228 							dateval.microsecond);
3229 			uint16_t	length=charstring::length(
3230 							bv->value.dateval.tz);
3231 			clientsock->write(length);
3232 			clientsock->write(bv->value.dateval.tz,length);
3233 			clientsock->write((bool)bv->value.dateval.isnegative);
3234 
3235 		}
3236 
3237 		if (cont->logEnabled() || cont->notificationsEnabled()) {
3238 			cont->raiseDebugMessageEvent(debugstr.getString());
3239 		}
3240 	}
3241 
3242 	// terminate the bind vars
3243 	clientsock->write((uint16_t)END_BIND_VARS);
3244 
3245 	cont->raiseDebugMessageEvent("done returning input/output bind values");
3246 }
3247 
sendColumnDefinition(const char * name,uint16_t namelen,uint16_t type,uint32_t size,uint32_t precision,uint32_t scale,uint16_t nullable,uint16_t primarykey,uint16_t unique,uint16_t partofkey,uint16_t unsignednumber,uint16_t zerofill,uint16_t binary,uint16_t autoincrement,const char * table,uint16_t tablelen)3248 void sqlrprotocol_sqlrclient::sendColumnDefinition(
3249 						const char *name,
3250 						uint16_t namelen,
3251 						uint16_t type,
3252 						uint32_t size,
3253 						uint32_t precision,
3254 						uint32_t scale,
3255 						uint16_t nullable,
3256 						uint16_t primarykey,
3257 						uint16_t unique,
3258 						uint16_t partofkey,
3259 						uint16_t unsignednumber,
3260 						uint16_t zerofill,
3261 						uint16_t binary,
3262 						uint16_t autoincrement,
3263 						const char *table,
3264 						uint16_t tablelen) {
3265 	debugFunction();
3266 
3267 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3268 		debugstr.clear();
3269 		for (uint16_t i=0; i<namelen; i++) {
3270 			debugstr.append(name[i]);
3271 		}
3272 		debugstr.append(":");
3273 		debugstr.append(type);
3274 		debugstr.append(":");
3275 		debugstr.append(size);
3276 		debugstr.append(" (");
3277 		debugstr.append(precision);
3278 		debugstr.append(",");
3279 		debugstr.append(scale);
3280 		debugstr.append(") ");
3281 		if (!nullable) {
3282 			debugstr.append("NOT NULL ");
3283 		}
3284 		if (primarykey) {
3285 			debugstr.append("Primary key ");
3286 		}
3287 		if (unique) {
3288 			debugstr.append("Unique");
3289 		}
3290 		cont->raiseDebugMessageEvent(debugstr.getString());
3291 	}
3292 
3293 	clientsock->write(namelen);
3294 	clientsock->write(name,namelen);
3295 	clientsock->write(type);
3296 	clientsock->write(size);
3297 	clientsock->write(precision);
3298 	clientsock->write(scale);
3299 	clientsock->write(nullable);
3300 	clientsock->write(primarykey);
3301 	clientsock->write(unique);
3302 	clientsock->write(partofkey);
3303 	clientsock->write(unsignednumber);
3304 	clientsock->write(zerofill);
3305 	clientsock->write(binary);
3306 	clientsock->write(autoincrement);
3307 
3308 	if (protocolversion<2) {
3309 		return;
3310 	}
3311 
3312 	clientsock->write(tablelen);
3313 	clientsock->write(table,tablelen);
3314 }
3315 
sendColumnDefinitionString(const char * name,uint16_t namelen,const char * type,uint16_t typelen,uint32_t size,uint32_t precision,uint32_t scale,uint16_t nullable,uint16_t primarykey,uint16_t unique,uint16_t partofkey,uint16_t unsignednumber,uint16_t zerofill,uint16_t binary,uint16_t autoincrement,const char * table,uint16_t tablelen)3316 void sqlrprotocol_sqlrclient::sendColumnDefinitionString(
3317 						const char *name,
3318 						uint16_t namelen,
3319 						const char *type,
3320 						uint16_t typelen,
3321 						uint32_t size,
3322 						uint32_t precision,
3323 						uint32_t scale,
3324 						uint16_t nullable,
3325 						uint16_t primarykey,
3326 						uint16_t unique,
3327 						uint16_t partofkey,
3328 						uint16_t unsignednumber,
3329 						uint16_t zerofill,
3330 						uint16_t binary,
3331 						uint16_t autoincrement,
3332 						const char *table,
3333 						uint16_t tablelen) {
3334 	debugFunction();
3335 
3336 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3337 		debugstr.clear();
3338 		for (uint16_t ni=0; ni<namelen; ni++) {
3339 			debugstr.append(name[ni]);
3340 		}
3341 		debugstr.append(":");
3342 		for (uint16_t ti=0; ti<typelen; ti++) {
3343 			debugstr.append(type[ti]);
3344 		}
3345 		debugstr.append(":");
3346 		debugstr.append(size);
3347 		debugstr.append(" (");
3348 		debugstr.append(precision);
3349 		debugstr.append(",");
3350 		debugstr.append(scale);
3351 		debugstr.append(") ");
3352 		if (!nullable) {
3353 			debugstr.append("NOT NULL ");
3354 		}
3355 		if (primarykey) {
3356 			debugstr.append("Primary key ");
3357 		}
3358 		if (unique) {
3359 			debugstr.append("Unique");
3360 		}
3361 		cont->raiseDebugMessageEvent(debugstr.getString());
3362 	}
3363 
3364 	clientsock->write(namelen);
3365 	clientsock->write(name,namelen);
3366 	clientsock->write(typelen);
3367 	clientsock->write(type,typelen);
3368 	clientsock->write(size);
3369 	clientsock->write(precision);
3370 	clientsock->write(scale);
3371 	clientsock->write(nullable);
3372 	clientsock->write(primarykey);
3373 	clientsock->write(unique);
3374 	clientsock->write(partofkey);
3375 	clientsock->write(unsignednumber);
3376 	clientsock->write(zerofill);
3377 	clientsock->write(binary);
3378 	clientsock->write(autoincrement);
3379 
3380 	if (protocolversion<2) {
3381 		return;
3382 	}
3383 
3384 	clientsock->write(tablelen);
3385 	clientsock->write(table,tablelen);
3386 }
3387 
returnResultSetData(sqlrservercursor * cursor,bool getskipandfetch,bool overridelazyfetch)3388 bool sqlrprotocol_sqlrclient::returnResultSetData(sqlrservercursor *cursor,
3389 						bool getskipandfetch,
3390 						bool overridelazyfetch) {
3391 	debugFunction();
3392 
3393 	cont->raiseDebugMessageEvent("returning result set data...");
3394 
3395 	// FIXME: push up?
3396 	cont->setState(RETURN_RESULT_SET);
3397 
3398 	// decide whether to use the cursor itself
3399 	// or an attached custom query cursor
3400 	// FIXME: push up?
3401 	sqlrservercursor	*customcursor=cursor->getCustomQueryCursor();
3402 	if (customcursor) {
3403 		cursor=customcursor;
3404 	}
3405 
3406 	// get the number of rows to skip and fetch
3407 	if (getskipandfetch) {
3408 		if (!getSkipAndFetch(false,cursor)) {
3409 			return false;
3410 		}
3411 	}
3412 
3413 	// reinit cursor state (in case it was suspended)
3414 	// FIXME: push up?
3415 	cont->setState(cursor,SQLRCURSORSTATE_BUSY);
3416 
3417 	if (!lazyfetch || overridelazyfetch) {
3418 
3419 		bool	error=false;
3420 
3421 		// for some queries, there are no rows to return,
3422 		if (cont->noRowsToReturn(cursor)) {
3423 			clientsock->write(endresultset);
3424 			clientsock->flushWriteBuffer(-1,-1);
3425 			cont->raiseDebugMessageEvent(
3426 				"done returning result set data");
3427 			return true;
3428 		}
3429 
3430 		// skip the specified number of rows
3431 		if (!cont->skipRows(cursor,skip,&error)) {
3432 			if (error) {
3433 				returnFetchError(cursor);
3434 			} else {
3435 				clientsock->write(endresultset);
3436 				cont->raiseDebugMessageEvent(
3437 					"done returning result set data");
3438 			}
3439 			clientsock->flushWriteBuffer(-1,-1);
3440 			return true;
3441 		}
3442 
3443 		if (cont->logEnabled() || cont->notificationsEnabled()) {
3444 			debugstr.clear();
3445 			debugstr.append("fetching ");
3446 			debugstr.append(fetch);
3447 			debugstr.append(" rows...");
3448 			cont->raiseDebugMessageEvent(debugstr.getString());
3449 		}
3450 
3451 		// send the specified number of rows back
3452 		for (uint64_t i=0; (!fetch || i<fetch); i++) {
3453 			if (cont->fetchRow(cursor,&error)) {
3454 				returnRow(cursor);
3455 				// FIXME: kludgy
3456 				cont->nextRow(cursor);
3457 			} else {
3458 				if (error) {
3459 					returnFetchError(cursor);
3460 				} else {
3461 					clientsock->write(endresultset);
3462 				}
3463 				break;
3464 			}
3465 		}
3466 	}
3467 	clientsock->flushWriteBuffer(-1,-1);
3468 
3469 	cont->raiseDebugMessageEvent("done returning result set data");
3470 	return true;
3471 }
3472 
returnFetchError(sqlrservercursor * cursor)3473 void sqlrprotocol_sqlrclient::returnFetchError(sqlrservercursor *cursor) {
3474 
3475 	clientsock->write((uint16_t)FETCH_ERROR);
3476 
3477 	cont->raiseDebugMessageEvent("returning error...");
3478 
3479 	// FIXME: this is a little kludgy, ideally we'd just call returnError()
3480 	// but it has some side effects
3481 
3482 	// get the error
3483 	const char	*errorstring;
3484 	uint32_t	errorlength;
3485 	int64_t		errnum;
3486 	bool		liveconnection;
3487 	cont->errorMessage(cursor,&errorstring,&errorlength,
3488 					&errnum,&liveconnection);
3489 
3490 	// send the error status
3491 	if (!liveconnection) {
3492 		clientsock->write((uint16_t)ERROR_OCCURRED_DISCONNECT);
3493 	} else {
3494 		clientsock->write((uint16_t)ERROR_OCCURRED);
3495 	}
3496 
3497 	// send the error code
3498 	clientsock->write((uint64_t)errnum);
3499 
3500 	// send the error string
3501 	clientsock->write((uint16_t)errorlength);
3502 	clientsock->write(errorstring,errorlength);
3503 
3504 	cont->raiseDebugMessageEvent("done returning error");
3505 }
3506 
returnRow(sqlrservercursor * cursor)3507 void sqlrprotocol_sqlrclient::returnRow(sqlrservercursor *cursor) {
3508 	debugFunction();
3509 
3510 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3511 		debugstr.clear();
3512 	}
3513 
3514 	// send fields
3515 	uint32_t	colcount=cont->colCount(cursor);
3516 	for (uint32_t i=0; i<colcount; i++) {
3517 
3518 		const char	*field=NULL;
3519 		uint64_t	fieldlength=0;
3520 		bool		blob=false;
3521 		bool		null=false;
3522 		if (!cont->getField(cursor,i,&field,&fieldlength,&blob,&null)) {
3523 			// FIXME: handle error
3524 		}
3525 
3526 		// send data to the client
3527 		if (null) {
3528 			sendNullField();
3529 		} else if (blob) {
3530 			sendLobField(cursor,i);
3531 		} else {
3532 			sendField(field,fieldlength);
3533 		}
3534 	}
3535 
3536 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3537 		cont->raiseDebugMessageEvent(debugstr.getString());
3538 	}
3539 }
3540 
sendField(const char * data,uint32_t size)3541 void sqlrprotocol_sqlrclient::sendField(const char *data, uint32_t size) {
3542 	debugFunction();
3543 
3544 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3545 		debugstr.append("\"");
3546 		debugstr.append(data,size);
3547 		debugstr.append("\",");
3548 	}
3549 
3550 	clientsock->write((uint16_t)STRING_DATA);
3551 	clientsock->write(size);
3552 	clientsock->write(data,size);
3553 }
3554 
sendNullField()3555 void sqlrprotocol_sqlrclient::sendNullField() {
3556 	debugFunction();
3557 
3558 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3559 		debugstr.append("NULL,");
3560 	}
3561 	clientsock->write((uint16_t)NULL_DATA);
3562 }
3563 
3564 #define MAX_BYTES_PER_CHAR	4
3565 
sendLobField(sqlrservercursor * cursor,uint32_t col)3566 void sqlrprotocol_sqlrclient::sendLobField(sqlrservercursor *cursor,
3567 							uint32_t col) {
3568 	debugFunction();
3569 
3570 	// Get lob length.  If this fails, send a NULL field.
3571 	uint64_t	loblength;
3572 	if (!cont->getLobFieldLength(cursor,col,&loblength)) {
3573 		sendNullField();
3574 		cont->closeLobField(cursor,col);
3575 		return;
3576 	}
3577 
3578 	// for lobs of 0 length
3579 	if (!loblength) {
3580 		startSendingLong(0);
3581 		sendLongSegment("",0);
3582 		endSendingLong();
3583 		cont->closeLobField(cursor,col);
3584 		return;
3585 	}
3586 
3587 	// initialize sizes and status
3588 	uint64_t	charstoread=sizeof(lobbuffer)/MAX_BYTES_PER_CHAR;
3589 	uint64_t	charsread=0;
3590 	uint64_t	offset=0;
3591 	bool		start=true;
3592 
3593 	for (;;) {
3594 
3595 		// read a segment from the lob
3596 		if (!cont->getLobFieldSegment(cursor,col,
3597 					lobbuffer,sizeof(lobbuffer),
3598 					offset,charstoread,&charsread) ||
3599 					!charsread) {
3600 
3601 			// if we fail to get a segment or got nothing...
3602 			// if we haven't started sending yet, then send a NULL,
3603 			// otherwise just end normally
3604 			if (start) {
3605 				sendNullField();
3606 			} else {
3607 				endSendingLong();
3608 			}
3609 			cont->closeLobField(cursor,col);
3610 			return;
3611 
3612 		} else {
3613 
3614 			// if we haven't started sending yet, then do that now
3615 			if (start) {
3616 				startSendingLong(loblength);
3617 				start=false;
3618 			}
3619 
3620 			// send the segment we just got
3621 			sendLongSegment(lobbuffer,charsread);
3622 
3623 			// FIXME: or should this be charsread?
3624 			offset=offset+charstoread;
3625 		}
3626 	}
3627 }
3628 
startSendingLong(uint64_t longlength)3629 void sqlrprotocol_sqlrclient::startSendingLong(uint64_t longlength) {
3630 	debugFunction();
3631 	clientsock->write((uint16_t)START_LONG_DATA);
3632 	clientsock->write(longlength);
3633 }
3634 
sendLongSegment(const char * data,uint32_t size)3635 void sqlrprotocol_sqlrclient::sendLongSegment(const char *data, uint32_t size) {
3636 	debugFunction();
3637 
3638 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3639 		debugstr.append(data,size);
3640 	}
3641 
3642 	clientsock->write((uint16_t)STRING_DATA);
3643 	clientsock->write(size);
3644 	clientsock->write(data,size);
3645 }
3646 
endSendingLong()3647 void sqlrprotocol_sqlrclient::endSendingLong() {
3648 	debugFunction();
3649 
3650 	if (cont->logEnabled() || cont->notificationsEnabled()) {
3651 		debugstr.append(",");
3652 	}
3653 
3654 	clientsock->write((uint16_t)END_LONG_DATA);
3655 }
3656 
returnError(bool forcedisconnect)3657 void sqlrprotocol_sqlrclient::returnError(bool forcedisconnect) {
3658 	debugFunction();
3659 
3660 	cont->raiseDebugMessageEvent("returning error...");
3661 
3662 	const char	*errorstring;
3663 	uint32_t	errorlength;
3664 	int64_t		errnum;
3665 	bool		liveconnection;
3666 	cont->errorMessage(&errorstring,&errorlength,&errnum,&liveconnection);
3667 
3668 	// send the appropriate error status
3669 	if (forcedisconnect || !liveconnection) {
3670 		clientsock->write((uint16_t)ERROR_OCCURRED_DISCONNECT);
3671 	} else {
3672 		clientsock->write((uint16_t)ERROR_OCCURRED);
3673 	}
3674 
3675 	// send the error code and error string
3676 	clientsock->write((uint64_t)errnum);
3677 
3678 	// send the error string
3679 	clientsock->write((uint16_t)errorlength);
3680 	clientsock->write(errorstring,errorlength);
3681 	clientsock->flushWriteBuffer(-1,-1);
3682 
3683 	cont->raiseDebugMessageEvent("done returning error");
3684 
3685 	cont->raiseDbErrorEvent(NULL,errorstring);
3686 }
3687 
returnError(sqlrservercursor * cursor,bool forcedisconnect)3688 void sqlrprotocol_sqlrclient::returnError(sqlrservercursor *cursor,
3689 						bool forcedisconnect) {
3690 	debugFunction();
3691 
3692 	cont->raiseDebugMessageEvent("returning error...");
3693 
3694 	const char	*errorstring;
3695 	uint32_t	errorlength;
3696 	int64_t		errnum;
3697 	bool		liveconnection;
3698 	cont->errorMessage(cursor,&errorstring,&errorlength,
3699 					&errnum,&liveconnection);
3700 
3701 	// send the appropriate error status
3702 	if (forcedisconnect || !liveconnection) {
3703 		clientsock->write((uint16_t)ERROR_OCCURRED_DISCONNECT);
3704 	} else {
3705 		clientsock->write((uint16_t)ERROR_OCCURRED);
3706 	}
3707 
3708 	// send the error code
3709 	clientsock->write((uint64_t)errnum);
3710 
3711 	// send the error string
3712 	clientsock->write((uint16_t)errorlength);
3713 	clientsock->write(errorstring,errorlength);
3714 
3715 	// client will be sending skip/fetch, better get
3716 	// it even though we're not going to use it
3717 	uint64_t	skipfetch;
3718 	clientsock->read(&skipfetch,idleclienttimeout,0);
3719 	clientsock->read(&skipfetch,idleclienttimeout,0);
3720 
3721 	// Even though there was an error, we still
3722 	// need to send the client the id of the
3723 	// cursor that it's going to use.
3724 	clientsock->write(cont->getId(cursor));
3725 	clientsock->flushWriteBuffer(-1,-1);
3726 
3727 	cont->raiseDebugMessageEvent("done returning error");
3728 
3729 	cont->raiseDbErrorEvent(cursor,errorstring);
3730 }
3731 
fetchResultSetCommand(sqlrservercursor * cursor)3732 bool sqlrprotocol_sqlrclient::fetchResultSetCommand(
3733 					sqlrservercursor *cursor) {
3734 	debugFunction();
3735 	cont->raiseDebugMessageEvent("fetching result set...");
3736 	bool	retval=returnResultSetData(cursor,true,true);
3737 	cont->raiseDebugMessageEvent("done fetching result set");
3738 	return retval;
3739 }
3740 
abortResultSetCommand(sqlrservercursor * cursor)3741 void sqlrprotocol_sqlrclient::abortResultSetCommand(
3742 					sqlrservercursor *cursor) {
3743 	debugFunction();
3744 	cont->raiseDebugMessageEvent("aborting result set...");
3745 	cont->abort(cursor);
3746 	cont->raiseDebugMessageEvent("done aborting result set");
3747 }
3748 
suspendResultSetCommand(sqlrservercursor * cursor)3749 void sqlrprotocol_sqlrclient::suspendResultSetCommand(
3750 					sqlrservercursor *cursor) {
3751 	debugFunction();
3752 	cont->raiseDebugMessageEvent("suspend result set...");
3753 	cont->suspendResultSet(cursor);
3754 	cont->raiseDebugMessageEvent("done suspending result set");
3755 }
3756 
resumeResultSetCommand(sqlrservercursor * cursor)3757 bool sqlrprotocol_sqlrclient::resumeResultSetCommand(
3758 					sqlrservercursor *cursor) {
3759 	debugFunction();
3760 	cont->raiseDebugMessageEvent("resume result set...");
3761 
3762 	bool	retval=true;
3763 
3764 	if (cont->getState(cursor)==SQLRCURSORSTATE_SUSPENDED) {
3765 
3766 		cont->raiseDebugMessageEvent(
3767 				"previous result set was suspended");
3768 
3769 		// indicate that no error has occurred
3770 		clientsock->write((uint16_t)NO_ERROR_OCCURRED);
3771 
3772 		// send the client the id of the
3773 		// cursor that it's going to use
3774 		clientsock->write(cont->getId(cursor));
3775 		clientsock->write((uint16_t)SUSPENDED_RESULT_SET);
3776 
3777 		// if the requested cursor really had a suspended
3778 		// result set, send the index of the last row that
3779 		// was fetched to the client then resume the result set
3780 		// (FIXME: 0 will be sent if no rows were fetched or if
3781 		// only the first row was fetched. This probably isn't
3782 		// correct.)
3783 		uint64_t	totalrowsfetched=
3784 				cont->getTotalRowsFetched(cursor);
3785 		clientsock->write((totalrowsfetched)?totalrowsfetched-1:0);
3786 
3787 		returnResultSetHeader(cursor);
3788 		retval=returnResultSetData(cursor,true,false);
3789 
3790 	} else {
3791 
3792 		cont->raiseDebugMessageEvent(
3793 				"previous result set was not suspended");
3794 
3795 		// indicate that an error has occurred
3796 		clientsock->write((uint16_t)ERROR_OCCURRED);
3797 
3798 		// send the error code (zero for now)
3799 		clientsock->write((uint64_t)SQLR_ERROR_RESULTSETNOTSUSPENDED);
3800 
3801 		// send the error itself
3802 		uint16_t	len=charstring::length(
3803 				SQLR_ERROR_RESULTSETNOTSUSPENDED_STRING);
3804 		clientsock->write(len);
3805 		clientsock->write(SQLR_ERROR_RESULTSETNOTSUSPENDED_STRING,len);
3806 
3807 		retval=false;
3808 	}
3809 
3810 	cont->raiseDebugMessageEvent("done resuming result set");
3811 	return retval;
3812 }
3813 
getDatabaseListCommand(sqlrservercursor * cursor)3814 bool sqlrprotocol_sqlrclient::getDatabaseListCommand(
3815 					sqlrservercursor *cursor) {
3816 	debugFunction();
3817 	cont->raiseDebugMessageEvent("get db list...");
3818 	bool	retval=getListCommand(cursor,
3819 				SQLRCLIENTQUERYTYPE_DATABASE_LIST,false);
3820 	cont->raiseDebugMessageEvent("done getting db list");
3821 	return retval;
3822 }
3823 
getSchemaListCommand(sqlrservercursor * cursor)3824 bool sqlrprotocol_sqlrclient::getSchemaListCommand(
3825 					sqlrservercursor *cursor) {
3826 	debugFunction();
3827 	cont->raiseDebugMessageEvent("get schema list...");
3828 	bool	retval=getListCommand(cursor,
3829 				SQLRCLIENTQUERYTYPE_SCHEMA_LIST,false);
3830 	cont->raiseDebugMessageEvent("done getting schema list");
3831 	return retval;
3832 }
3833 
getTableListCommand(sqlrservercursor * cursor)3834 bool sqlrprotocol_sqlrclient::getTableListCommand(
3835 					sqlrservercursor *cursor) {
3836 	debugFunction();
3837 	cont->raiseDebugMessageEvent("get table list...");
3838 	bool	retval=getListCommand(cursor,
3839 				SQLRCLIENTQUERYTYPE_TABLE_LIST,false);
3840 	cont->raiseDebugMessageEvent("done getting table list");
3841 	return retval;
3842 }
3843 
getTableList2Command(sqlrservercursor * cursor)3844 bool sqlrprotocol_sqlrclient::getTableList2Command(
3845 					sqlrservercursor *cursor) {
3846 	debugFunction();
3847 	cont->raiseDebugMessageEvent("get table list...");
3848 	bool	retval=getListCommand(cursor,
3849 				SQLRCLIENTQUERYTYPE_TABLE_LIST_2,false);
3850 	cont->raiseDebugMessageEvent("done getting table list");
3851 	return retval;
3852 }
3853 
getTableTypeListCommand(sqlrservercursor * cursor)3854 bool sqlrprotocol_sqlrclient::getTableTypeListCommand(
3855 					sqlrservercursor *cursor) {
3856 	debugFunction();
3857 	cont->raiseDebugMessageEvent("get table type list...");
3858 	bool	retval=getListCommand(cursor,
3859 				SQLRCLIENTQUERYTYPE_TABLE_TYPE_LIST,false);
3860 	cont->raiseDebugMessageEvent("done getting table type list");
3861 	return retval;
3862 }
3863 
getColumnListCommand(sqlrservercursor * cursor)3864 bool sqlrprotocol_sqlrclient::getColumnListCommand(
3865 					sqlrservercursor *cursor) {
3866 	debugFunction();
3867 	cont->raiseDebugMessageEvent("get column list...");
3868 	bool	retval=getListCommand(cursor,
3869 				SQLRCLIENTQUERYTYPE_COLUMN_LIST,true);
3870 	cont->raiseDebugMessageEvent("done getting column list");
3871 	return retval;
3872 }
3873 
getPrimaryKeyListCommand(sqlrservercursor * cursor)3874 bool sqlrprotocol_sqlrclient::getPrimaryKeyListCommand(
3875 					sqlrservercursor *cursor) {
3876 	debugFunction();
3877 	cont->raiseDebugMessageEvent("get primary key list...");
3878 	bool	retval=getListCommand(cursor,
3879 				SQLRCLIENTQUERYTYPE_PRIMARY_KEY_LIST,true);
3880 	cont->raiseDebugMessageEvent("done getting primary key list");
3881 	return retval;
3882 }
3883 
getKeyAndIndexListCommand(sqlrservercursor * cursor)3884 bool sqlrprotocol_sqlrclient::getKeyAndIndexListCommand(
3885 					sqlrservercursor *cursor) {
3886 	debugFunction();
3887 	cont->raiseDebugMessageEvent("get key and index list...");
3888 	bool	retval=getListCommand(cursor,
3889 				SQLRCLIENTQUERYTYPE_KEY_AND_INDEX_LIST,true);
3890 	cont->raiseDebugMessageEvent("done getting key and index list");
3891 	return retval;
3892 }
3893 
getProcedureBindAndColumnListCommand(sqlrservercursor * cursor)3894 bool sqlrprotocol_sqlrclient::getProcedureBindAndColumnListCommand(
3895 						sqlrservercursor *cursor) {
3896 	debugFunction();
3897 	cont->raiseDebugMessageEvent("get procedure bind and column list...");
3898 	bool	retval=getListCommand(cursor,
3899 		SQLRCLIENTQUERYTYPE_PROCEDURE_BIND_AND_COLUMN_LIST,true);
3900 	cont->raiseDebugMessageEvent("done getting procedure "
3901 					"bind and column list");
3902 	return retval;
3903 }
3904 
getTypeInfoListCommand(sqlrservercursor * cursor)3905 bool sqlrprotocol_sqlrclient::getTypeInfoListCommand(
3906 					sqlrservercursor *cursor) {
3907 	debugFunction();
3908 	cont->raiseDebugMessageEvent("get type info list...");
3909 	bool	retval=getListCommand(cursor,
3910 				SQLRCLIENTQUERYTYPE_TYPE_INFO_LIST,true);
3911 	cont->raiseDebugMessageEvent("done getting type info list");
3912 	return retval;
3913 }
3914 
getProcedureListCommand(sqlrservercursor * cursor)3915 bool sqlrprotocol_sqlrclient::getProcedureListCommand(
3916 					sqlrservercursor *cursor) {
3917 	debugFunction();
3918 	cont->raiseDebugMessageEvent("get procedure list...");
3919 	bool	retval=getListCommand(cursor,
3920 				SQLRCLIENTQUERYTYPE_PROCEDURE_LIST,false);
3921 	cont->raiseDebugMessageEvent("done getting procedure list");
3922 	return retval;
3923 }
3924 
3925 
getListCommand(sqlrservercursor * cursor,sqlrclientquerytype_t querytype,bool getobject)3926 bool sqlrprotocol_sqlrclient::getListCommand(sqlrservercursor *cursor,
3927 					sqlrclientquerytype_t querytype,
3928 					bool getobject) {
3929 	debugFunction();
3930 
3931 	// if we're using a custom cursor then close it
3932 	// FIXME: push up?
3933 	sqlrservercursor	*customcursor=cursor->getCustomQueryCursor();
3934 	if (customcursor) {
3935 		customcursor->close();
3936 		cursor->clearCustomQueryCursor();
3937 	}
3938 
3939 	// get the list format
3940 	uint16_t	listformat;
3941 	ssize_t		result=clientsock->read(&listformat,
3942 						idleclienttimeout,0);
3943 	if (result!=sizeof(uint16_t)) {
3944 		cont->raiseClientProtocolErrorEvent(cursor,
3945 				"get list failed: "
3946 				"failed to get list format",result);
3947 		return false;
3948 	}
3949 
3950 	// get length of wild parameter
3951 	uint32_t	wildlen;
3952 	result=clientsock->read(&wildlen,idleclienttimeout,0);
3953 	if (result!=sizeof(uint32_t)) {
3954 		cont->raiseClientProtocolErrorEvent(cursor,
3955 				"get list failed: "
3956 				"failed to get wild length",result);
3957 		return false;
3958 	}
3959 
3960 	// bounds checking
3961 	if (wildlen>maxquerysize) {
3962 		debugstr.clear();
3963 		debugstr.append("get list failed: wild length too large: ");
3964 		debugstr.append(wildlen);
3965 		cont->raiseClientProtocolErrorEvent(
3966 					cursor,debugstr.getString(),1);
3967 		return false;
3968 	}
3969 
3970 	// read the wild parameter into the buffer
3971 	char	*wild=new char[wildlen+1];
3972 	if (wildlen) {
3973 		result=clientsock->read(wild,wildlen,idleclienttimeout,0);
3974 		if ((uint32_t)result!=wildlen) {
3975 			cont->raiseClientProtocolErrorEvent(cursor,
3976 					"get list failed: "
3977 					"failed to get wild parameter",result);
3978 			return false;
3979 		}
3980 	}
3981 	wild[wildlen]='\0';
3982 
3983 	// read the object parameter into the buffer
3984 	char	*object=NULL;
3985 	if (getobject) {
3986 
3987 		// get length of object parameter
3988 		uint32_t	objectlen;
3989 		result=clientsock->read(&objectlen,idleclienttimeout,0);
3990 		if (result!=sizeof(uint32_t)) {
3991 			cont->raiseClientProtocolErrorEvent(cursor,
3992 					"get list failed: "
3993 					"failed to get object length",result);
3994 			return false;
3995 		}
3996 
3997 		// bounds checking
3998 		if (objectlen>maxquerysize) {
3999 			debugstr.clear();
4000 			debugstr.append("get list failed: "
4001 					"object length too large: ");
4002 			debugstr.append(objectlen);
4003 			cont->raiseClientProtocolErrorEvent(
4004 					cursor,debugstr.getString(),1);
4005 			return false;
4006 		}
4007 
4008 		// read the object parameter into the buffer
4009 		object=new char[objectlen+1];
4010 		if (objectlen) {
4011 			result=clientsock->read(object,objectlen,
4012 						idleclienttimeout,0);
4013 			if ((uint32_t)result!=objectlen) {
4014 				cont->raiseClientProtocolErrorEvent(cursor,
4015 					"get list failed: "
4016 					"failed to get object parameter",
4017 					result);
4018 				return false;
4019 			}
4020 		}
4021 		object[objectlen]='\0';
4022 
4023 		// some apps aren't well behaved, trim spaces off of both sides
4024 		charstring::bothTrim(object);
4025 
4026 		// translate object name, if necessary
4027 		const char	*newobject=cont->translateTableName(object);
4028 		if (newobject) {
4029 			delete[] object;
4030 			object=charstring::duplicate(newobject);
4031 		}
4032 	}
4033 
4034 	// read the object types
4035 	uint16_t	objecttypes=0;
4036 	if (querytype==SQLRCLIENTQUERYTYPE_TABLE_LIST_2) {
4037 
4038 		result=clientsock->read(&objecttypes,idleclienttimeout,0);
4039 		if (result!=sizeof(uint16_t)) {
4040 			cont->raiseClientProtocolErrorEvent(cursor,
4041 					"get list failed: "
4042 					"failed to get object types",
4043 					result);
4044 			return false;
4045 		}
4046 	}
4047 
4048 	// set the values that we won't get from the client
4049 	cont->setInputBindCount(cursor,0);
4050 	cont->setOutputBindCount(cursor,0);
4051 	cont->setInputOutputBindCount(cursor,0);
4052 	cont->setSendColumnInfo(SEND_COLUMN_INFO);
4053 
4054 	// get the list and return it
4055 	bool	retval=true;
4056 	if (cont->getListsByApiCalls()) {
4057 		retval=getListByApiCall(cursor,querytype,object,wild,
4058 					(sqlrserverlistformat_t)listformat,
4059 					objecttypes);
4060 	} else {
4061 		retval=getListByQuery(cursor,querytype,object,wild,
4062 					(sqlrserverlistformat_t)listformat,
4063 					objecttypes);
4064 	}
4065 
4066 	// clean up
4067 	delete[] wild;
4068 	delete[] object;
4069 
4070 	return retval;
4071 }
4072 
getListByApiCall(sqlrservercursor * cursor,sqlrclientquerytype_t querytype,const char * object,const char * wild,sqlrserverlistformat_t listformat,uint16_t objecttypes)4073 bool sqlrprotocol_sqlrclient::getListByApiCall(sqlrservercursor *cursor,
4074 					sqlrclientquerytype_t querytype,
4075 					const char *object,
4076 					const char *wild,
4077 					sqlrserverlistformat_t listformat,
4078 					uint16_t objecttypes) {
4079 	debugFunction();
4080 
4081 	// initialize flags andbuffers
4082 	bool	success=false;
4083 
4084 	// get the appropriate list
4085 	switch (querytype) {
4086 		case SQLRCLIENTQUERYTYPE_DATABASE_LIST:
4087 			cont->setDatabaseListColumnMap(listformat);
4088 			success=cont->getDatabaseList(cursor,wild);
4089 			break;
4090 		case SQLRCLIENTQUERYTYPE_SCHEMA_LIST:
4091 			cont->setSchemaListColumnMap(listformat);
4092 			success=cont->getSchemaList(cursor,wild);
4093 			break;
4094 		case SQLRCLIENTQUERYTYPE_TABLE_LIST:
4095 		case SQLRCLIENTQUERYTYPE_TABLE_LIST_2:
4096 			cont->setTableListColumnMap(listformat);
4097 			success=cont->getTableList(cursor,wild,objecttypes);
4098 			break;
4099 		case SQLRCLIENTQUERYTYPE_TABLE_TYPE_LIST:
4100 			cont->setTableTypeListColumnMap(listformat);
4101 			success=cont->getTableTypeList(cursor,wild);
4102 			break;
4103 		case SQLRCLIENTQUERYTYPE_COLUMN_LIST:
4104 			cont->setColumnListColumnMap(listformat);
4105 			success=cont->getColumnList(cursor,object,wild);
4106 			break;
4107 		case SQLRCLIENTQUERYTYPE_PRIMARY_KEY_LIST:
4108 			cont->setPrimaryKeyListColumnMap(listformat);
4109 			success=cont->getPrimaryKeyList(cursor,object,wild);
4110 			break;
4111 		case SQLRCLIENTQUERYTYPE_KEY_AND_INDEX_LIST:
4112 			cont->setKeyAndIndexListColumnMap(listformat);
4113 			success=cont->getKeyAndIndexList(cursor,object,wild);
4114 			break;
4115 		case SQLRCLIENTQUERYTYPE_PROCEDURE_BIND_AND_COLUMN_LIST:
4116 			cont->setProcedureBindAndColumnListColumnMap(
4117 								listformat);
4118 			success=cont->getProcedureBindAndColumnList(
4119 							cursor,object,wild);
4120 			break;
4121 		case SQLRCLIENTQUERYTYPE_TYPE_INFO_LIST:
4122 			cont->setTypeInfoListColumnMap(listformat);
4123 			success=cont->getTypeInfoList(cursor,object,wild);
4124 			break;
4125 		case SQLRCLIENTQUERYTYPE_PROCEDURE_LIST:
4126 			cont->setProcedureListColumnMap(listformat);
4127 			success=cont->getProcedureList(cursor,wild);
4128 		default:
4129 			break;
4130 	}
4131 
4132 	if (success) {
4133 		success=getSkipAndFetch(true,cursor);
4134 	}
4135 
4136 	// if an error occurred...
4137 	if (!success) {
4138 		returnError(cursor,false);
4139 
4140 		// this is actually OK, only return false on a network error
4141 		return true;
4142 	}
4143 
4144 	// indicate that no error has occurred
4145 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
4146 
4147 	// send the client the id of the
4148 	// cursor that it's going to use
4149 	clientsock->write(cont->getId(cursor));
4150 
4151 	// tell the client that this is not a
4152 	// suspended result set
4153 	clientsock->write((uint16_t)NO_SUSPENDED_RESULT_SET);
4154 
4155 	// if the query processed ok then send a result set header and return...
4156 	returnResultSetHeader(cursor);
4157 	if (!returnResultSetData(cursor,false,false)) {
4158 		return false;
4159 	}
4160 	return true;
4161 }
4162 
getListByQuery(sqlrservercursor * cursor,sqlrclientquerytype_t querytype,const char * object,const char * wild,sqlrserverlistformat_t listformat,uint16_t objecttypes)4163 bool sqlrprotocol_sqlrclient::getListByQuery(sqlrservercursor *cursor,
4164 					sqlrclientquerytype_t querytype,
4165 					const char *object,
4166 					const char *wild,
4167 					sqlrserverlistformat_t listformat,
4168 					uint16_t objecttypes) {
4169 	debugFunction();
4170 
4171 	// build the appropriate query
4172 	const char	*query=NULL;
4173 	bool		havewild=charstring::length(wild);
4174 	switch (querytype) {
4175 		case SQLRCLIENTQUERYTYPE_DATABASE_LIST:
4176 			query=cont->getDatabaseListQuery(havewild);
4177 			break;
4178 		case SQLRCLIENTQUERYTYPE_SCHEMA_LIST:
4179 			query=cont->getSchemaListQuery(havewild);
4180 			break;
4181 		case SQLRCLIENTQUERYTYPE_TABLE_LIST:
4182 		case SQLRCLIENTQUERYTYPE_TABLE_LIST_2:
4183 			query=cont->getTableListQuery(havewild,objecttypes);
4184 			break;
4185 		case SQLRCLIENTQUERYTYPE_TABLE_TYPE_LIST:
4186 			query=cont->getTableTypeListQuery(havewild);
4187 			break;
4188 		case SQLRCLIENTQUERYTYPE_COLUMN_LIST:
4189 			query=cont->getColumnListQuery(object,havewild);
4190 			break;
4191 		case SQLRCLIENTQUERYTYPE_PRIMARY_KEY_LIST:
4192 			query=cont->getPrimaryKeyListQuery(object,havewild);
4193 			break;
4194 		case SQLRCLIENTQUERYTYPE_KEY_AND_INDEX_LIST:
4195 			query=cont->getKeyAndIndexListQuery(object,havewild);
4196 			break;
4197 		case SQLRCLIENTQUERYTYPE_PROCEDURE_BIND_AND_COLUMN_LIST:
4198 			query=cont->getProcedureBindAndColumnListQuery(
4199 							object,havewild);
4200 			break;
4201 		case SQLRCLIENTQUERYTYPE_TYPE_INFO_LIST:
4202 			query=cont->getTypeInfoListQuery(object,havewild);
4203 			break;
4204 		case SQLRCLIENTQUERYTYPE_PROCEDURE_LIST:
4205 			query=cont->getProcedureListQuery(havewild);
4206 			break;
4207 		default:
4208 			break;
4209 	}
4210 
4211 	// FIXME: this can fail
4212 	buildListQuery(cursor,query,wild,object);
4213 
4214 	return processQueryOrBindCursor(cursor,querytype,
4215 					listformat,false,false);
4216 }
4217 
buildListQuery(sqlrservercursor * cursor,const char * query,const char * wild,const char * object)4218 bool sqlrprotocol_sqlrclient::buildListQuery(sqlrservercursor *cursor,
4219 						const char *query,
4220 						const char *wild,
4221 						const char *object) {
4222 	debugFunction();
4223 
4224 	// If the object was given like catalog.schema.object, then just
4225 	// get the object.
4226 	const char	*realobject=charstring::findLast(object,".");
4227 	if (realobject) {
4228 		realobject++;
4229 	} else {
4230 		realobject=object;
4231 	}
4232 
4233 	// clean up buffers to avoid SQL injection
4234 	stringbuffer	wildbuf;
4235 	escapeParameter(&wildbuf,wild);
4236 	stringbuffer	objectbuf;
4237 	escapeParameter(&objectbuf,realobject);
4238 
4239 	// bounds checking
4240 	cont->setQueryLength(cursor,charstring::length(query)+
4241 					wildbuf.getStringLength()+
4242 					objectbuf.getStringLength());
4243 	if (cont->getQueryLength(cursor)>maxquerysize) {
4244 		return false;
4245 	}
4246 
4247 	// fill the query buffer and update the length
4248 	char	*querybuffer=cont->getQueryBuffer(cursor);
4249 	if (objectbuf.getStringLength()) {
4250 		charstring::printf(querybuffer,maxquerysize+1,
4251 						query,objectbuf.getString(),
4252 						wildbuf.getString());
4253 	} else {
4254 		charstring::printf(querybuffer,maxquerysize+1,
4255 						query,wildbuf.getString());
4256 	}
4257 	cont->setQueryLength(cursor,charstring::length(querybuffer));
4258 	return true;
4259 }
4260 
escapeParameter(stringbuffer * buffer,const char * parameter)4261 void sqlrprotocol_sqlrclient::escapeParameter(stringbuffer *buffer,
4262 						const char *parameter) {
4263 	debugFunction();
4264 
4265 	if (!parameter) {
4266 		return;
4267 	}
4268 
4269 	// escape single quotes
4270 	for (const char *ptr=parameter; *ptr; ptr++) {
4271 		if (*ptr=='\'') {
4272 			buffer->append('\'');
4273 		}
4274 		buffer->append(*ptr);
4275 	}
4276 }
4277 
getQueryTreeCommand(sqlrservercursor * cursor)4278 bool sqlrprotocol_sqlrclient::getQueryTreeCommand(sqlrservercursor *cursor) {
4279 	debugFunction();
4280 
4281 	cont->raiseDebugMessageEvent("getting query tree");
4282 
4283 	// get the tree as a string
4284 	xmldom	*tree=cont->getQueryTree(cursor);
4285 	domnode	*root=(tree)?tree->getRootNode():NULL;
4286 	stringbuffer	xml;
4287 	if (root) {
4288 		root->write(&xml);
4289 	}
4290 
4291 	// send the tree
4292 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
4293 	clientsock->write((uint64_t)xml.getStringLength());
4294 	clientsock->write(xml.getString(),xml.getStringLength());
4295 	clientsock->flushWriteBuffer(-1,-1);
4296 
4297 	return true;
4298 }
4299 
getTranslatedQueryCommand(sqlrservercursor * cursor)4300 bool sqlrprotocol_sqlrclient::getTranslatedQueryCommand(
4301 					sqlrservercursor *cursor) {
4302 	debugFunction();
4303 
4304 	cont->raiseDebugMessageEvent("getting translated query");
4305 
4306 	// get the query
4307 	const char	*query=cont->getTranslatedQuery(cursor);
4308 	uint64_t	querylen=charstring::length(query);
4309 
4310 	// send the tree
4311 	clientsock->write((uint16_t)NO_ERROR_OCCURRED);
4312 	clientsock->write(querylen);
4313 	clientsock->write(query,querylen);
4314 	clientsock->flushWriteBuffer(-1,-1);
4315 
4316 	return true;
4317 }
4318 
getGSSContext()4319 gsscontext *sqlrprotocol_sqlrclient::getGSSContext() {
4320 	return &gctx;
4321 }
4322 
getTLSContext()4323 tlscontext *sqlrprotocol_sqlrclient::getTLSContext() {
4324 	return &tctx;
4325 }
4326 
4327 extern "C" {
new_sqlrprotocol_sqlrclient(sqlrservercontroller * cont,sqlrprotocols * ps,domnode * parameters)4328 	SQLRSERVER_DLLSPEC sqlrprotocol	*new_sqlrprotocol_sqlrclient(
4329 						sqlrservercontroller *cont,
4330 						sqlrprotocols *ps,
4331 						domnode *parameters) {
4332 		return new sqlrprotocol_sqlrclient(cont,ps,parameters);
4333 	}
4334 }
4335