Break parser functions into smaller files, group together.
authorBruce Momjian
Tue, 25 Nov 1997 22:07:18 +0000 (22:07 +0000)
committerBruce Momjian
Tue, 25 Nov 1997 22:07:18 +0000 (22:07 +0000)
62 files changed:
src/backend/access/common/tupdesc.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/pg_operator.c
src/backend/catalog/pg_proc.c
src/backend/catalog/pg_type.c
src/backend/commands/_deadcode/version.c
src/backend/commands/explain.c
src/backend/commands/recipe.c
src/backend/commands/remove.c
src/backend/commands/vacuum.c
src/backend/commands/view.c
src/backend/executor/execTuples.c
src/backend/executor/functions.c
src/backend/executor/nodeAgg.c
src/backend/executor/spi.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/print.c
src/backend/optimizer/path/xfunc.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/preptlist.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/tlist.c
src/backend/parser/Makefile
src/backend/parser/analyze.c
src/backend/parser/catalog_utils.c [deleted file]
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_agg.c [new file with mode: 0644]
src/backend/parser/parse_clause.c [new file with mode: 0644]
src/backend/parser/parse_expr.c [new file with mode: 0644]
src/backend/parser/parse_func.c [new file with mode: 0644]
src/backend/parser/parse_node.c [moved from src/backend/parser/parse_query.c with 56% similarity]
src/backend/parser/parse_oper.c [new file with mode: 0644]
src/backend/parser/parse_relation.c [new file with mode: 0644]
src/backend/parser/parse_target.c [new file with mode: 0644]
src/backend/parser/parse_type.c [new file with mode: 0644]
src/backend/parser/parser.c
src/backend/parser/scansup.c
src/backend/rewrite/rewriteDefine.c
src/backend/tcop/aclchk.c
src/backend/tcop/postgres.c
src/include/executor/spi.h
src/include/nodes/nodeFuncs.h
src/include/optimizer/planner.h
src/include/parser/analyze.h [new file with mode: 0644]
src/include/parser/catalog_utils.h [deleted file]
src/include/parser/parse_agg.h [new file with mode: 0644]
src/include/parser/parse_clause.h [new file with mode: 0644]
src/include/parser/parse_expr.h [new file with mode: 0644]
src/include/parser/parse_func.h [new file with mode: 0644]
src/include/parser/parse_node.h [new file with mode: 0644]
src/include/parser/parse_oper.h [new file with mode: 0644]
src/include/parser/parse_query.h [deleted file]
src/include/parser/parse_relation.h [new file with mode: 0644]
src/include/parser/parse_state.h [deleted file]
src/include/parser/parse_target.h [new file with mode: 0644]
src/include/parser/parse_type.h [new file with mode: 0644]
src/include/parser/parser.h [new file with mode: 0644]
src/include/tcop/tcopprot.h
src/test/regress/checkresults

index 04622a1362a112f65748820e5554676a8c0c295d..1a8d2975cc4ccb8618e3d2244b1f553a01b67565 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.28 1997/11/24 05:07:42 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.29 1997/11/25 21:58:35 momjian Exp $
  *
  * NOTES
  *   some of the executor utility code such as "ExecTypeFromTL" should be
@@ -20,8 +20,9 @@
 
 #include 
 
-#include <parser/catalog_utils.h>
+#include <catalog/pg_type.h>
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -377,10 +378,10 @@ TupleDescInitEntry(TupleDesc desc,
       */
    if (attisset)
    {
-       Type        t = type("oid");
+       Type        t = typeidType(OIDOID);
 
-       att->attlen = tlen(t);
-       att->attbyval = tbyval(t);
+       att->attlen = typeLen(t);
+       att->attbyval = typeByVal(t);
    }
    else
    {
@@ -410,12 +411,12 @@ TupleDescMakeSelfReference(TupleDesc desc,
                           char *relname)
 {
    AttributeTupleForm att;
-   Type        t = type("oid");
+   Type        t = typeidType(OIDOID);
 
    att = desc->attrs[attnum - 1];
    att->atttypid = TypeShellMake(relname);
-   att->attlen = tlen(t);
-   att->attbyval = tbyval(t);
+   att->attlen = typeLen(t);
+   att->attbyval = typeByVal(t);
    att->attnelems = 0;
 }
 
index 6a150a01b22a411038eaf09a80c2a8f684c4ad8b..512e2a0fe31b2500d7895b10e73a99865224aede 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.33 1997/11/24 05:08:07 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.34 1997/11/25 21:58:40 momjian Exp $
  *
  * INTERFACE ROUTINES
  *     heap_creatr()           - Create an uncataloged heap relation
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
-#include 
-#include 
 #include 
 #include 
 #include 
@@ -722,8 +723,8 @@ addNewRelationType(char *typeName, Oid new_rel_oid)
     */
    new_type_oid = TypeCreate(typeName, /* type name */
                              new_rel_oid,      /* relation oid */
-                             tlen(type("oid")),        /* internal size */
-                             tlen(type("oid")),        /* external size */
+                             typeLen(typeidType(OIDOID)),  /* internal size */
+                             typeLen(typeidType(OIDOID)),  /* external size */
                              'c',      /* type-type (catalog) */
                              ',',      /* default array delimiter */
                              "int4in", /* input procedure */
index 418123a0aa5979e9ad4907b4b6fc056f7b3ced7e..deb908e24f80b1f2d1fd8b93ced5930db332e061 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.29 1997/11/24 05:08:11 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.30 1997/11/25 21:58:43 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
 #include 
 #include 
 #include 
-#include 
-#include 
+#include 
 #include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
-#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #ifndef HAVE_MEMMOVE
 #include 
index a4b4919417e3b689bb5e3b39937fa8d30a6e02b7..bbdd23701ade6e0d21b32c46e6a6f6dd0843c2f5 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.16 1997/11/24 05:08:15 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.17 1997/11/25 21:58:46 momjian Exp $
  *
  * NOTES
  *   these routines moved here from commands/define.c and somewhat cleaned up.
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
index 9cbf4e3d7c7aa6c620e8e1361631bd1136b93214..e08bb549c61bd326468c28b6aa8e2a954461d9aa 100644 (file)
@@ -7,28 +7,28 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.9 1997/09/18 20:20:18 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.10 1997/11/25 21:58:48 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 
+#include 
+#include 
 #include 
 #include 
 #include 
 #include 
-#include 
-#include 
-#include 
 #include 
 #include 
-#include 
+#include 
+#include 
 #include 
-#include 
+#include 
+#include 
+#include 
 #include 
 #include 
-#include 
-#include 
 #ifndef HAVE_MEMMOVE
 #include 
 #else
@@ -200,7 +200,7 @@ ProcedureCreate(char *procedureName,
    if (parameterCount == 1 &&
        (toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
        defined &&
-       (relid = typeid_get_relid(toid)) != 0 &&
+       (relid = typeidTypeRelid(toid)) != 0 &&
        get_attnum(relid, procedureName) != InvalidAttrNumber)
        elog(WARN, "method %s already an attribute of type %s",
             procedureName, strVal(lfirst(argList)));
index 2dc80bbbe002ec4da346d07f53e12379caa9d18e..1cd0fa936c8c83b033d21c74714e3df6b6134a78 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.13 1997/11/24 05:08:17 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.14 1997/11/25 21:58:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #ifndef HAVE_MEMMOVE
index 0059405767209fcd54d73c2e8df1d1c8530520f8..829f9241ee8cfc4b1b57060dc67e8b09250d3799 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.7 1997/09/08 02:22:18 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.8 1997/11/25 21:59:11 momjian Exp $
  *
  * NOTES
  *   At the point the version is defined, 2 physical relations are created
@@ -30,6 +30,7 @@
 #include 
 #include 
 #include        /* for GetCurrentXactStartTime */
+#include 
 #include 
 
 #define MAX_QUERY_LEN 1024
index c0a74122765d657fc0594ac168dbfdc5acbd21b5..5c2c1a28597bea36f487144ae3e484487e93bb08 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.14 1997/09/18 20:20:22 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.15 1997/11/25 21:58:53 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include 
 
-#include 
-#include  /* for MakeTimeRange() */
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
index 9e5d2819e06b87a4a9db684ea98bdca9ee5a01af..5b77b732a8827765308d2acb648d6769e8dec020 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.12 1997/11/21 18:09:51 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.13 1997/11/25 21:59:00 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,9 +20,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include         /* for RelationNameGetRelation */
-#include 
 #include 
 #include 
 #include 
@@ -488,7 +488,7 @@ tg_replaceNumberedParam(Node *expression,
                         * "result" attribute from the tee relation
                         */
 
-                       isRel = (typeid_get_relid(p->paramtype) != 0);
+                       isRel = (typeidTypeRelid(p->paramtype) != 0);
                        if (isRel)
                        {
                            newVar = makeVar(rt_ind,
index aaf2127e460bd0aa8636907ce09bbb4967b50ddf..3bfdfb09629fb692e1fde46a54396dc550de4819 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.16 1997/11/20 23:21:13 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.17 1997/11/25 21:59:03 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,7 +24,8 @@
 #include 
 #include 
 #include 
-#include 
+#include 
+#include 
 #include 
 #include 
 #ifndef HAVE_MEMMOVE
index 7ae8fa1256d0de9384b7f80bd36ffe099fbae61c..2de53600ceb8f1a9049704fc656a30765b948113 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.52 1997/11/21 19:59:34 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.53 1997/11/25 21:59:09 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -44,7 +45,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include "storage/shmem.h"
 #ifndef HAVE_GETRUSAGE
index 64b4de2ef4b15148b04af7492bd30f30432f58ba..a752e3020c88000de813ad365acddddcdbb59dca 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.15 1997/11/21 18:09:58 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.16 1997/11/25 21:59:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,8 +21,8 @@
 #include 
 #include 
 #include 
-#include catalog_utils.h>
-#include query.h>
+#include parse_relation.h>
+#include type.h>
 #include 
 #include 
 #include 
@@ -72,7 +72,7 @@ DefineVirtualRelation(char *relname, List *tlist)
            entry = lfirst(t);
            res = entry->resdom;
            resname = res->resname;
-           restypename = tname(get_id_type(res->restype));
+           restypename = typeidTypeName(res->restype);
 
            typename = makeNode(TypeName);
 
index f513354e4958aeb738a4ff28a1a088be3d5dcac9..d541f29d9ec730575d4336d2b9e2b4e279202596 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.10 1997/09/18 20:20:32 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.11 1997/11/25 21:59:16 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #undef ExecStoreTuple
 
 #include "access/tupdesc.h"
+#include "catalog/pg_type.h"
+#include "parser/parse_type.h"
+#include "storage/bufmgr.h"
 #include "utils/palloc.h"
 #include "utils/lsyscache.h"
-#include "storage/bufmgr.h"
-#include "parser/catalog_utils.h"
-#include "catalog/pg_type.h"
 
 static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);
 
index a2f143d862c4f6d1a4e99a9241ab3bd7d08967c4..2f0e0b91e202133cf5d91c87c5c6111cd4837d09 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.12 1997/09/18 20:20:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.13 1997/11/25 21:59:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,6 @@
 #include "nodes/plannodes.h"
 
 #include "catalog/pg_proc.h"
-#include "parser/parse_query.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
index b9d7999573f6cdbe474ae7720f16920d7ae632ba..accc7b1fb7c07db54fee0ffe9f328b8b61371b11 100644 (file)
 #include "access/heapam.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/catalog.h"
+#include "parser/parse_type.h"
 #include "executor/executor.h"
 #include "executor/nodeAgg.h"
 #include "storage/bufmgr.h"
 #include "utils/palloc.h"
 #include "utils/syscache.h"
-#include "parser/catalog_utils.h"
 
 /*
  * AggFuncInfo -
@@ -172,7 +172,7 @@ ExecAgg(Agg *node)
        if (!HeapTupleIsValid(aggTuple))
            elog(WARN, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
                 aggname,
-                tname(get_id_type(agg->basetype)));
+                typeidTypeName(agg->basetype));
        aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple);
 
        xfn1_oid = aggp->aggtransfn1;
index 16a8ee3212834d9eaf1d76259af1833e798d2151..f954dbe432ee4f4966b741880282b29322ba8c25 100644 (file)
@@ -6,6 +6,7 @@
  *-------------------------------------------------------------------------
  */
 #include "executor/spi.h"
+#include "catalog/pg_type.h"
 #include "access/printtup.h"
 #include "fmgr.h"
 
index 62b72ab8344f0eed527309222b1050ed73bd2091..5d848df5ab46cc20f77043aa0e4df4b272cdec45 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.15 1997/11/20 23:21:40 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.16 1997/11/25 21:59:40 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,7 +22,6 @@
 #include "nodes/parsenodes.h"
 #include "nodes/primnodes.h"
 #include "nodes/relation.h"
-#include "parser/parse_query.h"
 
 #include "utils/syscache.h"
 #include "utils/builtins.h"        /* for namecpy */
index d674263a32480fe52d0264bf111fc2b14aa17ae2..6b62064de9edd2e24589f549afa68abf95d1f081 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.10 1997/10/25 01:09:28 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.11 1997/11/25 21:59:44 momjian Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
 #include "nodes/parsenodes.h"
 #include "nodes/print.h"
 #include "parser/parsetree.h"
-#include "parser/catalog_utils.h"
 #include "access/heapam.h"
 #include "utils/lsyscache.h"
 #include "nodes/nodes.h"
 #include "nodes/plannodes.h"
+#include "parser/parse_relation.h"
 #include "optimizer/clauses.h"
 
 static char *plannode_type(Plan *p);
@@ -194,7 +194,7 @@ print_expr(Node *expr, List *rtable)
                    r = heap_openr(relname);
                    if (rt->refname)
                        relname = rt->refname;  /* table renamed */
-                   attname = getAttrName(r, var->varattno);
+                   attname = attnumAttName(r, var->varattno);
                    heap_close(r);
                }
                break;
index 39d41319798d0e2cd56e98a79f4b09dec320b780..0f6894eec485d8f15784f0363e82ee911ed79479 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.6 1997/09/08 21:45:10 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.7 1997/11/25 21:59:50 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -641,10 +641,10 @@ xfunc_width(LispValue clause)
    }
    else if (IsA(clause, Param))
    {
-       if (typeid_get_relid(get_paramtype((Param) clause)))
+       if (typeidTypeRelid(get_paramtype((Param) clause)))
        {
            /* Param node returns a tuple.  Find its width */
-           rd = heap_open(typeid_get_relid(get_paramtype((Param) clause)));
+           rd = heap_open(typeidTypeRelid(get_paramtype((Param) clause)));
            retval = xfunc_tuple_width(rd);
            heap_close(rd);
        }
@@ -659,7 +659,7 @@ xfunc_width(LispValue clause)
        else
        {
            /* Param node returns a base type */
-           retval = tlen(get_id_type(get_paramtype((Param) clause)));
+           retval = typeLen(typeidType(get_paramtype((Param) clause)));
        }
        goto exit;
    }
@@ -1324,9 +1324,9 @@ xfunc_func_width(RegProcedure funcid, LispValue args)
    proc = (Form_pg_proc) GETSTRUCT(tupl);
 
    /* if function returns a tuple, get the width of that */
-   if (typeid_get_relid(proc->prorettype))
+   if (typeidTypeRelid(proc->prorettype))
    {
-       rd = heap_open(typeid_get_relid(proc->prorettype));
+       rd = heap_open(typeidTypeRelid(proc->prorettype));
        retval = xfunc_tuple_width(rd);
        heap_close(rd);
        goto exit;
index 11d777e8341aef085fc981e836ed9253a84f02a9..00898ded097b31272f2b8ef6362b12f3ee6aba51 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.15 1997/09/08 21:45:13 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.16 1997/11/25 21:59:56 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,7 +31,6 @@
 #include "utils/palloc.h"
 #include "utils/builtins.h"
 
-#include "parser/parse_query.h"
 #include "optimizer/clauseinfo.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
index e10e36bdcd92b4bd7393dfb2551420de1d34aa0c..ceddbbe2d6beacdd924b35c3e3b9ac32a0de231f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.10 1997/11/21 18:10:26 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.11 1997/11/25 21:59:59 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,9 +19,8 @@
 #include "nodes/plannodes.h"
 #include "nodes/parsenodes.h"
 #include "nodes/relation.h"
+#include "parser/parse_expr.h"
 
-#include "parser/catalog_utils.h"
-#include "parser/parse_query.h"
 #include "utils/elog.h"
 #include "utils/lsyscache.h"
 #include "access/heapam.h"
@@ -310,7 +309,7 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
    }
 
    /* by here, the function is declared to return some type */
-   if ((typ = (Type) get_id_type(rettype)) == NULL)
+   if ((typ = typeidType(rettype)) == NULL)
        elog(WARN, "can't find return type %d for function\n", rettype);
 
    /*
@@ -318,21 +317,21 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
     * final query had better be a retrieve.
     */
    if (cmd != CMD_SELECT)
-       elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ));
+       elog(WARN, "function declared to return type %s, but final query is not a retrieve", typeTypeName(typ));
 
    /*
     * test 4:  for base type returns, the target list should have exactly
     * one entry, and its type should agree with what the user declared.
     */
 
-   if (get_typrelid(typ) == InvalidOid)
+   if (typeTypeRelid(typ) == InvalidOid)
    {
        if (exec_tlist_length(tlist) > 1)
-           elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ));
+           elog(WARN, "function declared to return %s returns multiple values in final retrieve", typeTypeName(typ));
 
        resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
        if (resnode->restype != rettype)
-           elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype)));
+           elog(WARN, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(typ), typeidTypeName(resnode->restype));
 
        /* by here, base return types match */
        return;
@@ -358,16 +357,16 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
     * declared return type, and be sure that attributes 1 .. n in the
     * target list match the declared types.
     */
-   reln = heap_open(get_typrelid(typ));
+   reln = heap_open(typeTypeRelid(typ));
 
    if (!RelationIsValid(reln))
-       elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
+       elog(WARN, "cannot open relation relid %d", typeTypeRelid(typ));
 
    relid = reln->rd_id;
    relnatts = reln->rd_rel->relnatts;
 
    if (exec_tlist_length(tlist) != relnatts)
-       elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ));
+       elog(WARN, "function declared to return type %s does not retrieve (%s.*)", typeTypeName(typ), typeTypeName(typ));
 
    /* expect attributes 1 .. n in order */
    for (i = 1; i <= relnatts; i++)
@@ -397,14 +396,14 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
            else if (IsA(thenode, Func))
                tletype = (Oid) get_functype((Func *) thenode);
            else
-               elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+               elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
        }
        else
-           elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+           elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
 #endif
        /* reach right in there, why don't you? */
        if (tletype != reln->rd_att->attrs[i - 1]->atttypid)
-           elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+           elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
    }
 
    heap_close(reln);
index 0010c69d6abe4a7e2d628ca3169f1d65aac03ed9..faf281985e4332810c9a6520451672394e341da4 100644 (file)
@@ -7,13 +7,14 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.5 1997/09/08 21:45:36 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.6 1997/11/25 22:00:06 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 #include "postgres.h"
 
+#include "catalog/pg_type.h"
 #include "nodes/pg_list.h"
 #include "nodes/relation.h"
 #include "nodes/primnodes.h"
@@ -24,9 +25,9 @@
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/palloc.h"
+#include "parser/parse_type.h"
 
 #include "parser/parsetree.h"  /* for getrelid() */
-#include "parser/catalog_utils.h"
 
 #include "optimizer/internal.h"
 #include "optimizer/prep.h"
@@ -278,7 +279,7 @@ new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
        attisset = get_attisset( /* type_id, */ relid, attname);
        if (attisset)
        {
-           typlen = tlen(type("oid"));
+           typlen = typeLen(typeidType(OIDOID));
        }
        else
        {
index a686f94e01cc63bbad18af2e8702a5137256f98b..00dd4079780f2c72a330e664ae1ff5c3c35d65e5 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.8 1997/11/21 18:10:44 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.9 1997/11/25 22:00:10 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,7 +22,6 @@
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
 
-#include "parser/parse_query.h"
 #include "parser/parsetree.h"
 
 #include "utils/elog.h"
index 089633033b154185de0d4d240e3959b7eca09940..aa867f4b5a3845ef8194a036ff844072c0f885e8 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.7 1997/09/08 21:45:55 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.8 1997/11/25 22:00:16 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,7 +26,6 @@
 #include "optimizer/clauses.h"
 
 #include "nodes/makefuncs.h"
-#include "parser/catalog_utils.h"
 
 static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist);
 
index 8559100ee3e21c82cb0da5886ae69ea72c15449b..7ab45e4beea8ec2de600d64f38294f5b25b27998 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for parser
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.11 1997/11/24 05:20:57 momjian Exp $
+#    $Header: /cvsroot/pgsql/src/backend/parser/Makefile,v 1.12 1997/11/25 22:00:21 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -22,8 +22,9 @@ CFLAGS+= -Wno-error
 endif
 
 
-OBJS= analyze.o catalog_utils.o gram.o \
-      keywords.o parser.o parse_query.o scan.o scansup.o
+OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \
+      parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \
+      parse_type.o parse_target.o scan.o scansup.o
 
 all: SUBSYS.o
 
index bee5132a8b94062b434e62617b04a40f80236fde..4a3800a8a4ed3af9fe30110dd49d181f1d001d34 100644 (file)
@@ -7,46 +7,30 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.49 1997/11/20 23:22:11 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.50 1997/11/25 22:00:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
+
 #include 
 #include 
 #include 
 #include "postgres.h"
-#include "nodes/nodes.h"
-#include "nodes/params.h"
-#include "nodes/primnodes.h"
-#include "nodes/parsenodes.h"
-#include "nodes/relation.h"
-#include "parse.h"             /* for AND, OR, etc. */
-#include "catalog/pg_aggregate.h"
-#include "catalog/pg_type.h"   /* for INT4OID, etc. */
-#include "catalog/pg_proc.h"
-#include "utils/elog.h"
-#include "utils/builtins.h"        /* namecmp(), textout() */
-#include "utils/lsyscache.h"
-#include "utils/palloc.h"
-#include "utils/mcxt.h"
-#include "utils/syscache.h"
-#include "utils/acl.h"
-#include "parser/parse_query.h"
-#include "parser/parse_state.h"
-#include "nodes/makefuncs.h"   /* for makeResdom(), etc. */
-#include "nodes/nodeFuncs.h"
-#include "commands/sequence.h"
-
-#include "optimizer/clauses.h"
-#include "access/heapam.h"
-
-#include "miscadmin.h"
 
-#include "port-protos.h"       /* strdup() */
+#include "access/heapam.h"
+#include "nodes/makefuncs.h"
+#include "nodes/memnodes.h"
+#include "nodes/pg_list.h"
+#include "parser/analyze.h"
+#include "parser/parse_agg.h"
+#include "parser/parse_node.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "parser/parse_clause.h"
+#include "utils/builtins.h"
+#include "utils/mcxt.h"
 
-/* convert the parse tree into a query tree */
 static Query *transformStmt(ParseState *pstate, Node *stmt);
-
 static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
 static Query *transformInsertStmt(ParseState *pstate, AppendStmt *stmt);
 static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
@@ -55,74 +39,7 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
 static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
 static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
 static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
-static Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
-
-#define EXPR_COLUMN_FIRST   1
-#define EXPR_RELATION_FIRST  2
-static Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
-static Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
-
-static void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
-static List *expandAllTables(ParseState *pstate);
-static char *figureColname(Node *expr, Node *resval);
-static List *makeTargetNames(ParseState *pstate, List *cols);
-static List *transformTargetList(ParseState *pstate, List *targetlist);
-static TargetEntry *make_targetlist_expr(ParseState *pstate,
-                    char *colname, Node *expr,
-                    List *arrayRef);
-static bool inWhereClause = false;
-static Node *transformWhereClause(ParseState *pstate, Node *a_expr);
-static List *transformGroupClause(ParseState *pstate, List *grouplist,
-                    List *targetlist);
-static List *transformSortClause(ParseState *pstate,
-                   List *orderlist, List *targetlist,
-                   char *uniqueFlag);
-
-static void parseFromClause(ParseState *pstate, List *frmList);
-static Node *ParseFunc(ParseState *pstate, char *funcname,
-         List *fargs, int *curr_resno);
-static List *setup_tlist(char *attname, Oid relid);
-static List *setup_base_tlist(Oid typeid);
-static void make_arguments(int nargs, List *fargs, Oid *input_typeids,
-              Oid *function_typeids);
-static void AddAggToParseState(ParseState *pstate, Aggreg *aggreg);
-static void finalizeAggregates(ParseState *pstate, Query *qry);
-static void parseCheckAggregates(ParseState *pstate, Query *qry);
-static ParseState *makeParseState(void);
-static Node *parser_typecast(Value *expr, TypeName *typename, int typlen);
-static Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen);
-static Aggreg *ParseAgg(char *aggname, Oid basetype, Node *target);
-
-/*****************************************************************************
- *
- *****************************************************************************/
 
-/*
- * makeParseState() --
- *   allocate and initialize a new ParseState.
- * the CALLERS is responsible for freeing the ParseState* returned
- *
- */
-
-static ParseState *
-makeParseState(void)
-{
-   ParseState *pstate;
-
-   pstate = malloc(sizeof(ParseState));
-   pstate->p_last_resno = 1;
-   pstate->p_rtable = NIL;
-   pstate->p_numAgg = 0;
-   pstate->p_aggs = NIL;
-   pstate->p_is_insert = false;
-   pstate->p_insert_columns = NIL;
-   pstate->p_is_update = false;
-   pstate->p_is_rule = false;
-   pstate->p_target_relation = NULL;
-   pstate->p_target_rangetblentry = NULL;
-
-   return (pstate);
-}
 
 /*
  * parse_analyze -
@@ -144,11 +61,9 @@ parse_analyze(List *pl)
    result->len = length(pl);
    result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
 
-   inWhereClause = false;      /* to avoid nextval(sequence) in WHERE */
-
    while (pl != NIL)
    {
-       pstate = makeParseState();
+       pstate = make_parsestate();
        result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
        pl = lnext(pl);
        if (pstate->p_target_relation != NULL)
@@ -620,2580 +535,3 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
 
    return (Query *) qry;
 }
