sqlcmd on Azure SQL Data Warehouse - SqlState 24000, Invalid cursor state after INSERT statement - sqlcmd

I am working on a script to reload a table using SQLCMD on Linux connecting to an Azure SQL Data Warehouse database.
After the INSERT statement completes, the next statement fails (but does not end the sqlcmd execution) with the "warning"
insert into
schema.table_temp
(
...list of columns
)
select
...list of columns
from
schema.table
;
GO (COMMENT--> in script, but not echoed in log.)
(0 rows affected)
IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES t WHERE TABLE_TYPE = 'BASE TABLE' and TABLE_SCHEMA = 'schema' AND TABLE_NAME = 'table_nox' )
DROP TABLE schema.table_nox
;
GO (COMMENT--> in script, but not echoed in log.)
SqlState 24000, Invalid cursor state
The script continues to run with each subsequent batch getting the same
SqlState 24000, Invalid cursor state "warning"
If I comment out the INSERT statement, the script runs without warning as expected. I speculate the INSERT statement is not closing a cursor and then subsequent commands get the warning which should really be considered an eror and end the execution. (I have the -b flag on in the sqlcmd invocation.)
Is my only solution to break the script into multiple parts?

this seems to be an issue with the ODBC Driver that is used by sqlcmd under the hood. Can you confirm if you see this issue with Azure SQL DB? It would also be good to see your odbc.ini and odbcinst.ini files. Can you share those out?
In the meanwhile, I would like to recommend a couple of very cool Node.js command line tools that are more suited for Linux and Mac environments:
SQL-CLI
Cheetah
Thanks,
Meet

I faced similar issue and adding GO between two statements helped me.

We had the same issue. When performing INSERT via a SELECT it resulted in a (0 rows affected) response and a invalid cursor state error. Adding SET NOCOUNT ON at the start of the script worked for us. As #meet-bhagdev has already pointed out it looks like a driver issue.

Related

MySql: stop script if SELECT != (certain result)

I have a data cleanup script that I execute in Mysql Workbench in Windows. At the beginning of the script I have:
select ##hostname;
-- WARNING: it HAS to be `srv-datatest`
(+ the rest of the script)
I want the script to stop at that line if the condition (##hostname = 'srv-datatest') is not met.
Things that I've tried:
How to throw an exception:
DECLARE invalid_database CONDITION FOR 1051;
SIGNAL invalid_database;
-- DECLARE is not accepted by my workbench, and it lacks the "if" part anyway
How to do an IF on a select:
SELECT IF(##hostname='srv-datatest','yes','no');
-- It lacks the "stop here" part
create a stored procedure that will perform your process and test.
your script in mysql workbench should only call your stored procedure
It is possible to run it without stored procedures, using this ingenious solution:
SET #hostname := (SELECT ##hostname);
SET #condition = (#hostname='srv-datatest');
SET SESSION sql_mode = if(#condition, ##SESSION.sql_mode, 'Script stopped. Check condition.');
In this code:
If #condition=1, the script will run smoothly.
If #condition=0 it will throw an exception, showing the message error.

MySQL transaction error_count

I'm using MySQL version 5.1.60 and I have a script like the following:
START TRANSACTION;
BEGIN;
USE myDB;
DELETE FROM mytbl WHERE .......
DELETE FROM mytbl2 WHERE ......
....
INSERT INTO mytblN VALUE (.......
UPDATE mytbl SET .....
....
COMMIT;
Now, if any statement fails for any reason the execution of the script stops, I get the error message and I have to issue manually a ROLLBACK; and fix the relevant statement.
This script contains from hundreds to thousands statements and if many fails it is hard to fix each statement one by one.
I'm looking for a way to get all the errors in one shot and to have the transaction to rollback automatically.
Somewhere I found that if I replace the final
COMMIT;
with the following
SELECT IF(##error_count=0,'COMMIT;','ROLLBACK;') INTO #res;
PREPARE stmt FROM #res;
EXECUTE stmt;
and combine it with a
--force
parameter executing the script from command line I would get what I wanted.
Unfortunately I found that the system variable ##error_count 'reset' after each statement, and also the MySQL documentation states it:
error_count
The number of errors that resulted from the last statement that
generated messages. This variable is read only. See Section 14.7.5.17,
“SHOW ERRORS Syntax”.
Is there a way, without using a Stored Procedure, to obtain what I want?
So when I call the script from command line like:
>mysql -u root -p --force < myscript.sql >log.txt 2>&1
I have all the error logged in the log.txt file and the transaction rolled back?
many thanks in advance.

Invalid descriptor index on LAST_INSERT_ID after insert

Strange situation with my ODBC code ( called from a C library ). Basically, I have the following sequence of events:
Create insert statement ( just a string )
Call SQLPrepare with that insert statement string
Bind the various parameters ( column values ), using
SQLBindParameter
Call SQLExecute to insert the row ( this works, by the way, as I can
see the row in the MySQL DB )
Create "select last_insert_id()" statement string
NOTE: if in SQL Server mode, we would create a "select ##identity"
statement
Bind column using SQLBindCol - this is where I get the "Invalid
descriptor index" error
NOTE: if in SQL Server mode, this works fine, with no error
Call SQLExecDirect to get the last insert id - this never happens
because of SQLBindCol error
Does the standard MySQL ODBC connector require something special in this situation? Does anyone have an ODBC example of this type of "insert" then "get last insert id" behavior? Maybe I need to call "SQLPrepare" before step 6 ( where I bind the column )? Another way to ask this: Should there be an SQLPrepare call for each SQLExecute or SQLExecDirect call?
I know it works directly in SQL, so the problem is my C ODBC code.
Thanks.
For those who are interested, I ended up changing the above steps by adding an SQLPrepare call between creating the "select last_insert_id()" ( step 5 ) and calling SQLBindCol ( step 6 ). Not sure if that would work for others, but it seems to be working rather well for me.
As for research, I looked all over the place online and never found a really good or clear answer. Most comments were about the SQL involved, not ODBC. And the references to ODBC were vague and did not seem to apply to my situation, from what I could see.
My assumption is that the SqlServer ODBC driver I am using handles the missing prepare statement differently ( maybe even better, but that is debatable ) than my MySql ODBC driver.
SQL Server ODBC driver was the one provided by Easysoft
MySql ODBC driver was the one provided with the standard CentOS install of MySql
Hopefully this will help people. Obviously, if people have a better idea, please tell us.

MySQL query browser procedure error code -1

I'm having a rather strange problem with MySQL. Trying to create a procedure to update some fields in the database (the code is below).
The problem is with the line that is currently commented. It seems that if no SELECT statements get executed during the procedure MySQL query browser will return an error code of "-1, error executing SQL query".
I tried the same thing in HeidiSQL and the error was "cannot return result set". So I suppose the question is do I always have to select something in the procedure, or is there some other thing I missed.
The query works fine when the comment is removed.
DELIMITER /
DROP PROCEDURE IF EXISTS updateFavourites /
CREATE PROCEDURE updateFavourites(quota INT)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE artist_id,releases INT;
DECLARE c_artist Cursor FOR
SELECT Artist.id_number,COUNT(Artist.id_number) FROM Artist
JOIN CD ON CD.is_fronted_by = Artist.id_number
GROUP BY Artist.id_number;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000'
SET done=1;
IF quota > 0 THEN
OPEN c_artist;
REPEAT
FETCH c_artist INTO artist_id,releases;
IF NOT done THEN
IF releases >= quota THEN
UPDATE CD SET CD.rating='favourite' WHERE CD.is_fronted_by = artist_id;
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE c_artist;
-- SELECT 'Great success';
ELSE
SELECT CONCAT('\'quota\' must be greater than 0.',' Got (',quota,')');
END IF;
END /
DELIMITER ;
Here's the sql to create the tables and some data:
DROP TABLE IF EXISTS CD;
DROP TABLE IF EXISTS Artist;
CREATE TABLE Artist (
id_number INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
);
CREATE TABLE CD (
catalog_no INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY,
is_fronted_by INT UNSIGNED,
rating ENUM ('favourite','top draw','good','so-so','poor','rubbish'),
CONSTRAINT fk_CD_Artist FOREIGN KEY (is_fronted_by) REFERENCES Artist(id_number) ON UPDATE CASCADE
);
INSERT INTO Artist VALUES(11,'Artist 1');
INSERT INTO Artist VALUES(10,'Artist 2');
INSERT INTO CD VALUES (7,11, 'top draw');
INSERT INTO CD VALUES (650,11,'good');
INSERT INTO CD VALUES (651,11,'good');
INSERT INTO CD VALUES (11,10,'favourite');
Query Browser is not for running scripts, just single query.
I tried your code by moving cursor into each query (except DELIMITER) and pressing Ctrl+Enter.
It created that stored procedure without problem. (just refresh schema on the left).
If you wish creating procedure, use menu "Script"->"Create stored procedure/function".
But better forget about QueryBrowser it is not supported at all (and actunally not useful).
If you have decent hardware and plenty resources, try Workbench 5.2 otherwise use SQLyog
Googling around, there are several reports of the same error, but little information to solve the problem. There's even a bug logged at mysql.com but it appears to have been abandoned without being resolved.
There's another StackOverflow question on the same error, but it's also unresolved.
All it means is that there is no result set from the query. Looking at the source code, it appears that sometimes an error status of MYX_SQL_ERROR is set when the query has no result set. Perhaps this is not an appropriate consequence?
I notice that when I use the mysql command-line client, it yields no error for calling a proc that returns no result set.
update: I tried to revive that MySQL bug report, and provide a good test case for them. They changed the bug from "no feedback" to "verified" -- so at least they acknowledge it's a bug in Query Browser:
[11 Dec 9:18] Sveta Smirnova
Bill,
thank you for the feedback. Verified
as described.
Although most likely this only be
fixed when MySQL Query Browser
functionality is part of MySQL
workbench.
I guess the workaround is to ignore the -1 error, or to test your stored procedures in the command-line mysql client, where the error does not occur.
The comment supposes the issue will disappear as the Query Browser functionality becomes part of MySQL Workbench. This is supposed to happen in MySQL Workbench 5.2. I'll download this beta and give it a try.
MySQL Workbench 5.2 is in Beta, but I would assume MySQL engineering can't predict when the Beta will become GA. Those kinds of predictions are hard enough under standard conditions, but there's a lot of extra uncertainty of MySQL's fate due to the unresolved Oracle acquisition.
update: Okay, I have tried MySQL Workbench 5.2.10 beta. I executed a stored procedure like this:
CREATE PROCEDURE FooProc(doquery SMALLINT)
BEGIN
IF doquery THEN
SELECT * FROM Foo;
END IF;
END
When I CALL FooProc(0) the response is no result set, and the status is simply "OK".
When I CALL FooProc(1) the response is the result of SELECT * FROM Foo as expected.
However, there's another bug related to calling procedures. Procedures may have multiple result sets, so it's hard to know when to close the statement when you execute a CALL query. The consequence is that MySQL Workbench 5.2 doesn't close the statement, and if you try to do another query (either CALL or SELECT) it gives you an error:
Commands out of sync; you can't run this command now.
MySQL doesn't support multiple concurrent open queries. So the last one must be closed before you can start a new one. But it isn't closing the CALL query. This bug is also logged at the MySQL site.
The bug about commands out of sync has been resolved. They say it's fixed in MySQL Workbench 5.2.11.
Try putting BEGIN and END blocks around the multiple statements in the IF block as such:
IF quota > 0 THEN
BEGIN
OPEN c_artist;
REPEAT
FETCH c_artist INTO artist_id,releases;
IF NOT done THEN
IF releases >= quota THEN
UPDATE CD SET CD.rating='favourite' WHERE CD.is_fronted_by = artist_id;
END IF;
END IF;
UNTIL done END REPEAT;
CLOSE c_artist;
END;
ELSE
SELECT CONCAT('\'quota\' must be greater than 0.',' Got (',quota,')');
END IF;

Issue calling a MySQL stored procedure (with params) via a linked server (SQL Server 2005) using OPENQUERY syntax

I'm having issues when trying to call a MySQL (5.0.77) stored procedure with parameters, via a linked server (SQL Server 2005) using the OPENQUERY syntax.
The MySQL stored procedure returns a result set, and when I use the 'EXEC ... AT ...' syntax the call works fine, e.g...
EXEC('CALL my_stored_proc(''2009-10-07'',''2009-10-07'');') AT MySQLSERVER;
The limitation of using 'EXEC ... AT ...' means I can't insert the result set into a temporary table in SQL Server, which is ultimately what I want to do. Which led me to trying the OPENQUERY syntax...
SELECT * FROM OPENQUERY(MySQLSERVER,'CALL my_stored_proc(''2009-10-07'',''2009-10-07'');')
...But this fails, and returns...
Msg 7357, Level 16, State 2, Line 1
Cannot process the object "CALL my_stored_proc(''2009-10-07'',''2009-10-07'');". The OLE DB provider "MSDASQL" for linked server "MySQLSERVER" indicates that either the object has no columns or the current user does not have permissions on that object.
Which is strange, given that the 'EXEC ... AT ...' call didn't complain about permissions. The following calls all work fine...
EXEC('SHOW TABLES;') AT MySQLSERVER;
SELECT * FROM OPENQUERY(MySQLSERVER,'SHOW TABLES;');
CREATE TABLE #tmpTest (
[table] varchar(255) null
);
INSERT INTO #tmpTest ([table])
SELECT * FROM OPENQUERY(MySQLSERVER,'SHOW TABLES;');
SELECT * FROM #tmpTest;
DROP TABLE #tmpTest;
So my question is, how can I make a call to a MySQL stored procedure, via a linked server, and store the result set in a temporary table in SQL Server? Either by using the 'EXEC ... AT ...' syntax, or by solving the object/permissions error when using the OPENQUERY syntax.
Any help would be greatly appreciated!
You need to enable "Ad Hoc Distributed Queries" on the SQL Server. This is not enabled by default, for security reasons. Most of the time, the "do not have permission" errors are related to this one.
Execute this on the SQL Server, and then try again your code:
EXEC sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
EXEC sp_configure 'Ad Hoc Distributed Queries', 1;
GO
RECONFIGURE;
GO
I hope it helps.
I tried the fix to configure "Ad Hoc Distributed Queries" but was still getting this same error:
"The OLE DB provider "MSDASQL" for linked server "MyMySQL" indicates
that either the object has no columns or the current user does not
have permissions on that object."
I am attempting a simple remote SELECT query against a linked MySQL database.
In my case, the query I was attempting looked like this. Pay attention to the number of lines used:
SELECT * FROM OPENQUERY
([MyMySQL],
'
SELECT
ID as ISSUE_ID, etc..
The fix was to remove the newline after the opening single-quote. Simple, huh? But not obvious.
The working code shown below:
SELECT * FROM OPENQUERY
([MyMySQL],
'SELECT
ID as ISSUE_ID, etc..
Hope it helps!
Rob
I realize this a pretty old post, but my problem was similar to Rob's in that the SQL within the OPENQUERY doesn't take line breaks as whitespace the same way SQL server does.
i.e. Laying out my query as follows:
SELECT
*
FROM
OPENQUERY(LINKEDSERVER, '
SELECT
SomeField
FROM
SomeTable
')
I needed to have spaces as if it were written on one line (using _ as a visible space for demonstration):
SELECT
*
FROM
OPENQUERY(LINKEDSERVER, '
SELECT_
SomeField_
FROM_
SomeTable
')