Header And Logo

PostgreSQL
| The world's most advanced open source database.

operatorcmds.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * operatorcmds.c
00004  *
00005  *    Routines for operator manipulation commands
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  *
00011  * IDENTIFICATION
00012  *    src/backend/commands/operatorcmds.c
00013  *
00014  * DESCRIPTION
00015  *    The "DefineFoo" routines take the parse tree and pick out the
00016  *    appropriate arguments/flags, passing the results to the
00017  *    corresponding "FooDefine" routines (in src/catalog) that do
00018  *    the actual catalog-munging.  These routines also verify permission
00019  *    of the user to execute the command.
00020  *
00021  * NOTES
00022  *    These things must be defined and committed in the following order:
00023  *      "create function":
00024  *              input/output, recv/send procedures
00025  *      "create type":
00026  *              type
00027  *      "create operator":
00028  *              operators
00029  *
00030  *      Most of the parse-tree manipulation routines are defined in
00031  *      commands/manip.c.
00032  *
00033  *-------------------------------------------------------------------------
00034  */
00035 #include "postgres.h"
00036 
00037 #include "access/heapam.h"
00038 #include "access/htup_details.h"
00039 #include "catalog/dependency.h"
00040 #include "catalog/indexing.h"
00041 #include "catalog/pg_operator.h"
00042 #include "catalog/pg_type.h"
00043 #include "commands/alter.h"
00044 #include "commands/defrem.h"
00045 #include "miscadmin.h"
00046 #include "parser/parse_func.h"
00047 #include "parser/parse_oper.h"
00048 #include "parser/parse_type.h"
00049 #include "utils/builtins.h"
00050 #include "utils/lsyscache.h"
00051 #include "utils/rel.h"
00052 #include "utils/syscache.h"
00053 
00054 /*
00055  * DefineOperator
00056  *      this function extracts all the information from the
00057  *      parameter list generated by the parser and then has
00058  *      OperatorCreate() do all the actual work.
00059  *
00060  * 'parameters' is a list of DefElem
00061  */
00062 Oid
00063 DefineOperator(List *names, List *parameters)
00064 {
00065     char       *oprName;
00066     Oid         oprNamespace;
00067     AclResult   aclresult;
00068     bool        canMerge = false;       /* operator merges */
00069     bool        canHash = false;    /* operator hashes */
00070     List       *functionName = NIL;     /* function for operator */
00071     TypeName   *typeName1 = NULL;       /* first type name */
00072     TypeName   *typeName2 = NULL;       /* second type name */
00073     Oid         typeId1 = InvalidOid;   /* types converted to OID */
00074     Oid         typeId2 = InvalidOid;
00075     Oid         rettype;
00076     List       *commutatorName = NIL;   /* optional commutator operator name */
00077     List       *negatorName = NIL;      /* optional negator operator name */
00078     List       *restrictionName = NIL;  /* optional restrict. sel. procedure */
00079     List       *joinName = NIL; /* optional join sel. procedure */
00080     Oid         functionOid;    /* functions converted to OID */
00081     Oid         restrictionOid;
00082     Oid         joinOid;
00083     Oid         typeId[5];      /* only need up to 5 args here */
00084     int         nargs;
00085     ListCell   *pl;
00086 
00087     /* Convert list of names to a name and namespace */
00088     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
00089 
00090     /*
00091      * The SQL standard committee has decided that => should be used for named
00092      * parameters; therefore, a future release of PostgreSQL may disallow it
00093      * as the name of a user-defined operator.
00094      */
00095     if (strcmp(oprName, "=>") == 0)
00096         ereport(WARNING,
00097                 (errmsg("=> is deprecated as an operator name"),
00098                  errdetail("This name may be disallowed altogether in future versions of PostgreSQL.")));
00099 
00100     /* Check we have creation rights in target namespace */
00101     aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
00102     if (aclresult != ACLCHECK_OK)
00103         aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00104                        get_namespace_name(oprNamespace));
00105 
00106     /*
00107      * loop over the definition list and extract the information we need.
00108      */
00109     foreach(pl, parameters)
00110     {
00111         DefElem    *defel = (DefElem *) lfirst(pl);
00112 
00113         if (pg_strcasecmp(defel->defname, "leftarg") == 0)
00114         {
00115             typeName1 = defGetTypeName(defel);
00116             if (typeName1->setof)
00117                 ereport(ERROR,
00118                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00119                     errmsg("SETOF type not allowed for operator argument")));
00120         }
00121         else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
00122         {
00123             typeName2 = defGetTypeName(defel);
00124             if (typeName2->setof)
00125                 ereport(ERROR,
00126                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00127                     errmsg("SETOF type not allowed for operator argument")));
00128         }
00129         else if (pg_strcasecmp(defel->defname, "procedure") == 0)
00130             functionName = defGetQualifiedName(defel);
00131         else if (pg_strcasecmp(defel->defname, "commutator") == 0)
00132             commutatorName = defGetQualifiedName(defel);
00133         else if (pg_strcasecmp(defel->defname, "negator") == 0)
00134             negatorName = defGetQualifiedName(defel);
00135         else if (pg_strcasecmp(defel->defname, "restrict") == 0)
00136             restrictionName = defGetQualifiedName(defel);
00137         else if (pg_strcasecmp(defel->defname, "join") == 0)
00138             joinName = defGetQualifiedName(defel);
00139         else if (pg_strcasecmp(defel->defname, "hashes") == 0)
00140             canHash = defGetBoolean(defel);
00141         else if (pg_strcasecmp(defel->defname, "merges") == 0)
00142             canMerge = defGetBoolean(defel);
00143         /* These obsolete options are taken as meaning canMerge */
00144         else if (pg_strcasecmp(defel->defname, "sort1") == 0)
00145             canMerge = true;
00146         else if (pg_strcasecmp(defel->defname, "sort2") == 0)
00147             canMerge = true;
00148         else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
00149             canMerge = true;
00150         else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
00151             canMerge = true;
00152         else
00153             ereport(WARNING,
00154                     (errcode(ERRCODE_SYNTAX_ERROR),
00155                      errmsg("operator attribute \"%s\" not recognized",
00156                             defel->defname)));
00157     }
00158 
00159     /*
00160      * make sure we have our required definitions
00161      */
00162     if (functionName == NIL)
00163         ereport(ERROR,
00164                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00165                  errmsg("operator procedure must be specified")));
00166 
00167     /* Transform type names to type OIDs */
00168     if (typeName1)
00169         typeId1 = typenameTypeId(NULL, typeName1);
00170     if (typeName2)
00171         typeId2 = typenameTypeId(NULL, typeName2);
00172 
00173     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
00174         ereport(ERROR,
00175                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00176            errmsg("at least one of leftarg or rightarg must be specified")));
00177 
00178     if (typeName1)
00179     {
00180         aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
00181         if (aclresult != ACLCHECK_OK)
00182             aclcheck_error_type(aclresult, typeId1);
00183     }
00184 
00185     if (typeName2)
00186     {
00187         aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
00188         if (aclresult != ACLCHECK_OK)
00189             aclcheck_error_type(aclresult, typeId2);
00190     }
00191 
00192     /*
00193      * Look up the operator's underlying function.
00194      */
00195     if (!OidIsValid(typeId1))
00196     {
00197         typeId[0] = typeId2;
00198         nargs = 1;
00199     }
00200     else if (!OidIsValid(typeId2))
00201     {
00202         typeId[0] = typeId1;
00203         nargs = 1;
00204     }
00205     else
00206     {
00207         typeId[0] = typeId1;
00208         typeId[1] = typeId2;
00209         nargs = 2;
00210     }
00211     functionOid = LookupFuncName(functionName, nargs, typeId, false);
00212 
00213     /*
00214      * We require EXECUTE rights for the function.  This isn't strictly
00215      * necessary, since EXECUTE will be checked at any attempted use of the
00216      * operator, but it seems like a good idea anyway.
00217      */
00218     aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
00219     if (aclresult != ACLCHECK_OK)
00220         aclcheck_error(aclresult, ACL_KIND_PROC,
00221                        NameListToString(functionName));
00222 
00223     rettype = get_func_rettype(functionOid);
00224     aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
00225     if (aclresult != ACLCHECK_OK)
00226         aclcheck_error_type(aclresult, rettype);
00227 
00228     /*
00229      * Look up restriction estimator if specified
00230      */
00231     if (restrictionName)
00232     {
00233         typeId[0] = INTERNALOID;    /* PlannerInfo */
00234         typeId[1] = OIDOID;     /* operator OID */
00235         typeId[2] = INTERNALOID;    /* args list */
00236         typeId[3] = INT4OID;    /* varRelid */
00237 
00238         restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
00239 
00240         /* estimators must return float8 */
00241         if (get_func_rettype(restrictionOid) != FLOAT8OID)
00242             ereport(ERROR,
00243                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00244                      errmsg("restriction estimator function %s must return type \"float8\"",
00245                             NameListToString(restrictionName))));
00246 
00247         /* Require EXECUTE rights for the estimator */
00248         aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
00249         if (aclresult != ACLCHECK_OK)
00250             aclcheck_error(aclresult, ACL_KIND_PROC,
00251                            NameListToString(restrictionName));
00252     }
00253     else
00254         restrictionOid = InvalidOid;
00255 
00256     /*
00257      * Look up join estimator if specified
00258      */
00259     if (joinName)
00260     {
00261         typeId[0] = INTERNALOID;    /* PlannerInfo */
00262         typeId[1] = OIDOID;     /* operator OID */
00263         typeId[2] = INTERNALOID;    /* args list */
00264         typeId[3] = INT2OID;    /* jointype */
00265         typeId[4] = INTERNALOID;    /* SpecialJoinInfo */
00266 
00267         /*
00268          * As of Postgres 8.4, the preferred signature for join estimators has
00269          * 5 arguments, but we still allow the old 4-argument form. Try the
00270          * preferred form first.
00271          */
00272         joinOid = LookupFuncName(joinName, 5, typeId, true);
00273         if (!OidIsValid(joinOid))
00274             joinOid = LookupFuncName(joinName, 4, typeId, true);
00275         /* If not found, reference the 5-argument signature in error msg */
00276         if (!OidIsValid(joinOid))
00277             joinOid = LookupFuncName(joinName, 5, typeId, false);
00278 
00279         /* estimators must return float8 */
00280         if (get_func_rettype(joinOid) != FLOAT8OID)
00281             ereport(ERROR,
00282                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00283              errmsg("join estimator function %s must return type \"float8\"",
00284                     NameListToString(joinName))));
00285 
00286         /* Require EXECUTE rights for the estimator */
00287         aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
00288         if (aclresult != ACLCHECK_OK)
00289             aclcheck_error(aclresult, ACL_KIND_PROC,
00290                            NameListToString(joinName));
00291     }
00292     else
00293         joinOid = InvalidOid;
00294 
00295     /*
00296      * now have OperatorCreate do all the work..
00297      */
00298     return
00299         OperatorCreate(oprName,     /* operator name */
00300                        oprNamespace,    /* namespace */
00301                        typeId1,     /* left type id */
00302                        typeId2,     /* right type id */
00303                        functionOid, /* function for operator */
00304                        commutatorName,      /* optional commutator operator name */
00305                        negatorName, /* optional negator operator name */
00306                        restrictionOid,      /* optional restrict. sel. procedure */
00307                        joinOid,     /* optional join sel. procedure name */
00308                        canMerge,    /* operator merges */
00309                        canHash);    /* operator hashes */
00310 }
00311 
00312 /*
00313  * Guts of operator deletion.
00314  */
00315 void
00316 RemoveOperatorById(Oid operOid)
00317 {
00318     Relation    relation;
00319     HeapTuple   tup;
00320 
00321     relation = heap_open(OperatorRelationId, RowExclusiveLock);
00322 
00323     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
00324     if (!HeapTupleIsValid(tup)) /* should not happen */
00325         elog(ERROR, "cache lookup failed for operator %u", operOid);
00326 
00327     simple_heap_delete(relation, &tup->t_self);
00328 
00329     ReleaseSysCache(tup);
00330 
00331     heap_close(relation, RowExclusiveLock);
00332 }