Mercurial > sqlpython
changeset 387:e3dd9e4467d1
first-pass metadata collection working
author | catherine@DellZilla |
---|---|
date | Tue, 06 Oct 2009 15:09:46 -0400 |
parents | 846a59c10cf4 (diff) 0f019dfb795f (current diff) |
children | 841573c48676 |
files | sqlpython/mysqlpy.py sqlpython/schemagroup.py sqlpython/sqlpyPlus.py sqlpython/sqlpython.py |
diffstat | 6 files changed, 110 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Thu Aug 13 14:33:55 2009 -0400 +++ b/.hgtags Tue Oct 06 15:09:46 2009 -0400 @@ -15,3 +15,4 @@ 09bb5789e72de737998e31027873ae1422dd37a0 nogerald branch; 1.6.5 f65f74c948bca2d22a6aab5964a42076ea8e70f2 1.6.6 477f0bf652b2f754dd72671e04460f7f2743eae4 1.6.7 +9fc0da48b2c41576c7ab40a3260988ce1d7919da 1.6.8
--- a/setup.py Thu Aug 13 14:33:55 2009 -0400 +++ b/setup.py Tue Oct 06 15:09:46 2009 -0400 @@ -9,7 +9,7 @@ Operating System :: OS Independent""".splitlines() setup(name="sqlpython", - version="1.6.7", + version="1.6.8", description="Command-line interface to Oracle", long_description="Customizable alternative to Oracle's SQL*PLUS command-line interface", author="Luca Canali",
--- a/sqlpython/mysqlpy.py Thu Aug 13 14:33:55 2009 -0400 +++ b/sqlpython/mysqlpy.py Tue Oct 06 15:09:46 2009 -0400 @@ -1,5 +1,5 @@ #!/usr/bin/python -# MySqlPy V1.6.7 +# MySqlPy V1.6.8 # Author: Luca.Canali@cern.ch # # @@ -14,9 +14,9 @@ class mysqlpy(sqlpyPlus): ''' -MySqlPy V1.6.7 - 'sqlplus in python' +MySqlPy V1.6.8 - 'sqlplus in python' Author: Luca.Canali@cern.ch -Rev: 1.6.7, 07-Jul-09 +Rev: 1.6.8, 02-Sep-09 Companion of SqlPython, a python module that reproduces Oracle's command line within python and sqlpyPlus. Major contributions by Catherine Devlin, http://catherinedevlin.blogspot.com @@ -211,4 +211,7 @@ sys.argv = [sys.argv[0]] # the --test argument upsets unittest.main() unittest.main() else: + #import cProfile, pstats + #cProfile.run('run()', 'stats.txt') run() +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sqlpython/schemagroup.py Tue Oct 06 15:09:46 2009 -0400 @@ -0,0 +1,61 @@ +import gerald, re, datetime, threading + +def get_schemagroup(rdbms, connstr, connection, user): + gerald_connstring = connstr.split('/?mode=')[0].replace('//','/') + if rdbms == 'oracle': + childtype = OracleSchemaGroup + grp = childtype(gerald_connstring, connection, user) + return grp + +def gerald_connection_string(sqlalchemy_connection_string): + return sqlalchemy_connection_string.split('/?mode=')[0].replace('//','/') + +class RefreshThread(threading.Thread): + def __init__(self, schemagroup, owner): + threading.Thread.__init__(self) + self.schemagroup = schemagroup + self.owner = owner + self.schema = self.schemagroup.schemas.get(self.owner) + def run(self): + if (not self.schema) or (self.schema.is_stale()): + self.schema = self.schemagroup.childtype(self.owner, self.schemagroup) + else: + self.schema.refreshed = self.schema.time() + self.schemagroup.schemas[self.owner] = self.schema + +class RefreshGroupThread(threading.Thread): + def __init__(self, schemas): + threading.Thread.__init__(self) + self.schemas = schemas + self.daemon = True + def run(self): + self.schemas.refresh() + +class SchemaDict(dict): + schema_types = {'oracle': gerald.OracleSchema} + def __init__(self, dct, rdbms, user, connection, connection_string): + dict.__init__(self, dct) + self.child_type = self.schema_types[rdbms] + self.user = user + self.connection = connection + self.gerald_connection_string = gerald_connection_string(connection_string) + self.refresh_thread = RefreshGroupThread(self) + self.complete = False + # do we need a second thread for a second run? + def refresh(self): + curs = self.connection.cursor() + curs.execute('SELECT sysdate FROM dual') + current_database_time = curs.fetchone()[0] + curs.execute('''SELECT owner, MAX(last_ddl_time) + FROM all_objects + GROUP BY owner + -- sort :username to top + ORDER BY REPLACE(owner, :username, 'A'), owner''', + {'username': self.user.upper()}) + for (owner, last_ddl_time) in curs.fetchall(): + if (owner not in self) or (self[owner].refreshed < last_ddl_time): + self[owner] = self.child_type(owner, self.gerald_connection_string) + self[owner].refreshed = current_database_time + # what if a user's last object is deleted? + self.complete = True + \ No newline at end of file
--- a/sqlpython/sqlpyPlus.py Thu Aug 13 14:33:55 2009 -0400 +++ b/sqlpython/sqlpyPlus.py Tue Oct 06 15:09:46 2009 -0400 @@ -1429,7 +1429,7 @@ 'WINDOW', 'WINDOW GROUP', 'XML SCHEMA') - + @options([make_option('-l', '--long', action='store_true', help='long descriptions'), make_option('-a', '--all', action='store_true', help="all schemas' objects"), make_option('-t', '--timesort', action='store_true', help="Sort by last_ddl_time"), @@ -1439,32 +1439,37 @@ Lists objects as through they were in an {object_type}/{object_name} UNIX directory structure. `*` and `%` may be used as wildcards. ''' - clauses = {'owner': '', 'moreColumns': '', - 'source': metaqueries['ls'][self.rdbms], - 'where': self.ls_where_clause(arg, opts)} - if opts.long: - clauses['moreColumns'] = ', status, last_ddl_time' - if opts.all: - clauses['owner'] = "owner || '.' ||" - - # 'Normal' sort order is DATE DESC (maybe), object type ASC, object name ASC - sortdirection = (hasattr(opts, 'reverse') and opts.reverse and 'DESC') or 'ASC' - orderby = 'object_type %s, object_name %s' % (sortdirection, sortdirection) - if hasattr(opts, 'timesort') and opts.timesort: - if hasattr(opts, 'reverse') and opts.reverse: - direction = 'DESC' + seek = '^%s$' % (arg.replace('*', '.*').replace('?','.'). \ + replace('%', '.*')) + schemas = self.connections[self.connection_number]['schemas'] + result = [] + username = self.connections[self.connection_number]['user'].upper() + for (schema_name, schema) in schemas.items(): + if opts.all or schema_name == username: + for (name, obj) in schema.schema.items(): + if hasattr(obj, 'type'): + dbtype = obj.type + else: + dbtype = str(type(obj)).rstrip("'>").split('.')[-1] + if opts.all: + name = '%s.%s' % (schema_name, name) + descriptor = '%s/%s' % (dbtype, name) + descriptor = descriptor.upper() + if (not arg) or \ + re.search(seek, descriptor, re.IGNORECASE) or \ + re.search(seek, name, re.IGNORECASE) or \ + re.search(seek, dbtype, re.IGNORECASE): + result.append(descriptor) + # if opts.long: status, last_ddl_time + if not schemas.complete: + if opts.all: + qualifier = 'may be ' else: - direction = 'ASC' - orderby = 'last_ddl_time %s, %s' % (direction, orderby) - clauses['orderby'] = orderby - statement = ''' - SELECT object_type || '/' || %(owner)s object_name AS name %(moreColumns)s - FROM (%(source)s) source - %(where)s - ORDER BY %(orderby)s;''' % clauses - self.do_select(self.parsed(statement, - terminator=arg.parsed.terminator or ';', - suffix=arg.parsed.suffix)) + qualifier = '' + self.perror('Metadata discovery still in progress - results %sincomplete' % qualifier) + if result: + result.sort(reverse=bool(opts.reverse)) + self.poutput('\n'.join(result)) @options([make_option('-i', '--ignore-case', dest='ignorecase', action='store_true', help='Case-insensitive search')]) def do_grep(self, arg, opts):
--- a/sqlpython/sqlpython.py Thu Aug 13 14:33:55 2009 -0400 +++ b/sqlpython/sqlpython.py Tue Oct 06 15:09:46 2009 -0400 @@ -1,7 +1,7 @@ # # SqlPython V1.6.7 # Author: Luca.Canali@cern.ch, Apr 2006 -# Rev 7-Jul-09 +# Rev 2-Sep-09 # A python module to reproduce Oracle's command line 'sqlplus-like' within python # Intended to allow easy customizations and extentions @@ -9,8 +9,8 @@ # See also http://twiki.cern.ch/twiki/bin/view/PSSGroup/SqlPython import cmd2,getpass,binascii,cx_Oracle,re,os,platform -import sqlalchemy, pyparsing -__version__ = '1.6.7' +import sqlalchemy, pyparsing, schemagroup +__version__ = '1.6.8' class Parser(object): comment_def = "--" + ~ ('-' + pyparsing.CaselessKeyword('begin')) + pyparsing.ZeroOrMore(pyparsing.CharsNotIn("\n")) @@ -98,9 +98,14 @@ def url_connect(self, arg): eng = sqlalchemy.create_engine(arg) self.conn = eng.connect().connection + user = eng.url.username or '' + rdbms = eng.url.drivername conn = {'conn': self.conn, 'prompt': self.prompt, 'dbname': eng.url.database, - 'rdbms': eng.url.drivername, 'user': eng.url.username or '', - 'eng': eng, 'connect_string': arg} + 'rdbms': rdbms, 'user': user, 'eng': eng, + 'schemas': schemagroup.get_schemagroup(rdbms, arg, + self.conn, user)} + s = conn['schemas'] + s.refresh() return conn def ora_connect(self, arg): modeval = 0