-
Notifications
You must be signed in to change notification settings - Fork 5
/
ifx_fdw.h
495 lines (443 loc) · 14.3 KB
/
ifx_fdw.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
/*-------------------------------------------------------------------------
*
* ifx_fdw.h
* foreign-data wrapper for IBM INFORMIX databases
*
* Copyright (c) 2012, credativ GmbH
*
* IDENTIFICATION
* informix_fdw/ifx_fdw.h
*
*-------------------------------------------------------------------------
*/
#ifndef HAVE_IFX_FDW_H
#define HAVE_IFX_FDW_H
#include "postgres.h"
#include "funcapi.h"
#include "access/reloptions.h"
#if PG_VERSION_NUM >= 120000
#include "access/table.h"
#endif
#include "catalog/indexing.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_user_mapping.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/explain.h"
#include "commands/vacuum.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
#include "nodes/nodes.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
#include "storage/fd.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#if PG_VERSION_NUM < 120000
#include "utils/tqual.h"
#endif
#include "access/attnum.h"
#include "nodes/pg_list.h"
#include "postgres_ext.h"
#include "ifx_type_compat.h"
/*
* For specific implicit fall through semantics we
* need to silence the compiler
*/
#if defined(__GNUC__) && __GNUC__ >= 7
#define EXPLICIT_FALL_THROUGH __attribute__ ((fallthrough))
#else
#define EXPLICIT_FALL_THROUGH ((void)0);
#endif
/**
* PostgreSQL 13 reimplements the old Lisp-style
* List API into a dynamic array based one. This changes
* some list functions, like lnext(), so we have to deal
* with older major releases for backwards compatibility.
*/
#if PG_VERSION_NUM >= 130000
#define PG_LIST_NEXT_ITEM(l, c) lnext((l), (c))
#else
#define PG_LIST_NEXT_ITEM(l, c) lnext((c))
#endif
/**
* PostgreSQL 13 renamed generic relation related functions
* from heap_* to relation_*, so we have to deal with it
* to support older major releases.
*/
#if PG_VERSION_NUM >= 130000
#define PG_RELATION_OPEN(r, l) relation_open((r), (l))
#define PG_RELATION_CLOSE(r, l) relation_close((r), (l))
#else
#define PG_RELATION_OPEN(r, l) heap_open((r), (l))
#define PG_RELATION_CLOSE(r, l) heap_close((r), (l))
#endif
/**
* Starting with PostgreSQL 17 MyBackendId is gone and renamed to
* MyProcNumber, reflecting its real purpose (being an index into PROCARRAY
* starting with 0).
*
* To keep the number starting at 1 and the old behavior with PG < 17, we simply
* always add 1.
*/
#if PG_VERSION_NUM >= 170000
#define IFX_BACKEND_ID (MyProcNumber + 1)
#else
#define IFX_BACKEND_ID MyBackendId
#endif
/*
* Defines actions for remote informix transactions.
*/
typedef enum
{
IFX_TX_COMMIT,
IFX_TX_ROLLBACK }
IfxXactAction;
/*
* Query information pushed down
* from the planner state to the executor
*/
typedef struct IfxQueryData
{
char *query;
char *stmt_name;
char *cursor_name;
} IfxQueryData;
/*
* PgAttrDef
*
* Holds PostgreSQL foreign table column type
* and other attributes.
*/
typedef struct PgAttrDef
{
int16 attnum;
int16 ifx_attnum;
int16 param_id; /* id of param in SQLDA structure (UPDATE only)
otherwise -1 */
Oid atttypid;
int atttypmod;
char* attname;
bool attnotnull;
} PgAttrDef;
/*
* IfxPGAttrDef
*
* Holds Informix values converted into PostgreSQL datums.
*
* NOTE: def ist normally just a pointer into
* IfxStatementInfo und should not be deallocated
* directly.
*/
typedef struct IfxValue
{
/*
* Allocated column definition retrieved from
* Informix...normally this is just a pointer
* into the IfxStatementInfo structure to the
* column holding the datum.
*/
IfxAttrDef *def;
/*
* PostgreSQL datum, converted Informix column
* value.
*/
Datum val;
} IfxValue;
/*
* Stores FDW-specific properties during execution.
*
* Effectively this is a super class which combines
* informix structs into a single class, which can then
* be used by PostgreSQL properly. This makes sure we don't
* need to include colliding PostgreSQL definitions into
* the informix ESQL/C namespace.
*/
typedef struct IfxFdwExecutionState
{
IfxStatementInfo stmt_info;
/*
* Number of dropped columns of foreign table.
*/
int pgDroppedAttrCount;
/*
* Number of attributes in the foreign table.
* Should match pgAttrDefs.
*/
int pgAttrCount;
/*
* If a rescan occurs, set to true.
*/
bool rescan;
/*
* Use rowid in modify actions. This is the default
* and is set during ifxBeginForeignModify().
*/
bool use_rowid;
/*
* Holds the attribute number of the ROWID
* resjunk columns, if use_rowid is set to true.
*/
AttrNumber rowid_attno;
/*
* Dynamic list of foreign table attribute
* definitions.
*/
PgAttrDef *pgAttrDefs;
/*
* Dynamic list of column values retrieved per iteration
* from the foreign table.
*/
IfxValue *values;
/*
* List of attribute numbers affected by a modify statement
* against the foreign table. Not used during normal scans.
*/
List *affectedAttrNums;
/*
* AFTER EACH ROW triggers present. This will always be false
* on PostgreSQL versions <= 9.3, but i think it's
* okay to waste some bytes in this case.
*/
bool has_after_row_triggers;
} IfxFdwExecutionState;
#if PG_VERSION_NUM >= 90200
/*
* PostgreSQL > 9.2 uses a much smarter planning infrastructure which
* requires us to submit state structures to different callbacks. Unify
* them to a single structure to ease passing them around.
*/
typedef struct IfxFdwPlanState
{
IfxConnectionInfo *coninfo;
IfxFdwExecutionState *state;
/*
* Excluded RestrictInfo after pushdown analysis.
*/
List *excl_restrictInfo;
} IfxFdwPlanState;
#endif
/*
* PostgreSQL operator types supported for pushdown
* to an Informix database.
*/
typedef enum IfxOprType
{
IFX_OPR_EQUAL,
IFX_OPR_NEQUAL,
IFX_OPR_LE,
IFX_OPR_GE,
IFX_OPR_GT,
IFX_OPR_LT,
IFX_OPR_LIKE,
IFX_OPR_AND,
IFX_OPR_OR,
IFX_OPR_NOT,
IFX_OPR_NOT_SUPPORTED,
IFX_IS_NULL,
IFX_IS_NOT_NULL,
IFX_OPR_IN,
IFX_OPR_UNKNOWN
} IfxOprType;
/*
* Type of deparsed predicate.
*
* Currently we distinguish between deparsed predicate expression
* directly derived from deparse_expression() and cooked expression
* which are rewritten to match the expectation from Informix.
*/
typedef enum IfxDeparseType
{
IFX_DEPARSED_EXPR, /* compatible expression */
IFX_MAKE_COOKED_EXPR, /* expression cooking not yet completed */
IFX_COOKED_EXPR /* generated expression to match Informix */
} IfxDeparseType;
/*
* Info structure for pushdown operators.
*/
typedef struct IfxPushdownOprInfo
{
IfxOprType type;
IfxDeparseType deparsetype; /* type of deparsed expressions */
int16 num_args; /* total number of operands (we support
binary operators currently only) */
int16 arg_idx; /* current index number of operand */
Expr *expr; /* pointer to operator expression */
text *expr_string; /* decoded string representation of expr */
} IfxPushdownOprInfo;
/*
* Context to build IN() expressions out of an ScalarArrayOpExpr.
*/
typedef struct IfxPushdownInOprContext
{
Var *colref; /* Column/Value referencing local relation */
/*
* Rewritten column reference for pushdown,
* might be just a reference for colref in case
* no rewrite needs to be done
*/
Var *col_rewritten;
Oid target_type; /* Type OID, valid OID indicates that this Var needs
a RelabelType conversion */
int32 target_typmod;
Oid target_collid;
Oid opno;
Oid opfunc;
List *elements; /* Elements of IN() expression */
} IfxPushdownInOprContext;
/*
* Pushdown context structure for generating
* pushed down query predicates. Actually used
* by ifx_predicate_tree_walker()
*/
typedef struct IfxPushdownOprContext
{
Oid foreign_relid; /* OID of foreign table */
Index foreign_rtid; /* range table index of foreign table */
List *predicates; /* list of IfxPushDownOprInfo */
int count; /* number of elements in predicates list */
int count_removed; /* number of removed predicates for FDW pushdown */
bool has_or_expr;
} IfxPushdownOprContext;
#if PG_VERSION_NUM >= 90500
typedef struct IfxImportTableDef
{
int tabid; /* unique id of the table */
char *owner; /* schema name */
char *tablename; /* name of the table, unquoted but maybe case sensitive */
short special_cols; /* Flags describing special column types */
List *columnDef; /* List of IfxAttrDef structures describing the
foreign table columns */
} IfxImportTableDef;
#endif
/*
* Number of required connection parameters
*/
#define IFX_REQUIRED_CONN_KEYWORDS 4
/*
* Helper macros to access various struct members.
*/
#define PG_ATTRTYPE_P(x, y) (x)->pgAttrDefs[(y)].atttypid
#define PG_ATTRTYPEMOD_P(x, y) (x)->pgAttrDefs[(y)].atttypmod
/*
* Maps the local attribute number to the remote table.
*
* NOTE: One word about attribute number mapping:
*
* The Informix FDW API doesn't rely on column names, instead we
* try to map the local definition of a remote table (or query,
* depending which was specified during CREATE FOREIGN TABLE). Since
* column can be dropped and readded it might happen that we get
* *holes* in the definition of a local table. We try to address this
* with mapping PG and IFX column attributes, but it should be clear
* that this whole magic doesn't cover all cases. PostgreSQL currently
* doesn't support *logical* column orders (or reording columns
* accordingly), so in case of a static table definition this doesn't
* work in all cases. For SELECT definitions of a remote table (when
* specified the 'query' option to CREATE FOREIGN TABLE) it might be
* easier to re-specify the 'query' option with an adjusted SQL instead
* of fiddling with column orders on local table definitions.
*
* IMPORTANT:
*
* Each access to IfxFdwExecutionState structures and their member
* fields in IfxStatementInfo should go through the PG_MAPPED_IFX_ATTNUM()
* macro, otherwise it is not guaranteed that you will get proper
* values back from the values datum list. The IFX_*() macros all
* encapsulate their accesses through PG_MAPPED_IFX_ATTNUM(), so there is
* no need to pass the attnum through PG_MAPPED_IFX_ATTNUM() explicitly when
* using them. You have to think in *PostgreSQL attribute number* logic
* when using those macros!
*/
#define PG_MAPPED_IFX_ATTNUM(x, y) ((x)->pgAttrDefs[(y)].ifx_attnum - 1)
/*
* Number of valid (means visible) columns on foreign table.
* Excludes dropped columns for example.
*/
#define PG_VALID_COLS_COUNT(x) ((x)->pgAttrCount - (x)->pgDroppedAttrCount)
/*
* In case we use a ROWID to modify the remote Informix table,
* reserve an extra slot, which is required to fetch the ID later.
*
* NOTE: We *don't* reflect the extra slot within pgAttrCount, since
* this will confuse the attribute number mapping code.
*/
#define IFX_PGATTRCOUNT(a) (((a)->use_rowid) ? (a)->pgAttrCount + 1 : (a)->pgAttrCount)
/*
* Returns the param id for a prepared informix statement and its
* offset into the sqlvar array.
*/
#define IFX_ATTR_PARAM_ID(x, y) (x)->pgAttrDefs[(y)].param_id
#define IFX_ATTRTYPE_P(x, y) (x)->stmt_info.ifxAttrDefs[PG_MAPPED_IFX_ATTNUM((x), (y))].type
#define IFX_SETVAL_P(x, y, z) (x)->values[PG_MAPPED_IFX_ATTNUM((x), (y))].val = (z)
#define IFX_GETVAL_P(x, y) (x)->values[PG_MAPPED_IFX_ATTNUM((x), (y))].val
#define IFX_ATTR_ISNULL_P(x, y) ((x)->stmt_info.ifxAttrDefs[PG_MAPPED_IFX_ATTNUM((x), (y))].indicator == INDICATOR_NULL)
#define IFX_ATTR_SETNOTVALID_P(x, y) (x)->stmt_info.ifxAttrDefs[PG_MAPPED_IFX_ATTNUM((x), (y))].indicator = INDICATOR_NOT_VALID
#define IFX_ATTR_IS_VALID_P(x, y) ((x)->stmt_info.ifxAttrDefs[PG_MAPPED_IFX_ATTNUM((x), (y))].indicator != INDICATOR_NOT_VALID)
#define IFX_ATTR_ALLOC_SIZE_P(x, y) (x)->stmt_info.ifxAttrDefs[PG_MAPPED_IFX_ATTNUM((x), (y))].mem_allocated
#define IFX_SET_INDICATOR_P(x, y, z) ((x)->stmt_info.ifxAttrDefs[PG_MAPPED_IFX_ATTNUM((x), (y))].indicator = (z))
/*
* Datatype conversion routines.
*/
Datum convertIfxFloat(IfxFdwExecutionState *state, int attnum);
Datum convertIfxTimestamp(IfxFdwExecutionState *state, int attnum);
Datum convertIfxInt(IfxFdwExecutionState *state, int attnum);
Datum convertIfxCharacterString(IfxFdwExecutionState *state, int attnum);
Datum convertIfxBoolean(IfxFdwExecutionState *state, int attnum);
Datum convertIfxDateString(IfxFdwExecutionState *state, int attnum);
Datum convertIfxTimestampString(IfxFdwExecutionState *state, int attnum);
Datum convertIfxInterval(IfxFdwExecutionState *state, int attnum);
void ifxRewindCallstack(IfxStatementInfo *info);
IfxOprType mapPushdownOperator(Oid oprid, IfxPushdownOprInfo *pushdownInfo);
Datum convertIfxSimpleLO(IfxFdwExecutionState *state, int attnum);
Datum convertIfxDecimal(IfxFdwExecutionState *state, int attnum);
void setIfxInteger(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
void setIfxText(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
void setIfxCharString(IfxFdwExecutionState *state,
int attnum,
char *val,
int len);
void setIfxDateTimestamp(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
void setIfxDate(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
void setIfxInterval(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
void setIfxDecimal(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
void setIfxFloat(IfxFdwExecutionState *state,
TupleTableSlot *slot,
int attnum);
/*
* Internal API for PostgreSQL 9.3 and above.
*/
#if PG_VERSION_NUM >= 90300
char *dispatchColumnIdentifier(int varno, int varattno, PlannerInfo *root);
void ifxGenerateDeleteSql(IfxFdwExecutionState *state,
IfxConnectionInfo *coninfo);
void ifxGenerateInsertSql(IfxFdwExecutionState *state,
IfxConnectionInfo *coninfo,
PlannerInfo *root,
Index rtindex);
#endif
/*
* Node support helper functions
*/
bool ifx_predicate_tree_walker(Node *node, struct IfxPushdownOprContext *context);
#endif