oracle reflection should raise a clear error message when table metadata is not accessible

Issue #363 resolved
Former user created an issue

Our client got the following traceback:

Traceback (most recent call last):
  File "<string>", line 8, in ?
  File "/home/ralf/bbot/py-bbfreeze/bbfreeze/initscripts/MyConsole.py",
line 85, in ?
  File "dumpdb.py", line 40, in ?
  File "dumpdb.py", line 29, in dump
  File "/usr/local/lib/python2.4/site-packages/sqlalchemy/schema.py",
line 138, in __call__
  File
"/usr/local/lib/python2.4/site-packages/sqlalchemy/engine/base.py", line
491, in reflecttable
  File
"/usr/local/lib/python2.4/site-packages/sqlalchemy/databases/oracle.py",
line 265, in reflecttable
TypeError: sequence item 0: expected string, NoneType found

Comments (28)

  1. Mike Bayer repo owner

    please attach a test case, which in this case would be the DDL for the oracle table you are trying to reflect, as well as sample code that illustrates the problem.

  2. Former user Account Deleted

    The problem is I currently don't have one. That's why I wanted to use reflection :)

    sample code:

    #! /usr/bin/env python
    
    import sys
    import csv
    import datetime
    
    import sqlalchemy
    import cx_Oracle
    import sqlalchemy.databases.oracle
    
    sa = sqlalchemy
    
    if len(sys.argv)!=4:
        print "Usage: dumpdb USER/PASSWORD@SID TABLENAME OUTPUT"
        sys.exit(10)
    
    credentials = sys.argv[1](1)
    tablename = sys.argv[2](2)
    outfile = sys.argv[3](3)
    
    def connect():
        return cx_Oracle.connect(credentials)
    
    engine =sqlalchemy.create_engine("oracle://", creator=connect)
    engine.connect()
    
    def dump():
        meta = sqlalchemy.BoundMetaData(engine)
        table = sqlalchemy.Table(tablename, meta, autoload=True) # introspect live db
    
        fd = open(outfile, 'wt') # CSV file to write to
        writer = csv.writer(fd, delimiter=',')
        writer.writerow(table.columns.keys()) # header
        for idx, r in enumerate(table.select().execute()): # SELECT * statement
            writer.writerow(r)
            if idx >= 10000:
                break
        fd.close()
    
    dump()
    

    I'm trying to get a DDL from our client. BTW, this is Oracle 9.

    Thanks for your fast response.

    PS: This is offtopic: What is the correct way to specify the connection string in create_engine? I always ended up with an error when I tried without the connect funtion.

  3. Mike Bayer repo owner

    your program seems to work to me:

    classic@localhost sqlalchemy]$ sqlplus
    
    SQL*Plus: Release 10.2.0.1.0 - Beta on Tue Nov 7 17:59:15 2006
    
    Copyright (c) 1982, 2005, Oracle.  All rights reserved.
    
    Enter user-name: scott
    Enter password:
    
    Connected to:
    Oracle Database 10g Express Edition Release 10.2.0.1.0 - Beta
    
    SQL> create table hello(id integer primary key, value varchar2(40), data varchar2(100));
    
    Table created.
    
    SQL> insert into hello values (1, 'some value', 'some data')
      2  ;
    
    1 row created.
    
    SQL> insert into hello values (2, 'some other value', 'some data')
      2  ;
    
    1 row created.
    
    SQL> commit;
    
    Commit complete.
    
    SQL> Disconnected from Oracle Database 10g Express Edition Release 10.2.0.1.0 - Beta
    [sqlalchemy](classic@localhost)$ python test.py scott/tiger@localhost hello somefile.txt
    [sqlalchemy](classic@localhost)$ cat somefile.txt 
    id,value,data
    1,some value,some data
    2,some other value,some data
    

    the correct way to connect with an SA string is:

    create_engine('oracle://username:password@hostname/dbname')
    

    the values are fed into cx_oracle's makedsn function via

     dsn = cx_oracle.makedsn(host,port,dbname)
     connection = cx_oracle.connect(user='scott', password='tiger', dsn=dsn)
    
  4. Former user Account Deleted

    Yes, the program is working for some tables. Here is the create-table-statement for the table that does not work. I'm going to test this myself with oracle 10 (today if time permits).

    CREATE TABLE "AXP"."AXP_BILD" ("ID" NUMBER(12) NOT NULL, 
        "POOL_ID" NUMBER(12) NOT NULL, "WEB_STATUS" CHAR(1), 
        "WEB_POOL_ID" NUMBER(12), "WEB_DATUM" NUMBER, "WEB_RANG" 
        NUMBER(12), "BEARBEITET" CHAR(1) NOT NULL, "IS_ONLINE" 
        CHAR(1) NOT NULL, "IMAGE_FORMAT" VARCHAR2(5), 
        "MD5SUM_ORIGINAL" CHAR(40), "DATEIDATUM" NUMBER, 
        "ERFASSUNGSDATUM" NUMBER, "ERFASSUNGSUSER" VARCHAR2(20), 
        "BIG_X" NUMBER, "BIG_Y" NUMBER, "RES_X" NUMBER, "RES_Y" 
        NUMBER, "MEDIUM_X" NUMBER, "MEDIUM_Y" NUMBER, "FILE_SIZE" 
        NUMBER, "FILE_SIZE_LAGERORT" NUMBER, "BILDDATUM_MITTE" NUMBER,
        "BILDDATUM_DIFF" NUMBER, "BILDDATUM_STATUS" NUMBER, 
        "VALIDDATUM_MITTE" NUMBER, "VALIDDATUM_DIFF" NUMBER, 
        "VALIDDATUM_STATUS" NUMBER, "CAPTION_DE" VARCHAR2(2500), 
        "ORT_DE" VARCHAR2(255), "CAPTION_US" VARCHAR2(2500), "ORT_US"
        VARCHAR2(255), "CAPTION_FR" VARCHAR2(2500), "ORT_FR" 
        VARCHAR2(255), "REFERENZ" VARCHAR2(40), "IPTC_ORIGINAL" 
        VARCHAR2(4000), "CREDIT_ORIGINAL" VARCHAR2(256), 
        "CREDIT_LINE" VARCHAR2(512), "DATEINAME_ORIGINAL" 
        VARCHAR2(255), "DATEINAME_LAGERORT" VARCHAR2(255), 
        "MD5SUM_LAGERORT" VARCHAR2(50), "DATEINAME_AXP" VARCHAR2(255),
        "DATEINAME_TXP" VARCHAR2(255), "LAGERORT" CHAR(1), "HEADLINE"
        VARCHAR2(512), "HINWEIS" VARCHAR2(255), "WEB_HINWEIS" 
        VARCHAR2(255), "NOTIZ" VARCHAR2(2500), "KEYWORDS" 
        VARCHAR2(4000), "RUECKSEITE_APPENDIX" VARCHAR2(50), 
        "HINWEIS_HISTORY" VARCHAR2(4000), "RESSORT_ORIGINAL" CHAR(4),
        "RESSORT" CHAR(4), "DELETED" CHAR(1), "DATE_DELETED" NUMBER, 
        "FILE_EXT" VARCHAR2(5), "FILE_EXTENSION" VARCHAR2(5), 
        CONSTRAINT "CHECK_WEBSTATUS" CHECK(not (deleted='J' 
        AND web_status != 'N')), 
        CONSTRAINT "FK_BILD_POOL" FOREIGN KEY("POOL_ID") 
        REFERENCES "AXP"."AXP_POOL"("ID"), 
        CONSTRAINT "FK_BILD_WEB_POOL" FOREIGN KEY("WEB_POOL_ID") 
        REFERENCES "AXP"."WEB_POOL"("ID"), 
        CONSTRAINT "PK_AXP_BILD" PRIMARY KEY("ID") 
        USING INDEX  
        TABLESPACE "INDX" 
        STORAGE ( INITIAL 512K NEXT 512K MINEXTENTS 1 MAXEXTENTS 
        2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1) 
        PCTFREE 10 INITRANS 2 MAXTRANS 255)  
        TABLESPACE "USERS" PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 
        255 
        STORAGE ( INITIAL 1024K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 
        2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1) 
        LOGGING
    
  5. Former user Account Deleted

    hmm...my tests did run with oracle 10. damn. However I did remove everything starting from the "USING INDEX" statement. Anything else I can do to help debug this?

  6. Mike Bayer repo owner

    one issue is I cant derive any meaning from your stack trace since the latest trunk has no code on line 265 of oracle.py. im guessing its acutally line 282 that the exception is arising from.

    insure youre on the latest trunk of SA. go into sqlalchemy/databases/oracle.py and uncomment two "print" statements on line 231 and 272 - these will print out the rows received when it queries the all_tab_columns and all_constraints tables. the error is due to something unexpected in a returned row, and it is most likely that there is either no "remote_table" or "remote_column" present in the row returned from the constraint query. we basically have to analzye what incompatibility exists within that query, i.e.

    SELECT
      ac.constraint_name,
      ac.constraint_type,
      LOWER(loc.column_name) AS local_column,
      LOWER(rem.table_name) AS remote_table,
      LOWER(rem.column_name) AS remote_column
    FROM all_constraints ac,
      all_cons_columns loc,
      all_cons_columns rem
    WHERE ac.table_name = :table_name
    AND ac.constraint_type IN ('R','P')
    AND ac.owner = :owner
    AND ac.owner = loc.owner
    AND ac.constraint_name = loc.constraint_name
    AND ac.r_owner = rem.owner(+)
    AND ac.r_constraint_name = rem.constraint_name(+)
    -- order multiple primary keys correctly
    ORDER BY ac.constraint_name, loc.position, rem.position
    
  7. Mike Bayer repo owner

    the query in question is:

    SELECT
      ac.constraint_name,
      ac.constraint_type,
      LOWER(loc.column_name) AS local_column,
      LOWER(rem.table_name) AS remote_table,
      LOWER(rem.column_name) AS remote_column
    FROM all_constraints ac,
      all_cons_columns loc,
      all_cons_columns rem
    WHERE ac.table_name = :table_name
    AND ac.constraint_type IN ('R','P')
    AND ac.owner = :owner
    AND ac.owner = loc.owner
    AND ac.constraint_name = loc.constraint_name
    AND ac.r_owner = rem.owner(+)
    AND ac.r_constraint_name = rem.constraint_name(+)
    -- order multiple primary keys correctly
    ORDER BY ac.constraint_name, loc.position, rem.position
    
  8. Former user Account Deleted

    I'm using version 0.2.8. line 265 reads:

    refspec = ".".join([remote_column](remote_table,))
    

    so remote_table is None here.

    I'll try with latest svn version...

  9. Former user Account Deleted

    okay, I've tried it with Oracle 9 and it also succeeds on my test system. I realized that reflection also happens on the tables referenced via foreign keys recursively, so there's no easy way to reproduce it without having the create table statements for those tables. I've asked our client to email them to us...

  10. Former user Account Deleted

    Okay, it turns out that this is a problem with missing rights. Using the following patch:

    Index: lib/sqlalchemy/databases/oracle.py
    ===================================================================
    --- lib/sqlalchemy/databases/oracle.py  (revision 2088)
    +++ lib/sqlalchemy/databases/oracle.py  (working copy)
    @@ -4,6 +4,7 @@
     # This module is part of SQLAlchemy and is released under
     # the MIT License: http://www.opensource.org/licenses/mit-license.php
    
    +patched = 1
    
     import sys, StringIO, string, re
    
    @@ -204,6 +205,8 @@
                 name = table.name.upper()
             else:
                 name = table.name
    +   print "analyzing", name
    +
             c = connection.execute ("select distinct OWNER from ALL_TAB_COLUMNS where TABLE_NAME = :table_name", {'table_name':name})
             rows = c.fetchall()
             if not rows :
    @@ -228,7 +231,7 @@
                     break
                 found_table = True
    
    -            #print "ROW:" , row
    +               print "ROW:" , row
                 (name, coltype, length, precision, scale, nullable, default) = (row[0](0), row[1](1), row[2](2), row[3](3), row[4](4), row[5](5)=='Y', row[6](6))
    
                 # INTEGER if the scale is 0 and precision is null
    @@ -269,7 +272,7 @@
                 row = c.fetchone()
                 if row is None:
                     break
    -            #print "ROW:" , row                
    +            print "ROW2:" , row                
                 (cons_name, cons_type, local_column, remote_table, remote_column) = row
                 if cons_type == 'P':
                     table.primary_key.add(table.c[local_column](local_column))
    

    I get the following output:

    analyzing AXP_BILD
    ROW: ('ID', 'NUMBER', 22, 12, 0, 'N', None)
    ROW: ('POOL_ID', 'NUMBER', 22, 12, 0, 'N', None)
    ROW: ('WEB_STATUS', 'CHAR', 1, None, None, 'Y', None)
    ROW: ('WEB_POOL_ID', 'NUMBER', 22, 12, 0, 'Y', None)
    ROW: ('WEB_DATUM', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('WEB_RANG', 'NUMBER', 22, 12, 0, 'Y', None)
    ROW: ('BEARBEITET', 'CHAR', 1, None, None, 'N', None)
    ROW: ('IS_ONLINE', 'CHAR', 1, None, None, 'N', None)
    ROW: ('IMAGE_FORMAT', 'VARCHAR2', 5, None, None, 'Y', None)
    ROW: ('MD5SUM_ORIGINAL', 'CHAR', 40, None, None, 'Y', None)
    ROW: ('DATEIDATUM', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('ERFASSUNGSDATUM', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('ERFASSUNGSUSER', 'VARCHAR2', 20, None, None, 'Y', None)
    ROW: ('BIG_X', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('BIG_Y', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('RES_X', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('RES_Y', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('MEDIUM_X', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('MEDIUM_Y', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('FILE_SIZE', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('FILE_SIZE_LAGERORT', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('BILDDATUM_MITTE', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('BILDDATUM_DIFF', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('BILDDATUM_STATUS', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('VALIDDATUM_MITTE', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('VALIDDATUM_DIFF', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('VALIDDATUM_STATUS', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('CAPTION_DE', 'VARCHAR2', 2500, None, None, 'Y', None)
    ROW: ('ORT_DE', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('CAPTION_US', 'VARCHAR2', 2500, None, None, 'Y', None)
    ROW: ('ORT_US', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('CAPTION_FR', 'VARCHAR2', 2500, None, None, 'Y', None)
    ROW: ('ORT_FR', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('REFERENZ', 'VARCHAR2', 40, None, None, 'Y', None)
    ROW: ('IPTC_ORIGINAL', 'VARCHAR2', 4000, None, None, 'Y', None)
    ROW: ('CREDIT_ORIGINAL', 'VARCHAR2', 256, None, None, 'Y', None)
    ROW: ('CREDIT_LINE', 'VARCHAR2', 512, None, None, 'Y', None)
    ROW: ('DATEINAME_ORIGINAL', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('DATEINAME_LAGERORT', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('MD5SUM_LAGERORT', 'VARCHAR2', 50, None, None, 'Y', None)
    ROW: ('DATEINAME_AXP', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('DATEINAME_TXP', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('LAGERORT', 'CHAR', 1, None, None, 'Y', None)
    ROW: ('HEADLINE', 'VARCHAR2', 512, None, None, 'Y', None)
    ROW: ('HINWEIS', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('WEB_HINWEIS', 'VARCHAR2', 255, None, None, 'Y', None)
    ROW: ('NOTIZ', 'VARCHAR2', 2500, None, None, 'Y', None)
    ROW: ('KEYWORDS', 'VARCHAR2', 4000, None, None, 'Y', None)
    ROW: ('RUECKSEITE_APPENDIX', 'VARCHAR2', 50, None, None, 'Y', None)
    ROW: ('HINWEIS_HISTORY', 'VARCHAR2', 4000, None, None, 'Y', None)
    ROW: ('RESSORT_ORIGINAL', 'CHAR', 4, None, None, 'Y', None)
    ROW: ('RESSORT', 'CHAR', 4, None, None, 'Y', None)
    ROW: ('DELETED', 'CHAR', 1, None, None, 'Y', None)
    ROW: ('DATE_DELETED', 'NUMBER', 22, None, None, 'Y', None)
    ROW: ('FILE_EXT', 'VARCHAR2', 5, None, None, 'Y', None)
    ROW: ('FILE_EXTENSION', 'VARCHAR2', 5, None, None, 'Y', None)
    ROW2: ('FK_BILD_POOL', 'R', 'pool_id', None, None)
    Traceback (most recent call last):
      File "./dumpdb.py", line 40, in <module>
        dump()
      File "./dumpdb.py", line 29, in dump
        table = sqlalchemy.Table(tablename, meta, autoload=True) # introspect live db
      File "/home/ralf/bbot/py-pix/sqlalchemy/schema.py", line 143, in __call__
        metadata.get_engine().reflecttable(table)
      File "/home/ralf/bbot/py-pix/sqlalchemy/engine/base.py", line 505, in reflecttable
        self.dialect.reflecttable(conn, table)
      File "/home/ralf/bbot/py-pix/sqlalchemy/databases/oracle.py", line 285, in reflecttable
        refspec = ".".join([remote_column](remote_table,))
    TypeError: sequence item 0: expected string, NoneType found
    

    I've just created another user and only gave him 'select' rights with 'grant select on AXP_BILD to user;' - but not on the AXP_POOL table (where the foreign key resides). You should be able to reproduce this with Oracle 10 (that's what I used in my last test).

  11. Former user Account Deleted

    I'm getting the same error with 0.3.1:

    .
    .
    .
    2006-11-28 11:17:44,680 INFO sqlalchemy.engine.base.Engine.0x..70 select distinct OWNER from ALL_TAB_COLUMNS where TABLE_NAME = :table_name
    2006-11-28 11:17:44,690 INFO sqlalchemy.engine.base.Engine.0x..70 {'table_name': 'PERSONNEL'}
    2006-11-28 11:17:44,910 INFO sqlalchemy.engine.base.Engine.0x..70 select COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE,
    DATA_DEFAULT from ALL_TAB_COLUMNS where TABLE_NAME = :table_name and OWNER = :owner
    2006-11-28 11:17:44,920 INFO sqlalchemy.engine.base.Engine.0x..70 {'owner': 'MARO', 'table_name': 'PERSONNEL'}
    2006-11-28 11:17:45,391 INFO sqlalchemy.engine.base.Engine.0x..70 SELECT
      ac.constraint_name,
      ac.constraint_type,
      LOWER(loc.column_name) AS local_column,
      LOWER(rem.table_name) AS remote_table,
      LOWER(rem.column_name) AS remote_column
    FROM all_constraints ac,
      all_cons_columns loc,
      all_cons_columns rem
    WHERE ac.table_name = :table_name
    AND ac.constraint_type IN ('R','P')
    AND ac.owner = :owner
    AND ac.owner = loc.owner
    AND ac.constraint_name = loc.constraint_name
    AND ac.r_owner = rem.owner(+)
    AND ac.r_constraint_name = rem.constraint_name(+)
    -- order multiple primary keys correctly
    ORDER BY ac.constraint_name, loc.position, rem.position
    2006-11-28 11:17:45,401 INFO sqlalchemy.engine.base.Engine.0x..70 {'owner': 'MARO', 'table_name': 'PERSONNEL'}
    Traceback (most recent call last):
      File "C:\Documents and Settings\Daystev\Desktop\temp\dlc_query.py", line 17, in ?
        pvt = Table('protocol_variant_type',metadata,autoload=True)
      File "build\bdist.win32\egg\sqlalchemy\schema.py", line 143, in __call__
      File "build\bdist.win32\egg\sqlalchemy\engine\base.py", line 505, in reflecttable
      File "build\bdist.win32\egg\sqlalchemy\databases\oracle.py", line 283, in reflecttable
      File "build\bdist.win32\egg\sqlalchemy\schema.py", line 141, in __call__
      File "build\bdist.win32\egg\sqlalchemy\engine\base.py", line 315, in reflecttable
      File "build\bdist.win32\egg\sqlalchemy\engine\base.py", line 505, in reflecttable
      File "build\bdist.win32\egg\sqlalchemy\databases\oracle.py", line 282, in reflecttable
    TypeError: sequence item 0: expected string, NoneType found
    >>>
    

    I can do the SQL querys above manually and post the output if it would help.

  12. Former user Account Deleted

    (original author: shday) Ok, it seems that our database has entries in all_cons_columns that refer to non-existent columns! I don't have enough rights to do anything about that on my own, so as a work-around, I changed line 283 in oracle.py from:

    to:
    
    {{{elif cons_type == 'R' and remote_column:}}}
    
    I was using revision 2115. Here is the error message I was getting before the fix:
    
    {{{
    Traceback (most recent call last):
      File "C:\Documents and Settings\Daystev\Desktop\temp\dlc_query.py", line 17, in -toplevel-
        pvt = Table('protocol_variant_type',metadata,autoload=True)
      File "C:\Python24\lib\site-packages\sqlalchemy\schema.py", line 143, in __call__
        metadata.get_engine().reflecttable(table)
      File "C:\Python24\lib\site-packages\sqlalchemy\engine\base.py", line 505, in reflecttable
        self.dialect.reflecttable(conn, table)
      File "C:\Python24\lib\site-packages\sqlalchemy\databases\oracle.py", line 290, in reflecttable
        schema.Table(remote_table, table.metadata, autoload=True, autoload_with=connection, owner=remote_owner)
      File "C:\Python24\lib\site-packages\sqlalchemy\schema.py", line 141, in __call__
        autoload_with.reflecttable(table)
      File "C:\Python24\lib\site-packages\sqlalchemy\engine\base.py", line 315, in reflecttable
        return self.__engine.reflecttable(table, connection=self, **kwargs)
      File "C:\Python24\lib\site-packages\sqlalchemy\engine\base.py", line 505, in reflecttable
        self.dialect.reflecttable(conn, table)
      File "C:\Python24\lib\site-packages\sqlalchemy\databases\oracle.py", line 289, in reflecttable
        refspec = ".".join([remote_column](remote_table,))
    TypeError: sequence item 0: expected string, NoneType found
    
  13. Former user Account Deleted

    (original author: shday) Actually, according to one of our DBA's, the column could be masked.

  14. Former user Account Deleted

    an error message (other than TypeError) which shows the cause of this error, would be enough for me. the current behaviour is rather confusing.

  15. Former user Account Deleted

    (original author: shday) The problem is that, as the reflection is recursive, it may try to reflect tables that you aren't interested in. It this case, it doesn't seem appropriate to raise an error. Maybe add an option to ignore "unreflectable" tables.

  16. Mike Bayer repo owner

    just a note, not raising an error definitely wouldnt work, since the table that was "successfully" reflected right before it is now in an invalid state; i.e. it contains a ForeignKey referencing an unloaded (or worse, partially-loaded) table.

    it really makes no sense to reflect a schema element to which the database user does not have complete access to the full metadata for all of its dependencies.

  17. Mike Bayer repo owner

    ive put in an untested fix for this in changeset:2335. basically looking for "None" where youre getting it and raising an error message. I dont know how to reproduce the error condition here and also dont quite understand it since it seems the same table is used twice in the query, and in one case you get a value back and the other you get back "None"....does the view only return certain rows to which you have access ?

    anyway, reopen ticket if the error message doesnt solve this issue.

  18. Former user Account Deleted
    • removed status
    • changed status to open

    May I suggest just issueing a warning instead of raising. The problem seems to arise if you have columns referencing tables in a schema you dont have any rights to alter. In my case, i referenced a restricted table(ro-access), which again referenced a "forbidden" table (no access). One cant sensibly alter that foreign key at all, it must be altered somewhere else, e.g. in a trigger. This column can be treated as if it didnt exist.

    A warning should tell the user that reflection is only partial, as partial as the user permissions. If the db setup is intentionally done that way, it should be ok. if it is in error, worse problems than partial reflections are heading your way...

    Thank you for your work on this nice project, will try to do some testing on oracle once i find the time.

  19. Mike Bayer repo owner

    a warning.....using logger.warn() ? sure. we dont have any warn()s as of yet so the initial audience for warnings may be small (or nonexistent).

  20. Former user Account Deleted
    • removed status
    • changed status to open

    (original author: shday) I tried bc1cc72d89c8eb0dd76f123d77599940c3060e2d and I still get the same minimal error message:

    ... File "build\bdist.win32\egg\sqlalchemy\databases\oracle.py", line 376, in refl ecttable TypeError: sequence item 0: expected string, NoneType found

    I like the idea of not raising an error at all here (just a warning and ignore the column entirely).

  21. Former user Account Deleted

    (original author: shday) Reflection works fine now. When I figure out how logging works I'll confirm the warning message also. :)

  22. Log in to comment