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.
Related
I am new to MySQL and I am building a Flask project and using mysql.connector to query a MySQL Database. I know this question has been answered many times before but this is more specific to using MySQL with Flask.
I need to pass a query where I want to plug in the table name into the query, dynamically, depending on the value stored in the session variable in Flask. But the problem is, if I try to do:
Method 1:
cur.execute('SELECT * FROM %s;',(session['table_name'],))
the database throws an error stating that such a table is not found. However, the problem is mysql.connector keeps enclosing the table name with single quotes, hence the error.
Sample Error Statement:
mysql.connector.errors.ProgrammingError: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''52_data'' at line 1
Here the table name should be 52_data and not '52_data'.
Only other workaround, I figured, is using:
Method 2:
cur.execute('SELECT * FROM '+session['table_name']+';')
which is working but it does not escape SQL Injection, I am guessing, since it's direct concatenation, unlike Method 1, where the cur.execute() function handles the escaping, as per this question.
The value being passed is stored in a sessions variable in Flask, which is not so secure, as per Miguel's Video. Hence, I want to escape that string, without triggering off an error.
Is it possible to implement Method 1 in a way that it does not add the quotes, or maybe escape the string using some function? Or maybe any other Python/Flask package that can handle this problem better?
Or if nothing works, is checking for SQL Injection manually using regex is a wiser option?
Thanks in advance.
Note: The package name for this mysql.connector is mysql-connector-python and not any other same sounding package.
For identifiers, you can use something like:
table_name = conn.converter.escape(session['table_name'])
cur.execute('SELECT * FROM `{}`'.format(table_name))
For values placeholders, you can use your Method 1, by using the parameters in the cur.execute() method. They will be escaped and quoted.
More details in https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-execute.html
NOTE: You don't need to end the SQL statements with ;
I'm working on a desktop-application, database, webserver-access combination which someone wrote some years ago. My task is to do some optimications/refactoring and to introduce new features to this application(s). I have not much experience in developing web applications, so it's quite difficult for me to find a solution to my problem described below, hoping someone can help me.
The webapplication is written with ASP and VBScript having some small javascript functions which do not affect my question. It uses ADODB for communicating with the database.
The database is a MS-SQLserver 2008 database.
The desktop-application is written in C++/CLI using the .Net built-in features for communicating with the database. With this application everything is working.
For introducing some features I need to add new columns to tables in the database. Inserting and updating of the main table is done with stored procedures. I added a column named "internal" of type "bit":
ALTER TABLE maintable
ADD internal bit
GO
I altered the stored procedures for inserting and updating, just by adding the internal column and a parameter for it. I made only these changes:
1x line for the parameter
added internal in the column and values list for the insert
added setting internal column with parameter for the update
In the vbscript which already was working before any changes I added the code for appending the value for internal as new parameter (its the same for insert & update):
sqlcmd.Parameters.Append(sqlcmd.CreateParameter("#internal",11,1))
sqlcmd.Parameters("#internal")=0
After these changes the update und insert procedures of the vbscript stopped working. I tried several datatypes for the parameter and also changing the column (different name, different datatype). Nothing worked. The stored procedures themself are working fine when executed directly in the database and also when used by the desktop-application.
I started to debug everything with printing some debuginformations ect. I added try/catch in the stored procedures and a outparameter to get some errors according to this answer and I selected all input-parameters into a varchar outparameter. This caused the next strange results.
While updating "worked" (because the stored procedure didn't cause a database error and I got the input-parameter informations which didn't show wrong values, but no update was performed) inserting didn't workin any way. My tracing outputs where printed till the sqlcmd.Execute, this line seems to crash since the trace outputs after this line wheren't printed. As long as I did not use the outparameter the insert itself didn't work, but all trace outputs got printed. I tried to retrieve information about a possible database error directly after the execution of the code with:
DECLARE #ErrorVariable INT;
SET #ErrorVariable = ##ERROR;
SELECT #ErrorVariable AS ErrorID,
text
FROM sys.messages
WHERE message_id = #ErrorVariable;
GO
There was no database error.
Everything works fine from the desktop-application side. As mentioned the stored procedures executed directly in the database will work properly. I suppose the the error is somewhere in web-scripting-stuff. So now here are the concrete questions:
Why would the stored procedure not work (properly) when adding a new column to the database (it is there) and no syntax errors in the stored procedures or vbscript?
Why the sqlcmd.Execute stops working when adding a outparameter to the insert stored procedure? The try-block in the stored procedures includes everything between "AS BEGIN" and "END" having the catch-block directly before "END". Syntax is here also correct.
try to catch the error at the asp end.
On Error Resume Next
sqlcmd.Execute
for each objerr in yourconnection.Errors
Response.write objerr.Description & "<br/>"
next
On Error GoTo 0
Please check this link:
ADO Connection Object Errors Collection
I'm using MySQL 5.5 (x64) and MySQL Workbench 5.2 deployed locally on a Windows 7 workstation for development purposes. I used MySQL Workbench to build a schema with the following function definition:
CREATE FUNCTION `db`.`get_public_name` (GPN_entID INT) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE GPN_pubName VARCHAR(64);
SELECT public_name INTO GPN_pubName
FROM entity WHERE id_entity=GPN_entID LIMIT 1;
RETURN GPN_pubName;
END
I then attempt to "Forward Engineer" the schema to the database with the following options specified:
DROP Objects Before Each Create Object
Generate DROP SCHEMA
Add SHOW WARNINGS After Every DDL Statement
GENERATE INSERT Statements for Tables
After this, MySQL Workbench attempts to publish to the server:
CREATE FUNCTION `db`.`get_public_name` (GPN_entID INT) RETURNS VARCHAR(64)
DETERMINISTIC
BEGIN
DECLARE GPN_pubName VARCHAR(64);
SELECT public_name FROM entity WHERE id_entity = GPN_entID;
RETURN GPN_pubName;
END
This results in the following error:
Executing SQL script in server
ERROR: Error 1415: Not allowed to return a result set from a function
Upon closer examination, I noticed the "INTO" and "LIMIT" clauses of the SELECT statement have been removed from the original function definition. This looks like it might be a cached version of the function, but I have tried everything I can think of (short of uninstalling and reinstalling MySQL Workbench) to flush any such cache to reload the correct version, but to no avail.
So, why is this change happening and how do I prevent it from happening?
Try changing to this:
SELECT public_name FROM entity WHERE id_entity = GPN_entID LIMIT 1 INTO GPN_pubName;
I'm embarrassed; if it wasn't for the fact this may be useful to others, I'd just go ahead and delete this question to hide my shame.
It turns out I created two functions with the same name and MySQL Workbench happily let me do so. I didn't notice that was the case until I started going through the stored routines with a more careful eye. I was editing one, but the other one (which had the error) was never changed. Since publishing each function involved dropping any earlier version from the database, I probably wouldn't have noticed this until things weren't working properly.
I'm writing a Java tool to validate SQL statements. For SELECT queries, I can do it with Connection.prepareStatement and PreparedStatemet.getMetaData. No exceptions == good query. Unfourtunately it doesn't work with eg. INSERT statements -- errors in query create exception only at executing the statement.
Is there a way to parse SQL via JDBC without executing the statement? An internal method maybe?
Unfourtunately I was also unable to find source code for Connector/J -- I'd be grateful for links to it.
OK, found an answer myself, need to call a protected method:com.mysql.jdbc.ServerPreparedStatement.getInstance(MySQLConnection conn, String sql, String catalog, int, int)
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
')