[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