Skip to content

Instantly share code, notes, and snippets.

@loveencounterflow
Last active March 22, 2018 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loveencounterflow/ce623d2905535c9e2dcbc0111e35aa9e to your computer and use it in GitHub Desktop.
Save loveencounterflow/ce623d2905535c9e2dcbc0111e35aa9e to your computer and use it in GitHub Desktop.
Three Examples where PostgreSQL has Horrible Error Messages
drop schema if exists X cascade;
create schema X;
create domain X.an_illegal_regex as text check ( value ~ '(' );
create table X.table_with_illegal_constraint (
a text,
constraint "column a must have a bogus value" check ( a::X.an_illegal_regex = a ) );
select * from X.table_with_illegal_constraint;
insert into X.table_with_illegal_constraint values
( 'xxx' ),
-- ( 'xxx' ),
( 'foo' ),
( 'xyx' );
⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔
╔═══╗
║ a ║
╠═══╣
╚═══╝
psql:db/experiments/pg-error-fail-illegal-regex.sql:17: ERROR:
invalid regular expression: parentheses () not balanced
⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔
FAILURE: the error is really in line 5 where a syntactically invalid
RegEx is created; the fact that it is a RegEx and not a general
string is obvious from the semantics of the `~` (tilde) operator at
that point in time.
FAILURE: the offending RegEx is not referred to and not quoted in the error
message. As such, it could be anywhere in my many, many kLOCs big
DB definition. I cannot even search the RegEx with a RegEx because all
I know is some parenthesis is missing, somewhere: RegExes cannot match
parentheses, and PG RegExes do not have a unique syntactic marker to them.
FAILURE: before the `insert` statement, everything runs dandy. We could have
built an entire data warehouse application on top of a table definition
that can never be syntactically processed but which will only fail when
someone accidentally tries to insert a line.
FAILURE: I can select from a table with a syntactically invalid definition.
drop schema if exists X cascade;
create schema X;
create domain X.a_legal_regex as text check ( value ~ '^x' );
create table X.table_with_constraints (
a text,
constraint "column a must start with x" check ( a::X.a_legal_regex = a ),
constraint "field b must have 3 characters" check ( character_length( a ) = 3 ) );
insert into X.table_with_constraints values
( 'xxx' ),
( 'foo' ), /* A: violates first constraint */
-- ( 'xxxx' ), /* B: violates second constraint */
( 'xyx' );
\quit
———————————————————————————————————————————————————————————————————————————————
With only line B active:
✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱
psql:db/experiments/pg-error-fail-no-constraint-name.sql:16:
ERROR: new row for relation "table_with_constraints" violates
check constraint "field b must have 3 characters"
DETAIL: Failing row contains (xxxx).
✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱
SUCCESS: we get the name of the relation *and* the name of the violated
rule.
SUCCESS: the offending piece of data is quoted.
FAILURE: we don't get the full name of the relation, which is
"X"."table_with_constraints". Ideally, we'd also be told that
the relation in question is a table (not a materialized view).
Frankly, when you say 'relation', that should be 'tuple', not 'row';
but when you say 'row', you might as well say 'table'.
———————————————————————————————————————————————————————————————————————————————
With only line A active:
⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔
psql:db/experiments/pg-error-fail-no-constraint-name.sql:16:
ERROR: value for domain x.a_legal_regex violates check constraint "a_legal_regex_check"
⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔⛔
FAILURE: no reference to the affected table is made.
FAILURE: no reference to the offending piece of data is made.
FAILURE: ne reference to the offended constraint is made ("column a must start with x").
drop schema if exists X cascade;
create schema X;
create domain X.only_a as text check ( value ~ '^a+$' );
create domain X.only_b as text check ( value ~ '^b+$' );
create function X.count_a( X.only_a ) returns integer language sql as $$
select character_length( $1 ); $$;
create function X.foo( X.only_b ) returns integer language sql as $$
select X.count_a( $1 ); $$;
-- select X.count_a( 'aaaa'::X.only_a );
select X.count_a( 'bbbb'::X.only_b ); /* A */
-- select X.foo( 'bbbb'::X.only_b ); /* B */
\quit
———————————————————————————————————————————————————————————————————————————————
With only line A active:
✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱
psql:db/experiments/pg-error-fail-wrong-domain.sql:15: ERROR:
value for domain x.only_a violates check constraint "only_a_check"
✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱
OK so far except the overall information given is too sparse to be truly useful.
———————————————————————————————————————————————————————————————————————————————
With only line B active:
✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱
psql:db/experiments/pg-error-fail-wrong-domain.sql:16: ERROR:
value for domain x.only_a violates check constraint "only_a_check"
✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱✱
Misleading in more than one way. `X.count_a()` was called by `X.foo()` because
it happened to be the closest match for a function called `X.count_a` with a
textual argument. Because no context is given at all, the user is left alone to
puzzle over how in the world `X.foo( 'bbbb'::X.only_b )` violates an `only_a`
constraint check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment