mirror of
https://github.com/postgres/postgres.git
synced 2025-10-29 22:49:41 +03:00
Add text-vs-name cross-type operators, and unify name_ops with text_ops.
Now that name comparison has effectively the same behavior as text comparison, we might as well merge the name_ops opfamily into text_ops, allowing cross-type comparisons to be processed without forcing a datatype coercion first. We need do little more than add cross-type operators to make the opfamily complete, and fix one or two places in the planner that assumed text_ops was a single-datatype opfamily. I chose to unify hash name_ops into hash text_ops as well, since the types have compatible hashing semantics. This allows marking the new cross-type equality operators as oprcanhash. (Note: this doesn't remove the name_ops opclasses, so there's no breakage of index definitions. Those opclasses are just reparented into the text_ops opfamily.) Discussion: https://postgr.es/m/15938.1544377821@sss.pgh.pa.us
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
@@ -3518,6 +3519,10 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation,
|
||||
case OID_TEXT_ICLIKE_OP:
|
||||
case OID_TEXT_REGEXEQ_OP:
|
||||
case OID_TEXT_ICREGEXEQ_OP:
|
||||
case OID_NAME_LIKE_OP:
|
||||
case OID_NAME_ICLIKE_OP:
|
||||
case OID_NAME_REGEXEQ_OP:
|
||||
case OID_NAME_ICREGEXEQ_OP:
|
||||
isIndexable =
|
||||
(opfamily == TEXT_PATTERN_BTREE_FAM_OID) ||
|
||||
(opfamily == TEXT_SPGIST_FAM_OID) ||
|
||||
@@ -3537,14 +3542,6 @@ match_special_index_operator(Expr *clause, Oid opfamily, Oid idxcollation,
|
||||
lc_collate_is_c(idxcollation)));
|
||||
break;
|
||||
|
||||
case OID_NAME_LIKE_OP:
|
||||
case OID_NAME_ICLIKE_OP:
|
||||
case OID_NAME_REGEXEQ_OP:
|
||||
case OID_NAME_ICREGEXEQ_OP:
|
||||
/* name uses locale-insensitive sorting */
|
||||
isIndexable = (opfamily == NAME_BTREE_FAM_OID);
|
||||
break;
|
||||
|
||||
case OID_BYTEA_LIKE_OP:
|
||||
isIndexable = (opfamily == BYTEA_BTREE_FAM_OID);
|
||||
break;
|
||||
@@ -4097,7 +4094,8 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
Const *prefix_const, Pattern_Prefix_Status pstatus)
|
||||
{
|
||||
List *result;
|
||||
Oid datatype;
|
||||
Oid ldatatype = exprType(leftop);
|
||||
Oid rdatatype;
|
||||
Oid oproid;
|
||||
Expr *expr;
|
||||
FmgrInfo ltproc;
|
||||
@@ -4110,20 +4108,16 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
case TEXT_BTREE_FAM_OID:
|
||||
case TEXT_PATTERN_BTREE_FAM_OID:
|
||||
case TEXT_SPGIST_FAM_OID:
|
||||
datatype = TEXTOID;
|
||||
rdatatype = TEXTOID;
|
||||
break;
|
||||
|
||||
case BPCHAR_BTREE_FAM_OID:
|
||||
case BPCHAR_PATTERN_BTREE_FAM_OID:
|
||||
datatype = BPCHAROID;
|
||||
break;
|
||||
|
||||
case NAME_BTREE_FAM_OID:
|
||||
datatype = NAMEOID;
|
||||
rdatatype = BPCHAROID;
|
||||
break;
|
||||
|
||||
case BYTEA_BTREE_FAM_OID:
|
||||
datatype = BYTEAOID;
|
||||
rdatatype = BYTEAOID;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -4136,7 +4130,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
* If necessary, coerce the prefix constant to the right type. The given
|
||||
* prefix constant is either text or bytea type.
|
||||
*/
|
||||
if (prefix_const->consttype != datatype)
|
||||
if (prefix_const->consttype != rdatatype)
|
||||
{
|
||||
char *prefix;
|
||||
|
||||
@@ -4154,7 +4148,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
prefix_const->consttype);
|
||||
return NIL;
|
||||
}
|
||||
prefix_const = string_to_const(prefix, datatype);
|
||||
prefix_const = string_to_const(prefix, rdatatype);
|
||||
pfree(prefix);
|
||||
}
|
||||
|
||||
@@ -4163,7 +4157,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
*/
|
||||
if (pstatus == Pattern_Prefix_Exact)
|
||||
{
|
||||
oproid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
oproid = get_opfamily_member(opfamily, ldatatype, rdatatype,
|
||||
BTEqualStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no = operator for opfamily %u", opfamily);
|
||||
@@ -4179,7 +4173,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
*
|
||||
* We can always say "x >= prefix".
|
||||
*/
|
||||
oproid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
oproid = get_opfamily_member(opfamily, ldatatype, rdatatype,
|
||||
BTGreaterEqualStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no >= operator for opfamily %u", opfamily);
|
||||
@@ -4196,7 +4190,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
|
||||
* using a C-locale index collation.
|
||||
*-------
|
||||
*/
|
||||
oproid = get_opfamily_member(opfamily, datatype, datatype,
|
||||
oproid = get_opfamily_member(opfamily, ldatatype, rdatatype,
|
||||
BTLessStrategyNumber);
|
||||
if (oproid == InvalidOid)
|
||||
elog(ERROR, "no < operator for opfamily %u", opfamily);
|
||||
|
||||
@@ -1292,14 +1292,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate)
|
||||
switch (vartype)
|
||||
{
|
||||
case TEXTOID:
|
||||
case NAMEOID:
|
||||
opfamily = TEXT_BTREE_FAM_OID;
|
||||
break;
|
||||
case BPCHAROID:
|
||||
opfamily = BPCHAR_BTREE_FAM_OID;
|
||||
break;
|
||||
case NAMEOID:
|
||||
opfamily = NAME_BTREE_FAM_OID;
|
||||
break;
|
||||
case BYTEAOID:
|
||||
opfamily = BYTEA_BTREE_FAM_OID;
|
||||
break;
|
||||
|
||||
@@ -2693,6 +2693,167 @@ text_smaller(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Cross-type comparison functions for types text and name.
|
||||
*/
|
||||
|
||||
Datum
|
||||
nameeqtext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name arg1 = PG_GETARG_NAME(0);
|
||||
text *arg2 = PG_GETARG_TEXT_PP(1);
|
||||
size_t len1 = strlen(NameStr(*arg1));
|
||||
size_t len2 = VARSIZE_ANY_EXHDR(arg2);
|
||||
bool result;
|
||||
|
||||
result = (len1 == len2 &&
|
||||
memcmp(NameStr(*arg1), VARDATA_ANY(arg2), len1) == 0);
|
||||
|
||||
PG_FREE_IF_COPY(arg2, 1);
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
texteqname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg1 = PG_GETARG_TEXT_PP(0);
|
||||
Name arg2 = PG_GETARG_NAME(1);
|
||||
size_t len1 = VARSIZE_ANY_EXHDR(arg1);
|
||||
size_t len2 = strlen(NameStr(*arg2));
|
||||
bool result;
|
||||
|
||||
result = (len1 == len2 &&
|
||||
memcmp(VARDATA_ANY(arg1), NameStr(*arg2), len1) == 0);
|
||||
|
||||
PG_FREE_IF_COPY(arg1, 0);
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
namenetext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name arg1 = PG_GETARG_NAME(0);
|
||||
text *arg2 = PG_GETARG_TEXT_PP(1);
|
||||
size_t len1 = strlen(NameStr(*arg1));
|
||||
size_t len2 = VARSIZE_ANY_EXHDR(arg2);
|
||||
bool result;
|
||||
|
||||
result = !(len1 == len2 &&
|
||||
memcmp(NameStr(*arg1), VARDATA_ANY(arg2), len1) == 0);
|
||||
|
||||
PG_FREE_IF_COPY(arg2, 1);
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
textnename(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg1 = PG_GETARG_TEXT_PP(0);
|
||||
Name arg2 = PG_GETARG_NAME(1);
|
||||
size_t len1 = VARSIZE_ANY_EXHDR(arg1);
|
||||
size_t len2 = strlen(NameStr(*arg2));
|
||||
bool result;
|
||||
|
||||
result = !(len1 == len2 &&
|
||||
memcmp(VARDATA_ANY(arg1), NameStr(*arg2), len1) == 0);
|
||||
|
||||
PG_FREE_IF_COPY(arg1, 0);
|
||||
|
||||
PG_RETURN_BOOL(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
btnametextcmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name arg1 = PG_GETARG_NAME(0);
|
||||
text *arg2 = PG_GETARG_TEXT_PP(1);
|
||||
int32 result;
|
||||
|
||||
result = varstr_cmp(NameStr(*arg1), strlen(NameStr(*arg1)),
|
||||
VARDATA_ANY(arg2), VARSIZE_ANY_EXHDR(arg2),
|
||||
PG_GET_COLLATION());
|
||||
|
||||
PG_FREE_IF_COPY(arg2, 1);
|
||||
|
||||
PG_RETURN_INT32(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
bttextnamecmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg1 = PG_GETARG_TEXT_PP(0);
|
||||
Name arg2 = PG_GETARG_NAME(1);
|
||||
int32 result;
|
||||
|
||||
result = varstr_cmp(VARDATA_ANY(arg1), VARSIZE_ANY_EXHDR(arg1),
|
||||
NameStr(*arg2), strlen(NameStr(*arg2)),
|
||||
PG_GET_COLLATION());
|
||||
|
||||
PG_FREE_IF_COPY(arg1, 0);
|
||||
|
||||
PG_RETURN_INT32(result);
|
||||
}
|
||||
|
||||
#define CmpCall(cmpfunc) \
|
||||
DatumGetInt32(DirectFunctionCall2Coll(cmpfunc, \
|
||||
PG_GET_COLLATION(), \
|
||||
PG_GETARG_DATUM(0), \
|
||||
PG_GETARG_DATUM(1)))
|
||||
|
||||
Datum
|
||||
namelttext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(btnametextcmp) < 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
nameletext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(btnametextcmp) <= 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
namegttext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(btnametextcmp) > 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
namegetext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(btnametextcmp) >= 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
textltname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(bttextnamecmp) < 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
textlename(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(bttextnamecmp) <= 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
textgtname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(bttextnamecmp) > 0);
|
||||
}
|
||||
|
||||
Datum
|
||||
textgename(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BOOL(CmpCall(bttextnamecmp) >= 0);
|
||||
}
|
||||
|
||||
#undef CmpCall
|
||||
|
||||
|
||||
/*
|
||||
* The following operators support character-by-character comparison
|
||||
* of text datums, to allow building indexes suitable for LIKE clauses.
|
||||
|
||||
Reference in New Issue
Block a user