-
-/*****************************************************************************
- *
- * Transform Exprs, Aggs, etc.
- *
- *****************************************************************************/
-
-/*
- * transformExpr -
- *   analyze and transform expressions. Type checking and type casting is
- *   done here. The optimizer and the executor cannot handle the original
- *   (raw) expressions collected by the parse tree. Hence the transformation
- *   here.
- */
-static Node *
-transformExpr(ParseState *pstate, Node *expr, int precedence)
-{
-   Node       *result = NULL;
-
-   if (expr == NULL)
-       return NULL;
-
-   switch (nodeTag(expr))
-   {
-       case T_Attr:
-           {
-               Attr       *att = (Attr *) expr;
-               Node       *temp;
-
-               /* what if att.attrs == "*"?? */
-               temp = handleNestedDots(pstate, att, &pstate->p_last_resno);
-               if (att->indirection != NIL)
-               {
-                   List       *idx = att->indirection;
-
-                   while (idx != NIL)
-                   {
-                       A_Indices  *ai = (A_Indices *) lfirst(idx);
-                       Node       *lexpr = NULL,
-                                  *uexpr;
-
-                       uexpr = transformExpr(pstate, ai->uidx, precedence);    /* must exists */
-                       if (exprType(uexpr) != INT4OID)
-                           elog(WARN, "array index expressions must be int4's");
-                       if (ai->lidx != NULL)
-                       {
-                           lexpr = transformExpr(pstate, ai->lidx, precedence);
-                           if (exprType(lexpr) != INT4OID)
-                               elog(WARN, "array index expressions must be int4's");
-                       }
-#if 0
-                       pfree(ai->uidx);
-                       if (ai->lidx != NULL)
-                           pfree(ai->lidx);
-#endif
-                       ai->lidx = lexpr;
-                       ai->uidx = uexpr;
-
-                       /*
-                        * note we reuse the list of indices, make sure we
-                        * don't free them! Otherwise, make a new list
-                        * here
-                        */
-                       idx = lnext(idx);
-                   }
-                   result = (Node *) make_array_ref(temp, att->indirection);
-               }
-               else
-               {
-                   result = temp;
-               }
-               break;
-           }
-       case T_A_Const:
-           {
-               A_Const    *con = (A_Const *) expr;
-               Value      *val = &con->val;
-
-               if (con->typename != NULL)
-               {
-                   result = parser_typecast(val, con->typename, -1);
-               }
-               else
-               {
-                   result = (Node *) make_const(val);
-               }
-               break;
-           }
-       case T_ParamNo:
-           {
-               ParamNo    *pno = (ParamNo *) expr;
-               Oid         toid;
-               int         paramno;
-               Param      *param;
-
-               paramno = pno->number;
-               toid = param_type(paramno);
-               if (!OidIsValid(toid))
-               {
-                   elog(WARN, "Parameter '$%d' is out of range",
-                        paramno);
-               }
-               param = makeNode(Param);
-               param->paramkind = PARAM_NUM;
-               param->paramid = (AttrNumber) paramno;
-               param->paramname = "";
-               param->paramtype = (Oid) toid;
-               param->param_tlist = (List *) NULL;
-
-               result = (Node *) param;
-               break;
-           }
-       case T_A_Expr:
-           {
-               A_Expr     *a = (A_Expr *) expr;
-
-               switch (a->oper)
-               {
-                   case OP:
-                       {
-                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
-                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
-                           result = (Node *) make_op(a->opname, lexpr, rexpr);
-                       }
-                       break;
-                   case ISNULL:
-                       {
-                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
-
-                           result = ParseFunc(pstate,
-                                         "nullvalue", lcons(lexpr, NIL),
-                                              &pstate->p_last_resno);
-                       }
-                       break;
-                   case NOTNULL:
-                       {
-                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
-
-                           result = ParseFunc(pstate,
-                                      "nonnullvalue", lcons(lexpr, NIL),
-                                              &pstate->p_last_resno);
-                       }
-                       break;
-                   case AND:
-                       {
-                           Expr       *expr = makeNode(Expr);
-                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
-                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
-                           if (exprType(lexpr) != BOOLOID)
-                               elog(WARN,
-                                    "left-hand side of AND is type '%s', not bool",
-                                    tname(get_id_type(exprType(lexpr))));
-                           if (exprType(rexpr) != BOOLOID)
-                               elog(WARN,
-                                    "right-hand side of AND is type '%s', not bool",
-                                    tname(get_id_type(exprType(rexpr))));
-                           expr->typeOid = BOOLOID;
-                           expr->opType = AND_EXPR;
-                           expr->args = makeList(lexpr, rexpr, -1);
-                           result = (Node *) expr;
-                       }
-                       break;
-                   case OR:
-                       {
-                           Expr       *expr = makeNode(Expr);
-                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
-                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
-                           if (exprType(lexpr) != BOOLOID)
-                               elog(WARN,
-                                    "left-hand side of OR is type '%s', not bool",
-                                    tname(get_id_type(exprType(lexpr))));
-                           if (exprType(rexpr) != BOOLOID)
-                               elog(WARN,
-                                    "right-hand side of OR is type '%s', not bool",
-                                    tname(get_id_type(exprType(rexpr))));
-                           expr->typeOid = BOOLOID;
-                           expr->opType = OR_EXPR;
-                           expr->args = makeList(lexpr, rexpr, -1);
-                           result = (Node *) expr;
-                       }
-                       break;
-                   case NOT:
-                       {
-                           Expr       *expr = makeNode(Expr);
-                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
-                           if (exprType(rexpr) != BOOLOID)
-                               elog(WARN,
-                               "argument to NOT is type '%s', not bool",
-                                    tname(get_id_type(exprType(rexpr))));
-                           expr->typeOid = BOOLOID;
-                           expr->opType = NOT_EXPR;
-                           expr->args = makeList(rexpr, -1);
-                           result = (Node *) expr;
-                       }
-                       break;
-               }
-               break;
-           }
-       case T_Ident:
-           {
-
-               /*
-                * look for a column name or a relation name (the default
-                * behavior)
-                */
-               result = transformIdent(pstate, expr, precedence);
-               break;
-           }
-       case T_FuncCall:
-           {
-               FuncCall   *fn = (FuncCall *) expr;
-               List       *args;
-
-               /* transform the list of arguments */
-               foreach(args, fn->args)
-                   lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);
-               result = ParseFunc(pstate,
-                         fn->funcname, fn->args, &pstate->p_last_resno);
-               break;
-           }
-       default:
-           /* should not reach here */
-           elog(WARN, "transformExpr: does not know how to transform %d\n",
-                nodeTag(expr));
-           break;
-   }
-
-   return result;
-}
-
-static Node *
-transformIdent(ParseState *pstate, Node *expr, int precedence)
-{
-   Ident      *ident = (Ident *) expr;
-   RangeTblEntry *rte;
-   Node       *column_result,
-              *relation_result,
-              *result;
-
-   column_result = relation_result = result = 0;
-   /* try to find the ident as a column */
-   if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
-   {
-       Attr       *att = makeNode(Attr);
-
-       att->relname = rte->refname;
-       att->attrs = lcons(makeString(ident->name), NIL);
-       column_result =
-           (Node *) handleNestedDots(pstate, att, &pstate->p_last_resno);
-   }
-
-   /* try to find the ident as a relation */
-   if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL)
-   {
-       ident->isRel = TRUE;
-       relation_result = (Node *) ident;
-   }
-
-   /* choose the right result based on the precedence */
-   if (precedence == EXPR_COLUMN_FIRST)
-   {
-       if (column_result)
-           result = column_result;
-       else
-           result = relation_result;
-   }
-   else
-   {
-       if (relation_result)
-           result = relation_result;
-       else
-           result = column_result;
-   }
-
-   if (result == NULL)
-       elog(WARN, "attribute '%s' not found", ident->name);
-
-   return result;
-}
-
-/*****************************************************************************
- *
- * From Clause
- *
- *****************************************************************************/
-
-/*
- * parseFromClause -
- *   turns the table references specified in the from-clause into a
- *   range table. The range table may grow as we transform the expressions
- *   in the target list. (Note that this happens because in POSTQUEL, we
- *   allow references to relations not specified in the from-clause. We
- *   also allow that in our POST-SQL)
- *
- */
-static void
-parseFromClause(ParseState *pstate, List *frmList)
-{
-   List       *fl;
-
-   foreach(fl, frmList)
-   {
-       RangeVar   *r = lfirst(fl);
-       RelExpr    *baserel = r->relExpr;
-       char       *relname = baserel->relname;
-       char       *refname = r->name;
-       RangeTblEntry *rte;
-
-       if (refname == NULL)
-           refname = relname;
-
-       /*
-        * marks this entry to indicate it comes from the FROM clause. In
-        * SQL, the target list can only refer to range variables
-        * specified in the from clause but we follow the more powerful
-        * POSTQUEL semantics and automatically generate the range
-        * variable if not specified. However there are times we need to
-        * know whether the entries are legitimate.
-        *
-        * eg. select * from foo f where f.x = 1; will generate wrong answer
-        * if we expand * to foo.x.
-        */
-       rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE);
-   }
-}
-
-/*
- * makeRangeTable -
- *   make a range table with the specified relation (optional) and the
- *   from-clause.
- */
-static void
-makeRangeTable(ParseState *pstate, char *relname, List *frmList)
-{
-   RangeTblEntry *rte;
-
-   parseFromClause(pstate, frmList);
-
-   if (relname == NULL)
-       return;
-
-   if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
-       rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE);
-   else
-       rte = refnameRangeTableEntry(pstate->p_rtable, relname);
-
-   pstate->p_target_rangetblentry = rte;
-   Assert(pstate->p_target_relation == NULL);
-   pstate->p_target_relation = heap_open(rte->relid);
-   Assert(pstate->p_target_relation != NULL);
-   /* will close relation later */
-}
-
-/*
- * exprType -
- *   returns the Oid of the type of the expression. (Used for typechecking.)
- */
-Oid
-exprType(Node *expr)
-{
-   Oid         type = (Oid) 0;
-
-   switch (nodeTag(expr))
-   {
-       case T_Func:
-           type = ((Func *) expr)->functype;
-           break;
-       case T_Iter:
-           type = ((Iter *) expr)->itertype;
-           break;
-       case T_Var:
-           type = ((Var *) expr)->vartype;
-           break;
-       case T_Expr:
-           type = ((Expr *) expr)->typeOid;
-           break;
-       case T_Const:
-           type = ((Const *) expr)->consttype;
-           break;
-       case T_ArrayRef:
-           type = ((ArrayRef *) expr)->refelemtype;
-           break;
-       case T_Aggreg:
-           type = ((Aggreg *) expr)->aggtype;
-           break;
-       case T_Param:
-           type = ((Param *) expr)->paramtype;
-           break;
-       case T_Ident:
-           /* is this right? */
-           type = UNKNOWNOID;
-           break;
-       default:
-           elog(WARN, "exprType: don't know how to get type for %d node",
-                nodeTag(expr));
-           break;
-   }
-   return type;
-}
-
-/*
- * expandAllTables -
- *   turns '*' (in the target list) into a list of attributes
- *    (of all relations in the range table)
- */
-static List *
-expandAllTables(ParseState *pstate)
-{
-   List       *target = NIL;
-   List       *legit_rtable = NIL;
-   List       *rt,
-              *rtable;
-
-   rtable = pstate->p_rtable;
-   if (pstate->p_is_rule)
-   {
-
-       /*
-        * skip first two entries, "*new*" and "*current*"
-        */
-       rtable = lnext(lnext(pstate->p_rtable));
-   }
-
-   /* this should not happen */
-   if (rtable == NULL)
-       elog(WARN, "cannot expand: null p_rtable");
-
-   /*
-    * go through the range table and make a list of range table entries
-    * which we will expand.
-    */
-   foreach(rt, rtable)
-   {
-       RangeTblEntry *rte = lfirst(rt);
-
-       /*
-        * we only expand those specify in the from clause. (This will
-        * also prevent us from using the wrong table in inserts: eg.
-        * tenk2 in "insert into tenk2 select * from tenk1;")
-        */
-       if (!rte->inFromCl)
-           continue;
-       legit_rtable = lappend(legit_rtable, rte);
-   }
-
-   foreach(rt, legit_rtable)
-   {
-       RangeTblEntry *rte = lfirst(rt);
-       List       *temp = target;
-
-       if (temp == NIL)
-           target = expandAll(pstate, rte->relname, rte->refname,
-                              &pstate->p_last_resno);
-       else
-       {
-           while (temp != NIL && lnext(temp) != NIL)
-               temp = lnext(temp);
-           lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
-                                   &pstate->p_last_resno);
-       }
-   }
-   return target;
-}
-
-
-/*
- * figureColname -
- *   if the name of the resulting column is not specified in the target
- *   list, we have to guess.
- *
- */
-static char *
-figureColname(Node *expr, Node *resval)
-{
-   switch (nodeTag(expr))
-   {
-           case T_Aggreg:
-           return (char *)     /* XXX */
-           ((Aggreg *) expr)->aggname;
-       case T_Expr:
-           if (((Expr *) expr)->opType == FUNC_EXPR)
-           {
-               if (nodeTag(resval) == T_FuncCall)
-                   return ((FuncCall *) resval)->funcname;
-           }
-           break;
-       default:
-           break;
-   }
-
-   return "?column?";
-}
-
-/*****************************************************************************
- *
- * Target list
- *
- *****************************************************************************/
-
-/*
- * makeTargetNames -
- *   generate a list of column names if not supplied or
- *   test supplied column names to make sure they are in target table
- *   (used exclusively for inserts)
- */
-static List *
-makeTargetNames(ParseState *pstate, List *cols)
-{
-   List       *tl = NULL;
-
-   /* Generate ResTarget if not supplied */
-
-   if (cols == NIL)
-   {
-       int         numcol;
-       int         i;
-       AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
-
-       numcol = pstate->p_target_relation->rd_rel->relnatts;
-       for (i = 0; i < numcol; i++)
-       {
-           Ident      *id = makeNode(Ident);
-
-           id->name = palloc(NAMEDATALEN);
-           StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
-           id->indirection = NIL;
-           id->isRel = false;
-           if (tl == NIL)
-               cols = tl = lcons(id, NIL);
-           else
-           {
-               lnext(tl) = lcons(id, NIL);
-               tl = lnext(tl);
-           }
-       }
-   }
-   else
-   {
-       foreach(tl, cols)
-       {
-           List       *nxt;
-           char       *name = ((Ident *) lfirst(tl))->name;
-       
-           /* elog on failure */
-           varattno(pstate->p_target_relation, name);
-           foreach(nxt, lnext(tl))
-               if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
-                   elog (WARN, "Attribute '%s' should be specified only once", name);
-       }
-   }
-   
-   return cols;
-}
-
-/*
- * transformTargetList -
- *   turns a list of ResTarget's into a list of TargetEntry's
- */
-static List *
-transformTargetList(ParseState *pstate, List *targetlist)
-{
-   List       *p_target = NIL;
-   List       *tail_p_target = NIL;
-
-   while (targetlist != NIL)
-   {
-       ResTarget  *res = (ResTarget *) lfirst(targetlist);
-       TargetEntry *tent = makeNode(TargetEntry);
-
-       switch (nodeTag(res->val))
-       {
-           case T_Ident:
-               {
-                   Node       *expr;
-                   Oid         type_id;
-                   int         type_len;
-                   char       *identname;
-                   char       *resname;
-
-                   identname = ((Ident *) res->val)->name;
-                   handleTargetColname(pstate, &res->name, NULL, identname);
-
-                   /*
-                    * here we want to look for column names only, not relation
-                    * names (even though they can be stored in Ident nodes, too)
-                    */
-                   expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
-                   type_id = exprType(expr);
-                   type_len = tlen(get_id_type(type_id));
-                   resname = (res->name) ? res->name : identname;
-                   tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
-                                             (Oid) type_id,
-                                             (Size) type_len,
-                                             resname,
-                                             (Index) 0,
-                                             (Oid) 0,
-                                             0);
-
-                   tent->expr = expr;
-                   break;
-               }
-           case T_ParamNo:
-           case T_FuncCall:
-           case T_A_Const:
-           case T_A_Expr:
-               {
-                   Node       *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
-
-                   handleTargetColname(pstate, &res->name, NULL, NULL);
-                   /* note indirection has not been transformed */
-                   if (pstate->p_is_insert && res->indirection != NIL)
-                   {
-                       /* this is an array assignment */
-                       char       *val;
-                       char       *str,
-                                  *save_str;
-                       List       *elt;
-                       int         i = 0,
-                                   ndims;
-                       int         lindx[MAXDIM],
-                                   uindx[MAXDIM];
-                       int         resdomno;
-                       Relation    rd;
-                       Value      *constval;
-
-                       if (exprType(expr) != UNKNOWNOID ||
-                           !IsA(expr, Const))
-                           elog(WARN, "yyparse: string constant expected");
-
-                       val = (char *) textout((struct varlena *)
-                                          ((Const *) expr)->constvalue);
-                       str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
-                       foreach(elt, res->indirection)
-                       {
-                           A_Indices  *aind = (A_Indices *) lfirst(elt);
-
-                           aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
-                           if (!IsA(aind->uidx, Const))
-                               elog(WARN,
-                                    "Array Index for Append should be a constant");
-                           uindx[i] = ((Const *) aind->uidx)->constvalue;
-                           if (aind->lidx != NULL)
-                           {
-                               aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
-                               if (!IsA(aind->lidx, Const))
-                                   elog(WARN,
-                                        "Array Index for Append should be a constant");
-                               lindx[i] = ((Const *) aind->lidx)->constvalue;
-                           }
-                           else
-                           {
-                               lindx[i] = 1;
-                           }
-                           if (lindx[i] > uindx[i])
-                               elog(WARN, "yyparse: lower index cannot be greater than upper index");
-                           sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
-                           str += strlen(str);
-                           i++;
-                       }
-                       sprintf(str, "=%s", val);
-                       rd = pstate->p_target_relation;
-                       Assert(rd != NULL);
-                       resdomno = varattno(rd, res->name);
-                       ndims = att_attnelems(rd, resdomno);
-                       if (i != ndims)
-                           elog(WARN, "yyparse: array dimensions do not match");
-                       constval = makeNode(Value);
-                       constval->type = T_String;
-                       constval->val.str = save_str;
-                       tent = make_targetlist_expr(pstate, res->name,
-                                          (Node *) make_const(constval),
-                                                   NULL);
-                       pfree(save_str);
-                   }
-                   else
-                   {
-                       char       *colname = res->name;
-
-                       /* this is not an array assignment */
-                       if (colname == NULL)
-                       {
-
-                           /*
-                            * if you're wondering why this is here, look
-                            * at the yacc grammar for why a name can be
-                            * missing. -ay
-                            */
-                           colname = figureColname(expr, res->val);
-                       }
-                       if (res->indirection)
-                       {
-                           List       *ilist = res->indirection;
-
-                           while (ilist != NIL)
-                           {
-                               A_Indices  *ind = lfirst(ilist);
-
-                               ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
-                               ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
-                               ilist = lnext(ilist);
-                           }
-                       }
-                       res->name = colname;
-                       tent = make_targetlist_expr(pstate, res->name, expr,
-                                                   res->indirection);
-                   }
-                   break;
-               }
-           case T_Attr:
-               {
-                   Oid         type_id;
-                   int         type_len;
-                   Attr       *att = (Attr *) res->val;
-                   Node       *result;
-                   char       *attrname;
-                   char       *resname;
-                   Resdom     *resnode;
-                   List       *attrs = att->attrs;
-
-                   /*
-                    * Target item is a single '*', expand all tables (eg.
-                    * SELECT * FROM emp)
-                    */
-                   if (att->relname != NULL && !strcmp(att->relname, "*"))
-                   {
-                       if (tail_p_target == NIL)
-                           p_target = tail_p_target = expandAllTables(pstate);
-                       else
-                           lnext(tail_p_target) = expandAllTables(pstate);
-
-                       while (lnext(tail_p_target) != NIL)
-                           /* make sure we point to the last target entry */
-                           tail_p_target = lnext(tail_p_target);
-
-                       /*
-                        * skip rest of while loop
-                        */
-                       targetlist = lnext(targetlist);
-                       continue;
-                   }
-
-                   /*
-                    * Target item is relation.*, expand the table (eg.
-                    * SELECT emp.*, dname FROM emp, dept)
-                    */
-                   attrname = strVal(lfirst(att->attrs));
-                   if (att->attrs != NIL && !strcmp(attrname, "*"))
-                   {
-
-                       /*
-                        * tail_p_target is the target list we're building
-                        * in the while loop. Make sure we fix it after
-                        * appending more nodes.
-                        */
-                       if (tail_p_target == NIL)
-                           p_target = tail_p_target = expandAll(pstate, att->relname,
-                                   att->relname, &pstate->p_last_resno);
-                       else
-                           lnext(tail_p_target) =
-                               expandAll(pstate, att->relname, att->relname,
-                                         &pstate->p_last_resno);
-                       while (lnext(tail_p_target) != NIL)
-                           /* make sure we point to the last target entry */
-                           tail_p_target = lnext(tail_p_target);
-
-                       /*
-                        * skip the rest of the while loop
-                        */
-                       targetlist = lnext(targetlist);
-                       continue;
-                   }
-
-
-                   /*
-                    * Target item is fully specified: ie.
-                    * relation.attribute
-                    */
-                   result = handleNestedDots(pstate, att, &pstate->p_last_resno);
-                   handleTargetColname(pstate, &res->name, att->relname, attrname);
-                   if (att->indirection != NIL)
-                   {
-                       List       *ilist = att->indirection;
-
-                       while (ilist != NIL)
-                       {
-                           A_Indices  *ind = lfirst(ilist);
-
-                           ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
-                           ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
-                           ilist = lnext(ilist);
-                       }
-                       result = (Node *) make_array_ref(result, att->indirection);
-                   }
-                   type_id = exprType(result);
-                   type_len = tlen(get_id_type(type_id));
-                   /* move to last entry */
-                   while (lnext(attrs) != NIL)
-                       attrs = lnext(attrs);
-                   resname = (res->name) ? res->name : strVal(lfirst(attrs));
-                   resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
-                                        (Oid) type_id,
-                                        (Size) type_len,
-                                        resname,
-                                        (Index) 0,
-                                        (Oid) 0,
-                                        0);
-                   tent->resdom = resnode;
-                   tent->expr = result;
-                   break;
-               }
-           default:
-               /* internal error */
-               elog(WARN,
-                    "internal error: do not know how to transform targetlist");
-               break;
-       }
-
-       if (p_target == NIL)
-       {
-           p_target = tail_p_target = lcons(tent, NIL);
-       }
-       else
-       {
-           lnext(tail_p_target) = lcons(tent, NIL);
-           tail_p_target = lnext(tail_p_target);
-       }
-       targetlist = lnext(targetlist);
-   }
-
-   return p_target;
-}
-
-
-/*
- * make_targetlist_expr -
- *   make a TargetEntry from an expression
- *
- * arrayRef is a list of transformed A_Indices
- */
-static TargetEntry *
-make_targetlist_expr(ParseState *pstate,
-                    char *colname,
-                    Node *expr,
-                    List *arrayRef)
-{
-   Oid         type_id,
-               attrtype;
-   int         type_len,
-               attrlen;
-   int         resdomno;
-   Relation    rd;
-   bool        attrisset;
-   TargetEntry *tent;
-   Resdom     *resnode;
-
-   if (expr == NULL)
-       elog(WARN, "make_targetlist_expr: invalid use of NULL expression");
-
-   type_id = exprType(expr);
-   if (type_id == InvalidOid)
-   {
-       type_len = 0;
-   }
-   else
-       type_len = tlen(get_id_type(type_id));
-
-   /* I have no idea what the following does! */
-   /* It appears to process target columns that will be receiving results */
-   if (pstate->p_is_insert || pstate->p_is_update)
-   {
-
-       /*
-        * append or replace query -- append, replace work only on one
-        * relation, so multiple occurence of same resdomno is bogus
-        */
-       rd = pstate->p_target_relation;
-       Assert(rd != NULL);
-       resdomno = varattno(rd, colname);
-       attrisset = varisset(rd, colname);
-       attrtype = att_typeid(rd, resdomno);
-       if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
-           attrtype = GetArrayElementType(attrtype);
-       if (attrtype == BPCHAROID || attrtype == VARCHAROID)
-       {
-           attrlen = rd->rd_att->attrs[resdomno - 1]->attlen;
-       }
-       else
-       {
-           attrlen = tlen(get_id_type(attrtype));
-       }
-#if 0
-       if (Input_is_string && Typecast_ok)
-       {
-           Datum       val;
-
-           if (type_id == typeid(type("unknown")))
-           {
-               val = (Datum) textout((struct varlena *)
-                                     ((Const) lnext(expr))->constvalue);
-           }
-           else
-           {
-               val = ((Const) lnext(expr))->constvalue;
-           }
-           if (attrisset)
-           {
-               lnext(expr) = makeConst(attrtype,
-                                       attrlen,
-                                       val,
-                                       false,
-                                       true,
-                                       true,   /* is set */
-                                       false);
-           }
-           else
-           {
-               lnext(expr) =
-                   makeConst(attrtype,
-                             attrlen,
-                             (Datum) fmgr(typeid_get_retinfunc(attrtype),
-                                        val, get_typelem(attrtype), -1),
-                             false,
-                             true /* Maybe correct-- 80% chance */ ,
-                             false,    /* is not a set */
-                             false);
-           }
-       }
-       else if ((Typecast_ok) && (attrtype != type_id))
-       {
-           lnext(expr) =
-               parser_typecast2(expr, get_id_type(attrtype));
-       }
-       else if (attrtype != type_id)
-       {
-           if ((attrtype == INT2OID) && (type_id == INT4OID))
-               lfirst(expr) = lispInteger(INT2OID);    /* handle CASHOID too */
-           else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
-               lfirst(expr) = lispInteger(FLOAT4OID);
-           else
-               elog(WARN, "unequal type in tlist : %s \n", colname);
-       }
-
-       Input_is_string = false;
-       Input_is_integer = false;
-       Typecast_ok = true;
-#endif
-
-       if (attrtype != type_id)
-       {
-           if (IsA(expr, Const))
-           {
-               /* try to cast the constant */
-               if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
-               {
-                   /* updating a single item */
-                   Oid         typelem = get_typelem(attrtype);
-
-                   expr = (Node *) parser_typecast2(expr,
-                                                    type_id,
-                                                    get_id_type(typelem),
-                                                    attrlen);
-               }
-               else
-                   expr = (Node *) parser_typecast2(expr,
-                                                    type_id,
-                                                  get_id_type(attrtype),
-                                                    attrlen);
-           }
-           else
-           {
-               /* currently, we can't handle casting of expressions */
-               elog(WARN, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
-                    colname,
-                    get_id_typname(attrtype),
-                    get_id_typname(type_id));
-           }
-       }
-
-       if (arrayRef != NIL)
-       {
-           Expr       *target_expr;
-           Attr       *att = makeNode(Attr);
-           List       *ar = arrayRef;
-           List       *upperIndexpr = NIL;
-           List       *lowerIndexpr = NIL;
-
-           att->relname = pstrdup(RelationGetRelationName(rd)->data);
-           att->attrs = lcons(makeString(colname), NIL);
-           target_expr = (Expr *) handleNestedDots(pstate, att,
-                                                 &pstate->p_last_resno);
-           while (ar != NIL)
-           {
-               A_Indices  *ind = lfirst(ar);
-
-               if (lowerIndexpr || (!upperIndexpr && ind->lidx))
-               {
-
-                   /*
-                    * XXX assume all lowerIndexpr is non-null in this
-                    * case
-                    */
-                   lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
-               }
-               upperIndexpr = lappend(upperIndexpr, ind->uidx);
-               ar = lnext(ar);
-           }
-
-           expr = (Node *) make_array_set(target_expr,
-                                          upperIndexpr,
-                                          lowerIndexpr,
-                                          (Expr *) expr);
-           attrtype = att_typeid(rd, resdomno);
-           attrlen = tlen(get_id_type(attrtype));
-       }
-   }
-   else
-   {
-       resdomno = pstate->p_last_resno++;
-       attrtype = type_id;
-       attrlen = type_len;
-   }
-   tent = makeNode(TargetEntry);
-
-   resnode = makeResdom((AttrNumber) resdomno,
-                        (Oid) attrtype,
-                        (Size) attrlen,
-                        colname,
-                        (Index) 0,
-                        (Oid) 0,
-                        0);
-
-   tent->resdom = resnode;
-   tent->expr = expr;
-
-   return tent;
-}
-
-
-/*****************************************************************************
- *
- * Where Clause
- *
- *****************************************************************************/
-
-/*
- * transformWhereClause -
- *   transforms the qualification and make sure it is of type Boolean
- *
- */
-static Node *
-transformWhereClause(ParseState *pstate, Node *a_expr)
-{
-   Node       *qual;
-
-   if (a_expr == NULL)
-       return (Node *) NULL;   /* no qualifiers */
-
-   inWhereClause = true;
-   qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
-   inWhereClause = false;
-   if (exprType(qual) != BOOLOID)
-   {
-       elog(WARN,
-            "where clause must return type bool, not %s",
-            tname(get_id_type(exprType(qual))));
-   }
-   return qual;
-}
-
-/*****************************************************************************
- *
- * Sort Clause
- *
- *****************************************************************************/
-
-/*
- * find_targetlist_entry -
- *   returns the Resdom in the target list matching the specified varname
- *   and range
- *
- */
-static TargetEntry *
-find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
-{
-   List       *i;
-   int         real_rtable_pos = 0,
-               target_pos = 0;
-   TargetEntry *target_result = NULL;
-
-   if (sortgroupby->range)
-       real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
-                                               sortgroupby->range);
-
-   foreach(i, tlist)
-   {
-       TargetEntry *target = (TargetEntry *) lfirst(i);
-       Resdom     *resnode = target->resdom;
-       Var        *var = (Var *) target->expr;
-       char       *resname = resnode->resname;
-       int         test_rtable_pos = var->varno;
-
-#ifdef PARSEDEBUG
-       printf("find_targetlist_entry- target name is %s, position %d, resno %d\n",
-              (sortgroupby->name ? sortgroupby->name : "(null)"), target_pos + 1, sortgroupby->resno);
-#endif
-
-       if (!sortgroupby->name)
-       {
-           if (sortgroupby->resno == ++target_pos)
-           {
-               target_result = target;
-               break;
-           }
-       }
-       else
-       {
-           if (!strcmp(resname, sortgroupby->name))
-           {
-               if (sortgroupby->range)
-               {
-                   if (real_rtable_pos == test_rtable_pos)
-                   {
-                       if (target_result != NULL)
-                           elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
-                       else
-                           target_result = target;
-                   }
-               }
-               else
-               {
-                   if (target_result != NULL)
-                       elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
-                   else
-                       target_result = target;
-               }
-           }
-       }
-   }
-   return target_result;
-}
-
-static Oid
-any_ordering_op(int restype)
-{
-   Operator    order_op;
-   Oid         order_opid;
-
-   order_op = oper("<", restype, restype, false);
-   order_opid = oprid(order_op);
-
-   return order_opid;
-}
-
-/*
- * transformGroupClause -
- *   transform a Group By clause
- *
- */
-static List *
-transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
-{
-   List       *glist = NIL,
-              *gl = NIL;
-
-   while (grouplist != NIL)
-   {
-       GroupClause *grpcl = makeNode(GroupClause);
-       TargetEntry *restarget;
-       Resdom     *resdom;
-
-       restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
-
-       if (restarget == NULL)
-           elog(WARN, "The field being grouped by must appear in the target list");
-
-       grpcl->entry = restarget;
-       resdom = restarget->resdom;
-       grpcl->grpOpoid = oprid(oper("<",
-                                    resdom->restype,
-                                    resdom->restype, false));
-       if (glist == NIL)
-           gl = glist = lcons(grpcl, NIL);
-       else
-       {
-           List       *i;
-           
-           foreach (i, glist)
-           {
-               GroupClause *gcl = (GroupClause *) lfirst (i);
-               
-               if ( gcl->entry == grpcl->entry )
-                   break;
-           }
-           if ( i == NIL )         /* not in grouplist already */
-           {
-               lnext(gl) = lcons(grpcl, NIL);
-               gl = lnext(gl);
-           }
-           else
-               pfree (grpcl);      /* get rid of this */
-       }
-       grouplist = lnext(grouplist);
-   }
-
-   return glist;
-}
-
-/*
- * transformSortClause -
- *   transform an Order By clause
- *
- */
-static List *
-transformSortClause(ParseState *pstate,
-                   List *orderlist, List *targetlist,
-                   char *uniqueFlag)
-{
-   List       *sortlist = NIL;
-   List       *s = NIL;
-
-   while (orderlist != NIL)
-   {
-       SortGroupBy *sortby = lfirst(orderlist);
-       SortClause *sortcl = makeNode(SortClause);
-       TargetEntry *restarget;
-       Resdom     *resdom;
-
-       restarget = find_targetlist_entry(pstate, sortby, targetlist);
-       if (restarget == NULL)
-           elog(WARN, "The field being ordered by must appear in the target list");
-
-       sortcl->resdom = resdom = restarget->resdom;
-       sortcl->opoid = oprid(oper(sortby->useOp,
-                                  resdom->restype,
-                                  resdom->restype, false));
-       if (sortlist == NIL)
-       {
-           s = sortlist = lcons(sortcl, NIL);
-       }
-       else
-       {
-           List       *i;
-           
-           foreach (i, sortlist)
-           {
-               SortClause *scl = (SortClause *) lfirst (i);
-               
-               if ( scl->resdom == sortcl->resdom )
-                   break;
-           }
-           if ( i == NIL )         /* not in sortlist already */
-           {
-               lnext(s) = lcons(sortcl, NIL);
-               s = lnext(s);
-           }
-           else
-               pfree (sortcl);     /* get rid of this */
-       }
-       orderlist = lnext(orderlist);
-   }
-
-   if (uniqueFlag)
-   {
-       List       *i;
-       
-       if (uniqueFlag[0] == '*')
-       {
-
-           /*
-            * concatenate all elements from target list that are not
-            * already in the sortby list
-            */
-           foreach(i, targetlist)
-           {
-               TargetEntry *tlelt = (TargetEntry *) lfirst(i);
-
-               s = sortlist;
-               while (s != NIL)
-               {
-                   SortClause *sortcl = lfirst(s);
-
-                   if (sortcl->resdom == tlelt->resdom)
-                       break;
-                   s = lnext(s);
-               }
-               if (s == NIL)
-               {
-                   /* not a member of the sortclauses yet */
-                   SortClause *sortcl = makeNode(SortClause);
-
-                   sortcl->resdom = tlelt->resdom;
-                   sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
-
-                   sortlist = lappend(sortlist, sortcl);
-               }
-           }
-       }
-       else
-       {
-           TargetEntry *tlelt = NULL;
-           char       *uniqueAttrName = uniqueFlag;
-
-           /* only create sort clause with the specified unique attribute */
-           foreach(i, targetlist)
-           {
-               tlelt = (TargetEntry *) lfirst(i);
-               if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
-                   break;
-           }
-           if (i == NIL)
-           {
-               elog(WARN, "The field specified in the UNIQUE ON clause is not in the targetlist");
-           }
-           s = sortlist;
-           foreach(s, sortlist)
-           {
-               SortClause *sortcl = lfirst(s);
-
-               if (sortcl->resdom == tlelt->resdom)
-                   break;
-           }
-           if (s == NIL)
-           {
-               /* not a member of the sortclauses yet */
-               SortClause *sortcl = makeNode(SortClause);
-
-               sortcl->resdom = tlelt->resdom;
-               sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
-
-               sortlist = lappend(sortlist, sortcl);
-           }
-       }
-
-   }
-
-   return sortlist;
-}
-
-/*
- ** HandleNestedDots --
- **    Given a nested dot expression (i.e. (relation func ... attr), build up
- ** a tree with of Iter and Func nodes.
- */
-static Node *
-handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno)
-{
-   List       *mutator_iter;
-   Node       *retval = NULL;
-
-   if (attr->paramNo != NULL)
-   {
-       Param      *param = (Param *) transformExpr(pstate, (Node *) attr->paramNo, EXPR_RELATION_FIRST);
-
-       retval =
-           ParseFunc(pstate, strVal(lfirst(attr->attrs)),
-                     lcons(param, NIL),
-                     curr_resno);
-   }
-   else
-   {
-       Ident      *ident = makeNode(Ident);
-
-       ident->name = attr->relname;
-       ident->isRel = TRUE;
-       retval =
-           ParseFunc(pstate, strVal(lfirst(attr->attrs)),
-                     lcons(ident, NIL),
-                     curr_resno);
-   }
-
-   foreach(mutator_iter, lnext(attr->attrs))
-   {
-       retval = ParseFunc(pstate, strVal(lfirst(mutator_iter)),
-                          lcons(retval, NIL),
-                          curr_resno);
-   }
-
-   return (retval);
-}
-
-/*
- ** make_arguments --
- **   Given the number and types of arguments to a function, and the
- **   actual arguments and argument types, do the necessary typecasting.
- */
-static void
-make_arguments(int nargs,
-              List *fargs,
-              Oid *input_typeids,
-              Oid *function_typeids)
-{
-
-   /*
-    * there are two ways an input typeid can differ from a function
-    * typeid : either the input type inherits the function type, so no
-    * typecasting is necessary, or the input type can be typecast into
-    * the function type. right now, we only typecast unknowns, and that
-    * is all we check for.
-    */
-
-   List       *current_fargs;
-   int         i;
-
-   for (i = 0, current_fargs = fargs;
-        i < nargs;
-        i++, current_fargs = lnext(current_fargs))
-   {
-
-       if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)
-       {
-           lfirst(current_fargs) =
-               parser_typecast2(lfirst(current_fargs),
-                                input_typeids[i],
-                                get_id_type(function_typeids[i]),
-                                -1);
-       }
-   }
-}
-
-/*
- ** setup_tlist --
- **        Build a tlist that says which attribute to project to.
- **        This routine is called by ParseFunc() to set up a target list
- **        on a tuple parameter or return value.  Due to a bug in 4.0,
- **        it's not possible to refer to system attributes in this case.
- */
-static List *
-setup_tlist(char *attname, Oid relid)
-{
-   TargetEntry *tle;
-   Resdom     *resnode;
-   Var        *varnode;
-   Oid         typeid;
-   int         attno;
-
-   attno = get_attnum(relid, attname);
-   if (attno < 0)
-       elog(WARN, "cannot reference attribute '%s' of tuple params/return values for functions", attname);
-
-   typeid = find_atttype(relid, attname);
-   resnode = makeResdom(1,
-                        typeid,
-                        tlen(get_id_type(typeid)),
-                        get_attname(relid, attno),
-                        0,
-                        (Oid) 0,
-                        0);
-   varnode = makeVar(-1, attno, typeid, -1, attno);
-
-   tle = makeNode(TargetEntry);
-   tle->resdom = resnode;
-   tle->expr = (Node *) varnode;
-   return (lcons(tle, NIL));
-}
-
-/*
- ** setup_base_tlist --
- **        Build a tlist that extracts a base type from the tuple
- **        returned by the executor.
- */
-static List *
-setup_base_tlist(Oid typeid)
-{
-   TargetEntry *tle;
-   Resdom     *resnode;
-   Var        *varnode;
-
-   resnode = makeResdom(1,
-                        typeid,
-                        tlen(get_id_type(typeid)),
-                        "",
-                        0,
-                        (Oid) 0,
-                        0);
-   varnode = makeVar(-1, 1, typeid, -1, 1);
-   tle = makeNode(TargetEntry);
-   tle->resdom = resnode;
-   tle->expr = (Node *) varnode;
-
-   return (lcons(tle, NIL));
-}
-
-/*
- * ParseComplexProjection -
- *   handles function calls with a single argument that is of complex type.
- *   This routine returns NULL if it can't handle the projection (eg. sets).
- */
-static Node *
-ParseComplexProjection(ParseState *pstate,
-                      char *funcname,
-                      Node *first_arg,
-                      bool *attisset)
-{
-   Oid         argtype;
-   Oid         argrelid;
-   Name        relname;
-   Relation    rd;
-   Oid         relid;
-   int         attnum;
-
-   switch (nodeTag(first_arg))
-   {
-       case T_Iter:
-           {
-               Func       *func;
-               Iter       *iter;
-
-               iter = (Iter *) first_arg;
-               func = (Func *) ((Expr *) iter->iterexpr)->oper;
-               argtype = funcid_get_rettype(func->funcid);
-               argrelid = typeid_get_relid(argtype);
-               if (argrelid &&
-                   ((attnum = get_attnum(argrelid, funcname))
-                    != InvalidAttrNumber))
-               {
-
-                   /*
-                    * the argument is a function returning a tuple, so
-                    * funcname may be a projection
-                    */
-
-                   /* add a tlist to the func node and return the Iter */
-                   rd = heap_openr(tname(get_id_type(argtype)));
-                   if (RelationIsValid(rd))
-                   {
-                       relid = RelationGetRelationId(rd);
-                       relname = RelationGetRelationName(rd);
-                       heap_close(rd);
-                   }
-                   if (RelationIsValid(rd))
-                   {
-                       func->func_tlist =
-                           setup_tlist(funcname, argrelid);
-                       iter->itertype = att_typeid(rd, attnum);
-                       return ((Node *) iter);
-                   }
-                   else
-                   {
-                       elog(WARN,
-                            "Function '%s' has bad returntype %d",
-                            funcname, argtype);
-                   }
-               }
-               else
-               {
-                   /* drop through */
-                   ;
-               }
-               break;
-           }
-       case T_Var:
-           {
-
-               /*
-                * The argument is a set, so this is either a projection
-                * or a function call on this set.
-                */
-               *attisset = true;
-               break;
-           }
-       case T_Expr:
-           {
-               Expr       *expr = (Expr *) first_arg;
-               Func       *funcnode;
-
-               if (expr->opType != FUNC_EXPR)
-                   break;
-
-               funcnode = (Func *) expr->oper;
-               argtype = funcid_get_rettype(funcnode->funcid);
-               argrelid = typeid_get_relid(argtype);
-
-               /*
-                * the argument is a function returning a tuple, so
-                * funcname may be a projection
-                */
-               if (argrelid &&
-                   (attnum = get_attnum(argrelid, funcname))
-                   != InvalidAttrNumber)
-               {
-
-                   /* add a tlist to the func node */
-                   rd = heap_openr(tname(get_id_type(argtype)));
-                   if (RelationIsValid(rd))
-                   {
-                       relid = RelationGetRelationId(rd);
-                       relname = RelationGetRelationName(rd);
-                       heap_close(rd);
-                   }
-                   if (RelationIsValid(rd))
-                   {
-                       Expr       *newexpr;
-
-                       funcnode->func_tlist =
-                           setup_tlist(funcname, argrelid);
-                       funcnode->functype = att_typeid(rd, attnum);
-
-                       newexpr = makeNode(Expr);
-                       newexpr->typeOid = funcnode->functype;
-                       newexpr->opType = FUNC_EXPR;
-                       newexpr->oper = (Node *) funcnode;
-                       newexpr->args = lcons(first_arg, NIL);
-
-                       return ((Node *) newexpr);
-                   }
-
-               }
-
-               elog(WARN, "Function '%s' has bad returntype %d",
-                    funcname, argtype);
-               break;
-           }
-       case T_Param:
-           {
-               Param      *param = (Param *) first_arg;
-
-               /*
-                * If the Param is a complex type, this could be a
-                * projection
-                */
-               rd = heap_openr(tname(get_id_type(param->paramtype)));
-               if (RelationIsValid(rd))
-               {
-                   relid = RelationGetRelationId(rd);
-                   relname = RelationGetRelationName(rd);
-                   heap_close(rd);
-               }
-               if (RelationIsValid(rd) &&
-                   (attnum = get_attnum(relid, funcname))
-                   != InvalidAttrNumber)
-               {
-
-                   param->paramtype = att_typeid(rd, attnum);
-                   param->param_tlist = setup_tlist(funcname, relid);
-                   return ((Node *) param);
-               }
-               break;
-           }
-       default:
-           break;
-   }
-
-   return NULL;
-}
-
-static Node *
-ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
-{
-   Oid         rettype = (Oid) 0;
-   Oid         argrelid = (Oid) 0;
-   Oid         funcid = (Oid) 0;
-   List       *i = NIL;
-   Node       *first_arg = NULL;
-   char       *relname = NULL;
-   char       *refname = NULL;
-   Relation    rd;
-   Oid         relid;
-   int         nargs;
-   Func       *funcnode;
-   Oid         oid_array[8];
-   Oid        *true_oid_array;
-   Node       *retval;
-   bool        retset;
-   bool        exists;
-   bool        attisset = false;
-   Oid         toid = (Oid) 0;
-   Expr       *expr;
-
-   if (fargs)
-   {
-       first_arg = lfirst(fargs);
-       if (first_arg == NULL)
-           elog(WARN, "function '%s' does not allow NULL input", funcname);
-   }
-
-   /*
-    * * check for projection methods: if function takes one argument, and *
-    * that argument is a relation, param, or PQ function returning a
-    * complex * type, then the function could be a projection.
-    */
-   if (length(fargs) == 1)
-   {
-
-       if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)
-       {
-           RangeTblEntry *rte;
-           Ident      *ident = (Ident *) first_arg;
-
-           /*
-            * first arg is a relation. This could be a projection.
-            */
-           refname = ident->name;
-
-           rte = refnameRangeTableEntry(pstate->p_rtable, refname);
-           if (rte == NULL)
-               rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE);
-
-           relname = rte->relname;
-           relid = rte->relid;
-
-           /*
-            * If the attr isn't a set, just make a var for it.  If it is
-            * a set, treat it like a function and drop through.
-            */
-           if (get_attnum(relid, funcname) != InvalidAttrNumber)
-           {
-               Oid         dummyTypeId;
-
-               return
-                   ((Node *) make_var(pstate,
-                                      refname,
-                                      funcname,
-                                      &dummyTypeId));
-           }
-           else
-           {
-               /* drop through - attr is a set */
-               ;
-           }
-       }
-       else if (ISCOMPLEX(exprType(first_arg)))
-       {
-
-           /*
-            * Attempt to handle projection of a complex argument. If
-            * ParseComplexProjection can't handle the projection, we have
-            * to keep going.
-            */
-           retval = ParseComplexProjection(pstate,
-                                           funcname,
-                                           first_arg,
-                                           &attisset);
-           if (attisset)
-           {
-               toid = exprType(first_arg);
-               rd = heap_openr(tname(get_id_type(toid)));
-               if (RelationIsValid(rd))
-               {
-                   relname = RelationGetRelationName(rd)->data;
-                   heap_close(rd);
-               }
-               else
-                   elog(WARN,
-                        "Type '%s' is not a relation type",
-                        tname(get_id_type(toid)));
-               argrelid = typeid_get_relid(toid);
-
-               /*
-                * A projection contains either an attribute name or the
-                * "*".
-                */
-               if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
-                   && strcmp(funcname, "*"))
-               {
-                   elog(WARN, "Functions on sets are not yet supported");
-               }
-           }
-
-           if (retval)
-               return retval;
-       }
-       else
-       {
-
-           /*
-            * Parsing aggregates.
-            */
-           Oid         basetype;
-
-           /*
-            * the aggregate count is a special case, ignore its base
-            * type.  Treat it as zero
-            */
-           if (strcmp(funcname, "count") == 0)
-               basetype = 0;
-           else
-               basetype = exprType(lfirst(fargs));
-           if (SearchSysCacheTuple(AGGNAME,
-                                   PointerGetDatum(funcname),
-                                   ObjectIdGetDatum(basetype),
-                                   0, 0))
-           {
-               Aggreg     *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
-
-               AddAggToParseState(pstate, aggreg);
-               return (Node *) aggreg;
-           }
-       }
-   }
-
-
-   /*
-    * * If we dropped through to here it's really a function (or a set,
-    * which * is implemented as a function.) * extract arg type info and
-    * transform relation name arguments into * varnodes of the
-    * appropriate form.
-    */
-   MemSet(&oid_array[0], 0, 8 * sizeof(Oid));
-
-   nargs = 0;
-   foreach(i, fargs)
-   {
-       int         vnum;
-       RangeTblEntry *rte;
-       Node       *pair = lfirst(i);
-
-       if (nodeTag(pair) == T_Ident && ((Ident *) pair)->isRel)
-       {
-
-           /*
-            * a relation
-            */
-           refname = ((Ident *) pair)->name;
-
-           rte = refnameRangeTableEntry(pstate->p_rtable, refname);
-           if (rte == NULL)
-               rte = addRangeTableEntry(pstate, refname, refname,
-                                        FALSE, FALSE);
-           relname = rte->relname;
-
-           vnum = refnameRangeTablePosn(pstate->p_rtable, rte->refname);
-
-           /*
-            * for func(relname), the param to the function is the tuple
-            * under consideration.  we build a special VarNode to reflect
-            * this -- it has varno set to the correct range table entry,
-            * but has varattno == 0 to signal that the whole tuple is the
-            * argument.
-            */
-           toid = typeid(type(relname));
-           /* replace it in the arg list */
-           lfirst(fargs) =
-               makeVar(vnum, 0, toid, vnum, 0);
-       }
-       else if (!attisset)
-       {                       /* set functions don't have parameters */
-
-           /*
-            * any functiona args which are typed "unknown", but aren't
-            * constants, we don't know what to do with, because we can't
-            * cast them    - jolly
-            */
-           if (exprType(pair) == UNKNOWNOID &&
-               !IsA(pair, Const))
-           {
-               elog(WARN, "ParseFunc: no function named '%s' that takes in an unknown type as argument #%d", funcname, nargs);
-           }
-           else
-               toid = exprType(pair);
-       }
-
-       oid_array[nargs++] = toid;
-   }
-
-   /*
-    * func_get_detail looks up the function in the catalogs, does
-    * disambiguation for polymorphic functions, handles inheritance, and
-    * returns the funcid and type and set or singleton status of the
-    * function's return value.  it also returns the true argument types
-    * to the function.  if func_get_detail returns true, the function
-    * exists.  otherwise, there was an error.
-    */
-   if (attisset)
-   {                           /* we know all of these fields already */
-
-       /*
-        * We create a funcnode with a placeholder function SetEval.
-        * SetEval() never actually gets executed.  When the function
-        * evaluation routines see it, they use the funcid projected out
-        * from the relation as the actual function to call. Example:
-        * retrieve (emp.mgr.name) The plan for this will scan the emp
-        * relation, projecting out the mgr attribute, which is a funcid.
-        * This function is then called (instead of SetEval) and "name" is
-        * projected from its result.
-        */
-       funcid = SetEvalRegProcedure;
-       rettype = toid;
-       retset = true;
-       true_oid_array = oid_array;
-       exists = true;
-   }
-   else
-   {
-       exists = func_get_detail(funcname, nargs, oid_array, &funcid,
-                                &rettype, &retset, &true_oid_array);
-   }
-
-   if (!exists)
-       elog(WARN, "no such attribute or function '%s'", funcname);
-
-   /* got it */
-   funcnode = makeNode(Func);
-   funcnode->funcid = funcid;
-   funcnode->functype = rettype;
-   funcnode->funcisindex = false;
-   funcnode->funcsize = 0;
-   funcnode->func_fcache = NULL;
-   funcnode->func_tlist = NIL;
-   funcnode->func_planlist = NIL;
-
-   /* perform the necessary typecasting */
-   make_arguments(nargs, fargs, oid_array, true_oid_array);
-
-   /*
-    * for functions returning base types, we want to project out the
-    * return value.  set up a target list to do that.  the executor will
-    * ignore these for c functions, and do the right thing for postquel
-    * functions.
-    */
-
-   if (typeid_get_relid(rettype) == InvalidOid)
-       funcnode->func_tlist = setup_base_tlist(rettype);
-
-   /*
-    * For sets, we want to make a targetlist to project out this
-    * attribute of the set tuples.
-    */
-   if (attisset)
-   {
-       if (!strcmp(funcname, "*"))
-       {
-           funcnode->func_tlist =
-               expandAll(pstate, relname, refname, curr_resno);
-       }
-       else
-       {
-           funcnode->func_tlist = setup_tlist(funcname, argrelid);
-           rettype = find_atttype(argrelid, funcname);
-       }
-   }
-
-   /*
-    * Sequence handling.
-    */
-   if (funcid == SeqNextValueRegProcedure ||
-       funcid == SeqCurrValueRegProcedure)
-   {
-       Const      *seq;
-       char       *seqrel;
-       text       *seqname;
-       int32       aclcheck_result = -1;
-       extern text *lower (text *string);
-
-       Assert(length(fargs) == 1);
-       seq = (Const *) lfirst(fargs);
-       if (!IsA((Node *) seq, Const))
-           elog(WARN, "%s: only constant sequence names are acceptable", funcname);
-       seqname = lower ((text*)DatumGetPointer(seq->constvalue));
-       pfree (DatumGetPointer(seq->constvalue));
-       seq->constvalue = PointerGetDatum (seqname);
-       seqrel = textout(seqname);
-
-       if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),
-              ((funcid == SeqNextValueRegProcedure) ? ACL_WR : ACL_RD)))
-           != ACLCHECK_OK)
-           elog(WARN, "%s.%s: %s",
-             seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
-
-       pfree(seqrel);
-
-       if (funcid == SeqNextValueRegProcedure && inWhereClause)
-           elog(WARN, "nextval of a sequence in WHERE disallowed");
-   }
-
-   expr = makeNode(Expr);
-   expr->typeOid = rettype;
-   expr->opType = FUNC_EXPR;
-   expr->oper = (Node *) funcnode;
-   expr->args = fargs;
-   retval = (Node *) expr;
-
-   /*
-    * if the function returns a set of values, then we need to iterate
-    * over all the returned values in the executor, so we stick an iter
-    * node here.  if it returns a singleton, then we don't need the iter
-    * node.
-    */
-
-   if (retset)
-   {
-       Iter       *iter = makeNode(Iter);
-
-       iter->itertype = rettype;
-       iter->iterexpr = retval;
-       retval = (Node *) iter;
-   }
-
-   return (retval);
-}
-
-/*****************************************************************************
- *
- *****************************************************************************/
-
-/*
- * AddAggToParseState -
- *   add the aggregate to the list of unique aggregates in pstate.
- *
- * SIDE EFFECT: aggno in target list entry will be modified
- */
-static void
-AddAggToParseState(ParseState *pstate, Aggreg *aggreg)
-{
-   List       *ag;
-   int         i;
-
-   /*
-    * see if we have the aggregate already (we only need to record the
-    * aggregate once)
-    */
-   i = 0;
-   foreach(ag, pstate->p_aggs)
-   {
-       Aggreg     *a = lfirst(ag);
-
-       if (!strcmp(a->aggname, aggreg->aggname) &&
-           equal(a->target, aggreg->target))
-       {
-
-           /* fill in the aggno and we're done */
-           aggreg->aggno = i;
-           return;
-       }
-       i++;
-   }
-
-   /* not found, new aggregate */
-   aggreg->aggno = i;
-   pstate->p_numAgg++;
-   pstate->p_aggs = lappend(pstate->p_aggs, aggreg);
-   return;
-}
-
-/*
- * finalizeAggregates -
- *   fill in qry_aggs from pstate. Also checks to make sure that aggregates
- *   are used in the proper place.
- */
-static void
-finalizeAggregates(ParseState *pstate, Query *qry)
-{
-   List       *l;
-   int         i;
-
-   parseCheckAggregates(pstate, qry);
-
-   qry->qry_numAgg = pstate->p_numAgg;
-   qry->qry_aggs =
-       (Aggreg **) palloc(sizeof(Aggreg *) * qry->qry_numAgg);
-   i = 0;
-   foreach(l, pstate->p_aggs)
-       qry->qry_aggs[i++] = (Aggreg *) lfirst(l);
-}
-
-/*
- * contain_agg_clause--
- *   Recursively find aggreg nodes from a clause.
- *
- *   Returns true if any aggregate found.
- */
-static bool
-contain_agg_clause(Node *clause)
-{
-   if (clause == NULL)
-       return FALSE;
-   else if (IsA(clause, Aggreg))
-       return TRUE;
-   else if (IsA(clause, Iter))
-       return contain_agg_clause(((Iter *) clause)->iterexpr);
-   else if (single_node(clause))
-       return FALSE;
-   else if (or_clause(clause))
-   {
-       List       *temp;
-
-       foreach(temp, ((Expr *) clause)->args)
-           if (contain_agg_clause(lfirst(temp)))
-           return TRUE;
-       return FALSE;
-   }
-   else if (is_funcclause(clause))
-   {
-       List       *temp;
-
-       foreach(temp, ((Expr *) clause)->args)
-           if (contain_agg_clause(lfirst(temp)))
-           return TRUE;
-       return FALSE;
-   }
-   else if (IsA(clause, ArrayRef))
-   {
-       List       *temp;
-
-       foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
-           if (contain_agg_clause(lfirst(temp)))
-           return TRUE;
-       foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
-           if (contain_agg_clause(lfirst(temp)))
-           return TRUE;
-       if (contain_agg_clause(((ArrayRef *) clause)->refexpr))
-           return TRUE;
-       if (contain_agg_clause(((ArrayRef *) clause)->refassgnexpr))
-           return TRUE;
-       return FALSE;
-   }
-   else if (not_clause(clause))
-       return contain_agg_clause((Node *) get_notclausearg((Expr *) clause));
-   else if (is_opclause(clause))
-       return (contain_agg_clause((Node *) get_leftop((Expr *) clause)) ||
-             contain_agg_clause((Node *) get_rightop((Expr *) clause)));
-
-   return FALSE;
-}
-
-/*
- * exprIsAggOrGroupCol -
- *   returns true if the expression does not contain non-group columns.
- */
-static bool
-exprIsAggOrGroupCol(Node *expr, List *groupClause)
-{
-   List       *gl;
-
-   if (expr == NULL || IsA(expr, Const) ||
-       IsA(expr, Param) ||IsA(expr, Aggreg))
-       return TRUE;
-
-   foreach(gl, groupClause)
-   {
-       GroupClause *grpcl = lfirst(gl);
-
-       if (equal(expr, grpcl->entry->expr))
-           return TRUE;
-   }
-
-   if (IsA(expr, Expr))
-   {
-       List       *temp;
-
-       foreach(temp, ((Expr *) expr)->args)
-           if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
-           return FALSE;
-       return TRUE;
-   }
-
-   return FALSE;
-}
-
-/*
- * tleIsAggOrGroupCol -
- *   returns true if the TargetEntry is Agg or GroupCol.
- */
-static bool
-tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
-{
-   Node       *expr = tle->expr;
-   List       *gl;
-
-   if (expr == NULL || IsA(expr, Const) ||IsA(expr, Param))
-       return TRUE;
-
-   foreach(gl, groupClause)
-   {
-       GroupClause *grpcl = lfirst(gl);
-
-       if (tle->resdom->resno == grpcl->entry->resdom->resno)
-       {
-           if (contain_agg_clause((Node *) expr))
-               elog(WARN, "parser: aggregates not allowed in GROUP BY clause");
-           return TRUE;
-       }
-   }
-
-   if (IsA(expr, Aggreg))
-       return TRUE;
-
-   if (IsA(expr, Expr))
-   {
-       List       *temp;
-
-       foreach(temp, ((Expr *) expr)->args)
-           if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
-           return FALSE;
-       return TRUE;
-   }
-
-   return FALSE;
-}
-
-/*
- * parseCheckAggregates -
- *   this should really be done earlier but the current grammar
- *   cannot differentiate functions from aggregates. So we have do check
- *   here when the target list and the qualifications are finalized.
- */
-static void
-parseCheckAggregates(ParseState *pstate, Query *qry)
-{
-   List       *tl;
-
-   Assert(pstate->p_numAgg > 0);
-
-   /*
-    * aggregates never appear in WHERE clauses. (we have to check where
-    * clause first because if there is an aggregate, the check for
-    * non-group column in target list may fail.)
-    */
-   if (contain_agg_clause(qry->qual))
-       elog(WARN, "parser: aggregates not allowed in WHERE clause");
-
-   /*
-    * the target list can only contain aggregates, group columns and
-    * functions thereof.
-    */
-   foreach(tl, qry->targetList)
-   {
-       TargetEntry *tle = lfirst(tl);
-
-       if (!tleIsAggOrGroupCol(tle, qry->groupClause))
-           elog(WARN,
-                "parser: illegal use of aggregates or non-group column in target list");
-   }
-
-   /*
-    * the expression specified in the HAVING clause has the same
-    * restriction as those in the target list.
-    */
-/*
- * Need to change here when we get HAVING works. Currently
- * qry->havingQual is NULL.        - vadim 04/05/97
-   if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
-       elog(WARN,
-            "parser: illegal use of aggregates or non-group column in HAVING clause");
- */
-   return;
-}
-
-/* not used
-#define    PSIZE(PTR)     (*((int32 *)(PTR) - 1))
-*/
-
-static Node       *
-parser_typecast(Value *expr, TypeName *typename, int typlen)
-{
-   /* check for passing non-ints */
-   Const      *adt;
-   Datum       lcp;
-   Type        tp;
-   char        type_string[NAMEDATALEN];
-   int32       len;
-   char       *cp = NULL;
-   char       *const_string = NULL;
-   bool        string_palloced = false;
-
-   switch (nodeTag(expr))
-   {
-       case T_String:
-           const_string = DatumGetPointer(expr->val.str);
-           break;
-       case T_Integer:
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%ld", expr->val.ival);
-           break;
-       default:
-           elog(WARN,
-           "parser_typecast: cannot cast this expression to type \"%s\"",
-                typename->name);
-   }
-
-   if (typename->arrayBounds != NIL)
-   {
-       sprintf(type_string, "_%s", typename->name);
-       tp = (Type) type(type_string);
-   }
-   else
-   {
-       tp = (Type) type(typename->name);
-   }
-
-   len = tlen(tp);
-
-#if 0                          /* fix me */
-   switch (CInteger(lfirst(expr)))
-   {
-       case INT4OID:           /* int4 */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue);
-           break;
-
-       case NAMEOID:           /* char16 */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue);
-           break;
-
-       case CHAROID:           /* char */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue);
-           break;
-
-       case FLOAT8OID: /* float8 */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue);
-           break;
-
-       case CASHOID:           /* money */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%d",
-                   (int) ((Const *) expr)->constvalue);
-           break;
-
-       case TEXTOID:           /* text */
-           const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
-           const_string = (char *) textout((struct varlena *) const_string);
-           break;
-
-       case UNKNOWNOID:        /* unknown */
-           const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
-           const_string = (char *) textout((struct varlena *) const_string);
-           break;
-
-       default:
-           elog(WARN, "unknown type %d", CInteger(lfirst(expr)));
-   }
-#endif
-
-   cp = instr2(tp, const_string, typlen);
-
-   if (!tbyvalue(tp))
-   {
-/*
-       if (len >= 0 && len != PSIZE(cp)) {
-           char *pp;
-           pp = (char *) palloc(len);
-           memmove(pp, cp, len);
-           cp = pp;
-       }
-*/
-       lcp = PointerGetDatum(cp);
-   }
-   else
-   {
-       switch (len)
-       {
-           case 1:
-               lcp = Int8GetDatum(cp);
-               break;
-           case 2:
-               lcp = Int16GetDatum(cp);
-               break;
-           case 4:
-               lcp = Int32GetDatum(cp);
-               break;
-           default:
-               lcp = PointerGetDatum(cp);
-               break;
-       }
-   }
-
-   adt = makeConst(typeid(tp),
-                   len,
-                   (Datum) lcp,
-                   false,
-                   tbyvalue(tp),
-                   false,      /* not a set */
-                   true /* is cast */ );
-
-   if (string_palloced)
-       pfree(const_string);
-
-   return (Node *) adt;
-}
-
-static Node       *
-parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen)
-{
-   /* check for passing non-ints */
-   Const      *adt;
-   Datum       lcp;
-   int32       len = tlen(tp);
-   char       *cp = NULL;
-
-   char       *const_string = NULL;
-   bool        string_palloced = false;
-
-   Assert(IsA(expr, Const));
-
-   switch (exprType)
-   {
-       case 0:         /* NULL */
-           break;
-       case INT4OID:           /* int4 */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%d",
-                   (int) ((Const *) expr)->constvalue);
-           break;
-       case NAMEOID:           /* char16 */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%s",
-                   (char *) ((Const *) expr)->constvalue);
-           break;
-       case CHAROID:           /* char */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%c",
-                   (char) ((Const *) expr)->constvalue);
-           break;
-       case FLOAT4OID: /* float4 */
-           {
-               float32     floatVal =
-               DatumGetFloat32(((Const *) expr)->constvalue);
-
-               const_string = (char *) palloc(256);
-               string_palloced = true;
-               sprintf(const_string, "%f", *floatVal);
-               break;
-           }
-       case FLOAT8OID: /* float8 */
-           {
-               float64     floatVal =
-               DatumGetFloat64(((Const *) expr)->constvalue);
-
-               const_string = (char *) palloc(256);
-               string_palloced = true;
-               sprintf(const_string, "%f", *floatVal);
-               break;
-           }
-       case CASHOID:           /* money */
-           const_string = (char *) palloc(256);
-           string_palloced = true;
-           sprintf(const_string, "%ld",
-                   (long) ((Const *) expr)->constvalue);
-           break;
-       case TEXTOID:           /* text */
-           const_string =
-               DatumGetPointer(((Const *) expr)->constvalue);
-           const_string = (char *) textout((struct varlena *) const_string);
-           break;
-       case UNKNOWNOID:        /* unknown */
-           const_string =
-               DatumGetPointer(((Const *) expr)->constvalue);
-           const_string = (char *) textout((struct varlena *) const_string);
-           break;
-       default:
-           elog(WARN, "unknown type %u ", exprType);
-   }
-
-   if (!exprType)
-   {
-       adt = makeConst(typeid(tp),
-                       (Size) 0,
-                       (Datum) NULL,
-                       true,   /* isnull */
-                       false,  /* was omitted */
-                       false,  /* not a set */
-                       true /* is cast */ );
-       return ((Node *) adt);
-   }
-
-   cp = instr2(tp, const_string, typlen);
-
-
-   if (!tbyvalue(tp))
-   {
-/*
-       if (len >= 0 && len != PSIZE(cp)) {
-           char *pp;
-           pp = (char *) palloc(len);
-           memmove(pp, cp, len);
-           cp = pp;
-       }
-*/
-       lcp = PointerGetDatum(cp);
-   }
-   else
-   {
-       switch (len)
-       {
-           case 1:
-               lcp = Int8GetDatum(cp);
-               break;
-           case 2:
-               lcp = Int16GetDatum(cp);
-               break;
-           case 4:
-               lcp = Int32GetDatum(cp);
-               break;
-           default:
-               lcp = PointerGetDatum(cp);
-               break;
-       }
-   }
-
-   adt = makeConst(typeid(tp),
-                   (Size) len,
-                   (Datum) lcp,
-                   false,
-                   false,      /* was omitted */
-                   false,      /* not a set */
-                   true /* is cast */ );
-
-   /*
-    * printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) , len,cp);
-    */
-   if (string_palloced)
-       pfree(const_string);
-
-   return ((Node *) adt);
-}
-
-static Aggreg     *
-ParseAgg(char *aggname, Oid basetype, Node *target)
-{
-   Oid         fintype;
-   Oid         vartype;
-   Oid         xfn1;
-   Form_pg_aggregate aggform;
-   Aggreg     *aggreg;
-   HeapTuple   theAggTuple;
-
-   theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
-                                     ObjectIdGetDatum(basetype),
-                                     0, 0);
-   if (!HeapTupleIsValid(theAggTuple))
-   {
-       elog(WARN, "aggregate %s does not exist", aggname);
-   }
-
-   aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
-   fintype = aggform->aggfinaltype;
-   xfn1 = aggform->aggtransfn1;
-
-   if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
-       elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
-
-   /* only aggregates with transfn1 need a base type */
-   if (OidIsValid(xfn1))
-   {
-       basetype = aggform->aggbasetype;
-       if (nodeTag(target) == T_Var)
-           vartype = ((Var *) target)->vartype;
-       else
-           vartype = ((Expr *) target)->typeOid;
-
-       if (basetype != vartype)
-       {
-           Type        tp1,
-                       tp2;
-
-           tp1 = get_id_type(basetype);
-           tp2 = get_id_type(vartype);
-           elog(NOTICE, "Aggregate type mismatch:");
-           elog(WARN, "%s works on %s, not %s", aggname,
-                tname(tp1), tname(tp2));
-       }
-   }
-
-   aggreg = makeNode(Aggreg);
-   aggreg->aggname = pstrdup(aggname);
-   aggreg->basetype = aggform->aggbasetype;
-   aggreg->aggtype = fintype;
-
-   aggreg->target = target;
-
-   return aggreg;
-}
diff --git a/src/backend/parser/catalog_utils.c b/src/backend/parser/catalog_utils.c
deleted file mode 100644 (file)
index b119c7d..0000000
+++ /dev/null
@@ -1,1686 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * catalog_utils.c--
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.30 1997/11/20 23:22:14 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include 
-#include "postgres.h"
-
-#include "lib/dllist.h"
-#include "utils/datum.h"
-
-#include "utils/builtins.h"
-#include "utils/elog.h"
-#include "utils/palloc.h"
-#include "fmgr.h"
-
-#include "nodes/pg_list.h"
-#include "nodes/parsenodes.h"
-#include "utils/syscache.h"
-#include "catalog/catname.h"
-
-#include "parser/catalog_utils.h"
-#include "catalog/pg_inherits.h"
-#include "catalog/pg_operator.h"
-#include "catalog/pg_type.h"
-#include "catalog/pg_proc.h"
-#include "catalog/indexing.h"
-#include "catalog/catname.h"
-
-#include "access/skey.h"
-#include "access/relscan.h"
-#include "access/tupdesc.h"
-#include "access/htup.h"
-#include "access/heapam.h"
-#include "access/genam.h"
-#include "access/itup.h"
-#include "access/tupmacs.h"
-
-#include "storage/buf.h"
-#include "storage/bufmgr.h"
-#include "utils/lsyscache.h"
-#include "storage/lmgr.h"
-
-#include "port-protos.h"       /* strdup() */
-
-struct
-{
-   char       *field;
-   int         code;
-}          special_attr[] =
-
-{
-   {
-       "ctid", SelfItemPointerAttributeNumber
-   },
-   {
-       "oid", ObjectIdAttributeNumber
-   },
-   {
-       "xmin", MinTransactionIdAttributeNumber
-   },
-   {
-       "cmin", MinCommandIdAttributeNumber
-   },
-   {
-       "xmax", MaxTransactionIdAttributeNumber
-   },
-   {
-       "cmax", MaxCommandIdAttributeNumber
-   },
-};
-
-#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
-
-static char *attnum_type[SPECIALS] = {
-   "tid",
-   "oid",
-   "xid",
-   "cid",
-   "xid",
-   "cid",
-};
-
-#define MAXFARGS 8             /* max # args to a c or postquel function */
-
-/*
- * This structure is used to explore the inheritance hierarchy above
- * nodes in the type tree in order to disambiguate among polymorphic
- * functions.
- */
-
-typedef struct _InhPaths
-{
-   int         nsupers;        /* number of superclasses */
-   Oid         self;           /* this class */
-   Oid        *supervec;       /* vector of superclasses */
-} InhPaths;
-
-/*
- * This structure holds a list of possible functions or operators that
- * agree with the known name and argument types of the function/operator.
- */
-typedef struct _CandidateList
-{
-   Oid        *args;
-   struct _CandidateList *next;
-}         *CandidateList;
-
-static Oid **argtype_inherit(int nargs, Oid *oid_array);
-static Oid **genxprod(InhPaths *arginh, int nargs);
-static int findsupers(Oid relid, Oid **supervec);
-static bool check_typeid(Oid id);
-static char *instr1(TypeTupleForm tp, char *string, int typlen);
-static void op_error(char *op, Oid arg1, Oid arg2);
-
-/* check to see if a type id is valid,
- * returns true if it is. By using this call before calling
- * get_id_type or get_id_typname, more meaningful error messages
- * can be produced because the caller typically has more context of
- * what's going on                 - jolly
- */
-static bool
-check_typeid(Oid id)
-{
-   return (SearchSysCacheTuple(TYPOID,
-                               ObjectIdGetDatum(id),
-                               0, 0, 0) != NULL);
-}
-
-
-/* return a Type structure, given an typid */
-Type
-get_id_type(Oid id)
-{
-   HeapTuple   tup;
-
-   if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
-                                   0, 0, 0)))
-   {
-       elog(WARN, "type id lookup of %ud failed", id);
-       return (NULL);
-   }
-   return ((Type) tup);
-}
-
-/* return a type name, given a typeid */
-char      *
-get_id_typname(Oid id)
-{
-   HeapTuple   tup;
-   TypeTupleForm typetuple;
-
-   if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
-                                   0, 0, 0)))
-   {
-       elog(WARN, "type id lookup of %ud failed", id);
-       return (NULL);
-   }
-   typetuple = (TypeTupleForm) GETSTRUCT(tup);
-   return (typetuple->typname).data;
-}
-
-/* return a Type structure, given type name */
-Type
-type(char *s)
-{
-   HeapTuple   tup;
-
-   if (s == NULL)
-   {
-       elog(WARN, "type(): Null type");
-   }
-
-   if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0, 0, 0)))
-   {
-       elog(WARN, "type name lookup of %s failed", s);
-   }
-   return ((Type) tup);
-}
-
-/* given attribute id, return type of that attribute */
-/* XXX Special case for pseudo-attributes is a hack */
-Oid
-att_typeid(Relation rd, int attid)
-{
-
-   if (attid < 0)
-   {
-       return (typeid(type(attnum_type[-attid - 1])));
-   }
-
-   /*
-    * -1 because varattno (where attid comes from) returns one more than
-    * index
-    */
-   return (rd->rd_att->attrs[attid - 1]->atttypid);
-}
-
-
-int
-att_attnelems(Relation rd, int attid)
-{
-   return (rd->rd_att->attrs[attid - 1]->attnelems);
-}
-
-/* given type, return the type OID */
-Oid
-typeid(Type tp)
-{
-   if (tp == NULL)
-   {
-       elog(WARN, "typeid() called with NULL type struct");
-   }
-   return (tp->t_oid);
-}
-
-/* given type (as type struct), return the length of type */
-int16
-tlen(Type t)
-{
-   TypeTupleForm typ;
-
-   typ = (TypeTupleForm) GETSTRUCT(t);
-   return (typ->typlen);
-}
-
-/* given type (as type struct), return the value of its 'byval' attribute.*/
-bool
-tbyval(Type t)
-{
-   TypeTupleForm typ;
-
-   typ = (TypeTupleForm) GETSTRUCT(t);
-   return (typ->typbyval);
-}
-
-/* given type (as type struct), return the name of type */
-char      *
-tname(Type t)
-{
-   TypeTupleForm typ;
-
-   typ = (TypeTupleForm) GETSTRUCT(t);
-   return (typ->typname).data;
-}
-
-/* given type (as type struct), return wether type is passed by value */
-int
-tbyvalue(Type t)
-{
-   TypeTupleForm typ;
-
-   typ = (TypeTupleForm) GETSTRUCT(t);
-   return (typ->typbyval);
-}
-
-/* given a type, return its typetype ('c' for 'c'atalog types) */
-static char
-typetypetype(Type t)
-{
-   TypeTupleForm typ;
-
-   typ = (TypeTupleForm) GETSTRUCT(t);
-   return (typ->typtype);
-}
-
-/* given operator, return the operator OID */
-Oid
-oprid(Operator op)
-{
-   return (op->t_oid);
-}
-
-/*
- * given opname, leftTypeId and rightTypeId,
- * find all possible (arg1, arg2) pairs for which an operator named
- * opname exists, such that leftTypeId can be coerced to arg1 and
- * rightTypeId can be coerced to arg2
- */
-static int
-binary_oper_get_candidates(char *opname,
-                          Oid leftTypeId,
-                          Oid rightTypeId,
-                          CandidateList *candidates)
-{
-   CandidateList current_candidate;
-   Relation    pg_operator_desc;
-   HeapScanDesc pg_operator_scan;
-   HeapTuple   tup;
-   OperatorTupleForm oper;
-   Buffer      buffer;
-   int         nkeys;
-   int         ncandidates = 0;
-   ScanKeyData opKey[3];
-
-   *candidates = NULL;
-
-   ScanKeyEntryInitialize(&opKey[0], 0,
-                          Anum_pg_operator_oprname,
-                          NameEqualRegProcedure,
-                          NameGetDatum(opname));
-
-   ScanKeyEntryInitialize(&opKey[1], 0,
-                          Anum_pg_operator_oprkind,
-                          CharacterEqualRegProcedure,
-                          CharGetDatum('b'));
-
-
-   if (leftTypeId == UNKNOWNOID)
-   {
-       if (rightTypeId == UNKNOWNOID)
-       {
-           nkeys = 2;
-       }
-       else
-       {
-           nkeys = 3;
-
-           ScanKeyEntryInitialize(&opKey[2], 0,
-                                  Anum_pg_operator_oprright,
-                                  ObjectIdEqualRegProcedure,
-                                  ObjectIdGetDatum(rightTypeId));
-       }
-   }
-   else if (rightTypeId == UNKNOWNOID)
-   {
-       nkeys = 3;
-
-       ScanKeyEntryInitialize(&opKey[2], 0,
-                              Anum_pg_operator_oprleft,
-                              ObjectIdEqualRegProcedure,
-                              ObjectIdGetDatum(leftTypeId));
-   }
-   else
-   {
-       /* currently only "unknown" can be coerced */
-       return 0;
-   }
-
-   pg_operator_desc = heap_openr(OperatorRelationName);
-   pg_operator_scan = heap_beginscan(pg_operator_desc,
-                                     0,
-                                     true,
-                                     nkeys,
-                                     opKey);
-
-   do
-   {
-       tup = heap_getnext(pg_operator_scan, 0, &buffer);
-       if (HeapTupleIsValid(tup))
-       {
-           current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
-           current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
-
-           oper = (OperatorTupleForm) GETSTRUCT(tup);
-           current_candidate->args[0] = oper->oprleft;
-           current_candidate->args[1] = oper->oprright;
-           current_candidate->next = *candidates;
-           *candidates = current_candidate;
-           ncandidates++;
-           ReleaseBuffer(buffer);
-       }
-   } while (HeapTupleIsValid(tup));
-
-   heap_endscan(pg_operator_scan);
-   heap_close(pg_operator_desc);
-
-   return ncandidates;
-}
-
-/*
- * equivalentOpersAfterPromotion -
- *   checks if a list of candidate operators obtained from
- *   binary_oper_get_candidates() contain equivalent operators. If
- *   this routine is called, we have more than 1 candidate and need to
- *   decided whether to pick one of them. This routine returns true if
- *   the all the candidates operate on the same data types after
- *   promotion (int2, int4, float4 -> float8).
- */
-static bool
-equivalentOpersAfterPromotion(CandidateList candidates)
-{
-   CandidateList result;
-   CandidateList promotedCandidates = NULL;
-   Oid         leftarg,
-               rightarg;
-
-   for (result = candidates; result != NULL; result = result->next)
-   {
-       CandidateList c;
-
-       c = (CandidateList) palloc(sizeof(*c));
-       c->args = (Oid *) palloc(2 * sizeof(Oid));
-       switch (result->args[0])
-       {
-           case FLOAT4OID:
-           case INT4OID:
-           case INT2OID:
-           case CASHOID:
-               c->args[0] = FLOAT8OID;
-               break;
-           default:
-               c->args[0] = result->args[0];
-               break;
-       }
-       switch (result->args[1])
-       {
-           case FLOAT4OID:
-           case INT4OID:
-           case INT2OID:
-           case CASHOID:
-               c->args[1] = FLOAT8OID;
-               break;
-           default:
-               c->args[1] = result->args[1];
-               break;
-       }
-       c->next = promotedCandidates;
-       promotedCandidates = c;
-   }
-
-   /*
-    * if we get called, we have more than 1 candidates so we can do the
-    * following safely
-    */
-   leftarg = promotedCandidates->args[0];
-   rightarg = promotedCandidates->args[1];
-
-   for (result = promotedCandidates->next; result != NULL; result = result->next)
-   {
-       if (result->args[0] != leftarg || result->args[1] != rightarg)
-
-           /*
-            * this list contains operators that operate on different data
-            * types even after promotion. Hence we can't decide on which
-            * one to pick. The user must do explicit type casting.
-            */
-           return FALSE;
-   }
-
-   /*
-    * all the candidates are equivalent in the following sense: they
-    * operate on equivalent data types and picking any one of them is as
-    * good.
-    */
-   return TRUE;
-}
-
-
-/*
- * given a choice of argument type pairs for a binary operator,
- * try to choose a default pair
- */
-static CandidateList
-binary_oper_select_candidate(Oid arg1,
-                            Oid arg2,
-                            CandidateList candidates)
-{
-   CandidateList result;
-
-   /*
-    * if both are "unknown", there is no way to select a candidate
-    *
-    * current wisdom holds that the default operator should be one in which
-    * both operands have the same type (there will only be one such
-    * operator)
-    *
-    * 7.27.93 - I have decided not to do this; it's too hard to justify, and
-    * it's easy enough to typecast explicitly -avi [the rest of this
-    * routine were commented out since then -ay]
-    */
-
-   if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
-       return (NULL);
-
-   /*
-    * 6/23/95 - I don't complete agree with avi. In particular, casting
-    * floats is a pain for users. Whatever the rationale behind not doing
-    * this is, I need the following special case to work.
-    *
-    * In the WHERE clause of a query, if a float is specified without
-    * quotes, we treat it as float8. I added the float48* operators so
-    * that we can operate on float4 and float8. But now we have more than
-    * one matching operator if the right arg is unknown (eg. float
-    * specified with quotes). This break some stuff in the regression
-    * test where there are floats in quotes not properly casted. Below is
-    * the solution. In addition to requiring the operator operates on the
-    * same type for both operands [as in the code Avi originally
-    * commented out], we also require that the operators be equivalent in
-    * some sense. (see equivalentOpersAfterPromotion for details.) - ay
-    * 6/95
-    */
-   if (!equivalentOpersAfterPromotion(candidates))
-       return NULL;
-
-   /*
-    * if we get here, any one will do but we're more picky and require
-    * both operands be the same.
-    */
-   for (result = candidates; result != NULL; result = result->next)
-   {
-       if (result->args[0] == result->args[1])
-           return result;
-   }
-
-   return (NULL);
-}
-
-/* Given operator, types of arg1, and arg2, return oper struct */
-/* arg1, arg2 --typeids */
-Operator
-oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
-{
-   HeapTuple   tup;
-   CandidateList candidates;
-   int         ncandidates;
-
-   if (!arg2)
-       arg2 = arg1;
-   if (!arg1)
-       arg1 = arg2;
-
-   if (!(tup = SearchSysCacheTuple(OPRNAME,
-                                   PointerGetDatum(op),
-                                   ObjectIdGetDatum(arg1),
-                                   ObjectIdGetDatum(arg2),
-                                   Int8GetDatum('b'))))
-   {
-       ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
-       if (ncandidates == 0)
-       {
-
-           /*
-            * no operators of the desired types found
-            */
-           if (!noWarnings)
-               op_error(op, arg1, arg2);
-           return (NULL);
-       }
-       else if (ncandidates == 1)
-       {
-
-           /*
-            * exactly one operator of the desired types found
-            */
-           tup = SearchSysCacheTuple(OPRNAME,
-                                     PointerGetDatum(op),
-                                  ObjectIdGetDatum(candidates->args[0]),
-                                  ObjectIdGetDatum(candidates->args[1]),
-                                     Int8GetDatum('b'));
-           Assert(HeapTupleIsValid(tup));
-       }
-       else
-       {
-
-           /*
-            * multiple operators of the desired types found
-            */
-           candidates = binary_oper_select_candidate(arg1, arg2, candidates);
-           if (candidates != NULL)
-           {
-               /* we chose one of them */
-               tup = SearchSysCacheTuple(OPRNAME,
-                                         PointerGetDatum(op),
-                                  ObjectIdGetDatum(candidates->args[0]),
-                                  ObjectIdGetDatum(candidates->args[1]),
-                                         Int8GetDatum('b'));
-               Assert(HeapTupleIsValid(tup));
-           }
-           else
-           {
-               Type        tp1,
-                           tp2;
-
-               /* we chose none of them */
-               tp1 = get_id_type(arg1);
-               tp2 = get_id_type(arg2);
-               if (!noWarnings)
-               {
-                   elog(NOTICE, "there is more than one operator %s for types", op);
-                   elog(NOTICE, "%s and %s. You will have to retype this query",
-                        tname(tp1), tname(tp2));
-                   elog(WARN, "using an explicit cast");
-               }
-               return (NULL);
-           }
-       }
-   }
-   return ((Operator) tup);
-}
-
-/*
- * given opname and typeId, find all possible types for which
- * a right/left unary operator named opname exists,
- * such that typeId can be coerced to it
- */
-static int
-unary_oper_get_candidates(char *op,
-                         Oid typeId,
-                         CandidateList *candidates,
-                         char rightleft)
-{
-   CandidateList current_candidate;
-   Relation    pg_operator_desc;
-   HeapScanDesc pg_operator_scan;
-   HeapTuple   tup;
-   OperatorTupleForm oper;
-   Buffer      buffer;
-   int         ncandidates = 0;
-
-   static ScanKeyData opKey[2] = {
-       {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
-   {0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure}};
-
-   *candidates = NULL;
-
-   fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func,
-             &opKey[0].sk_nargs);
-   opKey[0].sk_argument = NameGetDatum(op);
-   fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func,
-             &opKey[1].sk_nargs);
-   opKey[1].sk_argument = CharGetDatum(rightleft);
-
-   /* currently, only "unknown" can be coerced */
-
-   /*
-    * but we should allow types that are internally the same to be
-    * "coerced"
-    */
-   if (typeId != UNKNOWNOID)
-   {
-       return 0;
-   }
-
-   pg_operator_desc = heap_openr(OperatorRelationName);
-   pg_operator_scan = heap_beginscan(pg_operator_desc,
-                                     0,
-                                     true,
-                                     2,
-                                     opKey);
-
-   do
-   {
-       tup = heap_getnext(pg_operator_scan, 0, &buffer);
-       if (HeapTupleIsValid(tup))
-       {
-           current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
-           current_candidate->args = (Oid *) palloc(sizeof(Oid));
-
-           oper = (OperatorTupleForm) GETSTRUCT(tup);
-           if (rightleft == 'r')
-               current_candidate->args[0] = oper->oprleft;
-           else
-               current_candidate->args[0] = oper->oprright;
-           current_candidate->next = *candidates;
-           *candidates = current_candidate;
-           ncandidates++;
-           ReleaseBuffer(buffer);
-       }
-   } while (HeapTupleIsValid(tup));
-
-   heap_endscan(pg_operator_scan);
-   heap_close(pg_operator_desc);
-
-   return ncandidates;
-}
-
-/* Given unary right-side operator (operator on right), return oper struct */
-/* arg-- type id */
-Operator
-right_oper(char *op, Oid arg)
-{
-   HeapTuple   tup;
-   CandidateList candidates;
-   int         ncandidates;
-
-   /*
-    * if (!OpCache) { init_op_cache(); }
-    */
-   if (!(tup = SearchSysCacheTuple(OPRNAME,
-                                   PointerGetDatum(op),
-                                   ObjectIdGetDatum(arg),
-                                   ObjectIdGetDatum(InvalidOid),
-                                   Int8GetDatum('r'))))
-   {
-       ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
-       if (ncandidates == 0)
-       {
-           elog(WARN,
-                "Can't find right op: %s for type %d", op, arg);
-           return (NULL);
-       }
-       else if (ncandidates == 1)
-       {
-           tup = SearchSysCacheTuple(OPRNAME,
-                                     PointerGetDatum(op),
-                                  ObjectIdGetDatum(candidates->args[0]),
-                                     ObjectIdGetDatum(InvalidOid),
-                                     Int8GetDatum('r'));
-           Assert(HeapTupleIsValid(tup));
-       }
-       else
-       {
-           elog(NOTICE, "there is more than one right operator %s", op);
-           elog(NOTICE, "you will have to retype this query");
-           elog(WARN, "using an explicit cast");
-           return (NULL);
-       }
-   }
-   return ((Operator) tup);
-}
-
-/* Given unary left-side operator (operator on left), return oper struct */
-/* arg--type id */
-Operator
-left_oper(char *op, Oid arg)
-{
-   HeapTuple   tup;
-   CandidateList candidates;
-   int         ncandidates;
-
-   /*
-    * if (!OpCache) { init_op_cache(); }
-    */
-   if (!(tup = SearchSysCacheTuple(OPRNAME,
-                                   PointerGetDatum(op),
-                                   ObjectIdGetDatum(InvalidOid),
-                                   ObjectIdGetDatum(arg),
-                                   Int8GetDatum('l'))))
-   {
-       ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
-       if (ncandidates == 0)
-       {
-           elog(WARN,
-                "Can't find left op: %s for type %d", op, arg);
-           return (NULL);
-       }
-       else if (ncandidates == 1)
-       {
-           tup = SearchSysCacheTuple(OPRNAME,
-                                     PointerGetDatum(op),
-                                     ObjectIdGetDatum(InvalidOid),
-                                  ObjectIdGetDatum(candidates->args[0]),
-                                     Int8GetDatum('l'));
-           Assert(HeapTupleIsValid(tup));
-       }
-       else
-       {
-           elog(NOTICE, "there is more than one left operator %s", op);
-           elog(NOTICE, "you will have to retype this query");
-           elog(WARN, "using an explicit cast");
-           return (NULL);
-       }
-   }
-   return ((Operator) tup);
-}
-
-/* given range variable, return id of variable */
-
-int
-varattno(Relation rd, char *a)
-{
-   int         i;
-
-   for (i = 0; i < rd->rd_rel->relnatts; i++)
-   {
-       if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
-       {
-           return (i + 1);
-       }
-   }
-   for (i = 0; i < SPECIALS; i++)
-   {
-       if (!strcmp(special_attr[i].field, a))
-       {
-           return (special_attr[i].code);
-       }
-   }
-
-   elog(WARN, "Relation %s does not have attribute %s",
-        RelationGetRelationName(rd), a);
-   return (-1);
-}
-
-/* Given range variable, return whether attribute of this name
- * is a set.
- * NOTE the ASSUMPTION here that no system attributes are, or ever
- * will be, sets.
- */
-bool
-varisset(Relation rd, char *name)
-{
-   int         i;
-
-   /* First check if this is a system attribute */
-   for (i = 0; i < SPECIALS; i++)
-   {
-       if (!strcmp(special_attr[i].field, name))
-       {
-           return (false);     /* no sys attr is a set */
-       }
-   }
-   return (get_attisset(rd->rd_id, name));
-}
-
-/* given range variable, return id of variable */
-int
-nf_varattno(Relation rd, char *a)
-{
-   int         i;
-
-   for (i = 0; i < rd->rd_rel->relnatts; i++)
-   {
-       if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
-       {
-           return (i + 1);
-       }
-   }
-   for (i = 0; i < SPECIALS; i++)
-   {
-       if (!strcmp(special_attr[i].field, a))
-       {
-           return (special_attr[i].code);
-       }
-   }
-   return InvalidAttrNumber;
-}
-
-/*-------------
- * given an attribute number and a relation, return its relation name
- */
-char      *
-getAttrName(Relation rd, int attrno)
-{
-   char       *name;
-   int         i;
-
-   if (attrno < 0)
-   {
-       for (i = 0; i < SPECIALS; i++)
-       {
-           if (special_attr[i].code == attrno)
-           {
-               name = special_attr[i].field;
-               return (name);
-           }
-       }
-       elog(WARN, "Illegal attr no %d for relation %s",
-            attrno, RelationGetRelationName(rd));
-   }
-   else if (attrno >= 1 && attrno <= RelationGetNumberOfAttributes(rd))
-   {
-       name = (rd->rd_att->attrs[attrno - 1]->attname).data;
-       return (name);
-   }
-   else
-   {
-       elog(WARN, "Illegal attr no %d for relation %s",
-            attrno, RelationGetRelationName(rd));
-   }
-
-   /*
-    * Shouldn't get here, but we want lint to be happy...
-    */
-
-   return (NULL);
-}
-
-/* Given a typename and value, returns the ascii form of the value */
-
-#ifdef NOT_USED
-char      *
-outstr(char *typename,         /* Name of type of value */
-      char *value)             /* Could be of any type */
-{
-   TypeTupleForm tp;
-   Oid         op;
-
-   tp = (TypeTupleForm) GETSTRUCT(type(typename));
-   op = tp->typoutput;
-   return ((char *) fmgr(op, value));
-}
-
-#endif
-
-/* Given a Type and a string, return the internal form of that string */
-char      *
-instr2(Type tp, char *string, int typlen)
-{
-   return (instr1((TypeTupleForm) GETSTRUCT(tp), string, typlen));
-}
-
-/* Given a type structure and a string, returns the internal form of
-   that string */
-static char *
-instr1(TypeTupleForm tp, char *string, int typlen)
-{
-   Oid         op;
-   Oid         typelem;
-
-   op = tp->typinput;
-   typelem = tp->typelem;      /* XXX - used for array_in */
-   /* typlen is for bpcharin() and varcharin() */
-   return ((char *) fmgr(op, string, typelem, typlen));
-}
-
-/* Given the attribute type of an array return the arrtribute type of
-   an element of the array */
-
-Oid
-GetArrayElementType(Oid typearray)
-{
-   HeapTuple   type_tuple;
-   TypeTupleForm type_struct_array;
-
-   type_tuple = SearchSysCacheTuple(TYPOID,
-                                    ObjectIdGetDatum(typearray),
-                                    0, 0, 0);
-
-   if (!HeapTupleIsValid(type_tuple))
-       elog(WARN, "GetArrayElementType: Cache lookup failed for type %d",
-            typearray);
-
-   /* get the array type struct from the type tuple */
-   type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
-
-   if (type_struct_array->typelem == InvalidOid)
-   {
-       elog(WARN, "GetArrayElementType: type %s is not an array",
-            (Name) &(type_struct_array->typname.data[0]));
-   }
-
-   return (type_struct_array->typelem);
-}
-
-Oid
-funcid_get_rettype(Oid funcid)
-{
-   HeapTuple   func_tuple = NULL;
-   Oid         funcrettype = (Oid) 0;
-
-   func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
-                                    0, 0, 0);
-
-   if (!HeapTupleIsValid(func_tuple))
-       elog(WARN, "function  %d does not exist", funcid);
-
-   funcrettype = (Oid)
-       ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
-
-   return (funcrettype);
-}
-
-/*
- * get a list of all argument type vectors for which a function named
- * funcname taking nargs arguments exists
- */
-static CandidateList
-func_get_candidates(char *funcname, int nargs)
-{
-   Relation    heapRelation;
-   Relation    idesc;
-   ScanKeyData skey;
-   HeapTuple   tuple;
-   IndexScanDesc sd;
-   RetrieveIndexResult indexRes;
-   Buffer      buffer;
-   Form_pg_proc pgProcP;
-   bool        bufferUsed = FALSE;
-   CandidateList candidates = NULL;
-   CandidateList current_candidate;
-   int         i;
-
-   heapRelation = heap_openr(ProcedureRelationName);
-   ScanKeyEntryInitialize(&skey,
-                          (bits16) 0x0,
-                          (AttrNumber) 1,
-                          (RegProcedure) NameEqualRegProcedure,
-                          (Datum) funcname);
-
-   idesc = index_openr(ProcedureNameIndex);
-
-   sd = index_beginscan(idesc, false, 1, &skey);
-
-   do
-   {
-       tuple = (HeapTuple) NULL;
-       if (bufferUsed)
-       {
-           ReleaseBuffer(buffer);
-           bufferUsed = FALSE;
-       }
-
-       indexRes = index_getnext(sd, ForwardScanDirection);
-       if (indexRes)
-       {
-           ItemPointer iptr;
-
-           iptr = &indexRes->heap_iptr;
-           tuple = heap_fetch(heapRelation, false, iptr, &buffer);
-           pfree(indexRes);
-           if (HeapTupleIsValid(tuple))
-           {
-               pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
-               bufferUsed = TRUE;
-               if (pgProcP->pronargs == nargs)
-               {
-                   current_candidate = (CandidateList)
-                       palloc(sizeof(struct _CandidateList));
-                   current_candidate->args = (Oid *)
-                       palloc(8 * sizeof(Oid));
-                   MemSet(current_candidate->args, 0, 8 * sizeof(Oid));
-                   for (i = 0; i < nargs; i++)
-                   {
-                       current_candidate->args[i] =
-                           pgProcP->proargtypes[i];
-                   }
-
-                   current_candidate->next = candidates;
-                   candidates = current_candidate;
-               }
-           }
-       }
-   } while (indexRes);
-
-   index_endscan(sd);
-   index_close(idesc);
-   heap_close(heapRelation);
-
-   return candidates;
-}
-
-/*
- * can input_typeids be coerced to func_typeids?
- */
-static bool
-can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
-{
-   int         i;
-   Type        tp;
-
-   /*
-    * right now, we only coerce "unknown", and we cannot coerce it to a
-    * relation type
-    */
-   for (i = 0; i < nargs; i++)
-   {
-       if (input_typeids[i] != func_typeids[i])
-       {
-           if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) ||
-               (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) ||
-               (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) ||
-               (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) ||
-           (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) ||
-            (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID))
-               ;               /* these are OK */
-           else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0)
-               return false;
-
-           tp = get_id_type(input_typeids[i]);
-           if (typetypetype(tp) == 'c')
-               return false;
-       }
-   }
-
-   return true;
-}
-
-/*
- * given a list of possible typeid arrays to a function and an array of
- * input typeids, produce a shortlist of those function typeid arrays
- * that match the input typeids (either exactly or by coercion), and
- * return the number of such arrays
- */
-static int
-match_argtypes(int nargs,
-              Oid *input_typeids,
-              CandidateList function_typeids,
-              CandidateList *candidates)       /* return value */
-{
-   CandidateList current_candidate;
-   CandidateList matching_candidate;
-   Oid        *current_typeids;
-   int         ncandidates = 0;
-
-   *candidates = NULL;
-
-   for (current_candidate = function_typeids;
-        current_candidate != NULL;
-        current_candidate = current_candidate->next)
-   {
-       current_typeids = current_candidate->args;
-       if (can_coerce(nargs, input_typeids, current_typeids))
-       {
-           matching_candidate = (CandidateList)
-               palloc(sizeof(struct _CandidateList));
-           matching_candidate->args = current_typeids;
-           matching_candidate->next = *candidates;
-           *candidates = matching_candidate;
-           ncandidates++;
-       }
-   }
-
-   return ncandidates;
-}
-
-/*
- * given the input argtype array and more than one candidate
- * for the function argtype array, attempt to resolve the conflict.
- * returns the selected argtype array if the conflict can be resolved,
- * otherwise returns NULL
- */
-static Oid *
-func_select_candidate(int nargs,
-                     Oid *input_typeids,
-                     CandidateList candidates)
-{
-   /* XXX no conflict resolution implemeneted yet */
-   return (NULL);
-}
-
-bool
-func_get_detail(char *funcname,
-               int nargs,
-               Oid *oid_array,
-               Oid *funcid,    /* return value */
-               Oid *rettype,   /* return value */
-               bool *retset,   /* return value */
-               Oid **true_typeids)     /* return value */
-{
-   Oid       **input_typeid_vector;
-   Oid        *current_input_typeids;
-   CandidateList function_typeids;
-   CandidateList current_function_typeids;
-   HeapTuple   ftup;
-   Form_pg_proc pform;
-
-   /*
-    * attempt to find named function in the system catalogs with
-    * arguments exactly as specified - so that the normal case is just as
-    * quick as before
-    */
-   ftup = SearchSysCacheTuple(PRONAME,
-                              PointerGetDatum(funcname),
-                              Int32GetDatum(nargs),
-                              PointerGetDatum(oid_array),
-                              0);
-   *true_typeids = oid_array;
-
-   /*
-    * If an exact match isn't found : 1) get a vector of all possible
-    * input arg type arrays constructed from the superclasses of the
-    * original input arg types 2) get a list of all possible argument
-    * type arrays to the function with given name and number of arguments
-    * 3) for each input arg type array from vector #1 : a) find how many
-    * of the function arg type arrays from list #2 it can be coerced to
-    * b) - if the answer is one, we have our function - if the answer is
-    * more than one, attempt to resolve the conflict - if the answer is
-    * zero, try the next array from vector #1
-    */
-   if (!HeapTupleIsValid(ftup))
-   {
-       function_typeids = func_get_candidates(funcname, nargs);
-
-       if (function_typeids != NULL)
-       {
-           int         ncandidates = 0;
-
-           input_typeid_vector = argtype_inherit(nargs, oid_array);
-           current_input_typeids = oid_array;
-
-           do
-           {
-               ncandidates = match_argtypes(nargs, current_input_typeids,
-                                            function_typeids,
-                                            ¤t_function_typeids);
-               if (ncandidates == 1)
-               {
-                   *true_typeids = current_function_typeids->args;
-                   ftup = SearchSysCacheTuple(PRONAME,
-                                              PointerGetDatum(funcname),
-                                              Int32GetDatum(nargs),
-                                         PointerGetDatum(*true_typeids),
-                                              0);
-                   Assert(HeapTupleIsValid(ftup));
-               }
-               else if (ncandidates > 1)
-               {
-                   *true_typeids =
-                       func_select_candidate(nargs,
-                                             current_input_typeids,
-                                             current_function_typeids);
-                   if (*true_typeids == NULL)
-                   {
-                       elog(NOTICE, "there is more than one function named \"%s\"",
-                            funcname);
-                       elog(NOTICE, "that satisfies the given argument types. you will have to");
-                       elog(NOTICE, "retype your query using explicit typecasts.");
-                       func_error("func_get_detail", funcname, nargs, oid_array);
-                   }
-                   else
-                   {
-                       ftup = SearchSysCacheTuple(PRONAME,
-                                              PointerGetDatum(funcname),
-                                                  Int32GetDatum(nargs),
-                                         PointerGetDatum(*true_typeids),
-                                                  0);
-                       Assert(HeapTupleIsValid(ftup));
-                   }
-               }
-               current_input_typeids = *input_typeid_vector++;
-           }
-           while (current_input_typeids !=
-                  InvalidOid && ncandidates == 0);
-       }
-   }
-
-   if (!HeapTupleIsValid(ftup))
-   {
-       Type        tp;
-
-       if (nargs == 1)
-       {
-           tp = get_id_type(oid_array[0]);
-           if (typetypetype(tp) == 'c')
-               elog(WARN, "no such attribute or function \"%s\"",
-                    funcname);
-       }
-       func_error("func_get_detail", funcname, nargs, oid_array);
-   }
-   else
-   {
-       pform = (Form_pg_proc) GETSTRUCT(ftup);
-       *funcid = ftup->t_oid;
-       *rettype = pform->prorettype;
-       *retset = pform->proretset;
-
-       return (true);
-   }
-/* shouldn't reach here */
-   return (false);
-
-}
-
-/*
- * argtype_inherit() -- Construct an argtype vector reflecting the
- *                      inheritance properties of the supplied argv.
- *
- *     This function is used to disambiguate among functions with the
- *     same name but different signatures.  It takes an array of eight
- *     type ids.  For each type id in the array that's a complex type
- *     (a class), it walks up the inheritance tree, finding all
- *     superclasses of that type.  A vector of new Oid type arrays
- *     is returned to the caller, reflecting the structure of the
- *     inheritance tree above the supplied arguments.
- *
- *     The order of this vector is as follows:  all superclasses of the
- *     rightmost complex class are explored first.  The exploration
- *     continues from right to left.  This policy means that we favor
- *     keeping the leftmost argument type as low in the inheritance tree
- *     as possible.  This is intentional; it is exactly what we need to
- *     do for method dispatch.  The last type array we return is all
- *     zeroes.  This will match any functions for which return types are
- *     not defined.  There are lots of these (mostly builtins) in the
- *     catalogs.
- */
-static Oid **
-argtype_inherit(int nargs, Oid *oid_array)
-{
-   Oid         relid;
-   int         i;
-   InhPaths    arginh[MAXFARGS];
-
-   for (i = 0; i < MAXFARGS; i++)
-   {
-       if (i < nargs)
-       {
-           arginh[i].self = oid_array[i];
-           if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid)
-           {
-               arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec));
-           }
-           else
-           {
-               arginh[i].nsupers = 0;
-               arginh[i].supervec = (Oid *) NULL;
-           }
-       }
-       else
-       {
-           arginh[i].self = InvalidOid;
-           arginh[i].nsupers = 0;
-           arginh[i].supervec = (Oid *) NULL;
-       }
-   }
-
-   /* return an ordered cross-product of the classes involved */
-   return (genxprod(arginh, nargs));
-}
-
-typedef struct _SuperQE
-{
-   Oid         sqe_relid;
-} SuperQE;
-
-static int
-findsupers(Oid relid, Oid **supervec)
-{
-   Oid        *relidvec;
-   Relation    inhrel;
-   HeapScanDesc inhscan;
-   ScanKeyData skey;
-   HeapTuple   inhtup;
-   TupleDesc   inhtupdesc;
-   int         nvisited;
-   SuperQE    *qentry,
-              *vnode;
-   Dllist     *visited,
-              *queue;
-   Dlelem     *qe,
-              *elt;
-
-   Relation    rd;
-   Buffer      buf;
-   Datum       d;
-   bool        newrelid;
-   char        isNull;
-
-   nvisited = 0;
-   queue = DLNewList();
-   visited = DLNewList();
-
-
-   inhrel = heap_openr(InheritsRelationName);
-   RelationSetLockForRead(inhrel);
-   inhtupdesc = RelationGetTupleDescriptor(inhrel);
-
-   /*
-    * Use queue to do a breadth-first traversal of the inheritance graph
-    * from the relid supplied up to the root.
-    */
-   do
-   {
-       ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
-                              ObjectIdEqualRegProcedure,
-                              ObjectIdGetDatum(relid));
-
-       inhscan = heap_beginscan(inhrel, 0, false, 1, &skey);
-
-       while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf)))
-       {
-           qentry = (SuperQE *) palloc(sizeof(SuperQE));
-
-           d = fastgetattr(inhtup, Anum_pg_inherits_inhparent,
-                           inhtupdesc, &isNull);
-           qentry->sqe_relid = DatumGetObjectId(d);
-
-           /* put this one on the queue */
-           DLAddTail(queue, DLNewElem(qentry));
-
-           ReleaseBuffer(buf);
-       }
-
-       heap_endscan(inhscan);
-
-       /* pull next unvisited relid off the queue */
-       do
-       {
-           qe = DLRemHead(queue);
-           qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL;
-
-           if (qentry == (SuperQE *) NULL)
-               break;
-
-           relid = qentry->sqe_relid;
-           newrelid = true;
-
-           for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
-           {
-               vnode = (SuperQE *) DLE_VAL(elt);
-               if (vnode && (qentry->sqe_relid == vnode->sqe_relid))
-               {
-                   newrelid = false;
-                   break;
-               }
-           }
-       } while (!newrelid);
-
-       if (qentry != (SuperQE *) NULL)
-       {
-
-           /* save the type id, rather than the relation id */
-           if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
-               elog(WARN, "relid %d does not exist", qentry->sqe_relid);
-           qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data));
-           heap_close(rd);
-
-           DLAddTail(visited, qe);
-
-           nvisited++;
-       }
-   } while (qentry != (SuperQE *) NULL);
-
-   RelationUnsetLockForRead(inhrel);
-   heap_close(inhrel);
-
-   if (nvisited > 0)
-   {
-       relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
-       *supervec = relidvec;
-
-       for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
-       {
-           vnode = (SuperQE *) DLE_VAL(elt);
-           *relidvec++ = vnode->sqe_relid;
-       }
-
-   }
-   else
-   {
-       *supervec = (Oid *) NULL;
-   }
-
-   return (nvisited);
-}
-
-static Oid **
-genxprod(InhPaths *arginh, int nargs)
-{
-   int         nanswers;
-   Oid       **result,
-             **iter;
-   Oid        *oneres;
-   int         i,
-               j;
-   int         cur[MAXFARGS];
-
-   nanswers = 1;
-   for (i = 0; i < nargs; i++)
-   {
-       nanswers *= (arginh[i].nsupers + 2);
-       cur[i] = 0;
-   }
-
-   iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
-
-   /* compute the cross product from right to left */
-   for (;;)
-   {
-       oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
-       MemSet(oneres, 0, MAXFARGS * sizeof(Oid));
-
-       for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
-           continue;
-
-       /* if we're done, terminate with NULL pointer */
-       if (i < 0)
-       {
-           *iter = NULL;
-           return (result);
-       }
-
-       /* no, increment this column and zero the ones after it */
-       cur[i] = cur[i] + 1;
-       for (j = nargs - 1; j > i; j--)
-           cur[j] = 0;
-
-       for (i = 0; i < nargs; i++)
-       {
-           if (cur[i] == 0)
-               oneres[i] = arginh[i].self;
-           else if (cur[i] > arginh[i].nsupers)
-               oneres[i] = 0;  /* wild card */
-           else
-               oneres[i] = arginh[i].supervec[cur[i] - 1];
-       }
-
-       *iter++ = oneres;
-   }
-}
-
-/* Given a type id, returns the in-conversion function of the type */
-Oid
-typeid_get_retinfunc(Oid type_id)
-{
-   HeapTuple   typeTuple;
-   TypeTupleForm type;
-   Oid         infunc;
-
-   typeTuple = SearchSysCacheTuple(TYPOID,
-                                   ObjectIdGetDatum(type_id),
-                                   0, 0, 0);
-   if (!HeapTupleIsValid(typeTuple))
-       elog(WARN, "typeid_get_retinfunc: Invalid type - oid = %u", type_id);
-
-   type = (TypeTupleForm) GETSTRUCT(typeTuple);
-   infunc = type->typinput;
-   return (infunc);
-}
-
-/* Given a type id, returns the out-conversion function of the type */
-Oid
-typeid_get_retoutfunc(Oid type_id)
-{
-   HeapTuple   typeTuple;
-   TypeTupleForm type;
-   Oid         outfunc;
-
-   typeTuple = SearchSysCacheTuple(TYPOID,
-                                   ObjectIdGetDatum(type_id),
-                                   0, 0, 0);
-   if (!HeapTupleIsValid(typeTuple))
-       elog(WARN, "typeid_get_retoutfunc: Invalid type - oid = %u", type_id);
-
-   type = (TypeTupleForm) GETSTRUCT(typeTuple);
-   outfunc = type->typoutput;
-   return (outfunc);
-}
-
-Oid
-typeid_get_relid(Oid type_id)
-{
-   HeapTuple   typeTuple;
-   TypeTupleForm type;
-   Oid         infunc;
-
-   typeTuple = SearchSysCacheTuple(TYPOID,
-                                   ObjectIdGetDatum(type_id),
-                                   0, 0, 0);
-   if (!HeapTupleIsValid(typeTuple))
-       elog(WARN, "typeid_get_relid: Invalid type - oid = %u", type_id);
-
-   type = (TypeTupleForm) GETSTRUCT(typeTuple);
-   infunc = type->typrelid;
-   return (infunc);
-}
-
-Oid
-get_typrelid(Type typ)
-{
-   TypeTupleForm typtup;
-
-   typtup = (TypeTupleForm) GETSTRUCT(typ);
-
-   return (typtup->typrelid);
-}
-
-Oid
-get_typelem(Oid type_id)
-{
-   HeapTuple   typeTuple;
-   TypeTupleForm type;
-
-   if (!(typeTuple = SearchSysCacheTuple(TYPOID,
-                                         ObjectIdGetDatum(type_id),
-                                         0, 0, 0)))
-   {
-       elog(WARN, "type id lookup of %u failed", type_id);
-   }
-   type = (TypeTupleForm) GETSTRUCT(typeTuple);
-
-   return (type->typelem);
-}
-
-#ifdef NOT_USED
-char
-FindDelimiter(char *typename)
-{
-   char        delim;
-   HeapTuple   typeTuple;
-   TypeTupleForm type;
-
-
-   if (!(typeTuple = SearchSysCacheTuple(TYPNAME,
-                                         PointerGetDatum(typename),
-                                         0, 0, 0)))
-   {
-       elog(WARN, "type name lookup of %s failed", typename);
-   }
-   type = (TypeTupleForm) GETSTRUCT(typeTuple);
-
-   delim = type->typdelim;
-   return (delim);
-}
-
-#endif
-
-/*
- * Give a somewhat useful error message when the operator for two types
- * is not found.
- */
-static void
-op_error(char *op, Oid arg1, Oid arg2)
-{
-   Type        tp1 = NULL,
-               tp2 = NULL;
-
-   if (check_typeid(arg1))
-   {
-       tp1 = get_id_type(arg1);
-   }
-   else
-   {
-       elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
-   }
-
-   if (check_typeid(arg2))
-   {
-       tp2 = get_id_type(arg2);
-   }
-   else
-   {
-       elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
-   }
-
-   elog(NOTICE, "there is no operator %s for types %s and %s",
-        op, tname(tp1), tname(tp2));
-   elog(NOTICE, "You will either have to retype this query using an");
-   elog(NOTICE, "explicit cast, or you will have to define the operator");
-   elog(WARN, "%s for %s and %s using CREATE OPERATOR",
-        op, tname(tp1), tname(tp2));
-}
-
-/*
- * Error message when function lookup fails that gives details of the
- * argument types
- */
-void
-func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
-{
-   char        p[(NAMEDATALEN + 2) * MAXFMGRARGS],
-              *ptr;
-   int         i;
-
-   ptr = p;
-   *ptr = '\0';
-   for (i = 0; i < nargs; i++)
-   {
-       if (i)
-       {
-           *ptr++ = ',';
-           *ptr++ = ' ';
-       }
-       if (argtypes[i] != 0)
-       {
-           strcpy(ptr, tname(get_id_type(argtypes[i])));
-           *(ptr + NAMEDATALEN) = '\0';
-       }
-       else
-           strcpy(ptr, "opaque");
-       ptr += strlen(ptr);
-   }
-
-   elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);
-}
-
-/*
- * Error message when aggregate lookup fails that gives details of the
- * basetype
- */
-void
-agg_error(char *caller, char *aggname, Oid basetypeID)
-{
-
-   /*
-    * basetypeID that is Invalid (zero) means aggregate over all types.
-    * (count)
-    */
-
-   if (basetypeID == InvalidOid)
-   {
-       elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname);
-   }
-   else
-   {
-       elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
-            tname(get_id_type(basetypeID)));
-   }
-}
index abaedbb57bb725b0bdfe7a3ba60dcdba8e5f945b..d146b6e4ce1a5d5da861cc0c5893ab5b9aa973b5 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.71 1997/11/24 16:55:22 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.72 1997/11/25 22:05:29 momjian Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -39,8 +39,6 @@
 #include "nodes/parsenodes.h"
 #include "nodes/print.h"
 #include "parser/gramparse.h"
