支持前缀索引

Offering: GaussDB Kernel

More detail:
1、支持前缀索引创建
2、支持前缀索引匹配
This commit is contained in:
li-judong 2022-04-09 11:38:05 +08:00
parent 5e987cdd3a
commit 056317bad3
28 changed files with 4564 additions and 49 deletions

View File

@ -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>

View File

@ -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
*/

View File

@ -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,

View File

@ -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))));

View File

@ -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"},

View File

@ -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
*/

View File

@ -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)) {

View File

@ -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;

View File

@ -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:
/*

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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));

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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));

View File

@ -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);
}

View File

@ -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,

View File

@ -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),

View File

@ -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$$;

View File

@ -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$$;

View File

@ -250,6 +250,7 @@ typedef enum NodeTag {
T_EstSPNode,
T_Rownum,
T_PseudoTargetEntry,
T_PrefixKey,
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)

View File

@ -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
*

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;