📄 pg_operator.c
字号:
{ rightTypeId = TypeGet(rightTypeName, &rightDefined); if (!OidIsValid(rightTypeId) || !rightDefined) elog(ERROR, "OperatorDef: right type '%s' nonexistent", rightTypeName); } if (!((OidIsValid(leftTypeId) && leftDefined) || (OidIsValid(rightTypeId) && rightDefined))) elog(ERROR, "OperatorDef: must have at least one argument type"); for (i = 0; i < Natts_pg_operator; ++i) { values[i] = (Datum) NULL; replaces[i] = 'r'; nulls[i] = ' '; } /* ---------------- * Look up registered procedures -- find the return type * of procedureName to place in "result" field. * Do this before shells are created so we don't * have to worry about deleting them later. * ---------------- */ MemSet(typeId, 0, 8 * sizeof(Oid)); if (!leftTypeName) { typeId[0] = rightTypeId; nargs = 1; } else if (!rightTypeName) { typeId[0] = leftTypeId; nargs = 1; } else { typeId[0] = leftTypeId; typeId[1] = rightTypeId; nargs = 2; } tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(procedureName), Int32GetDatum(nargs), PointerGetDatum(typeId), 0); if (!HeapTupleIsValid(tup)) func_error("OperatorDef", procedureName, nargs, typeId, NULL); values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid); values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc) GETSTRUCT(tup))->prorettype); /* ---------------- * find restriction * ---------------- */ if (restrictionName) { /* optional */ MemSet(typeId, 0, 8 * sizeof(Oid)); typeId[0] = OIDOID; /* operator OID */ typeId[1] = OIDOID; /* relation OID */ typeId[2] = INT2OID; /* attribute number */ typeId[3] = 0; /* value - can be any type */ typeId[4] = INT4OID; /* flags - left or right selectivity */ tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(restrictionName), Int32GetDatum(5), PointerGetDatum(typeId), 0); if (!HeapTupleIsValid(tup)) func_error("OperatorDef", restrictionName, 5, typeId, NULL); values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_data->t_oid); } else values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); /* ---------------- * find join - only valid for binary operators * ---------------- */ if (joinName) { /* optional */ MemSet(typeId, 0, 8 * sizeof(Oid)); typeId[0] = OIDOID; /* operator OID */ typeId[1] = OIDOID; /* relation OID 1 */ typeId[2] = INT2OID; /* attribute number 1 */ typeId[3] = OIDOID; /* relation OID 2 */ typeId[4] = INT2OID; /* attribute number 2 */ tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(joinName), Int32GetDatum(5), PointerGetDatum(typeId), 0); if (!HeapTupleIsValid(tup)) func_error("OperatorDef", joinName, 5, typeId, NULL); values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_data->t_oid); } else values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); /* ---------------- * set up values in the operator tuple * ---------------- */ i = 0; namestrcpy(&oname, operatorName); values[i++] = NameGetDatum(&oname); values[i++] = Int32GetDatum(GetUserId()); values[i++] = UInt16GetDatum(precedence); values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l'; values[i++] = Int8GetDatum(isLeftAssociative); values[i++] = Int8GetDatum(canHash); values[i++] = ObjectIdGetDatum(leftTypeId); values[i++] = ObjectIdGetDatum(rightTypeId); ++i; /* Skip "oprresult", it was filled in * above */ /* * Set up the other operators. If they do not currently exist, create * shells in order to get ObjectId's. */ name[0] = commutatorName; name[1] = negatorName; name[2] = leftSortName; name[3] = rightSortName; for (j = 0; j < 4; ++j) { if (name[j]) { char *otherLeftTypeName = NULL; char *otherRightTypeName = NULL; Oid otherLeftTypeId = InvalidOid; Oid otherRightTypeId = InvalidOid; Oid other_oid = InvalidOid; bool otherDefined = false; switch (j) { case 0: /* commutator has reversed arg types */ otherLeftTypeName = rightTypeName; otherRightTypeName = leftTypeName; otherLeftTypeId = rightTypeId; otherRightTypeId = leftTypeId; other_oid = OperatorGet(name[j], otherLeftTypeName, otherRightTypeName, &otherDefined); commutatorId = other_oid; break; case 1: /* negator has same arg types */ otherLeftTypeName = leftTypeName; otherRightTypeName = rightTypeName; otherLeftTypeId = leftTypeId; otherRightTypeId = rightTypeId; other_oid = OperatorGet(name[j], otherLeftTypeName, otherRightTypeName, &otherDefined); negatorId = other_oid; break; case 2: /* left sort op takes left-side data type */ otherLeftTypeName = leftTypeName; otherRightTypeName = leftTypeName; otherLeftTypeId = leftTypeId; otherRightTypeId = leftTypeId; other_oid = OperatorGet(name[j], otherLeftTypeName, otherRightTypeName, &otherDefined); break; case 3: /* right sort op takes right-side data * type */ otherLeftTypeName = rightTypeName; otherRightTypeName = rightTypeName; otherLeftTypeId = rightTypeId; otherRightTypeId = rightTypeId; other_oid = OperatorGet(name[j], otherLeftTypeName, otherRightTypeName, &otherDefined); break; } if (OidIsValid(other_oid)) { /* other op already in catalogs */ values[i++] = ObjectIdGetDatum(other_oid); } else if (strcmp(operatorName, name[j]) != 0 || otherLeftTypeId != leftTypeId || otherRightTypeId != rightTypeId) { /* not in catalogs, different from operator */ other_oid = OperatorShellMake(name[j], otherLeftTypeName, otherRightTypeName); if (!OidIsValid(other_oid)) elog(ERROR, "OperatorDef: can't create operator shell '%s'", name[j]); values[i++] = ObjectIdGetDatum(other_oid); } else { /* * self-linkage to this operator; will fix below. Note * that only self-linkage for commutation makes sense. */ if (j != 0) elog(ERROR, "OperatorDef: operator can't be its own negator or sort op"); selfCommutator = true; values[i++] = ObjectIdGetDatum(InvalidOid); } } else { /* other operator is omitted */ values[i++] = ObjectIdGetDatum(InvalidOid); } } /* last three fields were filled in above */ /* * If we are adding to an operator shell, get its t_self */ pg_operator_desc = heap_openr(OperatorRelationName); if (operatorObjectId) { opKey[0].sk_argument = PointerGetDatum(operatorName); opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId); opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId); pg_operator_scan = heap_beginscan(pg_operator_desc, 0, SnapshotSelf, /* no cache? */ 3, opKey); tup = heap_getnext(pg_operator_scan, 0); if (HeapTupleIsValid(tup)) { tup = heap_modifytuple(tup, pg_operator_desc, values, nulls, replaces); setheapoverride(true); heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); } else elog(ERROR, "OperatorDef: no operator %u", operatorObjectId); heap_endscan(pg_operator_scan); } else { tupDesc = pg_operator_desc->rd_att; tup = heap_formtuple(tupDesc, values, nulls); heap_insert(pg_operator_desc, tup); operatorObjectId = tup->t_data->t_oid; } heap_close(pg_operator_desc); /* * 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);}/* ---------------------------------------------------------------- * 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; HeapScanDesc pg_operator_scan; HeapTuple tup; char nulls[Natts_pg_operator]; char replaces[Natts_pg_operator]; Datum values[Natts_pg_operator]; static ScanKeyData opKey[1] = { {0, ObjectIdAttributeNumber, F_OIDEQ}, }; fmgr_info(F_OIDEQ, &opKey[0].sk_func); opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs; for (i = 0; i < Natts_pg_operator; ++i) { values[i] = (Datum) NULL; replaces[i] = ' '; nulls[i] = ' '; } pg_operator_desc = heap_openr(OperatorRelationName); /* check and update the commutator, if necessary */ opKey[0].sk_argument = ObjectIdGetDatum(commId); pg_operator_scan = heap_beginscan(pg_operator_desc, 0, SnapshotSelf, /* no cache? */ 1, opKey); tup = heap_getnext(pg_operator_scan, 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; 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, pg_operator_desc, values, nulls, replaces); setheapoverride(true); heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); } } heap_endscan(pg_operator_scan); heap_close(pg_operator_desc); 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, pg_operator_desc, values, nulls, replaces); setheapoverride(true); heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); values[Anum_pg_operator_oprcom - 1] = (Datum) NULL; replaces[Anum_pg_operator_oprcom - 1] = ' '; } heap_endscan(pg_operator_scan); /* check and update the negator, if necessary */ opKey[0].sk_argument = ObjectIdGetDatum(negId); pg_operator_scan = heap_beginscan(pg_operator_desc, 0, SnapshotSelf, /* no cache? */ 1, opKey); tup = heap_getnext(pg_operator_scan, 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, pg_operator_desc, values, nulls, replaces); setheapoverride(true); heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); } heap_endscan(pg_operator_scan); heap_close(pg_operator_desc);}/* ---------------------------------------------------------------- * OperatorCreate * * This is now just an interface procedure for OperatorDef ... * * "X" indicates an optional argument (i.e. one that can be NULL) * operatorName; -- operator name * leftTypeName; -- X left type name * rightTypeName; -- X right type name * procedureName; -- procedure for operator * precedence; -- operator precedence * isLeftAssociative; -- operator is left associative * commutatorName; -- X commutator operator name * negatorName; -- X negator operator name * restrictionName; -- X restriction sel. procedure * joinName; -- X join sel. procedure * canHash; -- hash join can be used with this operator * leftSortName; -- X left sort operator (for merge join) * rightSortName; -- X right sort operator (for merge join) */voidOperatorCreate(char *operatorName, char *leftTypeName, char *rightTypeName, char *procedureName, uint16 precedence, bool isLeftAssociative, char *commutatorName, char *negatorName, char *restrictionName, char *joinName, bool canHash, char *leftSortName, char *rightSortName){ if (!leftTypeName && !rightTypeName) elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined"); if (!(leftTypeName && rightTypeName)) { /* If it's not a binary op, these things mustn't be set: */ if (commutatorName) elog(ERROR, "OperatorCreate: only binary operators can have commutators"); if (negatorName) elog(ERROR, "OperatorCreate: only binary operators can have negators"); if (restrictionName || joinName) elog(ERROR, "OperatorCreate: only binary operators can have selectivity"); if (canHash) elog(ERROR, "OperatorCreate: only binary operators can hash"); if (leftSortName || rightSortName) elog(ERROR, "OperatorCreate: only binary operators can have sort links"); } /* ---------------- * Use OperatorDef() to define the specified operator and * also create shells for the operator's associated operators * if they don't already exist. * ---------------- */ OperatorDef(operatorName, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, leftSortName, rightSortName);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -