Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  operatorcmds.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * operatorcmds.c
 *
 *   Routines for operator manipulation commands
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *   src/backend/commands/operatorcmds.c
 *
 * DESCRIPTION
 *   The "DefineFoo" routines take the parse tree and pick out the
 *   appropriate arguments/flags, passing the results to the
 *   corresponding "FooCreate" routines (in src/backend/catalog) that do
 *   the actual catalog-munging.  These routines also verify permission
 *   of the user to execute the command.
 *
 * NOTES
 *   These things must be defined and committed in the following order:
 *  "create function":
 *    input/output, recv/send functions
 *  "create type":
 *    type
 *  "create operator":
 *    operators
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/indexing.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 "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"

static Oid ValidateRestrictionEstimator(List *restrictionName);
static Oid ValidateJoinEstimator(List *joinName);
static Oid ValidateOperatorReference(List *name,
           Oid leftTypeId,
           Oid rightTypeId);

/*
 * DefineOperator
 *  this function extracts all the information from the
 *  parameter list generated by the parser and then has
 *  OperatorCreate() do all the actual work.
 *
 * 'parameters' is a list of DefElem
 */

ObjectAddress
DefineOperator(List *names, List *parameters)
{
 char    *oprName;
 Oid   oprNamespace;
 AclResult aclresult;
 bool  canMerge = false/* operator merges */
 bool  canHash = false/* operator hashes */
 List    *functionName = NIL; /* function for operator */
 TypeName   *typeName1 = NULL; /* first type name */
 TypeName   *typeName2 = NULL; /* second type name */
 Oid   typeId1 = InvalidOid; /* types converted to OID */
 Oid   typeId2 = InvalidOid;
 Oid   rettype;
 List    *commutatorName = NIL; /* optional commutator operator name */
 List    *negatorName = NIL; /* optional negator operator name */
 List    *restrictionName = NIL; /* optional restrict. sel. function */
 List    *joinName = NIL; /* optional join sel. function */
 Oid   functionOid; /* functions converted to OID */
 Oid   restrictionOid;
 Oid   joinOid;
 Oid   typeId[2];  /* to hold left and right arg */
 int   nargs;
 ListCell   *pl;

 /* Convert list of names to a name and namespace */
 oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);

 /* Check we have creation rights in target namespace */
 aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
 if (aclresult != ACLCHECK_OK)
  aclcheck_error(aclresult, OBJECT_SCHEMA,
        get_namespace_name(oprNamespace));

 /*
  * loop over the definition list and extract the information we need.
 */

 foreach(pl, parameters)
 {
  DefElem    *defel = (DefElem *) lfirst(pl);

  if (strcmp(defel->defname, "leftarg") == 0)
  {
   typeName1 = defGetTypeName(defel);
   if (typeName1->setof)
    ereport(ERROR,
      (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
       errmsg("SETOF type not allowed for operator argument")));
  }
  else if (strcmp(defel->defname, "rightarg") == 0)
  {
   typeName2 = defGetTypeName(defel);
   if (typeName2->setof)
    ereport(ERROR,
      (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
       errmsg("SETOF type not allowed for operator argument")));
  }
  /* "function" and "procedure" are equivalent here */
  else if (strcmp(defel->defname, "function") == 0)
   functionName = defGetQualifiedName(defel);
  else if (strcmp(defel->defname, "procedure") == 0)
   functionName = defGetQualifiedName(defel);
  else if (strcmp(defel->defname, "commutator") == 0)
   commutatorName = defGetQualifiedName(defel);
  else if (strcmp(defel->defname, "negator") == 0)
   negatorName = defGetQualifiedName(defel);
  else if (strcmp(defel->defname, "restrict") == 0)
   restrictionName = defGetQualifiedName(defel);
  else if (strcmp(defel->defname, "join") == 0)
   joinName = defGetQualifiedName(defel);
  else if (strcmp(defel->defname, "hashes") == 0)
   canHash = defGetBoolean(defel);
  else if (strcmp(defel->defname, "merges") == 0)
   canMerge = defGetBoolean(defel);
  /* These obsolete options are taken as meaning canMerge */
  else if (strcmp(defel->defname, "sort1") == 0)
   canMerge = true;
  else if (strcmp(defel->defname, "sort2") == 0)
   canMerge = true;
  else if (strcmp(defel->defname, "ltcmp") == 0)
   canMerge = true;
  else if (strcmp(defel->defname, "gtcmp") == 0)
   canMerge = true;
  else
  {
   /* WARNING, not ERROR, for historical backwards-compatibility */
   ereport(WARNING,
     (errcode(ERRCODE_SYNTAX_ERROR),
      errmsg("operator attribute \"%s\" not recognized",
       defel->defname)));
  }
 }

 /*
  * make sure we have our required definitions
 */

 if (functionName == NIL)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator function must be specified")));

 /* Transform type names to type OIDs */
 if (typeName1)
  typeId1 = typenameTypeId(NULL, typeName1);
 if (typeName2)
  typeId2 = typenameTypeId(NULL, typeName2);

 /*
  * If only the right argument is missing, the user is likely trying to
  * create a postfix operator, so give them a hint about why that does not
  * work.  But if both arguments are missing, do not mention postfix
  * operators, as the user most likely simply neglected to mention the
  * arguments.
 */

 if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator argument types must be specified")));
 if (!OidIsValid(typeId2))
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator right argument type must be specified"),
     errdetail("Postfix operators are not supported.")));

 if (typeName1)
 {
  aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
  if (aclresult != ACLCHECK_OK)
   aclcheck_error_type(aclresult, typeId1);
 }

 if (typeName2)
 {
  aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
  if (aclresult != ACLCHECK_OK)
   aclcheck_error_type(aclresult, typeId2);
 }

 /*
  * Look up the operator's underlying function.
 */

 if (!OidIsValid(typeId1))
 {
  typeId[0] = typeId2;
  nargs = 1;
 }
 else if (!OidIsValid(typeId2))
 {
  typeId[0] = typeId1;
  nargs = 1;
 }
 else
 {
  typeId[0] = typeId1;
  typeId[1] = typeId2;
  nargs = 2;
 }
 functionOid = LookupFuncName(functionName, nargs, typeIdfalse);

 /*
  * We require EXECUTE rights for the function.  This isn't strictly
  * necessary, since EXECUTE will be checked at any attempted use of the
  * operator, but it seems like a good idea anyway.
 */

 aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
 if (aclresult != ACLCHECK_OK)
  aclcheck_error(aclresult, OBJECT_FUNCTION,
        NameListToString(functionName));

 rettype = get_func_rettype(functionOid);
 aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
 if (aclresult != ACLCHECK_OK)
  aclcheck_error_type(aclresult, rettype);

 /*
  * Look up restriction and join estimators if specified
 */

 if (restrictionName)
  restrictionOid = ValidateRestrictionEstimator(restrictionName);
 else
  restrictionOid = InvalidOid;
 if (joinName)
  joinOid = ValidateJoinEstimator(joinName);
 else
  joinOid = InvalidOid;

 /*
  * now have OperatorCreate do all the work..
 */

 return
  OperatorCreate(oprName, /* operator name */
        oprNamespace, /* namespace */
        typeId1, /* left type id */
        typeId2, /* right type id */
        functionOid, /* function for operator */
        commutatorName, /* optional commutator operator name */
        negatorName, /* optional negator operator name */
        restrictionOid, /* optional restrict. sel. function */
        joinOid, /* optional join sel. function name */
        canMerge, /* operator merges */
        canHash); /* operator hashes */
}

