diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-08-17 19:58:06 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-08-17 19:58:06 +0000 |
commit | ec646dbc65afc8c55118cb3fb75cb6fd18d78dd8 (patch) | |
tree | bd256cf157c4636382d59938162326fccc70b62c /src/backend/utils/adt | |
parent | d89578ccbefb83aa9f9d1c00269cd866be2cc857 (diff) | |
download | postgresql-ec646dbc65afc8c55118cb3fb75cb6fd18d78dd8.tar.gz postgresql-ec646dbc65afc8c55118cb3fb75cb6fd18d78dd8.zip |
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.
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/acl.c | 19 | ||||
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 132 | ||||
-rw-r--r-- | src/backend/utils/adt/cash.c | 19 | ||||
-rw-r--r-- | src/backend/utils/adt/nabstime.c | 254 | ||||
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 76 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 35 |
6 files changed, 247 insertions, 288 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 504e8f55652..8d5a675006b 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -481,6 +481,23 @@ aclitem_eq(PG_FUNCTION_ARGS) } /* + * 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 * * Change this routine if you want to alter the default access policy for diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 37504718ad5..46f7881d648 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -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; - } - - 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; + 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; } - 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; diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index e33aad28d64..c4fc14134f0 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -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. diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c index a4f3b061e6f..f694349db7a 100644 --- a/src/backend/utils/adt/nabstime.c +++ b/src/backend/utils/adt/nabstime.c @@ -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,59 +1306,71 @@ 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. */ -Datum -tintervaleq(PG_FUNCTION_ARGS) +static int +tinterval_cmp_internal(TimeInterval a, TimeInterval b) { - TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); - TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); - AbsoluteTime t10, - t11, - t20, - t21; + bool a_invalid; + bool b_invalid; + AbsoluteTime a_len; + AbsoluteTime b_len; - if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL) - PG_RETURN_BOOL(false); + /* + * 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 */ + } - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + if (b_invalid) + return -1; /* non-INVALID < INVALID */ - if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - PG_RETURN_BOOL(false); + a_len = a->data[1] - a->data[0]; + b_len = b->data[1] - b->data[0]; - PG_RETURN_BOOL((t11 - t10) == (t21 - t20)); + if (a_len > b_len) + return 1; + else if (a_len == b_len) + return 0; + else + return -1; } Datum -tintervalne(PG_FUNCTION_ARGS) +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]; + PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) == 0); +} - if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - PG_RETURN_BOOL(false); +Datum +tintervalne(PG_FUNCTION_ARGS) +{ + TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); + TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); - 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); - t10 = i1->data[0]; - t11 = i1->data[1]; - t20 = i2->data[0]; - t21 = i2->data[1]; + PG_RETURN_BOOL(tinterval_cmp_internal(i1, i2) >= 0); +} - if ((t10 == INVALID_ABSTIME) || (t11 == INVALID_ABSTIME) - || (t20 == INVALID_ABSTIME) || (t21 == INVALID_ABSTIME)) - PG_RETURN_BOOL(false); +Datum +bttintervalcmp(PG_FUNCTION_ARGS) +{ + TimeInterval i1 = PG_GETARG_TIMEINTERVAL(0); + TimeInterval i2 = PG_GETARG_TIMEINTERVAL(1); - 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 ']' */ diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 7476204d89f..55a6944971e 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -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)); } diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 83989292d6a..5504251bc47 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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? */ |