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