-#include "parser/catalog_utils.h"
-#include "parser/parse_query.h"
 #include "utils/acl.h"
 #include "catalog/catname.h"
 #include "utils/elog.h"
 static char saved_relname[NAMEDATALEN];  /* need this for complex attributes */
 static bool QueryIsRule = FALSE;
 static Node *saved_In_Expr;
+static Oid *param_type_info;
+static int pfunc_num_args;
 extern List *parsetree;
 
+
 /*
  * If you need access to certain yacc-generated variables and find that
  * they're static by default, uncomment the next line.  (this is not a
@@ -64,6 +65,9 @@ static List *makeConstantList( A_Const *node);
 static char *FlattenStringList(List *list);
 static char *fmtId(char *rawid);
 static Node *makeIndexable(char *opname, Node *lexpr, Node *rexpr);
+static void param_type_init(Oid *typev, int nargs);
+
+Oid    param_type(int t); /* used in parse_expr.c */
 
 /* old versions of flex define this as a macro */
 #if defined(yywrap)
@@ -2324,7 +2328,7 @@ Typename:  Array opt_array_bounds
                         * emp(name=text,mgr=emp)
                         */
                        $$->setof = TRUE;
-                   else if (get_typrelid((Type)type($$->name)) != InvalidOid)
+                   else if (typeTypeRelid(typenameType($$->name)) != InvalidOid)
                         /* (Eventually add in here that the set can only
                          * contain one element.)
                          */
@@ -3690,4 +3694,24 @@ printf("fmtId- %sconvert %s to %s\n", ((cp == rawid)? "do not ": ""), rawid, cp)
 #endif
 
    return(cp);
-} /* fmtId() */
+}
+
+/*
+ * param_type_init()
+ *
+ * keep enough information around fill out the type of param nodes
+ * used in postquel functions
+ */
+static void
+param_type_init(Oid *typev, int nargs)
+{
+   pfunc_num_args = nargs;
+   param_type_info = typev;
+}
+
+Oid param_type(int t)
+{
+   if ((t > pfunc_num_args) || (t == 0))
+       return InvalidOid;
+   return param_type_info[t - 1];
+}
index 0312e0251be1637c534c1b07730aedcad18af96d..1c4b63c44efdba6de4db29e3f3b3a29d55f04f91 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.24 1997/11/24 05:32:28 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.25 1997/11/25 22:05:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,8 @@
 #include "nodes/pg_list.h"
 #include "nodes/parsenodes.h"
 #include "parse.h"
-#include "utils/elog.h"
 #include "parser/keywords.h"
+#include "utils/elog.h"
 
 /*
  * List of (keyword-name, keyword-token-value) pairs.
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
new file mode 100644 (file)
index 0000000..b64b920
--- /dev/null
@@ -0,0 +1,371 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_agg.c--
+ *   handle aggregates in parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.1 1997/11/25 22:05:34 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include 
+#include 
+
+#include "postgres.h"
+#include "access/heapam.h"
+#include "catalog/pg_aggregate.h"
+#include "nodes/nodeFuncs.h"
+#include "nodes/primnodes.h"
+#include "nodes/relation.h"
+#include "optimizer/clauses.h"
+#include "parser/parse_agg.h"
+#include "parser/parse_node.h"
+#include "parser/parse_target.h"
+#include "utils/syscache.h"
+
+#ifdef 0
+#include "nodes/nodes.h"
+#include "nodes/params.h"
+#include "parse.h"             /* for AND, OR, etc. */
+#include "catalog/pg_type.h"   /* for INT4OID, etc. */
+#include "catalog/pg_proc.h"
+#include "utils/elog.h"
+#include "utils/builtins.h"        /* namecmp(), textout() */
+#include "utils/lsyscache.h"
+#include "utils/palloc.h"
+#include "utils/mcxt.h"
+#include "utils/acl.h"
+#include "nodes/makefuncs.h"   /* for makeResdom(), etc. */
+#include "commands/sequence.h"
+
+#endif
+
+/*
+ * AddAggToParseState -
+ *   add the aggregate to the list of unique aggregates in pstate.
+ *
+ * SIDE EFFECT: aggno in target list entry will be modified
+ */
+void
+AddAggToParseState(ParseState *pstate, Aggreg *aggreg)
+{
+   List       *ag;
+   int         i;
+
+   /*
+    * see if we have the aggregate already (we only need to record the
+    * aggregate once)
+    */
+   i = 0;
+   foreach(ag, pstate->p_aggs)
+   {
+       Aggreg     *a = lfirst(ag);
+
+       if (!strcmp(a->aggname, aggreg->aggname) &&
+           equal(a->target, aggreg->target))
+       {
+
+           /* fill in the aggno and we're done */
+           aggreg->aggno = i;
+           return;
+       }
+       i++;
+   }
+
+   /* not found, new aggregate */
+   aggreg->aggno = i;
+   pstate->p_numAgg++;
+   pstate->p_aggs = lappend(pstate->p_aggs, aggreg);
+   return;
+}
+
+/*
+ * finalizeAggregates -
+ *   fill in qry_aggs from pstate. Also checks to make sure that aggregates
+ *   are used in the proper place.
+ */
+void
+finalizeAggregates(ParseState *pstate, Query *qry)
+{
+   List       *l;
+   int         i;
+
+   parseCheckAggregates(pstate, qry);
+
+   qry->qry_numAgg = pstate->p_numAgg;
+   qry->qry_aggs =
+       (Aggreg **) palloc(sizeof(Aggreg *) * qry->qry_numAgg);
+   i = 0;
+   foreach(l, pstate->p_aggs)
+       qry->qry_aggs[i++] = (Aggreg *) lfirst(l);
+}
+
+/*
+ * contain_agg_clause--
+ *   Recursively find aggreg nodes from a clause.
+ *
+ *   Returns true if any aggregate found.
+ */
+bool
+contain_agg_clause(Node *clause)
+{
+   if (clause == NULL)
+       return FALSE;
+   else if (IsA(clause, Aggreg))
+       return TRUE;
+   else if (IsA(clause, Iter))
+       return contain_agg_clause(((Iter *) clause)->iterexpr);
+   else if (single_node(clause))
+       return FALSE;
+   else if (or_clause(clause))
+   {
+       List       *temp;
+
+       foreach(temp, ((Expr *) clause)->args)
+           if (contain_agg_clause(lfirst(temp)))
+           return TRUE;
+       return FALSE;
+   }
+   else if (is_funcclause(clause))
+   {
+       List       *temp;
+
+       foreach(temp, ((Expr *) clause)->args)
+           if (contain_agg_clause(lfirst(temp)))
+           return TRUE;
+       return FALSE;
+   }
+   else if (IsA(clause, ArrayRef))
+   {
+       List       *temp;
+
+       foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
+           if (contain_agg_clause(lfirst(temp)))
+           return TRUE;
+       foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
+           if (contain_agg_clause(lfirst(temp)))
+           return TRUE;
+       if (contain_agg_clause(((ArrayRef *) clause)->refexpr))
+           return TRUE;
+       if (contain_agg_clause(((ArrayRef *) clause)->refassgnexpr))
+           return TRUE;
+       return FALSE;
+   }
+   else if (not_clause(clause))
+       return contain_agg_clause((Node *) get_notclausearg((Expr *) clause));
+   else if (is_opclause(clause))
+       return (contain_agg_clause((Node *) get_leftop((Expr *) clause)) ||
+             contain_agg_clause((Node *) get_rightop((Expr *) clause)));
+
+   return FALSE;
+}
+
+/*
+ * exprIsAggOrGroupCol -
+ *   returns true if the expression does not contain non-group columns.
+ */
+bool
+exprIsAggOrGroupCol(Node *expr, List *groupClause)
+{
+   List       *gl;
+
+   if (expr == NULL || IsA(expr, Const) ||
+       IsA(expr, Param) ||IsA(expr, Aggreg))
+       return TRUE;
+
+   foreach(gl, groupClause)
+   {
+       GroupClause *grpcl = lfirst(gl);
+
+       if (equal(expr, grpcl->entry->expr))
+           return TRUE;
+   }
+
+   if (IsA(expr, Expr))
+   {
+       List       *temp;
+
+       foreach(temp, ((Expr *) expr)->args)
+           if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
+           return FALSE;
+       return TRUE;
+   }
+
+   return FALSE;
+}
+
+/*
+ * tleIsAggOrGroupCol -
+ *   returns true if the TargetEntry is Agg or GroupCol.
+ */
+bool
+tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
+{
+   Node       *expr = tle->expr;
+   List       *gl;
+
+   if (expr == NULL || IsA(expr, Const) ||IsA(expr, Param))
+       return TRUE;
+
+   foreach(gl, groupClause)
+   {
+       GroupClause *grpcl = lfirst(gl);
+
+       if (tle->resdom->resno == grpcl->entry->resdom->resno)
+       {
+           if (contain_agg_clause((Node *) expr))
+               elog(WARN, "parser: aggregates not allowed in GROUP BY clause");
+           return TRUE;
+       }
+   }
+
+   if (IsA(expr, Aggreg))
+       return TRUE;
+
+   if (IsA(expr, Expr))
+   {
+       List       *temp;
+
+       foreach(temp, ((Expr *) expr)->args)
+           if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
+           return FALSE;
+       return TRUE;
+   }
+
+   return FALSE;
+}
+
+/*
+ * parseCheckAggregates -
+ *   this should really be done earlier but the current grammar
+ *   cannot differentiate functions from aggregates. So we have do check
+ *   here when the target list and the qualifications are finalized.
+ */
+void
+parseCheckAggregates(ParseState *pstate, Query *qry)
+{
+   List       *tl;
+
+   Assert(pstate->p_numAgg > 0);
+
+   /*
+    * aggregates never appear in WHERE clauses. (we have to check where
+    * clause first because if there is an aggregate, the check for
+    * non-group column in target list may fail.)
+    */
+   if (contain_agg_clause(qry->qual))
+       elog(WARN, "parser: aggregates not allowed in WHERE clause");
+
+   /*
+    * the target list can only contain aggregates, group columns and
+    * functions thereof.
+    */
+   foreach(tl, qry->targetList)
+   {
+       TargetEntry *tle = lfirst(tl);
+
+       if (!tleIsAggOrGroupCol(tle, qry->groupClause))
+           elog(WARN,
+                "parser: illegal use of aggregates or non-group column in target list");
+   }
+
+   /*
+    * the expression specified in the HAVING clause has the same
+    * restriction as those in the target list.
+    */
+/*
+ * Need to change here when we get HAVING works. Currently
+ * qry->havingQual is NULL.        - vadim 04/05/97
+   if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
+       elog(WARN,
+            "parser: illegal use of aggregates or non-group column in HAVING clause");
+ */
+   return;
+}
+
+
+Aggreg    *
+ParseAgg(char *aggname, Oid basetype, Node *target)
+{
+   Oid         fintype;
+   Oid         vartype;
+   Oid         xfn1;
+   Form_pg_aggregate aggform;
+   Aggreg     *aggreg;
+   HeapTuple   theAggTuple;
+
+   theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
+                                     ObjectIdGetDatum(basetype),
+                                     0, 0);
+   if (!HeapTupleIsValid(theAggTuple))
+   {
+       elog(WARN, "aggregate %s does not exist", aggname);
+   }
+
+   aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
+   fintype = aggform->aggfinaltype;
+   xfn1 = aggform->aggtransfn1;
+
+   if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
+       elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
+
+   /* only aggregates with transfn1 need a base type */
+   if (OidIsValid(xfn1))
+   {
+       basetype = aggform->aggbasetype;
+       if (nodeTag(target) == T_Var)
+           vartype = ((Var *) target)->vartype;
+       else
+           vartype = ((Expr *) target)->typeOid;
+
+       if (basetype != vartype)
+       {
+           Type        tp1,
+                       tp2;
+
+           tp1 = typeidType(basetype);
+           tp2 = typeidType(vartype);
+           elog(NOTICE, "Aggregate type mismatch:");
+           elog(WARN, "%s works on %s, not %s", aggname,
+                typeTypeName(tp1), typeTypeName(tp2));
+       }
+   }
+
+   aggreg = makeNode(Aggreg);
+   aggreg->aggname = pstrdup(aggname);
+   aggreg->basetype = aggform->aggbasetype;
+   aggreg->aggtype = fintype;
+
+   aggreg->target = target;
+
+   return aggreg;
+}
+
+/*
+ * Error message when aggregate lookup fails that gives details of the
+ * basetype
+ */
+void
+agg_error(char *caller, char *aggname, Oid basetypeID)
+{
+
+   /*
+    * basetypeID that is Invalid (zero) means aggregate over all types.
+    * (count)
+    */
+
+   if (basetypeID == InvalidOid)
+   {
+       elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname);
+   }
+   else
+   {
+       elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
+            typeidTypeName(basetypeID));
+   }
+}
+
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
new file mode 100644 (file)
index 0000000..8e08e00
--- /dev/null
@@ -0,0 +1,407 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_clause.c--
+ *   handle clauses in parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.1 1997/11/25 22:05:35 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include 
+#include 
+#include "postgres.h"
+#include "access/heapam.h"
+#include "parser/parse_clause.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_node.h"
+#include "parser/parse_oper.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "catalog/pg_type.h"
+
+#ifdef 0
+#include "nodes/nodes.h"
+#include "nodes/params.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#include "nodes/relation.h"
+#include "parse.h"             /* for AND, OR, etc. */
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_proc.h"
+#include "utils/elog.h"
+#include "utils/builtins.h"        /* namecmp(), textout() */
+#include "utils/lsyscache.h"
+#include "utils/palloc.h"
+#include "utils/mcxt.h"
+#include "utils/syscache.h"
+#include "utils/acl.h"
+#include "nodes/makefuncs.h"   /* for makeResdom(), etc. */
+#include "nodes/nodeFuncs.h"
+#include "commands/sequence.h"
+
+#include "optimizer/clauses.h"
+
+#include "miscadmin.h"
+
+#include "port-protos.h"       /* strdup() */
+#endif
+
+/*
+ * parseFromClause -
+ *   turns the table references specified in the from-clause into a
+ *   range table. The range table may grow as we transform the expressions
+ *   in the target list. (Note that this happens because in POSTQUEL, we
+ *   allow references to relations not specified in the from-clause. We
+ *   also allow that in our POST-SQL)
+ *
+ */
+void
+parseFromClause(ParseState *pstate, List *frmList)
+{
+   List       *fl;
+
+   foreach(fl, frmList)
+   {
+       RangeVar   *r = lfirst(fl);
+       RelExpr    *baserel = r->relExpr;
+       char       *relname = baserel->relname;
+       char       *refname = r->name;
+       RangeTblEntry *rte;
+
+       if (refname == NULL)
+           refname = relname;
+
+       /*
+        * marks this entry to indicate it comes from the FROM clause. In
+        * SQL, the target list can only refer to range variables
+        * specified in the from clause but we follow the more powerful
+        * POSTQUEL semantics and automatically generate the range
+        * variable if not specified. However there are times we need to
+        * know whether the entries are legitimate.
+        *
+        * eg. select * from foo f where f.x = 1; will generate wrong answer
+        * if we expand * to foo.x.
+        */
+       rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE);
+   }
+}
+
+/*
+ * makeRangeTable -
+ *   make a range table with the specified relation (optional) and the
+ *   from-clause.
+ */
+void
+makeRangeTable(ParseState *pstate, char *relname, List *frmList)
+{
+   RangeTblEntry *rte;
+
+   parseFromClause(pstate, frmList);
+
+   if (relname == NULL)
+       return;
+
+   if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
+       rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE);
+   else
+       rte = refnameRangeTableEntry(pstate->p_rtable, relname);
+
+   pstate->p_target_rangetblentry = rte;
+   Assert(pstate->p_target_relation == NULL);
+   pstate->p_target_relation = heap_open(rte->relid);
+   Assert(pstate->p_target_relation != NULL);
+   /* will close relation later */
+}
+
+/*****************************************************************************
+ *
+ * Where Clause
+ *
+ *****************************************************************************/
+
+/*
+ * transformWhereClause -
+ *   transforms the qualification and make sure it is of type Boolean
+ *
+ */
+Node *
+transformWhereClause(ParseState *pstate, Node *a_expr)
+{
+   Node       *qual;
+
+   if (a_expr == NULL)
+       return (Node *) NULL;   /* no qualifiers */
+
+   pstate->p_in_where_clause = true;
+   qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
+   pstate->p_in_where_clause = false;
+   if (exprType(qual) != BOOLOID)
+   {
+       elog(WARN,
+            "where clause must return type bool, not %s",
+            typeidTypeName(exprType(qual)));
+   }
+   return qual;
+}
+
+/*****************************************************************************
+ *
+ * Sort Clause
+ *
+ *****************************************************************************/
+
+/*
+ * find_targetlist_entry -
+ *   returns the Resdom in the target list matching the specified varname
+ *   and range
+ *
+ */
+TargetEntry *
+find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
+{
+   List       *i;
+   int         real_rtable_pos = 0,
+               target_pos = 0;
+   TargetEntry *target_result = NULL;
+
+   if (sortgroupby->range)
+       real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
+                                               sortgroupby->range);
+
+   foreach(i, tlist)
+   {
+       TargetEntry *target = (TargetEntry *) lfirst(i);
+       Resdom     *resnode = target->resdom;
+       Var        *var = (Var *) target->expr;
+       char       *resname = resnode->resname;
+       int         test_rtable_pos = var->varno;
+
+#ifdef PARSEDEBUG
+       printf("find_targetlist_entry- target name is %s, position %d, resno %d\n",
+              (sortgroupby->name ? sortgroupby->name : "(null)"), target_pos + 1, sortgroupby->resno);
+#endif
+
+       if (!sortgroupby->name)
+       {
+           if (sortgroupby->resno == ++target_pos)
+           {
+               target_result = target;
+               break;
+           }
+       }
+       else
+       {
+           if (!strcmp(resname, sortgroupby->name))
+           {
+               if (sortgroupby->range)
+               {
+                   if (real_rtable_pos == test_rtable_pos)
+                   {
+                       if (target_result != NULL)
+                           elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
+                       else
+                           target_result = target;
+                   }
+               }
+               else
+               {
+                   if (target_result != NULL)
+                       elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
+                   else
+                       target_result = target;
+               }
+           }
+       }
+   }
+   return target_result;
+}
+
+/*
+ * transformGroupClause -
+ *   transform a Group By clause
+ *
+ */
+List *
+transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
+{
+   List       *glist = NIL,
+              *gl = NIL;
+
+   while (grouplist != NIL)
+   {
+       GroupClause *grpcl = makeNode(GroupClause);
+       TargetEntry *restarget;
+       Resdom     *resdom;
+
+       restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
+
+       if (restarget == NULL)
+           elog(WARN, "The field being grouped by must appear in the target list");
+
+       grpcl->entry = restarget;
+       resdom = restarget->resdom;
+       grpcl->grpOpoid = oprid(oper("<",
+                                    resdom->restype,
+                                    resdom->restype, false));
+       if (glist == NIL)
+           gl = glist = lcons(grpcl, NIL);
+       else
+       {
+           List       *i;
+           
+           foreach (i, glist)
+           {
+               GroupClause *gcl = (GroupClause *) lfirst (i);
+               
+               if ( gcl->entry == grpcl->entry )
+                   break;
+           }
+           if ( i == NIL )         /* not in grouplist already */
+           {
+               lnext(gl) = lcons(grpcl, NIL);
+               gl = lnext(gl);
+           }
+           else
+               pfree (grpcl);      /* get rid of this */
+       }
+       grouplist = lnext(grouplist);
+   }
+
+   return glist;
+}
+
+/*
+ * transformSortClause -
+ *   transform an Order By clause
+ *
+ */
+List *
+transformSortClause(ParseState *pstate,
+                   List *orderlist, List *targetlist,
+                   char *uniqueFlag)
+{
+   List       *sortlist = NIL;
+   List       *s = NIL;
+
+   while (orderlist != NIL)
+   {
+       SortGroupBy *sortby = lfirst(orderlist);
+       SortClause *sortcl = makeNode(SortClause);
+       TargetEntry *restarget;
+       Resdom     *resdom;
+
+       restarget = find_targetlist_entry(pstate, sortby, targetlist);
+       if (restarget == NULL)
+           elog(WARN, "The field being ordered by must appear in the target list");
+
+       sortcl->resdom = resdom = restarget->resdom;
+       sortcl->opoid = oprid(oper(sortby->useOp,
+                                  resdom->restype,
+                                  resdom->restype, false));
+       if (sortlist == NIL)
+       {
+           s = sortlist = lcons(sortcl, NIL);
+       }
+       else
+       {
+           List       *i;
+           
+           foreach (i, sortlist)
+           {
+               SortClause *scl = (SortClause *) lfirst (i);
+               
+               if ( scl->resdom == sortcl->resdom )
+                   break;
+           }
+           if ( i == NIL )         /* not in sortlist already */
+           {
+               lnext(s) = lcons(sortcl, NIL);
+               s = lnext(s);
+           }
+           else
+               pfree (sortcl);     /* get rid of this */
+       }
+       orderlist = lnext(orderlist);
+   }
+
+   if (uniqueFlag)
+   {
+       List       *i;
+       
+       if (uniqueFlag[0] == '*')
+       {
+
+           /*
+            * concatenate all elements from target list that are not
+            * already in the sortby list
+            */
+           foreach(i, targetlist)
+           {
+               TargetEntry *tlelt = (TargetEntry *) lfirst(i);
+
+               s = sortlist;
+               while (s != NIL)
+               {
+                   SortClause *sortcl = lfirst(s);
+
+                   if (sortcl->resdom == tlelt->resdom)
+                       break;
+                   s = lnext(s);
+               }
+               if (s == NIL)
+               {
+                   /* not a member of the sortclauses yet */
+                   SortClause *sortcl = makeNode(SortClause);
+
+                   sortcl->resdom = tlelt->resdom;
+                   sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
+
+                   sortlist = lappend(sortlist, sortcl);
+               }
+           }
+       }
+       else
+       {
+           TargetEntry *tlelt = NULL;
+           char       *uniqueAttrName = uniqueFlag;
+
+           /* only create sort clause with the specified unique attribute */
+           foreach(i, targetlist)
+           {
+               tlelt = (TargetEntry *) lfirst(i);
+               if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
+                   break;
+           }
+           if (i == NIL)
+           {
+               elog(WARN, "The field specified in the UNIQUE ON clause is not in the targetlist");
+           }
+           s = sortlist;
+           foreach(s, sortlist)
+           {
+               SortClause *sortcl = lfirst(s);
+
+               if (sortcl->resdom == tlelt->resdom)
+                   break;
+           }
+           if (s == NIL)
+           {
+               /* not a member of the sortclauses yet */
+               SortClause *sortcl = makeNode(SortClause);
+
+               sortcl->resdom = tlelt->resdom;
+               sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
+
+               sortlist = lappend(sortlist, sortcl);
+           }
+       }
+
+   }
+
+   return sortlist;
+}
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
new file mode 100644 (file)
index 0000000..fe00b2b
--- /dev/null
@@ -0,0 +1,694 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_expr.c
+ *   handle expressions in parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.1 1997/11/25 22:05:39 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include 
+#include 
+
+#include "postgres.h"
+#include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
+#include "nodes/nodes.h"
+#include "nodes/params.h"
+#include "nodes/relation.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_func.h"
+#include "parser/parse_node.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "parse.h"
+#include "utils/builtins.h"
+
+#ifdef 0
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_proc.h"
+#include "utils/elog.h"
+#include "utils/lsyscache.h"
+#include "utils/palloc.h"
+#include "utils/mcxt.h"
+#include "utils/syscache.h"
+#include "utils/acl.h"
+#include "nodes/nodeFuncs.h"
+#include "commands/sequence.h"
+
+#include "optimizer/clauses.h"
+#include "access/heapam.h"
+
+#include "miscadmin.h"
+#endif
+
+Oid param_type(int t); /* from gram.y */
+
+/*
+ * transformExpr -
+ *   analyze and transform expressions. Type checking and type casting is
+ *   done here. The optimizer and the executor cannot handle the original
+ *   (raw) expressions collected by the parse tree. Hence the transformation
+ *   here.
+ */
+Node *
+transformExpr(ParseState *pstate, Node *expr, int precedence)
+{
+   Node       *result = NULL;
+
+   if (expr == NULL)
+       return NULL;
+
+   switch (nodeTag(expr))
+   {
+       case T_Attr:
+           {
+               Attr       *att = (Attr *) expr;
+               Node       *temp;
+
+               /* what if att.attrs == "*"?? */
+               temp = handleNestedDots(pstate, att, &pstate->p_last_resno);
+               if (att->indirection != NIL)
+               {
+                   List       *idx = att->indirection;
+
+                   while (idx != NIL)
+                   {
+                       A_Indices  *ai = (A_Indices *) lfirst(idx);
+                       Node       *lexpr = NULL,
+                                  *uexpr;
+
+                       uexpr = transformExpr(pstate, ai->uidx, precedence);    /* must exists */
+                       if (exprType(uexpr) != INT4OID)
+                           elog(WARN, "array index expressions must be int4's");
+                       if (ai->lidx != NULL)
+                       {
+                           lexpr = transformExpr(pstate, ai->lidx, precedence);
+                           if (exprType(lexpr) != INT4OID)
+                               elog(WARN, "array index expressions must be int4's");
+                       }
+#if 0
+                       pfree(ai->uidx);
+                       if (ai->lidx != NULL)
+                           pfree(ai->lidx);
+#endif
+                       ai->lidx = lexpr;
+                       ai->uidx = uexpr;
+
+                       /*
+                        * note we reuse the list of indices, make sure we
+                        * don't free them! Otherwise, make a new list
+                        * here
+                        */
+                       idx = lnext(idx);
+                   }
+                   result = (Node *) make_array_ref(temp, att->indirection);
+               }
+               else
+               {
+                   result = temp;
+               }
+               break;
+           }
+       case T_A_Const:
+           {
+               A_Const    *con = (A_Const *) expr;
+               Value      *val = &con->val;
+
+               if (con->typename != NULL)
+               {
+                   result = parser_typecast(val, con->typename, -1);
+               }
+               else
+               {
+                   result = (Node *) make_const(val);
+               }
+               break;
+           }
+       case T_ParamNo:
+           {
+               ParamNo    *pno = (ParamNo *) expr;
+               Oid         toid;
+               int         paramno;
+               Param      *param;
+
+               paramno = pno->number;
+               toid = param_type(paramno);
+               if (!OidIsValid(toid))
+               {
+                   elog(WARN, "Parameter '$%d' is out of range",
+                        paramno);
+               }
+               param = makeNode(Param);
+               param->paramkind = PARAM_NUM;
+               param->paramid = (AttrNumber) paramno;
+               param->paramname = "";
+               param->paramtype = (Oid) toid;
+               param->param_tlist = (List *) NULL;
+
+               result = (Node *) param;
+               break;
+           }
+       case T_A_Expr:
+           {
+               A_Expr     *a = (A_Expr *) expr;
+
+               switch (a->oper)
+               {
+                   case OP:
+                       {
+                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
+                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+                           result = (Node *) make_op(a->opname, lexpr, rexpr);
+                       }
+                       break;
+                   case ISNULL:
+                       {
+                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
+
+                           result = ParseFunc(pstate,
+                                         "nullvalue", lcons(lexpr, NIL),
+                                              &pstate->p_last_resno);
+                       }
+                       break;
+                   case NOTNULL:
+                       {
+                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
+
+                           result = ParseFunc(pstate,
+                                      "nonnullvalue", lcons(lexpr, NIL),
+                                              &pstate->p_last_resno);
+                       }
+                       break;
+                   case AND:
+                       {
+                           Expr       *expr = makeNode(Expr);
+                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
+                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+                           if (exprType(lexpr) != BOOLOID)
+                               elog(WARN,
+                                    "left-hand side of AND is type '%s', not bool",
+                                    typeidTypeName(exprType(lexpr)));
+                           if (exprType(rexpr) != BOOLOID)
+                               elog(WARN,
+                                    "right-hand side of AND is type '%s', not bool",
+                                    typeidTypeName(exprType(rexpr)));
+                           expr->typeOid = BOOLOID;
+                           expr->opType = AND_EXPR;
+                           expr->args = makeList(lexpr, rexpr, -1);
+                           result = (Node *) expr;
+                       }
+                       break;
+                   case OR:
+                       {
+                           Expr       *expr = makeNode(Expr);
+                           Node       *lexpr = transformExpr(pstate, a->lexpr, precedence);
+                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+                           if (exprType(lexpr) != BOOLOID)
+                               elog(WARN,
+                                    "left-hand side of OR is type '%s', not bool",
+                                    typeidTypeName(exprType(lexpr)));
+                           if (exprType(rexpr) != BOOLOID)
+                               elog(WARN,
+                                    "right-hand side of OR is type '%s', not bool",
+                                    typeidTypeName(exprType(rexpr)));
+                           expr->typeOid = BOOLOID;
+                           expr->opType = OR_EXPR;
+                           expr->args = makeList(lexpr, rexpr, -1);
+                           result = (Node *) expr;
+                       }
+                       break;
+                   case NOT:
+                       {
+                           Expr       *expr = makeNode(Expr);
+                           Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+                           if (exprType(rexpr) != BOOLOID)
+                               elog(WARN,
+                               "argument to NOT is type '%s', not bool",
+                                    typeidTypeName(exprType(rexpr)));
+                           expr->typeOid = BOOLOID;
+                           expr->opType = NOT_EXPR;
+                           expr->args = makeList(rexpr, -1);
+                           result = (Node *) expr;
+                       }
+                       break;
+               }
+               break;
+           }
+       case T_Ident:
+           {
+
+               /*
+                * look for a column name or a relation name (the default
+                * behavior)
+                */
+               result = transformIdent(pstate, expr, precedence);
+               break;
+           }
+       case T_FuncCall:
+           {
+               FuncCall   *fn = (FuncCall *) expr;
+               List       *args;
+
+               /* transform the list of arguments */
+               foreach(args, fn->args)
+                   lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);
+               result = ParseFunc(pstate,
+                         fn->funcname, fn->args, &pstate->p_last_resno);
+               break;
+           }
+       default:
+           /* should not reach here */
+           elog(WARN, "transformExpr: does not know how to transform %d\n",
+                nodeTag(expr));
+           break;
+   }
+
+   return result;
+}
+
+Node *
+transformIdent(ParseState *pstate, Node *expr, int precedence)
+{
+   Ident      *ident = (Ident *) expr;
+   RangeTblEntry *rte;
+   Node       *column_result,
+              *relation_result,
+              *result;
+
+   column_result = relation_result = result = 0;
+   /* try to find the ident as a column */
+   if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
+   {
+       Attr       *att = makeNode(Attr);
+
+       att->relname = rte->refname;
+       att->attrs = lcons(makeString(ident->name), NIL);
+       column_result =
+           (Node *) handleNestedDots(pstate, att, &pstate->p_last_resno);
+   }
+
+   /* try to find the ident as a relation */
+   if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL)
+   {
+       ident->isRel = TRUE;
+       relation_result = (Node *) ident;
+   }
+
+   /* choose the right result based on the precedence */
+   if (precedence == EXPR_COLUMN_FIRST)
+   {
+       if (column_result)
+           result = column_result;
+       else
+           result = relation_result;
+   }
+   else
+   {
+       if (relation_result)
+           result = relation_result;
+       else
+           result = column_result;
+   }
+
+   if (result == NULL)
+       elog(WARN, "attribute '%s' not found", ident->name);
+
+   return result;
+}
+
+/*
+ * exprType -
+ *   returns the Oid of the type of the expression. (Used for typechecking.)
+ */
+Oid
+exprType(Node *expr)
+{
+   Oid         type = (Oid) 0;
+
+   switch (nodeTag(expr))
+   {
+       case T_Func:
+           type = ((Func *) expr)->functype;
+           break;
+       case T_Iter:
+           type = ((Iter *) expr)->itertype;
+           break;
+       case T_Var:
+           type = ((Var *) expr)->vartype;
+           break;
+       case T_Expr:
+           type = ((Expr *) expr)->typeOid;
+           break;
+       case T_Const:
+           type = ((Const *) expr)->consttype;
+           break;
+       case T_ArrayRef:
+           type = ((ArrayRef *) expr)->refelemtype;
+           break;
+       case T_Aggreg:
+           type = ((Aggreg *) expr)->aggtype;
+           break;
+       case T_Param:
+           type = ((Param *) expr)->paramtype;
+           break;
+       case T_Ident:
+           /* is this right? */
+           type = UNKNOWNOID;
+           break;
+       default:
+           elog(WARN, "exprType: don't know how to get type for %d node",
+                nodeTag(expr));
+           break;
+   }
+   return type;
+}
+
+/*
+ ** HandleNestedDots --
+ **    Given a nested dot expression (i.e. (relation func ... attr), build up
+ ** a tree with of Iter and Func nodes.
+ */
+Node *
+handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno)
+{
+   List       *mutator_iter;
+   Node       *retval = NULL;
+
+   if (attr->paramNo != NULL)
+   {
+       Param      *param = (Param *) transformExpr(pstate, (Node *) attr->paramNo, EXPR_RELATION_FIRST);
+
+       retval =
+           ParseFunc(pstate, strVal(lfirst(attr->attrs)),
+                     lcons(param, NIL),
+                     curr_resno);
+   }
+   else
+   {
+       Ident      *ident = makeNode(Ident);
+
+       ident->name = attr->relname;
+       ident->isRel = TRUE;
+       retval =
+           ParseFunc(pstate, strVal(lfirst(attr->attrs)),
+                     lcons(ident, NIL),
+                     curr_resno);
+   }
+
+   foreach(mutator_iter, lnext(attr->attrs))
+   {
+       retval = ParseFunc(pstate, strVal(lfirst(mutator_iter)),
+                          lcons(retval, NIL),
+                          curr_resno);
+   }
+
+   return (retval);
+}
+
+Node      *
+parser_typecast(Value *expr, TypeName *typename, int typlen)
+{
+   /* check for passing non-ints */
+   Const      *adt;
+   Datum       lcp;
+   Type        tp;
+   char        type_string[NAMEDATALEN];
+   int32       len;
+   char       *cp = NULL;
+   char       *const_string = NULL;
+   bool        string_palloced = false;
+
+   switch (nodeTag(expr))
+   {
+       case T_String:
+           const_string = DatumGetPointer(expr->val.str);
+           break;
+       case T_Integer:
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%ld", expr->val.ival);
+           break;
+       default:
+           elog(WARN,
+           "parser_typecast: cannot cast this expression to type \"%s\"",
+                typename->name);
+   }
+
+   if (typename->arrayBounds != NIL)
+   {
+       sprintf(type_string, "_%s", typename->name);
+       tp = (Type) typenameType(type_string);
+   }
+   else
+   {
+       tp = (Type) typenameType(typename->name);
+   }
+
+   len = typeLen(tp);
+
+#if 0                          /* fix me */
+   switch (CInteger(lfirst(expr)))
+   {
+       case INT4OID:           /* int4 */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue);
+           break;
+
+       case NAMEOID:           /* char16 */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue);
+           break;
+
+       case CHAROID:           /* char */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue);
+           break;
+
+       case FLOAT8OID: /* float8 */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue);
+           break;
+
+       case CASHOID:           /* money */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%d",
+                   (int) ((Const *) expr)->constvalue);
+           break;
+
+       case TEXTOID:           /* text */
+           const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
+           const_string = (char *) textout((struct varlena *) const_string);
+           break;
+
+       case UNKNOWNOID:        /* unknown */
+           const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
+           const_string = (char *) textout((struct varlena *) const_string);
+           break;
+
+       default:
+           elog(WARN, "unknown type %d", CInteger(lfirst(expr)));
+   }
+#endif
+
+   cp = stringTypeString(tp, const_string, typlen);
+
+   if (!typeByVal(tp))
+   {
+/*
+       if (len >= 0 && len != PSIZE(cp)) {
+           char *pp;
+           pp = (char *) palloc(len);
+           memmove(pp, cp, len);
+           cp = pp;
+       }
+*/
+       lcp = PointerGetDatum(cp);
+   }
+   else
+   {
+       switch (len)
+       {
+           case 1:
+               lcp = Int8GetDatum(cp);
+               break;
+           case 2:
+               lcp = Int16GetDatum(cp);
+               break;
+           case 4:
+               lcp = Int32GetDatum(cp);
+               break;
+           default:
+               lcp = PointerGetDatum(cp);
+               break;
+       }
+   }
+
+   adt = makeConst(typeTypeId(tp),
+                   len,
+                   (Datum) lcp,
+                   false,
+                   typeByVal(tp),
+                   false,      /* not a set */
+                   true /* is cast */ );
+
+   if (string_palloced)
+       pfree(const_string);
+
+   return (Node *) adt;
+}
+
+Node      *
+parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen)
+{
+   /* check for passing non-ints */
+   Const      *adt;
+   Datum       lcp;
+   int32       len = typeLen(tp);
+   char       *cp = NULL;
+
+   char       *const_string = NULL;
+   bool        string_palloced = false;
+
+   Assert(IsA(expr, Const));
+
+   switch (exprType)
+   {
+       case 0:         /* NULL */
+           break;
+       case INT4OID:           /* int4 */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%d",
+                   (int) ((Const *) expr)->constvalue);
+           break;
+       case NAMEOID:           /* char16 */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%s",
+                   (char *) ((Const *) expr)->constvalue);
+           break;
+       case CHAROID:           /* char */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%c",
+                   (char) ((Const *) expr)->constvalue);
+           break;
+       case FLOAT4OID: /* float4 */
+           {
+               float32     floatVal =
+               DatumGetFloat32(((Const *) expr)->constvalue);
+
+               const_string = (char *) palloc(256);
+               string_palloced = true;
+               sprintf(const_string, "%f", *floatVal);
+               break;
+           }
+       case FLOAT8OID: /* float8 */
+           {
+               float64     floatVal =
+               DatumGetFloat64(((Const *) expr)->constvalue);
+
+               const_string = (char *) palloc(256);
+               string_palloced = true;
+               sprintf(const_string, "%f", *floatVal);
+               break;
+           }
+       case CASHOID:           /* money */
+           const_string = (char *) palloc(256);
+           string_palloced = true;
+           sprintf(const_string, "%ld",
+                   (long) ((Const *) expr)->constvalue);
+           break;
+       case TEXTOID:           /* text */
+           const_string =
+               DatumGetPointer(((Const *) expr)->constvalue);
+           const_string = (char *) textout((struct varlena *) const_string);
+           break;
+       case UNKNOWNOID:        /* unknown */
+           const_string =
+               DatumGetPointer(((Const *) expr)->constvalue);
+           const_string = (char *) textout((struct varlena *) const_string);
+           break;
+       default:
+           elog(WARN, "unknown type %u ", exprType);
+   }
+
+   if (!exprType)
+   {
+       adt = makeConst(typeTypeId(tp),
+                       (Size) 0,
+                       (Datum) NULL,
+                       true,   /* isnull */
+                       false,  /* was omitted */
+                       false,  /* not a set */
+                       true /* is cast */ );
+       return ((Node *) adt);
+   }
+
+   cp = stringTypeString(tp, const_string, typlen);
+
+
+   if (!typeByVal(tp))
+   {
+/*
+       if (len >= 0 && len != PSIZE(cp)) {
+           char *pp;
+           pp = (char *) palloc(len);
+           memmove(pp, cp, len);
+           cp = pp;
+       }
+*/
+       lcp = PointerGetDatum(cp);
+   }
+   else
+   {
+       switch (len)
+       {
+           case 1:
+               lcp = Int8GetDatum(cp);
+               break;
+           case 2:
+               lcp = Int16GetDatum(cp);
+               break;
+           case 4:
+               lcp = Int32GetDatum(cp);
+               break;
+           default:
+               lcp = PointerGetDatum(cp);
+               break;
+       }
+   }
+
+   adt = makeConst(typeTypeId(tp),
+                   (Size) len,
+                   (Datum) lcp,
+                   false,
+                   false,      /* was omitted */
+                   false,      /* not a set */
+                   true /* is cast */ );
+
+   /*
+    * printf("adt %s : %u %d %d\n",CString(expr),typeTypeId(tp) , len,cp);
+    */
+   if (string_palloced)
+       pfree(const_string);
+
+   return ((Node *) adt);
+} 
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
new file mode 100644 (file)
index 0000000..bb2a777
--- /dev/null
@@ -0,0 +1,1264 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_func.c
+ *     handle function calls in parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.1 1997/11/25 22:05:41 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include "postgres.h"
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "access/itup.h"
+#include "access/relscan.h"
+#include "access/sdir.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_inherits.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "lib/dllist.h"
+#include "nodes/makefuncs.h"
+#include "nodes/relation.h"
+#include "parser/parse_agg.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_func.h"
+#include "parser/parse_node.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_type.h"
+#include "storage/bufmgr.h"
+#include "storage/lmgr.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+#ifdef 0
+#include "utils/datum.h"
+
+#include "utils/elog.h"
+#include "utils/palloc.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
+
+#include "catalog/pg_operator.h"
+#include "catalog/catname.h"
+
+#include "access/skey.h"
+#include "access/tupdesc.h"
+#include "access/htup.h"
+#include "access/genam.h"
+#include "access/itup.h"
+#include "access/tupmacs.h"
+
+#include "storage/buf.h"
+#endif
+
+#define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)
+
+#define MAXFARGS 8             /* max # args to a c or postquel function */
+
+typedef struct _SuperQE
+{
+   Oid         sqe_relid;
+} SuperQE;
+
+/*
+ * parse function
+ */
+
+Node *
+ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
+{
+   Oid         rettype = (Oid) 0;
+   Oid         argrelid = (Oid) 0;
+   Oid         funcid = (Oid) 0;
+   List       *i = NIL;
+   Node       *first_arg = NULL;
+   char       *relname = NULL;
+   char       *refname = NULL;
+   Relation    rd;
+   Oid         relid;
+   int         nargs;
+   Func       *funcnode;
+   Oid         oid_array[8];
+   Oid        *true_oid_array;
+   Node       *retval;
+   bool        retset;
+   bool        exists;
+   bool        attisset = false;
+   Oid         toid = (Oid) 0;
+   Expr       *expr;
+
+   if (fargs)
+   {
+       first_arg = lfirst(fargs);
+       if (first_arg == NULL)
+           elog(WARN, "function '%s' does not allow NULL input", funcname);
+   }
+
+   /*
+    * check for projection methods: if function takes one argument, and
+    * that argument is a relation, param, or PQ function returning a
+    * complex * type, then the function could be a projection.
+    */
+   if (length(fargs) == 1)
+   {
+
+       if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)
+       {
+           RangeTblEntry *rte;
+           Ident      *ident = (Ident *) first_arg;
+
+           /*
+            * first arg is a relation. This could be a projection.
+            */
+           refname = ident->name;
+
+           rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+           if (rte == NULL)
+               rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE);
+
+           relname = rte->relname;
+           relid = rte->relid;
+
+           /*
+            * If the attr isn't a set, just make a var for it.  If it is
+            * a set, treat it like a function and drop through.
+            */
+           if (get_attnum(relid, funcname) != InvalidAttrNumber)
+           {
+               Oid         dummyTypeId;
+
+               return
+                   ((Node *) make_var(pstate,
+                                      refname,
+                                      funcname,
+                                      &dummyTypeId));
+           }
+           else
+           {
+               /* drop through - attr is a set */
+               ;
+           }
+       }
+       else if (ISCOMPLEX(exprType(first_arg)))
+       {
+
+           /*
+            * Attempt to handle projection of a complex argument. If
+            * ParseComplexProjection can't handle the projection, we have
+            * to keep going.
+            */
+           retval = ParseComplexProjection(pstate,
+                                           funcname,
+                                           first_arg,
+                                           &attisset);
+           if (attisset)
+           {
+               toid = exprType(first_arg);
+               rd = heap_openr(typeidTypeName(toid));
+               if (RelationIsValid(rd))
+               {
+                   relname = RelationGetRelationName(rd)->data;
+                   heap_close(rd);
+               }
+               else
+                   elog(WARN,
+                        "Type '%s' is not a relation type",
+                        typeidTypeName(toid));
+               argrelid = typeidTypeRelid(toid);
+
+               /*
+                * A projection contains either an attribute name or the
+                * "*".
+                */
+               if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
+                   && strcmp(funcname, "*"))
+               {
+                   elog(WARN, "Functions on sets are not yet supported");
+               }
+           }
+
+           if (retval)
+               return retval;
+       }
+       else
+       {
+
+           /*
+            * Parsing aggregates.
+            */
+           Oid         basetype;
+
+           /*
+            * the aggregate count is a special case, ignore its base
+            * type.  Treat it as zero
+            */
+           if (strcmp(funcname, "count") == 0)
+               basetype = 0;
+           else
+               basetype = exprType(lfirst(fargs));
+           if (SearchSysCacheTuple(AGGNAME,
+                                   PointerGetDatum(funcname),
+                                   ObjectIdGetDatum(basetype),
+                                   0, 0))
+           {
+               Aggreg     *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
+
+               AddAggToParseState(pstate, aggreg);
+               return (Node *) aggreg;
+           }
+       }
+   }
+
+
+   /*
+    * * If we dropped through to here it's really a function (or a set,
+    * which * is implemented as a function.) * extract arg type info and
+    * transform relation name arguments into * varnodes of the
+    * appropriate form.
+    */
+   MemSet(&oid_array[0], 0, 8 * sizeof(Oid));
+
+   nargs = 0;
+   foreach(i, fargs)
+   {
+       int         vnum;
+       RangeTblEntry *rte;
+       Node       *pair = lfirst(i);
+
+       if (nodeTag(pair) == T_Ident && ((Ident *) pair)->isRel)
+       {
+
+           /*
+            * a relation
+            */
+           refname = ((Ident *) pair)->name;
+
+           rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+           if (rte == NULL)
+               rte = addRangeTableEntry(pstate, refname, refname,
+                                        FALSE, FALSE);
+           relname = rte->relname;
+
+           vnum = refnameRangeTablePosn(pstate->p_rtable, rte->refname);
+
+           /*
+            * for func(relname), the param to the function is the tuple
+            * under consideration.  we build a special VarNode to reflect
+            * this -- it has varno set to the correct range table entry,
+            * but has varattno == 0 to signal that the whole tuple is the
+            * argument.
+            */
+           toid = typeTypeId(typenameType(relname));
+           /* replace it in the arg list */
+           lfirst(fargs) =
+               makeVar(vnum, 0, toid, vnum, 0);
+       }
+       else if (!attisset)
+       {                       /* set functions don't have parameters */
+
+           /*
+            * any functiona args which are typed "unknown", but aren't
+            * constants, we don't know what to do with, because we can't
+            * cast them    - jolly
+            */
+           if (exprType(pair) == UNKNOWNOID &&
+               !IsA(pair, Const))
+           {
+               elog(WARN, "ParseFunc: no function named '%s' that takes in an unknown type as argument #%d", funcname, nargs);
+           }
+           else
+               toid = exprType(pair);
+       }
+
+       oid_array[nargs++] = toid;
+   }
+
+   /*
+    * func_get_detail looks up the function in the catalogs, does
+    * disambiguation for polymorphic functions, handles inheritance, and
+    * returns the funcid and type and set or singleton status of the
+    * function's return value.  it also returns the true argument types
+    * to the function.  if func_get_detail returns true, the function
+    * exists.  otherwise, there was an error.
+    */
+   if (attisset)
+   {                           /* we know all of these fields already */
+
+       /*
+        * We create a funcnode with a placeholder function SetEval.
+        * SetEval() never actually gets executed.  When the function
+        * evaluation routines see it, they use the funcid projected out
+        * from the relation as the actual function to call. Example:
+        * retrieve (emp.mgr.name) The plan for this will scan the emp
+        * relation, projecting out the mgr attribute, which is a funcid.
+        * This function is then called (instead of SetEval) and "name" is
+        * projected from its result.
+        */
+       funcid = SetEvalRegProcedure;
+       rettype = toid;
+       retset = true;
+       true_oid_array = oid_array;
+       exists = true;
+   }
+   else
+   {
+       exists = func_get_detail(funcname, nargs, oid_array, &funcid,
+                                &rettype, &retset, &true_oid_array);
+   }
+
+   if (!exists)
+       elog(WARN, "no such attribute or function '%s'", funcname);
+
+   /* got it */
+   funcnode = makeNode(Func);
+   funcnode->funcid = funcid;
+   funcnode->functype = rettype;
+   funcnode->funcisindex = false;
+   funcnode->funcsize = 0;
+   funcnode->func_fcache = NULL;
+   funcnode->func_tlist = NIL;
+   funcnode->func_planlist = NIL;
+
+   /* perform the necessary typecasting */
+   make_arguments(nargs, fargs, oid_array, true_oid_array);
+
+   /*
+    * for functions returning base types, we want to project out the
+    * return value.  set up a target list to do that.  the executor will
+    * ignore these for c functions, and do the right thing for postquel
+    * functions.
+    */
+
+   if (typeidTypeRelid(rettype) == InvalidOid)
+       funcnode->func_tlist = setup_base_tlist(rettype);
+
+   /*
+    * For sets, we want to make a targetlist to project out this
+    * attribute of the set tuples.
+    */
+   if (attisset)
+   {
+       if (!strcmp(funcname, "*"))
+       {
+           funcnode->func_tlist =
+               expandAll(pstate, relname, refname, curr_resno);
+       }
+       else
+       {
+           funcnode->func_tlist = setup_tlist(funcname, argrelid);
+           rettype = attnameTypeId(argrelid, funcname);
+       }
+   }
+
+   /*
+    * Sequence handling.
+    */
+   if (funcid == SeqNextValueRegProcedure ||
+       funcid == SeqCurrValueRegProcedure)
+   {
+       Const      *seq;
+       char       *seqrel;
+       text       *seqname;
+       int32       aclcheck_result = -1;
+       extern text *lower (text *string);
+
+       Assert(length(fargs) == 1);
+       seq = (Const *) lfirst(fargs);
+       if (!IsA((Node *) seq, Const))
+           elog(WARN, "%s: only constant sequence names are acceptable", funcname);
+       seqname = lower ((text*)DatumGetPointer(seq->constvalue));
+       pfree (DatumGetPointer(seq->constvalue));
+       seq->constvalue = PointerGetDatum (seqname);
+       seqrel = textout(seqname);
+
+       if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),
+              ((funcid == SeqNextValueRegProcedure) ? ACL_WR : ACL_RD)))
+           != ACLCHECK_OK)
+           elog(WARN, "%s.%s: %s",
+             seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
+
+       pfree(seqrel);
+
+       if (funcid == SeqNextValueRegProcedure && pstate->p_in_where_clause)
+           elog(WARN, "nextval of a sequence in WHERE disallowed");
+   }
+
+   expr = makeNode(Expr);
+   expr->typeOid = rettype;
+   expr->opType = FUNC_EXPR;
+   expr->oper = (Node *) funcnode;
+   expr->args = fargs;
+   retval = (Node *) expr;
+
+   /*
+    * if the function returns a set of values, then we need to iterate
+    * over all the returned values in the executor, so we stick an iter
+    * node here.  if it returns a singleton, then we don't need the iter
+    * node.
+    */
+
+   if (retset)
+   {
+       Iter       *iter = makeNode(Iter);
+
+       iter->itertype = rettype;
+       iter->iterexpr = retval;
+       retval = (Node *) iter;
+   }
+
+   return (retval);
+}
+
+Oid
+funcid_get_rettype(Oid funcid)
+{
+   HeapTuple   func_tuple = NULL;
+   Oid         funcrettype = (Oid) 0;
+
+   func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
+                                    0, 0, 0);
+
+   if (!HeapTupleIsValid(func_tuple))
+       elog(WARN, "function  %d does not exist", funcid);
+
+   funcrettype = (Oid)
+       ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
+
+   return (funcrettype);
+}
+
+/*
+ * get a list of all argument type vectors for which a function named
+ * funcname taking nargs arguments exists
+ */
+CandidateList
+func_get_candidates(char *funcname, int nargs)
+{
+   Relation    heapRelation;
+   Relation    idesc;
+   ScanKeyData skey;
+   HeapTuple   tuple;
+   IndexScanDesc sd;
+   RetrieveIndexResult indexRes;
+   Buffer      buffer;
+   Form_pg_proc pgProcP;
+   bool        bufferUsed = FALSE;
+   CandidateList candidates = NULL;
+   CandidateList current_candidate;
+   int         i;
+
+   heapRelation = heap_openr(ProcedureRelationName);
+   ScanKeyEntryInitialize(&skey,
+                          (bits16) 0x0,
+                          (AttrNumber) 1,
+                          (RegProcedure) NameEqualRegProcedure,
+                          (Datum) funcname);
+
+   idesc = index_openr(ProcedureNameIndex);
+
+   sd = index_beginscan(idesc, false, 1, &skey);
+
+   do
+   {
+       tuple = (HeapTuple) NULL;
+       if (bufferUsed)
+       {
+           ReleaseBuffer(buffer);
+           bufferUsed = FALSE;
+       }
+
+       indexRes = index_getnext(sd, ForwardScanDirection);
+       if (indexRes)
+       {
+           ItemPointer iptr;
+
+           iptr = &indexRes->heap_iptr;
+           tuple = heap_fetch(heapRelation, false, iptr, &buffer);
+           pfree(indexRes);
+           if (HeapTupleIsValid(tuple))
+           {
+               pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
+               bufferUsed = TRUE;
+               if (pgProcP->pronargs == nargs)
+               {
+                   current_candidate = (CandidateList)
+                       palloc(sizeof(struct _CandidateList));
+                   current_candidate->args = (Oid *)
+                       palloc(8 * sizeof(Oid));
+                   MemSet(current_candidate->args, 0, 8 * sizeof(Oid));
+                   for (i = 0; i < nargs; i++)
+                   {
+                       current_candidate->args[i] =
+                           pgProcP->proargtypes[i];
+                   }
+
+                   current_candidate->next = candidates;
+                   candidates = current_candidate;
+               }
+           }
+       }
+   } while (indexRes);
+
+   index_endscan(sd);
+   index_close(idesc);
+   heap_close(heapRelation);
+
+   return candidates;
+}
+
+/*
+ * can input_typeids be coerced to func_typeids?
+ */
+bool
+can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
+{
+   int         i;
+   Type        tp;
+
+   /*
+    * right now, we only coerce "unknown", and we cannot coerce it to a
+    * relation type
+    */
+   for (i = 0; i < nargs; i++)
+   {
+       if (input_typeids[i] != func_typeids[i])
+       {
+           if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) ||
+               (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) ||
+               (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) ||
+               (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) ||
+           (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) ||
+            (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID))
+               ;               /* these are OK */
+           else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0)
+               return false;
+
+           tp = typeidType(input_typeids[i]);
+           if (typeTypeFlag(tp) == 'c')
+               return false;
+       }
+   }
+
+   return true;
+}
+
+/*
+ * given a list of possible typeid arrays to a function and an array of
+ * input typeids, produce a shortlist of those function typeid arrays
+ * that match the input typeids (either exactly or by coercion), and
+ * return the number of such arrays
+ */
+int
+match_argtypes(int nargs,
+              Oid *input_typeids,
+              CandidateList function_typeids,
+              CandidateList *candidates)       /* return value */
+{
+   CandidateList current_candidate;
+   CandidateList matching_candidate;
+   Oid        *current_typeids;
+   int         ncandidates = 0;
+
+   *candidates = NULL;
+
+   for (current_candidate = function_typeids;
+        current_candidate != NULL;
+        current_candidate = current_candidate->next)
+   {
+       current_typeids = current_candidate->args;
+       if (can_coerce(nargs, input_typeids, current_typeids))
+       {
+           matching_candidate = (CandidateList)
+               palloc(sizeof(struct _CandidateList));
+           matching_candidate->args = current_typeids;
+           matching_candidate->next = *candidates;
+           *candidates = matching_candidate;
+           ncandidates++;
+       }
+   }
+
+   return ncandidates;
+}
+
+/*
+ * given the input argtype array and more than one candidate
+ * for the function argtype array, attempt to resolve the conflict.
+ * returns the selected argtype array if the conflict can be resolved,
+ * otherwise returns NULL
+ */
+Oid *
+func_select_candidate(int nargs,
+                     Oid *input_typeids,
+                     CandidateList candidates)
+{
+   /* XXX no conflict resolution implemeneted yet */
+   return (NULL);
+}
+
+bool
+func_get_detail(char *funcname,
+               int nargs,
+               Oid *oid_array,
+               Oid *funcid,    /* return value */
+               Oid *rettype,   /* return value */
+               bool *retset,   /* return value */
+               Oid **true_typeids)     /* return value */
+{
+   Oid       **input_typeid_vector;
+   Oid        *current_input_typeids;
+   CandidateList function_typeids;
+   CandidateList current_function_typeids;
+   HeapTuple   ftup;
+   Form_pg_proc pform;
+
+   /*
+    * attempt to find named function in the system catalogs with
+    * arguments exactly as specified - so that the normal case is just as
+    * quick as before
+    */
+   ftup = SearchSysCacheTuple(PRONAME,
+                              PointerGetDatum(funcname),
+                              Int32GetDatum(nargs),
+                              PointerGetDatum(oid_array),
+                              0);
+   *true_typeids = oid_array;
+
+   /*
+    * If an exact match isn't found : 1) get a vector of all possible
+    * input arg type arrays constructed from the superclasses of the
+    * original input arg types 2) get a list of all possible argument
+    * type arrays to the function with given name and number of arguments
+    * 3) for each input arg type array from vector #1 : a) find how many
+    * of the function arg type arrays from list #2 it can be coerced to
+    * b) - if the answer is one, we have our function - if the answer is
+    * more than one, attempt to resolve the conflict - if the answer is
+    * zero, try the next array from vector #1
+    */
+   if (!HeapTupleIsValid(ftup))
+   {
+       function_typeids = func_get_candidates(funcname, nargs);
+
+       if (function_typeids != NULL)
+       {
+           int         ncandidates = 0;
+
+           input_typeid_vector = argtype_inherit(nargs, oid_array);
+           current_input_typeids = oid_array;
+
+           do
+           {
+               ncandidates = match_argtypes(nargs, current_input_typeids,
+                                            function_typeids,
+                                            ¤t_function_typeids);
+               if (ncandidates == 1)
+               {
+                   *true_typeids = current_function_typeids->args;
+                   ftup = SearchSysCacheTuple(PRONAME,
+                                              PointerGetDatum(funcname),
+                                              Int32GetDatum(nargs),
+                                         PointerGetDatum(*true_typeids),
+                                              0);
+                   Assert(HeapTupleIsValid(ftup));
+               }
+               else if (ncandidates > 1)
+               {
+                   *true_typeids =
+                       func_select_candidate(nargs,
+                                             current_input_typeids,
+                                             current_function_typeids);
+                   if (*true_typeids == NULL)
+                   {
+                       elog(NOTICE, "there is more than one function named \"%s\"",
+                            funcname);
+                       elog(NOTICE, "that satisfies the given argument types. you will have to");
+                       elog(NOTICE, "retype your query using explicit typecasts.");
+                       func_error("func_get_detail", funcname, nargs, oid_array);
+                   }
+                   else
+                   {
+                       ftup = SearchSysCacheTuple(PRONAME,
+                                              PointerGetDatum(funcname),
+                                                  Int32GetDatum(nargs),
+                                         PointerGetDatum(*true_typeids),
+                                                  0);
+                       Assert(HeapTupleIsValid(ftup));
+                   }
+               }
+               current_input_typeids = *input_typeid_vector++;
+           }
+           while (current_input_typeids !=
+                  InvalidOid && ncandidates == 0);
+       }
+   }
+
+   if (!HeapTupleIsValid(ftup))
+   {
+       Type        tp;
+
+       if (nargs == 1)
+       {
+           tp = typeidType(oid_array[0]);
+           if (typeTypeFlag(tp) == 'c')
+               elog(WARN, "no such attribute or function \"%s\"",
+                    funcname);
+       }
+       func_error("func_get_detail", funcname, nargs, oid_array);
+   }
+   else
+   {
+       pform = (Form_pg_proc) GETSTRUCT(ftup);
+       *funcid = ftup->t_oid;
+       *rettype = pform->prorettype;
+       *retset = pform->proretset;
+
+       return (true);
+   }
+/* shouldn't reach here */
+   return (false);
+
+}
+
+/*
+ * argtype_inherit() -- Construct an argtype vector reflecting the
+ *                      inheritance properties of the supplied argv.
+ *
+ *     This function is used to disambiguate among functions with the
+ *     same name but different signatures.  It takes an array of eight
+ *     type ids.  For each type id in the array that's a complex type
+ *     (a class), it walks up the inheritance tree, finding all
+ *     superclasses of that type.  A vector of new Oid type arrays
+ *     is returned to the caller, reflecting the structure of the
+ *     inheritance tree above the supplied arguments.
+ *
+ *     The order of this vector is as follows:  all superclasses of the
+ *     rightmost complex class are explored first.  The exploration
+ *     continues from right to left.  This policy means that we favor
+ *     keeping the leftmost argument type as low in the inheritance tree
+ *     as possible.  This is intentional; it is exactly what we need to
+ *     do for method dispatch.  The last type array we return is all
+ *     zeroes.  This will match any functions for which return types are
+ *     not defined.  There are lots of these (mostly builtins) in the
+ *     catalogs.
+ */
+Oid **
+argtype_inherit(int nargs, Oid *oid_array)
+{
+   Oid         relid;
+   int         i;
+   InhPaths    arginh[MAXFARGS];
+
+   for (i = 0; i < MAXFARGS; i++)
+   {
+       if (i < nargs)
+       {
+           arginh[i].self = oid_array[i];
+           if ((relid = typeidTypeRelid(oid_array[i])) != InvalidOid)
+           {
+               arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec));
+           }
+           else
+           {
+               arginh[i].nsupers = 0;
+               arginh[i].supervec = (Oid *) NULL;
+           }
+       }
+       else
+       {
+           arginh[i].self = InvalidOid;
+           arginh[i].nsupers = 0;
+           arginh[i].supervec = (Oid *) NULL;
+       }
+   }
+
+   /* return an ordered cross-product of the classes involved */
+   return (genxprod(arginh, nargs));
+}
+
+int findsupers(Oid relid, Oid **supervec)
+{
+   Oid        *relidvec;
+   Relation    inhrel;
+   HeapScanDesc inhscan;
+   ScanKeyData skey;
+   HeapTuple   inhtup;
+   TupleDesc   inhtupdesc;
+   int         nvisited;
+   SuperQE    *qentry,
+              *vnode;
+   Dllist     *visited,
+              *queue;
+   Dlelem     *qe,
+              *elt;
+
+   Relation    rd;
+   Buffer      buf;
+   Datum       d;
+   bool        newrelid;
+   char        isNull;
+
+   nvisited = 0;
+   queue = DLNewList();
+   visited = DLNewList();
+
+
+   inhrel = heap_openr(InheritsRelationName);
+   RelationSetLockForRead(inhrel);
+   inhtupdesc = RelationGetTupleDescriptor(inhrel);
+
+   /*
+    * Use queue to do a breadth-first traversal of the inheritance graph
+    * from the relid supplied up to the root.
+    */
+   do
+   {
+       ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
+                              ObjectIdEqualRegProcedure,
+                              ObjectIdGetDatum(relid));
+
+       inhscan = heap_beginscan(inhrel, 0, false, 1, &skey);
+
+       while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf)))
+       {
+           qentry = (SuperQE *) palloc(sizeof(SuperQE));
+
+           d = fastgetattr(inhtup, Anum_pg_inherits_inhparent,
+                           inhtupdesc, &isNull);
+           qentry->sqe_relid = DatumGetObjectId(d);
+
+           /* put this one on the queue */
+           DLAddTail(queue, DLNewElem(qentry));
+
+           ReleaseBuffer(buf);
+       }
+
+       heap_endscan(inhscan);
+
+       /* pull next unvisited relid off the queue */
+       do
+       {
+           qe = DLRemHead(queue);
+           qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL;
+
+           if (qentry == (SuperQE *) NULL)
+               break;
+
+           relid = qentry->sqe_relid;
+           newrelid = true;
+
+           for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
+           {
+               vnode = (SuperQE *) DLE_VAL(elt);
+               if (vnode && (qentry->sqe_relid == vnode->sqe_relid))
+               {
+                   newrelid = false;
+                   break;
+               }
+           }
+       } while (!newrelid);
+
+       if (qentry != (SuperQE *) NULL)
+       {
+
+           /* save the type id, rather than the relation id */
+           if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
+               elog(WARN, "relid %d does not exist", qentry->sqe_relid);
+           qentry->sqe_relid = typeTypeId(typenameType(RelationGetRelationName(rd)->data));
+           heap_close(rd);
+
+           DLAddTail(visited, qe);
+
+           nvisited++;
+       }
+   } while (qentry != (SuperQE *) NULL);
+
+   RelationUnsetLockForRead(inhrel);
+   heap_close(inhrel);
+
+   if (nvisited > 0)
+   {
+       relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
+       *supervec = relidvec;
+
+       for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
+       {
+           vnode = (SuperQE *) DLE_VAL(elt);
+           *relidvec++ = vnode->sqe_relid;
+       }
+
+   }
+   else
+   {
+       *supervec = (Oid *) NULL;
+   }
+
+   return (nvisited);
+}
+
+Oid **
+genxprod(InhPaths *arginh, int nargs)
+{
+   int         nanswers;
+   Oid       **result,
+             **iter;
+   Oid        *oneres;
+   int         i,
+               j;
+   int         cur[MAXFARGS];
+
+   nanswers = 1;
+   for (i = 0; i < nargs; i++)
+   {
+       nanswers *= (arginh[i].nsupers + 2);
+       cur[i] = 0;
+   }
+
+   iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
+
+   /* compute the cross product from right to left */
+   for (;;)
+   {
+       oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
+       MemSet(oneres, 0, MAXFARGS * sizeof(Oid));
+
+       for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
+           continue;
+
+       /* if we're done, terminate with NULL pointer */
+       if (i < 0)
+       {
+           *iter = NULL;
+           return (result);
+       }
+
+       /* no, increment this column and zero the ones after it */
+       cur[i] = cur[i] + 1;
+       for (j = nargs - 1; j > i; j--)
+           cur[j] = 0;
+
+       for (i = 0; i < nargs; i++)
+       {
+           if (cur[i] == 0)
+               oneres[i] = arginh[i].self;
+           else if (cur[i] > arginh[i].nsupers)
+               oneres[i] = 0;  /* wild card */
+           else
+               oneres[i] = arginh[i].supervec[cur[i] - 1];
+       }
+
+       *iter++ = oneres;
+   }
+}
+
+
+/*
+ ** make_arguments --
+ **   Given the number and types of arguments to a function, and the
+ **   actual arguments and argument types, do the necessary typecasting.
+ */
+void
+make_arguments(int nargs,
+              List *fargs,
+              Oid *input_typeids,
+              Oid *function_typeids)
+{
+
+   /*
+    * there are two ways an input typeid can differ from a function
+    * typeid : either the input type inherits the function type, so no
+    * typecasting is necessary, or the input type can be typecast into
+    * the function type. right now, we only typecast unknowns, and that
+    * is all we check for.
+    */
+
+   List       *current_fargs;
+   int         i;
+
+   for (i = 0, current_fargs = fargs;
+        i < nargs;
+        i++, current_fargs = lnext(current_fargs))
+   {
+
+       if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)
+       {
+           lfirst(current_fargs) =
+               parser_typecast2(lfirst(current_fargs),
+                                input_typeids[i],
+                                typeidType(function_typeids[i]),
+                                -1);
+       }
+   }
+}
+
+/*
+ ** setup_tlist --
+ **        Build a tlist that says which attribute to project to.
+ **        This routine is called by ParseFunc() to set up a target list
+ **        on a tuple parameter or return value.  Due to a bug in 4.0,
+ **        it's not possible to refer to system attributes in this case.
+ */
+List *
+setup_tlist(char *attname, Oid relid)
+{
+   TargetEntry *tle;
+   Resdom     *resnode;
+   Var        *varnode;
+   Oid         typeid;
+   int         attno;
+
+   attno = get_attnum(relid, attname);
+   if (attno < 0)
+       elog(WARN, "cannot reference attribute '%s' of tuple params/return values for functions", attname);
+
+   typeid = attnameTypeId(relid, attname);
+   resnode = makeResdom(1,
+                        typeid,
+                        typeLen(typeidType(typeid)),
+                        get_attname(relid, attno),
+                        0,
+                        (Oid) 0,
+                        0);
+   varnode = makeVar(-1, attno, typeid, -1, attno);
+
+   tle = makeNode(TargetEntry);
+   tle->resdom = resnode;
+   tle->expr = (Node *) varnode;
+   return (lcons(tle, NIL));
+}
+
+/*
+ ** setup_base_tlist --
+ **        Build a tlist that extracts a base type from the tuple
+ **        returned by the executor.
+ */
+List *
+setup_base_tlist(Oid typeid)
+{
+   TargetEntry *tle;
+   Resdom     *resnode;
+   Var        *varnode;
+
+   resnode = makeResdom(1,
+                        typeid,
+                        typeLen(typeidType(typeid)),
+                        "",
+                        0,
+                        (Oid) 0,
+                        0);
+   varnode = makeVar(-1, 1, typeid, -1, 1);
+   tle = makeNode(TargetEntry);
+   tle->resdom = resnode;
+   tle->expr = (Node *) varnode;
+
+   return (lcons(tle, NIL));
+}
+
+/*
+ * ParseComplexProjection -
+ *   handles function calls with a single argument that is of complex type.
+ *   This routine returns NULL if it can't handle the projection (eg. sets).
+ */
+Node *
+ParseComplexProjection(ParseState *pstate,
+                      char *funcname,
+                      Node *first_arg,
+                      bool *attisset)
+{
+   Oid         argtype;
+   Oid         argrelid;
+   Name        relname;
+   Relation    rd;
+   Oid         relid;
+   int         attnum;
+
+   switch (nodeTag(first_arg))
+   {
+       case T_Iter:
+           {
+               Func       *func;
+               Iter       *iter;
+
+               iter = (Iter *) first_arg;
+               func = (Func *) ((Expr *) iter->iterexpr)->oper;
+               argtype = funcid_get_rettype(func->funcid);
+               argrelid = typeidTypeRelid(argtype);
+               if (argrelid &&
+                   ((attnum = get_attnum(argrelid, funcname))
+                    != InvalidAttrNumber))
+               {
+
+                   /*
+                    * the argument is a function returning a tuple, so
+                    * funcname may be a projection
+                    */
+
+                   /* add a tlist to the func node and return the Iter */
+                   rd = heap_openr(typeidTypeName(argtype));
+                   if (RelationIsValid(rd))
+                   {
+                       relid = RelationGetRelationId(rd);
+                       relname = RelationGetRelationName(rd);
+                       heap_close(rd);
+                   }
+                   if (RelationIsValid(rd))
+                   {
+                       func->func_tlist =
+                           setup_tlist(funcname, argrelid);
+                       iter->itertype = attnumTypeId(rd, attnum);
+                       return ((Node *) iter);
+                   }
+                   else
+                   {
+                       elog(WARN,
+                            "Function '%s' has bad returntype %d",
+                            funcname, argtype);
+                   }
+               }
+               else
+               {
+                   /* drop through */
+                   ;
+               }
+               break;
+           }
+       case T_Var:
+           {
+
+               /*
+                * The argument is a set, so this is either a projection
+                * or a function call on this set.
+                */
+               *attisset = true;
+               break;
+           }
+       case T_Expr:
+           {
+               Expr       *expr = (Expr *) first_arg;
+               Func       *funcnode;
+
+               if (expr->opType != FUNC_EXPR)
+                   break;
+
+               funcnode = (Func *) expr->oper;
+               argtype = funcid_get_rettype(funcnode->funcid);
+               argrelid = typeidTypeRelid(argtype);
+
+               /*
+                * the argument is a function returning a tuple, so
+                * funcname may be a projection
+                */
+               if (argrelid &&
+                   (attnum = get_attnum(argrelid, funcname))
+                   != InvalidAttrNumber)
+               {
+
+                   /* add a tlist to the func node */
+                   rd = heap_openr(typeidTypeName(argtype));
+                   if (RelationIsValid(rd))
+                   {
+                       relid = RelationGetRelationId(rd);
+                       relname = RelationGetRelationName(rd);
+                       heap_close(rd);
+                   }
+                   if (RelationIsValid(rd))
+                   {
+                       Expr       *newexpr;
+
+                       funcnode->func_tlist =
+                           setup_tlist(funcname, argrelid);
+                       funcnode->functype = attnumTypeId(rd, attnum);
+
+                       newexpr = makeNode(Expr);
+                       newexpr->typeOid = funcnode->functype;
+                       newexpr->opType = FUNC_EXPR;
+                       newexpr->oper = (Node *) funcnode;
+                       newexpr->args = lcons(first_arg, NIL);
+
+                       return ((Node *) newexpr);
+                   }
+
+               }
+
+               elog(WARN, "Function '%s' has bad returntype %d",
+                    funcname, argtype);
+               break;
+           }
+       case T_Param:
+           {
+               Param      *param = (Param *) first_arg;
+
+               /*
+                * If the Param is a complex type, this could be a
+                * projection
+                */
+               rd = heap_openr(typeidTypeName(param->paramtype));
+               if (RelationIsValid(rd))
+               {
+                   relid = RelationGetRelationId(rd);
+                   relname = RelationGetRelationName(rd);
+                   heap_close(rd);
+               }
+               if (RelationIsValid(rd) &&
+                   (attnum = get_attnum(relid, funcname))
+                   != InvalidAttrNumber)
+               {
+
+                   param->paramtype = attnumTypeId(rd, attnum);
+                   param->param_tlist = setup_tlist(funcname, relid);
+                   return ((Node *) param);
+               }
+               break;
+           }
+       default:
+           break;
+   }
+
+   return NULL;
+}
+
+/*
+ * Error message when function lookup fails that gives details of the
+ * argument types
+ */
+void
+func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
+{
+   char        p[(NAMEDATALEN + 2) * MAXFMGRARGS],
+              *ptr;
+   int         i;
+
+   ptr = p;
+   *ptr = '\0';
+   for (i = 0; i < nargs; i++)
+   {
+       if (i)
+       {
+           *ptr++ = ',';
+           *ptr++ = ' ';
+       }
+       if (argtypes[i] != 0)
+       {
+           strcpy(ptr, typeidTypeName(argtypes[i]));
+           *(ptr + NAMEDATALEN) = '\0';
+       }
+       else
+           strcpy(ptr, "opaque");
+       ptr += strlen(ptr);
+   }
+
+   elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);
+}
+
+
+
similarity index 56%
rename from src/backend/parser/parse_query.c
rename to src/backend/parser/parse_node.c
index c47feeaa1145a1ecc7fc7297f24ebb99e5f7b66d..c06e00888b90526b2aeddb2a417280f93a6330ab 100644 (file)
 /*-------------------------------------------------------------------------
  *
- * parse_query.c--
- *   take an "optimizable" stmt and make the query tree that
- *    the planner requires.
+ * parse_node.c--
+ *   various routines that make nodes for query plans
  *
  * Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.25 1997/11/24 05:08:27 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.1 1997/11/25 22:05:42 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 #include 
-#include "postgres.h"
 
+#include "postgres.h"
 #include "fmgr.h"
 #include "access/heapam.h"
-#include "access/tupmacs.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_oper.h"
+#include "parser/parse_node.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_type.h"
 #include "utils/builtins.h"
+#include "utils/syscache.h"
+
+#ifdef 0
+#include "access/tupmacs.h"
 #include "utils/elog.h"
 #include "utils/palloc.h"
 #include "utils/acl.h"         /* for ACL_NO_PRIV_WARNING */
 #include "utils/rel.h"         /* Relation stuff */
 
 #include "utils/syscache.h"
