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