]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Define routines and catalog entries for string min()/max() functions.
authorThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 8 Dec 1998 06:19:15 +0000 (06:19 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 8 Dec 1998 06:19:15 +0000 (06:19 +0000)
Extend new type coersion techniques to aggregates.
Clean up a few elog() messages.

src/backend/parser/parse_agg.c
src/backend/parser/parse_func.c
src/backend/parser/parse_oper.c
src/backend/utils/adt/varlena.c

index eef2808f50da9dd94747cfbe5c9252aabda2eb21..8aa940413228f19e4c6f3dfee94ec5df3d84c1dc 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.14 1998/09/09 03:48:17 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.15 1998/12/08 06:18:56 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_node.h"
 #include "parser/parse_target.h"
+#include "parser/parse_coerce.h"
 #include "utils/syscache.h"
 #include "utils/lsyscache.h"
 
@@ -149,7 +150,7 @@ tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
                if (tle->resdom->resno == grpcl->entry->resdom->resno)
                {
                        if (contain_agg_clause((Node *) expr))
-                               elog(ERROR, "parser: aggregates not allowed in GROUP BY clause");
+                               elog(ERROR, "Aggregates not allowed in GROUP BY clause");
                        return TRUE;
                }
        }
@@ -189,7 +190,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
         * non-group column in target list may fail.)
         */
        if (contain_agg_clause(qry->qual))