-#include "catalog/pg_type.h"
-#include "catalog/pg_operator.h"
-#include "parser/catalog_utils.h"
-#include "parser/parse_query.h"
-#include "utils/lsyscache.h"
 
 #include "nodes/pg_list.h"
 #include "nodes/primnodes.h"
 #include "nodes/parsenodes.h"
-#include "nodes/makefuncs.h"
-
-static void
-checkTargetTypes(ParseState *pstate, char *target_colname,
-                char *refname, char *colname);
-
-Oid           *param_type_info;
-int            pfunc_num_args;
-
-/* given refname, return a pointer to the range table entry */
-RangeTblEntry *
-refnameRangeTableEntry(List *rtable, char *refname)
-{
-   List       *temp;
-
-   foreach(temp, rtable)
-   {
-       RangeTblEntry *rte = lfirst(temp);
-
-       if (!strcmp(rte->refname, refname))
-           return rte;
-   }
-   return NULL;
-}
-
-/* given refname, return id of variable; position starts with 1 */
-int
-refnameRangeTablePosn(List *rtable, char *refname)
-{
-   int         index;
-   List       *temp;
-
-   index = 1;
-   foreach(temp, rtable)
-   {
-       RangeTblEntry *rte = lfirst(temp);
-
-       if (!strcmp(rte->refname, refname))
-           return index;
-       index++;
-   }
-   return (0);
-}
+#endif
 
 /*
- * returns range entry if found, else NULL
+ * make_parsestate() --
+ *   allocate and initialize a new ParseState.
+ * the CALLERS is responsible for freeing the ParseState* returned
+ *
  */
