mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Make inet/cidr << and <<= operators indexable. From Alex Pilosov <alex@pilosoft.com>.
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.106 2001/06/05 17:13:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.107 2001/06/17 02:05:19 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -95,6 +95,7 @@ static bool match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
bool indexkey_on_left);
|
||||
static List *prefix_quals(Var *leftop, Oid expr_op,
|
||||
char *prefix, Pattern_Prefix_Status pstatus);
|
||||
static List *network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop);
|
||||
static Oid find_operator(const char *opname, Oid datatype);
|
||||
static Datum string_to_datum(const char *str, Oid datatype);
|
||||
static Const *string_to_const(const char *str, Oid datatype);
|
||||
@ -1761,6 +1762,13 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
pfree(patt);
|
||||
}
|
||||
break;
|
||||
|
||||
case OID_INET_SUB_OP:
|
||||
case OID_INET_SUBEQ_OP:
|
||||
case OID_CIDR_SUB_OP:
|
||||
case OID_CIDR_SUBEQ_OP:
|
||||
isIndexable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* done if the expression doesn't look indexable */
|
||||
@ -1810,6 +1818,22 @@ match_special_index_operator(Expr *clause, Oid opclass, Oid relam,
|
||||
!op_class(find_operator("<", NAMEOID), opclass, relam))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
case OID_INET_SUB_OP:
|
||||
case OID_INET_SUBEQ_OP:
|
||||
/* for SUB we actually need ">" not ">=", but this should do */
|
||||
if (!op_class(find_operator(">=", INETOID), opclass, relam) ||
|
||||
!op_class(find_operator("<=", INETOID), opclass, relam))
|
||||
isIndexable = false;
|
||||
break;
|
||||
|
||||
case OID_CIDR_SUB_OP:
|
||||
case OID_CIDR_SUBEQ_OP:
|
||||
/* for SUB we actually need ">" not ">=", but this should do */
|
||||
if (!op_class(find_operator(">=", CIDROID), opclass, relam) ||
|
||||
!op_class(find_operator("<=", CIDROID), opclass, relam))
|
||||
isIndexable = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return isIndexable;
|
||||
@ -1924,6 +1948,16 @@ expand_indexqual_conditions(List *indexquals)
|
||||
pfree(patt);
|
||||
break;
|
||||
|
||||
case OID_INET_SUB_OP:
|
||||
case OID_INET_SUBEQ_OP:
|
||||
case OID_CIDR_SUB_OP:
|
||||
case OID_CIDR_SUBEQ_OP:
|
||||
constvalue = ((Const *) rightop)->constvalue;
|
||||
resultquals = nconc(resultquals,
|
||||
network_prefix_quals(leftop, expr_op,
|
||||
constvalue));
|
||||
break;
|
||||
|
||||
default:
|
||||
resultquals = lappend(resultquals, clause);
|
||||
break;
|
||||
@ -2037,6 +2071,86 @@ prefix_quals(Var *leftop, Oid expr_op,
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a leftop and a rightop, and a inet-class sup/sub operator,
|
||||
* generate suitable indexqual condition(s). expr_op is the original
|
||||
* operator.
|
||||
*/
|
||||
static List *
|
||||
network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
|
||||
{
|
||||
bool is_eq;
|
||||
char *opr1name;
|
||||
Datum opr1right;
|
||||
Datum opr2right;
|
||||
Oid opr1oid;
|
||||
Oid opr2oid;
|
||||
List *result;
|
||||
Oid datatype;
|
||||
Oper *op;
|
||||
Expr *expr;
|
||||
|
||||
switch (expr_op)
|
||||
{
|
||||
case OID_INET_SUB_OP:
|
||||
datatype = INETOID;
|
||||
is_eq = false;
|
||||
break;
|
||||
case OID_INET_SUBEQ_OP:
|
||||
datatype = INETOID;
|
||||
is_eq = true;
|
||||
break;
|
||||
case OID_CIDR_SUB_OP:
|
||||
datatype = CIDROID;
|
||||
is_eq = false;
|
||||
break;
|
||||
case OID_CIDR_SUBEQ_OP:
|
||||
datatype = CIDROID;
|
||||
is_eq = true;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "network_prefix_quals: unexpected operator %u",
|
||||
expr_op);
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* create clause "key >= network_scan_first( rightop )", or ">"
|
||||
* if the operator disallows equality.
|
||||
*/
|
||||
|
||||
opr1name = is_eq ? ">=" : ">";
|
||||
opr1oid = find_operator(opr1name, datatype);
|
||||
if (opr1oid == InvalidOid)
|
||||
elog(ERROR, "network_prefix_quals: no %s operator for type %u",
|
||||
opr1name, datatype);
|
||||
|
||||
opr1right = network_scan_first( rightop );
|
||||
|
||||
op = makeOper(opr1oid, InvalidOid, BOOLOID);
|
||||
expr = make_opclause(op, leftop,
|
||||
(Var *) makeConst(datatype, -1, opr1right,
|
||||
false, false, false, false));
|
||||
result = makeList1(expr);
|
||||
|
||||
/* create clause "key <= network_scan_last( rightop )" */
|
||||
|
||||
opr2oid = find_operator("<=", datatype);
|
||||
if (opr2oid == InvalidOid)
|
||||
elog(ERROR, "network_prefix_quals: no <= operator for type %u",
|
||||
datatype);
|
||||
|
||||
opr2right = network_scan_last( rightop );
|
||||
|
||||
op = makeOper(opr2oid, InvalidOid, BOOLOID);
|
||||
expr = make_opclause(op, leftop,
|
||||
(Var *) makeConst(datatype, -1, opr2right,
|
||||
false, false, false, false));
|
||||
result = lappend(result, expr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handy subroutines for match_special_index_operator() and friends.
|
||||
*/
|
||||
|
@ -3,7 +3,7 @@
|
||||
* is for IP V4 CIDR notation, but prepared for V6: just
|
||||
* add the necessary bits where the comments indicate.
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.31 2001/06/13 21:08:59 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.32 2001/06/17 02:05:20 tgl Exp $
|
||||
*
|
||||
* Jon Postel RIP 16 Oct 1998
|
||||
*/
|
||||
@ -707,3 +707,31 @@ v4addressOK(unsigned long a1, int bits)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These functions are used by planner to generate indexscan limits
|
||||
* for clauses a << b and a <<= b
|
||||
*/
|
||||
|
||||
/* return the minimal value for an IP on a given network */
|
||||
Datum
|
||||
network_scan_first(Datum in)
|
||||
{
|
||||
return DirectFunctionCall1(network_network, in);
|
||||
}
|
||||
|
||||
/*
|
||||
* return "last" IP on a given network. It's the broadcast address,
|
||||
* however, masklen has to be set to 32, since
|
||||
* 192.168.0.255/24 is considered less than 192.168.0.255/32
|
||||
*
|
||||
* NB: this is not IPv6 ready ...
|
||||
*/
|
||||
Datum
|
||||
network_scan_last(Datum in)
|
||||
{
|
||||
return DirectFunctionCall2(inet_set_masklen,
|
||||
DirectFunctionCall1(network_broadcast, in),
|
||||
Int32GetDatum(32));
|
||||
}
|
||||
|
Reference in New Issue
Block a user