diff -Naur pgsql.virg/src/backend/utils/adt/selfuncs.c pgsql.dev/src/backend/utils/adt/selfuncs.c --- pgsql.virg/src/backend/utils/adt/selfuncs.c Sat Aug 11 04:57:46 2001 +++ pgsql.dev/src/backend/utils/adt/selfuncs.c Mon Aug 13 00:38:18 2001 @@ -134,8 +134,16 @@ double *scaledlobound, unsigned char *hibound, double *scaledhibound); +static void convert_bytea_to_scalar(Datum value, + double *scaledvalue, + Datum lobound, + double *scaledlobound, + Datum hibound, + double *scaledhibound); static double convert_one_string_to_scalar(unsigned char *value, int rangelo, int rangehi); +static double convert_one_bytea_to_scalar(unsigned char *value, int valuelen, + int rangelo, int rangehi); static unsigned char *convert_string_datum(Datum value, Oid typid); static double convert_timevalue_to_scalar(Datum value, Oid typid); static double get_att_numdistinct(Query *root, Var *var, @@ -1719,6 +1727,17 @@ } /* + * Built-in bytea type + */ + case BYTEAOID: + { + convert_bytea_to_scalar(value, scaledvalue, + lobound, scaledlobound, + hibound, scaledhibound); + return true; + } + + /* * Built-in time types */ case TIMESTAMPOID: @@ -1787,7 +1806,8 @@ } /* - * Do convert_to_scalar()'s work for any character-string data type. + * Do convert_to_scalar()'s work for any character-string data type + * except bytea (since we can't assume null-termination with bytea) * * String datatypes are converted to a scale that ranges from 0 to 1, * where we visualize the bytes of the string as fractional digits. @@ -1994,6 +2014,99 @@ #endif return (unsigned char *) val; +} + +/* + * Do convert_to_scalar()'s work for any bytea data type. + * + * Very similar to convert_string_to_scalar except + * we don't assume string-safe null-termination and + * therefore pass explicit lengths around. + * + * Also assumptions about likely "normal" ranges of + * charachters have been removed - 0..255 is always + * used. + */ +static void +convert_bytea_to_scalar(Datum value, + double *scaledvalue, + Datum lobound, + double *scaledlobound, + Datum hibound, + double *scaledhibound) +{ + int rangelo, + rangehi, + valuelen = VARSIZE(DatumGetPointer(value)) - VARHDRSZ, + loboundlen = VARSIZE(DatumGetPointer(lobound)) - VARHDRSZ, + hiboundlen = VARSIZE(DatumGetPointer(hibound)) - VARHDRSZ, + i; + unsigned char *valstr = (unsigned char *) VARDATA(DatumGetPointer(value)), + *lostr = (unsigned char *) VARDATA(DatumGetPointer(lobound)), + *histr = (unsigned char *) VARDATA(DatumGetPointer(hibound)); + + /* + * Assume binary data is uniformily distributed + * and therefore includes the entire ASCII set. + */ + rangelo = 0; + rangehi = 255; + + /* + * Now strip any common prefix of the three strings. + */ + + for (i = 0; i < Min(Min(valuelen, loboundlen), hiboundlen); i++) + { + if (*lostr != *histr || *lostr != *valstr) + break; + lostr++, histr++, valstr++; + loboundlen--, hiboundlen--, valuelen--; + } + + /* + * Now we can do the conversions. + */ + *scaledvalue = convert_one_bytea_to_scalar(valstr, valuelen, rangelo, rangehi); + *scaledlobound = convert_one_bytea_to_scalar(lostr, loboundlen, rangelo, rangehi); + *scaledhibound = convert_one_bytea_to_scalar(histr, hiboundlen, rangelo, rangehi); +} + +static double +convert_one_bytea_to_scalar(unsigned char *value, int valuelen, + int rangelo, int rangehi) +{ + double num, + denom, + base; + + if (valuelen <= 0) + return 0.0; /* empty string has scalar value 0 */ + + /* + * Since base is 256, need not consider more than about 10 + * chars (even this many seems like overkill) + */ + if (valuelen > 10) + valuelen = 10; + + /* Convert initial characters to fraction */ + base = rangehi - rangelo + 1; + num = 0.0; + denom = base; + while (valuelen-- > 0) + { + int ch = *value++; + + if (ch < rangelo) + ch = rangelo - 1; + else if (ch > rangehi) + ch = rangehi + 1; + num += ((double) (ch - rangelo)) / denom; + denom *= base; + } + + return num; } /* diff -Naur pgsql.virg/src/backend/utils/adt/varlena.c pgsql.dev/src/backend/utils/adt/varlena.c --- pgsql.virg/src/backend/utils/adt/varlena.c Sat Aug 11 04:57:46 2001 +++ pgsql.dev/src/backend/utils/adt/varlena.c Sun Aug 12 02:01:15 2001 @@ -875,3 +875,162 @@ PG_RETURN_TEXT_P(result); } + + +/***************************************************************************** + * Comparison Functions used for bytea + * + * Note: btree indexes need these routines not to leak memory; therefore, + * be careful to free working copies of toasted datums. Most places don't + * need to be so careful. + *****************************************************************************/ + +Datum +byteaeq(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + bool result; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + /* fast path for different-length inputs */ + if (len1 != len2) + result = false; + else + result = (memcmp(VARDATA(arg1), VARDATA(arg2), len1) == 0); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(result); +} + +Datum +byteane(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + bool result; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + /* fast path for different-length inputs */ + if (len1 != len2) + result = true; + else + result = (memcmp(VARDATA(arg1), VARDATA(arg2), len1) != 0); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL(result); +} + +Datum +bytealt(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + int cmp; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2))); +} + +Datum +byteale(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + int cmp; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2))); +} + +Datum +byteagt(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + int cmp; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2))); +} + +Datum +byteage(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + int cmp; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2))); +} + +Datum +byteacmp(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_P(0); + bytea *arg2 = PG_GETARG_BYTEA_P(1); + int len1, + len2; + int cmp; + + len1 = VARSIZE(arg1) - VARHDRSZ; + len2 = VARSIZE(arg2) - VARHDRSZ; + + cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + if ((cmp == 0) && (len1 != len2)) + cmp = (len1 < len2) ? -1 : 1; + + PG_FREE_IF_COPY(arg1, 0); + PG_FREE_IF_COPY(arg2, 1); + + PG_RETURN_INT32(cmp); +} diff -Naur pgsql.virg/src/include/catalog/catversion.h pgsql.dev/src/include/catalog/catversion.h --- pgsql.virg/src/include/catalog/catversion.h Sat Aug 11 04:57:50 2001 +++ pgsql.dev/src/include/catalog/catversion.h Sat Aug 11 21:11:59 2001 @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200108101 +#define CATALOG_VERSION_NO 200108121 #endif diff -Naur pgsql.virg/src/include/catalog/pg_amop.h pgsql.dev/src/include/catalog/pg_amop.h --- pgsql.virg/src/include/catalog/pg_amop.h Sat Aug 11 04:57:51 2001 +++ pgsql.dev/src/include/catalog/pg_amop.h Sat Aug 11 20:49:01 2001 @@ -250,6 +250,16 @@ DATA(insert ( 403 1077 1068 5 )); /* + * nbtree bytea_ops + */ + +DATA(insert ( 403 1970 1976 1 )); +DATA(insert ( 403 1970 1977 2 )); +DATA(insert ( 403 1970 1972 3 )); +DATA(insert ( 403 1970 1979 4 )); +DATA(insert ( 403 1970 1978 5 )); + +/* * nbtree date_ops */ diff -Naur pgsql.virg/src/include/catalog/pg_amproc.h pgsql.dev/src/include/catalog/pg_amproc.h --- pgsql.virg/src/include/catalog/pg_amproc.h Sat Aug 11 04:57:51 2001 +++ pgsql.dev/src/include/catalog/pg_amproc.h Sat Aug 11 21:08:47 2001 @@ -101,7 +101,7 @@ DATA(insert (403 1399 1358 1)); DATA(insert (403 424 1596 1)); DATA(insert (403 425 1672 1)); - +DATA(insert (403 1970 1986 1)); /* hash */ DATA(insert (405 421 449 1)); diff -Naur pgsql.virg/src/include/catalog/pg_opclass.h pgsql.dev/src/include/catalog/pg_opclass.h --- pgsql.virg/src/include/catalog/pg_opclass.h Sat Aug 11 04:57:51 2001 +++ pgsql.dev/src/include/catalog/pg_opclass.h Sat Aug 11 20:28:52 2001 @@ -123,5 +123,7 @@ DESCR(""); DATA(insert OID = 425 ( varbit_ops 1562 )); DESCR(""); +DATA(insert OID = 1970 ( bytea_ops 17 )); +DESCR(""); #endif /* PG_OPCLASS_H */ diff -Naur pgsql.virg/src/include/catalog/pg_operator.h pgsql.dev/src/include/catalog/pg_operator.h --- pgsql.virg/src/include/catalog/pg_operator.h Sat Aug 11 04:57:51 2001 +++ pgsql.dev/src/include/catalog/pg_operator.h Sat Aug 11 20:47:50 2001 @@ -809,6 +809,14 @@ DATA(insert OID = 1920 ( "+" PGUID 0 l t f 0 701 701 0 0 0 0 float8up - - )); DATA(insert OID = 1921 ( "+" PGUID 0 l t f 0 1700 1700 0 0 0 0 numeric_uplus - - )); +/* bytea operators */ +DATA(insert OID = 1972 ( "=" PGUID 0 b t t 17 17 16 1972 1975 1976 1976 byteaeq eqsel eqjoinsel )); +DATA(insert OID = 1975 ( "<>" PGUID 0 b t f 17 17 16 1975 1972 0 0 byteane neqsel neqjoinsel )); +DATA(insert OID = 1976 ( "<" PGUID 0 b t f 17 17 16 1978 1979 0 0 bytealt scalarltsel scalarltjoinsel )); +DATA(insert OID = 1977 ( "<=" PGUID 0 b t f 17 17 16 1979 1978 0 0 byteale scalarltsel scalarltjoinsel )); +DATA(insert OID = 1978 ( ">" PGUID 0 b t f 17 17 16 1976 1977 0 0 byteagt scalargtsel scalargtjoinsel )); +DATA(insert OID = 1979 ( ">=" PGUID 0 b t f 17 17 16 1977 1976 0 0 byteage scalargtsel scalargtjoinsel )); + /* * function prototypes */ diff -Naur pgsql.virg/src/include/catalog/pg_proc.h pgsql.dev/src/include/catalog/pg_proc.h --- pgsql.virg/src/include/catalog/pg_proc.h Sat Aug 11 04:57:51 2001 +++ pgsql.dev/src/include/catalog/pg_proc.h Sat Aug 11 21:00:24 2001 @@ -2699,6 +2699,22 @@ DESCR("Convert bytea value into some ascii-only text string"); DATA(insert OID = 1947 ( decode PGUID 12 f t t t 2 f 17 "25 25" 100 0 0 100 binary_decode - )); DESCR("Convert ascii-encoded text string into bytea value"); + +DATA(insert OID = 1980 ( byteaeq PGUID 12 f t t t 2 f 16 "17 17" 100 0 0 100 byteaeq - )); +DESCR("equal"); +DATA(insert OID = 1981 ( bytealt PGUID 12 f t t t 2 f 16 "17 17" 100 0 0 100 bytealt - )); +DESCR("less-than"); +DATA(insert OID = 1982 ( byteale PGUID 12 f t t t 2 f 16 "17 17" 100 0 0 100 byteale - )); +DESCR("less-than-or-equal"); +DATA(insert OID = 1983 ( byteagt PGUID 12 f t t t 2 f 16 "17 17" 100 0 0 100 byteagt - )); +DESCR("greater-than"); +DATA(insert OID = 1984 ( byteage PGUID 12 f t t t 2 f 16 "17 17" 100 0 0 100 byteage - )); +DESCR("greater-than-or-equal"); +DATA(insert OID = 1985 ( byteane PGUID 12 f t t t 2 f 16 "17 17" 100 0 0 100 byteane - )); +DESCR("not equal"); +DATA(insert OID = 1986 ( byteacmp PGUID 12 f t t t 2 f 23 "17 17" 100 0 0 100 byteacmp - )); +DESCR("less-equal-greater"); + /* * prototypes for functions pg_proc.c diff -Naur pgsql.virg/src/include/utils/builtins.h pgsql.dev/src/include/utils/builtins.h --- pgsql.virg/src/include/utils/builtins.h Sat Aug 11 04:57:55 2001 +++ pgsql.dev/src/include/utils/builtins.h Sat Aug 11 21:04:30 2001 @@ -412,6 +412,13 @@ extern Datum byteaSetBit(PG_FUNCTION_ARGS); extern Datum binary_encode(PG_FUNCTION_ARGS); extern Datum binary_decode(PG_FUNCTION_ARGS); +extern Datum byteaeq(PG_FUNCTION_ARGS); +extern Datum byteane(PG_FUNCTION_ARGS); +extern Datum bytealt(PG_FUNCTION_ARGS); +extern Datum byteale(PG_FUNCTION_ARGS); +extern Datum byteagt(PG_FUNCTION_ARGS); +extern Datum byteage(PG_FUNCTION_ARGS); +extern Datum byteacmp(PG_FUNCTION_ARGS); /* version.c */ extern Datum pgsql_version(PG_FUNCTION_ARGS);