Custom error message for Postgresql CHECK IN list constraint












0















I would like to create a more specific error message for Postgres CHECK IN violations. So for example a violation of the following CHECK constraint on a column:



management_zone varchar(15) NOT NULL CHECK (management_zone IN ('Marine', 'Terrestrial') ),


should return a custom error message such as ie.: "Hint: Check spelling. Only allowed inputs are: 'Marine', 'Terrestrial'.



The best solution I have seen so far solves it by using the error message as the name of the check constraint, ie



ADD CONSTRAINT c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial' CHECK (management_zone IN ('Marine', 'Terrestrial') ),


and then applying a function that fixes the error message after the @ sign by replacing the underscores with space to make it more readable. The function is then called using a try and catch statement.



This code however is in t-sql which I am unfamiliar with, and I also don't know enough PL/pgSQL to be able to convert and replicate it. I therefore wonder if anyone can suggest how something similar can be done in postgres, ex. using a function and a trigger?



The t-sql code and explanation is available from here and I copy paste it below:
https://social.technet.microsoft.com/wiki/contents/articles/29187.t-sql-error-handling-for-check-constraints.aspx



CREATE FUNCTION dbo.ufnGetClearErrorMessage2()
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE @Msg NVARCHAR(4000) = ERROR_MESSAGE() ;
DECLARE @ErrNum INT = ERROR_NUMBER() ;
DECLARE @ClearMessage NVARCHAR(4000) ;
IF @ErrNum = 547
BEGIN
/*--how to find @ClearMessage:
SELECT @msg ,
CHARINDEX('@', @msg) ,
RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)) ,
CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) ,
LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ) ,
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'
*/
SELECT @ClearMessage = @Msg + CHAR(13) +
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'

END
ELSE
SET @ClearMessage = @Msg ;

RETURN @ClearMessage ;
END


Try and catch:



BEGIN TRY
INSERT dbo.Book
( BookId, WritingDate, publishDate )
VALUES ( 1, GETDATE(), GETDATE() + 1 )
END TRY
BEGIN CATCH

DECLARE @Msg NVARCHAR(4000) = dbo.ufnGetClearErrorMessage2();
THROW 60001, @Msg, 1;
END CATCH


Any advice much apreciated.










share|improve this question























  • That won't work. The constraint name is longer than 63 characters and thus it will be truncated You will get a warning like: identifier "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial'" will be truncated to "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Mar'"

    – a_horse_with_no_name
    Nov 23 '18 at 14:31













  • ah, okay. darn! Thanks for info.

    – Ric
    Nov 23 '18 at 14:39


















0















I would like to create a more specific error message for Postgres CHECK IN violations. So for example a violation of the following CHECK constraint on a column:



management_zone varchar(15) NOT NULL CHECK (management_zone IN ('Marine', 'Terrestrial') ),


should return a custom error message such as ie.: "Hint: Check spelling. Only allowed inputs are: 'Marine', 'Terrestrial'.



The best solution I have seen so far solves it by using the error message as the name of the check constraint, ie



ADD CONSTRAINT c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial' CHECK (management_zone IN ('Marine', 'Terrestrial') ),


and then applying a function that fixes the error message after the @ sign by replacing the underscores with space to make it more readable. The function is then called using a try and catch statement.



This code however is in t-sql which I am unfamiliar with, and I also don't know enough PL/pgSQL to be able to convert and replicate it. I therefore wonder if anyone can suggest how something similar can be done in postgres, ex. using a function and a trigger?



The t-sql code and explanation is available from here and I copy paste it below:
https://social.technet.microsoft.com/wiki/contents/articles/29187.t-sql-error-handling-for-check-constraints.aspx



CREATE FUNCTION dbo.ufnGetClearErrorMessage2()
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE @Msg NVARCHAR(4000) = ERROR_MESSAGE() ;
DECLARE @ErrNum INT = ERROR_NUMBER() ;
DECLARE @ClearMessage NVARCHAR(4000) ;
IF @ErrNum = 547
BEGIN
/*--how to find @ClearMessage:
SELECT @msg ,
CHARINDEX('@', @msg) ,
RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)) ,
CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) ,
LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ) ,
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'
*/
SELECT @ClearMessage = @Msg + CHAR(13) +
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'

END
ELSE
SET @ClearMessage = @Msg ;

RETURN @ClearMessage ;
END


Try and catch:



BEGIN TRY
INSERT dbo.Book
( BookId, WritingDate, publishDate )
VALUES ( 1, GETDATE(), GETDATE() + 1 )
END TRY
BEGIN CATCH

DECLARE @Msg NVARCHAR(4000) = dbo.ufnGetClearErrorMessage2();
THROW 60001, @Msg, 1;
END CATCH


Any advice much apreciated.










share|improve this question























  • That won't work. The constraint name is longer than 63 characters and thus it will be truncated You will get a warning like: identifier "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial'" will be truncated to "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Mar'"

    – a_horse_with_no_name
    Nov 23 '18 at 14:31













  • ah, okay. darn! Thanks for info.

    – Ric
    Nov 23 '18 at 14:39
















0












0








0


1






I would like to create a more specific error message for Postgres CHECK IN violations. So for example a violation of the following CHECK constraint on a column:



management_zone varchar(15) NOT NULL CHECK (management_zone IN ('Marine', 'Terrestrial') ),


should return a custom error message such as ie.: "Hint: Check spelling. Only allowed inputs are: 'Marine', 'Terrestrial'.



The best solution I have seen so far solves it by using the error message as the name of the check constraint, ie



ADD CONSTRAINT c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial' CHECK (management_zone IN ('Marine', 'Terrestrial') ),


and then applying a function that fixes the error message after the @ sign by replacing the underscores with space to make it more readable. The function is then called using a try and catch statement.



This code however is in t-sql which I am unfamiliar with, and I also don't know enough PL/pgSQL to be able to convert and replicate it. I therefore wonder if anyone can suggest how something similar can be done in postgres, ex. using a function and a trigger?



The t-sql code and explanation is available from here and I copy paste it below:
https://social.technet.microsoft.com/wiki/contents/articles/29187.t-sql-error-handling-for-check-constraints.aspx



CREATE FUNCTION dbo.ufnGetClearErrorMessage2()
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE @Msg NVARCHAR(4000) = ERROR_MESSAGE() ;
DECLARE @ErrNum INT = ERROR_NUMBER() ;
DECLARE @ClearMessage NVARCHAR(4000) ;
IF @ErrNum = 547
BEGIN
/*--how to find @ClearMessage:
SELECT @msg ,
CHARINDEX('@', @msg) ,
RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)) ,
CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) ,
LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ) ,
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'
*/
SELECT @ClearMessage = @Msg + CHAR(13) +
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'

END
ELSE
SET @ClearMessage = @Msg ;

RETURN @ClearMessage ;
END


Try and catch:



BEGIN TRY
INSERT dbo.Book
( BookId, WritingDate, publishDate )
VALUES ( 1, GETDATE(), GETDATE() + 1 )
END TRY
BEGIN CATCH

DECLARE @Msg NVARCHAR(4000) = dbo.ufnGetClearErrorMessage2();
THROW 60001, @Msg, 1;
END CATCH


Any advice much apreciated.










share|improve this question














I would like to create a more specific error message for Postgres CHECK IN violations. So for example a violation of the following CHECK constraint on a column:



management_zone varchar(15) NOT NULL CHECK (management_zone IN ('Marine', 'Terrestrial') ),


should return a custom error message such as ie.: "Hint: Check spelling. Only allowed inputs are: 'Marine', 'Terrestrial'.



The best solution I have seen so far solves it by using the error message as the name of the check constraint, ie



ADD CONSTRAINT c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial' CHECK (management_zone IN ('Marine', 'Terrestrial') ),


and then applying a function that fixes the error message after the @ sign by replacing the underscores with space to make it more readable. The function is then called using a try and catch statement.



This code however is in t-sql which I am unfamiliar with, and I also don't know enough PL/pgSQL to be able to convert and replicate it. I therefore wonder if anyone can suggest how something similar can be done in postgres, ex. using a function and a trigger?



The t-sql code and explanation is available from here and I copy paste it below:
https://social.technet.microsoft.com/wiki/contents/articles/29187.t-sql-error-handling-for-check-constraints.aspx



CREATE FUNCTION dbo.ufnGetClearErrorMessage2()
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE @Msg NVARCHAR(4000) = ERROR_MESSAGE() ;
DECLARE @ErrNum INT = ERROR_NUMBER() ;
DECLARE @ClearMessage NVARCHAR(4000) ;
IF @ErrNum = 547
BEGIN
/*--how to find @ClearMessage:
SELECT @msg ,
CHARINDEX('@', @msg) ,
RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)) ,
CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) ,
LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ) ,
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'
*/
SELECT @ClearMessage = @Msg + CHAR(13) +
REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'

END
ELSE
SET @ClearMessage = @Msg ;

RETURN @ClearMessage ;
END


Try and catch:



BEGIN TRY
INSERT dbo.Book
( BookId, WritingDate, publishDate )
VALUES ( 1, GETDATE(), GETDATE() + 1 )
END TRY
BEGIN CATCH

DECLARE @Msg NVARCHAR(4000) = dbo.ufnGetClearErrorMessage2();
THROW 60001, @Msg, 1;
END CATCH


Any advice much apreciated.







postgresql function triggers check-constraints custom-error-handling






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 23 '18 at 14:26









RicRic

72




72













  • That won't work. The constraint name is longer than 63 characters and thus it will be truncated You will get a warning like: identifier "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial'" will be truncated to "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Mar'"

    – a_horse_with_no_name
    Nov 23 '18 at 14:31













  • ah, okay. darn! Thanks for info.

    – Ric
    Nov 23 '18 at 14:39





















  • That won't work. The constraint name is longer than 63 characters and thus it will be truncated You will get a warning like: identifier "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial'" will be truncated to "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Mar'"

    – a_horse_with_no_name
    Nov 23 '18 at 14:31













  • ah, okay. darn! Thanks for info.

    – Ric
    Nov 23 '18 at 14:39



















That won't work. The constraint name is longer than 63 characters and thus it will be truncated You will get a warning like: identifier "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial'" will be truncated to "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Mar'"

– a_horse_with_no_name
Nov 23 '18 at 14:31







That won't work. The constraint name is longer than 63 characters and thus it will be truncated You will get a warning like: identifier "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial'" will be truncated to "c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Mar'"

– a_horse_with_no_name
Nov 23 '18 at 14:31















ah, okay. darn! Thanks for info.

– Ric
Nov 23 '18 at 14:39







ah, okay. darn! Thanks for info.

– Ric
Nov 23 '18 at 14:39














1 Answer
1






active

oldest

votes


















1














If you can live with a slightly different check constraint, you can do the following:



Create a function that checks the values:



create function check_zone(p_input text)
returns boolean
as
$$
declare
l_allowed text := array['Marine', 'Terrestrial'];
begin
if p_input = any(l_allowed) then
return true;
end if;
raise 'The only allowed values are: %', array_to_string(l_allowed, ', ');
end;
$$
language plpgsql
immutable;


And then use that function instead of an IN condition:



create table data
(
management_zone text not null,
CONSTRAINT check_zone CHECK (check_zone(management_zone))
);


The following INSERT



insert into data values ('foo');


will result in:




ERROR: The only allowed values are: Marine, Terrestrial







share|improve this answer
























  • Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

    – Ric
    Nov 23 '18 at 16:49











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53448473%2fcustom-error-message-for-postgresql-check-in-list-constraint%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














If you can live with a slightly different check constraint, you can do the following:



Create a function that checks the values:



create function check_zone(p_input text)
returns boolean
as
$$
declare
l_allowed text := array['Marine', 'Terrestrial'];
begin
if p_input = any(l_allowed) then
return true;
end if;
raise 'The only allowed values are: %', array_to_string(l_allowed, ', ');
end;
$$
language plpgsql
immutable;


And then use that function instead of an IN condition:



create table data
(
management_zone text not null,
CONSTRAINT check_zone CHECK (check_zone(management_zone))
);


The following INSERT



insert into data values ('foo');


will result in:




ERROR: The only allowed values are: Marine, Terrestrial







share|improve this answer
























  • Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

    – Ric
    Nov 23 '18 at 16:49
















1














If you can live with a slightly different check constraint, you can do the following:



Create a function that checks the values:



create function check_zone(p_input text)
returns boolean
as
$$
declare
l_allowed text := array['Marine', 'Terrestrial'];
begin
if p_input = any(l_allowed) then
return true;
end if;
raise 'The only allowed values are: %', array_to_string(l_allowed, ', ');
end;
$$
language plpgsql
immutable;


And then use that function instead of an IN condition:



create table data
(
management_zone text not null,
CONSTRAINT check_zone CHECK (check_zone(management_zone))
);


The following INSERT



insert into data values ('foo');


will result in:




ERROR: The only allowed values are: Marine, Terrestrial







share|improve this answer
























  • Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

    – Ric
    Nov 23 '18 at 16:49














1












1








1







If you can live with a slightly different check constraint, you can do the following:



Create a function that checks the values:



create function check_zone(p_input text)
returns boolean
as
$$
declare
l_allowed text := array['Marine', 'Terrestrial'];
begin
if p_input = any(l_allowed) then
return true;
end if;
raise 'The only allowed values are: %', array_to_string(l_allowed, ', ');
end;
$$
language plpgsql
immutable;


And then use that function instead of an IN condition:



create table data
(
management_zone text not null,
CONSTRAINT check_zone CHECK (check_zone(management_zone))
);


The following INSERT



insert into data values ('foo');


will result in:




ERROR: The only allowed values are: Marine, Terrestrial







share|improve this answer













If you can live with a slightly different check constraint, you can do the following:



Create a function that checks the values:



create function check_zone(p_input text)
returns boolean
as
$$
declare
l_allowed text := array['Marine', 'Terrestrial'];
begin
if p_input = any(l_allowed) then
return true;
end if;
raise 'The only allowed values are: %', array_to_string(l_allowed, ', ');
end;
$$
language plpgsql
immutable;


And then use that function instead of an IN condition:



create table data
(
management_zone text not null,
CONSTRAINT check_zone CHECK (check_zone(management_zone))
);


The following INSERT



insert into data values ('foo');


will result in:




ERROR: The only allowed values are: Marine, Terrestrial








share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 23 '18 at 14:59









a_horse_with_no_namea_horse_with_no_name

298k46454548




298k46454548













  • Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

    – Ric
    Nov 23 '18 at 16:49



















  • Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

    – Ric
    Nov 23 '18 at 16:49

















Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

– Ric
Nov 23 '18 at 16:49





Thank you so much! Your initial comments got me thinking along the right lines and I was able to get a crude trigger happening -But, this solution that you have just provided is so much more sophisticated than what I was able to produce, and is just what I am looking for. Thanks again.

– Ric
Nov 23 '18 at 16:49




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53448473%2fcustom-error-message-for-postgresql-check-in-list-constraint%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Wiesbaden

Marschland

Dieringhausen