On 2021-02-03 15:52, Peter Eisentraut wrote:
On 2021-02-02 13:26, Heikki Linnakangas wrote:
How about this?

CREATE TABLE fail_part PARTITION OF hash_parted FOR VALUES WITH (MODULUS
25, REMAINDER 3);
ERROR:  every hash partition modulus must be a factor of the next larger
modulus
DETAIL:  25 is not divisible by 10, the modulus of existing partition
"hpart_1"

I don't know if we can easily get the name of the existing partition.
I'll have to check that.

I'm worried that this phrasing requires the user to understand that
"divisible by" is related to "factor of", which is of course correct but
introduces yet more complexity into this.

I'll play around with this a bit more.

Here is a new patch that implements the suggestions.
From 537e8f2f27e43b94777b962e408245fb1d4784dd Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 15 Feb 2021 17:10:11 +0100
Subject: [PATCH v2] Improve new hash partition bound check error messages

For the error message "every hash partition modulus must be a factor
of the next larger modulus", add a detail message that shows the
particular numbers involved.  Also comment the code more.

Discussion: 
https://www.postgresql.org/message-id/flat/bb9d60b4-aadb-607a-1a9d-fdc3434dddcd%40enterprisedb.com
---
 src/backend/partitioning/partbounds.c      | 62 +++++++++++++++-------
 src/test/regress/expected/alter_table.out  |  1 +
 src/test/regress/expected/create_table.out |  2 +
 3 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/src/backend/partitioning/partbounds.c 
