Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

Changeset 146

Show
Ignore:
Timestamp:
08/23/07 21:15:00
Author:
fumanchu
Message:

Much better multischema support:

  1. Databases now have name, qname attributes.
  2. Moved Schema.create/drop_database to Database.create/drop(), and added new Schema.create/drop() methods.
  3. Schema.name is now optional (may be None) for providers that are not multischema
  4. Schema discovery methods now only return tables, etc from their own schema.
  5. Moved 'name' arg from zoo_fixture.run into the opts dict as a keyword.

This will affect Dejavu--people using multiple PostgreSQL schemas, for example, will need either multiple SM's or a new SM which is multiple-schema-aware.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/geniusql/objects.py

    r145 r146  
    483483    """ 
    484484     
     485    name = None 
     486    qname = None 
     487     
    485488    tableclass = Table 
    486489    indexsetclass = IndexSet 
    487490     
    488     def __new__(cls, db, name): 
     491    def __new__(cls, db, name=None): 
    489492        return dict.__new__(cls) 
    490493     
    491     def __init__(self, db, name): 
     494    def __init__(self, db, name=None): 
    492495        dict.__init__(self) 
    493496         
    494497        self.db = db 
    495         self.name = self.db.sql_name(name) 
    496         self.qname = self.db.quote(self.name) 
     498        # Although __init__ should set this instance's "name" attribute, 
     499        # allow subclasses to pull that information from other sources 
     500        # if necessary. 
     501        if name is not None: 
     502            self.name = self.db.sql_name(name) 
     503            self.qname = self.db.quote(name) 
    497504        self._discover_lock = threading.Lock() 
    498         self.discover_dbinfo() 
    499505     
    500506    def __repr__(self): 
     
    503509     
    504510    #                              Discovery                              # 
    505      
    506     def _get_dbinfo(self, conn=None): 
    507         return {} 
    508      
    509     def discover_dbinfo(self, conn=None): 
    510         """Set attributes on self with actual DB metadata, where possible.""" 
    511         for k, v in self._get_dbinfo(conn).iteritems(): 
    512             setattr(self, k, v) 
    513511     
    514512    def _get_tables(self, conn=None): 
     
    730728        dict.__setitem__(self, newkey, newtable) 
    731729     
    732     def create_database(self): 
    733         self.db.execute_ddl("CREATE DATABASE %s;" % self.qname) 
     730    def create(self): 
     731        """Create this schema in the database.""" 
    734732        self.clear() 
    735733     
    736     def drop_database(self): 
     734    def drop(self): 
     735        """Drop this schema from the database.""" 
    737736        # Must shut down all connections to avoid 
    738737        # "being accessed by other users" error. 
    739738        self.db.connections.shutdown() 
    740         self.db.execute_ddl("DROP DATABASE %s;" % self.qname) 
    741         self.clear() 
     739         
     740        seen = {} 
     741        for tkey, table in self.items(): 
     742            # We might have multiple keys pointing at the same table. 
     743            if table.name not in seen: 
     744                del self[tkey] 
     745                seen[table.name] = None 
    742746 
    743747 
     
    745749     
    746750    __metaclass__ = geniusql._AttributeDocstrings 
     751     
     752    name = None 
     753    qname = None 
    747754     
    748755    typeset = dbtypes.DatabaseTypeSet() 
     
    757764     
    758765    multischema = True 
    759     multischema__doc = """If True, instances of this Database class may 
    760     spawn multiple Schema instances. This is False, for example, when 
    761     the underlying Database engine binds connections to individual files. 
     766    multischema__doc = """If True, instances of this Database class 
     767    may spawn multiple Schema instances. This is False, for example, 
     768    when the underlying engine binds connections to individual files. 
    762769    In most applications (that use a single schema) this presents no 
    763770    problems; applications that need to handle more than one schema 
     
    773780     
    774781    def __init__(self, **kwargs): 
     782        # Although __init__ should set this instance's "name" attribute, 
     783        # allow subclasses to pull that information from other kwargs 
     784        # or other sources if necessary. 
     785        self.name = kwargs.get('name', None) 
     786        if self.name: 
     787            self.qname = self.quote(self.name) 
     788         
    775789        self.connections = self.connectionmanager(self) 
    776790         
     
    787801            childobj = getattr(self, namespace) 
    788802            setattr(childobj, name, v) 
     803         
     804        self.discover_dbinfo() 
    789805     
    790806    def version(self): 
     
    795811        pass 
    796812     
    797     def schema(self, name): 
     813    def schema(self, name=None): 
    798814        return self.schemaclass(self, name) 
     815     
     816    def create(self): 
     817        """Create this database.""" 
     818        self.execute_ddl("CREATE DATABASE %s;" % self.qname) 
     819     
     820    def drop(self): 
     821        """Drop this database.""" 
     822        # Must shut down all connections to avoid 
     823        # "being accessed by other users" error. 
     824        self.connections.shutdown() 
     825        self.execute_ddl("DROP DATABASE %s;" % self.qname) 
     826     
     827    #                              Discovery                              # 
     828     
     829    def _get_dbinfo(self, conn=None): 
     830        return {} 
     831     
     832    def discover_dbinfo(self, conn=None): 
     833        """Set attributes on self with actual DB metadata, where possible.""" 
     834        for k, v in self._get_dbinfo(conn).iteritems(): 
     835            setattr(self, k, v) 
     836     
     837    def _get_schemas(self, conn=None): 
     838        """Return a list of schema names.""" 
     839        raise NotImplementedError 
     840     
     841    def discover_schemas(self, conn=None): 
     842        """Return a list of Schema objects.""" 
     843        if self.multischema: 
     844            return [self.schema(name) for name in self._get_schemas(conn)] 
     845        else: 
     846            return self.schema() 
    799847     
    800848    #                               Naming                               # 
     
    810858     
    811859    def sql_name(self, key): 
    812         """Return the native SQL version of key.""" 
     860        """Return the native SQL version of key (unquoted).""" 
    813861        if self.sql_name_caseless: 
    814862            key = key.lower() 
  • trunk/geniusql/providers/ado.py

    r145 r146  
    381381                for row in data 
    382382                # Ignore linked and system tables 
    383                 if row[3] == "TABLE"
     383                if row[3] == "TABLE" and row[1] == self.name
    384384     
    385385    def _get_table(self, tablename, conn=None): 
     
    391391        for row in data: 
    392392            name = str(row[2]) 
    393             if name == tablename
     393            if name == tablename and row[1] == self.name
    394394                return self.tableclass(name, self.db.quote(name), 
    395395                                       self, created=True) 
     
    411411            # I tried passing criteria to OpenSchema, but passing None is 
    412412            # not the same as passing pythoncom.Empty (which errors). 
    413             if table.name and row[2] != table.name: 
    414                 continue 
    415             i = geniusql.Index(row[5], self.db.quote(row[5]), 
    416                                row[2], row[17], row[7]) 
    417             indices.append(i) 
     413            if (row[2] == table.name and row[1] == self.name): 
     414                i = geniusql.Index(row[5], self.db.quote(row[5]), 
     415                                   row[2], row[17], row[7]) 
     416                indices.append(i) 
    418417        return indices 
    419418     
  • trunk/geniusql/providers/firebird.py

    r145 r146  
    732732    tableclass = FirebirdTable 
    733733     
    734     def __init__(self, db, name): 
    735         dict.__init__(self) 
    736          
    737         self.db = db 
    738          
    739         # Here's where we differ from the superclass. 
    740         # The Firebird "database name" is a filename, not an identifier, 
    741         # so we don't set self.name = sql_name(name). 
    742         self.name = name 
    743         # We also have to set our parent's "name" so conns can use it. 
    744         self.db.name = name 
    745          
    746         self.qname = self.db.quote(self.name) 
    747         self._discover_lock = threading.Lock() 
    748         self.discover_dbinfo() 
    749      
    750734    def _get_tables(self, conn=None): 
    751735        data, _ = self.db.fetch( 
     
    876860            self.db.execute_ddl("DROP GENERATOR %s;" % column.sequence_name) 
    877861            column.sequence_name = None 
    878      
    879     def create_database(self): 
    880         # Firebird DB 'names' are actually filesystem paths. 
    881         sql = ("CREATE DATABASE %s USER '%s' PASSWORD '%s';" 
    882                % (self.qname, self.db.user, self.db.password)) 
    883          
    884         # Use the kinterbasdb helper methods for cleaner create and drop. 
    885         # We also use dialect 3 *always* to help with quoted identifiers. 
    886         # Note that DATE has no time in dialect 3 (use TIMESTAMP instead). 
    887         conn = kinterbasdb.create_database(sql, 3) 
    888         conn.close() 
    889          
    890         self.clear() 
    891      
    892     def drop_database(self): 
    893         # Must shut down all connections to avoid 
    894         # "being accessed by other users" error. 
    895         self.db.connections.shutdown() 
    896          
    897         conn = self.db.connections._get_conn() 
    898         conn.drop_database() 
    899         # For some reason, the conn is already closed... 
    900 ##        conn.close() 
    901         self.clear() 
    902862 
    903863 
     
    1011971        return ("KInterbasDB Version: %r\nServer Version: %r" 
    1012972                % (kinterbasdb.__version__, svcCon.getServerVersion())) 
    1013  
    1014  
     973     
     974    def create(self): 
     975        # Firebird DB 'names' are actually filesystem paths. 
     976        sql = ("CREATE DATABASE %s USER '%s' PASSWORD '%s';" 
     977               % (self.qname, self.user, self.password)) 
     978         
     979        # Use the kinterbasdb helper methods for cleaner create and drop. 
     980        # We also use dialect 3 *always* to help with quoted identifiers. 
     981        # Note that DATE has no time in dialect 3 (use TIMESTAMP instead). 
     982        conn = kinterbasdb.create_database(sql, 3) 
     983        conn.close() 
     984     
     985    def drop(self): 
     986        # Must shut down all connections to avoid 
     987        # "being accessed by other users" error. 
     988        self.connections.shutdown() 
     989         
     990        conn = self.connections._get_conn() 
     991        conn.drop_database() 
     992        # For some reason, the conn is already closed... 
     993##        conn.close() 
     994 
     995 
  • trunk/geniusql/providers/msaccess.py

    r145 r146  
    468468        data, _ = self.db.fetch(ado.adSchemaIndexes, conn=conn, schema=True) 
    469469        pknames = [row[17] for row in data 
    470                    if (table.name == row[2]) and row[6]] 
     470                   if (row[2] == table.name and 
     471                       row[1] == self.name) and row[6]] 
    471472         
    472473        # columns will be 
     
    623624         
    624625        return '%s %s' % (column.qname, ddl) 
    625      
    626     def create_database(self): 
    627         # By not providing an Engine Type, it defaults to 5 = Access 2000. 
    628         cat = win32com.client.Dispatch(r'ADOX.Catalog') 
    629         cat.Create(self.db.connections.Connect) 
    630         cat.ActiveConnection.Close() 
    631         self.clear() 
    632      
    633     def drop_database(self): 
    634         # Must shut down our only connection to avoid 
    635         # "Permission denied" error on os.remove call below. 
    636         self.db.connections.shutdown() 
    637          
    638         import os 
    639         # This should accept relative or absolute paths 
    640         if os.path.exists(self.name): 
    641             os.remove(self.name) 
    642          
    643         self.clear() 
    644626 
    645627 
     
    686668        del conn 
    687669        return "ADO Version: %s" % v 
    688  
     670     
     671    def create(self): 
     672        # By not providing an Engine Type, it defaults to 5 = Access 2000. 
     673        cat = win32com.client.Dispatch(r'ADOX.Catalog') 
     674        cat.Create(self.connections.Connect) 
     675        cat.ActiveConnection.Close() 
     676     
     677    def drop(self): 
     678        # Must shut down our only connection to avoid 
     679        # "Permission denied" error on os.remove call below. 
     680        self.connections.shutdown() 
     681         
     682        import os 
     683        # This should accept relative or absolute paths 
     684        if os.path.exists(self.name): 
     685            os.remove(self.name) 
     686 
  • trunk/geniusql/providers/mysql.py

    r145 r146  
    477477     
    478478    def _get_tables(self, conn=None): 
    479         data, _ = self.db.fetch("SHOW TABLES FROM %s" % self.qname, conn=conn) 
     479        data, _ = self.db.fetch("SHOW TABLES FROM %s" % self.db.qname, conn=conn) 
    480480        return [self.tableclass(row[0], self.db.quote(row[0]), 
    481481                                self, created=True) 
     
    484484    def _get_table(self, tablename, conn=None): 
    485485        data, _ = self.db.fetch("SHOW TABLES FROM %s LIKE '%s'" 
    486                              % (self.qname, tablename), conn=conn) 
     486                             % (self.db.qname, tablename), conn=conn) 
    487487        for row in data: 
    488488            name = row[0] 
     
    496496        # See http://dev.mysql.com/doc/refman/4.1/en/describe.html 
    497497        data, _ = self.db.fetch("SHOW COLUMNS FROM %s.%s" % 
    498                                 (self.qname, table.qname), conn=conn) 
     498                                (self.db.qname, table.qname), conn=conn) 
    499499        cols = [] 
    500500        for row in data: 
     
    533533            # Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment 
    534534            data, _ = self.db.fetch("SHOW INDEX FROM %s.%s" 
    535                                     % (self.qname, table.qname), conn=conn) 
     535                                    % (self.db.qname, table.qname), conn=conn) 
    536536        except _mysql.ProgrammingError, x: 
    537537            if x.args[0] != 1146: 
     
    543543                indices.append(i) 
    544544        return indices 
    545      
    546     def create_database(self): 
    547         # _mysql has create_db and drop_db commands, but they're deprecated. 
    548         encoding = self.db.encoding 
    549         if encoding: 
    550             encoding = " CHARACTER SET %s" % encoding 
    551         sql = 'CREATE DATABASE %s%s;' % (self.qname, encoding) 
    552         conn = self.db.connections._get_conn(master=True) 
    553         self.db.execute_ddl(sql, conn) 
    554         conn.close() 
    555         self.clear() 
    556      
    557     def drop_database(self): 
    558         conn = self.db.connections._get_conn(master=True) 
    559         self.db.execute_ddl('DROP DATABASE %s;' % self.qname, conn) 
    560         conn.close() 
    561         self.clear() 
    562545 
    563546 
     
    577560     
    578561    def __init__(self, **kwargs): 
     562        kwargs['name'] = kwargs['db'] 
    579563        geniusql.Database.__init__(self, **kwargs) 
    580564         
     
    652636            return False 
    653637        return exc.args[0] == 1205 
    654  
     638     
     639    def create(self): 
     640        # _mysql has create_db and drop_db commands, but they're deprecated. 
     641        encoding = self.encoding 
     642        if encoding: 
     643            encoding = " CHARACTER SET %s" % encoding 
     644        sql = 'CREATE DATABASE %s%s;' % (self.qname, encoding) 
     645        conn = self.connections._get_conn(master=True) 
     646        self.execute_ddl(sql, conn) 
     647        conn.close() 
     648     
     649    def drop(self): 
     650        conn = self.connections._get_conn(master=True) 
     651        self.execute_ddl('DROP DATABASE %s;' % self.qname, conn) 
     652        conn.close() 
     653 
  • trunk/geniusql/providers/postgres.py

    r145 r146  
    560560    discover_pg_tables = False 
    561561     
     562    def __init__(self, db, name=None): 
     563        if name is None: 
     564            name = 'public' 
     565        geniusql.Schema.__init__(self, db, name) 
     566     
    562567    def _get_tables(self, conn=None): 
     568        data, _ = self.db.fetch("SELECT oid FROM pg_class WHERE " 
     569                                "relname = 'pg_class' and relkind='r'", conn=conn) 
     570        pgclass_OID = data[0][0] 
     571         
     572        data, _ = self.db.fetch( 
     573            "SELECT c.relname, d.description FROM " 
     574            "(pg_class c LEFT JOIN pg_namespace n ON c.relnamespace = n.oid) " 
     575            "LEFT JOIN (SELECT description, objoid FROM pg_shdescription " 
     576            "WHERE classoid = %s) AS d ON c.oid = d.objoid WHERE n.nspname " 
     577            "= '%s' and c.relkind = 'r';" % (pgclass_OID, self.name), 
     578            conn=conn) 
     579        return [self.tableclass(name, self.db.quote(name), self, 
     580                                created=True, description=description) 
     581                for name, description in data 
     582                if self.discover_pg_tables or not name.startswith("pg_")] 
     583     
     584    def _get_table(self, tablename, conn=None): 
     585        if (not self.discover_pg_tables) and tablename.startswith("pg_"): 
     586            raise errors.MappingError(tablename) 
     587         
    563588        data, _ = self.db.fetch("SELECT oid FROM pg_class WHERE " 
    564589                                "relname = 'pg_class'", conn=conn) 
    565590        pgclass_OID = data[0][0] 
    566591         
    567         data, _ = self.db.fetch( 
    568             "SELECT c.relname, d.description, n.nspname FROM " 
    569             "(pg_class c LEFT JOIN pg_namespace n ON c.relnamespace = n.oid) " 
    570             "LEFT JOIN (SELECT description, objoid FROM pg_shdescription " 
    571             "WHERE classoid = %s) AS d ON c.oid = d.objoid WHERE n.nspname " 
    572             "!= 'information_schema' and n.nspname NOT LIKE 'pg\\_%%';" % 
    573             pgclass_OID, conn=conn) 
    574         tables = [] 
    575         for name, description, namespace in data: 
    576             if (not self.discover_pg_tables) and name.startswith("pg_"): 
    577                 continue 
    578             t = self.tableclass(name, self.db.quote(name), 
    579                                 self, created=True, description=description) 
    580             t.namespace = namespace 
    581             tables.append(t) 
    582         return tables 
    583      
    584     def _get_table(self, tablename, conn=None): 
    585         if (not self.discover_pg_tables) and name.startswith("pg_"): 
    586             raise errors.MappingError(tablename) 
    587          
    588         data, _ = self.db.fetch("SELECT oid FROM pg_class WHERE " 
    589                                 "relname = 'pg_class'", conn=conn) 
    590         pgclass_OID = data[0][0] 
    591          
    592         data, _ = self.db.fetch("SELECT c.oid, c.relname, n.nspname FROM " 
     592        data, _ = self.db.fetch("SELECT c.oid, c.relname FROM " 
    593593                    "pg_class c LEFT JOIN pg_namespace n ON c.relnamespace " 
    594                     "= n.oid WHERE c.relname = '%s'" % tablename, conn=conn) 
    595         for table_OID, name, namespace in data: 
     594                    "= n.oid WHERE c.relname = '%s' AND c.relkind = 'r' " 
     595                    "AND n.nspname = '%s'" % (tablename, self.name), 
     596                    conn=conn) 
     597        for table_OID, name in data: 
    596598            if name == tablename: 
    597599                t = self.tableclass(name, self.db.quote(name), 
    598600                                    self, created=True) 
    599                 t.namespace = namespace 
    600601                 
    601602                # Get the description of the table, if any 
     
    614615        data, _ = self.db.fetch("SELECT c.oid FROM pg_class c LEFT JOIN " 
    615616                    "pg_namespace n ON c.relnamespace = n.oid WHERE " 
    616                     "c.relname = '%s' AND n.nspname = '%s'" % 
    617                     (table.name, table.namespace), conn=conn) 
     617                    "c.relname = '%s' AND c.relkind = 'r' " 
     618                    "AND n.nspname = '%s'" % (table.name, self.name), 
     619                    conn=conn) 
    618620        table_OID = data[0][0] 
    619621         
     
    636638        typeset = self.db.typeset 
    637639##        print 
    638 ##        print table.name, table.namespace, ">>", 
     640##        print self.name, table.name, ">>", 
    639641        for row in data: 
    640642            name = row[0] 
     
    689691                    c.sequence_name = seq_name.search(default).group(1) 
    690692                    c.initial = self.db.fetch("SELECT min_value FROM %s.%s" % 
    691                                               (table.namespace, c.sequence_name), 
     693                                              (self.name, c.sequence_name), 
    692694                                              conn=conn)[0][0][0] 
    693695                    c.default = None 
     
    715717        data, _ = self.db.fetch("SELECT c.oid FROM pg_class c LEFT JOIN " 
    716718                    "pg_namespace n ON c.relnamespace = n.oid WHERE " 
    717                     "c.relname = '%s' AND n.nspname = '%s'" % 
    718                     (table.name, table.namespace), conn=conn) 
    719         if not data: 
    720             return [] 
    721          
     719                    "c.relname = '%s' AND c.relkind = 'r' " 
     720                    "AND n.nspname = '%s'" % (table.name, self.name), 
     721                    conn=conn) 
    722722        table_OID = data[0][0] 
     723         
    723724        indices = [] 
    724725        data, _ = self.db.fetch( 
     
    783784            column.sequence_name = None 
    784785     
    785     def create_database(self): 
    786         c = self.db.connections._get_conn(master=True) 
    787         encoding = self.db.encoding 
    788         if encoding: 
    789             encoding = " WITH ENCODING '%s'" % encoding 
    790         self.db.execute_ddl("CREATE DATABASE %s%s" % (self.qname, encoding), c) 
    791         self.db.connections._del_conn(c) 
    792         del c 
     786    def create(self): 
     787        if self.name != "public": 
     788            c = self.db.connections._get_conn(master=True) 
     789            self.db.execute_ddl("CREATE SCHEMA %s" % self.qname, c) 
     790            self.db.connections._del_conn(c) 
     791            del c 
    793792        self.clear() 
    794793     
    795     def drop_database(self): 
    796         c = self.db.connections._get_conn(master=True) 
    797         self.db.execute_ddl("DROP DATABASE %s;" % self.qname, c) 
    798         self.db.connections._del_conn(c) 
    799         del c 
     794    def drop(self): 
     795        if self.name != "public": 
     796            c = self.db.connections._get_conn(master=True) 
     797            self.db.execute_ddl("DROP SCHEMA %s;" % self.qname, c) 
     798            self.db.connections._del_conn(c) 
     799            del c 
    800800        self.clear() 
    801801 
     
    822822            name = name.lower() 
    823823        return name 
    824  
     824     
     825    def schema(self, name="public"): 
     826        return self.schemaclass(self, name) 
     827     
     828    def create(self): 
     829        c = self.connections._get_conn(master=True) 
     830        encoding = self.encoding 
     831        if encoding: 
     832            encoding = " WITH ENCODING '%s'" % encoding 
     833        self.execute_ddl("CREATE DATABASE %s%s" % (self.qname, encoding), c) 
     834        self.connections._del_conn(c) 
     835     
     836    def drop(self): 
     837        c = self.connections._get_conn(master=True) 
     838        self.execute_ddl("DROP DATABASE %s;" % self.qname, c) 
     839        self.connections._del_conn(c) 
     840     
     841    def _get_schemas(self, conn=None): 
     842        """Return a list of schema names.""" 
     843        data, _ = self.fetch("SELECT nspname FROM pg_namespace;", conn=conn) 
     844        return [name for name, in data if name != 'information_schema' 
     845                and not name.startswith('pg_')] 
     846 
  • trunk/geniusql/providers/pypgsql.py

    r145 r146  
    3636 
    3737 
    38 class PyPgSchema(postgres.PgSchema): 
     38class PyPgDatabase(postgres.PgDatabase): 
     39     
     40    connectionmanager = PyPgConnectionManager 
     41     
     42    def __init__(self, **opts): 
     43        postgres.PgDatabase.__init__(self, **opts) 
     44        connstr = opts.get('connections.Connect', None) 
     45        if connstr: 
     46            for atom in connstr.split(" "): 
     47                k, v = atom.split("=", 1) 
     48                if k == 'dbname': 
     49                    self.name = v 
     50                    self.qname = self.quote(v) 
    3951     
    4052    def _get_dbinfo(self, conn=None): 
    4153        dbinfo = {} 
    4254        try: 
    43             data, _ = self.db.fetch("SELECT pg_encoding_to_char(encoding) " 
    44                                     "FROM pg_database;", conn=conn) 
     55            data, _ = self.fetch("SELECT pg_encoding_to_char(encoding) " 
     56                                 "FROM pg_database;", conn=conn) 
    4557            dbinfo['encoding'] = data[0][0] 
    4658        except libpq.DatabaseError, x: 
     
    4860                raise 
    4961        return dbinfo 
    50  
    51  
    52 class PyPgDatabase(postgres.PgDatabase): 
    53      
    54     connectionmanager = PyPgConnectionManager 
    55     schemaclass = PyPgSchema 
    5662     
    5763    def fetch(self, sql, conn=None): 
  • trunk/geniusql/providers/sqlite.py

    r145 r146  
    653653    tableclass = SQLiteTable 
    654654     
    655     def __init__(self, db, name): 
    656         if name != ':memory:': 
    657             if not os.path.isabs(name): 
    658                 name = os.path.join(os.getcwd(), name) 
    659         geniusql.Schema.__init__(self, db, name) 
    660         self.db.name = self.name 
    661      
    662     def get_pragma(self, name, conn=None): 
    663         data, _ = self.db.fetch("PRAGMA %s;" % name, conn=conn) 
    664         return data[0][0] 
    665 ##     
    666 ##    def _get_dbinfo(self, conn=None): 
    667 ##        dbinfo = {} 
    668 ##        for pragma in ('encoding', 'case_sensitive_like', 'locking_mode', 
    669 ##                       'page_size', 'read_uncommitted'): 
    670 ##            dbinfo[pragma] = self.get_pragma(pragma, conn) 
    671 ##        return dbinfo 
    672      
    673655    def _get_tables(self, conn=None): 
    674656        data, _ = self.db.fetch("SELECT name FROM sqlite_master " 
     
    834816            raise NotImplementedError 
    835817     
    836     def create_database(self): 
    837         self.db.connections.get() 
    838      
    839     def drop_database(self): 
    840         self.db.connections.shutdown() 
    841         if self.name != ":memory:": 
    842             # This should accept relative or absolute paths 
    843             os.remove(self.name) 
    844         self.clear() 
     818    def drop(self): 
     819        """Drop this schema from the database.""" 
     820        if self.db.name == ':memory:': 
     821            # Not much we can do, here. If we try to drop a table, we end 
     822            # up stuck in "database schema has changed"-land forever. 
     823            # Just assume for now we're going to drop the whole database. 
     824            self.db.drop() 
     825            self.db.create() 
     826        else: 
     827            # Must shut down all connections to avoid 
     828            # "being accessed by other users" error. 
     829            self.db.connections.shutdown() 
     830             
     831            seen = {} 
     832            for tkey, table in self.items(): 
     833                # We might have multiple keys pointing at the same table. 
     834                if table.name not in seen: 
     835                    del self[tkey] 
     836                    seen[table.name] = None 
    845837 
    846838 
     
    865857    def __init__(self, **kwargs): 
    866858        kwargs['mode'] = int(kwargs.pop('mode', '0755'), 8) 
     859         
     860        if kwargs['name'] != ':memory:': 
     861            if not os.path.isabs(kwargs['name']): 
     862                kwargs['name'] = os.path.join(os.getcwd(), kwargs['name']) 
     863         
    867864        geniusql.Database.__init__(self, **kwargs) 
     865     
     866##    def _get_dbinfo(self, conn=None): 
     867##        dbinfo = {} 
     868##        for pragma in ('encoding', 'case_sensitive_like', 'locking_mode', 
     869##                       'page_size', 'read_uncommitted'): 
     870##            dbinfo[pragma] = self.get_pragma(pragma, conn) 
     871##        return dbinfo 
     872     
     873    def get_pragma(self, name, conn=None): 
     874        data, _ = self.fetch("PRAGMA %s;" % name, conn=conn) 
     875        return data[0][0] 
     876     
     877    def create(self): 
     878        self.connections._set_factory() 
     879        self.connections.get() 
     880     
     881    def drop(self): 
     882        self.connections.shutdown() 
     883        if self.name != ":memory:": 
     884            # This should accept relative or absolute paths 
     885            os.remove(self.name) 
    868886     
    869887    def quote(self, name): 
     
    946964        return "SQLite Version: %s" % _version 
    947965     
    948     def schema(self, name): 
     966    def schema(self, name=None): 
    949967        s = self.schemaclass(self, name) 
    950         self.name = name 
    951         self.connections._set_factory() 
    952968        return s 
    953969 
  • trunk/geniusql/providers/sqlserver.py

    r145 r146  
    364364        # 132: USERDEFINED, 133: DBDATE, 134: DBTIME, 
    365365    } 
     366     
     367    def __init__(self, db, name=None): 
     368        if name is None: 
     369            name = 'dbo' 
     370        geniusql.Schema.__init__(self, db, name) 
    366371     
    367372    def _get_columns(self, table, conn=None): 
     
    442447        return cols 
    443448     
    444     def create_database(self): 
    445         conn = self.db.connections._get_conn(master=True) 
    446         self.db.execute_ddl("CREATE DATABASE %s;" % self.qname, conn) 
    447         conn.Close() 
     449    def create(self): 
    448450        self.clear() 
    449451     
    450     def drop_database(self): 
    451         conn = self.db.connections._get_conn(master=True) 
    452         self.db.execute_ddl("DROP DATABASE %s;" % self.qname, conn) 
    453         conn.Close() 
     452    def drop(self): 
    454453        self.clear() 
    455454     
     
    499498        return "ADO Version: %s\n%s" % (adov, sqlv) 
    500499     
     500    def create(self): 
     501        conn = self.connections._get_conn(master=True) 
     502        self.execute_ddl("CREATE DATABASE %s;" % self.qname, conn) 
     503        conn.Close() 
     504     
     505    def drop(self): 
     506        conn = self.connections._get_conn(master=True) 
     507        self.execute_ddl("DROP DATABASE %s;" % self.qname, conn) 
     508        conn.Close() 
     509     
    501510    def is_timeout_error(self, exc): 
    502511        """If the given exception instance is a lock timeout, return True. 
  • trunk/geniusql/test/benchmark.py

    r145 r146  
    266266    try: 
    267267        db = geniusql.db(provider, **opts) 
     268        print db.version() 
     269        db.create() 
    268270        schema = db.schema(name) 
    269         print db.version() 
    270         schema.create_database() 
     271        schema.create() 
    271272         
    272273        db.connections.implicit_trans = True 
  • trunk/geniusql/test/test_firebird.py

    r145 r146  
    3333        reload(zoo_fixture) 
    3434        try: 
    35             zoo_fixture.run(DB_class, opts['name'], opts
     35            zoo_fixture.run(DB_class, opts
    3636        except kinterbasdb.OperationalError, e: 
    3737            if e.args[0] == -902 and 'Failed to establish a connection' in e.args[1]: 
  • trunk/geniusql/test/test_msaccess.py

    r145 r146  
    1919        opts = {'connections.Connect': 
    2020                    "PROVIDER=MICROSOFT.JET.OLEDB.4.0;DATA SOURCE=zoo.mdb;", 
     21                'name': 'zoo.mdb', 
    2122                } 
    2223         
     
    4445            print "Standard MSAccess test." 
    4546##            zoo_fixture.ZooTests.test_currency = test_currency_dbtypes 
    46             zoo_fixture.run(DB_class, "zoo.mdb", opts) 
     47            zoo_fixture.run(DB_class, opts) 
    4748             
    4849            if currency: 
     
    5657                # plugin the adapter for testing CURRENCY columns 
    5758                opts['typeadapter'] = CurrencyAdapter() 
    58                 zoo_fixture.run(DB_class, "zoo.mdb", opts) 
     59                zoo_fixture.run(DB_class, opts) 
    5960                del opts['typeadapter'] 
    6061                 
     
    6869                print "MSAccess test - CURRENCY returned as Decimal." 
    6970                zoo_fixture.ZooTests.test_currency = test_currency_dbtypes 
    70                 zoo_fixture.run(DB_class, "zoo.mdb", opts) 
     71                zoo_fixture.run(DB_class, opts) 
    7172 
    7273 
  • trunk/geniusql/test/test_mysql.py

    r145 r146  
    2424        opts['encoding'] = "latin1" 
    2525        reload(zoo_fixture) 
    26         zoo_fixture.run(DB_class, 'geniusql_test', opts) 
     26        zoo_fixture.run(DB_class, opts) 
    2727         
    2828        print 
     
    3030        opts['encoding'] = "utf8" 
    3131        reload(zoo_fixture) 
    32         zoo_fixture.run(DB_class, 'geniusql_test', opts) 
     32        zoo_fixture.run(DB_class, opts) 
    3333 
    3434if __name__ == "__main__": 
  • trunk/geniusql/test/test_pypgsql.py

    r145 r146  
    1717                ("host=localhost dbname=geniusql_test user=%s password=%s" 
    1818                 % (user, passwd)), 
     19            'name': 'geniusql_test', 
    1920            } 
    2021    DB_class = "postgres" 
     
    2930        opts['encoding'] = "SQL_ASCII" 
    3031        reload(zoo_fixture) 
    31         zoo_fixture.run(DB_class, 'geniusql_test', opts) 
     32        zoo_fixture.run(DB_class, opts) 
    3233         
    3334        print 
     
    3536        opts['encoding'] = "UNICODE" 
    3637        reload(zoo_fixture) 
    37         zoo_fixture.run(DB_class, 'geniusql_test', opts) 
     38        zoo_fixture.run(DB_class, opts) 
    3839 
    3940if __name__ == "__main__": 
  • trunk/geniusql/test/test_sqlite.py

    r145 r146  
    2222if _sqlite: 
    2323    DB_class = "sqlite" 
    24     opts = {} 
    2524     
    2625    def run(memonly=False): 
     
    3029        print "Testing SQLite ':memory:' database..." 
    3130        reload(zoo_fixture) 
    32         zoo_fixture.run(DB_class, ':memory:', opts
     31        zoo_fixture.run(DB_class, {'name': ':memory:'}
    3332         
    3433        if not memonly: 
     
    3736            print "Testing SQLite file database..." 
    3837            reload(zoo_fixture) 
    39             zoo_fixture.run(DB_class, dbpath, opts
     38            zoo_fixture.run(DB_class, {'name': dbpath}
    4039 
    4140if __name__ == "__main__": 
  • trunk/geniusql/test/test_sqlserver.py

    r145 r146  
    2929            # Isolate schema changes from one test to the next. 
    3030            reload(zoo_fixture) 
    31             zoo_fixture.run(DB_class, "geniusql_test", opts) 
     31            zoo_fixture.run(DB_class, opts) 
    3232 
    3333if __name__ == "__main__": 
  • trunk/geniusql/test/zoo_fixture.py

    r145 r146  
    13491349    f.close() 
    13501350 
    1351 def setup(provider, name, opts): 
     1351def setup(provider, opts): 
    13521352    """Set up storage for Zoo classes.""" 
    13531353    global db, schema 
    13541354    db = geniusql.db(provider, **opts) 
    1355     schema = db.schema(name) 
    13561355    db.log = _geniusqllog 
    13571356    print db.version() 
    1358     schema.create_database() 
     1357    db.create() 
     1358     
     1359    schema = db.schema() 
     1360    schema.create() 
    13591361 
    13601362def teardown(): 
    13611363    """Tear down storage for Zoo classes.""" 
    13621364    try: 
    1363         schema.drop_database() 
     1365        schema.drop() 
     1366    except (AttributeError, NotImplementedError): 
     1367        pass 
     1368    try: 
     1369        db.drop() 
    13641370    except (AttributeError, NotImplementedError): 
    13651371        pass 
    13661372    db.connections.shutdown() 
    13671373 
    1368 def run(DB_class, name, opts): 
     1374def run(DB_class, opts): 
    13691375    """Run the zoo fixture.""" 
    13701376    skiptests = [x[7:] for x in sys.argv if x.startswith("--skip_")] 
     
    13721378    try: 
    13731379        try: 
    1374             setup(DB_class, name, opts) 
     1380            setup(DB_class, opts) 
    13751381            loader = unittest.TestLoader().loadTestsFromTestCase 
    13761382             
     
    13891395            # Each thread opens a new SQLite :memory: database, 
    13901396            # so the concept of "isolation" is pretty meaningless. 
    1391             if name != ':memory:' and 'isolation' not in skiptests: 
     1397            if opts.get('name') != ':memory:' and 'isolation' not in skiptests: 
    13921398                tools.TestRunner.run(loader(IsolationTests)) 
    13931399