Try/Catch fails to catch exception in stored procedure - stored-procedures

I'm struggling to get my try/catch to work with my stored procedure, it seems to not catch the error. I've been searching around, but no luck. What I'm trying to accomplish is to display the error number if an invalid value, no value, or null is given when the stored procedure is called. I've tried moving the try and catch it feels like everywhere, but it seems like the error may be on the "#SomeID as int" line. I appreciate any help I can get.
alter procedure DeleteAcct
#SomeID as int
as
begin try
declare #counter int
set #counter = (select count(SomeDate) from Table1 where SomeID = #SomeID group by SomeID)
begin
if(#counter > 0)
begin
Print 'Testing'
end
else
begin
delete from Table2
where SomeID = #SomeID
Print 'Delete successful'
end
end
end try
begin catch
print error_number()
end catch
<!-- calling the stored procedure -->
exec DeleteAcct '1231231231221'
<!-- Error received -->
Msg 8114, Level 16, State 5, Procedure DeleteAcct, Line 0
Error converting data type varchar to int.

You declare param #SomeID as an int then try to pass a string!
Make call like so:
exec DeleteAcct 1231231231221
In fact I suspect #SomeID should be declared as a varchar

Well this answer is late, but we do this at work all the time.
You should try/catch the launcher and not the SP that is being executed.
I believe the explanation was quite obvious, but lets develop:
The called procedure does not need any try/catch:
alter procedure DeleteAcct
#SomeID as int
as
declare #counter int
set #counter = (select count(SomeDate) from Table1 where SomeID = #SomeID group by SomeID)
begin
if(#counter > 0)
begin
Print 'Testing'
end
else
begin
delete from Table2
where SomeID = #SomeID
Print 'Delete successful'
end
end
The launcher or the calling procedure needs to be put into try/catch block so that the error from the executed procedure is displayed at the launcher level.
begin try
exec DeleteAcct '1231231231221'
end try
begin catch
print error_number()
end catch

Related

OUT Parameter Issue in DB2 Stored Procedure

I am getting an error complaining about the OUT Parameter ID as an Undefined name when I try to set its value at the end of the procedure. Commenting it out the procedure executes fine.
What am I doing wrong?
CREATE PROCEDURE P3.CUST_CRT(IN NAME VARCHAR(15),
IN GENDER CHAR(1),
IN AGE INTEGER,
IN PIN INTEGER,
OUT ID INTEGER)
LANGUAGE SQL
P1: BEGIN
--Check if Customer NAME is NULL.
IF NAME IS NULL THEN
SIGNAL SQLSTATE VALUE '20010'
SET MESSAGE_TEXT = 'No NAME.';
END IF;
--Check if Customer NAME is an empty string.
IF NAME = '' THEN
SIGNAL SQLSTATE VALUE '20020'
SET MESSAGE_TEXT = 'NAME cannot be an empty string.';
END IF;
--Check if Customer GENDER falls in either of the two acceptable categories.
IF GENDER NOT IN ('M','F') THEN
SIGNAL SQLSTATE VALUE '20030'
SET MESSAGE_TEXT = 'GENDER can either be M or F';
END IF;
--Check if Customer AGE is not null.
IF AGE IS NULL THEN
SIGNAL SQLSTATE VALUE '20040'
SET MESSAGE_TEXT = 'AGE cannot be NULL';
END IF;
--Check that AGE is not negative.
IF AGE < 0 THEN
SIGNAL SQLSTATE VALUE '20060'
SET MESSAGE_TEXT = 'AGE cannot be negative.';
END IF;
--Check that the Customer is an adult.
IF AGE < 18 THEN
SIGNAL SQLSTATE VALUE '20070'
SET MESSAGE_TEXT = 'You have to be over 18 years to have an account.';
END IF;
--Check that PIN is not null.
IF PIN IS NULL THEN
SIGNAL SQLSTATE VALUE '20080'
SET MESSAGE_TEXT = 'PIN cannot be empty.';
END IF;
--Pin cannot be less than zero.
IF PIN < 0 THEN
SIGNAL SQLSTATE VALUE '20090'
SET MESSAGE_TEXT = 'PIN cannot be less than 0.';
END IF;
INSERT INTO P3.CUSTOMER(Name, Gender, Age, Pin) VALUES(NAME, GENDER, AGE, P3.ENCRYPT(PIN));
SET ID = ID.CURRVAL;
END P1 #
Always specify your Db2 Server version and operating-system when asking for help. Never write "getting an error" unless you specify the exact error message and error code. You code presumes that the sequence object you named "ID" is in the schema, and you should not allow an output parameter name to be the same as a sequence name. Give a sequence object a different name from the output parameter
For "Code: -204, SQL State: 42704] "DB2ADMIN.ID" is an undefined name.. SQLCODE=-204, SQLSTATE=42704, DRIVER=4.22.29", Db2 is telling you that the output parameter (named ID) has the same name as the sequence object, and that Db2 cannot find the sequence object in the schema called DB2ADMIN - that is the schema that you are connecting to the database to do the compile.
So, either qualify your sequence object name (i.e. put the schema name before it for example P3.ID (if that is your sequence fully qualified name), or give the correct full name for your sequence object. The sequence object needs to exist in the specified or implied schema before your code will compile.
It's unclear from your code where you consume the next value of the sequence (you only use its current value), but that is a separate matter from the -204 - in other words you may have other errors.
If you seek to return the most recently consumed sequence value, then one way (there are other ways, including more elegant ways) to do it is like this (in this example the sequence object is pre-created as P3.THEID ):
INSERT INTO P3.CUSTOMER(ID, Name, Gender, Age, Pin) VALUES( NEXT VALUE FOR P3.THEID , NAME, GENDER, AGE, P3.ENCRYPT(PIN));
SET ID = P3.THEID.CURRVAL;
Your ID variable is defined as INTEGER while in order to use the CURRVAL function it has to be defined as a SEQUENCE object.

Create Rails SQL Function + PostgreSQL

I want to know the correct syntax for writing down function in rails.
This needs to accept parameters.
Code I have managed is:
def up
self.connection.execute %Q( CREATE OR REPLACE FUNCTION business_objective_function RETURNS INT AS $$
BEGIN
RETURN 1;
END
)
end
While running migration : syntax error at or near "RETURNS"

undefined method 'exec_prepared' on Rails 4 postgresql query

Every time, I submit a form supposed to create a Deal and sending a very high nb of Prizes (>200K) to the Prize table using a transaction and raw postgresql, I have first the error 'undefined method exec_prepared' then if I reload the form then I get a new error 'ERROR: prepared statement 'xixie' already exists'.
I used this question wrong number of arguments (1 for 2..3) for Active Record postgresql query (Rails 4/postgresql 9.4) and Prepared Statement on Postgresql in Rails to create the following Postgresql query:
models deals.rb
CONNEXION = ActiveRecord::Base.connection.raw_connection
def create_prizes
Deal.transaction do
self.prize_number.times do |i|
st = CONNEXION.prepare('xixie', 'INSERT INTO prizes (deal_id) values ($1)')
values = [ { value: self.id} ]
st.exec_prepared('xixie', values )
st.close()
end
end
end
I have this problem in Local (not production) and I am not using any puma/unicorn. I do use Zeus and Guard.
Is it impossible with Rails4/postgresql prepared_statements to insert multiple rows at a time ?
How can I change the query to make it work ?
Also as Rails gives me ' ERROR: prepared statement 'xixie' already exists', I had to change multiple times the name of the prepared_statements but will they "live" forever? how can I "kill" them after I do all theses iterations trying to find the appropriate query.
EDIT
Updated the code after some proposed answer:
CONNECTION = ActiveRecord::Base.connection.raw_connection
def create_prizes
Deal.transaction do
self.prize_number.times do |i|
CONNECTION.prepare('mimiku', 'INSERT INTO deal_prizes (deal_id, created_at, updated_at) values ($1, $2, $3)')
CONNECTION.exec_prepared('mimiku', [ { value: self.id}, { value: '2009-01-23 20:21:13' }, { value: '2009-01-23 20:21:13' } ] )
end
# CONNECTION.close()
end
end
(added '2009-01-23 20:21:13' as Rails required created_at and updated_at for some reason).
I get this error:
ERROR: prepared statement "mimiku" already exists
Even if I change the name from 'mimiku' to 'somethingelse', I still get this type of error.
The prepare method returns a result according to the docs:
http://deveiate.org/code/pg/PG/Connection.html#method-i-prepare
Maybe try call exec_prepared on the connection object
connection = ActiveRecord::Base.connection.raw_connection
def create_prizes
begin
connection.describe_prepared('xixie')
rescue PG::InvalidSqlStatementName
connection.prepare('xixie', 'INSERT INTO prizes (deal_id) values ($1)')
end
Deal.transaction do
self.prize_number.times do |i|
connection.exec_prepared('xixie', [ { value: self.id} ] )
end
end
end
UPDATE: I reworked the code above to first check if a prepared statement exists. If it doesn't exist it creates it. Sorry I haven't realized it in the first place but you don't need to prepare a statement more than once. This is the actual benefit of such a statement, since it has to be only parsed once and can than be executed with different values, which is then much faster than a regular query.
As prepared statements last for the duration of the AR connection you only need to prepare it once.

ruby raise exception on iterator

The following function might return a null value hence I want to use the exception flow. Can someone direct me to the correct way to do it because right now I am getting the error.
syntax error, unexpected keyword_else, expecting keyword_end else
def value_from_table1(field, key)
begin
##connection.query("SELECT #{field} FROM table1 Where key = #{key} ").each do |row|
rescue Exception=>e
puts e
else
return row[field]
end
end
end
You are passing a block to Enumerator#each which introduces a new scope, so you need to put begin as a start of exception block inside.
If you also need handle exceptions of ##connection.query, just put rescue after do-end block of .each. begin is implicit at start of method's body.
First, rescuing from Exception is always a bad idea, see Why is it a bad style to `rescue Exception => e` in Ruby? for details.
Second a begin rescue block always has to have a closing end, else is only possible after an if before
begin
# ...
rescue StandardError => e
# ...
end
Third as already said by Justin Turner in the comment, just passing a value to the DB like that makes it prone to SQL injections. Is there any reason you don't use ActiveRecord but want direct DB access?
Overall there are so many issues with this short piece of code, I would suggest to read http://guides.rubyonrails.org/ to better understand what is going on.

Assigning of value in fast report variable

Hi I'm new in Delphi and I'm dealing with creating a reports for newly hired employee. I'm using Fast Report, Delphi XE2 and Firebird database.
I have a problem in writing a condition for the value of my variables.
I want the value of my variable to be handled value such as 'HIGH SCHOOL GRADUATE if the EDU_COLL_REMARK field value is null. and COLLEGE GRADUATE if it has a value.. just Like I did.
if dmapp.sqtrans.parambyname('EDU_COLL_REMARK').IsNull then
dmapp.frxReport1.Variables['edu'] := QuotedStr('HIGH SCHOOL GRADUATE');
else
dmapp.frxReport1.Variables['edu'] := QuotedStr('COLLEGE GRADUATE');
but it doesnt work. It returns an
Error SQTrans: Parameter EDU_COLL_REMARK not found.
Whats wrong? please help me.
this is my whole codes:
dmApp.sqTRANS.SQL.Clear;
dmApp.sqtrans.SQL.Add('Select s.SKILLS_NAME, c.CUST_NAME, e.FULL_NAME, e.REFER_1NAME, e.HIRE_DATE, e.AGE, e.HEIGHT_FEET, e.HEIGHT_INCH, e.EDU_COLL_REMARK, e.TEST_1TITLE, e.SEC_EXPERIENCE_YEARS, e.CELL_NO, e.ADDRESS_LINE FROM EMPLOYEE e INNER JOIN CUSTOMER c ' +
'on e.CUST_NO=c.CUST_NO ' +
'FULL JOIN SKILLSTABLE s on e.SKILLS_NO=s.SKILLS_NO ' +
'WHERE EXTRACT(MONTH FROM HIRE_DATE) = :M_HIRE_DATE ' +
'AND EXTRACT(YEAR FROM HIRE_DATE) = :Y_HIRE_DATE ' +
'order by HIRE_DATE DESC');
dmApp.sqTRANS.ParamByName('M_HIRE_DATE').AsString := FormatDateTime('MM', dpdate.Date);
dmApp.sqTRANS.ParamByName('Y_HIRE_DATE').AsString := FormatDateTime('yyyy', dpdate.Date);
if dmapp.sqtrans.parambyname('EDU_COLL_REMARK').IsNull then
dmapp.frxReport1.Variables['edu'] := QuotedStr('HIGH SCHOOL GRADUATE');
else
dmapp.frxReport1.Variables['edu'] := QuotedStr('COLLEGE GRADUATE');
dmApp.sqTRANS.ExecSQL();
dmApp.frxDBDataset1.DataSet := dmApp.sqTRANS;
dmApp.frxReport1.LoadFromFile('c:\vitech3\NewlyHired.fr3');
dmapp.frxReport1.variables['COMPANYNAME'] := QuotedStr(Globals.GetCompanyName);
dmapp.frxReport1.variables['COMPANYADD'] := QuotedStr(Globals.GetCompanyAddr + ' Cubao, Quezon City');
dmapp.frxReport1.variables['CAPTION'] := QuotedStr('Newly Hired Report for ' + FormatDateTime('MMMM', dpdate.date) + ' ' + FormatDateTime('yyyy', dpdate.date));
dmApp.frxReport1.ShowReport();
EDU_COLL_MARK is not a 'parameter' of your query; the parameters are those items prefixed with a ':'.
Return the value you want from the query, though. Have a look at case .. when in the Firebird docs. This will show you how to return a conditional value from your query.
SELECT
CASE EDU_COLL_MARK
WHEN NULL THEN 'HIGH SCHOOL GRADUATE'
ELSE 'COLLEGE GRADUATE'
END AS EDU
FROM ...
-------------- or perhaps
SELECT
CASE COALESCE(EDU_COLL_MARK, '')
WHEN '' THEN 'HIGH SCHOOL GRADUATE'
ELSE 'COLLEGE GRADUATE'
END AS EDU
FROM ...

Resources