mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Create a 'type cache' that keeps track of the data needed for any particular
datatype by array_eq and array_cmp; use this to solve problems with memory leaks in array indexing support. The parser's equality_oper and ordering_oper routines also use the cache. Change the operator search algorithms to look for appropriate btree or hash index opclasses, instead of assuming operators named '<' or '=' have the right semantics. (ORDER BY ASC/DESC now also look at opclasses, instead of assuming '<' and '>' are the right things.) Add several more index opclasses so that there is no regression in functionality for base datatypes. initdb forced due to catalog additions.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.95 2003/08/14 14:19:07 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.96 2003/08/17 19:58:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -480,6 +480,23 @@ aclitem_eq(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* aclitem hash function
|
||||
*
|
||||
* We make aclitems hashable not so much because anyone is likely to hash
|
||||
* them, as because we want array equality to work on aclitem arrays, and
|
||||
* with the typcache mechanism we must have a hash or btree opclass.
|
||||
*/
|
||||
Datum
|
||||
hash_aclitem(PG_FUNCTION_ARGS)
|
||||
{
|
||||
AclItem *a = PG_GETARG_ACLITEM_P(0);
|
||||
|
||||
/* not very bright, but avoids any issue of padding in struct */
|
||||
PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acldefault() --- create an ACL describing default access permissions
|
||||
*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.98 2003/08/15 00:22:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.99 2003/08/17 19:58:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/typcache.h"
|
||||
|
||||
|
||||
/*----------
|
||||
@@ -2341,6 +2342,9 @@ deconstruct_array(ArrayType *array,
|
||||
* compares two arrays for equality
|
||||
* result :
|
||||
* returns true if the arrays are equal, false otherwise.
|
||||
*
|
||||
* Note: we do not use array_cmp here, since equality may be meaningful in
|
||||
* datatypes that don't have a total ordering (and hence no btree support).
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
Datum
|
||||
@@ -2357,13 +2361,12 @@ array_eq(PG_FUNCTION_ARGS)
|
||||
int nitems1 = ArrayGetNItems(ndims1, dims1);
|
||||
int nitems2 = ArrayGetNItems(ndims2, dims2);
|
||||
Oid element_type = ARR_ELEMTYPE(array1);
|
||||
FmgrInfo *ae_fmgr_info = fcinfo->flinfo;
|
||||
bool result = true;
|
||||
TypeCacheEntry *typentry;
|
||||
int typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
int i;
|
||||
ArrayMetaState *my_extra;
|
||||
FunctionCallInfoData locfcinfo;
|
||||
|
||||
if (element_type != ARR_ELEMTYPE(array2))
|
||||
@@ -2379,38 +2382,31 @@ array_eq(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* We arrange to look up the equality function only once per
|
||||
* series of calls, assuming the element type doesn't change
|
||||
* underneath us.
|
||||
* underneath us. The typcache is used so that we have no
|
||||
* memory leakage when being used as an index support function.
|
||||
*/
|
||||
my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
|
||||
if (my_extra == NULL)
|
||||
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
||||
if (typentry == NULL ||
|
||||
typentry->type_id != element_type)
|
||||
{
|
||||
ae_fmgr_info->fn_extra = MemoryContextAlloc(ae_fmgr_info->fn_mcxt,
|
||||
sizeof(ArrayMetaState));
|
||||
my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra;
|
||||
my_extra->element_type = InvalidOid;
|
||||
typentry = lookup_type_cache(element_type,
|
||||
TYPECACHE_EQ_OPR_FINFO);
|
||||
if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
||||
errmsg("could not identify an equality operator for type %s",
|
||||
format_type_be(element_type))));
|
||||
fcinfo->flinfo->fn_extra = (void *) typentry;
|
||||
}
|
||||
|
||||
if (my_extra->element_type != element_type)
|
||||
{
|
||||
Oid opfuncid = equality_oper_funcid(element_type);
|
||||
|
||||
get_typlenbyvalalign(element_type,
|
||||
&my_extra->typlen,
|
||||
&my_extra->typbyval,
|
||||
&my_extra->typalign);
|
||||
fmgr_info_cxt(opfuncid, &my_extra->proc,
|
||||
ae_fmgr_info->fn_mcxt);
|
||||
my_extra->element_type = element_type;
|
||||
}
|
||||
typlen = my_extra->typlen;
|
||||
typbyval = my_extra->typbyval;
|
||||
typalign = my_extra->typalign;
|
||||
typlen = typentry->typlen;
|
||||
typbyval = typentry->typbyval;
|
||||
typalign = typentry->typalign;
|
||||
|
||||
/*
|
||||
* apply the operator to each pair of array elements.
|
||||
*/
|
||||
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
||||
locfcinfo.flinfo = &my_extra->proc;
|
||||
locfcinfo.flinfo = &typentry->eq_opr_finfo;
|
||||
locfcinfo.nargs = 2;
|
||||
|
||||
/* Loop over source data */
|
||||
@@ -2519,23 +2515,14 @@ array_cmp(FunctionCallInfo fcinfo)
|
||||
int nitems1 = ArrayGetNItems(ndims1, dims1);
|
||||
int nitems2 = ArrayGetNItems(ndims2, dims2);
|
||||
Oid element_type = ARR_ELEMTYPE(array1);
|
||||
FmgrInfo *ac_fmgr_info = fcinfo->flinfo;
|
||||
int result = 0;
|
||||
TypeCacheEntry *typentry;
|
||||
int typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
int min_nitems;
|
||||
int i;
|
||||
typedef struct
|
||||
{
|
||||
Oid element_type;
|
||||
int16 typlen;
|
||||
bool typbyval;
|
||||
char typalign;
|
||||
FmgrInfo eqproc;
|
||||
FmgrInfo ordproc;
|
||||
} ac_extra;
|
||||
ac_extra *my_extra;
|
||||
FunctionCallInfoData locfcinfo;
|
||||
|
||||
if (element_type != ARR_ELEMTYPE(array2))
|
||||
ereport(ERROR,
|
||||
@@ -2543,37 +2530,34 @@ array_cmp(FunctionCallInfo fcinfo)
|
||||
errmsg("cannot compare arrays of different element types")));
|
||||
|
||||
/*
|
||||
* We arrange to look up the element type info and related functions
|
||||
* only once per series of calls, assuming the element type doesn't
|
||||
* change underneath us.
|
||||
* We arrange to look up the comparison function only once per series of
|
||||
* calls, assuming the element type doesn't change underneath us.
|
||||
* The typcache is used so that we have no memory leakage when being used
|
||||
* as an index support function.
|
||||
*/
|
||||
my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
|
||||
if (my_extra == NULL)
|
||||
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
|
||||
if (typentry == NULL ||
|
||||
typentry->type_id != element_type)
|
||||
{
|
||||
ac_fmgr_info->fn_extra = MemoryContextAlloc(ac_fmgr_info->fn_mcxt,
|
||||
sizeof(ac_extra));
|
||||
my_extra = (ac_extra *) ac_fmgr_info->fn_extra;
|
||||
my_extra->element_type = InvalidOid;
|
||||
typentry = lookup_type_cache(element_type,
|
||||
TYPECACHE_CMP_PROC_FINFO);
|
||||
if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
||||
errmsg("could not identify a comparison function for type %s",
|
||||
format_type_be(element_type))));
|
||||
fcinfo->flinfo->fn_extra = (void *) typentry;
|
||||
}
|
||||
typlen = typentry->typlen;
|
||||
typbyval = typentry->typbyval;
|
||||
typalign = typentry->typalign;
|
||||
|
||||
if (my_extra->element_type != element_type)
|
||||
{
|
||||
Oid eqfuncid = equality_oper_funcid(element_type);
|
||||
Oid ordfuncid = ordering_oper_funcid(element_type);
|
||||
|
||||
get_typlenbyvalalign(element_type,
|
||||
&my_extra->typlen,
|
||||
&my_extra->typbyval,
|
||||
&my_extra->typalign);
|
||||
fmgr_info_cxt(eqfuncid, &my_extra->eqproc,
|
||||
ac_fmgr_info->fn_mcxt);
|
||||
fmgr_info_cxt(ordfuncid, &my_extra->ordproc,
|
||||
ac_fmgr_info->fn_mcxt);
|
||||
my_extra->element_type = element_type;
|
||||
}
|
||||
typlen = my_extra->typlen;
|
||||
typbyval = my_extra->typbyval;
|
||||
typalign = my_extra->typalign;
|
||||
/*
|
||||
* apply the operator to each pair of array elements.
|
||||
*/
|
||||
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
|
||||
locfcinfo.flinfo = &typentry->cmp_proc_finfo;
|
||||
locfcinfo.nargs = 2;
|
||||
|
||||
/* Loop over source data */
|
||||
min_nitems = Min(nitems1, nitems2);
|
||||
@@ -2581,7 +2565,7 @@ array_cmp(FunctionCallInfo fcinfo)
|
||||
{
|
||||
Datum elt1;
|
||||
Datum elt2;
|
||||
Datum opresult;
|
||||
int32 cmpresult;
|
||||
|
||||
/* Get element pair */
|
||||
elt1 = fetch_att(p1, typbyval, typlen);
|
||||
@@ -2594,15 +2578,17 @@ array_cmp(FunctionCallInfo fcinfo)
|
||||
p2 = (char *) att_align(p2, typalign);
|
||||
|
||||
/* Compare the pair of elements */
|
||||
locfcinfo.arg[0] = elt1;
|
||||
locfcinfo.arg[1] = elt2;
|
||||
locfcinfo.argnull[0] = false;
|
||||
locfcinfo.argnull[1] = false;
|
||||
locfcinfo.isnull = false;
|
||||
cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
|
||||
|
||||
/* are they equal */
|
||||
opresult = FunctionCall2(&my_extra->eqproc, elt1, elt2);
|
||||
if (DatumGetBool(opresult))
|
||||
continue;
|
||||
if (cmpresult == 0)
|
||||
continue; /* equal */
|
||||
|
||||
/* nope, see if arg1 is less than arg2 */
|
||||
opresult = FunctionCall2(&my_extra->ordproc, elt1, elt2);
|
||||
if (DatumGetBool(opresult))
|
||||
if (cmpresult < 0)
|
||||
{
|
||||
/* arg1 is less than arg2 */
|
||||
result = -1;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* workings can be found in the book "Software Solutions in C" by
|
||||
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.59 2003/07/27 04:53:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.60 2003/08/17 19:58:05 tgl Exp $
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
@@ -342,6 +342,9 @@ cash_send(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison functions
|
||||
*/
|
||||
|
||||
Datum
|
||||
cash_eq(PG_FUNCTION_ARGS)
|
||||
@@ -397,6 +400,20 @@ cash_ge(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(c1 >= c2);
|
||||
}
|
||||
|
||||
Datum
|
||||
cash_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Cash c1 = PG_GETARG_CASH(0);
|
||||
Cash c2 = PG_GETARG_CASH(1);
|
||||
|
||||
if (c1 > c2)
|
||||
PG_RETURN_INT32(1);
|
||||
else if (c1 == c2)
|
||||
PG_RETURN_INT32(0);
|
||||
else
|
||||
PG_RETURN_INT32(-1);
|
||||
}
|
||||
|
||||
|
||||
/* cash_pl()
|
||||
* Add two cash values.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.113 2003/08/04 02:40:05 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.114 2003/08/17 19:58:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -505,11 +505,11 @@ abstime_finite(PG_FUNCTION_ARGS)
|
||||
static int
|
||||
abstime_cmp_internal(AbsoluteTime a, AbsoluteTime b)
|
||||
{
|
||||
/*
|
||||
* We consider all INVALIDs to be equal and larger than any non-INVALID.
|
||||
* This is somewhat arbitrary; the important thing is to have a
|
||||
* consistent sort order.
|
||||
*/
|
||||
/*
|
||||
* We consider all INVALIDs to be equal and larger than any non-INVALID.
|
||||
* This is somewhat arbitrary; the important thing is to have a
|
||||
* consistent sort order.
|
||||
*/
|
||||
if (a == INVALID_ABSTIME)
|
||||
{
|
||||
if (b == INVALID_ABSTIME)
|
||||
@@ -904,7 +904,7 @@ tintervalout(PG_FUNCTION_ARGS)
|
||||
char *i_str,
|
||||
*p;
|
||||
|
||||
i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */
|
||||
i_str = (char *) palloc(T_INTERVAL_LEN); /* ["..." "..."] */
|
||||
strcpy(i_str, "[\"");
|
||||
if (interval->status == T_INTERVAL_INVAL)
|
||||
strcat(i_str, INVALID_INTERVAL_STR);
|
||||
@@ -920,7 +920,7 @@ tintervalout(PG_FUNCTION_ARGS)
|
||||
strcat(i_str, p);
|
||||
pfree(p);
|
||||
}
|
||||
strcat(i_str, "\"]\0");
|
||||
strcat(i_str, "\"]");
|
||||
PG_RETURN_CSTRING(i_str);
|
||||
}
|
||||
|
||||
@@ -1190,22 +1190,42 @@ timenow(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
/*
|
||||
* reltimeeq - returns true iff arguments are equal
|
||||
* reltimene - returns true iff arguments are not equal
|
||||
* reltimelt - returns true iff t1 less than t2
|
||||
* reltimegt - returns true iff t1 greater than t2
|
||||
* reltimele - returns true iff t1 less than or equal to t2
|
||||
* reltimege - returns true iff t1 greater than or equal to t2
|
||||
* reltime comparison routines
|
||||
*/
|
||||
static int
|
||||
reltime_cmp_internal(RelativeTime a, RelativeTime b)
|
||||
{
|
||||
/*
|
||||
* We consider all INVALIDs to be equal and larger than any non-INVALID.
|
||||
* This is somewhat arbitrary; the important thing is to have a
|
||||
* consistent sort order.
|
||||
*/
|
||||
if (a == INVALID_RELTIME)
|
||||
{
|
||||
if (b == INVALID_RELTIME)
|
||||
return 0; /* INVALID = INVALID */
|
||||
else
|
||||
return 1; /* INVALID > non-INVALID */
|
||||
}
|
||||
|
||||
if (b == INVALID_RELTIME)
|
||||
return -1; /* non-INVALID < INVALID */
|
||||
|
||||
if (a > b)
|
||||
return 1;
|
||||
else if (a == b)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
Datum
|
||||
reltimeeq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(t1 == t2);
|
||||
PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) == 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1214,9 +1234,7 @@ reltimene(PG_FUNCTION_ARGS)
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(t1 != t2);
|
||||
PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) != 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1225,9 +1243,7 @@ reltimelt(PG_FUNCTION_ARGS)
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(t1 < t2);
|
||||
PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) < 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1236,9 +1252,7 @@ reltimegt(PG_FUNCTION_ARGS)
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(t1 > t2);
|
||||
PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) > 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1247,9 +1261,7 @@ reltimele(PG_FUNCTION_ARGS)
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(t1 <= t2);
|
||||
PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) <= 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1258,9 +1270,16 @@ reltimege(PG_FUNCTION_ARGS)
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(t1 >= t2);
|
||||
PG_RETURN_BOOL(reltime_cmp_internal(t1, t2) >= 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
btreltimecmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RelativeTime t1 = PG_GETARG_RELATIVETIME(0);
|
||||
RelativeTime t2 = PG_GETARG_RELATIVETIME(1);
|
||||
|
||||
PG_RETURN_INT32(reltime_cmp_internal(t1, t2));
|
||||
}
|
||||
|
||||
|
||||
@@ -1287,34 +1306,62 @@ tintervalsame(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* tintervaleq - returns true iff interval i1 is equal to interval i2
|
||||
* Check length of intervals.
|
||||
* tinterval comparison routines
|
||||
*
|
||||
* Note: comparison is based on the lengths of the intervals, not on
|
||||
* endpoint value. This is pretty bogus, but since it's only a legacy
|
||||
* datatype I'm not going to propose changing it.
|
||||
*/
|
||||
static int
|
||||
tinterval_cmp_internal(TimeInterval a, TimeInterval b)
|
||||
{
|
||||
bool a_invalid;
|
||||
bool b_invalid;
|
||||
AbsoluteTime a_len;
|
||||
AbsoluteTime b_len;
|
||||
|
||||
/*
|
||||
* We consider all INVALIDs to be equal and larger than any non-INVALID.
|
||||
* This is somewhat arbitrary; the important thing is to have a
|
||||
* consistent sort order.
|
||||
*/
|
||||
a_invalid = ((a->status == T_INTERVAL_INVAL) ||
|
||||
(a->data[0] == INVALID_ABSTIME) ||
|
||||
(a->data[1] == INVALID_ABSTIME));
|
||||
b_invalid = ((b->status == T_INTERVAL_INVAL) ||
|
||||
(b->data[0] == INVALID_ABSTIME) ||
|
||||
(b->data[1] == INVALID_ABSTIME));
|
||||
|
||||
if (a_invalid)
|
||||
{
|
||||
if (b_invalid)
|
||||
return 0; /* INVALID = INVALID */
|
||||
else
|
||||
return 1; /* INVALID > non-INVALID */
|
||||
}
|
||||
|
||||
if (b_invalid)
|
||||
return -1; /* non-INVALID < INVALID */
|
||||
|
||||
a_len = a->data[1] - a->data[0];
|
||||
b_len = b->data[1] - b->data[0];
|
||||
|
||||
if (a_len > b_len)
|
||||
return 1;
|
||||
else if (a_len == b_len)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
Datum
|
||||
tintervaleq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
AbsoluteTime t10,
|
||||
t11,
|
||||
t20,
|
||||
t21;
|
||||
|
||||
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
t10 = i1->data[0];
|
||||
t11 = i1->data[1];
|
||||
t20 = i2->data[0];
|
||||
t21 = i2->data[1];
|
||||
|
||||
if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|
||||
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
PG_RETURN_BOOL((t11 - t10) == (t21 - t20));
|
||||
PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1322,24 +1369,8 @@ tintervalne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
AbsoluteTime t10,
|
||||
t11,
|
||||
t20,
|
||||
t21;
|
||||
|
||||
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
t10 = i1->data[0];
|
||||
t11 = i1->data[1];
|
||||
t20 = i2->data[0];
|
||||
t21 = i2->data[1];
|
||||
|
||||
if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|
||||
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
PG_RETURN_BOOL((t11 - t10) != (t21 - t20));
|
||||
PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) != 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1347,24 +1378,8 @@ tintervallt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
AbsoluteTime t10,
|
||||
t11,
|
||||
t20,
|
||||
t21;
|
||||
|
||||
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
t10 = i1->data[0];
|
||||
t11 = i1->data[1];
|
||||
t20 = i2->data[0];
|
||||
t21 = i2->data[1];
|
||||
|
||||
if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|
||||
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
PG_RETURN_BOOL((t11 - t10) < (t21 - t20));
|
||||
PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) < 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1372,24 +1387,8 @@ tintervalle(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
AbsoluteTime t10,
|
||||
t11,
|
||||
t20,
|
||||
t21;
|
||||
|
||||
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
t10 = i1->data[0];
|
||||
t11 = i1->data[1];
|
||||
t20 = i2->data[0];
|
||||
t21 = i2->data[1];
|
||||
|
||||
if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|
||||
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
PG_RETURN_BOOL((t11 - t10) <= (t21 - t20));
|
||||
PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) <= 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1397,24 +1396,8 @@ tintervalgt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
AbsoluteTime t10,
|
||||
t11,
|
||||
t20,
|
||||
t21;
|
||||
|
||||
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
t10 = i1->data[0];
|
||||
t11 = i1->data[1];
|
||||
t20 = i2->data[0];
|
||||
t21 = i2->data[1];
|
||||
|
||||
if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|
||||
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
PG_RETURN_BOOL((t11 - t10) > (t21 - t20));
|
||||
PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) > 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -1422,24 +1405,17 @@ tintervalge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
AbsoluteTime t10,
|
||||
t11,
|
||||
t20,
|
||||
t21;
|
||||
|
||||
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
|
||||
PG_RETURN_BOOL(false);
|
||||
PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0);
|
||||
}
|
||||
|
||||
t10 = i1->data[0];
|
||||
t11 = i1->data[1];
|
||||
t20 = i2->data[0];
|
||||
t21 = i2->data[1];
|
||||
Datum
|
||||
bttintervalcmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0);
|
||||
TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1);
|
||||
|
||||
if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME)
|
||||
|| (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME))
|
||||
PG_RETURN_BOOL(false);
|
||||
|
||||
PG_RETURN_BOOL((t11 - t10) >= (t21 - t20));
|
||||
PG_RETURN_INT32(tinterval_cmp_internal(i1, i2));
|
||||
}
|
||||
|
||||
|
||||
@@ -1652,7 +1628,7 @@ istinterval(char *i_string,
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
/* skip leading blanks up to "'" */
|
||||
/* skip leading blanks up to '"' */
|
||||
while ((c = *p) != '\0')
|
||||
{
|
||||
if (IsSpace(c))
|
||||
@@ -1680,10 +1656,10 @@ istinterval(char *i_string,
|
||||
/* get the first date */
|
||||
*i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
|
||||
CStringGetDatum(p)));
|
||||
/* rechange NULL at the end of the first date to a "'" */
|
||||
/* rechange NULL at the end of the first date to a '"' */
|
||||
*p1 = '"';
|
||||
p = ++p1;
|
||||
/* skip blanks up to "'", beginning of second date */
|
||||
/* skip blanks up to '"', beginning of second date */
|
||||
while ((c = *p) != '\0')
|
||||
{
|
||||
if (IsSpace(c))
|
||||
@@ -1708,7 +1684,7 @@ istinterval(char *i_string,
|
||||
/* get the second date */
|
||||
*i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
|
||||
CStringGetDatum(p)));
|
||||
/* rechange NULL at the end of the first date to a ''' */
|
||||
/* rechange NULL at the end of the first date to a '"' */
|
||||
*p1 = '"';
|
||||
p = ++p1;
|
||||
/* skip blanks up to ']' */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*
|
||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.54 2003/08/04 02:40:05 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.55 2003/08/17 19:58:05 tgl Exp $
|
||||
*
|
||||
* ----------
|
||||
*/
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "parser/parse_oper.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/typcache.h"
|
||||
#include "miscadmin.h"
|
||||
|
||||
|
||||
@@ -48,7 +49,6 @@
|
||||
*/
|
||||
|
||||
#define RI_INIT_QUERYHASHSIZE 128
|
||||
#define RI_INIT_OPREQHASHSIZE 128
|
||||
|
||||
#define RI_MATCH_TYPE_UNSPECIFIED 0
|
||||
#define RI_MATCH_TYPE_FULL 1
|
||||
@@ -109,20 +109,11 @@ typedef struct RI_QueryHashEntry
|
||||
} RI_QueryHashEntry;
|
||||
|
||||
|
||||
typedef struct RI_OpreqHashEntry
|
||||
{
|
||||
Oid typeid;
|
||||
FmgrInfo oprfmgrinfo;
|
||||
} RI_OpreqHashEntry;
|
||||
|
||||
|
||||
|
||||
/* ----------
|
||||
* Local data
|
||||
* ----------
|
||||
*/
|
||||
static HTAB *ri_query_cache = (HTAB *) NULL;
|
||||
static HTAB *ri_opreq_cache = (HTAB *) NULL;
|
||||
|
||||
|
||||
/* ----------
|
||||
@@ -3197,8 +3188,8 @@ ri_NullCheck(Relation rel, HeapTuple tup, RI_QueryKey *key, int pairidx)
|
||||
/* ----------
|
||||
* ri_InitHashTables -
|
||||
*
|
||||
* Initialize our internal hash tables for prepared
|
||||
* query plans and equal operators.
|
||||
* Initialize our internal hash table for prepared
|
||||
* query plans.
|
||||
* ----------
|
||||
*/
|
||||
static void
|
||||
@@ -3212,12 +3203,6 @@ ri_InitHashTables(void)
|
||||
ctl.hash = tag_hash;
|
||||
ri_query_cache = hash_create("RI query cache", RI_INIT_QUERYHASHSIZE,
|
||||
&ctl, HASH_ELEM | HASH_FUNCTION);
|
||||
|
||||
ctl.keysize = sizeof(Oid);
|
||||
ctl.entrysize = sizeof(RI_OpreqHashEntry);
|
||||
ctl.hash = tag_hash;
|
||||
ri_opreq_cache = hash_create("RI OpReq cache", RI_INIT_OPREQHASHSIZE,
|
||||
&ctl, HASH_ELEM | HASH_FUNCTION);
|
||||
}
|
||||
|
||||
|
||||
@@ -3438,57 +3423,22 @@ ri_OneKeyEqual(Relation rel, int column, HeapTuple oldtup, HeapTuple newtup,
|
||||
static bool
|
||||
ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
|
||||
{
|
||||
RI_OpreqHashEntry *entry;
|
||||
bool found;
|
||||
TypeCacheEntry *typentry;
|
||||
|
||||
/*
|
||||
* On the first call initialize the hashtable
|
||||
* Find the data type in the typcache, and ask for eq_opr info.
|
||||
*/
|
||||
if (!ri_opreq_cache)
|
||||
ri_InitHashTables();
|
||||
typentry = lookup_type_cache(typeid, TYPECACHE_EQ_OPR_FINFO);
|
||||
|
||||
/*
|
||||
* Try to find the '=' operator for this type in our cache
|
||||
*/
|
||||
entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
|
||||
(void *) &typeid,
|
||||
HASH_FIND, NULL);
|
||||
|
||||
/*
|
||||
* If not found, lookup the operator, then do the function manager
|
||||
* lookup, and remember that info.
|
||||
*/
|
||||
if (!entry)
|
||||
{
|
||||
Oid opr_proc;
|
||||
FmgrInfo finfo;
|
||||
|
||||
opr_proc = equality_oper_funcid(typeid);
|
||||
|
||||
/*
|
||||
* Since fmgr_info could fail, call it *before* creating the
|
||||
* hashtable entry --- otherwise we could ereport leaving an
|
||||
* incomplete entry in the hashtable. Also, because this will be
|
||||
* a permanent table entry, we must make sure any subsidiary
|
||||
* structures of the fmgr record are kept in TopMemoryContext.
|
||||
*/
|
||||
fmgr_info_cxt(opr_proc, &finfo, TopMemoryContext);
|
||||
|
||||
entry = (RI_OpreqHashEntry *) hash_search(ri_opreq_cache,
|
||||
(void *) &typeid,
|
||||
HASH_ENTER, &found);
|
||||
if (entry == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
|
||||
entry->typeid = typeid;
|
||||
memcpy(&(entry->oprfmgrinfo), &finfo, sizeof(FmgrInfo));
|
||||
}
|
||||
if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
||||
errmsg("could not identify an equality operator for type %s",
|
||||
format_type_be(typeid))));
|
||||
|
||||
/*
|
||||
* Call the type specific '=' function
|
||||
*/
|
||||
return DatumGetBool(FunctionCall2(&(entry->oprfmgrinfo),
|
||||
return DatumGetBool(FunctionCall2(&(typentry->eq_opr_finfo),
|
||||
oldvalue, newvalue));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* back to source text
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.151 2003/08/11 23:04:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.152 2003/08/17 19:58:05 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -69,6 +69,7 @@
|
||||
#include "utils/array.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/typcache.h"
|
||||
|
||||
|
||||
/* ----------
|
||||
@@ -1815,21 +1816,24 @@ get_select_query_def(Query *query, deparse_context *context,
|
||||
SortClause *srt = (SortClause *) lfirst(l);
|
||||
Node *sortexpr;
|
||||
Oid sortcoltype;
|
||||
char *opname;
|
||||
TypeCacheEntry *typentry;
|
||||
|
||||
appendStringInfo(buf, sep);
|
||||
sortexpr = get_rule_sortgroupclause(srt, query->targetList,
|
||||
force_colno, context);
|
||||
sortcoltype = exprType(sortexpr);
|
||||
opname = generate_operator_name(srt->sortop,
|
||||
sortcoltype, sortcoltype);
|
||||
if (strcmp(opname, "<") != 0)
|
||||
{
|
||||
if (strcmp(opname, ">") == 0)
|
||||
appendStringInfo(buf, " DESC");
|
||||
else
|
||||
appendStringInfo(buf, " USING %s", opname);
|
||||
}
|
||||
/* See whether operator is default < or > for datatype */
|
||||
typentry = lookup_type_cache(sortcoltype,
|
||||
TYPECACHE_LT_OPR | TYPECACHE_GT_OPR);
|
||||
if (srt->sortop == typentry->lt_opr)
|
||||
/* ASC is default, so emit nothing */ ;
|
||||
else if (srt->sortop == typentry->gt_opr)
|
||||
appendStringInfo(buf, " DESC");
|
||||
else
|
||||
appendStringInfo(buf, " USING %s",
|
||||
generate_operator_name(srt->sortop,
|
||||
sortcoltype,
|
||||
sortcoltype));
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
@@ -4032,6 +4036,15 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
|
||||
if (!HeapTupleIsValid(ht_opc))
|
||||
elog(ERROR, "cache lookup failed for opclass %u", opclass);
|
||||
opcrec = (Form_pg_opclass) GETSTRUCT(ht_opc);
|
||||
|
||||
/* Special case for ARRAY_OPS: pretend it is default for any array type */
|
||||
if (OidIsValid(actual_datatype))
|
||||
{
|
||||
if (opcrec->opcintype == ANYARRAYOID &&
|
||||
OidIsValid(get_element_type(actual_datatype)))
|
||||
actual_datatype = opcrec->opcintype;
|
||||
}
|
||||
|
||||
if (actual_datatype != opcrec->opcintype || !opcrec->opcdefault)
|
||||
{
|
||||
/* Okay, we need the opclass name. Do we need to qualify it? */
|
||||
|
||||
Reference in New Issue
Block a user