PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_operator.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_oper.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_operator.c:

Go to the source code of this file.

Functions

static Oid OperatorGet (const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
 
static Oid OperatorShellMake (const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
 
static Oid get_other_operator (List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
 
static bool validOperatorName (const char *name)
 
Oid OperatorLookup (List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
 
ObjectAddress OperatorCreate (const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId, List *commutatorName, List *negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)
 
void OperatorValidateParams (Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
 
void OperatorUpd (Oid baseId, Oid commId, Oid negId, bool isDelete)
 
ObjectAddress makeOperatorDependencies (HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
 

Function Documentation

◆ get_other_operator()

static Oid get_other_operator ( List otherOp,
Oid  otherLeftTypeId,
Oid  otherRightTypeId,
const char operatorName,
Oid  operatorNamespace,
Oid  leftTypeId,
Oid  rightTypeId 
)
static

Definition at line 622 of file pg_operator.c.

625{
627 bool otherDefined;
628 char *otherName;
631
635 &otherDefined);
636
638 {
639 /* other op already in catalogs */
640 return other_oid;
641 }
642
644 &otherName);
645
646 if (strcmp(otherName, operatorName) == 0 &&
650 {
651 /* self-linkage to new operator; caller must handle this */
652 return InvalidOid;
653 }
654
655 /* not in catalogs, different from operator, so make shell */
656
658 ACL_CREATE);
659 if (aclresult != ACLCHECK_OK)
662
667 return other_oid;
668}
AclResult
Definition acl.h:182
@ ACLCHECK_OK
Definition acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3836
#define OidIsValid(objectId)
Definition c.h:788
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3516
Oid GetUserId(void)
Definition miscinit.c:469
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3557
@ OBJECT_SCHEMA
#define ACL_CREATE
Definition parsenodes.h:85
static Oid OperatorShellMake(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
#define InvalidOid
unsigned int Oid
static int fb(int x)

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, fb(), get_namespace_name(), GetUserId(), InvalidOid, object_aclcheck(), OBJECT_SCHEMA, OidIsValid, OperatorLookup(), OperatorShellMake(), and QualifiedNameGetCreationNamespace().

Referenced by OperatorCreate().

◆ makeOperatorDependencies()

ObjectAddress makeOperatorDependencies ( HeapTuple  tuple,
bool  makeExtensionDep,
bool  isUpdate 
)

Definition at line 853 of file pg_operator.c.

856{
860 ObjectAddresses *addrs;
861
863
864 /*
865 * If we are updating the operator, delete any existing entries, except
866 * for extension membership which should remain the same.
867 */
868 if (isUpdate)
869 {
870 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
871 deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
872 }
873
874 addrs = new_object_addresses();
875
876 /* Dependency on namespace */
877 if (OidIsValid(oper->oprnamespace))
878 {
881 }
882
883 /* Dependency on left type */
884 if (OidIsValid(oper->oprleft))
885 {
888 }
889
890 /* Dependency on right type */
891 if (OidIsValid(oper->oprright))
892 {
895 }
896
897 /* Dependency on result type */
898 if (OidIsValid(oper->oprresult))
899 {
902 }
903
904 /*
905 * NOTE: we do not consider the operator to depend on the associated
906 * operators oprcom and oprnegate. We do not want to delete this operator
907 * if those go away, but only reset the link fields; which is not a
908 * function that the dependency logic can handle. (It's taken care of
909 * manually within RemoveOperatorById, instead.)
910 */
911
912 /* Dependency on implementation function */
913 if (OidIsValid(oper->oprcode))
914 {
917 }
918
919 /* Dependency on restriction selectivity function */
920 if (OidIsValid(oper->oprrest))
921 {
924 }
925
926 /* Dependency on join selectivity function */
927 if (OidIsValid(oper->oprjoin))
928 {
931 }
932
935
936 /* Dependency on owner */
938 oper->oprowner);
939
940 /* Dependency on extension */
943
944 return myself;
945}
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
@ DEPENDENCY_NORMAL
Definition dependency.h:33
static void * GETSTRUCT(const HeapTupleData *tuple)
#define ObjectAddressSet(addr, class_id, object_id)
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition parse_oper.c:371
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition pg_depend.c:301
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition pg_depend.c:193
FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:83
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)

References add_exact_object_address(), deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_NORMAL, fb(), free_object_addresses(), GETSTRUCT(), new_object_addresses(), ObjectAddressSet, OidIsValid, oper(), record_object_address_dependencies(), recordDependencyOnCurrentExtension(), and recordDependencyOnOwner().

Referenced by AlterOperator(), OperatorCreate(), and OperatorShellMake().

◆ OperatorCreate()

ObjectAddress OperatorCreate ( const char operatorName,
Oid  operatorNamespace,
Oid  leftTypeId,
Oid  rightTypeId,
Oid  procedureId,
List commutatorName,
List negatorName,
Oid  restrictionId,
Oid  joinId,
bool  canMerge,
bool  canHash 
)

Definition at line 321 of file pg_operator.c.

332{
335 bool isUpdate;
336 bool nulls[Natts_pg_operator];
343 negatorId;
344 bool selfCommutator = false;
346 int i;
347 ObjectAddress address;
348
349 /*
350 * Sanity checks
351 */
355 errmsg("\"%s\" is not a valid operator name",
356 operatorName)));
357
359
364 negatorName != NIL,
367 canMerge,
368 canHash);
369
375
379 errmsg("operator %s already exists",
380 operatorName)));
381
382 /*
383 * At this point, if operatorObjectId is not InvalidOid then we are
384 * filling in a previously-created shell. Insist that the user own any
385 * such shell.
386 */
391
392 /*
393 * Set up the other operators. If they do not currently exist, create
394 * shells in order to get ObjectId's.
395 */
396
397 if (commutatorName)
398 {
399 /* commutator has reversed arg types */
404
405 /* Permission check: must own other operator */
410
411 /*
412 * If self-linkage to the new operator is requested, we'll fix it
413 * below. (In case of self-linkage to an existing shell operator, we
414 * need do nothing special.)
415 */
417 selfCommutator = true;
418 }
419 else
421
422 if (negatorName)
423 {
424 /* negator has same arg types */
429
430 /* Permission check: must own other operator */
431 if (OidIsValid(negatorId) &&
435
436 /*
437 * Prevent self negation, as it doesn't make sense. It's self
438 * negation if result is InvalidOid (negator would be the same
439 * operator but it doesn't exist yet) or operatorObjectId (we are
440 * replacing a shell that would need to be its own negator).
441 */
445 errmsg("operator cannot be its own negator")));
446 }
447 else
449
450 /*
451 * set up values in the operator tuple
452 */
453
454 for (i = 0; i < Natts_pg_operator; ++i)
455 {
456 values[i] = (Datum) 0;
457 replaces[i] = true;
458 nulls[i] = false;
459 }
460
476
478
479 /*
480 * If we are replacing an operator shell, update; else insert
481 */
483 {
484 isUpdate = true;
485
488 if (!HeapTupleIsValid(tup))
489 elog(ERROR, "cache lookup failed for operator %u",
491
492 replaces[Anum_pg_operator_oid - 1] = false;
495 values,
496 nulls,
497 replaces);
498
500 }
501 else
502 {
503 isUpdate = false;
504
509
511 values, nulls);
512
514 }
515
516 /* Add dependencies for the entry */
517 address = makeOperatorDependencies(tup, true, isUpdate);
518
519 /*
520 * If a commutator and/or negator link is provided, update the other
521 * operator(s) to point at this one, if they don't already have a link.
522 * This supports an alternative style of operator definition wherein the
523 * user first defines one operator without giving negator or commutator,
524 * then defines the other operator of the pair with the proper commutator
525 * or negator attribute. That style doesn't require creation of a shell,
526 * and it's the only style that worked right before Postgres version 6.5.
527 * This code also takes care of the situation where the new operator is
528 * its own commutator.
529 */
530 if (selfCommutator)
532
535
536 /* Post creation hook for new operator */
538
540
541 return address;
542}
@ ACLCHECK_NOT_OWNER
Definition acl.h:185
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4090
static Datum values[MAXATTR]
Definition bootstrap.c:155
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
#define HeapTupleIsValid(tuple)
Definition htup.h:78
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
int i
Definition isn.c:77
#define RowExclusiveLock
Definition lockdefs.h:38
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1805
void namestrcpy(Name name, const char *str)
Definition name.c:233
char * NameListToString(const List *names)
Definition namespace.c:3664
#define InvokeObjectPostCreateHook(classId, objectId, subId)
@ OBJECT_OPERATOR
#define NIL
Definition pg_list.h:68
static Oid get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
static Oid OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
static bool validOperatorName(const char *name)
Definition pg_operator.c:68
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:403
uint64_t Datum
Definition postgres.h:70
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define RelationGetDescr(relation)
Definition rel.h:540
Definition c.h:760
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References aclcheck_error(), ACLCHECK_NOT_OWNER, BoolGetDatum(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), elog, ereport, errcode(), errmsg(), ERROR, fb(), get_func_rettype(), get_other_operator(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostCreateHook, makeOperatorDependencies(), NameGetDatum(), NameListToString(), namestrcpy(), NIL, OBJECT_OPERATOR, object_ownercheck(), ObjectIdGetDatum(), OidIsValid, OperatorGet(), OperatorUpd(), OperatorValidateParams(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, table_close(), table_open(), validOperatorName(), and values.

Referenced by DefineOperator().

◆ OperatorGet()

static Oid OperatorGet ( const char operatorName,
Oid  operatorNamespace,
Oid  leftObjectId,
Oid  rightObjectId,
bool defined 
)
static

Definition at line 124 of file pg_operator.c.

129{
132
139 {
141
145 }
146 else
147 {
149 *defined = false;
150 }
151
152 return operatorObjectId;
153}
#define RegProcedureIsValid(p)
Definition c.h:792
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition syscache.c:250

References fb(), GETSTRUCT(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), PointerGetDatum(), RegProcedureIsValid, ReleaseSysCache(), and SearchSysCache4().

Referenced by OperatorCreate().

◆ OperatorLookup()

Oid OperatorLookup ( List operatorName,
Oid  leftObjectId,
Oid  rightObjectId,
bool defined 
)

Definition at line 164 of file pg_operator.c.

168{
170 RegProcedure oprcode;
171
174 true, -1);
176 {
177 *defined = false;
178 return InvalidOid;
179 }
180
181 oprcode = get_opcode(operatorObjectId);
182 *defined = RegProcedureIsValid(oprcode);
183
184 return operatorObjectId;
185}
regproc RegProcedure
Definition c.h:664
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1435
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition parse_oper.c:100

References fb(), get_opcode(), InvalidOid, LookupOperName(), OidIsValid, and RegProcedureIsValid.

Referenced by get_other_operator(), and ValidateOperatorReference().

◆ OperatorShellMake()

static Oid OperatorShellMake ( const char operatorName,
Oid  operatorNamespace,
Oid  leftTypeId,
Oid  rightTypeId 
)
static

Definition at line 193 of file pg_operator.c.

197{
200 int i;
203 bool nulls[Natts_pg_operator];
205 TupleDesc tupDesc;
206
207 /*
208 * validate operator name
209 */
213 errmsg("\"%s\" is not a valid operator name",
214 operatorName)));
215
216 /*
217 * open pg_operator
218 */
220 tupDesc = pg_operator_desc->rd_att;
221
222 /*
223 * initialize our *nulls and *values arrays
224 */
225 for (i = 0; i < Natts_pg_operator; ++i)
226 {
227 nulls[i] = false;
228 values[i] = (Datum) 0; /* redundant, but safe */
229 }
230
231 /*
232 * initialize values[] with the operator name and input data types. Note
233 * that oprcode is set to InvalidOid, indicating it's a shell.
234 */
253
254 /*
255 * create a new operator tuple
256 */
257 tup = heap_form_tuple(tupDesc, values, nulls);
258
259 /*
260 * insert our "shell" operator tuple
261 */
263
264 /* Add dependencies for the entry */
265 makeOperatorDependencies(tup, true, false);
266
268
269 /* Post creation hook for new shell operator */
271
272 /*
273 * Make sure the tuple is visible for subsequent lookups/updates.
274 */
276
277 /*
278 * close the operator relation and return the oid.
279 */
281
282 return operatorObjectId;
283}
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1435
void CommandCounterIncrement(void)
Definition xact.c:1101