b/src/backend/partitioning/partbounds.c
index 0c3f212ff2..02cd58ce5f 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -2832,14 +2832,9 @@ check_new_partition_bound(char *relname, Relation parent,
 
                                if (partdesc->nparts > 0)
                                {
-                                       Datum     **datums = boundinfo->datums;
-                                       int                     ndatums = 
boundinfo->ndatums;
                                        int                     
greatest_modulus;
                                        int                     remainder;
                                        int                     offset;
-                                       bool            valid_modulus = true;
-                                       int                     prev_modulus,   
/* Previous largest modulus */
-                                                               next_modulus;   
/* Next largest modulus */
 
                                        /*
                                         * Check rule that every modulus must 
be a factor of the
@@ -2849,7 +2844,9 @@ check_new_partition_bound(char *relname, Relation parent,
                                         * modulus 15, but you cannot add both 
a partition with
                                         * modulus 10 and a partition with 
modulus 15, because 10
                                         * is not a factor of 15.
-                                        *
+                                        */
+
+                                       /*
                                         * Get the greatest (modulus, 
remainder) pair contained in
                                         * boundinfo->datums that is less than 
or equal to the
                                         * (spec->modulus, spec->remainder) 
pair.
@@ -2859,26 +2856,55 @@ check_new_partition_bound(char *relname, Relation 
parent,
                                                                                
                        spec->remainder);
                                        if (offset < 0)
                                        {
-                                               next_modulus = 
DatumGetInt32(datums[0][0]);
-                                               valid_modulus = (next_modulus % 
spec->modulus) == 0;
+                                               int                     
next_modulus;
+
+                                               /*
+                                                * All existing moduli are 
greater or equal, so the
+                                                * new one must be a factor of 
the smallest one, which
+                                                * is first in the boundinfo.
+                                                */
+                                               next_modulus = 
DatumGetInt32(boundinfo->datums[0][0]);
+                                               if (next_modulus % 
spec->modulus != 0)
+                                                       ereport(ERROR,
+                                                                       
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                                                        
errmsg("every hash partition modulus must be a factor of the next larger 
modulus"),
+                                                                        
errdetail("The new modulus %d is not a factor of %d, the modulus of existing 
partition \"%s\".",
+                                                                               
           spec->modulus, next_modulus,
+                                                                               
           get_rel_name(partdesc->oids[boundinfo->indexes[0]]))));
                                        }
                                        else
                                        {
-                                               prev_modulus = 
DatumGetInt32(datums[offset][0]);
-                                               valid_modulus = (spec->modulus 
% prev_modulus) == 0;
+                                               int                     
prev_modulus;
+
+                                               /* We found the largest modulus 
less than or equal to ours. */
+                                               prev_modulus = 
DatumGetInt32(boundinfo->datums[offset][0]);
+
+                                               if (spec->modulus % 
prev_modulus != 0)
+                                                       ereport(ERROR,
+                                                                       
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                                                        
errmsg("every hash partition modulus must be a factor of the next larger 
modulus"),
+                                                                        
errdetail("The new modulus %d is not divisible by %d, the modulus of existing 
partition \"%s\".",
+                                                                               
           spec->modulus,
+                                                                               
           prev_modulus,
+                                                                               
           get_rel_name(partdesc->oids[boundinfo->indexes[offset]]))));
 
-                                               if (valid_modulus && (offset + 
1) < ndatums)
+                                               if (offset + 1 < 
boundinfo->ndatums)
                                                {
-                                                       next_modulus = 
DatumGetInt32(datums[offset + 1][0]);
-                                                       valid_modulus = 
(next_modulus % spec->modulus) == 0;
+                                                       int                     
next_modulus;
+
+                                                       /* Look at the next 
higher modulus */
+                                                       next_modulus = 
DatumGetInt32(boundinfo->datums[offset + 1][0]);
+
+                                                       if (next_modulus % 
spec->modulus != 0)
+                                                               ereport(ERROR,
+                                                                               
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                                                               
 errmsg("every hash partition modulus must be a factor of the next larger 
modulus"),
+                                                                               
 errdetail("The new modulus %d is not factor of %d, the modulus of existing 
partition \"%s\".",
+                                                                               
                   spec->modulus, next_modulus,
+                                                                               
                   get_rel_name(partdesc->oids[boundinfo->indexes[offset + 
1]]))));
                                                }
                                        }
 
-                                       if (!valid_modulus)
-                                               ereport(ERROR,
-                                                               
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-                                                                errmsg("every 
hash partition modulus must be a factor of the next larger modulus")));
-
                                        greatest_modulus = boundinfo->nindexes;
                                        remainder = spec->remainder;
 
diff --git a/src/test/regress/expected/alter_table.out 
b/src/test/regress/expected/alter_table.out
index 0ce6ee4622..bb3f873f22 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -4109,6 +4109,7 @@ ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR 
VALUES WITH (MODULUS 8, R
 ERROR:  remainder for hash partition must be less than modulus
 ALTER TABLE hash_parted ATTACH PARTITION fail_part FOR VALUES WITH (MODULUS 3, 
REMAINDER 2);
 ERROR:  every hash partition modulus must be a factor of the next larger 
modulus
+DETAIL:  The new modulus 3 is not a factor of 4, the modulus of existing 
partition "hpart_1".
 DROP TABLE fail_part;
 --
 -- DETACH PARTITION
diff --git a/src/test/regress/expected/create_table.out 
b/src/test/regress/expected/create_table.out
index ed8c01b8de..a392df2d6a 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -783,9 +783,11 @@ CREATE TABLE hpart_3 PARTITION OF hash_parted FOR VALUES 
WITH (MODULUS 200, REMA
 -- modulus 25 is factor of modulus of 50 but 10 is not factor of 25.
 CREATE TABLE fail_part PARTITION OF hash_parted FOR VALUES WITH (MODULUS 25, 
REMAINDER 3);
 ERROR:  every hash partition modulus must be a factor of the next larger 
modulus
+DETAIL:  The new modulus 25 is not divisible by 10, the modulus of existing 
partition "hpart_1".
 -- previous modulus 50 is factor of 150 but this modulus is not factor of next 
modulus 200.
 CREATE TABLE fail_part PARTITION OF hash_parted FOR VALUES WITH (MODULUS 150, 
REMAINDER 3);
 ERROR:  every hash partition modulus must be a factor of the next larger 
modulus
+DETAIL:  The new modulus 150 is not factor of 200, the modulus of existing 
partition "hpart_3".
 -- trying to specify range for the hash partitioned table
 CREATE TABLE fail_part PARTITION OF hash_parted FOR VALUES FROM ('a', 1) TO 
('z');
 ERROR:  invalid bound specification for a hash partition
-- 
2.30.0

Reply via email to