1 // Copyright (c) 1999-2018 David Muse
2 // See the file COPYING for more information
3
4 #include <sqlrelay/sqlrserver.h>
5 #include <rudiments/bytestring.h>
6 #include <rudiments/character.h>
7 #include <rudiments/snooze.h>
8 #include <rudiments/regularexpression.h>
9
10 #include <datatypes.h>
11 #include <defines.h>
12 #include <config.h>
13
14 #include <sqlrelay/sqlrclient.h>
15
16 struct outputbindvar {
17 const char *variable;
18 union {
19 char *stringvalue;
20 int64_t *intvalue;
21 double *doublevalue;
22 struct {
23 int16_t *year;
24 int16_t *month;
25 int16_t *day;
26 int16_t *hour;
27 int16_t *minute;
28 int16_t *second;
29 int32_t *microsecond;
30 const char **tz;
31 bool *isnegative;
32 } datevalue;
33 } value;
34 uint32_t valuesize;
35 sqlrserverbindvartype_t type;
36 int16_t *isnull;
37 };
38
39 struct cursorbindvar {
40 const char *variable;
41 sqlrservercursor *cursor;
42 };
43
44 class routercursor;
45
46 class SQLRSERVER_DLLSPEC routerconnection : public sqlrserverconnection {
47 friend class routercursor;
48 public:
49 routerconnection(sqlrservercontroller *cont);
50 ~routerconnection();
51 private:
52 bool supportsAuthOnDatabase();
53 void handleConnectString();
54 bool logIn(const char **error, const char **warning);
55 sqlrservercursor *newCursor(uint16_t id);
56 void deleteCursor(sqlrservercursor *curs);
57 void logOut();
58 bool autoCommitOn();
59 bool autoCommitOff();
60 bool supportsAutoCommit();
61 bool begin();
62 bool commit();
63 bool rollback();
64 void errorMessage(char *errorbuffer,
65 uint32_t errorbufferlength,
66 uint32_t *errorlength,
67 int64_t *errorcode,
68 bool *liveconnection);
69 const char *identify();
70 const char *dbVersion();
71 const char *dbHostName();
72 const char *dbIpAddress();
73 bool cacheDbHostInfo();
74 bool getListsByApiCalls();
75 bool getDatabaseList(sqlrservercursor *cursor,
76 const char *wild);
77 bool getTableList(sqlrservercursor *cursor,
78 const char *wild,
79 uint16_t objecttypes);
80 bool getColumnList(sqlrservercursor *cursor,
81 const char *table,
82 const char *wild);
83 bool ping();
84 const char *selectDatabaseQuery();
85 char *getCurrentDatabase();
86 bool getLastInsertId(uint64_t *id);
87 void endSession();
88
89 void route(bool *routed, bool *err);
90
91 void autoCommitOnFailed(uint16_t index);
92 void autoCommitOffFailed(uint16_t index);
93 void beginFailed(uint16_t index);
94 void commitFailed(uint16_t index);
95 void rollbackFailed(uint16_t index);
96 void beginQueryFailed(uint16_t index);
97 void raiseIntegrityViolationEvent(const char *command,
98 uint16_t index);
99 const char *identity;
100
101 const char **conids;
102 sqlrconnection **cons;
103 uint16_t concount;
104 const char **beginquery;
105 bool anymustbegin;
106
107 sqlrconnection *currentcon;
108 uint16_t currentconindex;
109
110 bool justloggedin;
111
112 int16_t nullbindvalue;
113 int16_t nonnullbindvalue;
114
115 sqlrrouters *sqlrr;
116
117 bool routeentiresession;
118
119 bool debug;
120
121 linkedlist< routercursor * > routercursors;
122 };
123
124 class SQLRSERVER_DLLSPEC routercursor : public sqlrservercursor {
125 friend class routerconnection;
126 private:
127 routercursor(sqlrserverconnection *conn,
128 uint16_t id);
129 ~routercursor();
130 bool prepareQuery(const char *query,
131 uint32_t length);
132 void route(bool *routed, bool *err);
133 bool supportsNativeBinds(const char *query,
134 uint32_t length);
135 bool inputBind(const char *variable,
136 uint16_t variablesize,
137 const char *value,
138 uint32_t valuesize,
139 int16_t *isnull);
140 bool inputBind(const char *variable,
141 uint16_t variablesize,
142 int64_t *value);
143 bool inputBind(const char *variable,
144 uint16_t variablesize,
145 double *value,
146 uint32_t precision,
147 uint32_t scale);
148 bool inputBind(const char *variable,
149 uint16_t variablesize,
150 int64_t year,
151 int16_t month,
152 int16_t day,
153 int16_t hour,
154 int16_t minute,
155 int16_t second,
156 int32_t microsecond,
157 const char *tz,
158 bool isnegative,
159 char *buffer,
160 uint16_t buffersize,
161 int16_t *isnull);
162 bool inputBindBlob(const char *variable,
163 uint16_t variablesize,
164 const char *value,
165 uint32_t valuesize,
166 int16_t *isnull);
167 bool inputBindClob(const char *variable,
168 uint16_t variablesize,
169 const char *value,
170 uint32_t valuesize,
171 int16_t *isnull);
172 bool outputBind(const char *variable,
173 uint16_t variablesize,
174 char *value,
175 uint32_t valuesize,
176 int16_t *isnull);
177 bool outputBind(const char *variable,
178 uint16_t variablesize,
179 int64_t *value,
180 int16_t *isnull);
181 bool outputBind(const char *variable,
182 uint16_t variablesize,
183 double *value,
184 uint32_t *precision,
185 uint32_t *scale,
186 int16_t *isnull);
187 bool outputBind(const char *variable,
188 uint16_t variablesize,
189 int16_t *year,
190 int16_t *month,
191 int16_t *day,
192 int16_t *hour,
193 int16_t *minute,
194 int16_t *second,
195 int32_t *microsecond,
196 const char **tz,
197 bool *isnegative,
198 char *buffer,
199 uint16_t buffersize,
200 int16_t *isnull);
201 bool outputBindBlob(const char *variable,
202 uint16_t variablesize,
203 uint16_t index,
204 int16_t *isnull);
205 bool outputBindClob(const char *variable,
206 uint16_t variablesize,
207 uint16_t index,
208 int16_t *isnull);
209 bool outputBindCursor(const char *variable,
210 uint16_t variablesize,
211 sqlrservercursor *cursor);
212 bool getLobOutputBindLength(uint16_t index,
213 uint64_t *length);
214 bool getLobOutputBindSegment(uint16_t index,
215 char *buffer,
216 uint64_t buffersize,
217 uint64_t offset,
218 uint64_t charstoread,
219 uint64_t *charsread);
220 bool executeQuery(const char *query,
221 uint32_t length);
222 void errorMessage(char *errorbuffer,
223 uint32_t errorbufferlength,
224 uint32_t *errorlength,
225 int64_t *errorcode,
226 bool *liveconnection);
227 bool knowsRowCount();
228 uint64_t rowCount();
229 uint64_t affectedRows();
230 uint32_t colCount();
231 uint16_t columnTypeFormat();
232 const char *getColumnName(uint32_t col);
233 const char *getColumnTypeName(uint32_t col);
234 uint32_t getColumnLength(uint32_t col);
235 uint32_t getColumnPrecision(uint32_t col);
236 uint32_t getColumnScale(uint32_t col);
237 uint16_t getColumnIsNullable(uint32_t col);
238 uint16_t getColumnIsPrimaryKey(uint32_t col);
239 uint16_t getColumnIsUnique(uint32_t col);
240 uint16_t getColumnIsPartOfKey(uint32_t col);
241 uint16_t getColumnIsUnsigned(uint32_t col);
242 uint16_t getColumnIsZeroFilled(uint32_t col);
243 uint16_t getColumnIsBinary(uint32_t col);
244 uint16_t getColumnIsAutoIncrement(uint32_t col);
245 const char *getColumnTable(uint32_t col);
246 bool noRowsToReturn();
247 bool fetchRow(bool *error);
248 void getField(uint32_t col,
249 const char **field,
250 uint64_t *fieldlength,
251 bool *blob,
252 bool *null);
253 void closeResultSet();
254
255 routerconnection *routerconn;
256
257 sqlrconnection *currentcon;
258 sqlrcursor *currentcur;
259
260 bool isbindcur;
261
262 sqlrcursor **curs;
263
264 uint64_t nextrow;
265
266 outputbindvar *obv;
267 uint16_t obcount;
268
269 cursorbindvar *cbv;
270 uint16_t cbcount;
271
272 bool emptyquery;
273 };
274
routerconnection(sqlrservercontroller * cont)275 routerconnection::routerconnection(sqlrservercontroller *cont) :
276 sqlrserverconnection(cont) {
277 identity=NULL;
278
279 conids=NULL;
280 cons=NULL;
281 concount=0;
282 currentcon=NULL;
283 currentconindex=0;
284 beginquery=NULL;
285 anymustbegin=false;
286 justloggedin=false;
287 nullbindvalue=nullBindValue();
288 nonnullbindvalue=nonNullBindValue();
289
290 sqlrr=NULL;
291 routeentiresession=false;
292
293 debug=cont->getConfig()->getDebugRouters();
294 }
295
~routerconnection()296 routerconnection::~routerconnection() {
297 for (uint16_t index=0; index<concount; index++) {
298 delete cons[index];
299 }
300 delete[] conids;
301 delete[] cons;
302 delete[] beginquery;
303 routercursors.clear();
304 delete sqlrr;
305 }
306
supportsAuthOnDatabase()307 bool routerconnection::supportsAuthOnDatabase() {
308 return false;
309 }
310
handleConnectString()311 void routerconnection::handleConnectString() {
312
313 identity=cont->getConnectStringValue("identity");
314
315 // re-get fetchatonce, defaulting to 10, and allowing it to be set to 0
316 uint32_t fetchatonce=10;
317 const char *fao=cont->getConnectStringValue("fetchatonce");
318 if (fao) {
319 fetchatonce=charstring::toUnsignedInteger(fao);
320 }
321 cont->setFetchAtOnce(fetchatonce);
322
323 cont->setMaxColumnCount(0);
324 cont->setMaxFieldLength(0);
325
326
327 // build the connections that we'll route to
328 // (this is just a convenient place to do it)
329 linkedlist< connectstringcontainer * > *cslist=
330 cont->getConfig()->getConnectStringList();
331 concount=cslist->getLength();
332
333 conids=new const char *[concount];
334 cons=new sqlrconnection *[concount];
335 beginquery=new const char *[concount];
336 anymustbegin=false;
337
338 uint16_t index=0;
339 connectstringnode *csln=cslist->getFirst();
340 while (index<concount) {
341
342 connectstringcontainer *csc=csln->getValue();
343
344 conids[index]=csc->getConnectionId();
345
346 cons[index]=new sqlrconnection(
347 csc->getConnectStringValue("server"),
348 charstring::toUnsignedInteger(
349 csc->getConnectStringValue("port")),
350 csc->getConnectStringValue("socket"),
351 csc->getConnectStringValue("user"),
352 csc->getConnectStringValue("password"),
353 0,1);
354
355 const char *id=cons[index]->identify();
356 if (!charstring::compare(id,"sap") ||
357 !charstring::compare(id,"sybase") ||
358 !charstring::compare(id,"freetds")) {
359 beginquery[index]="begin tran";
360 } else if (!charstring::compare(id,"sqlite")) {
361 beginquery[index]="begin transaction";
362 } else if (!charstring::compare(id,"postgresql") ||
363 !charstring::compare(id,"router")) {
364 beginquery[index]="begin";
365 } else {
366 beginquery[index]=NULL;
367 }
368
369 if (beginquery[index]) {
370 anymustbegin=true;
371 }
372
373 index++;
374 csln=csln->getNext();
375 }
376
377 // load the router modules
378 // (this is just a convenient place to do it)
379 domnode *routers=cont->getConfig()->getRouters();
380 if (!routers->isNullNode()) {
381 sqlrr=new sqlrrouters(cont,conids,cons,concount);
382 sqlrr->load(routers);
383 routeentiresession=sqlrr->routeEntireSession();
384 }
385 }
386
logIn(const char ** error,const char ** warning)387 bool routerconnection::logIn(const char **error, const char **warning) {
388
389 justloggedin=true;
390
391 while (!ping()) {
392 snooze::macrosnooze(1);
393 }
394 endSession();
395 return true;
396 }
397
newCursor(uint16_t id)398 sqlrservercursor *routerconnection::newCursor(uint16_t id) {
399 return (sqlrservercursor *)new routercursor(
400 (sqlrserverconnection *)this,id);
401 }
402
deleteCursor(sqlrservercursor * curs)403 void routerconnection::deleteCursor(sqlrservercursor *curs) {
404 delete (routercursor *)curs;
405 }
406
logOut()407 void routerconnection::logOut() {
408 }
409
autoCommitOn()410 bool routerconnection::autoCommitOn() {
411
412 if (debug) {
413 stdoutput.printf("autoCommitOn {\n");
414 }
415
416 if (justloggedin) {
417 justloggedin=false;
418 }
419
420 // route
421 bool routed=false;
422 bool err=false;
423 route(&routed,&err);
424 if (err) {
425 if (debug) {
426 stdoutput.printf(" routing error\n}\n");
427 }
428 return false;
429 }
430
431 // if routing entire sessions, then just enable for
432 // the appropriate connection
433 if (routed && routeentiresession) {
434 if (debug) {
435 stdoutput.printf(" only executing on: %s\n}\n",
436 (currentcon)?conids[currentconindex]:NULL);
437 }
438 return (currentcon)?currentcon->autoCommitOn():true;
439 }
440
441 // otherwise, turn autocommit on for all connections,
442 // if any fail, return failure
443 bool result=true;
444 for (uint16_t index=0; index<concount; index++) {
445
446 if (debug) {
447 stdoutput.printf(" executing on: %s\n",
448 conids[index]);
449 }
450
451 bool res=cons[index]->autoCommitOn();
452 if (!res) {
453 if (debug) {
454 stdoutput.printf(" failed\n");
455 }
456 autoCommitOnFailed(index);
457 }
458 // The connection class calls autoCommitOn or autoCommitOff
459 // immediately after logging in, which will cause the
460 // cons to connect to the relay's and tie them up unless we
461 // call endSession. We'd rather not tie them up until a
462 // client connects, so if we just logged in, we'll call
463 // endSession.
464 if (justloggedin) {
465 // if any of the connections must begin transactions,
466 // then those connections will start off in auto-commit
467 // mode no matter what, so put all connections in
468 // autocommit mode
469 // (this is a convenient place to do this...)
470 if (anymustbegin) {
471 cons[index]->autoCommitOn();
472 }
473 cons[index]->endSession();
474 }
475 if (result) {
476 result=res;
477 }
478 }
479
480 if (debug) {
481 stdoutput.printf("}\n");
482 }
483 return result;
484 }
485
autoCommitOff()486 bool routerconnection::autoCommitOff() {
487
488 if (debug) {
489 stdoutput.printf("autoCommitOff {\n");
490 }
491
492 if (justloggedin) {
493 justloggedin=false;
494 }
495
496 // route
497 bool routed=false;
498 bool err=false;
499 route(&routed,&err);
500 if (err) {
501 if (debug) {
502 stdoutput.printf(" routing error\n}\n");
503 }
504 return false;
505 }
506
507 // if routing entire sessions, then just disable for
508 // the appropriate connection
509 if (routed && routeentiresession) {
510 if (debug) {
511 stdoutput.printf(" only executing on: %s\n}\n",
512 (currentcon)?conids[currentconindex]:NULL);
513 }
514 return (currentcon)?currentcon->autoCommitOff():true;
515 }
516
517 // otherwise, turn autocommit on for all connections,
518 // if any fail, return failure
519 bool result=true;
520 for (uint16_t index=0; index<concount; index++) {
521
522 if (debug) {
523 stdoutput.printf(" executing on: %s\n",
524 conids[index]);
525 }
526
527 bool res=cons[index]->autoCommitOff();
528 if (!res) {
529 if (debug) {
530 stdoutput.printf(" failed\n");
531 }
532 autoCommitOffFailed(index);
533 }
534 // The connection class calls autoCommitOn or autoCommitOff
535 // immediately after logging in, which will cause the
536 // cons to connect to the relay's and tie them up unless we
537 // call endSession. We'd rather not tie them up until a
538 // client connects, so if we just logged in, we'll call
539 // endSession.
540 if (justloggedin) {
541 // if any of the connections must begin transactions,
542 // then those connections will start off in auto-commit
543 // mode no matter what, so put all connections in
544 // autocommit mode, even if autocommit-off is called
545 // here
546 // (this is a convenient place to do this...)
547 if (anymustbegin) {
548 cons[index]->autoCommitOn();
549 }
550 cons[index]->endSession();
551 }
552 if (result) {
553 result=res;
554 }
555 }
556
557 if (debug) {
558 stdoutput.printf("}\n");
559 }
560 return result;
561 }
562
supportsAutoCommit()563 bool routerconnection::supportsAutoCommit() {
564 return true;
565 }
566
begin()567 bool routerconnection::begin() {
568
569 if (debug) {
570 stdoutput.printf("begin {\n");
571 }
572
573 // route
574 bool routed=false;
575 bool err=false;
576 route(&routed,&err);
577 if (err) {
578 if (debug) {
579 stdoutput.printf(" routing error\n}\n");
580 }
581 return false;
582 }
583
584 // if routing entire sessions, then just begin for
585 // the appropriate connection
586 if (routed && routeentiresession) {
587 if (debug) {
588 stdoutput.printf(" only executing on: %s\n}\n",
589 (currentcon)?conids[currentconindex]:NULL);
590 }
591 return (currentcon)?currentcon->begin():true;
592 }
593
594 // otherwise, begin all connections, if any fail, return failure
595 bool result=true;
596 for (uint16_t index=0; index<concount; index++) {
597
598 if (debug) {
599 stdoutput.printf(" executing on: %s\n",
600 conids[index]);
601 }
602
603 bool res=cons[index]->begin();
604 if (!res) {
605 if (debug) {
606 stdoutput.printf(" failed\n");
607 }
608 beginFailed(index);
609 }
610 if (result) {
611 result=res;
612 }
613 }
614
615 if (debug) {
616 stdoutput.printf("}\n");
617 }
618 return result;
619 }
620
commit()621 bool routerconnection::commit() {
622
623 if (debug) {
624 stdoutput.printf("commit {\n");
625 }
626
627 // route
628 bool routed=false;
629 bool err=false;
630 route(&routed,&err);
631 if (err) {
632 if (debug) {
633 stdoutput.printf(" routing error\n}\n");
634 }
635 return false;
636 }
637
638 // if routing entire sessions, then just commit for
639 // the appropriate connection
640 if (routed && routeentiresession) {
641 if (debug) {
642 stdoutput.printf(" only executing on: %s\n}\n",
643 (currentcon)?conids[currentconindex]:NULL);
644 }
645 return (currentcon)?currentcon->commit():true;
646 }
647
648 // otherwise, commit all connections, if any fail, return failure
649 bool result=true;
650 for (uint16_t index=0; index<concount; index++) {
651
652 if (debug) {
653 stdoutput.printf(" executing on: %s\n",
654 conids[index]);
655 }
656
657 bool res=cons[index]->commit();
658 if (!res) {
659 if (debug) {
660 stdoutput.printf(" failed\n");
661 }
662 commitFailed(index);
663 }
664 if (result) {
665 result=res;
666 }
667 }
668
669 if (debug) {
670 stdoutput.printf("}\n");
671 }
672 return result;
673 }
674
rollback()675 bool routerconnection::rollback() {
676
677 if (debug) {
678 stdoutput.printf("rollback {\n");
679 }
680
681 // route
682 bool routed=false;
683 bool err=false;
684 route(&routed,&err);
685 if (err) {
686 if (debug) {
687 stdoutput.printf(" routing error\n}\n");
688 }
689 return false;
690 }
691
692 // if routing entire sessions, then just rollback for
693 // the appropriate connection
694 if (routed && routeentiresession) {
695 if (debug) {
696 stdoutput.printf(" only executing on: %s\n}\n",
697 (currentcon)?conids[currentconindex]:NULL);
698 }
699 return (currentcon)?currentcon->rollback():true;
700 }
701
702 // otherwise, rollback all connections, if any fail, return failure
703 bool result=true;
704 for (uint16_t index=0; index<concount; index++) {
705
706 if (debug) {
707 stdoutput.printf(" executing on: %s\n",
708 conids[index]);
709 }
710
711 bool res=cons[index]->rollback();
712 if (!res) {
713 if (debug) {
714 stdoutput.printf(" failed\n");
715 }
716 rollbackFailed(index);
717 }
718 if (result) {
719 result=res;
720 }
721 }
722
723 if (debug) {
724 stdoutput.printf("}\n");
725 }
726 return result;
727 }
728
errorMessage(char * errorbuffer,uint32_t errorbufferlength,uint32_t * errorlength,int64_t * errorcode,bool * liveconnection)729 void routerconnection::errorMessage(char *errorbuffer,
730 uint32_t errorbufferlength,
731 uint32_t *errorlength,
732 int64_t *errorcode,
733 bool *liveconnection) {
734
735 for (uint16_t index=0; index<concount; index++) {
736 const char *errormessage=cons[index]->errorMessage();
737 if (!charstring::length(errormessage)) {
738 *errorlength=charstring::length(errormessage);
739 charstring::safeCopy(errorbuffer,errorbufferlength,
740 errormessage,*errorlength);
741 *errorcode=cons[index]->errorNumber();
742 break;
743 }
744 }
745 *liveconnection=true;
746 }
747
identify()748 const char *routerconnection::identify() {
749 // FIXME: maybe this should only return router if there's no currentcon
750 return (identity)?identity:"router";
751 }
752
dbVersion()753 const char *routerconnection::dbVersion() {
754
755 if (debug) {
756 stdoutput.printf("dbVersion {\n");
757 }
758
759 // route
760 bool routed=false;
761 bool err=false;
762 route(&routed,&err);
763 if (err) {
764 if (debug) {
765 stdoutput.printf(" routing error\n}\n");
766 }
767 return NULL;
768 }
769
770 // if routing entire sessions, then get this for
771 // the appropriate connection
772 if (routeentiresession) {
773 if (debug) {
774 stdoutput.printf(" only executing on: %s\n}\n",
775 (currentcon)?conids[currentconindex]:NULL);
776 }
777 return (currentcon)?currentcon->dbVersion():NULL;
778 }
779
780 // otherwise, try to find a usable connection
781 if (!currentcon) {
782 for (uint16_t index=0; !currentcon && index<concount; index++) {
783 currentcon=cons[index];
784 currentconindex=index;
785 }
786 }
787
788 if (debug) {
789 stdoutput.printf(" executing on: %s\n",
790 (currentcon)?conids[currentconindex]:NULL);
791 }
792
793 const char *retval=(currentcon)?currentcon->dbVersion():NULL;
794 if (debug) {
795 stdoutput.printf(" db version: %s\n}\n",retval);
796 }
797 return retval;
798 }
799
dbHostName()800 const char *routerconnection::dbHostName() {
801
802 if (debug) {
803 stdoutput.printf("dbHostName {\n");
804 }
805
806 // route
807 bool routed=false;
808 bool err=false;
809 route(&routed,&err);
810 if (err) {
811 if (debug) {
812 stdoutput.printf(" routing error\n}\n");
813 }
814 return NULL;
815 }
816
817 // if routing entire sessions, then get this for
818 // the appropriate connection
819 if (routeentiresession) {
820 if (debug) {
821 stdoutput.printf(" only executing on: %s\n}\n",
822 (currentcon)?conids[currentconindex]:NULL);
823 }
824 return (currentcon)?currentcon->dbHostName():NULL;
825 }
826
827 // otherwise, try to find a usable connection
828 if (!currentcon) {
829 for (uint16_t index=0; !currentcon && index<concount; index++) {
830 currentcon=cons[index];
831 currentconindex=index;
832 }
833 }
834
835 if (debug) {
836 stdoutput.printf(" executing on: %s\n",
837 (currentcon)?conids[currentconindex]:NULL);
838 }
839
840 const char *retval=(currentcon)?currentcon->dbHostName():NULL;
841 if (debug) {
842 stdoutput.printf(" db hostname: %s\n}\n",retval);
843 }
844 return retval;
845 }
846
dbIpAddress()847 const char *routerconnection::dbIpAddress() {
848
849 if (debug) {
850 stdoutput.printf("dbIpAddress {\n");
851 }
852
853 // route
854 bool routed=false;
855 bool err=false;
856 route(&routed,&err);
857 if (err) {
858 if (debug) {
859 stdoutput.printf(" routing error\n}\n");
860 }
861 return NULL;
862 }
863
864 // if routing entire sessions, then get this for
865 // the appropriate connection
866 if (routeentiresession) {
867 if (debug) {
868 stdoutput.printf(" only executing on: %s\n}\n",
869 (currentcon)?conids[currentconindex]:NULL);
870 }
871 return (currentcon)?currentcon->dbIpAddress():NULL;
872 }
873
874 // otherwise, try to find a usable connection
875 if (!currentcon) {
876 for (uint16_t index=0; !currentcon && index<concount; index++) {
877 currentcon=cons[index];
878 currentconindex=index;
879 }
880 }
881
882 if (debug) {
883 stdoutput.printf(" executing on: %s\n",
884 (currentcon)?conids[currentconindex]:NULL);
885 }
886
887 const char *retval=(currentcon)?currentcon->dbIpAddress():NULL;
888 if (debug) {
889 stdoutput.printf(" db ip address: %s\n}\n",retval);
890 }
891 return retval;
892 }
893
cacheDbHostInfo()894 bool routerconnection::cacheDbHostInfo() {
895 return false;
896 }
897
getListsByApiCalls()898 bool routerconnection::getListsByApiCalls() {
899 return true;
900 }
901
getDatabaseList(sqlrservercursor * cursor,const char * wild)902 bool routerconnection::getDatabaseList(sqlrservercursor *cursor,
903 const char *wild) {
904 // FIXME: implement this
905 cont->setError(cursor,SQLR_ERROR_NOTIMPLEMENTED_STRING,
906 SQLR_ERROR_NOTIMPLEMENTED,true);
907 return false;
908 }
909
getTableList(sqlrservercursor * cursor,const char * wild,uint16_t objecttypes)910 bool routerconnection::getTableList(sqlrservercursor *cursor,
911 const char *wild,
912 uint16_t objecttypes) {
913 // FIXME: implement this
914 cont->setError(cursor,SQLR_ERROR_NOTIMPLEMENTED_STRING,
915 SQLR_ERROR_NOTIMPLEMENTED,true);
916 return false;
917 }
918
getColumnList(sqlrservercursor * cursor,const char * table,const char * wild)919 bool routerconnection::getColumnList(sqlrservercursor *cursor,
920 const char *table,
921 const char *wild) {
922 // FIXME: implement this
923 cont->setError(cursor,SQLR_ERROR_NOTIMPLEMENTED_STRING,
924 SQLR_ERROR_NOTIMPLEMENTED,true);
925 return false;
926 }
927
ping()928 bool routerconnection::ping() {
929
930 if (debug) {
931 stdoutput.printf("ping {\n");
932 }
933
934 // route
935 bool routed=false;
936 bool err=false;
937 route(&routed,&err);
938 if (err) {
939 if (debug) {
940 stdoutput.printf(" routing error\n}\n");
941 }
942 return false;
943 }
944
945 // if routing entire sessions, then ping the appropriate connection
946 if (routed && routeentiresession) {
947 if (debug) {
948 stdoutput.printf(" only executing on: %s\n}\n",
949 (currentcon)?conids[currentconindex]:NULL);
950 }
951 return (currentcon)?currentcon->ping():true;
952 }
953
954 // ping all connections, if any fail, return failure
955 bool result=true;
956 for (uint16_t index=0; index<concount; index++) {
957
958 if (debug) {
959 stdoutput.printf(" executing on: %s\n",
960 conids[index]);
961 }
962
963 bool res=cons[index]->ping();
964 if (!res) {
965 if (debug) {
966 stdoutput.printf(" failed\n");
967 }
968 result=res;
969 }
970 }
971
972 if (debug) {
973 stdoutput.printf("}\n");
974 }
975 return result;
976 }
977
selectDatabaseQuery()978 const char *routerconnection::selectDatabaseQuery() {
979 return "use %s";
980 }
981
getCurrentDatabase()982 char *routerconnection::getCurrentDatabase() {
983 return (currentcon)?
984 charstring::duplicate(currentcon->getCurrentDatabase()):NULL;
985 }
986
getLastInsertId(uint64_t * id)987 bool routerconnection::getLastInsertId(uint64_t *id) {
988 // get this from the most recently used connection
989 if (!currentcon) {
990 *id=0;
991 return true;
992 }
993 *id=currentcon->getLastInsertId();
994 return (*id!=0);
995 }
996
endSession()997 void routerconnection::endSession() {
998
999 if (debug) {
1000 stdoutput.printf("endSession {\n");
1001 }
1002
1003 // route
1004 bool routed=false;
1005 bool err=false;
1006 route(&routed,&err);
1007 if (err) {
1008 if (debug) {
1009 stdoutput.printf(" routing error\n}\n");
1010 }
1011 return;
1012 }
1013
1014 if (routed && routeentiresession) {
1015
1016 // if routing entire sessions, then end-session
1017 // on the appropriate connection
1018 if (debug) {
1019 stdoutput.printf(" only executing on: %s\n}\n",
1020 (currentcon)?conids[currentconindex]:NULL);
1021 }
1022 currentcon->endSession();
1023
1024 } else {
1025
1026 // otherwise end-session on all connections
1027 for (uint16_t index=0; index<concount; index++) {
1028 if (debug) {
1029 stdoutput.printf(" executing on: %s\n",
1030 conids[index]);
1031 }
1032 cons[index]->endSession();
1033 }
1034 }
1035
1036 // reset pointers and index
1037 currentcon=NULL;
1038 currentconindex=0;
1039 for (linkedlistnode< routercursor * > *node=routercursors.getFirst();
1040 node; node=node->getNext()) {
1041 routercursor *rcur=node->getValue();
1042 rcur->currentcon=NULL;
1043 rcur->currentcur=NULL;
1044 }
1045 sqlrr->setCurrentConnectionId(NULL);
1046
1047 if (debug) {
1048 stdoutput.printf("}\n");
1049 }
1050 }
1051
route(bool * routed,bool * err)1052 void routerconnection::route(bool *routed, bool *err) {
1053
1054 if (debug) {
1055 stdoutput.printf(" route (connection) {\n");
1056 }
1057
1058 // initialize return values
1059 *err=false;
1060 *routed=false;
1061
1062 // bail if we're routing the entire session
1063 // and we already have a currentcon
1064 if (routeentiresession && currentcon) {
1065 if (debug) {
1066 stdoutput.printf(" "
1067 "routing entire session and "
1068 "have currentcon\n }\n");
1069 }
1070 return;
1071 }
1072
1073 // otherwise, sort ourselves out...
1074
1075 // reset pointers and index
1076 currentcon=NULL;
1077 currentconindex=0;
1078
1079 // route...
1080 const char *errm=NULL;
1081 int64_t errn=0;
1082 const char *connectionid=sqlrr->route(this,NULL,&errm,&errn);
1083 if (!connectionid) {
1084 if (debug) {
1085 stdoutput.printf(" "
1086 "no connection id returned\n");
1087 }
1088 if (errm) {
1089 if (debug) {
1090 stdoutput.printf(" "
1091 "an error occurred: "
1092 "%d - %s\n",errn,errm);
1093 }
1094 cont->setError(errm,errn,true);
1095 *err=true;
1096 }
1097 if (debug) {
1098 stdoutput.printf(" }\n");
1099 }
1100 return;
1101 }
1102 if (debug) {
1103 stdoutput.printf(" routing to: %s\n",connectionid);
1104 }
1105
1106 // get the corresponding connection
1107 for (uint16_t i=0; i<concount; i++) {
1108 if (!charstring::compare(connectionid,conids[i])) {
1109 currentcon=cons[i];
1110 currentconindex=i;
1111 sqlrr->setCurrentConnectionId(connectionid);
1112 *routed=true;
1113 if (debug) {
1114 stdoutput.printf(" }\n");
1115 }
1116 return;
1117 }
1118 }
1119
1120 if (debug) {
1121 stdoutput.printf(" "
1122 "%s not found\n }\n",connectionid);
1123 }
1124 }
1125
autoCommitOnFailed(uint16_t index)1126 void routerconnection::autoCommitOnFailed(uint16_t index) {
1127 raiseIntegrityViolationEvent("autocommit-on",index);
1128 }
1129
autoCommitOffFailed(uint16_t index)1130 void routerconnection::autoCommitOffFailed(uint16_t index) {
1131 raiseIntegrityViolationEvent("autocommit-off",index);
1132 }
1133
beginFailed(uint16_t index)1134 void routerconnection::beginFailed(uint16_t index) {
1135 raiseIntegrityViolationEvent("begin",index);
1136 }
1137
commitFailed(uint16_t index)1138 void routerconnection::commitFailed(uint16_t index) {
1139 raiseIntegrityViolationEvent("commit",index);
1140 }
1141
rollbackFailed(uint16_t index)1142 void routerconnection::rollbackFailed(uint16_t index) {
1143 raiseIntegrityViolationEvent("rollback",index);
1144 }
1145
beginQueryFailed(uint16_t index)1146 void routerconnection::beginQueryFailed(uint16_t index) {
1147 raiseIntegrityViolationEvent("begin",index);
1148 }
1149
raiseIntegrityViolationEvent(const char * command,uint16_t index)1150 void routerconnection::raiseIntegrityViolationEvent(const char *command,
1151 uint16_t index) {
1152 stringbuffer info;
1153 info.append(command);
1154 info.append(" failed on connectionid: ");
1155 info.append(conids[index]);
1156 cont->raiseIntegrityViolationEvent(info.getString());
1157
1158 cont->setInstanceDisabled(true);
1159 }
1160
1161
routercursor(sqlrserverconnection * conn,uint16_t id)1162 routercursor::routercursor(sqlrserverconnection *conn, uint16_t id) :
1163 sqlrservercursor(conn,id) {
1164 routerconn=(routerconnection *)conn;
1165 nextrow=0;
1166 currentcon=NULL;
1167 currentcur=NULL;
1168 isbindcur=false;
1169 curs=new sqlrcursor *[routerconn->concount];
1170 for (uint16_t index=0; index<routerconn->concount; index++) {
1171 curs[index]=NULL;
1172 if (!routerconn->cons[index]) {
1173 continue;
1174 }
1175 curs[index]=new sqlrcursor(routerconn->cons[index]);
1176 curs[index]->setResultSetBufferSize(
1177 conn->cont->getFetchAtOnce());
1178 }
1179
1180 obv=new outputbindvar[conn->cont->getConfig()->getMaxBindCount()];
1181 obcount=0;
1182
1183 cbv=new cursorbindvar[conn->cont->getConfig()->getMaxBindCount()];
1184 cbcount=0;
1185
1186 emptyquery=false;
1187
1188 routerconn->routercursors.append(this);
1189 }
1190
~routercursor()1191 routercursor::~routercursor() {
1192 for (uint16_t index=0; index<routerconn->concount; index++) {
1193 delete curs[index];
1194 }
1195 delete[] curs;
1196 delete[] obv;
1197 delete[] cbv;
1198 routerconn->routercursors.remove(this);
1199 }
1200
prepareQuery(const char * query,uint32_t length)1201 bool routercursor::prepareQuery(const char *query, uint32_t length) {
1202
1203 if (routerconn->debug) {
1204 stdoutput.printf("prepareQuery {\n");
1205 }
1206
1207 // FIXME: remove this and use a translation
1208
1209 // convert to lowercase and normalize whitespace, for regex matching
1210 char *nquery=new char[length+1];
1211 if (query) {
1212 for (uint32_t i=0; i<length; ++i) {
1213 char c=query[i];
1214 if (character::isWhitespace(c)) {
1215 nquery[i]=' ';
1216 } else {
1217 nquery[i]=character::toLowerCase(c);
1218 }
1219 }
1220 }
1221 nquery[length]='\0';
1222
1223 // reset bind cursor
1224 if (isbindcur) {
1225 delete currentcur;
1226 currentcur=NULL;
1227 isbindcur=false;
1228 }
1229
1230 // initialize the output bind count
1231 obcount=0;
1232
1233 // initialize the cursor bind count
1234 cbcount=0;
1235
1236 // initialize the empty query flag
1237 emptyquery=false;
1238
1239 // route
1240 bool routed=false;
1241 bool err=false;
1242 route(&routed,&err);
1243 if (err) {
1244 if (routerconn->debug) {
1245 stdoutput.printf(" routing error\n}\n");
1246 }
1247 return false;
1248 }
1249
1250 // free normalized query
1251 delete[] nquery;
1252
1253 // currentcur could be NULL here if no
1254 // connection could be found to run the query.
1255 if (!currentcur) {
1256 if (routerconn->debug) {
1257 stdoutput.printf(" no connection "
1258 "found, bailing\n}\n");
1259 }
1260 return false;
1261 }
1262
1263 // Did a module make the query empty? If so, then we won't actually
1264 // prepare/execute it, just return true. The usedatabase module does
1265 // this.
1266 emptyquery=!getQueryLength();
1267 if (routerconn->debug) {
1268 stdoutput.printf("%s",(emptyquery)?" query set empty\n":"");
1269 }
1270
1271 // prepare the query using the cursor from whichever
1272 // connection turned out to be the right one
1273 if (!emptyquery) {
1274 if (routerconn->debug) {
1275 stdoutput.printf(" query: %.*s\n",length,query);
1276 }
1277 currentcur->prepareQuery(query,length);
1278 }
1279
1280 if (routerconn->debug) {
1281 stdoutput.printf("}\n");
1282 }
1283 return true;
1284 }
1285
route(bool * routed,bool * err)1286 void routercursor::route(bool *routed, bool *err) {
1287
1288 if (routerconn->debug) {
1289 stdoutput.printf(" route (cursor) {\n");
1290 }
1291
1292 // initialize return values
1293 *err=false;
1294 *routed=false;
1295
1296 // if we're routing the entire session and this particular routercursor
1297 // hasn't sorted itself out, but the routerconnection has, then get
1298 // which connection and cursor to use from the routerconnection
1299 if (routerconn->routeentiresession) {
1300
1301 if (routerconn->debug) {
1302 stdoutput.printf(" "
1303 "routing entire session ");
1304 }
1305 if (currentcon) {
1306 if (routerconn->debug) {
1307 stdoutput.printf("and have currentcon\n }\n");
1308 }
1309 return;
1310 } else if (routerconn->currentcon) {
1311 if (routerconn->debug) {
1312 stdoutput.printf("and conn has "
1313 "currentcon\n }\n");
1314 }
1315 currentcon=routerconn->currentcon;
1316 currentcur=curs[routerconn->currentconindex];
1317 return;
1318 }
1319 if (routerconn->debug) {
1320 stdoutput.printf("but need to get currentcon\n");
1321 }
1322 }
1323
1324 // otherwise, sort this routercursor out...
1325
1326 // reset pointers and index
1327 currentcon=NULL;
1328 currentcur=NULL;
1329 routerconn->currentcon=NULL;
1330 routerconn->currentconindex=0;
1331
1332 // route...
1333 const char *errm=NULL;
1334 int64_t errn=0;
1335 const char *connectionid=routerconn->sqlrr->route(
1336 routerconn,this,&errm,&errn);
1337 if (!connectionid) {
1338 if (routerconn->debug) {
1339 stdoutput.printf(" "
1340 "no connection id returned\n");
1341 }
1342 if (errm) {
1343 if (routerconn->debug) {
1344 stdoutput.printf(" "
1345 "an error occurred: "
1346 "%d - %s\n",errn,errm);
1347 }
1348 conn->cont->setError(this,errm,errn,true);
1349 *err=true;
1350 }
1351 if (routerconn->debug) {
1352 stdoutput.printf(" }\n");
1353 }
1354 return;
1355 }
1356 if (routerconn->debug) {
1357 stdoutput.printf(" routing to: %s\n",connectionid);
1358 }
1359
1360 // get the corresponding connection and cursor
1361 for (uint16_t i=0; i<routerconn->concount; i++) {
1362 if (!charstring::compare(connectionid,routerconn->conids[i])) {
1363 currentcon=routerconn->cons[i];
1364 currentcur=curs[i];
1365 routerconn->currentcon=currentcon;
1366 routerconn->currentconindex=i;
1367 routerconn->sqlrr->setCurrentConnectionId(connectionid);
1368 *routed=true;
1369 if (routerconn->debug) {
1370 stdoutput.printf(" }\n");
1371 }
1372 return;
1373 }
1374 }
1375
1376 if (routerconn->debug) {
1377 stdoutput.printf(" "
1378 "%s not found\n }\n",connectionid);
1379 }
1380 }
1381
supportsNativeBinds(const char * query,uint32_t length)1382 bool routercursor::supportsNativeBinds(const char *query, uint32_t length) {
1383 return true;
1384 }
1385
inputBind(const char * variable,uint16_t variablesize,const char * value,uint32_t valuesize,int16_t * isnull)1386 bool routercursor::inputBind(const char *variable,
1387 uint16_t variablesize,
1388 const char *value,
1389 uint32_t valuesize,
1390 int16_t *isnull) {
1391 currentcur->inputBind(variable+1,value);
1392 return true;
1393 }
1394
inputBind(const char * variable,uint16_t variablesize,int64_t * value)1395 bool routercursor::inputBind(const char *variable,
1396 uint16_t variablesize,
1397 int64_t *value) {
1398 currentcur->inputBind(variable+1,*value);
1399 return true;
1400 }
1401
inputBind(const char * variable,uint16_t variablesize,double * value,uint32_t precision,uint32_t scale)1402 bool routercursor::inputBind(const char *variable,
1403 uint16_t variablesize,
1404 double *value,
1405 uint32_t precision,
1406 uint32_t scale) {
1407 currentcur->inputBind(variable+1,*value,precision,scale);
1408 return true;
1409 }
1410
inputBind(const char * variable,uint16_t variablesize,int64_t year,int16_t month,int16_t day,int16_t hour,int16_t minute,int16_t second,int32_t microsecond,const char * tz,bool isnegative,char * buffer,uint16_t buffersize,int16_t * isnull)1411 bool routercursor::inputBind(const char *variable,
1412 uint16_t variablesize,
1413 int64_t year,
1414 int16_t month,
1415 int16_t day,
1416 int16_t hour,
1417 int16_t minute,
1418 int16_t second,
1419 int32_t microsecond,
1420 const char *tz,
1421 bool isnegative,
1422 char *buffer,
1423 uint16_t buffersize,
1424 int16_t *isnull) {
1425 currentcur->inputBind(variable+1,year,month,day,
1426 hour,minute,second,microsecond,tz,isnegative);
1427 return true;
1428 }
1429
inputBindBlob(const char * variable,uint16_t variablesize,const char * value,uint32_t valuesize,int16_t * isnull)1430 bool routercursor::inputBindBlob(const char *variable,
1431 uint16_t variablesize,
1432 const char *value,
1433 uint32_t valuesize,
1434 int16_t *isnull) {
1435 currentcur->inputBindBlob(variable+1,value,valuesize);
1436 return true;
1437 }
1438
inputBindClob(const char * variable,uint16_t variablesize,const char * value,uint32_t valuesize,int16_t * isnull)1439 bool routercursor::inputBindClob(const char *variable,
1440 uint16_t variablesize,
1441 const char *value,
1442 uint32_t valuesize,
1443 int16_t *isnull) {
1444 currentcur->inputBindClob(variable+1,value,valuesize);
1445 return true;
1446 }
1447
outputBind(const char * variable,uint16_t variablesize,char * value,uint32_t valuesize,int16_t * isnull)1448 bool routercursor::outputBind(const char *variable,
1449 uint16_t variablesize,
1450 char *value,
1451 uint32_t valuesize,
1452 int16_t *isnull) {
1453 currentcur->defineOutputBindString(variable+1,valuesize);
1454 obv[obcount].variable=variable+1;
1455 obv[obcount].type=SQLRSERVERBINDVARTYPE_STRING;
1456 obv[obcount].value.stringvalue=value;
1457 obv[obcount].valuesize=valuesize;
1458 obv[obcount].isnull=isnull;
1459 obcount++;
1460 return true;
1461 }
1462
outputBind(const char * variable,uint16_t variablesize,int64_t * value,int16_t * isnull)1463 bool routercursor::outputBind(const char *variable,
1464 uint16_t variablesize,
1465 int64_t *value,
1466 int16_t *isnull) {
1467 currentcur->defineOutputBindInteger(variable+1);
1468 obv[obcount].variable=variable+1;
1469 obv[obcount].type=SQLRSERVERBINDVARTYPE_INTEGER;
1470 obv[obcount].value.intvalue=value;
1471 obv[obcount].isnull=isnull;
1472 obcount++;
1473 return true;
1474 }
1475
outputBind(const char * variable,uint16_t variablesize,double * value,uint32_t * precision,uint32_t * scale,int16_t * isnull)1476 bool routercursor::outputBind(const char *variable,
1477 uint16_t variablesize,
1478 double *value,
1479 uint32_t *precision,
1480 uint32_t *scale,
1481 int16_t *isnull) {
1482 currentcur->defineOutputBindDouble(variable+1);
1483 obv[obcount].variable=variable+1;
1484 obv[obcount].type=SQLRSERVERBINDVARTYPE_DOUBLE;
1485 obv[obcount].value.doublevalue=value;
1486 obv[obcount].isnull=isnull;
1487 obcount++;
1488 return true;
1489 }
1490
outputBind(const char * variable,uint16_t variablesize,int16_t * year,int16_t * month,int16_t * day,int16_t * hour,int16_t * minute,int16_t * second,int32_t * microsecond,const char ** tz,bool * isnegative,char * buffer,uint16_t buffersize,int16_t * isnull)1491 bool routercursor::outputBind(const char *variable,
1492 uint16_t variablesize,
1493 int16_t *year,
1494 int16_t *month,
1495 int16_t *day,
1496 int16_t *hour,
1497 int16_t *minute,
1498 int16_t *second,
1499 int32_t *microsecond,
1500 const char **tz,
1501 bool *isnegative,
1502 char *buffer,
1503 uint16_t buffersize,
1504 int16_t *isnull) {
1505 currentcur->defineOutputBindDouble(variable+1);
1506 obv[obcount].variable=variable+1;
1507 obv[obcount].type=SQLRSERVERBINDVARTYPE_DATE;
1508 obv[obcount].value.datevalue.year=year;
1509 obv[obcount].value.datevalue.month=month;
1510 obv[obcount].value.datevalue.day=day;
1511 obv[obcount].value.datevalue.hour=hour;
1512 obv[obcount].value.datevalue.minute=minute;
1513 obv[obcount].value.datevalue.second=second;
1514 obv[obcount].value.datevalue.microsecond=microsecond;
1515 obv[obcount].value.datevalue.tz=tz;
1516 obv[obcount].isnull=isnull;
1517 obv[obcount].value.datevalue.isnegative=isnegative;
1518 obcount++;
1519 return true;
1520 }
1521
1522
outputBindBlob(const char * variable,uint16_t variablesize,uint16_t index,int16_t * isnull)1523 bool routercursor::outputBindBlob(const char *variable,
1524 uint16_t variablesize,
1525 uint16_t index,
1526 int16_t *isnull) {
1527 currentcur->defineOutputBindBlob(variable+1);
1528 obv[obcount].variable=variable+1;
1529 obv[obcount].type=SQLRSERVERBINDVARTYPE_BLOB;
1530 obv[obcount].isnull=isnull;
1531 obcount++;
1532 return true;
1533 }
1534
outputBindClob(const char * variable,uint16_t variablesize,uint16_t index,int16_t * isnull)1535 bool routercursor::outputBindClob(const char *variable,
1536 uint16_t variablesize,
1537 uint16_t index,
1538 int16_t *isnull) {
1539 currentcur->defineOutputBindClob(variable+1);
1540 obv[obcount].variable=variable+1;
1541 obv[obcount].type=SQLRSERVERBINDVARTYPE_CLOB;
1542 obv[obcount].isnull=isnull;
1543 obcount++;
1544 return true;
1545 }
1546
outputBindCursor(const char * variable,uint16_t variablesize,sqlrservercursor * cursor)1547 bool routercursor::outputBindCursor(const char *variable,
1548 uint16_t variablesize,
1549 sqlrservercursor *cursor) {
1550 currentcur->defineOutputBindCursor(variable+1);
1551 cbv[cbcount].variable=variable+1;
1552 cbv[cbcount].cursor=cursor;
1553 cbcount++;
1554 return true;
1555 }
1556
getLobOutputBindLength(uint16_t index,uint64_t * length)1557 bool routercursor::getLobOutputBindLength(uint16_t index, uint64_t *length) {
1558 *length=currentcur->getOutputBindLength(obv[index].variable);
1559 return true;
1560 }
1561
getLobOutputBindSegment(uint16_t index,char * buffer,uint64_t buffersize,uint64_t offset,uint64_t charstoread,uint64_t * charsread)1562 bool routercursor::getLobOutputBindSegment(uint16_t index,
1563 char *buffer, uint64_t buffersize,
1564 uint64_t offset, uint64_t charstoread,
1565 uint64_t *charsread) {
1566 const char *varname=obv[index].variable;
1567 const char *var=currentcur->getOutputBindClob(varname);
1568 if (!var) {
1569 var=currentcur->getOutputBindBlob(varname);
1570 }
1571 uint32_t length=currentcur->getOutputBindLength(varname);
1572 if (offset+charstoread>length) {
1573 charstoread=length-offset;
1574 }
1575 bytestring::copy(buffer,var,charstoread);
1576 *charsread=charstoread;
1577 return true;
1578 }
1579
executeQuery(const char * query,uint32_t length)1580 bool routercursor::executeQuery(const char *query, uint32_t length) {
1581
1582 // FIXME: if routing entire sessions, then compare and just do this for
1583 // the appropriate connection
1584
1585 if (!currentcur) {
1586 if (!prepareQuery(query,length)) {
1587 return false;
1588 }
1589 }
1590
1591 if (!currentcur) {
1592 return false;
1593 }
1594
1595 if (!emptyquery) {
1596 if (!currentcur->executeQuery()) {
1597 return false;
1598 }
1599 }
1600
1601 nextrow=0;
1602
1603 // populate output bind values
1604 for (uint16_t outi=0; outi<obcount; outi++) {
1605 const char *variable=obv[outi].variable;
1606 *(obv[outi].isnull)=routerconn->nonnullbindvalue;
1607 if (obv[outi].type==SQLRSERVERBINDVARTYPE_STRING) {
1608 const char *str=
1609 currentcur->getOutputBindString(variable);
1610 uint32_t len=
1611 currentcur->getOutputBindLength(variable);
1612 if (str) {
1613 charstring::copy(obv[outi].value.stringvalue,
1614 str,len);
1615 } else {
1616 obv[outi].value.stringvalue[0]='\0';
1617 *(obv[outi].isnull)=routerconn->nullbindvalue;
1618 }
1619 } else if (obv[outi].type==SQLRSERVERBINDVARTYPE_INTEGER) {
1620 *(obv[outi].value.intvalue)=
1621 currentcur->getOutputBindInteger(variable);
1622 } else if (obv[outi].type==SQLRSERVERBINDVARTYPE_DOUBLE) {
1623 *(obv[outi].value.doublevalue)=
1624 currentcur->getOutputBindDouble(variable);
1625 } else if (obv[outi].type==SQLRSERVERBINDVARTYPE_DATE) {
1626 currentcur->getOutputBindDate(variable,
1627 obv[outi].value.datevalue.year,
1628 obv[outi].value.datevalue.month,
1629 obv[outi].value.datevalue.day,
1630 obv[outi].value.datevalue.hour,
1631 obv[outi].value.datevalue.minute,
1632 obv[outi].value.datevalue.second,
1633 obv[outi].value.datevalue.microsecond,
1634 obv[outi].value.datevalue.tz,
1635 obv[outi].value.datevalue.isnegative);
1636 }
1637 }
1638
1639 // handle cursor bind values
1640 for (uint16_t curi=0; curi<cbcount; curi++) {
1641 routercursor *rcur=(routercursor *)cbv[curi].cursor;
1642 rcur->currentcon=currentcon;
1643 rcur->currentcur=
1644 currentcur->getOutputBindCursor(cbv[curi].variable);
1645 if (!rcur->currentcur) {
1646 return false;
1647 }
1648 rcur->currentcur->setResultSetBufferSize(
1649 conn->cont->getFetchAtOnce());
1650 rcur->isbindcur=true;
1651 rcur->nextrow=0;
1652 if (!rcur->currentcur->fetchFromBindCursor()) {
1653 return false;
1654 }
1655 }
1656 return true;
1657 }
1658
errorMessage(char * errorbuffer,uint32_t errorbufferlength,uint32_t * errorlength,int64_t * errorcode,bool * liveconnection)1659 void routercursor::errorMessage(char *errorbuffer,
1660 uint32_t errorbufferlength,
1661 uint32_t *errorlength,
1662 int64_t *errorcode,
1663 bool *liveconnection) {
1664 const char *errormessage=
1665 (currentcur)?currentcur->errorMessage():"";
1666 *errorlength=charstring::length(errormessage);
1667 charstring::safeCopy(errorbuffer,errorbufferlength,
1668 errormessage,*errorlength);
1669 *errorcode=(currentcur)?currentcur->errorNumber():0;
1670 *liveconnection=true;
1671 }
1672
knowsRowCount()1673 bool routercursor::knowsRowCount() {
1674 return true;
1675 }
1676
rowCount()1677 uint64_t routercursor::rowCount() {
1678 return (currentcur)?currentcur->rowCount():0;
1679 }
1680
affectedRows()1681 uint64_t routercursor::affectedRows() {
1682 return (currentcur)?currentcur->affectedRows():0;
1683 }
1684
colCount()1685 uint32_t routercursor::colCount() {
1686 return (currentcur)?currentcur->colCount():0;
1687 }
1688
columnTypeFormat()1689 uint16_t routercursor::columnTypeFormat() {
1690 return (uint16_t)COLUMN_TYPE_NAMES;
1691 }
1692
getColumnName(uint32_t col)1693 const char *routercursor::getColumnName(uint32_t col) {
1694 return (currentcur)?currentcur->getColumnName(col):NULL;
1695 }
1696
getColumnTypeName(uint32_t col)1697 const char *routercursor::getColumnTypeName(uint32_t col) {
1698 return (currentcur)?currentcur->getColumnType(col):NULL;
1699 }
1700
getColumnLength(uint32_t col)1701 uint32_t routercursor::getColumnLength(uint32_t col) {
1702 return (currentcur)?currentcur->getColumnLength(col):0;
1703 }
1704
getColumnPrecision(uint32_t col)1705 uint32_t routercursor::getColumnPrecision(uint32_t col) {
1706 return (currentcur)?currentcur->getColumnPrecision(col):0;
1707 }
1708
getColumnScale(uint32_t col)1709 uint32_t routercursor::getColumnScale(uint32_t col) {
1710 return (currentcur)?currentcur->getColumnScale(col):0;
1711 }
1712
getColumnIsNullable(uint32_t col)1713 uint16_t routercursor::getColumnIsNullable(uint32_t col) {
1714 return (currentcur)?currentcur->getColumnIsNullable(col):0;
1715 }
1716
getColumnIsPrimaryKey(uint32_t col)1717 uint16_t routercursor::getColumnIsPrimaryKey(uint32_t col) {
1718 return (currentcur)?currentcur->getColumnIsPrimaryKey(col):0;
1719 }
1720
getColumnIsUnique(uint32_t col)1721 uint16_t routercursor::getColumnIsUnique(uint32_t col) {
1722 return (currentcur)?currentcur->getColumnIsUnique(col):0;
1723 }
1724
getColumnIsPartOfKey(uint32_t col)1725 uint16_t routercursor::getColumnIsPartOfKey(uint32_t col) {
1726 return (currentcur)?currentcur->getColumnIsPartOfKey(col):0;
1727 }
1728
getColumnIsUnsigned(uint32_t col)1729 uint16_t routercursor::getColumnIsUnsigned(uint32_t col) {
1730 return (currentcur)?currentcur->getColumnIsUnsigned(col):0;
1731 }
1732
getColumnIsZeroFilled(uint32_t col)1733 uint16_t routercursor::getColumnIsZeroFilled(uint32_t col) {
1734 return (currentcur)?currentcur->getColumnIsZeroFilled(col):0;
1735 }
1736
getColumnIsBinary(uint32_t col)1737 uint16_t routercursor::getColumnIsBinary(uint32_t col) {
1738 return (currentcur)?currentcur->getColumnIsBinary(col):0;
1739 }
1740
getColumnIsAutoIncrement(uint32_t col)1741 uint16_t routercursor::getColumnIsAutoIncrement(uint32_t col) {
1742 return (currentcur)?currentcur->getColumnIsAutoIncrement(col):0;
1743 }
1744
getColumnTable(uint32_t col)1745 const char *routercursor::getColumnTable(uint32_t col) {
1746 return (currentcur)?currentcur->getColumnTable(col):NULL;
1747 }
1748
noRowsToReturn()1749 bool routercursor::noRowsToReturn() {
1750 return (((currentcur)?currentcur->rowCount():0)==0);
1751 }
1752
fetchRow(bool * error)1753 bool routercursor::fetchRow(bool *error) {
1754
1755 *error=false;
1756
1757 if (!currentcur) {
1758 return false;
1759 }
1760 if (currentcur->getField(nextrow,(uint32_t)0)) {
1761 nextrow++;
1762 return true;
1763 }
1764 if (currentcur->errorMessage()) {
1765 *error=true;
1766 }
1767 return false;
1768 }
1769
getField(uint32_t col,const char ** field,uint64_t * fieldlength,bool * blob,bool * null)1770 void routercursor::getField(uint32_t col,
1771 const char **field, uint64_t *fieldlength,
1772 bool *blob, bool *null) {
1773 const char *fld=currentcur->getField(nextrow-1,col);
1774 uint32_t len=currentcur->getFieldLength(nextrow-1,col);
1775 if (len) {
1776 *field=fld;
1777 *fieldlength=len;
1778 } else {
1779 *null=true;
1780 }
1781 }
1782
closeResultSet()1783 void routercursor::closeResultSet() {
1784 if (currentcur) {
1785 currentcur->clearBinds();
1786 }
1787 obcount=0;
1788 cbcount=0;
1789 }
1790
1791
1792 extern "C" {
new_routerconnection(sqlrservercontroller * cont)1793 SQLRSERVER_DLLSPEC sqlrserverconnection *new_routerconnection(
1794 sqlrservercontroller *cont) {
1795 return new routerconnection(cont);
1796 }
1797 }
1798