On Jan 28, 2013, at 4:54 PM, jank wrote:

> On implementing a new dialect I am running into lots of issues. All caught by 
> test cases part of the standard test suite - so thanks for this!
> 
> I have an issue with a reserved word being used as column name: data.
> 
> The test case HasTableTest.test_has_table creates a table using:
> 
> Table('test_table', metadata,
>                 Column('id', Integer, primary_key=True),
>                 Column('data', String(50))
>             )
> 
> A few things are suspicious. Running the resulting create statement on the DB 
> console I get an error. However, I do not see any error on test execution, 
> but only the message that the table does not exist:
> 
> Error emptying table test_table: ProgrammingError("(ProgrammingError) 
> ('42000', '[42000] [EXASOL][EXASolution driver]object TEST_TABLE not found 
> [line 1, column 13] (-1) (SQLExecDirectW)')",)
> ERROR
> 
> I would have expected an error on CREATE TABLE. 

running the tests with --log-debug=sqlalchemy.engine will help to see all the 
SQL being emitted.   The "not found" seems like your has_table() function might 
not be working.

> I also added 'data' to the list of reserved_words

OK, make sure you use the latest default as of yesterday as I just had to 
change that test so that it quotes the "data" term, apparently it is reserved 
on DB2 as well.


> and added a _bindparam_requires_quotes method similar to the Oracle dialect.

that's a very unusual setting and unless exaDB is extremely similar to Oracle 
it's unlikely you need it.   what this means is that if you have a statement 
like this:

INSERT INTO sometable (somecol) VALUES (:data)

above, we've named a bound parameter with the name "data".   Because it is 
syntaxed like a bound parameter, it's very unusual that a database client API 
would choke on the fact that "data" is a reserved word.  But Oracle OCI does 
choke on this, so it wants this:

INSERT INTO sometable (somecol) VALUES (":data")

the logic to get the quotes in there on a bound parameter, while still keeping 
the name of the parameter as "data" without the quotes, is very awkward but 
that's what _bindparam_requires_quotes does.  This is not usually what's needed 
for quoting of reserved words.

Usually, quoting of reserved words means that a statement like this:

INSERT into sometable (data) VALUES (:param)

should instead be rendered like this, because "data" is reserved:

INSERT into sometable ("data") VALUES (:param)

All dialects will do this automatically assuming "data" is in the reserved 
words registered with the IdentifierPreparer.



> But I am not sure if, how and when this set is being used. When running the 
> test suite I do not see any prints I have added to check if my code is being 
> executed (but adding syntax errors cause the expected error). So far I have 
> not understood the test suite magic. 
> 
> Any help on understanding the test suite magic or how reserved words are 
> being used is greatly appreciated.

my guess is based on the error message:

> object TEST_TABLE not found

the fact that the table name is being reported as UPPERCASE suggests that this 
database may store and report on case insensitive names as UPPERCASE.   In 
SQLAlchemy, an all lower case name is considered to be case insensitive.   So 
when performing table inspection, an all lower case name on the SQLAlchemy side 
must be "normalized" and "denormalized" as it is passed to the database for 
schema inspection functions.   The Oracle dialect includes this behavior, as 
does the Firebird dialect as well as the DB2 dialect I've been working on.  To 
enable it looks like this (you can copy this from oracle/base.py):


class MyDialect(default.DefaultDialect):
   # ...

    requires_name_normalize = True

    def normalize_name(self, name):
        if name is None:
            return None
        # Py2K
        if isinstance(name, str):
            name = name.decode(self.encoding)
        # end Py2K
        if name.upper() == name and \
              not self.identifier_preparer._requires_quotes(name.lower()):
            return name.lower()
        else:
            return name

    def denormalize_name(self, name):
        if name is None:
            return None
        elif name.lower() == name and not 
self.identifier_preparer._requires_quotes(name.lower()):
            name = name.upper()
        # Py2K
        if not self.supports_unicode_binds:
            name = name.encode(self.encoding)
        else:
            name = unicode(name)
        # end Py2K
        return name

you'll then want to call upon denormalize_name() as you query the databases 
information schema for tables, schemas and columns - you can see this in 
Oracle's has_table() method.

this is again just a hunch based on that UPPERCASE name in your error message.  
 Running with --log-debug=sqlalchemy.engine will show all queries being emitted 
as well as results.   I'd recommend running tests individually when that 
setting is enabled.



-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
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