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