Capture error message from Sp_send_dbmail to catch block - sql-server-2019

I have a below query in the stored procedure. And I have the invalid location #file_attachments.
BEGIN TRY
EXEC msdb.dbo.Sp_send_dbmail
#recipients='raja#gmail.com',
#subject='hello',
#body='hello',
#body_format='HTML',
#file_attachments='\\1.1.1.1\Image\Logo.png',
#profile_name='EmailDev'
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage
END CATCH
When I execute I'm getting this error:
Msg 22051, Level 16, State 1, Line 25
Attachment file \1.1.1.1\Image\Logo.png is invalid.
But I'm not able to capture this in error in the catch block, rather it is not hitting the catch block.
How to capture the error message in the catch block instead of the standard way of displaying an error?

Seems there is a problem sp_send_dbmail to capture the error in TRY CATCH block.
As per the suggestion on the thread
I have modified my code as below, which solves my problem.
BEGIN TRY
Declare #FileInfo Table(FileExist Int,IsDirectory Int,ParentDirectoryExist Int)
Declare #file_attachments VARCHAR(1000)
SET #file_attachments = '\\1.1.1.1\Image\Logo.png'
INSERT INTO #AtthacmentFileInfo EXEC XP_FILEEXIST #Attachment
IF (SELECT FileExist FROM #AtthacmentFileInfo)=0
BEGIN
SET #ErrMessage = 'Invalid logo location or it is not accessible. '+#Attachment+''
;THROW 50000,#ErrMessage,1;
END
EXEC msdb.dbo.Sp_send_dbmail
#recipients='raja#gmail.com',
#subject='hello',
#body='hello',
#body_format='HTML',
#file_attachments='\\1.1.1.1\Image\Logo.png',
#profile_name='echohealth'
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage
END CATCH

Related

How to check for custom Postgres exceptions raised via RAISE EXCEPTION in Golang?

I'm using Postgres with Golang via pgx
I've a trigger function something like the following:
CREATE OR REPLACE FUNCTION foo()
RETURNS TRIGGER AS
$$
BEGIN
IF (bar = 'baz') THEN
-- something
ELSE
RAISE EXCEPTION 'oops error';
END IF;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
How do I check for oops error in Go code?
The way I'm doing it now is:
errOops := errors.New("ERROR: oops error (SQLSTATE P0001)")
err := myDBFunc()
if errors.Is(err, errOops) {
}
But I wonder if there's a better way other than relying on the hardcoded message.
Should have read the Wiki: Error Handling in pgx
So I can do:
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "P0001" {
}
or something similar.
You can find that information in appendix A of the documentation: it will be a raise_exception, and the SQLSTATE is P0001.

Can SQL Server return an informational message to .NET System.Data.SqlClient program in contexts that do not involve any error

Is it possible with a .NET client program, communicating with back-end SQL Server using the System.Data.SqlClient library, for the server to send an informational message to the client program in contexts that do not involve any error and for the client program to obtain the message that was sent?
create proc NewFoo
#value text,
#userid text
as
begin
insert foo
(name, createdby) values (#value, #userid);
declare #recordcount int
select #recordcount = count(*) from foo where createdby= #userid;
if #recordcount = 100
begin
-- let user know they've created their 100th record. Woo-hoo!!
end
end
Here is an additional pseudo-code example, closer to the actual use case; note the differing severity:
if #value > #maxallowed
begin
if #userlevel = 'manager'
raiserror('Exceeded max. Intentional?',10,1)
else
raiserror('Exceeds max. Your edit was not saved',11,1)
end
P.S. Without using an OUT parameter or RETURN value parameter in the client-side command object.
P.P.S. I am using the SqlDataAdapter.Update method and some of the code uses a DataReader on the SqlCommand object.
You can use PRINT in your stored procedure, and to capture it in the code by subscribing to the InfoMessage event in the SqlConnection object.
In your sql just put:
PRINT 'Exceeded max. Intentional'
and in your code grab it like this:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
string msg = null;
connection.InfoMessage += (sender, e) => { msg = e.Message; };
// execute the procedure
// check msg
}

function sign(json, unknown) does not exist

I'm following the tutorial on https://postgrest.org/en/v5.0/auth.html#jwt-from-sql
I created this function:
create or replace function
login(email text, pass text) returns basic_auth.jwt_token
language plpgsql
as $$
declare
_role name;
result basic_auth.jwt_token;
begin
-- check email and password
select basic_auth.user_role(email, pass) into _role;
if _role is null then
raise invalid_password using message = 'invalid user or password';
end if;
select sign(
row_to_json(r), 'reallyreallyreallyreallyverysafe'
) as token
from (
select _role as role, login.email as email,
extract(epoch from now())::integer + 60*60 as exp
) r
into result;
return result;
end;
$$;
When I try to do the login request, I get the following error message:
{
"hint": "No function matches the given name and argument types. You might need to add explicit type casts.",
"details": null,
"code": "42883",
"message": "function public.sign(json, unknown) does not exist" }
I don't see the sign function anywhere in the tutorial, does anyone know what is going on here?
The sign function is created when you install pgjwt.
Also, make sure that you install the extension on a schema that is included in your search_path(a list of imported schemas). This can be specified by doing CREATE EXTENSION pgjwt WITH SCHEMA public.
PostgREST adds the public schema by default on the search_path, so the extension should work with no additional config.

PostgreSQL/JPA - Import functions in import.sql file?

I'm trying to define some PostgreSQL functions and triggers in my JPA import.sql file. I'm using Hibernate 5.x as my underlying JPA provider. Since my import.sql file has commands that are multiple lines, I've got this property set in my persistence.xml file:
<property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />
From there, I'm trying to define my functions in import.sql. They look something like this:
DROP FUNCTION IF EXISTS update_total_feedback_count() CASCADE;
CREATE FUNCTION update_total_feedback_count() RETURNS TRIGGER AS
$$
DECLARE
application_version_id BIGINT := 0;
app_version_metadata_id BIGINT:= 0;
application_id BIGINT := 0;
app_metadata_id BIGINT := 0;
BEGIN
IF (TG_OP = 'INSERT') THEN
SELECT INTO application_version_id tbl_application_version.id
FROM tbl_application_version
INNER JOIN tbl_feedback ON tbl_feedback.application_version_id = tbl_application_version.id
WHERE tbl_feedback.id = NEW.id;
SELECT INTO app_version_metadata_id tbl_application_version.application_version_metadata_id
FROM tbl_application_version
WHERE id = application_version_id;
SELECT INTO app_metadata_id registered_application_metadata_id
FROM tbl_registered_application
INNER JOIN tbl_application_version ON tbl_application_version.registered_application_id = tbl_registered_application.id
WHERE tbl_application_version.id = application_version_id;
UPDATE tbl_registered_application_metadata SET feedbackcount = (feedbackcount + 1), lastfeedbackdate = NEW.createddate WHERE id = app_metadata_id;
UPDATE tbl_application_version_metadata SET feedbackcount = (feedbackcount + 1), lastfeedbackdate = NEW.createddate WHERE id = app_version_metadata_id;
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
-- IMPLEMENT THIS TRIGGER
RETURN NULL;
END IF;
END;
$$
LANGUAGE 'plpgsql';
ALTER FUNCTION update_total_feedback_count() OWNER TO feedback_tracker;
However, when I deploy my WAR file, I get an error saying something like this:
Unterminated dollar quote started at position 65 in SQL CREATE
FUNCTION my_function() RETURNS TRIGGER AS $$
So, clearly it's dying on the $$ in my function declaration. Is there a way around this? Should I be declaring my function/trigger differently? Is there a property I can set in my persistence.xml file that will get around this?
the problem with hibernate's default SqlStatementParser implementation, which is used in multiline sql command extractor.
if you look at grammar definition hibernate-core/src/main/antlr/sql-stmt.g there is definition of Statement End:
STMT_END
: ';' ( '\t' | ' ' | '\r' | '\n' )*
;
NOT_STMT_END
: ~( ';' )
;
This tells that statement end is semicolon symbol followed by "Space" "tab" "carret return" or "new line" symbols.
THUS: DEFAULT IMPLEMENTATION IN HIBERNATE DOESN'T SUPPORT DOLLAR QUOTING.
If you don't want to implement custom hibernate's parser you can rewrite all functions without dollar quoting, using simple ' quoting. But you will need to carefully escape ' chars.
UPDATE: you can create your custom ImportSqlCommandExtractor. For example: separate your commands with --****** (6 star symbols in comment, just to make your file proper SQL file, but with custom command separation in comments, or choose any insane combination, which you like) and then split those in simple implementation
public class ImportSqlCE implements ImportSqlCommandExtractor {
private static final Logger log = LoggerFactory.getLogger(ImportSqlCE.class);
#Override
public String[] extractCommands(Reader reader) {
try {
String allCommands = IOUtils.toString(reader);
return allCommands.split("--******");
} catch (IOException e) {
log.error("error reading import commands", e);
log.info("sengind default empty command set");
return new String[0];
}
}
}
and then configure hibernate to use it <property name="hibernate.hbm2ddl.import_files_sql_extractor" value="example.ImportSqlCE" />
with this your import.sql will support dollar quoting (i.e. it will simply ignore any sql awareness of what is happening.)

Why doesn't Matlab `fopen` throw an exception?

Why doesn't fopen throw an exception when the filename or path doesn't exist?
in_path = 'pqlcnaf8765mlr9f6lf2;
try
in_file_id = fopen(in_path,'r');
catch
error('Problem with input file.')
end
The in_path doesn't exist. The call returns in_file_id with the value of -1, but no exception is thrown. Does somebody know why?
It's not designed to throw an exception, as the documentation states:
If fopen cannot open the file, it returns -1.
You need to design your code to throw the exception that you want:
in_path = 'pqlcnaf8765mlr9f6lf2;
in_file_id = fopen(in_path,'r');
if in_file_id == -1
error('Problem with input file.')
end
edit
Re: The link in the 1st comment -> shows how to deal with a try catch block. It is throwing an error because of the fread line. You could do the same in your code:
try
in_file_id = fopen(in_path,'r');
fread(in_file_id);
catch
error('Problem with input file.')
end
Having said that I don't think the link is a good example how to deal with a file not existing.