From 1ab5d44aa22c24a36034501cdba6977ec63b1282 Mon Sep 17 00:00:00 2001 From: erthalion <9erthalion6@gmail.com> Date: Fri, 1 Feb 2019 11:38:52 +0100 Subject: [PATCH v19 2/4] Subscripting for array Subscripting implementation for array data types. It includes all array specific parts, that were removed from the generalized code. Note, that for some array-like data types it's not necessary to assign array_subscript_handler explicitely, since it's done in Catalog.pm Reviewed-by: Tom Lane, Arthur Zakirov --- src/backend/catalog/Catalog.pm | 1 + src/backend/catalog/heap.c | 2 +- src/backend/commands/typecmds.c | 8 +- src/backend/executor/execExprInterp.c | 15 +- src/backend/nodes/nodeFuncs.c | 2 +- src/backend/parser/parse_node.c | 11 -- src/backend/parser/parse_target.c | 4 +- src/backend/utils/adt/arrayfuncs.c | 289 ++++++++++++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 7 + src/include/catalog/pg_type.dat | 30 ++-- src/test/regress/expected/arrays.out | 12 +- src/test/regress/sql/arrays.sql | 4 +- 12 files changed, 346 insertions(+), 39 deletions(-) diff --git a/src/backend/catalog/Catalog.pm b/src/backend/catalog/Catalog.pm index 3bf308fe3b..830c5bd557 100644 --- a/src/backend/catalog/Catalog.pm +++ b/src/backend/catalog/Catalog.pm @@ -385,6 +385,7 @@ sub GenerateArrayTypes # Arrays require INT alignment, unless the element type requires # DOUBLE alignment. $array_type{typalign} = $elem_type->{typalign} eq 'd' ? 'd' : 'i'; + $array_type{typsubshandler} = 'array_subscript_handler'; # Fill in the rest of the array entry's fields. foreach my $column (@$pgtype_schema) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index e945bb566a..28ab9d9d8a 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1296,7 +1296,7 @@ heap_create_with_catalog(const char *relname, 0, /* array dimensions for typBaseType */ false, /* Type NOT NULL */ InvalidOid, /* rowtypes never have a collation */ - 0); /* array implementation */ + F_ARRAY_SUBSCRIPT_HANDLER); /* array implementation */ pfree(relarrayname); } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 7b0046aea5..39eb3e8ab9 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -689,7 +689,7 @@ DefineType(ParseState *pstate, List *names, List *parameters) 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ collation, /* type's collation */ - 0); + F_ARRAY_SUBSCRIPT_HANDLER); pfree(array_type); @@ -1129,7 +1129,7 @@ DefineDomain(CreateDomainStmt *stmt) 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ domaincoll, /* type's collation */ - 0); /* array subscripting implementation */ + F_ARRAY_SUBSCRIPT_HANDLER); /* array subscripting implementation */ pfree(domainArrayName); @@ -1286,7 +1286,7 @@ DefineEnum(CreateEnumStmt *stmt) 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid, /* type's collation */ - 0); /* array subscripting implementation */ + F_ARRAY_SUBSCRIPT_HANDLER); /* array subscripting implementation */ pfree(enumArrayName); @@ -1618,7 +1618,7 @@ DefineRange(CreateRangeStmt *stmt) 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid, /* typcollation */ - 0); /* array subscripting implementation */ + F_ARRAY_SUBSCRIPT_HANDLER); /* array subscripting implementation */ pfree(rangeArrayName); diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index f90145fe52..1c47ceff2f 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -3067,7 +3067,7 @@ ExecEvalSubscriptingRef(ExprState *state, ExprEvalStep *op) if (sbsrefstate->isassignment) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), - errmsg("array subscript in assignment must not be null"))); + errmsg("subscript in assignment must not be null"))); *op->resnull = true; return false; } @@ -3139,9 +3139,20 @@ ExecEvalSubscriptingRefOld(ExprState *state, ExprEvalStep *op) void ExecEvalSubscriptingRefAssign(ExprState *state, ExprEvalStep *op) { - SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state; + SubscriptingRefState *sbsrefstate = op->d.sbsref.state; SubscriptRoutines *sbsroutines = sbsrefstate->sbsroutines; + /* + * For an assignment to a fixed-length container type, both the original + * container and the value to be assigned into it must be non-NULL, else we + * punt and return the original container. + */ + if (sbsrefstate->refattrlength > 0) + { + if (*op->resnull || sbsrefstate->replacenull) + return; + } + sbsrefstate->resnull = *op->resnull; *op->resvalue = sbsroutines->assign(*op->resvalue, sbsrefstate); *op->resnull = sbsrefstate->resnull; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 8ed30c011a..a5c41bbbd8 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -71,7 +71,7 @@ exprType(const Node *expr) const SubscriptingRef *sbsref = (const SubscriptingRef *) expr; /* slice and/or store operations yield the container type */ - if (sbsref->reflowerindexpr || sbsref->refassgnexpr) + if (IsAssignment(sbsref) || sbsref->reflowerindexpr) type = sbsref->refcontainertype; else type = sbsref->refelemtype; diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index ba2b93440b..fa717c53a0 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -331,17 +331,6 @@ transformContainerSubscripts(ParseState *pstate, lowerIndexpr = lappend(lowerIndexpr, subexpr); indexprSlice = lappend(indexprSlice, ai); } - else - Assert(ai->lidx == NULL && !ai->is_slice); - - if (ai->uidx) - subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind); - else - { - /* Slice with omitted upper bound, put NULL into the list */ - Assert(isSlice && ai->is_slice); - subexpr = NULL; - } subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind); upperIndexpr = lappend(upperIndexpr, subexpr); } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 8fd8604794..bcf4f89291 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -685,7 +685,7 @@ transformAssignmentIndirection(ParseState *pstate, Node *rhs, int location) { - Node *result = NULL; + Node *result; List *subscripts = NIL; bool isSlice = false; ListCell *i; @@ -870,6 +870,8 @@ transformAssignmentIndirection(ParseState *pstate, errhint("You will need to rewrite or cast the expression."), parser_errposition(pstate, location))); } + else + result = rhs; return result; } diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 5b2917d159..01a52c7e6c 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -25,14 +25,20 @@ #include "nodes/nodeFuncs.h" #include "nodes/supportnodes.h" #include "optimizer/optimizer.h" +#include "nodes/makefuncs.h" +#include "executor/execExpr.h" #include "utils/array.h" #include "utils/arrayaccess.h" #include "utils/builtins.h" #include "utils/datum.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/selfuncs.h" +#include "utils/syscache.h" #include "utils/typcache.h" +#include "parser/parse_node.h" +#include "parser/parse_coerce.h" /* @@ -159,7 +165,14 @@ static int width_bucket_array_variable(Datum operand, ArrayType *thresholds, Oid collation, TypeCacheEntry *typentry); +static SubscriptingRef *array_subscript_prepare(bool isAssignment, SubscriptingRef *sbsref); +static SubscriptingRef *array_subscript_validate(bool isAssignment, SubscriptingRef *sbsref, + ParseState *pstate); +static Datum array_subscript_fetch(Datum containerSource, + SubscriptingRefState *sbstate); +static Datum array_subscript_assign(Datum containerSource, + SubscriptingRefState *sbstate); /* * array_in : @@ -6599,3 +6612,279 @@ width_bucket_array_variable(Datum operand, return left; } + +/* + * Perform an actual data extraction or modification for the array + * subscripting. As a result the extracted Datum or the modified containers + * value will be returned. + */ +Datum +array_subscript_assign(Datum containerSource, SubscriptingRefState *sbstate) +{ + bool is_slice = (sbstate->numlower != 0); + IntArray u_index, l_index; + bool eisnull = sbstate->resnull; + int i = 0; + + if (sbstate->refelemlength == 0) + { + /* do one-time catalog lookups for type info */ + get_typlenbyvalalign(sbstate->refelemtype, + &sbstate->refelemlength, + &sbstate->refelembyval, + &sbstate->refelemalign); + } + + for(i = 0; i < sbstate->numupper; i++) + u_index.indx[i] = DatumGetInt32(sbstate->upperindex[i]); + + if (is_slice) + { + for(i = 0; i < sbstate->numlower; i++) + l_index.indx[i] = DatumGetInt32(sbstate->lowerindex[i]); + } + + /* + * For assignment to varlena arrays, we handle a NULL original array + * by substituting an empty (zero-dimensional) array; insertion of the + * new element will result in a singleton array value. It does not + * matter whether the new element is NULL. + */ + if (eisnull) + { + containerSource = PointerGetDatum(construct_empty_array(sbstate->refelemtype)); + sbstate->resnull = false; + eisnull = false; + } + + if (!is_slice) + return array_set_element(containerSource, sbstate->numupper, + u_index.indx, + sbstate->replacevalue, + sbstate->replacenull, + sbstate->refattrlength, + sbstate->refelemlength, + sbstate->refelembyval, + sbstate->refelemalign); + else + return array_set_slice(containerSource, sbstate->numupper, + u_index.indx, l_index.indx, + sbstate->upperprovided, + sbstate->lowerprovided, + sbstate->replacevalue, + sbstate->replacenull, + sbstate->refattrlength, + sbstate->refelemlength, + sbstate->refelembyval, + sbstate->refelemalign); +} + +Datum +array_subscript_fetch(Datum containerSource, SubscriptingRefState *sbstate) +{ + bool is_slice = (sbstate->numlower != 0); + IntArray u_index, l_index; + int i = 0; + + if (sbstate->refelemlength == 0) + { + /* do one-time catalog lookups for type info */ + get_typlenbyvalalign(sbstate->refelemtype, + &sbstate->refelemlength, + &sbstate->refelembyval, + &sbstate->refelemalign); + } + + for(i = 0; i < sbstate->numupper; i++) + u_index.indx[i] = DatumGetInt32(sbstate->upperindex[i]); + + if (is_slice) + { + for(i = 0; i < sbstate->numlower; i++) + l_index.indx[i] = DatumGetInt32(sbstate->lowerindex[i]); + } + + if (!is_slice) + return array_get_element(containerSource, sbstate->numupper, + u_index.indx, + sbstate->refattrlength, + sbstate->refelemlength, + sbstate->refelembyval, + sbstate->refelemalign, + &sbstate->resnull); + else + return array_get_slice(containerSource, sbstate->numupper, + u_index.indx, l_index.indx, + sbstate->upperprovided, + sbstate->lowerprovided, + sbstate->refattrlength, + sbstate->refelemlength, + sbstate->refelembyval, + sbstate->refelemalign); +} + +/* + * Handle array-type subscripting logic. + */ +Datum +array_subscript_handler(PG_FUNCTION_ARGS) +{ + SubscriptRoutines *sbsroutines = (SubscriptRoutines *) + palloc(sizeof(SubscriptRoutines)); + + sbsroutines->prepare = array_subscript_prepare; + sbsroutines->validate = array_subscript_validate; + sbsroutines->fetch = array_subscript_fetch; + sbsroutines->assign = array_subscript_assign; + + PG_RETURN_POINTER(sbsroutines); +} + +SubscriptingRef * +array_subscript_prepare(bool isAssignment, SubscriptingRef *sbsref) +{ + Oid array_type = sbsref->refcontainertype; + HeapTuple type_tuple_container; + Form_pg_type type_struct_container; + bool is_slice = sbsref->reflowerindexpr != NIL; + + /* Get the type tuple for the container */ + type_tuple_container = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_type)); + if (!HeapTupleIsValid(type_tuple_container)) + elog(ERROR, "cache lookup failed for type %u", array_type); + type_struct_container = (Form_pg_type) GETSTRUCT(type_tuple_container); + + /* needn't check typisdefined since this will fail anyway */ + sbsref->refelemtype = type_struct_container->typelem; + + /* Identify type that RHS must provide */ + if (isAssignment) + sbsref->refassgntype = is_slice ? sbsref->refcontainertype : sbsref->refelemtype; + + ReleaseSysCache(type_tuple_container); + + return sbsref; +} + +SubscriptingRef * +array_subscript_validate(bool isAssignment, SubscriptingRef *sbsref, + ParseState *pstate) +{ + bool is_slice = sbsref->reflowerindexpr != NIL; + Oid typeneeded = InvalidOid, + typesource = InvalidOid; + Node *new_from; + Node *subexpr; + List *upperIndexpr = NIL; + List *lowerIndexpr = NIL; + ListCell *u, *l, *s; + + foreach(u, sbsref->refupperindexpr) + { + subexpr = (Node *) lfirst(u); + + if (subexpr == NULL) + { + upperIndexpr = lappend(upperIndexpr, subexpr); + continue; + } + + subexpr = coerce_to_target_type(pstate, + subexpr, exprType(subexpr), + INT4OID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (subexpr == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("array subscript must have type integer"), + parser_errposition(pstate, exprLocation(subexpr)))); + + upperIndexpr = lappend(upperIndexpr, subexpr); + } + + sbsref->refupperindexpr = upperIndexpr; + + forboth(l, sbsref->reflowerindexpr, s, sbsref->refindexprslice) + { + A_Indices *ai = (A_Indices *) lfirst(s); + subexpr = (Node *) lfirst(l); + + if (subexpr == NULL && !ai->is_slice) + { + /* Make a constant 1 */ + subexpr = (Node *) makeConst(INT4OID, + -1, + InvalidOid, + sizeof(int32), + Int32GetDatum(1), + false, + true); /* pass by value */ + } + + if (subexpr == NULL) + { + lowerIndexpr = lappend(lowerIndexpr, subexpr); + continue; + } + + subexpr = coerce_to_target_type(pstate, + subexpr, exprType(subexpr), + INT4OID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (subexpr == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("array subscript must have type integer"), + parser_errposition(pstate, exprLocation(subexpr)))); + + lowerIndexpr = lappend(lowerIndexpr, subexpr); + } + + sbsref->reflowerindexpr = lowerIndexpr; + + if (isAssignment) + { + SubscriptingRef *assignRef = (SubscriptingRef *) sbsref; + Node *assignExpr = (Node *) assignRef->refassgnexpr; + + typesource = exprType(assignExpr); + typeneeded = is_slice ? sbsref->refcontainertype : sbsref->refelemtype; + new_from = coerce_to_target_type(pstate, + assignExpr, typesource, + typeneeded, sbsref->reftypmod, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (new_from == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("array assignment requires type %s" + " but expression is of type %s", + format_type_be(sbsref->refelemtype), + format_type_be(typesource)), + errhint("You will need to rewrite or cast the expression."), + parser_errposition(pstate, exprLocation(assignExpr)))); + assignRef->refassgnexpr = (Expr *) new_from; + } + + sbsref->refnestedfunc = F_ARRAY_SUBSCRIPT_HANDLER; + + /* Verify subscript list lengths are within limit */ + if (list_length(sbsref->refupperindexpr) > MAXDIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", + list_length(sbsref->refupperindexpr), MAXDIM))); + + if (list_length(sbsref->reflowerindexpr) > MAXDIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", + list_length(sbsref->reflowerindexpr), MAXDIM))); + + return sbsref; +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index a4e173b484..af0dc692bd 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -10473,6 +10473,13 @@ proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}', prosrc => 'pg_control_init' }, +{ oid => '4004', + descr => 'Array subscripting logic', + proname => 'array_subscript_handler', + prorettype => 'internal', + proargtypes => 'internal', + prosrc => 'array_subscript_handler' }, + # collation management functions { oid => '3445', descr => 'import collations from operating system', proname => 'pg_import_system_collations', procost => '100', diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index 4b7750d439..71b21a8a14 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -54,7 +54,8 @@ typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f', typcategory => 'S', typelem => 'char', typinput => 'namein', typoutput => 'nameout', typreceive => 'namerecv', typsend => 'namesend', - typalign => 'c', typcollation => '950' }, + typalign => 'c', typcollation => '950', + typsubshandler => 'array_subscript_handler' }, { oid => '20', array_type_oid => '1016', descr => '~18 digit integer, 8-byte storage', typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', @@ -70,7 +71,7 @@ typname => 'int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A', typelem => 'int2', typinput => 'int2vectorin', typoutput => 'int2vectorout', typreceive => 'int2vectorrecv', typsend => 'int2vectorsend', - typalign => 'i' }, + typalign => 'i', typsubshandler => 'array_subscript_handler' }, { oid => '23', array_type_oid => '1007', descr => '-2 billion to 2 billion integer, 4-byte storage', typname => 'int4', typlen => '4', typbyval => 't', typcategory => 'N', @@ -109,7 +110,8 @@ descr => 'array of oids, used in system tables', typname => 'oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A', typelem => 'oid', typinput => 'oidvectorin', typoutput => 'oidvectorout', - typreceive => 'oidvectorrecv', typsend => 'oidvectorsend', typalign => 'i' }, + typreceive => 'oidvectorrecv', typsend => 'oidvectorsend', typalign => 'i', + typsubshandler => 'array_subscript_handler' }, # hand-built rowtype entries for bootstrapped catalogs # NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations @@ -185,32 +187,37 @@ descr => 'geometric point \'(x, y)\'', typname => 'point', typlen => '16', typbyval => 'f', typcategory => 'G', typelem => 'float8', typinput => 'point_in', typoutput => 'point_out', - typreceive => 'point_recv', typsend => 'point_send', typalign => 'd' }, + typreceive => 'point_recv', typsend => 'point_send', typalign => 'd', + typsubshandler => 'array_subscript_handler' }, { oid => '601', array_type_oid => '1018', descr => 'geometric line segment \'(pt1,pt2)\'', typname => 'lseg', typlen => '32', typbyval => 'f', typcategory => 'G', typelem => 'point', typinput => 'lseg_in', typoutput => 'lseg_out', - typreceive => 'lseg_recv', typsend => 'lseg_send', typalign => 'd' }, + typreceive => 'lseg_recv', typsend => 'lseg_send', typalign => 'd', + typsubshandler => 'array_subscript_handler' }, { oid => '602', array_type_oid => '1019', descr => 'geometric path \'(pt1,...)\'', typname => 'path', typlen => '-1', typbyval => 'f', typcategory => 'G', typinput => 'path_in', typoutput => 'path_out', typreceive => 'path_recv', - typsend => 'path_send', typalign => 'd', typstorage => 'x' }, + typsend => 'path_send', typalign => 'd', typstorage => 'x', + typsubshandler => 'array_subscript_handler' }, { oid => '603', array_type_oid => '1020', descr => 'geometric box \'(lower left,upper right)\'', typname => 'box', typlen => '32', typbyval => 'f', typcategory => 'G', typdelim => ';', typelem => 'point', typinput => 'box_in', typoutput => 'box_out', typreceive => 'box_recv', typsend => 'box_send', - typalign => 'd' }, + typalign => 'd', typsubshandler => 'array_subscript_handler' }, { oid => '604', array_type_oid => '1027', descr => 'geometric polygon \'(pt1,...)\'', typname => 'polygon', typlen => '-1', typbyval => 'f', typcategory => 'G', typinput => 'poly_in', typoutput => 'poly_out', typreceive => 'poly_recv', - typsend => 'poly_send', typalign => 'd', typstorage => 'x' }, + typsend => 'poly_send', typalign => 'd', typstorage => 'x', + typsubshandler => 'array_subscript_handler' }, { oid => '628', array_type_oid => '629', descr => 'geometric line', typname => 'line', typlen => '24', typbyval => 'f', typcategory => 'G', typelem => 'float8', typinput => 'line_in', typoutput => 'line_out', - typreceive => 'line_recv', typsend => 'line_send', typalign => 'd' }, + typreceive => 'line_recv', typsend => 'line_send', typalign => 'd', + typsubshandler => 'array_subscript_handler' }, # OIDS 700 - 799 @@ -269,7 +276,7 @@ { oid => '1033', array_type_oid => '1034', descr => 'access control list', typname => 'aclitem', typlen => '12', typbyval => 'f', typcategory => 'U', typinput => 'aclitemin', typoutput => 'aclitemout', typreceive => '-', - typsend => '-', typalign => 'i' }, + typsend => '-', typalign => 'i', typsubshandler => 'array_subscript_handler' }, { oid => '1042', array_type_oid => '1014', descr => 'char(length), blank-padded string, fixed storage length', typname => 'bpchar', typlen => '-1', typbyval => 'f', typcategory => 'S', @@ -308,7 +315,8 @@ typcategory => 'D', typispreferred => 't', typinput => 'timestamptz_in', typoutput => 'timestamptz_out', typreceive => 'timestamptz_recv', typsend => 'timestamptz_send', typmodin => 'timestamptztypmodin', - typmodout => 'timestamptztypmodout', typalign => 'd' }, + typmodout => 'timestamptztypmodout', typalign => 'd', + typsubshandler => 'array_subscript_handler' }, { oid => '1186', array_type_oid => '1187', descr => '@ , time interval', typname => 'interval', typlen => '16', typbyval => 'f', typcategory => 'T', diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index c730563f03..f54b73c9da 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -190,9 +190,9 @@ select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2]; -- -- check subscription corner cases -- --- More subscripts than MAXDIMS(6) -SELECT ('{}'::int[])[1][2][3][4][5][6][7]; -ERROR: number of array dimensions (7) exceeds the maximum allowed (6) +-- More subscripts than MAXDIMS(12) +SELECT ('{}'::int[])[1][2][3][4][5][6][7][8][9][10][11][12][13]; +ERROR: number of array dimensions (13) exceeds the maximum allowed (6) -- NULL index yields NULL when selecting SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL][1]; int4 @@ -216,15 +216,15 @@ SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][1:NULL][1]; UPDATE arrtest SET c[NULL] = '{"can''t assign"}' WHERE array_dims(c) is not null; -ERROR: array subscript in assignment must not be null +ERROR: subscript in assignment must not be null UPDATE arrtest SET c[NULL:1] = '{"can''t assign"}' WHERE array_dims(c) is not null; -ERROR: array subscript in assignment must not be null +ERROR: subscript in assignment must not be null UPDATE arrtest SET c[1:NULL] = '{"can''t assign"}' WHERE array_dims(c) is not null; -ERROR: array subscript in assignment must not be null +ERROR: subscript in assignment must not be null -- test slices with empty lower and/or upper index CREATE TEMP TABLE arrtest_s ( a int2[], diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index 25dd4e2c6d..fb7a319118 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -106,8 +106,8 @@ select ('[0:2][0:2]={{1,2,3},{4,5,6},{7,8,9}}'::int[])[1:2][2]; -- -- check subscription corner cases -- --- More subscripts than MAXDIMS(6) -SELECT ('{}'::int[])[1][2][3][4][5][6][7]; +-- More subscripts than MAXDIMS(12) +SELECT ('{}'::int[])[1][2][3][4][5][6][7][8][9][10][11][12][13]; -- NULL index yields NULL when selecting SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL][1]; SELECT ('{{{1},{2},{3}},{{4},{5},{6}}}'::int[])[1][NULL:1][1]; -- 2.16.4