/*
 * Look up a restriction estimator function by name, and verify that it has
 * the correct signature and we have the permissions to attach it to an
 * operator.
 */

static Oid
ValidateRestrictionEstimator(List *restrictionName)
{
 Oid   typeId[4];
 Oid   restrictionOid;

 typeId[0] = INTERNALOID; /* PlannerInfo */
 typeId[1] = OIDOID;   /* operator OID */
 typeId[2] = INTERNALOID; /* args list */
 typeId[3] = INT4OID;  /* varRelid */

 restrictionOid = LookupFuncName(restrictionName, 4typeIdfalse);

 /* estimators must return float8 */
 if (get_func_rettype(restrictionOid) != FLOAT8OID)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     errmsg("restriction estimator function %s must return type %s",
      NameListToString(restrictionName), "float8")));

 /*
  * If the estimator is not a built-in function, require superuser
  * privilege to install it.  This protects against using something that is
  * not a restriction estimator or has hard-wired assumptions about what
  * data types it is working with.  (Built-in estimators are required to
  * defend themselves adequately against unexpected data type choices, but
  * it seems impractical to expect that of extensions' estimators.)
  *
  * If it is built-in, only require EXECUTE rights.
 */

 if (restrictionOid >= FirstGenbkiObjectId)
 {
  if (!superuser())
   ereport(ERROR,
     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
      errmsg("must be superuser to specify a non-built-in restriction estimator function")));
 }
 else
 {
  AclResult aclresult;

  aclresult = object_aclcheck(ProcedureRelationId, restrictionOid,
         GetUserId(), ACL_EXECUTE);
  if (aclresult != ACLCHECK_OK)
   aclcheck_error(aclresult, OBJECT_FUNCTION,
         NameListToString(restrictionName));
 }

 return restrictionOid;
}

