LCOV - code coverage report
Current view: top level - src/backend/commands - aggregatecmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 136 161 84.5 %
Date: 2017-09-29 15:12:54 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * aggregatecmds.c
       4             :  *
       5             :  *    Routines for aggregate-manipulation commands
       6             :  *
       7             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/backend/commands/aggregatecmds.c
      13             :  *
      14             :  * DESCRIPTION
      15             :  *    The "DefineFoo" routines take the parse tree and pick out the
      16             :  *    appropriate arguments/flags, passing the results to the
      17             :  *    corresponding "FooDefine" routines (in src/catalog) that do
      18             :  *    the actual catalog-munging.  These routines also verify permission
      19             :  *    of the user to execute the command.
      20             :  *
      21             :  *-------------------------------------------------------------------------
      22             :  */
      23             : #include "postgres.h"
      24             : 
      25             : #include "access/htup_details.h"
      26             : #include "catalog/dependency.h"
      27             : #include "catalog/indexing.h"
      28             : #include "catalog/pg_aggregate.h"
      29             : #include "catalog/pg_proc.h"
      30             : #include "catalog/pg_type.h"
      31             : #include "commands/alter.h"
      32             : #include "commands/defrem.h"
      33             : #include "miscadmin.h"
      34             : #include "parser/parse_func.h"
      35             : #include "parser/parse_type.h"
      36             : #include "utils/acl.h"
      37             : #include "utils/builtins.h"
      38             : #include "utils/lsyscache.h"
      39             : #include "utils/syscache.h"
      40             : 
      41             : 
      42             : /*
      43             :  *  DefineAggregate
      44             :  *
      45             :  * "oldstyle" signals the old (pre-8.2) style where the aggregate input type
      46             :  * is specified by a BASETYPE element in the parameters.  Otherwise,
      47             :  * "args" is a pair, whose first element is a list of FunctionParameter structs
      48             :  * defining the agg's arguments (both direct and aggregated), and whose second
      49             :  * element is an Integer node with the number of direct args, or -1 if this
      50             :  * isn't an ordered-set aggregate.
      51             :  * "parameters" is a list of DefElem representing the agg's definition clauses.
      52             :  */
      53             : ObjectAddress
      54         119 : DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List *parameters)
      55             : {
      56             :     char       *aggName;
      57             :     Oid         aggNamespace;
      58             :     AclResult   aclresult;
      59         119 :     char        aggKind = AGGKIND_NORMAL;
      60         119 :     List       *transfuncName = NIL;
      61         119 :     List       *finalfuncName = NIL;
      62         119 :     List       *combinefuncName = NIL;
      63         119 :     List       *serialfuncName = NIL;
      64         119 :     List       *deserialfuncName = NIL;
      65         119 :     List       *mtransfuncName = NIL;
      66         119 :     List       *minvtransfuncName = NIL;
      67         119 :     List       *mfinalfuncName = NIL;
      68         119 :     bool        finalfuncExtraArgs = false;
      69         119 :     bool        mfinalfuncExtraArgs = false;
      70         119 :     List       *sortoperatorName = NIL;
      71         119 :     TypeName   *baseType = NULL;
      72         119 :     TypeName   *transType = NULL;
      73         119 :     TypeName   *mtransType = NULL;
      74         119 :     int32       transSpace = 0;
      75         119 :     int32       mtransSpace = 0;
      76         119 :     char       *initval = NULL;
      77         119 :     char       *minitval = NULL;
      78         119 :     char       *parallel = NULL;
      79             :     int         numArgs;
      80         119 :     int         numDirectArgs = 0;
      81             :     oidvector  *parameterTypes;
      82             :     ArrayType  *allParameterTypes;
      83             :     ArrayType  *parameterModes;
      84             :     ArrayType  *parameterNames;
      85             :     List       *parameterDefaults;
      86             :     Oid         variadicArgType;
      87             :     Oid         transTypeId;
      88         119 :     Oid         mtransTypeId = InvalidOid;
      89             :     char        transTypeType;
      90         119 :     char        mtransTypeType = 0;
      91         119 :     char        proparallel = PROPARALLEL_UNSAFE;
      92             :     ListCell   *pl;
      93             : 
      94             :     /* Convert list of names to a name and namespace */
      95         119 :     aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
      96             : 
      97             :     /* Check we have creation rights in target namespace */
      98         119 :     aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
      99         119 :     if (aclresult != ACLCHECK_OK)
     100           0 :         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
     101           0 :                        get_namespace_name(aggNamespace));
     102             : 
     103             :     /* Deconstruct the output of the aggr_args grammar production */
     104         119 :     if (!oldstyle)
     105             :     {
     106          61 :         Assert(list_length(args) == 2);
     107          61 :         numDirectArgs = intVal(lsecond(args));
     108          61 :         if (numDirectArgs >= 0)
     109           2 :             aggKind = AGGKIND_ORDERED_SET;
     110             :         else
     111          59 :             numDirectArgs = 0;
     112          61 :         args = linitial_node(List, args);
     113             :     }
     114             : 
     115             :     /* Examine aggregate's definition clauses */
     116         591 :     foreach(pl, parameters)
     117             :     {
     118         472 :         DefElem    *defel = lfirst_node(DefElem, pl);
     119             : 
     120             :         /*
     121             :          * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
     122             :          * for sfunc, stype, initcond.
     123             :          */
     124         472 :         if (pg_strcasecmp(defel->defname, "sfunc") == 0)
     125         114 :             transfuncName = defGetQualifiedName(defel);
     126         358 :         else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
     127           5 :             transfuncName = defGetQualifiedName(defel);
     128         353 :         else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
     129          53 :             finalfuncName = defGetQualifiedName(defel);
     130         300 :         else if (pg_strcasecmp(defel->defname, "combinefunc") == 0)
     131           2 :             combinefuncName = defGetQualifiedName(defel);
     132         298 :         else if (pg_strcasecmp(defel->defname, "serialfunc") == 0)
     133           5 :             serialfuncName = defGetQualifiedName(defel);
     134         293 :         else if (pg_strcasecmp(defel->defname, "deserialfunc") == 0)
     135           4 :             deserialfuncName = defGetQualifiedName(defel);
     136         289 :         else if (pg_strcasecmp(defel->defname, "msfunc") == 0)
     137           8 :             mtransfuncName = defGetQualifiedName(defel);
     138         281 :         else if (pg_strcasecmp(defel->defname, "minvfunc") == 0)
     139           8 :             minvtransfuncName = defGetQualifiedName(defel);
     140         273 :         else if (pg_strcasecmp(defel->defname, "mfinalfunc") == 0)
     141           0 :             mfinalfuncName = defGetQualifiedName(defel);
     142         273 :         else if (pg_strcasecmp(defel->defname, "finalfunc_extra") == 0)
     143           2 :             finalfuncExtraArgs = defGetBoolean(defel);
     144         271 :         else if (pg_strcasecmp(defel->defname, "mfinalfunc_extra") == 0)
     145           0 :             mfinalfuncExtraArgs = defGetBoolean(defel);
     146         271 :         else if (pg_strcasecmp(defel->defname, "sortop") == 0)
     147           0 :             sortoperatorName = defGetQualifiedName(defel);
     148         271 :         else if (pg_strcasecmp(defel->defname, "basetype") == 0)
     149          57 :             baseType = defGetTypeName(defel);
     150         214 :         else if (pg_strcasecmp(defel->defname, "hypothetical") == 0)
     151             :         {
     152           1 :             if (defGetBoolean(defel))
     153             :             {
     154           1 :                 if (aggKind == AGGKIND_NORMAL)
     155           0 :                     ereport(ERROR,
     156             :                             (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     157             :                              errmsg("only ordered-set aggregates can be hypothetical")));
     158           1 :                 aggKind = AGGKIND_HYPOTHETICAL;
     159             :             }
     160             :         }
     161         213 :         else if (pg_strcasecmp(defel->defname, "stype") == 0)
     162         114 :             transType = defGetTypeName(defel);
     163          99 :         else if (pg_strcasecmp(defel->defname, "stype1") == 0)
     164           5 :             transType = defGetTypeName(defel);
     165          94 :         else if (pg_strcasecmp(defel->defname, "sspace") == 0)
     166           1 :             transSpace = defGetInt32(defel);
     167          93 :         else if (pg_strcasecmp(defel->defname, "mstype") == 0)
     168           8 :             mtransType = defGetTypeName(defel);
     169          85 :         else if (pg_strcasecmp(defel->defname, "msspace") == 0)
     170           0 :             mtransSpace = defGetInt32(defel);
     171          85 :         else if (pg_strcasecmp(defel->defname, "initcond") == 0)
     172          79 :             initval = defGetString(defel);
     173           6 :         else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
     174           2 :             initval = defGetString(defel);
     175           4 :         else if (pg_strcasecmp(defel->defname, "minitcond") == 0)
     176           2 :             minitval = defGetString(defel);
     177           2 :         else if (pg_strcasecmp(defel->defname, "parallel") == 0)
     178           2 :             parallel = defGetString(defel);
     179             :         else
     180           0 :             ereport(WARNING,
     181             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     182             :                      errmsg("aggregate attribute \"%s\" not recognized",
     183             :                             defel->defname)));
     184             :     }
     185             : 
     186             :     /*
     187             :      * make sure we have our required definitions
     188             :      */
     189         119 :     if (transType == NULL)
     190           0 :         ereport(ERROR,
     191             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     192             :                  errmsg("aggregate stype must be specified")));
     193         119 :     if (transfuncName == NIL)
     194           0 :         ereport(ERROR,
     195             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     196             :                  errmsg("aggregate sfunc must be specified")));
     197             : 
     198             :     /*
     199             :      * if mtransType is given, mtransfuncName and minvtransfuncName must be as
     200             :      * well; if not, then none of the moving-aggregate options should have
     201             :      * been given.
     202             :      */
     203         119 :     if (mtransType != NULL)
     204             :     {
     205           8 :         if (mtransfuncName == NIL)
     206           0 :             ereport(ERROR,
     207             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     208             :                      errmsg("aggregate msfunc must be specified when mstype is specified")));
     209           8 :         if (minvtransfuncName == NIL)
     210           0 :             ereport(ERROR,
     211             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     212             :                      errmsg("aggregate minvfunc must be specified when mstype is specified")));
     213             :     }
     214             :     else
     215             :     {
     216         111 :         if (mtransfuncName != NIL)
     217           0 :             ereport(ERROR,
     218             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     219             :                      errmsg("aggregate msfunc must not be specified without mstype")));
     220         111 :         if (minvtransfuncName != NIL)
     221           0 :             ereport(ERROR,
     222             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     223             :                      errmsg("aggregate minvfunc must not be specified without mstype")));
     224         111 :         if (mfinalfuncName != NIL)
     225           0 :             ereport(ERROR,
     226             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     227             :                      errmsg("aggregate mfinalfunc must not be specified without mstype")));
     228         111 :         if (mtransSpace != 0)
     229           0 :             ereport(ERROR,
     230             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     231             :                      errmsg("aggregate msspace must not be specified without mstype")));
     232         111 :         if (minitval != NULL)
     233           0 :             ereport(ERROR,
     234             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     235             :                      errmsg("aggregate minitcond must not be specified without mstype")));
     236             :     }
     237             : 
     238             :     /*
     239             :      * look up the aggregate's input datatype(s).
     240             :      */
     241         119 :     if (oldstyle)
     242             :     {
     243             :         /*
     244             :          * Old style: use basetype parameter.  This supports aggregates of
     245             :          * zero or one input, with input type ANY meaning zero inputs.
     246             :          *
     247             :          * Historically we allowed the command to look like basetype = 'ANY'
     248             :          * so we must do a case-insensitive comparison for the name ANY. Ugh.
     249             :          */
     250             :         Oid         aggArgTypes[1];
     251             : 
     252          58 :         if (baseType == NULL)
     253           1 :             ereport(ERROR,
     254             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     255             :                      errmsg("aggregate input type must be specified")));
     256             : 
     257          57 :         if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
     258             :         {
     259           1 :             numArgs = 0;
     260           1 :             aggArgTypes[0] = InvalidOid;
     261             :         }
     262             :         else
     263             :         {
     264          56 :             numArgs = 1;
     265          56 :             aggArgTypes[0] = typenameTypeId(NULL, baseType);
     266             :         }
     267          57 :         parameterTypes = buildoidvector(aggArgTypes, numArgs);
     268          57 :         allParameterTypes = NULL;
     269          57 :         parameterModes = NULL;
     270          57 :         parameterNames = NULL;
     271          57 :         parameterDefaults = NIL;
     272          57 :         variadicArgType = InvalidOid;
     273             :     }
     274             :     else
     275             :     {
     276             :         /*
     277             :          * New style: args is a list of FunctionParameters (possibly zero of
     278             :          * 'em).  We share functioncmds.c's code for processing them.
     279             :          */
     280             :         Oid         requiredResultType;
     281             : 
     282          61 :         if (baseType != NULL)
     283           0 :             ereport(ERROR,
     284             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     285             :                      errmsg("basetype is redundant with aggregate input type specification")));
     286             : 
     287          61 :         numArgs = list_length(args);
     288          61 :         interpret_function_parameter_list(pstate,
     289             :                                           args,
     290             :                                           InvalidOid,
     291             :                                           true, /* is an aggregate */
     292             :                                           &parameterTypes,
     293             :                                           &allParameterTypes,
     294             :                                           &parameterModes,
     295             :                                           &parameterNames,
     296             :                                           &parameterDefaults,
     297             :                                           &variadicArgType,
     298             :                                           &requiredResultType);
     299             :         /* Parameter defaults are not currently allowed by the grammar */
     300          60 :         Assert(parameterDefaults == NIL);
     301             :         /* There shouldn't have been any OUT parameters, either */
     302          60 :         Assert(requiredResultType == InvalidOid);
     303             :     }
     304             : 
     305             :     /*
     306             :      * look up the aggregate's transtype.
     307             :      *
     308             :      * transtype can't be a pseudo-type, since we need to be able to store
     309             :      * values of the transtype.  However, we can allow polymorphic transtype
     310             :      * in some cases (AggregateCreate will check).  Also, we allow "internal"
     311             :      * for functions that want to pass pointers to private data structures;
     312             :      * but allow that only to superusers, since you could crash the system (or
     313             :      * worse) by connecting up incompatible internal-using functions in an
     314             :      * aggregate.
     315             :      */
     316         117 :     transTypeId = typenameTypeId(NULL, transType);
     317         117 :     transTypeType = get_typtype(transTypeId);
     318         117 :     if (transTypeType == TYPTYPE_PSEUDO &&
     319          40 :         !IsPolymorphicType(transTypeId))
     320             :     {
     321           7 :         if (transTypeId == INTERNALOID && superuser())
     322             :              /* okay */ ;
     323             :         else
     324           0 :             ereport(ERROR,
     325             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     326             :                      errmsg("aggregate transition data type cannot be %s",
     327             :                             format_type_be(transTypeId))));
     328             :     }
     329             : 
     330         117 :     if (serialfuncName && deserialfuncName)
     331             :     {
     332             :         /*
     333             :          * Serialization is only needed/allowed for transtype INTERNAL.
     334             :          */
     335           8 :         if (transTypeId != INTERNALOID)
     336           0 :             ereport(ERROR,
     337             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     338             :                      errmsg("serialization functions may be specified only when the aggregate transition data type is %s",
     339             :                             format_type_be(INTERNALOID))));
     340             :     }
     341         113 :     else if (serialfuncName || deserialfuncName)
     342             :     {
     343             :         /*
     344             :          * Cannot specify one function without the other.
     345             :          */
     346           1 :         ereport(ERROR,
     347             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     348             :                  errmsg("must specify both or neither of serialization and deserialization functions")));
     349             :     }
     350             : 
     351             :     /*
     352             :      * If a moving-aggregate transtype is specified, look that up.  Same
     353             :      * restrictions as for transtype.
     354             :      */
     355         116 :     if (mtransType)
     356             :     {
     357           8 :         mtransTypeId = typenameTypeId(NULL, mtransType);
     358           8 :         mtransTypeType = get_typtype(mtransTypeId);
     359           8 :         if (mtransTypeType == TYPTYPE_PSEUDO &&
     360           0 :             !IsPolymorphicType(mtransTypeId))
     361             :         {
     362           0 :             if (mtransTypeId == INTERNALOID && superuser())
     363             :                  /* okay */ ;
     364             :             else
     365           0 :                 ereport(ERROR,
     366             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     367             :                          errmsg("aggregate transition data type cannot be %s",
     368             :                                 format_type_be(mtransTypeId))));
     369             :         }
     370             :     }
     371             : 
     372             :     /*
     373             :      * If we have an initval, and it's not for a pseudotype (particularly a
     374             :      * polymorphic type), make sure it's acceptable to the type's input
     375             :      * function.  We will store the initval as text, because the input
     376             :      * function isn't necessarily immutable (consider "now" for timestamp),
     377             :      * and we want to use the runtime not creation-time interpretation of the
     378             :      * value.  However, if it's an incorrect value it seems much more
     379             :      * user-friendly to complain at CREATE AGGREGATE time.
     380             :      */
     381         116 :     if (initval && transTypeType != TYPTYPE_PSEUDO)
     382             :     {
     383             :         Oid         typinput,
     384             :                     typioparam;
     385             : 
     386          48 :         getTypeInputInfo(transTypeId, &typinput, &typioparam);
     387          48 :         (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
     388             :     }
     389             : 
     390             :     /*
     391             :      * Likewise for moving-aggregate initval.
     392             :      */
     393         116 :     if (minitval && mtransTypeType != TYPTYPE_PSEUDO)
     394             :     {
     395             :         Oid         typinput,
     396             :                     typioparam;
     397             : 
     398           2 :         getTypeInputInfo(mtransTypeId, &typinput, &typioparam);
     399           2 :         (void) OidInputFunctionCall(typinput, minitval, typioparam, -1);
     400             :     }
     401             : 
     402         116 :     if (parallel)
     403             :     {
     404           2 :         if (pg_strcasecmp(parallel, "safe") == 0)
     405           1 :             proparallel = PROPARALLEL_SAFE;
     406           1 :         else if (pg_strcasecmp(parallel, "restricted") == 0)
     407           0 :             proparallel = PROPARALLEL_RESTRICTED;
     408           1 :         else if (pg_strcasecmp(parallel, "unsafe") == 0)
     409           0 :             proparallel = PROPARALLEL_UNSAFE;
     410             :         else
     411           1 :             ereport(ERROR,
     412             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     413             :                      errmsg("parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE")));
     414             :     }
     415             : 
     416             :     /*
     417             :      * Most of the argument-checking is done inside of AggregateCreate
     418             :      */
     419         115 :     return AggregateCreate(aggName, /* aggregate name */
     420             :                            aggNamespace,    /* namespace */
     421             :                            aggKind,
     422             :                            numArgs,
     423             :                            numDirectArgs,
     424             :                            parameterTypes,
     425             :                            PointerGetDatum(allParameterTypes),
     426             :                            PointerGetDatum(parameterModes),
     427             :                            PointerGetDatum(parameterNames),
     428             :                            parameterDefaults,
     429             :                            variadicArgType,
     430             :                            transfuncName,   /* step function name */
     431             :                            finalfuncName,   /* final function name */
     432             :                            combinefuncName, /* combine function name */
     433             :                            serialfuncName,  /* serial function name */
     434             :                            deserialfuncName,    /* deserial function name */
     435             :                            mtransfuncName,  /* fwd trans function name */
     436             :                            minvtransfuncName,   /* inv trans function name */
     437             :                            mfinalfuncName,  /* final function name */
     438             :                            finalfuncExtraArgs,
     439             :                            mfinalfuncExtraArgs,
     440             :                            sortoperatorName,    /* sort operator name */
     441             :                            transTypeId, /* transition data type */
     442             :                            transSpace,  /* transition space */
     443             :                            mtransTypeId,    /* transition data type */
     444             :                            mtransSpace, /* transition space */
     445             :                            initval, /* initial condition */
     446             :                            minitval,    /* initial condition */
     447             :                            proparallel);    /* parallel safe? */
     448             : }

Generated by: LCOV version 1.11