1 /*------------------------------------------------------------------
2 *
3 *				Foreign data wrapper for TDS (Sybase and Microsoft SQL Server)
4 *
5 * Author: Geoff Montee
6 * Name: tds_fdw
7 * File: tds_fdw/include/tds_fdw.h
8 *
9 * Description:
10 * This is a PostgreSQL foreign data wrapper for use to connect to databases that use TDS,
11 * such as Sybase databases and Microsoft SQL server.
12 *
13 * This foreign data wrapper requires requires a library that uses the DB-Library interface,
14 * such as FreeTDS (http://www.freetds.org/). This has been tested with FreeTDS, but not
15 * the proprietary implementations of DB-Library.
16 *----------------------------------------------------------------------------
17 */
18 
19 
20 #ifndef TDS_FDW_H
21 #define TDS_FDW_H
22 
23 /* postgres headers */
24 
25 #include "postgres.h"
26 #include "funcapi.h"
27 #include "commands/explain.h"
28 #include "foreign/fdwapi.h"
29 #include "foreign/foreign.h"
30 
31 #if (PG_VERSION_NUM >= 90200)
32 #include "optimizer/pathnode.h"
33 #include "optimizer/restrictinfo.h"
34 #include "optimizer/planmain.h"
35 #endif
36 
37 /* DB-Library headers (e.g. FreeTDS) */
38 #include <sybfront.h>
39 #include <sybdb.h>
40 
41 #include "options.h"
42 
43 #if PG_VERSION_NUM >= 90500
44 #define IMPORT_API
45 #else
46 #undef IMPORT_API
47 #endif  /* PG_VERSION_NUM */
48 
49 /* a column */
50 
51 typedef union COL_VALUE
52 {
53 	DBSMALLINT dbsmallint;
54 	DBINT dbint;
55 	DBBIGINT dbbigint;
56 	DBREAL dbreal;
57 	DBFLT8 dbflt8;
58 } COL_VALUE;
59 
60 typedef struct COL
61 {
62 	char *name;
63 	int srctype;
64 	bool useraw;
65 	COL_VALUE value;
66 	int local_index;
67 	Oid attr_oid;
68 } COL;
69 
70 /* This struct is similar to PgFdwRelationInfo from postgres_fdw */
71 typedef struct TdsFdwRelationInfo
72 {
73 	/* baserestrictinfo clauses, broken down into safe and unsafe subsets. */
74 	List	   *remote_conds;
75 	List	   *local_conds;
76 
77 	/* Bitmap of attr numbers we need to fetch from the remote server. */
78 	Bitmapset  *attrs_used;
79 
80 	/* Cost and selectivity of local_conds. */
81 	QualCost	local_conds_cost;
82 	Selectivity local_conds_sel;
83 
84 	/* Estimated size and cost for a scan with baserestrictinfo quals. */
85 	double		rows;
86 	int			width;
87 	Cost		startup_cost;
88 	Cost		total_cost;
89 
90 	/* Options extracted from catalogs. */
91 	bool		use_remote_estimate;
92 	Cost		fdw_startup_cost;
93 	Cost		fdw_tuple_cost;
94 	/* tds_fdw won't ship any PostgreSQL extensions. remove this later. */
95 	//List	   *shippable_extensions;	/* OIDs of whitelisted extensions */
96 
97 	/* Cached catalog information. */
98 	ForeignTable *table;
99 	ForeignServer *server;
100 	UserMapping *user;			/* only set in use_remote_estimate mode */
101 } TdsFdwRelationInfo;
102 
103 /* this maintains state */
104 
105 typedef struct TdsFdwExecutionState
106 {
107 	LOGINREC *login;
108 	DBPROCESS *dbproc;
109 	AttInMetadata *attinmeta;
110 	char *query;
111 	List *retrieved_attrs;
112 	int first;
113 	COL *columns;
114 	Datum *datums;
115 	bool *isnull;
116 	int ncols;
117 	int row;
118 	MemoryContext mem_cxt;
119 } TdsFdwExecutionState;
120 
121 /* Callback argument for ec_member_matches_foreign */
122 typedef struct
123 {
124 	Expr	   *current;		/* current expr, or NULL if not yet found */
125 	List	   *already_used;	/* expressions already dealt with */
126 } ec_member_foreign_arg;
127 
128 /* functions called via SQL */
129 
130 extern Datum tds_fdw_handler(PG_FUNCTION_ARGS);
131 extern Datum tds_fdw_validator(PG_FUNCTION_ARGS);
132 
133 /* FDW callback routines */
134 
135 void tdsExplainForeignScan(ForeignScanState *node, ExplainState *es);
136 void tdsBeginForeignScan(ForeignScanState *node, int eflags);
137 TupleTableSlot* tdsIterateForeignScan(ForeignScanState *node);
138 void tdsReScanForeignScan(ForeignScanState *node);
139 void tdsEndForeignScan(ForeignScanState *node);
140 
141 /* routines for 9.2.0+ */
142 #if (PG_VERSION_NUM >= 90200)
143 void tdsGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
144 void tdsEstimateCosts(PlannerInfo *root, RelOptInfo *baserel, Cost *startup_cost, Cost *total_cost, Oid foreigntableid);
145 void tdsGetForeignPaths(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid);
146 bool tdsAnalyzeForeignTable(Relation relation, AcquireSampleRowsFunc *func, BlockNumber *totalpages);
147 #if (PG_VERSION_NUM >= 90500)
148 ForeignScan* tdsGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses, Plan *outer_plan);
149 #else
150 ForeignScan* tdsGetForeignPlan(PlannerInfo *root, RelOptInfo *baserel, Oid foreigntableid, ForeignPath *best_path, List *tlist, List *scan_clauses);
151 #endif
152 /* routines for versions older than 9.2.0 */
153 #else
154 FdwPlan* tdsPlanForeignScan(Oid foreigntableid, PlannerInfo *root, RelOptInfo *baserel);
155 #endif
156 
157 #ifdef IMPORT_API
158 List *tdsImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid);
159 #endif  /* IMPORT_API */
160 
161 /* compatibility with PostgreSQL 9.6+ */
162 #ifndef ALLOCSET_DEFAULT_SIZES
163 #define ALLOCSET_DEFAULT_SIZES \
164 ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
165 #endif
166 
167 /* compatibility with PostgreSQL v11+ */
168 #if PG_VERSION_NUM < 110000
169 /* new in v11 */
170 #define TupleDescAttr(tupdesc, i) ((tupdesc)->attrs[(i)])
171 #else
172 /* removed in v11 */
173 #define get_relid_attribute_name(relid, varattno) get_attname((relid), (varattno), false)
174 #endif
175 
176 /* Helper functions */
177 
178 bool is_builtin(Oid objectId);
179 Expr * find_em_expr_for_rel(EquivalenceClass *ec, RelOptInfo *rel);
180 bool is_shippable(Oid objectId, Oid classId, TdsFdwRelationInfo *fpinfo);
181 void tdsBuildForeignQuery(PlannerInfo *root, RelOptInfo *baserel, TdsFdwOptionSet* option_set,
182 	Bitmapset* attrs_used, List** retrieved_attrs,
183 	List* remote_conds, List* remote_join_conds, List* pathkeys);
184 int tdsSetupConnection(TdsFdwOptionSet* option_set, LOGINREC *login, DBPROCESS **dbproc);
185 double tdsGetRowCount(TdsFdwOptionSet* option_set, LOGINREC *login, DBPROCESS *dbproc);
186 double tdsGetRowCountShowPlanAll(TdsFdwOptionSet* option_set, LOGINREC *login, DBPROCESS *dbproc);
187 double tdsGetRowCountExecute(TdsFdwOptionSet* option_set, LOGINREC *login, DBPROCESS *dbproc);
188 double tdsGetStartupCost(TdsFdwOptionSet* option_set);
189 void tdsGetColumnMetadata(ForeignScanState *node, TdsFdwOptionSet *option_set);
190 char* tdsConvertToCString(DBPROCESS* dbproc, int srctype, const BYTE* src, DBINT srclen);
191 #if (PG_VERSION_NUM >= 90400)
192 int tdsDatetimeToDatum(DBPROCESS *dbproc, DBDATETIME *src, Datum *datetime_out);
193 #endif
194 
195 /* Helper functions for DB-Library API */
196 
197 int tds_err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr);
198 int tds_notice_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *svr_name, char *proc_name, int line);
199 int tds_blackhole_msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *svr_name, char *proc_name, int line);
200 
201 #endif
202