-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Load iidbcapabilities and use to build column definition involving unique constraints #58
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code as it stands will work for most use cases, but will break under some circumstances.
Can we get the new dictionary attached to the connection some how? For example, is IngresExecutionContext() something that's per connection that we could store those details in?
Anything in the other adapters we can review for ideas?
lib/sqlalchemy_ingres/base.py
Outdated
@@ -81,6 +81,8 @@ | |||
'TIMESTAMP WITH LOCAL TIME ZONE': types.TIMESTAMP, | |||
'VARCHAR': types.VARCHAR} | |||
|
|||
iidbcapabilities = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will make this essentially global to all connections. I.e.:
- application with single connection will be fine
- application with multiple connections to same database (or type) will be fine
- application with more than one connection to different types will end up with last connection meta data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created SQLAlchemy discussion 11574 seeking help with associating a dictionary of catalog options with the related connection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latest commit fixes a scope/concurrency problem that was present in the initial commit so that the catalog settings are now loaded and distinct for each individual IngresDialect class instance.
I tested the dialect changes with a program that creates multiple simultaneous instances of the SQLAlchemy engine object with corresponding unique database connections to differing backends and there was no interference with the retrieved iidbcapabilities
values across the multiple instances of the IngresDialect class.
Attached is simple SQLAlchemy ORM program createTableHouse.py.txt that was also used to test the updated fix. The test code defines column address_id
without a NOT NULL
constraint (sa.Column('address_id', sa.Integer)
) or alternatively with a NOT NULL
constraint (sa.Column('address_id', sa.Integer, nullable=False)
) and includes the column as part of a UNIQUE
constraint. If the backend DBMS_TYPE
is INGRES
, the Ingres dialect adds the required NOT NULL
clause to the column definition. Otherwise, the column definition does not include the NOT NULL
clause.
The differences can be seen in the following excerpts showing the generated SQL and column definitions when the program is run against Ingres versus Vector.
Ingres 11.2 database
CREATE TABLE house (
house_id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
address_id INTEGER NOT NULL, PRIMARY KEY (house_id),
UNIQUE (house_id, address_id))
Key
Column Name Type Length Nulls Defaults Seq
house_id integer 4 no identity
address_id integer 4 no no
Vector 6.3 database
CREATE TABLE house (
house_id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
address_id INTEGER, PRIMARY KEY (house_id),
UNIQUE (house_id, address_id))
Key
Column Name Type Length Nulls Defaults Seq Minmax
house_id integer 4 no identity Y
address_id integer 4 yes null Y
I re-ran the dialect compliance suite with and without the latest changes to the Ingres dialect and the results were the same as in the opening comment of this PR. With the latest changes against Ingres 11.2, there were 7 more tests that passed than failed as compared to a run using the original (pre-PR) Ingres dialect code as a baseline..
Overview
Method added for loading a dictionary of database values retrieved from the
iidbcapabilities
catalog upon initialization of theIngresDialect
class. The dictionary can subsequently be used byIngresDialect
class methods to query backend database settings.Knowledge of the type of backend DBMS is then used in method
get_column_specification
to correctly handle whether aNOT NULL
clause should be appended for columns inCREATE TABLE
statements involvingUNIQUE
constraints when the backend is of typeINGRES
.See documentation link for information about the difference between Ingres and X100 tables for columns that are unique constraints.
The values in dictionary
iidbcapabilities
can be queried directly using known keys, although possibly creating internal getter methods might be worth considering.Justification for changes
Allowing the dialect to know the backend database configuration is important in some cases when processing SQL statements.
Examples:
Ingres
orX100
.SQLAlchemy standalone program used for testing changes
Testing with the SQLAlchemy Dialect Compliance Suite
Test execution command:
pytest --db %dsn% --maxfail=1000 .\test\dialect\test_suite.py
Results
Using the SQLAlchemy Dialect Compliance Suite (
lib/sqlalchemy/testing/suite
)(a) Of the 785 errors that occur when running the suite against Vector, 771 involve invalid SQL operations with X100 tables. These issues will be dealt with in part via internal issue II-13753.
Environments
Windows 10 Client
Backends
Ingres on Windows
Vector on Ubuntu