/*
 * Look up a join estimator function by name, and verify that it has the
 * correct signature and we have the permissions to attach it to an
 * operator.
 */

static Oid
ValidateJoinEstimator(List *joinName)
{
 Oid   typeId[5];
 Oid   joinOid;
 Oid   joinOid2;

 typeId[0] = INTERNALOID; /* PlannerInfo */
 typeId[1] = OIDOID;   /* operator OID */
 typeId[2] = INTERNALOID; /* args list */
 typeId[3] = INT2OID;  /* jointype */
 typeId[4] = INTERNALOID; /* SpecialJoinInfo */

 /*
  * As of Postgres 8.4, the preferred signature for join estimators has 5
  * arguments, but we still allow the old 4-argument form.  Whine about
  * ambiguity if both forms exist.
 */

 joinOid = LookupFuncName(joinName, 5typeIdtrue);
 joinOid2 = LookupFuncName(joinName, 4typeIdtrue);
 if (OidIsValid(joinOid))
 {
  if (OidIsValid(joinOid2))
   ereport(ERROR,
     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
      errmsg("join estimator function %s has multiple matches",
       NameListToString(joinName))));
 }
 else
 {
  joinOid = joinOid2;
  /* If not found, reference the 5-argument signature in error msg */
  if (!OidIsValid(joinOid))
   joinOid = LookupFuncName(joinName, 5typeIdfalse);
 }

 /* estimators must return float8 */
 if (get_func_rettype(joinOid) != FLOAT8OID)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     errmsg("join estimator function %s must return type %s",
      NameListToString(joinName), "float8")));

 /* privilege checks are the same as in ValidateRestrictionEstimator */
 if (joinOid >= FirstGenbkiObjectId)
 {
  if (!superuser())
   ereport(ERROR,
     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
      errmsg("must be superuser to specify a non-built-in join estimator function")));
 }
 else
 {
  AclResult aclresult;

  aclresult = object_aclcheck(ProcedureRelationId, joinOid,
         GetUserId(), ACL_EXECUTE);
  if (aclresult != ACLCHECK_OK)
   aclcheck_error(aclresult, OBJECT_FUNCTION,
         NameListToString(joinName));
 }

 return joinOid;
}

/*
 * Look up and return the OID of an operator,
 * given a possibly-qualified name and left and right type IDs.
 *
 * Verifies that the operator is defined (not a shell) and owned by
 * the current user, so that we have permission to associate it with
 * the operator being altered.  Rejecting shell operators is a policy
 * choice to help catch mistakes, rather than something essential.
 */

static Oid
ValidateOperatorReference(List *name,
        Oid leftTypeId,
        Oid rightTypeId)
{
 Oid   oid;
 bool  defined;

 oid = OperatorLookup(name,
       leftTypeId,
       rightTypeId,
       &defined);

 /* These message strings are chosen to match parse_oper.c */
 if (!OidIsValid(oid))
  ereport(ERROR,
    (errcode(ERRCODE_UNDEFINED_FUNCTION),
     errmsg("operator does not exist: %s",
      op_signature_string(name,
           leftTypeId,
           rightTypeId))));

 if (!defined)
  ereport(ERROR,
    (errcode(ERRCODE_UNDEFINED_FUNCTION),
     errmsg("operator is only a shell: %s",
      op_signature_string(name,
           leftTypeId,
           rightTypeId))));

 if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
  aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
        NameListToString(name));

 return oid;
}


