1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* pg_operator.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* routines to support manipulation of the pg_operator relation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-01-24 20:43:33 +01:00
|
|
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2001-08-10 17:49:39 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.61 2001/08/10 15:49:39 petere Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
* these routines moved here from commands/define.c and somewhat cleaned up.
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "catalog/catname.h"
|
1999-11-22 18:56:41 +01:00
|
|
|
#include "catalog/indexing.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "catalog/pg_operator.h"
|
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "miscadmin.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "parser/parse_func.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "utils/builtins.h"
|
2000-05-28 19:56:29 +02:00
|
|
|
#include "utils/fmgroids.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "utils/syscache.h"
|
|
|
|
|
1996-11-04 00:27:08 +01:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
1999-05-25 18:15:34 +02:00
|
|
|
const char *operatorName,
|
|
|
|
Oid leftObjectId,
|
|
|
|
Oid rightObjectId,
|
|
|
|
bool *defined);
|
1999-04-11 04:30:59 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
static Oid OperatorGet(char *operatorName,
|
1999-05-25 18:15:34 +02:00
|
|
|
char *leftTypeName,
|
|
|
|
char *rightTypeName,
|
|
|
|
bool *defined);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *operatorName,
|
|
|
|
Oid leftObjectId,
|
|
|
|
Oid rightObjectId);
|
1999-04-11 04:30:59 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
static Oid OperatorShellMake(char *operatorName,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *leftTypeName,
|
|
|
|
char *rightTypeName);
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
static void OperatorDef(char *operatorName,
|
1996-07-09 08:22:35 +02:00
|
|
|
char *leftTypeName,
|
|
|
|
char *rightTypeName,
|
|
|
|
char *procedureName,
|
|
|
|
uint16 precedence,
|
|
|
|
bool isLeftAssociative,
|
|
|
|
char *commutatorName,
|
|
|
|
char *negatorName,
|
|
|
|
char *restrictionName,
|
|
|
|
char *oinName,
|
|
|
|
bool canHash,
|
|
|
|
char *leftSortName,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *rightSortName);
|
1999-04-11 04:30:59 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* OperatorGetWithOpenRelation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-05-20 22:28:20 +02:00
|
|
|
* performs a scan on pg_operator for an operator tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
* with given name and left/right type oids.
|
2001-06-01 04:41:36 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* pg_operator_desc -- reldesc for pg_operator
|
|
|
|
* operatorName -- name of operator to fetch
|
1999-04-11 04:30:59 +02:00
|
|
|
* leftObjectId -- left data type oid of operator to fetch
|
|
|
|
* rightObjectId -- right data type oid of operator to fetch
|
|
|
|
* defined -- set TRUE if defined (not a shell)
|
2001-06-01 04:41:36 +02:00
|
|
|
* ----------------------------------------------------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
1997-09-07 07:04:48 +02:00
|
|
|
const char *operatorName,
|
|
|
|
Oid leftObjectId,
|
1999-04-11 04:30:59 +02:00
|
|
|
Oid rightObjectId,
|
|
|
|
bool *defined)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapScanDesc pg_operator_scan;
|
|
|
|
Oid operatorObjectId;
|
|
|
|
HeapTuple tup;
|
2001-06-01 04:41:36 +02:00
|
|
|
ScanKeyData opKey[3];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* form scan key
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2001-06-01 04:41:36 +02:00
|
|
|
ScanKeyEntryInitialize(&opKey[0], 0x0,
|
|
|
|
Anum_pg_operator_oprname,
|
|
|
|
F_NAMEEQ,
|
|
|
|
PointerGetDatum(operatorName));
|
|
|
|
ScanKeyEntryInitialize(&opKey[1], 0x0,
|
|
|
|
Anum_pg_operator_oprleft,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(leftObjectId));
|
|
|
|
ScanKeyEntryInitialize(&opKey[2], 0x0,
|
|
|
|
Anum_pg_operator_oprright,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(rightObjectId));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* begin the scan
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
pg_operator_scan = heap_beginscan(pg_operator_desc,
|
|
|
|
0,
|
1998-09-01 06:40:42 +02:00
|
|
|
SnapshotSelf, /* no cache? */
|
1997-09-07 07:04:48 +02:00
|
|
|
3,
|
|
|
|
opKey);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* fetch the operator tuple, if it exists, and determine the proper
|
|
|
|
* return oid value.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
tup = heap_getnext(pg_operator_scan, 0);
|
1999-04-11 04:30:59 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
|
|
|
regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
1999-04-11 04:30:59 +02:00
|
|
|
operatorObjectId = tup->t_data->t_oid;
|
|
|
|
*defined = RegProcedureIsValid(oprcode);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
operatorObjectId = InvalidOid;
|
|
|
|
*defined = false;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* close the scan and return the oid.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
heap_endscan(pg_operator_scan);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
return operatorObjectId;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* OperatorGet
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* finds the operator associated with the specified name
|
|
|
|
* and left and right type names.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
OperatorGet(char *operatorName,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *leftTypeName,
|
1999-04-11 04:30:59 +02:00
|
|
|
char *rightTypeName,
|
|
|
|
bool *defined)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_operator_desc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid operatorObjectId;
|
|
|
|
Oid leftObjectId = InvalidOid;
|
|
|
|
Oid rightObjectId = InvalidOid;
|
|
|
|
bool leftDefined = false;
|
|
|
|
bool rightDefined = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* look up the operator data types.
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* Note: types must be defined before operators
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (leftTypeName)
|
|
|
|
{
|
|
|
|
leftObjectId = TypeGet(leftTypeName, &leftDefined);
|
|
|
|
|
|
|
|
if (!OidIsValid(leftObjectId) || !leftDefined)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "left type \"%s\" of operator %s does not exist",
|
|
|
|
leftTypeName, operatorName);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rightTypeName)
|
|
|
|
{
|
|
|
|
rightObjectId = TypeGet(rightTypeName, &rightDefined);
|
|
|
|
|
|
|
|
if (!OidIsValid(rightObjectId) || !rightDefined)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "right type \"%s\" of operator %s does not exist",
|
|
|
|
rightTypeName, operatorName);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!((OidIsValid(leftObjectId) && leftDefined) ||
|
|
|
|
(OidIsValid(rightObjectId) && rightDefined)))
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "operator %s must have at least one operand type", operatorName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* open the pg_operator relation
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get the oid for the operator with the appropriate name and
|
|
|
|
* left/right types.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
|
|
|
|
operatorName,
|
|
|
|
leftObjectId,
|
1999-04-11 04:30:59 +02:00
|
|
|
rightObjectId,
|
|
|
|
defined);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* close the relation and return the operator oid.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_operator_desc, AccessShareLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
return operatorObjectId;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* OperatorShellMakeWithOpenRelation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *operatorName,
|
|
|
|
Oid leftObjectId,
|
|
|
|
Oid rightObjectId)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
int i;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
|
|
|
Datum values[Natts_pg_operator];
|
|
|
|
char nulls[Natts_pg_operator];
|
|
|
|
Oid operatorObjectId;
|
1998-04-01 17:35:33 +02:00
|
|
|
NameData oname;
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupDesc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize our *nulls and *values arrays
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < Natts_pg_operator; ++i)
|
|
|
|
{
|
|
|
|
nulls[i] = ' ';
|
|
|
|
values[i] = (Datum) NULL; /* redundant, but safe */
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize *values with the operator name and input data types.
|
|
|
|
* Note that oprcode is set to InvalidOid, indicating it's a shell.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
i = 0;
|
1998-04-01 17:35:33 +02:00
|
|
|
namestrcpy(&oname, operatorName);
|
|
|
|
values[i++] = NameGetDatum(&oname);
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = Int32GetDatum(GetUserId());
|
2000-08-21 19:22:36 +02:00
|
|
|
values[i++] = UInt16GetDatum(0);
|
2001-03-22 05:01:46 +01:00
|
|
|
values[i++] = CharGetDatum('b'); /* assume it's binary */
|
2000-08-21 19:22:36 +02:00
|
|
|
values[i++] = BoolGetDatum(false);
|
|
|
|
values[i++] = BoolGetDatum(false);
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
|
|
|
|
values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* create a new operator tuple
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
tupDesc = pg_operator_desc->rd_att;
|
|
|
|
|
|
|
|
tup = heap_formtuple(tupDesc,
|
|
|
|
values,
|
|
|
|
nulls);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* insert our "shell" operator tuple and close the relation
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
heap_insert(pg_operator_desc, tup);
|
1998-11-27 20:52:36 +01:00
|
|
|
operatorObjectId = tup->t_data->t_oid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-11-22 18:56:41 +01:00
|
|
|
if (RelationGetForm(pg_operator_desc)->relhasindex)
|
|
|
|
{
|
|
|
|
Relation idescs[Num_pg_operator_indices];
|
|
|
|
|
|
|
|
CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
|
|
|
|
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* free the tuple and return the operator oid
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-12-16 23:20:03 +01:00
|
|
|
heap_freetuple(tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
return operatorObjectId;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* OperatorShellMake
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Specify operator name and left and right type names,
|
|
|
|
* fill an operator struct with this info and NULL's,
|
|
|
|
* call heap_insert and return the Oid
|
|
|
|
* to the caller.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
OperatorShellMake(char *operatorName,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *leftTypeName,
|
|
|
|
char *rightTypeName)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_operator_desc;
|
|
|
|
Oid operatorObjectId;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid leftObjectId = InvalidOid;
|
|
|
|
Oid rightObjectId = InvalidOid;
|
|
|
|
bool leftDefined = false;
|
|
|
|
bool rightDefined = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get the left and right type oid's for this operator
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (leftTypeName)
|
|
|
|
leftObjectId = TypeGet(leftTypeName, &leftDefined);
|
|
|
|
|
|
|
|
if (rightTypeName)
|
|
|
|
rightObjectId = TypeGet(rightTypeName, &rightDefined);
|
|
|
|
|
|
|
|
if (!((OidIsValid(leftObjectId) && leftDefined) ||
|
|
|
|
(OidIsValid(rightObjectId) && rightDefined)))
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "OperatorShellMake: the operand types are not valid");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* open pg_operator
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* add a "shell" operator tuple to the operator relation and recover
|
|
|
|
* the shell tuple's oid.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-02-03 22:18:02 +01:00
|
|
|
operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
|
1999-05-25 18:15:34 +02:00
|
|
|
operatorName,
|
|
|
|
leftObjectId,
|
|
|
|
rightObjectId);
|
2001-03-22 07:16:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* close the operator relation and return the oid.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_operator_desc, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-03 22:18:02 +01:00
|
|
|
return operatorObjectId;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------
|
|
|
|
* OperatorDef
|
|
|
|
*
|
|
|
|
* This routine gets complicated because it allows the user to
|
|
|
|
* specify operators that do not exist. For example, if operator
|
|
|
|
* "op" is being defined, the negator operator "negop" and the
|
|
|
|
* commutator "commop" can also be defined without specifying
|
1997-09-07 07:04:48 +02:00
|
|
|
* any information other than their names. Since in order to
|
1996-07-09 08:22:35 +02:00
|
|
|
* add "op" to the PG_OPERATOR catalog, all the Oid's for these
|
|
|
|
* operators must be placed in the fields of "op", a forward
|
|
|
|
* declaration is done on the commutator and negator operators.
|
|
|
|
* This is called creating a shell, and its main effect is to
|
|
|
|
* create a tuple in the PG_OPERATOR catalog with minimal
|
|
|
|
* information about the operator (just its name and types).
|
|
|
|
* Forward declaration is used only for this purpose, it is
|
|
|
|
* not available to the user as it is for type definition.
|
|
|
|
*
|
|
|
|
* Algorithm:
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
|
|
|
* check if operator already defined
|
1999-04-11 04:30:59 +02:00
|
|
|
* if so, but oprcode is null, save the Oid -- we are filling in a shell
|
|
|
|
* otherwise error
|
1996-07-09 08:22:35 +02:00
|
|
|
* get the attribute types from relation descriptor for pg_operator
|
|
|
|
* assign values to the fields of the operator:
|
1997-09-07 07:04:48 +02:00
|
|
|
* operatorName
|
|
|
|
* owner id (simply the user id of the caller)
|
|
|
|
* precedence
|
|
|
|
* operator "kind" either "b" for binary or "l" for left unary
|
|
|
|
* isLeftAssociative boolean
|
|
|
|
* canHash boolean
|
|
|
|
* leftTypeObjectId -- type must already be defined
|
|
|
|
* rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
|
|
|
|
* resultType -- defer this, since it must be determined from
|
|
|
|
* the pg_procedure catalog
|
|
|
|
* commutatorObjectId -- if this is NULL, enter ObjectId=0
|
2000-01-05 19:23:54 +01:00
|
|
|
* else if this already exists, enter its ObjectId
|
1997-09-07 07:04:48 +02:00
|
|
|
* else if this does not yet exist, and is not
|
|
|
|
* the same as the main operatorName, then create
|
|
|
|
* a shell and enter the new ObjectId
|
|
|
|
* else if this does not exist but IS the same
|
1999-04-11 04:30:59 +02:00
|
|
|
* name & types as the main operator, set the ObjectId=0.
|
|
|
|
* (We are creating a self-commutating operator.)
|
|
|
|
* The link will be fixed later by OperatorUpd.
|
1997-09-07 07:04:48 +02:00
|
|
|
* negatorObjectId -- same as for commutatorObjectId
|
|
|
|
* leftSortObjectId -- same as for commutatorObjectId
|
|
|
|
* rightSortObjectId -- same as for commutatorObjectId
|
|
|
|
* operatorProcedure -- must access the pg_procedure catalog to get the
|
|
|
|
* ObjectId of the procedure that actually does the operator
|
Restructure index AM interface for index building and index tuple deletion,
per previous discussion on pghackers. Most of the duplicate code in
different AMs' ambuild routines has been moved out to a common routine
in index.c; this means that all index types now do the right things about
inserting recently-dead tuples, etc. (I also removed support for EXTEND
INDEX in the ambuild routines, since that's about to go away anyway, and
it cluttered the code a lot.) The retail indextuple deletion routines have
been replaced by a "bulk delete" routine in which the indexscan is inside
the access method. I haven't pushed this change as far as it should go yet,
but it should allow considerable simplification of the internal bookkeeping
for deletions. Also, add flag columns to pg_am to eliminate various
hardcoded tests on AM OIDs, and remove unused pg_am columns.
Fix rtree and gist index types to not attempt to store NULLs; before this,
gist usually crashed, while rtree managed not to crash but computed wacko
bounding boxes for NULL entries (which might have had something to do with
the performance problems we've heard about occasionally).
Add AtEOXact routines to hash, rtree, and gist, all of which have static
state that needs to be reset after an error. We discovered this need long
ago for btree, but missed the other guys.
Oh, one more thing: concurrent VACUUM is now the default.
2001-07-16 00:48:19 +02:00
|
|
|
* actions this is required. Do a lookup to find out the
|
1997-09-07 07:04:48 +02:00
|
|
|
* return type of the procedure
|
|
|
|
* restrictionProcedure -- must access the pg_procedure catalog to get
|
|
|
|
* the ObjectId but this is optional
|
|
|
|
* joinProcedure -- same as restrictionProcedure
|
1996-07-09 08:22:35 +02:00
|
|
|
* now either insert or replace the operator into the pg_operator catalog
|
|
|
|
* if the operator shell is being filled in
|
1997-09-07 07:04:48 +02:00
|
|
|
* access the catalog in order to get a valid buffer
|
|
|
|
* create a tuple using ModifyHeapTuple
|
1998-11-27 20:52:36 +01:00
|
|
|
* get the t_self from the modified tuple and call RelationReplaceHeapTuple
|
1996-07-09 08:22:35 +02:00
|
|
|
* else if a new operator is being created
|
1997-09-07 07:04:48 +02:00
|
|
|
* create a tuple using heap_formtuple
|
|
|
|
* call heap_insert
|
1996-07-09 08:22:35 +02:00
|
|
|
* --------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* "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
|
1999-04-11 04:30:59 +02:00
|
|
|
* procedureName; -- procedure name for operator code
|
1997-09-07 07:04:48 +02:00
|
|
|
* precedence; -- operator precedence
|
|
|
|
* isLeftAssociative; -- operator is left associative?
|
|
|
|
* commutatorName; -- X commutator operator name
|
|
|
|
* negatorName; -- X negator operator name
|
|
|
|
* restrictionName; -- X restriction sel. procedure name
|
|
|
|
* joinName; -- X join sel. procedure name
|
1999-04-11 04:30:59 +02:00
|
|
|
* canHash; -- can hash join be used with operator?
|
|
|
|
* leftSortName; -- X left sort operator (for merge join)
|
|
|
|
* rightSortName; -- X right sort operator (for merge join)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
OperatorDef(char *operatorName,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *leftTypeName,
|
|
|
|
char *rightTypeName,
|
|
|
|
char *procedureName,
|
|
|
|
uint16 precedence,
|
|
|
|
bool isLeftAssociative,
|
|
|
|
char *commutatorName,
|
|
|
|
char *negatorName,
|
|
|
|
char *restrictionName,
|
|
|
|
char *joinName,
|
|
|
|
bool canHash,
|
|
|
|
char *leftSortName,
|
|
|
|
char *rightSortName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-02-11 20:14:04 +01:00
|
|
|
int i,
|
1997-09-08 04:41:22 +02:00
|
|
|
j;
|
|
|
|
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];
|
|
|
|
Oid operatorObjectId;
|
1999-04-11 04:30:59 +02:00
|
|
|
bool operatorAlreadyDefined;
|
1997-09-08 04:41:22 +02:00
|
|
|
Oid leftTypeId = InvalidOid;
|
|
|
|
Oid rightTypeId = InvalidOid;
|
|
|
|
Oid commutatorId = InvalidOid;
|
|
|
|
Oid negatorId = InvalidOid;
|
|
|
|
bool leftDefined = false;
|
|
|
|
bool rightDefined = false;
|
1999-04-11 04:30:59 +02:00
|
|
|
bool selfCommutator = false;
|
1997-09-08 04:41:22 +02:00
|
|
|
char *name[4];
|
2000-01-10 18:14:46 +01:00
|
|
|
Oid typeId[FUNC_MAX_ARGS];
|
1997-09-08 04:41:22 +02:00
|
|
|
int nargs;
|
1998-09-01 06:40:42 +02:00
|
|
|
NameData oname;
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupDesc;
|
2001-06-01 04:41:36 +02:00
|
|
|
ScanKeyData opKey[3];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
operatorObjectId = OperatorGet(operatorName,
|
|
|
|
leftTypeName,
|
1999-04-11 04:30:59 +02:00
|
|
|
rightTypeName,
|
|
|
|
&operatorAlreadyDefined);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-04-11 04:30:59 +02:00
|
|
|
if (operatorAlreadyDefined)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "OperatorDef: operator \"%s\" already defined",
|
1997-09-07 07:04:48 +02:00
|
|
|
operatorName);
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
/*
|
|
|
|
* At this point, if operatorObjectId is not InvalidOid then we are
|
|
|
|
* filling in a previously-created shell.
|
1999-04-11 04:30:59 +02:00
|
|
|
*/
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* look up the operator data types.
|
1999-04-11 04:30:59 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* Note: types must be defined before operators
|
1999-04-11 04:30:59 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
if (leftTypeName)
|
1999-04-11 04:30:59 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
leftTypeId = TypeGet(leftTypeName, &leftDefined);
|
|
|
|
|
1999-04-11 04:30:59 +02:00
|
|
|
if (!OidIsValid(leftTypeId) || !leftDefined)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "left type \"%s\" does not exist",
|
1999-04-11 04:30:59 +02:00
|
|
|
leftTypeName);
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (rightTypeName)
|
1999-04-11 04:30:59 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
rightTypeId = TypeGet(rightTypeName, &rightDefined);
|
|
|
|
|
1999-04-11 04:30:59 +02:00
|
|
|
if (!OidIsValid(rightTypeId) || !rightDefined)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "right type \"%s\" does not exist",
|
1999-04-11 04:30:59 +02:00
|
|
|
rightTypeName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!((OidIsValid(leftTypeId) && leftDefined) ||
|
|
|
|
(OidIsValid(rightTypeId) && rightDefined)))
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "operator must have at least one operand type");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < Natts_pg_operator; ++i)
|
|
|
|
{
|
|
|
|
values[i] = (Datum) NULL;
|
|
|
|
replaces[i] = 'r';
|
|
|
|
nulls[i] = ' ';
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2000-01-10 18:14:46 +01:00
|
|
|
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!leftTypeName)
|
|
|
|
{
|
|
|
|
typeId[0] = rightTypeId;
|
|
|
|
nargs = 1;
|
|
|
|
}
|
|
|
|
else if (!rightTypeName)
|
|
|
|
{
|
|
|
|
typeId[0] = leftTypeId;
|
|
|
|
nargs = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
typeId[0] = leftTypeId;
|
|
|
|
typeId[1] = rightTypeId;
|
|
|
|
nargs = 2;
|
|
|
|
}
|
2000-11-16 23:30:52 +01:00
|
|
|
tup = SearchSysCache(PROCNAME,
|
|
|
|
PointerGetDatum(procedureName),
|
|
|
|
Int32GetDatum(nargs),
|
|
|
|
PointerGetDatum(typeId),
|
|
|
|
0);
|
1998-08-19 04:04:17 +02:00
|
|
|
if (!HeapTupleIsValid(tup))
|
1998-05-10 01:43:45 +02:00
|
|
|
func_error("OperatorDef", procedureName, nargs, typeId, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-11-27 20:52:36 +01:00
|
|
|
values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid);
|
1999-02-03 22:18:02 +01:00
|
|
|
values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc)
|
1999-05-25 18:15:34 +02:00
|
|
|
GETSTRUCT(tup))->prorettype);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-05-20 22:28:20 +02:00
|
|
|
* find restriction estimator
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (restrictionName)
|
|
|
|
{ /* optional */
|
2001-03-22 05:01:46 +01:00
|
|
|
Oid restOid;
|
2000-11-16 23:30:52 +01:00
|
|
|
|
2000-01-10 18:14:46 +01:00
|
|
|
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
2001-05-20 22:28:20 +02:00
|
|
|
typeId[0] = 0; /* Query (opaque type) */
|
|
|
|
typeId[1] = OIDOID; /* operator OID */
|
|
|
|
typeId[2] = 0; /* args list (opaque type) */
|
|
|
|
typeId[3] = INT4OID; /* varRelid */
|
2000-11-16 23:30:52 +01:00
|
|
|
|
|
|
|
restOid = GetSysCacheOid(PROCNAME,
|
|
|
|
PointerGetDatum(restrictionName),
|
2001-05-20 22:28:20 +02:00
|
|
|
Int32GetDatum(4),
|
2000-11-16 23:30:52 +01:00
|
|
|
PointerGetDatum(typeId),
|
|
|
|
0);
|
|
|
|
if (!OidIsValid(restOid))
|
2001-05-20 22:28:20 +02:00
|
|
|
func_error("OperatorDef", restrictionName, 4, typeId, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-05-20 22:28:20 +02:00
|
|
|
* find join estimator
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (joinName)
|
|
|
|
{ /* optional */
|
2001-03-22 05:01:46 +01:00
|
|
|
Oid joinOid;
|
2000-11-16 23:30:52 +01:00
|
|
|
|
2000-01-10 18:14:46 +01:00
|
|
|
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
2001-05-20 22:28:20 +02:00
|
|
|
typeId[0] = 0; /* Query (opaque type) */
|
|
|
|
typeId[1] = OIDOID; /* operator OID */
|
|
|
|
typeId[2] = 0; /* args list (opaque type) */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
joinOid = GetSysCacheOid(PROCNAME,
|
|
|
|
PointerGetDatum(joinName),
|
2001-05-20 22:28:20 +02:00
|
|
|
Int32GetDatum(3),
|
2000-11-16 23:30:52 +01:00
|
|
|
PointerGetDatum(typeId),
|
|
|
|
0);
|
|
|
|
if (!OidIsValid(joinOid))
|
2001-05-20 22:28:20 +02:00
|
|
|
func_error("OperatorDef", joinName, 3, typeId, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* set up values in the operator tuple
|
|
|
|
*/
|
|
|
|
i = 0;
|
1998-04-01 17:35:33 +02:00
|
|
|
namestrcpy(&oname, operatorName);
|
|
|
|
values[i++] = NameGetDatum(&oname);
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = Int32GetDatum(GetUserId());
|
|
|
|
values[i++] = UInt16GetDatum(precedence);
|
2000-08-21 19:22:36 +02:00
|
|
|
values[i++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
|
|
|
|
values[i++] = BoolGetDatum(isLeftAssociative);
|
|
|
|
values[i++] = BoolGetDatum(canHash);
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(leftTypeId);
|
|
|
|
values[i++] = ObjectIdGetDatum(rightTypeId);
|
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
++i; /* Skip "oprresult", it was filled in
|
|
|
|
* above */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
1999-04-11 04:30:59 +02:00
|
|
|
* Set up the other operators. If they do not currently exist, create
|
|
|
|
* shells in order to get ObjectId's.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
name[0] = commutatorName;
|
|
|
|
name[1] = negatorName;
|
|
|
|
name[2] = leftSortName;
|
|
|
|
name[3] = rightSortName;
|
|
|
|
|
|
|
|
for (j = 0; j < 4; ++j)
|
|
|
|
{
|
|
|
|
if (name[j])
|
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
char *otherLeftTypeName = NULL;
|
|
|
|
char *otherRightTypeName = NULL;
|
|
|
|
Oid otherLeftTypeId = InvalidOid;
|
|
|
|
Oid otherRightTypeId = InvalidOid;
|
|
|
|
Oid other_oid = InvalidOid;
|
|
|
|
bool otherDefined = false;
|
1999-04-11 04:30:59 +02:00
|
|
|
|
|
|
|
switch (j)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
case 0: /* commutator has reversed arg types */
|
1999-04-11 04:30:59 +02:00
|
|
|
otherLeftTypeName = rightTypeName;
|
|
|
|
otherRightTypeName = leftTypeName;
|
|
|
|
otherLeftTypeId = rightTypeId;
|
|
|
|
otherRightTypeId = leftTypeId;
|
|
|
|
other_oid = OperatorGet(name[j],
|
|
|
|
otherLeftTypeName,
|
|
|
|
otherRightTypeName,
|
|
|
|
&otherDefined);
|
|
|
|
commutatorId = other_oid;
|
|
|
|
break;
|
1999-05-25 18:15:34 +02:00
|
|
|
case 1: /* negator has same arg types */
|
1999-04-11 04:30:59 +02:00
|
|
|
otherLeftTypeName = leftTypeName;
|
|
|
|
otherRightTypeName = rightTypeName;
|
|
|
|
otherLeftTypeId = leftTypeId;
|
|
|
|
otherRightTypeId = rightTypeId;
|
|
|
|
other_oid = OperatorGet(name[j],
|
|
|
|
otherLeftTypeName,
|
|
|
|
otherRightTypeName,
|
|
|
|
&otherDefined);
|
1997-09-07 07:04:48 +02:00
|
|
|
negatorId = other_oid;
|
1999-04-11 04:30:59 +02:00
|
|
|
break;
|
1999-05-25 18:15:34 +02:00
|
|
|
case 2: /* left sort op takes left-side data type */
|
1999-04-11 04:30:59 +02:00
|
|
|
otherLeftTypeName = leftTypeName;
|
|
|
|
otherRightTypeName = leftTypeName;
|
|
|
|
otherLeftTypeId = leftTypeId;
|
|
|
|
otherRightTypeId = leftTypeId;
|
|
|
|
other_oid = OperatorGet(name[j],
|
|
|
|
otherLeftTypeName,
|
|
|
|
otherRightTypeName,
|
|
|
|
&otherDefined);
|
|
|
|
break;
|
1999-05-25 18:15:34 +02:00
|
|
|
case 3: /* right sort op takes right-side data
|
|
|
|
* type */
|
1999-04-11 04:30:59 +02:00
|
|
|
otherLeftTypeName = rightTypeName;
|
|
|
|
otherRightTypeName = rightTypeName;
|
|
|
|
otherLeftTypeId = rightTypeId;
|
|
|
|
otherRightTypeId = rightTypeId;
|
|
|
|
other_oid = OperatorGet(name[j],
|
|
|
|
otherLeftTypeName,
|
|
|
|
otherRightTypeName,
|
|
|
|
&otherDefined);
|
|
|
|
break;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1999-04-11 04:30:59 +02:00
|
|
|
if (OidIsValid(other_oid))
|
|
|
|
{
|
|
|
|
/* other op already in catalogs */
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(other_oid);
|
1999-04-11 04:30:59 +02:00
|
|
|
}
|
|
|
|
else if (strcmp(operatorName, name[j]) != 0 ||
|
|
|
|
otherLeftTypeId != leftTypeId ||
|
|
|
|
otherRightTypeId != rightTypeId)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
/* not in catalogs, different from operator */
|
1999-04-11 04:30:59 +02:00
|
|
|
other_oid = OperatorShellMake(name[j],
|
|
|
|
otherLeftTypeName,
|
|
|
|
otherRightTypeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!OidIsValid(other_oid))
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR,
|
2001-03-22 05:01:46 +01:00
|
|
|
"OperatorDef: can't create operator shell \"%s\"",
|
1997-09-07 07:04:48 +02:00
|
|
|
name[j]);
|
|
|
|
values[i++] = ObjectIdGetDatum(other_oid);
|
|
|
|
}
|
|
|
|
else
|
1999-04-11 04:30:59 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* self-linkage to this operator; will fix below. Note
|
|
|
|
* that only self-linkage for commutation makes sense.
|
1999-04-11 04:30:59 +02:00
|
|
|
*/
|
|
|
|
if (j != 0)
|
|
|
|
elog(ERROR,
|
2001-08-10 17:49:39 +02:00
|
|
|
"operator cannot be its own negator or sort operator");
|
1999-04-11 04:30:59 +02:00
|
|
|
selfCommutator = true;
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
1999-04-11 04:30:59 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
1999-04-11 04:30:59 +02:00
|
|
|
{
|
|
|
|
/* other operator is omitted */
|
1997-09-07 07:04:48 +02:00
|
|
|
values[i++] = ObjectIdGetDatum(InvalidOid);
|
1999-04-11 04:30:59 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1999-04-11 04:30:59 +02:00
|
|
|
/* last three fields were filled in above */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1998-11-27 20:52:36 +01:00
|
|
|
* If we are adding to an operator shell, get its t_self
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
if (operatorObjectId)
|
|
|
|
{
|
2000-01-18 00:57:48 +01:00
|
|
|
/* Make sure we can see the shell even if it is new in current cmd */
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
2001-06-01 04:41:36 +02:00
|
|
|
ScanKeyEntryInitialize(&opKey[0], 0x0,
|
|
|
|
Anum_pg_operator_oprname,
|
|
|
|
F_NAMEEQ,
|
|
|
|
PointerGetDatum(operatorName));
|
|
|
|
ScanKeyEntryInitialize(&opKey[1], 0x0,
|
|
|
|
Anum_pg_operator_oprleft,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(leftTypeId));
|
|
|
|
ScanKeyEntryInitialize(&opKey[2], 0x0,
|
|
|
|
Anum_pg_operator_oprright,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(rightTypeId));
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
pg_operator_scan = heap_beginscan(pg_operator_desc,
|
|
|
|
0,
|
1998-08-19 04:04:17 +02:00
|
|
|
SnapshotSelf, /* no cache? */
|
1997-09-07 07:04:48 +02:00
|
|
|
3,
|
|
|
|
opKey);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
tup = heap_getnext(pg_operator_scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
|
|
|
tup = heap_modifytuple(tup,
|
|
|
|
pg_operator_desc,
|
|
|
|
values,
|
|
|
|
nulls,
|
|
|
|
replaces);
|
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
heap_endscan(pg_operator_scan);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tupDesc = pg_operator_desc->rd_att;
|
|
|
|
tup = heap_formtuple(tupDesc, values, nulls);
|
|
|
|
|
|
|
|
heap_insert(pg_operator_desc, tup);
|
1998-11-27 20:52:36 +01:00
|
|
|
operatorObjectId = tup->t_data->t_oid;
|
1999-11-22 18:56:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (RelationGetForm(pg_operator_desc)->relhasindex)
|
|
|
|
{
|
|
|
|
Relation idescs[Num_pg_operator_indices];
|
|
|
|
|
|
|
|
CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
|
|
|
|
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_operator_desc, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
1999-04-11 04:30:59 +02:00
|
|
|
* If a commutator and/or negator link is provided, update the other
|
1999-05-25 18:15:34 +02:00
|
|
|
* 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.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-04-11 04:30:59 +02:00
|
|
|
if (selfCommutator)
|
|
|
|
commutatorId = operatorObjectId;
|
|
|
|
|
|
|
|
if (OidIsValid(commutatorId) || OidIsValid(negatorId))
|
1997-09-07 07:04:48 +02:00
|
|
|
OperatorUpd(operatorObjectId, commutatorId, negatorId);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* OperatorUpd
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* For a given operator, look up its negator and commutator operators.
|
1999-04-11 04:30:59 +02:00
|
|
|
* If they are defined, but their negator and commutator fields
|
|
|
|
* (respectively) are empty, then use the new operator for neg or comm.
|
1997-09-07 07:04:48 +02:00
|
|
|
* This solves a problem for users who need to insert two new operators
|
|
|
|
* which are the negator or commutator of each other.
|
|
|
|
* ----------------------------------------------------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
OperatorUpd(Oid baseId, Oid commId, Oid negId)
|
|
|
|
{
|
1998-02-11 20:14:04 +01:00
|
|
|
int i;
|
1997-09-08 04:41:22 +02:00
|
|
|
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];
|
2001-06-01 04:41:36 +02:00
|
|
|
ScanKeyData opKey[1];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < Natts_pg_operator; ++i)
|
|
|
|
{
|
2001-06-01 04:41:36 +02:00
|
|
|
values[i] = (Datum) 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
replaces[i] = ' ';
|
|
|
|
nulls[i] = ' ';
|
|
|
|
}
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-01-18 00:57:48 +01:00
|
|
|
/*
|
|
|
|
* check and update the commutator & negator, if necessary
|
|
|
|
*
|
|
|
|
* First make sure we can see them...
|
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
2001-06-01 04:41:36 +02:00
|
|
|
ScanKeyEntryInitialize(&opKey[0], 0x0,
|
|
|
|
ObjectIdAttributeNumber,
|
|
|
|
F_OIDEQ,
|
|
|
|
ObjectIdGetDatum(commId));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
pg_operator_scan = heap_beginscan(pg_operator_desc,
|
|
|
|
0,
|
1998-09-01 06:40:42 +02:00
|
|
|
SnapshotSelf, /* no cache? */
|
1997-09-07 07:04:48 +02:00
|
|
|
1,
|
|
|
|
opKey);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
tup = heap_getnext(pg_operator_scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
/*
|
|
|
|
* if the commutator and negator are the same operator, do one update.
|
1999-04-11 04:30:59 +02:00
|
|
|
* XXX this is probably useless code --- I doubt it ever makes sense
|
|
|
|
* for commutator and negator to be the same thing...
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
if (commId == negId)
|
|
|
|
{
|
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_operator t;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
t = (Form_pg_operator) GETSTRUCT(tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!OidIsValid(t->oprcom)
|
|
|
|
|| !OidIsValid(t->oprnegate))
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!OidIsValid(t->oprnegate))
|
|
|
|
{
|
1999-02-03 22:18:02 +01:00
|
|
|
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
|
1997-09-07 07:04:48 +02:00
|
|
|
replaces[Anum_pg_operator_oprnegate - 1] = 'r';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!OidIsValid(t->oprcom))
|
|
|
|
{
|
1999-02-03 22:18:02 +01:00
|
|
|
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
|
1997-09-07 07:04:48 +02:00
|
|
|
replaces[Anum_pg_operator_oprcom - 1] = 'r';
|
|
|
|
}
|
|
|
|
|
|
|
|
tup = heap_modifytuple(tup,
|
|
|
|
pg_operator_desc,
|
|
|
|
values,
|
|
|
|
nulls,
|
|
|
|
replaces);
|
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
|
2000-01-10 18:14:46 +01:00
|
|
|
|
1999-11-22 18:56:41 +01:00
|
|
|
if (RelationGetForm(pg_operator_desc)->relhasindex)
|
|
|
|
{
|
|
|
|
Relation idescs[Num_pg_operator_indices];
|
2000-01-10 18:14:46 +01:00
|
|
|
|
1999-11-22 18:56:41 +01:00
|
|
|
CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
|
|
|
|
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_endscan(pg_operator_scan);
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_operator_desc, RowExclusiveLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if commutator and negator are different, do two updates */
|
1999-04-23 02:50:57 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (HeapTupleIsValid(tup) &&
|
1998-09-01 05:29:17 +02:00
|
|
|
!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
|
|
|
|
replaces[Anum_pg_operator_oprcom - 1] = 'r';
|
1996-07-09 08:22:35 +02:00
|
|
|
tup = heap_modifytuple(tup,
|
1997-09-07 07:04:48 +02:00
|
|
|
pg_operator_desc,
|
|
|
|
values,
|
|
|
|
nulls,
|
|
|
|
replaces);
|
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-11-22 18:56:41 +01:00
|
|
|
if (RelationGetForm(pg_operator_desc)->relhasindex)
|
|
|
|
{
|
|
|
|
Relation idescs[Num_pg_operator_indices];
|
2000-01-10 18:14:46 +01:00
|
|
|
|
1999-11-22 18:56:41 +01:00
|
|
|
CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
|
|
|
|
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
|
|
|
|
replaces[Anum_pg_operator_oprcom - 1] = ' ';
|
|
|
|
}
|
|
|
|
|
1999-04-23 02:50:57 +02:00
|
|
|
heap_endscan(pg_operator_scan);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* check and update the negator, if necessary */
|
|
|
|
opKey[0].sk_argument = ObjectIdGetDatum(negId);
|
|
|
|
|
|
|
|
pg_operator_scan = heap_beginscan(pg_operator_desc,
|
|
|
|
0,
|
1998-09-01 06:40:42 +02:00
|
|
|
SnapshotSelf, /* no cache? */
|
1997-09-07 07:04:48 +02:00
|
|
|
1,
|
|
|
|
opKey);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
tup = heap_getnext(pg_operator_scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (HeapTupleIsValid(tup) &&
|
1998-09-01 05:29:17 +02:00
|
|
|
!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2001-01-23 05:32:23 +01:00
|
|
|
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
|
1999-11-22 18:56:41 +01:00
|
|
|
|
|
|
|
if (RelationGetForm(pg_operator_desc)->relhasindex)
|
|
|
|
{
|
|
|
|
Relation idescs[Num_pg_operator_indices];
|
2000-01-10 18:14:46 +01:00
|
|
|
|
1999-11-22 18:56:41 +01:00
|
|
|
CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs);
|
|
|
|
CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup);
|
|
|
|
CatalogCloseIndices(Num_pg_operator_indices, idescs);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_endscan(pg_operator_scan);
|
|
|
|
|
1999-09-18 21:08:25 +02:00
|
|
|
heap_close(pg_operator_desc, RowExclusiveLock);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* OperatorCreate
|
|
|
|
*
|
1999-04-11 04:30:59 +02:00
|
|
|
* This is now just an interface procedure for OperatorDef ...
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* "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
|
1999-04-11 04:30:59 +02:00
|
|
|
* 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)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
OperatorCreate(char *operatorName,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *leftTypeName,
|
|
|
|
char *rightTypeName,
|
|
|
|
char *procedureName,
|
|
|
|
uint16 precedence,
|
|
|
|
bool isLeftAssociative,
|
|
|
|
char *commutatorName,
|
|
|
|
char *negatorName,
|
|
|
|
char *restrictionName,
|
|
|
|
char *joinName,
|
|
|
|
bool canHash,
|
|
|
|
char *leftSortName,
|
|
|
|
char *rightSortName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!leftTypeName && !rightTypeName)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "at least one of leftarg or rightarg must be specified");
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-05-25 18:15:34 +02:00
|
|
|
if (!(leftTypeName && rightTypeName))
|
1999-04-11 04:30:59 +02:00
|
|
|
{
|
|
|
|
/* If it's not a binary op, these things mustn't be set: */
|
|
|
|
if (commutatorName)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "only binary operators can have commutators");
|
2001-05-20 22:28:20 +02:00
|
|
|
if (joinName)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "only binary operators can have join selectivity");
|
1999-04-11 04:30:59 +02:00
|
|
|
if (canHash)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "only binary operators can hash");
|
1999-04-11 04:30:59 +02:00
|
|
|
if (leftSortName || rightSortName)
|
2001-08-10 17:49:39 +02:00
|
|
|
elog(ERROR, "only binary operators can have sort links");
|
1999-04-11 04:30:59 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Use OperatorDef() to define the specified operator and also create
|
|
|
|
* shells for the operator's associated operators if they don't
|
|
|
|
* already exist.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
OperatorDef(operatorName,
|
|
|
|
leftTypeName,
|
|
|
|
rightTypeName,
|
|
|
|
procedureName,
|
|
|
|
precedence,
|
|
|
|
isLeftAssociative,
|
|
|
|
commutatorName,
|
|
|
|
negatorName,
|
|
|
|
restrictionName,
|
|
|
|
joinName,
|
|
|
|
canHash,
|
|
|
|
leftSortName,
|
|
|
|
rightSortName);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|