Is it possible to return from a HSQLDB Stored procedure before reaching its end?
I've tried:
IF (condition) THEN
RETURN;
END IF;
This doesn't compile.
Neither with EXIT or LEAVE instead of RETURN.
CREATE PROCEDURE PRO (VAR INT)
mylabel: BEGIN ATOMIC
...
IF VAR = 3 THEN
LEAVE mylabel;
END IF;
...
END
Related
Below is a function I have in VB that will run a stored proc. The stored proc has 2 out parameters. One called #Success and one called #Message.
I am trying to set the success and message parameters to the values of the corresponding output params from the stored proc. I don't know much about VB.NET. How can I achieve this based off of the function I have currently written?
Public Function InvalidateCertificate(ByVal context As DbContextBase,
ByVal certificateId As System.String,
ByRef success As System.Boolean,
ByRef message As System.String) As Int32
Dim successParameter As New SqlParameter("#Success", success) With {.Direction = ParameterDirection.InputOutput, .Value = success}
Dim messageParameter As New SqlParameter("#Message", message) With {.Direction = ParameterDirection.InputOutput, .Value = message}
Dim parameters() As SqlParameter = {New SqlParameter("#CertificationValue", certificateId), successParameter, messageParameter}
Dim results As Int32 = context.ExecuteProcedure("Orders.spInvalidateCertificate", parameters)
success = DirectCast(successParameter.Value, System.Boolean)
message = DirectCast(messageParameter.Value, System.String)
Return 0
End Function
Stored proc:
ALTER PROCEDURE [Orders].[spInvalidateCertificate]
-- Add the parameters for the stored procedure here
#CertificationValue VARCHAR(20),
#Success BIT OUTPUT,
#Message VARCHAR(50) OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Log the call to this procedure
EXEC [Logs].[spLogStoredProcedureCall] ##PROCID;
--Check to see if CertificationValue exists or is invalid
IF(select CertificationValue from
[Certificate].CertificateOrderDetailImageXref where CertificationValue =
#CertificationValue) is null
BEGIN
SET #Success = 0
SET #Message = 'Certification does not exist or is already
invalidated.'
END
ELSE
BEGIN
-- Insert statements for procedure here
UPDATE Certificate.CertificateOrderDetailImageXref
SET CertificationValue = CONCAT(#CertificationValue,'-VOID')
WHERE CertificationValue = #CertificationValue
SET #Success = 1
SET #Message = 'Success, certification has been invalidated.'
END;
END
GO
To note, what's actually happening is that only the first letter of the message is being returned. so if its a success, and the sql output should be "success!" I just get "S". If the certification does not exist I just get "C".
I am just new in oracle and using procedure and still learning, but I have a problem how can I populate the combo box using store procedure? I already have a code but when I run it, it shows an error IndexOutOfRangedException was unhandled and Cannot find Column 1.
Here's my code
(Procedure/Oracle Sql:)
procedure cmbbox_location (o_output out o_refcur)
as
o_cur o_refcur;
begin
open o_cur for
select city_id, city_name from city;
o_output := o_cur;
end cmbbox_location;
(program/vb.net)
Private Sub Main_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
instantiate_dev()
ora_conn.Open()
populate_cmbbox_loc()
End Sub
Private Sub populate_cmbbox_loc()
instantiate_dev()
ora_conn.Open()
qr.populate_location()
cmblocation.DataSource = dt
cmblocation.ValueMember = dt.Columns(0).ColumnName
cmblocation.DisplayMember = dt.Columns(1).ColumnName
cmblocation.Text = ""
cmblocation.SelectedIndex = 0
End Sub
Public Function populate_location()
dt = New DataTable
bg.GetProcDataTable(connStr, "Location_Package.cmbbox_location")
cmd.Parameters.Add(New OracleParameter("O_OUTPUT", OracleDbType.RefCursor)).Direction = ParameterDirection.Output
adap_or.SelectCommand = cmd
adap_or.Fill(dt)
Return dt
ora_conn.Close()
End Function
The error you are getting indicates that you are indexing something that doesn't exist, it's possible/probable your stored procedure isn't returning anything. To address William Robertson's concern about the ref cursor:
There are any number of ways to output a ref cursor. The one I use the most is a ref cursor type defined in the package definition, for example:
CREATE OR REPLACE PACKAGE Location_Package IS
TYPE DataOutCursor IS REF CURSOR;
procedure cmbbox_location (o_output out DataOutCursor);
END Location_Package;
/
Then in the procedure in the package body:
CREATE OR REPLACE PACKAGE BODY Location_Package IS
procedure cmbbox_location (o_output out DataOutCursor) as
begin
open o_output for
select city_id, city_name from city;
end;
END;
/
I assume the error is occurring here:
cmblocation.ValueMember = dt.Columns(0).ColumnName
cmblocation.DisplayMember = dt.Columns(1).ColumnName
It is always best to make sure the data table has data first so wrap the combo box lines with:
IF dt.Rows.Count > 0 Then
' ..... assign the data table to the combo box
Else
' Some error message ...
End IF
This will get rid of the unhandled exception and help you to figure out the issue.
On last thing, your function needs to return a value (datatable):
Public Function populate_location() as Datatable
dt = New DataTable
bg.GetProcDataTable(connStr, "Location_Package.cmbbox_location")
cmd.Parameters.Add(New OracleParameter("O_OUTPUT", OracleDbType.RefCursor)).Direction = ParameterDirection.Output
adap_or.SelectCommand = cmd
adap_or.Fill(dt)
Return dt
ora_conn.Close()
End Function
I have the following stored procedure:
CREATE PROCEDURE MyProc
#posted_xml_body xml
AS
INSERT INTO MyTable
(post_datetime, post_body)
VALUES
(getdate(), #posted_xml_body)
And the following VB code:
Using aConnection As New Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings(connectionString).ConnectionString)
aConnection.Open()
Dim aCommand As New Data.SqlClient.SqlCommand("MyProc", aConnection)
aCommand.CommandType = Data.CommandType.StoredProcedure
aCommand.Parameters.AddWithValue("#posted_xml_body", aXMLString)
Dim rows_affected As Integer = aCommand.ExecuteNonQuery()
aCommand.Dispose()
aConnection.Close()
Return rows_affected
End Using
However, I keep receiving the following error
"Procedure or function has too many arguments specified."
Thanks for any suggestions.
You pasted wrong or is missing a ")" here
VALUES
(getdate(), #posted_xml_body)
There are couple things I would suggest.
chang the column type to nvarchar(max), select scope identity, just make sure your table as a primary key because you vb code will give you an exception trying to convert date to integer.
CREATE PROCEDURE MyProc
#posted_xml_body as nvarchar(max)
AS
Begin
INSERT INTO MyTable
(post_datetime, post_body)
VALUES
(getdate(), #posted_xml_body);SELECT SCOPE_IDENTITY()
END
Your Vb Code
Using aConnection As New Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings(connectionString).ConnectionString)
Dim rows_affected As Integer = 0
Try
aConnection.Open()
Dim aCommand As New Data.SqlClient.SqlCommand("MyProc", aConnection)
aCommand.CommandType = Data.CommandType.StoredProcedure
aCommand.Parameters.AddWithValue("#posted_xml_body", aXMLString)
rows_affected = aCommand.ExecuteScalar()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
If aConnection.State = ConnectionState.Open Then
aConnection.Close()
End If
End Try
Return rows_affected
End Using
I deliberately trigger a SqlException in the following insert statement in the code below and replaced the correct column name ModifiedBy by ModifiedB
You need to wrap the entire SQL Code in a transaction. Take this example:
create table errTest
(
intVal int
)
insert into errTest select 1
insert into errTest select 1/0
select * from errTest --one record
The second insert fails, but since no transaction was explicitly started, each insert is inherently its own transaction. The first succeeds, the second fails, and the table ends up retaining the successful insert.
If all inserts are wrapped in a transaction, and if xact_abort is on, then any error thrown by any insert will cause the entire transaction to rollback:
create table errTest
(
intVal int
)
set xact_abort on
begin transaction
insert into errTest select 1
insert into errTest select 1/0
commit transaction
select * from errTest --zero records
You need to pass your transaction and connection to all your commands you wish to use inside a SQL transaction, this is my example (I cut some things out using notepad so it might give errors in studio)
Private Sub main()
Using sql_conn
sql_conn.Open()
Dim SQL_transaction_INPUT As SqlClient.SqlTransaction = sql_conn.BeginTransaction
Try
Dim isOK as Boolean = False
isOK = update_BSE(myID, sql_conn, SQL_transaction_INPUT)
If isOK Then
SQL_transaction_INPUT.Commit()
sql_conn.Close()
Else
SQL_transaction_INPUT.Rollback()
sql_conn.Close()
End If
Catch ex As Exception
SQL_transaction_INPUT.Rollback()
If sql_conn.State = ConnectionState.Open Then sql_conn.Close()
End Try
End Using
End Sub
Private Function update_BSE(ByVal _IDmod As Integer, _
ByVal conn_with_trans As SqlConnection, _
ByVal conn_transaction As SqlTransaction) As Boolean
Dim ins As String = "UPDATE something WHERE IDrec = #IDmod"
Dim cmdINS As New SqlCommand(ins, conn_with_trans, conn_transaction)
Try
With cmdINS.Parameters
.Add("IDmod", SqlDbType.Int).Value = _IDmod
End With
cmdINS.ExecuteNonQuery()
Return True
Catch ex As Exception
Return False
End Try
End Function
I have a Stored Procedure that seems to be very slow.
Executing it in Oracle SQL Developer;
SET TIMING ON;
DECLARE
CUR_OUT UTILS.T_CURSOR;
P_ARTTYID NUMBER;
P_ORDERST VARCHAR2(200);
P_DRUMNO VARCHAR2(200);
P_SHIPPINGNO VARCHAR2(200);
P_DELIVERYDATEFROM DATE;
BEGIN
P_ARTTYID := 2;
P_ORDERST := '3';
P_DRUMNO := '611-480';
P_SHIPPINGNO := NULL;
P_DELIVERYDATEFROM := '2005-01-01';
C_T_ORDER_GETOVERVIEW(
CUR_OUT => CUR_OUT,
P_ARTTYID => P_ARTTYID,
P_ORDERST => P_ORDERST,
P_DRUMNO => P_DRUMNO,
P_SHIPPINGNO => P_SHIPPINGNO,
P_DELIVERYDATEFROM => P_DELIVERYDATEFROM
);
--DBMS_OUTPUT.PUT_LINE('CUR_OUT = ' || CUR_OUT); -- Doesn´t work ;|
END;
Gives the "Statement output"
anonymous block completed
139ms elapsed
Now the problem is when I call it from my VB.NET application using
Microsoft.Practices.EnterpriseLibrary.Data.Database.ExecuteReader() that returns a System.Data.IDataReader and the following function to convert the IDataReader to a DataSet.
Public Shared Function ConvertIDataReaderToDataSet(ByVal reader As IDataReader) As DataSet
Dim schemaTable As DataTable = reader.GetSchemaTable()
Dim dataTable As DataTable = New DataTable
For intCounter As Integer = 0 To schemaTable.Rows.Count - 1
Dim dataRow As DataRow = schemaTable.Rows(intCounter)
Dim columnName As String = CType(dataRow("ColumnName"), String)
Dim column As DataColumn = New DataColumn(columnName, CType(dataRow("DataType"), Type))
dataTable.Columns.Add(column)
Next
Dim dataSet As DataSet = New DataSet
dataSet.Tables.Add(dataTable)
'dataSet.Load(reader, LoadOption.OverwriteChanges, dataTable) ' DEBUG
While reader.Read()
Dim dataRow As DataRow = dataTable.NewRow()
For intCounter As Integer = 0 To reader.FieldCount - 1
dataRow(intCounter) = reader.GetValue(intCounter)
Next
dataTable.Rows.Add(dataRow)
End While
Return dataSet
End Function
Debugging and stepping through the function ends at the line for "While reader.Read()".
Also tried another version using DataSet.Load() but with the same result.
Found this thread on MSDN where others with the same problem seems to have solved it by tuning their queries by adding indexes.
How can I continue investigating the issue when it seems like the procedure works (responds within ~100 - 200ms) and the IDataReader.Read() just ends (or continues in the background?)
Can I time the procedure in another (better) way?
Can there be any table or transaction locks involved?
All advices are highly appreciated :)
Your test in SQL Developer is simply measuring the time required to open the cursor. Opening the cursor does not cause Oracle to actually execute the query-- that does not happen until you fetch data from the cursor and each time you fetch, Oracle will continue processing the query to get the next set of rows. Oracle does not, in general, need to execute the entire query at any point in time. To be a comparable test, your PL/SQL block would need to fetch all the data from the cursor. Something like
DECLARE
CUR_OUT UTILS.T_CURSOR;
P_ARTTYID NUMBER;
P_ORDERST VARCHAR2(200);
P_DRUMNO VARCHAR2(200);
P_SHIPPINGNO VARCHAR2(200);
P_DELIVERYDATEFROM DATE;
BEGIN
P_ARTTYID := 2;
P_ORDERST := '3';
P_DRUMNO := '611-480';
P_SHIPPINGNO := NULL;
P_DELIVERYDATEFROM := '2005-01-01';
C_T_ORDER_GETOVERVIEW(
CUR_OUT => CUR_OUT,
P_ARTTYID => P_ARTTYID,
P_ORDERST => P_ORDERST,
P_DRUMNO => P_DRUMNO,
P_SHIPPINGNO => P_SHIPPINGNO,
P_DELIVERYDATEFROM => P_DELIVERYDATEFROM
);
LOOP
FETCH cur_out
INTO <<list of variables to fetch data into>>;
EXIT WHEN cur_out%notfound;
END LOOP;
--DBMS_OUTPUT.PUT_LINE('CUR_OUT = ' || CUR_OUT); -- Doesn´t work ;|
END;
Are you saying that in your .Net code, the reader.Read() line never returns? Or are you saying your code aborts at that point?