1
0
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:
Tom Lane
2003-08-17 19:58:06 +00:00
parent d89578ccbe
commit ec646dbc65
40 changed files with 968 additions and 495 deletions

View File

@@ -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
*

View File

@@ -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;

View File

@@ -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.

View File

@@ -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 ']' */

View File

@@ -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));
}

View File

@@ -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? */