-RangeTblEntry *
-colnameRangeTableEntry(ParseState *pstate, char *colname)
-{
-   List       *et;
-   List       *rtable;
-   RangeTblEntry *rte_result;
-
-   if (pstate->p_is_rule)
-       rtable = lnext(lnext(pstate->p_rtable));
-   else
-       rtable = pstate->p_rtable;
-
-   rte_result = NULL;
-   foreach(et, rtable)
-   {
-       RangeTblEntry *rte = lfirst(et);
-
-       /* only entries on outer(non-function?) scope */
-       if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
-           continue;
-
-       if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
-       {
-           if (rte_result != NULL)
-           {
-               if (!pstate->p_is_insert ||
-                   rte != pstate->p_target_rangetblentry)
-                   elog(WARN, "Column %s is ambiguous", colname);
-           }
-           else
-               rte_result = rte;
-       }
-   }
-   return rte_result;
-}
 
-/*
- * put new entry in pstate p_rtable structure, or return pointer
- * if pstate null
-*/
-RangeTblEntry *
-addRangeTableEntry(ParseState *pstate,
-                  char *relname,
-                  char *refname,
-                  bool inh,
-                  bool inFromCl)
-{
-   Relation    relation;
-   RangeTblEntry *rte = makeNode(RangeTblEntry);
-
-   if (pstate != NULL &&
-       refnameRangeTableEntry(pstate->p_rtable, refname) != NULL)
-       elog(WARN, "Table name %s specified more than once", refname);
-
-   rte->relname = pstrdup(relname);
-   rte->refname = pstrdup(refname);
-
-   relation = heap_openr(relname);
-   if (relation == NULL)
-   {
-       elog(WARN, "%s: %s",
-            relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
-   }
-
-   /*
-    * Flags - zero or more from inheritance,union,version or
-    * recursive (transitive closure) [we don't support them all -- ay
-    * 9/94 ]
-    */
-   rte->inh = inh;
-
-   /* RelOID */
-   rte->relid = RelationGetRelationId(relation);
-
-   rte->inFromCl = inFromCl;
-
-   /*
-    * close the relation we're done with it for now.
-    */
-   if (pstate != NULL)
-       pstate->p_rtable = lappend(pstate->p_rtable, rte);
-
-   heap_close(relation);
-
-   return rte;
-}
-
-/*
- * expandAll -
- *   makes a list of attributes
- *   assumes reldesc caching works
- */
-List      *
-expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
+ParseState *
+make_parsestate(void)
 {
-   Relation    rdesc;
-   List       *te_tail = NIL,
-              *te_head = NIL;
-   Var        *varnode;
-   int         varattno,
-               maxattrs;
-   Oid         type_id;
-   int         type_len;
-   RangeTblEntry *rte;
-
-   rte = refnameRangeTableEntry(pstate->p_rtable, refname);
-   if (rte == NULL)
-       rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE);
-
-   rdesc = heap_open(rte->relid);
-
-   if (rdesc == NULL)
-   {
-       elog(WARN, "Unable to expand all -- heap_open failed on %s",
-            rte->refname);
-       return NIL;
-   }
-   maxattrs = RelationGetNumberOfAttributes(rdesc);
-
-   for (varattno = 0; varattno <= maxattrs - 1; varattno++)
-   {
-       char       *attrname;
-       char       *resname = NULL;
-       TargetEntry *te = makeNode(TargetEntry);
-
-       attrname = pstrdup((rdesc->rd_att->attrs[varattno]->attname).data);
-       varnode = (Var *) make_var(pstate, refname, attrname, &type_id);
-       type_len = (int) tlen(get_id_type(type_id));
-
-       handleTargetColname(pstate, &resname, refname, attrname);
-       if (resname != NULL)
-           attrname = resname;
-
-       /*
-        * Even if the elements making up a set are complex, the set
-        * itself is not.
-        */
-
-       te->resdom = makeResdom((AttrNumber) (*this_resno)++,
-                               type_id,
-                               (Size) type_len,
-                               attrname,
-                               (Index) 0,
-                               (Oid) 0,
-                               0);
-       te->expr = (Node *) varnode;
-       if (te_head == NIL)
-           te_head = te_tail = lcons(te, NIL);
-       else
-           te_tail = lappend(te_tail, te);
-   }
-
-   heap_close(rdesc);
-   return (te_head);
+   ParseState *pstate;
+
+   pstate = malloc(sizeof(ParseState));
+   pstate->p_last_resno = 1;
+   pstate->p_rtable = NIL;
+   pstate->p_numAgg = 0;
+   pstate->p_aggs = NIL;
+   pstate->p_is_insert = false;
+   pstate->p_insert_columns = NIL;
+   pstate->p_is_update = false;
+   pstate->p_is_rule = false;
+   pstate->p_in_where_clause = false;
+   pstate->p_target_relation = NULL;
+   pstate->p_target_rangetblentry = NULL;
+
+   return (pstate);
 }
 