-               elog(ERROR, "parser: aggregates not allowed in WHERE clause");
+               elog(ERROR, "Aggregates not allowed in WHERE clause");
 
        /*
         * the target list can only contain aggregates, group columns and
@@ -201,7 +202,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
 
                if (!tleIsAggOrGroupCol(tle, qry->groupClause))
                        elog(ERROR,
-                                "parser: illegal use of aggregates or non-group column in target list");
+                                "Illegal use of aggregates or non-group column in target list");
        }
 
        /*
@@ -211,7 +212,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
 
        if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
                elog(ERROR,
-                        "parser: illegal use of aggregates or non-group column in HAVING clause");
+                        "Illegal use of aggregates or non-group column in HAVING clause");
        return;
 }
 
@@ -233,7 +234,7 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
                                                                          ObjectIdGetDatum(basetype),
                                                                          0, 0);
        if (!HeapTupleIsValid(theAggTuple))
-               elog(ERROR, "aggregate %s does not exist", aggname);
+               elog(ERROR, "Aggregate %s does not exist", aggname);
 
        /*
         * We do a major hack for count(*) here.
@@ -309,16 +310,17 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
                else
                        vartype = ((Expr *) lfirst(target))->typeOid;
 
-               if (basetype != vartype)
+               if ((basetype != vartype)
+                       && (! IS_BINARY_COMPATIBLE(basetype, vartype)))
                {
                        Type            tp1,
                                                tp2;
 
                        tp1 = typeidType(basetype);
                        tp2 = typeidType(vartype);
-                       elog(NOTICE, "Aggregate type mismatch:");
-                       elog(ERROR, "%s works on %s, not %s", aggname,
-                                typeTypeName(tp1), typeTypeName(tp2));
+                       elog(ERROR, "Aggregate type mismatch"
+                                               "\n\t%s() works on %s, not on %s",
+                                                aggname, typeTypeName(tp1), typeTypeName(tp2));
                }
        }
 
index 81b887e8a5fd2329801813427070264aca44dabc..e1a625f9ef2611d50489d8139fdcf6d92ff6f0e2 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.31 1998/11/27 19:52:13 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.32 1998/12/08 06:18:56 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,6 +25,7 @@
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_aggregate.h"
 #include "fmgr.h"
 #include "lib/dllist.h"
 #include "miscadmin.h"
@@ -76,6 +77,8 @@ static List *setup_tlist(char *attname, Oid relid);
 static List *setup_base_tlist(Oid typeid);
 static Oid *func_select_candidate(int nargs, Oid *input_typeids,
                                CandidateList candidates);
+static int agg_get_candidates(char *aggname, Oid typeId, CandidateList *candidates);
+static Oid agg_select_candidate(Oid typeid, CandidateList candidates);
 
 #define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)
 
@@ -130,6 +133,108 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int pre
        return retval;
 }
 
+static int
+agg_get_candidates(char *aggname,
+                                  Oid typeId,
+                                  CandidateList *candidates)
+{
+       CandidateList           current_candidate;
+       Relation                        pg_aggregate_desc;
+       HeapScanDesc            pg_aggregate_scan;
+       HeapTuple                       tup;
+       Form_pg_aggregate       agg;
+       int                                     ncandidates = 0;
+
+       static ScanKeyData aggKey[1] = {
+       {0, Anum_pg_aggregate_aggname, F_NAMEEQ}};
+
+       *candidates = NULL;
+
+       fmgr_info(F_NAMEEQ, (FmgrInfo *) &aggKey[0].sk_func);
+       aggKey[0].sk_argument = NameGetDatum(aggname);
+
+       pg_aggregate_desc = heap_openr(AggregateRelationName);
+       pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,
+                                                                          0,
+                                                                          SnapshotSelf,     /* ??? */
+                                                                          1,
+                                                                          aggKey);
+
+       while (HeapTupleIsValid(tup = heap_getnext(pg_aggregate_scan, 0)))
+       {
+               current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+               current_candidate->args = (Oid *) palloc(sizeof(Oid));
+
+               agg = (Form_pg_aggregate) GETSTRUCT(tup);
+               current_candidate->args[0] = agg->aggbasetype;
+               current_candidate->next = *candidates;
+               *candidates = current_candidate;
+               ncandidates++;
+       }
+
+       heap_endscan(pg_aggregate_scan);
+       heap_close(pg_aggregate_desc);
+
+       return ncandidates;
+}      /* agg_get_candidates() */
+
+/* agg_select_candidate()
+ * Try to choose only one candidate aggregate function from a list of possibles.
+ */
+static Oid
+agg_select_candidate(Oid typeid, CandidateList candidates)
+{
+       CandidateList   current_candidate;
+       CandidateList   last_candidate;
+       Oid                             current_typeid;
+       int                             ncandidates;
+       CATEGORY                category,
+                                       current_category;
+
+/*
+ * Look for candidates which allow coersion and have a preferred type.
+ * Keep all candidates if none match.
+ */
+       category = TypeCategory(typeid);
+       ncandidates = 0;
+       last_candidate = NULL;
+       for (current_candidate = candidates;
+                current_candidate != NULL;
+                current_candidate = current_candidate->next)
+       {
+               current_typeid = current_candidate->args[0];
+               current_category = TypeCategory(current_typeid);
+
+               if ((current_category == category)
+                       && IsPreferredType(current_category, current_typeid)
+                       && can_coerce_type(1, &typeid, &current_typeid))
+               {
+                       /* only one so far? then keep it... */
+                       if (last_candidate == NULL)
+                       {
+                               candidates = current_candidate;
+                               last_candidate = current_candidate;
+                               ncandidates = 1;
+                       }
+                       /* otherwise, keep this one too... */
+                       else
+                       {
+                               last_candidate->next = current_candidate;
+                               last_candidate = current_candidate;
+                               ncandidates++;
+                       }
+               }
+               /* otherwise, don't bother keeping this one around... */
+               else
+               {
+                       last_candidate->next = NULL;
+               }
+       }
+
+       return ((ncandidates == 1) ? candidates->args[0] : 0);
+}   /* agg_select_candidate() */
+
+
 /*
  * parse function
  */
@@ -250,8 +355,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                        /*
                         * Parsing aggregates.
                         */