/*
 * Guts of operator deletion.
 */

void
RemoveOperatorById(Oid operOid)
{
 Relation relation;
 HeapTuple tup;
 Form_pg_operator op;

 relation = table_open(OperatorRelationId, RowExclusiveLock);

 tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
 if (!HeapTupleIsValid(tup)) /* should not happen */
  elog(ERROR, "cache lookup failed for operator %u", operOid);
 op = (Form_pg_operator) GETSTRUCT(tup);

 /*
  * Reset links from commutator and negator, if any.  In case of a
  * self-commutator or self-negator, this means we have to re-fetch the
  * updated tuple.  (We could optimize away updates on the tuple we're
  * about to drop, but it doesn't seem worth convoluting the logic for.)
 */

 if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
 {
  OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
  if (operOid == op->oprcom || operOid == op->oprnegate)
  {
   ReleaseSysCache(tup);
   tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
   if (!HeapTupleIsValid(tup)) /* should not happen */
    elog(ERROR, "cache lookup failed for operator %u", operOid);
  }
 }

 CatalogTupleDelete(relation, &tup->t_self);

 ReleaseSysCache(tup);

 table_close(relation, RowExclusiveLock);
}

/*
 * AlterOperator
 *  routine implementing ALTER OPERATOR <operator> SET (option = ...).
 *
 * Currently, only RESTRICT and JOIN estimator functions can be changed.
 * COMMUTATOR, NEGATOR, MERGES, and HASHES attributes can be set if they
 * have not been set previously.  (Changing or removing one of these
 * attributes could invalidate existing plans, which seems more trouble
 * than it's worth.)
 */

