📄 pg_operator.c
字号:
restOid = LookupFuncName(restrictionName, 4, typeId, false); } else restOid = InvalidOid; /* * find join estimator */ if (joinName) { typeId[0] = INTERNALOID; /* Query */ typeId[1] = OIDOID; /* operator OID */ typeId[2] = INTERNALOID; /* args list */ typeId[3] = INT2OID; /* jointype */ joinOid = LookupFuncName(joinName, 4, typeId, false); } else joinOid = InvalidOid; /* * set up values in the operator tuple */ for (i = 0; i < Natts_pg_operator; ++i) { values[i] = (Datum) NULL; replaces[i] = 'r'; nulls[i] = ' '; } i = 0; namestrcpy(&oname, operatorName); values[i++] = NameGetDatum(&oname); /* oprname */ values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */ values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */ values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */ values[i++] = BoolGetDatum(canHash); /* oprcanhash */ values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */ values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */ values[i++] = ObjectIdGetDatum(operResultType); /* oprresult */ /* * Set up the other operators. If they do not currently exist, create * shells in order to get ObjectId's. */ if (commutatorName) { /* commutator has reversed arg types */ commutatorId = get_other_operator(commutatorName, rightTypeId, leftTypeId, operatorName, operatorNamespace, leftTypeId, rightTypeId, true); /* * self-linkage to this operator; will fix below. Note that only * self-linkage for commutation makes sense. */ if (!OidIsValid(commutatorId)) selfCommutator = true; } else commutatorId = InvalidOid; values[i++] = ObjectIdGetDatum(commutatorId); /* oprcom */ if (negatorName) { /* negator has same arg types */ negatorId = get_other_operator(negatorName, leftTypeId, rightTypeId, operatorName, operatorNamespace, leftTypeId, rightTypeId, false); } else negatorId = InvalidOid; values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */ if (leftSortName) { /* left sort op takes left-side data type */ leftSortId = get_other_operator(leftSortName, leftTypeId, leftTypeId, operatorName, operatorNamespace, leftTypeId, rightTypeId, false); } else leftSortId = InvalidOid; values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */ if (rightSortName) { /* right sort op takes right-side data type */ rightSortId = get_other_operator(rightSortName, rightTypeId, rightTypeId, operatorName, operatorNamespace, leftTypeId, rightTypeId, false); } else rightSortId = InvalidOid; values[i++] = ObjectIdGetDatum(rightSortId); /* oprrsortop */ if (ltCompareName) { /* comparator has same arg types */ ltCompareId = get_other_operator(ltCompareName, leftTypeId, rightTypeId, operatorName, operatorNamespace, leftTypeId, rightTypeId, false); } else ltCompareId = InvalidOid; values[i++] = ObjectIdGetDatum(ltCompareId); /* oprltcmpop */ if (gtCompareName) { /* comparator has same arg types */ gtCompareId = get_other_operator(gtCompareName, leftTypeId, rightTypeId, operatorName, operatorNamespace, leftTypeId, rightTypeId, false); } else gtCompareId = InvalidOid; values[i++] = ObjectIdGetDatum(gtCompareId); /* oprgtcmpop */ values[i++] = ObjectIdGetDatum(procOid); /* oprcode */ values[i++] = ObjectIdGetDatum(restOid); /* oprrest */ values[i++] = ObjectIdGetDatum(joinOid); /* oprjoin */ pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock); /* * If we are adding to an operator shell, update; else insert */ if (operatorObjectId) { tup = SearchSysCacheCopy(OPEROID, ObjectIdGetDatum(operatorObjectId), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for operator %u", operatorObjectId); tup = heap_modifytuple(tup, RelationGetDescr(pg_operator_desc), values, nulls, replaces); simple_heap_update(pg_operator_desc, &tup->t_self, tup); } else { tupDesc = pg_operator_desc->rd_att; tup = heap_formtuple(tupDesc, values, nulls); operatorObjectId = simple_heap_insert(pg_operator_desc, tup); } /* Must update the indexes in either case */ CatalogUpdateIndexes(pg_operator_desc, tup); /* Add dependencies for the entry */ makeOperatorDependencies(tup); heap_close(pg_operator_desc, RowExclusiveLock); /* * If a commutator and/or negator link is provided, update the other * operator(s) to point at this one, if they don't already have a link. * This supports an alternate style of operator definition wherein the * user first defines one operator without giving negator or commutator, * then defines the other operator of the pair with the proper commutator * or negator attribute. That style doesn't require creation of a shell, * and it's the only style that worked right before Postgres version 6.5. * This code also takes care of the situation where the new operator is * its own commutator. */ if (selfCommutator) commutatorId = operatorObjectId; if (OidIsValid(commutatorId) || OidIsValid(negatorId)) OperatorUpd(operatorObjectId, commutatorId, negatorId);}/* * Try to lookup another operator (commutator, etc) * * If not found, check to see if it is exactly the operator we are trying * to define; if so, return InvalidOid. (Note that this case is only * sensible for a commutator, so we error out otherwise.) If it is not * the same operator, create a shell operator. */static Oidget_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, bool isCommutator){ Oid other_oid; bool otherDefined; char *otherName; Oid otherNamespace; AclResult aclresult; other_oid = OperatorLookup(otherOp, otherLeftTypeId, otherRightTypeId, &otherDefined); if (OidIsValid(other_oid)) { /* other op already in catalogs */ return other_oid; } otherNamespace = QualifiedNameGetCreationNamespace(otherOp, &otherName); if (strcmp(otherName, operatorName) == 0 && otherNamespace == operatorNamespace && otherLeftTypeId == leftTypeId && otherRightTypeId == rightTypeId) { /* * self-linkage to this operator; caller will fix later. Note that * only self-linkage for commutation makes sense. */ if (!isCommutator) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("operator cannot be its own negator or sort operator"))); return InvalidOid; } /* not in catalogs, different from operator, so make shell */ aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(otherNamespace)); other_oid = OperatorShellMake(otherName, otherNamespace, otherLeftTypeId, otherRightTypeId); return other_oid;}/* * OperatorUpd * * For a given operator, look up its negator and commutator operators. * If they are defined, but their negator and commutator fields * (respectively) are empty, then use the new operator for neg or comm. * This solves a problem for users who need to insert two new operators * which are the negator or commutator of each other. */static voidOperatorUpd(Oid baseId, Oid commId, Oid negId){ int i; Relation pg_operator_desc; HeapTuple tup; char nulls[Natts_pg_operator]; char replaces[Natts_pg_operator]; Datum values[Natts_pg_operator]; for (i = 0; i < Natts_pg_operator; ++i) { values[i] = (Datum) 0; replaces[i] = ' '; nulls[i] = ' '; } /* * check and update the commutator & negator, if necessary * * First make sure we can see them... */ CommandCounterIncrement(); pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock); tup = SearchSysCacheCopy(OPEROID, ObjectIdGetDatum(commId), 0, 0, 0); /* * if the commutator and negator are the same operator, do one update. XXX * this is probably useless code --- I doubt it ever makes sense for * commutator and negator to be the same thing... */ if (commId == negId) { if (HeapTupleIsValid(tup)) { Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup); if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate)) { if (!OidIsValid(t->oprnegate)) { values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); replaces[Anum_pg_operator_oprnegate - 1] = 'r'; } if (!OidIsValid(t->oprcom)) { values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); replaces[Anum_pg_operator_oprcom - 1] = 'r'; } tup = heap_modifytuple(tup, RelationGetDescr(pg_operator_desc), values, nulls, replaces); simple_heap_update(pg_operator_desc, &tup->t_self, tup); CatalogUpdateIndexes(pg_operator_desc, tup); } } heap_close(pg_operator_desc, RowExclusiveLock); return; } /* if commutator and negator are different, do two updates */ if (HeapTupleIsValid(tup) && !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom))) { values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); replaces[Anum_pg_operator_oprcom - 1] = 'r'; tup = heap_modifytuple(tup, RelationGetDescr(pg_operator_desc), values, nulls, replaces); simple_heap_update(pg_operator_desc, &tup->t_self, tup); CatalogUpdateIndexes(pg_operator_desc, tup); values[Anum_pg_operator_oprcom - 1] = (Datum) NULL; replaces[Anum_pg_operator_oprcom - 1] = ' '; } /* check and update the negator, if necessary */ tup = SearchSysCacheCopy(OPEROID, ObjectIdGetDatum(negId), 0, 0, 0); if (HeapTupleIsValid(tup) && !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate))) { values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); replaces[Anum_pg_operator_oprnegate - 1] = 'r'; tup = heap_modifytuple(tup, RelationGetDescr(pg_operator_desc), values, nulls, replaces); simple_heap_update(pg_operator_desc, &tup->t_self, tup); CatalogUpdateIndexes(pg_operator_desc, tup); } heap_close(pg_operator_desc, RowExclusiveLock);}/* * Create dependencies for a new operator (either a freshly inserted * complete operator, a new shell operator, or a just-updated shell). * * NB: the OidIsValid tests in this routine are necessary, in case * the given operator is a shell. */static voidmakeOperatorDependencies(HeapTuple tuple){ Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple); ObjectAddress myself, referenced; myself.classId = OperatorRelationId; myself.objectId = HeapTupleGetOid(tuple); myself.objectSubId = 0; /* In case we are updating a shell, delete any existing entries */ deleteDependencyRecordsFor(myself.classId, myself.objectId); deleteSharedDependencyRecordsFor(myself.classId, myself.objectId); /* Dependency on namespace */ if (OidIsValid(oper->oprnamespace)) { referenced.classId = NamespaceRelationId; referenced.objectId = oper->oprnamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on left type */ if (OidIsValid(oper->oprleft)) { referenced.classId = TypeRelationId; referenced.objectId = oper->oprleft; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on right type */ if (OidIsValid(oper->oprright)) { referenced.classId = TypeRelationId; referenced.objectId = oper->oprright; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on result type */ if (OidIsValid(oper->oprresult)) { referenced.classId = TypeRelationId; referenced.objectId = oper->oprresult; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* * NOTE: we do not consider the operator to depend on the associated * operators oprcom, oprnegate, oprlsortop, oprrsortop, oprltcmpop, * oprgtcmpop. We would not want to delete this operator if those go * away, but only reset the link fields; which is not a function that the * dependency code can presently handle. (Something could perhaps be done * with objectSubId though.) For now, it's okay to let those links dangle * if a referenced operator is removed. */ /* Dependency on implementation function */ if (OidIsValid(oper->oprcode)) { referenced.classId = ProcedureRelationId; referenced.objectId = oper->oprcode; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on restriction selectivity function */ if (OidIsValid(oper->oprrest)) { referenced.classId = ProcedureRelationId; referenced.objectId = oper->oprrest; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on join selectivity function */ if (OidIsValid(oper->oprjoin)) { referenced.classId = ProcedureRelationId; referenced.objectId = oper->oprjoin; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* Dependency on owner */ recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple), oper->oprowner);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -