# HG changeset patch # User catherine.devlin@gmail.com # Date 1285182993 14400 # Node ID 0b584c8238b4c2f954476710b4761c8a93332e1a # Parent 2b3974b0a5847ee34f2bb842f7531126a1a86101 ls working on Oracle diff -r 2b3974b0a584 -r 0b584c8238b4 sqlpython/connections.py --- a/sqlpython/connections.py Tue Sep 21 15:26:24 2010 -0400 +++ b/sqlpython/connections.py Wed Sep 22 15:16:33 2010 -0400 @@ -173,38 +173,35 @@ pyparsing.Optional(sqlname("owner") + ".") + pyparsing.Optional(sqlname("name")) + pyparsing.stringEnd )) + identifier_regex = re.compile( + r'((?PDATABASE LINK|DIRECTORY|FUNCTION|INDEX|JOB|MATERIALIZED VIEW|PACKAGE|PROCEDURE|SEQUENCE|SYNONYM|TABLE|TRIGGER|TYPE|VIEW|BASE TABLE)($|[\\/.\s])+)?(?P.*)', + re.IGNORECASE) def parse_identifier(self, identifier): """ >>> opts = OptionTestDummy(postgres=True, password='password') >>> db = DatabaseInstance('thedatabase theuser', opts) >>> result = db.parse_identifier('scott.pets') - >>> (result.owner, result.type, result.name) - ('scott', '%', 'pets') + >>> (result['object_type'], result['name1'], result['name2']) + (None, 'scott', 'pets') >>> result = db.parse_identifier('pets') - >>> (result.owner, result.type, result.name) - ('%', '%', 'pets') + >>> (result['object_type'], result['name1'], result['name2']) + (None, 'pets', '') >>> result = db.parse_identifier('pe*') - >>> (result.owner, result.type, result.name) + >>> (result['object_type'], result['name1'], result['name2']) ('%', '%', 'pe%') >>> result = db.parse_identifier('scott/table/pets') - >>> (result.owner, result.type, result.name) + >>> (result['object_type'], result['name1'], result['name2']) ('scott', 'table', 'pets') >>> result = db.parse_identifier('table/scott.pets') - >>> (result.owner, result.type, result.name) + >>> (result['object_type'], result['name1'], result['name2']) ('scott', 'table', 'pets') >>> result = db.parse_identifier('') - >>> (result.owner, result.type, result.name) + >>> (result['object_type'], result['name1'], result['name2']) ('%', '%', '%') >>> result = db.parse_identifier('table/scott.*') - >>> (str(result.owner), str(result.type), str(result.name)) + >>> (result['object_type'], result['name1'], result['name2']) ('scott', 'table', '%') """ - identifier = self.sql_format_wildcards(identifier) - result = {'owner': '%', 'type': '%', 'name': '%'} - result.update(dict(self.ls_parser.parseString(identifier))) - return result - dotsplitter = re.compile(r'([a-zA-Z$_#]+)([./]([a-zA-Z$_#]+))?') - def parse_identifier(self, identifier): object_type = None for otype in self.gerald_types: stripped = re.search('$' + otype + '\b(.*)', identifier, re.IGNORECASE) @@ -212,9 +209,8 @@ identifier = stripped.groups(0) object_type = otype break - match = self.dotsplitter.search(identifier) - return {'object_type': object_type, 'name1': match.group(1), 'name2': match.group(3)} - + names = identifier.split('.') + return (object_type, names) def comparison_operator(self, target): if ('%' in target) or ('_' in target): @@ -224,20 +220,29 @@ return operator def sql_format_wildcards(self, target): return target.replace('*', '%').replace('?', '_') + def comparitor(self, target): + if '%' in target or '_' in target: + return 'LIKE' + else: + return '=' def objects(self, target, opts): - identifier = self.parse_identifier(target) - clauses = {'sort': 'ASC'} - if (identifier['owner'] == '%') and (not opts.all): - identifier['owner'] = self.username - for col in ('owner', 'type', 'name'): - operator = self.comparison_operator(identifier[col]) - clauses[col] = '%s %s' % (operator, self.bindSyntax(col)) + match = self.identifier_regex.search(target) + object_type = self.object_type_case(match.group('object_type') or '%') + names = [n.strip() or '%' for n in self.name_case(match.group('remainder').replace('*', '%').replace('?', '_')).split('.')] + ['%', '%'] + replacements = {'name1_comparitor': self.comparitor(names[0]), + 'name2_comparitor': self.comparitor(names[1]), + 'object_type_comparitor': self.comparitor(object_type), + 'sort_order': 'ASC', + 'all': '1 = 0'} if hasattr(opts, 'reverse') and opts.reverse: - clauses['sort'] = 'DESC' - qry = self.all_object_qry % clauses - binds = (('owner', identifier['owner']), ('type', identifier['type']), ('name', identifier['name'])) + replacements['sort'] = 'DESC' + if hasattr(opts, 'all') and opts.all: + replacements['all'] = '1 = 1' + qry = self.all_object_qry % replacements + binds = {'schema': self.name_case(self.username), 'object_type': object_type, + 'name1': names[0], 'name2': names[1]} curs = self.connection.cursor() - curs.execute(qry, self.bindVariables(binds)) + curs.execute(qry, binds) return curs def columns(self, target, opts): target = self.sql_format_wildcards(target) @@ -319,8 +324,10 @@ class PostgresInstance(DatabaseInstance): rdbms = 'postgres' default_port = 5432 - case = str.lower - object_type_case = str.upper + def name_case(self, s): + return s.lower() + def object_type_case(self, s): + return s.upper() def set_defaults(self): self.port = os.getenv('PGPORT') or self.default_port self.database = os.getenv('ORACLE_SID') @@ -359,10 +366,9 @@ default_port = 1521 connection_parser = re.compile('(?P[^/\s@]*)(/(?P[^/\s@]*))?(@((?P[^/\s:]*)(:(?P\d{1,4}))?/)?(?P[^/\s:]*))?(\s+as\s+(?Psys(dba|oper)))?', re.IGNORECASE) - case = str.upper - database_types = ['DATABASE LINK', 'DIRECTORY', 'FUNCTION', 'INDEX', 'JOB', - 'MATERIALIZED VIEW', 'PACKAGE', 'PROCEDURE', 'SEQUENCE', - 'SYNONYM', 'TABLE', 'TRIGGER', 'TYPE', 'VIEW'] + def name_case(self, s): + return s.upper() + object_type_case = name_case def uri(self): if self.hostname: uri = '%s://%s:%s@%s:%s/%s' % (self.rdbms, self.username, self.password, @@ -392,20 +398,39 @@ return False def connect(self): self.connection = cx_Oracle.connect(user = self.username, password = self.password, - dsn = self.dsn, mode = self.mode) - all_object_qry = """SELECT owner, object_type, object_name - FROM all_objects - WHERE ( owner %(owner)s - AND object_type %(type)s - AND object_name %(name)s ) - OR - ( (owner, object_name) - IN - ( SELECT table_owner, table_name - FROM all_synonyms - WHERE synonym_name %(name)s ) - ) - ORDER BY owner, object_type, object_name %(sort)s""" + dsn = self.dsn, mode = self.mode) + all_object_qry = """SELECT * FROM ( + SELECT ao.owner, ao.object_type, ao.object_name, NULL AS synonym_name + FROM all_objects ao + WHERE ao.object_type %(object_type_comparitor)s :object_type + AND ao.owner = :schema + AND ao.object_name %(name1_comparitor)s :name1 + UNION + SELECT asyn.table_owner, ao.object_type, asyn.table_name, asyn.synonym_name + FROM all_synonyms asyn + JOIN all_objects ao ON ( asyn.table_owner = ao.owner + AND asyn.table_name = ao.object_name) + WHERE %(all)s + AND ao.object_type %(object_type_comparitor)s :object_type + AND asyn.synonym_name %(name1_comparitor)s :name1 + AND asyn.owner IN (:schema, 'PUBLIC') + UNION + SELECT ao.owner, ao.object_type, ao.object_name, NULL AS synonym_name + FROM all_objects ao + WHERE :name1 != '%%' + AND ao.object_type %(object_type_comparitor)s :object_type + AND ao.owner %(name1_comparitor)s :name1 + AND ao.object_name %(name2_comparitor)s :name2 + UNION + SELECT asyn.table_owner, ao.object_type, asyn.table_name, asyn.synonym_name + FROM all_synonyms asyn + JOIN all_objects ao ON ( asyn.table_owner = ao.owner + AND asyn.table_name = ao.object_name) + WHERE %(all)s + AND ao.object_type %(object_type_comparitor)s :object_type + AND asyn.synonym_name %(name2_comparitor)s :name2 + AND asyn.owner %(name1_comparitor)s :name1 + ) ORDER BY object_type, owner, object_name ASC""" column_qry = """SELECT atc.owner, ao.object_type, atc.table_name, atc.column_name FROM all_tab_columns atc JOIN all_objects ao ON (atc.table_name = ao.object_name AND atc.owner = ao.owner) @@ -425,7 +450,4 @@ if __name__ == '__main__': - opts = OptionTestDummy(password='password') - db = DatabaseInstance('oracle://system:twttatl@orcl', opts) - print list(db.findAll('')) - #doctest.testmod() + doctest.testmod() diff -r 2b3974b0a584 -r 0b584c8238b4 sqlpython/sqlpyPlus.py --- a/sqlpython/sqlpyPlus.py Tue Sep 21 15:26:24 2010 -0400 +++ b/sqlpython/sqlpyPlus.py Wed Sep 22 15:16:33 2010 -0400 @@ -866,7 +866,7 @@ def _pull(self, arg, opts, vc=None): statekeeper = Statekeeper(opts.dump and self, ('stdout',)) try: - for (owner, object_type, name) in self.current_instance.objects(arg, opts): + for (owner, object_type, name, synonym_name) in self.current_instance.objects(arg, opts): obj = self.current_instance.object_metadata(owner, object_type, name) txt = obj.get_ddl() if opts.get('lines'): @@ -1048,7 +1048,9 @@ all_users_option, make_option('-l', '--long', action='store_true', help='long descriptions'), make_option('-r', '--reverse', action='store_true', help="Reverse order while sorting")] - + + def object_label(self, object_type, owner, name, synonym_name): + return '%s %s.%s%s' % (object_type, owner, name, synonym_name and (synonym_name != name) and ' ("%s")' % synonym_name or '') @options(standard_options + [ make_option('-A', '--alpha', action='store_true', help='List columns alphabetically')]) def do_describe(self, arg, opts): @@ -1057,9 +1059,9 @@ sortkey = operator.itemgetter('name') else: sortkey = operator.itemgetter('sequence') - for (owner, object_type, name) in self.current_instance.objects(arg, opts): + for (owner, object_type, name, synonym_name) in self.current_instance.objects(arg, opts): obj = self.current_instance.object_metadata(owner, object_type, name) - self.tblname = '%s %s.%s' % (object_type, owner, name) + self.tblname = self.object_label(object_type, owner, name, synonym_name) self.pfeedback(self.tblname) if opts.long and hasattr(obj, 'comments') and obj.comments: self.poutput(obj.comments) @@ -1096,8 +1098,9 @@ def do_deps(self, arg, opts): '''Lists indexes, constraints, and triggers depending on an object''' #TODO: doesn't account for views; don't know about primary keys - for (owner, object_type, name) in self.current_instance.objects(arg, opts): + for (owner, object_type, name, synonym_name) in self.current_instance.objects(arg, opts): obj = self.current_instance.object_metadata(owner, object_type, name) + self.poutput(self.object_label(object_type, owner, name, synonym_name)) for deptype in ('indexes', 'constraints', 'triggers'): if hasattr(obj, deptype): for (depname, depobj) in getattr(obj, deptype).items(): @@ -1106,10 +1109,10 @@ @options([all_users_option]) def do_comments(self, arg, opts): 'Prints comments on a table and its columns.' - for (owner, object_type, name) in self.current_instance.objects(arg, opts): + for (owner, object_type, name, synonym_name) in self.current_instance.objects(arg, opts): obj = self.current_instance.object_metadata(owner, object_type, name) - if hasattr(obj, 'comments'): - self.poutput('%s %s.%s' % object_type, owner, name) + if hasattr(obj, 'comments'): + self.poutput(self.object_label(object_type, owner, name, synonym_name)) self.poutput(obj.comments) if hasattr(obj, 'columns'): columns = obj.columns.values() @@ -1286,10 +1289,10 @@ def do__dir_(self, arg, opts, plural_name, str_function): long = opts.get('long') - for (owner, object_type, name) in self.current_instance.objects(arg, opts): + for (owner, object_type, name, synonym_name) in self.current_instance.objects(arg, opts): obj = self.current_instance.object_metadata(owner, object_type, name) if hasattr(obj, plural_name): - self.pfeedback('%s on %s' % (plural_name.title(), '%s %s.%s' % (object_type, owner, name))) + self.pfeedback('%s on %s' % (plural_name.title(), self.object_label(object_type, owner, name, synonym_name))) result = [str_function(depobj, long) for depobj in getattr(obj, plural_name).values()] result.sort(reverse=bool(opts.reverse)) self.poutput('\n'.join(result)) @@ -1527,8 +1530,8 @@ def _do_ls(self, arg, opts): 'Functional core of ``do_ls``, split out into an undecorated version to be callable from other methods' - for row in self.current_instance.objects(arg, opts): - self.poutput('%s/%s/%s' % row) + for (owner, type, name, synonym_name) in self.current_instance.objects(arg, opts): + self.poutput(self.object_label(type, owner, name, synonym_name)) @options(standard_options) def do_ls(self, arg, opts): @@ -1560,9 +1563,9 @@ re_pattern = re.compile(self._to_re_wildcards(pattern), (opts.ignorecase and re.IGNORECASE) or 0) for target in targets: - for (owner, object_type, name) in self.current_instance.objects(target, opts): + for (owner, object_type, name, synonym_name) in self.current_instance.objects(target, opts): obj = self.current_instance.object_metadata(owner, object_type, name) - self.pfeedback('%s %s.%s' % (object_type, owner, name)) + self.pfeedback(self.object_label(object_type, owner, name, synonym_name)) if hasattr(obj, 'columns'): clauses = [] for col in obj.columns: