]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix assignment to array of domain over composite.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 19 Oct 2021 17:54:46 +0000 (13:54 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 19 Oct 2021 17:54:46 +0000 (13:54 -0400)
An update such as "UPDATE ... SET fld[n].subfld = whatever"
failed if the array elements were domains rather than plain
composites.  That's because isAssignmentIndirectionExpr()
failed to cope with the CoerceToDomain node that would appear
in the expression tree in this case.  The result would typically
be a crash, and even if we accidentally didn't crash, we'd not
correctly preserve other fields of the same array element.

Per report from Onder Kalaci.  Back-patch to v11 where arrays of
domains came in.

Discussion: https://postgr.es/m/PH0PR21MB132823A46AA36F0685B7A29AD8BD9@PH0PR21MB1328.namprd21.prod.outlook.com

src/backend/executor/execExpr.c
src/test/regress/expected/domain.out
src/test/regress/sql/domain.sql

index 427516d224bebef8c18802d200aea48ec979f857..b671259ff98cde02e6e02dd3c73b2f953d3bd3d9 100644 (file)
@@ -2768,11 +2768,14 @@ ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref,
  * (We could use this in FieldStore too, but in that case passing the old
  * value is so cheap there's no need.)
  *
- * Note: it might seem that this needs to recurse, but it does not; the
- * CaseTestExpr, if any, will be directly the arg or refexpr of the top-level
- * node.  Nested-assignment situations give rise to expression trees in which
- * each level of assignment has its own CaseTestExpr, and the recursive
- * structure appears within the newvals or refassgnexpr field.
+ * Note: it might seem that this needs to recurse, but in most cases it does
+ * not; the CaseTestExpr, if any, will be directly the arg or refexpr of the
+ * top-level node.  Nested-assignment situations give rise to expression
+ * trees in which each level of assignment has its own CaseTestExpr, and the
+ * recursive structure appears within the newvals or refassgnexpr field.
+ * There is an exception, though: if the array is an array-of-domain, we will
+ * have a CoerceToDomain as the refassgnexpr, and we need to be able to look
+ * through that.
  */
 static bool
 isAssignmentIndirectionExpr(Expr *expr)
@@ -2793,6 +2796,12 @@ isAssignmentIndirectionExpr(Expr *expr)
                if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
                        return true;
        }
+       else if (IsA(expr, CoerceToDomain))
+       {
+               CoerceToDomain *cd = (CoerceToDomain *) expr;
+
+               return isAssignmentIndirectionExpr(cd->arg);
+       }
        return false;
 }
 
index 4ff1b4af418b8b9fc3ad083e610d29f85a18ccca..579a3d5f13fa2eaeb0ab83bbbb7dab2e42833326 100644 (file)
@@ -518,6 +518,30 @@ LINE 1: update dposintatable set (f1[2])[1] = array[98];
 drop table dposintatable;
 drop domain posint cascade;
 NOTICE:  drop cascades to type dposinta
+-- Test arrays over domains of composite
+create type comptype as (cf1 int, cf2 int);
+create domain dcomptype as comptype check ((value).cf1 > 0);
+create table dcomptable (f1 dcomptype[]);
+insert into dcomptable values (null);
+update dcomptable set f1[1].cf2 = 5;
+table dcomptable;
+    f1    
+----------
+ {"(,5)"}
+(1 row)
+
+update dcomptable set f1[1].cf1 = -1;  -- fail
+ERROR:  value for domain dcomptype violates check constraint "dcomptype_check"
+update dcomptable set f1[1].cf1 = 1;
+table dcomptable;
+    f1     
+-----------
+ {"(1,5)"}
+(1 row)
+
+drop table dcomptable;
+drop type comptype cascade;
+NOTICE:  drop cascades to type dcomptype
 -- Test not-null restrictions
 create domain dnotnull varchar(15) NOT NULL;
 create domain dnull    varchar(15);
index 1291d550d687ef7d2c7b10196a95e31bd1fe65d6..55c7cf74533fb312709bcac5729c432cf6337efb 100644 (file)
@@ -268,6 +268,23 @@ drop table dposintatable;
 drop domain posint cascade;
 
 
+-- Test arrays over domains of composite
+
+create type comptype as (cf1 int, cf2 int);
+create domain dcomptype as comptype check ((value).cf1 > 0);
+
+create table dcomptable (f1 dcomptype[]);
+insert into dcomptable values (null);
+update dcomptable set f1[1].cf2 = 5;
+table dcomptable;
+update dcomptable set f1[1].cf1 = -1;  -- fail
+update dcomptable set f1[1].cf1 = 1;
+table dcomptable;
+
+drop table dcomptable;
+drop type comptype cascade;
+
+
 -- Test not-null restrictions
 
 create domain dnotnull varchar(15) NOT NULL;