Dapper - Stored Procedure - Incorrect syntax near 'GO' - c#

I have a stored procedure in a myscript.sql file that looks like this:
CREATE PROCEDURE [dbo].[_GetUserID]
#EmailAddress NVARCHAR(254)
AS
DECLARE #UserID UNIQUEIDENTIFIER;
SELECT #UserID = [ID]
FROM [dbo].[User]
WHERE [EmailAddress] = #EmailAddress
PRINT #UserID
GO
I have some C# code that relies on Dapper to run this script. I can successfully run this script when I copy-and-paste it into Azure Data Studio. However, when I am trying to run this script from code, I get an error:
Incorrect syntax near 'GO'
My C# code looks like this:
try
{
var script = File.ReadAllText("<path to myScript.sql is here>");
using (var connection = new SqlConnection(dbConnectionString))
{
var command = connection.CreateCommand();
command.CommandText = script;
command.CommandType = CommandType.Text;
connection.Open();
command.ExecuteNonQuery();
}
Console.WriteLine("Success.");
}
catch (Exception ex)
{
Console.WriteLine($"Failed. Reason: '{ex.Message}')");
}
I don't understand why I can run myScript.sql from Azure Data Studio, however, it's not working from my C# code. I'm also creating tables using the same approach and it works fine. I'm not sure what I'm missing.

GO is not a valid T-SQL keyword - it's a separator that is used by SQL Server Management Studio and obviously also Azure Data Studio.
To fix this, just simply remove that GO line from your .sql script file and run it without this - should be just fine.
On a different note: having nothing but a PRINT statement in your stored procedure doesn't make a lot of sense - don't you want to actually SELECT #UserId to get that data sent back to the caller??

Related

How to Select an out parameter from a MySql Procedure in .net

Assume we have a stored procedure like so
CREATE PROCEDURE CopyValue(IN src INT, OUT dest INT)
BEGIN
SET dest = src;
END
I want to call this from a .net app (assume connection etc created successfully)
var sql = "call CopyValue(100, #destValue); select #destValue as Results;";
The string in the above statement works perfectly well when called in MySql Workbench.
However this - obviously - fails with "MySqlException: Parameter '#destValue' must be defined" when executed on a MySqlCommand object in .net
How do I arrange this statement so I can capture an output parameter from an existing procedure?
NB: I'm running against MySql 5.6, which I can't upgrade at this time.
NB Calling the procedure directly with CommandType.StoredProcedure goes against company guidelines.
By default, user-defined variables aren't allowed in SQL statements by MySQL Connector/NET. You can relax this restriction by adding AllowUserVariables=true; to your connection string. No modifications to your SQL or how you're executing the MySqlCommand should be necessary.
For information about why this is the default, you can read the research on this MySqlConnector issue (which also has the same default behaviour, but a much better error message that will tell you how to solve the problem): https://github.com/mysql-net/MySqlConnector/issues/194
A colleague (who wishes to remain anonymous) has answered this perfectly. Essentially put backticks ` after the # and at the end of the variable name e.g.
#`MyParam`
A fully working example.
static void Main(string[] args)
{
using var con = new MySql.Data.MySqlClient.MySqlConnection("Data Source=localhost; User Id=...;Password=...;Initial Catalog=...");
con.Open();
using var cmd = con.CreateCommand();
cmd.CommandText = "call CopyValue2(100, #`v2`); select #`v2` as Results;";
using var reader = cmd.ExecuteReader();
if (reader.Read())
Console.WriteLine($"Copied Value {reader.GetInt64(0)}");
}
Thanks OG :)

MySql.Data.MySqlClient Error when calling stored procedure

I am running into an issue, that I believe lies within my privileges granted. However, I can't figure out why this is happening. I have a stored procedure in MySQL defined by:
DELIMITER //
CREATE PROCEDURE my_stored_procedure (var_one VARCHAR(20), var_two INT4)
BEGIN
UPDATE table_name SET ACTIVATION_DATE = UTC_TIMESTAMP(),
DEACTIVATION_DATE = TIMESTAMPADD(MONTH, var_two, UTC_TIMESTAMP()),
USER_ACTIVATED = 1 WHERE ID = var_one;
END //
DELIMITER ;
I am calling this from my c# application. The code runs fine when I use userA's credentials. However, when I use userB it doesn't work. userA was granted privileges with the command:
GRANT ALL PRIVILEGES ON * . * TO 'userA'#'%';
userB was granted privileges with these commands:
GRANT UPDATE, SELECT ON current_db.table_im_updating TO 'userB'#'%';
GRANT EXECUTE ON PROCEDURE my_stored_procedure TO 'userB'#'%';
My code to call the mysql stored procedure is as follows:
connection = new MySql.Data.MySqlClient.MySqlConnection("server=ip_address; port=3306; database=data_base; UID=userA; password=password; pooling=false");
MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand();
command.Connection = connection;
command.CommandText = "my_stored_procedure";
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#_id","associated_id");
command.Parameters["#_id"].Direction = System.Data.ParameterDirection.Input;
command.Parameters.AddWithValue("#subscription_length", "6");
command.Parameters["#subscription_length"].Direction = System.Data.ParameterDirection.Input;
command.ExecuteNonQuery();
Like I mentioned. This code works fine when userA and userA's password are entered; but when I switch to userB the error says,
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
It is also worth noting that if I change my method of calling the procedure to this:
MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand("CALL my_stored_procedure(var_one, var_two)", connection);
I get no errors. I am not trying to just make my code work, I want it to work properly. Please help me understand what is causing this Error. Thanks.
TL;DR
userB should be granted with SELECT access to the mysql.proc table.
Explaination
First, MySQL Connnector/NET is executed SHOW CREATE PROCEDURE my_stored_procedure to get all parameters definition. (Order, Direction, DbType etc.)
Then, it will combine procedure name and parameters to create a sql like CALL my_stored_procedure(var_one, var_two) to execute.
To use SHOW CREATE PROCEDURE, you must be the user named in the routine DEFINER clause or have SELECT access to the mysql.proc table. If you do not have privileges for the routine itself, the value displayed for the Create Procedure field will be NULL.
-- Doc: SHOW CREATE PROCEDURE Syntax
-- Issue: Connector 8.0 - Stored Procedure Error in MySqlDataReader
Give the userB the privileges to Execute the SP and add CheckParameters=false to Connection String

Conversion failed in SQL procedure while executing from C#

I have a SQL stored procedure which uses openrowset command and fetches values from an excel sheet and inserts it into the database.
I have created a C# application which will call the procedure and execute it.
PROBLEM!
When I execute the procedure from SQL management studio, there are no errors. It happens perfectly. But when I execute it through the C# application I get an error: "Conversion failed when converting date and/or time from character string."
Code
SQL Query (only the insert part)
insert into tbl_item ([Item code],[Dt Created])
select[Item code] ,
case when [Dt Created] is null or [Dt Created]='' then null when ISDATE(CONVERT(nvarchar,CONVERT(datetime, [Dt Created],103))) =1 then CONVERT(datetime, [Dt Created],103) else null end as [Dt Created]
FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0','Excel 12.0; Database=C:\Upload\Report.xlsx;HDR=YES;IMEX=1;',
'select * from [Sheet1$]')
C# Code
public int updateItem()
{
SqlCommand cmd; cmd = new SqlCommand("usp_updateItem", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
try
{
if (conn.State.Equals(ConnectionState.Closed))
conn.Open();
cmd.ExecuteNonQuery();
ret = Convert.ToInt32(returnParameter.Value);
}
catch (Exception e)
{
err = "Error: " + e.Message;
return -1;
}
finally
{
conn.Close();
}
return ret;
}
What is the format you are having in the [Dt Created] variable.
the convert statement you have in the case will convert only the following types below
YYYY-MM-DD
YYYY-DD-MM
DD-MM-YYYY
The error you are getting is since you have a date in the format of "MM-DD-YYYY" something like '12-24-2015'. Due to this you are getting the conversion error.
Excuse me I want to stop you here. Your problem has resolved now but whatever
Karthik Venkatraman had said is correct. Somehow you got solution but for learning purpose i recommended to investigate little bit more. This is not belongs to the whatever you have said but damm sure this belongs to date-format.
**
One trick
Create one DateTimeVariable and once its initialized then just parse it using DateTimeParse class according to the records exist in database.
I am sure you will get solution.. Thanks :)
This is how I finally solved it...
The SQL error message 'Failed Conversion' was absolutely a wrong pointer. It had no connection to the issue at hand. [If only I knew this before :( ]
The actual problem was that I had called another procedure within the main procedure I had posted above. This setup ran perfectly in SQL management studio which was running under my credentials. Now in the C# application, I had created another SQL login user ID to run it. And this user ID did not have execute permission to run the sub procedure. And ironically, SQL gave me a misleading conversion error. Once I gave the right permission it worked perfectly.

invalid object name sql exception for table name in c#

I wrote this code, but it doesn't work. Gives Invalid object name 'Inventory'`. Any Suggestion?
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString =
#"Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AutoLot";
cn.Open();
string strSQL = "Select * From Inventory";
SqlCommand myCommand = new SqlCommand(strSQL, cn);
// Obtain a data reader a la ExecuteReader().
using (SqlDataReader mydatareader = mycommand.ExecuteReader())
{}
Check in Database Inventory table is present or not and if Present then both name should be same
If you've checked all your database settings, access rights and table definitions and still cannot get rid of that error?
It's because ASP.net cannot understand your SQL query - as shocking as that may sound.
I had the same problem, with UPDATE statements wanting to use aliases and not the usually expected dbo.myTable name definitions.
The simplest way to avoid this situation, where asp.net just doesn't parse SQL like SQL Server would (!!), is to place the code into a Stored Procedure.
This was my SQL directly from SQL Server 2005 and it worked perfectly as is...
UPDATE tsa
SET tsa.ActionComplete = #ActionComplete,
tsa.CompleteDate = GETDATE(),
tsa.Notes = #ActionNotes
FROM blahblah
WHERE blahblah
But for what ever reason, the ASP.net parser inside the SqlDataSource control could not make sense of it (even though it ran perfectly inside the GUI's Test Query feature!).
I was getting
invalid object name in 'tsa'
So I placed the lot inside a Stored Procedure...
USE [mydatabase];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
ALTER PROCEDURE [dbo].[spTETupdateActions]
#StudentID VARCHAR(10),
#ActionComplete INT = 0,
#ActionNotes VARCHAR(MAX),
#TETmeetingID INT,
#WeekNo INT,
#TETID INT,
#TETdate DATETIME,
#ActionItem VARCHAR(MAX)
WITH
EXEC AS CALLER AS
UPDATE tsa
SET tsa.ActionComplete = #ActionComplete,
tsa.CompleteDate = GETDATE(),
tsa.Notes = #ActionNotes
FROM blahblah
WHERE blahblah
GO
And voila! No more errors! Why? Because the parsing of the SQL is done inside SQL Server not ASP.net!

Update SQL table through C# code

I want to update a table through sql code executed in a c# application. To do this, I've used the alter data generated my MSSMS and manually saved it as an sql-file. The c# then reads the file and tries to execute it but it can't. If I use the sql code by itself it works, but not when read by the c# funtion. What's wrong with my c# code?
The sql code generated my MSSMS:
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.tTest ADD
NewColumn int NULL
GO
ALTER TABLE dbo.tTest SET (LOCK_ESCALATION = TABLE)
GO
COMMIT
The c# code that reads it:
string content = string.Empty;
try
{
content = File.ReadAllText(string.Format(#"C:\temp\{0}.sql", name));
SqlConnection conn = new SqlConnection(ConnectionString);
SqlCommand command = new SqlCommand(content, conn);
command.Connection.Open();
command.ExecuteNonQuery();
command.Connection.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
The output that comes from the c# function (the console message):
A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll
Incorrect syntax near 'GO'.
Incorrect syntax near 'GO'.
Each batch (ended with GO) should be sent separately in one command.ExecuteNonQuery(). This method is not to be used for multiple batches.
Split your query into several pieces (where GO is) and execute it step by step.
The core issue with the script you are trying to run is wrapping a transaction around query batches (A query batch is terminated with a GO statement in SQL Server Management Studio).
To do the operations in C# you can execute both statements in one query batch. They do not require to be separate. If you wrap them in one query in a SqlCommand object you do not need to handle transactions as there is an "implicit" transaction created.
A last point to look out for is proper disposal of the objects implementing IDisposable. The easiest way to do this in C# is by wrapping them in a using clause. Once you did that, there is no more need to call the Close method on the command/connection objects.
Combining all these remarks gives you the following code:
try
{
using(var conn = new SqlConnection(ConnectionString))
using(var command = new SqlCommand(
#"ALTER TABLE dbo.tTest ADD NewColumn int NULL;
ALTER TABLE dbo.tTest SET (LOCK_ESCALATION = TABLE);", conn))
{
conn.Open();
command.ExecuteNonQuery();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}

Categories