ObjectAddress
AlterOperator(AlterOperatorStmt *stmt)
{
 ObjectAddress address;
 Oid   oprId;
 Relation catalog;
 HeapTuple tup;
 Form_pg_operator oprForm;
 int   i;
 ListCell   *pl;
 Datum  values[Natts_pg_operator];
 bool  nulls[Natts_pg_operator];
 bool  replaces[Natts_pg_operator];
 List    *restrictionName = NIL; /* optional restrict. sel. function */
 bool  updateRestriction = false;
 Oid   restrictionOid;
 List    *joinName = NIL; /* optional join sel. function */
 bool  updateJoin = false;
 Oid   joinOid;
 List    *commutatorName = NIL; /* optional commutator operator name */
 Oid   commutatorOid;
 List    *negatorName = NIL; /* optional negator operator name */
 Oid   negatorOid;
 bool  canMerge = false;
 bool  updateMerges = false;
 bool  canHash = false;
 bool  updateHashes = false;

 /* Look up the operator */
 oprId = LookupOperWithArgs(stmt->opername, false);
 catalog = table_open(OperatorRelationId, RowExclusiveLock);
 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
 if (!HeapTupleIsValid(tup))
  elog(ERROR, "cache lookup failed for operator %u", oprId);
 oprForm = (Form_pg_operator) GETSTRUCT(tup);

 /* Process options */
 foreach(pl, stmt->options)
 {
  DefElem    *defel = (DefElem *) lfirst(pl);
  List    *param;

  if (defel->arg == NULL)
   param = NIL;  /* NONE, removes the function */
  else
   param = defGetQualifiedName(defel);

  if (strcmp(defel->defname, "restrict") == 0)
  {
   restrictionName = param;
   updateRestriction = true;
  }
  else if (strcmp(defel->defname, "join") == 0)
  {
   joinName = param;
   updateJoin = true;
  }
  else if (strcmp(defel->defname, "commutator") == 0)
  {
   commutatorName = defGetQualifiedName(defel);
  }
  else if (strcmp(defel->defname, "negator") == 0)
  {
   negatorName = defGetQualifiedName(defel);
  }
  else if (strcmp(defel->defname, "merges") == 0)
  {
   canMerge = defGetBoolean(defel);
   updateMerges = true;
  }
  else if (strcmp(defel->defname, "hashes") == 0)
  {
   canHash = defGetBoolean(defel);
   updateHashes = true;
  }

  /*
   * The rest of the options that CREATE accepts cannot be changed.
   * Check for them so that we can give a meaningful error message.
 */

  else if (strcmp(defel->defname, "leftarg") == 0 ||
     strcmp(defel->defname, "rightarg") == 0 ||
     strcmp(defel->defname, "function") == 0 ||
     strcmp(defel->defname, "procedure") == 0)
  {
   ereport(ERROR,
     (errcode(ERRCODE_SYNTAX_ERROR),
      errmsg("operator attribute \"%s\" cannot be changed",
       defel->defname)));
  }
  else
   ereport(ERROR,
     (errcode(ERRCODE_SYNTAX_ERROR),
      errmsg("operator attribute \"%s\" not recognized",
       defel->defname)));
 }

 /* Check permissions. Must be owner. */
 if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
  aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
        NameStr(oprForm->oprname));

 /*
  * Look up OIDs for any parameters specified
 */

 if (restrictionName)
  restrictionOid = ValidateRestrictionEstimator(restrictionName);
 else
  restrictionOid = InvalidOid;
 if (joinName)
  joinOid = ValidateJoinEstimator(joinName);
 else
  joinOid = InvalidOid;

 if (commutatorName)
 {
  /* commutator has reversed arg types */
  commutatorOid = ValidateOperatorReference(commutatorName,
              oprForm->oprright,
              oprForm->oprleft);

  /*
   * We don't need to do anything extra for a self commutator as in
   * OperatorCreate, since the operator surely exists already.
 */

 }
 else
  commutatorOid = InvalidOid;

 if (negatorName)
 {
  negatorOid = ValidateOperatorReference(negatorName,
              oprForm->oprleft,
              oprForm->oprright);

  /* Must reject self-negation */
  if (negatorOid == oprForm->oid)
   ereport(ERROR,
     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
      errmsg("operator cannot be its own negator")));
 }
 else
 {
  negatorOid = InvalidOid;
 }

 /*
  * Check that we're not changing any attributes that might be depended on
  * by plans, while allowing no-op updates.
 */

 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
  commutatorOid != oprForm->oprcom)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
      "commutator")));

 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
  negatorOid != oprForm->oprnegate)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
      "negator")));

 if (updateMerges && oprForm->oprcanmerge && !canMerge)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
      "merges")));

 if (updateHashes && oprForm->oprcanhash && !canHash)
  ereport(ERROR,
    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
      "hashes")));

 /* Perform additional checks, like OperatorCreate does */
 OperatorValidateParams(oprForm->oprleft,
         oprForm->oprright,
         oprForm->oprresult,
         OidIsValid(commutatorOid),
         OidIsValid(negatorOid),
         OidIsValid(restrictionOid),
         OidIsValid(joinOid),
         canMerge,
         canHash);

 /* Update the tuple */
 for (i = 0; i < Natts_pg_operator; ++i)
 {
  values[i] = (Datum) 0;
  replaces[i] = false;
  nulls[i] = false;
 }
 if (updateRestriction)
 {
  replaces[Anum_pg_operator_oprrest - 1] = true;
  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
 }
 if (updateJoin)
 {
  replaces[Anum_pg_operator_oprjoin - 1] = true;
  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
 }
 if (OidIsValid(commutatorOid))
 {
  replaces[Anum_pg_operator_oprcom - 1] = true;
  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
 }
 if (OidIsValid(negatorOid))
 {
  replaces[Anum_pg_operator_oprnegate - 1] = true;
  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
 }
 if (updateMerges)
 {
  replaces[Anum_pg_operator_oprcanmerge - 1] = true;
  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
 }
 if (updateHashes)
 {
  replaces[Anum_pg_operator_oprcanhash - 1] = true;
  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
 }

 tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
       values, nulls, replaces);

 CatalogTupleUpdate(catalog, &tup->t_self, tup);

 address = makeOperatorDependencies(tup, falsetrue);

 if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
  OperatorUpd(oprId, commutatorOid, negatorOid, false);

 InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);

 table_close(catalog, NoLock);

 return address;
}

Messung V0.5 in Prozent
C=89 H=100 G=94

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002