1
2 /* postgres headers */
3
4 #include "postgres.h"
5 #include "funcapi.h"
6 #include "access/reloptions.h"
7 #include "catalog/pg_foreign_server.h"
8 #include "catalog/pg_foreign_table.h"
9 #include "catalog/pg_user_mapping.h"
10 #include "catalog/pg_type.h"
11 #include "commands/defrem.h"
12 #include "commands/explain.h"
13 #include "foreign/fdwapi.h"
14 #include "foreign/foreign.h"
15 #include "miscadmin.h"
16 #include "mb/pg_wchar.h"
17 #include "optimizer/cost.h"
18 #include "storage/fd.h"
19 #include "utils/array.h"
20 #include "utils/builtins.h"
21 #include "utils/rel.h"
22 #include "utils/memutils.h"
23
24 #if (PG_VERSION_NUM >= 90200)
25 #include "optimizer/pathnode.h"
26 #include "optimizer/restrictinfo.h"
27 #include "optimizer/planmain.h"
28 #endif
29
30 /* DB-Library headers (e.g. FreeTDS */
31 #include <sybfront.h>
32 #include <sybdb.h>
33
34 #include "tds_fdw.h"
35 #include "options.h"
36
37 void tdsGetForeignServerOptions(List *options_list, TdsFdwOptionSet *option_set);
38 void tdsGetForeignServerTableOptions(List *options_list, TdsFdwOptionSet *option_set);
39 void tdsGetForeignTableOptions(List *options_list, TdsFdwOptionSet *option_set);
40 void tdsGetUserMappingOptions(List *options_list, TdsFdwOptionSet *option_set);
41
42 void tdsValidateForeignTableOptionSet(TdsFdwOptionSet *option_set);
43
44 void tdsSetDefaultOptions(TdsFdwOptionSet *option_set);
45
46 bool tdsIsValidOption(const char *option, Oid context);
47 void tdsOptionSetInit(TdsFdwOptionSet* option_set);
48
49 /* these are valid options */
50
51 static struct TdsFdwOption valid_options[] =
52 {
53 { "servername", ForeignServerRelationId },
54 { "language", ForeignServerRelationId },
55 { "character_set", ForeignServerRelationId },
56 { "port", ForeignServerRelationId },
57 { "database", ForeignServerRelationId },
58 { "dbuse", ForeignServerRelationId },
59 { "tds_version", ForeignServerRelationId },
60 { "msg_handler", ForeignServerRelationId },
61 { "row_estimate_method", ForeignServerRelationId },
62 { "use_remote_estimate", ForeignServerRelationId },
63 { "fdw_startup_cost", ForeignServerRelationId },
64 { "fdw_tuple_cost", ForeignServerRelationId },
65 { "username", UserMappingRelationId },
66 { "password", UserMappingRelationId },
67 { "query", ForeignTableRelationId },
68 { "table", ForeignTableRelationId },
69 { "schema_name", ForeignTableRelationId },
70 { "table_name", ForeignTableRelationId },
71 { "row_estimate_method", ForeignTableRelationId },
72 { "match_column_names", ForeignTableRelationId },
73 { "use_remote_estimate", ForeignTableRelationId },
74 { "local_tuple_estimate", ForeignTableRelationId },
75 { "column_name", AttributeRelationId },
76 { NULL, InvalidOid }
77 };
78
79 /* default IP address */
80
81 static const char *DEFAULT_SERVERNAME = "127.0.0.1";
82
83 /* default method to use to estimate rows in results */
84
85 static const char *DEFAULT_ROW_ESTIMATE_METHOD = "execute";
86
87 /* default function used to handle TDS messages */
88
89 static const char *DEFAULT_MSG_HANDLER = "blackhole";
90
91 /* whether to match on column names by default. if not, we use column order. */
92
93 static const int DEFAULT_MATCH_COLUMN_NAMES = 1;
94
95 /* by default we use remote estimates */
96
97 static const int DEFAULT_USE_REMOTE_ESTIMATE = 1;
98
99 /* by default we use remote estimates */
100
101 static const int DEFAULT_FDW_STARTUP_COST = 100;
102
103 /* by default we use remote estimates */
104
105 static const int DEFAULT_FDW_TUPLE_COST = 100;
106
107 /* conservative default tuple count */
108
109 static const int DEFAULT_LOCAL_TUPLE_ESTIMATE = 1000;
110
tdsValidateOptions(List * options_list,Oid context,TdsFdwOptionSet * option_set)111 void tdsValidateOptions(List *options_list, Oid context, TdsFdwOptionSet* option_set)
112 {
113 #ifdef DEBUG
114 ereport(NOTICE,
115 (errmsg("----> starting tdsValidateOptions")
116 ));
117 #endif
118
119 tdsOptionSetInit(option_set);
120
121 if (context == ForeignServerRelationId)
122 {
123 tdsGetForeignServerOptions(options_list, option_set);
124 tdsGetForeignServerTableOptions(options_list, option_set);
125 }
126
127 else if (context == ForeignTableRelationId)
128 {
129 tdsGetForeignTableOptions(options_list, option_set);
130 tdsValidateForeignTableOptionSet(option_set);
131 }
132
133 else if (context == UserMappingRelationId)
134 {
135 tdsGetUserMappingOptions(options_list, option_set);
136 }
137
138 #ifdef DEBUG
139 ereport(NOTICE,
140 (errmsg("----> finishing tdsValidateOptions")
141 ));
142 #endif
143 }
144
145 /* get options for FOREIGN SERVER objects using this module */
146
tdsGetForeignServerOptionsFromCatalog(Oid foreignserverid,TdsFdwOptionSet * option_set)147 void tdsGetForeignServerOptionsFromCatalog(Oid foreignserverid, TdsFdwOptionSet* option_set)
148 {
149 ForeignServer *f_server;
150 UserMapping *f_mapping;
151
152 #ifdef DEBUG
153 ereport(NOTICE,
154 (errmsg("----> starting tdsGetForeignServerOptionsFromCatalog")
155 ));
156 #endif
157
158 tdsOptionSetInit(option_set);
159
160 f_server = GetForeignServer(foreignserverid);
161 f_mapping = GetUserMapping(GetUserId(), foreignserverid);
162
163 tdsGetForeignServerOptions(f_server->options, option_set);
164 tdsGetForeignServerTableOptions(f_server->options, option_set);
165
166 tdsGetUserMappingOptions(f_mapping->options, option_set);
167
168 tdsSetDefaultOptions(option_set);
169
170 #ifdef DEBUG
171 ereport(NOTICE,
172 (errmsg("----> finishing tdsGetForeignTableOptionsFromCatalog")
173 ));
174 #endif
175 }
176
177 /* get options for FOREIGN TABLE and FOREIGN SERVER objects using this module */
178
tdsGetForeignTableOptionsFromCatalog(Oid foreigntableid,TdsFdwOptionSet * option_set)179 void tdsGetForeignTableOptionsFromCatalog(Oid foreigntableid, TdsFdwOptionSet* option_set)
180 {
181 ForeignTable *f_table;
182 ForeignServer *f_server;
183 UserMapping *f_mapping;
184
185 #ifdef DEBUG
186 ereport(NOTICE,
187 (errmsg("----> starting tdsGetForeignTableOptionsFromCatalog")
188 ));
189 #endif
190
191 tdsOptionSetInit(option_set);
192
193 f_table = GetForeignTable(foreigntableid);
194 f_server = GetForeignServer(f_table->serverid);
195 f_mapping = GetUserMapping(GetUserId(), f_table->serverid);
196
197 tdsGetForeignServerOptions(f_server->options, option_set);
198 tdsGetForeignServerTableOptions(f_server->options, option_set);
199
200 tdsGetForeignTableOptions(f_table->options, option_set);
201
202 tdsGetUserMappingOptions(f_mapping->options, option_set);
203
204 tdsSetDefaultOptions(option_set);
205 tdsValidateOptionSet(option_set);
206
207 #ifdef DEBUG
208 ereport(NOTICE,
209 (errmsg("----> finishing tdsGetForeignTableOptionsFromCatalog")
210 ));
211 #endif
212 }
213
tdsGetForeignServerOptions(List * options_list,TdsFdwOptionSet * option_set)214 void tdsGetForeignServerOptions(List *options_list, TdsFdwOptionSet *option_set)
215 {
216 ListCell *cell;
217
218 #ifdef DEBUG
219 ereport(NOTICE,
220 (errmsg("----> starting tdsGetForeignServerOptions")
221 ));
222 #endif
223
224 foreach (cell, options_list)
225 {
226 DefElem *def = (DefElem *) lfirst(cell);
227
228 #ifdef DEBUG
229 ereport(NOTICE,
230 (errmsg("Working on option %s", def->defname)
231 ));
232 #endif
233
234 if (!tdsIsValidOption(def->defname, ForeignServerRelationId))
235 {
236 TdsFdwOption *opt;
237 StringInfoData buf;
238
239 initStringInfo(&buf);
240 for (opt = valid_options; opt->optname; opt++)
241 {
242 if (ForeignServerRelationId == opt->optcontext)
243 appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", opt->optname);
244 }
245
246 ereport(ERROR,
247 (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
248 errmsg("Invalid option \"%s\"", def->defname),
249 errhint("Valid options in this context are: %s", buf.len ? buf.data : "<none>")
250 ));
251 }
252
253 if (strcmp(def->defname, "servername") == 0)
254 {
255 if (option_set->servername)
256 ereport(ERROR,
257 (errcode(ERRCODE_SYNTAX_ERROR),
258 errmsg("Redundant option: servername (%s)", defGetString(def))
259 ));
260
261 option_set->servername = defGetString(def);
262 }
263
264 else if (strcmp(def->defname, "language") == 0)
265 {
266 if (option_set->language)
267 ereport(ERROR,
268 (errcode(ERRCODE_SYNTAX_ERROR),
269 errmsg("Redundant option: language (%s)", defGetString(def))
270 ));
271
272 option_set->language = defGetString(def);
273 }
274
275 else if (strcmp(def->defname, "character_set") == 0)
276 {
277 if (option_set->character_set)
278 ereport(ERROR,
279 (errcode(ERRCODE_SYNTAX_ERROR),
280 errmsg("Redundant option: character_set (%s)", defGetString(def))
281 ));
282
283 option_set->character_set = defGetString(def);
284 }
285
286 else if (strcmp(def->defname, "port") == 0)
287 {
288 if (option_set->port)
289 ereport(ERROR,
290 (errcode(ERRCODE_SYNTAX_ERROR),
291 errmsg("Redundant option: port (%s)", defGetString(def))
292 ));
293
294 option_set->port = atoi(defGetString(def));
295 }
296
297 else if (strcmp(def->defname, "database") == 0)
298 {
299 if (option_set->database)
300 ereport(ERROR,
301 (errcode(ERRCODE_SYNTAX_ERROR),
302 errmsg("Redundant option: database (%s)", defGetString(def))
303 ));
304
305 option_set->database = defGetString(def);
306 }
307
308 else if (strcmp(def->defname, "dbuse") == 0)
309 {
310 if (option_set->dbuse)
311 ereport(ERROR,
312 (errcode(ERRCODE_SYNTAX_ERROR),
313 errmsg("Redundant option: dbuse (%s)", defGetString(def))
314 ));
315
316 option_set->dbuse = atoi(defGetString(def));
317 }
318
319 else if (strcmp(def->defname, "tds_version") == 0)
320 {
321 int tds_version_test = 0;
322
323 if (option_set->tds_version)
324 ereport(ERROR,
325 (errcode(ERRCODE_SYNTAX_ERROR),
326 errmsg("Redundant option: database (%s)", defGetString(def))
327 ));
328
329 option_set->tds_version = defGetString(def);
330
331 if (strcmp(option_set->tds_version, "4.2") == 0)
332 {
333 tds_version_test = 1;
334 }
335
336 else if (strcmp(option_set->tds_version, "5.0") == 0)
337 {
338 tds_version_test = 1;
339 }
340
341 else if (strcmp(option_set->tds_version, "7.0") == 0)
342 {
343 tds_version_test = 1;
344 }
345
346 #ifdef DBVERSION_71
347 else if (strcmp(option_set->tds_version, "7.1") == 0)
348 {
349 tds_version_test = 1;
350 }
351 #endif
352
353 #ifdef DBVERSION_72
354 else if (strcmp(option_set->tds_version, "7.2") == 0)
355 {
356 tds_version_test = 1;
357 }
358 #endif
359
360 #ifdef DBVERSION_73
361 else if (strcmp(option_set->tds_version, "7.3") == 0)
362 {
363 tds_version_test = 1;
364 }
365 #endif
366
367 #ifdef DBVERSION_74
368 else if (strcmp(option_set->tds_version, "7.4") == 0)
369 {
370 tds_version_test = 1;
371 }
372 #endif
373
374 if (!tds_version_test)
375 {
376 ereport(ERROR,
377 (errcode(ERRCODE_SYNTAX_ERROR),
378 errmsg("Unknown tds version: %s.", option_set->tds_version)
379 ));
380 }
381 }
382
383 else if (strcmp(def->defname, "msg_handler") == 0)
384 {
385 int msg_handler_test = 0;
386
387 if (option_set->msg_handler)
388 ereport(ERROR,
389 (errcode(ERRCODE_SYNTAX_ERROR),
390 errmsg("Redundant option: msg_handler (%s)", defGetString(def))
391 ));
392
393 option_set->msg_handler = defGetString(def);
394
395 if (strcmp(option_set->msg_handler, "notice") == 0)
396 {
397 msg_handler_test = 1;
398 }
399
400 else if (strcmp(option_set->msg_handler, "blackhole") == 0)
401 {
402 msg_handler_test = 1;
403 }
404
405 if (!msg_handler_test)
406 {
407 ereport(ERROR,
408 (errcode(ERRCODE_SYNTAX_ERROR),
409 errmsg("Unknown msg handler: %s.", option_set->msg_handler)
410 ));
411 }
412 }
413
414 else if (strcmp(def->defname, "fdw_startup_cost") == 0)
415 {
416 if (option_set->fdw_startup_cost)
417 ereport(ERROR,
418 (errcode(ERRCODE_SYNTAX_ERROR),
419 errmsg("Redundant option: fdw_startup_cost (%s)", defGetString(def))
420 ));
421
422 option_set->fdw_startup_cost = atoi(defGetString(def));
423 }
424
425 else if (strcmp(def->defname, "fdw_tuple_cost") == 0)
426 {
427 if (option_set->fdw_tuple_cost)
428 ereport(ERROR,
429 (errcode(ERRCODE_SYNTAX_ERROR),
430 errmsg("Redundant option: fdw_tuple_cost (%s)", defGetString(def))
431 ));
432
433 option_set->fdw_tuple_cost = atoi(defGetString(def));
434 }
435 }
436
437 #ifdef DEBUG
438 ereport(NOTICE,
439 (errmsg("----> finishing tdsGetForeignServerOptions")
440 ));
441 #endif
442 }
443
tdsGetForeignServerTableOptions(List * options_list,TdsFdwOptionSet * option_set)444 void tdsGetForeignServerTableOptions(List *options_list, TdsFdwOptionSet *option_set)
445 {
446 ListCell *cell;
447
448 #ifdef DEBUG
449 ereport(NOTICE,
450 (errmsg("----> starting tdsGetForeignServerTableOptions")
451 ));
452 #endif
453
454 foreach (cell, options_list)
455 {
456 DefElem *def = (DefElem *) lfirst(cell);
457
458 #ifdef DEBUG
459 ereport(NOTICE,
460 (errmsg("Working on option %s", def->defname)
461 ));
462 #endif
463
464 if (!tdsIsValidOption(def->defname, ForeignServerRelationId))
465 {
466 TdsFdwOption *opt;
467 StringInfoData buf;
468
469 initStringInfo(&buf);
470 for (opt = valid_options; opt->optname; opt++)
471 {
472 if (ForeignServerRelationId == opt->optcontext)
473 appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", opt->optname);
474 }
475
476 ereport(ERROR,
477 (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
478 errmsg("Invalid option \"%s\"", def->defname),
479 errhint("Valid options in this context are: %s", buf.len ? buf.data : "<none>")
480 ));
481 }
482
483 if (strcmp(def->defname, "row_estimate_method") == 0)
484 {
485 if (option_set->row_estimate_method)
486 ereport(ERROR,
487 (errcode(ERRCODE_SYNTAX_ERROR),
488 errmsg("Redundant option: row_estimate_method (%s)", defGetString(def))
489 ));
490
491 option_set->row_estimate_method = defGetString(def);
492
493 if ((strcmp(option_set->row_estimate_method, "execute") != 0)
494 && (strcmp(option_set->row_estimate_method, "showplan_all") != 0))
495 {
496 ereport(ERROR,
497 (errcode(ERRCODE_SYNTAX_ERROR),
498 errmsg("row_estimate_method should be set to \"execute\" or \"showplan_all\". Currently set to %s", option_set->row_estimate_method)
499 ));
500 }
501 }
502
503 else if (strcmp(def->defname, "use_remote_estimate") == 0)
504 {
505 if (option_set->use_remote_estimate)
506 ereport(ERROR,
507 (errcode(ERRCODE_SYNTAX_ERROR),
508 errmsg("Redundant option: use_remote_estimate (%s)", defGetString(def))
509 ));
510
511 option_set->use_remote_estimate = atoi(defGetString(def));
512 }
513 }
514
515 #ifdef DEBUG
516 ereport(NOTICE,
517 (errmsg("----> finishing tdsGetForeignServerTableOptions")
518 ));
519 #endif
520 }
521
tdsGetForeignTableOptions(List * options_list,TdsFdwOptionSet * option_set)522 void tdsGetForeignTableOptions(List *options_list, TdsFdwOptionSet *option_set)
523 {
524 ListCell *cell;
525
526 #ifdef DEBUG
527 ereport(NOTICE,
528 (errmsg("----> starting tdsGetForeignTableOptions")
529 ));
530 #endif
531
532 foreach (cell, options_list)
533 {
534 DefElem *def = (DefElem *) lfirst(cell);
535
536 #ifdef DEBUG
537 ereport(NOTICE,
538 (errmsg("Working on option %s", def->defname)
539 ));
540 #endif
541
542 if (!tdsIsValidOption(def->defname, ForeignTableRelationId))
543 {
544 TdsFdwOption *opt;
545 StringInfoData buf;
546
547 initStringInfo(&buf);
548 for (opt = valid_options; opt->optname; opt++)
549 {
550 if (ForeignTableRelationId == opt->optcontext)
551 appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", opt->optname);
552 }
553
554 ereport(ERROR,
555 (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
556 errmsg("Invalid option \"%s\"", def->defname),
557 errhint("Valid options in this context are: %s", buf.len ? buf.data : "<none>")
558 ));
559 }
560
561 if (strcmp(def->defname, "query") == 0)
562 {
563 if (option_set->query)
564 ereport(ERROR,
565 (errcode(ERRCODE_SYNTAX_ERROR),
566 errmsg("Redundant option: query (%s)", defGetString(def))
567 ));
568
569 option_set->query = defGetString(def);
570 }
571
572 else if (strcmp(def->defname, "schema_name") == 0)
573 {
574 if (option_set->schema_name)
575 ereport(ERROR,
576 (errcode(ERRCODE_SYNTAX_ERROR),
577 errmsg("Redundant option: schema_name (%s)", defGetString(def))
578 ));
579
580 option_set->schema_name = defGetString(def);
581 }
582
583 else if (strcmp(def->defname, "table") == 0
584 || strcmp(def->defname, "table_name") == 0)
585 {
586 if (option_set->table_name)
587 ereport(ERROR,
588 (errcode(ERRCODE_SYNTAX_ERROR),
589 errmsg("Redundant option: %s (%s)", def->defname, defGetString(def))
590 ));
591
592 option_set->table_name = defGetString(def);
593 }
594
595 else if (strcmp(def->defname, "row_estimate_method") == 0)
596 {
597 if (option_set->row_estimate_method)
598 ereport(ERROR,
599 (errcode(ERRCODE_SYNTAX_ERROR),
600 errmsg("Redundant option: row_estimate_method (%s)", defGetString(def))
601 ));
602
603 option_set->row_estimate_method = defGetString(def);
604
605 if ((strcmp(option_set->row_estimate_method, "execute") != 0)
606 && (strcmp(option_set->row_estimate_method, "showplan_all") != 0))
607 {
608 ereport(ERROR,
609 (errcode(ERRCODE_SYNTAX_ERROR),
610 errmsg("row_estimate_method should be set to \"execute\" or \"showplan_all\". Currently set to %s", option_set->row_estimate_method)
611 ));
612 }
613 }
614
615 else if (strcmp(def->defname, "match_column_names") == 0)
616 {
617 option_set->match_column_names = atoi(defGetString(def));
618 }
619
620 else if (strcmp(def->defname, "use_remote_estimate") == 0)
621 {
622
623 option_set->use_remote_estimate = atoi(defGetString(def));
624 }
625
626 else if (strcmp(def->defname, "local_tuple_estimate") == 0)
627 {
628 if (option_set->local_tuple_estimate)
629 ereport(ERROR,
630 (errcode(ERRCODE_SYNTAX_ERROR),
631 errmsg("Redundant option: local_tuple_estimate (%s)", defGetString(def))
632 ));
633
634 option_set->local_tuple_estimate = atoi(defGetString(def));
635 }
636 }
637
638 #ifdef DEBUG
639 ereport(NOTICE,
640 (errmsg("----> finishing tdsGetForeignTableOptions")
641 ));
642 #endif
643 }
644
tdsGetUserMappingOptions(List * options_list,TdsFdwOptionSet * option_set)645 void tdsGetUserMappingOptions(List *options_list, TdsFdwOptionSet *option_set)
646 {
647 ListCell *cell;
648
649 #ifdef DEBUG
650 ereport(NOTICE,
651 (errmsg("----> starting tdsGetUserMappingOptions")
652 ));
653 #endif
654
655 foreach (cell, options_list)
656 {
657 DefElem *def = (DefElem *) lfirst(cell);
658
659 #ifdef DEBUG
660 ereport(NOTICE,
661 (errmsg("Working on option %s", def->defname)
662 ));
663 #endif
664
665 if (!tdsIsValidOption(def->defname, UserMappingRelationId))
666 {
667 TdsFdwOption *opt;
668 StringInfoData buf;
669
670 initStringInfo(&buf);
671 for (opt = valid_options; opt->optname; opt++)
672 {
673 if (UserMappingRelationId == opt->optcontext)
674 appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "", opt->optname);
675 }
676
677 ereport(ERROR,
678 (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
679 errmsg("Invalid option \"%s\"", def->defname),
680 errhint("Valid options in this context are: %s", buf.len ? buf.data : "<none>")
681 ));
682 }
683
684 if (strcmp(def->defname, "username") == 0)
685 {
686 if (option_set->username)
687 ereport(ERROR,
688 (errcode(ERRCODE_SYNTAX_ERROR),
689 errmsg("Redundant option: username (%s)", defGetString(def))
690 ));
691
692 option_set->username = defGetString(def);
693 }
694
695 else if (strcmp(def->defname, "password") == 0)
696 {
697 if (option_set->password)
698 ereport(ERROR,
699 (errcode(ERRCODE_SYNTAX_ERROR),
700 errmsg("Redundant option: password (%s)", defGetString(def))
701 ));
702
703 option_set->password = defGetString(def);
704 }
705 }
706
707 #ifdef DEBUG
708 ereport(NOTICE,
709 (errmsg("----> finishing tdsGetUserMappingOptions")
710 ));
711 #endif
712 }
713
tdsSetDefaultOptions(TdsFdwOptionSet * option_set)714 void tdsSetDefaultOptions(TdsFdwOptionSet *option_set)
715 {
716 #ifdef DEBUG
717 ereport(NOTICE,
718 (errmsg("----> starting tdsSetDefaultOptions")
719 ));
720 #endif
721
722 if (!option_set->servername)
723 {
724 if ((option_set->servername = palloc((strlen(DEFAULT_SERVERNAME) + 1) * sizeof(char))) == NULL)
725 {
726 ereport(ERROR,
727 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
728 errmsg("Failed to allocate memory for server name")
729 ));
730 }
731
732 sprintf(option_set->servername, "%s", DEFAULT_SERVERNAME);
733
734 #ifdef DEBUG
735 ereport(NOTICE,
736 (errmsg("Set servername to default: %s", option_set->servername)
737 ));
738 #endif
739 }
740
741 if (!option_set->row_estimate_method)
742 {
743 if ((option_set->row_estimate_method = palloc((strlen(DEFAULT_ROW_ESTIMATE_METHOD) + 1) * sizeof(char))) == NULL)
744 {
745 ereport(ERROR,
746 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
747 errmsg("Failed to allocate memory for row estimate method")
748 ));
749 }
750
751 sprintf(option_set->row_estimate_method, "%s", DEFAULT_ROW_ESTIMATE_METHOD);
752
753 #ifdef DEBUG
754 ereport(NOTICE,
755 (errmsg("Set row_estimate_method to default: %s", option_set->row_estimate_method)
756 ));
757 #endif
758 }
759
760 if (!option_set->msg_handler)
761 {
762 if ((option_set->msg_handler= palloc((strlen(DEFAULT_MSG_HANDLER) + 1) * sizeof(char))) == NULL)
763 {
764 ereport(ERROR,
765 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
766 errmsg("Failed to allocate memory for msg handler")
767 ));
768 }
769
770 sprintf(option_set->msg_handler, "%s", DEFAULT_MSG_HANDLER);
771
772 #ifdef DEBUG
773 ereport(NOTICE,
774 (errmsg("Set msg_handler to default: %s", option_set->msg_handler)
775 ));
776 #endif
777 }
778
779 if (!option_set->use_remote_estimate)
780 {
781 option_set->use_remote_estimate = DEFAULT_USE_REMOTE_ESTIMATE;
782
783 #ifdef DEBUG
784 ereport(NOTICE,
785 (errmsg("Set use_remote_estimate to default: %d", option_set->use_remote_estimate)
786 ));
787 #endif
788 }
789
790 if (!option_set->local_tuple_estimate)
791 {
792 option_set->local_tuple_estimate = DEFAULT_LOCAL_TUPLE_ESTIMATE;
793
794 #ifdef DEBUG
795 ereport(NOTICE,
796 (errmsg("Set local_tuple_estimate to default: %d", option_set->local_tuple_estimate)
797 ));
798 #endif
799 }
800
801 if (!option_set->fdw_startup_cost)
802 {
803 option_set->fdw_startup_cost = DEFAULT_FDW_STARTUP_COST;
804
805 #ifdef DEBUG
806 ereport(NOTICE,
807 (errmsg("Set fdw_startup_cost to default: %d", option_set->fdw_startup_cost)
808 ));
809 #endif
810 }
811
812 if (!option_set->fdw_tuple_cost)
813 {
814 option_set->fdw_tuple_cost = DEFAULT_FDW_TUPLE_COST;
815
816 #ifdef DEBUG
817 ereport(NOTICE,
818 (errmsg("Set fdw_tuple_cost to default: %d", option_set->fdw_tuple_cost)
819 ));
820 #endif
821 }
822
823 #ifdef DEBUG
824 ereport(NOTICE,
825 (errmsg("----> finishing tdsSetDefaultOptions")
826 ));
827 #endif
828 }
829
tdsValidateOptionSet(TdsFdwOptionSet * option_set)830 void tdsValidateOptionSet(TdsFdwOptionSet *option_set)
831 {
832 #ifdef DEBUG
833 ereport(NOTICE,
834 (errmsg("----> starting tdsValidateOptionSet")
835 ));
836 #endif
837
838 tdsValidateForeignTableOptionSet(option_set);
839
840 #ifdef DEBUG
841 ereport(NOTICE,
842 (errmsg("----> finishing tdsValidateOptionSet")
843 ));
844 #endif
845 }
846
tdsValidateForeignTableOptionSet(TdsFdwOptionSet * option_set)847 void tdsValidateForeignTableOptionSet(TdsFdwOptionSet *option_set)
848 {
849 #ifdef DEBUG
850 ereport(NOTICE,
851 (errmsg("----> starting tdsValidateForeignTableOptionSet")
852 ));
853 #endif
854
855 /* Check conflicting options */
856
857 if (option_set->table_name && option_set->query)
858 {
859 ereport(ERROR,
860 (errcode(ERRCODE_SYNTAX_ERROR),
861 errmsg("Conflicting options: table and query options can't be used together.")
862 ));
863 }
864
865 /* Check required options */
866
867 if (!option_set->table_name && !option_set->query)
868 {
869 ereport(ERROR,
870 (errcode(ERRCODE_SYNTAX_ERROR),
871 errmsg("Required options: either a table or a query must be specified")
872 ));
873 }
874
875 #ifdef DEBUG
876 ereport(NOTICE,
877 (errmsg("----> finishing tdsValidateForeignTableOptionSet")
878 ));
879 #endif
880 }
881
882 /* validate options for FOREIGN TABLE and FOREIGN SERVER objects using this module */
883
tdsIsValidOption(const char * option,Oid context)884 bool tdsIsValidOption(const char *option, Oid context)
885 {
886 TdsFdwOption *opt;
887
888 #ifdef DEBUG
889 ereport(NOTICE,
890 (errmsg("----> starting tdsIdValidOption")
891 ));
892 #endif
893
894 for (opt = valid_options; opt->optname; opt++)
895 {
896 if (context == opt->optcontext && strcmp(opt->optname, option) == 0)
897 return true;
898 }
899
900 #ifdef DEBUG
901 ereport(NOTICE,
902 (errmsg("----> finishing tdsIdValidOption")
903 ));
904 #endif
905
906 return false;
907 }
908
909 /* initialize the option set */
910
tdsOptionSetInit(TdsFdwOptionSet * option_set)911 void tdsOptionSetInit(TdsFdwOptionSet* option_set)
912 {
913 #ifdef DEBUG
914 ereport(NOTICE,
915 (errmsg("----> starting tdsOptionSetInit")
916 ));
917 #endif
918
919 option_set->servername = NULL;
920 option_set->language = NULL;
921 option_set->character_set = NULL;
922 option_set->port = 0;
923 option_set->database = NULL;
924 option_set->dbuse = 0;
925 option_set->tds_version = NULL;
926 option_set->msg_handler = NULL;
927 option_set->username = NULL;
928 option_set->password = NULL;
929 option_set->query = NULL;
930 option_set->schema_name = NULL;
931 option_set->table_name = NULL;
932 option_set->row_estimate_method = NULL;
933 option_set->match_column_names = DEFAULT_MATCH_COLUMN_NAMES;
934 option_set->use_remote_estimate = 0;
935 option_set->fdw_startup_cost = 0;
936 option_set->fdw_tuple_cost = 0;
937 option_set->local_tuple_estimate = 0;
938
939 #ifdef DEBUG
940 ereport(NOTICE,
941 (errmsg("----> finishing tdsOptionSetInit")
942 ));
943 #endif
944 }
945
946