[Python-modules-commits] [python-pgspecial] 01/06: Imported Upstream version 1.2.0
ChangZhuo Chen
czchen at moszumanska.debian.org
Wed Nov 25 05:38:59 UTC 2015
This is an automated email from the git hooks/post-receive script.
czchen pushed a commit to branch debian/sid
in repository python-pgspecial.
commit 1c2669f91bd28b100167d54db79e45d012180ade
Author: ChangZhuo Chen (陳昌倬) <czchen at debian.org>
Date: Mon Nov 23 23:16:59 2015 +0800
Imported Upstream version 1.2.0
---
PKG-INFO | 100 ++++
README.rst | 76 +++
pgspecial.egg-info/PKG-INFO | 100 ++++
pgspecial.egg-info/SOURCES.txt | 15 +
pgspecial.egg-info/dependency_links.txt | 1 +
pgspecial.egg-info/pbr.json | 1 +
pgspecial.egg-info/requires.txt | 1 +
pgspecial.egg-info/top_level.txt | 1 +
pgspecial/__init__.py | 12 +
pgspecial/dbcommands.py | 998 ++++++++++++++++++++++++++++++++
pgspecial/help/__init__.py | 0
pgspecial/help/commands.py | 666 +++++++++++++++++++++
pgspecial/iocommands.py | 147 +++++
pgspecial/main.py | 213 +++++++
pgspecial/namedqueries.py | 62 ++
setup.cfg | 5 +
setup.py | 43 ++
17 files changed, 2441 insertions(+)
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..2d5f2aa
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,100 @@
+Metadata-Version: 1.1
+Name: pgspecial
+Version: 1.2.0
+Summary: Meta-commands handler for Postgres Database.
+Home-page: http://pgcli.com
+Author: Amjith Ramanujam
+Author-email: amjith[dot]r[at]gmail.com
+License: LICENSE.txt
+Description: Meta-commands for Postgres
+ --------------------------
+
+ |BuildStatus| |PyPI|
+
+ This package provides an API to execute meta-commands (AKA "special", or
+ "backslash commands") on PostgreSQL.
+
+ Quick Start
+ -----------
+
+ This is a python package. It can be installed with:
+
+ ::
+
+ $ pip install pgspecial
+
+
+ Usage
+ -----
+
+ Once this library is included into your project, you will most likely use the
+ following imports:
+
+ ::
+
+ from pgspecial.main import PGSpecial
+ from pgspecial.namedqueries import NamedQueries
+
+ Then you will create and use an instance of PGSpecial:
+
+ ::
+
+ pgspecial = PGSpecial()
+ for result in pgspecial.execute(cur, sql):
+ # Do something
+
+ If you want to import named queries from an existing config file, it is
+ convenient to initialize and keep around the class variable in
+ ``NamedQueries``:
+
+ ::
+
+ from configobj import ConfigObj
+
+ NamedQueries.instance = NamedQueries.from_config(
+ ConfigObj('~/.config_file_name'))
+
+ Contributions:
+ --------------
+
+ If you're interested in contributing to this project, first of all I would like
+ to extend my heartfelt gratitude. I've written a small doc to describe how to
+ get this running in a development setup.
+
+ https://github.com/dbcli/pgspecial/blob/master/DEVELOP.rst
+
+ Please feel free to reach out to me if you need help.
+ My email: amjith.r at gmail.com, Twitter: `@amjithr <http://twitter.com/amjithr>`_
+
+ Projects using it:
+ ------------------
+
+ This module is being used by pgcli_: A REPL for Postgres.
+
+ If you find this module useful and include it in your project, I'll be happy
+ to know about it and list it here.
+
+ .. |BuildStatus| image:: https://api.travis-ci.org/dbcli/pgspecial.svg?branch=master
+ :target: https://travis-ci.org/dbcli/pgspecial
+
+ .. |PyPI| image:: https://badge.fury.io/py/pgspecial.svg
+ :target: https://pypi.python.org/pypi/pgspecial/
+ :alt: Latest Version
+
+ .. _pgcli: https://github.com/dbcli/pgcli
+
+Platform: UNKNOWN
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: Unix
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: SQL
+Classifier: Topic :: Database
+Classifier: Topic :: Database :: Front-Ends
+Classifier: Topic :: Software Development
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..a1430aa
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,76 @@
+Meta-commands for Postgres
+--------------------------
+
+|BuildStatus| |PyPI|
+
+This package provides an API to execute meta-commands (AKA "special", or
+"backslash commands") on PostgreSQL.
+
+Quick Start
+-----------
+
+This is a python package. It can be installed with:
+
+::
+
+ $ pip install pgspecial
+
+
+Usage
+-----
+
+Once this library is included into your project, you will most likely use the
+following imports:
+
+::
+
+ from pgspecial.main import PGSpecial
+ from pgspecial.namedqueries import NamedQueries
+
+Then you will create and use an instance of PGSpecial:
+
+::
+
+ pgspecial = PGSpecial()
+ for result in pgspecial.execute(cur, sql):
+ # Do something
+
+If you want to import named queries from an existing config file, it is
+convenient to initialize and keep around the class variable in
+``NamedQueries``:
+
+::
+
+ from configobj import ConfigObj
+
+ NamedQueries.instance = NamedQueries.from_config(
+ ConfigObj('~/.config_file_name'))
+
+Contributions:
+--------------
+
+If you're interested in contributing to this project, first of all I would like
+to extend my heartfelt gratitude. I've written a small doc to describe how to
+get this running in a development setup.
+
+https://github.com/dbcli/pgspecial/blob/master/DEVELOP.rst
+
+Please feel free to reach out to me if you need help.
+My email: amjith.r at gmail.com, Twitter: `@amjithr <http://twitter.com/amjithr>`_
+
+Projects using it:
+------------------
+
+This module is being used by pgcli_: A REPL for Postgres.
+
+If you find this module useful and include it in your project, I'll be happy
+to know about it and list it here.
+
+.. |BuildStatus| image:: https://api.travis-ci.org/dbcli/pgspecial.svg?branch=master
+ :target: https://travis-ci.org/dbcli/pgspecial
+
+.. |PyPI| image:: https://badge.fury.io/py/pgspecial.svg
+ :target: https://pypi.python.org/pypi/pgspecial/
+ :alt: Latest Version
+
+.. _pgcli: https://github.com/dbcli/pgcli
diff --git a/pgspecial.egg-info/PKG-INFO b/pgspecial.egg-info/PKG-INFO
new file mode 100644
index 0000000..2d5f2aa
--- /dev/null
+++ b/pgspecial.egg-info/PKG-INFO
@@ -0,0 +1,100 @@
+Metadata-Version: 1.1
+Name: pgspecial
+Version: 1.2.0
+Summary: Meta-commands handler for Postgres Database.
+Home-page: http://pgcli.com
+Author: Amjith Ramanujam
+Author-email: amjith[dot]r[at]gmail.com
+License: LICENSE.txt
+Description: Meta-commands for Postgres
+ --------------------------
+
+ |BuildStatus| |PyPI|
+
+ This package provides an API to execute meta-commands (AKA "special", or
+ "backslash commands") on PostgreSQL.
+
+ Quick Start
+ -----------
+
+ This is a python package. It can be installed with:
+
+ ::
+
+ $ pip install pgspecial
+
+
+ Usage
+ -----
+
+ Once this library is included into your project, you will most likely use the
+ following imports:
+
+ ::
+
+ from pgspecial.main import PGSpecial
+ from pgspecial.namedqueries import NamedQueries
+
+ Then you will create and use an instance of PGSpecial:
+
+ ::
+
+ pgspecial = PGSpecial()
+ for result in pgspecial.execute(cur, sql):
+ # Do something
+
+ If you want to import named queries from an existing config file, it is
+ convenient to initialize and keep around the class variable in
+ ``NamedQueries``:
+
+ ::
+
+ from configobj import ConfigObj
+
+ NamedQueries.instance = NamedQueries.from_config(
+ ConfigObj('~/.config_file_name'))
+
+ Contributions:
+ --------------
+
+ If you're interested in contributing to this project, first of all I would like
+ to extend my heartfelt gratitude. I've written a small doc to describe how to
+ get this running in a development setup.
+
+ https://github.com/dbcli/pgspecial/blob/master/DEVELOP.rst
+
+ Please feel free to reach out to me if you need help.
+ My email: amjith.r at gmail.com, Twitter: `@amjithr <http://twitter.com/amjithr>`_
+
+ Projects using it:
+ ------------------
+
+ This module is being used by pgcli_: A REPL for Postgres.
+
+ If you find this module useful and include it in your project, I'll be happy
+ to know about it and list it here.
+
+ .. |BuildStatus| image:: https://api.travis-ci.org/dbcli/pgspecial.svg?branch=master
+ :target: https://travis-ci.org/dbcli/pgspecial
+
+ .. |PyPI| image:: https://badge.fury.io/py/pgspecial.svg
+ :target: https://pypi.python.org/pypi/pgspecial/
+ :alt: Latest Version
+
+ .. _pgcli: https://github.com/dbcli/pgcli
+
+Platform: UNKNOWN
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: Unix
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: SQL
+Classifier: Topic :: Database
+Classifier: Topic :: Database :: Front-Ends
+Classifier: Topic :: Software Development
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
diff --git a/pgspecial.egg-info/SOURCES.txt b/pgspecial.egg-info/SOURCES.txt
new file mode 100644
index 0000000..0a1bb52
--- /dev/null
+++ b/pgspecial.egg-info/SOURCES.txt
@@ -0,0 +1,15 @@
+README.rst
+setup.py
+pgspecial/__init__.py
+pgspecial/dbcommands.py
+pgspecial/iocommands.py
+pgspecial/main.py
+pgspecial/namedqueries.py
+pgspecial.egg-info/PKG-INFO
+pgspecial.egg-info/SOURCES.txt
+pgspecial.egg-info/dependency_links.txt
+pgspecial.egg-info/pbr.json
+pgspecial.egg-info/requires.txt
+pgspecial.egg-info/top_level.txt
+pgspecial/help/__init__.py
+pgspecial/help/commands.py
\ No newline at end of file
diff --git a/pgspecial.egg-info/dependency_links.txt b/pgspecial.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/pgspecial.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/pgspecial.egg-info/pbr.json b/pgspecial.egg-info/pbr.json
new file mode 100644
index 0000000..14a80e3
--- /dev/null
+++ b/pgspecial.egg-info/pbr.json
@@ -0,0 +1 @@
+{"is_release": false, "git_version": "4a122da"}
\ No newline at end of file
diff --git a/pgspecial.egg-info/requires.txt b/pgspecial.egg-info/requires.txt
new file mode 100644
index 0000000..e86a836
--- /dev/null
+++ b/pgspecial.egg-info/requires.txt
@@ -0,0 +1 @@
+click >= 4.1
diff --git a/pgspecial.egg-info/top_level.txt b/pgspecial.egg-info/top_level.txt
new file mode 100644
index 0000000..a8ad873
--- /dev/null
+++ b/pgspecial.egg-info/top_level.txt
@@ -0,0 +1 @@
+pgspecial
diff --git a/pgspecial/__init__.py b/pgspecial/__init__.py
new file mode 100644
index 0000000..8a0fb6b
--- /dev/null
+++ b/pgspecial/__init__.py
@@ -0,0 +1,12 @@
+__all__ = []
+__version__ = '1.2.0'
+
+
+def export(defn):
+ """Decorator to explicitly mark functions that are exposed in a lib."""
+ globals()[defn.__name__] = defn
+ __all__.append(defn.__name__)
+ return defn
+
+from . import dbcommands
+from . import iocommands
diff --git a/pgspecial/dbcommands.py b/pgspecial/dbcommands.py
new file mode 100644
index 0000000..041d630
--- /dev/null
+++ b/pgspecial/dbcommands.py
@@ -0,0 +1,998 @@
+import logging
+from collections import namedtuple
+from .main import special_command, RAW_QUERY
+
+TableInfo = namedtuple("TableInfo", ['checks', 'relkind', 'hasindex',
+'hasrules', 'hastriggers', 'hasoids', 'tablespace', 'reloptions', 'reloftype',
+'relpersistence'])
+
+log = logging.getLogger(__name__)
+
+
+ at special_command('\\l', '\\l', 'List databases.', arg_type=RAW_QUERY)
+def list_databases(cur, **_):
+ query = 'SELECT datname FROM pg_database;'
+ cur.execute(query)
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+ else:
+ return [(None, None, None, cur.statusmessage)]
+
+
+ at special_command('\\du', '\\du[+] [pattern]', 'List roles.')
+def list_roles(cur, pattern, verbose):
+ """
+ Returns (title, rows, headers, status)
+ """
+ sql = '''SELECT r.rolname, r.rolsuper, r.rolinherit,
+ r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
+ r.rolconnlimit, r.rolvaliduntil,
+ ARRAY(SELECT b.rolname
+ FROM pg_catalog.pg_auth_members m
+ JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
+ WHERE m.member = r.oid) as memberof''' + (''',
+ pg_catalog.shobj_description(r.oid, 'pg_authid') AS description'''
+ if verbose else '') + """, r.rolreplication
+ FROM pg_catalog.pg_roles r """
+
+ params = []
+ if pattern:
+ _, schema = sql_name_pattern(pattern)
+ sql += 'WHERE r.rolname ~ %s'
+ params.append(schema)
+ sql = cur.mogrify(sql + " ORDER BY 1", params)
+
+ log.debug(sql)
+ cur.execute(sql)
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+
+
+ at special_command('\\dn', '\\dn[+] [pattern]', 'List schemas.')
+def list_schemas(cur, pattern, verbose):
+ """
+ Returns (title, rows, headers, status)
+ """
+
+ sql = '''SELECT n.nspname AS "Name",
+ pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner"''' + (''',
+ pg_catalog.array_to_string(n.nspacl, E'\\n') AS "Access privileges",
+ pg_catalog.obj_description(n.oid, 'pg_namespace') AS "Description"''' if verbose else '') + """
+ FROM pg_catalog.pg_namespace n WHERE n.nspname """
+
+ params = []
+ if pattern:
+ _, schema = sql_name_pattern(pattern)
+ sql += '~ %s'
+ params.append(schema)
+ else:
+ sql += "!~ '^pg_' AND n.nspname <> 'information_schema'"
+ sql = cur.mogrify(sql + " ORDER BY 1", params)
+
+ log.debug(sql)
+ cur.execute(sql)
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+
+
+def list_objects(cur, pattern, verbose, relkinds):
+ """
+ Returns (title, rows, header, status)
+
+ This method is used by list_tables, list_views, and list_indexes
+
+ relkinds is a list of strings to filter pg_class.relkind
+
+ """
+ schema_pattern, table_pattern = sql_name_pattern(pattern)
+
+ if verbose:
+ verbose_columns = '''
+ ,pg_catalog.pg_size_pretty(pg_catalog.pg_table_size(c.oid)) as "Size",
+ pg_catalog.obj_description(c.oid, 'pg_class') as "Description" '''
+ else:
+ verbose_columns = ''
+
+ sql = '''SELECT n.nspname as "Schema",
+ c.relname as "Name",
+ CASE c.relkind
+ WHEN 'r' THEN 'table' WHEN 'v' THEN 'view'
+ WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index'
+ WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special'
+ WHEN 'f' THEN 'foreign table' END
+ as "Type",
+ pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
+ ''' + verbose_columns + '''
+ FROM pg_catalog.pg_class c
+ LEFT JOIN pg_catalog.pg_namespace n
+ ON n.oid = c.relnamespace
+ WHERE c.relkind = ANY(%s) '''
+
+ params = [relkinds]
+
+ if schema_pattern:
+ sql += ' AND n.nspname ~ %s'
+ params.append(schema_pattern)
+ else:
+ sql += '''
+ AND n.nspname <> 'pg_catalog'
+ AND n.nspname <> 'information_schema'
+ AND n.nspname !~ '^pg_toast'
+ AND pg_catalog.pg_table_is_visible(c.oid) '''
+
+ if table_pattern:
+ sql += ' AND c.relname ~ %s'
+ params.append(table_pattern)
+
+ sql = cur.mogrify(sql + ' ORDER BY 1, 2', params)
+
+ log.debug(sql)
+ cur.execute(sql)
+
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+
+
+ at special_command('\\dt', '\\dt[+] [pattern]', 'List tables.')
+def list_tables(cur, pattern, verbose):
+ return list_objects(cur, pattern, verbose, ['r', ''])
+
+
+ at special_command('\\dv', '\\dv[+] [pattern]', 'List views.')
+def list_views(cur, pattern, verbose):
+ return list_objects(cur, pattern, verbose, ['v', 's', ''])
+
+
+ at special_command('\\ds', '\\ds[+] [pattern]', 'List sequences.')
+def list_sequences(cur, pattern, verbose):
+ return list_objects(cur, pattern, verbose, ['S', 's', ''])
+
+
+ at special_command('\\di', '\\di[+] [pattern]', 'List indexes.')
+def list_indexes(cur, pattern, verbose):
+ return list_objects(cur, pattern, verbose, ['i', 's', ''])
+
+
+ at special_command('\\df', '\\df[+] [pattern]', 'List functions.')
+def list_functions(cur, pattern, verbose):
+
+ if verbose:
+ verbose_columns = '''
+ ,CASE
+ WHEN p.provolatile = 'i' THEN 'immutable'
+ WHEN p.provolatile = 's' THEN 'stable'
+ WHEN p.provolatile = 'v' THEN 'volatile'
+ END as "Volatility",
+ pg_catalog.pg_get_userbyid(p.proowner) as "Owner",
+ l.lanname as "Language",
+ p.prosrc as "Source code",
+ pg_catalog.obj_description(p.oid, 'pg_proc') as "Description" '''
+
+ verbose_table = ''' LEFT JOIN pg_catalog.pg_language l
+ ON l.oid = p.prolang'''
+ else:
+ verbose_columns = verbose_table = ''
+
+ sql = '''
+ SELECT n.nspname as "Schema",
+ p.proname as "Name",
+ pg_catalog.pg_get_function_result(p.oid)
+ as "Result data type",
+ pg_catalog.pg_get_function_arguments(p.oid)
+ as "Argument data types",
+ CASE
+ WHEN p.proisagg THEN 'agg'
+ WHEN p.proiswindow THEN 'window'
+ WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype
+ THEN 'trigger'
+ ELSE 'normal'
+ END as "Type" ''' + verbose_columns + '''
+ FROM pg_catalog.pg_proc p
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
+ ''' + verbose_table + '''
+ WHERE '''
+
+ schema_pattern, func_pattern = sql_name_pattern(pattern)
+ params = []
+
+ if schema_pattern:
+ sql += ' n.nspname ~ %s '
+ params.append(schema_pattern)
+ else:
+ sql += ' pg_catalog.pg_function_is_visible(p.oid) '
+
+ if func_pattern:
+ sql += ' AND p.proname ~ %s '
+ params.append(func_pattern)
+
+ if not (schema_pattern or func_pattern):
+ sql += ''' AND n.nspname <> 'pg_catalog'
+ AND n.nspname <> 'information_schema' '''
+
+ sql = cur.mogrify(sql + ' ORDER BY 1, 2, 4', params)
+
+ log.debug(sql)
+ cur.execute(sql)
+
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+
+
+ at special_command('\\dT', '\\dT[S+] [pattern]', 'List data types')
+def list_datatypes(cur, pattern, verbose):
+ assert True
+ sql = '''SELECT n.nspname as "Schema",
+ pg_catalog.format_type(t.oid, NULL) AS "Name", '''
+
+ if verbose:
+ sql += r''' t.typname AS "Internal name",
+ CASE
+ WHEN t.typrelid != 0
+ THEN CAST('tuple' AS pg_catalog.text)
+ WHEN t.typlen < 0
+ THEN CAST('var' AS pg_catalog.text)
+ ELSE CAST(t.typlen AS pg_catalog.text)
+ END AS "Size",
+ pg_catalog.array_to_string(
+ ARRAY(
+ SELECT e.enumlabel
+ FROM pg_catalog.pg_enum e
+ WHERE e.enumtypid = t.oid
+ ORDER BY e.enumsortorder
+ ), E'\n') AS "Elements",
+ pg_catalog.array_to_string(t.typacl, E'\n')
+ AS "Access privileges",
+ pg_catalog.obj_description(t.oid, 'pg_type')
+ AS "Description"'''
+ else:
+ sql += ''' pg_catalog.obj_description(t.oid, 'pg_type')
+ as "Description" '''
+
+ sql += ''' FROM pg_catalog.pg_type t
+ LEFT JOIN pg_catalog.pg_namespace n
+ ON n.oid = t.typnamespace
+ WHERE (t.typrelid = 0 OR
+ ( SELECT c.relkind = 'c'
+ FROM pg_catalog.pg_class c
+ WHERE c.oid = t.typrelid))
+ AND NOT EXISTS(
+ SELECT 1
+ FROM pg_catalog.pg_type el
+ WHERE el.oid = t.typelem
+ AND el.typarray = t.oid) '''
+
+ schema_pattern, type_pattern = sql_name_pattern(pattern)
+ params = []
+
+ if schema_pattern:
+ sql += ' AND n.nspname ~ %s '
+ params.append(schema_pattern)
+ else:
+ sql += ' AND pg_catalog.pg_type_is_visible(t.oid) '
+
+ if type_pattern:
+ sql += ''' AND (t.typname ~ %s
+ OR pg_catalog.format_type(t.oid, NULL) ~ %s) '''
+ params.extend(2 * [type_pattern])
+
+ if not (schema_pattern or type_pattern):
+ sql += ''' AND n.nspname <> 'pg_catalog'
+ AND n.nspname <> 'information_schema' '''
+
+ sql = cur.mogrify(sql + ' ORDER BY 1, 2', params)
+ log.debug(sql)
+ cur.execute(sql)
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+
+
+ at special_command('describe', 'DESCRIBE [pattern]', '', hidden=True, case_sensitive=False)
+ at special_command('\\d', '\\d [pattern]', 'List or describe tables, views and sequences.')
+def describe_table_details(cur, pattern, verbose):
+ """
+ Returns (title, rows, headers, status)
+ """
+
+ # This is a simple \d command. No table name to follow.
+ if not pattern:
+ sql = """SELECT n.nspname as "Schema", c.relname as "Name",
+ CASE c.relkind WHEN 'r' THEN 'table'
+ WHEN 'v' THEN 'view'
+ WHEN 'm' THEN 'materialized view'
+ WHEN 'i' THEN 'index'
+ WHEN 'S' THEN 'sequence'
+ WHEN 's' THEN 'special'
+ WHEN 'f' THEN 'foreign table'
+ END as "Type",
+ pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
+ FROM pg_catalog.pg_class c
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
+ WHERE c.relkind IN ('r','v','m','S','f','')
+ AND n.nspname <> 'pg_catalog'
+ AND n.nspname <> 'information_schema'
+ AND n.nspname !~ '^pg_toast'
+ AND pg_catalog.pg_table_is_visible(c.oid)
+ ORDER BY 1,2 """
+
+ log.debug(sql)
+ cur.execute(sql)
+ if cur.description:
+ headers = [x[0] for x in cur.description]
+ return [(None, cur, headers, cur.statusmessage)]
+
+ # This is a \d <tablename> command. A royal pain in the ass.
+ schema, relname = sql_name_pattern(pattern)
+ where = []
+ params = []
+
+ if not pattern:
+ where.append('pg_catalog.pg_table_is_visible(c.oid)')
+
+ if schema:
+ where.append('n.nspname ~ %s')
+ params.append(schema)
+
+ if relname:
+ where.append('c.relname ~ %s')
+ params.append(relname)
+
+ sql = """SELECT c.oid, n.nspname, c.relname
+ FROM pg_catalog.pg_class c
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
+ """ + ('WHERE ' + ' AND '.join(where) if where else '') + """
+ ORDER BY 2,3"""
+ sql = cur.mogrify(sql, params)
+
+ # Execute the sql, get the results and call describe_one_table_details on each table.
+
+ log.debug(sql)
+ cur.execute(sql)
+ if not (cur.rowcount > 0):
+ return [(None, None, None, 'Did not find any relation named %s.' % pattern)]
+
+ results = []
+ for oid, nspname, relname in cur.fetchall():
+ results.append(describe_one_table_details(cur, nspname, relname, oid, verbose))
+
+ return results
+
+
+def describe_one_table_details(cur, schema_name, relation_name, oid, verbose):
+ if verbose:
+ suffix = """pg_catalog.array_to_string(c.reloptions || array(select
+ 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')"""
+ else:
+ suffix = "''"
+
+ sql ="""SELECT c.relchecks, c.relkind, c.relhasindex,
+ c.relhasrules, c.relhastriggers, c.relhasoids,
+ %s,
+ c.reltablespace,
+ CASE WHEN c.reloftype = 0 THEN ''
+ ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text
+ END,
+ c.relpersistence
+ FROM pg_catalog.pg_class c
+ LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)
+ WHERE c.oid = '%s'""" % (suffix, oid)
+
+ # Create a namedtuple called tableinfo and match what's in describe.c
+
+ log.debug(sql)
+ cur.execute(sql)
+ if (cur.rowcount > 0):
+ tableinfo = TableInfo._make(cur.fetchone())
+ else:
+ return (None, None, None, 'Did not find any relation with OID %s.' % oid)
+
+ # If it's a seq, fetch it's value and store it for later.
+ if tableinfo.relkind == 'S':
+ # Do stuff here.
+ sql = '''SELECT * FROM "%s"."%s"''' % (schema_name, relation_name)
+ log.debug(sql)
+ cur.execute(sql)
+ if not (cur.rowcount > 0):
+ return (None, None, None, 'Something went wrong.')
+
+ seq_values = cur.fetchone()
+
+ # Get column info
+ sql = """SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod),
+ (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
+ FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum =
+ a.attnum AND a.atthasdef), a.attnotnull, a.attnum, (SELECT c.collname
+ FROM pg_catalog.pg_collation c, pg_catalog.pg_type t WHERE c.oid =
+ a.attcollation AND t.oid = a.atttypid AND a.attcollation <>
+ t.typcollation) AS attcollation"""
+
+ if tableinfo.relkind == 'i':
+ sql += """, pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE)
+ AS indexdef"""
+ else:
+ sql += """, NULL AS indexdef"""
+
+ if tableinfo.relkind == 'f':
+ sql += """, CASE WHEN attfdwoptions IS NULL THEN '' ELSE '(' ||
+ array_to_string(ARRAY(SELECT quote_ident(option_name) || ' '
+ || quote_literal(option_value) FROM
+ pg_options_to_table(attfdwoptions)), ', ') || ')' END AS
+ attfdwoptions"""
+ else:
+ sql += """, NULL AS attfdwoptions"""
+
+ if verbose:
+ sql += """, a.attstorage"""
+ sql += """, CASE WHEN a.attstattarget=-1 THEN NULL ELSE
+ a.attstattarget END AS attstattarget"""
+ if (tableinfo.relkind == 'r' or tableinfo.relkind == 'v' or
+ tableinfo.relkind == 'm' or tableinfo.relkind == 'f' or
+ tableinfo.relkind == 'c'):
+ sql += """, pg_catalog.col_description(a.attrelid,
+ a.attnum)"""
+
+ sql += """ FROM pg_catalog.pg_attribute a WHERE a.attrelid = '%s' AND
+ a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum; """ % oid
+
+ log.debug(sql)
+ cur.execute(sql)
+ res = cur.fetchall()
+
+ title = (tableinfo.relkind, schema_name, relation_name)
+
+ # Set the column names.
+ headers = ['Column', 'Type']
+
+ show_modifiers = False
+ if (tableinfo.relkind == 'r' or tableinfo.relkind == 'v' or
+ tableinfo.relkind == 'm' or tableinfo.relkind == 'f' or
+ tableinfo.relkind == 'c'):
+ headers.append('Modifiers')
+ show_modifiers = True
+
+ if (tableinfo.relkind == 'S'):
+ headers.append("Value")
+
+ if (tableinfo.relkind == 'i'):
+ headers.append("Definition")
+
+ if (tableinfo.relkind == 'f'):
+ headers.append("FDW Options")
+
+ if (verbose):
+ headers.append("Storage")
+ if (tableinfo.relkind == 'r' or tableinfo.relkind == 'm' or
+ tableinfo.relkind == 'f'):
+ headers.append("Stats target")
+ # Column comments, if the relkind supports this feature. */
+ if (tableinfo.relkind == 'r' or tableinfo.relkind == 'v' or
+ tableinfo.relkind == 'm' or
+ tableinfo.relkind == 'c' or tableinfo.relkind == 'f'):
+ headers.append("Description")
+
+ view_def = ''
+ # /* Check if table is a view or materialized view */
+ if ((tableinfo.relkind == 'v' or tableinfo.relkind == 'm') and verbose):
+ sql = """SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true)""" % oid
+ log.debug(sql)
+ cur.execute(sql)
+ if cur.rowcount > 0:
+ view_def = cur.fetchone()
+
+ # Prepare the cells of the table to print.
+ cells = []
+ for i, row in enumerate(res):
+ cell = []
+ cell.append(row[0]) # Column
+ cell.append(row[1]) # Type
+
+ if show_modifiers:
+ modifier = ''
+ if row[5]:
+ modifier += ' collate %s' % row[5]
+ if row[3]:
+ modifier += ' not null'
+ if row[2]:
+ modifier += ' default %s' % row[2]
+
+ cell.append(modifier)
+
+ # Sequence
+ if tableinfo.relkind == 'S':
+ cell.append(seq_values[i])
+
+ # Index column
+ if TableInfo.relkind == 'i':
+ cell.append(row[6])
+
+ # /* FDW options for foreign table column, only for 9.2 or later */
+ if tableinfo.relkind == 'f':
+ cell.append(row[7])
+
+ if verbose:
+ storage = row[8]
+
+ if storage[0] == 'p':
+ cell.append('plain')
+ elif storage[0] == 'm':
+ cell.append('main')
+ elif storage[0] == 'x':
+ cell.append('extended')
+ elif storage[0] == 'e':
+ cell.append('external')
+ else:
+ cell.append('???')
+
+ if (tableinfo.relkind == 'r' or tableinfo.relkind == 'm' or
+ tableinfo.relkind == 'f'):
+ cell.append(row[9])
+
+ # /* Column comments, if the relkind supports this feature. */
+ if (tableinfo.relkind == 'r' or tableinfo.relkind == 'v' or
+ tableinfo.relkind == 'm' or
+ tableinfo.relkind == 'c' or tableinfo.relkind == 'f'):
+ cell.append(row[10])
+ cells.append(cell)
+
+ # Make Footers
+
+ status = []
+ if (tableinfo.relkind == 'i'):
+ # /* Footer information about an index */
+
+ sql = """SELECT i.indisunique, i.indisprimary, i.indisclustered,
+ i.indisvalid, (NOT i.indimmediate) AND EXISTS (SELECT 1 FROM
+ pg_catalog.pg_constraint WHERE conrelid = i.indrelid AND conindid =
+ i.indexrelid AND contype IN ('p','u','x') AND condeferrable) AS
+ condeferrable, (NOT i.indimmediate) AND EXISTS (SELECT 1 FROM
+ pg_catalog.pg_constraint WHERE conrelid = i.indrelid AND conindid =
+ i.indexrelid AND contype IN ('p','u','x') AND condeferred) AS
+ condeferred, a.amname, c2.relname, pg_catalog.pg_get_expr(i.indpred,
+ i.indrelid, true) FROM pg_catalog.pg_index i, pg_catalog.pg_class c,
+ pg_catalog.pg_class c2, pg_catalog.pg_am a WHERE i.indexrelid = c.oid
+ AND c.oid = '%s' AND c.relam = a.oid AND i.indrelid = c2.oid;""" % oid
+
+ log.debug(sql)
+ cur.execute(sql)
+
+ (indisunique, indisprimary, indisclustered, indisvalid,
+ deferrable, deferred, indamname, indtable, indpred) = cur.fetchone()
+
+ if indisprimary:
+ status.append("primary key, ")
+ elif indisunique:
+ status.append("unique, ")
+ status.append("%s, " % indamname)
+
+ #/* we assume here that index and table are in same schema */
+ status.append('for table "%s.%s"' % (schema_name, indtable))
+
+ if indpred:
+ status.append(", predicate (%s)" % indpred)
+
+ if indisclustered:
+ status.append(", clustered")
+
+ if indisvalid:
+ status.append(", invalid")
+
+ if deferrable:
+ status.append(", deferrable")
+
+ if deferred:
+ status.append(", initially deferred")
+
+ status.append('\n')
+ #add_tablespace_footer(&cont, tableinfo.relkind,
+ #tableinfo.tablespace, true);
+
+ elif tableinfo.relkind == 'S':
+ # /* Footer information about a sequence */
+ # /* Get the column that owns this sequence */
+ sql = ("SELECT pg_catalog.quote_ident(nspname) || '.' ||"
+ "\n pg_catalog.quote_ident(relname) || '.' ||"
+ "\n pg_catalog.quote_ident(attname)"
+ "\nFROM pg_catalog.pg_class c"
+ "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
+ "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
+ "\nINNER JOIN pg_catalog.pg_attribute a ON ("
+ "\n a.attrelid=c.oid AND"
+ "\n a.attnum=d.refobjsubid)"
+ "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
... 1567 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-pgspecial.git
More information about the Python-modules-commits
mailing list