00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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
00056
00057
00058
00059
00060
00061
00062 Oid
00063 DefineOperator(List *names, List *parameters)
00064 {
00065 char *oprName;
00066 Oid oprNamespace;
00067 AclResult aclresult;
00068 bool canMerge = false;
00069 bool canHash = false;
00070 List *functionName = NIL;
00071 TypeName *typeName1 = NULL;
00072 TypeName *typeName2 = NULL;
00073 Oid typeId1 = InvalidOid;
00074 Oid typeId2 = InvalidOid;
00075 Oid rettype;
00076 List *commutatorName = NIL;
00077 List *negatorName = NIL;
00078 List *restrictionName = NIL;
00079 List *joinName = NIL;
00080 Oid functionOid;
00081 Oid restrictionOid;
00082 Oid joinOid;
00083 Oid typeId[5];
00084 int nargs;
00085 ListCell *pl;
00086
00087
00088 oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
00089
00090
00091
00092
00093
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
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
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
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
00161
00162 if (functionName == NIL)
00163 ereport(ERROR,
00164 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00165 errmsg("operator procedure must be specified")));
00166
00167
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
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
00215
00216
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
00230
00231 if (restrictionName)
00232 {
00233 typeId[0] = INTERNALOID;
00234 typeId[1] = OIDOID;
00235 typeId[2] = INTERNALOID;
00236 typeId[3] = INT4OID;
00237
00238 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
00239
00240
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
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
00258
00259 if (joinName)
00260 {
00261 typeId[0] = INTERNALOID;
00262 typeId[1] = OIDOID;
00263 typeId[2] = INTERNALOID;
00264 typeId[3] = INT2OID;
00265 typeId[4] = INTERNALOID;
00266
00267
00268
00269
00270
00271
00272 joinOid = LookupFuncName(joinName, 5, typeId, true);
00273 if (!OidIsValid(joinOid))
00274 joinOid = LookupFuncName(joinName, 4, typeId, true);
00275
00276 if (!OidIsValid(joinOid))
00277 joinOid = LookupFuncName(joinName, 5, typeId, false);
00278
00279
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
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
00297
00298 return
00299 OperatorCreate(oprName,
00300 oprNamespace,
00301 typeId1,
00302 typeId2,
00303 functionOid,
00304 commutatorName,
00305 negatorName,
00306 restrictionOid,
00307 joinOid,
00308 canMerge,
00309 canHash);
00310 }
00311
00312
00313
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))
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 }