-static void
-disallow_setop(char *op, Type optype, Node *operand)
-{
-   if (operand == NULL)
-       return;
-
-   if (nodeTag(operand) == T_Iter)
-   {
-       elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
-            op, tname(optype));
-       elog(WARN, "but '%s' takes single values, not sets.",
-            op);
-   }
-}
-
-static Node *
+Node *
 make_operand(char *opname,
             Node *tree,
             Oid orig_typeId,
@@ -267,7 +84,7 @@ make_operand(char *opname,
    if (tree != NULL)
    {
        result = tree;
-       true_type = get_id_type(true_typeId);
+       true_type = typeidType(true_typeId);
        disallow_setop(opname, true_type, result);
        if (true_typeId != orig_typeId)
        {                       /* must coerce */
@@ -276,13 +93,13 @@ make_operand(char *opname,
            Assert(nodeTag(result) == T_Const);
            val = (Datum) textout((struct varlena *)
                                  con->constvalue);
-           infunc = typeid_get_retinfunc(true_typeId);
+           infunc = typeidRetinfunc(true_typeId);
            con = makeNode(Const);
            con->consttype = true_typeId;
-           con->constlen = tlen(true_type);
+           con->constlen = typeLen(true_type);
            con->constvalue = (Datum) fmgr(infunc,
                                           val,
-                                          get_typelem(true_typeId),
+                                          typeidTypElem(true_typeId),
                                           -1 /* for varchar() type */ );
            con->constisnull = false;
            con->constbyval = true;
@@ -307,6 +124,21 @@ make_operand(char *opname,
 }
 
 
+void
+disallow_setop(char *op, Type optype, Node *operand)
+{
+   if (operand == NULL)
+       return;
+
+   if (nodeTag(operand) == T_Iter)
+   {
+       elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
+            op, typeTypeName(optype));
+       elog(WARN, "but '%s' takes single values, not sets.",
+            op);
+   }
+}
+
 Expr      *
 make_op(char *opname, Node *ltree, Node *rtree)
 {
@@ -367,30 +199,30 @@ make_op(char *opname, Node *ltree, Node *rtree)
            CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
            !((Const *) rtree)->constiscast)
        {
-           outfunc = typeid_get_retoutfunc(rtypeId);
-           infunc = typeid_get_retinfunc(ltypeId);
+           outfunc = typeidRetoutfunc(rtypeId);
+           infunc = typeidRetinfunc(ltypeId);
            outstr = (char *) fmgr(outfunc, ((Const *) rtree)->constvalue);
            ((Const *) rtree)->constvalue = (Datum) fmgr(infunc, outstr);
            pfree(outstr);
            ((Const *) rtree)->consttype = rtypeId = ltypeId;
-           newtype = get_id_type(rtypeId);
-           ((Const *) rtree)->constlen = tlen(newtype);
-           ((Const *) rtree)->constbyval = tbyval(newtype);
+           newtype = typeidType(rtypeId);
+           ((Const *) rtree)->constlen = typeLen(newtype);
+           ((Const *) rtree)->constbyval = typeByVal(newtype);
        }
 
        if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
            CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
            !((Const *) ltree)->constiscast)
        {
-           outfunc = typeid_get_retoutfunc(ltypeId);
-           infunc = typeid_get_retinfunc(rtypeId);
+           outfunc = typeidRetoutfunc(ltypeId);
+           infunc = typeidRetinfunc(rtypeId);
            outstr = (char *) fmgr(outfunc, ((Const *) ltree)->constvalue);
            ((Const *) ltree)->constvalue = (Datum) fmgr(infunc, outstr);
            pfree(outstr);
            ((Const *) ltree)->consttype = ltypeId = rtypeId;
-           newtype = get_id_type(ltypeId);
-           ((Const *) ltree)->constlen = tlen(newtype);
-           ((Const *) ltree)->constbyval = tbyval(newtype);
+           newtype = typeidType(ltypeId);
+           ((Const *) ltree)->constlen = typeLen(newtype);
+           ((Const *) ltree)->constbyval = typeByVal(newtype);
        }
 
        temp = oper(opname, ltypeId, rtypeId, false);
@@ -426,38 +258,6 @@ make_op(char *opname, Node *ltree, Node *rtree)
    return result;
 }
 
-Oid
-find_atttype(Oid relid, char *attrname)
-{
-   int         attid;
-   Oid         vartype;
-   Relation    rd;
-
-   rd = heap_open(relid);
-   if (!RelationIsValid(rd))
-   {
-       rd = heap_openr(tname(get_id_type(relid)));
-       if (!RelationIsValid(rd))
-           elog(WARN, "cannot compute type of att %s for relid %d",
-                attrname, relid);
-   }
-
-   attid = nf_varattno(rd, attrname);
-
-   if (attid == InvalidAttrNumber)
-       elog(WARN, "Invalid attribute %s\n", attrname);
-
-   vartype = att_typeid(rd, attid);
-
-   /*
-    * close relation we're done with it now
-    */
-   heap_close(rd);
-
-   return (vartype);
-}
-
-
 Var           *
 make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
 {
@@ -476,10 +276,8 @@ make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
 
    rd = heap_open(rte->relid);
 
-   attid = nf_varattno(rd, attrname);
-   if (attid == InvalidAttrNumber)
-       elog(WARN, "Invalid attribute %s\n", attrname);
-   vartypeid = att_typeid(rd, attid);
+   attid = attnameAttNum(rd, attrname); /* could elog(WARN) */
+   vartypeid = attnumTypeId(rd, attid);
 
    varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
 
@@ -667,7 +465,7 @@ make_const(Value *value)
    switch (nodeTag(value))
    {
        case T_Integer:
-           tp = type("int4");
+           tp = typeidType(INT4OID);
            val = Int32GetDatum(intVal(value));
            break;
 
@@ -675,7 +473,7 @@ make_const(Value *value)
            {
                float64     dummy;
 
-               tp = type("float8");
+               tp = typeidType(FLOAT8OID);
 
                dummy = (float64) palloc(sizeof(float64data));
                *dummy = floatVal(value);
@@ -685,7 +483,7 @@ make_const(Value *value)
            break;
 
        case T_String:
-           tp = type("unknown");       /* unknown for now, will be type
+           tp = typeidType(UNKNOWNOID);    /* unknown for now, will be type
                                         * coerced */
            val = PointerGetDatum(textin(strVal(value)));
            break;
@@ -702,111 +500,14 @@ make_const(Value *value)
            }
    }
 
-   con = makeConst(typeid(tp),
-                   tlen(tp),
+   con = makeConst(typeTypeId(tp),
+                   typeLen(tp),
                    val,
                    false,
-                   tbyval(tp),
+                   typeByVal(tp),
                    false,      /* not a set */
                    false);
 
    return (con);
 }
 
-/*
- * param_type_init()
- *
- * keep enough information around fill out the type of param nodes
- * used in postquel functions
- */
-void
-param_type_init(Oid *typev, int nargs)
-{
-   pfunc_num_args = nargs;
-   param_type_info = typev;
-}
-
-Oid
-param_type(int t)
-{
-   if ((t > pfunc_num_args) || (t == 0))
-       return InvalidOid;
-   return param_type_info[t - 1];
-}
-
-/*
- * handleTargetColname -
- *   use column names from insert
- */
-void
-handleTargetColname(ParseState *pstate, char **resname,
-                   char *refname, char *colname)
-{
-   if (pstate->p_is_insert)
-   {
-       if (pstate->p_insert_columns != NIL)
-       {
-           Ident      *id = lfirst(pstate->p_insert_columns);
-
-           *resname = id->name;
-           pstate->p_insert_columns = lnext(pstate->p_insert_columns);
-       }
-       else
-           elog(WARN, "insert: more expressions than target columns");
-   }
-   if (pstate->p_is_insert || pstate->p_is_update)
-       checkTargetTypes(pstate, *resname, refname, colname);
-}
-
-/*
- * checkTargetTypes -
- *   checks value and target column types
- */
-static void
-checkTargetTypes(ParseState *pstate, char *target_colname,
-                char *refname, char *colname)
-{
-   Oid         attrtype_id,
-               attrtype_target;
-   int         resdomno_id,
-               resdomno_target;
-   Relation    rd;
-   RangeTblEntry *rte;
-
-   if (target_colname == NULL || colname == NULL)
-       return;
-
-   if (refname != NULL)
-       rte = refnameRangeTableEntry(pstate->p_rtable, refname);
-   else
-   {
-       rte = colnameRangeTableEntry(pstate, colname);
-       if (rte == (RangeTblEntry *) NULL)
-           elog(WARN, "attribute %s not found", colname);
-       refname = rte->refname;
-   }
-
-/*
-   if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
-       elog(WARN, "%s not available in this context", colname);
-*/
-   rd = heap_open(rte->relid);
-
-   resdomno_id = varattno(rd, colname);
-   attrtype_id = att_typeid(rd, resdomno_id);
-
-   resdomno_target = varattno(pstate->p_target_relation, target_colname);
-   attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target);
-
-   if (attrtype_id != attrtype_target)
-       elog(WARN, "Type of %s does not match target column %s",
-            colname, target_colname);
-
-   if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) &&
-       rd->rd_att->attrs[resdomno_id - 1]->attlen !=
-   pstate->p_target_relation->rd_att->attrs[resdomno_target - 1]->attlen)
-       elog(WARN, "Length of %s does not match length of target column %s",
-            colname, target_colname);
-
-   heap_close(rd);
-}
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
new file mode 100644 (file)
index 0000000..d82a46b
--- /dev/null
@@ -0,0 +1,613 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_oper.h
+ *     handle operator things for parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.1 1997/11/25 22:05:43 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include "postgres.h"
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef 0
+#include "lib/dllist.h"
+#include "utils/datum.h"
+
+#include "utils/builtins.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
+
+#include "catalog/pg_inherits.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
+#include "catalog/indexing.h"
+#include "catalog/catname.h"
+
+#include "access/skey.h"
+#include "access/relscan.h"
+#include "access/tupdesc.h"
+#include "access/htup.h"
+#include "access/genam.h"
+#include "access/itup.h"
+#include "access/tupmacs.h"
+#include "storage/buf.h"
+#include "utils/lsyscache.h"
+#include "storage/lmgr.h"
+
+#include "port-protos.h"       /* strdup() */
+#endif
+
+Oid
+any_ordering_op(int restype)
+{
+   Operator    order_op;
+   Oid         order_opid;
+
+   order_op = oper("<", restype, restype, false);
+   order_opid = oprid(order_op);
+
+   return order_opid;
+}
+
+/* given operator, return the operator OID */
+Oid
+oprid(Operator op)
+{
+   return (op->t_oid);
+}
+
+/*
+ * given opname, leftTypeId and rightTypeId,
+ * find all possible (arg1, arg2) pairs for which an operator named
+ * opname exists, such that leftTypeId can be coerced to arg1 and
+ * rightTypeId can be coerced to arg2
+ */
+int
+binary_oper_get_candidates(char *opname,
+                          Oid leftTypeId,
+                          Oid rightTypeId,
+                          CandidateList *candidates)
+{
+   CandidateList current_candidate;
+   Relation    pg_operator_desc;
+   HeapScanDesc pg_operator_scan;
+   HeapTuple   tup;
+   OperatorTupleForm oper;
+   Buffer      buffer;
+   int         nkeys;
+   int         ncandidates = 0;
+   ScanKeyData opKey[3];
+
+   *candidates = NULL;
+
+   ScanKeyEntryInitialize(&opKey[0], 0,
+                          Anum_pg_operator_oprname,
+                          NameEqualRegProcedure,
+                          NameGetDatum(opname));
+
+   ScanKeyEntryInitialize(&opKey[1], 0,
+                          Anum_pg_operator_oprkind,
+                          CharacterEqualRegProcedure,
+                          CharGetDatum('b'));
+
+
+   if (leftTypeId == UNKNOWNOID)
+   {
+       if (rightTypeId == UNKNOWNOID)
+       {
+           nkeys = 2;
+       }
+       else
+       {
+           nkeys = 3;
+
+           ScanKeyEntryInitialize(&opKey[2], 0,
+                                  Anum_pg_operator_oprright,
+                                  ObjectIdEqualRegProcedure,
+                                  ObjectIdGetDatum(rightTypeId));
+       }
+   }
+   else if (rightTypeId == UNKNOWNOID)
+   {
+       nkeys = 3;
+
+       ScanKeyEntryInitialize(&opKey[2], 0,
+                              Anum_pg_operator_oprleft,
+                              ObjectIdEqualRegProcedure,
+                              ObjectIdGetDatum(leftTypeId));
+   }
+   else
+       /* currently only "unknown" can be coerced */
+       return 0;
+
+   pg_operator_desc = heap_openr(OperatorRelationName);
+   pg_operator_scan = heap_beginscan(pg_operator_desc,
+                                     0,
+                                     true,
+                                     nkeys,
+                                     opKey);
+
+   do
+   {
+       tup = heap_getnext(pg_operator_scan, 0, &buffer);
+       if (HeapTupleIsValid(tup))
+       {
+           current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+           current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
+
+           oper = (OperatorTupleForm) GETSTRUCT(tup);
+           current_candidate->args[0] = oper->oprleft;
+           current_candidate->args[1] = oper->oprright;
+           current_candidate->next = *candidates;
+           *candidates = current_candidate;
+           ncandidates++;
+           ReleaseBuffer(buffer);
+       }
+   } while (HeapTupleIsValid(tup));
+
+   heap_endscan(pg_operator_scan);
+   heap_close(pg_operator_desc);
+
+   return ncandidates;
+}
+
+/*
+ * equivalentOpersAfterPromotion -
+ *   checks if a list of candidate operators obtained from
+ *   binary_oper_get_candidates() contain equivalent operators. If
+ *   this routine is called, we have more than 1 candidate and need to
+ *   decided whether to pick one of them. This routine returns true if
+ *   the all the candidates operate on the same data types after
+ *   promotion (int2, int4, float4 -> float8).
+ */
+bool
+equivalentOpersAfterPromotion(CandidateList candidates)
+{
+   CandidateList result;
+   CandidateList promotedCandidates = NULL;
+   Oid         leftarg,
+               rightarg;
+
+   for (result = candidates; result != NULL; result = result->next)
+   {
+       CandidateList c;
+
+       c = (CandidateList) palloc(sizeof(*c));
+       c->args = (Oid *) palloc(2 * sizeof(Oid));
+       switch (result->args[0])
+       {
+           case FLOAT4OID:
+           case INT4OID:
+           case INT2OID:
+           case CASHOID:
+               c->args[0] = FLOAT8OID;
+               break;
+           default:
+               c->args[0] = result->args[0];
+               break;
+       }
+       switch (result->args[1])
+       {
+           case FLOAT4OID:
+           case INT4OID:
+           case INT2OID:
+           case CASHOID:
+               c->args[1] = FLOAT8OID;
+               break;
+           default:
+               c->args[1] = result->args[1];
+               break;
+       }
+       c->next = promotedCandidates;
+       promotedCandidates = c;
+   }
+
+   /*
+    * if we get called, we have more than 1 candidates so we can do the
+    * following safely
+    */
+   leftarg = promotedCandidates->args[0];
+   rightarg = promotedCandidates->args[1];
+
+   for (result = promotedCandidates->next; result != NULL; result = result->next)
+   {
+       if (result->args[0] != leftarg || result->args[1] != rightarg)
+
+           /*
+            * this list contains operators that operate on different data
+            * types even after promotion. Hence we can't decide on which
+            * one to pick. The user must do explicit type casting.
+            */
+           return FALSE;
+   }
+
+   /*
+    * all the candidates are equivalent in the following sense: they
+    * operate on equivalent data types and picking any one of them is as
+    * good.
+    */
+   return TRUE;
+}
+
+
+/*
+ * given a choice of argument type pairs for a binary operator,
+ * try to choose a default pair
+ */
+CandidateList
+binary_oper_select_candidate(Oid arg1,
+                            Oid arg2,
+                            CandidateList candidates)
+{
+   CandidateList result;
+
+   /*
+    * if both are "unknown", there is no way to select a candidate
+    *
+    * current wisdom holds that the default operator should be one in which
+    * both operands have the same type (there will only be one such
+    * operator)
+    *
+    * 7.27.93 - I have decided not to do this; it's too hard to justify, and
+    * it's easy enough to typecast explicitly -avi [the rest of this
+    * routine were commented out since then -ay]
+    */
+
+   if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
+       return (NULL);
+
+   /*
+    * 6/23/95 - I don't complete agree with avi. In particular, casting
+    * floats is a pain for users. Whatever the rationale behind not doing
+    * this is, I need the following special case to work.
+    *
+    * In the WHERE clause of a query, if a float is specified without
+    * quotes, we treat it as float8. I added the float48* operators so
+    * that we can operate on float4 and float8. But now we have more than
+    * one matching operator if the right arg is unknown (eg. float
+    * specified with quotes). This break some stuff in the regression
+    * test where there are floats in quotes not properly casted. Below is
+    * the solution. In addition to requiring the operator operates on the
+    * same type for both operands [as in the code Avi originally
+    * commented out], we also require that the operators be equivalent in
+    * some sense. (see equivalentOpersAfterPromotion for details.) - ay
+    * 6/95
+    */
+   if (!equivalentOpersAfterPromotion(candidates))
+       return NULL;
+
+   /*
+    * if we get here, any one will do but we're more picky and require
+    * both operands be the same.
+    */
+   for (result = candidates; result != NULL; result = result->next)
+   {
+       if (result->args[0] == result->args[1])
+           return result;
+   }
+
+   return (NULL);
+}
+
+/* Given operator, types of arg1, and arg2, return oper struct */
+/* arg1, arg2 --typeids */
+Operator
+oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
+{
+   HeapTuple   tup;
+   CandidateList candidates;
+   int         ncandidates;
+
+   if (!arg2)
+       arg2 = arg1;
+   if (!arg1)
+       arg1 = arg2;
+
+   if (!(tup = SearchSysCacheTuple(OPRNAME,
+                                   PointerGetDatum(op),
+                                   ObjectIdGetDatum(arg1),
+                                   ObjectIdGetDatum(arg2),
+                                   Int8GetDatum('b'))))
+   {
+       ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
+       if (ncandidates == 0)
+       {
+
+           /*
+            * no operators of the desired types found
+            */
+           if (!noWarnings)
+               op_error(op, arg1, arg2);
+           return (NULL);
+       }
+       else if (ncandidates == 1)
+       {
+
+           /*
+            * exactly one operator of the desired types found
+            */
+           tup = SearchSysCacheTuple(OPRNAME,
+                                     PointerGetDatum(op),
+                                  ObjectIdGetDatum(candidates->args[0]),
+                                  ObjectIdGetDatum(candidates->args[1]),
+                                     Int8GetDatum('b'));
+           Assert(HeapTupleIsValid(tup));
+       }
+       else
+       {
+
+           /*
+            * multiple operators of the desired types found
+            */
+           candidates = binary_oper_select_candidate(arg1, arg2, candidates);
+           if (candidates != NULL)
+           {
+               /* we chose one of them */
+               tup = SearchSysCacheTuple(OPRNAME,
+                                         PointerGetDatum(op),
+                                  ObjectIdGetDatum(candidates->args[0]),
+                                  ObjectIdGetDatum(candidates->args[1]),
+                                         Int8GetDatum('b'));
+               Assert(HeapTupleIsValid(tup));
+           }
+           else
+           {
+               Type        tp1,
+                           tp2;
+
+               /* we chose none of them */
+               tp1 = typeidType(arg1);
+               tp2 = typeidType(arg2);
+               if (!noWarnings)
+               {
+                   elog(NOTICE, "there is more than one operator %s for types", op);
+                   elog(NOTICE, "%s and %s. You will have to retype this query",
+                        typeTypeName(tp1), typeTypeName(tp2));
+                   elog(WARN, "using an explicit cast");
+               }
+               return (NULL);
+           }
+       }
+   }
+   return ((Operator) tup);
+}
+
+/*
+ * given opname and typeId, find all possible types for which
+ * a right/left unary operator named opname exists,
+ * such that typeId can be coerced to it
+ */
+int
+unary_oper_get_candidates(char *op,
+                         Oid typeId,
+                         CandidateList *candidates,
+                         char rightleft)
+{
+   CandidateList current_candidate;
+   Relation    pg_operator_desc;
+   HeapScanDesc pg_operator_scan;
+   HeapTuple   tup;
+   OperatorTupleForm oper;
+   Buffer      buffer;
+   int         ncandidates = 0;
+
+   static ScanKeyData opKey[2] = {
+       {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
+   {0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure}};
+
+   *candidates = NULL;
+
+   fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func,
+             &opKey[0].sk_nargs);
+   opKey[0].sk_argument = NameGetDatum(op);
+   fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func,
+             &opKey[1].sk_nargs);
+   opKey[1].sk_argument = CharGetDatum(rightleft);
+
+   /* currently, only "unknown" can be coerced */
+
+   /*
+    * but we should allow types that are internally the same to be
+    * "coerced"
+    */
+   if (typeId != UNKNOWNOID)
+   {
+       return 0;
+   }
+
+   pg_operator_desc = heap_openr(OperatorRelationName);
+   pg_operator_scan = heap_beginscan(pg_operator_desc,
+                                     0,
+                                     true,
+                                     2,
+                                     opKey);
+
+   do
+   {
+       tup = heap_getnext(pg_operator_scan, 0, &buffer);
+       if (HeapTupleIsValid(tup))
+       {
+           current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+           current_candidate->args = (Oid *) palloc(sizeof(Oid));
+
+           oper = (OperatorTupleForm) GETSTRUCT(tup);
+           if (rightleft == 'r')
+               current_candidate->args[0] = oper->oprleft;
+           else
+               current_candidate->args[0] = oper->oprright;
+           current_candidate->next = *candidates;
+           *candidates = current_candidate;
+           ncandidates++;
+           ReleaseBuffer(buffer);
+       }
+   } while (HeapTupleIsValid(tup));
+
+   heap_endscan(pg_operator_scan);
+   heap_close(pg_operator_desc);
+
+   return ncandidates;
+}
+
+/* Given unary right-side operator (operator on right), return oper struct */
+/* arg-- type id */
+Operator
+right_oper(char *op, Oid arg)
+{
+   HeapTuple   tup;
+   CandidateList candidates;
+   int         ncandidates;
+
+   /*
+    * if (!OpCache) { init_op_cache(); }
+    */
+   if (!(tup = SearchSysCacheTuple(OPRNAME,
+                                   PointerGetDatum(op),
+                                   ObjectIdGetDatum(arg),
+                                   ObjectIdGetDatum(InvalidOid),
+                                   Int8GetDatum('r'))))
+   {
+       ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
+       if (ncandidates == 0)
+       {
+           elog(WARN,
+                "Can't find right op: %s for type %d", op, arg);
+           return (NULL);
+       }
+       else if (ncandidates == 1)
+       {
+           tup = SearchSysCacheTuple(OPRNAME,
+                                     PointerGetDatum(op),
+                                  ObjectIdGetDatum(candidates->args[0]),
+                                     ObjectIdGetDatum(InvalidOid),
+                                     Int8GetDatum('r'));
+           Assert(HeapTupleIsValid(tup));
+       }
+       else
+       {
+           elog(NOTICE, "there is more than one right operator %s", op);
+           elog(NOTICE, "you will have to retype this query");
+           elog(WARN, "using an explicit cast");
+           return (NULL);
+       }
+   }
+   return ((Operator) tup);
+}
+
+/* Given unary left-side operator (operator on left), return oper struct */
+/* arg--type id */
+Operator
+left_oper(char *op, Oid arg)
+{
+   HeapTuple   tup;
+   CandidateList candidates;
+   int         ncandidates;
+
+   /*
+    * if (!OpCache) { init_op_cache(); }
+    */
+   if (!(tup = SearchSysCacheTuple(OPRNAME,
+                                   PointerGetDatum(op),
+                                   ObjectIdGetDatum(InvalidOid),
+                                   ObjectIdGetDatum(arg),
+                                   Int8GetDatum('l'))))
+   {
+       ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
+       if (ncandidates == 0)
+       {
+           elog(WARN,
+                "Can't find left op: %s for type %d", op, arg);
+           return (NULL);
+       }
+       else if (ncandidates == 1)
+       {
+           tup = SearchSysCacheTuple(OPRNAME,
+                                     PointerGetDatum(op),
+                                     ObjectIdGetDatum(InvalidOid),
+                                  ObjectIdGetDatum(candidates->args[0]),
+                                     Int8GetDatum('l'));
+           Assert(HeapTupleIsValid(tup));
+       }
+       else
+       {
+           elog(NOTICE, "there is more than one left operator %s", op);
+           elog(NOTICE, "you will have to retype this query");
+           elog(WARN, "using an explicit cast");
+           return (NULL);
+       }
+   }
+   return ((Operator) tup);
+}
+
+/* Given a typename and value, returns the ascii form of the value */
+
+#ifdef NOT_USED
+char      *
+outstr(char *typename,         /* Name of type of value */
+      char *value)             /* Could be of any type */
+{
+   TypeTupleForm tp;
+   Oid         op;
+
+   tp = (TypeTupleForm) GETSTRUCT(type(typename));
+   op = tp->typoutput;
+   return ((char *) fmgr(op, value));
+}
+
+#endif
+
+/*
+ * Give a somewhat useful error message when the operator for two types
+ * is not found.
+ */
+void
+op_error(char *op, Oid arg1, Oid arg2)
+{
+   Type        tp1 = NULL,
+               tp2 = NULL;
+
+   if (typeidIsValid(arg1))
+   {
+       tp1 = typeidType(arg1);
+   }
+   else
+   {
+       elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
+   }
+
+   if (typeidIsValid(arg2))
+   {
+       tp2 = typeidType(arg2);
+   }
+   else
+   {
+       elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
+   }
+
+   elog(NOTICE, "there is no operator %s for types %s and %s",
+        op, typeTypeName(tp1), typeTypeName(tp2));
+   elog(NOTICE, "You will either have to retype this query using an");
+   elog(NOTICE, "explicit cast, or you will have to define the operator");
+   elog(WARN, "%s for %s and %s using CREATE OPERATOR",
+        op, typeTypeName(tp1), typeTypeName(tp2));
+}
+
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
new file mode 100644 (file)
index 0000000..dd3fa27
--- /dev/null
@@ -0,0 +1,480 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_relation.c--
+ *   parser support routines dealing with relations
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.1 1997/11/25 22:05:45 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include 
+
+#include "postgres.h"
+#include "access/heapam.h"
+#include 
+#include 
+#include "nodes/makefuncs.h"
+#include 
+#include 
+#include "utils/builtins.h"
+#include 
+
+#ifdef 0
+#include "fmgr.h"
+#include "access/tupmacs.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "utils/acl.h"         /* for ACL_NO_PRIV_WARNING */
+
+#include "utils/syscache.h"
+#include "catalog/pg_operator.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#endif
+
+struct
+{
+   char       *field;
+   int         code;
+}          special_attr[] =
+
+{
+   {
+       "ctid", SelfItemPointerAttributeNumber
+   },
+   {
+       "oid", ObjectIdAttributeNumber
+   },
+   {
+       "xmin", MinTransactionIdAttributeNumber
+   },
+   {
+       "cmin", MinCommandIdAttributeNumber
+   },
+   {
+       "xmax", MaxTransactionIdAttributeNumber
+   },
+   {
+       "cmax", MaxCommandIdAttributeNumber
+   },
+};
+
+#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
+
+static char *attnum_type[SPECIALS] = {
+   "tid",
+   "oid",
+   "xid",
+   "cid",
+   "xid",
+   "cid",
+};
+
+/* given refname, return a pointer to the range table entry */
+RangeTblEntry *
+refnameRangeTableEntry(List *rtable, char *refname)
+{
+   List       *temp;
+
+   foreach(temp, rtable)
+   {
+       RangeTblEntry *rte = lfirst(temp);
+
+       if (!strcmp(rte->refname, refname))
+           return rte;
+   }
+   return NULL;
+}
+
+/* given refname, return id of variable; position starts with 1 */
+int
+refnameRangeTablePosn(List *rtable, char *refname)
+{
+   int         index;
+   List       *temp;
+
+   index = 1;
+   foreach(temp, rtable)
+   {
+       RangeTblEntry *rte = lfirst(temp);
+
+       if (!strcmp(rte->refname, refname))
+           return index;
+       index++;
+   }
+   return (0);
+}
+
+/*
+ * returns range entry if found, else NULL
+ */
+RangeTblEntry *
+colnameRangeTableEntry(ParseState *pstate, char *colname)
+{
+   List       *et;
+   List       *rtable;
+   RangeTblEntry *rte_result;
+
+   if (pstate->p_is_rule)
+       rtable = lnext(lnext(pstate->p_rtable));
+   else
+       rtable = pstate->p_rtable;
+
+   rte_result = NULL;
+   foreach(et, rtable)
+   {
+       RangeTblEntry *rte = lfirst(et);
+
+       /* only entries on outer(non-function?) scope */
+       if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
+           continue;
+
+       if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
+       {
+           if (rte_result != NULL)
+           {
+               if (!pstate->p_is_insert ||
+                   rte != pstate->p_target_rangetblentry)
+                   elog(WARN, "Column %s is ambiguous", colname);
+           }
+           else
+               rte_result = rte;
+       }
+   }
+   return rte_result;
+}
+
+/*
+ * put new entry in pstate p_rtable structure, or return pointer
+ * if pstate null
+*/
+RangeTblEntry *
+addRangeTableEntry(ParseState *pstate,
+                  char *relname,
+                  char *refname,
+                  bool inh,
+                  bool inFromCl)
+{
+   Relation    relation;
+   RangeTblEntry *rte = makeNode(RangeTblEntry);
+
+   if (pstate != NULL &&
+       refnameRangeTableEntry(pstate->p_rtable, refname) != NULL)
+       elog(WARN, "Table name %s specified more than once", refname);
+
+   rte->relname = pstrdup(relname);
+   rte->refname = pstrdup(refname);
+
+   relation = heap_openr(relname);
+   if (relation == NULL)
+   {
+       elog(WARN, "%s: %s",
+            relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
+   }
+
+   /*
+    * Flags - zero or more from inheritance,union,version or
+    * recursive (transitive closure) [we don't support them all -- ay
+    * 9/94 ]
+    */
+   rte->inh = inh;
+
+   /* RelOID */
+   rte->relid = RelationGetRelationId(relation);
+
+   rte->inFromCl = inFromCl;
+
+   /*
+    * close the relation we're done with it for now.
+    */
+   if (pstate != NULL)
+       pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+   heap_close(relation);
+
+   return rte;
+}
+
+/*
+ * expandAll -
+ *   makes a list of attributes
+ *   assumes reldesc caching works
+ */
+List      *
+expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
+{
+   Relation    rdesc;
+   List       *te_tail = NIL,
+              *te_head = NIL;
+   Var        *varnode;
+   int         varattno,
+               maxattrs;
+   Oid         type_id;
+   int         type_len;
+   RangeTblEntry *rte;
+
+   rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+   if (rte == NULL)
+       rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE);
+
+   rdesc = heap_open(rte->relid);
+
+   if (rdesc == NULL)
+   {
+       elog(WARN, "Unable to expand all -- heap_open failed on %s",
+            rte->refname);
+       return NIL;
+   }
+   maxattrs = RelationGetNumberOfAttributes(rdesc);
+
+   for (varattno = 0; varattno <= maxattrs - 1; varattno++)
+   {
+       char       *attrname;
+       char       *resname = NULL;
+       TargetEntry *te = makeNode(TargetEntry);
+
+       attrname = pstrdup((rdesc->rd_att->attrs[varattno]->attname).data);
+       varnode = (Var *) make_var(pstate, refname, attrname, &type_id);
+       type_len = (int) typeLen(typeidType(type_id));
+
+       handleTargetColname(pstate, &resname, refname, attrname);
+       if (resname != NULL)
+           attrname = resname;
+
+       /*
+        * Even if the elements making up a set are complex, the set
+        * itself is not.
+        */
+
+       te->resdom = makeResdom((AttrNumber) (*this_resno)++,
+                               type_id,
+                               (Size) type_len,
+                               attrname,
+                               (Index) 0,
+                               (Oid) 0,
+                               0);
+       te->expr = (Node *) varnode;
+       if (te_head == NIL)
+           te_head = te_tail = lcons(te, NIL);
+       else
+           te_tail = lappend(te_tail, te);
+   }
+
+   heap_close(rdesc);
+   return (te_head);
+}
+
+/* given relation and att name, return id of variable */
+int
+attnameAttNum(Relation rd, char *a)
+{
+   int         i;
+
+   for (i = 0; i < rd->rd_rel->relnatts; i++)
+       if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
+           return (i + 1);
+
+   for (i = 0; i < SPECIALS; i++)
+       if (!strcmp(special_attr[i].field, a))
+           return (special_attr[i].code);
+
+   /* on failure */
+   elog(WARN, "Relation %s does not have attribute %s",
+        RelationGetRelationName(rd), a);
+   return 0;  /* lint */
+}
+
+/* Given range variable, return whether attribute of this name
+ * is a set.
+ * NOTE the ASSUMPTION here that no system attributes are, or ever
+ * will be, sets.
+ */
+bool
+attnameIsSet(Relation rd, char *name)
+{
+   int         i;
+
+   /* First check if this is a system attribute */
+   for (i = 0; i < SPECIALS; i++)
+   {
+       if (!strcmp(special_attr[i].field, name))
+       {
+           return (false);     /* no sys attr is a set */
+       }
+   }
+   return (get_attisset(rd->rd_id, name));
+}
+
+/*-------------
+ * given an attribute number and a relation, return its relation name
+ */
+char      *
+attnumAttName(Relation rd, int attrno)
+{
+   char       *name;
+   int         i;
+
+   if (attrno < 0)
+   {
+       for (i = 0; i < SPECIALS; i++)
+       {
+           if (special_attr[i].code == attrno)
+           {
+               name = special_attr[i].field;
+               return (name);
+           }
+       }
+       elog(WARN, "Illegal attr no %d for relation %s",
+            attrno, RelationGetRelationName(rd));
+   }
+   else if (attrno >= 1 && attrno <= RelationGetNumberOfAttributes(rd))
+   {
+       name = (rd->rd_att->attrs[attrno - 1]->attname).data;
+       return (name);
+   }
+   else
+   {
+       elog(WARN, "Illegal attr no %d for relation %s",
+            attrno, RelationGetRelationName(rd));
+   }
+
+   /*
+    * Shouldn't get here, but we want lint to be happy...
+    */
+
+   return (NULL);
+}
+
+int
+attnumAttNelems(Relation rd, int attid)
+{
+   return (rd->rd_att->attrs[attid - 1]->attnelems);
+}
+
+Oid
+attnameTypeId(Oid relid, char *attrname)
+{
+   int         attid;
+   Oid         vartype;
+   Relation    rd;
+
+   rd = heap_open(relid);
+   if (!RelationIsValid(rd))
+   {
+       rd = heap_openr(typeidTypeName(relid));
+       if (!RelationIsValid(rd))
+           elog(WARN, "cannot compute type of att %s for relid %d",
+                attrname, relid);
+   }
+
+   attid = attnameAttNum(rd, attrname); /* could elog(WARN) and never return */
+
+   vartype = attnumTypeId(rd, attid);
+
+   /*
+    * close relation we're done with it now
+    */
+   heap_close(rd);
+
+   return (vartype);
+}
+
+/* given attribute id, return type of that attribute */
+/* XXX Special case for pseudo-attributes is a hack */
+Oid
+attnumTypeId(Relation rd, int attid)
+{
+
+   if (attid < 0)
+       return (typeTypeId(typenameType(attnum_type[-attid - 1])));
+
+   /*
+    * -1 because varattno (where attid comes from) returns one more than
+    * index
+    */
+   return (rd->rd_att->attrs[attid - 1]->atttypid);
+}
+
+/*
+ * handleTargetColname -
+ *   use column names from insert
+ */
+void
+handleTargetColname(ParseState *pstate, char **resname,
+                   char *refname, char *colname)
+{
+   if (pstate->p_is_insert)
+   {
+       if (pstate->p_insert_columns != NIL)
+       {
+           Ident      *id = lfirst(pstate->p_insert_columns);
+
+           *resname = id->name;
+           pstate->p_insert_columns = lnext(pstate->p_insert_columns);
+       }
+       else
+           elog(WARN, "insert: more expressions than target columns");
+   }
+   if (pstate->p_is_insert || pstate->p_is_update)
+       checkTargetTypes(pstate, *resname, refname, colname);
+}
+
+/*
+ * checkTargetTypes -
+ *   checks value and target column types
+ */
+void
+checkTargetTypes(ParseState *pstate, char *target_colname,
+                char *refname, char *colname)
+{
+   Oid         attrtype_id,
+               attrtype_target;
+   int         resdomno_id,
+               resdomno_target;
+   Relation    rd;
+   RangeTblEntry *rte;
+
+   if (target_colname == NULL || colname == NULL)
+       return;
+
+   if (refname != NULL)
+       rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+   else
+   {
+       rte = colnameRangeTableEntry(pstate, colname);
+       if (rte == (RangeTblEntry *) NULL)
+           elog(WARN, "attribute %s not found", colname);
+       refname = rte->refname;
+   }
+
+/*
+   if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
+       elog(WARN, "%s not available in this context", colname);
+*/
+   rd = heap_open(rte->relid);
+
+   resdomno_id = attnameAttNum(rd, colname);
+   attrtype_id = attnumTypeId(rd, resdomno_id);
+
+   resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname);
+   attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target);
+
+   if (attrtype_id != attrtype_target)
+       elog(WARN, "Type of %s does not match target column %s",
+            colname, target_colname);
+
+   if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) &&
+       rd->rd_att->attrs[resdomno_id - 1]->attlen !=
+   pstate->p_target_relation->rd_att->attrs[resdomno_target - 1]->attlen)
+       elog(WARN, "Length of %s does not match length of target column %s",
+            colname, target_colname);
+
+   heap_close(rd);
+}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
new file mode 100644 (file)
index 0000000..f29aa49
--- /dev/null
@@ -0,0 +1,679 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_target.c
+ *   handle target lists
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.1 1997/11/25 22:05:47 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include 
+#include 
+#include "postgres.h"
+#include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
+#include "nodes/primnodes.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "parser/parse_node.h"
+#include "utils/builtins.h"
+
+#ifdef 0
+#include "nodes/nodes.h"
+#include "nodes/params.h"
+#include "nodes/parsenodes.h"
+#include "nodes/relation.h"
+#include "parse.h"             /* for AND, OR, etc. */
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_proc.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "utils/mcxt.h"
+#include "utils/syscache.h"
+#include "utils/acl.h"
+#include "nodes/nodeFuncs.h"
+#include "commands/sequence.h"
+
+#include "optimizer/clauses.h"
+#include "access/heapam.h"
+
+#include "miscadmin.h"
+
+#include "port-protos.h"       /* strdup() */
+#endif
+
+/*
+ * transformTargetList -
+ *   turns a list of ResTarget's into a list of TargetEntry's
+ */
+List *
+transformTargetList(ParseState *pstate, List *targetlist)
+{
+   List       *p_target = NIL;
+   List       *tail_p_target = NIL;
+
+   while (targetlist != NIL)
+   {
+       ResTarget  *res = (ResTarget *) lfirst(targetlist);
+       TargetEntry *tent = makeNode(TargetEntry);
+
+       switch (nodeTag(res->val))
+       {
+           case T_Ident:
+               {
+                   Node       *expr;
+                   Oid         type_id;
+                   int         type_len;
+                   char       *identname;
+                   char       *resname;
+
+                   identname = ((Ident *) res->val)->name;
+                   handleTargetColname(pstate, &res->name, NULL, identname);
+
+                   /*
+                    * here we want to look for column names only, not relation
+                    * names (even though they can be stored in Ident nodes, too)
+                    */
+                   expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
+                   type_id = exprType(expr);
+                   type_len = typeLen(typeidType(type_id));
+                   resname = (res->name) ? res->name : identname;
+                   tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
+                                             (Oid) type_id,
+                                             (Size) type_len,
+                                             resname,
+                                             (Index) 0,
+                                             (Oid) 0,
+                                             0);
+
+                   tent->expr = expr;
+                   break;
+               }
+           case T_ParamNo:
+           case T_FuncCall:
+           case T_A_Const:
+           case T_A_Expr:
+               {
+                   Node       *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
+
+                   handleTargetColname(pstate, &res->name, NULL, NULL);
+                   /* note indirection has not been transformed */
+                   if (pstate->p_is_insert && res->indirection != NIL)
+                   {
+                       /* this is an array assignment */
+                       char       *val;
+                       char       *str,
+                                  *save_str;
+                       List       *elt;
+                       int         i = 0,
+                                   ndims;
+                       int         lindx[MAXDIM],
+                                   uindx[MAXDIM];
+                       int         resdomno;
+                       Relation    rd;
+                       Value      *constval;
+
+                       if (exprType(expr) != UNKNOWNOID ||
+                           !IsA(expr, Const))
+                           elog(WARN, "yyparse: string constant expected");
+
+                       val = (char *) textout((struct varlena *)
+                                          ((Const *) expr)->constvalue);
+                       str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
+                       foreach(elt, res->indirection)
+                       {
+                           A_Indices  *aind = (A_Indices *) lfirst(elt);
+
+                           aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
+                           if (!IsA(aind->uidx, Const))
+                               elog(WARN,
+                                    "Array Index for Append should be a constant");
+                           uindx[i] = ((Const *) aind->uidx)->constvalue;
+                           if (aind->lidx != NULL)
+                           {
+                               aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
+                               if (!IsA(aind->lidx, Const))
+                                   elog(WARN,
+                                        "Array Index for Append should be a constant");
+                               lindx[i] = ((Const *) aind->lidx)->constvalue;
+                           }
+                           else
+                           {
+                               lindx[i] = 1;
+                           }
+                           if (lindx[i] > uindx[i])
+                               elog(WARN, "yyparse: lower index cannot be greater than upper index");
+                           sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
+                           str += strlen(str);
+                           i++;
+                       }
+                       sprintf(str, "=%s", val);
+                       rd = pstate->p_target_relation;
+                       Assert(rd != NULL);
+                       resdomno = attnameAttNum(rd, res->name);
+                       ndims = attnumAttNelems(rd, resdomno);
+                       if (i != ndims)
+                           elog(WARN, "yyparse: array dimensions do not match");
+                       constval = makeNode(Value);
+                       constval->type = T_String;
+                       constval->val.str = save_str;
+                       tent = make_targetlist_expr(pstate, res->name,
+                                          (Node *) make_const(constval),
+                                                   NULL);
+                       pfree(save_str);
+                   }
+                   else
+                   {
+                       char       *colname = res->name;
+
+                       /* this is not an array assignment */
+                       if (colname == NULL)
+                       {
+
+                           /*
+                            * if you're wondering why this is here, look
+                            * at the yacc grammar for why a name can be
+                            * missing. -ay
+                            */
+                           colname = figureColname(expr, res->val);
+                       }
+                       if (res->indirection)
+                       {
+                           List       *ilist = res->indirection;
+
+                           while (ilist != NIL)
+                           {
+                               A_Indices  *ind = lfirst(ilist);
+
+                               ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
+                               ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
+                               ilist = lnext(ilist);
+                           }
+                       }
+                       res->name = colname;
+                       tent = make_targetlist_expr(pstate, res->name, expr,
+                                                   res->indirection);
+                   }
+                   break;
+               }
+           case T_Attr:
+               {
+                   Oid         type_id;
+                   int         type_len;
+                   Attr       *att = (Attr *) res->val;
+                   Node       *result;
+                   char       *attrname;
+                   char       *resname;
+                   Resdom     *resnode;
+                   List       *attrs = att->attrs;
+
+                   /*
+                    * Target item is a single '*', expand all tables (eg.
+                    * SELECT * FROM emp)
+                    */
+                   if (att->relname != NULL && !strcmp(att->relname, "*"))
+                   {
+                       if (tail_p_target == NIL)
+                           p_target = tail_p_target = expandAllTables(pstate);
+                       else
+                           lnext(tail_p_target) = expandAllTables(pstate);
+
+                       while (lnext(tail_p_target) != NIL)
+                           /* make sure we point to the last target entry */
+                           tail_p_target = lnext(tail_p_target);
+
+                       /*
+                        * skip rest of while loop
+                        */
+                       targetlist = lnext(targetlist);
+                       continue;
+                   }
+
+                   /*
+                    * Target item is relation.*, expand the table (eg.
+                    * SELECT emp.*, dname FROM emp, dept)
+                    */
+                   attrname = strVal(lfirst(att->attrs));
+                   if (att->attrs != NIL && !strcmp(attrname, "*"))
+                   {
+
+                       /*
+                        * tail_p_target is the target list we're building
+                        * in the while loop. Make sure we fix it after
+                        * appending more nodes.
+                        */
+                       if (tail_p_target == NIL)
+                           p_target = tail_p_target = expandAll(pstate, att->relname,
+                                   att->relname, &pstate->p_last_resno);
+                       else
+                           lnext(tail_p_target) =
+                               expandAll(pstate, att->relname, att->relname,
+                                         &pstate->p_last_resno);
+                       while (lnext(tail_p_target) != NIL)
+                           /* make sure we point to the last target entry */
+                           tail_p_target = lnext(tail_p_target);
+
+                       /*
+                        * skip the rest of the while loop
+                        */
+                       targetlist = lnext(targetlist);
+                       continue;
+                   }
+
+
+                   /*
+                    * Target item is fully specified: ie.
+                    * relation.attribute
+                    */
+                   result = handleNestedDots(pstate, att, &pstate->p_last_resno);
+                   handleTargetColname(pstate, &res->name, att->relname, attrname);
+                   if (att->indirection != NIL)
+                   {
+                       List       *ilist = att->indirection;
+
+                       while (ilist != NIL)
+                       {
+                           A_Indices  *ind = lfirst(ilist);
+
+                           ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
+                           ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
+                           ilist = lnext(ilist);
+                       }
+                       result = (Node *) make_array_ref(result, att->indirection);
+                   }
+                   type_id = exprType(result);
+                   type_len = typeLen(typeidType(type_id));
+                   /* move to last entry */
+                   while (lnext(attrs) != NIL)
+                       attrs = lnext(attrs);
+                   resname = (res->name) ? res->name : strVal(lfirst(attrs));
+                   resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
+                                        (Oid) type_id,
+                                        (Size) type_len,
+                                        resname,
+                                        (Index) 0,
+                                        (Oid) 0,
+                                        0);
+                   tent->resdom = resnode;
+                   tent->expr = result;
+                   break;
+               }
+           default:
+               /* internal error */
+               elog(WARN,
+                    "internal error: do not know how to transform targetlist");
+               break;
+       }
+
+       if (p_target == NIL)
+       {
+           p_target = tail_p_target = lcons(tent, NIL);
+       }
+       else
+       {
+           lnext(tail_p_target) = lcons(tent, NIL);
+           tail_p_target = lnext(tail_p_target);
+       }
+       targetlist = lnext(targetlist);
+   }
+
+   return p_target;
+}
+
+
+/*
+ * make_targetlist_expr -
+ *   make a TargetEntry from an expression
+ *
+ * arrayRef is a list of transformed A_Indices
+ */
+TargetEntry *
+make_targetlist_expr(ParseState *pstate,
+                    char *colname,
+                    Node *expr,
+                    List *arrayRef)
+{
+   Oid         type_id,
+               attrtype;
+   int         type_len,
+               attrlen;
+   int         resdomno;
+   Relation    rd;
+   bool        attrisset;
+   TargetEntry *tent;
+   Resdom     *resnode;
+
+   if (expr == NULL)
+       elog(WARN, "make_targetlist_expr: invalid use of NULL expression");
+
+   type_id = exprType(expr);
+   if (type_id == InvalidOid)
+   {
+       type_len = 0;
+   }
+   else
+       type_len = typeLen(typeidType(type_id));
+
+   /* I have no idea what the following does! */
+   /* It appears to process target columns that will be receiving results */
+   if (pstate->p_is_insert || pstate->p_is_update)
+   {
+
+       /*
+        * append or replace query -- append, replace work only on one
+        * relation, so multiple occurence of same resdomno is bogus
+        */
+       rd = pstate->p_target_relation;
+       Assert(rd != NULL);
+       resdomno = attnameAttNum(rd, colname);
+       attrisset = attnameIsSet(rd, colname);
+       attrtype = attnumTypeId(rd, resdomno);
+       if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
+           attrtype = GetArrayElementType(attrtype);
+       if (attrtype == BPCHAROID || attrtype == VARCHAROID)
+       {
+           attrlen = rd->rd_att->attrs[resdomno - 1]->attlen;
+       }
+       else
+       {
+           attrlen = typeLen(typeidType(attrtype));
+       }
+#if 0
+       if (Input_is_string && Typecast_ok)
+       {
+           Datum       val;
+
+           if (type_id == typeTypeId(type("unknown")))
+           {
+               val = (Datum) textout((struct varlena *)
+                                     ((Const) lnext(expr))->constvalue);
+           }
+           else
+           {
+               val = ((Const) lnext(expr))->constvalue;
+           }
+           if (attrisset)
+           {
+               lnext(expr) = makeConst(attrtype,
+                                       attrlen,
+                                       val,
+                                       false,
+                                       true,
+                                       true,   /* is set */
+                                       false);
+           }
+           else
+           {
+               lnext(expr) =
+                   makeConst(attrtype,
+                             attrlen,
+                             (Datum) fmgr(typeidRetinfunc(attrtype),
+                                        val, typeidTypElem(attrtype), -1),
+                             false,
+                             true /* Maybe correct-- 80% chance */ ,
+                             false,    /* is not a set */
+                             false);
+           }
+       }
+       else if ((Typecast_ok) && (attrtype != type_id))
+       {
+           lnext(expr) =
+               parser_typecast2(expr, typeidType(attrtype));
+       }
+       else if (attrtype != type_id)
+       {
+           if ((attrtype == INT2OID) && (type_id == INT4OID))
+               lfirst(expr) = lispInteger(INT2OID);    /* handle CASHOID too */
+           else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
+               lfirst(expr) = lispInteger(FLOAT4OID);
+           else
+               elog(WARN, "unequal type in tlist : %s \n", colname);
+       }
+
+       Input_is_string = false;
+       Input_is_integer = false;
+       Typecast_ok = true;
+#endif
+
+       if (attrtype != type_id)
+       {
+           if (IsA(expr, Const))
+           {
+               /* try to cast the constant */
+               if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
+               {
+                   /* updating a single item */
+                   Oid         typelem = typeidTypElem(attrtype);
+
+                   expr = (Node *) parser_typecast2(expr,
+                                                    type_id,
+                                                    typeidType(typelem),
+                                                    attrlen);
+               }
+               else
+                   expr = (Node *) parser_typecast2(expr,
+                                                    type_id,
+                                                  typeidType(attrtype),
+                                                    attrlen);
+           }
+           else
+           {
+               /* currently, we can't handle casting of expressions */
+               elog(WARN, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
+                    colname,
+                    typeidTypeName(attrtype),
+                    typeidTypeName(type_id));
+           }
+       }
+
+       if (arrayRef != NIL)
+       {
+           Expr       *target_expr;
+           Attr       *att = makeNode(Attr);
+           List       *ar = arrayRef;
+           List       *upperIndexpr = NIL;
+           List       *lowerIndexpr = NIL;
+
+           att->relname = pstrdup(RelationGetRelationName(rd)->data);
+           att->attrs = lcons(makeString(colname), NIL);
+           target_expr = (Expr *) handleNestedDots(pstate, att,
+                                                 &pstate->p_last_resno);
+           while (ar != NIL)
+           {
+               A_Indices  *ind = lfirst(ar);
+
+               if (lowerIndexpr || (!upperIndexpr && ind->lidx))
+               {
+
+                   /*
+                    * XXX assume all lowerIndexpr is non-null in this
+                    * case
+                    */
+                   lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
+               }
+               upperIndexpr = lappend(upperIndexpr, ind->uidx);
+               ar = lnext(ar);
+           }
+
+           expr = (Node *) make_array_set(target_expr,
+                                          upperIndexpr,
+                                          lowerIndexpr,
+                                          (Expr *) expr);
+           attrtype = attnumTypeId(rd, resdomno);
+           attrlen = typeLen(typeidType(attrtype));
+       }
+   }
+   else
+   {
+       resdomno = pstate->p_last_resno++;
+       attrtype = type_id;
+       attrlen = type_len;
+   }
+   tent = makeNode(TargetEntry);
+
+   resnode = makeResdom((AttrNumber) resdomno,
+                        (Oid) attrtype,
+                        (Size) attrlen,
+                        colname,
+                        (Index) 0,
+                        (Oid) 0,
+                        0);
+
+   tent->resdom = resnode;
+   tent->expr = expr;
+
+   return tent;
+}
+
+/*
+ * makeTargetNames -
+ *   generate a list of column names if not supplied or
+ *   test supplied column names to make sure they are in target table
+ *   (used exclusively for inserts)
+ */
+List *
+makeTargetNames(ParseState *pstate, List *cols)
+{
+   List       *tl = NULL;
+
+   /* Generate ResTarget if not supplied */
+
+   if (cols == NIL)
+   {
+       int         numcol;
+       int         i;
+       AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
+
+       numcol = pstate->p_target_relation->rd_rel->relnatts;
+       for (i = 0; i < numcol; i++)
+       {
+           Ident      *id = makeNode(Ident);
+
+           id->name = palloc(NAMEDATALEN);
+           StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
+           id->indirection = NIL;
+           id->isRel = false;
+           if (tl == NIL)
+               cols = tl = lcons(id, NIL);
+           else
+           {
+               lnext(tl) = lcons(id, NIL);
+               tl = lnext(tl);
+           }
+       }
+   }
+   else
+   {
+       foreach(tl, cols)
+       {
+           List       *nxt;
+           char       *name = ((Ident *) lfirst(tl))->name;
+       
+           /* elog on failure */
+           attnameAttNum(pstate->p_target_relation, name);
+           foreach(nxt, lnext(tl))
+               if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
+                   elog (WARN, "Attribute '%s' should be specified only once", name);
+       }
+   }
+   
+   return cols;
+}
+
+/*
+ * expandAllTables -
+ *   turns '*' (in the target list) into a list of attributes
+ *    (of all relations in the range table)
+ */
+List *
+expandAllTables(ParseState *pstate)
+{
+   List       *target = NIL;
+   List       *legit_rtable = NIL;
+   List       *rt,
+              *rtable;
+
+   rtable = pstate->p_rtable;
+   if (pstate->p_is_rule)
+   {
+
+       /*
+        * skip first two entries, "*new*" and "*current*"
+        */
+       rtable = lnext(lnext(pstate->p_rtable));
+   }
+
+   /* this should not happen */
+   if (rtable == NULL)
+       elog(WARN, "cannot expand: null p_rtable");
+
+   /*
+    * go through the range table and make a list of range table entries
+    * which we will expand.
+    */
+   foreach(rt, rtable)
+   {
+       RangeTblEntry *rte = lfirst(rt);
+
+       /*
+        * we only expand those specify in the from clause. (This will
+        * also prevent us from using the wrong table in inserts: eg.
+        * tenk2 in "insert into tenk2 select * from tenk1;")
+        */
+       if (!rte->inFromCl)
+           continue;
+       legit_rtable = lappend(legit_rtable, rte);
+   }
+
+   foreach(rt, legit_rtable)
+   {
+       RangeTblEntry *rte = lfirst(rt);
+       List       *temp = target;
+
+       if (temp == NIL)
+           target = expandAll(pstate, rte->relname, rte->refname,
+                              &pstate->p_last_resno);
+       else
+       {
+           while (temp != NIL && lnext(temp) != NIL)
+               temp = lnext(temp);
+           lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
+                                   &pstate->p_last_resno);
+       }
+   }
+   return target;
+}
+
+/*
+ * figureColname -
+ *   if the name of the resulting column is not specified in the target
+ *   list, we have to guess.
+ *
+ */
+char *
+figureColname(Node *expr, Node *resval)
+{
+   switch (nodeTag(expr))
+   {
+           case T_Aggreg:
+           return (char *)     /* XXX */
+           ((Aggreg *) expr)->aggname;
+       case T_Expr:
+           if (((Expr *) expr)->opType == FUNC_EXPR)
+           {
+               if (nodeTag(resval) == T_FuncCall)
+                   return ((FuncCall *) resval)->funcname;
+           }
+           break;
+       default:
+           break;
+   }
+
+   return "?column?";
+}
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
new file mode 100644 (file)
index 0000000..67632cd
--- /dev/null
@@ -0,0 +1,319 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_type.h
+ *     handle type operations for parser
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.1 1997/11/25 22:05:51 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include "postgres.h"
+#include "fmgr.h"
+
+#include 
+#include 
+#include 
+#include "utils/syscache.h"
+
+#ifdef 0
+#include "lib/dllist.h"
+#include "utils/datum.h"
+
+#include "utils/builtins.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/parsenodes.h"
+#include "catalog/catname.h"
+
+#include "catalog/pg_inherits.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
+#include "catalog/indexing.h"
+#include "catalog/catname.h"
+
+#include "access/skey.h"
+#include "access/relscan.h"
+#include "access/tupdesc.h"
+#include "access/htup.h"
+#include "access/heapam.h"
+#include "access/genam.h"
+#include "access/itup.h"
+#include "access/tupmacs.h"
+
+#include "storage/buf.h"
+#include "storage/bufmgr.h"
+#include "utils/lsyscache.h"
+#include "storage/lmgr.h"
+
+#include "port-protos.h"       /* strdup() */
+#endif
+
+/* check to see if a type id is valid,
+ * returns true if it is. By using this call before calling
+ * typeidType or typeidTypeName, more meaningful error messages
+ * can be produced because the caller typically has more context of
+ * what's going on                 - jolly
+ */
+bool
+typeidIsValid(Oid id)
+{
+   return (SearchSysCacheTuple(TYPOID,
+                               ObjectIdGetDatum(id),
+                               0, 0, 0) != NULL);
+}
+
+/* return a type name, given a typeid */
+char      *
+typeidTypeName(Oid id)
+{
+   HeapTuple   tup;
+   TypeTupleForm typetuple;
+
+   if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
+                                   0, 0, 0)))
+   {
+       elog(WARN, "type id lookup of %ud failed", id);
+       return (NULL);
+   }
+   typetuple = (TypeTupleForm) GETSTRUCT(tup);
+   return (typetuple->typname).data;
+}
+
+/* return a Type structure, given an typid */
+Type
+typeidType(Oid id)
+{
+   HeapTuple   tup;
+
+   if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
+                                   0, 0, 0)))
+   {
+       elog(WARN, "type id lookup of %ud failed", id);
+       return (NULL);
+   }
+   return ((Type) tup);
+}
+
+/* return a Type structure, given type name */
+Type
+typenameType(char *s)
+{
+   HeapTuple   tup;
+
+   if (s == NULL)
+   {
+       elog(WARN, "type(): Null type");
+   }
+
+   if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0, 0, 0)))
+   {
+       elog(WARN, "type name lookup of %s failed", s);
+   }
+   return ((Type) tup);
+}
+
+/* given type, return the type OID */
+Oid
+typeTypeId(Type tp)
+{
+   if (tp == NULL)
+       elog(WARN, "typeTypeId() called with NULL type struct");
+   return (tp->t_oid);
+}
+
+/* given type (as type struct), return the length of type */
+int16
+typeLen(Type t)
+{
+   TypeTupleForm typ;
+
+   typ = (TypeTupleForm) GETSTRUCT(t);
+   return (typ->typlen);
+}
+
+/* given type (as type struct), return the value of its 'byval' attribute.*/
+bool
+typeByVal(Type t)
+{
+   TypeTupleForm typ;
+
+   typ = (TypeTupleForm) GETSTRUCT(t);
+   return (typ->typbyval);
+}
+
+/* given type (as type struct), return the name of type */
+char      *
+typeTypeName(Type t)
+{
+   TypeTupleForm typ;
+
+   typ = (TypeTupleForm) GETSTRUCT(t);
+   return (typ->typname).data;
+}
+
+/* given a type, return its typetype ('c' for 'c'atalog types) */
+char
+typeTypeFlag(Type t)
+{
+   TypeTupleForm typ;
+
+   typ = (TypeTupleForm) GETSTRUCT(t);
+   return (typ->typtype);
+}
+
+/* Given a type structure and a string, returns the internal form of
+   that string */
+char *
+stringTypeString(Type tp, char *string, int typlen)
+{
+   Oid         op;
+   Oid         typelem;
+
+   op = ((TypeTupleForm) GETSTRUCT(tp))->typinput;
+   typelem = ((TypeTupleForm) GETSTRUCT(tp))->typelem; /* XXX - used for array_in */
+   /* typlen is for bpcharin() and varcharin() */
+   return ((char *) fmgr(op, string, typelem, typlen));
+}
+
+/* Given a type id, returns the out-conversion function of the type */
+Oid
+typeidRetoutfunc(Oid type_id)
+{
+   HeapTuple   typeTuple;
+   TypeTupleForm type;
+   Oid         outfunc;
+
+   typeTuple = SearchSysCacheTuple(TYPOID,
+                                   ObjectIdGetDatum(type_id),
+                                   0, 0, 0);
+   if (!HeapTupleIsValid(typeTuple))
+       elog(WARN, "typeidRetoutfunc: Invalid type - oid = %u", type_id);
+
+   type = (TypeTupleForm) GETSTRUCT(typeTuple);
+   outfunc = type->typoutput;
+   return (outfunc);
+}
+
+Oid
+typeidTypeRelid(Oid type_id)
+{
+   HeapTuple   typeTuple;
+   TypeTupleForm type;
+   Oid         infunc;
+
+   typeTuple = SearchSysCacheTuple(TYPOID,
+                                   ObjectIdGetDatum(type_id),
+                                   0, 0, 0);
+   if (!HeapTupleIsValid(typeTuple))
+       elog(WARN, "typeidTypeRelid: Invalid type - oid = %u", type_id);
+
+   type = (TypeTupleForm) GETSTRUCT(typeTuple);
+   infunc = type->typrelid;
+   return (infunc);
+}
+
+Oid
+typeTypeRelid(Type typ)
+{
+   TypeTupleForm typtup;
+
+   typtup = (TypeTupleForm) GETSTRUCT(typ);
+
+   return (typtup->typrelid);
+}
+
+Oid
+typeidTypElem(Oid type_id)
+{
+   HeapTuple   typeTuple;
+   TypeTupleForm type;
+
+   if (!(typeTuple = SearchSysCacheTuple(TYPOID,
+                                         ObjectIdGetDatum(type_id),
+                                         0, 0, 0)))
+   {
+       elog(WARN, "type id lookup of %u failed", type_id);
+   }
+   type = (TypeTupleForm) GETSTRUCT(typeTuple);
+
+   return (type->typelem);
+}
+
+/* Given the attribute type of an array return the arrtribute type of
+   an element of the array */
+
+Oid
+GetArrayElementType(Oid typearray)
+{
+   HeapTuple   type_tuple;
+   TypeTupleForm type_struct_array;
+
+   type_tuple = SearchSysCacheTuple(TYPOID,
+                                    ObjectIdGetDatum(typearray),
+                                    0, 0, 0);
+
+   if (!HeapTupleIsValid(type_tuple))
+       elog(WARN, "GetArrayElementType: Cache lookup failed for type %d",
+            typearray);
+
+   /* get the array type struct from the type tuple */
+   type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+   if (type_struct_array->typelem == InvalidOid)
+   {
+       elog(WARN, "GetArrayElementType: type %s is not an array",
+            (Name) &(type_struct_array->typname.data[0]));
+   }
+
+   return (type_struct_array->typelem);
+}
+
+/* Given a type id, returns the in-conversion function of the type */
+Oid
+typeidRetinfunc(Oid type_id)
+{
+   HeapTuple   typeTuple;
+   TypeTupleForm type;
+   Oid         infunc;
+
+   typeTuple = SearchSysCacheTuple(TYPOID,
+                                   ObjectIdGetDatum(type_id),
+                                   0, 0, 0);
+   if (!HeapTupleIsValid(typeTuple))
+       elog(WARN, "typeidRetinfunc: Invalid type - oid = %u", type_id);
+
+   type = (TypeTupleForm) GETSTRUCT(typeTuple);
+   infunc = type->typinput;
+   return (infunc);
+}
+
+
+#ifdef NOT_USED
+char
+FindDelimiter(char *typename)
+{
+   char        delim;
+   HeapTuple   typeTuple;
+   TypeTupleForm type;
+
+
+   if (!(typeTuple = SearchSysCacheTuple(TYPNAME,
+                                         PointerGetDatum(typename),
+                                         0, 0, 0)))
+   {
+       elog(WARN, "type name lookup of %s failed", typename);
+   }
+   type = (TypeTupleForm) GETSTRUCT(typeTuple);
+
+   delim = type->typdelim;
+   return (delim);
+}
+
+#endif
index d658c30896c8c21451fee4c6f5ce5274f8d30fd9..ea309c3c28ecb216ec4d64f2b727f0d057682c7a 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.28 1997/11/20 23:22:24 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.29 1997/11/25 22:05:52 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include 
 
 #include "postgres.h"
