I'm writing one update statement in my procedure but there are chances that CommandTimeout(30 sec for testing my code) may expire. So I was looking for a solution.
Then I came to know that in mysql Diagnostic is available. So i tried that. It is working fine in my workbench. It is returning the variable with message that after which count it is failing.
To execute the procedure failure I putted a condition that if it is true then say signal error
I'm executing this line of code in c#
object Result = _DBCommand.ExecuteScalar();
And after this when timeout is happening mysql error in coming.
I'm wondering how can i catch the variable that I'm throwing from Procedure.
DROP PROCEDURE IF EXISTS udsp_Test;
DELIMITER //
CREATE PROCEDURE udsp_Test(
-- paramters...
)
BEGIN
-- --------------------------------------------------------------------------
-- 00 Declaration
-- --------------------------------------------------------------------------
DECLARE error_InvalidInputs CONDITION FOR SQLSTATE 'HY000';
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
GET DIAGNOSTICS CONDITION 1 #var_SqlState = RETURNED_SQLSTATE, #var_MessageText = MESSAGE_TEXT, #var_MySqlErrorNo = MYSQL_ERRNO, #var_SchemaName = SCHEMA_NAME, #var_TableName = TABLE_NAME;
SET #var_FullError = CONCAT("ERROR: ", #var_MySqlErrorNo, " (", #var_SqlState, "): ", #var_MessageText, "Scheman Name: ", #var_SchemaName, "Table Name: ",#var_TableName);
SET #var_ErrorMessage = CONCAT(#var_ErrorMessage,';;;;;', #var_FullError);
SELECT #var_ErrorMessage;
RESIGNAL ;
END;
SET #var_ErrorMessage = '';
SET #var_ErrorMessage = CONCAT(#var_ErrorMessage,'Error message: = Now; ');
-- update statement here
SET #var_ErrorMessage = CONCAT(#var_ErrorMessage,'Error message: = Now; ');
SELECT 1 as UpdatedSuccessfully;
END//
DELIMITER ;
Related
I have a stored procedure which returns a 0 or a 1 depending on whether or not a specified email address exists in my database:
CREATE PROCEDURE [DatabaseSchema].[EmailAddressIsDuplicate] (#emailAddress nvarchar(255))
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS(
SELECT *
FROM [DatabaseSchema].[EmailUpdatesRegistrant]
WHERE EmailAddress = #emailAddress
)
RETURN 1
ELSE
RETURN 0
RETURN 0
END
GO
And I'm trying to derive the results of this stored procedure from an Entity Framework 6 database context:
using (DatabaseContext dbContext = new DatabaseContext())
{
ObjectParameter param = new ObjectParameter("emailAddress", typeof(bool));
var result = dbContext.EmailAddressIsDuplicate(emailAddress);
}
I'm getting lots of errors.
Error #1: Using the code above, var result is always set to -1.
Error #2: I tried navigated to Edit Function Import and set the Returns a Collection Of to a Boolean scalar value. This throws the following error:
The data reader returned by the store data provider does not have enough columns for the query requested.
Error #3: I went back and set the Edit Function Import return value to None. Then I tried the following code from this answer:
using (DatabaseContext dbContext = new DatabaseContext())
{
var p = new SqlParameter("#emailAddress", emailAddress);
var result = dbContext.Database.SqlQuery<bool>("DatabaseSchema.EmailAddressIsDuplicate", p);
}
No immediate errors thrown, but I have no idea whether or not I can derive useful data from var result. Trying to cast result to bool throws the following error:
Cannot convert type 'System.Data.Entity.Infrastructure.DbRawSqlQuery' to 'bool'
Any ideas on how I can see the results of this stored procedure (0 or 1)?
You could try adding an output parameter (#result) in the stored procedure signature:
CREATE PROCEDURE [DatabaseSchema].[EmailAddressIsDuplicate]
(#emailAddress nvarchar(255), #result bit out)
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS(SELECT *
FROM [DatabaseSchema].[EmailUpdatesRegistrant]
WHERE EmailAddress = #emailAddress)
SET #result = 1
ELSE
SET #result = 0
RETURN #result
END
GO
(you'll have to re-define your EF Model Function definition accordingly)
using (DatabaseContext dbContext = new DatabaseContext())
{
ObjectParameter isDuplicate = new ObjectParameter("isDuplicate", typeof(bool));
var result = dbContext.EmailAddressIsDuplicate(emailAddress, isDuplicate);
bool emailIsDuplicate = (bool)isDuplicate.Value;.
}
If you want to call the stored procedure directly with an out parameter you could follow this suggestion:
Database.SqlQuery calling stored procedure that has multiple output parameters
REASON - The template builder for EF (including v6) incorrectly sets the SP up as returning an INT containing the row count rather than the return value because it incorrectly calls the wrong ObjectContext.ExecuteFunction (found in the template-generated class YourDatabaseEntities that is the child of the DBContext).
Why wrong ExecuteFunction? - The result set incorrectly says the row count of changed rows rather than the return value or output parameters because it calls a different ExecuteFunction that discards the results. The flyover intellisense hint of the ObjectContext.ExecuteFunction says "Executes a stored procedure ….; discards any results returned from the function; and returns the number of rows affected by the execution" rather than the usual "Executes a stored procedure …. with the specified parameters".
WHY -1: I believe the SET NOCOUNT ON is causing the SP to return no count result and that Microsoft's ExecuteFunction returns that as error code.
SP FIXES - 1) You have to comment out SET NOCOUNT ON .
2) You have to change stored procedure to do the SELECT command as last statement instead of the RETURN command.
SOLUTION FIX - 1) After fixing SP, delete SP from Function Imports folder and the Data Store's SP folder. 2) Reload the SP into the EDMX by using the "Update Model from Database" 3) Rebuild all of your data project where the EDMX resides. 4) Exit Visual Studio and return. 5) Rebuild overall solution.
See: Entity Framework (Database first) has incorrect return result from stored procedure
Implement the stored procedure in C# to a value using parameters.
Resource: https://msdn.microsoft.com/en-us/library/yy6y35y8(v=vs.110).aspx
This way, the values can be stored to a variable from the ExecuteReader.
Add the value to model similar to adding a value to a property. The stored procedure could be called from ActionResult. Though this may require adding the stored procedure to a separate layer, that simply runs the stored procedure and adds the value to model afterwards.
try this
CREATE PROCEDURE [DatabaseSchema].[EmailAddressIsDuplicate] (#emailAddress nvarchar(255))
AS
BEGIN
SELECT *
FROM [DatabaseSchema].[EmailUpdatesRegistrant]
WHERE EmailAddress = #emailAddress
SELECT ##ROWCOUNT
END
GO
using (DatabaseContext dbContext = new DatabaseContext())
{
var result = dbContext.Database.SqlQuery<int32>("exec DatabaseSchema.EmailAddressIsDuplicate {0}", emailAddress).FirstOrDefault();
}
Anything other 0 in the return value indicates there is a match and the number indicates the number of matches
I'm using MySqlConnector to execute query in C# code.
I have example procedure:
CREATE PROCEDURE RC_TEST
(
ZIPCODE VARCHAR(7),
INOUT SEARCH_VALUE VARCHAR(2)
)
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
SET #SWV_Error = 1;
END;
SELECT TB_TABLE.SEARCH_VALUE INTO SEARCH_VALUE FROM TB_TABLE
WHERE TB_TABLE.ZIPCODE = ZIPCODE;
IF #SWV_ERROR <> 0 THEN
SET SEARCH_VALUE = NULL
END IF;
END;
When I'm executing this procedure in MySql Workbench - everything is ok.
But when I'm the same piece of code execute in C# code:
conn.Open();
var command = new MySqlCommand(script, conn);
command.ExecuteNonQuery();
conn.Close();
I got the error:
"Parameter '#SWV_Error' must be defined."
What am I doing wrong?
I'm trying to create a stored procedure from out C# into Firebird 2.1.
The code is:
String sql = #"EXECUTE BLOCK AS BEGIN " +
"ALTER TABLE EXAMPLE ALTER FIELD1 TYPE Char(50); " +
"SET TERM ^ ; CREATE PROCEDURE name ( input_parameter_name < datatype>, ... )" +
"RETURNS ( output_parameter_name < datatype>, ... ) AS DECLARE VARIABLE variable_name < datatype>;" +
"BEGIN /* write your code here */ END^ SET TERM ; ^" +
" END";
public int Execute(string sql)
{
int result = 0;
if (this.OpenConnection() == true)
{
FbTransaction transaction = Fbconnection.BeginTransaction();
try
{
FbCommand command = new FbCommand(sql, Fbconnection, transaction);
int rc = command.ExecuteNonQuery();
result = rc;
transaction.Commit();
}
catch (Exception e)
{
globals.logfile.log(e.ToString());
globals.logfile.flush();
result = 0;
}
finally
{
this.CloseConnection();
}
}
return result;
}
The error message given is:
FirebirdSql.Data.FirebirdClient.FbException (0x80004005):
Dynamic SQL Error SQL error code = -104 Token unknown - line 1, column 24 ALTER
Must be something small, but I can't get it.
DDL is not allowed in PSQL (stored procedures, triggers, execute block), so executing an ALTER TABLE like this is rejected.
Also SET TERM is not part of the Firebird statement syntax. It is specific to query tools like isql and FlameRobin, as they use statement terminators like ; to know when they end of a statement is reached and can be sent to the server. When executing PSQL blocks those tools need to watch for a different statement terminator to prevent them from sending incomplete statements to the server. In the actual Firebird statement syntax ; is only part of PSQL blocks.
You will need to execute the ALTER TABLE and the CREATE PROCEDURE separately without an EXECUTE BLOCK.
I'm using C# and System.Data.OracleClient to add functions to a database. This works for most functions, except one. The function is created but its state is INVALID. After examining the cause for this invalid state, I noticed I could simply compile the function within SQL Developer, but not from my c# application.
Any ideas why there is a difference using .NET and SQL Developer?
This is the function I use
string sql =
#"CREATE OR REPLACE FUNCTION MYUSER.TEMPJOINSTRINGS
( P_CURSOR SYS_REFCURSOR,
P_DEL VARCHAR2 := ', '
) RETURN VARCHAR2
IS
L_VALUE VARCHAR2(32767);
L_RESULT VARCHAR2(32767);
BEGIN
LOOP
FETCH P_CURSOR INTO L_VALUE;
EXIT WHEN P_CURSOR%notfound;
IF L_RESULT IS NOT NULL THEN
L_RESULT := L_RESULT || P_DEL;
END IF;
L_RESULT := L_RESULT || L_VALUE;
END LOOP;
RETURN L_RESULT;
END;";
try
{
using (OracleConnection connection = new OracleConnection(#"Data source=TEST10;User Id=MYUSER;Password=MYPASS;"))
{
connection.Open();
DbCommand cmd = connection.CreateCommand();
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
connection.Close();
return true;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
and after that I execute
ALTER FUNCTION MYUSER.TEMPJOINSTRINGS COMPILE
But compiling will only work from SQL Developer, not my c# application.
i'd take a guess that the String in .NET is bieng formatted as windows syle ie.
\r\n linefeeds.
try this
sql = sql.Replace("\r", "");
after you have the function string built.
you can quickly confirm this if you did:
SQL> show errors function TEMPJOINSTRINGS
Errors for FUNCTION TEMPJOINSTRINGS:
LINE/COL ERROR
-------- -----------------------------------------------------------------
1/26 PLS-00103: Encountered the symbol "" when expecting one of the
following:
( return compress compiled wrapped
SQL> select status from user_objects where object_name = 'TEMPJOINSTRINGS';
STATUS
-------
INVALID
SQL> select text, dump(text) from user_source where name = 'TEMPJOINSTRINGS' and line = 1;
TEXT
--------------------------------------------------------------------------------
DUMP(TEXT)
--------------------------------------------------------------------------------
FUNCTION TEMPJOINSTRINGS
Typ=1 Len=26: 70,85,78,67,84,73,79,78,32,84,69,77,80,74,79,73,78,83,84,82,73,78,
71,83,13,10
13,10 at the end being \r\n
I have a stored procedure that recives as paramter as OUTPUT paramter. The store procedure sets its value. I have the following code in C# application. But I am not getting the value in application (the output is returned as zero). What is the missing link here?
CREATEPROCEDURE [dbo].aspInsertZipCode
(
#CountOfUnchangedZipCode AS INT=0 OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SET #CountOfUnchangedZipCode = 13
END
In the application, code is as follows
DbCommand cmd = db.GetStoredProcCommand("aspInsertZipCode");
cmd.CommandTimeout = 0;
db.AddOutParameter(cmd, "CountOfUnchangedZipCode", DbType.String, 1000);
The execution happens ...
int TempUnchageZipCount = Convert.ToInt32(db.GetParameterValue(cmd, "#CountOfUnchangedZipCode"));
Add to your SP:
RETURN #CountOfUnchangedZipCode
Otherwise you could use something like this after executing the command in your code:
var TempUnchageZipCount = (int) cmd.Parameters[0].Value;