summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/createplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r--src/backend/optimizer/plan/createplan.c222
1 files changed, 218 insertions, 4 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 382e56888c..8a42c7176d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -5414,7 +5414,7 @@ create_remoteinsert_plan(PlannerInfo *root, Plan *topplan)
buf = makeStringInfo();
- /* Compose DELETE FROM target_table */
+ /* Compose INSERT FROM target_table */
nspid = get_rel_namespace(ttab->relid);
nspname = get_namespace_name(nspid);
@@ -5549,11 +5549,226 @@ create_remoteinsert_plan(PlannerInfo *root, Plan *topplan)
/*
* create_remoteupdate_plan()
*
- * Dummy
+ * For every target relation, add a remote query node to carry out remote
+ * operations.
+ * WHERE and SET clauses are populated with the relation attributes.
+ * Target list is used for SET clause and completed with the expressions already given.
+ * SET clause is completed with new parameters whose values are resulting from the
+ * SELECT query generated by create_remotequery_plan.
*/
Plan *
create_remoteupdate_plan(PlannerInfo *root, Plan *topplan)
{
+ ModifyTable *mt = (ModifyTable *)topplan;
+ ListCell *l;
+
+ /* We expect to work only on ModifyTable node */
+ if (!IsA(topplan, ModifyTable))
+ elog(ERROR, "Unexpected node type: %d", topplan->type);
+
+ /*
+ * For every result relation, build a remote plan to execute remote update.
+ */
+ foreach(l, mt->resultRelations)
+ {
+ Index resultRelationIndex = lfirst_int(l);
+ Query *parse = root->parse;
+ RangeTblEntry *ttab;
+ RelationLocInfo *rel_loc_info;
+ StringInfo buf, buf2;
+ Oid nspid; /* Relation namespace Oid */
+ char *nspname; /* Relation namespace name */
+ Oid *att_types; /* Types of query parameters */
+ int natts, att;
+ List *tlist = NIL; /* Target list of remote UPDATE */
+ bool is_set_printed = false; /* Control of SET generation */
+ bool is_where_printed = false; /* Control of WHERE generation */
+ RemoteQuery *fstep; /* Plan step generated */
+
+ ttab = rt_fetch(resultRelationIndex, parse->rtable);
+
+ /* Bad relation ? */
+ if (ttab == NULL || ttab->rtekind != RTE_RELATION)
+ continue;
+
+ /* Get location info of the target table */
+ rel_loc_info = GetRelationLocInfo(ttab->relid);
+ if (rel_loc_info == NULL)
+ continue;
+
+ /* Get number of arrtibutes */
+ natts = get_relnatts(ttab->relid);
+
+ /*
+ * PGXCTODO: Allow use of remote UPDATE in case all the columns are
+ * updated at once. In this case, create_remotequery_plan refers to
+ * remote tuples with only the ctid which is not used by this part of
+ * planning. CTID needs to be coupled with the node name of where
+ * the tuple is located to avoid inconsistency due to similar CTIDs
+ * among PGXC remote nodes.
+ * This has no impact on distributed table as distribution column
+ * cannot be updated yet, so only replicated tables are impacted now.
+ */
+ if (list_length(parse->targetList) == natts + 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Postgres-XC does not support remote UPDATE on all columns"),
+ errdetail("At least one column reference to a remote value is necessary")));
+
+ /* Create query buffers */
+ buf = makeStringInfo(); /* For SET clause */
+ buf2 = makeStringInfo(); /* For WHERE clause */
+
+ /* Compose UPDATE target_table */
+ nspid = get_rel_namespace(ttab->relid);
+ nspname = get_namespace_name(nspid);
+
+ /*
+ * Do not qualify with namespace for TEMP tables. The schema name may
+ * vary on each node
+ */
+ if (IsTempTable(ttab->relid))
+ appendStringInfo(buf, "UPDATE %s SET",
+ quote_identifier(ttab->relname));
+ else
+ appendStringInfo(buf, "UPDATE %s.%s SET ", quote_identifier(nspname),
+ quote_identifier(ttab->relname));
+ fstep = make_remotequery(NIL, ttab, NIL, ttab->relid);
+ fstep->is_temp = IsTempTable(ttab->relid);
+
+ /* All the parameters are the tuple attributes */
+ att_types = (Oid *) palloc0 (sizeof (Oid) * natts);
+
+ /*
+ * Populate the SET and WHERE clauses with parameters.
+ * WHERE clause is completed by attributes located in the target list
+ * as those parameters will be set with the result of the SELECT remote
+ * query generated by create_remotequery_plan.
+ * SET is completed with the attributes in remote query and their given
+ * expressions.
+ */
+ for (att = 1; att <= natts; att++)
+ {
+ HeapTuple tp;
+
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(ttab->relid),
+ Int16GetDatum(att),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ ListCell *elt;
+ bool is_found = false;
+ TargetEntry *tle_saved;
+
+ /*
+ * Attributes in the target list are inserted in the SET clause directly
+ * because they are the values being changed, the attributes not in target
+ * list are used to select correct elements on remote nodes and added in target list.
+ */
+ foreach(elt, parse->targetList)
+ {
+ TargetEntry *tle = lfirst(elt);
+ tle_saved = tle;
+ if (strcmp(tle->resname, NameStr(att_tup->attname)) == 0)
+ {
+ is_found = true;
+ break;
+ }
+ }
+
+ /*
+ * If attribute is found in target list, add it to SET clause and
+ * create associated parameter. If it is not found, this attribute
+ * is used in WHERE clause with a new parameter whose value is set
+ * with the SELECT query created by create_remotequery_plan on top
+ * of this plan.
+ */
+ if (is_found)
+ {
+ TargetEntry *tle;
+
+ /* Add comma before all except first attributes */
+ if (!is_set_printed)
+ is_set_printed = true;
+ else
+ appendStringInfoString(buf, ", ");
+
+ att_types[att - 1] = att_tup->atttypid;
+ appendStringInfo(buf, "%s = $%d",
+ quote_identifier(NameStr(att_tup->attname)),
+ att);
+
+ /*
+ * Add attribute to target list for remote query,
+ * and use here the original target entry expression
+ */
+ tle = makeTargetEntry(tle_saved->expr, att,
+ NameStr(att_tup->attname), false);
+ tlist = lappend(tlist, tle);
+ }
+ else
+ {
+ TargetEntry *tle;
+ Var *expr;
+
+ /* Set the clause if necessary */
+ if (!is_where_printed)
+ {
+ is_where_printed = true;
+ appendStringInfoString(buf2, " WHERE ");
+ }
+ else
+ appendStringInfoString(buf2, "AND ");
+
+ /* Build parameter string */
+ att_types[att - 1] = att_tup->atttypid;
+ appendStringInfo(buf2, "%s = $%d ",
+ quote_identifier(NameStr(att_tup->attname)),
+ att);
+
+ /* Add parameter to the target list for remote query */
+ expr = makeVar(att, att, att_tup->atttypid,
+ att_tup->atttypmod, InvalidOid, 0);
+ tle = makeTargetEntry((Expr *) expr, att,
+ NameStr(att_tup->attname), false);
+ tlist = lappend(tlist, tle);
+ }
+ ReleaseSysCache(tp);
+ }
+ else
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ att, ttab->relid);
+ }
+
+ /* Finish building the query by gathering SET and WHERE clauses */
+ appendStringInfo(buf, "%s", buf2->data);
+
+ /* Finally build the final UPDATE step */
+ fstep = make_remotequery(tlist, ttab, NIL, ttab->relid);
+ fstep->is_temp = IsTempTable(ttab->relid);
+ fstep->sql_statement = pstrdup(buf->data);
+ fstep->combine_type = COMBINE_TYPE_NONE;
+
+ fstep->read_only = false;
+ fstep->exec_nodes = makeNode(ExecNodes);
+ fstep->exec_nodes = GetRelationNodes(rel_loc_info, 0, UNKNOWNOID, RELATION_ACCESS_UPDATE);
+ fstep->exec_nodes->baselocatortype = rel_loc_info->locatorType;
+ fstep->exec_nodes->tableusagetype = TABLE_USAGE_TYPE_USER;
+ fstep->exec_nodes->primarynodelist = NULL;
+ fstep->exec_nodes->nodeList = NULL;
+ fstep->exec_nodes->en_relid = ttab->relid;
+ fstep->exec_nodes->accesstype = RELATION_ACCESS_UPDATE;
+ SetRemoteStatementName((Plan *) fstep, NULL, natts, att_types, 0);
+ pfree(buf->data);
+ pfree(buf2->data);
+ pfree(buf);
+ pfree(buf2);
+
+ mt->remote_plans = lappend(mt->remote_plans, fstep);
+ }
+
return topplan;
}
@@ -5587,7 +5802,6 @@ create_remotedelete_plan(PlannerInfo *root, Plan *topplan)
char *nspname;
Var *ctid;
-
/* Get target table */
ttab = (RangeTblEntry *) list_nth(parse->rtable, parse->resultRelation - 1);
/* Bad relation ? */
@@ -5989,7 +6203,7 @@ create_remotegrouping_plan(PlannerInfo *root, Plan *local_plan)
remote_group->remotejoin = false;
remote_group->inner_alias = pstrdup(in_alias->data);
remote_group->inner_reduce_level = remote_scan->reduce_level;
- remote_group->inner_relids = in_relids;
+ remote_group->inner_relids = in_relids;
remote_group->inner_statement = pstrdup(remote_scan->sql_statement);
remote_group->exec_nodes = remote_scan->exec_nodes;
/* Don't forget to increment the index for the next time around! */