References BoolGetDatum(), CatalogTupleInsert(), CharGetDatum(), CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, fb(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), i, InvalidOid, InvokeObjectPostCreateHook, makeOperatorDependencies(), NameGetDatum(), namestrcpy(), ObjectIdGetDatum(), RowExclusiveLock, table_close(), table_open(), validOperatorName(), and values.

Referenced by get_other_operator().

◆ OperatorUpd()

void OperatorUpd ( Oid  baseId,
Oid  commId,
Oid  negId,
bool  isDelete 
)

Definition at line 684 of file pg_operator.c.

685{
688
689 /*
690 * If we're making an operator into its own commutator, then we need a
691 * command-counter increment here, since we've just inserted the tuple
692 * we're about to update. But when we're dropping an operator, we can
693 * skip this because we're at the beginning of the command.
694 */
695 if (!isDelete)
697
698 /* Open the relation. */
700
701 /* Get a writable copy of the commutator's tuple. */
702 if (OidIsValid(commId))
704 else
705 tup = NULL;
706
707 /* Update the commutator's tuple if need be. */
709 {
711 bool update_commutator = false;
712
713 /*
714 * We can skip doing anything if the commutator's oprcom field is
715 * already what we want. While that's not expected in the isDelete
716 * case, it's perfectly possible when filling in a shell operator.
717 */
718 if (isDelete && OidIsValid(t->oprcom))
719 {
720 t->oprcom = InvalidOid;
721 update_commutator = true;
722 }
723 else if (!isDelete && t->oprcom != baseId)
724 {
725 /*
726 * If commutator's oprcom field is already set to point to some
727 * third operator, it's an error. Changing its link would be
728 * unsafe, and letting the inconsistency stand would not be good
729 * either. This might be indicative of catalog corruption, so
730 * don't assume t->oprcom is necessarily a valid operator.
731 */
732 if (OidIsValid(t->oprcom))
733 {
734 char *thirdop = get_opname(t->oprcom);
735
736 if (thirdop != NULL)
739 errmsg("commutator operator %s is already the commutator of operator %s",
740 NameStr(t->oprname), thirdop)));
741 else
744 errmsg("commutator operator %s is already the commutator of operator %u",
745 NameStr(t->oprname), t->oprcom)));
746 }
747
748 t->oprcom = baseId;
749 update_commutator = true;
750 }
751
752 /* If any columns were found to need modification, update tuple. */
754 {
756
757 /*
758 * Do CCI to make the updated tuple visible. We must do this in
759 * case the commutator is also the negator. (Which would be a
760 * logic error on the operator definer's part, but that's not a
761 * good reason to fail here.) We would need a CCI anyway in the
762 * deletion case for a self-commutator with no negator.
763 */
765 }
766 }
767
768 /*
769 * Similarly find and update the negator, if any.
770 */
771 if (OidIsValid(negId))
773 else
774 tup = NULL;
775
777 {
779 bool update_negator = false;
780
781 /*
782 * We can skip doing anything if the negator's oprnegate field is
783 * already what we want. While that's not expected in the isDelete
784 * case, it's perfectly possible when filling in a shell operator.
785 */
786 if (isDelete && OidIsValid(t->oprnegate))
787 {
788 t->oprnegate = InvalidOid;
789 update_negator = true;
790 }
791 else if (!isDelete && t->oprnegate != baseId)
792 {
793 /*
794 * If negator's oprnegate field is already set to point to some
795 * third operator, it's an error. Changing its link would be
796 * unsafe, and letting the inconsistency stand would not be good
797 * either. This might be indicative of catalog corruption, so
798 * don't assume t->oprnegate is necessarily a valid operator.
799 */
800 if (OidIsValid(t->oprnegate))
801 {
802 char *thirdop = get_opname(t->oprnegate);
803
804 if (thirdop != NULL)
807 errmsg("negator operator %s is already the negator of operator %s",
808 NameStr(t->oprname), thirdop)));
809 else
812 errmsg("negator operator %s is already the negator of operator %u",
813 NameStr(t->oprname), t->oprnegate)));
814 }
815
816 t->oprnegate = baseId;
817 update_negator = true;
818 }
819
820 /* If any columns were found to need modification, update tuple. */
821 if (update_negator)
822 {
824
825 /*
826 * In the deletion case, do CCI to make the updated tuple visible.
827 * We must do this in case the operator is its own negator. (Which
828 * would be a logic error on the operator definer's part, but
829 * that's not a good reason to fail here.)
830 */
831 if (isDelete)
833 }
834 }
835
836 /* Close relation and release catalog lock. */
838}
#define NameStr(name)
Definition c.h:765
char * get_opname(Oid opno)
Definition lsyscache.c:1460

