Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit529cb26

Browse files
committed
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinkingabout the difference between a domain type and its underlying array type.In particular, the operation of updating one element of such an arrayhas to be considered as yielding a value of the underlying array type,*not* a value of the domain, because there's no assurance that thedomain's CHECK constraints are still satisfied. If we're intending tostore the result back into a domain column, we have to re-cast to thedomain type so that constraints are re-checked.For similar reasons, such a domain can't be blindly matched to an ANYARRAYpolymorphic parameter, because the polymorphic function is likely to applyarray-ish operations that could invalidate the domain constraints. For themoment, we just forbid such matching. We might later wish to insert anautomatic downcast to the underlying array type, but such a change shouldalso change matching of domains to ANYELEMENT for consistency.To ensure that all such logic is rechecked, this patch removes the originalhack of setting a domain's pg_type.typelem field to match its base type;the typelem will always be zero instead. In those places where it's reallyokay to look through the domain type with no other logic changes, use thenewly added get_base_element_type function in place of get_element_type.catversion bumped due to change in pg_type contents.Per bug #5717 from Richard Huxton and subsequent discussion.
1 parent572ab1a commit529cb26

File tree

21 files changed

+439
-101
lines changed

21 files changed

+439
-101
lines changed

‎doc/src/sgml/catalogs.sgml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5698,9 +5698,8 @@
56985698
<entry></entry>
56995699
<entry><para>
57005700
<structfield>typndims</structfield> is the number of array dimensions
5701-
for a domain that is an array (that is, <structfield>typbasetype</> is
5702-
an array type; the domain's <structfield>typelem</> will match the base
5703-
type's <structfield>typelem</structfield>).
5701+
for a domain over an array (that is, <structfield>typbasetype</> is
5702+
an array type).
57045703
Zero for types other than domains over array types.
57055704
</para></entry>
57065705
</row>

‎src/backend/commands/functioncmds.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,23 @@ CreateCast(CreateCastStmt *stmt)
16571657
ereport(ERROR,
16581658
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
16591659
errmsg("array data types are not binary-compatible")));
1660+
1661+
/*
1662+
* We also disallow creating binary-compatibility casts involving
1663+
* domains. Casting from a domain to its base type is already
1664+
* allowed, and casting the other way ought to go through domain
1665+
* coercion to permit constraint checking. Again, if you're intent on
1666+
* having your own semantics for that, create a no-op cast function.
1667+
*
1668+
* NOTE: if we were to relax this, the above checks for composites
1669+
* etc. would have to be modified to look through domains to their
1670+
* base types.
1671+
*/
1672+
if (sourcetyptype==TYPTYPE_DOMAIN||
1673+
targettyptype==TYPTYPE_DOMAIN)
1674+
ereport(ERROR,
1675+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1676+
errmsg("domain data types must not be marked binary-compatible")));
16601677
}
16611678