-                       Type            tp;
-                       Oid                     basetype;
+                       Type                    tp;
+                       Oid                             basetype;
+                       int                             ncandidates;
+                       CandidateList   candidates;
+
 
                        /*
                         * the aggregate COUNT is a special case, ignore its base
@@ -261,6 +369,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                                basetype = 0;
                        else
                                basetype = exprType(lfirst(fargs));
+
+                       /* try for exact match first... */
                        if (SearchSysCacheTuple(AGGNAME,
                                                                        PointerGetDatum(funcname),
                                                                        ObjectIdGetDatum(basetype),
@@ -268,16 +378,47 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                                return (Node *) ParseAgg(pstate, funcname, basetype,
                                                                                 fargs, precedence);
 
+                       /*
+                        * No exact match yet, so see if there is another entry
+                        * in the aggregate table which is compatible.
+                        * - thomas 1998-12-05
+                        */
+                       ncandidates = agg_get_candidates(funcname, basetype, &candidates);
+                       if (ncandidates > 0)
+                       {
+                               Oid             type;
+
+                               type = agg_select_candidate(basetype, candidates);
+                               if (OidIsValid(type))
+                               {
+                                       lfirst(fargs) = coerce_type(pstate, lfirst(fargs), basetype, type);
+                                       basetype = type;
+
+                                       return (Node *) ParseAgg(pstate, funcname, basetype,
+                                                                                        fargs, precedence);
+                               }
+                               else
+                               {
+                                       elog(ERROR,"Unable to select an aggregate function for type %s",
+                                                typeidTypeName(basetype));
+                               }
+                       }
+
                        /*
                         * See if this is a single argument function with the function
                         * name also a type name and the input argument and type name
                         * binary compatible...
+                        * This means that you are trying for a type conversion which does not
+                        * need to take place, so we'll just pass through the argument itself.
+                        * (make this clearer with some extra brackets - thomas 1998-12-05)
                         */
                        if ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPNAME,
-                                                                                          PointerGetDatum(funcname),
+                                                                                                                  PointerGetDatum(funcname),
                                                                                                                   0, 0, 0)))
                                && IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))
+                       {
                                return ((Node *) lfirst(fargs));
+                       }
                }
        }
 
index f9e13f160421965bd89af64febb2227de647def9..6ee4d216099423605606a613f4cb512b23a6f1d9 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.21 1998/11/27 19:52:14 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.22 1998/12/08 06:18:57 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -210,6 +210,7 @@ oper_select_candidate(int nargs,
                                nmatch++;
                }
 
+               /* take this one as the best choice so far? */
                if ((nmatch > nbestMatch) || (last_candidate == NULL))
                {
                        nbestMatch = nmatch;
@@ -217,12 +218,14 @@ oper_select_candidate(int nargs,
                        last_candidate = current_candidate;
                        ncandidates = 1;
                }
+               /* no worse than the last choice, so keep this one too? */
                else if (nmatch == nbestMatch)
                {
                        last_candidate->next = current_candidate;
                        last_candidate = current_candidate;
                        ncandidates++;
                }
+               /* otherwise, don't bother keeping this one... */
                else
                {
                        last_candidate->next = NULL;
index 4be36bbba82f8972e387763f1320c854a19cae45..963abf97b3d29941486968598fbe3f4e6501da1e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.44 1998/10/08 18:30:12 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.45 1998/12/08 06:19:15 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -577,6 +577,38 @@ text_ge(text *arg1, text *arg2)
        return (bool) !text_lt(arg1, arg2);
 }
 
+text *
+text_larger(text *arg1, text *arg2)
+{
+       text *result;
+       text *temp;
+
+       temp = ((text_cmp(arg1, arg2) <= 0)? arg2: arg1);
+
+       /* Make a copy */
+
+       result = (text *) palloc(VARSIZE(temp));
+       memmove((char *) result, (char *) temp, VARSIZE(temp));
+
+       return (result);
+}
+
+text *
+text_smaller(text *arg1, text *arg2)
+{
+       text *result;
+       text *temp;
+
+       temp = ((text_cmp(arg1, arg2) > 0)? arg2: arg1);
+
+       /* Make a copy */
+
+       result = (text *) palloc(VARSIZE(temp));
+       memmove((char *) result, (char *) temp, VARSIZE(temp));
+
+       return (result);
+}
+
 /*-------------------------------------------------------------
  * byteaGetSize
  *