References CatalogTupleUpdate(), CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, fb(), get_opname(), GETSTRUCT(), HeapTupleIsValid, InvalidOid, NameStr, ObjectIdGetDatum(), OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by AlterOperator(), OperatorCreate(), and RemoveOperatorById().

◆ OperatorValidateParams()

void OperatorValidateParams ( Oid  leftTypeId,
Oid  rightTypeId,
Oid  operResultType,
bool  hasCommutator,
bool  hasNegator,
bool  hasRestrictionSelectivity,
bool  hasJoinSelectivity,
bool  canMerge,
bool  canHash 
)

Definition at line 556 of file pg_operator.c.

565{
567 {
568 /* If it's not a binary op, these things mustn't be set: */
569 if (hasCommutator)
572 errmsg("only binary operators can have commutators")));
576 errmsg("only binary operators can have join selectivity")));
577 if (canMerge)
580 errmsg("only binary operators can merge join")));
581 if (canHash)
584 errmsg("only binary operators can hash")));
585 }
586
587 if (operResultType != BOOLOID)
588 {
589 /* If it's not a boolean op, these things mustn't be set: */
590 if (hasNegator)
593 errmsg("only boolean operators can have negators")));
597 errmsg("only boolean operators can have restriction selectivity")));
601 errmsg("only boolean operators can have join selectivity")));
602 if (canMerge)
605 errmsg("only boolean operators can merge join")));
606 if (canHash)
609 errmsg("only boolean operators can hash")));
610 }
611}

