Hi Michael,

thank you for all that input. I will give the test suite a try and also 
look into all your suggestions. I'll try to provide a minimal test case for 
the auto_increment behavior. This will take some time...

Jan

Am Freitag, 25. Januar 2013 16:22:23 UTC+1 schrieb Michael Bayer:
>
>
> On Jan 25, 2013, at 2:25 AM, jank wrote:
>
> Hello,
> I have implemented a dialect for a new database (EXASol). 
>
>
> that's great.   I'd like to point you to a new system we have for testing 
> and deploying external dialects, where your dialect can be packaged with a 
> standard layout and make use of a series of "compliance" suites within 
> SQLAlchemy.   Within this test system, you can customize fully those 
> capabilities which your dialect supports.   
>
> If you check out SQLAlchemy-Access and SQLAlchemy-Akiban, you can see the 
> standard forms:
>
> https://bitbucket.org/zzzeek/sqlalchemy-access
> https://github.com/zzzeek/sqlalchemy_akiban
>
> the key files within these packages regarding using the SQLAlchemy 
> compliance suite are:
>
> /run_tests.py - test runner, is a front-end to Nose
> /setup.cfg - test runner configuration
> /test/requirements.py - a custom SuiteRequirements class which provides 
> rules for those features and behaviors supported by the database
> /test/test_suite.py - pulls in the sqlalchemy.testing.suite package which 
> causes the "suite" tests to be present for the Nose runner.
>
> the "compliance suite" is a work in progress and doesn't cover everything 
> yet.   Key areas that it does cover are the whole INSERT/lastrowid 
> mechanics you're concerned with here, database reflection, and basic SQL 
> types.
>
>
> I have not done tests using the ORM layer of SA so far as I am primarily 
> interested in the Core layer.
> So far things worked out pretty well DDL and DML support are basically 
> running.
> The EXASol DB does not offer Sequences but autoincrement columns that are 
> very similar to postgres SERIAL types.
>
> Example DDL statement:
>
> CREATE TABLE test_exadialect.test (
>         id INTEGER IDENTITY 10 NOT NULL, 
>         name VARCHAR(40) NOT NULL, 
>         age INTEGER, 
>         PRIMARY KEY (id)
> )
>
> Identity is the keyword to add autoincrement behavior to an Integer-like 
> column. 10 is the initial value of the autoincrement.
>
> This DDL statement is generated based on this table metadata:
>
> Table('test', self.metadata,
>       Column('id', Integer, Sequence('test.id.seq', start=10, 
> optional=True), primary_key=True),
>       Column('name', String(40), nullable=False),
>       Column('age', Integer)
> )
>
> Looking at the postgres dialect implementation, I came to the conclusion 
> that using Sequences is the only way to get the desired behavior.
>
>
> The best dialect for you to look at here would be the MSSQL dialect, 
> lib/sqlalchemy/dialects/mssql/base.py and perhaps the pyodbc implementation 
> of it, lib/sqlalchemy/dialects/mssql/pyodbc.py.    MSSQL's INSERT system 
> resembles this the most, where we use the Sequence to allow configurability 
> of the IDENTITY column, and a "post-fetch" at the cursor level is used to 
> get at the last inserted identity.    The post-fetch is performed right on 
> the same cursor that the INSERT occurred on and bypasses the usual 
> SQLAlchemy mechanics of executing a statement, so to that degree the Python 
> overhead of this "post fetch" is negligible.   
>
>
> I have also implemented the get_lastrowid() method of the ExecutionContext 
> class. This all works as expected albeit at the costs of an additional 
> roundtrip for each single insert as the DB in question does not support 
> RETURNING.
>
> First question: is this the intended way to implement autoincrement 
> behavior in the absence of support for explicit sequence objects in the DB?
>
>
> sounds like you're on the right track, the usage of Sequence is optional 
> overall but if you want configurability of the "start" and all that then 
> yes.
>
> No to the problem that I could not solve so far. I want to make the costs 
> of fetching the last autoincrement id upon insert/update optional. 
>
>
> the last row id mechanics only come into play when an Insert() construct 
> is used.    This construct supports a flag "inline=True" which is intended 
> to indicate an INSERT where you don't need any of the "default" values 
> back.   If you execute a table.insert(inline=True)... the entire 
> "lastrowid" mechanics are bypassed, you can see this in 
> sqlalchemy/engine/default.py line 663 post_insert().     This functionality 
> of this flag is invoked automatically whenever the Insert() construct is 
> used in an "executemany" context as well.
>
>
>
>
>
> In our use case we are fine with the DB determining the next id value 
> without knowing about the value upon insert. I tried to fiddle around with 
> various configuration switches. Namely:
>
>    - postfetch_lastrowid
>    
> postfetch_lastrowid refers to whether or not the method of acquiring the 
> last inserted id, when it is desired, is done via post-fetch, or whether 
> the last inserted id is provided by some other method, which could be one 
> of: pre-execute+embed in the INSERT, embed in the INSERT+use RETURNING, use 
> the dbapi lastrowid() method.   When this flag is False, in the absense of 
> lastrowid() or RETURNING the system behaves as though a "pre-execute" 
> insert is present, but since that's not implemented either you get a NULL.
>
> The flag does not indicate that the dialect flat out doesn't support 
> returning an inserted PK value - the ability to return the last inserted PK 
> is a requirement for a SQLAlchemy dialect as this is one of the most 
> fundamental features the Core provides.
>
>
>
>    - autoincrement
>
>
> I tried setting for the id column autoincrement=False would prevent the 
> SQLCompiler from forcing it into the INSERT statement:
>
> Column('id', Integer, Sequence('test.id.seq', start=10, optional=True), 
> primary_key=True, 
> autoincrement=False),
>
> Running and debugging my test case, the column object had the value True 
> for the autoincrement property. I assume that the combination of Sequence 
> and primary_key somehow overrides the value to True but I am lost in the SA 
> code base.
>
>
> autoincrement this is a Column level flag that indicates whether or not a 
> column should be treated as autoincrement during the DDL process, assuming 
> the column is integer based and doesn't have a foreign key constraint.  It 
> also has some significance during the "postfetch" process, but doesn't at 
> the moment indicate that the postfetch process should be skipped 
> unconditionally - however, you can certainly, if you wanted, check this 
> flag within your own postfetch() routine and then not perform the lastrowid 
> action.
>
> As for the autoincrement flag being flipped to True, I can't reproduce 
> your behavior:
>
> from sqlalchemy import Column, Integer, Table, MetaData, Sequence
>
> t = Table('t', MetaData(),
>     Column('x', Integer, Sequence('y'), primary_key=True, 
> autoincrement=False))
>
> assert t.c.x.autoincrement is False
> assert t._autoincrement_column is None
>
> if you can send me a code example illustrating the autoincrement flag 
> being silently flipped to True that would be helpful.   
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to