Changing the MySQL query delimiter through the C API - c

How can I change the MySQL query delimiter using the C API? I tried sending DELIMITER | as a query, complained about ..the right syntax to use near 'delimiter' at line 1..
Tried DELIMITER |; too, no luck. Tried DELIMITER |; SELECT 1|, no luck. :(
The reason I ask is that I need to create a trigger through the C API such as the following:
create trigger increase_count after insert on torrent_clients for each row
begin
IF NEW.BytesLeft = 0 THEN
UPDATE torrents SET Seeders = Seeders + 1 WHERE torrents.InfoHash = NEW.InfoHash;
ELSE
UPDATE torrents SET Leechers = Leechers + 1 WHERE torrents.InfoHash = NEW.InfoHash;
END IF;
end|
but I don't think there is a way to do it without changing the delimiter, is there?
Thanks!
EDIT: Note that I do need to explicitly write the delimiter at the end, as I'm running multiple queries with only one API call (I have multi statements on)
EDIT2: the mysqlclient that uses the C api does this so there must be a way..

Changing the delimiter is only needed when using the mysql client program (because it is mysql that interpretes the semicolon as statement delimiter). You don't need to change the delimiter when using the C API:
Normally, you can execute only a single SQL command with mysql_query(). A semicolon can appear in such a command only when it is syntactically allowed, and that is normally not the case! In particular, SQL does not allow for a command to end in a semicolon. (The C API will raise an error if you attempt to do so.)
The commands CREATE PROCEDURE, CREATE FUNCTION, CREATE TRIGGER, and the like are exceptions when they define a stored procedure or trigger: In such commands the semicolon serves as a separator between the SQL instructions that are part of the stored procedure or trigger. Such commands can be executed without problem.
P.S. You probably should set multi statements off again.

You can execute multiple commands using mysql_query. You will have to set some parameters though while establishing the connection.
e.g.,
unsigned long opt_flags = CLIENT_FOUND_ROWS | CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS ;
if (0 == mysql_real_connect(mConn,mHostName,mUserName,mUserPass,mDbName,mPort,0,opt_flags))
...
/* execute multiple statements */
status = mysql_query(mysql,
"DROP TABLE IF EXISTS test_table;\
CREATE TABLE test_table(id INT);\
INSERT INTO test_table VALUES(10);\
UPDATE test_table SET id=20 WHERE id=10;\
SELECT * FROM test_table;\
DROP TABLE test_table");

Did you try
DELIMITER //
Without a ";" at the end? It might be not possible to change the delimiter within a query that has multiple queries in it.

Related

Using UDF's in Excel SQL Server DB query [duplicate]

How can I execute the following SQL inside a single command (single execution) through ADO.NET?
ALTER TABLE [MyTable]
ADD NewCol INT
GO
UPDATE [MyTable]
SET [NewCol] = 1
The batch separator GO is not supported, and without it the second statement fails.
Are there any solutions to this other than using multiple command executions?
The GO keyword is not T-SQL, but a SQL Server Management Studio artifact that allows you to separate the execution of a script file in multiple batches.I.e. when you run a T-SQL script file in SSMS, the statements are run in batches separated by the GO keyword. More details can be found here: https://msdn.microsoft.com/en-us/library/ms188037.aspx
If you read that, you'll see that sqlcmd and osql do also support GO.
SQL Server doesn't understand the GO keyword. So if you need an equivalent, you need to separate and run the batches individually on your own.
Remove the GO:
String sql = "ALTER TABLE [MyTable] ADD NewCol INT;";
cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
sql = "UPDATE [MyTable] SET [NewCol] = 1";
cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
It seems that you can use the Server class for that. Here is an article:
C#: Executing batch T-SQL Scripts containing GO statements
In SSMS (SQL Server Management System), you can run GO after any query, but there's a catch. You can't have the semicolon and the GO on the same line. Go figure.
This works:
SELECT 'This Works';
GO
This works too:
SELECT 'This Too'
;
GO
But this doesn't:
SELECT 'This Doesn''t Work'
;GO
This can also happen when your batch separator has been changed in your settings. In SSMS click on Tools --> Options and go to Query Execution/SQL Server/General to check that batch separator.
I've just had this fail with a script that didn't have CR LF line endings. Closing and reopening the script seems to prompt a fix. Just another thing to check for!
Came across this trying to determine why my query was not working in SSRS. You don't use GO in SSRS, instead use semicolons between your different statements.
I placed a semicolon ; after the GO, which was the cause of my error.
You will also get this error if you have used IF statements and closed them incorrectly.
Remember that you must use BEGIN/END if your IF statement is longer than one line.
This works:
IF ##ROWCOUNT = 0
PRINT 'Row count is zero.'
But if you have two lines, it should look like this:
IF ##ROWCOUNT = 0
BEGIN
PRINT 'Row count is zero.'
PRINT 'You should probably do something about that.'
END
I got this error message when I placed the 'GO' keyword after a sql query in the same line, like this:
insert into fruits (Name) values ('Apple'); GO
Writing this in two separate lines run. Maybe this will help someone...
I first tried to remove GO statements by pattern matching on (?:\s|\r?\n)+GO(?:\s|\r?\n)+ regex but found more issues with our SQL scripts that were not compatible for SQL Command executions.
However, thanks to #tim-schmelter answer, I ended up using Microsoft.SqlServer.SqlManagementObjects package.
string sqlText;
string connectionString = #"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=FOO;Integrated Security=True;";
var sqlConnection = new System.Data.SqlClient.SqlConnection(connectionString);
var serverConnection = new Microsoft.SqlServer.Management.Common.ServerConnection(sqlConnection);
var server = new Microsoft.SqlServer.Management.Smo.Server(serverConnection);
int result = server.ConnectionContext.ExecuteNonQuery(sqlText);

select ... into variable from table where 1=0 leads to the replacement of the variable with null

We are migrating a lot of code from SQL Server to Postgresql. We met the following problem, a serious difference between SQL Server and Postgresql.
Of course, below, by the expression 1=0, I meant cases when the query conditions do not return a single record.
A query in SQL Server:
select #variable = t.field
from table t
where 1 = 0
saves the previous value of the variable.
A query in Postgresql:
select t.field
into variable
from table t
where 1 = 0
replaces the previous value of the variable with null.
We have already rewritten a lot of code without taking this feature into account.
Is there an easy way in postgresql, without rewriting the code, to save the value of a variable in such cases? For example, maybe there is some kind of server's or database's or session's settings? We did not find any relevant information in the documentation. We do not understand such a pattern of behavior in postgresql, which requires the introduction of additional variables and lines of code to check the result of the every query.
As far as I know there is no way to change postgresql's behavior here.
I don't have access to the SQL/PSM specifications, so I couldn't tell you which one matches the standard (if any / if SELECT INTO <variable> even is in it).
You don't need to use additional variables though, you can use INTO STRICT and catch the exception when no rows were returned:
DO $$
DECLARE
variable int = 1;
BEGIN
BEGIN
SELECT 1
INTO STRICT variable
WHERE FALSE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
END;
RAISE NOTICE 'kept the previous value: %', variable;
END
$$
shows "kept the previous value: 1".
Though it is obviously more verbose than the SQL Server version.

Python3 pypyodbc SQL Server call stored procedure fails

The Python 3.8.1 code that I am working with makes several calls to stored procedures, gets results, does a simple select statement passing a string -- all successfully, using pypyodbc. My last call has me stumped as it simply fails to produce any results, or fails miserably. The stored procedure updates 1 column in 3 tables based on an OrderID, and inserts 1 row in another table. Using SSMS, the call would look like this:
exec GK_set_order '123456'
where 123456 is the OrderID. OrderID is a varchar(). I have logged into SSMS as the user in my Python connect statement and executed that stored procedure and it works every time.
In Python, the order number is used throughout as ADCOrderID, a string. My suspicion is that the single quotes are what is biting me. My first attempt was to create a separate string and execute that string.
exec_SP = "exec GK_set_order '" + ADCOrderID + "'"
cur.execute(exec_SP)
A print(exec_SP) statement shows that it is exactly what I want. But I get no errors, no exceptions, and nothing is updated in the database. I've tried 20 different variations, including double and triple quotes. Nothing was effective.
Changed to:
exec_SP = "exec GK_set_Order(?)"
cur.execute(exec_SP, ADCOrderID)
Now I get an error:
TypeError: Params must be in a list, tuple, or Row
What am I fundamentally missing?

Very strange SQL Server query behaviour

I have a very strange issue with a SQL query.
IF NOT EXISTS ([special query here])
BEGIN
SELECT 1;
END
ELSE
BEGIN
SELECT 2;
END
The query above outputs: 2.
However when I replace the SELECT 1; part with a large query containing create tables etc. multiple errors are thrown. How is it possible that SQL Server executes code inside the case of an IF statement while that case is not true?
If you are changing schema, the parser will look to see that all the entities exist before running it.
ALTER TABLE myTable ADD aNewColumn INT
UPDATE myTable SET aNewColumn = 0
This will produce an error.
You can use dynamic sql, as long as you aren't taking in parameters from a client.
EXEC sp_executesql N'UPDATE myTable SET aNewColumn = 0'
Syntax errors are syntax errors, whether you're in a conditional branch that'll run or a conditional branch that won't run. Parsing occurs before execution, and must be successful.
Consider this analogous example written in C++:
int main()
{
if (false) {
acbukasygdfukasygdaskuygdfas##4r9837y214r
}
}
You can't write that nonsense line even though it's inside of a block that'll never run, because the program's intended meaning cannot be determined by the compiler.

Issue with parameters in SQL Server stored procedures

I remember reading a while back that randomly SQL Server can slow down and / or take a stupidly long time to execute a stored procedure when it is written like:
CREATE PROCEDURE spMyExampleProc
(
#myParameterINT
)
AS
BEGIN
SELECT something FROM myTable WHERE myColumn = #myParameter
END
The way to fix this error is to do this:
CREATE PROCEDURE spMyExampleProc
(
#myParameterINT
)
AS
BEGIN
DECLARE #newParameter INT
SET #newParameter = #myParameter
SELECT something FROM myTable WHERE myColumn = #newParameter
END
Now my question is firstly is it bad practice to follow the second example for all my stored procedures? This seems like a bug that could be easily prevented with little work, but would there be any drawbacks to doing this and if so why?
When I read about this the problem was that the same proc would take varying times to execute depending on the value in the parameter, if anyone can tell me what this problem is called / why it occurs I would be really grateful, I cant seem to find the link to the post anywhere and it seems like a problem that could occur for our company.
The problem is "parameter sniffing" (SO Search)
The pattern with #newParameter is called "parameter masking" (also SO Search)
You could always use the this masking pattern but it isn't always needed. For example, a simple select by unique key, with no child tables or other filters should behave as expected every time.
Since SQL Server 2008, you can also use the OPTIMISE FOR UNKNOWN (SO). Also see Alternative to using local variables in a where clause and Experience with when to use OPTIMIZE FOR UNKNOWN

Resources