Column name in error text: value too long for type character - postgresql

We have a table with 2 columns (both have the same type and size) and 2 constraints for them:
create table colors
(
color varchar(6)
constraint color_check check
((color)::text ~ '^[0-9a-fA-F]{6}$'::text),
color_secodandry varchar(6)
constraint color_secondary_check check
((color_secodandry)::text ~ '^[0-9a-fA-F]{6}$'::text),
);
In case of inserts with long values:
insert into colors (color, color_secondary) values ('ccaabb', 'TOO_LONG_TEXT');
insert into colors (color, color_secondary) values ('TOO_LONG_TEXT', 'ccaabb');
we'll get the same errors for two error cases:
ERROR: value too long for type character varying(6) (SQLSTATE 22001)
PostgreSQL validates length for that columns before make inserts, so our checks never run. Is there a way to understand, which column has an invalid data?

The issue you are having is the order of evaluation for the intended values. You told Postgres to not allow a length over 6 (character varying(6)) you also specified additional certain criteria those values have to satisfy. What is happening is Postgres validates the length criteria and throws an exception when the value fails, in that case the check constraint is not preformed as Postgres works on an exit on first failure. The check constraint is processed only after the length passes. Example:
create table test1( id integer generated always as identity
, color6 character varying (6)
constraint color6_check check (color6 ~ '^[0-9a-fA-F]{6}$')
, color60 character varying (60)
constraint color60_check check (color60 ~ '^[0-9a-fA-F]{6}$')
) ;
insert into test1( color6 ) values ('aabbccdd') ;
/* Result
SQL Error [22001]: ERROR: value too long for type character varying(6)
ERROR: value too long for type character varying(6)
*/
insert into test1( color60 ) values ('aabbccdd') ;
/* Result
SQL Error [23514]: ERROR: new row for relation "test1" violates check constraint "color60_check"
Detail: Failing row contains (3, null, aabbccdd).
ERROR: new row for relation "test1" violates check constraint "color60_check"
*/
Notice the only difference between them is the length specification for the column being inserted. Yet they fail, but for a different reasons. Since both the length specification and the check constraint enforce the length you need to decide now how you want to handle the 2 conditions: a separate error for each condition or a single error for both. (IMHO: separate messages)

Related

How to limit the length of array text objects in PostgreSQL?

Is there any way to add a constraint on a column that is an array to limit length text objects?
I know that I can do this without constraint:
colA varchar(100)[] not null
I tried to do it in the following way:
alter table "tableA" ADD CONSTRAINT "colA_text_size"
CHECK ((SELECT max(length(pc)) from unnest(colA) as pc) <= 100) NOT VALID;
alter table "tableA" VALIDATE CONSTRAINT colA_text_size;
But got error: cannot use subquery in check constraint (SQLSTATE 0A000)
Try the following definition for your check constraint: (see demo, for demo I limit length to 25).
check (length(replace(array_to_string( text_array ,','), ',','')) <= 100)
What it does:
First the function array_to_string( ... ) converts the array to a csv.
The replace() function then removes the commas replacing them with the zero length string ''.
The length() function gets number of remaining characters in the string.
Finally that number is compared to the limit value (100) and the check constraint is either passed of failed.
References:
array_to_string(),
replace(), length()

Check if character varying is between range of numbers

I hava data in my database and i need to select all data where 1 column number is between 1-100.
Im having problems, because i cant use - between 1 and 100; Because that column is character varying, not integer. But all data are numbers (i cant change it to integer).
Code;
dst_db1.eachRow("Select length_to_fault from diags where length_to_fault between 1 AND 100")
Error - operator does not exist: character varying >= integer
Since your column supposed to contain numeric values but is defined as text (or version of text) there will be times when it does not i.e. You need 2 validations: that the column actually contains numeric data and that it falls into your value restriction. So add the following predicates to your query.
and length_to_fault ~ '^\+?\d+(\.\d*)?$'
and length_to_fault::numeric <# ('[1.0,100.0]')::numrange;
The first builds a regexp that insures the column is a valid floating point value. The second insures the numeric value fall within the specified numeric range. See fiddle.
I understand you cannot change the database, but this looks like a good place for a check constraint esp. if n/a is the only non-numeric are allowed. You may want to talk with your DBA ans see about the following constraint.
alter table diags
add constraint length_to_fault_check
check ( lower(length_to_fault) = 'n/a'
or ( length_to_fault ~ '^\+?\d+(\.\d*)?$'
and length_to_fault::numeric <# ('[1.0,100.0]')::numrange
)
);
Then your query need only check that:
lower(lenth_to_fault) != 'n/a'
The below PostgreSQL query will work
SELECT length_to_fault FROM diags WHERE regexp_replace(length_to_fault, '[\s+]', '', 'g')::numeric BETWEEN 1 AND 100;

Is posible to get better error message when a domain check fail on postgresql?

I create a domain to catch empty strings:
CREATE DOMAIN TEXTN AS TEXT
CONSTRAINT non_empty CHECK (length(VALUE) > 0);
Then I replace all text/varchars fields on the DB with TEXTN.
However, when I get a error, it not give much info:
DbError { severity: "ERROR", parsed_severity: Some(Error),
code: SqlState("23514"),
message: "value for domain textn violates check constraint \"non_empty\"",
detail: None, hint: None, position: None, where_: None,
schema: Some("libs"),
table: None,
column: None, datatype: Some("textn"),
constraint: Some("non_empty")}
It not even tell me in what table and field the check fail.
If is even possible to print the row to insert better, but at least table and field is possible?
PostgreSQL (I checked version 11) simply does not provide this information as part of the protocol. Consider these statements:
=> CREATE DOMAIN TEXTN AS TEXT CONSTRAINT non_empty CHECK (length(VALUE) > 0);
CREATE DOMAIN
=> CREATE TABLE test_table (test_column textn);
CREATE TABLE
=> INSERT INTO test_table VALUES ('');
ERROR: value for domain textn violates check constraint "non_empty"
The error message on the wire looks like this:
S ERROR
V ERROR
C 23514
M value for domain textn violates check constraint "non_empty\
s public
d textn
n non_empty
F execExprInterp.c
L 3494
R ExecEvalConstraintCheck
There is no trace of test_table or test_column.
If you have some control over how your framework creates tables, it may be possible to use named table constraints instead of domain types, like this:
CREATE TABLE test_table (
test_column text
CONSTRAINT test_column_check CHECK (length(test_column) > 0));
If you make sure that the constraint name uniquely identifies the column, you can use that to recover the problematic column.
Even for a CHECK constraint defined on the column, as in CREATE TABLE test_table (test_column text CHECK (length(test_column) > 0));, PostgreSQL does not report the column name. You only get the name of the constraint, which is autogenerated by PostgreSQL on table creation and usually starts with the column name, but this is not guaranteed.

postgreSQL check constraint and null

I created a table "TEST" and i tried to input some data however i got an error. The error is ERROR: new row for relation "test" violates check constraint "test_status_check" DETAIL: Failing row contains (5 , 2015-07-21, 15:00:00, I7 , 9 , NULL, NULL).
I think it is because of the null of the status. Therefore, i tried put a null in the test table but still not working
Create table test(
clientID CHAR (20),
startDate date,
startTime time,
instructorNO CHAR(20),
centreID CHAR(20),
status CHAR(4) CHECK (status IN ('Fail','Pass')) NULL,
reason VARCHAR(400),
omitted...
)
ERROR: new row for relation "test" violates check constraint "test_status_check" DETAIL: Failing row contains (5 , 2015-07-21, 15:00:00, I7 , 9 , NULL, NULL).
EDIT: I've completely changed my mind. Your existing code is valid (and the NULL part is unnecessary).
According to the documentation,
It should be noted that a check constraint is satisfied if the check expression evaluates to true or the null value. Since most expressions will evaluate to the null value if any operand is null, they will not prevent null values in the constrained columns. To ensure that a column does not contain null values, the not-null constraint described in the next section can be used.
So, something else is messed up. See here for an example of your original code working.

Postgres_erro --> ERROR: operator does not exist: double precision[] = numeric[]

I am trying to create a table in postgres for storing raster data.
I have 2 different environments: dev and prod.
if I execute the DDL statement in dev then it is creating the table without any problem.
But in prod I am getting the some strange error. How to solve this issue? I am not an admin person and currently facing difficulties with this.
DDL for the table
CREATE TABLE test_shema.test_table (
rid int4 NOT NULL,
rast raster NULL,
CONSTRAINT elevation_hi_pkey_test PRIMARY KEY (rid),
CONSTRAINT enforce_height_rast_test CHECK ((st_height(rast) = ANY (ARRAY[100, 92]))),
CONSTRAINT enforce_max_extent_rast_test CHECK ((st_envelope(rast) # '0103000020E61000000100000005000000A2221ECF131C64C07F55AF453F8C3240A2221ECF131C64C0FEE6DF13C4963640444672D5B14263C0FEE6DF13C4963640444672D5B14263C07F55AF453F8C3240A2221ECF131C64C07F55AF453F8C3240'::geometry)) NOT VALID,
CONSTRAINT enforce_nodata_values_rast_test CHECK ((_raster_constraint_nodata_values(rast) = '{32767.0000000000}'::numeric[])),
CONSTRAINT enforce_num_bands_rast_test CHECK ((st_numbands(rast) = 1)),
CONSTRAINT enforce_out_db_rast_test CHECK ((_raster_constraint_out_db(rast) = '{f}'::boolean[])),
CONSTRAINT enforce_pixel_types_rast_test CHECK ((_raster_constraint_pixel_types(rast) = '{16BSI}'::text[])),
CONSTRAINT enforce_same_alignment_rast_test CHECK (st_samealignment(rast, '01000000006A98816335DA4E3F6A98816335DA4EBFA2221ECF131C64C0FEE6DF13C496364000000000000000000000000000000000E610000001000100'::raster)),
CONSTRAINT enforce_scalex_rast_test CHECK ((round((st_scalex(rast))::numeric, 10) = round(0.000941539829921079, 10))),
CONSTRAINT enforce_scaley_rast_test CHECK ((round((st_scaley(rast))::numeric, 10) = round((-0.000941539829921079), 10))),
CONSTRAINT enforce_srid_rast_test CHECK ((st_srid(rast) = 4326)),
CONSTRAINT enforce_width_rast_test CHECK ((st_width(rast) = ANY (ARRAY[100, 15])))
);
Error that I am getting in prod environment
ERROR: operator does not exist: double precision[] = numeric[]
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Must be the third constraint. Compare with this instead:
'{32767.0000000000}'::double precision[]