16621679
/*

‎src/backend/commands/typecmds.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -525,14 +525,12 @@ DefineType(List *names, List *parameters)
525525

526526
/*
527527
* now have TypeCreate do all the real work.
528+
*
529+
* Note: the pg_type.oid is stored in user tables as array elements (base
530+
* types) in ArrayType and in composite types in DatumTupleFields. This
531+
* oid must be preserved by binary upgrades.
528532
*/
529533
typoid=
530-
531-
/*
532-
* The pg_type.oid is stored in user tables as array elements (base types)
533-
* in ArrayType and in composite types in DatumTupleFields. This oid must
534-
* be preserved by binary upgrades.
535-
*/
536534
TypeCreate(InvalidOid,/* no predetermined type OID */
537535
typeName,/* type name */
538536
typeNamespace,/* namespace */
@@ -746,7 +744,6 @@ DefineDomain(CreateDomainStmt *stmt)
746744
OidsendProcedure;
747745
OidanalyzeProcedure;
748746
boolbyValue;
749-
Oidtypelem;
750747
charcategory;
751748
chardelimiter;
752749
charalignment;
@@ -831,9 +828,6 @@ DefineDomain(CreateDomainStmt *stmt)
831828
/* Type Category */
832829
category=baseType->typcategory;
833830

834-
/* Array element type (in case base type is an array) */
835-
typelem=baseType->typelem;
836-
837831
/* Array element Delimiter */
838832
delimiter=baseType->typdelim;
839833

@@ -1033,7 +1027,7 @@ DefineDomain(CreateDomainStmt *stmt)
10331027
InvalidOid,/* typmodin procedure - none */
10341028
InvalidOid,/* typmodout procedure - none */
10351029
analyzeProcedure,/* analyze procedure */
1036-
typelem,/* element type ID */
1030+
InvalidOid,/*no arrayelement type */
10371031
false,/* this isn't an array */
10381032
InvalidOid,/* no arrays for domains (yet) */
10391033
basetypeoid,/* base type ID */
@@ -1670,7 +1664,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
16701664
typTup->typmodin,
16711665
typTup->typmodout,
16721666
typTup->typanalyze,
1673-
typTup->typelem,
1667+
InvalidOid,
16741668
false,/* a domain isn't an implicit array */
16751669
typTup->typbasetype,
16761670
defaultExpr,

‎src/backend/parser/parse_coerce.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,9 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
19081908
* array types. If so, and if the element types have a suitable cast,
19091909
* report that we can coerce with an ArrayCoerceExpr.
19101910
*
1911+
* Note that the source type can be a domain over array, but not the
1912+
* target, because ArrayCoerceExpr won't check domain constraints.
1913+
*
19111914
* Hack: disallow coercions to oidvector and int2vector, which
19121915
* otherwise tend to capture coercions that should go to "real" array
19131916
* types. We want those types to be considered "real" arrays for many
@@ -1921,7 +1924,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
19211924
OidsourceElem;
19221925

19231926
if ((targetElem=get_element_type(targetTypeId))!=InvalidOid&&
1924-
(sourceElem=get_element_type(sourceTypeId))!=InvalidOid)
1927+
(sourceElem=get_base_element_type(sourceTypeId))!=InvalidOid)
19251928
{
19261929
CoercionPathTypeelempathtype;
19271930
Oidelemfuncid;
@@ -2001,10 +2004,8 @@ find_typmod_coercion_function(Oid typeId,
20012004
targetType=typeidType(typeId);
20022005
typeForm= (Form_pg_type)GETSTRUCT(targetType);
20032006

2004-
/* Check for a varlena array type (and not a domain) */
2005-
if (typeForm->typelem!=InvalidOid&&
2006-
typeForm->typlen==-1&&
2007-
typeForm->typtype!=TYPTYPE_DOMAIN)
2007+
/* Check for a varlena array type */
2008+
if (typeForm->typelem!=InvalidOid&&typeForm->typlen==-1)
20082009
{
20092010
/* Yes, switch our attention to the element type */
20102011
typeId=typeForm->typelem;

‎src/backend/parser/parse_expr.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,19 +161,17 @@ transformExpr(ParseState *pstate, Node *expr)
161161

162162
targetType=typenameTypeId(pstate,tc->typeName,
163163
&targetTypmod);
164+
/*
165+
* If target is a domain over array, work with the base
166+
* array type here. transformTypeCast below will cast the
167+
* array type to the domain. In the usual case that the
168+
* target is not a domain, transformTypeCast is a no-op.
169+
*/
170+
targetType=getBaseTypeAndTypmod(targetType,
171+
&targetTypmod);
164172
elementType=get_element_type(targetType);
165173
if (OidIsValid(elementType))
166174
{
167-
/*
168-
* tranformArrayExpr doesn't know how to check domain
169-
* constraints, so ask it to return the base type
170-
* instead. transformTypeCast below will cast it to
171-
* the domain. In the usual case that the target is
172-
* not a domain, transformTypeCast is a no-op.
173-
*/
174-
targetType=getBaseTypeAndTypmod(targetType,
175-
&targetTypmod);
176-
177175
tc=copyObject(tc);
178176
tc->arg=transformArrayExpr(pstate,
179177
(A_ArrayExpr*)tc->arg,

‎src/backend/parser/parse_node.c

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include"parser/parse_relation.h"
2626
#include"utils/builtins.h"
2727
#include"utils/int8.h"
28+
#include"utils/lsyscache.h"
2829
#include"utils/syscache.h"
2930
#include"utils/varbit.h"
3031

@@ -198,19 +199,35 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
198199

199200
/*
200201
* transformArrayType()
201-
*Get the element type of an array type in preparation for subscripting
202+
*Identify the types involved in a subscripting operation
203+
*
204+
* On entry, arrayType/arrayTypmod identify the type of the input value
205+
* to be subscripted (which could be a domain type). These are modified
206+
* if necessary to identify the actual array type and typmod, and the
207+
* array's element type is returned. An error is thrown if the input isn't
208+
* an array type.
202209
*/
203210
Oid
204-
transformArrayType(OidarrayType)
211+
transformArrayType(Oid*arrayType,int32*arrayTypmod)
205212
{
213+
OidorigArrayType=*arrayType;
206214
OidelementType;
207215
HeapTupletype_tuple_array;
208216
Form_pg_typetype_struct_array;
209217

218+
/*
219+
* If the input is a domain, smash to base type, and extract the actual
220+
* typmod to be applied to the base type. Subscripting a domain is an
221+
* operation that necessarily works on the base array type, not the domain
222+
* itself. (Note that we provide no method whereby the creator of a
223+
* domain over an array type could hide its ability to be subscripted.)
224+
*/
225+
*arrayType=getBaseTypeAndTypmod(*arrayType,arrayTypmod);
226+
210227
/* Get the type tuple for the array */
211-
type_tuple_array=SearchSysCache1(TYPEOID,ObjectIdGetDatum(arrayType));
228+
type_tuple_array=SearchSysCache1(TYPEOID,ObjectIdGetDatum(*arrayType));
212229
if (!HeapTupleIsValid(type_tuple_array))
213-
elog(ERROR,"cache lookup failed for type %u",arrayType);
230+
elog(ERROR,"cache lookup failed for type %u",*arrayType);
214231
type_struct_array= (Form_pg_type)GETSTRUCT(type_tuple_array);
215232

216233
/* needn't check typisdefined since this will fail anyway */
@@ -220,7 +237,7 @@ transformArrayType(Oid arrayType)
220237
ereport(ERROR,
221238
(errcode(ERRCODE_DATATYPE_MISMATCH),
222239
errmsg("cannot subscript type %s because it is not an array",
223-
format_type_be(arrayType))));
240+
format_type_be(origArrayType))));
224241

225242
ReleaseSysCache(type_tuple_array);
226243

@@ -241,13 +258,17 @@ transformArrayType(Oid arrayType)
241258
* that array.We produce an expression that represents the new array value
242259
* with the source data inserted into the right part of the array.
243260
*
261+
* For both cases, if the source array is of a domain-over-array type,
262+
* the result is of the base array type or its element type; essentially,
263+
* we must fold a domain to its base type before applying subscripting.
264+
*
244265
* pstateParse state
245266
* arrayBaseAlready-transformed expression for the array as a whole
246-
* arrayTypeOID of array's datatype (should match type of arrayBase)
267+
* arrayTypeOID of array's datatype (should match type of arrayBase,
268+
*or be the base type of arrayBase's domain type)
247269
* elementTypeOID of array's element type (fetch with transformArrayType,
248270
*or pass InvalidOid to do it here)
249-
* elementTypMod typmod to be applied to array elements (if storing) or of
250-
*the source array (if fetching)
271+
* arrayTypModtypmod for the array (which is also typmod for the elements)
251272
* indirectionUntransformed list of subscripts (must not be NIL)
252273
* assignFromNULL for array fetch, else transformed expression for source.
253274
*/
@@ -256,7 +277,7 @@ transformArraySubscripts(ParseState *pstate,
256277
Node*arrayBase,
257278
OidarrayType,
258279
OidelementType,
259-
int32elementTypMod,
280+
int32arrayTypMod,
260281
List*indirection,
261282
Node*assignFrom)
262283
{
@@ -266,9 +287,13 @@ transformArraySubscripts(ParseState *pstate,
266287
ListCell*idx;
267288
ArrayRef*aref;
268289

269-
/* Caller may or may not have bothered to determine elementType */
290+
/*
291+
* Caller may or may not have bothered to determine elementType. Note
292+
* that if the caller did do so, arrayType/arrayTypMod must be as
293+
* modified by transformArrayType, ie, smash domain to base type.
294+
*/
270295
if (!OidIsValid(elementType))
271-
elementType=transformArrayType(arrayType);
296+
elementType=transformArrayType(&arrayType,&arrayTypMod);
272297

273298
/*
274299
* A list containing only single subscripts refers to a single array
@@ -356,7 +381,7 @@ transformArraySubscripts(ParseState *pstate,
356381

357382
newFrom=coerce_to_target_type(pstate,
358383
assignFrom,typesource,
359-
typeneeded,elementTypMod,
384+
typeneeded,arrayTypMod,
360385
COERCION_ASSIGNMENT,
361386
COERCE_IMPLICIT_CAST,
362387
-1);
@@ -378,7 +403,7 @@ transformArraySubscripts(ParseState *pstate,
378403
aref=makeNode(ArrayRef);
379404
aref->refarraytype=arrayType;
380405
aref->refelemtype=elementType;
381-
aref->reftypmod=elementTypMod;
406+
aref->reftypmod=arrayTypMod;
382407
aref->refupperindexpr=upperIndexpr;
383408
aref->reflowerindexpr=lowerIndexpr;
384409
aref->refexpr= (Expr*)arrayBase;

‎src/backend/parser/parse_oper.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ get_sort_group_operators(Oid argtype,
209209
eq_opr==ARRAY_EQ_OP||
210210
gt_opr==ARRAY_GT_OP)
211211
{
212-
Oidelem_type=get_element_type(argtype);
212+
Oidelem_type=get_base_element_type(argtype);
213213

214214
if (OidIsValid(elem_type))
215215
{
@@ -906,7 +906,7 @@ make_scalar_array_op(ParseState *pstate, List *opname,
906906
rtypeId=UNKNOWNOID;
907907
else
908908
{
909-
rtypeId=get_element_type(atypeId);
909+
rtypeId=get_base_element_type(atypeId);
910910
if (!OidIsValid(rtypeId))
911911
ereport(ERROR,
912912
(errcode(ERRCODE_WRONG_OBJECT_TYPE),

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp