Informix + SQLAlchemy looking for table that doesn't exist - sqlalchemy

I'm trying to connect to an Informix database with SQLAlchemy. All my tests seem to show the connection is working; however, whenever I try and perform a read of the database I get the error:
DatabaseError: (DatabaseError) SQLCODE -217 in PREPARE:
IX000: Column (current_role) not found in any table in the query (or SLV is undefined).
'select CURRENT_ROLE from systables' ()
Now the database that I am connecting to doesn't have CURRENT_ROLE, so how can I get round this?
My interactive traceback of the error is shown below in a gist:
https://gist.github.com/2157378
The offending line is:
File "build/bdist.linux-i686/egg/sqlalchemy/dialects/informix/base.py", line 593, in _get_default_schema_name
return connection.execute('select CURRENT_ROLE from systables').scalar()
Is there any workaround for this problem?
I am now led to believe this is a bug in SQLAlchemy (after talking to users in #sqlalchemy) and I have filed a bug report:
http://www.sqlalchemy.org/trac/ticket/2448

You've not identified which version of IBM Informix Dynamic Server (IDS) you are using or which platform you are using it on, so it is hard to help you.
It appears that SQLAlchemy expects a more recent version of Informix than you are using. Somewhat to my surprise, the niladic function CURRENT_ROLE appears to be available in IDS 11.70 (tested on 11.70.FC4 on RHEL 5 for x86/64). It was not recently added, so it will be in any 11.70 version, and possibly in some earlier versions (but not as early as the version you are using).
I'm not sure how much of a bug it is in SQLAlchemy. If the version of Informix that you're using is really old, there is limited virtue in them adding support for it. You can find out which version you're using by running:
SELECT DBINFO('version', 'full')
FROM 'informix'.systables
WHERE tabid = 1;
If that doesn't work, you are many years out of date with your server.
Addendum
Thinking about it a bit more...I wonder what SQLAlchemy is going to do with the role. It probably shouldn't be trying to analyze whether you have permission; it should try an operation and deal with failures. That will be quicker, especially in the common case where you actually do have permission.
There could be two issues:
SQLAlchemy should be aware that some (as yet indeterminate) list of old versions of IDS do not support CURRENT_ROLE.
SQLAlchemy should review why it needs to be aware of the current role.

Related

Knex : universal way to get the last inserted id

I'm using Knex, because I'm working on an application that I would like to use with multiple database servers, currently Sqlite3, Postgres and MySQL.
I'm realizing that this might be more difficult that I expected.
On MySQL, it appears that this syntax will return an array with an id:
knex('table').insert({ field: 'value'}, 'id');
On postgres I need something like this:
knex('table').insert({ field: 'value'}, 'id').returning(['id']);
In each case, the structure they return is different. The latter doesn't break MySQL, but on SQlite it will throw a fatal error.
The concept of 'insert a record, get an id' seems to exist everywhere though. What am I missing in Knex that lets me write this once and use everywhere?
Way back in 2007, I implemented the database access class for a PHP framework. It was to support MySQL, PostgreSQL, SQLite, Microsoft SQL Server, Oracle, and IBM DB2.
When it came time to support auto-incremented columns, I discovered that all of these implement that feature differently. Some have SERIAL, some have AUTO-INCREMENT (or AUTOINCREMENT), some have SEQUENCE, some have GENERATED, some support multiple solutions.
The solution was to not try to write one implementation that worked with all of them. I wrote classes using the Adapter Pattern, one for each brand of SQL database, so I could implement each adapter class tailored to the features supported by the respective database. The adapter satisfied an interface that I defined in my framework, to allow the primary key column to be defined and the last inserted id to be fetched in a consistent manner. But the internal implementation varied.
This was the only sane way to develop that code, in my opinion. When it comes to variations of SQL implementations, it's a fallacy that one can develop "portable" code that works on multiple brands.

ODBC call failed - Random date overflow errors after moving from 32-bit ODBC 5.1 to 64-bit 5.3

Background:
Legacy code running in MS Access 2003.
Sqls run by CurrentDB in Access.
Currently running on Windows 7 32-bit machine.
Connecting to MySQL Server 5.5 through a ODBC 5.1 Driver.
Problem:
Trying to migrate to Windows server 2012 64 bit.
ODBC 5.3 Unicode Driver (32 bit).
Don't want to use time rewriting everything as there is a lot of code, and it will in a not to distant future be removed.
Issue:
Several sql statements fail when running on the new servers. Worked on old servers.
All the failed sqls have now() in the statement.
Error description says ODBC call failed. While the more detailed description says date overflow - "[MySQL][ODBC 5.3(w) Driver][mysqlid-5.5.28-log]Date overflow".
Happens randomly, and when it happens and Access stops one can usually just choose continue and the sql will then work. It fails less than 1% of the times it runs (of thousands).
The only dates in the sql are in the where clause: "and fieldA > now()", where fieldA is a datetime column. This is a get recordset sql. Another error during an insert is the same, but where an integer was subtracted from now() before compared to a datetime.
I don't understand why it says date overflow when there doesn't seem to be a reason for the time of either datetime or "now" to be removed? And since the datetime field is already in the database and now() will get current date and time there shouldn't be any invalid dates?
Any help in what the problem might be or how to debug/log anything that might help would be highly appreciated.
Turning trace on in the ODBC driver is not an option because it happens so randomly, there is so much traffic therefore this would slow down everything such that nothing happens.
Note that I also did encounter one sql where the date overflow error message was correct. It seems that prior to 5.3 when inserting a datetime into a date field it was automatically truncated, because a sql which had been successfull 3000 times started failing. Therefore this sql has been fixed by extracting the date from the field first. But the other errors must be something different.
New version containing a bugfix has been released by Oracle: 5.3.8
This error was a bug that seems to have been introduced in version 5.1.11.
In advanced options there is now a Date overflow check box which has to be ticked for the code to continue when there is an error.
Reply from Oracle about the fix:
"For your information the fix approach was that in C or C++ it is possible to read or write DATE type using SQL_TIMESTAMP_STRUCT.
This struct can hold both date and time.
The error (Date overflow) was generated when with operations that are supposed to be DATE-only this struct got non-zero values for time.
That is the canonical approach as ODBC API requires, however, it causes inconveniences sometimes when for instance the app did not bother
to initialize the whole structure with 0 values because it knows it will only need the DATE part but the random values for TIME fraction could cause the errors despite of being truncated.
A new option was introduced to continue with the query execution rather then return error.
The server will ignore the TIME part and the result is the same as if there were zeroes."
This appears to be an issue with MySQL Connector/ODBC versions 5.2 and later. A web search led to this thread on another site, which in turn led to this unresolved bug report. Note that this is a broader MySQL Connector/ODBC issue; it is not specific to Access applications.
MySQL Connector/ODBC 5.1.13 is still available for download, so your most expedient solution would probably be to simply use that version until the code in question is taken out of service. Your other alternatives might include:
using a newer version of MySQL Server (with [better?] support for fractional seconds), or
tweaking the Access SQL queries to use something other than the Now() function (which you, understandably, would like to avoid).
I had exactly the same problem - "Date overflow" error when saving the data in an Access form.
I changed the data type from "datetime" to "timestamp" in the linked MySQL table and this solved the issue. The datetime data type seems to be too short to accommodate the value of Now() in MS Access.
Remember to refresh the linked tables in Access afterwards.
I also noticed that there was a "Not Null" tick mark next to the ModifyTime timestamp field in the MySQL table. I unticked this.
After these two changes I no longer get the Date Overflow error when Me.Dirty=False executes in Access.
I use Access365 (x64), MySQL ODBC Connector 8.0.31 (x64) and MySQL 5.6

Query to detect MySQL

I'm fixing a bug in a proprietary piece of software, where I have some kind of JDBC Connection (pooled or not, wrapped or not,...). I need to detect if it is a MySQL connection or not. All I can use is an SQL query.
What would be an SQL query that succeeds on MySQL each and every time (MySQL 5 and higher is enough) and fails (Syntax error) on every other database?
The preferred way, using JDBC Metadata...
If you have access to a JDBC Connection, you can retrieve the vendor of database server fairly easily without going through an SQL query.
Simply check the connection metadata:
string dbType = connection.getMetaData().getDatabaseProductName();
This will should give you a string that beings with "MySQL" if the database is in fact MySQL (the string can differ between the community and enterprise edition).
If your bug is caused by the lack of support for one particular type of statement which so happens that MySQL doesn't support, you really should in fact rely on the appropriate metadata method to verify support for that particular feature instead of hard coding a workaround specifically for MySQL. There are other MySQL-like databases out there (MariaDB for example).
If you really must pass through an SQL query, you can retrieve the same string using this query:
SELECT ##version_comment as 'DatabaseProductName';
However, the preferred way is by reading the DatabaseMetaData object JDBC provides you with.
Assuming your interesting preconditions (which other answers try to work around):
Do something like this:
SELECT SQL_NO_CACHE 1;
This gives you a single value in MySQL, and fails in other platforms because SQL_NO_CACHE is a MySQL instruction, not a column.
Alternatively, if your connection has the appropriate privileges:
SELECT * FROM mysql.db;
This is an information table in a database specific to MySQL, so will fail on other platforms.
The other ways are better, but if you really are constrained as you say in your question, this is the way to do it.
MySql may be the only db engine that uses backticks. That means something like this should work.
SELECT count(*)
FROM `INFORMATION_SCHEMA.CHARACTER_SETS`
where 1=3
I might not have the backticks in the right spot. Maybe they go like this:
FROM `INFORMATION_SCHEMA`.`CHARACTER_SETS`
Someone who works with MySql would know.

How do you coerce float values in MySQL for classic ASP scripts?

I have been charged with maintaining a legacy classic ASP application. The application uses an ODBC system DSN to connect to a MySQL database.
We had to recently update the servers to satisfy some licencing requirements. We were on Windows, with MySQL 4.x and the 3.51 ODBC driver. We moved to a Linux machine running MySQL 5.1.43 and are running the 5.1.6 ODBC driver on the new IIS server.
Users almost instantly started reporting errors as such:
Row cannot be located for updating.
Some values may have been changed
since it was last read.
This is a ghost error, and the same data changes, on the same record, at a different time won't always produce the error. It is also intermittent between different records, as in, sometimes, no matter what values I plug in, I haven't been able to repro the defect on all records.
It is happening across 70 of about 120 scripts, many over 1,000 lines long.
The only consistency I can find is that on all of the scripts that fail, they are all reading/writing floats to the DB. Fields that have a null value don't seem to crash, but if there is a value like '19' in the database (note the no decimal places) that seems to fail, whereas, '19.00' does not. Most floats are defined as 11,2.
The scripts are using ADODB and recordsets. Updates are done with the following pattern:
select * from table where ID =
udpdated recordID
update properties of the record from the form
call RecordSet.Update and RecordSet.Close
The error is generated from the RecordSet.Update command.
I have created a workaround, where rather than select/copy/update I generate an SQL statement that I execute. This works flawlessly (obviously, an UPDATE statement with a where clause is more focused and doesn't consider fields not updated), so I have a pretty good feeling that it is a rounding issue with the floats that is causing a mis-match with the re-retrieval of the record on the update call.
I really would prefer NOT re-writing 100's of these instances (a grep across the source directly finds 280+ update calls).
Can anyone confirm that the issue here is related to floats/rounding?
And if so, is there a global fix I can apply?
Thanks in advance,
-jc
Have a look at MySQL Forums :: ODBC :: Row cannot be located for updating.
They seem to have found some workaround and some explanations as well..
I ran into a similar issue with a VBA macro utilizing 4.1. When upgraded to 5 errors started popping up.
For me the issue was that values being returned to VBA from MySQL was in a unhandled (by VBA) decimal format.
A CAST on the numbers when querying helped to fix the issue.
So for your issue perhaps the ODBC/ASP combination is recording/reading values differently then what you might expect them to be.

MySQL Field Length Errors

Just moved a site over to a new server and we started getting some errors. Mainly that some data we were passing into a MySQL table was too long for the field. Having checked through the DB it seems the old server was truncating the data to fit the table, yet the new server throws a TEP STOP. Any ideas what the setting is to switch this back on, to temporarily get stuff working again?
Thanks!
MySQL used to be famous/infamous for silently "correcting" data it could not store directly (overlong strings, invalid dates) etc.. That has fortunately changed in recent versions.
You can now configure this behaviour using "Server SQL Modes". You probably want to switch off STRICT_ALL_TABLES or STRICT_TRANS_TABLES.
See MySQL's docs for details.