forked from openGauss-Ecosystem/openGauss-server
支持前缀索引
Offering: GaussDB Kernel More detail: 1、支持前缀索引创建 2、支持前缀索引匹配
This commit is contained in:
parent
5e987cdd3a
commit
056317bad3
|
@ -11,7 +11,7 @@
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<synopsis>
|
<synopsis>
|
||||||
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [schema_name.] index_name ] ON table_name [ USING method ]
|
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [schema_name.] index_name ] ON table_name [ USING method ]
|
||||||
({ { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] }[, ...] )
|
({ { column_name [ ( length ) ] | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] }[, ...] )
|
||||||
[ INCLUDE ( { column_name | ( expression ) }[, ...] ) ]
|
[ INCLUDE ( { column_name | ( expression ) }[, ...] ) ]
|
||||||
[ WITH ( {storage_parameter = value} [, ... ] ) ]
|
[ WITH ( {storage_parameter = value} [, ... ] ) ]
|
||||||
[ TABLESPACE tablespace_name ]
|
[ TABLESPACE tablespace_name ]
|
||||||
|
@ -24,6 +24,7 @@ CREATE [ UNIQUE ] INDEX [ [schema_name.] index_name ] ON table_name [ USING meth
|
||||||
[ TABLESPACE tablespace_name ];
|
[ TABLESPACE tablespace_name ];
|
||||||
|
|
||||||
NOTICE: 'SUBPARTITION index_subpartition_name' is only avaliable in CENTRALIZED mode!
|
NOTICE: 'SUBPARTITION index_subpartition_name' is only avaliable in CENTRALIZED mode!
|
||||||
|
NOTICE: 'column_name ( length )' is only avaliable in B-format database!
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|
|
@ -6784,6 +6784,16 @@ static SubPartitionPruningResult *_copySubPartitionPruningResult(const SubPartit
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PrefixKey* _copyPrefixKey(const PrefixKey* from)
|
||||||
|
{
|
||||||
|
PrefixKey* newnode = makeNode(PrefixKey);
|
||||||
|
|
||||||
|
COPY_NODE_FIELD(arg);
|
||||||
|
COPY_SCALAR_FIELD(length);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copyObject
|
* copyObject
|
||||||
*
|
*
|
||||||
|
@ -7257,6 +7267,9 @@ void* copyObject(const void* from)
|
||||||
case T_MergeAction:
|
case T_MergeAction:
|
||||||
retval = _copyMergeAction((MergeAction*)from);
|
retval = _copyMergeAction((MergeAction*)from);
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
retval = _copyPrefixKey((PrefixKey*)from);
|
||||||
|
break;
|
||||||
/*
|
/*
|
||||||
* RELATION NODES
|
* RELATION NODES
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3248,6 +3248,13 @@ static bool _equalShutDown(const ShutdownStmt* a, const ShutdownStmt* b)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _equalPrefixKey(const PrefixKey* a, const PrefixKey* b)
|
||||||
|
{
|
||||||
|
COMPARE_NODE_FIELD(arg);
|
||||||
|
COMPARE_SCALAR_FIELD(length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* equal
|
* equal
|
||||||
* returns whether two nodes are equal
|
* returns whether two nodes are equal
|
||||||
|
@ -4121,6 +4128,9 @@ bool equal(const void* a, const void* b)
|
||||||
case T_DropSubscriptionStmt:
|
case T_DropSubscriptionStmt:
|
||||||
retval = _equalDropSubscriptionStmt((DropSubscriptionStmt *)a, (DropSubscriptionStmt *)b);
|
retval = _equalDropSubscriptionStmt((DropSubscriptionStmt *)a, (DropSubscriptionStmt *)b);
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
retval = _equalPrefixKey((PrefixKey *)a, (PrefixKey *)b);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
|
|
@ -228,6 +228,9 @@ Oid exprType(const Node* expr)
|
||||||
type = INT8OID;
|
type = INT8OID;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
type = exprType((Node*)((PrefixKey*)expr)->arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
|
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
|
||||||
|
@ -465,6 +468,8 @@ int32 exprTypmod(const Node* expr)
|
||||||
return ((const SetToDefault*)expr)->typeMod;
|
return ((const SetToDefault*)expr)->typeMod;
|
||||||
case T_PlaceHolderVar:
|
case T_PlaceHolderVar:
|
||||||
return exprTypmod((Node*)((const PlaceHolderVar*)expr)->phexpr);
|
return exprTypmod((Node*)((const PlaceHolderVar*)expr)->phexpr);
|
||||||
|
case T_PrefixKey:
|
||||||
|
return exprTypmod((Node*)((const PrefixKey*)expr)->arg);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -846,6 +851,9 @@ Oid exprCollation(const Node* expr)
|
||||||
case T_PlaceHolderVar:
|
case T_PlaceHolderVar:
|
||||||
coll = exprCollation((Node*)((const PlaceHolderVar*)expr)->phexpr);
|
coll = exprCollation((Node*)((const PlaceHolderVar*)expr)->phexpr);
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
coll = exprCollation((Node*)((const PrefixKey*)expr)->arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ereport(
|
ereport(
|
||||||
ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
|
ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
|
||||||
|
@ -1046,6 +1054,8 @@ void exprSetCollation(Node* expr, Oid collation)
|
||||||
case T_CurrentOfExpr:
|
case T_CurrentOfExpr:
|
||||||
Assert(!OidIsValid(collation)); /* result is always boolean */
|
Assert(!OidIsValid(collation)); /* result is always boolean */
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
return exprSetCollation((Node*)((const PrefixKey*)expr)->arg, collation);
|
||||||
default:
|
default:
|
||||||
ereport(
|
ereport(
|
||||||
ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
|
ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unrecognized node type: %d", (int)nodeTag(expr))));
|
||||||
|
@ -1406,6 +1416,9 @@ int exprLocation(const Node* expr)
|
||||||
case T_Rownum:
|
case T_Rownum:
|
||||||
loc = ((const Rownum*)expr)->location;
|
loc = ((const Rownum*)expr)->location;
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
loc = exprLocation((Node*)((const PrefixKey*)expr)->arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* for any other node type it's just unknown... */
|
/* for any other node type it's just unknown... */
|
||||||
loc = -1;
|
loc = -1;
|
||||||
|
@ -1876,6 +1889,8 @@ bool expression_tree_walker(Node* node, bool (*walker)(), void* context)
|
||||||
} break;
|
} break;
|
||||||
case T_PlaceHolderInfo:
|
case T_PlaceHolderInfo:
|
||||||
return p2walker(((PlaceHolderInfo*)node)->ph_var, context);
|
return p2walker(((PlaceHolderInfo*)node)->ph_var, context);
|
||||||
|
case T_PrefixKey:
|
||||||
|
return p2walker(((PrefixKey*)node)->arg, context);
|
||||||
default:
|
default:
|
||||||
ereport(
|
ereport(
|
||||||
ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unrecognized node type: %d", (int)nodeTag(node))));
|
ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("unrecognized node type: %d", (int)nodeTag(node))));
|
||||||
|
@ -2609,6 +2624,14 @@ Node* expression_tree_mutator(Node* node, Node* (*mutator)(Node*, void*), void*
|
||||||
MUTATE(newnode->tvver, tcc->tvver, Node*);
|
MUTATE(newnode->tvver, tcc->tvver, Node*);
|
||||||
return (Node*)newnode;
|
return (Node*)newnode;
|
||||||
} break;
|
} break;
|
||||||
|
case T_PrefixKey: {
|
||||||
|
PrefixKey* pkey = (PrefixKey*)node;
|
||||||
|
PrefixKey* newnode = NULL;
|
||||||
|
|
||||||
|
FLATCOPY(newnode, pkey, PrefixKey, isCopy);
|
||||||
|
MUTATE(newnode->arg, pkey->arg, Expr*);
|
||||||
|
return (Node*)newnode;
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(node))));
|
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), errmsg("unrecognized node type: %d", (int)nodeTag(node))));
|
||||||
|
|
|
@ -190,6 +190,7 @@ static const TagStr g_tagStrArr[] = {{T_Invalid, "Invalid"},
|
||||||
{T_JoinExpr, "JoinExpr"},
|
{T_JoinExpr, "JoinExpr"},
|
||||||
{T_FromExpr, "FromExpr"},
|
{T_FromExpr, "FromExpr"},
|
||||||
{T_IntoClause, "IntoClause"},
|
{T_IntoClause, "IntoClause"},
|
||||||
|
{T_PrefixKey, "PrefixKey"},
|
||||||
{T_DistributeBy, "DistributeBy"},
|
{T_DistributeBy, "DistributeBy"},
|
||||||
{T_PGXCSubCluster, "PGXCSubCluster"},
|
{T_PGXCSubCluster, "PGXCSubCluster"},
|
||||||
{T_DistState, "DistState"},
|
{T_DistState, "DistState"},
|
||||||
|
|
|
@ -5660,6 +5660,13 @@ static void _outTrainModel(StringInfo str, TrainModel* node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _outPrefixKey(StringInfo str, PrefixKey* node)
|
||||||
|
{
|
||||||
|
WRITE_NODE_TYPE("PREFIXKEY");
|
||||||
|
WRITE_NODE_FIELD(arg);
|
||||||
|
WRITE_INT_FIELD(length);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _outNode -
|
* _outNode -
|
||||||
* converts a Node into ascii string and append it to 'str'
|
* converts a Node into ascii string and append it to 'str'
|
||||||
|
@ -6343,6 +6350,9 @@ static void _outNode(StringInfo str, const void* obj)
|
||||||
case T_DfsPrivateItem:
|
case T_DfsPrivateItem:
|
||||||
_outDfsPrivateItem(str, (DfsPrivateItem*)obj);
|
_outDfsPrivateItem(str, (DfsPrivateItem*)obj);
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
_outPrefixKey(str, (PrefixKey*)obj);
|
||||||
|
break;
|
||||||
/*
|
/*
|
||||||
* Vector Nodes
|
* Vector Nodes
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5754,6 +5754,16 @@ static TdigestData* _readTdigestData()
|
||||||
READ_DONE();
|
READ_DONE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PrefixKey* _readPrefixKey()
|
||||||
|
{
|
||||||
|
READ_LOCALS(PrefixKey);
|
||||||
|
|
||||||
|
READ_NODE_FIELD(arg);
|
||||||
|
READ_INT_FIELD(length);
|
||||||
|
|
||||||
|
READ_DONE();
|
||||||
|
}
|
||||||
|
|
||||||
static UserSetElem* _readUserSetElem()
|
static UserSetElem* _readUserSetElem()
|
||||||
{
|
{
|
||||||
READ_LOCALS(UserSetElem);
|
READ_LOCALS(UserSetElem);
|
||||||
|
@ -6233,6 +6243,8 @@ Node* parseNodeString(void)
|
||||||
return_value = _readPLDebug_frame();
|
return_value = _readPLDebug_frame();
|
||||||
} else if (MATCH("TdigestData", 11)) {
|
} else if (MATCH("TdigestData", 11)) {
|
||||||
return_value = _readTdigestData();
|
return_value = _readTdigestData();
|
||||||
|
} else if (MATCH("PREFIXKEY", 9)) {
|
||||||
|
return_value = _readPrefixKey();
|
||||||
} else if (MATCH("USERSETELEM", 11)) {
|
} else if (MATCH("USERSETELEM", 11)) {
|
||||||
return_value = _readUserSetElem();
|
return_value = _readUserSetElem();
|
||||||
} else if (MATCH("USERVAR", 7)) {
|
} else if (MATCH("USERVAR", 7)) {
|
||||||
|
|
|
@ -630,7 +630,7 @@ static int errstate;
|
||||||
%type <node> var_value zone_value
|
%type <node> var_value zone_value
|
||||||
|
|
||||||
%type <keyword> unreserved_keyword type_func_name_keyword
|
%type <keyword> unreserved_keyword type_func_name_keyword
|
||||||
%type <keyword> col_name_keyword reserved_keyword
|
%type <keyword> col_name_keyword reserved_keyword col_name_keyword_nonambiguous
|
||||||
|
|
||||||
%type <node> TableConstraint TableLikeClause ForeignTableLikeClause
|
%type <node> TableConstraint TableLikeClause ForeignTableLikeClause
|
||||||
%type <ival> excluding_option_list TableLikeOptionList TableLikeIncludingOption TableLikeExcludingOption
|
%type <ival> excluding_option_list TableLikeOptionList TableLikeIncludingOption TableLikeExcludingOption
|
||||||
|
@ -656,7 +656,7 @@ static int errstate;
|
||||||
%type <ival> document_or_content
|
%type <ival> document_or_content
|
||||||
%type <boolean> xml_whitespace_option
|
%type <boolean> xml_whitespace_option
|
||||||
|
|
||||||
%type <node> func_application func_with_separator func_expr_common_subexpr
|
%type <node> func_application func_with_separator func_expr_common_subexpr index_functional_expr_key func_application_special
|
||||||
%type <node> func_expr func_expr_windowless
|
%type <node> func_expr func_expr_windowless
|
||||||
%type <node> common_table_expr
|
%type <node> common_table_expr
|
||||||
%type <with> with_clause opt_with_clause
|
%type <with> with_clause opt_with_clause
|
||||||
|
@ -12187,7 +12187,7 @@ index_elem: ColId opt_collate opt_class opt_asc_desc opt_nulls_order
|
||||||
$$->ordering = (SortByDir)$4;
|
$$->ordering = (SortByDir)$4;
|
||||||
$$->nulls_ordering = (SortByNulls)$5;
|
$$->nulls_ordering = (SortByNulls)$5;
|
||||||
}
|
}
|
||||||
| func_expr_windowless opt_collate opt_class opt_asc_desc opt_nulls_order
|
| index_functional_expr_key opt_collate opt_class opt_asc_desc opt_nulls_order
|
||||||
{
|
{
|
||||||
$$ = makeNode(IndexElem);
|
$$ = makeNode(IndexElem);
|
||||||
$$->name = NULL;
|
$$->name = NULL;
|
||||||
|
@ -12211,6 +12211,54 @@ index_elem: ColId opt_collate opt_class opt_asc_desc opt_nulls_order
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
index_functional_expr_key: col_name_keyword_nonambiguous '(' Iconst ')'
|
||||||
|
{
|
||||||
|
if (u_sess->attr.attr_sql.sql_compatibility != B_FORMAT) {
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("prefix key is supported only in B-format database")));
|
||||||
|
}
|
||||||
|
PrefixKey* pk = makeNode(PrefixKey);
|
||||||
|
pk->arg = (Expr*)makeColumnRef(pstrdup($1), NIL, @1, yyscanner);
|
||||||
|
pk->length = $3;
|
||||||
|
$$ = (Node*)pk;
|
||||||
|
}
|
||||||
|
| func_name '(' func_arg_list opt_sort_clause ')'
|
||||||
|
{
|
||||||
|
List* elist = (List*)$3;
|
||||||
|
List* nlist = (List*)$1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This syntax branch can be parsed either as a column prefix or as a function.
|
||||||
|
* In B-compatible mode, it is preferentially treated as a column prefix.
|
||||||
|
*/
|
||||||
|
if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT &&
|
||||||
|
$4 == NIL && list_length(elist) == 1 && list_length(nlist) == 1) {
|
||||||
|
Node* arg = (Node*)linitial(elist);
|
||||||
|
if (IsA(arg, A_Const) && ((A_Const*)arg)->val.type == T_Integer) {
|
||||||
|
PrefixKey* pk = makeNode(PrefixKey);
|
||||||
|
pk->arg = (Expr*)makeColumnRef(strVal(linitial(nlist)), NIL, @1, yyscanner);
|
||||||
|
pk->length = intVal(&((A_Const*)arg)->val);
|
||||||
|
$$ = (Node*)pk;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncCall *n = makeNode(FuncCall);
|
||||||
|
n->funcname = $1;
|
||||||
|
n->args = $3;
|
||||||
|
n->agg_order = $4;
|
||||||
|
n->agg_star = FALSE;
|
||||||
|
n->agg_distinct = FALSE;
|
||||||
|
n->func_variadic = FALSE;
|
||||||
|
n->over = NULL;
|
||||||
|
n->location = @1;
|
||||||
|
n->call_func = false;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
|
| func_application_special { $$ = $1; }
|
||||||
|
| func_expr_common_subexpr { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
opt_include: INCLUDE '(' index_including_params ')' { $$ = $3; }
|
opt_include: INCLUDE '(' index_including_params ')' { $$ = $3; }
|
||||||
| /* EMPTY */ { $$ = NIL; }
|
| /* EMPTY */ { $$ = NIL; }
|
||||||
;
|
;
|
||||||
|
@ -22481,12 +22529,12 @@ func_expr: func_application within_group_clause over_clause
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
func_application: func_name '(' ')'
|
func_application: func_name '(' func_arg_list opt_sort_clause ')'
|
||||||
{
|
{
|
||||||
FuncCall *n = makeNode(FuncCall);
|
FuncCall *n = makeNode(FuncCall);
|
||||||
n->funcname = $1;
|
n->funcname = $1;
|
||||||
n->args = NIL;
|
n->args = $3;
|
||||||
n->agg_order = NIL;
|
n->agg_order = $4;
|
||||||
n->agg_star = FALSE;
|
n->agg_star = FALSE;
|
||||||
n->agg_distinct = FALSE;
|
n->agg_distinct = FALSE;
|
||||||
n->func_variadic = FALSE;
|
n->func_variadic = FALSE;
|
||||||
|
@ -22495,12 +22543,15 @@ func_application: func_name '(' ')'
|
||||||
n->call_func = false;
|
n->call_func = false;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| func_name '(' func_arg_list opt_sort_clause ')'
|
| func_application_special { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
func_application_special: func_name '(' ')'
|
||||||
{
|
{
|
||||||
FuncCall *n = makeNode(FuncCall);
|
FuncCall *n = makeNode(FuncCall);
|
||||||
n->funcname = $1;
|
n->funcname = $1;
|
||||||
n->args = $3;
|
n->args = NIL;
|
||||||
n->agg_order = $4;
|
n->agg_order = NIL;
|
||||||
n->agg_star = FALSE;
|
n->agg_star = FALSE;
|
||||||
n->agg_distinct = FALSE;
|
n->agg_distinct = FALSE;
|
||||||
n->func_variadic = FALSE;
|
n->func_variadic = FALSE;
|
||||||
|
@ -24899,6 +24950,9 @@ unreserved_keyword:
|
||||||
* The type names appearing here are not usable as function names
|
* The type names appearing here are not usable as function names
|
||||||
* because they can be followed by '(' in typename productions, which
|
* because they can be followed by '(' in typename productions, which
|
||||||
* looks too much like a function call for an LR(1) parser.
|
* looks too much like a function call for an LR(1) parser.
|
||||||
|
*
|
||||||
|
* If the new col_name_keyword is not used in func_expr_common_subexpr,
|
||||||
|
* add it to col_name_keyword_nonambiguous too!
|
||||||
*/
|
*/
|
||||||
col_name_keyword:
|
col_name_keyword:
|
||||||
BETWEEN
|
BETWEEN
|
||||||
|
@ -24966,6 +25020,56 @@ col_name_keyword:
|
||||||
| XMLSERIALIZE
|
| XMLSERIALIZE
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* Column identifier --- keywords that can be column, table, etc names.
|
||||||
|
*
|
||||||
|
* These keywords will not be recognized as function names. These keywords
|
||||||
|
* are used to distinguish index prefix keys from function keys.
|
||||||
|
*/
|
||||||
|
col_name_keyword_nonambiguous:
|
||||||
|
BETWEEN
|
||||||
|
| BIGINT
|
||||||
|
| BINARY_DOUBLE
|
||||||
|
| BINARY_INTEGER
|
||||||
|
| BIT
|
||||||
|
| BOOLEAN_P
|
||||||
|
| BUCKETCNT
|
||||||
|
| BYTEAWITHOUTORDER
|
||||||
|
| BYTEAWITHOUTORDERWITHEQUAL
|
||||||
|
| CHAR_P
|
||||||
|
| CHARACTER
|
||||||
|
| DATE_P
|
||||||
|
| DEC
|
||||||
|
| DECIMAL_P
|
||||||
|
| DECODE
|
||||||
|
| EXISTS
|
||||||
|
| FLOAT_P
|
||||||
|
| GROUPING_P
|
||||||
|
| INOUT
|
||||||
|
| INT_P
|
||||||
|
| INTEGER
|
||||||
|
| INTERVAL
|
||||||
|
| NATIONAL
|
||||||
|
| NCHAR
|
||||||
|
| NONE
|
||||||
|
| NUMBER_P
|
||||||
|
| NUMERIC
|
||||||
|
| NVARCHAR2
|
||||||
|
| OUT_P
|
||||||
|
| PRECISION
|
||||||
|
| REAL
|
||||||
|
| ROW
|
||||||
|
| SETOF
|
||||||
|
| SMALLDATETIME
|
||||||
|
| SMALLINT
|
||||||
|
| TIME
|
||||||
|
| TIMESTAMP
|
||||||
|
| TINYINT
|
||||||
|
| VALUES
|
||||||
|
| VARCHAR
|
||||||
|
| VARCHAR2
|
||||||
|
| XMLATTRIBUTES
|
||||||
|
;
|
||||||
|
|
||||||
/* Type/function identifier --- keywords that can be type or function names.
|
/* Type/function identifier --- keywords that can be type or function names.
|
||||||
*
|
*
|
||||||
* Most of these are keywords that are used as operators in expressions;
|
* Most of these are keywords that are used as operators in expressions;
|
||||||
|
|
|
@ -508,6 +508,7 @@ static bool assign_collations_walker(Node* node, assign_collations_context* cont
|
||||||
case T_CaseTestExpr:
|
case T_CaseTestExpr:
|
||||||
case T_SetToDefault:
|
case T_SetToDefault:
|
||||||
case T_CurrentOfExpr:
|
case T_CurrentOfExpr:
|
||||||
|
case T_PrefixKey:
|
||||||
case T_UserVar:
|
case T_UserVar:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -89,9 +89,10 @@ static Node* transformConnectByRootFuncCall(ParseState* pstate, Node* funcNameVa
|
||||||
static char *ColumnRefFindRelname(ParseState *pstate, const char *colname);
|
static char *ColumnRefFindRelname(ParseState *pstate, const char *colname);
|
||||||
static Node *transformStartWithColumnRef(ParseState *pstate, ColumnRef *cref, char **colname);
|
static Node *transformStartWithColumnRef(ParseState *pstate, ColumnRef *cref, char **colname);
|
||||||
static Node* tryTransformFunc(ParseState* pstate, List* fields, int location);
|
static Node* tryTransformFunc(ParseState* pstate, List* fields, int location);
|
||||||
|
static Node* transformPrefixKey(ParseState* pstate, PrefixKey* pkey);
|
||||||
|
|
||||||
#define OrientedIsCOLorPAX(rte) ((rte)->orientation == REL_COL_ORIENTED || (rte)->orientation == REL_PAX_ORIENTED)
|
#define OrientedIsCOLorPAX(rte) ((rte)->orientation == REL_COL_ORIENTED || (rte)->orientation == REL_PAX_ORIENTED)
|
||||||
|
#define INDEX_KEY_MAX_PREFIX_LENGTH (int)2676
|
||||||
/*
|
/*
|
||||||
* transformExpr -
|
* transformExpr -
|
||||||
* Analyze and transform expressions. Type checking and type casting is
|
* Analyze and transform expressions. Type checking and type casting is
|
||||||
|
@ -311,6 +312,9 @@ Node* transformExpr(ParseState* pstate, Node* expr)
|
||||||
case T_PredictByFunction:
|
case T_PredictByFunction:
|
||||||
result = transformPredictByFunction(pstate, (PredictByFunction*) expr);
|
result = transformPredictByFunction(pstate, (PredictByFunction*) expr);
|
||||||
break;
|
break;
|
||||||
|
case T_PrefixKey:
|
||||||
|
result = transformPrefixKey(pstate, (PrefixKey*)expr);
|
||||||
|
break;
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
* Quietly accept node types that may be presented when we are
|
* Quietly accept node types that may be presented when we are
|
||||||
|
@ -3105,3 +3109,60 @@ static char *ColumnRefFindRelname(ParseState *pstate, const char *colname)
|
||||||
|
|
||||||
return relname;
|
return relname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transform a PrefixKey.
|
||||||
|
*/
|
||||||
|
static Node* transformPrefixKey(ParseState* pstate, PrefixKey* pkey)
|
||||||
|
{
|
||||||
|
Node *argnode = (Node*)pkey->arg;
|
||||||
|
int maxlen;
|
||||||
|
int location = ((ColumnRef*)argnode)->location;
|
||||||
|
|
||||||
|
Assert(nodeTag(argnode) == T_ColumnRef);
|
||||||
|
|
||||||
|
if (pkey->length <= 0 || pkey->length > INDEX_KEY_MAX_PREFIX_LENGTH) {
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
|
errmsg("index key prefix length(%d) must be positive and cannot exceed %d",
|
||||||
|
pkey->length, INDEX_KEY_MAX_PREFIX_LENGTH),
|
||||||
|
parser_errposition(pstate, location)));
|
||||||
|
}
|
||||||
|
argnode = transformExpr(pstate, argnode);
|
||||||
|
|
||||||
|
Assert(nodeTag(argnode) == T_Var);
|
||||||
|
|
||||||
|
switch (((Var*)argnode)->vartype) {
|
||||||
|
case TEXTOID:
|
||||||
|
case CLOBOID:
|
||||||
|
case BPCHAROID:
|
||||||
|
case VARCHAROID:
|
||||||
|
case NVARCHAR2OID:
|
||||||
|
case BLOBOID:
|
||||||
|
case RAWOID:
|
||||||
|
case BYTEAOID:
|
||||||
|
pkey->arg = (Expr*)argnode;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
|
errmsg("index prefix key are not supported by column type %s",
|
||||||
|
format_type_be(((Var*)argnode)->vartype)),
|
||||||
|
parser_errposition(pstate, location)));
|
||||||
|
}
|
||||||
|
|
||||||
|
maxlen = ((Var*)argnode)->vartypmod;
|
||||||
|
if (maxlen > 0) {
|
||||||
|
maxlen -= VARHDRSZ;
|
||||||
|
if (pkey->length > maxlen) {
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||||
|
errmsg("index key prefix length(%d) too long for type %s(%d)",
|
||||||
|
pkey->length, format_type_be(((Var*)argnode)->vartype), maxlen),
|
||||||
|
parser_errposition(pstate, location)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Node*)pkey;
|
||||||
|
}
|
|
@ -3813,6 +3813,12 @@ IndexStmt* transformIndexStmt(Oid relid, IndexStmt* stmt, const char* queryStrin
|
||||||
#endif
|
#endif
|
||||||
if (expression_returns_set(ielem->expr))
|
if (expression_returns_set(ielem->expr))
|
||||||
ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("index expression cannot return a set")));
|
ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("index expression cannot return a set")));
|
||||||
|
if (IsA(ielem->expr, PrefixKey) &&
|
||||||
|
(0 != pg_strcasecmp(stmt->accessMethod, DEFAULT_INDEX_TYPE)) &&
|
||||||
|
(0 != pg_strcasecmp(stmt->accessMethod, DEFAULT_USTORE_INDEX_TYPE))) {
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("access method \"%s\" does not support prefix key", stmt->accessMethod)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsElementExisted(indexElements, ielem)) {
|
if (IsElementExisted(indexElements, ielem)) {
|
||||||
|
|
|
@ -3313,7 +3313,9 @@ static char *pg_get_indexdef_worker(Oid indexrelid, int colno, const Oid *exclud
|
||||||
str = deparse_expression_pretty(indexkey, context, false, false, prettyFlags, 0);
|
str = deparse_expression_pretty(indexkey, context, false, false, prettyFlags, 0);
|
||||||
if (!colno || colno == keyno + 1) {
|
if (!colno || colno == keyno + 1) {
|
||||||
/* Need parens if it's not a bare function call */
|
/* Need parens if it's not a bare function call */
|
||||||
if (indexkey && IsA(indexkey, FuncExpr) && ((FuncExpr*)indexkey)->funcformat == COERCE_EXPLICIT_CALL)
|
if (indexkey &&
|
||||||
|
((IsA(indexkey, FuncExpr) && ((FuncExpr*)indexkey)->funcformat == COERCE_EXPLICIT_CALL) ||
|
||||||
|
IsA(indexkey, PrefixKey)))
|
||||||
appendStringInfoString(&buf, str);
|
appendStringInfoString(&buf, str);
|
||||||
else
|
else
|
||||||
appendStringInfo(&buf, "(%s)", str);
|
appendStringInfo(&buf, "(%s)", str);
|
||||||
|
@ -9957,6 +9959,12 @@ static void get_rule_expr(Node* node, deparse_context* context, bool showimplici
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case T_PrefixKey: {
|
||||||
|
PrefixKey* pkey = (PrefixKey*)node;
|
||||||
|
get_rule_expr((Node*)pkey->arg, context, showimplicit, no_alias);
|
||||||
|
appendStringInfo(buf, "(%d)", pkey->length);
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (context->qrw_phase)
|
if (context->qrw_phase)
|
||||||
appendStringInfo(buf, "<unknown %d>", (int)nodeTag(node));
|
appendStringInfo(buf, "<unknown %d>", (int)nodeTag(node));
|
||||||
|
|
|
@ -5398,7 +5398,7 @@ static bool get_actual_variable_range(PlannerInfo* root, VariableStatData* varda
|
||||||
* The first index column must match the desired variable and sort
|
* The first index column must match the desired variable and sort
|
||||||
* operator --- but we can use a descending-order index.
|
* operator --- but we can use a descending-order index.
|
||||||
*/
|
*/
|
||||||
if (!match_index_to_operand(vardata->var, 0, index))
|
if (!match_index_to_operand(vardata->var, 0, index, true))
|
||||||
continue;
|
continue;
|
||||||
switch (get_op_opfamily_strategy(sortop, index->sortopfamily[0])) {
|
switch (get_op_opfamily_strategy(sortop, index->sortopfamily[0])) {
|
||||||
case BTLessStrategyNumber:
|
case BTLessStrategyNumber:
|
||||||
|
@ -6697,10 +6697,10 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
|
||||||
continue; /* keep compiler quiet */
|
continue; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match_index_to_operand(leftop, indexcol, index)) {
|
if (match_index_to_operand(leftop, indexcol, index, true)) {
|
||||||
/* clause_op is correct */
|
/* clause_op is correct */
|
||||||
} else {
|
} else {
|
||||||
Assert(match_index_to_operand(rightop, indexcol, index));
|
Assert(match_index_to_operand(rightop, indexcol, index, true));
|
||||||
/* Must flip operator to get the opfamily member */
|
/* Must flip operator to get the opfamily member */
|
||||||
clause_op = get_commutator(clause_op);
|
clause_op = get_commutator(clause_op);
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,6 @@ static text* text_catenate(text* t1, text* t2);
|
||||||
static text* text_overlay(text* t1, text* t2, int sp, int sl);
|
static text* text_overlay(text* t1, text* t2, int sp, int sl);
|
||||||
static void appendStringInfoText(StringInfo str, const text* t);
|
static void appendStringInfoText(StringInfo str, const text* t);
|
||||||
static bytea* bytea_catenate(bytea* t1, bytea* t2);
|
static bytea* bytea_catenate(bytea* t1, bytea* t2);
|
||||||
static bytea* bytea_substring(Datum str, int S, int L, bool length_not_specified);
|
|
||||||
static bytea* bytea_substring_orclcompat(Datum str, int S, int L, bool length_not_specified);
|
static bytea* bytea_substring_orclcompat(Datum str, int S, int L, bool length_not_specified);
|
||||||
static bytea* bytea_overlay(bytea* t1, bytea* t2, int sp, int sl);
|
static bytea* bytea_overlay(bytea* t1, bytea* t2, int sp, int sl);
|
||||||
static StringInfo makeStringAggState(FunctionCallInfo fcinfo);
|
static StringInfo makeStringAggState(FunctionCallInfo fcinfo);
|
||||||
|
@ -3042,7 +3041,7 @@ Datum bytea_substr_no_len(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), -1, true));
|
PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0), PG_GETARG_INT32(1), -1, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bytea* bytea_substring(Datum str, int S, int L, bool length_not_specified)
|
bytea* bytea_substring(Datum str, int S, int L, bool length_not_specified)
|
||||||
{
|
{
|
||||||
int S1; /* adjusted start position */
|
int S1; /* adjusted start position */
|
||||||
int L1; /* adjusted substring length */
|
int L1; /* adjusted substring length */
|
||||||
|
|
|
@ -59,7 +59,7 @@ bool open_join_children = true;
|
||||||
bool will_shutdown = false;
|
bool will_shutdown = false;
|
||||||
|
|
||||||
/* hard-wired binary version number */
|
/* hard-wired binary version number */
|
||||||
const uint32 GRAND_VERSION_NUM = 92616;
|
const uint32 GRAND_VERSION_NUM = 92617;
|
||||||
|
|
||||||
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
||||||
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||||
|
|
|
@ -754,6 +754,12 @@ void UniqueSql::JumbleExpr(pgssJumbleState* jstate, Node* node)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case T_PrefixKey: {
|
||||||
|
PrefixKey* pkey = (PrefixKey*)node;
|
||||||
|
UniqueSql::JumbleExpr(jstate, (Node*)pkey->arg);
|
||||||
|
APP_JUMB(pkey->length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
/* Only a warning, since we can stumble along anyway */
|
/* Only a warning, since we can stumble along anyway */
|
||||||
elog(DEBUG1, "unrecognized node type: %d", (int)nodeTag(node));
|
elog(DEBUG1, "unrecognized node type: %d", (int)nodeTag(node));
|
||||||
|
|
|
@ -51,6 +51,12 @@
|
||||||
#define IndexCollMatchesExprColl(idxcollation, exprcollation) \
|
#define IndexCollMatchesExprColl(idxcollation, exprcollation) \
|
||||||
((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
|
((idxcollation) == InvalidOid || (idxcollation) == (exprcollation))
|
||||||
|
|
||||||
|
#define PrefixKeyColumnMatched(indexkey, operand) \
|
||||||
|
((indexkey) && IsA((indexkey), PrefixKey) && IsA(((PrefixKey*)(indexkey))->arg, Var) && \
|
||||||
|
(operand) && IsA((operand), Var) && \
|
||||||
|
((Var*)((PrefixKey*)(indexkey))->arg)->varno == ((Var*)(operand))->varno && \
|
||||||
|
((Var*)((PrefixKey*)(indexkey))->arg)->varattno == ((Var*)(operand))->varattno)
|
||||||
|
|
||||||
/* Whether to use ScalarArrayOpExpr to build index qualifications */
|
/* Whether to use ScalarArrayOpExpr to build index qualifications */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SAOP_PER_AM, /* Use ScalarArrayOpExpr if amsearcharray */
|
SAOP_PER_AM, /* Use ScalarArrayOpExpr if amsearcharray */
|
||||||
|
@ -135,12 +141,18 @@ static Expr* match_clause_to_ordering_op(IndexOptInfo* index, int indexcol, Expr
|
||||||
static bool match_boolean_index_clause(Node* clause, int indexcol, IndexOptInfo* index);
|
static bool match_boolean_index_clause(Node* clause, int indexcol, IndexOptInfo* index);
|
||||||
static bool match_special_index_operator(Expr* clause, Oid opfamily, Oid idxcollation, bool indexkey_on_left);
|
static bool match_special_index_operator(Expr* clause, Oid opfamily, Oid idxcollation, bool indexkey_on_left);
|
||||||
static Expr* expand_boolean_index_clause(Node* clause, int indexcol, IndexOptInfo* index);
|
static Expr* expand_boolean_index_clause(Node* clause, int indexcol, IndexOptInfo* index);
|
||||||
static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid idxcollation);
|
static List* expand_indexqual_opclause(IndexOptInfo* index, RestrictInfo* rinfo, Oid opfamily, Oid idxcollation,
|
||||||
|
int indexcol);
|
||||||
static RestrictInfo* expand_indexqual_rowcompare(RestrictInfo* rinfo, IndexOptInfo* index, int indexcol);
|
static RestrictInfo* expand_indexqual_rowcompare(RestrictInfo* rinfo, IndexOptInfo* index, int indexcol);
|
||||||
static List* prefix_quals(Node* leftop, Oid opfamily, Oid collation, Const* prefix, Pattern_Prefix_Status pstatus);
|
static List* prefix_quals(Node* leftop, Oid opfamily, Oid collation, Const* prefix,
|
||||||
|
Pattern_Prefix_Status pstatus, int prefixkey_len);
|
||||||
static List* network_prefix_quals(Node* leftop, Oid expr_op, Oid opfamily, Datum rightop);
|
static List* network_prefix_quals(Node* leftop, Oid expr_op, Oid opfamily, Datum rightop);
|
||||||
static Datum string_to_datum(const char* str, Oid datatype);
|
static Datum string_to_datum(const char* str, Oid datatype);
|
||||||
static Const* string_to_const(const char* str, Oid datatype);
|
static Const* string_to_const(const char* str, Oid datatype);
|
||||||
|
static int get_index_column_prefix_lenth(IndexOptInfo *index, int indexcol);
|
||||||
|
static Const* prefix_const_node(Const* con, int prefix_len, Oid datatype);
|
||||||
|
static RestrictInfo* rewrite_opclause_for_prefixkey(
|
||||||
|
RestrictInfo *rinfo, IndexOptInfo* index, Oid opfamily, int prefix_len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create_index_paths
|
* create_index_paths
|
||||||
|
@ -2398,7 +2410,7 @@ static bool match_clause_to_indexcol(IndexOptInfo* index, int indexcol, Restrict
|
||||||
} else if (index->amsearchnulls && IsA(clause, NullTest)) {
|
} else if (index->amsearchnulls && IsA(clause, NullTest)) {
|
||||||
NullTest* nt = (NullTest*)clause;
|
NullTest* nt = (NullTest*)clause;
|
||||||
|
|
||||||
if (!nt->argisrow && match_index_to_operand((Node*)nt->arg, indexcol, index))
|
if (!nt->argisrow && match_index_to_operand((Node*)nt->arg, indexcol, index, true))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
} else
|
} else
|
||||||
|
@ -2408,7 +2420,7 @@ static bool match_clause_to_indexcol(IndexOptInfo* index, int indexcol, Restrict
|
||||||
* Check for clauses of the form: (indexkey operator constant) or
|
* Check for clauses of the form: (indexkey operator constant) or
|
||||||
* (constant operator indexkey). See above notes about const-ness.
|
* (constant operator indexkey). See above notes about const-ness.
|
||||||
*/
|
*/
|
||||||
if (match_index_to_operand(leftop, indexcol, index) && !bms_is_member(index_relid, right_relids) &&
|
if (match_index_to_operand(leftop, indexcol, index, true) && !bms_is_member(index_relid, right_relids) &&
|
||||||
!contain_volatile_functions(rightop)) {
|
!contain_volatile_functions(rightop)) {
|
||||||
if (IndexCollMatchesExprColl(idxcollation, expr_coll) && is_indexable_operator(expr_op, opfamily, true))
|
if (IndexCollMatchesExprColl(idxcollation, expr_coll) && is_indexable_operator(expr_op, opfamily, true))
|
||||||
return true;
|
return true;
|
||||||
|
@ -2422,8 +2434,8 @@ static bool match_clause_to_indexcol(IndexOptInfo* index, int indexcol, Restrict
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plain_op && match_index_to_operand(rightop, indexcol, index) && !bms_is_member(index_relid, left_relids) &&
|
if (plain_op && match_index_to_operand(rightop, indexcol, index, true) &&
|
||||||
!contain_volatile_functions(leftop)) {
|
!bms_is_member(index_relid, left_relids) && !contain_volatile_functions(leftop)) {
|
||||||
if (IndexCollMatchesExprColl(idxcollation, expr_coll) && is_indexable_operator(expr_op, opfamily, false))
|
if (IndexCollMatchesExprColl(idxcollation, expr_coll) && is_indexable_operator(expr_op, opfamily, false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -2849,7 +2861,7 @@ bool eclass_member_matches_indexcol(EquivalenceClass* ec, EquivalenceMember* em,
|
||||||
if (!IndexCollMatchesExprColl(curCollation, ec->ec_collation))
|
if (!IndexCollMatchesExprColl(curCollation, ec->ec_collation))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return match_index_to_operand((Node*)em->em_expr, indexcol, index);
|
return match_index_to_operand((Node*)em->em_expr, indexcol, index, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool relation_has_unique_index_for_no_index(PlannerInfo* root, RelOptInfo* rel)
|
static bool relation_has_unique_index_for_no_index(PlannerInfo* root, RelOptInfo* rel)
|
||||||
|
@ -2978,7 +2990,7 @@ bool relation_has_unique_index_for(
|
||||||
else
|
else
|
||||||
rexpr = get_leftop(rinfo->clause);
|
rexpr = get_leftop(rinfo->clause);
|
||||||
|
|
||||||
if (match_index_to_operand(rexpr, c, ind)) {
|
if (match_index_to_operand(rexpr, c, ind, true)) {
|
||||||
matched = true; /* column is unique */
|
matched = true; /* column is unique */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2993,7 +3005,7 @@ bool relation_has_unique_index_for(
|
||||||
Oid opr = lfirst_oid(lc2);
|
Oid opr = lfirst_oid(lc2);
|
||||||
|
|
||||||
/* See if the expression matches the index key */
|
/* See if the expression matches the index key */
|
||||||
if (!match_index_to_operand(expr, c, ind))
|
if (!match_index_to_operand(expr, c, ind, true))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3039,13 +3051,14 @@ bool relation_has_unique_index_for(
|
||||||
* operand: the nodetree to be compared to the index
|
* operand: the nodetree to be compared to the index
|
||||||
* indexcol: the column number of the index (counting from 0)
|
* indexcol: the column number of the index (counting from 0)
|
||||||
* index: the index of interest
|
* index: the index of interest
|
||||||
|
* match_prefixkey: if match prefix key to column
|
||||||
*
|
*
|
||||||
* Note that we aren't interested in collations here; the caller must check
|
* Note that we aren't interested in collations here; the caller must check
|
||||||
* for a collation match, if it's dealing with an operator where that matters.
|
* for a collation match, if it's dealing with an operator where that matters.
|
||||||
*
|
*
|
||||||
* This is exported for use in selfuncs.c.
|
* This is exported for use in selfuncs.c.
|
||||||
*/
|
*/
|
||||||
bool match_index_to_operand(Node* operand, int indexcol, IndexOptInfo* index)
|
bool match_index_to_operand(Node* operand, int indexcol, IndexOptInfo* index, bool match_prefixkey)
|
||||||
{
|
{
|
||||||
int indkey;
|
int indkey;
|
||||||
|
|
||||||
|
@ -3099,7 +3112,12 @@ bool match_index_to_operand(Node* operand, int indexcol, IndexOptInfo* index)
|
||||||
*/
|
*/
|
||||||
if (indexkey && IsA(indexkey, RelabelType))
|
if (indexkey && IsA(indexkey, RelabelType))
|
||||||
indexkey = (Node*)((RelabelType*)indexkey)->arg;
|
indexkey = (Node*)((RelabelType*)indexkey)->arg;
|
||||||
|
/*
|
||||||
|
* PrefixKey is not a strict expression. It can be matched to column.
|
||||||
|
*/
|
||||||
|
if (match_prefixkey && PrefixKeyColumnMatched(indexkey, operand)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (equal(indexkey, operand))
|
if (equal(indexkey, operand))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3405,7 +3423,8 @@ void expand_indexqual_conditions(
|
||||||
* RowCompare, or NullTest
|
* RowCompare, or NullTest
|
||||||
*/
|
*/
|
||||||
if (is_opclause(clause)) {
|
if (is_opclause(clause)) {
|
||||||
indexquals = list_concat(indexquals, expand_indexqual_opclause(rinfo, curFamily, curCollation));
|
indexquals = list_concat(indexquals,
|
||||||
|
expand_indexqual_opclause(index, rinfo, curFamily, curCollation, indexcol));
|
||||||
/* expand_indexqual_opclause can produce multiple clauses */
|
/* expand_indexqual_opclause can produce multiple clauses */
|
||||||
while (list_length(indexqualcols) < list_length(indexquals))
|
while (list_length(indexqualcols) < list_length(indexquals))
|
||||||
indexqualcols = lappend_int(indexqualcols, indexcol);
|
indexqualcols = lappend_int(indexqualcols, indexcol);
|
||||||
|
@ -3508,7 +3527,8 @@ static Expr* expand_boolean_index_clause(Node* clause, int indexcol, IndexOptInf
|
||||||
* In the base case this is just list_make1(), but we have to be prepared to
|
* In the base case this is just list_make1(), but we have to be prepared to
|
||||||
* expand special cases that were accepted by match_special_index_operator().
|
* expand special cases that were accepted by match_special_index_operator().
|
||||||
*/
|
*/
|
||||||
static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid idxcollation)
|
static List* expand_indexqual_opclause(IndexOptInfo* index, RestrictInfo* rinfo, Oid opfamily, Oid idxcollation,
|
||||||
|
int indexcol)
|
||||||
{
|
{
|
||||||
Expr* clause = rinfo->clause;
|
Expr* clause = rinfo->clause;
|
||||||
|
|
||||||
|
@ -3520,6 +3540,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
||||||
Const* patt = (Const*)rightop;
|
Const* patt = (Const*)rightop;
|
||||||
Const* prefix = NULL;
|
Const* prefix = NULL;
|
||||||
Pattern_Prefix_Status pstatus;
|
Pattern_Prefix_Status pstatus;
|
||||||
|
int prefixkey_len = get_index_column_prefix_lenth(index, indexcol);
|
||||||
|
|
||||||
if (patt == NULL) {
|
if (patt == NULL) {
|
||||||
ereport(ERROR, (errmodule(MOD_OPT), errmsg("right operator can not be NULL")));
|
ereport(ERROR, (errmodule(MOD_OPT), errmsg("right operator can not be NULL")));
|
||||||
|
@ -3540,7 +3561,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
||||||
case OID_BYTEA_LIKE_OP:
|
case OID_BYTEA_LIKE_OP:
|
||||||
if (!op_in_opfamily(expr_op, opfamily)) {
|
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like, expr_coll, &prefix, NULL);
|
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like, expr_coll, &prefix, NULL);
|
||||||
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus);
|
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus, prefixkey_len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3550,7 +3571,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
||||||
if (!op_in_opfamily(expr_op, opfamily)) {
|
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||||
/* the right-hand const is type text for all of these */
|
/* the right-hand const is type text for all of these */
|
||||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, expr_coll, &prefix, NULL);
|
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC, expr_coll, &prefix, NULL);
|
||||||
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus);
|
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus, prefixkey_len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3560,7 +3581,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
||||||
if (!op_in_opfamily(expr_op, opfamily)) {
|
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||||
/* the right-hand const is type text for all of these */
|
/* the right-hand const is type text for all of these */
|
||||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex, expr_coll, &prefix, NULL);
|
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex, expr_coll, &prefix, NULL);
|
||||||
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus);
|
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus, prefixkey_len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3570,7 +3591,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
||||||
if (!op_in_opfamily(expr_op, opfamily)) {
|
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||||
/* the right-hand const is type text for all of these */
|
/* the right-hand const is type text for all of these */
|
||||||
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, expr_coll, &prefix, NULL);
|
pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC, expr_coll, &prefix, NULL);
|
||||||
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus);
|
return prefix_quals(leftop, opfamily, idxcollation, prefix, pstatus, prefixkey_len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -3581,6 +3602,9 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (prefixkey_len > 0 && op_in_opfamily(expr_op, opfamily)) {
|
||||||
|
return list_make1(rewrite_opclause_for_prefixkey(rinfo, index, opfamily, prefixkey_len));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3838,7 +3862,8 @@ Expr* adjust_rowcompare_for_index(
|
||||||
* operator family; we use it to deduce the appropriate comparison
|
* operator family; we use it to deduce the appropriate comparison
|
||||||
* operators and operand datatypes. collation is the input collation to use.
|
* operators and operand datatypes. collation is the input collation to use.
|
||||||
*/
|
*/
|
||||||
static List* prefix_quals(Node* leftop, Oid opfamily, Oid collation, Const* prefix_const, Pattern_Prefix_Status pstatus)
|
static List* prefix_quals(Node* leftop, Oid opfamily, Oid collation, Const* prefix_const,
|
||||||
|
Pattern_Prefix_Status pstatus, int prefixkey_len)
|
||||||
{
|
{
|
||||||
List* result = NIL;
|
List* result = NIL;
|
||||||
Oid datatype;
|
Oid datatype;
|
||||||
|
@ -3909,7 +3934,28 @@ static List* prefix_quals(Node* leftop, Oid opfamily, Oid collation, Const* pref
|
||||||
prefix_const = string_to_const(prefix, datatype);
|
prefix_const = string_to_const(prefix, datatype);
|
||||||
pfree_ext(prefix);
|
pfree_ext(prefix);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* If matched key is prefix key, try generate an "=" indexqual firstly.
|
||||||
|
*/
|
||||||
|
if (prefixkey_len > 0) {
|
||||||
|
/* Prefix key is not supported for "name" type, ignore it. */
|
||||||
|
int prefix_const_len = (datatype == BYTEAOID) ?
|
||||||
|
(int)VARSIZE_ANY_EXHDR(DatumGetPointer(prefix_const->constvalue)) :
|
||||||
|
text_length(prefix_const->constvalue);
|
||||||
|
if (prefixkey_len <= prefix_const_len) {
|
||||||
|
prefix_const = prefix_const_node(prefix_const, prefixkey_len, datatype);
|
||||||
|
oproid = get_opfamily_member(opfamily, datatype, datatype, BTEqualStrategyNumber);
|
||||||
|
if (oproid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmodule(MOD_OPT),
|
||||||
|
errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),
|
||||||
|
(errmsg("no = operator for opfamily %u when generate indexqual condition by prefix quals",
|
||||||
|
opfamily))));
|
||||||
|
expr = make_opclause(oproid, BOOLOID, false, (Expr*)leftop, (Expr*)prefix_const, InvalidOid, collation);
|
||||||
|
result = list_make1(make_simple_restrictinfo(expr));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* If we found an exact-match pattern, generate an "=" indexqual.
|
* If we found an exact-match pattern, generate an "=" indexqual.
|
||||||
*/
|
*/
|
||||||
|
@ -4135,3 +4181,149 @@ static Const* string_to_const(const char* str, Oid datatype)
|
||||||
return makeConst(datatype, -1, collation, constlen, conval, false, false);
|
return makeConst(datatype, -1, collation, constlen, conval, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_index_column_prefix_lenth
|
||||||
|
* Get the prefix length of a specified index column.
|
||||||
|
* Returns length if it is a prefix key, otherwise returns 0.
|
||||||
|
*/
|
||||||
|
static int get_index_column_prefix_lenth(IndexOptInfo *index, int indexcol)
|
||||||
|
{
|
||||||
|
if (index->indexkeys[indexcol] != 0) {
|
||||||
|
/* It's a simple index column, not a prefix key. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* indexkey = NULL;
|
||||||
|
ListCell* indexpr_item = list_head(index->indexprs);
|
||||||
|
if (indexpr_item == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < indexcol; i++) {
|
||||||
|
if (index->indexkeys[i] != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexpr_item = lnext(indexpr_item);
|
||||||
|
if (indexpr_item == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indexkey = (Node*)lfirst(indexpr_item);
|
||||||
|
if (indexkey && IsA(indexkey, RelabelType)) {
|
||||||
|
indexkey = (Node*)((RelabelType*)indexkey)->arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexkey && IsA(indexkey, PrefixKey)) {
|
||||||
|
return ((PrefixKey*)indexkey)->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Const* prefix_const_node(Const* con, int prefix_len, Oid datatype)
|
||||||
|
{
|
||||||
|
int prefix_const_len;
|
||||||
|
Datum prefix_value;
|
||||||
|
if (datatype == BYTEAOID || datatype == RAWOID || datatype == BLOBOID) {
|
||||||
|
/* length of bytes */
|
||||||
|
prefix_const_len = VARSIZE_ANY_EXHDR(DatumGetPointer(con->constvalue));
|
||||||
|
if (prefix_len < prefix_const_len) {
|
||||||
|
prefix_value = PointerGetDatum(bytea_substring(con->constvalue, 1, prefix_len, false));
|
||||||
|
return makeConst(datatype, -1, con->constcollid, con->constlen, prefix_value, false, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* length of characters */
|
||||||
|
prefix_const_len = text_length(con->constvalue);
|
||||||
|
if (prefix_len < prefix_const_len) {
|
||||||
|
prefix_value = PointerGetDatum(text_substring(con->constvalue, 1, prefix_len, false));
|
||||||
|
return makeConst(datatype, -1, con->constcollid, con->constlen, prefix_value, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return con;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rewrite_opclause_for_prefixkey
|
||||||
|
* Rewrite an indexqual for prefix key.
|
||||||
|
*
|
||||||
|
* The prefix key stores only the prefix of a column. Index scan using the original
|
||||||
|
* indexqual may miss some keys we need. The indexqual for index scanning must
|
||||||
|
* include all possible keys.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* If index prefix key length is 3, we cannot use clause (prefixkey > 'ABC123') to
|
||||||
|
* approach index key 'ABC'. However, the column value corresponding to this key value
|
||||||
|
* may meets the clause. We can find right keys in index scan by converting the
|
||||||
|
* clause to (prefixkey >= 'ABC').
|
||||||
|
*/
|
||||||
|
static RestrictInfo* rewrite_opclause_for_prefixkey(RestrictInfo *rinfo, IndexOptInfo* index, Oid opfamily,
|
||||||
|
int prefix_len)
|
||||||
|
{
|
||||||
|
OpExpr* op = (OpExpr*)rinfo->clause;
|
||||||
|
Oid oproid = op->opno;
|
||||||
|
Node *leftop = NULL;
|
||||||
|
Node *rightop = NULL;
|
||||||
|
Node *chgnode = NULL;
|
||||||
|
Expr* newop = NULL;
|
||||||
|
int strategy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An index with a prefix key must be a btree index.
|
||||||
|
* We only need to rewrite binary OpExpr.
|
||||||
|
*/
|
||||||
|
if (list_length(op->args) != 2) {
|
||||||
|
return rinfo;
|
||||||
|
}
|
||||||
|
leftop = (Node*)linitial(op->args);
|
||||||
|
rightop = (Node*)lsecond(op->args);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check where indexkey is, rewrite the expression on the other side.
|
||||||
|
*/
|
||||||
|
chgnode = (bms_equal(rinfo->left_relids, index->rel->relids)) ? rightop : leftop;
|
||||||
|
|
||||||
|
if (IsA(chgnode, Const)) {
|
||||||
|
/*
|
||||||
|
* Prefixes the Const if its length is longger than prefix length.
|
||||||
|
*/
|
||||||
|
chgnode = (Node*)prefix_const_node((Const*)chgnode, prefix_len, ((Const*)chgnode)->consttype);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Add PrefixeKey node on the expression.
|
||||||
|
*/
|
||||||
|
PrefixKey *pexpr = makeNode(PrefixKey);
|
||||||
|
pexpr->length = prefix_len;
|
||||||
|
pexpr->arg = (Expr*)chgnode;
|
||||||
|
chgnode = (Node*)pexpr;
|
||||||
|
}
|
||||||
|
if (bms_equal(rinfo->left_relids, index->rel->relids)) {
|
||||||
|
rightop = chgnode;
|
||||||
|
} else {
|
||||||
|
leftop = chgnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Operators "> and "<" may cause required keys to be skipped.
|
||||||
|
* Replace them with ">=" or "<=".
|
||||||
|
*/
|
||||||
|
strategy = get_op_opfamily_strategy(oproid, opfamily);
|
||||||
|
if (strategy == BTGreaterStrategyNumber) {
|
||||||
|
oproid = get_opfamily_member(opfamily, exprType(leftop), exprType(rightop), BTGreaterEqualStrategyNumber);
|
||||||
|
} else if (strategy == BTLessStrategyNumber) {
|
||||||
|
oproid = get_opfamily_member(opfamily, exprType(leftop), exprType(rightop), BTLessEqualStrategyNumber);
|
||||||
|
}
|
||||||
|
if (oproid == InvalidOid)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmodule(MOD_OPT),
|
||||||
|
errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),
|
||||||
|
(errmsg(
|
||||||
|
"no >= or <= operator for opfamily %u when generate indexqual for prefix key", opfamily))));
|
||||||
|
newop = make_opclause(oproid, BOOLOID, op->opretset, (Expr*)leftop, (Expr*)rightop, op->opcollid, op->inputcollid);
|
||||||
|
|
||||||
|
return make_simple_restrictinfo(newop);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "access/skey.h"
|
#include "access/skey.h"
|
||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
|
#include "access/sysattr.h"
|
||||||
#include "bulkload/foreignroutine.h"
|
#include "bulkload/foreignroutine.h"
|
||||||
#include "catalog/pg_class.h"
|
#include "catalog/pg_class.h"
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
|
@ -120,9 +121,9 @@ static HashJoin* create_hashjoin_plan(PlannerInfo* root, HashPath* best_path, Pl
|
||||||
static Node* replace_nestloop_params(PlannerInfo* root, Node* expr);
|
static Node* replace_nestloop_params(PlannerInfo* root, Node* expr);
|
||||||
static Node* replace_nestloop_params_mutator(Node* node, PlannerInfo* root);
|
static Node* replace_nestloop_params_mutator(Node* node, PlannerInfo* root);
|
||||||
static void process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params);
|
static void process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params);
|
||||||
static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path);
|
static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path, Bitmapset** prefixkeys);
|
||||||
static List* fix_indexorderby_references(PlannerInfo* root, IndexPath* index_path);
|
static List* fix_indexorderby_references(PlannerInfo* root, IndexPath* index_path);
|
||||||
static Node* fix_indexqual_operand(Node* node, IndexOptInfo* index, int indexcol);
|
static Node* fix_indexqual_operand(Node* node, IndexOptInfo* index, int indexcol, Bitmapset** prefixkeys);
|
||||||
static List* get_switched_clauses(List* clauses, Relids outerrelids);
|
static List* get_switched_clauses(List* clauses, Relids outerrelids);
|
||||||
static List* order_qual_clauses(PlannerInfo* root, List* clauses);
|
static List* order_qual_clauses(PlannerInfo* root, List* clauses);
|
||||||
static void copy_path_costsize(Plan* dest, Path* src);
|
static void copy_path_costsize(Plan* dest, Path* src);
|
||||||
|
@ -2515,6 +2516,18 @@ static TsStoreScan* create_tsstorescan_plan(PlannerInfo* root, Path* best_path,
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_MULTIPLE_NODES */
|
#endif /* ENABLE_MULTIPLE_NODES */
|
||||||
|
|
||||||
|
static bool clause_relate_to_prefixkey(RestrictInfo* rinfo, IndexOptInfo* index, Bitmapset* prefixkeys)
|
||||||
|
{
|
||||||
|
Index relid = index->rel->relid;
|
||||||
|
Bitmapset* columns = NULL;
|
||||||
|
|
||||||
|
if (prefixkeys == NULL || bms_is_empty(prefixkeys) || !bms_is_member(relid, rinfo->clause_relids)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pull_varattnos((Node*)rinfo->clause, relid, &columns);
|
||||||
|
return bms_overlap(columns, prefixkeys);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create_indexscan_plan
|
* create_indexscan_plan
|
||||||
* Returns an indexscan plan for the base relation scanned by 'best_path'
|
* Returns an indexscan plan for the base relation scanned by 'best_path'
|
||||||
|
@ -2539,6 +2552,7 @@ static Scan* create_indexscan_plan(
|
||||||
List* fixed_indexorderbys = NIL;
|
List* fixed_indexorderbys = NIL;
|
||||||
List* opquals = NIL;
|
List* opquals = NIL;
|
||||||
ListCell* l = NULL;
|
ListCell* l = NULL;
|
||||||
|
Bitmapset *prefixkeys = NULL;
|
||||||
|
|
||||||
/* it should be a base rel... */
|
/* it should be a base rel... */
|
||||||
Assert(baserelid > 0);
|
Assert(baserelid > 0);
|
||||||
|
@ -2554,7 +2568,7 @@ static Scan* create_indexscan_plan(
|
||||||
* The executor needs a copy with the indexkey on the left of each clause
|
* The executor needs a copy with the indexkey on the left of each clause
|
||||||
* and with index Vars substituted for table ones.
|
* and with index Vars substituted for table ones.
|
||||||
*/
|
*/
|
||||||
fixed_indexquals = fix_indexqual_references(root, best_path);
|
fixed_indexquals = fix_indexqual_references(root, best_path, &prefixkeys);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Likewise fix up index attr references in the ORDER BY expressions.
|
* Likewise fix up index attr references in the ORDER BY expressions.
|
||||||
|
@ -2602,6 +2616,10 @@ static Scan* create_indexscan_plan(
|
||||||
|
|
||||||
if (list_member_ptr(indexquals, rinfo))
|
if (list_member_ptr(indexquals, rinfo))
|
||||||
continue; /* simple duplicate */
|
continue; /* simple duplicate */
|
||||||
|
if (clause_relate_to_prefixkey(rinfo, best_path->indexinfo, prefixkeys)) {
|
||||||
|
qpqual = lappend(qpqual, rinfo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (is_redundant_derived_clause(rinfo, indexquals))
|
if (is_redundant_derived_clause(rinfo, indexquals))
|
||||||
continue; /* derived from same EquivalenceClass */
|
continue; /* derived from same EquivalenceClass */
|
||||||
if (!contain_mutable_functions((Node*)rinfo->clause)) {
|
if (!contain_mutable_functions((Node*)rinfo->clause)) {
|
||||||
|
@ -5151,7 +5169,7 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
|
||||||
* with the original; this is needed in case there is a subplan in it (we need
|
* with the original; this is needed in case there is a subplan in it (we need
|
||||||
* two separate copies of the subplan tree, or things will go awry).
|
* two separate copies of the subplan tree, or things will go awry).
|
||||||
*/
|
*/
|
||||||
static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path)
|
static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path, Bitmapset** prefixkeys)
|
||||||
{
|
{
|
||||||
IndexOptInfo* index = index_path->indexinfo;
|
IndexOptInfo* index = index_path->indexinfo;
|
||||||
List* fixed_indexquals = NIL;
|
List* fixed_indexquals = NIL;
|
||||||
|
@ -5192,11 +5210,10 @@ static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path)
|
||||||
*/
|
*/
|
||||||
if (!bms_equal(rinfo->left_relids, index->rel->relids))
|
if (!bms_equal(rinfo->left_relids, index->rel->relids))
|
||||||
CommuteOpExpr(op);
|
CommuteOpExpr(op);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now replace the indexkey expression with an index Var.
|
* Now replace the indexkey expression with an index Var.
|
||||||
*/
|
*/
|
||||||
linitial(op->args) = fix_indexqual_operand((Node*)linitial(op->args), index, indexcol);
|
linitial(op->args) = fix_indexqual_operand((Node*)linitial(op->args), index, indexcol, prefixkeys);
|
||||||
} else if (IsA(clause, RowCompareExpr)) {
|
} else if (IsA(clause, RowCompareExpr)) {
|
||||||
RowCompareExpr* rc = (RowCompareExpr*)clause;
|
RowCompareExpr* rc = (RowCompareExpr*)clause;
|
||||||
Expr* newrc = NULL;
|
Expr* newrc = NULL;
|
||||||
|
@ -5234,19 +5251,19 @@ static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path)
|
||||||
Assert(list_length(rc->largs) == list_length(indexcolnos));
|
Assert(list_length(rc->largs) == list_length(indexcolnos));
|
||||||
forboth(lca, rc->largs, lcai, indexcolnos)
|
forboth(lca, rc->largs, lcai, indexcolnos)
|
||||||
{
|
{
|
||||||
lfirst(lca) = fix_indexqual_operand((Node*)lfirst(lca), index, lfirst_int(lcai));
|
lfirst(lca) = fix_indexqual_operand((Node*)lfirst(lca), index, lfirst_int(lcai), prefixkeys);
|
||||||
}
|
}
|
||||||
} else if (IsA(clause, ScalarArrayOpExpr)) {
|
} else if (IsA(clause, ScalarArrayOpExpr)) {
|
||||||
ScalarArrayOpExpr* saop = (ScalarArrayOpExpr*)clause;
|
ScalarArrayOpExpr* saop = (ScalarArrayOpExpr*)clause;
|
||||||
|
|
||||||
/* Never need to commute... */
|
/* Never need to commute... */
|
||||||
/* Replace the indexkey expression with an index Var. */
|
/* Replace the indexkey expression with an index Var. */
|
||||||
linitial(saop->args) = fix_indexqual_operand((Node*)linitial(saop->args), index, indexcol);
|
linitial(saop->args) = fix_indexqual_operand((Node*)linitial(saop->args), index, indexcol, prefixkeys);
|
||||||
} else if (IsA(clause, NullTest)) {
|
} else if (IsA(clause, NullTest)) {
|
||||||
NullTest* nt = (NullTest*)clause;
|
NullTest* nt = (NullTest*)clause;
|
||||||
|
|
||||||
/* Replace the indexkey expression with an index Var. */
|
/* Replace the indexkey expression with an index Var. */
|
||||||
nt->arg = (Expr*)fix_indexqual_operand((Node*)nt->arg, index, indexcol);
|
nt->arg = (Expr*)fix_indexqual_operand((Node*)nt->arg, index, indexcol, prefixkeys);
|
||||||
} else
|
} else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmodule(MOD_OPT),
|
(errmodule(MOD_OPT),
|
||||||
|
@ -5259,6 +5276,7 @@ static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path)
|
||||||
return fixed_indexquals;
|
return fixed_indexquals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fix_indexorderby_references
|
* fix_indexorderby_references
|
||||||
* Adjust indexorderby clauses to the form the executor's index
|
* Adjust indexorderby clauses to the form the executor's index
|
||||||
|
@ -5304,7 +5322,7 @@ static List* fix_indexorderby_references(PlannerInfo* root, IndexPath* index_pat
|
||||||
/*
|
/*
|
||||||
* Now replace the indexkey expression with an index Var.
|
* Now replace the indexkey expression with an index Var.
|
||||||
*/
|
*/
|
||||||
linitial(op->args) = fix_indexqual_operand((Node*)linitial(op->args), index, indexcol);
|
linitial(op->args) = fix_indexqual_operand((Node*)linitial(op->args), index, indexcol, NULL);
|
||||||
} else
|
} else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errmodule(MOD_OPT),
|
(errmodule(MOD_OPT),
|
||||||
|
@ -5327,7 +5345,7 @@ static List* fix_indexorderby_references(PlannerInfo* root, IndexPath* index_pat
|
||||||
* Most of the code here is just for sanity cross-checking that the given
|
* Most of the code here is just for sanity cross-checking that the given
|
||||||
* expression actually matches the index column it's claimed to.
|
* expression actually matches the index column it's claimed to.
|
||||||
*/
|
*/
|
||||||
static Node* fix_indexqual_operand(Node* node, IndexOptInfo* index, int indexcol)
|
static Node* fix_indexqual_operand(Node* node, IndexOptInfo* index, int indexcol, Bitmapset** prefixkeys)
|
||||||
{
|
{
|
||||||
Var* result = NULL;
|
Var* result = NULL;
|
||||||
int pos;
|
int pos;
|
||||||
|
@ -5374,6 +5392,13 @@ static Node* fix_indexqual_operand(Node* node, IndexOptInfo* index, int indexcol
|
||||||
indexkey = (Node*)lfirst(indexpr_item);
|
indexkey = (Node*)lfirst(indexpr_item);
|
||||||
if (indexkey && IsA(indexkey, RelabelType))
|
if (indexkey && IsA(indexkey, RelabelType))
|
||||||
indexkey = (Node*)((RelabelType*)indexkey)->arg;
|
indexkey = (Node*)((RelabelType*)indexkey)->arg;
|
||||||
|
if (indexkey && IsA(indexkey, PrefixKey)) {
|
||||||
|
indexkey = (Node*)((PrefixKey*)indexkey)->arg;
|
||||||
|
if (prefixkeys != NULL) {
|
||||||
|
*prefixkeys = bms_add_member(*prefixkeys,
|
||||||
|
((Var*)indexkey)->varattno - FirstLowInvalidHeapAttributeNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (equal(node, indexkey)) {
|
if (equal(node, indexkey)) {
|
||||||
result = makeVar(INDEX_VAR,
|
result = makeVar(INDEX_VAR,
|
||||||
indexcol + 1,
|
indexcol + 1,
|
||||||
|
|
|
@ -5148,6 +5148,37 @@ static Datum ExecEvalCurrentOfExpr(ExprState* exprstate, ExprContext* econtext,
|
||||||
return 0; /* keep compiler quiet */
|
return 0; /* keep compiler quiet */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecEvalPrefixText
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static Datum ExecEvalPrefixText(GenericExprState* state, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
|
||||||
|
{
|
||||||
|
PrefixKey* pkey = (PrefixKey*)state->xprstate.expr;
|
||||||
|
Datum result = ExecEvalExpr(state->arg, econtext, isNull, isDone);
|
||||||
|
|
||||||
|
if (*isNull) {
|
||||||
|
return (Datum)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PointerGetDatum(text_substring(result, 1, pkey->length, false));
|
||||||
|
}
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecEvalPrefixBytea
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static Datum ExecEvalPrefixBytea(GenericExprState* state, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone)
|
||||||
|
{
|
||||||
|
PrefixKey* pkey = (PrefixKey*)state->xprstate.expr;
|
||||||
|
Datum result = ExecEvalExpr(state->arg, econtext, isNull, isDone);
|
||||||
|
|
||||||
|
if (*isNull) {
|
||||||
|
return (Datum)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PointerGetDatum(bytea_substring(result, 1, pkey->length, false));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExecEvalExprSwitchContext
|
* ExecEvalExprSwitchContext
|
||||||
*
|
*
|
||||||
|
@ -5859,6 +5890,19 @@ ExprState* ExecInitExpr(Expr* node, PlanState* parent)
|
||||||
state = (ExprState*)rnstate;
|
state = (ExprState*)rnstate;
|
||||||
state->evalfunc = (ExprStateEvalFunc)ExecEvalRownum;
|
state->evalfunc = (ExprStateEvalFunc)ExecEvalRownum;
|
||||||
} break;
|
} break;
|
||||||
|
case T_PrefixKey: {
|
||||||
|
PrefixKey* pkey = (PrefixKey*)node;
|
||||||
|
GenericExprState* gstate = makeNode(GenericExprState);
|
||||||
|
Oid argtype = exprType((Node*)pkey->arg);
|
||||||
|
|
||||||
|
if (argtype == BYTEAOID || argtype == RAWOID || argtype == BLOBOID) {
|
||||||
|
gstate->xprstate.evalfunc = (ExprStateEvalFunc)ExecEvalPrefixBytea;
|
||||||
|
} else {
|
||||||
|
gstate->xprstate.evalfunc = (ExprStateEvalFunc)ExecEvalPrefixText;
|
||||||
|
}
|
||||||
|
gstate->arg = ExecInitExpr(pkey->arg, parent);
|
||||||
|
state = (ExprState*)gstate;
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
|
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
-- drop prefix key index
|
||||||
|
DO $$
|
||||||
|
DECLARE
|
||||||
|
stmt text;
|
||||||
|
cursor r is SELECT ns.nspname as nmspc, cl.relname as idxname
|
||||||
|
from pg_catalog.pg_index idx
|
||||||
|
join pg_catalog.pg_class cl on idx.indexrelid = cl.oid
|
||||||
|
join pg_catalog.pg_namespace ns on cl.relnamespace = ns.oid
|
||||||
|
where pg_catalog.strpos(idx.indexprs, '{PREFIXKEY') > 0;
|
||||||
|
res r%rowtype;
|
||||||
|
BEGIN
|
||||||
|
for res in r loop
|
||||||
|
stmt := 'DROP INDEX ' || res.nmspc || '.' || res.idxname;
|
||||||
|
execute immediate stmt;
|
||||||
|
end loop;
|
||||||
|
END$$;
|
|
@ -0,0 +1,16 @@
|
||||||
|
-- drop prefix key index
|
||||||
|
DO $$
|
||||||
|
DECLARE
|
||||||
|
stmt text;
|
||||||
|
cursor r is SELECT ns.nspname as nmspc, cl.relname as idxname
|
||||||
|
from pg_catalog.pg_index idx
|
||||||
|
join pg_catalog.pg_class cl on idx.indexrelid = cl.oid
|
||||||
|
join pg_catalog.pg_namespace ns on cl.relnamespace = ns.oid
|
||||||
|
where pg_catalog.strpos(idx.indexprs, '{PREFIXKEY') > 0;
|
||||||
|
res r%rowtype;
|
||||||
|
BEGIN
|
||||||
|
for res in r loop
|
||||||
|
stmt := 'DROP INDEX ' || res.nmspc || '.' || res.idxname;
|
||||||
|
execute immediate stmt;
|
||||||
|
end loop;
|
||||||
|
END$$;
|
|
@ -250,6 +250,7 @@ typedef enum NodeTag {
|
||||||
T_EstSPNode,
|
T_EstSPNode,
|
||||||
T_Rownum,
|
T_Rownum,
|
||||||
T_PseudoTargetEntry,
|
T_PseudoTargetEntry,
|
||||||
|
T_PrefixKey,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
|
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
|
||||||
|
|
|
@ -1025,6 +1025,12 @@ typedef struct XmlExpr {
|
||||||
int location; /* token location, or -1 if unknown */
|
int location; /* token location, or -1 if unknown */
|
||||||
} XmlExpr;
|
} XmlExpr;
|
||||||
|
|
||||||
|
typedef struct PrefixKey {
|
||||||
|
Expr xpr;
|
||||||
|
Expr* arg; /* should be a ColumnRef or Var */
|
||||||
|
int length; /* prefix length */
|
||||||
|
} PrefixKey;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* NullTest
|
* NullTest
|
||||||
*
|
*
|
||||||
|
|
|
@ -64,7 +64,7 @@ extern bool relation_has_unique_index_for(
|
||||||
PlannerInfo* root, RelOptInfo* rel, List* restrictlist, List* exprlist, List* oprlist);
|
PlannerInfo* root, RelOptInfo* rel, List* restrictlist, List* exprlist, List* oprlist);
|
||||||
extern bool eclass_member_matches_indexcol(
|
extern bool eclass_member_matches_indexcol(
|
||||||
EquivalenceClass* ec, EquivalenceMember* em, IndexOptInfo* index, int indexcol);
|
EquivalenceClass* ec, EquivalenceMember* em, IndexOptInfo* index, int indexcol);
|
||||||
extern bool match_index_to_operand(Node* operand, int indexcol, IndexOptInfo* index);
|
extern bool match_index_to_operand(Node* operand, int indexcol, IndexOptInfo* index, bool match_prefixkey = false);
|
||||||
extern void expand_indexqual_conditions(
|
extern void expand_indexqual_conditions(
|
||||||
IndexOptInfo* index, List* indexclauses, List* indexclausecols, List** indexquals_p, List** indexqualcols_p);
|
IndexOptInfo* index, List* indexclauses, List* indexclausecols, List** indexquals_p, List** indexqualcols_p);
|
||||||
extern void check_partial_indexes(PlannerInfo* root, RelOptInfo* rel);
|
extern void check_partial_indexes(PlannerInfo* root, RelOptInfo* rel);
|
||||||
|
|
|
@ -912,6 +912,7 @@ extern Datum instr_3args(PG_FUNCTION_ARGS);
|
||||||
extern Datum instr_4args(PG_FUNCTION_ARGS);
|
extern Datum instr_4args(PG_FUNCTION_ARGS);
|
||||||
extern Datum byteain(PG_FUNCTION_ARGS);
|
extern Datum byteain(PG_FUNCTION_ARGS);
|
||||||
extern void text_to_bktmap(text* gbucket, uint2* bktmap, int *bktlen);
|
extern void text_to_bktmap(text* gbucket, uint2* bktmap, int *bktlen);
|
||||||
|
extern bytea* bytea_substring(Datum str, int S, int L, bool length_not_specified);
|
||||||
|
|
||||||
#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))
|
#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))
|
||||||
#define TextDatumGetCString(d) text_to_cstring((text*)DatumGetPointer(d))
|
#define TextDatumGetCString(d) text_to_cstring((text*)DatumGetPointer(d))
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -164,6 +164,7 @@ test: single_node_random transactions_test
|
||||||
#test: single_node_arrays
|
#test: single_node_arrays
|
||||||
#test: single_node_btree_index single_node_hash_index single_node_update
|
#test: single_node_btree_index single_node_hash_index single_node_update
|
||||||
|
|
||||||
|
test: prefixkey_index
|
||||||
test: hash_index_001
|
test: hash_index_001
|
||||||
test: hash_index_002
|
test: hash_index_002
|
||||||
test: single_node_update
|
test: single_node_update
|
||||||
|
|
|
@ -0,0 +1,816 @@
|
||||||
|
create database prefix_index_db WITH ENCODING 'UTF-8' LC_COLLATE='C' LC_CTYPE='C' dbcompatibility 'B';
|
||||||
|
\c prefix_index_db
|
||||||
|
|
||||||
|
--
|
||||||
|
-- CREATE_INDEX
|
||||||
|
--
|
||||||
|
-- test datatype
|
||||||
|
CREATE TABLE test_prefix_datatype (
|
||||||
|
f1 int,
|
||||||
|
f2 money,
|
||||||
|
f3 boolean,
|
||||||
|
f4 date,
|
||||||
|
f5 point,
|
||||||
|
f6 cidr,
|
||||||
|
f7 bit(64),
|
||||||
|
f8 json,
|
||||||
|
f9 NAME,
|
||||||
|
f10 CHAR(64),
|
||||||
|
f11 VARCHAR(64),
|
||||||
|
f12 VARCHAR2(64),
|
||||||
|
f13 NVARCHAR2(64),
|
||||||
|
f14 NVARCHAR(64),
|
||||||
|
f15 TEXT,
|
||||||
|
f16 CLOB,
|
||||||
|
f17 "char",
|
||||||
|
f18 BLOB,
|
||||||
|
f19 RAW,
|
||||||
|
f20 BYTEA
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_prefix_f1 ON test_prefix_datatype (f1(4));
|
||||||
|
CREATE INDEX idx_prefix_f2 ON test_prefix_datatype (f2(4));
|
||||||
|
CREATE INDEX idx_prefix_f3 ON test_prefix_datatype (f3(4));
|
||||||
|
CREATE INDEX idx_prefix_f4 ON test_prefix_datatype (f4(4));
|
||||||
|
CREATE INDEX idx_prefix_f5 ON test_prefix_datatype (f5(4));
|
||||||
|
CREATE INDEX idx_prefix_f6 ON test_prefix_datatype (f6(4));
|
||||||
|
CREATE INDEX idx_prefix_f7 ON test_prefix_datatype (f7(4));
|
||||||
|
CREATE INDEX idx_prefix_f8 ON test_prefix_datatype (f8(4));
|
||||||
|
CREATE INDEX idx_prefix_f9 ON test_prefix_datatype (f9(4));
|
||||||
|
CREATE INDEX idx_prefix_f10 ON test_prefix_datatype (f10(65));
|
||||||
|
CREATE INDEX idx_prefix_f10 ON test_prefix_datatype (f10(4));
|
||||||
|
CREATE INDEX idx_prefix_f11 ON test_prefix_datatype (f11(65));
|
||||||
|
CREATE INDEX idx_prefix_f11 ON test_prefix_datatype (f11(4));
|
||||||
|
CREATE INDEX idx_prefix_f12 ON test_prefix_datatype (f12(65));
|
||||||
|
CREATE INDEX idx_prefix_f12 ON test_prefix_datatype (f12(4));
|
||||||
|
CREATE INDEX idx_prefix_f13 ON test_prefix_datatype (f13(65));
|
||||||
|
CREATE INDEX idx_prefix_f13 ON test_prefix_datatype (f13(4));
|
||||||
|
CREATE INDEX idx_prefix_f14 ON test_prefix_datatype (f14(65));
|
||||||
|
CREATE INDEX idx_prefix_f14 ON test_prefix_datatype (f14(4));
|
||||||
|
CREATE INDEX idx_prefix_f15 ON test_prefix_datatype (f15(4));
|
||||||
|
CREATE INDEX idx_prefix_f16 ON test_prefix_datatype (f16(4));
|
||||||
|
CREATE INDEX idx_prefix_f17 ON test_prefix_datatype (f17(4));
|
||||||
|
CREATE INDEX idx_prefix_f18 ON test_prefix_datatype (f18(4));
|
||||||
|
CREATE INDEX idx_prefix_f19 ON test_prefix_datatype (f19(4));
|
||||||
|
CREATE INDEX idx_prefix_f20 ON test_prefix_datatype (f20(4));
|
||||||
|
|
||||||
|
DROP TABLE test_prefix_datatype;
|
||||||
|
|
||||||
|
-- test syntax
|
||||||
|
CREATE TABLE test_prefix_syntax (
|
||||||
|
fchar CHAR(64),
|
||||||
|
BETWEEN VARCHAR(64),
|
||||||
|
GREATEST TEXT,
|
||||||
|
fblob BLOB
|
||||||
|
) ;
|
||||||
|
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(0));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(-1));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(1+1));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(6.4));
|
||||||
|
|
||||||
|
CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(0));
|
||||||
|
CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(-1));
|
||||||
|
CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(1+1));
|
||||||
|
CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(6.4));
|
||||||
|
-- GREATEST cannot be parsed as prefix key yet
|
||||||
|
CREATE INDEX error_index_GREATEST1 ON test_prefix_syntax (GREATEST(0));
|
||||||
|
CREATE INDEX error_index_GREATEST2 ON test_prefix_syntax (GREATEST(-1));
|
||||||
|
CREATE INDEX error_index_GREATEST3 ON test_prefix_syntax (GREATEST(1+1));
|
||||||
|
CREATE INDEX error_index_GREATEST4 ON test_prefix_syntax (GREATEST(6.4));
|
||||||
|
|
||||||
|
CREATE INDEX error_index_fblob ON test_prefix_syntax using hash (fblob(5));
|
||||||
|
CREATE INDEX error_index_fblob ON test_prefix_syntax using gin (fblob(5));
|
||||||
|
CREATE INDEX error_index_fblob ON test_prefix_syntax using gist (fblob(5));
|
||||||
|
|
||||||
|
DROP TABLE test_prefix_syntax;
|
||||||
|
|
||||||
|
-- test btree prefix length
|
||||||
|
CREATE TABLE test_prefix_key_len (
|
||||||
|
fchar CHAR(4096),
|
||||||
|
ftext TEXT,
|
||||||
|
fbytea BYTEA
|
||||||
|
);
|
||||||
|
insert into test_prefix_key_len
|
||||||
|
select array_to_string(array(
|
||||||
|
select '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'
|
||||||
|
FROM generate_series(1, 80)), '') as col1, col1 as col2, convert_to(col2, 'UTF8') as col3;
|
||||||
|
select length(fchar),length(ftext),length(fbytea) from test_prefix_key_len;
|
||||||
|
select lengthb(fchar),lengthb(ftext),octet_length(fbytea) from test_prefix_key_len;
|
||||||
|
CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_ftext ON test_prefix_key_len (ftext(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_ftext ON test_prefix_key_len (ftext(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_comb ON test_prefix_key_len (fchar(2676),ftext(2676),fbytea(2676));
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
DROP TABLE test_prefix_key_len;
|
||||||
|
|
||||||
|
-- test btree prefix length with multibyte characters
|
||||||
|
CREATE TABLE test_prefix_key_len (
|
||||||
|
fchar CHAR(4096),
|
||||||
|
ftext TEXT,
|
||||||
|
fbytea BYTEA
|
||||||
|
);
|
||||||
|
insert into test_prefix_key_len
|
||||||
|
select array_to_string(array(
|
||||||
|
select '一二三四五六七八九十百千万亿兆'
|
||||||
|
FROM generate_series(1, 200)), '') as col1, col1 as col2, convert_to(col2, 'UTF8') as col3;
|
||||||
|
select length(fchar),length(ftext),length(fbytea) from test_prefix_key_len;
|
||||||
|
select lengthb(fchar),lengthb(ftext),octet_length(fbytea) from test_prefix_key_len;
|
||||||
|
CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_ftext ON test_prefix_key_len (ftext(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_ftext ON test_prefix_key_len (ftext(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_comb ON test_prefix_key_len (fchar(2676),ftext(2676),fbytea(2676));
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
|
||||||
|
DROP TABLE test_prefix_key_len;
|
||||||
|
|
||||||
|
-- test ubtree prefix length
|
||||||
|
CREATE TABLE test_prefix_key_len (
|
||||||
|
fchar CHAR(4096),
|
||||||
|
ftext TEXT,
|
||||||
|
fbytea BYTEA
|
||||||
|
) WITH (STORAGE_TYPE=USTORE);
|
||||||
|
insert into test_prefix_key_len
|
||||||
|
select array_to_string(array(
|
||||||
|
select '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'
|
||||||
|
FROM generate_series(1, 80)), '') as col1, col1 as col2, convert_to(col2, 'UTF8') as col3;
|
||||||
|
select length(fchar),length(ftext),length(fbytea) from test_prefix_key_len;
|
||||||
|
select lengthb(fchar),lengthb(ftext),octet_length(fbytea) from test_prefix_key_len;
|
||||||
|
CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_ftext ON test_prefix_key_len (ftext(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(2677));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_ftext ON test_prefix_key_len (ftext(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(2676));
|
||||||
|
CREATE INDEX idx_prefix_len_test_comb ON test_prefix_key_len (fchar(2676),ftext(2676),fbytea(2676));
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
|
||||||
|
DROP TABLE test_prefix_key_len;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- CREATE_INDEX and USE INDEX
|
||||||
|
--
|
||||||
|
CREATE TABLE test_prefix_table (
|
||||||
|
id INTEGER,
|
||||||
|
fchar CHAR(64),
|
||||||
|
fvchar VARCHAR(64),
|
||||||
|
ftext TEXT,
|
||||||
|
fclob CLOB,
|
||||||
|
fblob BLOB,
|
||||||
|
fraw RAW,
|
||||||
|
fbytea BYTEA
|
||||||
|
) ;
|
||||||
|
INSERT INTO test_prefix_table VALUES(0, NULL, NULL, NULL, NULL , NULL, NULL, NULL);
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'ZZZZZ-123', 'ZZZZZ-123', 'ZZZZZ-123', 'ZZZZZ-123', '5A5A5A5A5A2D313233', HEXTORAW('5A5A5A5A5A2D313233'),E'\\x5A5A5A5A5A2D313233');
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'ZZZZZ-300', 'ZZZZZ-300', 'ZZZZZ-300', 'ZZZZZ-300', '5A5A5A5A5A2D333030', HEXTORAW('5A5A5A5A5A2D333030'),E'\\x5A5A5A5A5A2D333030');
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'ZZZZZ-000', 'ZZZZZ-000', 'ZZZZZ-000', 'ZZZZZ-000', '5A5A5A5A5A2D303030', HEXTORAW('5A5A5A5A5A2D303030'),E'\\x5A5A5A5A5A2D303030');
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'ZZZZZ-211', 'ZZZZZ-211', 'ZZZZZ-211', 'ZZZZZ-211', '5A5A5A5A5A2D323131', HEXTORAW('5A5A5A5A5A2D323131'),E'\\x5A5A5A5A5A2D323131');
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'ZZZZZ-111', 'ZZZZZ-111', 'ZZZZZ-111', 'ZZZZZ-111', '5A5A5A5A5A2D313131', HEXTORAW('5A5A5A5A5A2D313131'),E'\\x5A5A5A5A5A2D313131');
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'ZZZZZ-210', 'ZZZZZ-210', 'ZZZZZ-210', 'ZZZZZ-210', '5A5A5A5A5A2D323130', HEXTORAW('5A5A5A5A5A2D323130'),E'\\x5A5A5A5A5A2D323130');
|
||||||
|
INSERT INTO test_prefix_table VALUES(30, 'Z', 'Z', 'Z', 'Z', '5A', HEXTORAW('5A'),E'\\x5A');
|
||||||
|
INSERT INTO test_prefix_table VALUES(0, NULL, NULL, NULL, NULL , NULL, NULL, NULL);
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, 'YYYYY-300', 'YYYYY-300', 'YYYYY-300', 'YYYYY-300', '59595959592D333030', HEXTORAW('59595959592D333030'),E'\\x59595959592D333030');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, 'YYYYY-000', 'YYYYY-000', 'YYYYY-000', 'YYYYY-000', '59595959592D303030', HEXTORAW('59595959592D303030'),E'\\x59595959592D303030');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, 'YYYYY-211', 'YYYYY-211', 'YYYYY-211', 'YYYYY-211', '59595959592D323131', HEXTORAW('59595959592D323131'),E'\\x59595959592D323131');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, 'YYYYY-111', 'YYYYY-111', 'YYYYY-111', 'YYYYY-111', '59595959592D313131', HEXTORAW('59595959592D313131'),E'\\x59595959592D313131');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, 'YYYYY-210', 'YYYYY-210', 'YYYYY-210', 'YYYYY-210', '59595959592D323130', HEXTORAW('59595959592D323130'),E'\\x59595959592D323130');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, 'Y', 'Y', 'Y', 'Y', '59', HEXTORAW('59'),E'\\x59');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, '高斯数据库-210', '高斯数据库-210', '高斯数据库-210', '高斯数据库-210', 'e9ab98e696afe695b0e68daee5ba932d323130', HEXTORAW('e9ab98e696afe695b0e68daee5ba932d323130'),E'\\xe9ab98e696afe695b0e68daee5ba932d323130');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, '开源数据库-210', '开源数据库-210', '开源数据库-210', '开源数据库-210', 'e5bc80e6ba90e695b0e68daee5ba932d323130', HEXTORAW('e5bc80e6ba90e695b0e68daee5ba932d323130'),E'\\xe5bc80e6ba90e695b0e68daee5ba932d323130');
|
||||||
|
INSERT INTO test_prefix_table VALUES(20, '高', '高', '高', '高', 'e9ab98', HEXTORAW('e9ab98'),E'\\xe9ab98');
|
||||||
|
|
||||||
|
CREATE INDEX prefix_index_fchar_fbytea ON test_prefix_table (fchar(5), fbytea(5));
|
||||||
|
CREATE INDEX prefix_index_fvchar ON test_prefix_table (fvchar(5));
|
||||||
|
CREATE INDEX prefix_index_ftext ON test_prefix_table (ftext(5));
|
||||||
|
CREATE INDEX prefix_index_fclob ON test_prefix_table (fclob(5));
|
||||||
|
CREATE INDEX prefix_index_fblob ON test_prefix_table (fblob(5));
|
||||||
|
CREATE UNIQUE INDEX prefix_index_fraw ON test_prefix_table (fraw(9));
|
||||||
|
\d+ test_prefix_table
|
||||||
|
select pg_get_tabledef('test_prefix_table'::regclass);
|
||||||
|
|
||||||
|
set enable_seqscan=false;
|
||||||
|
set enable_opfusion=false;
|
||||||
|
set enable_partition_opfusion=false;
|
||||||
|
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'XXXXX%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
--insert
|
||||||
|
INSERT INTO test_prefix_table VALUES(0, NULL, NULL, NULL, NULL , NULL, NULL, NULL);
|
||||||
|
INSERT INTO test_prefix_table VALUES(10, 'XXXXX-300', 'XXXXX-300', 'XXXXX-300', 'XXXXX-300', '58585858582D333030', HEXTORAW('58585858582D333030'),E'\\x58585858582D333030');
|
||||||
|
INSERT INTO test_prefix_table VALUES(10, 'XXXXX-000', 'XXXXX-000', 'XXXXX-000', 'XXXXX-000', '58585858582D303030', HEXTORAW('58585858582D303030'),E'\\x58585858582D303030');
|
||||||
|
INSERT INTO test_prefix_table VALUES(10, 'XXXXX-211', 'XXXXX-211', 'XXXXX-211', 'XXXXX-211', '58585858582D323131', HEXTORAW('58585858582D323131'),E'\\x58585858582D323131');
|
||||||
|
INSERT INTO test_prefix_table VALUES(10, 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', '58585858582D313131', HEXTORAW('58585858582D313131'),E'\\x58585858582D313131');
|
||||||
|
INSERT INTO test_prefix_table VALUES(10, 'XXXXX-210', 'XXXXX-210', 'XXXXX-210', 'XXXXX-210', '58585858582D323130', HEXTORAW('58585858582D323130'),E'\\x58585858582D323130');
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'XXXXX%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
|
||||||
|
--update
|
||||||
|
UPDATE test_prefix_table SET fchar=replace(fchar, 'XXXXX', 'AAAAA'), ftext=replace(ftext, 'XXXXX', 'AAAAA') where fvchar like 'XXXXX%';
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'AAAAA%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
|
||||||
|
--delete
|
||||||
|
DELETE FROM test_prefix_table where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211');
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'AAAAA%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
|
||||||
|
--check query plan
|
||||||
|
analyze test_prefix_table;
|
||||||
|
--single table index scan
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYY%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYY%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYYY%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYYY%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-1%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-1%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like '开%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like '开%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like '开源数据库%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like '开源数据库%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like '开源数据库-2%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext like '开源数据库-2%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext = '开源数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext = '开源数据库-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext > '开' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext > '开' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext > '开源数据库' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext > '开源数据库' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext > '开源数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext > '开源数据库-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext < '开' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext < '开' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext < '开源数据库' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext < '开源数据库' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext < '开源数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext < '开源数据库-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YY%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YY%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY-111' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY-111' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like '高%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like '高%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like '高斯数据库-%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea like '高斯数据库-%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库-210' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea > 'Y' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea > 'Y' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY-210' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea < 'Y' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea < 'Y' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY-210' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fchar FROM test_prefix_table where fchar ~ '^开' ORDER BY 1;
|
||||||
|
SELECT fchar FROM test_prefix_table where fchar ~ '^开' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY-100' ORDER BY 1;
|
||||||
|
SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY-100' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY' ORDER BY 1;
|
||||||
|
SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fclob FROM test_prefix_table t where fclob < 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT fclob FROM test_prefix_table t where fclob < 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fclob FROM test_prefix_table t where fclob < 'Z' ORDER BY 1;
|
||||||
|
SELECT fclob FROM test_prefix_table t where fclob < 'Z' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fblob FROM test_prefix_table t where fblob IS NOT NULL ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_table t where fblob IS NOT NULL ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT DISTINCT fraw FROM test_prefix_table t where fraw IS NOT NULL ORDER BY 1;
|
||||||
|
SELECT DISTINCT fraw FROM test_prefix_table t where fraw IS NOT NULL ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fraw FROM test_prefix_table t where fraw IS NULL or ftext like '高%' ORDER BY 1;
|
||||||
|
SELECT fraw FROM test_prefix_table t where fraw IS NULL or ftext like '高%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_table t where fraw IS NULL or fvchar > 'ZZZZZ-200' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_table t where fraw IS NULL or fvchar > 'ZZZZZ-200' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_table t where NOT fvchar <> 'ZZZZZ-211' ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_table t where NOT fvchar <>'ZZZZZ-211' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') = false ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') = false ORDER BY 1;
|
||||||
|
PREPARE testprefixindex(text) as SELECT fvchar FROM test_prefix_table t where fraw IS NULL or fvchar > $1 and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false) execute testprefixindex('ZZZZZ-200');
|
||||||
|
EXECUTE testprefixindex('ZZZZZ-200');
|
||||||
|
--prefix index not used
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') IS false ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') IS false ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_table t where fvchar <> 'ZZZZZ-210';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT left(ftext, 5) FROM test_prefix_table where left(ftext, 5) = 'YYYYY';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table ORDER BY ftext;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
select * from test_prefix_table tab1 where (fchar, fbytea)<('YYYYY-210', E'\\x59595959592D323130');
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext not like 'YYYY%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_table where fvchar = 'YYYYY-100'::name;
|
||||||
|
|
||||||
|
|
||||||
|
set enable_bitmapscan=false;
|
||||||
|
set enable_material=false;
|
||||||
|
set enable_hashjoin=false;
|
||||||
|
set enable_mergejoin=false;
|
||||||
|
--join index scan
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext = t2.fchar ORDER BY 1,2;
|
||||||
|
SELECT t1.ftext,t2.fchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext = t2.fchar ORDER BY 1,2;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT count(1) FROM test_prefix_table t1 join test_prefix_table t2 on (t2.fvchar LIKE 'X%' AND t1.ftext > t2.fvchar);
|
||||||
|
SELECT count(1) FROM test_prefix_table t1 join test_prefix_table t2 on (t2.fvchar LIKE 'X%' AND t1.ftext > t2.fvchar);
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext = t2.fvchar where t1.id=30 and t2.id > 10 ORDER BY 1;
|
||||||
|
SELECT t1.ftext FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext = t2.fvchar where t1.id=30 and t2.id > 10 ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_table t1, test_prefix_table t2 where t1.ftext = t2.fvchar and t1.id=30 ORDER BY 1,2;
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_table t1, test_prefix_table t2 where t1.ftext = t2.fvchar and t1.id=30 ORDER BY 1,2;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.fvchar,t2.fvchar FROM test_prefix_table t1 left join test_prefix_table t2 on (t1.fvchar = t2.fvchar and t2.fvchar > 'ZZZZZ-3' ) ORDER BY 1,2;
|
||||||
|
SELECT t1.fvchar,t2.fvchar FROM test_prefix_table t1 left join test_prefix_table t2 on (t1.fvchar = t2.fvchar and t2.fvchar > 'ZZZZZ-3' ) ORDER BY 1,2;
|
||||||
|
--prefix index not used
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext like t2.fvchar;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext not like t2.fvchar;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext <> t2.fvchar;
|
||||||
|
|
||||||
|
--alter table
|
||||||
|
ALTER TABLE test_prefix_table MODIFY ftext varchar(64);
|
||||||
|
ALTER TABLE test_prefix_table ALTER COLUMN ftext TYPE text;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
DELETE FROM test_prefix_table WHERE ftext IS NULL;
|
||||||
|
DELETE FROM test_prefix_table WHERE ftext IS NULL;
|
||||||
|
ALTER TABLE test_prefix_table ALTER COLUMN ftext SET NOT NULL;
|
||||||
|
ALTER TABLE test_prefix_table ALTER COLUMN ftext DROP NOT NULL;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext = '高斯数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext = '高斯数据库-210' ORDER BY 1;
|
||||||
|
|
||||||
|
CREATE SCHEMA prefix_index_schema;
|
||||||
|
ALTER TABLE test_prefix_table SET SCHEMA prefix_index_schema;
|
||||||
|
set current_schema = prefix_index_schema;
|
||||||
|
set enable_seqscan=false;
|
||||||
|
set enable_opfusion=false;
|
||||||
|
set enable_partition_opfusion=false;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext >= '高斯数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_table where ftext >= '高斯数据库-210' ORDER BY 1;
|
||||||
|
|
||||||
|
ALTER TABLE test_prefix_table RENAME TO test_prefix_tb;
|
||||||
|
ALTER TABLE test_prefix_tb RENAME COLUMN fchar TO fbpchar;
|
||||||
|
ALTER TABLE test_prefix_tb DROP ftext;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbpchar FROM test_prefix_tb where fbpchar > '开源' ORDER BY 1;
|
||||||
|
SELECT fbpchar FROM test_prefix_tb where fbpchar > '开源' ORDER BY 1;
|
||||||
|
ALTER INDEX prefix_index_fchar_fbytea UNUSABLE;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbpchar FROM test_prefix_tb where fbpchar like '高斯数据库-%' ORDER BY 1;
|
||||||
|
|
||||||
|
RESET enable_seqscan;
|
||||||
|
RESET enable_opfusion;
|
||||||
|
RESET enable_partition_opfusion;
|
||||||
|
DROP TABLE IF EXISTS test_prefix_tb;
|
||||||
|
RESET current_schema;
|
||||||
|
DROP SCHEMA prefix_index_schema CASCADE;
|
||||||
|
|
||||||
|
RESET enable_bitmapscan;
|
||||||
|
RESET enable_material;
|
||||||
|
RESET enable_hashjoin;
|
||||||
|
RESET enable_mergejoin;
|
||||||
|
RESET enable_seqscan;
|
||||||
|
RESET enable_opfusion;
|
||||||
|
RESET enable_partition_opfusion;
|
||||||
|
|
||||||
|
--partition table
|
||||||
|
CREATE TABLE test_prefix_parttable (
|
||||||
|
id INTEGER,
|
||||||
|
fchar CHAR(64),
|
||||||
|
fvchar VARCHAR(64),
|
||||||
|
ftext TEXT,
|
||||||
|
fclob CLOB,
|
||||||
|
fblob BLOB,
|
||||||
|
fraw RAW,
|
||||||
|
fbytea BYTEA
|
||||||
|
) PARTITION BY RANGE (ftext) SUBPARTITION BY LIST (fvchar)
|
||||||
|
(
|
||||||
|
PARTITION p_xxxxx VALUES LESS THAN( 'YYYYY' )
|
||||||
|
(
|
||||||
|
SUBPARTITION p_xxxxx_1 values ('XXXXX-111'),
|
||||||
|
SUBPARTITION p_xxxxx_2 values ('XXXXX-211'),
|
||||||
|
SUBPARTITION p_xxxxx_3 values ('XXXXX-300'),
|
||||||
|
SUBPARTITION p_xxxxx_4 values ('高斯数据库-210')
|
||||||
|
),
|
||||||
|
PARTITION p_yyyyy VALUES LESS THAN( 'ZZZZZ' )
|
||||||
|
(
|
||||||
|
SUBPARTITION p_yyyyy_1 values ('YYYYY-111'),
|
||||||
|
SUBPARTITION p_yyyyy_2 values ('YYYYY-211'),
|
||||||
|
SUBPARTITION p_yyyyy_3 values ('YYYYY-300'),
|
||||||
|
SUBPARTITION p_yyyyy_4 values ('高斯数据库-210')
|
||||||
|
),
|
||||||
|
PARTITION p_zzzzz VALUES LESS THAN( MAXVALUE )
|
||||||
|
(
|
||||||
|
SUBPARTITION p_zzzzz_1 values ('ZZZZZ-111'),
|
||||||
|
SUBPARTITION p_zzzzz_2 values ('ZZZZZ-211'),
|
||||||
|
SUBPARTITION p_zzzzz_3 values ('ZZZZZ-300'),
|
||||||
|
SUBPARTITION p_zzzzz_4 values ('高斯数据库-210')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(30, 'ZZZZZ-300', 'ZZZZZ-300', 'ZZZZZ-300', 'ZZZZZ-300', '5A5A5A5A5A2D333030', HEXTORAW('5A5A5A5A5A2D333030'),E'\\x5A5A5A5A5A2D333030');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(30, 'ZZZZZ-211', 'ZZZZZ-211', 'ZZZZZ-211', 'ZZZZZ-211', '5A5A5A5A5A2D323131', HEXTORAW('5A5A5A5A5A2D323131'),E'\\x5A5A5A5A5A2D323131');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(30, 'ZZZZZ-111', 'ZZZZZ-111', 'ZZZZZ-111', 'ZZZZZ-111', '5A5A5A5A5A2D313131', HEXTORAW('5A5A5A5A5A2D313131'),E'\\x5A5A5A5A5A2D313131');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(20, 'YYYYY-300', 'YYYYY-300', 'YYYYY-300', 'YYYYY-300', '59595959592D333030', HEXTORAW('59595959592D333030'),E'\\x59595959592D333030');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(20, 'YYYYY-211', 'YYYYY-211', 'YYYYY-211', 'YYYYY-211', '59595959592D323131', HEXTORAW('59595959592D323131'),E'\\x59595959592D323131');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(20, 'YYYYY-111', 'YYYYY-111', 'YYYYY-111', 'YYYYY-111', '59595959592D313131', HEXTORAW('59595959592D313131'),E'\\x59595959592D313131');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(20, '高斯数据库-210', '高斯数据库-210', '高斯数据库-210', '高斯数据库-210', 'e9ab98e696afe695b0e68daee5ba932d323130', HEXTORAW('e9ab98e696afe695b0e68daee5ba932d323130'),E'\\xe9ab98e696afe695b0e68daee5ba932d323130');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(10, 'XXXXX-300', 'XXXXX-300', 'XXXXX-300', 'XXXXX-300', '58585858582D333030', HEXTORAW('58585858582D333030'),E'\\x58585858582D333030');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(10, 'XXXXX-211', 'XXXXX-211', 'XXXXX-211', 'XXXXX-211', '58585858582D323131', HEXTORAW('58585858582D323131'),E'\\x58585858582D323131');
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(10, 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', '58585858582D313131', HEXTORAW('58585858582D313131'),E'\\x58585858582D313131');
|
||||||
|
--global index not support
|
||||||
|
CREATE INDEX error_index_ftext_global ON test_prefix_parttable(ftext(5)) GLOBAL;
|
||||||
|
--local index
|
||||||
|
CREATE INDEX prefix_index_ftext_part ON test_prefix_parttable(ftext(5)) LOCAL
|
||||||
|
(
|
||||||
|
PARTITION prefix_index_ftext_part1 (SUBPARTITION prefix_index_ftext_subpart11, SUBPARTITION prefix_index_ftext_subpart12,SUBPARTITION prefix_index_ftext_subpart13, SUBPARTITION prefix_index_ftext_subpart14),
|
||||||
|
PARTITION prefix_index_ftext_part2 (SUBPARTITION prefix_index_ftext_subpart21, SUBPARTITION prefix_index_ftext_subpart22,SUBPARTITION prefix_index_ftext_subpart23, SUBPARTITION prefix_index_ftext_subpart24),
|
||||||
|
PARTITION prefix_index_ftext_part3 (SUBPARTITION prefix_index_ftext_subpart31, SUBPARTITION prefix_index_ftext_subpart32,SUBPARTITION prefix_index_ftext_subpart33, SUBPARTITION prefix_index_ftext_subpart34)
|
||||||
|
);
|
||||||
|
set enable_seqscan=false;
|
||||||
|
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_parttable where ftext like '高斯%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_parttable where ftext like '高斯%' ORDER BY 1;
|
||||||
|
|
||||||
|
--unique
|
||||||
|
CREATE UNIQUE INDEX prefix_index_ftext_part_unique ON test_prefix_parttable(ftext, fvchar, fbytea(5)) LOCAL;
|
||||||
|
INSERT INTO test_prefix_parttable VALUES(10, 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', '58585858582D313131', HEXTORAW('58585858582D313131'),E'\\x58585858582D313131');
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_parttable t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_parttable t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
|
||||||
|
|
||||||
|
RESET enable_seqscan;
|
||||||
|
DROP TABLE IF EXISTS test_prefix_parttable;
|
||||||
|
|
||||||
|
--ustore
|
||||||
|
CREATE TABLE test_prefix_ustore(
|
||||||
|
id INTEGER,
|
||||||
|
fchar CHAR(64),
|
||||||
|
fvchar VARCHAR(64),
|
||||||
|
ftext TEXT,
|
||||||
|
fclob CLOB,
|
||||||
|
fblob BLOB,
|
||||||
|
fraw RAW,
|
||||||
|
fbytea BYTEA
|
||||||
|
) WITH (STORAGE_TYPE=USTORE);
|
||||||
|
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(0, NULL, NULL, NULL, NULL , NULL, NULL, NULL);
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'ZZZZZ-123', 'ZZZZZ-123', 'ZZZZZ-123', 'ZZZZZ-123', '5A5A5A5A5A2D313233', HEXTORAW('5A5A5A5A5A2D313233'),E'\\x5A5A5A5A5A2D313233');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'ZZZZZ-300', 'ZZZZZ-300', 'ZZZZZ-300', 'ZZZZZ-300', '5A5A5A5A5A2D333030', HEXTORAW('5A5A5A5A5A2D333030'),E'\\x5A5A5A5A5A2D333030');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'ZZZZZ-000', 'ZZZZZ-000', 'ZZZZZ-000', 'ZZZZZ-000', '5A5A5A5A5A2D303030', HEXTORAW('5A5A5A5A5A2D303030'),E'\\x5A5A5A5A5A2D303030');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'ZZZZZ-211', 'ZZZZZ-211', 'ZZZZZ-211', 'ZZZZZ-211', '5A5A5A5A5A2D323131', HEXTORAW('5A5A5A5A5A2D323131'),E'\\x5A5A5A5A5A2D323131');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'ZZZZZ-111', 'ZZZZZ-111', 'ZZZZZ-111', 'ZZZZZ-111', '5A5A5A5A5A2D313131', HEXTORAW('5A5A5A5A5A2D313131'),E'\\x5A5A5A5A5A2D313131');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'ZZZZZ-210', 'ZZZZZ-210', 'ZZZZZ-210', 'ZZZZZ-210', '5A5A5A5A5A2D323130', HEXTORAW('5A5A5A5A5A2D323130'),E'\\x5A5A5A5A5A2D323130');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(30, 'Z', 'Z', 'Z', 'Z', '5A', HEXTORAW('5A'),E'\\x5A');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(0, NULL, NULL, NULL, NULL , NULL, NULL, NULL);
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, 'YYYYY-300', 'YYYYY-300', 'YYYYY-300', 'YYYYY-300', '59595959592D333030', HEXTORAW('59595959592D333030'),E'\\x59595959592D333030');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, 'YYYYY-000', 'YYYYY-000', 'YYYYY-000', 'YYYYY-000', '59595959592D303030', HEXTORAW('59595959592D303030'),E'\\x59595959592D303030');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, 'YYYYY-211', 'YYYYY-211', 'YYYYY-211', 'YYYYY-211', '59595959592D323131', HEXTORAW('59595959592D323131'),E'\\x59595959592D323131');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, 'YYYYY-111', 'YYYYY-111', 'YYYYY-111', 'YYYYY-111', '59595959592D313131', HEXTORAW('59595959592D313131'),E'\\x59595959592D313131');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, 'YYYYY-210', 'YYYYY-210', 'YYYYY-210', 'YYYYY-210', '59595959592D323130', HEXTORAW('59595959592D323130'),E'\\x59595959592D323130');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, 'Y', 'Y', 'Y', 'Y', '59', HEXTORAW('59'),E'\\x59');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, '高斯数据库-210', '高斯数据库-210', '高斯数据库-210', '高斯数据库-210', 'e9ab98e696afe695b0e68daee5ba932d323130', HEXTORAW('e9ab98e696afe695b0e68daee5ba932d323130'),E'\\xe9ab98e696afe695b0e68daee5ba932d323130');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, '开源数据库-210', '开源数据库-210', '开源数据库-210', '开源数据库-210', 'e5bc80e6ba90e695b0e68daee5ba932d323130', HEXTORAW('e5bc80e6ba90e695b0e68daee5ba932d323130'),E'\\xe5bc80e6ba90e695b0e68daee5ba932d323130');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(20, '高', '高', '高', '高', 'e9ab98', HEXTORAW('e9ab98'),E'\\xe9ab98');
|
||||||
|
--err
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_ustore (fchar(0));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_ustore (fchar(-1));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_ustore (fchar(1+1));
|
||||||
|
CREATE INDEX error_index_fvchar ON test_prefix_ustore (fvchar(80));
|
||||||
|
CREATE INDEX error_index_ftext ON test_prefix_ustore (ftext(4096));
|
||||||
|
CREATE INDEX error_index_id ON test_prefix_ustore (id(5));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_ustore using hash (fchar(5));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_ustore using gin (fchar(5));
|
||||||
|
CREATE INDEX error_index_fchar ON test_prefix_ustore using gist (fchar(5));
|
||||||
|
--success
|
||||||
|
CREATE INDEX prefix_index_fchar_fbytea ON test_prefix_ustore (fchar(5), fbytea(5));
|
||||||
|
CREATE INDEX prefix_index_fvchar ON test_prefix_ustore (fvchar(5));
|
||||||
|
CREATE INDEX prefix_index_ftext ON test_prefix_ustore (ftext(5));
|
||||||
|
CREATE INDEX prefix_index_fblob ON test_prefix_ustore (fblob(5));
|
||||||
|
CREATE UNIQUE INDEX prefix_index_fraw ON test_prefix_ustore (fraw(9));
|
||||||
|
\d+ test_prefix_ustore
|
||||||
|
select pg_get_tabledef('test_prefix_ustore'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
set enable_seqscan=false;
|
||||||
|
set enable_opfusion=false;
|
||||||
|
set enable_partition_opfusion=false;
|
||||||
|
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext like 'XXXXX%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
--insert
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(0, NULL, NULL, NULL, NULL , NULL, NULL, NULL);
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(10, 'XXXXX-300', 'XXXXX-300', 'XXXXX-300', 'XXXXX-300', '58585858582D333030', HEXTORAW('58585858582D333030'),E'\\x58585858582D333030');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(10, 'XXXXX-000', 'XXXXX-000', 'XXXXX-000', 'XXXXX-000', '58585858582D303030', HEXTORAW('58585858582D303030'),E'\\x58585858582D303030');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(10, 'XXXXX-211', 'XXXXX-211', 'XXXXX-211', 'XXXXX-211', '58585858582D323131', HEXTORAW('58585858582D323131'),E'\\x58585858582D323131');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(10, 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', 'XXXXX-111', '58585858582D313131', HEXTORAW('58585858582D313131'),E'\\x58585858582D313131');
|
||||||
|
INSERT INTO test_prefix_ustore VALUES(10, 'XXXXX-210', 'XXXXX-210', 'XXXXX-210', 'XXXXX-210', '58585858582D323130', HEXTORAW('58585858582D323130'),E'\\x58585858582D323130');
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext like 'XXXXX%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
|
||||||
|
--update
|
||||||
|
UPDATE test_prefix_ustore SET fchar=replace(fchar, 'XXXXX', 'AAAAA'), ftext=replace(ftext, 'XXXXX', 'AAAAA') where fvchar like 'XXXXX%';
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext like 'AAAAA%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
|
||||||
|
--delete
|
||||||
|
DELETE FROM test_prefix_ustore where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211');
|
||||||
|
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext like 'AAAAA%' ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
|
||||||
|
SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
|
||||||
|
|
||||||
|
--check query plan
|
||||||
|
analyze test_prefix_ustore;
|
||||||
|
--single table index scan
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext like 'YYYY%' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext like 'YYYY%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext like '开源数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext like '开源数据库-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fchar FROM test_prefix_ustore t where fchar ~~ '高斯数据库' ORDER BY 1;
|
||||||
|
SELECT fchar FROM test_prefix_ustore t where fchar ~~ '高斯数据库' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fchar FROM test_prefix_ustore t where fchar ~ '^开' ORDER BY 1;
|
||||||
|
SELECT fchar FROM test_prefix_ustore t where fchar ~ '^开' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea like '高%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea like '高%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ '开源数据库%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ '开源数据库%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY-100' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY-100' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fvchar < 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fvchar < 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fvchar < 'Z' ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fvchar < 'Z' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59' ORDER BY 1;
|
||||||
|
SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fblob FROM test_prefix_ustore t where fblob IS NOT NULL ORDER BY 1;
|
||||||
|
SELECT fblob FROM test_prefix_ustore t where fblob IS NOT NULL ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT DISTINCT fraw FROM test_prefix_ustore t where fraw IS NOT NULL ORDER BY 1;
|
||||||
|
SELECT DISTINCT fraw FROM test_prefix_ustore t where fraw IS NOT NULL ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fraw FROM test_prefix_ustore t where fraw IS NULL or ftext like '高%' ORDER BY 1;
|
||||||
|
SELECT fraw FROM test_prefix_ustore t where fraw IS NULL or ftext like '高%' ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fraw IS NULL or fvchar > 'ZZZZZ-200' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fraw IS NULL or fvchar > 'ZZZZZ-200' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
|
||||||
|
--prefix index not used
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fvchar FROM test_prefix_ustore t where fvchar <> 'ZZZZZ-210';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT left(ftext, 5) FROM test_prefix_ustore where left(ftext, 5) = 'YYYYY';
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore ORDER BY ftext;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
select * from test_prefix_ustore tab1 where (fchar, fbytea)<('YYYYY-210', E'\\x59595959592D323130');
|
||||||
|
|
||||||
|
set enable_bitmapscan=false;
|
||||||
|
set enable_material=false;
|
||||||
|
set enable_hashjoin=false;
|
||||||
|
set enable_mergejoin=false;
|
||||||
|
--join index scan
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fchar FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext = t2.fchar ORDER BY 1,2;
|
||||||
|
SELECT t1.ftext,t2.fchar FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext = t2.fchar ORDER BY 1,2;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT count(1) FROM test_prefix_ustore t1 join test_prefix_ustore t2 on (t2.fvchar LIKE 'X%' AND t1.ftext > t2.fvchar);
|
||||||
|
SELECT count(1) FROM test_prefix_ustore t1 join test_prefix_ustore t2 on (t2.fvchar LIKE 'X%' AND t1.ftext > t2.fvchar);
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext = t2.fvchar where t1.id=30 and t2.id > 10 ORDER BY 1;
|
||||||
|
SELECT t1.ftext FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext = t2.fvchar where t1.id=30 and t2.id > 10 ORDER BY 1;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_ustore t1, test_prefix_ustore t2 where t1.ftext = t2.fvchar and t1.id=30 ORDER BY 1,2;
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_ustore t1, test_prefix_ustore t2 where t1.ftext = t2.fvchar and t1.id=30 ORDER BY 1,2;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.fvchar,t2.fvchar FROM test_prefix_ustore t1 left join test_prefix_ustore t2 on (t1.fvchar = t2.fvchar and t2.fvchar > 'ZZZZZ-3' ) ORDER BY 1,2;
|
||||||
|
SELECT t1.fvchar,t2.fvchar FROM test_prefix_ustore t1 left join test_prefix_ustore t2 on (t1.fvchar = t2.fvchar and t2.fvchar > 'ZZZZZ-3' ) ORDER BY 1,2;
|
||||||
|
--prefix index not used
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext like t2.fvchar;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT t1.ftext,t2.fvchar FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext <> t2.fvchar;
|
||||||
|
|
||||||
|
--alter table
|
||||||
|
ALTER TABLE test_prefix_ustore MODIFY ftext varchar(64);
|
||||||
|
ALTER TABLE test_prefix_ustore ALTER COLUMN ftext TYPE text;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
DELETE FROM test_prefix_ustore WHERE ftext IS NULL;
|
||||||
|
DELETE FROM test_prefix_ustore WHERE ftext IS NULL;
|
||||||
|
ALTER TABLE test_prefix_ustore ALTER COLUMN ftext SET NOT NULL;
|
||||||
|
ALTER TABLE test_prefix_ustore ALTER COLUMN ftext DROP NOT NULL;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext = '高斯数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext = '高斯数据库-210' ORDER BY 1;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE SCHEMA prefix_index_schema;
|
||||||
|
ALTER TABLE test_prefix_ustore SET SCHEMA prefix_index_schema;
|
||||||
|
set current_schema = prefix_index_schema;
|
||||||
|
set enable_seqscan=false;
|
||||||
|
set enable_opfusion=false;
|
||||||
|
set enable_partition_opfusion=false;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext >= '高斯数据库-210' ORDER BY 1;
|
||||||
|
SELECT ftext FROM test_prefix_ustore where ftext >= '高斯数据库-210' ORDER BY 1;
|
||||||
|
|
||||||
|
ALTER TABLE test_prefix_ustore RENAME TO test_prefix_utb;
|
||||||
|
ALTER TABLE test_prefix_utb RENAME COLUMN fchar TO fbpchar;
|
||||||
|
ALTER TABLE test_prefix_utb DROP ftext;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbpchar FROM test_prefix_utb where fbpchar > '开源' ORDER BY 1;
|
||||||
|
SELECT fbpchar FROM test_prefix_utb where fbpchar > '开源' ORDER BY 1;
|
||||||
|
ALTER INDEX prefix_index_fchar_fbytea UNUSABLE;
|
||||||
|
EXPLAIN (costs false)
|
||||||
|
SELECT fbpchar FROM test_prefix_utb where fbpchar like '高斯数据库-%' ORDER BY 1;
|
||||||
|
|
||||||
|
RESET enable_seqscan;
|
||||||
|
RESET enable_opfusion;
|
||||||
|
RESET enable_partition_opfusion;
|
||||||
|
DROP TABLE IF EXISTS test_prefix_utb;
|
||||||
|
RESET current_schema;
|
||||||
|
DROP SCHEMA prefix_index_schema CASCADE;
|
||||||
|
|
||||||
|
RESET enable_bitmapscan;
|
||||||
|
RESET enable_material;
|
||||||
|
RESET enable_hashjoin;
|
||||||
|
RESET enable_mergejoin;
|
||||||
|
RESET enable_seqscan;
|
||||||
|
RESET enable_opfusion;
|
||||||
|
RESET enable_partition_opfusion;
|
||||||
|
|
||||||
|
--cstore not support
|
||||||
|
DROP TABLE IF EXISTS test_prefix_cstore;
|
||||||
|
CREATE TABLE test_prefix_cstore(
|
||||||
|
id INTEGER,
|
||||||
|
fchar CHAR(64),
|
||||||
|
fvchar VARCHAR(64),
|
||||||
|
ftext TEXT,
|
||||||
|
fclob CLOB,
|
||||||
|
fbytea BYTEA
|
||||||
|
) WITH (ORIENTATION=column, COMPRESSION=high, COMPRESSLEVEL=2);
|
||||||
|
|
||||||
|
CREATE INDEX prefix_cindex_fchar_fbytea ON test_prefix_cstore using btree (fchar(5), fbytea(5));
|
||||||
|
CREATE INDEX prefix_cindex_ftext ON test_prefix_cstore (ftext(5));
|
||||||
|
DROP TABLE IF EXISTS test_prefix_cstore;
|
||||||
|
|
||||||
|
\c regression
|
||||||
|
drop database prefix_index_db;
|
Loading…
Reference in New Issue