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>
|
||||
<synopsis>
|
||||
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 ) }[, ...] ) ]
|
||||
[ WITH ( {storage_parameter = value} [, ... ] ) ]
|
||||
[ TABLESPACE tablespace_name ]
|
||||
|
@ -24,6 +24,7 @@ CREATE [ UNIQUE ] INDEX [ [schema_name.] index_name ] ON table_name [ USING meth
|
|||
[ TABLESPACE tablespace_name ];
|
||||
|
||||
NOTICE: 'SUBPARTITION index_subpartition_name' is only avaliable in CENTRALIZED mode!
|
||||
NOTICE: 'column_name ( length )' is only avaliable in B-format database!
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
</refentry>
|
||||
|
|
|
@ -6784,6 +6784,16 @@ static SubPartitionPruningResult *_copySubPartitionPruningResult(const SubPartit
|
|||
return newnode;
|
||||
}
|
||||
|
||||
static PrefixKey* _copyPrefixKey(const PrefixKey* from)
|
||||
{
|
||||
PrefixKey* newnode = makeNode(PrefixKey);
|
||||
|
||||
COPY_NODE_FIELD(arg);
|
||||
COPY_SCALAR_FIELD(length);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* copyObject
|
||||
*
|
||||
|
@ -7257,6 +7267,9 @@ void* copyObject(const void* from)
|
|||
case T_MergeAction:
|
||||
retval = _copyMergeAction((MergeAction*)from);
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
retval = _copyPrefixKey((PrefixKey*)from);
|
||||
break;
|
||||
/*
|
||||
* RELATION NODES
|
||||
*/
|
||||
|
|
|
@ -3248,6 +3248,13 @@ static bool _equalShutDown(const ShutdownStmt* a, const ShutdownStmt* b)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool _equalPrefixKey(const PrefixKey* a, const PrefixKey* b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(arg);
|
||||
COMPARE_SCALAR_FIELD(length);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* equal
|
||||
* returns whether two nodes are equal
|
||||
|
@ -4121,6 +4128,9 @@ bool equal(const void* a, const void* b)
|
|||
case T_DropSubscriptionStmt:
|
||||
retval = _equalDropSubscriptionStmt((DropSubscriptionStmt *)a, (DropSubscriptionStmt *)b);
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
retval = _equalPrefixKey((PrefixKey *)a, (PrefixKey *)b);
|
||||
break;
|
||||
|
||||
default:
|
||||
ereport(ERROR,
|
||||
|
|
|
@ -228,6 +228,9 @@ Oid exprType(const Node* expr)
|
|||
type = INT8OID;
|
||||
}
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
type = exprType((Node*)((PrefixKey*)expr)->arg);
|
||||
break;
|
||||
default:
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
case T_PlaceHolderVar:
|
||||
return exprTypmod((Node*)((const PlaceHolderVar*)expr)->phexpr);
|
||||
case T_PrefixKey:
|
||||
return exprTypmod((Node*)((const PrefixKey*)expr)->arg);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -846,6 +851,9 @@ Oid exprCollation(const Node* expr)
|
|||
case T_PlaceHolderVar:
|
||||
coll = exprCollation((Node*)((const PlaceHolderVar*)expr)->phexpr);
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
coll = exprCollation((Node*)((const PrefixKey*)expr)->arg);
|
||||
break;
|
||||
default:
|
||||
ereport(
|
||||
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:
|
||||
Assert(!OidIsValid(collation)); /* result is always boolean */
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
return exprSetCollation((Node*)((const PrefixKey*)expr)->arg, collation);
|
||||
default:
|
||||
ereport(
|
||||
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:
|
||||
loc = ((const Rownum*)expr)->location;
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
loc = exprLocation((Node*)((const PrefixKey*)expr)->arg);
|
||||
break;
|
||||
default:
|
||||
/* for any other node type it's just unknown... */
|
||||
loc = -1;
|
||||
|
@ -1876,6 +1889,8 @@ bool expression_tree_walker(Node* node, bool (*walker)(), void* context)
|
|||
} break;
|
||||
case T_PlaceHolderInfo:
|
||||
return p2walker(((PlaceHolderInfo*)node)->ph_var, context);
|
||||
case T_PrefixKey:
|
||||
return p2walker(((PrefixKey*)node)->arg, context);
|
||||
default:
|
||||
ereport(
|
||||
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*);
|
||||
return (Node*)newnode;
|
||||
} 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:
|
||||
ereport(ERROR,
|
||||
(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_FromExpr, "FromExpr"},
|
||||
{T_IntoClause, "IntoClause"},
|
||||
{T_PrefixKey, "PrefixKey"},
|
||||
{T_DistributeBy, "DistributeBy"},
|
||||
{T_PGXCSubCluster, "PGXCSubCluster"},
|
||||
{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 -
|
||||
* 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:
|
||||
_outDfsPrivateItem(str, (DfsPrivateItem*)obj);
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
_outPrefixKey(str, (PrefixKey*)obj);
|
||||
break;
|
||||
/*
|
||||
* Vector Nodes
|
||||
*/
|
||||
|
|
|
@ -5754,6 +5754,16 @@ static TdigestData* _readTdigestData()
|
|||
READ_DONE();
|
||||
}
|
||||
|
||||
static PrefixKey* _readPrefixKey()
|
||||
{
|
||||
READ_LOCALS(PrefixKey);
|
||||
|
||||
READ_NODE_FIELD(arg);
|
||||
READ_INT_FIELD(length);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
static UserSetElem* _readUserSetElem()
|
||||
{
|
||||
READ_LOCALS(UserSetElem);
|
||||
|
@ -6233,6 +6243,8 @@ Node* parseNodeString(void)
|
|||
return_value = _readPLDebug_frame();
|
||||
} else if (MATCH("TdigestData", 11)) {
|
||||
return_value = _readTdigestData();
|
||||
} else if (MATCH("PREFIXKEY", 9)) {
|
||||
return_value = _readPrefixKey();
|
||||
} else if (MATCH("USERSETELEM", 11)) {
|
||||
return_value = _readUserSetElem();
|
||||
} else if (MATCH("USERVAR", 7)) {
|
||||
|
|
|
@ -630,7 +630,7 @@ static int errstate;
|
|||
%type <node> var_value zone_value
|
||||
|
||||
%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 <ival> excluding_option_list TableLikeOptionList TableLikeIncludingOption TableLikeExcludingOption
|
||||
|
@ -656,7 +656,7 @@ static int errstate;
|
|||
%type <ival> document_or_content
|
||||
%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> common_table_expr
|
||||
%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;
|
||||
$$->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);
|
||||
$$->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; }
|
||||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
@ -22481,12 +22529,12 @@ func_expr: func_application within_group_clause over_clause
|
|||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
func_application: func_name '(' ')'
|
||||
func_application: func_name '(' func_arg_list opt_sort_clause ')'
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->args = $3;
|
||||
n->agg_order = $4;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
|
@ -22495,12 +22543,15 @@ func_application: func_name '(' ')'
|
|||
n->call_func = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| func_name '(' func_arg_list opt_sort_clause ')'
|
||||
| func_application_special { $$ = $1; }
|
||||
;
|
||||
|
||||
func_application_special: func_name '(' ')'
|
||||
{
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
n->funcname = $1;
|
||||
n->args = $3;
|
||||
n->agg_order = $4;
|
||||
n->args = NIL;
|
||||
n->agg_order = NIL;
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
n->func_variadic = FALSE;
|
||||
|
@ -24899,6 +24950,9 @@ unreserved_keyword:
|
|||
* The type names appearing here are not usable as function names
|
||||
* because they can be followed by '(' in typename productions, which
|
||||
* 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:
|
||||
BETWEEN
|
||||
|
@ -24966,6 +25020,56 @@ col_name_keyword:
|
|||
| 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.
|
||||
*
|
||||
* 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_SetToDefault:
|
||||
case T_CurrentOfExpr:
|
||||
case T_PrefixKey:
|
||||
case T_UserVar:
|
||||
|
||||
/*
|
||||
|
|
|
@ -89,9 +89,10 @@ static Node* transformConnectByRootFuncCall(ParseState* pstate, Node* funcNameVa
|
|||
static char *ColumnRefFindRelname(ParseState *pstate, const char *colname);
|
||||
static Node *transformStartWithColumnRef(ParseState *pstate, ColumnRef *cref, char **colname);
|
||||
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 INDEX_KEY_MAX_PREFIX_LENGTH (int)2676
|
||||
/*
|
||||
* transformExpr -
|
||||
* Analyze and transform expressions. Type checking and type casting is
|
||||
|
@ -311,6 +312,9 @@ Node* transformExpr(ParseState* pstate, Node* expr)
|
|||
case T_PredictByFunction:
|
||||
result = transformPredictByFunction(pstate, (PredictByFunction*) expr);
|
||||
break;
|
||||
case T_PrefixKey:
|
||||
result = transformPrefixKey(pstate, (PrefixKey*)expr);
|
||||
break;
|
||||
|
||||
/*********************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
if (expression_returns_set(ielem->expr))
|
||||
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)) {
|
||||
|
|
|
@ -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);
|
||||
if (!colno || colno == keyno + 1) {
|
||||
/* 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);
|
||||
else
|
||||
appendStringInfo(&buf, "(%s)", str);
|
||||
|
@ -9957,6 +9959,12 @@ static void get_rule_expr(Node* node, deparse_context* context, bool showimplici
|
|||
}
|
||||
} 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:
|
||||
if (context->qrw_phase)
|
||||
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
|
||||
* 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;
|
||||
switch (get_op_opfamily_strategy(sortop, index->sortopfamily[0])) {
|
||||
case BTLessStrategyNumber:
|
||||
|
@ -6697,10 +6697,10 @@ Datum btcostestimate(PG_FUNCTION_ARGS)
|
|||
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 */
|
||||
} 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 */
|
||||
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 void appendStringInfoText(StringInfo str, const text* t);
|
||||
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_overlay(bytea* t1, bytea* t2, int sp, int sl);
|
||||
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));
|
||||
}
|
||||
|
||||
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 L1; /* adjusted substring length */
|
||||
|
|
|
@ -59,7 +59,7 @@ bool open_join_children = true;
|
|||
bool will_shutdown = false;
|
||||
|
||||
/* 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 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||
|
|
|
@ -754,6 +754,12 @@ void UniqueSql::JumbleExpr(pgssJumbleState* jstate, Node* node)
|
|||
|
||||
break;
|
||||
}
|
||||
case T_PrefixKey: {
|
||||
PrefixKey* pkey = (PrefixKey*)node;
|
||||
UniqueSql::JumbleExpr(jstate, (Node*)pkey->arg);
|
||||
APP_JUMB(pkey->length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Only a warning, since we can stumble along anyway */
|
||||
elog(DEBUG1, "unrecognized node type: %d", (int)nodeTag(node));
|
||||
|
|
|
@ -51,6 +51,12 @@
|
|||
#define IndexCollMatchesExprColl(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 */
|
||||
typedef enum {
|
||||
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_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 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 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 Datum string_to_datum(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
|
||||
|
@ -2398,7 +2410,7 @@ static bool match_clause_to_indexcol(IndexOptInfo* index, int indexcol, Restrict
|
|||
} else if (index->amsearchnulls && IsA(clause, NullTest)) {
|
||||
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 false;
|
||||
} 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
|
||||
* (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)) {
|
||||
if (IndexCollMatchesExprColl(idxcollation, expr_coll) && is_indexable_operator(expr_op, opfamily, true))
|
||||
return true;
|
||||
|
@ -2422,8 +2434,8 @@ static bool match_clause_to_indexcol(IndexOptInfo* index, int indexcol, Restrict
|
|||
return false;
|
||||
}
|
||||
|
||||
if (plain_op && match_index_to_operand(rightop, indexcol, index) && !bms_is_member(index_relid, left_relids) &&
|
||||
!contain_volatile_functions(leftop)) {
|
||||
if (plain_op && match_index_to_operand(rightop, indexcol, index, true) &&
|
||||
!bms_is_member(index_relid, left_relids) && !contain_volatile_functions(leftop)) {
|
||||
if (IndexCollMatchesExprColl(idxcollation, expr_coll) && is_indexable_operator(expr_op, opfamily, false))
|
||||
return true;
|
||||
|
||||
|
@ -2849,7 +2861,7 @@ bool eclass_member_matches_indexcol(EquivalenceClass* ec, EquivalenceMember* em,
|
|||
if (!IndexCollMatchesExprColl(curCollation, ec->ec_collation))
|
||||
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)
|
||||
|
@ -2978,7 +2990,7 @@ bool relation_has_unique_index_for(
|
|||
else
|
||||
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 */
|
||||
break;
|
||||
}
|
||||
|
@ -2993,7 +3005,7 @@ bool relation_has_unique_index_for(
|
|||
Oid opr = lfirst_oid(lc2);
|
||||
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
|
@ -3039,13 +3051,14 @@ bool relation_has_unique_index_for(
|
|||
* operand: the nodetree to be compared to the index
|
||||
* indexcol: the column number of the index (counting from 0)
|
||||
* 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
|
||||
* for a collation match, if it's dealing with an operator where that matters.
|
||||
*
|
||||
* 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;
|
||||
|
||||
|
@ -3099,7 +3112,12 @@ bool match_index_to_operand(Node* operand, int indexcol, IndexOptInfo* index)
|
|||
*/
|
||||
if (indexkey && IsA(indexkey, RelabelType))
|
||||
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))
|
||||
return true;
|
||||
}
|
||||
|
@ -3405,7 +3423,8 @@ void expand_indexqual_conditions(
|
|||
* RowCompare, or NullTest
|
||||
*/
|
||||
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 */
|
||||
while (list_length(indexqualcols) < list_length(indexquals))
|
||||
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
|
||||
* 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;
|
||||
|
||||
|
@ -3520,6 +3540,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
|||
Const* patt = (Const*)rightop;
|
||||
Const* prefix = NULL;
|
||||
Pattern_Prefix_Status pstatus;
|
||||
int prefixkey_len = get_index_column_prefix_lenth(index, indexcol);
|
||||
|
||||
if (patt == 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:
|
||||
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||
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;
|
||||
|
||||
|
@ -3550,7 +3571,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
|||
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||
/* the right-hand const is type text for all of these */
|
||||
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;
|
||||
|
||||
|
@ -3560,7 +3581,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
|||
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||
/* the right-hand const is type text for all of these */
|
||||
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;
|
||||
|
||||
|
@ -3570,7 +3591,7 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
|||
if (!op_in_opfamily(expr_op, opfamily)) {
|
||||
/* the right-hand const is type text for all of these */
|
||||
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;
|
||||
|
||||
|
@ -3581,6 +3602,9 @@ static List* expand_indexqual_opclause(RestrictInfo* rinfo, Oid opfamily, Oid id
|
|||
}
|
||||
break;
|
||||
default:
|
||||
if (prefixkey_len > 0 && op_in_opfamily(expr_op, opfamily)) {
|
||||
return list_make1(rewrite_opclause_for_prefixkey(rinfo, index, opfamily, prefixkey_len));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3838,7 +3862,8 @@ Expr* adjust_rowcompare_for_index(
|
|||
* operator family; we use it to deduce the appropriate comparison
|
||||
* 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;
|
||||
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);
|
||||
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.
|
||||
*/
|
||||
|
@ -4135,3 +4181,149 @@ static Const* string_to_const(const char* str, Oid datatype)
|
|||
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/transam.h"
|
||||
#include "access/sysattr.h"
|
||||
#include "bulkload/foreignroutine.h"
|
||||
#include "catalog/pg_class.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_mutator(Node* node, PlannerInfo* root);
|
||||
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 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* order_qual_clauses(PlannerInfo* root, List* clauses);
|
||||
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 */
|
||||
|
||||
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
|
||||
* 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* opquals = NIL;
|
||||
ListCell* l = NULL;
|
||||
Bitmapset *prefixkeys = NULL;
|
||||
|
||||
/* it should be a base rel... */
|
||||
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
|
||||
* 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.
|
||||
|
@ -2602,6 +2616,10 @@ static Scan* create_indexscan_plan(
|
|||
|
||||
if (list_member_ptr(indexquals, rinfo))
|
||||
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))
|
||||
continue; /* derived from same EquivalenceClass */
|
||||
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
|
||||
* 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;
|
||||
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))
|
||||
CommuteOpExpr(op);
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
RowCompareExpr* rc = (RowCompareExpr*)clause;
|
||||
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));
|
||||
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)) {
|
||||
ScalarArrayOpExpr* saop = (ScalarArrayOpExpr*)clause;
|
||||
|
||||
/* Never need to commute... */
|
||||
/* 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)) {
|
||||
NullTest* nt = (NullTest*)clause;
|
||||
|
||||
/* 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
|
||||
ereport(ERROR,
|
||||
(errmodule(MOD_OPT),
|
||||
|
@ -5259,6 +5276,7 @@ static List* fix_indexqual_references(PlannerInfo* root, IndexPath* index_path)
|
|||
return fixed_indexquals;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fix_indexorderby_references
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
ereport(ERROR,
|
||||
(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
|
||||
* 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;
|
||||
int pos;
|
||||
|
@ -5374,6 +5392,13 @@ static Node* fix_indexqual_operand(Node* node, IndexOptInfo* index, int indexcol
|
|||
indexkey = (Node*)lfirst(indexpr_item);
|
||||
if (indexkey && IsA(indexkey, RelabelType))
|
||||
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)) {
|
||||
result = makeVar(INDEX_VAR,
|
||||
indexcol + 1,
|
||||
|
|
|
@ -5148,6 +5148,37 @@ static Datum ExecEvalCurrentOfExpr(ExprState* exprstate, ExprContext* econtext,
|
|||
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
|
||||
*
|
||||
|
@ -5859,6 +5890,19 @@ ExprState* ExecInitExpr(Expr* node, PlanState* parent)
|
|||
state = (ExprState*)rnstate;
|
||||
state->evalfunc = (ExprStateEvalFunc)ExecEvalRownum;
|
||||
} 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:
|
||||
ereport(ERROR,
|
||||
(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_Rownum,
|
||||
T_PseudoTargetEntry,
|
||||
T_PrefixKey,
|
||||
|
||||
/*
|
||||
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
|
||||
|
|
|
@ -1025,6 +1025,12 @@ typedef struct XmlExpr {
|
|||
int location; /* token location, or -1 if unknown */
|
||||
} XmlExpr;
|
||||
|
||||
typedef struct PrefixKey {
|
||||
Expr xpr;
|
||||
Expr* arg; /* should be a ColumnRef or Var */
|
||||
int length; /* prefix length */
|
||||
} PrefixKey;
|
||||
|
||||
/* ----------------
|
||||
* NullTest
|
||||
*
|
||||
|
|
|
@ -64,7 +64,7 @@ extern bool relation_has_unique_index_for(
|
|||
PlannerInfo* root, RelOptInfo* rel, List* restrictlist, List* exprlist, List* oprlist);
|
||||
extern bool eclass_member_matches_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(
|
||||
IndexOptInfo* index, List* indexclauses, List* indexclausecols, List** indexquals_p, List** indexqualcols_p);
|
||||
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 byteain(PG_FUNCTION_ARGS);
|
||||
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 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_btree_index single_node_hash_index single_node_update
|
||||
|
||||
test: prefixkey_index
|
||||
test: hash_index_001
|
||||
test: hash_index_002
|
||||
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