diff options
Diffstat (limited to 'src/backend/optimizer/prep/preptlist.c')
-rw-r--r-- | src/backend/optimizer/prep/preptlist.c | 322 |
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); +} + + |