+#include "nodes/pg_list.h"
+#include "parser/parser.h"
+#include "parser/analyze.h"
+#include "parser/parse_node.h"
+
+void   init_io();      /* from scan.l */
+void   parser_init(Oid *typev, int nargs); /* from gram.y */
+int    yyparse();      /* from gram.c */
+
+#ifdef 0
+#include "parser/parse.h"
 #include "parser/gramparse.h"
-#include "parser/parse_query.h"
 #include "utils/palloc.h"
+#endif
 
 char      *parseString;        /* the char* which holds the string to be
                                 * parsed */
@@ -103,10 +114,10 @@ static void
 define_sets(Node *clause)
 {
    Oid         setoid;
-   Type        t = type("oid");
-   Oid         typeoid = typeid(t);
-   Size        oidsize = tlen(t);
-   bool        oidbyval = tbyval(t);
+   Type        t = typeidType(OIDOID);
+   Oid         typeoid = typeTypeId(t);
+   Size        oidsize = typeLen(t);
+   bool        oidbyval = typeByVal(t);
 
    if (clause == NULL)
    {
@@ -125,11 +136,11 @@ define_sets(Node *clause)
            return;
        }
        setoid = SetDefine(((Const *) clause)->constvalue,
-                          get_id_typname(((Const *) clause)->consttype));
+                          typeidTypeName(((Const *) clause)->consttype));
        set_constvalue((Const) clause, setoid);
        set_consttype((Const) clause, typeoid);
        set_constlen((Const) clause, oidsize);
-       set_constbyval((Const) clause, oidbyval);
+       set_constypeByVal((Const) clause, oidbyval);
    }
    else if (IsA(clause, Iter))
    {
@@ -173,6 +184,5 @@ define_sets(Node *clause)
        define_sets(get_rightop(clause));
    }
 }
-
 #endif
 
index dcc66145a5018cd54ec0f1e5541725e16375d4f4..e50757940aa3b0f6aa9b6029b9dfcc9686a95f4b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.7 1997/09/08 02:25:22 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.8 1997/11/25 22:05:55 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,6 @@
 
 #include 
 #include 
-#include "c.h"
 #include "postgres.h"
 #include "miscadmin.h"
 #include "utils/elog.h"
index 37d1e1c1555765b8cd52ae924fbf6a47324ade8d..c6f471915c3a9fa58e12188c5b2f9845155ba843 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.7 1997/10/25 05:37:07 thomas Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.8 1997/11/25 22:06:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,7 +23,8 @@
 #include "utils/lsyscache.h"   /* for get_typlen */
 #include "nodes/pg_list.h"     /* for Lisp support */
 #include "nodes/parsenodes.h"
-#include "parser/catalog_utils.h"
+#include "parser/parse_relation.h"
+
 #include "rewrite/locks.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteRemove.h"
@@ -107,7 +108,7 @@ InsertRule(char *rulname,
    if (evslot == NULL)
        evslot_index = -1;
    else
-       evslot_index = varattno(eventrel, (char *) evslot);
+       evslot_index = attnameAttNum(eventrel, (char *) evslot);
    heap_close(eventrel);
 
    if (evinstead)
@@ -221,8 +222,8 @@ DefineQueryRewrite(RuleStmt *stmt)
    }
    else
    {
-       event_attno = varattno(event_relation, eslot_string);
-       event_attype = att_typeid(event_relation, event_attno);
+       event_attno = attnameAttNum(event_relation, eslot_string);
+       event_attype = attnumTypeId(event_relation, event_attno);
    }
    heap_close(event_relation);
 
index 0b8a49f1882aecd85190b1f95ca3002d1ec227d6..0021213365c7125faa9b1a0add0932dbe0fff55b 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.19 1997/11/24 05:08:47 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.20 1997/11/25 22:06:08 momjian Exp $
  *
  * NOTES
  *   See acl.h.
 #include "catalog/pg_operator.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
 #include "catalog/pg_user.h"
+#include "parser/parse_agg.h"
+#include "parser/parse_func.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
-#include "parser/catalog_utils.h"
 #include "fmgr.h"
 
 static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
index 7659d90275cd0a1a4d1c474815bd2c75a8a4f3b0..d0d134e331ae54ebef0697097123cd4897057cbe 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.54 1997/11/10 15:24:55 thomas Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.55 1997/11/25 22:06:14 momjian Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
 
 #include "lib/dllist.h"
 
-#include "parser/catalog_utils.h"
-#include "parser/parse_query.h" /* for MakeTimeRange() */
 #include "commands/async.h"
 #include "tcop/tcopprot.h"     /* where declarations for this file go */
 #include "optimizer/planner.h"
+#include "parser/parser.h"
 
 #include "tcop/tcopprot.h"
 #include "tcop/tcopdebug.h"
@@ -1341,7 +1340,7 @@ PostgresMain(int argc, char *argv[])
    if (IsUnderPostmaster == false)
    {
        puts("\nPOSTGRES backend interactive interface");
-       puts("$Revision: 1.54 $ $Date: 1997/11/10 15:24:55 $");
+       puts("$Revision: 1.55 $ $Date: 1997/11/25 22:06:14 $");
    }
 
    /* ----------------
index 4a38e207e830a23f79373301b2f9f6c595fd399c..7a02f6aaabf89db565243c892f365c00445be7c7 100644 (file)
@@ -15,7 +15,6 @@
 #include "nodes/execnodes.h"
 #include "nodes/plannodes.h"
 #include "catalog/pg_proc.h"
-#include "parser/parse_query.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
index de5ad32ab5085b798c8faf3aa044e8904a998ca1..696f5f7fa66b6c2ea7ef7fb4516007ab10f0f20e 100644 (file)
@@ -6,13 +6,16 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodeFuncs.h,v 1.5 1997/09/08 21:52:45 momjian Exp $
+ * $Id: nodeFuncs.h,v 1.6 1997/11/25 22:06:30 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef NODEFUNCS_H
 #define NODEFUNCS_H
 
+#include 
+#include 
+
 extern bool single_node(Node *node);
 extern bool var_is_outer(Var *var);
 extern bool var_is_rel(Var *var);
index da90b768c611f6b973172a02c4b603bc6ae1a628..59bd8738d086c6cd0341614b10a428af03b73ca1 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: planner.h,v 1.5 1997/09/08 21:53:29 momjian Exp $
+ * $Id: planner.h,v 1.6 1997/11/25 22:06:37 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,8 @@
 /*
 */
 
+#include 
+
 extern Plan *planner(Query *parse);
 extern void pg_checkretval(Oid rettype, QueryTreeList *querytree_list);
 
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
new file mode 100644 (file)
index 0000000..a85e207
--- /dev/null
@@ -0,0 +1,19 @@
+/*-------------------------------------------------------------------------
+ *
+ * analyze.h
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: analyze.h,v 1.1 1997/11/25 22:06:47 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef ANALYZE_H
+#define ANALYZE_H
+
+#include 
+
+QueryTreeList *parse_analyze(List *pl);
+
+#endif                         /* ANALYZE_H */
diff --git a/src/include/parser/catalog_utils.h b/src/include/parser/catalog_utils.h
deleted file mode 100644 (file)
index 707ca3a..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * catalog_utils.h--
- *
- *
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- * $Id: catalog_utils.h,v 1.13 1997/09/08 21:53:35 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef CATALOG_UTILS_H
-#define CATALOG_UTILS_H
-
-#include 
-#include 
-
-typedef HeapTuple Type;
-typedef HeapTuple Operator;
-
-extern Type get_id_type(Oid id);
-extern char *get_id_typname(Oid id);
-extern Type type(char *);
-extern Oid att_typeid(Relation rd, int attid);
-extern int att_attnelems(Relation rd, int attid);
-extern Oid typeid(Type tp);
-extern int16 tlen(Type t);
-extern bool tbyval(Type t);
-extern char *tname(Type t);
-extern int tbyvalue(Type t);
-extern Oid oprid(Operator op);
-extern Operator oper(char *op, Oid arg1, Oid arg2, bool noWarnings);
-extern Operator right_oper(char *op, Oid arg);
-extern Operator left_oper(char *op, Oid arg);
-extern int varattno(Relation rd, char *a);
-extern bool varisset(Relation rd, char *name);
-extern int nf_varattno(Relation rd, char *a);
-extern char *getAttrName(Relation rd, int attrno);
-extern char *instr2(Type tp, char *string, int typlen);
-extern Oid GetArrayElementType(Oid typearray);
-extern Oid funcid_get_rettype(Oid funcid);
-extern bool
-func_get_detail(char *funcname, int nargs, Oid *oid_array,
-           Oid *funcid, Oid *rettype, bool *retset, Oid **true_typeids);
-extern Oid typeid_get_retinfunc(Oid type_id);
-extern Oid typeid_get_retoutfunc(Oid type_id);
-extern Oid typeid_get_relid(Oid type_id);
-extern Oid get_typrelid(Type typ);
-extern Oid get_typelem(Oid type_id);
-extern void func_error(char *caller, char *funcname, int nargs, Oid *argtypes);
-extern void agg_error(char *caller, char *aggname, Oid basetypeID);
-
-#endif                         /* CATALOG_UTILS_H */
diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h
new file mode 100644 (file)
index 0000000..21ef362
--- /dev/null
@@ -0,0 +1,38 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_agg.h
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_agg.h,v 1.1 1997/11/25 22:06:53 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_AGG_H
+#define PARSE_AGG_H
+
+#include 
+#include 
+#include 
+#include 
+
+void AddAggToParseState(ParseState *pstate, Aggreg *aggreg);
+
+void finalizeAggregates(ParseState *pstate, Query *qry);
+
+bool contain_agg_clause(Node *clause);
+
+bool exprIsAggOrGroupCol(Node *expr, List *groupClause);
+
+bool tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause);
+
+void parseCheckAggregates(ParseState *pstate, Query *qry);
+
+Aggreg *ParseAgg(char *aggname, Oid basetype, Node *target);
+
+void agg_error(char *caller, char *aggname, Oid basetypeID);
+
+#endif                         /* PARSE_AGG_H */
+
diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h
new file mode 100644 (file)
index 0000000..2c0a527
--- /dev/null
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_clause.h
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_clause.h,v 1.1 1997/11/25 22:06:54 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_CLAUSE_H
+#define PARSE_CLAUSE_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+void parseFromClause(ParseState *pstate, List *frmList);
+
+void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
+
+Node *transformWhereClause(ParseState *pstate, Node *a_expr);
+
+TargetEntry *find_targetlist_entry(ParseState *pstate,
+           SortGroupBy *sortgroupby, List *tlist);
+
+List *transformGroupClause(ParseState *pstate, List *grouplist,
+           List *targetlist);
+
+List *transformSortClause(ParseState *pstate,
+                   List *orderlist, List *targetlist,
+                   char *uniqueFlag);
+
+#endif                         /* PARSE_CLAUSE_H */
+
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
new file mode 100644 (file)
index 0000000..e7c4a04
--- /dev/null
@@ -0,0 +1,34 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_exer.h
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_expr.h,v 1.1 1997/11/25 22:06:55 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_EXPR_H
+#define PARSE_EXPR_H
+
+#include 
+#include 
+#include 
+#include 
+
+Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
+
+Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
+
+Oid exprType(Node *expr);
+
+Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
+
+Node *parser_typecast(Value *expr, TypeName *typename, int typlen);
+
+Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen);
+
+#endif                         /* PARSE_EXPR_H */
+
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
new file mode 100644 (file)
index 0000000..de8fc66
--- /dev/null
@@ -0,0 +1,97 @@
+/*-------------------------------------------------------------------------
+ *
+ * catalog_utils.h--
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_func.h,v 1.1 1997/11/25 22:06:56 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSER_FUNC_H
+#define PARSER_FUNC_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * This structure is used to explore the inheritance hierarchy above
+ * nodes in the type tree in order to disambiguate among polymorphic
+ * functions.
+ */
+typedef struct _InhPaths
+{
+   int         nsupers;        /* number of superclasses */
+   Oid         self;           /* this class */
+   Oid        *supervec;       /* vector of superclasses */
+} InhPaths;
+
+/*
+ * This structure holds a list of possible functions or operators that
+ * agree with the known name and argument types of the function/operator.
+ */
+typedef struct _CandidateList
+{
+   Oid        *args;
+   struct _CandidateList *next;
+}         *CandidateList;
+
+Node *ParseFunc(ParseState *pstate, char *funcname, List *fargs,
+   int *curr_resno);
+
+Oid funcid_get_rettype(Oid funcid);
+
+CandidateList func_get_candidates(char *funcname, int nargs);
+
+bool can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids);
+
+int match_argtypes(int nargs,
+                  Oid *input_typeids,
+                  CandidateList function_typeids,
+                  CandidateList *candidates);
+
+Oid * func_select_candidate(int nargs,
+                         Oid *input_typeids,
+                         CandidateList candidates);
+
+bool func_get_detail(char *funcname,
+                   int nargs,
+                   Oid *oid_array,
+                   Oid *funcid,    /* return value */
+                   Oid *rettype,   /* return value */
+                   bool *retset,   /* return value */
+                   Oid **true_typeids);
+
+Oid ** argtype_inherit(int nargs, Oid *oid_array);
+
+int findsupers(Oid relid, Oid **supervec);
+
+Oid **genxprod(InhPaths *arginh, int nargs);
+
+void make_arguments(int nargs,
+                  List *fargs,
+                  Oid *input_typeids,
+                  Oid *function_typeids);
+
+List *setup_tlist(char *attname, Oid relid);
+
+List *setup_base_tlist(Oid typeid);
+
+Node *ParseComplexProjection(ParseState *pstate,
+                          char *funcname,
+                          Node *first_arg,
+                          bool *attisset);
+   
+void func_error(char *caller, char *funcname, int nargs, Oid *argtypes);
+
+                  
+
+
+#endif                         /* PARSE_FUNC_H */
+
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
new file mode 100644 (file)
index 0000000..bac05cb
--- /dev/null
@@ -0,0 +1,67 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_node.h
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_node.h,v 1.1 1997/11/25 22:06:57 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_NODE_H
+#define PARSE_NODE_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+typedef struct QueryTreeList
+{
+   int         len;            /* number of queries */
+   Query     **qtrees;
+} QueryTreeList;
+
+/* state information used during parse analysis */
+typedef struct ParseState
+{
+   int         p_last_resno;
+   List       *p_rtable;
+   int         p_numAgg;
+   List       *p_aggs;
+   bool        p_is_insert;
+   List       *p_insert_columns;
+   bool        p_is_update;
+   bool        p_is_rule;
+   bool        p_in_where_clause;
+   Relation    p_target_relation;
+   RangeTblEntry *p_target_rangetblentry;
+} ParseState;
+
+ParseState *make_parsestate(void);
+
+Node *make_operand(char *opname,
+            Node *tree,
+            Oid orig_typeId,
+            Oid true_typeId);
+
+void disallow_setop(char *op, Type optype, Node *operand);
+
+Expr *make_op(char *opname, Node *ltree, Node *rtree);
+
+Var *make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id);
+
+ArrayRef   *make_array_ref(Node *expr,
+              List *indirection);
+
+ArrayRef   *make_array_set(Expr *target_expr,
+                          List *upperIndexpr,
+                          List *lowerIndexpr,
+                          Expr *expr);
+
+Const *make_const(Value *value);
+              
+#endif                         /* PARSE_NODE_H */
diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h
new file mode 100644 (file)
index 0000000..c013af6
--- /dev/null
@@ -0,0 +1,50 @@
+/*-------------------------------------------------------------------------
+ *
+ * catalog_utils.h--
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_oper.h,v 1.1 1997/11/25 22:06:59 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_OPER_H
+#define PARSE_OPER_H
+
+#include 
+#include 
+
+typedef HeapTuple Operator;
+
+Oid any_ordering_op(int restype);
+
+Oid oprid(Operator op);
+
+int binary_oper_get_candidates(char *opname,
+                          Oid leftTypeId,
+                          Oid rightTypeId,
+                          CandidateList *candidates);
+
+bool equivalentOpersAfterPromotion(CandidateList candidates);
+
+CandidateList binary_oper_select_candidate(Oid arg1,
+                            Oid arg2,
+                            CandidateList candidates);
+
+Operator oper(char *op, Oid arg1, Oid arg2, bool noWarnings);
+
+int
+unary_oper_get_candidates(char *op,
+                         Oid typeId,
+                         CandidateList *candidates,
+                         char rightleft);
+
+Operator right_oper(char *op, Oid arg);
+                         
+Operator left_oper(char *op, Oid arg);
+
+void op_error(char *op, Oid arg1, Oid arg2);
+
+#endif                         /* PARSE_OPER_H */
diff --git a/src/include/parser/parse_query.h b/src/include/parser/parse_query.h
deleted file mode 100644 (file)
index 0a7d534..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
- /*-------------------------------------------------------------------------
- *
- * parse_query.h--
- *   prototypes for parse_query.c.
- *
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- * $Id: parse_query.h,v 1.14 1997/11/20 23:23:53 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef PARSE_QUERY_H
-#define PARSE_QUERY_H
-
-#include 
-#include 
-#include 
-
-typedef struct QueryTreeList
-{
-   int         len;            /* number of queries */
-   Query     **qtrees;
-} QueryTreeList;
-
-extern RangeTblEntry *refnameRangeTableEntry(List *rtable, char *refname);
-extern RangeTblEntry *colnameRangeTableEntry(ParseState *pstate, char *colname);
-extern int refnameRangeTablePosn(List *rtable, char *refname);
-extern RangeTblEntry *
-addRangeTableEntry(ParseState *pstate,
-                  char *relname, char *refname,
-                  bool inh, bool inFromCl);
-extern List *
-expandAll(ParseState *pstate, char *relname, char *refname,
-         int *this_resno);
-extern Expr *make_op(char *opname, Node *ltree, Node *rtree);
-
-extern Oid find_atttype(Oid relid, char *attrname);
-extern Var *
-make_var(ParseState *pstate,
-        char *relname, char *attrname, Oid *type_id);
-extern ArrayRef *make_array_ref(Node *array, List *indirection);
-extern ArrayRef *
-make_array_set(Expr *target_expr, List *upperIndexpr,
-              List *lowerIndexpr, Expr *expr);
-extern Const *make_const(Value *value);
-
-extern void param_type_init(Oid *typev, int nargs);
-extern Oid param_type(int t);
-
-extern QueryTreeList *parser(char *str, Oid *typev, int nargs);
-
-extern void handleTargetColname(ParseState *pstate, char **resname,
-                   char *refname, char *colname);
-
-/*
- * analyze.c
- */
-
-Oid            exprType(Node *expr);
-QueryTreeList *parse_analyze(List *querytree_list);
-
-/* define in parse_query.c, used in gram.y */
-extern Oid *param_type_info;
-extern int pfunc_num_args;
-
-/* useful macros */
-#define ISCOMPLEX(type) (typeid_get_relid(type) ? true : false)
-
-#endif                         /* PARSE_QUERY_H */
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
new file mode 100644 (file)
index 0000000..ed47082
--- /dev/null
@@ -0,0 +1,56 @@
+ /*-------------------------------------------------------------------------
+ *
+ * parse_query.h--
+ *   prototypes for parse_query.c.
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_relation.h,v 1.1 1997/11/25 22:07:02 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_QUERY_H
+#define PARSE_RANGE_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+RangeTblEntry *refnameRangeTableEntry(List *rtable, char *refname);
+
+int refnameRangeTablePosn(List *rtable, char *refname);
+
+RangeTblEntry *colnameRangeTableEntry(ParseState *pstate, char *colname);
+
+RangeTblEntry *addRangeTableEntry(ParseState *pstate,
+                                  char *relname,
+                                  char *refname,
+                                  bool inh,
+                                  bool inFromCl);
+
+List *expandAll(ParseState *pstate, char *relname, char *refname,
+                       int *this_resno);
+
+int attnameAttNum(Relation rd, char *a);
+
+bool attnameIsSet(Relation rd, char *name);
+
+char *attnumAttName(Relation rd, int attrno);
+
+int attnumAttNelems(Relation rd, int attid);
+
+Oid attnameTypeId(Oid relid, char *attrname);
+
+Oid attnumTypeId(Relation rd, int attid);
+
+void handleTargetColname(ParseState *pstate, char **resname,
+                   char *refname, char *colname);
+
+void checkTargetTypes(ParseState *pstate, char *target_colname,
+                char *refname, char *colname);
+
+#endif                         /* PARSE_RANGE_H */
diff --git a/src/include/parser/parse_state.h b/src/include/parser/parse_state.h
deleted file mode 100644 (file)
index abda19b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * parse_state.h--
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- * $Id: parse_state.h,v 1.8 1997/09/08 21:53:40 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#ifndef PARSE_STATE_H
-#define PARSE_STATE_H
-
-#include 
-#include 
-
-/* state information used during parse analysis */
-typedef struct ParseState
-{
-   int         p_last_resno;
-   List       *p_rtable;
-   int         p_numAgg;
-   List       *p_aggs;
-   bool        p_is_insert;
-   List       *p_insert_columns;
-   bool        p_is_update;
-   bool        p_is_rule;
-   Relation    p_target_relation;
-   RangeTblEntry *p_target_rangetblentry;
-} ParseState;
-
-
-#endif                         /* PARSE_QUERY_H */
diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h
new file mode 100644 (file)
index 0000000..c7faa6b
--- /dev/null
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_target.h
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_target.h,v 1.1 1997/11/25 22:07:06 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_TARGET_H
+#define PARSE_TARGET_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define EXPR_COLUMN_FIRST  1
+#define EXPR_RELATION_FIRST    2
+
+List *transformTargetList(ParseState *pstate, List *targetlist);
+
+TargetEntry *make_targetlist_expr(ParseState *pstate,
+                    char *colname,
+                    Node *expr,
+                    List *arrayRef);
+
+List *expandAllTables(ParseState *pstate);
+
+char *figureColname(Node *expr, Node *resval);
+
+List *makeTargetNames(ParseState *pstate, List *cols);
+
+#endif                         /* PARSE_TARGET_H */
+
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
new file mode 100644 (file)
index 0000000..63c38ab
--- /dev/null
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_type.h
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parse_type.h,v 1.1 1997/11/25 22:07:07 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSE_TYPE_H
+#define PARSE_TYPE_H
+
+#include "access/htup.h"
+
+typedef HeapTuple Type;
+
+bool typeidIsValid(Oid id);
+Type typeidType(Oid id);
+Type typenameType(char *s);
+char *typeidTypeName(Oid id);
+Oid typeTypeId(Type tp);
+int16 typeLen(Type t);
+bool typeByVal(Type t);
+char *typeTypeName(Type t);
+char typeTypeFlag(Type t);
+char *stringTypeString(Type tp, char *string, int typlen);
+Oid typeidRetoutfunc(Oid type_id);
+Oid typeidTypeRelid(Oid type_id);
+Oid typeTypeRelid(Type typ);
+Oid typeidTypElem(Oid type_id);
+Oid GetArrayElementType(Oid typearray);
+Oid typeidRetinfunc(Oid type_id);
+
+#endif                         /* PARSE_TYPE_H */
diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h
new file mode 100644 (file)
index 0000000..4362ebb
--- /dev/null
@@ -0,0 +1,21 @@
+/*-------------------------------------------------------------------------
+ *
+ * parser.h
+ *
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: parser.h,v 1.1 1997/11/25 22:07:08 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PARSER_H
+#define PARSER_H
+
+#include 
+
+QueryTreeList *parser(char *str, Oid *typev, int nargs);
+
+#endif                         /* PARSER_H */
+
index 6142f24e9658af8b31149b6a0f7ad815438a590d..eeb21b91bed5a2fc0c989054b5dab47a555432c6 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tcopprot.h,v 1.7 1997/09/08 21:54:42 momjian Exp $
+ * $Id: tcopprot.h,v 1.8 1997/11/25 22:07:10 momjian Exp $
  *
  * OLD COMMENTS
  *   This file was created so that other c files could get the two
@@ -19,7 +19,7 @@
 #define TCOPPROT_H
 
 #include 
-#include query.h>
+#include node.h>
 
 #ifndef BOOTSTRAP_INCLUDE
 extern List *
index 1536dc2dba1e045d3062cd4fdabd8b519c100aea..39783cf46822cfbef5f40cdbf4012ee930e0f5b4 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/sh
 # check regression tests
-# usage:  checkresults < results.out
+# usage:  checkresults [ regress.out ]
+
+[ "$#" -eq 0 ] && set regress.out
 
 for file in `cat "$@" | grep 'failed$' | cut -d " " -f 1`
 do