aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/prep/preptlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/prep/preptlist.c')
-rw-r--r--src/backend/optimizer/prep/preptlist.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
new file mode 100644
index 00000000000..fe1c2c92ba2
--- /dev/null
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -0,0 +1,322 @@
+/*-------------------------------------------------------------------------
+ *
+ * preptlist.c--
+ * Routines to preprocess the parse tree target list
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <string.h>
+#include "postgres.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/relation.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+
+#include "nodes/makefuncs.h"
+
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/palloc.h"
+
+#include "parser/parsetree.h" /* for getrelid() */
+#include "parser/catalog_utils.h"
+
+#include "optimizer/internal.h"
+#include "optimizer/prep.h"
+#include "optimizer/clauses.h"
+#include "optimizer/tlist.h"
+
+static List *expand_targetlist(List *tlist, Oid relid, int command_type,
+ Index result_relation);
+static List *replace_matching_resname(List *new_tlist,
+ List *old_tlist);
+static List *new_relation_targetlist(Oid relid, Index rt_index,
+ NodeTag node_type);
+
+
+/*
+ * preprocess-targetlist--
+ * Driver for preprocessing the parse tree targetlist.
+ *
+ * 1. Deal with appends and replaces by filling missing attributes
+ * in the target list.
+ * 2. Reset operator OIDs to the appropriate regproc ids.
+ *
+ * Returns the new targetlist.
+ */
+List *
+preprocess_targetlist(List *tlist,
+ int command_type,
+ Index result_relation,
+ List *range_table)
+{
+ List *expanded_tlist = NIL;
+ Oid relid = InvalidOid;
+ List *t_list = NIL;
+ List *temp = NIL;
+
+ if (result_relation>=1 && command_type != CMD_SELECT) {
+ relid = getrelid(result_relation, range_table);
+ }
+
+ /*
+ * for heap_formtuple to work, the targetlist must match the exact
+ * order of the attributes. We also need to fill in the missing
+ * attributes here. -ay 10/94
+ */
+ expanded_tlist =
+ expand_targetlist(tlist, relid, command_type, result_relation);
+
+ /* XXX should the fix-opids be this early?? */
+ /* was mapCAR */
+ foreach (temp,expanded_tlist) {
+ TargetEntry *tle = lfirst(temp);
+ if (tle->expr)
+ fix_opid(tle->expr);
+ }
+ t_list = copyObject(expanded_tlist);
+
+ /* ------------------
+ * for "replace" or "delete" queries, add ctid of the result
+ * relation into the target list so that the ctid can get
+ * propogate through the execution and in the end ExecReplace()
+ * will find the right tuple to replace or delete. This
+ * extra field will be removed in ExecReplace().
+ * For convinient, we append this extra field to the end of
+ * the target list.
+ * ------------------
+ */
+ if (command_type == CMD_UPDATE || command_type == CMD_DELETE) {
+ TargetEntry *ctid;
+ Resdom *resdom;
+ Var *var;
+
+ resdom = makeResdom(length(t_list) + 1,
+ 27,
+ 6,
+ "ctid",
+ 0,
+ 0,
+ 1);
+
+ var = makeVar(result_relation, -1, 27, result_relation, -1);
+
+ ctid = makeNode(TargetEntry);
+ ctid->resdom = resdom;
+ ctid->expr = (Node *)var;
+ t_list = lappend(t_list, ctid);
+ }
+
+ return(t_list);
+}
+
+/*****************************************************************************
+ *
+ * TARGETLIST EXPANSION
+ *
+ *****************************************************************************/
+
+/*
+ * expand-targetlist--
+ * Given a target list as generated by the parser and a result relation,
+ * add targetlist entries for the attributes which have not been used.
+ *
+ * XXX This code is only supposed to work with unnested relations.
+ *
+ * 'tlist' is the original target list
+ * 'relid' is the relid of the result relation
+ * 'command' is the update command
+ *
+ * Returns the expanded target list, sorted in resno order.
+ */
+static List *
+expand_targetlist(List *tlist,
+ Oid relid,
+ int command_type,
+ Index result_relation)
+{
+ NodeTag node_type = T_Invalid;
+
+ switch (command_type) {
+ case CMD_INSERT:
+ node_type = (NodeTag)T_Const;
+ break;
+ case CMD_UPDATE:
+ node_type = (NodeTag)T_Var;
+ break;
+ }
+
+ if(node_type != T_Invalid) {
+ List *ntlist = new_relation_targetlist(relid,
+ result_relation,
+ node_type);
+
+ return (replace_matching_resname(ntlist, tlist));
+ } else {
+ return (tlist);
+ }
+
+}
+
+
+static List *
+replace_matching_resname(List *new_tlist, List *old_tlist)
+{
+ List *temp, *i;
+ List *t_list = NIL;
+
+ foreach (i,new_tlist) {
+ TargetEntry *new_tle = (TargetEntry *)lfirst(i);
+ TargetEntry *matching_old_tl = NULL;
+
+ foreach (temp, old_tlist) {
+ TargetEntry *old_tle = (TargetEntry *)lfirst(temp);
+
+ old_tle = lfirst(temp);
+ if (!strcmp(old_tle->resdom->resname,
+ new_tle->resdom->resname)) {
+ matching_old_tl = old_tle;
+ break;
+ }
+ }
+
+ if(matching_old_tl) {
+ matching_old_tl->resdom->resno =
+ new_tle->resdom->resno;
+ t_list = lappend(t_list, matching_old_tl);
+ }
+ else {
+ t_list = lappend(t_list, new_tle);
+ }
+ }
+
+ /*
+ * It is possible that 'old_tlist' has some negative
+ * attributes (i.e. negative resnos). This only happens
+ * if this is a replace/append command and we explicitly
+ * specify a system attribute. Of course this is not a very good
+ * idea if this is a user query, but on the other hand the rule
+ * manager uses this mechanism to replace rule locks.
+ *
+ * So, copy all these entries to the end of the target list
+ * and set their 'resjunk' value to 1 to show that these are
+ * special attributes and have to be treated specially by the
+ * executor!
+ */
+ foreach (temp, old_tlist) {
+ TargetEntry *old_tle, *new_tl;
+ Resdom *newresno;
+
+ old_tle = lfirst(temp);
+ if (old_tle->resdom->resno < 0) {
+ newresno = (Resdom*) copyObject((Node*)old_tle->resdom);
+ newresno->resno = length(t_list) +1;
+ newresno->resjunk = 1;
+ new_tl = MakeTLE(newresno, old_tle->expr);
+ t_list = lappend(t_list, new_tl);
+ }
+ }
+
+ return (t_list);
+}
+
+/*
+ * new-relation-targetlist--
+ * Generate a targetlist for the relation with relation OID 'relid'
+ * and rangetable index 'rt-index'.
+ *
+ * Returns the new targetlist.
+ */
+static List *
+new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
+{
+ AttrNumber attno;
+ List *t_list = NIL;
+ char *attname;
+ Oid atttype = 0;
+ int16 typlen = 0;
+ bool attisset = false;
+/* Oid type_id; */
+/* type_id = RelationIdGetTypeId(relid); */
+
+ for(attno=1; attno <= get_relnatts(relid); attno++) {
+ attname = get_attname(/*type_id,*/ relid, attno);
+ atttype = get_atttype(/*type_id,*/ relid, attno);
+ /*
+ * Since this is an append or replace, the size of any set
+ * attribute is the size of the OID used to represent it.
+ */
+ attisset = get_attisset(/* type_id,*/ relid, attname);
+ if (attisset) {
+ typlen = tlen(type("oid"));
+ } else {
+ typlen = get_typlen(atttype);
+ }
+
+ switch (node_type) {
+ case T_Const:
+ {
+ struct varlena *typedefault = get_typdefault(atttype);
+ int temp = 0;
+ Const *temp2 = (Const*)NULL;
+ TargetEntry *temp3 = (TargetEntry *)NULL;
+
+ if (typedefault==NULL)
+ temp = 0;
+ else
+ temp = typlen;
+
+ temp2 = makeConst (atttype,
+ temp,
+ (Datum)typedefault,
+ (typedefault == (struct varlena *)NULL),
+ /* XXX this is bullshit */
+ false,
+ false /* not a set */);
+
+ temp3 = MakeTLE (makeResdom(attno,
+ atttype,
+ typlen,
+ attname,
+ 0,
+ (Oid)0,
+ 0),
+ (Node*)temp2);
+ t_list = lappend(t_list,temp3);
+ break;
+ }
+ case T_Var:
+ {
+ Var *temp_var = (Var*)NULL;
+ TargetEntry *temp_list = NULL;
+
+ temp_var =
+ makeVar(rt_index, attno, atttype, rt_index, attno);
+
+ temp_list = MakeTLE(makeResdom(attno,
+ atttype,
+ typlen,
+ attname,
+ 0,
+ (Oid)0,
+ 0),
+ (Node*)temp_var);
+ t_list = lappend(t_list,temp_list);
+ break;
+ }
+ default: /* do nothing */
+ break;
+ }
+ }
+
+ return(t_list);
+}
+
+