References ereport, errcode(), errmsg(), ERROR, fb(), and OidIsValid.

Referenced by AlterOperator(), and OperatorCreate().

◆ validOperatorName()

static bool validOperatorName ( const char name)
static

Definition at line 68 of file pg_operator.c.

69{
70 size_t len = strlen(name);
71
72 /* Can't be empty or too long */
73 if (len == 0 || len >= NAMEDATALEN)
74 return false;
75
76 /* Can't contain any invalid characters */
77 /* Test string here should match op_chars in scan.l */
78 if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
79 return false;
80
81 /* Can't contain slash-star or dash-dash (comment starts) */
82 if (strstr(name, "/*") || strstr(name, "--"))
83 return false;
84
85 /*
86 * For SQL standard compatibility, '+' and '-' cannot be the last char of
87 * a multi-char operator unless the operator contains chars that are not
88 * in SQL operators. The idea is to lex '=-' as two operators, but not to
89 * forbid operator names like '?-' that could not be sequences of standard
90 * SQL operators.
91 */
92 if (len > 1 &&
93 (name[len - 1] == '+' ||
94 name[len - 1] == '-'))
95 {
96 int ic;
97
98 for (ic = len - 2; ic >= 0; ic--)
99 {
100 if (strchr("~!@#^&|`?%", name[ic]))
101 break;
102 }
103 if (ic < 0)
104 return false; /* nope, not valid */
105 }
106
107 /* != isn't valid either, because parser will convert it to <> */
108 if (strcmp(name, "!=") == 0)
109 return false;
110
111 return true;
112}
#define NAMEDATALEN
const void size_t len
const char * name

References fb(), len, name, and NAMEDATALEN.

Referenced by OperatorCreate(), and OperatorShellMake().