diff --git a/doc/src/sgml/ref/create_index.sgmlin b/doc/src/sgml/ref/create_index.sgmlin
index 35b827fed..bac3a7eb0 100644
--- a/doc/src/sgml/ref/create_index.sgmlin
+++ b/doc/src/sgml/ref/create_index.sgmlin
@@ -11,7 +11,7 @@
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!
diff --git a/src/common/backend/nodes/copyfuncs.cpp b/src/common/backend/nodes/copyfuncs.cpp
index b5c1e926d..de58cb2d1 100644
--- a/src/common/backend/nodes/copyfuncs.cpp
+++ b/src/common/backend/nodes/copyfuncs.cpp
@@ -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
*/
diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp
index 60486dfa3..29249bd46 100644
--- a/src/common/backend/nodes/equalfuncs.cpp
+++ b/src/common/backend/nodes/equalfuncs.cpp
@@ -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,
diff --git a/src/common/backend/nodes/nodeFuncs.cpp b/src/common/backend/nodes/nodeFuncs.cpp
index 0b67f0225..4eb8be944 100644
--- a/src/common/backend/nodes/nodeFuncs.cpp
+++ b/src/common/backend/nodes/nodeFuncs.cpp
@@ -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))));
diff --git a/src/common/backend/nodes/nodes.cpp b/src/common/backend/nodes/nodes.cpp
index 0124924b2..5058ca97d 100755
--- a/src/common/backend/nodes/nodes.cpp
+++ b/src/common/backend/nodes/nodes.cpp
@@ -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"},
diff --git a/src/common/backend/nodes/outfuncs.cpp b/src/common/backend/nodes/outfuncs.cpp
index 31fbfbeff..d898478f7 100755
--- a/src/common/backend/nodes/outfuncs.cpp
+++ b/src/common/backend/nodes/outfuncs.cpp
@@ -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
*/
diff --git a/src/common/backend/nodes/readfuncs.cpp b/src/common/backend/nodes/readfuncs.cpp
index 914c05703..f047dc368 100755
--- a/src/common/backend/nodes/readfuncs.cpp
+++ b/src/common/backend/nodes/readfuncs.cpp
@@ -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)) {
diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y
index f641a4a75..0a72516da 100644
--- a/src/common/backend/parser/gram.y
+++ b/src/common/backend/parser/gram.y
@@ -630,7 +630,7 @@ static int errstate;
%type var_value zone_value
%type unreserved_keyword type_func_name_keyword
-%type col_name_keyword reserved_keyword
+%type col_name_keyword reserved_keyword col_name_keyword_nonambiguous
%type TableConstraint TableLikeClause ForeignTableLikeClause
%type excluding_option_list TableLikeOptionList TableLikeIncludingOption TableLikeExcludingOption
@@ -656,7 +656,7 @@ static int errstate;
%type document_or_content
%type xml_whitespace_option
-%type func_application func_with_separator func_expr_common_subexpr
+%type func_application func_with_separator func_expr_common_subexpr index_functional_expr_key func_application_special
%type func_expr func_expr_windowless
%type common_table_expr
%type 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;
diff --git a/src/common/backend/parser/parse_collate.cpp b/src/common/backend/parser/parse_collate.cpp
index 5e9c98196..d9f712341 100644
--- a/src/common/backend/parser/parse_collate.cpp
+++ b/src/common/backend/parser/parse_collate.cpp
@@ -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:
/*
diff --git a/src/common/backend/parser/parse_expr.cpp b/src/common/backend/parser/parse_expr.cpp
index cab889cab..5797ab7e7 100644
--- a/src/common/backend/parser/parse_expr.cpp
+++ b/src/common/backend/parser/parse_expr.cpp
@@ -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;
+}
\ No newline at end of file
diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp
index 051d31622..631b5b2f4 100644
--- a/src/common/backend/parser/parse_utilcmd.cpp
+++ b/src/common/backend/parser/parse_utilcmd.cpp
@@ -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)) {
diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp
index 4b677b027..a2a9a3d50 100644
--- a/src/common/backend/utils/adt/ruleutils.cpp
+++ b/src/common/backend/utils/adt/ruleutils.cpp
@@ -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, "", (int)nodeTag(node));
diff --git a/src/common/backend/utils/adt/selfuncs.cpp b/src/common/backend/utils/adt/selfuncs.cpp
index 35c572731..d10ab8cd1 100755
--- a/src/common/backend/utils/adt/selfuncs.cpp
+++ b/src/common/backend/utils/adt/selfuncs.cpp
@@ -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);
}
diff --git a/src/common/backend/utils/adt/varlena.cpp b/src/common/backend/utils/adt/varlena.cpp
index 01c5e1897..b46090e8b 100644
--- a/src/common/backend/utils/adt/varlena.cpp
+++ b/src/common/backend/utils/adt/varlena.cpp
@@ -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 */
diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp
index 0aa4ed022..e070688af 100644
--- a/src/common/backend/utils/init/globals.cpp
+++ b/src/common/backend/utils/init/globals.cpp
@@ -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;
diff --git a/src/gausskernel/cbb/instruments/utils/unique_query.cpp b/src/gausskernel/cbb/instruments/utils/unique_query.cpp
index 0afdfed52..49f9ca5cd 100755
--- a/src/gausskernel/cbb/instruments/utils/unique_query.cpp
+++ b/src/gausskernel/cbb/instruments/utils/unique_query.cpp
@@ -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));
diff --git a/src/gausskernel/optimizer/path/indxpath.cpp b/src/gausskernel/optimizer/path/indxpath.cpp
index 2afe50bdf..752ea023f 100755
--- a/src/gausskernel/optimizer/path/indxpath.cpp
+++ b/src/gausskernel/optimizer/path/indxpath.cpp
@@ -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);
+}
+
+
+
diff --git a/src/gausskernel/optimizer/plan/createplan.cpp b/src/gausskernel/optimizer/plan/createplan.cpp
index fbd71ad57..a67e77352 100755
--- a/src/gausskernel/optimizer/plan/createplan.cpp
+++ b/src/gausskernel/optimizer/plan/createplan.cpp
@@ -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,
diff --git a/src/gausskernel/runtime/executor/execQual.cpp b/src/gausskernel/runtime/executor/execQual.cpp
index 8aef44d95..4b5752ff5 100644
--- a/src/gausskernel/runtime/executor/execQual.cpp
+++ b/src/gausskernel/runtime/executor/execQual.cpp
@@ -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),
diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_617.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_617.sql
new file mode 100644
index 000000000..0300abea7
--- /dev/null
+++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_92_617.sql
@@ -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$$;
diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_617.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_617.sql
new file mode 100644
index 000000000..0300abea7
--- /dev/null
+++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_92_617.sql
@@ -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$$;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index d0883b31c..1432c83f4 100755
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -250,6 +250,7 @@ typedef enum NodeTag {
T_EstSPNode,
T_Rownum,
T_PseudoTargetEntry,
+ T_PrefixKey,
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index c287c0a9c..1970dada2 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1025,6 +1025,12 @@ typedef struct XmlExpr {
int location; /* token location, or -1 if unknown */
} XmlExpr;
+typedef struct PrefixKey {
+ Expr xpr;
+ Expr* arg; /* should be a ColumnRef or Var */
+ int length; /* prefix length */
+} PrefixKey;
+
/* ----------------
* NullTest
*
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 5325f638a..aef306d5f 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -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);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 52b6dde09..6b94e80a8 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -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))
diff --git a/src/test/regress/expected/prefixkey_index.out b/src/test/regress/expected/prefixkey_index.out
new file mode 100644
index 000000000..3a71e0c47
--- /dev/null
+++ b/src/test/regress/expected/prefixkey_index.out
@@ -0,0 +1,3142 @@
+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));
+ERROR: index prefix key are not supported by column type integer
+LINE 1: CREATE INDEX idx_prefix_f1 ON test_prefix_datatype (f1(4));
+ ^
+CREATE INDEX idx_prefix_f2 ON test_prefix_datatype (f2(4));
+ERROR: index prefix key are not supported by column type money
+LINE 1: CREATE INDEX idx_prefix_f2 ON test_prefix_datatype (f2(4));
+ ^
+CREATE INDEX idx_prefix_f3 ON test_prefix_datatype (f3(4));
+ERROR: index prefix key are not supported by column type boolean
+LINE 1: CREATE INDEX idx_prefix_f3 ON test_prefix_datatype (f3(4));
+ ^
+CREATE INDEX idx_prefix_f4 ON test_prefix_datatype (f4(4));
+ERROR: index prefix key are not supported by column type date
+LINE 1: CREATE INDEX idx_prefix_f4 ON test_prefix_datatype (f4(4));
+ ^
+CREATE INDEX idx_prefix_f5 ON test_prefix_datatype (f5(4));
+ERROR: index prefix key are not supported by column type point
+LINE 1: CREATE INDEX idx_prefix_f5 ON test_prefix_datatype (f5(4));
+ ^
+CREATE INDEX idx_prefix_f6 ON test_prefix_datatype (f6(4));
+ERROR: index prefix key are not supported by column type cidr
+LINE 1: CREATE INDEX idx_prefix_f6 ON test_prefix_datatype (f6(4));
+ ^
+CREATE INDEX idx_prefix_f7 ON test_prefix_datatype (f7(4));
+ERROR: index prefix key are not supported by column type bit
+LINE 1: CREATE INDEX idx_prefix_f7 ON test_prefix_datatype (f7(4));
+ ^
+CREATE INDEX idx_prefix_f8 ON test_prefix_datatype (f8(4));
+ERROR: index prefix key are not supported by column type json
+LINE 1: CREATE INDEX idx_prefix_f8 ON test_prefix_datatype (f8(4));
+ ^
+CREATE INDEX idx_prefix_f9 ON test_prefix_datatype (f9(4));
+ERROR: index prefix key are not supported by column type name
+LINE 1: CREATE INDEX idx_prefix_f9 ON test_prefix_datatype (f9(4));
+ ^
+CREATE INDEX idx_prefix_f10 ON test_prefix_datatype (f10(65));
+ERROR: index key prefix length(65) too long for type character(64)
+LINE 1: ...EATE 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));
+ERROR: index key prefix length(65) too long for type character varying(64)
+LINE 1: ...EATE 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));
+ERROR: index key prefix length(65) too long for type character varying(64)
+LINE 1: ...EATE 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));
+ERROR: index key prefix length(65) too long for type nvarchar2(64)
+LINE 1: ...EATE 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));
+ERROR: index key prefix length(65) too long for type nvarchar2(64)
+LINE 1: ...EATE 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));
+ERROR: index prefix key are not supported by column type "char"
+LINE 1: ...REATE 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));
+ERROR: index key prefix length(0) must be positive and cannot exceed 2676
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_syntax (fchar(0));
+ ^
+CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(-1));
+ERROR: index key prefix length(-1) must be positive and cannot exceed 2676
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_syntax (fchar(-1))...
+ ^
+CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(1+1));
+ERROR: function fchar(integer) does not exist
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_syntax (fchar(1+1)...
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+CREATE INDEX error_index_fchar ON test_prefix_syntax (fchar(6.4));
+ERROR: function fchar(numeric) does not exist
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_syntax (fchar(6.4)...
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(0));
+ERROR: index key prefix length(0) must be positive and cannot exceed 2676
+LINE 1: ... INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(0)...
+ ^
+CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(-1));
+ERROR: syntax error at or near "-"
+LINE 1: ...DEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(-1));
+ ^
+CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(1+1));
+ERROR: syntax error at or near "+"
+LINE 1: ...EX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(1+1));
+ ^
+CREATE INDEX error_index_BETWEEN ON test_prefix_syntax (BETWEEN(6.4));
+ERROR: syntax error at or near "6.4"
+LINE 1: ...EX 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));
+ERROR: access method "hash" does not support prefix key
+CREATE INDEX error_index_fblob ON test_prefix_syntax using gin (fblob(5));
+ERROR: access method "gin" does not support prefix key
+CREATE INDEX error_index_fblob ON test_prefix_syntax using gist (fblob(5));
+ERROR: access method "gist" does not support prefix key
+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;
+ length | length | length
+--------+--------+--------
+ 4000 | 4000 | 4000
+(1 row)
+
+select lengthb(fchar),lengthb(ftext),octet_length(fbytea) from test_prefix_key_len;
+ lengthb | lengthb | octet_length
+---------+---------+--------------
+ 4096 | 4000 | 4000
+(1 row)
+
+CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2677));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...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));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...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));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...dx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(267...
+ ^
+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%';
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_fchar on test_prefix_key_len
+ Index Cond: ((fchar >= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'::bpchar) AND (fchar < '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmo'::bpchar))
+ Filter: (fchar ~~ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_ftext on test_prefix_key_len
+ Index Cond: ((ftext >= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'::text) AND (ftext < '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmo'::text))
+ Filter: (ftext ~~ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_fbytea on test_prefix_key_len
+ Index Cond: ((fbytea >= '\x303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e'::bytea) AND (fbytea < '\x303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6f'::bytea))
+ Filter: (fbytea ~~ '\x303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e25'::bytea)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_comb on test_prefix_key_len
+ Index Cond: ((ftext >= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'::text) AND (ftext < '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmo'::text))
+ Filter: (ftext ~~ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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;
+ length | length | length
+--------+--------+--------
+ 3000 | 3000 | 9000
+(1 row)
+
+select lengthb(fchar),lengthb(ftext),octet_length(fbytea) from test_prefix_key_len;
+ lengthb | lengthb | octet_length
+---------+---------+--------------
+ 9000 | 9000 | 9000
+(1 row)
+
+CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2677));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...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));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...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));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...dx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(267...
+ ^
+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 '一二三四五六七八九十百千万亿兆%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_fchar on test_prefix_key_len
+ Index Cond: ((fchar >= '一二三四五六七八九十百千万亿兆'::bpchar) AND (fchar < '一二三四五六七八九十百千万亿兇'::bpchar))
+ Filter: (fchar ~~ '一二三四五六七八九十百千万亿兆%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '一二三四五六七八九十百千万亿兆%';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (costs false)
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_ftext on test_prefix_key_len
+ Index Cond: ((ftext >= '一二三四五六七八九十百千万亿兆'::text) AND (ftext < '一二三四五六七八九十百千万亿兇'::text))
+ Filter: (ftext ~~ '一二三四五六七八九十百千万亿兆%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (costs false)
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '一二三四五六七八九十百千万亿兆%';
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_fbytea on test_prefix_key_len
+ Index Cond: ((fbytea >= '\xe4b880e4ba8ce4b889e59b9be4ba94e585ade4b883e585abe4b99de58d81e799bee58d83e4b887e4babfe58586'::bytea) AND (fbytea < '\xe4b880e4ba8ce4b889e59b9be4ba94e585ade4b883e585abe4b99de58d81e799bee58d83e4b887e4babfe58587'::bytea))
+ Filter: (fbytea ~~ '\xe4b880e4ba8ce4b889e59b9be4ba94e585ade4b883e585abe4b99de58d81e799bee58d83e4b887e4babfe5858625'::bytea)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '一二三四五六七八九十百千万亿兆%';
+ count
+-------
+ 1
+(1 row)
+
+EXPLAIN (costs false)
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_comb on test_prefix_key_len
+ Index Cond: ((ftext >= '一二三四五六七八九十百千万亿兆'::text) AND (ftext < '一二三四五六七八九十百千万亿兇'::text))
+ Filter: (ftext ~~ '一二三四五六七八九十百千万亿兆%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '一二三四五六七八九十百千万亿兆%';
+ count
+-------
+ 1
+(1 row)
+
+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;
+ length | length | length
+--------+--------+--------
+ 4000 | 4000 | 4000
+(1 row)
+
+select lengthb(fchar),lengthb(ftext),octet_length(fbytea) from test_prefix_key_len;
+ lengthb | lengthb | octet_length
+---------+---------+--------------
+ 4096 | 4000 | 4000
+(1 row)
+
+CREATE INDEX idx_prefix_len_test_fchar ON test_prefix_key_len (fchar(2677));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...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));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...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));
+ERROR: index key prefix length(2677) must be positive and cannot exceed 2676
+LINE 1: ...dx_prefix_len_test_fbytea ON test_prefix_key_len (fbytea(267...
+ ^
+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%';
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_fchar on test_prefix_key_len
+ Index Cond: ((fchar >= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'::bpchar) AND (fchar < '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmo'::bpchar))
+ Filter: (fchar ~~ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fchar) */count(1) FROM test_prefix_key_len WHERE fchar LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_ftext on test_prefix_key_len
+ Index Cond: ((ftext >= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'::text) AND (ftext < '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmo'::text))
+ Filter: (ftext ~~ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_ftext) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_fbytea on test_prefix_key_len
+ Index Cond: ((fbytea >= '\x303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e'::bytea) AND (fbytea < '\x303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6f'::bytea))
+ Filter: (fbytea ~~ '\x303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e25'::bytea)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_fbytea) */count(1) FROM test_prefix_key_len WHERE fbytea LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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%';
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Aggregate
+ -> Index Scan using idx_prefix_len_test_comb on test_prefix_key_len
+ Index Cond: ((ftext >= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'::text) AND (ftext < '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmo'::text))
+ Filter: (ftext ~~ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%'::text)
+(4 rows)
+
+SELECT /*+ indexscan(test_prefix_key_len idx_prefix_len_test_comb) */count(1) FROM test_prefix_key_len WHERE ftext LIKE '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn%';
+ count
+-------
+ 1
+(1 row)
+
+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
+ Table "public.test_prefix_table"
+ Column | Type | Modifiers | Storage | Stats target | Description
+--------+-----------------------+-----------+----------+--------------+-------------
+ id | integer | | plain | |
+ fchar | character(64) | | extended | |
+ fvchar | character varying(64) | | extended | |
+ ftext | text | | extended | |
+ fclob | clob | | extended | |
+ fblob | blob | | extended | |
+ fraw | raw | | extended | |
+ fbytea | bytea | | extended | |
+Indexes:
+ "prefix_index_fraw" UNIQUE, btree (fraw(9)) TABLESPACE pg_default
+ "prefix_index_fblob" btree (fblob(5)) TABLESPACE pg_default
+ "prefix_index_fchar_fbytea" btree (fchar(5), fbytea(5)) TABLESPACE pg_default
+ "prefix_index_fclob" btree (fclob(5)) TABLESPACE pg_default
+ "prefix_index_ftext" btree (ftext(5)) TABLESPACE pg_default
+ "prefix_index_fvchar" btree (fvchar(5)) TABLESPACE pg_default
+Has OIDs: no
+Options: orientation=row, compression=no
+
+select pg_get_tabledef('test_prefix_table'::regclass);
+ pg_get_tabledef
+----------------------------------------------------------------------------------------------------------------------
+ SET search_path = public; +
+ CREATE TABLE test_prefix_table ( +
+ id integer, +
+ fchar character(64), +
+ fvchar character varying(64), +
+ ftext text, +
+ fclob clob, +
+ fblob blob, +
+ fraw raw, +
+ fbytea bytea +
+ ) +
+ WITH (orientation=row, compression=no); +
+ CREATE UNIQUE INDEX prefix_index_fraw ON test_prefix_table USING btree (fraw(9)) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fblob ON test_prefix_table USING btree (fblob(5)) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fclob ON test_prefix_table USING btree (fclob(5)) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_ftext ON test_prefix_table USING btree (ftext(5)) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fvchar ON test_prefix_table USING btree (fvchar(5)) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fchar_fbytea ON test_prefix_table USING btree (fchar(5), fbytea(5)) TABLESPACE pg_default;
+(1 row)
+
+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;
+ ftext
+-------
+(0 rows)
+
+SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+-------
+(0 rows)
+
+SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+-------+--------
+(0 rows)
+
+--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;
+ ftext
+-----------
+ XXXXX-000
+ XXXXX-111
+ XXXXX-210
+ XXXXX-211
+ XXXXX-300
+(5 rows)
+
+SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+--------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D323131
+(4 rows)
+
+SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+------------------------------------------------------------------+----------------------
+ XXXXX-211 | \x58585858582d323131
+(1 row)
+
+--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;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-211
+ AAAAA-300
+(5 rows)
+
+SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+--------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D323131
+(4 rows)
+
+SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+------------------------------------------------------------------+----------------------
+ AAAAA-211 | \x58585858582d323131
+(1 row)
+
+--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;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+(4 rows)
+
+SELECT fblob FROM test_prefix_table where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+--------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+(3 rows)
+
+SELECT fchar, fbytea FROM test_prefix_table where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+-------+--------
+(0 rows)
+
+--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;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: ((ftext >= 'YYYY'::text) AND (ftext < 'YYYZ'::text))
+ Filter: (ftext ~~ 'YYYY%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like 'YYYY%' ORDER BY 1;
+ ftext
+-----------
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext like 'YYYYY%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = 'YYYYY'::text)
+ Filter: (ftext ~~ 'YYYYY%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like 'YYYYY%' ORDER BY 1;
+ ftext
+-----------
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-1%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = 'YYYYY'::text)
+ Filter: (ftext ~~ 'YYYYY-1%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-1%' ORDER BY 1;
+ ftext
+-----------
+ YYYYY-111
+(1 row)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-210' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = 'YYYYY'::text)
+ Filter: (ftext ~~ 'YYYYY-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like 'YYYYY-210' ORDER BY 1;
+ ftext
+-----------
+ YYYYY-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext like '开%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: ((ftext >= '开'::text) AND (ftext < '弁'::text))
+ Filter: (ftext ~~ '开%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like '开%' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext like '开源数据库%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = '开源数据库'::text)
+ Filter: (ftext ~~ '开源数据库%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like '开源数据库%' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext like '开源数据库-2%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = '开源数据库'::text)
+ Filter: (ftext ~~ '开源数据库-2%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext like '开源数据库-2%' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext = '开源数据库-210' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------
+ Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = '开源数据库'::text)
+ Filter: (ftext = '开源数据库-210'::text)
+(3 rows)
+
+SELECT ftext FROM test_prefix_table where ftext = '开源数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext > '开' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext >= '开'::text)
+ Filter: (ftext > '开'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext > '开' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(3 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext > '开源数据库' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext >= '开源数据库'::text)
+ Filter: (ftext > '开源数据库'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext > '开源数据库' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(3 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext > '开源数据库-210' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext >= '开源数据库'::text)
+ Filter: (ftext > '开源数据库-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext > '开源数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 高
+ 高斯数据库-210
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext < '开' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext <= '开'::text)
+ Filter: (ftext < '开'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext < '开' ORDER BY 1;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+(17 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext < '开源数据库' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext <= '开源数据库'::text)
+ Filter: (ftext < '开源数据库'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext < '开源数据库' ORDER BY 1;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+(17 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext < '开源数据库-210' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext <= '开源数据库'::text)
+ Filter: (ftext < '开源数据库-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext < '开源数据库-210' ORDER BY 1;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+(17 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YY%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: ((fbytea >= '\x5959'::bytea) AND (fbytea < '\x595a'::bytea))
+ Filter: (fbytea ~~ '\x595925'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YY%' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d303030
+ \x59595959592d313131
+ \x59595959592d323130
+ \x59595959592d323131
+ \x59595959592d333030
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY%' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea ~~ '\x595959595925'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY%' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d303030
+ \x59595959592d313131
+ \x59595959592d323130
+ \x59595959592d323131
+ \x59595959592d333030
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea ~~ '\x59595959592d25'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d303030
+ \x59595959592d313131
+ \x59595959592d323130
+ \x59595959592d323131
+ \x59595959592d333030
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY-111' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea ~~ '\x59595959592d313131'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea like 'YYYYY-111' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d313131
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea like '高%' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: ((fbytea >= '\xe9ab98'::bytea) AND (fbytea < '\xe9ab99'::bytea))
+ Filter: (fbytea ~~ '\xe9ab9825'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea like '高%' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \xe9ab98
+ \xe9ab98e696afe695b0e68daee5ba932d323130
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库%' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\xe5bc80e6ba'::bytea)
+ Filter: (fbytea ~~ '\xe5bc80e6ba90e695b0e68daee5ba9325'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库%' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \xe5bc80e6ba90e695b0e68daee5ba932d323130
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea like '高斯数据库-%' ORDER BY 1;
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\xe9ab98e696'::bytea)
+ Filter: (fbytea ~~ '\xe9ab98e696afe695b0e68daee5ba932d25'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea like '高斯数据库-%' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \xe9ab98e696afe695b0e68daee5ba932d323130
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库-210' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\xe5bc80e6ba'::bytea)
+ Filter: (fbytea ~~ '\xe5bc80e6ba90e695b0e68daee5ba932d323130'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea ~~ '开源数据库-210' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \xe5bc80e6ba90e695b0e68daee5ba932d323130
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea = '\x59595959592d323131'::bytea)
+(3 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d323131
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea = '\x59'::bytea)
+ Filter: (fbytea = '\x59'::bytea)
+(3 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea = E'\\x59' ORDER BY 1;
+ fbytea
+--------
+ \x59
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea > 'Y' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea >= '\x59'::bytea)
+ Filter: (fbytea > '\x59'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea > 'Y' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \x59595959592d303030
+ \x59595959592d313131
+ \x59595959592d323130
+ \x59595959592d323131
+ \x59595959592d333030
+ \x5a
+ \x5a5a5a5a5a2d303030
+ \x5a5a5a5a5a2d313131
+ \x5a5a5a5a5a2d313233
+ \x5a5a5a5a5a2d323130
+ \x5a5a5a5a5a2d323131
+ \x5a5a5a5a5a2d333030
+ \xe5bc80e6ba90e695b0e68daee5ba932d323130
+ \xe9ab98
+ \xe9ab98e696afe695b0e68daee5ba932d323130
+(15 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea >= '\x5959595959'::bytea)
+ Filter: (fbytea > '\x5959595959'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \x59595959592d303030
+ \x59595959592d313131
+ \x59595959592d323130
+ \x59595959592d323131
+ \x59595959592d333030
+ \x5a
+ \x5a5a5a5a5a2d303030
+ \x5a5a5a5a5a2d313131
+ \x5a5a5a5a5a2d313233
+ \x5a5a5a5a5a2d323130
+ \x5a5a5a5a5a2d323131
+ \x5a5a5a5a5a2d333030
+ \xe5bc80e6ba90e695b0e68daee5ba932d323130
+ \xe9ab98
+ \xe9ab98e696afe695b0e68daee5ba932d323130
+(15 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY-210' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea >= '\x5959595959'::bytea)
+ Filter: (fbytea > '\x59595959592d323130'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea > 'YYYYY-210' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \x59595959592d323131
+ \x59595959592d333030
+ \x5a
+ \x5a5a5a5a5a2d303030
+ \x5a5a5a5a5a2d313131
+ \x5a5a5a5a5a2d313233
+ \x5a5a5a5a5a2d323130
+ \x5a5a5a5a5a2d323131
+ \x5a5a5a5a5a2d333030
+ \xe5bc80e6ba90e695b0e68daee5ba932d323130
+ \xe9ab98
+ \xe9ab98e696afe695b0e68daee5ba932d323130
+(12 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea < 'Y' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea <= '\x59'::bytea)
+ Filter: (fbytea < '\x59'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea < 'Y' ORDER BY 1;
+ fbytea
+----------------------
+ \x58585858582d303030
+ \x58585858582d313131
+ \x58585858582d323130
+ \x58585858582d333030
+(4 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea <= '\x5959595959'::bytea)
+ Filter: (fbytea < '\x5959595959'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY' ORDER BY 1;
+ fbytea
+----------------------
+ \x58585858582d303030
+ \x58585858582d313131
+ \x58585858582d323130
+ \x58585858582d333030
+ \x59
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY-210' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table t
+ Index Cond: (fbytea <= '\x5959595959'::bytea)
+ Filter: (fbytea < '\x59595959592d323130'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_table t where fbytea < 'YYYYY-210' ORDER BY 1;
+ fbytea
+----------------------
+ \x58585858582d303030
+ \x58585858582d313131
+ \x58585858582d323130
+ \x58585858582d333030
+ \x59
+ \x59595959592d303030
+ \x59595959592d313131
+(7 rows)
+
+EXPLAIN (costs false)
+SELECT fchar FROM test_prefix_table where fchar ~ '^开' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: fchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table
+ Index Cond: ((fchar >= '开'::bpchar) AND (fchar < '弁'::bpchar))
+ Filter: (fchar ~ '^开'::text)
+(5 rows)
+
+SELECT fchar FROM test_prefix_table where fchar ~ '^开' ORDER BY 1;
+ fchar
+-------------------------------------------------------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY-100' ORDER BY 1;
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Sort
+ Sort Key: fchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table
+ Index Cond: (fchar <= 'YYYYY'::bpchar)
+ Filter: (fchar <= 'YYYYY-100'::bpchar)
+(5 rows)
+
+SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY-100' ORDER BY 1;
+ fchar
+------------------------------------------------------------------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+ YYYYY-000
+(6 rows)
+
+EXPLAIN (costs false)
+SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY' ORDER BY 1;
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Sort
+ Sort Key: fchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_table
+ Index Cond: (fchar <= 'YYYYY'::bpchar)
+ Filter: (fchar <= 'YYYYY'::bpchar)
+(5 rows)
+
+SELECT fchar FROM test_prefix_table where fchar <= 'YYYYY' ORDER BY 1;
+ fchar
+------------------------------------------------------------------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fclob FROM test_prefix_table t where fclob < 'ZZZZZ-210' ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------
+ Sort
+ Sort Key: fclob
+ -> Index Scan using prefix_index_fclob on test_prefix_table t
+ Index Cond: ((fclob)::text <= 'ZZZZZ'::text)
+ Filter: ((fclob)::text < 'ZZZZZ-210'::text)
+(5 rows)
+
+SELECT fclob FROM test_prefix_table t where fclob < 'ZZZZZ-210' ORDER BY 1;
+ fclob
+-----------
+ XXXXX-000
+ XXXXX-111
+ XXXXX-210
+ XXXXX-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+(14 rows)
+
+EXPLAIN (costs false)
+SELECT fclob FROM test_prefix_table t where fclob < 'Z' ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------
+ Sort
+ Sort Key: fclob
+ -> Index Scan using prefix_index_fclob on test_prefix_table t
+ Index Cond: ((fclob)::text <= 'Z'::text)
+ Filter: ((fclob)::text < 'Z'::text)
+(5 rows)
+
+SELECT fclob FROM test_prefix_table t where fclob < 'Z' ORDER BY 1;
+ fclob
+-----------
+ XXXXX-000
+ XXXXX-111
+ XXXXX-210
+ XXXXX-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+(10 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: ((fvchar)::text >= 'ZZZZZ-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(6 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: ((fvchar)::text >= 'ZZZZZ'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table t where fvchar >= 'ZZZZZ' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(9 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: (((fvchar)::text > 'ZZZZZ-'::text) AND ((fvchar)::text <> 'ZZZZZ-210'::text))
+(5 rows)
+
+SELECT ftext FROM test_prefix_table t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(8 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: (((fvchar)::text > 'ZZZZZ-2'::text) AND ((fvchar)::text <> 'ZZZZZ-211'::text))
+(5 rows)
+
+SELECT ftext FROM test_prefix_table t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-210
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fblob FROM test_prefix_table t where fblob IS NOT NULL ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------
+ Sort
+ Sort Key: fblob
+ -> Index Scan using prefix_index_fblob on test_prefix_table t
+ Index Cond: (fblob IS NOT NULL)
+(4 rows)
+
+SELECT fblob FROM test_prefix_table t where fblob IS NOT NULL ORDER BY 1;
+ fblob
+----------------------------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D333030
+ 59
+ 59595959592D303030
+ 59595959592D313131
+ 59595959592D323130
+ 59595959592D323131
+ 59595959592D333030
+ 5A
+ 5A5A5A5A5A2D303030
+ 5A5A5A5A5A2D313131
+ 5A5A5A5A5A2D313233
+ 5A5A5A5A5A2D323130
+ 5A5A5A5A5A2D323131
+ 5A5A5A5A5A2D333030
+ E5BC80E6BA90E695B0E68DAEE5BA932D323130
+ E9AB98
+ E9AB98E696AFE695B0E68DAEE5BA932D323130
+(20 rows)
+
+EXPLAIN (costs false)
+SELECT DISTINCT fraw FROM test_prefix_table t where fraw IS NOT NULL ORDER BY 1;
+ QUERY PLAN
+-----------------------------------------------------------------------
+ Unique
+ -> Sort
+ Sort Key: fraw
+ -> Index Scan using prefix_index_fraw on test_prefix_table t
+ Index Cond: (fraw IS NOT NULL)
+(5 rows)
+
+SELECT DISTINCT fraw FROM test_prefix_table t where fraw IS NOT NULL ORDER BY 1;
+ fraw
+----------------------------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D333030
+ 59
+ 59595959592D303030
+ 59595959592D313131
+ 59595959592D323130
+ 59595959592D323131
+ 59595959592D333030
+ 5A
+ 5A5A5A5A5A2D303030
+ 5A5A5A5A5A2D313131
+ 5A5A5A5A5A2D313233
+ 5A5A5A5A5A2D323130
+ 5A5A5A5A5A2D323131
+ 5A5A5A5A5A2D333030
+ E5BC80E6BA90E695B0E68DAEE5BA932D323130
+ E9AB98
+ E9AB98E696AFE695B0E68DAEE5BA932D323130
+(20 rows)
+
+EXPLAIN (costs false)
+SELECT fraw FROM test_prefix_table t where fraw IS NULL or ftext like '高%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------------------------
+ Sort
+ Sort Key: fraw
+ -> Bitmap Heap Scan on test_prefix_table t
+ Recheck Cond: ((fraw IS NULL) OR (ftext ~~ '高%'::text))
+ Filter: ((fraw IS NULL) OR (ftext ~~ '高%'::text))
+ -> BitmapOr
+ -> Bitmap Index Scan on prefix_index_fraw
+ Index Cond: (fraw IS NULL)
+ -> Bitmap Index Scan on prefix_index_ftext
+ Index Cond: ((ftext >= '高'::text) AND (ftext < '髙'::text))
+(10 rows)
+
+SELECT fraw FROM test_prefix_table t where fraw IS NULL or ftext like '高%' ORDER BY 1;
+ fraw
+----------------------------------------
+ E9AB98
+ E9AB98E696AFE695B0E68DAEE5BA932D323130
+
+
+
+(5 rows)
+
+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;
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: fvchar
+ -> Bitmap Heap Scan on test_prefix_table t
+ Recheck Cond: ((fraw IS NULL) OR ((fvchar)::text > 'ZZZZZ-200'::text))
+ Filter: ((fraw IS NULL) OR (((fvchar)::text > 'ZZZZZ-200'::text) AND ((fvchar)::text <> 'ZZZZZ-210'::text)))
+ -> BitmapOr
+ -> Bitmap Index Scan on prefix_index_fraw
+ Index Cond: (fraw IS NULL)
+ -> Bitmap Index Scan on prefix_index_fvchar
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+(10 rows)
+
+SELECT fvchar FROM test_prefix_table t where fraw IS NULL or fvchar > 'ZZZZZ-200' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
+ fvchar
+----------------
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+
+
+
+(8 rows)
+
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_table t where NOT fvchar <> 'ZZZZZ-211' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------
+ Index Scan using prefix_index_fvchar on test_prefix_table t
+ Index Cond: ((fvchar)::text = 'ZZZZZ'::text)
+ Filter: ((fvchar)::text = 'ZZZZZ-211'::text)
+(3 rows)
+
+SELECT fvchar FROM test_prefix_table t where NOT fvchar <>'ZZZZZ-211' ORDER BY 1;
+ fvchar
+-----------
+ ZZZZZ-211
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') = false ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------
+ Index Scan using prefix_index_fvchar on test_prefix_table t
+ Index Cond: ((fvchar)::text = 'ZZZZZ'::text)
+ Filter: ((fvchar)::text = 'ZZZZZ-211'::text)
+(3 rows)
+
+SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') = false ORDER BY 1;
+ fvchar
+-----------
+ ZZZZZ-211
+(1 row)
+
+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');
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: fvchar
+ -> Bitmap Heap Scan on test_prefix_table t
+ Recheck Cond: ((fraw IS NULL) OR ((fvchar)::text > $1))
+ Filter: ((fraw IS NULL) OR (((fvchar)::text > $1) AND ((fvchar)::text <> 'ZZZZZ-210'::text)))
+ -> BitmapOr
+ -> Bitmap Index Scan on prefix_index_fraw
+ Index Cond: (fraw IS NULL)
+ -> Bitmap Index Scan on prefix_index_fvchar
+ Index Cond: ((fvchar)::text >= $1(5))
+(10 rows)
+
+EXECUTE testprefixindex('ZZZZZ-200');
+ fvchar
+----------------
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+
+
+
+(8 rows)
+
+--prefix index not used
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') IS false ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------
+ Sort
+ Sort Key: fvchar
+ -> Seq Scan on test_prefix_table t
+ Filter: (((fvchar)::text <> 'ZZZZZ-211'::text) IS FALSE)
+(4 rows)
+
+SELECT fvchar FROM test_prefix_table t where (fvchar <> 'ZZZZZ-211') IS false ORDER BY 1;
+ fvchar
+-----------
+ ZZZZZ-211
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_table t where fvchar <> 'ZZZZZ-210';
+ QUERY PLAN
+-------------------------------------------------
+ Seq Scan on test_prefix_table t
+ Filter: ((fvchar)::text <> 'ZZZZZ-210'::text)
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT left(ftext, 5) FROM test_prefix_table where left(ftext, 5) = 'YYYYY';
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on test_prefix_table
+ Filter: ("left"(ftext, 5) = 'YYYYY'::text)
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table ORDER BY ftext;
+ QUERY PLAN
+-------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Seq Scan on test_prefix_table
+(3 rows)
+
+EXPLAIN (costs false)
+select * from test_prefix_table tab1 where (fchar, fbytea)<('YYYYY-210', E'\\x59595959592D323130');
+ QUERY PLAN
+------------------------------------------------------------------------------------------
+ Seq Scan on test_prefix_table tab1
+ Filter: (ROW(fchar, fbytea) < ROW('YYYYY-210'::bpchar, '\x59595959592d323130'::bytea))
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_table where ftext not like 'YYYY%' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Seq Scan on test_prefix_table
+ Filter: (ftext !~~ 'YYYY%'::text)
+(4 rows)
+
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_table where fvchar = 'YYYYY-100'::name;
+ QUERY PLAN
+------------------------------------------------
+ Seq Scan on test_prefix_table
+ Filter: ((fvchar)::name = 'YYYYY-100'::name)
+(2 rows)
+
+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;
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.ftext, t2.fchar
+ -> Nested Loop
+ -> Seq Scan on test_prefix_table t2
+ -> Index Scan using prefix_index_ftext on test_prefix_table t1
+ Index Cond: (ftext = (t2.fchar)::text(5))
+ Filter: ((t2.fchar)::text = ftext)
+(7 rows)
+
+SELECT t1.ftext,t2.fchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext = t2.fchar ORDER BY 1,2;
+ ftext | fchar
+----------------+------------------------------------------------------------------
+ AAAAA-000 | AAAAA-000
+ AAAAA-111 | AAAAA-111
+ AAAAA-210 | AAAAA-210
+ AAAAA-300 | AAAAA-300
+ Y | Y
+ YYYYY-000 | YYYYY-000
+ YYYYY-111 | YYYYY-111
+ YYYYY-210 | YYYYY-210
+ YYYYY-211 | YYYYY-211
+ YYYYY-300 | YYYYY-300
+ Z | Z
+ ZZZZZ-000 | ZZZZZ-000
+ ZZZZZ-111 | ZZZZZ-111
+ ZZZZZ-123 | ZZZZZ-123
+ ZZZZZ-210 | ZZZZZ-210
+ ZZZZZ-211 | ZZZZZ-211
+ ZZZZZ-300 | ZZZZZ-300
+ 开源数据库-210 | 开源数据库-210
+ 高 | 高
+ 高斯数据库-210 | 高斯数据库-210
+(20 rows)
+
+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);
+ QUERY PLAN
+--------------------------------------------------------------------------------------------
+ Aggregate
+ -> Nested Loop
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t2
+ Index Cond: (((fvchar)::text >= 'X'::text) AND ((fvchar)::text < 'Y'::text))
+ Filter: ((fvchar)::text ~~ 'X%'::text)
+ -> Index Scan using prefix_index_ftext on test_prefix_table t1
+ Index Cond: (ftext >= (t2.fvchar)::text(5))
+ Filter: (ftext > (t2.fvchar)::text)
+(8 rows)
+
+SELECT count(1) FROM test_prefix_table t1 join test_prefix_table t2 on (t2.fvchar LIKE 'X%' AND t1.ftext > t2.fvchar);
+ count
+-------
+ 64
+(1 row)
+
+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;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.ftext
+ -> Nested Loop
+ -> Seq Scan on test_prefix_table t1
+ Filter: (id = 30)
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t2
+ Index Cond: ((fvchar)::text = t1.ftext(5))
+ Filter: ((id > 10) AND (t1.ftext = (fvchar)::text))
+(8 rows)
+
+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;
+ ftext
+-----------
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+(7 rows)
+
+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;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.ftext
+ -> Nested Loop
+ -> Seq Scan on test_prefix_table t1
+ Filter: (id = 30)
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t2
+ Index Cond: ((fvchar)::text = t1.ftext(5))
+ Filter: (t1.ftext = (fvchar)::text)
+(8 rows)
+
+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;
+ ftext | fvchar
+-----------+-----------
+ Z | Z
+ ZZZZZ-000 | ZZZZZ-000
+ ZZZZZ-111 | ZZZZZ-111
+ ZZZZZ-123 | ZZZZZ-123
+ ZZZZZ-210 | ZZZZZ-210
+ ZZZZZ-211 | ZZZZZ-211
+ ZZZZZ-300 | ZZZZZ-300
+(7 rows)
+
+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;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.fvchar, t2.fvchar
+ -> Nested Loop Left Join
+ -> Seq Scan on test_prefix_table t1
+ -> Index Scan using prefix_index_fvchar on test_prefix_table t2
+ Index Cond: (((t1.fvchar)::text(5) = (fvchar)::text) AND ((fvchar)::text >= 'ZZZZZ'::text))
+ Filter: (((fvchar)::text > 'ZZZZZ-3'::text) AND ((t1.fvchar)::text = (fvchar)::text))
+(7 rows)
+
+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;
+ fvchar | fvchar
+----------------+----------------
+ XXXXX-000 |
+ XXXXX-111 |
+ XXXXX-210 |
+ XXXXX-300 |
+ Y |
+ YYYYY-000 |
+ YYYYY-111 |
+ YYYYY-210 |
+ YYYYY-211 |
+ YYYYY-300 |
+ Z |
+ ZZZZZ-000 |
+ ZZZZZ-111 |
+ ZZZZZ-123 |
+ ZZZZZ-210 |
+ ZZZZZ-211 |
+ ZZZZZ-300 | ZZZZZ-300
+ 开源数据库-210 | 开源数据库-210
+ 高 | 高
+ 高斯数据库-210 | 高斯数据库-210
+ |
+ |
+ |
+(23 rows)
+
+--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;
+ QUERY PLAN
+------------------------------------------------
+ Nested Loop
+ Join Filter: (t1.ftext ~~ (t2.fvchar)::text)
+ -> Seq Scan on test_prefix_table t1
+ -> Seq Scan on test_prefix_table t2
+(4 rows)
+
+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;
+ QUERY PLAN
+-------------------------------------------------
+ Nested Loop
+ Join Filter: (t1.ftext !~~ (t2.fvchar)::text)
+ -> Seq Scan on test_prefix_table t1
+ -> Seq Scan on test_prefix_table t2
+(4 rows)
+
+EXPLAIN (costs false)
+SELECT t1.ftext,t2.fvchar FROM test_prefix_table t1 join test_prefix_table t2 on t1.ftext <> t2.fvchar;
+ QUERY PLAN
+------------------------------------------------
+ Nested Loop
+ Join Filter: (t1.ftext <> (t2.fvchar)::text)
+ -> Seq Scan on test_prefix_table t1
+ -> Seq Scan on test_prefix_table t2
+(4 rows)
+
+--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;
+ QUERY PLAN
+----------------------------------------------------------------
+ Delete on test_prefix_table
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext IS NULL)
+(3 rows)
+
+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;
+ QUERY PLAN
+----------------------------------------------------------
+ Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext = '高斯数据库'::text)
+ Filter: (ftext = '高斯数据库-210'::text)
+(3 rows)
+
+SELECT ftext FROM test_prefix_table where ftext = '高斯数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 高斯数据库-210
+(1 row)
+
+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;
+ QUERY PLAN
+----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_table
+ Index Cond: (ftext >= '高斯数据库'::text)
+ Filter: (ftext >= '高斯数据库-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_table where ftext >= '高斯数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 高斯数据库-210
+(1 row)
+
+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;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: fbpchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_tb
+ Index Cond: (fbpchar >= '开源'::bpchar)
+ Filter: (fbpchar > '开源'::bpchar)
+(5 rows)
+
+SELECT fbpchar FROM test_prefix_tb where fbpchar > '开源' ORDER BY 1;
+ fbpchar
+-----------------------------------------------------------------
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(3 rows)
+
+ALTER INDEX prefix_index_fchar_fbytea UNUSABLE;
+EXPLAIN (costs false)
+SELECT fbpchar FROM test_prefix_tb where fbpchar like '高斯数据库-%' ORDER BY 1;
+ QUERY PLAN
+---------------------------------------------------
+ Sort
+ Sort Key: fbpchar
+ -> Seq Scan on test_prefix_tb
+ Filter: (fbpchar ~~ '高斯数据库-%'::text)
+(4 rows)
+
+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;
+ERROR: Global partition index does not support EXPRESSION index
+--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;
+ QUERY PLAN
+-------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Partition Iterator
+ Iterations: 3, Sub Iterations: 12
+ -> Partitioned Index Scan using prefix_index_ftext_part on test_prefix_parttable
+ Index Cond: ((ftext >= '高斯'::text) AND (ftext < '高新'::text))
+ Filter: (ftext ~~ '高斯%'::text)
+ Selected Partitions: 1..3
+ Selected Subpartitions: ALL
+(9 rows)
+
+SELECT ftext FROM test_prefix_parttable where ftext like '高斯%' ORDER BY 1;
+ ftext
+----------------
+ 高斯数据库-210
+(1 row)
+
+--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');
+ERROR: duplicate key value violates unique constraint "prefix_index_ftext_part_unique"
+DETAIL: Key (ftext, fvchar, fbytea(5))=(XXXXX-111, XXXXX-111, \x5858585858) already exists.
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_parttable t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------------------------------------
+ Partition Iterator
+ Iterations: 3, Sub Iterations: 12
+ -> Partitioned Index Scan using prefix_index_ftext_part_unique on test_prefix_parttable t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea = '\x59595959592d323131'::bytea)
+ Selected Partitions: 1..3
+ Selected Subpartitions: ALL
+(7 rows)
+
+SELECT fbytea FROM test_prefix_parttable t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d323131
+(1 row)
+
+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));
+ERROR: index key prefix length(0) must be positive and cannot exceed 2676
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_ustore (fchar(0));
+ ^
+CREATE INDEX error_index_fchar ON test_prefix_ustore (fchar(-1));
+ERROR: index key prefix length(-1) must be positive and cannot exceed 2676
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_ustore (fchar(-1))...
+ ^
+CREATE INDEX error_index_fchar ON test_prefix_ustore (fchar(1+1));
+ERROR: function fchar(integer) does not exist
+LINE 1: ...TE INDEX error_index_fchar ON test_prefix_ustore (fchar(1+1)...
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+CREATE INDEX error_index_fvchar ON test_prefix_ustore (fvchar(80));
+ERROR: index key prefix length(80) too long for type character varying(64)
+LINE 1: ...E INDEX error_index_fvchar ON test_prefix_ustore (fvchar(80)...
+ ^
+CREATE INDEX error_index_ftext ON test_prefix_ustore (ftext(4096));
+ERROR: index key prefix length(4096) must be positive and cannot exceed 2676
+LINE 1: ...TE INDEX error_index_ftext ON test_prefix_ustore (ftext(4096...
+ ^
+CREATE INDEX error_index_id ON test_prefix_ustore (id(5));
+ERROR: index prefix key are not supported by column type integer
+LINE 1: CREATE INDEX error_index_id ON test_prefix_ustore (id(5));
+ ^
+CREATE INDEX error_index_fchar ON test_prefix_ustore using hash (fchar(5));
+ERROR: access method "hash" does not support prefix key
+CREATE INDEX error_index_fchar ON test_prefix_ustore using gin (fchar(5));
+ERROR: access method "gin" does not support prefix key
+CREATE INDEX error_index_fchar ON test_prefix_ustore using gist (fchar(5));
+ERROR: access method "gist" does not support prefix key
+--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
+ Table "public.test_prefix_ustore"
+ Column | Type | Modifiers | Storage | Stats target | Description
+--------+-----------------------+-----------+----------+--------------+-------------
+ id | integer | | plain | |
+ fchar | character(64) | | extended | |
+ fvchar | character varying(64) | | extended | |
+ ftext | text | | extended | |
+ fclob | clob | | extended | |
+ fblob | blob | | extended | |
+ fraw | raw | | extended | |
+ fbytea | bytea | | extended | |
+Indexes:
+ "prefix_index_fraw" UNIQUE, ubtree (fraw(9)) WITH (storage_type=USTORE) TABLESPACE pg_default
+ "prefix_index_fblob" ubtree (fblob(5)) WITH (storage_type=USTORE) TABLESPACE pg_default
+ "prefix_index_fchar_fbytea" ubtree (fchar(5), fbytea(5)) WITH (storage_type=USTORE) TABLESPACE pg_default
+ "prefix_index_ftext" ubtree (ftext(5)) WITH (storage_type=USTORE) TABLESPACE pg_default
+ "prefix_index_fvchar" ubtree (fvchar(5)) WITH (storage_type=USTORE) TABLESPACE pg_default
+Has OIDs: no
+Options: orientation=row, storage_type=ustore, compression=no, toast.storage_type=ustore
+
+select pg_get_tabledef('test_prefix_ustore'::regclass);
+ pg_get_tabledef
+---------------------------------------------------------------------------------------------------------------------------------------------------
+ SET search_path = public; +
+ CREATE TABLE test_prefix_ustore ( +
+ id integer, +
+ fchar character(64), +
+ fvchar character varying(64), +
+ ftext text, +
+ fclob clob, +
+ fblob blob, +
+ fraw raw, +
+ fbytea bytea +
+ ) +
+ WITH (orientation=row, storage_type=ustore, compression=no); +
+ CREATE UNIQUE INDEX prefix_index_fraw ON test_prefix_ustore USING ubtree (fraw(9)) WITH (storage_type=USTORE) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fblob ON test_prefix_ustore USING ubtree (fblob(5)) WITH (storage_type=USTORE) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_ftext ON test_prefix_ustore USING ubtree (ftext(5)) WITH (storage_type=USTORE) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fvchar ON test_prefix_ustore USING ubtree (fvchar(5)) WITH (storage_type=USTORE) TABLESPACE pg_default; +
+ CREATE INDEX prefix_index_fchar_fbytea ON test_prefix_ustore USING ubtree (fchar(5), fbytea(5)) WITH (storage_type=USTORE) TABLESPACE pg_default;
+(1 row)
+
+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;
+ ftext
+-------
+(0 rows)
+
+SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+-------
+(0 rows)
+
+SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+-------+--------
+(0 rows)
+
+--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;
+ ftext
+-----------
+ XXXXX-000
+ XXXXX-111
+ XXXXX-210
+ XXXXX-211
+ XXXXX-300
+(5 rows)
+
+SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+--------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D323131
+(4 rows)
+
+SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('XXXXX-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+------------------------------------------------------------------+----------------------
+ XXXXX-211 | \x58585858582d323131
+(1 row)
+
+--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;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-211
+ AAAAA-300
+(5 rows)
+
+SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+--------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D323131
+(4 rows)
+
+SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+------------------------------------------------------------------+----------------------
+ AAAAA-211 | \x58585858582d323131
+(1 row)
+
+--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;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+(4 rows)
+
+SELECT fblob FROM test_prefix_ustore where fblob < '58585858582D333030' ORDER BY 1;
+ fblob
+--------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+(3 rows)
+
+SELECT fchar, fbytea FROM test_prefix_ustore where (fchar, fbytea)= ('AAAAA-211', 'XXXXX-211') ORDER BY 1,2;
+ fchar | fbytea
+-------+--------
+(0 rows)
+
+--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;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore t
+ Index Cond: ((ftext >= 'YYYY'::text) AND (ftext < 'YYYZ'::text))
+ Filter: (ftext ~~ 'YYYY%'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where ftext like 'YYYY%' ORDER BY 1;
+ ftext
+-----------
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where ftext like '开源数据库-210' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore t
+ Index Cond: (ftext = '开源数据库'::text)
+ Filter: (ftext ~~ '开源数据库-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where ftext like '开源数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fchar FROM test_prefix_ustore t where fchar ~~ '高斯数据库' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: fchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: (fchar = '高斯数据库'::bpchar)
+ Filter: (fchar ~~ '高斯数据库'::text)
+(5 rows)
+
+SELECT fchar FROM test_prefix_ustore t where fchar ~~ '高斯数据库' ORDER BY 1;
+ fchar
+-------
+(0 rows)
+
+EXPLAIN (costs false)
+SELECT fchar FROM test_prefix_ustore t where fchar ~ '^开' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: fchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: ((fchar >= '开'::bpchar) AND (fchar < '弁'::bpchar))
+ Filter: (fchar ~ '^开'::text)
+(5 rows)
+
+SELECT fchar FROM test_prefix_ustore t where fchar ~ '^开' ORDER BY 1;
+ fchar
+-------------------------------------------------------------
+ 开源数据库-210
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_ustore t where fbytea like '高%' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: ((fbytea >= '\xe9ab98'::bytea) AND (fbytea < '\xe9ab99'::bytea))
+ Filter: (fbytea ~~ '\xe9ab9825'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_ustore t where fbytea like '高%' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \xe9ab98
+ \xe9ab98e696afe695b0e68daee5ba932d323130
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ '开源数据库%' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: (fbytea = '\xe5bc80e6ba'::bytea)
+ Filter: (fbytea ~~ '\xe5bc80e6ba90e695b0e68daee5ba9325'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ '开源数据库%' ORDER BY 1;
+ fbytea
+------------------------------------------
+ \xe5bc80e6ba90e695b0e68daee5ba932d323130
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: fbytea
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea ~~ '\x59595959592d25'::bytea)
+(5 rows)
+
+SELECT fbytea FROM test_prefix_ustore t where fbytea ~~ 'YYYYY-%' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d303030
+ \x59595959592d313131
+ \x59595959592d323130
+ \x59595959592d323131
+ \x59595959592d333030
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY-100' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore t
+ Index Cond: (ftext <= 'YYYYY'::text)
+ Filter: (ftext <= 'YYYYY-100'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY-100' ORDER BY 1;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+ YYYYY-000
+(6 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY' ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore t
+ Index Cond: (ftext <= 'YYYYY'::text)
+ Filter: (ftext <= 'YYYYY'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where ftext <= 'YYYYY' ORDER BY 1;
+ ftext
+-----------
+ AAAAA-000
+ AAAAA-111
+ AAAAA-210
+ AAAAA-300
+ Y
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_ustore t where fvchar < 'ZZZZZ-210' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: fvchar
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t
+ Index Cond: ((fvchar)::text <= 'ZZZZZ'::text)
+ Filter: ((fvchar)::text < 'ZZZZZ-210'::text)
+(5 rows)
+
+SELECT fvchar FROM test_prefix_ustore t where fvchar < 'ZZZZZ-210' ORDER BY 1;
+ fvchar
+-----------
+ XXXXX-000
+ XXXXX-111
+ XXXXX-210
+ XXXXX-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+(14 rows)
+
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_ustore t where fvchar < 'Z' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: fvchar
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t
+ Index Cond: ((fvchar)::text <= 'Z'::text)
+ Filter: ((fvchar)::text < 'Z'::text)
+(5 rows)
+
+SELECT fvchar FROM test_prefix_ustore t where fvchar < 'Z' ORDER BY 1;
+ fvchar
+-----------
+ XXXXX-000
+ XXXXX-111
+ XXXXX-210
+ XXXXX-300
+ Y
+ YYYYY-000
+ YYYYY-111
+ YYYYY-210
+ YYYYY-211
+ YYYYY-300
+(10 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: ((fvchar)::text >= 'ZZZZZ-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ-210' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(6 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: ((fvchar)::text >= 'ZZZZZ'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where fvchar >= 'ZZZZZ' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(9 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: (((fvchar)::text > 'ZZZZZ-'::text) AND ((fvchar)::text <> 'ZZZZZ-210'::text))
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where fvchar > 'ZZZZZ-' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(8 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+ Filter: (((fvchar)::text > 'ZZZZZ-2'::text) AND ((fvchar)::text <> 'ZZZZZ-211'::text))
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore t where fvchar > left('ZZZZZ-211', 7) and fvchar <> 'ZZZZZ-211' ORDER BY 1;
+ ftext
+----------------
+ ZZZZZ-210
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(5 rows)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: (fbytea = '\x5959595959'::bytea)
+ Filter: (fbytea = '\x59595959592d323131'::bytea)
+(3 rows)
+
+SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59595959592D323131' ORDER BY 1;
+ fbytea
+----------------------
+ \x59595959592d323131
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59' ORDER BY 1;
+ QUERY PLAN
+--------------------------------------------------------------------
+ Index Scan using prefix_index_fchar_fbytea on test_prefix_ustore t
+ Index Cond: (fbytea = '\x59'::bytea)
+ Filter: (fbytea = '\x59'::bytea)
+(3 rows)
+
+SELECT fbytea FROM test_prefix_ustore t where fbytea = E'\\x59' ORDER BY 1;
+ fbytea
+--------
+ \x59
+(1 row)
+
+EXPLAIN (costs false)
+SELECT fblob FROM test_prefix_ustore t where fblob IS NOT NULL ORDER BY 1;
+ QUERY PLAN
+-------------------------------------------------------------------
+ Sort
+ Sort Key: fblob
+ -> Index Scan using prefix_index_fblob on test_prefix_ustore t
+ Index Cond: (fblob IS NOT NULL)
+(4 rows)
+
+SELECT fblob FROM test_prefix_ustore t where fblob IS NOT NULL ORDER BY 1;
+ fblob
+----------------------------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D333030
+ 59
+ 59595959592D303030
+ 59595959592D313131
+ 59595959592D323130
+ 59595959592D323131
+ 59595959592D333030
+ 5A
+ 5A5A5A5A5A2D303030
+ 5A5A5A5A5A2D313131
+ 5A5A5A5A5A2D313233
+ 5A5A5A5A5A2D323130
+ 5A5A5A5A5A2D323131
+ 5A5A5A5A5A2D333030
+ E5BC80E6BA90E695B0E68DAEE5BA932D323130
+ E9AB98
+ E9AB98E696AFE695B0E68DAEE5BA932D323130
+(20 rows)
+
+EXPLAIN (costs false)
+SELECT DISTINCT fraw FROM test_prefix_ustore t where fraw IS NOT NULL ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------------
+ Unique
+ -> Sort
+ Sort Key: fraw
+ -> Index Scan using prefix_index_fraw on test_prefix_ustore t
+ Index Cond: (fraw IS NOT NULL)
+(5 rows)
+
+SELECT DISTINCT fraw FROM test_prefix_ustore t where fraw IS NOT NULL ORDER BY 1;
+ fraw
+----------------------------------------
+ 58585858582D303030
+ 58585858582D313131
+ 58585858582D323130
+ 58585858582D333030
+ 59
+ 59595959592D303030
+ 59595959592D313131
+ 59595959592D323130
+ 59595959592D323131
+ 59595959592D333030
+ 5A
+ 5A5A5A5A5A2D303030
+ 5A5A5A5A5A2D313131
+ 5A5A5A5A5A2D313233
+ 5A5A5A5A5A2D323130
+ 5A5A5A5A5A2D323131
+ 5A5A5A5A5A2D333030
+ E5BC80E6BA90E695B0E68DAEE5BA932D323130
+ E9AB98
+ E9AB98E696AFE695B0E68DAEE5BA932D323130
+(20 rows)
+
+EXPLAIN (costs false)
+SELECT fraw FROM test_prefix_ustore t where fraw IS NULL or ftext like '高%' ORDER BY 1;
+ QUERY PLAN
+----------------------------------------------------------------------------------
+ Sort
+ Sort Key: fraw
+ -> Bitmap Heap Scan on test_prefix_ustore t
+ Recheck Cond: ((fraw IS NULL) OR (ftext ~~ '高%'::text))
+ Filter: ((fraw IS NULL) OR (ftext ~~ '高%'::text))
+ -> BitmapOr
+ -> Bitmap Index Scan on prefix_index_fraw
+ Index Cond: (fraw IS NULL)
+ -> Bitmap Index Scan on prefix_index_ftext
+ Index Cond: ((ftext >= '高'::text) AND (ftext < '髙'::text))
+(10 rows)
+
+SELECT fraw FROM test_prefix_ustore t where fraw IS NULL or ftext like '高%' ORDER BY 1;
+ fraw
+----------------------------------------
+ E9AB98
+ E9AB98E696AFE695B0E68DAEE5BA932D323130
+
+
+
+(5 rows)
+
+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;
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: fvchar
+ -> Bitmap Heap Scan on test_prefix_ustore t
+ Recheck Cond: ((fraw IS NULL) OR ((fvchar)::text > 'ZZZZZ-200'::text))
+ Filter: ((fraw IS NULL) OR (((fvchar)::text > 'ZZZZZ-200'::text) AND ((fvchar)::text <> 'ZZZZZ-210'::text)))
+ -> BitmapOr
+ -> Bitmap Index Scan on prefix_index_fraw
+ Index Cond: (fraw IS NULL)
+ -> Bitmap Index Scan on prefix_index_fvchar
+ Index Cond: ((fvchar)::text >= 'ZZZZZ'::text)
+(10 rows)
+
+SELECT fvchar FROM test_prefix_ustore t where fraw IS NULL or fvchar > 'ZZZZZ-200' and fvchar <> 'ZZZZZ-210' ORDER BY 1;
+ fvchar
+----------------
+ ZZZZZ-211
+ ZZZZZ-300
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+
+
+
+(8 rows)
+
+--prefix index not used
+EXPLAIN (costs false)
+SELECT fvchar FROM test_prefix_ustore t where fvchar <> 'ZZZZZ-210';
+ QUERY PLAN
+-------------------------------------------------
+ Seq Scan on test_prefix_ustore t
+ Filter: ((fvchar)::text <> 'ZZZZZ-210'::text)
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT left(ftext, 5) FROM test_prefix_ustore where left(ftext, 5) = 'YYYYY';
+ QUERY PLAN
+----------------------------------------------
+ Seq Scan on test_prefix_ustore
+ Filter: ("left"(ftext, 5) = 'YYYYY'::text)
+(2 rows)
+
+EXPLAIN (costs false)
+SELECT ftext FROM test_prefix_ustore ORDER BY ftext;
+ QUERY PLAN
+--------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Seq Scan on test_prefix_ustore
+(3 rows)
+
+EXPLAIN (costs false)
+select * from test_prefix_ustore tab1 where (fchar, fbytea)<('YYYYY-210', E'\\x59595959592D323130');
+ QUERY PLAN
+------------------------------------------------------------------------------------------
+ Seq Scan on test_prefix_ustore tab1
+ Filter: (ROW(fchar, fbytea) < ROW('YYYYY-210'::bpchar, '\x59595959592d323130'::bytea))
+(2 rows)
+
+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;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.ftext, t2.fchar
+ -> Nested Loop
+ -> Seq Scan on test_prefix_ustore t2
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore t1
+ Index Cond: (ftext = (t2.fchar)::text(5))
+ Filter: ((t2.fchar)::text = ftext)
+(7 rows)
+
+SELECT t1.ftext,t2.fchar FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext = t2.fchar ORDER BY 1,2;
+ ftext | fchar
+----------------+------------------------------------------------------------------
+ AAAAA-000 | AAAAA-000
+ AAAAA-111 | AAAAA-111
+ AAAAA-210 | AAAAA-210
+ AAAAA-300 | AAAAA-300
+ Y | Y
+ YYYYY-000 | YYYYY-000
+ YYYYY-111 | YYYYY-111
+ YYYYY-210 | YYYYY-210
+ YYYYY-211 | YYYYY-211
+ YYYYY-300 | YYYYY-300
+ Z | Z
+ ZZZZZ-000 | ZZZZZ-000
+ ZZZZZ-111 | ZZZZZ-111
+ ZZZZZ-123 | ZZZZZ-123
+ ZZZZZ-210 | ZZZZZ-210
+ ZZZZZ-211 | ZZZZZ-211
+ ZZZZZ-300 | ZZZZZ-300
+ 开源数据库-210 | 开源数据库-210
+ 高 | 高
+ 高斯数据库-210 | 高斯数据库-210
+(20 rows)
+
+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);
+ QUERY PLAN
+--------------------------------------------------------------------------------------------
+ Aggregate
+ -> Nested Loop
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t2
+ Index Cond: (((fvchar)::text >= 'X'::text) AND ((fvchar)::text < 'Y'::text))
+ Filter: ((fvchar)::text ~~ 'X%'::text)
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore t1
+ Index Cond: (ftext >= (t2.fvchar)::text(5))
+ Filter: (ftext > (t2.fvchar)::text)
+(8 rows)
+
+SELECT count(1) FROM test_prefix_ustore t1 join test_prefix_ustore t2 on (t2.fvchar LIKE 'X%' AND t1.ftext > t2.fvchar);
+ count
+-------
+ 64
+(1 row)
+
+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;
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.ftext
+ -> Nested Loop
+ -> Seq Scan on test_prefix_ustore t1
+ Filter: (id = 30)
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t2
+ Index Cond: ((fvchar)::text = t1.ftext(5))
+ Filter: ((id > 10) AND (t1.ftext = (fvchar)::text))
+(8 rows)
+
+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;
+ ftext
+-----------
+ Z
+ ZZZZZ-000
+ ZZZZZ-111
+ ZZZZZ-123
+ ZZZZZ-210
+ ZZZZZ-211
+ ZZZZZ-300
+(7 rows)
+
+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;
+ QUERY PLAN
+---------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.ftext
+ -> Nested Loop
+ -> Seq Scan on test_prefix_ustore t1
+ Filter: (id = 30)
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t2
+ Index Cond: ((fvchar)::text = t1.ftext(5))
+ Filter: (t1.ftext = (fvchar)::text)
+(8 rows)
+
+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;
+ ftext | fvchar
+-----------+-----------
+ Z | Z
+ ZZZZZ-000 | ZZZZZ-000
+ ZZZZZ-111 | ZZZZZ-111
+ ZZZZZ-123 | ZZZZZ-123
+ ZZZZZ-210 | ZZZZZ-210
+ ZZZZZ-211 | ZZZZZ-211
+ ZZZZZ-300 | ZZZZZ-300
+(7 rows)
+
+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;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------
+ Sort
+ Sort Key: t1.fvchar, t2.fvchar
+ -> Nested Loop Left Join
+ -> Seq Scan on test_prefix_ustore t1
+ -> Index Scan using prefix_index_fvchar on test_prefix_ustore t2
+ Index Cond: (((t1.fvchar)::text(5) = (fvchar)::text) AND ((fvchar)::text >= 'ZZZZZ'::text))
+ Filter: (((fvchar)::text > 'ZZZZZ-3'::text) AND ((t1.fvchar)::text = (fvchar)::text))
+(7 rows)
+
+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;
+ fvchar | fvchar
+----------------+----------------
+ XXXXX-000 |
+ XXXXX-111 |
+ XXXXX-210 |
+ XXXXX-300 |
+ Y |
+ YYYYY-000 |
+ YYYYY-111 |
+ YYYYY-210 |
+ YYYYY-211 |
+ YYYYY-300 |
+ Z |
+ ZZZZZ-000 |
+ ZZZZZ-111 |
+ ZZZZZ-123 |
+ ZZZZZ-210 |
+ ZZZZZ-211 |
+ ZZZZZ-300 | ZZZZZ-300
+ 开源数据库-210 | 开源数据库-210
+ 高 | 高
+ 高斯数据库-210 | 高斯数据库-210
+ |
+ |
+ |
+(23 rows)
+
+--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;
+ QUERY PLAN
+------------------------------------------------
+ Nested Loop
+ Join Filter: (t1.ftext ~~ (t2.fvchar)::text)
+ -> Seq Scan on test_prefix_ustore t1
+ -> Seq Scan on test_prefix_ustore t2
+(4 rows)
+
+EXPLAIN (costs false)
+SELECT t1.ftext,t2.fvchar FROM test_prefix_ustore t1 join test_prefix_ustore t2 on t1.ftext <> t2.fvchar;
+ QUERY PLAN
+------------------------------------------------
+ Nested Loop
+ Join Filter: (t1.ftext <> (t2.fvchar)::text)
+ -> Seq Scan on test_prefix_ustore t1
+ -> Seq Scan on test_prefix_ustore t2
+(4 rows)
+
+--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;
+ QUERY PLAN
+-----------------------------------------------------------------
+ Delete on test_prefix_ustore
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore
+ Index Cond: (ftext IS NULL)
+(3 rows)
+
+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;
+ QUERY PLAN
+-----------------------------------------------------------
+ Index Scan using prefix_index_ftext on test_prefix_ustore
+ Index Cond: (ftext = '高斯数据库'::text)
+ Filter: (ftext = '高斯数据库-210'::text)
+(3 rows)
+
+SELECT ftext FROM test_prefix_ustore where ftext = '高斯数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 高斯数据库-210
+(1 row)
+
+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;
+ QUERY PLAN
+-----------------------------------------------------------------
+ Sort
+ Sort Key: ftext
+ -> Index Scan using prefix_index_ftext on test_prefix_ustore
+ Index Cond: (ftext >= '高斯数据库'::text)
+ Filter: (ftext >= '高斯数据库-210'::text)
+(5 rows)
+
+SELECT ftext FROM test_prefix_ustore where ftext >= '高斯数据库-210' ORDER BY 1;
+ ftext
+----------------
+ 高斯数据库-210
+(1 row)
+
+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;
+ QUERY PLAN
+---------------------------------------------------------------------
+ Sort
+ Sort Key: fbpchar
+ -> Index Scan using prefix_index_fchar_fbytea on test_prefix_utb
+ Index Cond: (fbpchar >= '开源'::bpchar)
+ Filter: (fbpchar > '开源'::bpchar)
+(5 rows)
+
+SELECT fbpchar FROM test_prefix_utb where fbpchar > '开源' ORDER BY 1;
+ fbpchar
+-----------------------------------------------------------------
+ 开源数据库-210
+ 高
+ 高斯数据库-210
+(3 rows)
+
+ALTER INDEX prefix_index_fchar_fbytea UNUSABLE;
+EXPLAIN (costs false)
+SELECT fbpchar FROM test_prefix_utb where fbpchar like '高斯数据库-%' ORDER BY 1;
+ QUERY PLAN
+---------------------------------------------------
+ Sort
+ Sort Key: fbpchar
+ -> Seq Scan on test_prefix_utb
+ Filter: (fbpchar ~~ '高斯数据库-%'::text)
+(4 rows)
+
+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;
+NOTICE: table "test_prefix_cstore" does not exist, skipping
+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));
+ERROR: access method "cbtree" does not support prefix key
+CREATE INDEX prefix_cindex_ftext ON test_prefix_cstore (ftext(5));
+ERROR: access method "psort" does not support prefix key
+DROP TABLE IF EXISTS test_prefix_cstore;
+\c regression
+drop database prefix_index_db;
diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0
index a967c9f52..89387dac9 100644
--- a/src/test/regress/parallel_schedule0
+++ b/src/test/regress/parallel_schedule0
@@ -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
diff --git a/src/test/regress/sql/prefixkey_index.sql b/src/test/regress/sql/prefixkey_index.sql
new file mode 100644
index 000000000..869ca947f
--- /dev/null
+++ b/src/test/regress/sql/prefixkey_index.sql
@@ -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;
\ No newline at end of file