mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Support writable foreign tables.
This patch adds the core-system infrastructure needed to support updates on foreign tables, and extends contrib/postgres_fdw to allow updates against remote Postgres servers. There's still a great deal of room for improvement in optimization of remote updates, but at least there's basic functionality there now. KaiGai Kohei, reviewed by Alexander Korotkov and Laurenz Albe, and rather heavily revised by Tom Lane.
This commit is contained in:
@@ -38,9 +38,6 @@ typedef ForeignScan *(*GetForeignPlan_function) (PlannerInfo *root,
|
||||
List *tlist,
|
||||
List *scan_clauses);
|
||||
|
||||
typedef void (*ExplainForeignScan_function) (ForeignScanState *node,
|
||||
struct ExplainState *es);
|
||||
|
||||
typedef void (*BeginForeignScan_function) (ForeignScanState *node,
|
||||
int eflags);
|
||||
|
||||
@@ -50,6 +47,48 @@ typedef void (*ReScanForeignScan_function) (ForeignScanState *node);
|
||||
|
||||
typedef void (*EndForeignScan_function) (ForeignScanState *node);
|
||||
|
||||
typedef void (*AddForeignUpdateTargets_function) (Query *parsetree,
|
||||
RangeTblEntry *target_rte,
|
||||
Relation target_relation);
|
||||
|
||||
typedef List *(*PlanForeignModify_function) (PlannerInfo *root,
|
||||
ModifyTable *plan,
|
||||
Index resultRelation,
|
||||
int subplan_index);
|
||||
|
||||
typedef void (*BeginForeignModify_function) (ModifyTableState *mtstate,
|
||||
ResultRelInfo *rinfo,
|
||||
List *fdw_private,
|
||||
int subplan_index,
|
||||
int eflags);
|
||||
|
||||
typedef TupleTableSlot *(*ExecForeignInsert_function) (EState *estate,
|
||||
ResultRelInfo *rinfo,
|
||||
TupleTableSlot *slot,
|
||||
TupleTableSlot *planSlot);
|
||||
|
||||
typedef TupleTableSlot *(*ExecForeignUpdate_function) (EState *estate,
|
||||
ResultRelInfo *rinfo,
|
||||
TupleTableSlot *slot,
|
||||
TupleTableSlot *planSlot);
|
||||
|
||||
typedef TupleTableSlot *(*ExecForeignDelete_function) (EState *estate,
|
||||
ResultRelInfo *rinfo,
|
||||
TupleTableSlot *slot,
|
||||
TupleTableSlot *planSlot);
|
||||
|
||||
typedef void (*EndForeignModify_function) (EState *estate,
|
||||
ResultRelInfo *rinfo);
|
||||
|
||||
typedef void (*ExplainForeignScan_function) (ForeignScanState *node,
|
||||
struct ExplainState *es);
|
||||
|
||||
typedef void (*ExplainForeignModify_function) (ModifyTableState *mtstate,
|
||||
ResultRelInfo *rinfo,
|
||||
List *fdw_private,
|
||||
int subplan_index,
|
||||
struct ExplainState *es);
|
||||
|
||||
typedef int (*AcquireSampleRowsFunc) (Relation relation, int elevel,
|
||||
HeapTuple *rows, int targrows,
|
||||
double *totalrows,
|
||||
@@ -73,22 +112,34 @@ typedef struct FdwRoutine
|
||||
{
|
||||
NodeTag type;
|
||||
|
||||
/*
|
||||
* These functions are required.
|
||||
*/
|
||||
/* Functions for scanning foreign tables */
|
||||
GetForeignRelSize_function GetForeignRelSize;
|
||||
GetForeignPaths_function GetForeignPaths;
|
||||
GetForeignPlan_function GetForeignPlan;
|
||||
ExplainForeignScan_function ExplainForeignScan;
|
||||
BeginForeignScan_function BeginForeignScan;
|
||||
IterateForeignScan_function IterateForeignScan;
|
||||
ReScanForeignScan_function ReScanForeignScan;
|
||||
EndForeignScan_function EndForeignScan;
|
||||
|
||||
/*
|
||||
* These functions are optional. Set the pointer to NULL for any that are
|
||||
* not provided.
|
||||
* Remaining functions are optional. Set the pointer to NULL for any that
|
||||
* are not provided.
|
||||
*/
|
||||
|
||||
/* Functions for updating foreign tables */
|
||||
AddForeignUpdateTargets_function AddForeignUpdateTargets;
|
||||
PlanForeignModify_function PlanForeignModify;
|
||||
BeginForeignModify_function BeginForeignModify;
|
||||
ExecForeignInsert_function ExecForeignInsert;
|
||||
ExecForeignUpdate_function ExecForeignUpdate;
|
||||
ExecForeignDelete_function ExecForeignDelete;
|
||||
EndForeignModify_function EndForeignModify;
|
||||
|
||||
/* Support functions for EXPLAIN */
|
||||
ExplainForeignScan_function ExplainForeignScan;
|
||||
ExplainForeignModify_function ExplainForeignModify;
|
||||
|
||||
/* Support functions for ANALYZE */
|
||||
AnalyzeForeignTable_function AnalyzeForeignTable;
|
||||
} FdwRoutine;
|
||||
|
||||
|
@@ -270,7 +270,8 @@ typedef struct ProjectionInfo
|
||||
* resultSlot: tuple slot used to hold cleaned tuple.
|
||||
* junkAttNo: not used by junkfilter code. Can be used by caller
|
||||
* to remember the attno of a specific junk attribute
|
||||
* (execMain.c stores the "ctid" attno here).
|
||||
* (nodeModifyTable.c keeps the "ctid" or "wholerow"
|
||||
* attno here).
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct JunkFilter
|
||||
@@ -300,6 +301,8 @@ typedef struct JunkFilter
|
||||
* TrigFunctions cached lookup info for trigger functions
|
||||
* TrigWhenExprs array of trigger WHEN expr states
|
||||
* TrigInstrument optional runtime measurements for triggers
|
||||
* FdwRoutine FDW callback functions, if foreign table
|
||||
* FdwState available to save private state of FDW
|
||||
* ConstraintExprs array of constraint-checking expr states
|
||||
* junkFilter for removing junk attributes from tuples
|
||||
* projectReturning for computing a RETURNING list
|
||||
@@ -317,6 +320,8 @@ typedef struct ResultRelInfo
|
||||
FmgrInfo *ri_TrigFunctions;
|
||||
List **ri_TrigWhenExprs;
|
||||
Instrumentation *ri_TrigInstrument;
|
||||
struct FdwRoutine *ri_FdwRoutine;
|
||||
void *ri_FdwState;
|
||||
List **ri_ConstraintExprs;
|
||||
JunkFilter *ri_junkFilter;
|
||||
ProjectionInfo *ri_projectReturning;
|
||||
|
@@ -173,6 +173,7 @@ typedef struct ModifyTable
|
||||
int resultRelIndex; /* index of first resultRel in plan's list */
|
||||
List *plans; /* plan(s) producing source data */
|
||||
List *returningLists; /* per-target-table RETURNING tlists */
|
||||
List *fdwPrivLists; /* per-target-table FDW private data lists */
|
||||
List *rowMarks; /* PlanRowMarks (non-locking only) */
|
||||
int epqParam; /* ID of Param for EvalPlanQual re-eval */
|
||||
} ModifyTable;
|
||||
@@ -752,13 +753,32 @@ typedef struct Limit
|
||||
* RowMarkType -
|
||||
* enums for types of row-marking operations
|
||||
*
|
||||
* When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we have to uniquely
|
||||
* The first four of these values represent different lock strengths that
|
||||
* we can take on tuples according to SELECT FOR [KEY] UPDATE/SHARE requests.
|
||||
* We only support these on regular tables. For foreign tables, any locking
|
||||
* that might be done for these requests must happen during the initial row
|
||||
* fetch; there is no mechanism for going back to lock a row later (and thus
|
||||
* no need for EvalPlanQual machinery during updates of foreign tables).
|
||||
* This means that the semantics will be a bit different than for a local
|
||||
* table; in particular we are likely to lock more rows than would be locked
|
||||
* locally, since remote rows will be locked even if they then fail
|
||||
* locally-checked restriction or join quals. However, the alternative of
|
||||
* doing a separate remote query to lock each selected row is extremely
|
||||
* unappealing, so let's do it like this for now.
|
||||
*
|
||||
* When doing UPDATE, DELETE, or SELECT FOR UPDATE/SHARE, we have to uniquely
|
||||
* identify all the source rows, not only those from the target relations, so
|
||||
* that we can perform EvalPlanQual rechecking at need. For plain tables we
|
||||
* can just fetch the TID, the same as for a target relation. Otherwise (for
|
||||
* example for VALUES or FUNCTION scans) we have to copy the whole row value.
|
||||
* The latter is pretty inefficient but fortunately the case is not
|
||||
* performance-critical in practice.
|
||||
* can just fetch the TID, much as for a target relation; this case is
|
||||
* represented by ROW_MARK_REFERENCE. Otherwise (for example for VALUES or
|
||||
* FUNCTION scans) we have to copy the whole row value. ROW_MARK_COPY is
|
||||
* pretty inefficient, since most of the time we'll never need the data; but
|
||||
* fortunately the case is not performance-critical in practice. Note that
|
||||
* we use ROW_MARK_COPY for non-target foreign tables, even if the FDW has a
|
||||
* concept of rowid and so could theoretically support some form of
|
||||
* ROW_MARK_REFERENCE. Although copying the whole row value is inefficient,
|
||||
* it's probably still faster than doing a second remote fetch, so it doesn't
|
||||
* seem worth the extra complexity to permit ROW_MARK_REFERENCE.
|
||||
*/
|
||||
typedef enum RowMarkType
|
||||
{
|
||||
@@ -776,10 +796,10 @@ typedef enum RowMarkType
|
||||
* PlanRowMark -
|
||||
* plan-time representation of FOR [KEY] UPDATE/SHARE clauses
|
||||
*
|
||||
* When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we create a separate
|
||||
* When doing UPDATE, DELETE, or SELECT FOR UPDATE/SHARE, we create a separate
|
||||
* PlanRowMark node for each non-target relation in the query. Relations that
|
||||
* are not specified as FOR [KEY] UPDATE/SHARE are marked ROW_MARK_REFERENCE (if
|
||||
* real tables) or ROW_MARK_COPY (if not).
|
||||
* are not specified as FOR UPDATE/SHARE are marked ROW_MARK_REFERENCE (if
|
||||
* regular tables) or ROW_MARK_COPY (if not).
|
||||
*
|
||||
* Initially all PlanRowMarks have rti == prti and isParent == false.
|
||||
* When the planner discovers that a relation is the root of an inheritance
|
||||
@@ -791,7 +811,7 @@ typedef enum RowMarkType
|
||||
*
|
||||
* The planner also adds resjunk output columns to the plan that carry
|
||||
* information sufficient to identify the locked or fetched rows. For
|
||||
* tables (markType != ROW_MARK_COPY), these columns are named
|
||||
* regular tables (markType != ROW_MARK_COPY), these columns are named
|
||||
* tableoid%u OID of table
|
||||
* ctid%u TID of row
|
||||
* The tableoid column is only present for an inheritance hierarchy.
|
||||
|
@@ -79,7 +79,8 @@ extern SetOp *make_setop(SetOpCmd cmd, SetOpStrategy strategy, Plan *lefttree,
|
||||
long numGroups, double outputRows);
|
||||
extern Result *make_result(PlannerInfo *root, List *tlist,
|
||||
Node *resconstantqual, Plan *subplan);
|
||||
extern ModifyTable *make_modifytable(CmdType operation, bool canSetTag,
|
||||
extern ModifyTable *make_modifytable(PlannerInfo *root,
|
||||
CmdType operation, bool canSetTag,
|
||||
List *resultRelations, List *subplans, List *returningLists,
|
||||
List *rowMarks, int epqParam);
|
||||
extern bool is_projection_capable_plan(Plan *plan);
|
||||
|
Reference in New Issue
Block a user