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