py-postgresql
Advanced tools
| include AUTHORS | ||
| include LICENSE | ||
| recursive-include postgresql *.c | ||
| recursive-include postgresql *.sql | ||
| recursive-include postgresql *.txt | ||
| recursive-include postgresql/documentation/sphinx *.rst conf.py |
| Administration | ||
| ============== | ||
| This chapter covers the administration of py-postgresql. This includes | ||
| installation and other aspects of working with py-postgresql such as | ||
| environment variables and configuration files. | ||
| Installation | ||
| ------------ | ||
| py-postgresql uses Python's distutils package to manage the build and | ||
| installation process of the package. The normal entry point for | ||
| this is the ``setup.py`` script contained in the root project directory. | ||
| After extracting the archive and changing the into the project's directory, | ||
| installation is normally as simple as:: | ||
| $ python3 ./setup.py install | ||
| However, if you need to install for use with a particular version of python, | ||
| just use the path of the executable that should be used:: | ||
| $ /usr/opt/bin/python3 ./setup.py install | ||
| Environment | ||
| ----------- | ||
| These environment variables effect the operation of the package: | ||
| ============== =============================================================================== | ||
| PGINSTALLATION The path to the ``pg_config`` executable of the installation to use by default. | ||
| ============== =============================================================================== |
| .. _alock: | ||
| ************** | ||
| Advisory Locks | ||
| ************** | ||
| .. warning:: `postgresql.alock` is a new feature in v1.0. | ||
| `Explicit Locking in PostgreSQL <http://www.postgresql.org/docs/current/static/explicit-locking.html#ADVISORY-LOCKS>`_. | ||
| PostgreSQL's advisory locks offer a cooperative synchronization primitive. | ||
| These are used in cases where an application needs access to a resource, but | ||
| using table locks may cause interference with other operations that can be | ||
| safely performed alongside the application-level, exclusive operation. | ||
| Advisory locks can be used by directly executing the stored procedures in the | ||
| database or by using the :class:`postgresql.alock.ALock` subclasses, which | ||
| provides a context manager that uses those stored procedures. | ||
| Currently, only two subclasses exist. Each represents the lock mode | ||
| supported by PostgreSQL's advisory locks: | ||
| * :class:`postgresql.alock.ShareLock` | ||
| * :class:`postgresql.alock.ExclusiveLock` | ||
| Acquiring ALocks | ||
| ================ | ||
| An ALock instance represents a sequence of advisory locks. A single ALock can | ||
| acquire and release multiple advisory locks by creating the instance with | ||
| multiple lock identifiers:: | ||
| >>> from postgresql import alock | ||
| >>> table1_oid = 192842 | ||
| >>> table2_oid = 192849 | ||
| >>> l = alock.ExclusiveLock(db, (table1_oid, 0), (table2_oid, 0)) | ||
| >>> l.acquire() | ||
| >>> ... | ||
| >>> l.release() | ||
| :class:`postgresql.alock.ALock` is similar to :class:`threading.RLock`; in | ||
| order for an ALock to be released, it must be released the number of times it | ||
| has been acquired. ALocks are associated with and survived by their session. | ||
| Much like how RLocks are associated with the thread they are acquired in: | ||
| acquiring an ALock again will merely increment its count. | ||
| PostgreSQL allows advisory locks to be identified using a pair of `int4` or a | ||
| single `int8`. ALock instances represent a *sequence* of those identifiers:: | ||
| >>> from postgresql import alock | ||
| >>> ids = [(0,0), 0, 1] | ||
| >>> with alock.ShareLock(db, *ids): | ||
| ... ... | ||
| Both types of identifiers may be used within the same ALock, and, regardless of | ||
| their type, will be aquired in the order that they were given to the class' | ||
| constructor. In the above example, ``(0,0)`` is acquired first, then ``0``, and | ||
| lastly ``1``. | ||
| ALocks | ||
| ====== | ||
| `postgresql.alock.ALock` is abstract; it defines the interface and some common | ||
| functionality. The lock mode is selected by choosing the appropriate subclass. | ||
| There are two: | ||
| ``postgresql.alock.ExclusiveLock(database, *identifiers)`` | ||
| Instantiate an ALock object representing the `identifiers` for use with the | ||
| `database`. Exclusive locks will conflict with other exclusive locks and share | ||
| locks. | ||
| ``postgresql.alock.ShareLock(database, *identifiers)`` | ||
| Instantiate an ALock object representing the `identifiers` for use with the | ||
| `database`. Share locks can be acquired when a share lock with the same | ||
| identifier has been acquired by another backend. However, an exclusive lock | ||
| with the same identifier will conflict. | ||
| ALock Interface Points | ||
| ---------------------- | ||
| Methods and properties available on :class:`postgresql.alock.ALock` instances: | ||
| ``alock.acquire(blocking = True)`` | ||
| Acquire the advisory locks represented by the ``alock`` object. If blocking is | ||
| `True`, the default, the method will block until locks on *all* the | ||
| identifiers have been acquired. | ||
| If blocking is `False`, acquisition may not block, and success will be | ||
| indicated by the returned object: `True` if *all* lock identifiers were | ||
| acquired and `False` if any of the lock identifiers could not be acquired. | ||
| ``alock.release()`` | ||
| Release the advisory locks represented by the ``alock`` object. If the lock | ||
| has not been acquired, a `RuntimeError` will be raised. | ||
| ``alock.locked()`` | ||
| Returns a boolean describing whether the locks are held or not. This will | ||
| return `False` if the lock connection has been closed. | ||
| ``alock.__enter__()`` | ||
| Alias to ``acquire``; context manager protocol. Always blocking. | ||
| ``alock.__exit__(typ, val, tb)`` | ||
| Alias to ``release``; context manager protocol. |
| Commands | ||
| ******** | ||
| This chapter discusses the usage of the available console scripts. | ||
| postgresql.bin.pg_python | ||
| ======================== | ||
| The ``pg_python`` command provides a simple way to write Python scripts against a | ||
| single target database. It acts like the regular Python console command, but | ||
| takes standard PostgreSQL options as well to specify the client parameters | ||
| to make establish connection with. The Python environment is then augmented | ||
| with the following built-ins: | ||
| ``db`` | ||
| The PG-API connection object. | ||
| ``xact`` | ||
| ``db.xact``, the transaction creator. | ||
| ``settings`` | ||
| ``db.settings`` | ||
| ``prepare`` | ||
| ``db.prepare``, the statement creator. | ||
| ``proc`` | ||
| ``db.proc`` | ||
| ``do`` | ||
| ``db.do``, execute a single DO statement. | ||
| ``sqlexec`` | ||
| ``db.execute``, execute multiple SQL statements (``None`` is always returned) | ||
| pg_python Usage | ||
| --------------- | ||
| Usage: postgresql.bin.pg_python [connection options] [script] ... | ||
| Options: | ||
| --unix=UNIX path to filesystem socket | ||
| --ssl-mode=SSLMODE SSL requirement for connectivity: require, prefer, | ||
| allow, disable | ||
| -s SETTINGS, --setting=SETTINGS | ||
| run-time parameters to set upon connecting | ||
| -I PQ_IRI, --iri=PQ_IRI | ||
| database locator string | ||
| [pq://user:password@host:port/database?setting=value] | ||
| -h HOST, --host=HOST database server host | ||
| -p PORT, --port=PORT database server port | ||
| -U USER, --username=USER | ||
| user name to connect as | ||
| -W, --password prompt for password | ||
| -d DATABASE, --database=DATABASE | ||
| database's name | ||
| --pq-trace=PQ_TRACE trace PQ protocol transmissions | ||
| -C PYTHON_CONTEXT, --context=PYTHON_CONTEXT | ||
| Python context code to run[file://,module:,<code>] | ||
| -m PYTHON_MAIN Python module to run as script(__main__) | ||
| -c PYTHON_MAIN Python expression to run(__main__) | ||
| --version show program's version number and exit | ||
| --help show this help message and exit | ||
| Interactive Console Backslash Commands | ||
| -------------------------------------- | ||
| Inspired by ``psql``:: | ||
| >>> \? | ||
| Backslash Commands: | ||
| \? Show this help message. | ||
| \E Edit a file or a temporary script. | ||
| \e Edit and Execute the file directly in the context. | ||
| \i Execute a Python script within the interpreter's context. | ||
| \set Configure environment variables. \set without arguments to show all | ||
| \x Execute the Python command within this process. | ||
| pg_python Examples | ||
| ------------------ | ||
| Module execution taking advantage of the new built-ins:: | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W -m timeit "prepare('SELECT 1').first()" | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| 1000 loops, best of 3: 1.35 msec per loop | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W -m timeit -s "ps=prepare('SELECT 1')" "ps.first()" | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| 1000 loops, best of 3: 442 usec per loop | ||
| Simple interactive usage:: | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| >>> ps = prepare('select 1') | ||
| >>> ps.first() | ||
| 1 | ||
| >>> c = ps() | ||
| >>> c.read() | ||
| [(1,)] | ||
| >>> ps.close() | ||
| >>> import sys | ||
| >>> sys.exit(0) | ||
| postgresql.bin.pg_dotconf | ||
| ========================= | ||
| pg_dotconf is used to modify a PostgreSQL cluster's configuration file. | ||
| It provides a means to apply settings specified from the command line and from a | ||
| file referenced using the ``-f`` option. | ||
| .. warning:: | ||
| ``include`` directives in configuration files are *completely* ignored. If | ||
| modification of an included file is desired, the command must be applied to | ||
| that specific file. | ||
| pg_dotconf Usage | ||
| ---------------- | ||
| Usage: postgresql.bin.pg_dotconf [--stdout] [-f filepath] postgresql.conf ([param=val]|[param])* | ||
| Options: | ||
| --version show program's version number and exit | ||
| -h, --help show this help message and exit | ||
| -f SETTINGS, --file=SETTINGS | ||
| A file of settings to *apply* to the given | ||
| "postgresql.conf" | ||
| --stdout Redirect the product to standard output instead of | ||
| writing back to the "postgresql.conf" file | ||
| Examples | ||
| -------- | ||
| Modifying a simple configuration file:: | ||
| $ echo "setting = value" >pg.conf | ||
| # change 'setting' | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf setting=newvalue | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| # new settings are appended to the file | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf another_setting=value | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| another_setting = 'value' | ||
| # comment a setting | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf another_setting | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| #another_setting = 'value' | ||
| When a setting is given on the command line, it must been seen as one argument | ||
| to the command, so it's *very* important to avoid invocations like:: | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf setting = value | ||
| ERROR: invalid setting, '=' after 'setting' | ||
| HINT: Settings must take the form 'setting=value' or 'setting_name_to_comment'. Settings must also be received as a single argument. |
| Changes in v1.0 | ||
| =============== | ||
| 1.0.4 in development | ||
| -------------------- | ||
| * Alter how changes are represented in documentation to simplify merging. | ||
| 1.0.3 released on 2011-09-24 | ||
| ---------------------------- | ||
| * Use raise x from y to generalize exceptions. (Elvis Pranskevichus) | ||
| * Alter postgresql.string.quote_ident to always quote. (Elvis Pranskevichus) | ||
| * Add postgresql.string.quote_ident_if_necessary (Modification of Elvis Pranskevichus' patch) | ||
| * Many postgresql.string bug fixes (Elvis Pranskevichus) | ||
| * Correct ResourceWarnings improving Python 3.2 support. (jwp) | ||
| * Add test command to setup.py (Elvis Pranskevichus) | ||
| 1.0.2 released on 2010-09-18 | ||
| ---------------------------- | ||
| * Add support for DOMAINs in registered composites. (Elvis Pranskevichus) | ||
| * Properly raise StopIteration in Cursor.__next__. (Elvis Pranskevichus) | ||
| * Add Cluster Management documentation. | ||
| * Release savepoints after rolling them back. | ||
| * Fix Startup() usage for Python 3.2. | ||
| * Emit deprecation warning when 'gid' is given to xact(). | ||
| * Compensate for Python3.2's ElementTree API changes. | ||
| 1.0.1 released on 2010-04-24 | ||
| ---------------------------- | ||
| * Fix unpacking of array NULLs. (Elvis Pranskevichus) | ||
| * Fix .first()'s handling of counts and commands. | ||
| Bad logic caused zero-counts to return the command tag. | ||
| * Don't interrupt and close a temporal connection if it's not open. | ||
| * Use the Driver's typio attribute for TypeIO overrides. (Elvis Pranskevichus) | ||
| 1.0 released on 2010-03-27 | ||
| -------------------------- | ||
| * **DEPRECATION**: Removed 2PC support documentation. | ||
| * **DEPRECATION**: Removed pg_python and pg_dotconf 'scripts'. | ||
| They are still accessible by python3 -m postgresql.bin.pg_* | ||
| * Add support for binary hstore. | ||
| * Add support for user service files. | ||
| * Implement a Copy manager for direct connection-to-connection COPY operations. | ||
| * Added db.do() method for DO-statement support(convenience method). | ||
| * Set the default client_min_messages level to WARNING. | ||
| NOTICEs are often not desired by programmers, and py-postgresql's | ||
| high verbosity further irritates that case. | ||
| * Added postgresql.project module to provide project information. | ||
| Project name, author, version, etc. | ||
| * Increased default recvsize and chunksize for improved performance. | ||
| * 'D' messages are special cased as builtins.tuples instead of | ||
| protocol.element3.Tuple | ||
| * Alter Statement.chunks() to return chunks of builtins.tuple. Being | ||
| an interface intended for speed, types.Row() impedes its performance. | ||
| * Fix handling of infinity values with timestamptz, timestamp, and date. | ||
| [Bug reported by Axel Rau.] | ||
| * Correct representation of PostgreSQL ARRAYs by properly recording | ||
| lowerbounds and upperbounds. Internally, sub-ARRAYs have their own | ||
| element lists. | ||
| * Implement a NotificationManager for managing the NOTIFYs received | ||
| by a connection. The class can manage NOTIFYs from multiple | ||
| connections, whereas the db.wait() method is tailored for single targets. | ||
| * Implement an ALock class for managing advisory locks using the | ||
| threading.Lock APIs. [Feedback from Valentine Gogichashvili] | ||
| * Implement reference symbols. Allow libraries to define symbols that | ||
| are used to create queries that inherit the original symbol's type and | ||
| execution method. ``db.prepare(db.prepare(...).first())`` | ||
| * Fix handling of unix domain sockets by pg.open and driver.connect. | ||
| [Reported by twitter.com/rintavarustus] | ||
| * Fix typo/dropped parts of a raise LoadError in .lib. | ||
| [Reported by Vlad Pranskevichus] | ||
| * Fix db.tracer and pg_python's --pq-trace= | ||
| * Fix count return from .first() method. Failed to provide an empty | ||
| tuple for the rformats of the bind statement. | ||
| [Reported by dou dou] |
| Changes in v1.1 | ||
| =============== | ||
| 1.1.0 | ||
| ----- | ||
| * Remove two-phase commit interfaces per deprecation in v1.0. | ||
| For proper two phase commit use, a lock manager must be employed that | ||
| the implementation did nothing to accommodate for. | ||
| * Add support for unpacking anonymous records (Elvis) | ||
| * Support PostgreSQL 9.2 (Elvis) | ||
| * Python 3.3 Support (Elvis) | ||
| * Add column execution method. (jwp) | ||
| * Add one-shot statement interface. Connection.query.* (jwp) | ||
| * Modify the inet/cidr support by relying on the ipaddress module introduced in Python 3.3 (Google's ipaddr project) | ||
| The existing implementation relied on simple str() representation supported by the | ||
| socket module. Unfortunately, MS Windows' socket library does not appear to support the | ||
| necessary functionality, or Python's socket module does not expose it. ipaddress fixes | ||
| the problem. | ||
| .. note:: | ||
| The `ipaddress` module is now required for local inet and cidr. While it is | ||
| of "preliminary" status, the ipaddr project has been around for some time and | ||
| well supported. ipaddress appears to be the safest way forward for native | ||
| network types. |
| Changes in v1.2 | ||
| =============== | ||
| 1.2.2 released on 2020-09-22 | ||
| ---------------------------- | ||
| * Correct broken Connection.proc. | ||
| * Correct IPv6 IRI host oversight. | ||
| * Document an ambiguity case of DB-API 2.0 connection creation and the workaround(unix vs host/port). | ||
| * (Pending, active in 1.3) DB-API 2.0 connect() failures caused an undesired exception chain; ClientCannotConnect is now raised. | ||
| * Minor maintenance on tests and support modules. | ||
| 1.2.0 released on 2016-06-23 | ||
| ---------------------------- | ||
| * PostgreSQL 9.3 compatibility fixes (Elvis) | ||
| * Python 3.5 compatibility fixes (Elvis) | ||
| * Add support for JSONB type (Elvis) |
| Client Parameters | ||
| ***************** | ||
| .. warning:: **The interfaces dealing with optparse are subject to change in 1.0**. | ||
| There are various sources of parameters used by PostgreSQL client applications. | ||
| The `postgresql.clientparameters` module provides a means for collecting and | ||
| managing those parameters. | ||
| Connection creation interfaces in `postgresql.driver` are purposefully simple. | ||
| All parameters taken by those interfaces are keywords, and are taken | ||
| literally; if a parameter is not given, it will effectively be `None`. | ||
| libpq-based drivers tend differ as they inherit some default client parameters | ||
| from the environment. Doing this by default is undesirable as it can cause | ||
| trivial failures due to unexpected parameter inheritance. However, using these | ||
| parameters from the environment and other sources are simply expected in *some* | ||
| cases: `postgresql.open`, `postgresql.bin.pg_python`, and other high-level | ||
| utilities. The `postgresql.clientparameters` module provides a means to collect | ||
| them into one dictionary object for subsequent application to a connection | ||
| creation interface. | ||
| `postgresql.clientparameters` is primarily useful to script authors that want to | ||
| provide an interface consistent with PostgreSQL commands like ``psql``. | ||
| Collecting Parameters | ||
| ===================== | ||
| The primary entry points in `postgresql.clientparameters` are | ||
| `postgresql.clientparameters.collect` and | ||
| `postgresql.clientparameters.resolve_password`. | ||
| For most purposes, ``collect`` will suffice. By default, it will prompt for the | ||
| password if instructed to(``-W``). Therefore, ``resolve_password`` need not be | ||
| used in most cases:: | ||
| >>> import sys | ||
| >>> import postgresql.clientparameters as pg_param | ||
| >>> p = pg_param.DefaultParser() | ||
| >>> co, ca = p.parse_args(sys.argv[1:]) | ||
| >>> params = pg_param.collect(parsed_options = co) | ||
| The `postgresql.clientparameters` module is executable, so you can see the | ||
| results of the above snippet by:: | ||
| $ python -m postgresql.clientparameters -h localhost -U a_db_user -ssearch_path=public | ||
| {'host': 'localhost', | ||
| 'password': None, | ||
| 'port': 5432, | ||
| 'settings': {'search_path': 'public'}, | ||
| 'user': 'a_db_user'} | ||
| `postgresql.clientparameters.collect` | ||
| -------------------------------------- | ||
| Build a client parameter dictionary from the environment and parsed command | ||
| line options. The following is a list of keyword arguments that ``collect`` will | ||
| accept: | ||
| ``parsed_options`` | ||
| Options parsed by `postgresql.clientparameters.StandardParser` or | ||
| `postgresql.clientparameters.DefaultParser` instances. | ||
| ``no_defaults`` | ||
| When `True`, don't include defaults like ``pgpassfile`` and ``user``. | ||
| Defaults to `False`. | ||
| ``environ`` | ||
| Environment variables to extract client parameter variables from. | ||
| Defaults to `os.environ` and expects a `collections.Mapping` interface. | ||
| ``environ_prefix`` | ||
| Environment variable prefix to use. Defaults to "PG". This allows the | ||
| collection of non-standard environment variables whose keys are partially | ||
| consistent with the standard variants. e.g. "PG_SRC_USER", "PG_SRC_HOST", | ||
| etc. | ||
| ``default_pg_sysconfdir`` | ||
| The location of the pg_service.conf file. The ``PGSYSCONFDIR`` environment | ||
| variable will override this. When a default installation is present, | ||
| ``PGINSTALLATION``, it should be set to this. | ||
| ``pg_service_file`` | ||
| Explicit location of the service file. This will override the "sysconfdir" | ||
| based path. | ||
| ``prompt_title`` | ||
| Descriptive title to use if a password prompt is needed. `None` to disable | ||
| password resolution entirely. Setting this to `None` will also disable | ||
| pgpassfile lookups, so it is necessary that further processing occurs when | ||
| this is `None`. | ||
| ``parameters`` | ||
| Base client parameters to use. These are set after the *defaults* are | ||
| collected. (The defaults that can be disabled by ``no_defaults``). | ||
| If ``prompt_title`` is not set to `None`, it will prompt for the password when | ||
| instructed to do by the ``prompt_password`` key in the parameters:: | ||
| >>> import postgresql.clientparameters as pg_param | ||
| >>> p = pg_param.collect(prompt_title = 'my_prompt!', parameters = {'prompt_password':True}) | ||
| Password for my_prompt![pq://jwp@localhost:5432]: | ||
| >>> p | ||
| {'host': 'localhost', 'user': 'jwp', 'password': 'secret', 'port': 5432} | ||
| If `None`, it will leave the necessary password resolution information in the | ||
| parameters dictionary for ``resolve_password``:: | ||
| >>> p = pg_param.collect(prompt_title = None, parameters = {'prompt_password':True}) | ||
| >>> p | ||
| {'pgpassfile': '/Users/jwp/.pgpass', 'prompt_password': True, 'host': 'localhost', 'user': 'jwp', 'port': 5432} | ||
| Of course, ``'prompt_password'`` is normally specified when ``parsed_options`` | ||
| received a ``-W`` option from the command line:: | ||
| >>> op = pg_param.DefaultParser() | ||
| >>> co, ca = op.parse_args(['-W']) | ||
| >>> p = pg_param.collect(parsed_options = co) | ||
| >>> p=pg_param.collect(parsed_options = co) | ||
| Password for [pq://jwp@localhost:5432]: | ||
| >>> p | ||
| {'host': 'localhost', 'user': 'jwp', 'password': 'secret', 'port': 5432} | ||
| >>> | ||
| `postgresql.clientparameters.resolve_password` | ||
| ---------------------------------------------- | ||
| Resolve the password for the given client parameters dictionary returned by | ||
| ``collect``. By default, this function need not be used as ``collect`` will | ||
| resolve the password by default. `resolve_password` accepts the following | ||
| arguments: | ||
| ``parameters`` | ||
| First positional argument. Normalized client parameters dictionary to update | ||
| in-place with the resolved password. If the 'prompt_password' key is in | ||
| ``parameters``, it will prompt regardless(normally comes from ``-W``). | ||
| ``getpass`` | ||
| Function to call to prompt for the password. Defaults to `getpass.getpass`. | ||
| ``prompt_title`` | ||
| Additional title to use if a prompt is requested. This can also be specified | ||
| in the ``parameters`` as the ``prompt_title`` key. This *augments* the IRI | ||
| display on the prompt. Defaults to an empty string, ``''``. | ||
| The resolution process is effected by the contents of the given ``parameters``. | ||
| Notable keywords: | ||
| ``prompt_password`` | ||
| If present in the given parameters, the user will be prompted for the using | ||
| the given ``getpass`` function. This disables the password file lookup | ||
| process. | ||
| ``prompt_title`` | ||
| This states a default prompt title to use. If the ``prompt_title`` keyword | ||
| argument is given to ``resolve_password``, this will not be used. | ||
| ``pgpassfile`` | ||
| The PostgreSQL password file to lookup the password in. If the ``password`` | ||
| parameter is present, this will not be used. | ||
| When resolution occurs, the ``prompt_password``, ``prompt_title``, and | ||
| ``pgpassfile`` keys are *removed* from the given parameters dictionary:: | ||
| >>> p=pg_param.collect(prompt_title = None) | ||
| >>> p | ||
| {'pgpassfile': '/Users/jwp/.pgpass', 'host': 'localhost', 'user': 'jwp', 'port': 5432} | ||
| >>> pg_param.resolve_password(p) | ||
| >>> p | ||
| {'host': 'localhost', 'password': 'secret', 'user': 'jwp', 'port': 5432} | ||
| Defaults | ||
| ======== | ||
| The following is a list of default parameters provided by ``collect`` and the | ||
| sources of their values: | ||
| ==================== =================================================================== | ||
| Key Value | ||
| ==================== =================================================================== | ||
| ``'user'`` `getpass.getuser()` or ``'postgres'`` | ||
| ``'host'`` `postgresql.clientparameters.default_host` (``'localhost'``) | ||
| ``'port'`` `postgresql.clientparameters.default_port` (``5432``) | ||
| ``'pgpassfile'`` ``"$HOME/.pgpassfile"`` or ``[PGDATA]`` + ``'pgpass.conf'`` (Win32) | ||
| ``'sslcrtfile'`` ``[PGDATA]`` + ``'postgresql.crt'`` | ||
| ``'sslkeyfile'`` ``[PGDATA]`` + ``'postgresql.key'`` | ||
| ``'sslrootcrtfile'`` ``[PGDATA]`` + ``'root.crt'`` | ||
| ``'sslrootcrlfile'`` ``[PGDATA]`` + ``'root.crl'`` | ||
| ==================== =================================================================== | ||
| ``[PGDATA]`` referenced in the above table is a directory whose path is platform | ||
| dependent. On most systems, it is ``"$HOME/.postgresql"``, but on Windows based | ||
| systems it is ``"%APPDATA%\postgresql"`` | ||
| .. note:: | ||
| [PGDATA] is *not* an environment variable. | ||
| .. _pg_envvars: | ||
| PostgreSQL Environment Variables | ||
| ================================ | ||
| The following is a list of environment variables that will be collected by the | ||
| `postgresql.clientparameter.collect` function using "PG" as the | ||
| ``environ_prefix`` and the keyword that it will be mapped to: | ||
| ===================== ====================================== | ||
| Environment Variable Keyword | ||
| ===================== ====================================== | ||
| ``PGUSER`` ``'user'`` | ||
| ``PGDATABASE`` ``'database'`` | ||
| ``PGHOST`` ``'host'`` | ||
| ``PGPORT`` ``'port'`` | ||
| ``PGPASSWORD`` ``'password'`` | ||
| ``PGSSLMODE`` ``'sslmode'`` | ||
| ``PGSSLKEY`` ``'sslkey'`` | ||
| ``PGCONNECT_TIMEOUT`` ``'connect_timeout'`` | ||
| ``PGREALM`` ``'kerberos4_realm'`` | ||
| ``PGKRBSRVNAME`` ``'kerberos5_service'`` | ||
| ``PGPASSFILE`` ``'pgpassfile'`` | ||
| ``PGTZ`` ``'settings' = {'timezone': }`` | ||
| ``PGDATESTYLE`` ``'settings' = {'datestyle': }`` | ||
| ``PGCLIENTENCODING`` ``'settings' = {'client_encoding': }`` | ||
| ``PGGEQO`` ``'settings' = {'geqo': }`` | ||
| ===================== ====================================== | ||
| .. _pg_passfile: | ||
| PostgreSQL Password File | ||
| ======================== | ||
| The password file is a simple newline separated list of ``:`` separated fields. It | ||
| is located at ``$HOME/.pgpass`` for most systems and at | ||
| ``%APPDATA%\postgresql\pgpass.conf`` for Windows based systems. However, the | ||
| ``PGPASSFILE`` environment variable may be used to override that location. | ||
| The lines in the file must be in the following form:: | ||
| hostname:port:database:username:password | ||
| A single asterisk, ``*``, may be used to indicate that any value will match the | ||
| field. However, this only effects fields other than ``password``. | ||
| See http://www.postgresql.org/docs/current/static/libpq-pgpass.html for more | ||
| details. | ||
| Client parameters produced by ``collect`` that have not been processed | ||
| by ``resolve_password`` will include a ``'pgpassfile'`` key. This is the value | ||
| that ``resolve_password`` will use to locate the pgpassfile to interrogate if a | ||
| password key is not present and it is not instructed to prompt for a password. | ||
| .. warning:: | ||
| Connection creation interfaces will *not* resolve ``'pgpassfile'``, so it is | ||
| important that the parameters produced by ``collect()`` are properly processed | ||
| before an attempt is made to establish a connection. |
| .. _cluster_management: | ||
| ****************** | ||
| Cluster Management | ||
| ****************** | ||
| py-postgresql provides cluster management tools in order to give the user | ||
| fine-grained control over a PostgreSQL cluster and access to information about an | ||
| installation of PostgreSQL. | ||
| .. _installation: | ||
| Installations | ||
| ============= | ||
| `postgresql.installation.Installation` objects are primarily used to | ||
| access PostgreSQL installation information. Normally, they are created using a | ||
| dictionary constructed from the output of the pg_config_ executable:: | ||
| from postgresql.installation import Installation, pg_config_dictionary | ||
| pg_install = Installation(pg_config_dictionary('/usr/local/pgsql/bin/pg_config')) | ||
| The extraction of pg_config_ information is isolated from Installation | ||
| instantiation in order to allow Installations to be created from arbitrary | ||
| dictionaries. This can be useful in cases where the installation layout is | ||
| inconsistent with the standard PostgreSQL installation layout, or if a faux | ||
| Installation needs to be created for testing purposes. | ||
| Installation Interface Points | ||
| ----------------------------- | ||
| ``Installation(info)`` | ||
| Instantiate an Installation using the given information. Normally, this | ||
| information is extracted from a pg_config_ executable using | ||
| `postgresql.installation.pg_config_dictionary`:: | ||
| info = pg_config_dictionary('/usr/local/pgsql/bin/pg_config') | ||
| pg_install = Installation(info) | ||
| ``Installation.version`` | ||
| The installation's version string:: | ||
| pg_install.version | ||
| 'PostgreSQL 9.0devel' | ||
| ``Installation.version_info`` | ||
| A tuple containing the version's ``(major, minor, patch, state, level)``. | ||
| Where ``major``, ``minor``, ``patch``, and ``level`` are `int` objects, and | ||
| ``state`` is a `str` object:: | ||
| pg_install.version_info | ||
| (9, 0, 0, 'devel', 0) | ||
| ``Installation.ssl`` | ||
| A `bool` indicating whether or not the installation has SSL support. | ||
| ``Installation.configure_options`` | ||
| The options given to the ``configure`` script that built the installation. The | ||
| options are represented using a dictionary object whose keys are normalized | ||
| long option names, and whose values are the option's argument. If the option | ||
| takes no argument, `True` will be used as the value. | ||
| The normalization of the long option names consists of removing the preceding | ||
| dashes, lowering the string, and replacing any dashes with underscores. For | ||
| instance, ``--enable-debug`` will be ``enable_debug``:: | ||
| pg_install.configure_options | ||
| {'enable_debug': True, 'with_libxml': True, | ||
| 'enable_cassert': True, 'with_libedit_preferred': True, | ||
| 'prefix': '/src/build/pg90', 'with_openssl': True, | ||
| 'enable_integer_datetimes': True, 'enable_depend': True} | ||
| ``Installation.paths`` | ||
| The paths of the installation as a dictionary where the keys are the path | ||
| identifiers and the values are the absolute file system paths. For instance, | ||
| ``'bindir'`` is associated with ``$PREFIX/bin``, ``'libdir'`` is associated | ||
| with ``$PREFIX/lib``, etc. The paths included in this dictionary are | ||
| listed on the class' attributes: `Installation.pg_directories` and | ||
| `Installation.pg_executables`. | ||
| The keys that point to installation directories are: ``bindir``, ``docdir``, | ||
| ``includedir``, ``pkgincludedir``, ``includedir_server``, ``libdir``, | ||
| ``pkglibdir``, ``localedir``, ``mandir``, ``sharedir``, and ``sysconfdir``. | ||
| The keys that point to installation executables are: ``pg_config``, ``psql``, | ||
| ``initdb``, ``pg_resetxlog``, ``pg_controldata``, ``clusterdb``, ``pg_ctl``, | ||
| ``pg_dump``, ``pg_dumpall``, ``postgres``, ``postmaster``, ``reindexdb``, | ||
| ``vacuumdb``, ``ipcclean``, ``createdb``, ``ecpg``, ``createuser``, | ||
| ``createlang``, ``droplang``, ``dropuser``, and ``pg_restore``. | ||
| .. note:: If the executable does not exist, the value will be `None` instead | ||
| of an absoluate path. | ||
| To get the path to the psql_ executable:: | ||
| from postgresql.installation import Installation | ||
| pg_install = Installation('/usr/local/pgsql/bin/pg_config') | ||
| psql_path = pg_install.paths['psql'] | ||
| Clusters | ||
| ======== | ||
| `postgresql.cluster.Cluster` is the class used to manage a PostgreSQL | ||
| cluster--a data directory created by initdb_. A Cluster represents a data | ||
| directory with respect to a given installation of PostgreSQL, so | ||
| creating a `postgresql.cluster.Cluster` object requires a | ||
| `postgresql.installation.Installation`, and a | ||
| file system path to the data directory. | ||
| In part, a `postgresql.cluster.Cluster` is the Python programmer's variant of | ||
| the pg_ctl_ command. However, it goes beyond the basic process control | ||
| functionality and extends into initialization and configuration as well. | ||
| A Cluster manages the server process using the `subprocess` module and | ||
| signals. The `subprocess.Popen` object, ``Cluster.daemon_process``, is | ||
| retained when the Cluster starts the server process itself. This gives | ||
| the Cluster access to the result code of server process when it exits, and the | ||
| ability to redirect stderr and stdout to a parameterized file object using | ||
| subprocess features. | ||
| Despite its use of `subprocess`, Clusters can control a server process | ||
| that was *not* started by the Cluster's ``start`` method. | ||
| Initializing Clusters | ||
| --------------------- | ||
| `postgresql.cluster.Cluster` provides a method for initializing a | ||
| `Cluster`'s data directory, ``init``. This method provides a Python interface to | ||
| the PostgreSQL initdb_ command. | ||
| ``init`` is a regular method and accepts a few keyword parameters. Normally, | ||
| parameters are directly mapped to initdb_ command options. However, ``password`` | ||
| makes use of initdb's capability to read the superuser's password from a file. | ||
| To do this, a temporary file is allocated internally by the method:: | ||
| from postgresql.installation import Installation, pg_config_dictionary | ||
| from postgresql.cluster import Cluster | ||
| pg_install = Installation(pg_config_dictionary('/usr/local/pgsql/bin/pg_config')) | ||
| pg_cluster = Cluster(pg_install, 'pg_data') | ||
| pg_cluster.init(user = 'pg', password = 'secret', encoding = 'utf-8') | ||
| The init method will block until the initdb command is complete. Once | ||
| initialized, the Cluster may be configured. | ||
| Configuring Clusters | ||
| -------------------- | ||
| A Cluster's `configuration file`_ can be manipulated using the | ||
| `Cluster.settings` mapping. The mapping's methods will always access the | ||
| configuration file, so it may be desirable to cache repeat reads. Also, if | ||
| multiple settings are being applied, using the ``update()`` method may be | ||
| important to avoid writing the entire file multiple times:: | ||
| pg_cluster.settings.update({'listen_addresses' : 'localhost', 'port' : '6543'}) | ||
| Similarly, to avoid opening and reading the entire file multiple times, | ||
| `Cluster.settings.getset` should be used to retrieve multiple settings:: | ||
| d = pg_cluster.settings.getset(set(('listen_addresses', 'port'))) | ||
| d | ||
| {'listen_addresses' : 'localhost', 'port' : '6543'} | ||
| Values contained in ``settings`` are always Python strings:: | ||
| assert pg_cluster.settings['max_connections'].__class__ is str | ||
| The ``postgresql.conf`` file is only one part of the server configuration. | ||
| Structured access and manipulation of the pg_hba_ file is not | ||
| supported. Clusters only provide the file path to the pg_hba_ file:: | ||
| hba = open(pg_cluster.hba_file) | ||
| If the configuration of the Cluster is altered while the server process is | ||
| running, it may be necessary to signal the process that configuration changes | ||
| have been made. This signal can be sent using the ``Cluster.reload()`` method. | ||
| ``Cluster.reload()`` will send a SIGHUP signal to the server process. However, | ||
| not all changes to configuration settings can go into effect after calling | ||
| ``Cluster.reload()``. In those cases, the server process will need to be | ||
| shutdown and started again. | ||
| Controlling Clusters | ||
| -------------------- | ||
| The server process of a Cluster object can be controlled with the ``start()``, | ||
| ``stop()``, ``shutdown()``, ``kill()``, and ``restart()`` methods. | ||
| These methods start the server process, signal the server process, or, in the | ||
| case of restart, a combination of the two. | ||
| When a Cluster starts the server process, it's ran as a subprocess. Therefore, | ||
| if the current process exits, the server process will exit as well. ``start()`` | ||
| does *not* automatically daemonize the server process. | ||
| .. note:: Under Microsoft Windows, above does not hold true. The server process | ||
| will continue running despite the exit of the parent process. | ||
| To terminate a server process, one of these three methods should be called: | ||
| ``stop``, ``shutdown``, or ``kill``. ``stop`` is a graceful shutdown and will | ||
| *wait for all clients to disconnect* before shutting down. ``shutdown`` will | ||
| close any open connections and safely shutdown the server process. | ||
| ``kill`` will immediately terminate the server process leading to recovery upon | ||
| starting the server process again. | ||
| .. note:: Using ``kill`` may cause shared memory to be leaked. | ||
| Normally, `Cluster.shutdown` is the appropriate way to terminate a server | ||
| process. | ||
| Cluster Interface Points | ||
| ------------------------ | ||
| Methods and properties available on `postgresql.cluster.Cluster` instances: | ||
| ``Cluster(installation, data_directory)`` | ||
| Create a `postgresql.cluster.Cluster` object for the specified | ||
| `postgresql.installation.Installation`, and ``data_directory``. | ||
| The ``data_directory`` must be an absoluate file system path. The directory | ||
| does *not* need to exist. The ``init()`` method may later be used to create | ||
| the cluster. | ||
| ``Cluster.installation`` | ||
| The Cluster's `postgresql.installation.Installation` instance. | ||
| ``Cluster.data_directory`` | ||
| The absolute path to the PostgreSQL data directory. | ||
| This directory may not exist. | ||
| ``Cluster.init([encoding = None[, user = None[, password = None]]])`` | ||
| Run the `initdb`_ executable of the configured installation to initialize the | ||
| cluster at the configured data directory, `Cluster.data_directory`. | ||
| ``encoding`` is mapped to ``-E``, the default database encoding. By default, | ||
| the encoding is determined from the environment's locale. | ||
| ``user`` is mapped to ``-U``, the database superuser name. By default, the | ||
| current user's name. | ||
| ``password`` is ultimately mapped to ``--pwfile``. The argument given to the | ||
| long option is actually a path to the temporary file that holds the given | ||
| password. | ||
| Raises `postgresql.cluster.InitDBError` when initdb_ returns a non-zero result | ||
| code. | ||
| Raises `postgresql.cluster.ClusterInitializationError` when there is no | ||
| initdb_ in the Installation. | ||
| ``Cluster.initialized()`` | ||
| Whether or not the data directory exists, *and* if it looks like a PostgreSQL | ||
| data directory. Meaning, the directory must contain a ``postgresql.conf`` file | ||
| and a ``base`` directory. | ||
| ``Cluster.drop()`` | ||
| Shutdown the Cluster's server process and completely remove the | ||
| `Cluster.data_directory` from the file system. | ||
| ``Cluster.pid()`` | ||
| The server's process identifier as a Python `int`. `None` if there is no | ||
| server process running. | ||
| This is a method rather than a property as it may read the PID from a file | ||
| in cases where the server process was not started by the Cluster. | ||
| ``Cluster.start([logfile = None[, settings = None]])`` | ||
| Start the PostgreSQL server process for the Cluster if it is not | ||
| already running. This will execute postgres_ as a subprocess. | ||
| If ``logfile``, an opened and writable file object, is given, stderr and | ||
| stdout will be redirected to that file. By default, both stderr and stdout are | ||
| closed. | ||
| If ``settings`` is given, the mapping or sequence of pairs will be used as | ||
| long options to the subprocess. For each item, ``--{key}={value}`` will be | ||
| given as an argument to the subprocess. | ||
| ``Cluster.running()`` | ||
| Whether or not the cluster's server process is running. Returns `True` or | ||
| `False`. Even if `True` is returned, it does *not* mean that the server | ||
| process is ready to accept connections. | ||
| ``Cluster.ready_for_connections()`` | ||
| Whether or not the Cluster is ready to accept connections. Usually called | ||
| after `Cluster.start`. | ||
| Returns `True` when the Cluster can accept connections, `False` when it | ||
| cannot, and `None` if the Cluster's server process is not running at all. | ||
| ``Cluster.wait_until_started([timeout = 10[, delay = 0.05]])`` | ||
| Blocks the process until the cluster is identified as being ready for | ||
| connections. Usually called after ``Cluster.start()``. | ||
| Raises `postgresql.cluster.ClusterNotRunningError` if the server process is | ||
| not running at all. | ||
| Raises `postgresql.cluster.ClusterTimeoutError` if | ||
| `Cluster.ready_for_connections()` does not return `True` within the given | ||
| `timeout` period. | ||
| Raises `postgresql.cluster.ClusterStartupError` if the server process | ||
| terminates while polling for readiness. | ||
| ``timeout`` and ``delay`` are both in seconds. Where ``timeout`` is the | ||
| maximum time to wait for the Cluster to be ready for connections, and | ||
| ``delay`` is the time to sleep between calls to | ||
| `Cluster.ready_for_connections()`. | ||
| ``Cluster.stop()`` | ||
| Signal the cluster to shutdown when possible. The *server* will wait for all | ||
| clients to disconnect before shutting down. | ||
| ``Cluster.shutdown()`` | ||
| Signal the cluster to shutdown immediately. Any open client connections will | ||
| be closed. | ||
| ``Cluster.kill()`` | ||
| Signal the absolute destruction of the server process(SIGKILL). | ||
| *This will require recovery when the cluster is started again.* | ||
| *Shared memory may be leaked.* | ||
| ``Cluster.wait_until_stopped([timeout = 10[, delay = 0.05]])`` | ||
| Blocks the process until the cluster is identified as being shutdown. Usually | ||
| called after `Cluster.stop` or `Cluster.shutdown`. | ||
| Raises `postgresql.cluster.ClusterTimeoutError` if | ||
| `Cluster.ready_for_connections` does not return `None` within the given | ||
| `timeout` period. | ||
| ``Cluster.reload()`` | ||
| Signal the server that it should reload its configuration files(SIGHUP). | ||
| Usually called after manipulating `Cluster.settings` or modifying the | ||
| contents of `Cluster.hba_file`. | ||
| ``Cluster.restart([logfile = None[, settings = None[, timeout = 10]]])`` | ||
| Stop the server process, wait until it is stopped, start the server | ||
| process, and wait until it has started. | ||
| .. note:: This calls ``Cluster.stop()``, so it will wait until clients | ||
| disconnect before starting up again. | ||
| The ``logfile`` and ``settings`` parameters will be given to `Cluster.start`. | ||
| ``timeout`` will be given to `Cluster.wait_until_stopped` and | ||
| `Cluster.wait_until_started`. | ||
| ``Cluster.settings`` | ||
| A `collections.Mapping` interface to the ``postgresql.conf`` file of the | ||
| cluster. | ||
| A notable extension to the mapping interface is the ``getset`` method. This | ||
| method will return a dictionary object containing the settings whose names | ||
| were contained in the `set` object given to the method. | ||
| This method should be used when multiple settings need to be retrieved from | ||
| the configuration file. | ||
| ``Cluster.hba_file`` | ||
| The path to the cluster's pg_hba_ file. This property respects the HBA file | ||
| location setting in ``postgresql.conf``. Usually, ``$PGDATA/pg_hba.conf``. | ||
| ``Cluster.daemon_path`` | ||
| The path to the executable to use to start the server process. | ||
| ``Cluster.daemon_process`` | ||
| The `subprocess.Popen` instance of the server process. `None` if the server | ||
| process was not started or was not started using the Cluster object. | ||
| .. _pg_hba: http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html | ||
| .. _pg_config: http://www.postgresql.org/docs/current/static/app-pgconfig.html | ||
| .. _initdb: http://www.postgresql.org/docs/current/static/app-initdb.html | ||
| .. _psql: http://www.postgresql.org/docs/current/static/app-psql.html | ||
| .. _postgres: http://www.postgresql.org/docs/current/static/app-postgres.html | ||
| .. _pg_ctl: http://www.postgresql.org/docs/current/static/app-pg-ctl.html | ||
| .. _configuration file: http://www.postgresql.org/docs/current/static/runtime-config.html |
| .. _pg_copyman: | ||
| *************** | ||
| Copy Management | ||
| *************** | ||
| The `postgresql.copyman` module provides a way to quickly move COPY data coming | ||
| from one connection to many connections. Alternatively, it can be sourced | ||
| by arbitrary iterators and target arbitrary callables. | ||
| Statement execution methods offer a way for running COPY operations | ||
| with iterators, but the cost of allocating objects for each row is too | ||
| significant for transferring gigabytes of COPY data from one connection to | ||
| another. The interfaces available on statement objects are primarily intended to | ||
| be used when transferring COPY data to and from arbitrary Python | ||
| objects. | ||
| Direct connection-to-connection COPY operations can be performed using the | ||
| high-level `postgresql.copyman.transfer` function:: | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> total_rows, total_bytes = copyman.transfer(send_stmt, receive_stmt) | ||
| However, if more control is needed, the `postgresql.copyman.CopyManager` class | ||
| should be used directly. | ||
| Copy Managers | ||
| ============= | ||
| The `postgresql.copyman.CopyManager` class manages the Producer and the | ||
| Receivers involved in a COPY operation. Normally, | ||
| `postgresql.copyman.StatementProducer` and | ||
| `postgresql.copyman.StatementReceiver` instances. Naturally, a Producer is the | ||
| object that produces the COPY data to be given to the Manager's Receivers. | ||
| Using a Manager directly means that there is a need for more control over | ||
| the operation. The Manager is both a context manager and an iterator. The | ||
| context manager interfaces handle initialization and finalization of the COPY | ||
| state, and the iterator provides an event loop emitting information about the | ||
| amount of COPY data transferred this cycle. Normal usage takes the form:: | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> producer = copyman.StatementProducer(send_stmt) | ||
| >>> receiver = copyman.StatementReceiver(receive_stmt) | ||
| >>> | ||
| >>> with source.xact(), destination.xact(): | ||
| ... with copyman.CopyManager(producer, receiver) as copy: | ||
| ... for num_messages, num_bytes in copy: | ||
| ... update_rate(num_bytes) | ||
| As an alternative to a for-loop inside a with-statement block, the `run` method | ||
| can be called to perform the operation:: | ||
| >>> with source.xact(), destination.xact(): | ||
| ... copyman.CopyManager(producer, receiver).run() | ||
| However, there is little benefit beyond using the high-level | ||
| `postgresql.copyman.transfer` function. | ||
| Manager Interface Points | ||
| ------------------------ | ||
| Primarily, the `postgresql.copyman.CopyManager` provides a context manager and | ||
| an iterator for controlling the COPY operation. | ||
| ``CopyManager.run()`` | ||
| Perform the entire COPY operation. | ||
| ``CopyManager.__enter__()`` | ||
| Start the COPY operation. Connections taking part in the COPY should **not** | ||
| be used until ``__exit__`` is ran. | ||
| ``CopyManager.__exit__(typ, val, tb)`` | ||
| Finish the COPY operation. Fails in the case of an incomplete | ||
| COPY, or an untrapped exception. Either returns `None` or raises the generalized | ||
| exception, `postgresql.copyman.CopyFail`. | ||
| ``CopyManager.__iter__()`` | ||
| Returns the CopyManager instance. | ||
| ``CopyManager.__next__()`` | ||
| Transfer the next chunk of COPY data to the receivers. Yields a tuple | ||
| consisting of the number of messages and bytes transferred, | ||
| ``(num_messages, num_bytes)``. Raises `StopIteration` when complete. | ||
| Raises `postgresql.copyman.ReceiverFault` when a Receiver raises an | ||
| exception. | ||
| Raises `postgresql.copyman.ProducerFault` when the Producer raises an | ||
| exception. The original exception is available via the exception's | ||
| ``__context__`` attribute. | ||
| ``CopyManager.reconcile(faulted_receiver)`` | ||
| Reconcile a faulted receiver. When a receiver faults, it will no longer | ||
| be in the set of Receivers. This method is used to signal to the manager that the | ||
| problem has been corrected, and the receiver is again ready to receive. | ||
| ``CopyManager.receivers`` | ||
| The `builtins.set` of Receivers involved in the COPY operation. | ||
| ``CopyManager.producer`` | ||
| The Producer emitting the data to be given to the Receivers. | ||
| Faults | ||
| ====== | ||
| The CopyManager generalizes any exceptions that occur during transfer. While | ||
| inside the context manager, `postgresql.copyman.Fault` may be raised if a | ||
| Receiver or a Producer raises an exception. A `postgresql.copyman.ProducerFault` | ||
| in the case of the Producer, and `postgresql.copyman.ReceiverFault` in the case | ||
| of the Receivers. | ||
| .. note:: | ||
| Faults are only raised by `postgresql.copyman.CopyManager.__next__`. The | ||
| ``run()`` method will only raise `postgresql.copyman.CopyFail`. | ||
| Receiver Faults | ||
| --------------- | ||
| The Manager assumes the Fault is fatal to a Receiver, and immediately removes | ||
| it from the set of target receivers. Additionally, if the Fault exception goes | ||
| untrapped, the copy will ultimately fail. | ||
| The Fault exception references the Manager that raised the exception, and the | ||
| actual exceptions that occurred associated with the Receiver that caused them. | ||
| In order to identify the exception that caused a Fault, the ``faults`` attribute | ||
| on the `postgresql.copyman.ReceiverFault` must be referenced:: | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> producer = copyman.StatementProducer(send_stmt) | ||
| >>> receiver = copyman.StatementReceiver(receive_stmt) | ||
| >>> | ||
| >>> with source.xact(), destination.xact(): | ||
| ... with copyman.CopyManager(producer, receiver) as copy: | ||
| ... while copy.receivers: | ||
| ... try: | ||
| ... for num_messages, num_bytes in copy: | ||
| ... update_rate(num_bytes) | ||
| ... break | ||
| ... except copyman.ReceiverFault as cf: | ||
| ... # Access the original exception using the receiver as the key. | ||
| ... original_exception = cf.faults[receiver] | ||
| ... if unknown_failure(original_exception): | ||
| ... ... | ||
| ... raise | ||
| ReceiverFault Properties | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| The following attributes exist on `postgresql.copyman.ReceiverFault` instances: | ||
| ``ReceiverFault.manager`` | ||
| The subject `postgresql.copyman.CopyManager` instance. | ||
| ``ReceiverFault.faults`` | ||
| A dictionary mapping the Receiver to the exception raised by that Receiver. | ||
| Reconciliation | ||
| ~~~~~~~~~~~~~~ | ||
| When a `postgresql.copyman.ReceiverFault` is raised, the Manager immediately | ||
| removes the Receiver so that the COPY operation can continue. Continuation of | ||
| the COPY can occur by trapping the exception and continuing the iteration of the | ||
| Manager. However, if the fault is recoverable, the | ||
| `postgresql.copyman.CopyManager.reconcile` method must be used to reintroduce the | ||
| Receiver into the Manager's set. Faults must be trapped from within the | ||
| Manager's context:: | ||
| >>> import socket | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> producer = copyman.StatementProducer(send_stmt) | ||
| >>> receiver = copyman.StatementReceiver(receive_stmt) | ||
| >>> | ||
| >>> with source.xact(), destination.xact(): | ||
| ... with copyman.CopyManager(producer, receiver) as copy: | ||
| ... while copy.receivers: | ||
| ... try: | ||
| ... for num_messages, num_bytes in copy: | ||
| ... update_rate(num_bytes) | ||
| ... except copyman.ReceiverFault as cf: | ||
| ... if isinstance(cf.faults[receiver], socket.timeout): | ||
| ... copy.reconcile(receiver) | ||
| ... else: | ||
| ... raise | ||
| Recovering from Faults does add significant complexity to a COPY operation, | ||
| so, often, it's best to avoid conditions in which reconciliable Faults may | ||
| occur. | ||
| Producer Faults | ||
| --------------- | ||
| Producer faults are normally fatal to the COPY operation and should rarely be | ||
| trapped. However, the Manager makes no state changes when a Producer faults, | ||
| so, unlike Receiver Faults, no reconciliation process is necessary; rather, | ||
| if it's safe to continue, the Manager's iterator should continue to be | ||
| processed. | ||
| ProducerFault Properties | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| The following attributes exist on `postgresql.copyman.ProducerFault` instances: | ||
| ``ReceiverFault.manager`` | ||
| The subject `postgresql.copyman.CopyManager`. | ||
| ``ReceiverFault.__context__`` | ||
| The original exception raised by the Producer. | ||
| Failures | ||
| ======== | ||
| When a COPY operation is aborted, either by an exception or by the iterator | ||
| being broken, a `postgresql.copyman.CopyFail` exception will be raised by the | ||
| Manager's ``__exit__()`` method. The `postgresql.copyman.CopyFail` exception | ||
| offers to record any exceptions that occur during the exit of the context | ||
| managers of the Producer and the Receivers. | ||
| CopyFail Properties | ||
| ------------------- | ||
| The following properties exist on `postgresql.copyman.CopyFail` exceptions: | ||
| ``CopyFail.manager`` | ||
| The Manager whose COPY operation failed. | ||
| ``CopyFail.receiver_faults`` | ||
| A dictionary mapping a `postgresql.copyman.Receiver` to the exception raised | ||
| by that Receiver's ``__exit__``. `None` if no exceptions were raised by the | ||
| Receivers. | ||
| ``CopyFail.producer_fault`` | ||
| The exception Raised by the `postgresql.copyman.Producer`. `None` if none. | ||
| Producers | ||
| ========= | ||
| The following Producers are available: | ||
| ``postgresql.copyman.StatementProducer(postgresql.api.Statement)`` | ||
| Given a Statement producing COPY data, construct a Producer. | ||
| ``postgresql.copyman.IteratorProducer(collections.Iterator)`` | ||
| Given an Iterator producing *chunks* of COPY lines, construct a Producer to | ||
| manage the data coming from the iterator. | ||
| Receivers | ||
| ========= | ||
| ``postgresql.copyman.StatementReceiver(postgresql.api.Statement)`` | ||
| Given a Statement producing COPY data, construct a Producer. | ||
| ``postgresql.copyman.CallReceiver(callable)`` | ||
| Given a callable, construct a Receiver that will transmit COPY data in chunks | ||
| of lines. That is, the callable will be given a list of COPY lines for each | ||
| transfer cycle. | ||
| Terminology | ||
| =========== | ||
| The following terms are regularly used to describe the implementation and | ||
| processes of the `postgresql.copyman` module: | ||
| Manager | ||
| The object used to manage data coming from a Producer and being given to the | ||
| Receivers. It also manages the necessary initialization and finalization steps | ||
| required by those factors. | ||
| Producer | ||
| The object used to produce the COPY data to be given to the Receivers. The | ||
| source. | ||
| Receiver | ||
| An object that consumes COPY data. A target. | ||
| Fault | ||
| Specifically, `postgresql.copyman.Fault` exceptions. A Fault is raised | ||
| when a Receiver or a Producer raises an exception during the COPY operation. | ||
| Reconciliation | ||
| Generally, the steps performed by the "reconcile" method on | ||
| `postgresql.copyman.CopyManager` instances. More precisely, the | ||
| necessary steps for a Receiver's reintroduction into the COPY operation after | ||
| a Fault. | ||
| Failed Copy | ||
| A failed copy is an aborted COPY operation. This occurs in situations of | ||
| untrapped exceptions or an incomplete COPY. Specifically, the COPY will be | ||
| noted as failed in cases where the Manager's iterator is *not* ran until | ||
| exhaustion. | ||
| Realignment | ||
| The process of providing compensating data to the Receivers so that the | ||
| connection will be on a message boundary. Occurs when the COPY operation | ||
| is aborted. |
Sorry, the diff of this file is too big to display
| Gotchas | ||
| ======= | ||
| It is recognized that decisions were made that may not always be ideal for a | ||
| given user. In order to highlight those potential issues and hopefully bring | ||
| some sense into a confusing situation, this document was drawn. | ||
| Non-English Locales | ||
| ------------------- | ||
| Many non-english locales are not supported due to the localization of the severity field | ||
| in messages and errors sent to the client. Internally, py-postgresql uses this to allow | ||
| client side filtering of messages and to identify FATAL connection errors that allow the | ||
| client to recognize that it should be expecting the connection to terminate. | ||
| Thread Safety | ||
| ------------- | ||
| py-postgresql connection operations are not thread safe. | ||
| `client_encoding` setting should be altered carefully | ||
| ----------------------------------------------------- | ||
| `postgresql.driver`'s streaming cursor implementation reads a fixed set of rows | ||
| when it queries the server for more. In order to optimize some situations, the | ||
| driver will send a request for more data, but makes no attempt to wait and | ||
| process the data as it is not yet needed. When the user comes back to read more | ||
| data from the cursor, it will then look at this new data. The problem being, if | ||
| `client_encoding` was switched, it may use the wrong codec to transform the | ||
| wire data into higher level Python objects(str). | ||
| To avoid this problem from ever happening, set the `client_encoding` early. | ||
| Furthermore, it is probably best to never change the `client_encoding` as the | ||
| driver automatically makes the necessary transformation to Python strings. | ||
| The user and password is correct, but it does not work when using `postgresql.driver` | ||
| ------------------------------------------------------------------------------------- | ||
| This issue likely comes from the possibility that the information sent to the | ||
| server early in the negotiation phase may not be in an encoding that is | ||
| consistent with the server's encoding. | ||
| One problem is that PostgreSQL does not provide the client with the server | ||
| encoding early enough in the negotiation phase, and, therefore, is unable to | ||
| process the password data in a way that is consistent with the server's | ||
| expectations. | ||
| Another problem is that PostgreSQL takes much of the data in the startup message | ||
| as-is, so a decision about the best way to encode parameters is difficult. | ||
| The easy way to avoid *most* issues with this problem is to initialize the | ||
| database in the `utf-8` encoding. The driver defaults the expected server | ||
| encoding to `utf-8`. However, this can be overridden by creating the `Connector` | ||
| with a `server_encoding` parameter. Setting `server_encoding` to the proper | ||
| value of the target server will allow the driver to properly encode *some* of | ||
| the parameters. Also, any GUC parameters passed via the `settings` parameter | ||
| should use typed objects when possible to hint that the server encoding should | ||
| not be used on that parameter(`bytes`, for instance). | ||
| Backslash characters are being treated literally | ||
| ------------------------------------------------ | ||
| The driver enables standard compliant strings. Stop using non-standard features. | ||
| ;) | ||
| If support for non-standard strings was provided it would require to the | ||
| driver to provide subjective quote interfaces(eg, db.quote_literal). Doing so is | ||
| not desirable as it introduces difficulties for the driver *and* the user. | ||
| Types without binary support in the driver are unsupported in arrays and records | ||
| -------------------------------------------------------------------------------- | ||
| When an array or composite type is identified, `postgresql.protocol.typio` | ||
| ultimately chooses the binary format for the transfer of the column or | ||
| parameter. When this is done, PostgreSQL will pack or expect *all* the values | ||
| in binary format as well. If that binary format is not supported and the type | ||
| is not an string, it will fail to unpack the row or pack the appropriate data for | ||
| the element or attribute. | ||
| In most cases issues related to this can be avoided with explicit casts to text. | ||
| NOTICEs, WARNINGs, and other messages are too verbose | ||
| ----------------------------------------------------- | ||
| For many situations, the information provided with database messages is | ||
| far too verbose. However, considering that py-postgresql is a programmer's | ||
| library, the default of high verbosity is taken with the express purpose of | ||
| allowing the programmer to "adjust the volume" until appropriate. | ||
| By default, py-postgresql adjusts the ``client_min_messages`` to only emit | ||
| messages at the WARNING level or higher--ERRORs, FATALs, and PANICs. | ||
| This reduces the number of messages generated by most connections dramatically. | ||
| If further customization is needed, the :ref:`db_messages` section has | ||
| information on overriding the default action taken with database messages. | ||
| Strange TypeError using load_rows() or load_chunks() | ||
| ---------------------------------------------------- | ||
| When a prepared statement is directly executed using ``__call__()``, it can easily | ||
| validate that the appropriate number of parameters are given to the function. | ||
| When ``load_rows()`` or ``load_chunks()`` is used, any tuple in the | ||
| the entire sequence can cause this TypeError during the loading process:: | ||
| TypeError: inconsistent items, N processors and M items in row | ||
| This exception is raised by a generic processing routine whose functionality | ||
| is abstract in nature, so the message is abstract as well. It essentially means | ||
| that a tuple in the sequence given to the loading method had too many or too few | ||
| items. |
| py-postgresql | ||
| ============= | ||
| py-postgresql is a project dedicated to improving the Python client interfaces to PostgreSQL. | ||
| At its core, py-postgresql provides a PG-API, `postgresql.api`, and | ||
| DB-API 2.0 interface for using a PostgreSQL database. | ||
| Contents | ||
| -------- | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
| admin | ||
| driver | ||
| copyman | ||
| notifyman | ||
| alock | ||
| cluster | ||
| lib | ||
| clientparameters | ||
| gotchas | ||
| Reference | ||
| --------- | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
| bin | ||
| reference | ||
| Changes | ||
| ------- | ||
| .. toctree:: | ||
| :maxdepth: 1 | ||
| changes-v1.2 | ||
| changes-v1.1 | ||
| changes-v1.0 | ||
| Sample Code | ||
| ----------- | ||
| Using `postgresql.driver`:: | ||
| >>> import postgresql | ||
| >>> db = postgresql.open("pq://user:password@host/name_of_database") | ||
| >>> db.execute("CREATE TABLE emp (emp_name text PRIMARY KEY, emp_salary numeric)") | ||
| >>> | ||
| >>> # Create the statements. | ||
| >>> make_emp = db.prepare("INSERT INTO emp VALUES ($1, $2)") | ||
| >>> raise_emp = db.prepare("UPDATE emp SET emp_salary = emp_salary + $2 WHERE emp_name = $1") | ||
| >>> get_emp_with_salary_lt = db.prepare("SELECT emp_name FROM emp WHERE emp_salay < $1") | ||
| >>> | ||
| >>> # Create some employees, but do it in a transaction--all or nothing. | ||
| >>> with db.xact(): | ||
| ... make_emp("John Doe", "150,000") | ||
| ... make_emp("Jane Doe", "150,000") | ||
| ... make_emp("Andrew Doe", "55,000") | ||
| ... make_emp("Susan Doe", "60,000") | ||
| >>> | ||
| >>> # Give some raises | ||
| >>> with db.xact(): | ||
| ... for row in get_emp_with_salary_lt("125,000"): | ||
| ... print(row["emp_name"]) | ||
| ... raise_emp(row["emp_name"], "10,000") | ||
| Of course, if DB-API 2.0 is desired, the module is located at | ||
| `postgresql.driver.dbapi20`. DB-API extends PG-API, so the features | ||
| illustrated above are available on DB-API connections. | ||
| See :ref:`db_interface` for more information. |
| Categories and Libraries | ||
| ************************ | ||
| This chapter discusses the usage and implementation of connection categories and | ||
| libraries. Originally these features were written with general purpose use in mind; | ||
| however, it is recommended that these features **not** be used in applications. | ||
| They are primarily used internally by the the driver and may be removed in the future. | ||
| Libraries are a collection of SQL statements that can be bound to a | ||
| connection. Libraries are *normally* bound directly to the connection object as | ||
| an attribute using a name specified by the library. | ||
| Libraries provide a common way for SQL statements to be managed outside of the | ||
| code that uses them. When using ILFs, this increases the portability of the SQL | ||
| by keeping the statements isolated from the Python code in an accessible format | ||
| that can be easily used by other languages or systems --- An ILF parser can be | ||
| implemented within a few dozen lines using basic text tools. | ||
| SQL statements defined by a Library are identified by their Symbol. These | ||
| symbols are named and annotated in order to allow the user to define how a | ||
| statement is to be used. The user may state the default execution method of | ||
| the statement object, or whether the symbol is to be preloaded at bind | ||
| time--these properties are Symbol Annotations. | ||
| The purpose of libraries are to provide a means to manage statements on | ||
| disk and at runtime. ILFs provide a means to reference a collection | ||
| of statements on disk, and, when loaded, the symbol bindings provides means to | ||
| reference a statement already prepared for use on a given connection. | ||
| The `postgresql.lib` package-module provides fundamental classes for supporting | ||
| categories and libraries. | ||
| Writing Libraries | ||
| ================= | ||
| ILF files are the recommended way to build a library. These files use the | ||
| naming convention "lib{NAME}.sql". The prefix and suffix are used describe the | ||
| purpose of the file and to provide a hint to editors that SQL highlighting | ||
| should be used. The format of an ILF takes the form:: | ||
| <Preface> | ||
| [name:type:method] | ||
| <statement> | ||
| ... | ||
| Where multiple symbols may be defined. The Preface that comes before the first | ||
| symbol is an arbitrary block of text that should be used to describe the library. | ||
| This block is free-form, and should be considered a good place for some | ||
| general documentation. | ||
| Symbols are named and described using the contents of section markers: | ||
| ``('[' ... ']')``. Section markers have three components: the symbol name, | ||
| the symbol type and the symbol method. Each of these components are separated | ||
| using a single colon, ``:``. All components are optional except the Symbol name. | ||
| For example:: | ||
| [get_user_info] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| [get_user_info_v2::] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| In the above example, ``get_user_info`` and ``get_user_info_v2`` are identical. | ||
| Empty components indicate the default effect. | ||
| The second component in the section identifier is the symbol type. All Symbol | ||
| types are listed in `Symbol Types`_. This can be | ||
| used to specify what the section's contents are or when to bind the | ||
| symbol:: | ||
| [get_user_info:preload] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| This provides the Binding with the knowledge that the statement should be | ||
| prepared when the Library is bound. Therefore, when this Symbol's statement | ||
| is used for the first time, it will have already been prepared. | ||
| Another type is the ``const`` Symbol type. This defines a data Symbol whose | ||
| *statement results* will be resolved when the Library is bound:: | ||
| [user_type_ids:const] | ||
| SELECT user_type_id, user_type FROM user_types; | ||
| Constant Symbols cannot take parameters as they are data properties. The | ||
| *result* of the above query is set to the Bindings' ``user_type_ids`` | ||
| attribute:: | ||
| >>> db.lib.user_type_ids | ||
| <sequence of (user_type_id, user_type)> | ||
| Where ``lib`` in the above is a Binding of the Library containing the | ||
| ``user_type_ids`` Symbol. | ||
| Finally, procedures can be bound as symbols using the ``proc`` type:: | ||
| [remove_user:proc] | ||
| remove_user(bigint) | ||
| All procedures symbols are loaded when the Library is bound. Procedure symbols | ||
| are special because the execution method is effectively specified by the | ||
| procedure itself. | ||
| The third component is the symbol ``method``. This defines the execution method | ||
| of the statement and ultimately what is returned when the Symbol is called at | ||
| runtime. All the execution methods are listed in `Symbol Execution Methods`_. | ||
| The default execution method is the default execution method of | ||
| `postgresql.api.PreparedStatement` objects; return the entire result set in a | ||
| list object:: | ||
| [get_numbers] | ||
| SELECT i FROM generate_series(0, 100-1) AS g(i); | ||
| When bound:: | ||
| >>> db.lib.get_numbers() == [(x,) for x in range(100)] | ||
| True | ||
| The transformation of range in the above is necessary as statements | ||
| return a sequence of row objects by default. | ||
| For large result-sets, fetching all the rows would be taxing on a system's | ||
| memory. The ``rows`` and ``chunks`` methods provide an iterator to rows produced | ||
| by a statement using a stream:: | ||
| [get_some_rows::rows] | ||
| SELECT i FROM generate_series(0, 1000) AS g(i); | ||
| [get_some_chunks::chunks] | ||
| SELECT i FROM generate_series(0, 1000) AS g(i); | ||
| ``rows`` means that the Symbol will return an iterator producing individual rows | ||
| of the result, and ``chunks`` means that the Symbol will return an iterator | ||
| producing sequences of rows of the result. | ||
| When bound:: | ||
| >>> from itertools import chain | ||
| >>> list(db.lib.get_some_rows()) == list(chain.from_iterable(db.lib.get_some_chunks())) | ||
| True | ||
| Other methods include ``column`` and ``first``. The column method provides a | ||
| means to designate that the symbol should return an iterator of the values in | ||
| the first column instead of an iterator to the rows:: | ||
| [another_generate_series_example::column] | ||
| SELECT i FROM generate_series(0, $1::int) AS g(i) | ||
| In use:: | ||
| >>> list(db.lib.another_generate_series_example(100-1)) == list(range(100)) | ||
| True | ||
| >>> list(db.lib.another_generate_series_example(10-1)) | ||
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
| The ``first`` method provides direct access to simple results. | ||
| Specifically, the first column of the first row when there is only one column. | ||
| When there are multiple columns the first row is returned:: | ||
| [get_one::first] | ||
| SELECT 1 | ||
| [get_one_twice::first] | ||
| SELECT 1, 1 | ||
| In use:: | ||
| >>> db.lib.get_one() == 1 | ||
| True | ||
| >>> db.lib.get_one_twice() == (1,1) | ||
| True | ||
| .. note:: | ||
| ``first`` should be used with care. When the result returns no rows, `None` | ||
| will be returned. | ||
| Using Libraries | ||
| =============== | ||
| After a library is created, it must be loaded before it can be bound using | ||
| programmer interfaces. The `postgresql.lib.load` interface provides the | ||
| primary entry point for loading libraries. | ||
| When ``load`` is given a string, it identifies if a directory separator is in | ||
| the string, if there is it will treat the string as a *path* to the ILF to be | ||
| loaded. If no separator is found, it will treat the string as the library | ||
| name fragment and look for "lib{NAME}.sql" in the directories listed in | ||
| `postgresql.sys.libpath`. | ||
| Once a `postgresql.lib.Library` instance has been acquired, it can then be | ||
| bound to a connection for use. `postgresql.lib.Binding` is used to create an | ||
| object that provides and manages the Bound Symbols:: | ||
| >>> import postgresql.lib as pg_lib | ||
| >>> lib = pg_lib.load(...) | ||
| >>> B = pg_lib.Binding(db, lib) | ||
| The ``B`` object in the above example provides the Library's Symbols as | ||
| attributes which can be called to in order to execute the Symbol's statement:: | ||
| >>> B.symbol(param) | ||
| ... | ||
| While it is sometimes necessary, manual creation of a Binding is discouraged. | ||
| Rather, `postgresql.lib.Category` objects should be used to manage the set of | ||
| Libraries to be bound to a connection. | ||
| Categories | ||
| ---------- | ||
| Libraries provide access to a collection of symbols; Bindings provide an | ||
| interface to the symbols with respect to a subject database. When a connection | ||
| is established, multiple Bindings may need to be created in order to fulfill | ||
| the requirements of the programmer. When a Binding is created, it exists in | ||
| isolation; this can be an inconvenience when access to both the Binding and | ||
| the Connection is necessary. Categories exist to provide a formal method for | ||
| defining the interface extensions on a `postgresql.api.Database` | ||
| instance(connection). | ||
| A Category is essentially a runtime-class for connections. It provides a | ||
| formal initialization procedure for connection objects at runtime. However, | ||
| the connection resource must be connected prior to category initialization. | ||
| Categories are sets of Libraries to be bound to a connection with optional name | ||
| substitutions. In order to create one directly, pass the Library instances to | ||
| `postgresql.lib.Category`:: | ||
| >>> import postgresql.lib as pg_lib | ||
| >>> cat = pg_lib.Category(lib1, lib2, libN) | ||
| Where ``lib1``, ``lib2``, ``libN`` are `postgresql.lib.Library` instances; | ||
| usually created by `postgresql.lib.load`. Once created, categories can then | ||
| used by passing the ``category`` keyword to connection creation interfaces:: | ||
| >>> import postgresql | ||
| >>> db = postgresql.open(category = cat) | ||
| The ``db`` object will now have Bindings for ``lib1``, ``lib2``, ..., and | ||
| ``libN``. | ||
| Categories can alter the access point(attribute name) of Bindings. This is done | ||
| by instantiating the Category using keyword parameters:: | ||
| >>> cat = pg_lib.Category(lib1, lib2, libname = libN) | ||
| At this point, when a connection is established as the category ``cat``, | ||
| ``libN`` will be bound to the connection object on the attribute ``libname`` | ||
| instead of the name defined by the library. | ||
| And a final illustration of Category usage:: | ||
| >>> db = postgresql.open(category = pg_lib.Category(pg_lib.load('name'))) | ||
| >>> db.name | ||
| <Library> | ||
| Symbol Types | ||
| ============ | ||
| The symbol type determines how a symbol is going to be treated by the Binding. | ||
| For instance, ``const`` symbols are resolved when the Library is bound and | ||
| the statement object is immediately discarded. Here is a list of symbol types | ||
| that can be used in ILF libraries: | ||
| ``<default>`` (Empty component) | ||
| The symbol's statement will never change. This allows the Bound Symbol to | ||
| hold onto the `postgresql.api.PreparedStatement` object. When the symbol is | ||
| used again, it will refer to the existing prepared statement object. | ||
| ``preload`` | ||
| Like the default type, the Symbol is a simple statement, but it should be | ||
| loaded when the library is bound to the connection. | ||
| ``const`` | ||
| The statement takes no parameters and only needs to be executed once. This | ||
| will cause the statement to be executed when the library is bound and the | ||
| results of the statement will be set to the Binding using the symbol name so | ||
| that it may be used as a property by the user. | ||
| ``proc`` | ||
| The contents of the section is a procedure identifier. When this type is used | ||
| the symbol method *should not* be specified as the method annotation will be | ||
| automatically resolved based on the procedure's signature. | ||
| ``transient`` | ||
| The Symbol is a statement that should *not* be retained. Specifically, it is | ||
| a statement object that will be discarded when the user discard the referenced | ||
| Symbol. Used in cases where the statement is used once or very infrequently. | ||
| Symbol Execution Methods | ||
| ======================== | ||
| The Symbol Execution Method provides a way to specify how a statement is going | ||
| to be used. Specifically, which `postgresql.api.PreparedStatement` method | ||
| should be executed when a Bound Symbol is called. The following is a list of | ||
| the symbol execution methods and the effect it will have when invoked: | ||
| ``<default>`` (Empty component) | ||
| Returns the entire result set in a single list object. If the statement does | ||
| not return rows, a ``(command, count)`` pair will be returned. | ||
| ``rows`` | ||
| Returns an iterator producing each row in the result set. | ||
| ``chunks`` | ||
| Returns an iterator producing "chunks" of rows in the result set. | ||
| ``first`` | ||
| Returns the first column of the first row if there is one column in the result | ||
| set. If there are multiple columns in the result set, the first row is | ||
| returned. If query is non-RETURNING DML--insert, update, or delete, the row | ||
| count is returned. | ||
| ``column`` | ||
| Returns an iterator to values in the first column. (Equivalent to | ||
| executing a statement as ``map(operator.itemgetter(0), ps.rows())``.) | ||
| ``declare`` | ||
| Returns a scrollable cursor, `postgresql.api.Cursor`, to the result set. | ||
| ``load_chunks`` | ||
| Takes an iterable row-chunks to be given to the statement. Returns `None`. If | ||
| the statement is a ``COPY ... FROM STDIN``, the iterable must produce chunks | ||
| of COPY lines. | ||
| ``load_rows`` | ||
| Takes an iterable rows to be given as parameters. If the statement is a ``COPY | ||
| ... FROM STDIN``, the iterable must produce COPY lines. | ||
| Reference Symbols | ||
| ================= | ||
| Reference Symbols provide a way to construct a Bound Symbol using the Symbol's | ||
| query. When invoked, A Reference Symbol's query is executed in order to produce | ||
| an SQL statement to be used as a Bound Symbol. In ILF files, a reference is | ||
| identified by its symbol name being prefixed with an ampersand:: | ||
| [&refsym::first] | ||
| SELECT 'SELECT 1::int4'::text | ||
| Then executed:: | ||
| >>> # Runs the 'refsym' SQL, and creates a Bound Symbol using the results. | ||
| >>> sym = lib.refsym() | ||
| >>> assert sym() == 1 | ||
| The Reference Symbol's type and execution method are inherited by the created | ||
| Bound Symbol. With one exception, ``const`` reference symbols are | ||
| special in that they immediately resolved into the target Bound Symbol. | ||
| A Reference Symbol's source query *must* produce rows of text columns. Multiple | ||
| columns and multiple rows may be produced by the query, but they must be | ||
| character types as the results are promptly joined together with whitespace so | ||
| that the target statement may be prepared. | ||
| Reference Symbols are most likely to be used in dynamic DDL and DML situations, | ||
| or, somewhat more specifically, any query whose definition depends on a | ||
| generated column list. | ||
| Distributing and Usage | ||
| ====================== | ||
| For applications, distribution and management can easily be a custom | ||
| process. The application designates the library directory; the entry point | ||
| adds the path to the `postgresql.sys.libpath` list; a category is built; and, a | ||
| connection is made using the category. | ||
| For mere Python extensions, however, ``distutils`` has a feature that can | ||
| aid in ILF distribution. The ``package_data`` setup keyword can be used to | ||
| include ILF files alongside the Python modules that make up a project. See | ||
| http://docs.python.org/3.1/distutils/setupscript.html#installing-package-data | ||
| for more detailed information on the keyword parameter. | ||
| The recommended way to manage libraries for extending projects is to | ||
| create a package to contain them. For instance, consider the following layout:: | ||
| project/ | ||
| setup.py | ||
| pkg/ | ||
| __init__.py | ||
| lib/ | ||
| __init__.py | ||
| libthis.sql | ||
| libthat.sql | ||
| The project's SQL libraries are organized into a single package directory, | ||
| ``lib``, so ``package_data`` would be configured:: | ||
| package_data = {'pkg.lib': ['*.sql']} | ||
| Subsequently, the ``lib`` package initialization script can then be used to | ||
| load the libraries, and create any categories(``project/pkg/lib/__init__.py``):: | ||
| import os.path | ||
| import postgresql.lib as pg_lib | ||
| import postgresql.sys as pg_sys | ||
| libdir = os.path.dirname(__file__) | ||
| pg_sys.libpath.append(libdir) | ||
| libthis = pg_lib.load('this') | ||
| libthat = pg_lib.load('that') | ||
| stdcat = pg_lib.Category(libthis, libthat) | ||
| However, it can be undesirable to add the package directory to the global | ||
| `postgresql.sys.libpath` search paths. Direct path loading can be used in those | ||
| cases:: | ||
| import os.path | ||
| import postgresql.lib as pg_lib | ||
| libdir = os.path.dirname(__file__) | ||
| libthis = pg_lib.load(os.path.join(libdir, 'libthis.sql')) | ||
| libthat = pg_lib.load(os.path.join(libdir, 'libthat.sql')) | ||
| stdcat = pg_lib.Category(libthis, libthat) | ||
| Using the established project context, a connection would then be created as:: | ||
| from pkg.lib import stdcat | ||
| import postgresql as pg | ||
| db = pg.open(..., category = stdcat) | ||
| # And execute some fictitious symbols. | ||
| db.this.sym_from_libthis() | ||
| db.that.sym_from_libthat(...) | ||
| Audience and Motivation | ||
| ======================= | ||
| This chapter covers advanced material. It is **not** recommended that categories | ||
| and libraries be used for trivial applications or introductory projects. | ||
| .. note:: | ||
| Libraries and categories are not likely to be of interest to ORM or DB-API users. | ||
| With exception to ORMs or other similar abstractions, the most common pattern | ||
| for managing connections and statements is delegation:: | ||
| class MyAppDB(object): | ||
| def __init__(self, connection): | ||
| self.connection = connection | ||
| def my_operation(self, op_arg1, op_arg2): | ||
| return self.connection.prepare( | ||
| "SELECT my_operation_proc($1,$2)", | ||
| )(op_arg1, op_arg2) | ||
| ... | ||
| The straightforward nature is likeable, but the usage does not take advantage of | ||
| prepared statements. In order to do that an extra condition is necessary to see | ||
| if the statement has already been prepared:: | ||
| ... | ||
| def my_operation(self, op_arg1, op_arg2): | ||
| if self.hasattr(self, '_my_operation'): | ||
| ps = self._my_operation | ||
| else: | ||
| ps = self._my_operation = self.connection.prepare( | ||
| "SELECT my_operation_proc($1, $2)", | ||
| ) | ||
| return ps(op_arg1, op_arg2) | ||
| ... | ||
| There are many variations that can implement the above. It works and it's | ||
| simple, but it will be exhausting if repeated and error prone if the | ||
| initialization condition is not factored out. Additionally, if access to statement | ||
| metadata is needed, the above example is still lacking as it would require | ||
| execution of the statement and further protocol expectations to be established. | ||
| This is the province of libraries: direct database interface management. | ||
| Categories and Libraries are used to factor out and simplify | ||
| the above functionality so re-implementation is unnecessary. For example, an | ||
| ILF library containing the symbol:: | ||
| [my_operation] | ||
| SELECT my_operation_proc($1, $2) | ||
| [<other_symbol>] | ||
| ... | ||
| Will provide the same functionality as the ``my_operation`` method in the | ||
| latter Python implementation. | ||
| Terminology | ||
| =========== | ||
| The following terms are used throughout this chapter: | ||
| Annotations | ||
| The information of about a Symbol describing what it is and how it should be | ||
| used. | ||
| Binding | ||
| An interface to the Symbols provided by a Library for use with a given | ||
| connection. | ||
| Bound Symbol | ||
| An interface to an individual Symbol ready for execution against the subject | ||
| database. | ||
| Bound Reference | ||
| An interface to an individual Reference Symbol that will produce a Bound | ||
| Symbol when executed. | ||
| ILF | ||
| INI-style Library Format. "lib{NAME}.sql" files. | ||
| Library | ||
| A collection of Symbols--mapping of names to SQL statements. | ||
| Local Symbol | ||
| A relative term used to denote a symbol that exists in the same library as | ||
| the subject symbol. | ||
| Preface | ||
| The block of text that comes before the first symbol in an ILF file. | ||
| Symbol | ||
| An named database operation provided by a Library. Usually, an SQL statement | ||
| with Annotations. | ||
| Reference Symbol | ||
| A Symbol whose SQL statement *produces* the source for a Bound Symbol. | ||
| Category | ||
| An object supporting a classification for connectors that provides database | ||
| initialization facilities for produced connections. For libraries, | ||
| `postgresql.lib.Category` objects are a set of Libraries, | ||
| `postgresql.lib.Library`. |
| .. _notifyman: | ||
| *********************** | ||
| Notification Management | ||
| *********************** | ||
| Relevant SQL commands: `NOTIFY <http://postgresql.org/docs/current/static/sql-notify.html>`_, | ||
| `LISTEN <http://postgresql.org/docs/current/static/sql-listen.html>`_, | ||
| `UNLISTEN <http://postgresql.org/docs/current/static/sql-unlisten.html>`_. | ||
| Asynchronous notifications offer a means for PostgreSQL to signal application | ||
| code. Often these notifications are used to signal cache invalidation. In 9.0 | ||
| and greater, notifications may include a "payload" in which arbitrary data may | ||
| be delivered on a channel being listened to. | ||
| By default, received notifications will merely be appended to an internal | ||
| list on the connection object. This list will remain empty for the duration | ||
| of a connection *unless* the connection begins listening to a channel that | ||
| receives notifications. | ||
| The `postgresql.notifyman.NotificationManager` class is used to wait for | ||
| messages to come in on a set of connections, pick up the messages, and deliver | ||
| the messages to the object's user via the `collections.Iterator` protocol. | ||
| Listening on a Single Connection | ||
| ================================ | ||
| The ``db.iternotifies()`` method is a simplification of the notification manager. It | ||
| returns an iterator to the notifications received on the subject connection. | ||
| The iterator yields triples consisting of the ``channel`` being | ||
| notified, the ``payload`` sent with the notification, and the ``pid`` of the | ||
| backend that caused the notification:: | ||
| >>> db.listen('for_rabbits') | ||
| >>> db.notify('for_rabbits') | ||
| >>> for x in db.iternotifies(): | ||
| ... channel, payload, pid = x | ||
| ... break | ||
| >>> assert channel == 'for_rabbits' | ||
| True | ||
| >>> assert payload == '' | ||
| True | ||
| >>> assert pid == db.backend_id | ||
| True | ||
| The iterator, by default, will continue listening forever unless the connection | ||
| is terminated--thus the immediate ``break`` statement in the above loop. In | ||
| cases where some additional activity is necessary, a timeout parameter may be | ||
| given to the ``iternotifies`` method in order to allow "idle" events to occur | ||
| at the designated frequency:: | ||
| >>> for x in db.iternotifies(0.5): | ||
| ... if x is None: | ||
| ... break | ||
| The above example illustrates that idle events are represented using `None` | ||
| objects. Idle events are guaranteed to occur *approximately* at the | ||
| specified interval--the ``timeout`` keyword parameter. In addition to | ||
| providing a means to do other processing or polling, they also offer a safe | ||
| break point for the loop. Internally, the iterator produced by the | ||
| ``iternotifies`` method *is* a `NotificationManager`, which will localize the | ||
| notifications prior to emitting them via the iterator. | ||
| *It's not safe to break out of the loop, unless an idle event is being handled.* | ||
| If the loop is broken while a regular event is being processed, some events may | ||
| remain in the iterator. In order to consume those events, the iterator *must* | ||
| be accessible. | ||
| The iterator will be exhausted when the connection is closed, but if the | ||
| connection is closed during the loop, any remaining notifications *will* | ||
| be emitted prior to the loop ending, so it is important to be prepared to | ||
| handle exceptions or check for a closed connection. | ||
| In situations where multiple connections need to be watched, direct use of the | ||
| `NotificationManager` is necessary. | ||
| Listening on Multiple Connections | ||
| ================================= | ||
| The `postgresql.notifyman.NotificationManager` class is used to manage | ||
| *connections* that are expecting to receive notifications. Instances are | ||
| iterators that yield the connection object and notifications received on the | ||
| connection or `None` in the case of an idle event. The manager emits events as | ||
| a pair; the connection object that received notifications, and *all* the | ||
| notifications picked up on that connection:: | ||
| >>> from postgresql.notifyman import NotificationManager | ||
| >>> # Using ``nm`` to reference the manager from here on. | ||
| >>> nm = NotificationManager(db1, db2, ..., dbN) | ||
| >>> nm.settimeout(2) | ||
| >>> for x in nm: | ||
| ... if x is None: | ||
| ... # idle | ||
| ... break | ||
| ... | ||
| ... db, notifies = x | ||
| ... for channel, payload, pid in notifies: | ||
| ... ... | ||
| The manager will continue to wait for and emit events so long as there are | ||
| good connections available in the set; it is possible for connections to be | ||
| added and removed at any time. Although, in rare circumstances, discarded | ||
| connections may still have pending events if it not removed during an idle | ||
| event. The ``connections`` attribute on `NotificationManager` objects is a | ||
| set object that may be used directly in order to add and remove connections | ||
| from the manager:: | ||
| >>> y = [] | ||
| >>> for x in nm: | ||
| ... if x is None: | ||
| ... if y: | ||
| ... nm.connections.add(y[0]) | ||
| ... del y[0] | ||
| ... | ||
| The notification manager is resilient; if a connection dies, it will discard the | ||
| connection from the set, and add it to the set of bad connections, the | ||
| ``garbage`` attribute. In these cases, the idle event *should* be leveraged to | ||
| check for these failures if that's a concern. It is the user's | ||
| responsibility to explicitly handle the failure cases, and remove the bad | ||
| connections from the ``garbage`` set:: | ||
| >>> for x in nm: | ||
| ... if x is None: | ||
| ... if nm.garbage: | ||
| ... recovered = take_out_trash(nm.garbage) | ||
| ... nm.connections.update(recovered) | ||
| ... nm.garbage.clear() | ||
| ... db, notifies = x | ||
| ... for channel, payload, pid in notifies: | ||
| ... ... | ||
| Explicitly removing connections from the set can also be a means to gracefully | ||
| terminate the event loop:: | ||
| >>> for x in nm: | ||
| ... if x in None: | ||
| ... if done_listening is True: | ||
| ... nm.connections.clear() | ||
| However, doing so inside the loop is not a requirement; it is safe to remove a | ||
| connection from the set at any point. | ||
| Notification Managers | ||
| ===================== | ||
| The `postgresql.notifyman.NotificationManager` is an event loop that services | ||
| multiple connections. In cases where only one connection needs to be serviced, | ||
| the `postgresql.api.Database.iternotifies` method can be used to simplify the | ||
| process. | ||
| Notification Manager Constructors | ||
| --------------------------------- | ||
| ``NotificationManager(*connections, timeout = None)`` | ||
| Create a NotificationManager instance that manages the notifications coming | ||
| from the given set of connections. The ``timeout`` keyword is optional and | ||
| can be configured using the ``settimeout`` method as well. | ||
| Notification Manager Interface Points | ||
| ------------------------------------- | ||
| ``NotificationManager.__iter__()`` | ||
| Returns the instance; it is an iterator. | ||
| ``NotificationManager.__next__()`` | ||
| Normally, yield the pair, connection and notifications list, when the next | ||
| event is received. If a timeout is configured, `None` may be yielded to signal | ||
| an idle event. The notifications list is a list of triples: | ||
| ``(channel, payload, pid)``. | ||
| ``NotificationManager.settimeout(timeout : int)`` | ||
| Set the amount of time to wait before the manager yields an idle event. | ||
| If zero, the manager will never wait and only yield notifications that are | ||
| immediately available. | ||
| If `None`, the manager will never emit idle events. | ||
| ``NotificationManager.gettimeout() -> [int, None]`` | ||
| Get the configured timeout; returns either `None`, or an `int`. | ||
| ``NotificationManager.connections`` | ||
| The set of connections that the manager is actively watching for | ||
| notifications. Connections may be added or removed from the set at any time. | ||
| ``NotificationManager.garbage`` | ||
| The set of connections that failed. Normally empty, but when a connection gets | ||
| an exceptional condition or explicitly raises an exception, it is removed from | ||
| the ``connections`` set, and placed in ``garbage``. | ||
| Zero Timeout | ||
| ------------ | ||
| When a timeout of zero, ``0``, is configured, the notification manager will | ||
| terminate early. Specifically, each connection will be polled for any pending | ||
| notifications, and once all of the collected notifications have been emitted | ||
| by the iterator, `StopIteration` will be raised. Notably, *no* idle events will | ||
| occur when the timeout is configured to zero. | ||
| Zero timeouts offer a means for the notification "queue" to be polled. Often, | ||
| this is the appropriate way to collect pending notifications on active | ||
| connections where using the connection exclusively for waiting is not | ||
| practical:: | ||
| >>> notifies = list(db.iternotifies(0)) | ||
| Or with a NotificationManager instance:: | ||
| >>> nm.settimeout(0) | ||
| >>> db_notifies = list(nm) | ||
| In both cases of zero timeout, the iterator may be promptly discarded without | ||
| losing any events. | ||
| Summary of Characteristics | ||
| -------------------------- | ||
| * The iterator will continue until the connections die. | ||
| * Objects yielded by the iterator are either `None`, an "idle event", or an | ||
| individual notification triple if using ``db.iternotifies()``, or a | ||
| ``(db, notifies)`` pair if using the base `NotificationManager`. | ||
| * When a connection dies or raises an exception, it will be removed from | ||
| the ``nm.connections`` set and added to the ``nm.garbage`` set. | ||
| * The NotificationManager instance will *not* hold any notifications | ||
| during an idle event. Idle events offer a break point in which the manager | ||
| may be discarded. | ||
| * A timeout of zero will cause the iterator to only yield the events | ||
| that are pending right now, and promptly end. However, the same manager | ||
| object may be used again. | ||
| * A notification triple is a tuple consisting of ``(channel, payload, pid)``. | ||
| * Connections may be added and removed from the ``nm.connections`` set at | ||
| any time. |
| Reference | ||
| ========= | ||
| :mod:`postgresql` | ||
| ----------------- | ||
| .. automodule:: postgresql | ||
| .. autodata:: version | ||
| .. autodata:: version_info | ||
| .. autofunction:: open | ||
| :mod:`postgresql.api` | ||
| --------------------- | ||
| .. automodule:: | ||
| postgresql.api | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.sys` | ||
| --------------------- | ||
| .. automodule:: | ||
| postgresql.sys | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.string` | ||
| ------------------------ | ||
| .. automodule:: | ||
| postgresql.string | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.exceptions` | ||
| ---------------------------- | ||
| .. automodule:: | ||
| postgresql.exceptions | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.temporal` | ||
| -------------------------- | ||
| .. automodule:: | ||
| postgresql.temporal | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.installation` | ||
| ------------------------------ | ||
| .. automodule:: | ||
| postgresql.installation | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.cluster` | ||
| ------------------------- | ||
| .. automodule:: | ||
| postgresql.cluster | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.copyman` | ||
| ------------------------- | ||
| .. automodule:: | ||
| postgresql.copyman | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.alock` | ||
| ----------------------- | ||
| .. automodule:: | ||
| postgresql.alock | ||
| :members: | ||
| :show-inheritance: |
| Metadata-Version: 2.1 | ||
| Name: py-postgresql | ||
| Version: 1.2.2 | ||
| Summary: PostgreSQL driver and tools library. | ||
| Home-page: http://github.com/python-postgres/fe | ||
| Author: James William Pye | ||
| Author-email: james.pye@gmail.com | ||
| Maintainer: James William Pye | ||
| Maintainer-email: james.pye@gmail.com | ||
| License: UNKNOWN | ||
| Description: | ||
| .. warning:: | ||
| In v1.3, `postgresql.driver.dbapi20.connect` will now raise `ClientCannotConnectError` directly. | ||
| Exception traps around connect should still function, but the `__context__` attribute | ||
| on the error instance will be `None` in the usual failure case as it is no longer | ||
| incorrectly chained. Trapping `ClientCannotConnectError` ahead of `Error` should | ||
| allow both cases to co-exist in the event that data is being extracted from | ||
| the `ClientCannotConnectError`. | ||
| py-postgresql is a set of Python modules providing interfaces to various parts | ||
| of PostgreSQL. Primarily, it provides a pure-Python driver with some C optimizations for | ||
| querying a PostgreSQL database. | ||
| http://github.com/python-postgres/fe | ||
| Features: | ||
| * Prepared Statement driven interfaces. | ||
| * Cluster tools for creating and controlling a cluster. | ||
| * Support for most PostgreSQL types: composites, arrays, numeric, lots more. | ||
| * COPY support. | ||
| Sample PG-API Code:: | ||
| >>> import postgresql | ||
| >>> db = postgresql.open('pq://user:password@host:port/database') | ||
| >>> db.execute("CREATE TABLE emp (emp_first_name text, emp_last_name text, emp_salary numeric)") | ||
| >>> make_emp = db.prepare("INSERT INTO emp VALUES ($1, $2, $3)") | ||
| >>> make_emp("John", "Doe", "75,322") | ||
| >>> with db.xact(): | ||
| ... make_emp("Jane", "Doe", "75,322") | ||
| ... make_emp("Edward", "Johnson", "82,744") | ||
| ... | ||
| There is a DB-API 2.0 module as well:: | ||
| postgresql.driver.dbapi20 | ||
| However, PG-API is recommended as it provides greater utility. | ||
| Once installed, try out the ``pg_python`` console script:: | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -p port -U theuser -d database_name | ||
| If a successful connection is made to the remote host, it will provide a Python | ||
| console with the database connection bound to the `db` name. | ||
| Platform: UNKNOWN | ||
| Classifier: Development Status :: 5 - Production/Stable | ||
| Classifier: Intended Audience :: Developers | ||
| Classifier: License :: OSI Approved :: BSD License | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Classifier: License :: OSI Approved :: Attribution Assurance License | ||
| Classifier: License :: OSI Approved :: Python Software Foundation License | ||
| Classifier: Natural Language :: English | ||
| Classifier: Operating System :: OS Independent | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Topic :: Database | ||
| Description-Content-Type: text/x-rst |
| AUTHORS | ||
| LICENSE | ||
| MANIFEST.in | ||
| README | ||
| setup.py | ||
| postgresql/__init__.py | ||
| postgresql/alock.py | ||
| postgresql/api.py | ||
| postgresql/clientparameters.py | ||
| postgresql/cluster.py | ||
| postgresql/configfile.py | ||
| postgresql/copyman.py | ||
| postgresql/exceptions.py | ||
| postgresql/installation.py | ||
| postgresql/iri.py | ||
| postgresql/message.py | ||
| postgresql/notifyman.py | ||
| postgresql/pgpassfile.py | ||
| postgresql/project.py | ||
| postgresql/string.py | ||
| postgresql/sys.py | ||
| postgresql/temporal.py | ||
| postgresql/versionstring.py | ||
| postgresql/bin/__init__.py | ||
| postgresql/bin/pg_dotconf.py | ||
| postgresql/bin/pg_python.py | ||
| postgresql/documentation/__init__.py | ||
| postgresql/documentation/sphinx/admin.rst | ||
| postgresql/documentation/sphinx/alock.rst | ||
| postgresql/documentation/sphinx/bin.rst | ||
| postgresql/documentation/sphinx/changes-v1.0.rst | ||
| postgresql/documentation/sphinx/changes-v1.1.rst | ||
| postgresql/documentation/sphinx/changes-v1.2.rst | ||
| postgresql/documentation/sphinx/clientparameters.rst | ||
| postgresql/documentation/sphinx/cluster.rst | ||
| postgresql/documentation/sphinx/conf.py | ||
| postgresql/documentation/sphinx/copyman.rst | ||
| postgresql/documentation/sphinx/driver.rst | ||
| postgresql/documentation/sphinx/gotchas.rst | ||
| postgresql/documentation/sphinx/index.rst | ||
| postgresql/documentation/sphinx/lib.rst | ||
| postgresql/documentation/sphinx/notifyman.rst | ||
| postgresql/documentation/sphinx/reference.rst | ||
| postgresql/driver/__init__.py | ||
| postgresql/driver/dbapi20.py | ||
| postgresql/driver/k.py | ||
| postgresql/driver/pq3.py | ||
| postgresql/encodings/__init__.py | ||
| postgresql/encodings/aliases.py | ||
| postgresql/encodings/bytea.py | ||
| postgresql/lib/__init__.py | ||
| postgresql/lib/libsys.sql | ||
| postgresql/port/__init__.py | ||
| postgresql/port/signal1_msw.py | ||
| postgresql/port/_optimized/buffer.c | ||
| postgresql/port/_optimized/element3.c | ||
| postgresql/port/_optimized/functools.c | ||
| postgresql/port/_optimized/module.c | ||
| postgresql/port/_optimized/structlib.c | ||
| postgresql/port/_optimized/wirestate.c | ||
| postgresql/protocol/__init__.py | ||
| postgresql/protocol/buffer.py | ||
| postgresql/protocol/client3.py | ||
| postgresql/protocol/element3.py | ||
| postgresql/protocol/message_types.py | ||
| postgresql/protocol/pbuffer.py | ||
| postgresql/protocol/version.py | ||
| postgresql/protocol/xact3.py | ||
| postgresql/python/__init__.py | ||
| postgresql/python/command.py | ||
| postgresql/python/datetime.py | ||
| postgresql/python/decorlib.py | ||
| postgresql/python/doc.py | ||
| postgresql/python/element.py | ||
| postgresql/python/functools.py | ||
| postgresql/python/itertools.py | ||
| postgresql/python/msw.py | ||
| postgresql/python/os.py | ||
| postgresql/python/socket.py | ||
| postgresql/python/string.py | ||
| postgresql/python/structlib.py | ||
| postgresql/release/__init__.py | ||
| postgresql/release/distutils.py | ||
| postgresql/resolved/__init__.py | ||
| postgresql/resolved/crypt.py | ||
| postgresql/resolved/riparse.py | ||
| postgresql/test/__init__.py | ||
| postgresql/test/cursor_integrity.py | ||
| postgresql/test/perf_copy_io.py | ||
| postgresql/test/perf_query_io.py | ||
| postgresql/test/support.py | ||
| postgresql/test/test_alock.py | ||
| postgresql/test/test_bytea_codec.py | ||
| postgresql/test/test_cluster.py | ||
| postgresql/test/test_configfile.py | ||
| postgresql/test/test_connect.py | ||
| postgresql/test/test_copyman.py | ||
| postgresql/test/test_dbapi20.py | ||
| postgresql/test/test_driver.py | ||
| postgresql/test/test_exceptions.py | ||
| postgresql/test/test_installation.py | ||
| postgresql/test/test_iri.py | ||
| postgresql/test/test_lib.py | ||
| postgresql/test/test_notifyman.py | ||
| postgresql/test/test_optimized.py | ||
| postgresql/test/test_pgpassfile.py | ||
| postgresql/test/test_protocol.py | ||
| postgresql/test/test_python.py | ||
| postgresql/test/test_ssl_connect.py | ||
| postgresql/test/test_string.py | ||
| postgresql/test/test_types.py | ||
| postgresql/test/testall.py | ||
| postgresql/types/__init__.py | ||
| postgresql/types/bitwise.py | ||
| postgresql/types/geometry.py | ||
| postgresql/types/namedtuple.py | ||
| postgresql/types/io/__init__.py | ||
| postgresql/types/io/builtins.py | ||
| postgresql/types/io/contrib_hstore.py | ||
| postgresql/types/io/lib.py | ||
| postgresql/types/io/pg_bitwise.py | ||
| postgresql/types/io/pg_geometry.py | ||
| postgresql/types/io/pg_network.py | ||
| postgresql/types/io/pg_system.py | ||
| postgresql/types/io/stdlib_datetime.py | ||
| postgresql/types/io/stdlib_decimal.py | ||
| postgresql/types/io/stdlib_jsonb.py | ||
| postgresql/types/io/stdlib_uuid.py | ||
| postgresql/types/io/stdlib_xml_etree.py | ||
| py_postgresql.egg-info/PKG-INFO | ||
| py_postgresql.egg-info/SOURCES.txt | ||
| py_postgresql.egg-info/dependency_links.txt | ||
| py_postgresql.egg-info/top_level.txt |
| postgresql |
| [egg_info] | ||
| tag_build = | ||
| tag_date = 0 | ||
+3
-8
| Contributors: | ||
| James William Pye [faults are mostly mine] <x@jwp.io> | ||
| James William Pye [faults are mostly mine] | ||
| Elvis Pranskevichus | ||
@@ -11,10 +11,5 @@ William Grzybowski [subjective paramstyle] | ||
| Further Credits | ||
| =============== | ||
| Imported | ||
| ======== | ||
| When licenses match, people win. Code is occasionally imported from other | ||
| projects to enhance py-postgresql and to allow users to enjoy dependency free | ||
| installation. | ||
| DB-API 2.0 Test Case | ||
@@ -21,0 +16,0 @@ -------------------- |
+0
-7
@@ -1,8 +0,1 @@ | ||
| BSD Licensed Software | ||
| Unless stated otherwise, the contained software is | ||
| copyright 2004-2009, James Williame Pye. | ||
| For more information: http://python.projects.postgresql.org | ||
| Redistribution and use in source and binary forms, | ||
@@ -9,0 +2,0 @@ with or without modification, are permitted provided |
+17
-14
@@ -1,15 +0,25 @@ | ||
| Metadata-Version: 1.1 | ||
| Metadata-Version: 2.1 | ||
| Name: py-postgresql | ||
| Version: 1.2.1 | ||
| Version: 1.2.2 | ||
| Summary: PostgreSQL driver and tools library. | ||
| Home-page: http://python.projects.postgresql.org/ | ||
| Home-page: http://github.com/python-postgres/fe | ||
| Author: James William Pye | ||
| Author-email: python-general@pgfoundry.org | ||
| Author-email: james.pye@gmail.com | ||
| Maintainer: James William Pye | ||
| Maintainer-email: james.pye@gmail.com | ||
| License: UNKNOWN | ||
| Description: | ||
| .. warning:: | ||
| In v1.3, `postgresql.driver.dbapi20.connect` will now raise `ClientCannotConnectError` directly. | ||
| Exception traps around connect should still function, but the `__context__` attribute | ||
| on the error instance will be `None` in the usual failure case as it is no longer | ||
| incorrectly chained. Trapping `ClientCannotConnectError` ahead of `Error` should | ||
| allow both cases to co-exist in the event that data is being extracted from | ||
| the `ClientCannotConnectError`. | ||
| py-postgresql is a set of Python modules providing interfaces to various parts | ||
| of PostgreSQL. Notably, it provides a pure-Python driver + C optimizations for | ||
| of PostgreSQL. Primarily, it provides a pure-Python driver with some C optimizations for | ||
| querying a PostgreSQL database. | ||
| http://python.projects.postgresql.org | ||
| http://github.com/python-postgres/fe | ||
@@ -48,10 +58,2 @@ Features: | ||
| History | ||
| ------- | ||
| py-postgresql is not yet another PostgreSQL driver, it's been in development for | ||
| years. py-postgresql is the Python 3 port of the ``pg_proboscis`` driver and | ||
| integration of the other ``pg/python`` projects. | ||
| Platform: UNKNOWN | ||
@@ -69,1 +71,2 @@ Classifier: Development Status :: 5 - Production/Stable | ||
| Classifier: Topic :: Database | ||
| Description-Content-Type: text/x-rst |
| ## | ||
| # py-postgresql root package | ||
| # http://python.projects.postgresql.org | ||
| # http://github.com/python-postgres/fe | ||
| ## | ||
| """ | ||
| py-postgresql is a Python package for using PostgreSQL. This includes low-level | ||
| protocol tools, a driver(PG-API and DB-API), and cluster management tools. | ||
| protocol tools, a driver(PG-API and DB-API 2.0), and cluster management tools. | ||
| If it's not documented in the narratives, `postgresql.documentation.index`, then | ||
| the stability of the APIs should *not* be trusted. | ||
| See <http://postgresql.org> for more information about PostgreSQL. | ||
| See <http://postgresql.org> for more information about PostgreSQL and <http://python.org> | ||
| for information about Python. | ||
| """ | ||
@@ -14,0 +12,0 @@ __all__ = [ |
@@ -157,3 +157,3 @@ ## | ||
| def envvars(environ = os.environ, modifier : "environment variable key modifier" = 'PG'.__add__): | ||
| def envvars(environ = os.environ, modifier = 'PG'.__add__): | ||
| """ | ||
@@ -186,2 +186,4 @@ Create a clientparams dictionary from the given environment variables. | ||
| itself. | ||
| :param modifier: environment variable key modifier | ||
| """ | ||
@@ -279,3 +281,5 @@ hostaddr = modifier('HOSTADDR') | ||
| def append_settings(option, opt_str, value, parser): | ||
| 'split the string into a (key,value) pair tuple' | ||
| """ | ||
| split the string into a (key,value) pair tuple | ||
| """ | ||
| kv = value.split('=', 1) | ||
@@ -373,7 +377,3 @@ if len(kv) != 2: | ||
| def resolve_password( | ||
| parameters : "a fully normalized set of client parameters(dict)", | ||
| getpass = getpass, | ||
| prompt_title = '', | ||
| ): | ||
| def resolve_password(parameters, getpass = getpass, prompt_title = ''): | ||
| """ | ||
@@ -393,2 +393,4 @@ Given a parameters dictionary, resolve the 'password' key. | ||
| given parameters. | ||
| :param parameters: a fully normalized set of client parameters(dict) | ||
| """ | ||
@@ -578,3 +580,3 @@ prompt_for_password = parameters.pop('prompt_password', False) | ||
| default_pg_sysconfdir = None, | ||
| default_pg_service_filename = pg_service_filename | ||
| default_pg_service_filename = pg_service_filename | ||
| ): | ||
@@ -587,14 +589,23 @@ sysconfdir = environ.get(pg_sysconfdir_envvar, default_pg_sysconfdir) | ||
| def collect( | ||
| parsed_options : "options parsed using the `DefaultParser`" = None, | ||
| no_defaults : "Don't build-out defaults like 'user' from getpass.getuser()" = False, | ||
| environ : "environment variables to use, `None` to disable" = os.environ, | ||
| environ_prefix : "prefix to use for collecting environment variables" = 'PG', | ||
| default_pg_sysconfdir : "default 'PGSYSCONFDIR' to use" = None, | ||
| pg_service_file : "the pg-service file to actually use" = None, | ||
| prompt_title : "additional title to use if a prompt request is made" = '', | ||
| parameters : "base-client parameters to use(applied after defaults)" = (), | ||
| ): | ||
| parsed_options = None, | ||
| no_defaults = False, | ||
| environ = os.environ, | ||
| environ_prefix = 'PG', | ||
| default_pg_sysconfdir = None, | ||
| pg_service_file = None, | ||
| prompt_title = '', | ||
| parameters = (), | ||
| ): | ||
| """ | ||
| Build a normalized client parameters dictionary for use with a connection | ||
| construction interface. | ||
| :param parsed_options: options parsed using the `DefaultParser` | ||
| :param no_defaults: Don't build-out defaults like 'user' from getpass.getuser() | ||
| :param environ: environment variables to use, `None` to disable | ||
| :param environ_prefix: prefix to use for collecting environment variables | ||
| :param default_pg_sysconfdir: default 'PGSYSCONFDIR' to use | ||
| :param pg_service_file: the pg-service file to actually use | ||
| :param prompt_title: additional title to use if a prompt request is made | ||
| :param parameters: base-client parameters to use(applied after defaults) | ||
| """ | ||
@@ -601,0 +612,0 @@ d_parameters = [] |
+20
-30
@@ -158,4 +158,4 @@ ## | ||
| def __init__(self, | ||
| installation : "installation object", | ||
| data_directory : "path to the data directory", | ||
| installation, | ||
| data_directory, | ||
| ): | ||
@@ -195,5 +195,4 @@ self.installation = installation | ||
| def init(self, | ||
| password : \ | ||
| "Password to assign to the " \ | ||
| "cluster's superuser(`user` keyword)." = None, | ||
| password = None, | ||
| timeout = None, | ||
| **kw | ||
@@ -260,3 +259,3 @@ ): | ||
| bufsize = 1024 * 5, # not expecting this to ever be filled. | ||
| stdin = sp.PIPE, | ||
| stdin = None, | ||
| stdout = logfile, | ||
@@ -266,15 +265,10 @@ # stderr is used to identify a reasonable error message. | ||
| ) | ||
| # stdin is not used; it is not desirable for initdb to be attached. | ||
| p.stdin.close() | ||
| while True: | ||
| try: | ||
| rc = p.wait() | ||
| break | ||
| except OSError as e: | ||
| if e.errno != errno.EINTR: | ||
| raise | ||
| finally: | ||
| if p.stdout is not None: | ||
| p.stdout.close() | ||
| try: | ||
| stdout, stderr = p.communicate(timeout=timeout) | ||
| except sp.TimeoutExpired: | ||
| p.kill() | ||
| stdout, stderr = p.communicate() | ||
| finally: | ||
| rc = p.returncode | ||
@@ -284,3 +278,3 @@ if rc != 0: | ||
| r = p.stderr.read().strip() | ||
| r = stderr | ||
| try: | ||
@@ -293,2 +287,3 @@ msg = r.decode('utf-8') | ||
| ]) | ||
| raise InitDBError( | ||
@@ -304,7 +299,2 @@ "initdb exited with non-zero status", | ||
| finally: | ||
| if p is not None: | ||
| for x in (p.stderr, p.stdin, p.stdout): | ||
| if x is not None: | ||
| x.close() | ||
| if supw_tmp is not None: | ||
@@ -344,4 +334,4 @@ n = supw_tmp.name | ||
| def start(self, | ||
| logfile : "Where to send stderr" = None, | ||
| settings : "Mapping of runtime parameters" = None | ||
| logfile = None, | ||
| settings = None | ||
| ): | ||
@@ -584,4 +574,4 @@ """ | ||
| def wait_until_started(self, | ||
| timeout : "how long to wait before throwing a timeout exception" = 10, | ||
| delay : "how long to sleep before re-testing" = 0.05, | ||
| timeout = 10, | ||
| delay = 0.05, | ||
| ): | ||
@@ -637,4 +627,4 @@ """ | ||
| def wait_until_stopped(self, | ||
| timeout : "how long to wait before throwing a timeout exception" = 10, | ||
| delay : "how long to sleep before re-testing" = 0.05 | ||
| timeout = 10, | ||
| delay = 0.05 | ||
| ): | ||
@@ -641,0 +631,0 @@ """ |
@@ -327,2 +327,6 @@ ## | ||
| # Explicitly manage DB-API connected state to properly | ||
| # throw the already closed error. This will be active in 1.3. | ||
| _dbapi_connected_flag = False | ||
| def autocommit_set(self, val): | ||
@@ -358,5 +362,6 @@ if val: | ||
| self._xact.start() | ||
| self._dbapi_connected_flag = True | ||
| def close(self): | ||
| if self.closed: | ||
| if self.closed:# and self._dbapi_connected_flag: | ||
| raise Error( | ||
@@ -367,2 +372,3 @@ "connection already closed", | ||
| ) | ||
| self._dbapi_connected_flag = True | ||
| super().close() | ||
@@ -405,2 +411,5 @@ | ||
| Create a DB-API connection using the given parameters. | ||
| Due to the way defaults are populated, when connecting to a local filesystem socket | ||
| using the `unix` keyword parameter, `host` and `port` must also be set to ``None``. | ||
| """ | ||
@@ -407,0 +416,0 @@ std_params = pg_param.collect(prompt_title = None) |
@@ -11,3 +11,2 @@ ## | ||
| import subprocess | ||
| import io | ||
| import errno | ||
@@ -22,4 +21,4 @@ from itertools import cycle, chain | ||
| # Get the output from the given command. | ||
| # *args are transformed into "long options", '--' + x | ||
| def get_command_output(exe, *args): | ||
| # Variable arguments are transformed into "long options", '--' + x | ||
| def get_command_output(exe, *args, encoding='utf-8', timeout=8): | ||
| pa = list(exe) + [ | ||
@@ -31,21 +30,19 @@ '--' + x.strip() for x in args if x is not None | ||
| stdout = subprocess.PIPE, | ||
| stderr = subprocess.PIPE, | ||
| stdin = subprocess.PIPE, | ||
| stderr = None, | ||
| stdin = None, | ||
| shell = False | ||
| ) | ||
| p.stdin.close() | ||
| p.stderr.close() | ||
| while True: | ||
| try: | ||
| rv = p.wait() | ||
| break | ||
| except OSError as e: | ||
| if e.errno != errno.EINTR: | ||
| raise | ||
| if rv != 0: | ||
| try: | ||
| stdout, stderr = p.communicate(timeout=timeout) | ||
| except subprocess.TimeoutExpired: | ||
| p.kill() | ||
| stdout, stderr = p.communicate(timeout=2) | ||
| if p.returncode != 0: | ||
| return None | ||
| with p.stdout, io.TextIOWrapper(p.stdout) as txt: | ||
| return txt.read() | ||
| def pg_config_dictionary(*pg_config_path): | ||
| return stdout.decode(encoding) | ||
| def pg_config_dictionary(*pg_config_path, encoding='utf-8', timeout=8): | ||
| """ | ||
@@ -56,3 +53,3 @@ Create a dictionary of the information available in the given | ||
| """ | ||
| default_output = get_command_output(pg_config_path) | ||
| default_output = get_command_output(pg_config_path, encoding=encoding, timeout=timeout) | ||
| if default_output is not None: | ||
@@ -74,3 +71,3 @@ d = {} | ||
| opt = [] | ||
| for l in get_command_output(pg_config_path, 'help').splitlines(): | ||
| for l in get_command_output(pg_config_path, 'help', encoding=encoding, timeout=timeout).splitlines(): | ||
| dash_pos = l.find('--') | ||
@@ -87,4 +84,4 @@ if dash_pos == -1: | ||
| d=dict(zip(opt, get_command_output(pg_config_path, *opt).splitlines())) | ||
| d['version'] = get_command_output(pg_config_path, 'version').strip() | ||
| d=dict(zip(opt, get_command_output(pg_config_path, *opt, encoding=encoding, timeout=timeout).splitlines())) | ||
| d['version'] = get_command_output(pg_config_path, 'version', encoding=encoding, timeout=timeout).strip() | ||
| return d | ||
@@ -91,0 +88,0 @@ |
@@ -49,3 +49,3 @@ ## | ||
| else: | ||
| cpd['host'] = host[1:-1] | ||
| cpd['host'] = host | ||
| else: | ||
@@ -52,0 +52,0 @@ cpd['host'] = fieldproc(host) |
@@ -103,3 +103,3 @@ /* | ||
| { | ||
| int32_t current = 0; | ||
| uint32_t current = 0; | ||
| struct p_list *pl; | ||
@@ -106,0 +106,0 @@ |
@@ -1,14 +0,12 @@ | ||
| 'project information' | ||
| """ | ||
| Project information. | ||
| """ | ||
| #: project name | ||
| name = 'py-postgresql' | ||
| identity = 'http://github.com/python-postgres/fe' | ||
| #: IRI based project identity | ||
| identity = 'http://python.projects.postgresql.org/' | ||
| meaculpa = 'Python+Postgres' | ||
| contact = 'python-general@pgfoundry.org' | ||
| abstract = 'Driver and tools library for PostgreSQL' | ||
| version_info = (1, 2, 1) | ||
| version_info = (1, 2, 2) | ||
| version = '.'.join(map(str, version_info)) |
| ## | ||
| # .protocol.element3 | ||
| ## | ||
| 'PQ version 3.0 elements' | ||
| """ | ||
| PQ version 3.0 elements. | ||
| """ | ||
| import sys | ||
@@ -303,3 +305,5 @@ import os | ||
| class Ready(Message): | ||
| 'Ready for new query' | ||
| """ | ||
| Ready for new query message. | ||
| """ | ||
| type = message_types[b'Z'[0]] | ||
@@ -323,3 +327,3 @@ possible_states = ( | ||
| """ | ||
| Notification message | ||
| Notification message. | ||
@@ -358,3 +362,5 @@ Used by PQ to emit INFO, NOTICE, and WARNING messages among other | ||
| class Error(Notice): | ||
| """Incoming error""" | ||
| """ | ||
| Error information message. | ||
| """ | ||
| type = message_types[b'E'[0]] | ||
@@ -374,3 +380,5 @@ __slots__ = () | ||
| class FunctionResult(Message): | ||
| """Function result value""" | ||
| """ | ||
| Function result value. | ||
| """ | ||
| type = message_types[b'V'[0]] | ||
@@ -401,3 +409,5 @@ __slots__ = ('result',) | ||
| class AttributeTypes(TupleMessage): | ||
| """Tuple attribute types""" | ||
| """ | ||
| Tuple attribute types. | ||
| """ | ||
| type = message_types[b't'[0]] | ||
@@ -418,3 +428,5 @@ __slots__ = () | ||
| class TupleDescriptor(TupleMessage): | ||
| """Tuple description""" | ||
| """ | ||
| Tuple structure description. | ||
| """ | ||
| type = message_types[b'T'[0]] | ||
@@ -451,3 +463,5 @@ struct = Struct("!LhLhlh") | ||
| class Tuple(TupleMessage): | ||
| """Incoming tuple""" | ||
| """ | ||
| Tuple Data. | ||
| """ | ||
| type = message_types[b'D'[0]] | ||
@@ -490,3 +504,5 @@ __slots__ = () | ||
| class KillInformation(Message): | ||
| 'Backend cancellation information' | ||
| """ | ||
| Backend cancellation information. | ||
| """ | ||
| type = message_types[b'K'[0]] | ||
@@ -508,3 +524,5 @@ struct = Struct("!LL") | ||
| class CancelRequest(KillInformation): | ||
| 'Abort the query in the specified backend' | ||
| """ | ||
| Abort the query in the specified backend. | ||
| """ | ||
| type = b'' | ||
@@ -531,3 +549,5 @@ from .version import CancelRequestCode as version | ||
| class NegotiateSSL(Message): | ||
| "Discover backend's SSL support" | ||
| """ | ||
| Discover backend's SSL support. | ||
| """ | ||
| type = b'' | ||
@@ -618,3 +638,5 @@ from .version import NegotiateSSLCode as version | ||
| class Authentication(Message): | ||
| """Authentication(request, salt)""" | ||
| """ | ||
| Authentication(request, salt) | ||
| """ | ||
| type = message_types[b'R'[0]] | ||
@@ -635,3 +657,5 @@ __slots__ = ('request', 'salt') | ||
| class Password(StringMessage): | ||
| 'Password supplement' | ||
| """ | ||
| Password supplement. | ||
| """ | ||
| type = message_types[b'p'[0]] | ||
@@ -641,3 +665,5 @@ __slots__ = ('data',) | ||
| class Disconnect(EmptyMessage): | ||
| 'Close the connection' | ||
| """ | ||
| Connection closed message. | ||
| """ | ||
| type = message_types[b'X'[0]] | ||
@@ -649,3 +675,5 @@ __slots__ = () | ||
| class Flush(EmptyMessage): | ||
| 'Flush' | ||
| """ | ||
| Flush message. | ||
| """ | ||
| type = message_types[b'H'[0]] | ||
@@ -657,3 +685,5 @@ __slots__ = () | ||
| class Synchronize(EmptyMessage): | ||
| 'Synchronize' | ||
| """ | ||
| Synchronize. | ||
| """ | ||
| type = message_types[b'S'[0]] | ||
@@ -665,3 +695,5 @@ __slots__ = () | ||
| class Query(StringMessage): | ||
| """Execute the query with the given arguments""" | ||
| """ | ||
| Execute the query with the given arguments. | ||
| """ | ||
| type = message_types[b'Q'[0]] | ||
@@ -671,3 +703,5 @@ __slots__ = ('data',) | ||
| class Parse(Message): | ||
| """Parse a query with the specified argument types""" | ||
| """ | ||
| Parse a query with the specified argument types. | ||
| """ | ||
| type = message_types[b'P'[0]] | ||
@@ -761,3 +795,5 @@ __slots__ = ('name', 'statement', 'argtypes') | ||
| class Execute(Message): | ||
| """Fetch results from the specified Portal""" | ||
| """ | ||
| Fetch results from the specified Portal. | ||
| """ | ||
| type = message_types[b'E'[0]] | ||
@@ -779,3 +815,5 @@ __slots__ = ('name', 'max') | ||
| class Describe(StringMessage): | ||
| """Describe a Portal or Prepared Statement""" | ||
| """ | ||
| Request a description of a Portal or Prepared Statement. | ||
| """ | ||
| type = message_types[b'D'[0]] | ||
@@ -806,3 +844,5 @@ __slots__ = ('data',) | ||
| class Close(StringMessage): | ||
| """Generic Close""" | ||
| """ | ||
| Generic Close | ||
| """ | ||
| type = message_types[b'C'[0]] | ||
@@ -825,3 +865,5 @@ __slots__ = () | ||
| class CloseStatement(Close): | ||
| """Close the specified Statement""" | ||
| """ | ||
| Close the specified Statement | ||
| """ | ||
| subtype = message_types[b'S'[0]] | ||
@@ -831,3 +873,5 @@ __slots__ = () | ||
| class ClosePortal(Close): | ||
| """Close the specified Portal""" | ||
| """ | ||
| Close the specified Portal | ||
| """ | ||
| subtype = message_types[b'P'[0]] | ||
@@ -837,3 +881,6 @@ __slots__ = () | ||
| class Function(Message): | ||
| """Execute the specified function with the given arguments""" | ||
| """ | ||
| Execute the specified function with the given arguments | ||
| """ | ||
| type = message_types[b'F'[0]] | ||
@@ -907,3 +954,5 @@ __slots__ = ('oid', 'aformats', 'arguments', 'rformat') | ||
| class CopyToBegin(CopyBegin): | ||
| """Begin copying to""" | ||
| """ | ||
| Begin copying to. | ||
| """ | ||
| type = message_types[b'H'[0]] | ||
@@ -913,3 +962,5 @@ __slots__ = ('format', 'formats') | ||
| class CopyFromBegin(CopyBegin): | ||
| """Begin copying from""" | ||
| """ | ||
| Begin copying from. | ||
| """ | ||
| type = message_types[b'G'[0]] | ||
@@ -916,0 +967,0 @@ __slots__ = ('format', 'formats') |
| ## | ||
| # .protocol.version | ||
| ## | ||
| 'PQ version class' | ||
| """ | ||
| PQ version class used by startup messages. | ||
| """ | ||
| from struct import Struct | ||
@@ -9,3 +11,4 @@ version_struct = Struct('!HH') | ||
| class Version(tuple): | ||
| """Version((major, minor)) -> Version | ||
| """ | ||
| Version((major, minor)) -> Version | ||
@@ -17,3 +20,3 @@ Version serializer and parser. | ||
| def __new__(subtype, major_minor : '(major, minor)'): | ||
| def __new__(subtype, major_minor): | ||
| (major, minor) = major_minor | ||
@@ -20,0 +23,0 @@ major = int(major) |
@@ -235,3 +235,3 @@ ## | ||
| return | ||
| else: | ||
| else: | ||
| self.authok = self.authtype | ||
@@ -238,0 +238,0 @@ |
@@ -8,3 +8,2 @@ ## | ||
| import socket | ||
| import math | ||
| import errno | ||
@@ -55,3 +54,5 @@ import ssl | ||
| def secure(self, socket : socket.socket) -> ssl.SSLSocket: | ||
| "secure a socket with SSL" | ||
| """ | ||
| Secure a socket with SSL. | ||
| """ | ||
| if self.socket_secure is not None: | ||
@@ -74,5 +75,5 @@ return ssl.wrap_socket(socket, **self.socket_secure) | ||
| def __init__(self, | ||
| socket_create : "positional parameters given to socket.socket()", | ||
| socket_connect : "parameter given to socket.connect()", | ||
| socket_secure : "keywords given to ssl.wrap_socket" = None, | ||
| socket_create, | ||
| socket_connect, | ||
| socket_secure = None, | ||
| ): | ||
@@ -87,34 +88,17 @@ self.socket_create = socket_create | ||
| def find_available_port( | ||
| interface : "attempt to bind to interface" = 'localhost', | ||
| address_family : "address family to use (default: AF_INET)" = socket.AF_INET, | ||
| limit : "Number tries to make before giving up" = 1024, | ||
| port_range = (6600, 56600) | ||
| ) -> (int, None): | ||
| interface = 'localhost', | ||
| address_family = socket.AF_INET, | ||
| ): | ||
| """ | ||
| Find an available port on the given interface for the given address family. | ||
| Returns a port number that was successfully bound to or `None` if the | ||
| attempt limit was reached. | ||
| """ | ||
| i = 0 | ||
| while i < limit: | ||
| i += 1 | ||
| port = ( | ||
| math.floor( | ||
| random.random() * (port_range[1] - port_range[0]) | ||
| ) + port_range[0] | ||
| ) | ||
| s = socket.socket(address_family, socket.SOCK_STREAM,) | ||
| try: | ||
| s.bind(('localhost', port)) | ||
| s.close() | ||
| except socket.error as e: | ||
| s.close() | ||
| if e.errno in (errno.EACCES, errno.EADDRINUSE, errno.EINTR): | ||
| # try again | ||
| continue | ||
| break | ||
| else: | ||
| port = None | ||
| port = None | ||
| s = socket.socket(address_family, socket.SOCK_STREAM,) | ||
| try: | ||
| s.bind(('localhost', 0)) | ||
| port = s.getsockname()[1] | ||
| finally: | ||
| s.close() | ||
| return port |
@@ -16,10 +16,21 @@ ## | ||
| from ..project import version, name, identity as url | ||
| from distutils.core import Extension, Command | ||
| try: | ||
| from setuptools import Extension, Command | ||
| except ImportError as e: | ||
| from distutils.core import Extension, Command | ||
| LONG_DESCRIPTION = """ | ||
| .. warning:: | ||
| In v1.3, `postgresql.driver.dbapi20.connect` will now raise `ClientCannotConnectError` directly. | ||
| Exception traps around connect should still function, but the `__context__` attribute | ||
| on the error instance will be `None` in the usual failure case as it is no longer | ||
| incorrectly chained. Trapping `ClientCannotConnectError` ahead of `Error` should | ||
| allow both cases to co-exist in the event that data is being extracted from | ||
| the `ClientCannotConnectError`. | ||
| py-postgresql is a set of Python modules providing interfaces to various parts | ||
| of PostgreSQL. Notably, it provides a pure-Python driver + C optimizations for | ||
| of PostgreSQL. Primarily, it provides a pure-Python driver with some C optimizations for | ||
| querying a PostgreSQL database. | ||
| http://python.projects.postgresql.org | ||
| http://github.com/python-postgres/fe | ||
@@ -57,10 +68,2 @@ Features: | ||
| console with the database connection bound to the `db` name. | ||
| History | ||
| ------- | ||
| py-postgresql is not yet another PostgreSQL driver, it's been in development for | ||
| years. py-postgresql is the Python 3 port of the ``pg_proboscis`` driver and | ||
| integration of the other ``pg/python`` projects. | ||
| """ | ||
@@ -169,6 +172,7 @@ | ||
| 'long_description' : LONG_DESCRIPTION, | ||
| 'long_description_content_type' : 'text/x-rst', | ||
| 'author' : 'James William Pye', | ||
| 'author_email' : 'x@jwp.name', | ||
| 'author_email' : 'james.pye@gmail.com', | ||
| 'maintainer' : 'James William Pye', | ||
| 'maintainer_email' : 'python-general@pgfoundry.org', | ||
| 'maintainer_email' : 'james.pye@gmail.com', | ||
| 'url' : url, | ||
@@ -175,0 +179,0 @@ 'classifiers' : CLASSIFIERS, |
+21
-17
@@ -9,2 +9,3 @@ ## | ||
| import atexit | ||
| import builtins | ||
| from collections import deque | ||
@@ -114,2 +115,3 @@ from .cluster import Cluster, ClusterError | ||
| vi = installation.version_info | ||
| cluster = Cluster(installation, self.cluster_path,) | ||
@@ -127,5 +129,6 @@ | ||
| # Configure | ||
| self.cluster_port = find_available_port() | ||
| if self.cluster_port is None: | ||
| try: | ||
| self.cluster_port = find_available_port() | ||
| except: | ||
| # Rely on chain. | ||
| raise ClusterError( | ||
@@ -136,2 +139,6 @@ 'could not find a port for the test cluster on localhost', | ||
| if vi[:2] > (9,6): | ||
| # Default changed in 10.x | ||
| cluster.settings['max_wal_senders'] = '0' | ||
| cluster.settings.update(dict( | ||
@@ -144,2 +151,3 @@ port = str(self.cluster_port), | ||
| log_min_messages = 'FATAL', | ||
| max_prepared_transactions = '10', | ||
| )) | ||
@@ -156,6 +164,2 @@ | ||
| cluster.settings.update(dict( | ||
| max_prepared_transactions = '10', | ||
| )) | ||
| # Start it up. | ||
@@ -186,3 +190,3 @@ with open(self.logfile, 'w') as lfo: | ||
| # The new builtins. | ||
| builtins = { | ||
| local_builtins = { | ||
| 'db' : c, | ||
@@ -201,4 +205,4 @@ 'prepare' : c.prepare, | ||
| current = { | ||
| k : __builtins__[k] for k in self.builtins_keys | ||
| if k in __builtins__ | ||
| k : builtins.__dict__[k] for k in self.builtins_keys | ||
| if k in builtins.__dict__ | ||
| } | ||
@@ -208,8 +212,8 @@ self.builtins_stack.append((current, [])) | ||
| # Store and push. | ||
| self.builtins_stack.append((builtins, extras)) | ||
| __builtins__.update(builtins) | ||
| self.builtins_stack.append((local_builtins, extras)) | ||
| builtins.__dict__.update(local_builtins) | ||
| self.sandbox_id += 1 | ||
| def pop(self, exc, drop_schema = 'DROP SCHEMA sandbox{0} CASCADE'.format): | ||
| builtins, extras = self.builtins_stack.pop() | ||
| local_builtins, extras = self.builtins_stack.pop() | ||
| self.sandbox_id -= 1 | ||
@@ -219,3 +223,3 @@ | ||
| if len(self.builtins_stack) > 1: | ||
| __builtins__.update(self.builtins_stack[-1][0]) | ||
| builtins.__dict__.update(self.builtins_stack[-1][0]) | ||
| else: | ||
@@ -225,6 +229,6 @@ previous = self.builtins_stack.popleft() | ||
| if x in previous: | ||
| __builtins__[x] = previous[x] | ||
| builtins.__dict__[x] = previous[x] | ||
| else: | ||
| # Wasn't set before. | ||
| __builtins__.pop(x, None) | ||
| builtins.__dict__.pop(x, None) | ||
@@ -235,3 +239,3 @@ # close popped connection, but only if we're not in an interrupt. | ||
| # Interrupt then close. Just in case something is lingering. | ||
| for xdb in [builtins['db']] + list(extras): | ||
| for xdb in [local_builtins['db']] + list(extras): | ||
| if xdb.closed is False: | ||
@@ -238,0 +242,0 @@ # In order for a clean close of the connection, |
@@ -33,3 +33,4 @@ ## | ||
| if self.cluster.installation.version_info[:2] >= (9, 3): | ||
| vi = self.cluster.installation.version_info[:2] | ||
| if vi >= (9, 3): | ||
| usd = 'unix_socket_directories' | ||
@@ -39,2 +40,5 @@ else: | ||
| if vi > (9, 6): | ||
| self.cluster.settings['max_wal_senders'] = '0' | ||
| self.cluster.settings.update({ | ||
@@ -41,0 +45,0 @@ 'max_connections' : '8', |
@@ -54,3 +54,3 @@ ## | ||
| self.cluster_path = \ | ||
| 'py_unittest_pg_cluster_' \ | ||
| 'pypg_test_' \ | ||
| + str(os.getpid()) + getattr(self, 'cluster_path_suffix', '') | ||
@@ -72,2 +72,4 @@ | ||
| self.disable_replication = self.installation.version_info[:2] > (9, 6) | ||
| def configure_cluster(self): | ||
@@ -84,2 +86,3 @@ self.cluster_port = find_available_port() | ||
| listen_addresses += ',::1' | ||
| self.cluster.settings.update(dict( | ||
@@ -94,2 +97,7 @@ port = str(self.cluster_port), | ||
| if self.disable_replication: | ||
| self.cluster.settings.update({ | ||
| 'max_wal_senders': '0', | ||
| }) | ||
| if self.cluster.installation.version_info[:2] < (9, 3): | ||
@@ -164,12 +172,23 @@ self.cluster.settings.update(dict( | ||
| mk_common_users = """ | ||
| CREATE USER md5 WITH ENCRYPTED PASSWORD 'md5_password'; | ||
| CREATE USER password WITH ENCRYPTED PASSWORD 'password_password'; | ||
| CREATE USER trusted; | ||
| """ | ||
| mk_crypt_user = """ | ||
| -- crypt doesn't work with encrypted passwords: | ||
| -- http://www.postgresql.org/docs/8.2/interactive/auth-methods.html#AUTH-PASSWORD | ||
| CREATE USER crypt WITH UNENCRYPTED PASSWORD 'crypt_password'; | ||
| """ | ||
| def __init__(self, *args, **kw): | ||
| super().__init__(*args,**kw) | ||
| # 8.4 nixed this. | ||
| self.do_crypt = self.cluster.installation.version_info < (8,4) | ||
| vi = self.cluster.installation.version_info | ||
| self.check_crypt_user = (vi < (8,4)) | ||
| def configure_cluster(self): | ||
| super().configure_cluster() | ||
| self.cluster.settings.update({ | ||
| 'log_min_messages' : 'log', | ||
| }) | ||
| self.cluster.settings['log_min_messages'] = 'log' | ||
@@ -181,3 +200,4 @@ # Configure the hba file with the supported methods. | ||
| hosts.append('0::0/0') | ||
| methods = ['md5', 'password'] + (['crypt'] if self.do_crypt else []) | ||
| methods = ['md5', 'password'] + (['crypt'] if self.check_crypt_user else []) | ||
| for h in hosts: | ||
@@ -190,2 +210,3 @@ for m in methods: | ||
| )]) | ||
| # trusted | ||
@@ -203,23 +224,8 @@ hba.writelines(["local all all trust\n"]) | ||
| super().initialize_database() | ||
| with self.cluster.connection(user = 'test') as db: | ||
| db.execute( | ||
| """ | ||
| CREATE USER md5 WITH | ||
| ENCRYPTED PASSWORD 'md5_password' | ||
| ; | ||
| db.execute(self.mk_common_users) | ||
| if self.check_crypt_user: | ||
| db.execute(self.mk_crypt_user) | ||
| -- crypt doesn't work with encrypted passwords: | ||
| -- http://www.postgresql.org/docs/8.2/interactive/auth-methods.html#AUTH-PASSWORD | ||
| CREATE USER crypt WITH | ||
| UNENCRYPTED PASSWORD 'crypt_password' | ||
| ; | ||
| CREATE USER password WITH | ||
| ENCRYPTED PASSWORD 'password_password' | ||
| ; | ||
| CREATE USER trusted; | ||
| """ | ||
| ) | ||
| def test_pg_open_SQL_ASCII(self): | ||
@@ -375,3 +381,3 @@ # postgresql.open | ||
| if self.do_crypt: | ||
| if self.check_crypt_user: | ||
| CRYPT = dbapi20.connect( | ||
@@ -416,2 +422,13 @@ user = 'crypt', | ||
| def test_dbapi_connect_failure(self): | ||
| host, port = self.cluster.address() | ||
| badlogin = (lambda: dbapi20.connect( | ||
| user = '--', | ||
| database = '--', | ||
| password = '...', | ||
| host = host, port = port, | ||
| **self.params | ||
| )) | ||
| self.assertRaises(pg_exc.ClientCannotConnectError, badlogin) | ||
| def test_IP4_connect(self): | ||
@@ -462,3 +479,3 @@ C = pg_driver.default.ip4( | ||
| def test_crypt_connect(self): | ||
| if self.do_crypt: | ||
| if self.check_crypt_user: | ||
| c = self.cluster.connection( | ||
@@ -465,0 +482,0 @@ user = 'crypt', |
@@ -57,4 +57,4 @@ ## | ||
| This implementation tests Gadfly, but the TestCase | ||
| is structured so that other self.drivers can subclass this | ||
| test case to ensure compiliance with the DB-API. It is | ||
| is structured so that other self.drivers can subclass this | ||
| test case to ensure compiliance with the DB-API. It is | ||
| expected that this TestCase may be expanded in the future | ||
@@ -69,5 +69,5 @@ if ambiguities or edge conditions are discovered. | ||
| import dbapi20 | ||
| import dbapi20 | ||
| class mytest(dbapi20.DatabaseAPI20Test): | ||
| [...] | ||
| [...] | ||
@@ -103,6 +103,6 @@ __rcs_id__ = 'Id: dbapi20.py,v 1.10 2003/10/09 03:14:14 zenzen Exp' | ||
| for ddl in (self.xddl1, self.xddl2): | ||
| try: | ||
| try: | ||
| cur.execute(ddl) | ||
| con.commit() | ||
| except self.driver.Error: | ||
| except self.driver.Error: | ||
| # Assume table didn't exist. Other tests will check if | ||
@@ -109,0 +109,0 @@ # execute is busted. |
@@ -1815,3 +1815,3 @@ ## | ||
| # It just exercises the code path. | ||
| db.typio.identify(contrib_hstore = 'pg_catalog.reltime') | ||
| db.typio.identify(contrib_hstore = 'pg_catalog.text') | ||
@@ -1818,0 +1818,0 @@ @pg_tmp |
@@ -87,2 +87,18 @@ ## | ||
| class test_iri(unittest.TestCase): | ||
| def testIP6Hosts(self): | ||
| """ | ||
| Validate that IPv6 hosts are properly extracted. | ||
| """ | ||
| s = [ | ||
| ('pq://[::1]/db', '::1'), | ||
| ('pq://[::1]:1234/db', '::1'), | ||
| ('pq://[1:2:3::1]/db', '1:2:3::1'), | ||
| ('pq://[1:2:3::1]:1234/db', '1:2:3::1'), | ||
| ('pq://[]:1234/db', ''), | ||
| ('pq://[]/db', ''), | ||
| ] | ||
| for i, h in s: | ||
| p = pg_iri.parse(i) | ||
| self.assertEqual(p['host'], h) | ||
| def testPresentPasswordObscure(self): | ||
@@ -89,0 +105,0 @@ "password is present in IRI, and obscure it" |
@@ -142,5 +142,4 @@ ## | ||
| def testFindAvailable(self): | ||
| # the port is randomly generated, so make a few trials before | ||
| # determining success. | ||
| for i in range(100): | ||
| # Host sanity check; this is likely fragile. | ||
| for i in range(4): | ||
| portnum = find_available_port() | ||
@@ -147,0 +146,0 @@ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
+19
-2
| About | ||
| ===== | ||
| py-postgresql is a Python 3 package providing modules to work with PostgreSQL. | ||
| py-postgresql is a Python 3 package providing modules for working with PostgreSQL. | ||
| This includes a high-level driver, and many other tools that support a developer | ||
| working with PostgreSQL databases. | ||
| For a high performance async interface, MagicStack's asyncpg | ||
| http://github.com/MagicStack/asyncpg should be considered. | ||
| py-postgresql, currently, does not have direct support for high-level async | ||
| interfaces provided by recent versions of Python. Future versions may change this. | ||
| Errata | ||
| ------ | ||
| .. warning:: | ||
| In v1.3, `postgresql.driver.dbapi20.connect` will now raise `ClientCannotConnectError` directly. | ||
| Exception traps around connect should still function, but the `__context__` attribute | ||
| on the error instance will be `None` in the usual failure case as it is no longer | ||
| incorrectly chained. Trapping `ClientCannotConnectError` ahead of `Error` should | ||
| allow both cases to co-exist in the event that data is being extracted from | ||
| the `ClientCannotConnectError`. | ||
| Installation | ||
@@ -38,3 +55,3 @@ ------------ | ||
| http://python.projects.postgresql.org | ||
| http://py-postgresql.readthedocs.io | ||
@@ -41,0 +58,0 @@ Or, you can read them in your pager: python -m postgresql.documentation.index |
+4
-1
@@ -28,3 +28,6 @@ #!/usr/bin/env python | ||
| if __name__ == '__main__': | ||
| from distutils.core import setup | ||
| try: | ||
| from setuptools import setup | ||
| except ImportError as e: | ||
| from distutils.core import setup | ||
| setup(**defaults) |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Overview: module code — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../index.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>All modules for which code is available</h1> | ||
| <ul><li><a href="postgresql.html">postgresql</a></li> | ||
| <ul><li><a href="postgresql/alock.html">postgresql.alock</a></li> | ||
| <li><a href="postgresql/api.html">postgresql.api</a></li> | ||
| <li><a href="postgresql/cluster.html">postgresql.cluster</a></li> | ||
| <li><a href="postgresql/copyman.html">postgresql.copyman</a></li> | ||
| <li><a href="postgresql/exceptions.html">postgresql.exceptions</a></li> | ||
| <li><a href="postgresql/installation.html">postgresql.installation</a></li> | ||
| <li><a href="postgresql/string.html">postgresql.string</a></li> | ||
| <li><a href="postgresql/sys.html">postgresql.sys</a></li> | ||
| <li><a href="postgresql/temporal.html">postgresql.temporal</a></li> | ||
| </ul></ul> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>postgresql — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../index.html" /> | ||
| <link rel="up" title="Module code" href="index.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="index.html" accesskey="U">Module code</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Source code for postgresql</h1><div class="highlight"><pre> | ||
| <span class="c">##</span> | ||
| <span class="c"># py-postgresql root package</span> | ||
| <span class="c"># http://python.projects.postgresql.org</span> | ||
| <span class="c">##</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd">py-postgresql is a Python package for using PostgreSQL. This includes low-level</span> | ||
| <span class="sd">protocol tools, a driver(PG-API and DB-API), and cluster management tools.</span> | ||
| <span class="sd">If it's not documented in the narratives, `postgresql.documentation.index`, then</span> | ||
| <span class="sd">the stability of the APIs should *not* be trusted.</span> | ||
| <span class="sd">See <http://postgresql.org> for more information about PostgreSQL.</span> | ||
| <span class="sd">"""</span> | ||
| <span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span> | ||
| <span class="s">'__author__'</span><span class="p">,</span> | ||
| <span class="s">'__date__'</span><span class="p">,</span> | ||
| <span class="s">'__version__'</span><span class="p">,</span> | ||
| <span class="s">'__docformat__'</span><span class="p">,</span> | ||
| <span class="s">'version'</span><span class="p">,</span> | ||
| <span class="s">'version_info'</span><span class="p">,</span> | ||
| <span class="s">'open'</span><span class="p">,</span> | ||
| <span class="p">]</span> | ||
| <span class="c">#: The version string of py-postgresql.</span> | ||
| <span class="n">version</span> <span class="o">=</span> <span class="s">''</span> <span class="c"># overridden by subsequent import from .project.</span> | ||
| <span class="c">#: The version triple of py-postgresql: (major, minor, patch).</span> | ||
| <span class="n">version_info</span> <span class="o">=</span> <span class="p">()</span> <span class="c"># overridden by subsequent import from .project.</span> | ||
| <span class="c"># Optional.</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="kn">from</span> <span class="nn">.project</span> <span class="kn">import</span> <span class="n">version_info</span><span class="p">,</span> <span class="n">version</span><span class="p">,</span> \ | ||
| <span class="n">author</span> <span class="k">as</span> <span class="n">__author__</span><span class="p">,</span> <span class="n">date</span> <span class="k">as</span> <span class="n">__date__</span> | ||
| <span class="n">__version__</span> <span class="o">=</span> <span class="n">version</span> | ||
| <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span> | ||
| <span class="k">pass</span> | ||
| <span class="c"># Avoid importing these until requested.</span> | ||
| <span class="n">_pg_iri</span> <span class="o">=</span> <span class="n">_pg_driver</span> <span class="o">=</span> <span class="n">_pg_param</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <div class="viewcode-block" id="open"><a class="viewcode-back" href="../reference.html#postgresql.open">[docs]</a><span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">iri</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">prompt_title</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Create a `postgresql.api.Connection` to the server referenced by the given</span> | ||
| <span class="sd"> `iri`::</span> | ||
| <span class="sd"> >>> import postgresql</span> | ||
| <span class="sd"> # General Format:</span> | ||
| <span class="sd"> >>> db = postgresql.open('pq://user:password@host:port/database')</span> | ||
| <span class="sd"> # Connect to 'postgres' at localhost.</span> | ||
| <span class="sd"> >>> db = postgresql.open('localhost/postgres')</span> | ||
| <span class="sd"> Connection keywords can also be used with `open`. See the narratives for</span> | ||
| <span class="sd"> more information.</span> | ||
| <span class="sd"> The `prompt_title` keyword is ignored. `open` will never prompt for</span> | ||
| <span class="sd"> the password unless it is explicitly instructed to do so.</span> | ||
| <span class="sd"> (Note: "pq" is the name of the protocol used to communicate with PostgreSQL)</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">global</span> <span class="n">_pg_iri</span><span class="p">,</span> <span class="n">_pg_driver</span><span class="p">,</span> <span class="n">_pg_param</span> | ||
| <span class="k">if</span> <span class="n">_pg_iri</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">iri</span> <span class="k">as</span> <span class="n">_pg_iri</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">driver</span> <span class="k">as</span> <span class="n">_pg_driver</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">clientparameters</span> <span class="k">as</span> <span class="n">_pg_param</span> | ||
| <span class="n">return_connector</span> <span class="o">=</span> <span class="bp">False</span> | ||
| <span class="k">if</span> <span class="n">iri</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">iri</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'&'</span><span class="p">):</span> | ||
| <span class="n">return_connector</span> <span class="o">=</span> <span class="bp">True</span> | ||
| <span class="n">iri</span> <span class="o">=</span> <span class="n">iri</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> | ||
| <span class="n">iri_params</span> <span class="o">=</span> <span class="n">_pg_iri</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">iri</span><span class="p">)</span> | ||
| <span class="n">iri_params</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'path'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">iri_params</span> <span class="o">=</span> <span class="p">{}</span> | ||
| <span class="n">std_params</span> <span class="o">=</span> <span class="n">_pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">prompt_title</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="c"># If unix is specified, it's going to conflict with any standard</span> | ||
| <span class="c"># settings, so remove them right here.</span> | ||
| <span class="k">if</span> <span class="s">'unix'</span> <span class="ow">in</span> <span class="n">kw</span> <span class="ow">or</span> <span class="s">'unix'</span> <span class="ow">in</span> <span class="n">iri_params</span><span class="p">:</span> | ||
| <span class="n">std_params</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'host'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="n">std_params</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'port'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="n">params</span> <span class="o">=</span> <span class="n">_pg_param</span><span class="o">.</span><span class="n">normalize</span><span class="p">(</span> | ||
| <span class="nb">list</span><span class="p">(</span><span class="n">_pg_param</span><span class="o">.</span><span class="n">denormalize_parameters</span><span class="p">(</span><span class="n">std_params</span><span class="p">))</span> <span class="o">+</span> \ | ||
| <span class="nb">list</span><span class="p">(</span><span class="n">_pg_param</span><span class="o">.</span><span class="n">denormalize_parameters</span><span class="p">(</span><span class="n">iri_params</span><span class="p">))</span> <span class="o">+</span> \ | ||
| <span class="nb">list</span><span class="p">(</span><span class="n">_pg_param</span><span class="o">.</span><span class="n">denormalize_parameters</span><span class="p">(</span><span class="n">kw</span><span class="p">))</span> | ||
| <span class="p">)</span> | ||
| <span class="n">_pg_param</span><span class="o">.</span><span class="n">resolve_password</span><span class="p">(</span><span class="n">params</span><span class="p">)</span> | ||
| <span class="n">C</span> <span class="o">=</span> <span class="n">_pg_driver</span><span class="o">.</span><span class="n">default</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="o">**</span><span class="n">params</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">return_connector</span> <span class="ow">is</span> <span class="bp">True</span><span class="p">:</span> | ||
| <span class="k">return</span> <span class="n">C</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">c</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span> | ||
| <span class="n">c</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> | ||
| <span class="k">return</span> <span class="n">c</span> | ||
| </div> | ||
| <span class="n">__docformat__</span> <span class="o">=</span> <span class="s">'reStructuredText'</span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="index.html" >Module code</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>postgresql.alock — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../../index.html" /> | ||
| <link rel="up" title="postgresql" href="../postgresql.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" accesskey="U">postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Source code for postgresql.alock</h1><div class="highlight"><pre> | ||
| <span class="c">##</span> | ||
| <span class="c"># .alock - Advisory Locks</span> | ||
| <span class="c">##</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd">Tools for Advisory Locks</span> | ||
| <span class="sd">"""</span> | ||
| <span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">abstractmethod</span><span class="p">,</span> <span class="n">abstractproperty</span> | ||
| <span class="kn">from</span> <span class="nn">.python.element</span> <span class="kn">import</span> <span class="n">Element</span> | ||
| <span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span> | ||
| <span class="s">'ALock'</span><span class="p">,</span> | ||
| <span class="s">'ExclusiveLock'</span><span class="p">,</span> | ||
| <span class="s">'ShareLock'</span><span class="p">,</span> | ||
| <span class="p">]</span> | ||
| <div class="viewcode-block" id="ALock"><a class="viewcode-back" href="../../reference.html#postgresql.alock.ALock">[docs]</a><span class="k">class</span> <span class="nc">ALock</span><span class="p">(</span><span class="n">Element</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Advisory Lock class for managing the acquisition and release of a sequence</span> | ||
| <span class="sd"> of PostgreSQL advisory locks.</span> | ||
| <span class="sd"> ALock()'s are fairly consistent with threading.RLock()'s. They can be</span> | ||
| <span class="sd"> acquired multiple times, and they must be released the same number of times</span> | ||
| <span class="sd"> for the lock to actually be released.</span> | ||
| <span class="sd"> A notably difference is that ALock's manage a sequence of lock identifiers.</span> | ||
| <span class="sd"> This means that a given ALock() may represent multiple advisory locks.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">_e_factors</span> <span class="o">=</span> <span class="p">(</span><span class="s">'database'</span><span class="p">,</span> <span class="s">'identifiers'</span><span class="p">,)</span> | ||
| <span class="n">_e_label</span> <span class="o">=</span> <span class="s">'ALOCK'</span> | ||
| <span class="k">def</span> <span class="nf">_e_metas</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> | ||
| <span class="n">headfmt</span> <span class="o">=</span> <span class="s">"{1} [{0}]"</span><span class="o">.</span><span class="n">format</span> | ||
| <span class="p">):</span> | ||
| <span class="k">yield</span> <span class="bp">None</span><span class="p">,</span> <span class="n">headfmt</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">state</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">mode</span><span class="p">)</span> | ||
| <span class="nd">@abstractproperty</span> | ||
| <div class="viewcode-block" id="ALock.mode"><a class="viewcode-back" href="../../reference.html#postgresql.alock.ALock.mode">[docs]</a> <span class="k">def</span> <span class="nf">mode</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> The mode of the lock class.</span> | ||
| <span class="sd"> """</span> | ||
| </div> | ||
| <span class="nd">@abstractproperty</span> | ||
| <span class="k">def</span> <span class="nf">__select_statements__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Implemented by subclasses to return the statements to try, acquire, and</span> | ||
| <span class="sd"> release the advisory lock.</span> | ||
| <span class="sd"> Returns a triple of callables where each callable takes two arguments,</span> | ||
| <span class="sd"> the lock-id pairs, and then the int8 lock-ids.</span> | ||
| <span class="sd"> ``(try, acquire, release)``.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="nd">@staticmethod</span> | ||
| <span class="k">def</span> <span class="nf">_split_lock_identifiers</span><span class="p">(</span><span class="n">idseq</span><span class="p">):</span> | ||
| <span class="c"># lame O(2)</span> | ||
| <span class="n">id_pairs</span> <span class="o">=</span> <span class="p">[</span> | ||
| <span class="nb">list</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">__class__</span> <span class="ow">is</span> <span class="ow">not</span> <span class="nb">int</span> <span class="k">else</span> <span class="p">[</span><span class="bp">None</span><span class="p">,</span><span class="bp">None</span><span class="p">]</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">idseq</span> | ||
| <span class="p">]</span> | ||
| <span class="n">ids</span> <span class="o">=</span> <span class="p">[</span> | ||
| <span class="n">x</span> <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">__class__</span> <span class="ow">is</span> <span class="nb">int</span> <span class="k">else</span> <span class="bp">None</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">idseq</span> | ||
| <span class="p">]</span> | ||
| <span class="k">return</span> <span class="p">(</span><span class="n">id_pairs</span><span class="p">,</span> <span class="n">ids</span><span class="p">)</span> | ||
| <div class="viewcode-block" id="ALock.acquire"><a class="viewcode-back" href="../../reference.html#postgresql.alock.ALock.acquire">[docs]</a> <span class="k">def</span> <span class="nf">acquire</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">blocking</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="nb">len</span> <span class="o">=</span> <span class="nb">len</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Acquire the locks using the configured identifiers.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> | ||
| <span class="c"># _count is zero, so the locks need to be acquired.</span> | ||
| <span class="n">wait</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="n">blocking</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">wait</span><span class="p">:</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_acquire</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_id_pairs</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_ids</span><span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># grab the success of each lock id. if some were</span> | ||
| <span class="c"># unsuccessful, then the ones that were successful need to be</span> | ||
| <span class="c"># released.</span> | ||
| <span class="n">r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_try</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_id_pairs</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_ids</span><span class="p">)</span> | ||
| <span class="c"># accumulate the identifiers that *did* lock</span> | ||
| <span class="n">release_seq</span> <span class="o">=</span> <span class="p">[</span> | ||
| <span class="nb">id</span> <span class="k">for</span> <span class="n">didlock</span><span class="p">,</span> <span class="nb">id</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">identifiers</span><span class="p">)</span> <span class="k">if</span> <span class="n">didlock</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> | ||
| <span class="p">]</span> | ||
| <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">release_seq</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">identifiers</span><span class="p">):</span> | ||
| <span class="c"># some failed, so release the acquired and return False</span> | ||
| <span class="c">#</span> | ||
| <span class="c"># reverse in case there is another waiting for all.</span> | ||
| <span class="c"># that is, release last-to-first so that if another is waiting</span> | ||
| <span class="c"># on the same seq that it should be able to acquire all of</span> | ||
| <span class="c"># them once the contended lock is released.</span> | ||
| <span class="n">release_seq</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_release</span><span class="p">(</span><span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">_split_lock_identifiers</span><span class="p">(</span><span class="n">release_seq</span><span class="p">))</span> | ||
| <span class="c"># unable to acquire all.</span> | ||
| <span class="k">return</span> <span class="bp">False</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">+</span> <span class="mi">1</span> | ||
| <span class="k">return</span> <span class="bp">True</span> | ||
| </div> | ||
| <span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span> | ||
| <span class="k">return</span> <span class="bp">self</span> | ||
| <div class="viewcode-block" id="ALock.release"><a class="viewcode-back" href="../../reference.html#postgresql.alock.ALock.release">[docs]</a> <span class="k">def</span> <span class="nf">release</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Release the locks using the configured identifiers.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o"><</span> <span class="mi">1</span><span class="p">:</span> | ||
| <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s">"cannot release un-acquired lock"</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">closed</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span> | ||
| <span class="c"># if the database has been closed, or the count will</span> | ||
| <span class="c"># remain non-zero, there is no need to release.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_release</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_id_pairs</span><span class="p">),</span> <span class="nb">reversed</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_ids</span><span class="p">))</span> | ||
| <span class="c"># decrement the count nonetheless.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">-</span> <span class="mi">1</span> | ||
| </div> | ||
| <span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">typ</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">tb</span><span class="p">):</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">release</span><span class="p">()</span> | ||
| <div class="viewcode-block" id="ALock.locked"><a class="viewcode-back" href="../../reference.html#postgresql.alock.ALock.locked">[docs]</a> <span class="k">def</span> <span class="nf">locked</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Whether the locks have been acquired. This method is sensitive to the</span> | ||
| <span class="sd"> connection's state. If the connection is closed, it will return False.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">closed</span><span class="p">)</span> | ||
| </div> | ||
| <span class="nd">@property</span> | ||
| <span class="k">def</span> <span class="nf">state</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="s">'locked'</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">locked</span><span class="p">()</span> <span class="k">else</span> <span class="s">'unlocked'</span> | ||
| <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">database</span><span class="p">,</span> <span class="o">*</span><span class="n">identifiers</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Initialize the lock object to manage a sequence of advisory locks</span> | ||
| <span class="sd"> for use with the given database.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_count</span> <span class="o">=</span> <span class="mi">0</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">database</span> <span class="o">=</span> <span class="n">database</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">identifiers</span> <span class="o">=</span> <span class="n">identifiers</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_id_pairs</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_ids</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_split_lock_identifiers</span><span class="p">(</span><span class="n">identifiers</span><span class="p">)</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_try</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_acquire</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_release</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__select_statements__</span><span class="p">()</span> | ||
| </div> | ||
| <span class="k">class</span> <span class="nc">ShareLock</span><span class="p">(</span><span class="n">ALock</span><span class="p">):</span> | ||
| <span class="n">mode</span> <span class="o">=</span> <span class="s">'share'</span> | ||
| <span class="k">def</span> <span class="nf">__select_statements__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="p">(</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">try_advisory_shared</span><span class="p">,</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">acquire_advisory_shared</span><span class="p">,</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">release_advisory_shared</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| <span class="k">class</span> <span class="nc">ExclusiveLock</span><span class="p">(</span><span class="n">ALock</span><span class="p">):</span> | ||
| <span class="n">mode</span> <span class="o">=</span> <span class="s">'exclusive'</span> | ||
| <span class="k">def</span> <span class="nf">__select_statements__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="p">(</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">try_advisory_exclusive</span><span class="p">,</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">acquire_advisory_exclusive</span><span class="p">,</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">database</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">release_advisory_exclusive</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" >postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>postgresql.installation — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../../index.html" /> | ||
| <link rel="up" title="postgresql" href="../postgresql.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" accesskey="U">postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Source code for postgresql.installation</h1><div class="highlight"><pre> | ||
| <span class="c">##</span> | ||
| <span class="c"># .installation</span> | ||
| <span class="c">##</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd">Collect and access PostgreSQL installation information.</span> | ||
| <span class="sd">"""</span> | ||
| <span class="kn">import</span> <span class="nn">sys</span> | ||
| <span class="kn">import</span> <span class="nn">os</span> | ||
| <span class="kn">import</span> <span class="nn">os.path</span> | ||
| <span class="kn">import</span> <span class="nn">subprocess</span> | ||
| <span class="kn">import</span> <span class="nn">io</span> | ||
| <span class="kn">import</span> <span class="nn">errno</span> | ||
| <span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">cycle</span><span class="p">,</span> <span class="n">chain</span> | ||
| <span class="kn">from</span> <span class="nn">operator</span> <span class="kn">import</span> <span class="n">itemgetter</span> | ||
| <span class="kn">from</span> <span class="nn">.python.os</span> <span class="kn">import</span> <span class="n">find_executable</span><span class="p">,</span> <span class="n">close_fds</span><span class="p">,</span> <span class="n">platform_exe</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">versionstring</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">api</span> <span class="k">as</span> <span class="n">pg_api</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">string</span> <span class="k">as</span> <span class="n">pg_str</span> | ||
| <span class="c"># Get the output from the given command.</span> | ||
| <span class="c"># *args are transformed into "long options", '--' + x</span> | ||
| <span class="k">def</span> <span class="nf">get_command_output</span><span class="p">(</span><span class="n">exe</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span> | ||
| <span class="n">pa</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">exe</span><span class="p">)</span> <span class="o">+</span> <span class="p">[</span> | ||
| <span class="s">'--'</span> <span class="o">+</span> <span class="n">x</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">args</span> <span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> | ||
| <span class="p">]</span> | ||
| <span class="n">p</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">(</span><span class="n">pa</span><span class="p">,</span> | ||
| <span class="n">close_fds</span> <span class="o">=</span> <span class="n">close_fds</span><span class="p">,</span> | ||
| <span class="n">stdout</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> | ||
| <span class="n">stderr</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> | ||
| <span class="n">stdin</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> | ||
| <span class="n">shell</span> <span class="o">=</span> <span class="bp">False</span> | ||
| <span class="p">)</span> | ||
| <span class="n">p</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> | ||
| <span class="n">p</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> | ||
| <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">rv</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span> | ||
| <span class="k">break</span> | ||
| <span class="k">except</span> <span class="ne">OSError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">e</span><span class="o">.</span><span class="n">errno</span> <span class="o">!=</span> <span class="n">errno</span><span class="o">.</span><span class="n">EINTR</span><span class="p">:</span> | ||
| <span class="k">raise</span> | ||
| <span class="k">if</span> <span class="n">rv</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span> | ||
| <span class="k">return</span> <span class="bp">None</span> | ||
| <span class="k">with</span> <span class="n">p</span><span class="o">.</span><span class="n">stdout</span><span class="p">,</span> <span class="n">io</span><span class="o">.</span><span class="n">TextIOWrapper</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">stdout</span><span class="p">)</span> <span class="k">as</span> <span class="n">txt</span><span class="p">:</span> | ||
| <span class="k">return</span> <span class="n">txt</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> | ||
| <div class="viewcode-block" id="pg_config_dictionary"><a class="viewcode-back" href="../../reference.html#postgresql.installation.pg_config_dictionary">[docs]</a><span class="k">def</span> <span class="nf">pg_config_dictionary</span><span class="p">(</span><span class="o">*</span><span class="n">pg_config_path</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Create a dictionary of the information available in the given</span> | ||
| <span class="sd"> pg_config_path. This provides a one-shot solution to fetching information</span> | ||
| <span class="sd"> from the pg_config binary. Returns a dictionary object.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">default_output</span> <span class="o">=</span> <span class="n">get_command_output</span><span class="p">(</span><span class="n">pg_config_path</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">default_output</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="n">d</span> <span class="o">=</span> <span class="p">{}</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">default_output</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span> | ||
| <span class="k">if</span> <span class="ow">not</span> <span class="n">x</span> <span class="ow">or</span> <span class="n">x</span><span class="o">.</span><span class="n">isspace</span><span class="p">()</span> <span class="ow">or</span> <span class="n">x</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">'='</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="k">continue</span> | ||
| <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'='</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> | ||
| <span class="c"># keep it semi-consistent with instance</span> | ||
| <span class="n">d</span><span class="p">[</span><span class="n">k</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()]</span> <span class="o">=</span> <span class="n">v</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> | ||
| <span class="k">return</span> <span class="n">d</span> | ||
| <span class="c"># Support for 8.0 pg_config and earlier.</span> | ||
| <span class="c"># This requires three invocations of pg_config:</span> | ||
| <span class="c"># First --help, to get the -- options available,</span> | ||
| <span class="c"># Second, all the -- options except version.</span> | ||
| <span class="c"># Third, --version as it appears to be exclusive in some cases.</span> | ||
| <span class="n">opt</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">get_command_output</span><span class="p">(</span><span class="n">pg_config_path</span><span class="p">,</span> <span class="s">'help'</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span> | ||
| <span class="n">dash_pos</span> <span class="o">=</span> <span class="n">l</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">'--'</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">dash_pos</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="k">continue</span> | ||
| <span class="n">sp_pos</span> <span class="o">=</span> <span class="n">l</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s">' '</span><span class="p">,</span> <span class="n">dash_pos</span><span class="p">)</span> | ||
| <span class="c"># the dashes are added by the call command</span> | ||
| <span class="n">opt</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">dash_pos</span><span class="o">+</span><span class="mi">2</span><span class="p">:</span><span class="n">sp_pos</span><span class="p">])</span> | ||
| <span class="k">if</span> <span class="s">'help'</span> <span class="ow">in</span> <span class="n">opt</span><span class="p">:</span> | ||
| <span class="n">opt</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s">'help'</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="s">'version'</span> <span class="ow">in</span> <span class="n">opt</span><span class="p">:</span> | ||
| <span class="n">opt</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s">'version'</span><span class="p">)</span> | ||
| <span class="n">d</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">opt</span><span class="p">,</span> <span class="n">get_command_output</span><span class="p">(</span><span class="n">pg_config_path</span><span class="p">,</span> <span class="o">*</span><span class="n">opt</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()))</span> | ||
| <span class="n">d</span><span class="p">[</span><span class="s">'version'</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_command_output</span><span class="p">(</span><span class="n">pg_config_path</span><span class="p">,</span> <span class="s">'version'</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> | ||
| <span class="k">return</span> <span class="n">d</span> | ||
| <span class="c">##</span> | ||
| <span class="c"># Build a key-value pair list of the configure options.</span> | ||
| <span class="c"># If the item is quoted, mind the quotes.</span></div> | ||
| <span class="k">def</span> <span class="nf">parse_configure_options</span><span class="p">(</span><span class="n">confopt</span><span class="p">,</span> <span class="n">quotes</span> <span class="o">=</span> <span class="s">'</span><span class="se">\'</span><span class="s">"'</span><span class="p">,</span> <span class="n">dash_and_quotes</span> <span class="o">=</span> <span class="s">'-</span><span class="se">\'</span><span class="s">"'</span><span class="p">):</span> | ||
| <span class="c"># This is not a robust solution, but it will usually work.</span> | ||
| <span class="c"># Chances are that there is a quote at the beginning of this string.</span> | ||
| <span class="c"># However, in the windows pg_config.exe, this appears to be absent.</span> | ||
| <span class="k">if</span> <span class="n">confopt</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">1</span><span class="p">]</span> <span class="ow">in</span> <span class="n">quotes</span><span class="p">:</span> | ||
| <span class="c"># quote at the beginning. assume it's used consistently.</span> | ||
| <span class="n">quote</span> <span class="o">=</span> <span class="n">confopt</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">1</span><span class="p">]</span> | ||
| <span class="k">elif</span> <span class="n">confopt</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">:]</span> <span class="ow">in</span> <span class="n">quotes</span><span class="p">:</span> | ||
| <span class="c"># quote at the end?</span> | ||
| <span class="n">quote</span> <span class="o">=</span> <span class="n">confopt</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># fallback to something. :(</span> | ||
| <span class="n">quote</span> <span class="o">=</span> <span class="s">"'"</span> | ||
| <span class="c">##</span> | ||
| <span class="c"># This is using the wrong kind of split, but the pg_config</span> | ||
| <span class="c"># output has been consistent enough for this to work.</span> | ||
| <span class="n">parts</span> <span class="o">=</span> <span class="n">pg_str</span><span class="o">.</span><span class="n">split_using</span><span class="p">(</span><span class="n">confopt</span><span class="p">,</span> <span class="n">quote</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">' '</span><span class="p">)</span> | ||
| <span class="n">qq</span> <span class="o">=</span> <span class="n">quote</span> <span class="o">*</span> <span class="mi">2</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">parts</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">qq</span> <span class="ow">in</span> <span class="n">x</span><span class="p">:</span> | ||
| <span class="c"># singularize the quotes</span> | ||
| <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">qq</span><span class="p">,</span> <span class="n">quote</span><span class="p">)</span> | ||
| <span class="c"># remove the quotes around '--' from option.</span> | ||
| <span class="c"># if it splits once, the '1' index will</span> | ||
| <span class="c"># be `True`, indicating that the flag was given, but</span> | ||
| <span class="c"># was not given a value.</span> | ||
| <span class="n">kv</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="n">dash_and_quotes</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'='</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="p">[</span><span class="bp">True</span><span class="p">]</span> | ||
| <span class="n">key</span> <span class="o">=</span> <span class="n">kv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'-'</span><span class="p">,</span><span class="s">'_'</span><span class="p">)</span> | ||
| <span class="c"># Ignore empty keys.</span> | ||
| <span class="k">if</span> <span class="n">key</span><span class="p">:</span> | ||
| <span class="k">yield</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">kv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> | ||
| <div class="viewcode-block" id="default_pg_config"><a class="viewcode-back" href="../../reference.html#postgresql.installation.default_pg_config">[docs]</a><span class="k">def</span> <span class="nf">default_pg_config</span><span class="p">(</span><span class="n">execname</span> <span class="o">=</span> <span class="s">'pg_config'</span><span class="p">,</span> <span class="n">envkey</span> <span class="o">=</span> <span class="s">'PGINSTALLATION'</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Get the default `pg_config` executable on the system.</span> | ||
| <span class="sd"> If 'PGINSTALLATION' is in the environment, use it.</span> | ||
| <span class="sd"> Otherwise, look through the system's PATH environment.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">pg_config_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">envkey</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">pg_config_path</span><span class="p">:</span> | ||
| <span class="c"># Trust PGINSTALLATION.</span> | ||
| <span class="k">return</span> <span class="n">platform_exe</span><span class="p">(</span><span class="n">pg_config_path</span><span class="p">)</span> | ||
| <span class="k">return</span> <span class="n">find_executable</span><span class="p">(</span><span class="n">execname</span><span class="p">)</span> | ||
| </div> | ||
| <div class="viewcode-block" id="Installation"><a class="viewcode-back" href="../../reference.html#postgresql.installation.Installation">[docs]</a><span class="k">class</span> <span class="nc">Installation</span><span class="p">(</span><span class="n">pg_api</span><span class="o">.</span><span class="n">Installation</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Class providing a Python interface to PostgreSQL installation information.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">version</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="n">version_info</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="nb">type</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="n">configure_options</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="c">#: The pg_config information dictionary.</span> | ||
| <span class="n">info</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="n">pg_executables</span> <span class="o">=</span> <span class="p">(</span> | ||
| <span class="s">'pg_config'</span><span class="p">,</span> | ||
| <span class="s">'psql'</span><span class="p">,</span> | ||
| <span class="s">'initdb'</span><span class="p">,</span> | ||
| <span class="s">'pg_resetxlog'</span><span class="p">,</span> | ||
| <span class="s">'pg_controldata'</span><span class="p">,</span> | ||
| <span class="s">'clusterdb'</span><span class="p">,</span> | ||
| <span class="s">'pg_ctl'</span><span class="p">,</span> | ||
| <span class="s">'pg_dump'</span><span class="p">,</span> | ||
| <span class="s">'pg_dumpall'</span><span class="p">,</span> | ||
| <span class="s">'postgres'</span><span class="p">,</span> | ||
| <span class="s">'postmaster'</span><span class="p">,</span> | ||
| <span class="s">'reindexdb'</span><span class="p">,</span> | ||
| <span class="s">'vacuumdb'</span><span class="p">,</span> | ||
| <span class="s">'ipcclean'</span><span class="p">,</span> | ||
| <span class="s">'createdb'</span><span class="p">,</span> | ||
| <span class="s">'ecpg'</span><span class="p">,</span> | ||
| <span class="s">'createuser'</span><span class="p">,</span> | ||
| <span class="s">'createlang'</span><span class="p">,</span> | ||
| <span class="s">'droplang'</span><span class="p">,</span> | ||
| <span class="s">'dropuser'</span><span class="p">,</span> | ||
| <span class="s">'pg_restore'</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| <span class="n">pg_libraries</span> <span class="o">=</span> <span class="p">(</span> | ||
| <span class="s">'libpq'</span><span class="p">,</span> | ||
| <span class="s">'libecpg'</span><span class="p">,</span> | ||
| <span class="s">'libpgtypes'</span><span class="p">,</span> | ||
| <span class="s">'libecpg_compat'</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| <span class="n">pg_directories</span> <span class="o">=</span> <span class="p">(</span> | ||
| <span class="s">'bindir'</span><span class="p">,</span> | ||
| <span class="s">'docdir'</span><span class="p">,</span> | ||
| <span class="s">'includedir'</span><span class="p">,</span> | ||
| <span class="s">'pkgincludedir'</span><span class="p">,</span> | ||
| <span class="s">'includedir_server'</span><span class="p">,</span> | ||
| <span class="s">'libdir'</span><span class="p">,</span> | ||
| <span class="s">'pkglibdir'</span><span class="p">,</span> | ||
| <span class="s">'localedir'</span><span class="p">,</span> | ||
| <span class="s">'mandir'</span><span class="p">,</span> | ||
| <span class="s">'sharedir'</span><span class="p">,</span> | ||
| <span class="s">'sysconfdir'</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| <span class="k">def</span> <span class="nf">_e_metas</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="n">l</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">configure_options</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> | ||
| <span class="n">l</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span> <span class="o">=</span> <span class="n">itemgetter</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> | ||
| <span class="k">yield</span> <span class="p">(</span><span class="s">'version'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">l</span><span class="p">:</span> | ||
| <span class="k">yield</span> <span class="p">(</span><span class="s">'configure_options'</span><span class="p">,</span> | ||
| <span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">((</span> | ||
| <span class="n">k</span> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="bp">True</span> <span class="k">else</span> <span class="n">k</span> <span class="o">+</span> <span class="s">'='</span> <span class="o">+</span> <span class="n">v</span> | ||
| <span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="ow">in</span> <span class="n">l</span> | ||
| <span class="p">))</span> | ||
| <span class="p">)</span> | ||
| <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">format</span> <span class="o">=</span> <span class="s">"{mod}.{name}({info!r})"</span><span class="o">.</span><span class="n">format</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="n">format</span><span class="p">(</span> | ||
| <span class="n">mod</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__module__</span><span class="p">,</span> | ||
| <span class="n">name</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> | ||
| <span class="n">info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info</span> | ||
| <span class="p">)</span> | ||
| <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">info</span> <span class="p">:</span> <span class="nb">dict</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Initialize the Installation using the given information dictionary.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">info</span> <span class="o">=</span> <span class="n">info</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="p">[</span><span class="s">"version"</span><span class="p">]</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="n">vs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span><span class="o">.</span><span class="n">split</span><span class="p">()</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">version_info</span> <span class="o">=</span> <span class="n">versionstring</span><span class="o">.</span><span class="n">normalize</span><span class="p">(</span><span class="n">versionstring</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">vs</span><span class="p">))</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">configure_options</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span> | ||
| <span class="n">parse_configure_options</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'configure'</span><span class="p">,</span> <span class="s">''</span><span class="p">))</span> | ||
| <span class="p">)</span> | ||
| <span class="c"># collect the paths in a dictionary first</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">paths</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> | ||
| <span class="n">exists</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span> | ||
| <span class="n">join</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span> | ||
| <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg_directories</span><span class="p">:</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">paths</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> | ||
| <span class="c"># find all the PG executables that exist for the installation.</span> | ||
| <span class="n">bindir_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'bindir'</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">bindir_path</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">paths</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pg_executables</span><span class="p">,</span> <span class="n">cycle</span><span class="p">((</span><span class="bp">None</span><span class="p">,))))</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pg_executables</span><span class="p">:</span> | ||
| <span class="n">path</span> <span class="o">=</span> <span class="n">platform_exe</span><span class="p">(</span><span class="n">join</span><span class="p">(</span><span class="n">bindir_path</span><span class="p">,</span> <span class="n">k</span><span class="p">))</span> | ||
| <span class="k">if</span> <span class="n">exists</span><span class="p">(</span><span class="n">path</span><span class="p">):</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">paths</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">path</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">paths</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">paths</span><span class="p">)</span> | ||
| <span class="nd">@property</span> | ||
| <div class="viewcode-block" id="Installation.ssl"><a class="viewcode-back" href="../../reference.html#postgresql.installation.Installation.ssl">[docs]</a> <span class="k">def</span> <span class="nf">ssl</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Whether the installation was compiled with SSL support.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">return</span> <span class="s">'with_openssl'</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">configure_options</span> | ||
| </div></div> | ||
| <div class="viewcode-block" id="default"><a class="viewcode-back" href="../../reference.html#postgresql.installation.default">[docs]</a><span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="n">typ</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Get the default Installation.</span> | ||
| <span class="sd"> Uses default_pg_config() to identify the executable.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">path</span> <span class="o">=</span> <span class="n">default_pg_config</span><span class="p">()</span> | ||
| <span class="k">if</span> <span class="n">path</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="k">return</span> <span class="bp">None</span> | ||
| <span class="k">return</span> <span class="n">typ</span><span class="p">(</span><span class="n">pg_config_dictionary</span><span class="p">(</span><span class="n">path</span><span class="p">))</span> | ||
| </div> | ||
| <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span> | ||
| <span class="n">d</span> <span class="o">=</span> <span class="n">pg_config_dictionary</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> | ||
| <span class="n">i</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">i</span> <span class="o">=</span> <span class="n">default</span><span class="p">()</span> | ||
| <span class="kn">from</span> <span class="nn">.python.element</span> <span class="kn">import</span> <span class="n">format_element</span> | ||
| <span class="k">print</span><span class="p">(</span><span class="n">format_element</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" >postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>postgresql.string — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../../index.html" /> | ||
| <link rel="up" title="postgresql" href="../postgresql.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" accesskey="U">postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Source code for postgresql.string</h1><div class="highlight"><pre> | ||
| <span class="c">##</span> | ||
| <span class="c"># .string</span> | ||
| <span class="c">##</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd">String split and join operations for dealing with literals and identifiers.</span> | ||
| <span class="sd">Notably, the functions in this module are intended to be used for simple</span> | ||
| <span class="sd">use-cases. It attempts to stay away from "real" parsing and simply provides</span> | ||
| <span class="sd">functions for common needs, like the ability to identify unquoted portions of a</span> | ||
| <span class="sd">query string so that logic or transformations can be applied to only unquoted</span> | ||
| <span class="sd">portions. Scanning for statement terminators, or safely interpolating</span> | ||
| <span class="sd">identifiers.</span> | ||
| <span class="sd">All functions deal with strict quoting rules.</span> | ||
| <span class="sd">"""</span> | ||
| <span class="kn">import</span> <span class="nn">re</span> | ||
| <div class="viewcode-block" id="escape_literal"><a class="viewcode-back" href="../../reference.html#postgresql.string.escape_literal">[docs]</a><span class="k">def</span> <span class="nf">escape_literal</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="s">"Replace every instance of ' with ''"</span> | ||
| <span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">"'"</span><span class="p">,</span> <span class="s">"''"</span><span class="p">)</span> | ||
| </div> | ||
| <div class="viewcode-block" id="quote_literal"><a class="viewcode-back" href="../../reference.html#postgresql.string.quote_literal">[docs]</a><span class="k">def</span> <span class="nf">quote_literal</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="s">"Escape the literal and wrap it in [single] quotations"</span> | ||
| <span class="k">return</span> <span class="s">"'"</span> <span class="o">+</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">"'"</span><span class="p">,</span> <span class="s">"''"</span><span class="p">)</span> <span class="o">+</span> <span class="s">"'"</span> | ||
| </div> | ||
| <div class="viewcode-block" id="escape_ident"><a class="viewcode-back" href="../../reference.html#postgresql.string.escape_ident">[docs]</a><span class="k">def</span> <span class="nf">escape_ident</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="s">'Replace every instance of " with ""'</span> | ||
| <span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'"'</span><span class="p">,</span> <span class="s">'""'</span><span class="p">)</span> | ||
| </div> | ||
| <span class="k">def</span> <span class="nf">needs_quoting</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="ow">not</span> <span class="p">(</span><span class="n">text</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">text</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">isdecimal</span><span class="p">()</span> <span class="ow">and</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'_'</span><span class="p">,</span> <span class="s">'a'</span><span class="p">)</span><span class="o">.</span><span class="n">isalnum</span><span class="p">())</span> | ||
| <div class="viewcode-block" id="quote_ident"><a class="viewcode-back" href="../../reference.html#postgresql.string.quote_ident">[docs]</a><span class="k">def</span> <span class="nf">quote_ident</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="s">"Replace every instance of '"' with '""' *and* place '"' on each end"</span> | ||
| <span class="k">return</span> <span class="s">'"'</span> <span class="o">+</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'"'</span><span class="p">,</span> <span class="s">'""'</span><span class="p">)</span> <span class="o">+</span> <span class="s">'"'</span> | ||
| </div> | ||
| <div class="viewcode-block" id="quote_ident_if_needed"><a class="viewcode-back" href="../../reference.html#postgresql.string.quote_ident_if_needed">[docs]</a><span class="k">def</span> <span class="nf">quote_ident_if_needed</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> If needed, replace every instance of '"' with '""' *and* place '"' on each end.</span> | ||
| <span class="sd"> Otherwise, just return the text.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">return</span> <span class="n">quote_ident</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="k">if</span> <span class="n">needs_quoting</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="k">else</span> <span class="n">text</span> | ||
| </div> | ||
| <span class="n">quote_re</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s">r"""(?xu)</span> | ||
| <span class="s"> E'(?:''|\\.|[^'])*(?:'|$) (?# Backslash escapes E'str')</span> | ||
| <span class="s">| '(?:''|[^'])*(?:'|$) (?# Regular literals 'str')</span> | ||
| <span class="s">| "(?:""|[^"])*(?:"|$) (?# Identifiers "str")</span> | ||
| <span class="s">| (\$(?:[^0-9$]\w*)?\$).*?(?:\1|$) (?# Dollar quotes $$str$$)</span> | ||
| <span class="s">"""</span><span class="p">)</span> | ||
| <div class="viewcode-block" id="split"><a class="viewcode-back" href="../../reference.html#postgresql.string.split">[docs]</a><span class="k">def</span> <span class="nf">split</span><span class="p">(</span><span class="n">text</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> split the string up by into non-quoted and quoted portions. Zero and even</span> | ||
| <span class="sd"> numbered indexes are unquoted portions, while odd indexes are quoted</span> | ||
| <span class="sd"> portions. </span> | ||
| <span class="sd"> Unquoted portions are regular strings, whereas quoted portions are</span> | ||
| <span class="sd"> pair-tuples specifying the quotation mechanism and the content thereof.</span> | ||
| <span class="sd"> >>> list(split("select $$foobar$$"))</span> | ||
| <span class="sd"> ['select ', ('$$', 'foobar'), '']</span> | ||
| <span class="sd"> If the split ends on a quoted section, it means the string's quote was not</span> | ||
| <span class="sd"> terminated. Subsequently, there will be an even number of objects in the</span> | ||
| <span class="sd"> list.</span> | ||
| <span class="sd"> Quotation errors are detected, but never raised. Rather it's up to the user</span> | ||
| <span class="sd"> to identify the best course of action for the given split.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">lastend</span> <span class="o">=</span> <span class="mi">0</span> | ||
| <span class="n">re</span> <span class="o">=</span> <span class="n">quote_re</span> | ||
| <span class="n">scan</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">scanner</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> | ||
| <span class="n">match</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="n">search</span><span class="p">()</span> | ||
| <span class="k">while</span> <span class="n">match</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="c"># text preceding the quotation</span> | ||
| <span class="k">yield</span> <span class="n">text</span><span class="p">[</span><span class="n">lastend</span><span class="p">:</span><span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">()]</span> | ||
| <span class="c"># the dollar quote, if any</span> | ||
| <span class="n">dq</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">groups</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span> | ||
| <span class="k">if</span> <span class="n">dq</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="n">endoff</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">dq</span><span class="p">)</span> | ||
| <span class="n">quote</span> <span class="o">=</span> <span class="n">dq</span> | ||
| <span class="n">end</span> <span class="o">=</span> <span class="n">quote</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">endoff</span> <span class="o">=</span> <span class="mi">1</span> | ||
| <span class="n">q</span> <span class="o">=</span> <span class="n">text</span><span class="p">[</span><span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">()]</span> | ||
| <span class="k">if</span> <span class="n">q</span> <span class="o">==</span> <span class="s">'E'</span><span class="p">:</span> | ||
| <span class="n">quote</span> <span class="o">=</span> <span class="s">"E'"</span> | ||
| <span class="n">end</span> <span class="o">=</span> <span class="s">"'"</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">end</span> <span class="o">=</span> <span class="n">quote</span> <span class="o">=</span> <span class="n">q</span> | ||
| <span class="c"># If the end is not the expected quote, it consumed</span> | ||
| <span class="c"># the end. Be sure to check that the match's end - end offset</span> | ||
| <span class="c"># is *not* the start, ie an empty quotation at the end of the string.</span> | ||
| <span class="k">if</span> <span class="n">text</span><span class="p">[</span><span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()</span><span class="o">-</span><span class="n">endoff</span><span class="p">:</span><span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()]</span> <span class="o">!=</span> <span class="n">end</span> \ | ||
| <span class="ow">or</span> <span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()</span> <span class="o">-</span> <span class="n">endoff</span> <span class="o">==</span> <span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">():</span> | ||
| <span class="k">yield</span> <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">text</span><span class="p">[</span><span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">()</span><span class="o">+</span><span class="nb">len</span><span class="p">(</span><span class="n">quote</span><span class="p">):])</span> | ||
| <span class="k">break</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="k">yield</span> <span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">text</span><span class="p">[</span><span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">()</span><span class="o">+</span><span class="nb">len</span><span class="p">(</span><span class="n">quote</span><span class="p">):</span><span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()</span><span class="o">-</span><span class="n">endoff</span><span class="p">])</span> | ||
| <span class="n">lastend</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">end</span><span class="p">()</span> | ||
| <span class="n">match</span> <span class="o">=</span> <span class="n">scan</span><span class="o">.</span><span class="n">search</span><span class="p">()</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># balanced quotes, yield the rest</span> | ||
| <span class="k">yield</span> <span class="n">text</span><span class="p">[</span><span class="n">lastend</span><span class="p">:]</span> | ||
| </div> | ||
| <div class="viewcode-block" id="unsplit"><a class="viewcode-back" href="../../reference.html#postgresql.string.unsplit">[docs]</a><span class="k">def</span> <span class="nf">unsplit</span><span class="p">(</span><span class="n">splitted_iter</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> catenate a split string. This is needed to handle the special</span> | ||
| <span class="sd"> cases created by pg.string.split(). (Run-away quotations, primarily)</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">s</span> <span class="o">=</span> <span class="s">''</span> | ||
| <span class="n">quoted</span> <span class="o">=</span> <span class="bp">False</span> | ||
| <span class="n">i</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">splitted_iter</span><span class="p">)</span> | ||
| <span class="n">endq</span> <span class="o">=</span> <span class="s">''</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">i</span><span class="p">:</span> | ||
| <span class="n">s</span> <span class="o">+=</span> <span class="n">endq</span> <span class="o">+</span> <span class="n">x</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">q</span><span class="p">,</span> <span class="n">qtext</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> | ||
| <span class="n">s</span> <span class="o">+=</span> <span class="n">q</span> <span class="o">+</span> <span class="n">qtext</span> | ||
| <span class="k">if</span> <span class="n">q</span> <span class="o">==</span> <span class="s">"E'"</span><span class="p">:</span> | ||
| <span class="n">endq</span> <span class="o">=</span> <span class="s">"'"</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">endq</span> <span class="o">=</span> <span class="n">q</span> | ||
| <span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span> | ||
| <span class="k">break</span> | ||
| <span class="k">return</span> <span class="n">s</span> | ||
| </div> | ||
| <div class="viewcode-block" id="split_using"><a class="viewcode-back" href="../../reference.html#postgresql.string.split_using">[docs]</a><span class="k">def</span> <span class="nf">split_using</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">quote</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">'.'</span><span class="p">,</span> <span class="n">maxsplit</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> split the string on the seperator ignoring the separator in quoted areas.</span> | ||
| <span class="sd"> This is only useful for simple quoted strings. Dollar quotes, and backslash</span> | ||
| <span class="sd"> escapes are not supported.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">escape</span> <span class="o">=</span> <span class="n">quote</span> <span class="o">*</span> <span class="mi">2</span> | ||
| <span class="n">esclen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">escape</span><span class="p">)</span> | ||
| <span class="n">offset</span> <span class="o">=</span> <span class="mi">0</span> | ||
| <span class="n">tl</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> | ||
| <span class="n">end</span> <span class="o">=</span> <span class="n">tl</span> | ||
| <span class="c"># Fast path: No quotes? Do a simple split.</span> | ||
| <span class="k">if</span> <span class="n">quote</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">text</span><span class="p">:</span> | ||
| <span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">sep</span><span class="p">,</span> <span class="n">maxsplit</span><span class="p">)</span> | ||
| <span class="n">l</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="o">!=</span> <span class="n">maxsplit</span><span class="p">:</span> | ||
| <span class="c"># Look for the separator first</span> | ||
| <span class="n">nextsep</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">sep</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">nextsep</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="c"># it's over. there are no more seps</span> | ||
| <span class="k">break</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># There's a sep ahead, but is there a quoted section before it?</span> | ||
| <span class="n">nextquote</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">nextsep</span><span class="p">)</span> | ||
| <span class="k">while</span> <span class="n">nextquote</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="c"># Yep, there's a quote before the sep;</span> | ||
| <span class="c"># need to eat the escaped portion.</span> | ||
| <span class="n">nextquote</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">nextquote</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,)</span> | ||
| <span class="k">while</span> <span class="n">nextquote</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">escape</span><span class="p">,</span> <span class="n">nextquote</span><span class="p">,</span> <span class="n">nextquote</span><span class="o">+</span><span class="n">esclen</span><span class="p">)</span> <span class="o">!=</span> <span class="n">nextquote</span><span class="p">:</span> | ||
| <span class="c"># Not an escape, so it's the end.</span> | ||
| <span class="k">break</span> | ||
| <span class="c"># Look for another quote past the escape quote.</span> | ||
| <span class="n">nextquote</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">nextquote</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># the sep was located in the escape, and</span> | ||
| <span class="c"># the escape consumed the rest of the string.</span> | ||
| <span class="n">nextsep</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> | ||
| <span class="k">break</span> | ||
| <span class="n">nextsep</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">sep</span><span class="p">,</span> <span class="n">nextquote</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">nextsep</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="c"># it's over. there are no more seps</span> | ||
| <span class="c"># [likely they were consumed by the escape]</span> | ||
| <span class="k">break</span> | ||
| <span class="n">nextquote</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">quote</span><span class="p">,</span> <span class="n">nextquote</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">nextsep</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">nextsep</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span> | ||
| <span class="k">break</span> | ||
| <span class="n">l</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">text</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">nextsep</span><span class="p">])</span> | ||
| <span class="n">offset</span> <span class="o">=</span> <span class="n">nextsep</span> <span class="o">+</span> <span class="mi">1</span> | ||
| <span class="n">l</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">text</span><span class="p">[</span><span class="n">offset</span><span class="p">:])</span> | ||
| <span class="k">return</span> <span class="n">l</span> | ||
| </div> | ||
| <div class="viewcode-block" id="split_ident"><a class="viewcode-back" href="../../reference.html#postgresql.string.split_ident">[docs]</a><span class="k">def</span> <span class="nf">split_ident</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">','</span><span class="p">,</span> <span class="n">quote</span> <span class="o">=</span> <span class="s">'"'</span><span class="p">,</span> <span class="n">maxsplit</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Split a series of identifiers using the specified separator.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">nr</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">split_using</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">quote</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="n">sep</span><span class="p">,</span> <span class="n">maxsplit</span> <span class="o">=</span> <span class="n">maxsplit</span><span class="p">):</span> | ||
| <span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> | ||
| <span class="k">if</span> <span class="n">x</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'"'</span><span class="p">):</span> | ||
| <span class="k">if</span> <span class="ow">not</span> <span class="n">x</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">'"'</span><span class="p">):</span> | ||
| <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> | ||
| <span class="s">"unterminated identifier quotation"</span><span class="p">,</span> <span class="n">x</span> | ||
| <span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">nr</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'""'</span><span class="p">,</span> <span class="s">'"'</span><span class="p">))</span> | ||
| <span class="k">elif</span> <span class="n">needs_quoting</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> | ||
| <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span> | ||
| <span class="s">"non-ident characters in unquoted identifier"</span><span class="p">,</span> <span class="n">x</span> | ||
| <span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># postgres implies a lower, so to stay consistent</span> | ||
| <span class="c"># with it on qname joins, lower the unquoted identifier now.</span> | ||
| <span class="n">nr</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span> | ||
| <span class="k">return</span> <span class="n">nr</span> | ||
| </div> | ||
| <div class="viewcode-block" id="split_qname"><a class="viewcode-back" href="../../reference.html#postgresql.string.split_qname">[docs]</a><span class="k">def</span> <span class="nf">split_qname</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">maxsplit</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Call to .split_ident() with a '.' sep parameter.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">return</span> <span class="n">split_ident</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">maxsplit</span> <span class="o">=</span> <span class="n">maxsplit</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">'.'</span><span class="p">)</span> | ||
| </div> | ||
| <div class="viewcode-block" id="qname"><a class="viewcode-back" href="../../reference.html#postgresql.string.qname">[docs]</a><span class="k">def</span> <span class="nf">qname</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span> | ||
| <span class="s">"Quote the identifiers and join them using '.'"</span> | ||
| <span class="k">return</span> <span class="s">'.'</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">quote_ident</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">args</span><span class="p">])</span> | ||
| </div> | ||
| <span class="k">def</span> <span class="nf">qname_if_needed</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="s">'.'</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">quote_ident_if_needed</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">args</span><span class="p">])</span> | ||
| <div class="viewcode-block" id="split_sql"><a class="viewcode-back" href="../../reference.html#postgresql.string.split_sql">[docs]</a><span class="k">def</span> <span class="nf">split_sql</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">';'</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Given SQL, safely split using the given separator.</span> | ||
| <span class="sd"> Notably, this yields fully split text. This should be used instead of</span> | ||
| <span class="sd"> split_sql_str() when quoted sections need be still be isolated.</span> | ||
| <span class="sd"> >>> list(split_sql('select $$1$$ AS "foo;"; select 2;'))</span> | ||
| <span class="sd"> [['select ', ('$$', '1'), ' AS ', ('"', 'foo;'), ''], (' select 2',), ['']]</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">i</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">split</span><span class="p">(</span><span class="n">sql</span><span class="p">))</span> | ||
| <span class="n">cur</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">i</span><span class="p">:</span> | ||
| <span class="n">sections</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">sep</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sections</span><span class="p">)</span> <span class="o"><</span> <span class="mi">2</span><span class="p">:</span> | ||
| <span class="n">cur</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">part</span><span class="p">)</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">cur</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sections</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> | ||
| <span class="k">yield</span> <span class="n">cur</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">sections</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span> | ||
| <span class="k">yield</span> <span class="p">(</span><span class="n">x</span><span class="p">,)</span> | ||
| <span class="n">cur</span> <span class="o">=</span> <span class="p">[</span><span class="n">sections</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]]</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">cur</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">next</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> | ||
| <span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span> | ||
| <span class="k">break</span> | ||
| <span class="k">if</span> <span class="n">cur</span><span class="p">:</span> | ||
| <span class="k">yield</span> <span class="n">cur</span> | ||
| </div> | ||
| <div class="viewcode-block" id="split_sql_str"><a class="viewcode-back" href="../../reference.html#postgresql.string.split_sql_str">[docs]</a><span class="k">def</span> <span class="nf">split_sql_str</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="s">';'</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Identical to split_sql but yields unsplit text.</span> | ||
| <span class="sd"> >>> list(split_sql_str('select $$1$$ AS "foo;"; select 2;'))</span> | ||
| <span class="sd"> ['select $$1$$ AS "foo;"', ' select 2', '']</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">split_sql</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">sep</span> <span class="o">=</span> <span class="n">sep</span><span class="p">):</span> | ||
| <span class="k">yield</span> <span class="n">unsplit</span><span class="p">(</span><span class="n">x</span><span class="p">)</span></div> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" >postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>postgresql.sys — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../../index.html" /> | ||
| <link rel="up" title="postgresql" href="../postgresql.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" accesskey="U">postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Source code for postgresql.sys</h1><div class="highlight"><pre> | ||
| <span class="c">##</span> | ||
| <span class="c"># .sys</span> | ||
| <span class="c">##</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd">py-postgresql system functions and data.</span> | ||
| <span class="sd">Data</span> | ||
| <span class="sd">----</span> | ||
| <span class="sd"> ``libpath``</span> | ||
| <span class="sd"> The local file system paths that contain query libraries.</span> | ||
| <span class="sd">Overridable Functions</span> | ||
| <span class="sd">---------------------</span> | ||
| <span class="sd"> excformat</span> | ||
| <span class="sd"> Information that makes up an exception's displayed "body".</span> | ||
| <span class="sd"> Effectively, the implementation of `postgresql.exception.Error.__str__`</span> | ||
| <span class="sd"> msghook</span> | ||
| <span class="sd"> Display a message.</span> | ||
| <span class="sd">"""</span> | ||
| <span class="kn">import</span> <span class="nn">sys</span> | ||
| <span class="kn">import</span> <span class="nn">os</span> | ||
| <span class="kn">import</span> <span class="nn">traceback</span> | ||
| <span class="kn">from</span> <span class="nn">.python.element</span> <span class="kn">import</span> <span class="n">format_element</span> | ||
| <span class="kn">from</span> <span class="nn">.python.string</span> <span class="kn">import</span> <span class="n">indent</span> | ||
| <span class="n">libpath</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <div class="viewcode-block" id="default_errformat"><a class="viewcode-back" href="../../reference.html#postgresql.sys.default_errformat">[docs]</a><span class="k">def</span> <span class="nf">default_errformat</span><span class="p">(</span><span class="n">val</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Built-in error formatter. DON'T TOUCH!</span> | ||
| <span class="sd"> """</span> | ||
| <span class="n">it</span> <span class="o">=</span> <span class="n">val</span><span class="o">.</span><span class="n">_e_metas</span><span class="p">()</span> | ||
| <span class="k">if</span> <span class="n">val</span><span class="o">.</span><span class="n">creator</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="c"># Protect against element traceback failures.</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">after</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">+</span> <span class="n">format_element</span><span class="p">(</span><span class="n">val</span><span class="o">.</span><span class="n">creator</span><span class="p">)</span> | ||
| <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> | ||
| <span class="n">after</span> <span class="o">=</span> <span class="s">'Element Traceback of </span><span class="si">%r</span><span class="s"> caused exception:</span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span><span class="p">(</span> | ||
| <span class="nb">type</span><span class="p">(</span><span class="n">val</span><span class="o">.</span><span class="n">creator</span><span class="p">)</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> | ||
| <span class="n">os</span><span class="o">.</span><span class="n">linesep</span> | ||
| <span class="p">)</span> | ||
| <span class="n">after</span> <span class="o">+=</span> <span class="n">indent</span><span class="p">(</span><span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">())</span> | ||
| <span class="n">after</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">+</span> <span class="n">indent</span><span class="p">(</span><span class="n">after</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">after</span> <span class="o">=</span> <span class="s">''</span> | ||
| <span class="k">return</span> <span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> \ | ||
| <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">+</span> <span class="s">' '</span> \ | ||
| <span class="o">+</span> <span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">linesep</span> <span class="o">+</span> <span class="s">' '</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> | ||
| <span class="n">k</span> <span class="o">+</span> <span class="s">': '</span> <span class="o">+</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">it</span> | ||
| <span class="p">)</span> <span class="o">+</span> <span class="n">after</span> | ||
| </div> | ||
| <div class="viewcode-block" id="default_msghook"><a class="viewcode-back" href="../../reference.html#postgresql.sys.default_msghook">[docs]</a><span class="k">def</span> <span class="nf">default_msghook</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">format_message</span> <span class="o">=</span> <span class="n">format_element</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Built-in message hook. DON'T TOUCH!</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">closed</span><span class="p">:</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">format_message</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">linesep</span><span class="p">)</span> | ||
| <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">sys</span><span class="o">.</span><span class="n">excepthook</span><span class="p">(</span><span class="o">*</span><span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">())</span> | ||
| <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> | ||
| <span class="c"># gasp.</span> | ||
| <span class="k">pass</span> | ||
| </div> | ||
| <div class="viewcode-block" id="errformat"><a class="viewcode-back" href="../../reference.html#postgresql.sys.errformat">[docs]</a><span class="k">def</span> <span class="nf">errformat</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Raised Database Error formatter pointing to default_excformat.</span> | ||
| <span class="sd"> Override if you like. All postgresql.exceptions.Error's are formatted using</span> | ||
| <span class="sd"> this function.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">return</span> <span class="n">default_errformat</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span> | ||
| </div> | ||
| <div class="viewcode-block" id="msghook"><a class="viewcode-back" href="../../reference.html#postgresql.sys.msghook">[docs]</a><span class="k">def</span> <span class="nf">msghook</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Message hook pointing to default_msghook.</span> | ||
| <span class="sd"> Override if you like. All untrapped messages raised by</span> | ||
| <span class="sd"> driver connections come here to be printed to stderr.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="k">return</span> <span class="n">default_msghook</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span> | ||
| </div> | ||
| <div class="viewcode-block" id="reset_errformat"><a class="viewcode-back" href="../../reference.html#postgresql.sys.reset_errformat">[docs]</a><span class="k">def</span> <span class="nf">reset_errformat</span><span class="p">(</span><span class="n">with_func</span> <span class="o">=</span> <span class="n">errformat</span><span class="p">):</span> | ||
| <span class="s">'restore the original excformat function'</span> | ||
| <span class="k">global</span> <span class="n">errformat</span> | ||
| <span class="n">errformat</span> <span class="o">=</span> <span class="n">with_func</span> | ||
| </div> | ||
| <div class="viewcode-block" id="reset_msghook"><a class="viewcode-back" href="../../reference.html#postgresql.sys.reset_msghook">[docs]</a><span class="k">def</span> <span class="nf">reset_msghook</span><span class="p">(</span><span class="n">with_func</span> <span class="o">=</span> <span class="n">msghook</span><span class="p">):</span> | ||
| <span class="s">'restore the original msghook function'</span> | ||
| <span class="k">global</span> <span class="n">msghook</span> | ||
| <span class="n">msghook</span> <span class="o">=</span> <span class="n">with_func</span></div> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" >postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>postgresql.temporal — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="../../_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '../../', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="../../_static/jquery.js"></script> | ||
| <script type="text/javascript" src="../../_static/underscore.js"></script> | ||
| <script type="text/javascript" src="../../_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="../../index.html" /> | ||
| <link rel="up" title="postgresql" href="../postgresql.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" accesskey="U">postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Source code for postgresql.temporal</h1><div class="highlight"><pre> | ||
| <span class="c">##</span> | ||
| <span class="c"># .temporal - manage the temporary cluster</span> | ||
| <span class="c">##</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd">Temporary PostgreSQL cluster for the process.</span> | ||
| <span class="sd">"""</span> | ||
| <span class="kn">import</span> <span class="nn">os</span> | ||
| <span class="kn">import</span> <span class="nn">atexit</span> | ||
| <span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">deque</span> | ||
| <span class="kn">from</span> <span class="nn">.cluster</span> <span class="kn">import</span> <span class="n">Cluster</span><span class="p">,</span> <span class="n">ClusterError</span> | ||
| <span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">installation</span> | ||
| <span class="kn">from</span> <span class="nn">.python.socket</span> <span class="kn">import</span> <span class="n">find_available_port</span> | ||
| <div class="viewcode-block" id="Temporal"><a class="viewcode-back" href="../../reference.html#postgresql.temporal.Temporal">[docs]</a><span class="k">class</span> <span class="nc">Temporal</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> | ||
| <span class="sd">"""</span> | ||
| <span class="sd"> Manages a temporary cluster for the duration of the process.</span> | ||
| <span class="sd"> Instances of this class reference a distinct cluster. These clusters are</span> | ||
| <span class="sd"> transient; they will only exist until the process exits.</span> | ||
| <span class="sd"> Usage::</span> | ||
| <span class="sd"> >>> from postgresql.temporal import pg_tmp</span> | ||
| <span class="sd"> >>> with pg_tmp:</span> | ||
| <span class="sd"> ... ps = db.prepare('SELECT 1')</span> | ||
| <span class="sd"> ... assert ps.first() == 1</span> | ||
| <span class="sd"> Or `pg_tmp` can decorate a method or function.</span> | ||
| <span class="sd"> """</span> | ||
| <span class="c">#: Format the cluster directory name.</span> | ||
| <span class="n">cluster_dirname</span> <span class="o">=</span> <span class="s">'pg_tmp_{0}_{1}'</span><span class="o">.</span><span class="n">format</span> | ||
| <span class="n">cluster</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="n">_init_pid_</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="n">_local_id_</span> <span class="o">=</span> <span class="mi">0</span> | ||
| <span class="n">builtins_keys</span> <span class="o">=</span> <span class="p">{</span> | ||
| <span class="s">'connector'</span><span class="p">,</span> | ||
| <span class="s">'db'</span><span class="p">,</span> | ||
| <span class="s">'do'</span><span class="p">,</span> | ||
| <span class="s">'xact'</span><span class="p">,</span> | ||
| <span class="s">'proc'</span><span class="p">,</span> | ||
| <span class="s">'settings'</span><span class="p">,</span> | ||
| <span class="s">'prepare'</span><span class="p">,</span> | ||
| <span class="s">'sqlexec'</span><span class="p">,</span> | ||
| <span class="s">'newdb'</span><span class="p">,</span> | ||
| <span class="p">}</span> | ||
| <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span> <span class="o">=</span> <span class="n">deque</span><span class="p">()</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span> <span class="o">=</span> <span class="mi">0</span> | ||
| <span class="c"># identifier for keeping temporary instances unique.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="o">.</span><span class="n">_local_id_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">local_id</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__class__</span><span class="o">.</span><span class="n">_local_id_</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> | ||
| <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">callable</span><span class="p">):</span> | ||
| <span class="k">def</span> <span class="nf">in_pg_temporal_context</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span> | ||
| <span class="k">with</span> <span class="bp">self</span><span class="p">:</span> | ||
| <span class="k">return</span> <span class="nb">callable</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span> | ||
| <span class="n">n</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="nb">callable</span><span class="p">,</span> <span class="s">'__name__'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="k">if</span> <span class="n">n</span><span class="p">:</span> | ||
| <span class="n">in_pg_temporal_context</span><span class="o">.</span><span class="n">__name__</span> <span class="o">=</span> <span class="n">n</span> | ||
| <span class="k">return</span> <span class="n">in_pg_temporal_context</span> | ||
| <span class="k">def</span> <span class="nf">destroy</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="c"># Don't destroy if it's not the initializing process.</span> | ||
| <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">()</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_init_pid_</span><span class="p">:</span> | ||
| <span class="c"># Kill all the open connections.</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">c</span> <span class="o">=</span> <span class="n">cluster</span><span class="o">.</span><span class="n">connection</span><span class="p">(</span><span class="n">user</span> <span class="o">=</span> <span class="s">'test'</span><span class="p">,</span> <span class="n">database</span> <span class="o">=</span> <span class="s">'template1'</span><span class="p">,)</span> | ||
| <span class="k">with</span> <span class="n">c</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">version_info</span><span class="p">[:</span><span class="mi">2</span><span class="p">]</span> <span class="o"><=</span> <span class="p">(</span><span class="mi">9</span><span class="p">,</span><span class="mi">1</span><span class="p">):</span> | ||
| <span class="n">c</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">terminate_backends</span><span class="p">()</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">c</span><span class="o">.</span><span class="n">sys</span><span class="o">.</span><span class="n">terminate_backends_92</span><span class="p">()</span> | ||
| <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> | ||
| <span class="c"># Doesn't matter much if it fails.</span> | ||
| <span class="k">pass</span> | ||
| <span class="n">cluster</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_init_pid_</span> <span class="o">=</span> <span class="bp">None</span> | ||
| <span class="k">if</span> <span class="n">cluster</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">wait_until_stopped</span><span class="p">(</span><span class="n">timeout</span> <span class="o">=</span> <span class="mi">5</span><span class="p">)</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">drop</span><span class="p">()</span> | ||
| <span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> | ||
| <span class="n">installation_factory</span> <span class="o">=</span> <span class="n">installation</span><span class="o">.</span><span class="n">default</span><span class="p">,</span> | ||
| <span class="n">inshint</span> <span class="o">=</span> <span class="p">{</span> | ||
| <span class="s">'hint'</span> <span class="p">:</span> <span class="s">"Try setting the PGINSTALLATION "</span> \ | ||
| <span class="s">"environment variable to the `pg_config` path"</span> | ||
| <span class="p">}</span> | ||
| <span class="p">):</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="k">return</span> | ||
| <span class="c">##</span> | ||
| <span class="c"># Hasn't been created yet, but doesn't matter.</span> | ||
| <span class="c"># On exit, obliterate the cluster directory.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">_init_pid_</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">()</span> | ||
| <span class="n">atexit</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">destroy</span><span class="p">)</span> | ||
| <span class="c"># [$HOME|.]/.pg_tmpdb_{pid}</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">cluster_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> | ||
| <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'HOME'</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">getcwd</span><span class="p">()),</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">cluster_dirname</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_init_pid_</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">local_id</span><span class="p">)</span> | ||
| <span class="p">)</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">logfile</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cluster_path</span><span class="p">,</span> <span class="s">'logfile'</span><span class="p">)</span> | ||
| <span class="n">installation</span> <span class="o">=</span> <span class="n">installation_factory</span><span class="p">()</span> | ||
| <span class="k">if</span> <span class="n">installation</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="k">raise</span> <span class="n">ClusterError</span><span class="p">(</span> | ||
| <span class="s">'could not find the default pg_config'</span><span class="p">,</span> <span class="n">details</span> <span class="o">=</span> <span class="n">inshint</span> | ||
| <span class="p">)</span> | ||
| <span class="n">cluster</span> <span class="o">=</span> <span class="n">Cluster</span><span class="p">(</span><span class="n">installation</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster_path</span><span class="p">,)</span> | ||
| <span class="c"># If it exists already, destroy it.</span> | ||
| <span class="k">if</span> <span class="n">cluster</span><span class="o">.</span><span class="n">initialized</span><span class="p">():</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">drop</span><span class="p">()</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">encoding</span> <span class="o">=</span> <span class="s">'utf-8'</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">init</span><span class="p">(</span> | ||
| <span class="n">user</span> <span class="o">=</span> <span class="s">'test'</span><span class="p">,</span> <span class="c"># Consistent username.</span> | ||
| <span class="n">encoding</span> <span class="o">=</span> <span class="n">cluster</span><span class="o">.</span><span class="n">encoding</span><span class="p">,</span> | ||
| <span class="n">logfile</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| <span class="c"># Configure</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">cluster_port</span> <span class="o">=</span> <span class="n">find_available_port</span><span class="p">()</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster_port</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="k">raise</span> <span class="n">ClusterError</span><span class="p">(</span> | ||
| <span class="s">'could not find a port for the test cluster on localhost'</span><span class="p">,</span> | ||
| <span class="n">creator</span> <span class="o">=</span> <span class="n">cluster</span> | ||
| <span class="p">)</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span> | ||
| <span class="n">port</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cluster_port</span><span class="p">),</span> | ||
| <span class="n">max_connections</span> <span class="o">=</span> <span class="s">'20'</span><span class="p">,</span> | ||
| <span class="n">shared_buffers</span> <span class="o">=</span> <span class="s">'200'</span><span class="p">,</span> | ||
| <span class="n">listen_addresses</span> <span class="o">=</span> <span class="s">'localhost'</span><span class="p">,</span> | ||
| <span class="n">log_destination</span> <span class="o">=</span> <span class="s">'stderr'</span><span class="p">,</span> | ||
| <span class="n">log_min_messages</span> <span class="o">=</span> <span class="s">'FATAL'</span><span class="p">,</span> | ||
| <span class="n">unix_socket_directory</span> <span class="o">=</span> <span class="n">cluster</span><span class="o">.</span><span class="n">data_directory</span><span class="p">,</span> | ||
| <span class="p">))</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span> | ||
| <span class="n">max_prepared_transactions</span> <span class="o">=</span> <span class="s">'10'</span><span class="p">,</span> | ||
| <span class="p">))</span> | ||
| <span class="c"># Start it up.</span> | ||
| <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">logfile</span><span class="p">,</span> <span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">lfo</span><span class="p">:</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">start</span><span class="p">(</span><span class="n">logfile</span> <span class="o">=</span> <span class="n">lfo</span><span class="p">)</span> | ||
| <span class="n">cluster</span><span class="o">.</span><span class="n">wait_until_started</span><span class="p">()</span> | ||
| <span class="c"># Initialize template1 and the test user database.</span> | ||
| <span class="n">c</span> <span class="o">=</span> <span class="n">cluster</span><span class="o">.</span><span class="n">connection</span><span class="p">(</span><span class="n">user</span> <span class="o">=</span> <span class="s">'test'</span><span class="p">,</span> <span class="n">database</span> <span class="o">=</span> <span class="s">'template1'</span><span class="p">,)</span> | ||
| <span class="k">with</span> <span class="n">c</span><span class="p">:</span> | ||
| <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">'create database test'</span><span class="p">)</span> | ||
| <span class="c"># It's ready.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span> <span class="o">=</span> <span class="n">cluster</span> | ||
| <span class="k">def</span> <span class="nf">push</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span><span class="o">.</span><span class="n">connection</span><span class="p">(</span><span class="n">user</span> <span class="o">=</span> <span class="s">'test'</span><span class="p">)</span> | ||
| <span class="n">c</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> | ||
| <span class="n">extras</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <span class="k">def</span> <span class="nf">new_pg_tmp_connection</span><span class="p">(</span><span class="n">l</span> <span class="o">=</span> <span class="n">extras</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">c</span><span class="p">,</span> <span class="n">sbid</span> <span class="o">=</span> <span class="s">'sandbox'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)):</span> | ||
| <span class="c"># Used to create a new connection that will be closed</span> | ||
| <span class="c"># when the context stack is popped along with 'db'.</span> | ||
| <span class="n">l</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">clone</span><span class="p">())</span> | ||
| <span class="n">l</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">settings</span><span class="p">[</span><span class="s">'search_path'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">sbid</span><span class="p">)</span> <span class="o">+</span> <span class="s">','</span> <span class="o">+</span> <span class="n">l</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">settings</span><span class="p">[</span><span class="s">'search_path'</span><span class="p">]</span> | ||
| <span class="k">return</span> <span class="n">l</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> | ||
| <span class="c"># The new builtins.</span> | ||
| <span class="n">builtins</span> <span class="o">=</span> <span class="p">{</span> | ||
| <span class="s">'db'</span> <span class="p">:</span> <span class="n">c</span><span class="p">,</span> | ||
| <span class="s">'prepare'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">prepare</span><span class="p">,</span> | ||
| <span class="s">'xact'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">xact</span><span class="p">,</span> | ||
| <span class="s">'sqlexec'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">,</span> | ||
| <span class="s">'do'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">do</span><span class="p">,</span> | ||
| <span class="s">'settings'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">settings</span><span class="p">,</span> | ||
| <span class="s">'proc'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">proc</span><span class="p">,</span> | ||
| <span class="s">'connector'</span> <span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">connector</span><span class="p">,</span> | ||
| <span class="s">'new'</span> <span class="p">:</span> <span class="n">new_pg_tmp_connection</span><span class="p">,</span> | ||
| <span class="p">}</span> | ||
| <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="p">:</span> | ||
| <span class="c"># Store any of those set or not set.</span> | ||
| <span class="n">current</span> <span class="o">=</span> <span class="p">{</span> | ||
| <span class="n">k</span> <span class="p">:</span> <span class="n">__builtins__</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">builtins_keys</span> | ||
| <span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">__builtins__</span> | ||
| <span class="p">}</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">current</span><span class="p">,</span> <span class="p">[]))</span> | ||
| <span class="c"># Store and push.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">builtins</span><span class="p">,</span> <span class="n">extras</span><span class="p">))</span> | ||
| <span class="n">__builtins__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">builtins</span><span class="p">)</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span> <span class="o">+=</span> <span class="mi">1</span> | ||
| <span class="k">def</span> <span class="nf">pop</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exc</span><span class="p">,</span> <span class="n">drop_schema</span> <span class="o">=</span> <span class="s">'DROP SCHEMA sandbox{0} CASCADE'</span><span class="o">.</span><span class="n">format</span><span class="p">):</span> | ||
| <span class="n">builtins</span><span class="p">,</span> <span class="n">extras</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span> <span class="o">-=</span> <span class="mi">1</span> | ||
| <span class="c"># restore __builtins__</span> | ||
| <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="p">)</span> <span class="o">></span> <span class="mi">1</span><span class="p">:</span> | ||
| <span class="n">__builtins__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">previous</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">builtins_stack</span><span class="o">.</span><span class="n">popleft</span><span class="p">()</span> | ||
| <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">builtins_keys</span><span class="p">:</span> | ||
| <span class="k">if</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">previous</span><span class="p">:</span> | ||
| <span class="n">__builtins__</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">previous</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># Wasn't set before.</span> | ||
| <span class="n">__builtins__</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="c"># close popped connection, but only if we're not in an interrupt.</span> | ||
| <span class="c"># However, temporal will always terminate all backends atexit.</span> | ||
| <span class="k">if</span> <span class="n">exc</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">or</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">exc</span><span class="p">,</span> <span class="ne">Exception</span><span class="p">):</span> | ||
| <span class="c"># Interrupt then close. Just in case something is lingering.</span> | ||
| <span class="k">for</span> <span class="n">xdb</span> <span class="ow">in</span> <span class="p">[</span><span class="n">builtins</span><span class="p">[</span><span class="s">'db'</span><span class="p">]]</span> <span class="o">+</span> <span class="nb">list</span><span class="p">(</span><span class="n">extras</span><span class="p">):</span> | ||
| <span class="k">if</span> <span class="n">xdb</span><span class="o">.</span><span class="n">closed</span> <span class="ow">is</span> <span class="bp">False</span><span class="p">:</span> | ||
| <span class="c"># In order for a clean close of the connection,</span> | ||
| <span class="c"># interrupt before closing. It is still</span> | ||
| <span class="c"># possible for the close to block, but less likely.</span> | ||
| <span class="n">xdb</span><span class="o">.</span><span class="n">interrupt</span><span class="p">()</span> | ||
| <span class="n">xdb</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> | ||
| <span class="c"># Interrupted and closed all the other connections at this level;</span> | ||
| <span class="c"># now remove the sandbox schema.</span> | ||
| <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span><span class="o">.</span><span class="n">connection</span><span class="p">(</span><span class="n">user</span> <span class="o">=</span> <span class="s">'test'</span><span class="p">)</span> | ||
| <span class="k">with</span> <span class="n">c</span><span class="p">:</span> | ||
| <span class="c"># Use a new connection so that the state of</span> | ||
| <span class="c"># the context connection will not have to be</span> | ||
| <span class="c"># contended with.</span> | ||
| <span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">drop_schema</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="c"># interrupt</span> | ||
| <span class="k">pass</span> | ||
| <span class="k">def</span> <span class="nf">__enter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">init</span><span class="p">()</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">push</span><span class="p">()</span> | ||
| <span class="k">try</span><span class="p">:</span> | ||
| <span class="n">db</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> | ||
| <span class="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">'CREATE SCHEMA sandbox'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span><span class="p">))</span> | ||
| <span class="n">db</span><span class="o">.</span><span class="n">settings</span><span class="p">[</span><span class="s">'search_path'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'sandbox'</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sandbox_id</span><span class="p">)</span> <span class="o">+</span> <span class="s">','</span> <span class="o">+</span> <span class="n">db</span><span class="o">.</span><span class="n">settings</span><span class="p">[</span><span class="s">'search_path'</span><span class="p">]</span> | ||
| <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> | ||
| <span class="c"># failed to initialize sandbox schema; pop it.</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> | ||
| <span class="k">raise</span> | ||
| <span class="k">def</span> <span class="nf">__exit__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exc</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">tb</span><span class="p">):</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cluster</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> | ||
| <span class="c">#: The process' temporary cluster.</span></div> | ||
| <span class="n">pg_tmp</span> <span class="o">=</span> <span class="n">Temporal</span><span class="p">()</span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="../../search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="../../genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="../../py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="../../index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| <li><a href="../index.html" >Module code</a> »</li> | ||
| <li><a href="../postgresql.html" >postgresql</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| Administration | ||
| ============== | ||
| This chapter covers the administration of py-postgresql. This includes | ||
| installation and other aspects of working with py-postgresql such as | ||
| environment variables and configuration files. | ||
| Installation | ||
| ------------ | ||
| py-postgresql uses Python's distutils package to manage the build and | ||
| installation process of the package. The normal entry point for | ||
| this is the ``setup.py`` script contained in the root project directory. | ||
| After extracting the archive and changing the into the project's directory, | ||
| installation is normally as simple as:: | ||
| $ python3 ./setup.py install | ||
| However, if you need to install for use with a particular version of python, | ||
| just use the path of the executable that should be used:: | ||
| $ /usr/opt/bin/python3 ./setup.py install | ||
| Environment | ||
| ----------- | ||
| These environment variables effect the operation of the package: | ||
| ============== =============================================================================== | ||
| PGINSTALLATION The path to the ``pg_config`` executable of the installation to use by default. | ||
| ============== =============================================================================== |
| .. _alock: | ||
| ************** | ||
| Advisory Locks | ||
| ************** | ||
| .. warning:: `postgresql.alock` is a new feature in v1.0. | ||
| `Explicit Locking in PostgreSQL <http://www.postgresql.org/docs/current/static/explicit-locking.html#ADVISORY-LOCKS>`_. | ||
| PostgreSQL's advisory locks offer a cooperative synchronization primitive. | ||
| These are used in cases where an application needs access to a resource, but | ||
| using table locks may cause interference with other operations that can be | ||
| safely performed alongside the application-level, exclusive operation. | ||
| Advisory locks can be used by directly executing the stored procedures in the | ||
| database or by using the :class:`postgresql.alock.ALock` subclasses, which | ||
| provides a context manager that uses those stored procedures. | ||
| Currently, only two subclasses exist. Each represents the lock mode | ||
| supported by PostgreSQL's advisory locks: | ||
| * :class:`postgresql.alock.ShareLock` | ||
| * :class:`postgresql.alock.ExclusiveLock` | ||
| Acquiring ALocks | ||
| ================ | ||
| An ALock instance represents a sequence of advisory locks. A single ALock can | ||
| acquire and release multiple advisory locks by creating the instance with | ||
| multiple lock identifiers:: | ||
| >>> from postgresql import alock | ||
| >>> table1_oid = 192842 | ||
| >>> table2_oid = 192849 | ||
| >>> l = alock.ExclusiveLock(db, (table1_oid, 0), (table2_oid, 0)) | ||
| >>> l.acquire() | ||
| >>> ... | ||
| >>> l.release() | ||
| :class:`postgresql.alock.ALock` is similar to :class:`threading.RLock`; in | ||
| order for an ALock to be released, it must be released the number of times it | ||
| has been acquired. ALocks are associated with and survived by their session. | ||
| Much like how RLocks are associated with the thread they are acquired in: | ||
| acquiring an ALock again will merely increment its count. | ||
| PostgreSQL allows advisory locks to be identified using a pair of `int4` or a | ||
| single `int8`. ALock instances represent a *sequence* of those identifiers:: | ||
| >>> from postgresql import alock | ||
| >>> ids = [(0,0), 0, 1] | ||
| >>> with alock.ShareLock(db, *ids): | ||
| ... ... | ||
| Both types of identifiers may be used within the same ALock, and, regardless of | ||
| their type, will be aquired in the order that they were given to the class' | ||
| constructor. In the above example, ``(0,0)`` is acquired first, then ``0``, and | ||
| lastly ``1``. | ||
| ALocks | ||
| ====== | ||
| `postgresql.alock.ALock` is abstract; it defines the interface and some common | ||
| functionality. The lock mode is selected by choosing the appropriate subclass. | ||
| There are two: | ||
| ``postgresql.alock.ExclusiveLock(database, *identifiers)`` | ||
| Instantiate an ALock object representing the `identifiers` for use with the | ||
| `database`. Exclusive locks will conflict with other exclusive locks and share | ||
| locks. | ||
| ``postgresql.alock.ShareLock(database, *identifiers)`` | ||
| Instantiate an ALock object representing the `identifiers` for use with the | ||
| `database`. Share locks can be acquired when a share lock with the same | ||
| identifier has been acquired by another backend. However, an exclusive lock | ||
| with the same identifier will conflict. | ||
| ALock Interface Points | ||
| ---------------------- | ||
| Methods and properties available on :class:`postgresql.alock.ALock` instances: | ||
| ``alock.acquire(blocking = True)`` | ||
| Acquire the advisory locks represented by the ``alock`` object. If blocking is | ||
| `True`, the default, the method will block until locks on *all* the | ||
| identifiers have been acquired. | ||
| If blocking is `False`, acquisition may not block, and success will be | ||
| indicated by the returned object: `True` if *all* lock identifiers were | ||
| acquired and `False` if any of the lock identifiers could not be acquired. | ||
| ``alock.release()`` | ||
| Release the advisory locks represented by the ``alock`` object. If the lock | ||
| has not been acquired, a `RuntimeError` will be raised. | ||
| ``alock.locked()`` | ||
| Returns a boolean describing whether the locks are held or not. This will | ||
| return `False` if the lock connection has been closed. | ||
| ``alock.__enter__()`` | ||
| Alias to ``acquire``; context manager protocol. Always blocking. | ||
| ``alock.__exit__(typ, val, tb)`` | ||
| Alias to ``release``; context manager protocol. |
| Commands | ||
| ******** | ||
| This chapter discusses the usage of the available console scripts. | ||
| postgresql.bin.pg_python | ||
| ======================== | ||
| The ``pg_python`` command provides a simple way to write Python scripts against a | ||
| single target database. It acts like the regular Python console command, but | ||
| takes standard PostgreSQL options as well to specify the client parameters | ||
| to make establish connection with. The Python environment is then augmented | ||
| with the following built-ins: | ||
| ``db`` | ||
| The PG-API connection object. | ||
| ``xact`` | ||
| ``db.xact``, the transaction creator. | ||
| ``settings`` | ||
| ``db.settings`` | ||
| ``prepare`` | ||
| ``db.prepare``, the statement creator. | ||
| ``proc`` | ||
| ``db.proc`` | ||
| ``do`` | ||
| ``db.do``, execute a single DO statement. | ||
| ``sqlexec`` | ||
| ``db.execute``, execute multiple SQL statements (``None`` is always returned) | ||
| pg_python Usage | ||
| --------------- | ||
| Usage: postgresql.bin.pg_python [connection options] [script] ... | ||
| Options: | ||
| --unix=UNIX path to filesystem socket | ||
| --ssl-mode=SSLMODE SSL requirement for connectivity: require, prefer, | ||
| allow, disable | ||
| -s SETTINGS, --setting=SETTINGS | ||
| run-time parameters to set upon connecting | ||
| -I PQ_IRI, --iri=PQ_IRI | ||
| database locator string | ||
| [pq://user:password@host:port/database?setting=value] | ||
| -h HOST, --host=HOST database server host | ||
| -p PORT, --port=PORT database server port | ||
| -U USER, --username=USER | ||
| user name to connect as | ||
| -W, --password prompt for password | ||
| -d DATABASE, --database=DATABASE | ||
| database's name | ||
| --pq-trace=PQ_TRACE trace PQ protocol transmissions | ||
| -C PYTHON_CONTEXT, --context=PYTHON_CONTEXT | ||
| Python context code to run[file://,module:,<code>] | ||
| -m PYTHON_MAIN Python module to run as script(__main__) | ||
| -c PYTHON_MAIN Python expression to run(__main__) | ||
| --version show program's version number and exit | ||
| --help show this help message and exit | ||
| Interactive Console Backslash Commands | ||
| -------------------------------------- | ||
| Inspired by ``psql``:: | ||
| >>> \? | ||
| Backslash Commands: | ||
| \? Show this help message. | ||
| \E Edit a file or a temporary script. | ||
| \e Edit and Execute the file directly in the context. | ||
| \i Execute a Python script within the interpreter's context. | ||
| \set Configure environment variables. \set without arguments to show all | ||
| \x Execute the Python command within this process. | ||
| pg_python Examples | ||
| ------------------ | ||
| Module execution taking advantage of the new built-ins:: | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W -m timeit "prepare('SELECT 1').first()" | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| 1000 loops, best of 3: 1.35 msec per loop | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W -m timeit -s "ps=prepare('SELECT 1')" "ps.first()" | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| 1000 loops, best of 3: 442 usec per loop | ||
| Simple interactive usage:: | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| >>> ps = prepare('select 1') | ||
| >>> ps.first() | ||
| 1 | ||
| >>> c = ps() | ||
| >>> c.read() | ||
| [(1,)] | ||
| >>> ps.close() | ||
| >>> import sys | ||
| >>> sys.exit(0) | ||
| postgresql.bin.pg_dotconf | ||
| ========================= | ||
| pg_dotconf is used to modify a PostgreSQL cluster's configuration file. | ||
| It provides a means to apply settings specified from the command line and from a | ||
| file referenced using the ``-f`` option. | ||
| .. warning:: | ||
| ``include`` directives in configuration files are *completely* ignored. If | ||
| modification of an included file is desired, the command must be applied to | ||
| that specific file. | ||
| pg_dotconf Usage | ||
| ---------------- | ||
| Usage: postgresql.bin.pg_dotconf [--stdout] [-f filepath] postgresql.conf ([param=val]|[param])* | ||
| Options: | ||
| --version show program's version number and exit | ||
| -h, --help show this help message and exit | ||
| -f SETTINGS, --file=SETTINGS | ||
| A file of settings to *apply* to the given | ||
| "postgresql.conf" | ||
| --stdout Redirect the product to standard output instead of | ||
| writing back to the "postgresql.conf" file | ||
| Examples | ||
| -------- | ||
| Modifying a simple configuration file:: | ||
| $ echo "setting = value" >pg.conf | ||
| # change 'setting' | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf setting=newvalue | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| # new settings are appended to the file | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf another_setting=value | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| another_setting = 'value' | ||
| # comment a setting | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf another_setting | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| #another_setting = 'value' | ||
| When a setting is given on the command line, it must been seen as one argument | ||
| to the command, so it's *very* important to avoid invocations like:: | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf setting = value | ||
| ERROR: invalid setting, '=' after 'setting' | ||
| HINT: Settings must take the form 'setting=value' or 'setting_name_to_comment'. Settings must also be received as a single argument. |
| Changes in v1.0 | ||
| =============== | ||
| 1.0.4 in development | ||
| -------------------- | ||
| * Alter how changes are represented in documentation to simplify merging. | ||
| 1.0.3 released on 2011-09-24 | ||
| ---------------------------- | ||
| * Use raise x from y to generalize exceptions. (Elvis Pranskevichus) | ||
| * Alter postgresql.string.quote_ident to always quote. (Elvis Pranskevichus) | ||
| * Add postgresql.string.quote_ident_if_necessary (Modification of Elvis Pranskevichus' patch) | ||
| * Many postgresql.string bug fixes (Elvis Pranskevichus) | ||
| * Correct ResourceWarnings improving Python 3.2 support. (jwp) | ||
| * Add test command to setup.py (Elvis Pranskevichus) | ||
| 1.0.2 released on 2010-09-18 | ||
| ---------------------------- | ||
| * Add support for DOMAINs in registered composites. (Elvis Pranskevichus) | ||
| * Properly raise StopIteration in Cursor.__next__. (Elvis Pranskevichus) | ||
| * Add Cluster Management documentation. | ||
| * Release savepoints after rolling them back. | ||
| * Fix Startup() usage for Python 3.2. | ||
| * Emit deprecation warning when 'gid' is given to xact(). | ||
| * Compensate for Python3.2's ElementTree API changes. | ||
| 1.0.1 released on 2010-04-24 | ||
| ---------------------------- | ||
| * Fix unpacking of array NULLs. (Elvis Pranskevichus) | ||
| * Fix .first()'s handling of counts and commands. | ||
| Bad logic caused zero-counts to return the command tag. | ||
| * Don't interrupt and close a temporal connection if it's not open. | ||
| * Use the Driver's typio attribute for TypeIO overrides. (Elvis Pranskevichus) | ||
| 1.0 released on 2010-03-27 | ||
| -------------------------- | ||
| * **DEPRECATION**: Removed 2PC support documentation. | ||
| * **DEPRECATION**: Removed pg_python and pg_dotconf 'scripts'. | ||
| They are still accessible by python3 -m postgresql.bin.pg_* | ||
| * Add support for binary hstore. | ||
| * Add support for user service files. | ||
| * Implement a Copy manager for direct connection-to-connection COPY operations. | ||
| * Added db.do() method for DO-statement support(convenience method). | ||
| * Set the default client_min_messages level to WARNING. | ||
| NOTICEs are often not desired by programmers, and py-postgresql's | ||
| high verbosity further irritates that case. | ||
| * Added postgresql.project module to provide project information. | ||
| Project name, author, version, etc. | ||
| * Increased default recvsize and chunksize for improved performance. | ||
| * 'D' messages are special cased as builtins.tuples instead of | ||
| protocol.element3.Tuple | ||
| * Alter Statement.chunks() to return chunks of builtins.tuple. Being | ||
| an interface intended for speed, types.Row() impedes its performance. | ||
| * Fix handling of infinity values with timestamptz, timestamp, and date. | ||
| [Bug reported by Axel Rau.] | ||
| * Correct representation of PostgreSQL ARRAYs by properly recording | ||
| lowerbounds and upperbounds. Internally, sub-ARRAYs have their own | ||
| element lists. | ||
| * Implement a NotificationManager for managing the NOTIFYs received | ||
| by a connection. The class can manage NOTIFYs from multiple | ||
| connections, whereas the db.wait() method is tailored for single targets. | ||
| * Implement an ALock class for managing advisory locks using the | ||
| threading.Lock APIs. [Feedback from Valentine Gogichashvili] | ||
| * Implement reference symbols. Allow libraries to define symbols that | ||
| are used to create queries that inherit the original symbol's type and | ||
| execution method. ``db.prepare(db.prepare(...).first())`` | ||
| * Fix handling of unix domain sockets by pg.open and driver.connect. | ||
| [Reported by twitter.com/rintavarustus] | ||
| * Fix typo/dropped parts of a raise LoadError in .lib. | ||
| [Reported by Vlad Pranskevichus] | ||
| * Fix db.tracer and pg_python's --pq-trace= | ||
| * Fix count return from .first() method. Failed to provide an empty | ||
| tuple for the rformats of the bind statement. | ||
| [Reported by dou dou] |
| Changes in v1.1 | ||
| =============== | ||
| 1.1.0 | ||
| ----- | ||
| * Remove two-phase commit interfaces per deprecation in v1.0. | ||
| For proper two phase commit use, a lock manager must be employed that | ||
| the implementation did nothing to accommodate for. | ||
| * Add support for unpacking anonymous records (Elvis) | ||
| * Support PostgreSQL 9.2 (Elvis) | ||
| * Python 3.3 Support (Elvis) | ||
| * Add column execution method. (jwp) | ||
| * Add one-shot statement interface. Connection.query.* (jwp) | ||
| * Modify the inet/cidr support by relying on the ipaddress module introduced in Python 3.3 (Google's ipaddr project) | ||
| The existing implementation relied on simple str() representation supported by the | ||
| socket module. Unfortunately, MS Windows' socket library does not appear to support the | ||
| necessary functionality, or Python's socket module does not expose it. ipaddress fixes | ||
| the problem. | ||
| .. note:: | ||
| The `ipaddress` module is now required for local inet and cidr. While it is | ||
| of "preliminary" status, the ipaddr project has been around for some time and | ||
| well supported. ipaddress appears to be the safest way forward for native | ||
| network types. |
| Client Parameters | ||
| ***************** | ||
| .. warning:: **The interfaces dealing with optparse are subject to change in 1.0**. | ||
| There are various sources of parameters used by PostgreSQL client applications. | ||
| The `postgresql.clientparameters` module provides a means for collecting and | ||
| managing those parameters. | ||
| Connection creation interfaces in `postgresql.driver` are purposefully simple. | ||
| All parameters taken by those interfaces are keywords, and are taken | ||
| literally; if a parameter is not given, it will effectively be `None`. | ||
| libpq-based drivers tend differ as they inherit some default client parameters | ||
| from the environment. Doing this by default is undesirable as it can cause | ||
| trivial failures due to unexpected parameter inheritance. However, using these | ||
| parameters from the environment and other sources are simply expected in *some* | ||
| cases: `postgresql.open`, `postgresql.bin.pg_python`, and other high-level | ||
| utilities. The `postgresql.clientparameters` module provides a means to collect | ||
| them into one dictionary object for subsequent application to a connection | ||
| creation interface. | ||
| `postgresql.clientparameters` is primarily useful to script authors that want to | ||
| provide an interface consistent with PostgreSQL commands like ``psql``. | ||
| Collecting Parameters | ||
| ===================== | ||
| The primary entry points in `postgresql.clientparameters` are | ||
| `postgresql.clientparameters.collect` and | ||
| `postgresql.clientparameters.resolve_password`. | ||
| For most purposes, ``collect`` will suffice. By default, it will prompt for the | ||
| password if instructed to(``-W``). Therefore, ``resolve_password`` need not be | ||
| used in most cases:: | ||
| >>> import sys | ||
| >>> import postgresql.clientparameters as pg_param | ||
| >>> p = pg_param.DefaultParser() | ||
| >>> co, ca = p.parse_args(sys.argv[1:]) | ||
| >>> params = pg_param.collect(parsed_options = co) | ||
| The `postgresql.clientparameters` module is executable, so you can see the | ||
| results of the above snippet by:: | ||
| $ python -m postgresql.clientparameters -h localhost -U a_db_user -ssearch_path=public | ||
| {'host': 'localhost', | ||
| 'password': None, | ||
| 'port': 5432, | ||
| 'settings': {'search_path': 'public'}, | ||
| 'user': 'a_db_user'} | ||
| `postgresql.clientparameters.collect` | ||
| -------------------------------------- | ||
| Build a client parameter dictionary from the environment and parsed command | ||
| line options. The following is a list of keyword arguments that ``collect`` will | ||
| accept: | ||
| ``parsed_options`` | ||
| Options parsed by `postgresql.clientparameters.StandardParser` or | ||
| `postgresql.clientparameters.DefaultParser` instances. | ||
| ``no_defaults`` | ||
| When `True`, don't include defaults like ``pgpassfile`` and ``user``. | ||
| Defaults to `False`. | ||
| ``environ`` | ||
| Environment variables to extract client parameter variables from. | ||
| Defaults to `os.environ` and expects a `collections.Mapping` interface. | ||
| ``environ_prefix`` | ||
| Environment variable prefix to use. Defaults to "PG". This allows the | ||
| collection of non-standard environment variables whose keys are partially | ||
| consistent with the standard variants. e.g. "PG_SRC_USER", "PG_SRC_HOST", | ||
| etc. | ||
| ``default_pg_sysconfdir`` | ||
| The location of the pg_service.conf file. The ``PGSYSCONFDIR`` environment | ||
| variable will override this. When a default installation is present, | ||
| ``PGINSTALLATION``, it should be set to this. | ||
| ``pg_service_file`` | ||
| Explicit location of the service file. This will override the "sysconfdir" | ||
| based path. | ||
| ``prompt_title`` | ||
| Descriptive title to use if a password prompt is needed. `None` to disable | ||
| password resolution entirely. Setting this to `None` will also disable | ||
| pgpassfile lookups, so it is necessary that further processing occurs when | ||
| this is `None`. | ||
| ``parameters`` | ||
| Base client parameters to use. These are set after the *defaults* are | ||
| collected. (The defaults that can be disabled by ``no_defaults``). | ||
| If ``prompt_title`` is not set to `None`, it will prompt for the password when | ||
| instructed to do by the ``prompt_password`` key in the parameters:: | ||
| >>> import postgresql.clientparameters as pg_param | ||
| >>> p = pg_param.collect(prompt_title = 'my_prompt!', parameters = {'prompt_password':True}) | ||
| Password for my_prompt![pq://jwp@localhost:5432]: | ||
| >>> p | ||
| {'host': 'localhost', 'user': 'jwp', 'password': 'secret', 'port': 5432} | ||
| If `None`, it will leave the necessary password resolution information in the | ||
| parameters dictionary for ``resolve_password``:: | ||
| >>> p = pg_param.collect(prompt_title = None, parameters = {'prompt_password':True}) | ||
| >>> p | ||
| {'pgpassfile': '/Users/jwp/.pgpass', 'prompt_password': True, 'host': 'localhost', 'user': 'jwp', 'port': 5432} | ||
| Of course, ``'prompt_password'`` is normally specified when ``parsed_options`` | ||
| received a ``-W`` option from the command line:: | ||
| >>> op = pg_param.DefaultParser() | ||
| >>> co, ca = op.parse_args(['-W']) | ||
| >>> p = pg_param.collect(parsed_options = co) | ||
| >>> p=pg_param.collect(parsed_options = co) | ||
| Password for [pq://jwp@localhost:5432]: | ||
| >>> p | ||
| {'host': 'localhost', 'user': 'jwp', 'password': 'secret', 'port': 5432} | ||
| >>> | ||
| `postgresql.clientparameters.resolve_password` | ||
| ---------------------------------------------- | ||
| Resolve the password for the given client parameters dictionary returned by | ||
| ``collect``. By default, this function need not be used as ``collect`` will | ||
| resolve the password by default. `resolve_password` accepts the following | ||
| arguments: | ||
| ``parameters`` | ||
| First positional argument. Normalized client parameters dictionary to update | ||
| in-place with the resolved password. If the 'prompt_password' key is in | ||
| ``parameters``, it will prompt regardless(normally comes from ``-W``). | ||
| ``getpass`` | ||
| Function to call to prompt for the password. Defaults to `getpass.getpass`. | ||
| ``prompt_title`` | ||
| Additional title to use if a prompt is requested. This can also be specified | ||
| in the ``parameters`` as the ``prompt_title`` key. This *augments* the IRI | ||
| display on the prompt. Defaults to an empty string, ``''``. | ||
| The resolution process is effected by the contents of the given ``parameters``. | ||
| Notable keywords: | ||
| ``prompt_password`` | ||
| If present in the given parameters, the user will be prompted for the using | ||
| the given ``getpass`` function. This disables the password file lookup | ||
| process. | ||
| ``prompt_title`` | ||
| This states a default prompt title to use. If the ``prompt_title`` keyword | ||
| argument is given to ``resolve_password``, this will not be used. | ||
| ``pgpassfile`` | ||
| The PostgreSQL password file to lookup the password in. If the ``password`` | ||
| parameter is present, this will not be used. | ||
| When resolution occurs, the ``prompt_password``, ``prompt_title``, and | ||
| ``pgpassfile`` keys are *removed* from the given parameters dictionary:: | ||
| >>> p=pg_param.collect(prompt_title = None) | ||
| >>> p | ||
| {'pgpassfile': '/Users/jwp/.pgpass', 'host': 'localhost', 'user': 'jwp', 'port': 5432} | ||
| >>> pg_param.resolve_password(p) | ||
| >>> p | ||
| {'host': 'localhost', 'password': 'secret', 'user': 'jwp', 'port': 5432} | ||
| Defaults | ||
| ======== | ||
| The following is a list of default parameters provided by ``collect`` and the | ||
| sources of their values: | ||
| ==================== =================================================================== | ||
| Key Value | ||
| ==================== =================================================================== | ||
| ``'user'`` `getpass.getuser()` or ``'postgres'`` | ||
| ``'host'`` `postgresql.clientparameters.default_host` (``'localhost'``) | ||
| ``'port'`` `postgresql.clientparameters.default_port` (``5432``) | ||
| ``'pgpassfile'`` ``"$HOME/.pgpassfile"`` or ``[PGDATA]`` + ``'pgpass.conf'`` (Win32) | ||
| ``'sslcrtfile'`` ``[PGDATA]`` + ``'postgresql.crt'`` | ||
| ``'sslkeyfile'`` ``[PGDATA]`` + ``'postgresql.key'`` | ||
| ``'sslrootcrtfile'`` ``[PGDATA]`` + ``'root.crt'`` | ||
| ``'sslrootcrlfile'`` ``[PGDATA]`` + ``'root.crl'`` | ||
| ==================== =================================================================== | ||
| ``[PGDATA]`` referenced in the above table is a directory whose path is platform | ||
| dependent. On most systems, it is ``"$HOME/.postgresql"``, but on Windows based | ||
| systems it is ``"%APPDATA%\postgresql"`` | ||
| .. note:: | ||
| [PGDATA] is *not* an environment variable. | ||
| .. _pg_envvars: | ||
| PostgreSQL Environment Variables | ||
| ================================ | ||
| The following is a list of environment variables that will be collected by the | ||
| `postgresql.clientparameter.collect` function using "PG" as the | ||
| ``environ_prefix`` and the keyword that it will be mapped to: | ||
| ===================== ====================================== | ||
| Environment Variable Keyword | ||
| ===================== ====================================== | ||
| ``PGUSER`` ``'user'`` | ||
| ``PGDATABASE`` ``'database'`` | ||
| ``PGHOST`` ``'host'`` | ||
| ``PGPORT`` ``'port'`` | ||
| ``PGPASSWORD`` ``'password'`` | ||
| ``PGSSLMODE`` ``'sslmode'`` | ||
| ``PGSSLKEY`` ``'sslkey'`` | ||
| ``PGCONNECT_TIMEOUT`` ``'connect_timeout'`` | ||
| ``PGREALM`` ``'kerberos4_realm'`` | ||
| ``PGKRBSRVNAME`` ``'kerberos5_service'`` | ||
| ``PGPASSFILE`` ``'pgpassfile'`` | ||
| ``PGTZ`` ``'settings' = {'timezone': }`` | ||
| ``PGDATESTYLE`` ``'settings' = {'datestyle': }`` | ||
| ``PGCLIENTENCODING`` ``'settings' = {'client_encoding': }`` | ||
| ``PGGEQO`` ``'settings' = {'geqo': }`` | ||
| ===================== ====================================== | ||
| .. _pg_passfile: | ||
| PostgreSQL Password File | ||
| ======================== | ||
| The password file is a simple newline separated list of ``:`` separated fields. It | ||
| is located at ``$HOME/.pgpass`` for most systems and at | ||
| ``%APPDATA%\postgresql\pgpass.conf`` for Windows based systems. However, the | ||
| ``PGPASSFILE`` environment variable may be used to override that location. | ||
| The lines in the file must be in the following form:: | ||
| hostname:port:database:username:password | ||
| A single asterisk, ``*``, may be used to indicate that any value will match the | ||
| field. However, this only effects fields other than ``password``. | ||
| See http://www.postgresql.org/docs/current/static/libpq-pgpass.html for more | ||
| details. | ||
| Client parameters produced by ``collect`` that have not been processed | ||
| by ``resolve_password`` will include a ``'pgpassfile'`` key. This is the value | ||
| that ``resolve_password`` will use to locate the pgpassfile to interrogate if a | ||
| password key is not present and it is not instructed to prompt for a password. | ||
| .. warning:: | ||
| Connection creation interfaces will *not* resolve ``'pgpassfile'``, so it is | ||
| important that the parameters produced by ``collect()`` are properly processed | ||
| before an attempt is made to establish a connection. |
| .. _cluster_management: | ||
| ****************** | ||
| Cluster Management | ||
| ****************** | ||
| py-postgresql provides cluster management tools in order to give the user | ||
| fine-grained control over a PostgreSQL cluster and access to information about an | ||
| installation of PostgreSQL. | ||
| .. _installation: | ||
| Installations | ||
| ============= | ||
| `postgresql.installation.Installation` objects are primarily used to | ||
| access PostgreSQL installation information. Normally, they are created using a | ||
| dictionary constructed from the output of the pg_config_ executable:: | ||
| from postgresql.installation import Installation, pg_config_dictionary | ||
| pg_install = Installation(pg_config_dictionary('/usr/local/pgsql/bin/pg_config')) | ||
| The extraction of pg_config_ information is isolated from Installation | ||
| instantiation in order to allow Installations to be created from arbitrary | ||
| dictionaries. This can be useful in cases where the installation layout is | ||
| inconsistent with the standard PostgreSQL installation layout, or if a faux | ||
| Installation needs to be created for testing purposes. | ||
| Installation Interface Points | ||
| ----------------------------- | ||
| ``Installation(info)`` | ||
| Instantiate an Installation using the given information. Normally, this | ||
| information is extracted from a pg_config_ executable using | ||
| `postgresql.installation.pg_config_dictionary`:: | ||
| info = pg_config_dictionary('/usr/local/pgsql/bin/pg_config') | ||
| pg_install = Installation(info) | ||
| ``Installation.version`` | ||
| The installation's version string:: | ||
| pg_install.version | ||
| 'PostgreSQL 9.0devel' | ||
| ``Installation.version_info`` | ||
| A tuple containing the version's ``(major, minor, patch, state, level)``. | ||
| Where ``major``, ``minor``, ``patch``, and ``level`` are `int` objects, and | ||
| ``state`` is a `str` object:: | ||
| pg_install.version_info | ||
| (9, 0, 0, 'devel', 0) | ||
| ``Installation.ssl`` | ||
| A `bool` indicating whether or not the installation has SSL support. | ||
| ``Installation.configure_options`` | ||
| The options given to the ``configure`` script that built the installation. The | ||
| options are represented using a dictionary object whose keys are normalized | ||
| long option names, and whose values are the option's argument. If the option | ||
| takes no argument, `True` will be used as the value. | ||
| The normalization of the long option names consists of removing the preceding | ||
| dashes, lowering the string, and replacing any dashes with underscores. For | ||
| instance, ``--enable-debug`` will be ``enable_debug``:: | ||
| pg_install.configure_options | ||
| {'enable_debug': True, 'with_libxml': True, | ||
| 'enable_cassert': True, 'with_libedit_preferred': True, | ||
| 'prefix': '/src/build/pg90', 'with_openssl': True, | ||
| 'enable_integer_datetimes': True, 'enable_depend': True} | ||
| ``Installation.paths`` | ||
| The paths of the installation as a dictionary where the keys are the path | ||
| identifiers and the values are the absolute file system paths. For instance, | ||
| ``'bindir'`` is associated with ``$PREFIX/bin``, ``'libdir'`` is associated | ||
| with ``$PREFIX/lib``, etc. The paths included in this dictionary are | ||
| listed on the class' attributes: `Installation.pg_directories` and | ||
| `Installation.pg_executables`. | ||
| The keys that point to installation directories are: ``bindir``, ``docdir``, | ||
| ``includedir``, ``pkgincludedir``, ``includedir_server``, ``libdir``, | ||
| ``pkglibdir``, ``localedir``, ``mandir``, ``sharedir``, and ``sysconfdir``. | ||
| The keys that point to installation executables are: ``pg_config``, ``psql``, | ||
| ``initdb``, ``pg_resetxlog``, ``pg_controldata``, ``clusterdb``, ``pg_ctl``, | ||
| ``pg_dump``, ``pg_dumpall``, ``postgres``, ``postmaster``, ``reindexdb``, | ||
| ``vacuumdb``, ``ipcclean``, ``createdb``, ``ecpg``, ``createuser``, | ||
| ``createlang``, ``droplang``, ``dropuser``, and ``pg_restore``. | ||
| .. note:: If the executable does not exist, the value will be `None` instead | ||
| of an absoluate path. | ||
| To get the path to the psql_ executable:: | ||
| from postgresql.installation import Installation | ||
| pg_install = Installation('/usr/local/pgsql/bin/pg_config') | ||
| psql_path = pg_install.paths['psql'] | ||
| Clusters | ||
| ======== | ||
| `postgresql.cluster.Cluster` is the class used to manage a PostgreSQL | ||
| cluster--a data directory created by initdb_. A Cluster represents a data | ||
| directory with respect to a given installation of PostgreSQL, so | ||
| creating a `postgresql.cluster.Cluster` object requires a | ||
| `postgresql.installation.Installation`, and a | ||
| file system path to the data directory. | ||
| In part, a `postgresql.cluster.Cluster` is the Python programmer's variant of | ||
| the pg_ctl_ command. However, it goes beyond the basic process control | ||
| functionality and extends into initialization and configuration as well. | ||
| A Cluster manages the server process using the `subprocess` module and | ||
| signals. The `subprocess.Popen` object, ``Cluster.daemon_process``, is | ||
| retained when the Cluster starts the server process itself. This gives | ||
| the Cluster access to the result code of server process when it exits, and the | ||
| ability to redirect stderr and stdout to a parameterized file object using | ||
| subprocess features. | ||
| Despite its use of `subprocess`, Clusters can control a server process | ||
| that was *not* started by the Cluster's ``start`` method. | ||
| Initializing Clusters | ||
| --------------------- | ||
| `postgresql.cluster.Cluster` provides a method for initializing a | ||
| `Cluster`'s data directory, ``init``. This method provides a Python interface to | ||
| the PostgreSQL initdb_ command. | ||
| ``init`` is a regular method and accepts a few keyword parameters. Normally, | ||
| parameters are directly mapped to initdb_ command options. However, ``password`` | ||
| makes use of initdb's capability to read the superuser's password from a file. | ||
| To do this, a temporary file is allocated internally by the method:: | ||
| from postgresql.installation import Installation, pg_config_dictionary | ||
| from postgresql.cluster import Cluster | ||
| pg_install = Installation(pg_config_dictionary('/usr/local/pgsql/bin/pg_config')) | ||
| pg_cluster = Cluster(pg_install, 'pg_data') | ||
| pg_cluster.init(user = 'pg', password = 'secret', encoding = 'utf-8') | ||
| The init method will block until the initdb command is complete. Once | ||
| initialized, the Cluster may be configured. | ||
| Configuring Clusters | ||
| -------------------- | ||
| A Cluster's `configuration file`_ can be manipulated using the | ||
| `Cluster.settings` mapping. The mapping's methods will always access the | ||
| configuration file, so it may be desirable to cache repeat reads. Also, if | ||
| multiple settings are being applied, using the ``update()`` method may be | ||
| important to avoid writing the entire file multiple times:: | ||
| pg_cluster.settings.update({'listen_addresses' : 'localhost', 'port' : '6543'}) | ||
| Similarly, to avoid opening and reading the entire file multiple times, | ||
| `Cluster.settings.getset` should be used to retrieve multiple settings:: | ||
| d = pg_cluster.settings.getset(set(('listen_addresses', 'port'))) | ||
| d | ||
| {'listen_addresses' : 'localhost', 'port' : '6543'} | ||
| Values contained in ``settings`` are always Python strings:: | ||
| assert pg_cluster.settings['max_connections'].__class__ is str | ||
| The ``postgresql.conf`` file is only one part of the server configuration. | ||
| Structured access and manipulation of the pg_hba_ file is not | ||
| supported. Clusters only provide the file path to the pg_hba_ file:: | ||
| hba = open(pg_cluster.hba_file) | ||
| If the configuration of the Cluster is altered while the server process is | ||
| running, it may be necessary to signal the process that configuration changes | ||
| have been made. This signal can be sent using the ``Cluster.reload()`` method. | ||
| ``Cluster.reload()`` will send a SIGHUP signal to the server process. However, | ||
| not all changes to configuration settings can go into effect after calling | ||
| ``Cluster.reload()``. In those cases, the server process will need to be | ||
| shutdown and started again. | ||
| Controlling Clusters | ||
| -------------------- | ||
| The server process of a Cluster object can be controlled with the ``start()``, | ||
| ``stop()``, ``shutdown()``, ``kill()``, and ``restart()`` methods. | ||
| These methods start the server process, signal the server process, or, in the | ||
| case of restart, a combination of the two. | ||
| When a Cluster starts the server process, it's ran as a subprocess. Therefore, | ||
| if the current process exits, the server process will exit as well. ``start()`` | ||
| does *not* automatically daemonize the server process. | ||
| .. note:: Under Microsoft Windows, above does not hold true. The server process | ||
| will continue running despite the exit of the parent process. | ||
| To terminate a server process, one of these three methods should be called: | ||
| ``stop``, ``shutdown``, or ``kill``. ``stop`` is a graceful shutdown and will | ||
| *wait for all clients to disconnect* before shutting down. ``shutdown`` will | ||
| close any open connections and safely shutdown the server process. | ||
| ``kill`` will immediately terminate the server process leading to recovery upon | ||
| starting the server process again. | ||
| .. note:: Using ``kill`` may cause shared memory to be leaked. | ||
| Normally, `Cluster.shutdown` is the appropriate way to terminate a server | ||
| process. | ||
| Cluster Interface Points | ||
| ------------------------ | ||
| Methods and properties available on `postgresql.cluster.Cluster` instances: | ||
| ``Cluster(installation, data_directory)`` | ||
| Create a `postgresql.cluster.Cluster` object for the specified | ||
| `postgresql.installation.Installation`, and ``data_directory``. | ||
| The ``data_directory`` must be an absoluate file system path. The directory | ||
| does *not* need to exist. The ``init()`` method may later be used to create | ||
| the cluster. | ||
| ``Cluster.installation`` | ||
| The Cluster's `postgresql.installation.Installation` instance. | ||
| ``Cluster.data_directory`` | ||
| The absolute path to the PostgreSQL data directory. | ||
| This directory may not exist. | ||
| ``Cluster.init([encoding = None[, user = None[, password = None]]])`` | ||
| Run the `initdb`_ executable of the configured installation to initialize the | ||
| cluster at the configured data directory, `Cluster.data_directory`. | ||
| ``encoding`` is mapped to ``-E``, the default database encoding. By default, | ||
| the encoding is determined from the environment's locale. | ||
| ``user`` is mapped to ``-U``, the database superuser name. By default, the | ||
| current user's name. | ||
| ``password`` is ultimately mapped to ``--pwfile``. The argument given to the | ||
| long option is actually a path to the temporary file that holds the given | ||
| password. | ||
| Raises `postgresql.cluster.InitDBError` when initdb_ returns a non-zero result | ||
| code. | ||
| Raises `postgresql.cluster.ClusterInitializationError` when there is no | ||
| initdb_ in the Installation. | ||
| ``Cluster.initialized()`` | ||
| Whether or not the data directory exists, *and* if it looks like a PostgreSQL | ||
| data directory. Meaning, the directory must contain a ``postgresql.conf`` file | ||
| and a ``base`` directory. | ||
| ``Cluster.drop()`` | ||
| Shutdown the Cluster's server process and completely remove the | ||
| `Cluster.data_directory` from the file system. | ||
| ``Cluster.pid()`` | ||
| The server's process identifier as a Python `int`. `None` if there is no | ||
| server process running. | ||
| This is a method rather than a property as it may read the PID from a file | ||
| in cases where the server process was not started by the Cluster. | ||
| ``Cluster.start([logfile = None[, settings = None]])`` | ||
| Start the PostgreSQL server process for the Cluster if it is not | ||
| already running. This will execute postgres_ as a subprocess. | ||
| If ``logfile``, an opened and writable file object, is given, stderr and | ||
| stdout will be redirected to that file. By default, both stderr and stdout are | ||
| closed. | ||
| If ``settings`` is given, the mapping or sequence of pairs will be used as | ||
| long options to the subprocess. For each item, ``--{key}={value}`` will be | ||
| given as an argument to the subprocess. | ||
| ``Cluster.running()`` | ||
| Whether or not the cluster's server process is running. Returns `True` or | ||
| `False`. Even if `True` is returned, it does *not* mean that the server | ||
| process is ready to accept connections. | ||
| ``Cluster.ready_for_connections()`` | ||
| Whether or not the Cluster is ready to accept connections. Usually called | ||
| after `Cluster.start`. | ||
| Returns `True` when the Cluster can accept connections, `False` when it | ||
| cannot, and `None` if the Cluster's server process is not running at all. | ||
| ``Cluster.wait_until_started([timeout = 10[, delay = 0.05]])`` | ||
| Blocks the process until the cluster is identified as being ready for | ||
| connections. Usually called after ``Cluster.start()``. | ||
| Raises `postgresql.cluster.ClusterNotRunningError` if the server process is | ||
| not running at all. | ||
| Raises `postgresql.cluster.ClusterTimeoutError` if | ||
| `Cluster.ready_for_connections()` does not return `True` within the given | ||
| `timeout` period. | ||
| Raises `postgresql.cluster.ClusterStartupError` if the server process | ||
| terminates while polling for readiness. | ||
| ``timeout`` and ``delay`` are both in seconds. Where ``timeout`` is the | ||
| maximum time to wait for the Cluster to be ready for connections, and | ||
| ``delay`` is the time to sleep between calls to | ||
| `Cluster.ready_for_connections()`. | ||
| ``Cluster.stop()`` | ||
| Signal the cluster to shutdown when possible. The *server* will wait for all | ||
| clients to disconnect before shutting down. | ||
| ``Cluster.shutdown()`` | ||
| Signal the cluster to shutdown immediately. Any open client connections will | ||
| be closed. | ||
| ``Cluster.kill()`` | ||
| Signal the absolute destruction of the server process(SIGKILL). | ||
| *This will require recovery when the cluster is started again.* | ||
| *Shared memory may be leaked.* | ||
| ``Cluster.wait_until_stopped([timeout = 10[, delay = 0.05]])`` | ||
| Blocks the process until the cluster is identified as being shutdown. Usually | ||
| called after `Cluster.stop` or `Cluster.shutdown`. | ||
| Raises `postgresql.cluster.ClusterTimeoutError` if | ||
| `Cluster.ready_for_connections` does not return `None` within the given | ||
| `timeout` period. | ||
| ``Cluster.reload()`` | ||
| Signal the server that it should reload its configuration files(SIGHUP). | ||
| Usually called after manipulating `Cluster.settings` or modifying the | ||
| contents of `Cluster.hba_file`. | ||
| ``Cluster.restart([logfile = None[, settings = None[, timeout = 10]]])`` | ||
| Stop the server process, wait until it is stopped, start the server | ||
| process, and wait until it has started. | ||
| .. note:: This calls ``Cluster.stop()``, so it will wait until clients | ||
| disconnect before starting up again. | ||
| The ``logfile`` and ``settings`` parameters will be given to `Cluster.start`. | ||
| ``timeout`` will be given to `Cluster.wait_until_stopped` and | ||
| `Cluster.wait_until_started`. | ||
| ``Cluster.settings`` | ||
| A `collections.Mapping` interface to the ``postgresql.conf`` file of the | ||
| cluster. | ||
| A notable extension to the mapping interface is the ``getset`` method. This | ||
| method will return a dictionary object containing the settings whose names | ||
| were contained in the `set` object given to the method. | ||
| This method should be used when multiple settings need to be retrieved from | ||
| the configuration file. | ||
| ``Cluster.hba_file`` | ||
| The path to the cluster's pg_hba_ file. This property respects the HBA file | ||
| location setting in ``postgresql.conf``. Usually, ``$PGDATA/pg_hba.conf``. | ||
| ``Cluster.daemon_path`` | ||
| The path to the executable to use to start the server process. | ||
| ``Cluster.daemon_process`` | ||
| The `subprocess.Popen` instance of the server process. `None` if the server | ||
| process was not started or was not started using the Cluster object. | ||
| .. _pg_hba: http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html | ||
| .. _pg_config: http://www.postgresql.org/docs/current/static/app-pgconfig.html | ||
| .. _initdb: http://www.postgresql.org/docs/current/static/app-initdb.html | ||
| .. _psql: http://www.postgresql.org/docs/current/static/app-psql.html | ||
| .. _postgres: http://www.postgresql.org/docs/current/static/app-postgres.html | ||
| .. _pg_ctl: http://www.postgresql.org/docs/current/static/app-pg-ctl.html | ||
| .. _configuration file: http://www.postgresql.org/docs/current/static/runtime-config.html |
| .. _pg_copyman: | ||
| *************** | ||
| Copy Management | ||
| *************** | ||
| The `postgresql.copyman` module provides a way to quickly move COPY data coming | ||
| from one connection to many connections. Alternatively, it can be sourced | ||
| by arbitrary iterators and target arbitrary callables. | ||
| Statement execution methods offer a way for running COPY operations | ||
| with iterators, but the cost of allocating objects for each row is too | ||
| significant for transferring gigabytes of COPY data from one connection to | ||
| another. The interfaces available on statement objects are primarily intended to | ||
| be used when transferring COPY data to and from arbitrary Python | ||
| objects. | ||
| Direct connection-to-connection COPY operations can be performed using the | ||
| high-level `postgresql.copyman.transfer` function:: | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> total_rows, total_bytes = copyman.transfer(send_stmt, receive_stmt) | ||
| However, if more control is needed, the `postgresql.copyman.CopyManager` class | ||
| should be used directly. | ||
| Copy Managers | ||
| ============= | ||
| The `postgresql.copyman.CopyManager` class manages the Producer and the | ||
| Receivers involved in a COPY operation. Normally, | ||
| `postgresql.copyman.StatementProducer` and | ||
| `postgresql.copyman.StatementReceiver` instances. Naturally, a Producer is the | ||
| object that produces the COPY data to be given to the Manager's Receivers. | ||
| Using a Manager directly means that there is a need for more control over | ||
| the operation. The Manager is both a context manager and an iterator. The | ||
| context manager interfaces handle initialization and finalization of the COPY | ||
| state, and the iterator provides an event loop emitting information about the | ||
| amount of COPY data transferred this cycle. Normal usage takes the form:: | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> producer = copyman.StatementProducer(send_stmt) | ||
| >>> receiver = copyman.StatementReceiver(receive_stmt) | ||
| >>> | ||
| >>> with source.xact(), destination.xact(): | ||
| ... with copyman.CopyManager(producer, receiver) as copy: | ||
| ... for num_messages, num_bytes in copy: | ||
| ... update_rate(num_bytes) | ||
| As an alternative to a for-loop inside a with-statement block, the `run` method | ||
| can be called to perform the operation:: | ||
| >>> with source.xact(), destination.xact(): | ||
| ... copyman.CopyManager(producer, receiver).run() | ||
| However, there is little benefit beyond using the high-level | ||
| `postgresql.copyman.transfer` function. | ||
| Manager Interface Points | ||
| ------------------------ | ||
| Primarily, the `postgresql.copyman.CopyManager` provides a context manager and | ||
| an iterator for controlling the COPY operation. | ||
| ``CopyManager.run()`` | ||
| Perform the entire COPY operation. | ||
| ``CopyManager.__enter__()`` | ||
| Start the COPY operation. Connections taking part in the COPY should **not** | ||
| be used until ``__exit__`` is ran. | ||
| ``CopyManager.__exit__(typ, val, tb)`` | ||
| Finish the COPY operation. Fails in the case of an incomplete | ||
| COPY, or an untrapped exception. Either returns `None` or raises the generalized | ||
| exception, `postgresql.copyman.CopyFail`. | ||
| ``CopyManager.__iter__()`` | ||
| Returns the CopyManager instance. | ||
| ``CopyManager.__next__()`` | ||
| Transfer the next chunk of COPY data to the receivers. Yields a tuple | ||
| consisting of the number of messages and bytes transferred, | ||
| ``(num_messages, num_bytes)``. Raises `StopIteration` when complete. | ||
| Raises `postgresql.copyman.ReceiverFault` when a Receiver raises an | ||
| exception. | ||
| Raises `postgresql.copyman.ProducerFault` when the Producer raises an | ||
| exception. The original exception is available via the exception's | ||
| ``__context__`` attribute. | ||
| ``CopyManager.reconcile(faulted_receiver)`` | ||
| Reconcile a faulted receiver. When a receiver faults, it will no longer | ||
| be in the set of Receivers. This method is used to signal to the manager that the | ||
| problem has been corrected, and the receiver is again ready to receive. | ||
| ``CopyManager.receivers`` | ||
| The `builtins.set` of Receivers involved in the COPY operation. | ||
| ``CopyManager.producer`` | ||
| The Producer emitting the data to be given to the Receivers. | ||
| Faults | ||
| ====== | ||
| The CopyManager generalizes any exceptions that occur during transfer. While | ||
| inside the context manager, `postgresql.copyman.Fault` may be raised if a | ||
| Receiver or a Producer raises an exception. A `postgresql.copyman.ProducerFault` | ||
| in the case of the Producer, and `postgresql.copyman.ReceiverFault` in the case | ||
| of the Receivers. | ||
| .. note:: | ||
| Faults are only raised by `postgresql.copyman.CopyManager.__next__`. The | ||
| ``run()`` method will only raise `postgresql.copyman.CopyFail`. | ||
| Receiver Faults | ||
| --------------- | ||
| The Manager assumes the Fault is fatal to a Receiver, and immediately removes | ||
| it from the set of target receivers. Additionally, if the Fault exception goes | ||
| untrapped, the copy will ultimately fail. | ||
| The Fault exception references the Manager that raised the exception, and the | ||
| actual exceptions that occurred associated with the Receiver that caused them. | ||
| In order to identify the exception that caused a Fault, the ``faults`` attribute | ||
| on the `postgresql.copyman.ReceiverFault` must be referenced:: | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> producer = copyman.StatementProducer(send_stmt) | ||
| >>> receiver = copyman.StatementReceiver(receive_stmt) | ||
| >>> | ||
| >>> with source.xact(), destination.xact(): | ||
| ... with copyman.CopyManager(producer, receiver) as copy: | ||
| ... while copy.receivers: | ||
| ... try: | ||
| ... for num_messages, num_bytes in copy: | ||
| ... update_rate(num_bytes) | ||
| ... break | ||
| ... except copyman.ReceiverFault as cf: | ||
| ... # Access the original exception using the receiver as the key. | ||
| ... original_exception = cf.faults[receiver] | ||
| ... if unknown_failure(original_exception): | ||
| ... ... | ||
| ... raise | ||
| ReceiverFault Properties | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| The following attributes exist on `postgresql.copyman.ReceiverFault` instances: | ||
| ``ReceiverFault.manager`` | ||
| The subject `postgresql.copyman.CopyManager` instance. | ||
| ``ReceiverFault.faults`` | ||
| A dictionary mapping the Receiver to the exception raised by that Receiver. | ||
| Reconciliation | ||
| ~~~~~~~~~~~~~~ | ||
| When a `postgresql.copyman.ReceiverFault` is raised, the Manager immediately | ||
| removes the Receiver so that the COPY operation can continue. Continuation of | ||
| the COPY can occur by trapping the exception and continuing the iteration of the | ||
| Manager. However, if the fault is recoverable, the | ||
| `postgresql.copyman.CopyManager.reconcile` method must be used to reintroduce the | ||
| Receiver into the Manager's set. Faults must be trapped from within the | ||
| Manager's context:: | ||
| >>> import socket | ||
| >>> from postgresql import copyman | ||
| >>> send_stmt = source.prepare("COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT") | ||
| >>> destination.execute("CREATE TEMP TABLE loading_table (i int8)") | ||
| >>> receive_stmt = destination.prepare("COPY loading_table FROM STDIN") | ||
| >>> producer = copyman.StatementProducer(send_stmt) | ||
| >>> receiver = copyman.StatementReceiver(receive_stmt) | ||
| >>> | ||
| >>> with source.xact(), destination.xact(): | ||
| ... with copyman.CopyManager(producer, receiver) as copy: | ||
| ... while copy.receivers: | ||
| ... try: | ||
| ... for num_messages, num_bytes in copy: | ||
| ... update_rate(num_bytes) | ||
| ... except copyman.ReceiverFault as cf: | ||
| ... if isinstance(cf.faults[receiver], socket.timeout): | ||
| ... copy.reconcile(receiver) | ||
| ... else: | ||
| ... raise | ||
| Recovering from Faults does add significant complexity to a COPY operation, | ||
| so, often, it's best to avoid conditions in which reconciliable Faults may | ||
| occur. | ||
| Producer Faults | ||
| --------------- | ||
| Producer faults are normally fatal to the COPY operation and should rarely be | ||
| trapped. However, the Manager makes no state changes when a Producer faults, | ||
| so, unlike Receiver Faults, no reconciliation process is necessary; rather, | ||
| if it's safe to continue, the Manager's iterator should continue to be | ||
| processed. | ||
| ProducerFault Properties | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| The following attributes exist on `postgresql.copyman.ProducerFault` instances: | ||
| ``ReceiverFault.manager`` | ||
| The subject `postgresql.copyman.CopyManager`. | ||
| ``ReceiverFault.__context__`` | ||
| The original exception raised by the Producer. | ||
| Failures | ||
| ======== | ||
| When a COPY operation is aborted, either by an exception or by the iterator | ||
| being broken, a `postgresql.copyman.CopyFail` exception will be raised by the | ||
| Manager's ``__exit__()`` method. The `postgresql.copyman.CopyFail` exception | ||
| offers to record any exceptions that occur during the exit of the context | ||
| managers of the Producer and the Receivers. | ||
| CopyFail Properties | ||
| ------------------- | ||
| The following properties exist on `postgresql.copyman.CopyFail` exceptions: | ||
| ``CopyFail.manager`` | ||
| The Manager whose COPY operation failed. | ||
| ``CopyFail.receiver_faults`` | ||
| A dictionary mapping a `postgresql.copyman.Receiver` to the exception raised | ||
| by that Receiver's ``__exit__``. `None` if no exceptions were raised by the | ||
| Receivers. | ||
| ``CopyFail.producer_fault`` | ||
| The exception Raised by the `postgresql.copyman.Producer`. `None` if none. | ||
| Producers | ||
| ========= | ||
| The following Producers are available: | ||
| ``postgresql.copyman.StatementProducer(postgresql.api.Statement)`` | ||
| Given a Statement producing COPY data, construct a Producer. | ||
| ``postgresql.copyman.IteratorProducer(collections.Iterator)`` | ||
| Given an Iterator producing *chunks* of COPY lines, construct a Producer to | ||
| manage the data coming from the iterator. | ||
| Receivers | ||
| ========= | ||
| ``postgresql.copyman.StatementReceiver(postgresql.api.Statement)`` | ||
| Given a Statement producing COPY data, construct a Producer. | ||
| ``postgresql.copyman.CallReceiver(callable)`` | ||
| Given a callable, construct a Receiver that will transmit COPY data in chunks | ||
| of lines. That is, the callable will be given a list of COPY lines for each | ||
| transfer cycle. | ||
| Terminology | ||
| =========== | ||
| The following terms are regularly used to describe the implementation and | ||
| processes of the `postgresql.copyman` module: | ||
| Manager | ||
| The object used to manage data coming from a Producer and being given to the | ||
| Receivers. It also manages the necessary initialization and finalization steps | ||
| required by those factors. | ||
| Producer | ||
| The object used to produce the COPY data to be given to the Receivers. The | ||
| source. | ||
| Receiver | ||
| An object that consumes COPY data. A target. | ||
| Fault | ||
| Specifically, `postgresql.copyman.Fault` exceptions. A Fault is raised | ||
| when a Receiver or a Producer raises an exception during the COPY operation. | ||
| Reconciliation | ||
| Generally, the steps performed by the "reconcile" method on | ||
| `postgresql.copyman.CopyManager` instances. More precisely, the | ||
| necessary steps for a Receiver's reintroduction into the COPY operation after | ||
| a Fault. | ||
| Failed Copy | ||
| A failed copy is an aborted COPY operation. This occurs in situations of | ||
| untrapped exceptions or an incomplete COPY. Specifically, the COPY will be | ||
| noted as failed in cases where the Manager's iterator is *not* ran until | ||
| exhaustion. | ||
| Realignment | ||
| The process of providing compensating data to the Receivers so that the | ||
| connection will be on a message boundary. Occurs when the COPY operation | ||
| is aborted. |
Sorry, the diff of this file is too big to display
| Gotchas | ||
| ======= | ||
| It is recognized that decisions were made that may not always be ideal for a | ||
| given user. In order to highlight those potential issues and hopefully bring | ||
| some sense into a confusing situation, this document was drawn. | ||
| Non-English Locales | ||
| ------------------- | ||
| Many non-english locales are not supported due to the localization of the severity field | ||
| in messages and errors sent to the client. Internally, py-postgresql uses this to allow | ||
| client side filtering of messages and to identify FATAL connection errors that allow the | ||
| client to recognize that it should be expecting the connection to terminate. | ||
| Thread Safety | ||
| ------------- | ||
| py-postgresql connection operations are not thread safe. | ||
| `client_encoding` setting should be altered carefully | ||
| ----------------------------------------------------- | ||
| `postgresql.driver`'s streaming cursor implementation reads a fixed set of rows | ||
| when it queries the server for more. In order to optimize some situations, the | ||
| driver will send a request for more data, but makes no attempt to wait and | ||
| process the data as it is not yet needed. When the user comes back to read more | ||
| data from the cursor, it will then look at this new data. The problem being, if | ||
| `client_encoding` was switched, it may use the wrong codec to transform the | ||
| wire data into higher level Python objects(str). | ||
| To avoid this problem from ever happening, set the `client_encoding` early. | ||
| Furthermore, it is probably best to never change the `client_encoding` as the | ||
| driver automatically makes the necessary transformation to Python strings. | ||
| The user and password is correct, but it does not work when using `postgresql.driver` | ||
| ------------------------------------------------------------------------------------- | ||
| This issue likely comes from the possibility that the information sent to the | ||
| server early in the negotiation phase may not be in an encoding that is | ||
| consistent with the server's encoding. | ||
| One problem is that PostgreSQL does not provide the client with the server | ||
| encoding early enough in the negotiation phase, and, therefore, is unable to | ||
| process the password data in a way that is consistent with the server's | ||
| expectations. | ||
| Another problem is that PostgreSQL takes much of the data in the startup message | ||
| as-is, so a decision about the best way to encode parameters is difficult. | ||
| The easy way to avoid *most* issues with this problem is to initialize the | ||
| database in the `utf-8` encoding. The driver defaults the expected server | ||
| encoding to `utf-8`. However, this can be overridden by creating the `Connector` | ||
| with a `server_encoding` parameter. Setting `server_encoding` to the proper | ||
| value of the target server will allow the driver to properly encode *some* of | ||
| the parameters. Also, any GUC parameters passed via the `settings` parameter | ||
| should use typed objects when possible to hint that the server encoding should | ||
| not be used on that parameter(`bytes`, for instance). | ||
| Backslash characters are being treated literally | ||
| ------------------------------------------------ | ||
| The driver enables standard compliant strings. Stop using non-standard features. | ||
| ;) | ||
| If support for non-standard strings was provided it would require to the | ||
| driver to provide subjective quote interfaces(eg, db.quote_literal). Doing so is | ||
| not desirable as it introduces difficulties for the driver *and* the user. | ||
| Types without binary support in the driver are unsupported in arrays and records | ||
| -------------------------------------------------------------------------------- | ||
| When an array or composite type is identified, `postgresql.protocol.typio` | ||
| ultimately chooses the binary format for the transfer of the column or | ||
| parameter. When this is done, PostgreSQL will pack or expect *all* the values | ||
| in binary format as well. If that binary format is not supported and the type | ||
| is not an string, it will fail to unpack the row or pack the appropriate data for | ||
| the element or attribute. | ||
| In most cases issues related to this can be avoided with explicit casts to text. | ||
| NOTICEs, WARNINGs, and other messages are too verbose | ||
| ----------------------------------------------------- | ||
| For many situations, the information provided with database messages is | ||
| far too verbose. However, considering that py-postgresql is a programmer's | ||
| library, the default of high verbosity is taken with the express purpose of | ||
| allowing the programmer to "adjust the volume" until appropriate. | ||
| By default, py-postgresql adjusts the ``client_min_messages`` to only emit | ||
| messages at the WARNING level or higher--ERRORs, FATALs, and PANICs. | ||
| This reduces the number of messages generated by most connections dramatically. | ||
| If further customization is needed, the :ref:`db_messages` section has | ||
| information on overriding the default action taken with database messages. | ||
| Strange TypeError using load_rows() or load_chunks() | ||
| ---------------------------------------------------- | ||
| When a prepared statement is directly executed using ``__call__()``, it can easily | ||
| validate that the appropriate number of parameters are given to the function. | ||
| When ``load_rows()`` or ``load_chunks()`` is used, any tuple in the | ||
| the entire sequence can cause this TypeError during the loading process:: | ||
| TypeError: inconsistent items, N processors and M items in row | ||
| This exception is raised by a generic processing routine whose functionality | ||
| is abstract in nature, so the message is abstract as well. It essentially means | ||
| that a tuple in the sequence given to the loading method had too many or too few | ||
| items. |
| py-postgresql | ||
| ============= | ||
| py-postgresql is a project dedicated to improving the Python client interfaces to PostgreSQL. | ||
| At its core, py-postgresql provides a PG-API, `postgresql.api`, and | ||
| DB-API 2.0 interface for using a PostgreSQL database. | ||
| Contents | ||
| -------- | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
| admin | ||
| driver | ||
| copyman | ||
| notifyman | ||
| alock | ||
| cluster | ||
| lib | ||
| clientparameters | ||
| gotchas | ||
| Reference | ||
| --------- | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
| bin | ||
| reference | ||
| Changes | ||
| ------- | ||
| .. toctree:: | ||
| :maxdepth: 1 | ||
| changes-v1.1 | ||
| changes-v1.0 | ||
| Sample Code | ||
| ----------- | ||
| Using `postgresql.driver`:: | ||
| >>> import postgresql | ||
| >>> db = postgresql.open("pq://user:password@host/name_of_database") | ||
| >>> db.execute("CREATE TABLE emp (emp_name text PRIMARY KEY, emp_salary numeric)") | ||
| >>> | ||
| >>> # Create the statements. | ||
| >>> make_emp = db.prepare("INSERT INTO emp VALUES ($1, $2)") | ||
| >>> raise_emp = db.prepare("UPDATE emp SET emp_salary = emp_salary + $2 WHERE emp_name = $1") | ||
| >>> get_emp_with_salary_lt = db.prepare("SELECT emp_name FROM emp WHERE emp_salay < $1") | ||
| >>> | ||
| >>> # Create some employees, but do it in a transaction--all or nothing. | ||
| >>> with db.xact(): | ||
| ... make_emp("John Doe", "150,000") | ||
| ... make_emp("Jane Doe", "150,000") | ||
| ... make_emp("Andrew Doe", "55,000") | ||
| ... make_emp("Susan Doe", "60,000") | ||
| >>> | ||
| >>> # Give some raises | ||
| >>> with db.xact(): | ||
| ... for row in get_emp_with_salary_lt("125,000"): | ||
| ... print(row["emp_name"]) | ||
| ... raise_emp(row["emp_name"], "10,000") | ||
| Of course, if DB-API 2.0 is desired, the module is located at | ||
| `postgresql.driver.dbapi20`. DB-API extends PG-API, so the features | ||
| illustrated above are available on DB-API connections. | ||
| See :ref:`db_interface` for more information. |
| Categories and Libraries | ||
| ************************ | ||
| This chapter discusses the usage and implementation of connection categories and | ||
| libraries. | ||
| .. note:: | ||
| First-time users are encouraged to read the `Audience and Motivation`_ | ||
| section first. | ||
| Libraries are a collection of SQL statements that can be bound to a | ||
| connection. Libraries are *normally* bound directly to the connection object as | ||
| an attribute using a name specified by the library. | ||
| Libraries provide a common way for SQL statements to be managed outside of the | ||
| code that uses them. When using ILFs, this increases the portability of the SQL | ||
| by keeping the statements isolated from the Python code in an accessible format | ||
| that can be easily used by other languages or systems --- An ILF parser can be | ||
| implemented within a few dozen lines using basic text tools. | ||
| SQL statements defined by a Library are identified by their Symbol. These | ||
| symbols are named and annotated in order to allow the user to define how a | ||
| statement is to be used. The user may state the default execution method of | ||
| the statement object, or whether the symbol is to be preloaded at bind | ||
| time--these properties are Symbol Annotations. | ||
| The purpose of libraries are to provide a means to manage statements on | ||
| disk and at runtime. ILFs provide a means to reference a collection | ||
| of statements on disk, and, when loaded, the symbol bindings provides means to | ||
| reference a statement already prepared for use on a given connection. | ||
| The `postgresql.lib` package-module provides fundamental classes for supporting | ||
| categories and libraries. | ||
| Writing Libraries | ||
| ================= | ||
| ILF files are the recommended way to build a library. These files use the | ||
| naming convention "lib{NAME}.sql". The prefix and suffix are used describe the | ||
| purpose of the file and to provide a hint to editors that SQL highlighting | ||
| should be used. The format of an ILF takes the form:: | ||
| <Preface> | ||
| [name:type:method] | ||
| <statement> | ||
| ... | ||
| Where multiple symbols may be defined. The Preface that comes before the first | ||
| symbol is an arbitrary block of text that should be used to describe the library. | ||
| This block is free-form, and should be considered a good place for some | ||
| general documentation. | ||
| Symbols are named and described using the contents of section markers: | ||
| ``('[' ... ']')``. Section markers have three components: the symbol name, | ||
| the symbol type and the symbol method. Each of these components are separated | ||
| using a single colon, ``:``. All components are optional except the Symbol name. | ||
| For example:: | ||
| [get_user_info] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| [get_user_info_v2::] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| In the above example, ``get_user_info`` and ``get_user_info_v2`` are identical. | ||
| Empty components indicate the default effect. | ||
| The second component in the section identifier is the symbol type. All Symbol | ||
| types are listed in `Symbol Types`_. This can be | ||
| used to specify what the section's contents are or when to bind the | ||
| symbol:: | ||
| [get_user_info:preload] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| This provides the Binding with the knowledge that the statement should be | ||
| prepared when the Library is bound. Therefore, when this Symbol's statement | ||
| is used for the first time, it will have already been prepared. | ||
| Another type is the ``const`` Symbol type. This defines a data Symbol whose | ||
| *statement results* will be resolved when the Library is bound:: | ||
| [user_type_ids:const] | ||
| SELECT user_type_id, user_type FROM user_types; | ||
| Constant Symbols cannot take parameters as they are data properties. The | ||
| *result* of the above query is set to the Bindings' ``user_type_ids`` | ||
| attribute:: | ||
| >>> db.lib.user_type_ids | ||
| <sequence of (user_type_id, user_type)> | ||
| Where ``lib`` in the above is a Binding of the Library containing the | ||
| ``user_type_ids`` Symbol. | ||
| Finally, procedures can be bound as symbols using the ``proc`` type:: | ||
| [remove_user:proc] | ||
| remove_user(bigint) | ||
| All procedures symbols are loaded when the Library is bound. Procedure symbols | ||
| are special because the execution method is effectively specified by the | ||
| procedure itself. | ||
| The third component is the symbol ``method``. This defines the execution method | ||
| of the statement and ultimately what is returned when the Symbol is called at | ||
| runtime. All the execution methods are listed in `Symbol Execution Methods`_. | ||
| The default execution method is the default execution method of | ||
| `postgresql.api.PreparedStatement` objects; return the entire result set in a | ||
| list object:: | ||
| [get_numbers] | ||
| SELECT i FROM generate_series(0, 100-1) AS g(i); | ||
| When bound:: | ||
| >>> db.lib.get_numbers() == [(x,) for x in range(100)] | ||
| True | ||
| The transformation of range in the above is necessary as statements | ||
| return a sequence of row objects by default. | ||
| For large result-sets, fetching all the rows would be taxing on a system's | ||
| memory. The ``rows`` and ``chunks`` methods provide an iterator to rows produced | ||
| by a statement using a stream:: | ||
| [get_some_rows::rows] | ||
| SELECT i FROM generate_series(0, 1000) AS g(i); | ||
| [get_some_chunks::chunks] | ||
| SELECT i FROM generate_series(0, 1000) AS g(i); | ||
| ``rows`` means that the Symbol will return an iterator producing individual rows | ||
| of the result, and ``chunks`` means that the Symbol will return an iterator | ||
| producing sequences of rows of the result. | ||
| When bound:: | ||
| >>> from itertools import chain | ||
| >>> list(db.lib.get_some_rows()) == list(chain.from_iterable(db.lib.get_some_chunks())) | ||
| True | ||
| Other methods include ``column`` and ``first``. The column method provides a | ||
| means to designate that the symbol should return an iterator of the values in | ||
| the first column instead of an iterator to the rows:: | ||
| [another_generate_series_example::column] | ||
| SELECT i FROM generate_series(0, $1::int) AS g(i) | ||
| In use:: | ||
| >>> list(db.lib.another_generate_series_example(100-1)) == list(range(100)) | ||
| True | ||
| >>> list(db.lib.another_generate_series_example(10-1)) | ||
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | ||
| The ``first`` method provides direct access to simple results. | ||
| Specifically, the first column of the first row when there is only one column. | ||
| When there are multiple columns the first row is returned:: | ||
| [get_one::first] | ||
| SELECT 1 | ||
| [get_one_twice::first] | ||
| SELECT 1, 1 | ||
| In use:: | ||
| >>> db.lib.get_one() == 1 | ||
| True | ||
| >>> db.lib.get_one_twice() == (1,1) | ||
| True | ||
| .. note:: | ||
| ``first`` should be used with care. When the result returns no rows, `None` | ||
| will be returned. | ||
| Using Libraries | ||
| =============== | ||
| After a library is created, it must be loaded before it can be bound using | ||
| programmer interfaces. The `postgresql.lib.load` interface provides the | ||
| primary entry point for loading libraries. | ||
| When ``load`` is given a string, it identifies if a directory separator is in | ||
| the string, if there is it will treat the string as a *path* to the ILF to be | ||
| loaded. If no separator is found, it will treat the string as the library | ||
| name fragment and look for "lib{NAME}.sql" in the directories listed in | ||
| `postgresql.sys.libpath`. | ||
| Once a `postgresql.lib.Library` instance has been acquired, it can then be | ||
| bound to a connection for use. `postgresql.lib.Binding` is used to create an | ||
| object that provides and manages the Bound Symbols:: | ||
| >>> import postgresql.lib as pg_lib | ||
| >>> lib = pg_lib.load(...) | ||
| >>> B = pg_lib.Binding(db, lib) | ||
| The ``B`` object in the above example provides the Library's Symbols as | ||
| attributes which can be called to in order to execute the Symbol's statement:: | ||
| >>> B.symbol(param) | ||
| ... | ||
| While it is sometimes necessary, manual creation of a Binding is discouraged. | ||
| Rather, `postgresql.lib.Category` objects should be used to manage the set of | ||
| Libraries to be bound to a connection. | ||
| Categories | ||
| ---------- | ||
| Libraries provide access to a collection of symbols; Bindings provide an | ||
| interface to the symbols with respect to a subject database. When a connection | ||
| is established, multiple Bindings may need to be created in order to fulfill | ||
| the requirements of the programmer. When a Binding is created, it exists in | ||
| isolation; this can be an inconvenience when access to both the Binding and | ||
| the Connection is necessary. Categories exist to provide a formal method for | ||
| defining the interface extensions on a `postgresql.api.Database` | ||
| instance(connection). | ||
| A Category is essentially a runtime-class for connections. It provides a | ||
| formal initialization procedure for connection objects at runtime. However, | ||
| the connection resource must be connected prior to category initialization. | ||
| Categories are sets of Libraries to be bound to a connection with optional name | ||
| substitutions. In order to create one directly, pass the Library instances to | ||
| `postgresql.lib.Category`:: | ||
| >>> import postgresql.lib as pg_lib | ||
| >>> cat = pg_lib.Category(lib1, lib2, libN) | ||
| Where ``lib1``, ``lib2``, ``libN`` are `postgresql.lib.Library` instances; | ||
| usually created by `postgresql.lib.load`. Once created, categories can then | ||
| used by passing the ``category`` keyword to connection creation interfaces:: | ||
| >>> import postgresql | ||
| >>> db = postgresql.open(category = cat) | ||
| The ``db`` object will now have Bindings for ``lib1``, ``lib2``, ..., and | ||
| ``libN``. | ||
| Categories can alter the access point(attribute name) of Bindings. This is done | ||
| by instantiating the Category using keyword parameters:: | ||
| >>> cat = pg_lib.Category(lib1, lib2, libname = libN) | ||
| At this point, when a connection is established as the category ``cat``, | ||
| ``libN`` will be bound to the connection object on the attribute ``libname`` | ||
| instead of the name defined by the library. | ||
| And a final illustration of Category usage:: | ||
| >>> db = postgresql.open(category = pg_lib.Category(pg_lib.load('name'))) | ||
| >>> db.name | ||
| <Library> | ||
| Symbol Types | ||
| ============ | ||
| The symbol type determines how a symbol is going to be treated by the Binding. | ||
| For instance, ``const`` symbols are resolved when the Library is bound and | ||
| the statement object is immediately discarded. Here is a list of symbol types | ||
| that can be used in ILF libraries: | ||
| ``<default>`` (Empty component) | ||
| The symbol's statement will never change. This allows the Bound Symbol to | ||
| hold onto the `postgresql.api.PreparedStatement` object. When the symbol is | ||
| used again, it will refer to the existing prepared statement object. | ||
| ``preload`` | ||
| Like the default type, the Symbol is a simple statement, but it should be | ||
| loaded when the library is bound to the connection. | ||
| ``const`` | ||
| The statement takes no parameters and only needs to be executed once. This | ||
| will cause the statement to be executed when the library is bound and the | ||
| results of the statement will be set to the Binding using the symbol name so | ||
| that it may be used as a property by the user. | ||
| ``proc`` | ||
| The contents of the section is a procedure identifier. When this type is used | ||
| the symbol method *should not* be specified as the method annotation will be | ||
| automatically resolved based on the procedure's signature. | ||
| ``transient`` | ||
| The Symbol is a statement that should *not* be retained. Specifically, it is | ||
| a statement object that will be discarded when the user discard the referenced | ||
| Symbol. Used in cases where the statement is used once or very infrequently. | ||
| Symbol Execution Methods | ||
| ======================== | ||
| The Symbol Execution Method provides a way to specify how a statement is going | ||
| to be used. Specifically, which `postgresql.api.PreparedStatement` method | ||
| should be executed when a Bound Symbol is called. The following is a list of | ||
| the symbol execution methods and the effect it will have when invoked: | ||
| ``<default>`` (Empty component) | ||
| Returns the entire result set in a single list object. If the statement does | ||
| not return rows, a ``(command, count)`` pair will be returned. | ||
| ``rows`` | ||
| Returns an iterator producing each row in the result set. | ||
| ``chunks`` | ||
| Returns an iterator producing "chunks" of rows in the result set. | ||
| ``first`` | ||
| Returns the first column of the first row if there is one column in the result | ||
| set. If there are multiple columns in the result set, the first row is | ||
| returned. If query is non-RETURNING DML--insert, update, or delete, the row | ||
| count is returned. | ||
| ``column`` | ||
| Returns an iterator to values in the first column. (Equivalent to | ||
| executing a statement as ``map(operator.itemgetter(0), ps.rows())``.) | ||
| ``declare`` | ||
| Returns a scrollable cursor, `postgresql.api.Cursor`, to the result set. | ||
| ``load_chunks`` | ||
| Takes an iterable row-chunks to be given to the statement. Returns `None`. If | ||
| the statement is a ``COPY ... FROM STDIN``, the iterable must produce chunks | ||
| of COPY lines. | ||
| ``load_rows`` | ||
| Takes an iterable rows to be given as parameters. If the statement is a ``COPY | ||
| ... FROM STDIN``, the iterable must produce COPY lines. | ||
| Reference Symbols | ||
| ================= | ||
| Reference Symbols provide a way to construct a Bound Symbol using the Symbol's | ||
| query. When invoked, A Reference Symbol's query is executed in order to produce | ||
| an SQL statement to be used as a Bound Symbol. In ILF files, a reference is | ||
| identified by its symbol name being prefixed with an ampersand:: | ||
| [&refsym::first] | ||
| SELECT 'SELECT 1::int4'::text | ||
| Then executed:: | ||
| >>> # Runs the 'refsym' SQL, and creates a Bound Symbol using the results. | ||
| >>> sym = lib.refsym() | ||
| >>> assert sym() == 1 | ||
| The Reference Symbol's type and execution method are inherited by the created | ||
| Bound Symbol. With one exception, ``const`` reference symbols are | ||
| special in that they immediately resolved into the target Bound Symbol. | ||
| A Reference Symbol's source query *must* produce rows of text columns. Multiple | ||
| columns and multiple rows may be produced by the query, but they must be | ||
| character types as the results are promptly joined together with whitespace so | ||
| that the target statement may be prepared. | ||
| Reference Symbols are most likely to be used in dynamic DDL and DML situations, | ||
| or, somewhat more specifically, any query whose definition depends on a | ||
| generated column list. | ||
| Distributing and Usage | ||
| ====================== | ||
| For applications, distribution and management can easily be a custom | ||
| process. The application designates the library directory; the entry point | ||
| adds the path to the `postgresql.sys.libpath` list; a category is built; and, a | ||
| connection is made using the category. | ||
| For mere Python extensions, however, ``distutils`` has a feature that can | ||
| aid in ILF distribution. The ``package_data`` setup keyword can be used to | ||
| include ILF files alongside the Python modules that make up a project. See | ||
| http://docs.python.org/3.1/distutils/setupscript.html#installing-package-data | ||
| for more detailed information on the keyword parameter. | ||
| The recommended way to manage libraries for extending projects is to | ||
| create a package to contain them. For instance, consider the following layout:: | ||
| project/ | ||
| setup.py | ||
| pkg/ | ||
| __init__.py | ||
| lib/ | ||
| __init__.py | ||
| libthis.sql | ||
| libthat.sql | ||
| The project's SQL libraries are organized into a single package directory, | ||
| ``lib``, so ``package_data`` would be configured:: | ||
| package_data = {'pkg.lib': ['*.sql']} | ||
| Subsequently, the ``lib`` package initialization script can then be used to | ||
| load the libraries, and create any categories(``project/pkg/lib/__init__.py``):: | ||
| import os.path | ||
| import postgresql.lib as pg_lib | ||
| import postgresql.sys as pg_sys | ||
| libdir = os.path.dirname(__file__) | ||
| pg_sys.libpath.append(libdir) | ||
| libthis = pg_lib.load('this') | ||
| libthat = pg_lib.load('that') | ||
| stdcat = pg_lib.Category(libthis, libthat) | ||
| However, it can be undesirable to add the package directory to the global | ||
| `postgresql.sys.libpath` search paths. Direct path loading can be used in those | ||
| cases:: | ||
| import os.path | ||
| import postgresql.lib as pg_lib | ||
| libdir = os.path.dirname(__file__) | ||
| libthis = pg_lib.load(os.path.join(libdir, 'libthis.sql')) | ||
| libthat = pg_lib.load(os.path.join(libdir, 'libthat.sql')) | ||
| stdcat = pg_lib.Category(libthis, libthat) | ||
| Using the established project context, a connection would then be created as:: | ||
| from pkg.lib import stdcat | ||
| import postgresql as pg | ||
| db = pg.open(..., category = stdcat) | ||
| # And execute some fictitious symbols. | ||
| db.this.sym_from_libthis() | ||
| db.that.sym_from_libthat(...) | ||
| Audience and Motivation | ||
| ======================= | ||
| This chapter covers advanced material. It is **not** recommended that categories | ||
| and libraries be used for trivial applications or introductory projects. | ||
| .. note:: | ||
| Libraries and categories are not likely to be of interest to ORM or DB-API users. | ||
| With exception to ORMs or other similar abstractions, the most common pattern | ||
| for managing connections and statements is delegation:: | ||
| class MyAppDB(object): | ||
| def __init__(self, connection): | ||
| self.connection = connection | ||
| def my_operation(self, op_arg1, op_arg2): | ||
| return self.connection.prepare( | ||
| "SELECT my_operation_proc($1,$2)", | ||
| )(op_arg1, op_arg2) | ||
| ... | ||
| The straightforward nature is likeable, but the usage does not take advantage of | ||
| prepared statements. In order to do that an extra condition is necessary to see | ||
| if the statement has already been prepared:: | ||
| ... | ||
| def my_operation(self, op_arg1, op_arg2): | ||
| if self.hasattr(self, '_my_operation'): | ||
| ps = self._my_operation | ||
| else: | ||
| ps = self._my_operation = self.connection.prepare( | ||
| "SELECT my_operation_proc($1, $2)", | ||
| ) | ||
| return ps(op_arg1, op_arg2) | ||
| ... | ||
| There are many variations that can implement the above. It works and it's | ||
| simple, but it will be exhausting if repeated and error prone if the | ||
| initialization condition is not factored out. Additionally, if access to statement | ||
| metadata is needed, the above example is still lacking as it would require | ||
| execution of the statement and further protocol expectations to be established. | ||
| This is the province of libraries: direct database interface management. | ||
| Categories and Libraries are used to factor out and simplify | ||
| the above functionality so re-implementation is unnecessary. For example, an | ||
| ILF library containing the symbol:: | ||
| [my_operation] | ||
| SELECT my_operation_proc($1, $2) | ||
| [<other_symbol>] | ||
| ... | ||
| Will provide the same functionality as the ``my_operation`` method in the | ||
| latter Python implementation. | ||
| Terminology | ||
| =========== | ||
| The following terms are used throughout this chapter: | ||
| Annotations | ||
| The information of about a Symbol describing what it is and how it should be | ||
| used. | ||
| Binding | ||
| An interface to the Symbols provided by a Library for use with a given | ||
| connection. | ||
| Bound Symbol | ||
| An interface to an individual Symbol ready for execution against the subject | ||
| database. | ||
| Bound Reference | ||
| An interface to an individual Reference Symbol that will produce a Bound | ||
| Symbol when executed. | ||
| ILF | ||
| INI-style Library Format. "lib{NAME}.sql" files. | ||
| Library | ||
| A collection of Symbols--mapping of names to SQL statements. | ||
| Local Symbol | ||
| A relative term used to denote a symbol that exists in the same library as | ||
| the subject symbol. | ||
| Preface | ||
| The block of text that comes before the first symbol in an ILF file. | ||
| Symbol | ||
| An named database operation provided by a Library. Usually, an SQL statement | ||
| with Annotations. | ||
| Reference Symbol | ||
| A Symbol whose SQL statement *produces* the source for a Bound Symbol. | ||
| Category | ||
| An object supporting a classification for connectors that provides database | ||
| initialization facilities for produced connections. For libraries, | ||
| `postgresql.lib.Category` objects are a set of Libraries, | ||
| `postgresql.lib.Library`. |
| .. _notifyman: | ||
| *********************** | ||
| Notification Management | ||
| *********************** | ||
| Relevant SQL commands: `NOTIFY <http://postgresql.org/docs/current/static/sql-notify.html>`_, | ||
| `LISTEN <http://postgresql.org/docs/current/static/sql-listen.html>`_, | ||
| `UNLISTEN <http://postgresql.org/docs/current/static/sql-unlisten.html>`_. | ||
| Asynchronous notifications offer a means for PostgreSQL to signal application | ||
| code. Often these notifications are used to signal cache invalidation. In 9.0 | ||
| and greater, notifications may include a "payload" in which arbitrary data may | ||
| be delivered on a channel being listened to. | ||
| By default, received notifications will merely be appended to an internal | ||
| list on the connection object. This list will remain empty for the duration | ||
| of a connection *unless* the connection begins listening to a channel that | ||
| receives notifications. | ||
| The `postgresql.notifyman.NotificationManager` class is used to wait for | ||
| messages to come in on a set of connections, pick up the messages, and deliver | ||
| the messages to the object's user via the `collections.Iterator` protocol. | ||
| Listening on a Single Connection | ||
| ================================ | ||
| The ``db.iternotifies()`` method is a simplification of the notification manager. It | ||
| returns an iterator to the notifications received on the subject connection. | ||
| The iterator yields triples consisting of the ``channel`` being | ||
| notified, the ``payload`` sent with the notification, and the ``pid`` of the | ||
| backend that caused the notification:: | ||
| >>> db.listen('for_rabbits') | ||
| >>> db.notify('for_rabbits') | ||
| >>> for x in db.iternotifies(): | ||
| ... channel, payload, pid = x | ||
| ... break | ||
| >>> assert channel == 'for_rabbits' | ||
| True | ||
| >>> assert payload == '' | ||
| True | ||
| >>> assert pid == db.backend_id | ||
| True | ||
| The iterator, by default, will continue listening forever unless the connection | ||
| is terminated--thus the immediate ``break`` statement in the above loop. In | ||
| cases where some additional activity is necessary, a timeout parameter may be | ||
| given to the ``iternotifies`` method in order to allow "idle" events to occur | ||
| at the designated frequency:: | ||
| >>> for x in db.iternotifies(0.5): | ||
| ... if x is None: | ||
| ... break | ||
| The above example illustrates that idle events are represented using `None` | ||
| objects. Idle events are guaranteed to occur *approximately* at the | ||
| specified interval--the ``timeout`` keyword parameter. In addition to | ||
| providing a means to do other processing or polling, they also offer a safe | ||
| break point for the loop. Internally, the iterator produced by the | ||
| ``iternotifies`` method *is* a `NotificationManager`, which will localize the | ||
| notifications prior to emitting them via the iterator. | ||
| *It's not safe to break out of the loop, unless an idle event is being handled.* | ||
| If the loop is broken while a regular event is being processed, some events may | ||
| remain in the iterator. In order to consume those events, the iterator *must* | ||
| be accessible. | ||
| The iterator will be exhausted when the connection is closed, but if the | ||
| connection is closed during the loop, any remaining notifications *will* | ||
| be emitted prior to the loop ending, so it is important to be prepared to | ||
| handle exceptions or check for a closed connection. | ||
| In situations where multiple connections need to be watched, direct use of the | ||
| `NotificationManager` is necessary. | ||
| Listening on Multiple Connections | ||
| ================================= | ||
| The `postgresql.notifyman.NotificationManager` class is used to manage | ||
| *connections* that are expecting to receive notifications. Instances are | ||
| iterators that yield the connection object and notifications received on the | ||
| connection or `None` in the case of an idle event. The manager emits events as | ||
| a pair; the connection object that received notifications, and *all* the | ||
| notifications picked up on that connection:: | ||
| >>> from postgresql.notifyman import NotificationManager | ||
| >>> # Using ``nm`` to reference the manager from here on. | ||
| >>> nm = NotificationManager(db1, db2, ..., dbN) | ||
| >>> nm.settimeout(2) | ||
| >>> for x in nm: | ||
| ... if x is None: | ||
| ... # idle | ||
| ... break | ||
| ... | ||
| ... db, notifies = x | ||
| ... for channel, payload, pid in notifies: | ||
| ... ... | ||
| The manager will continue to wait for and emit events so long as there are | ||
| good connections available in the set; it is possible for connections to be | ||
| added and removed at any time. Although, in rare circumstances, discarded | ||
| connections may still have pending events if it not removed during an idle | ||
| event. The ``connections`` attribute on `NotificationManager` objects is a | ||
| set object that may be used directly in order to add and remove connections | ||
| from the manager:: | ||
| >>> y = [] | ||
| >>> for x in nm: | ||
| ... if x is None: | ||
| ... if y: | ||
| ... nm.connections.add(y[0]) | ||
| ... del y[0] | ||
| ... | ||
| The notification manager is resilient; if a connection dies, it will discard the | ||
| connection from the set, and add it to the set of bad connections, the | ||
| ``garbage`` attribute. In these cases, the idle event *should* be leveraged to | ||
| check for these failures if that's a concern. It is the user's | ||
| responsibility to explicitly handle the failure cases, and remove the bad | ||
| connections from the ``garbage`` set:: | ||
| >>> for x in nm: | ||
| ... if x is None: | ||
| ... if nm.garbage: | ||
| ... recovered = take_out_trash(nm.garbage) | ||
| ... nm.connections.update(recovered) | ||
| ... nm.garbage.clear() | ||
| ... db, notifies = x | ||
| ... for channel, payload, pid in notifies: | ||
| ... ... | ||
| Explicitly removing connections from the set can also be a means to gracefully | ||
| terminate the event loop:: | ||
| >>> for x in nm: | ||
| ... if x in None: | ||
| ... if done_listening is True: | ||
| ... nm.connections.clear() | ||
| However, doing so inside the loop is not a requirement; it is safe to remove a | ||
| connection from the set at any point. | ||
| Notification Managers | ||
| ===================== | ||
| The `postgresql.notifyman.NotificationManager` is an event loop that services | ||
| multiple connections. In cases where only one connection needs to be serviced, | ||
| the `postgresql.api.Database.iternotifies` method can be used to simplify the | ||
| process. | ||
| Notification Manager Constructors | ||
| --------------------------------- | ||
| ``NotificationManager(*connections, timeout = None)`` | ||
| Create a NotificationManager instance that manages the notifications coming | ||
| from the given set of connections. The ``timeout`` keyword is optional and | ||
| can be configured using the ``settimeout`` method as well. | ||
| Notification Manager Interface Points | ||
| ------------------------------------- | ||
| ``NotificationManager.__iter__()`` | ||
| Returns the instance; it is an iterator. | ||
| ``NotificationManager.__next__()`` | ||
| Normally, yield the pair, connection and notifications list, when the next | ||
| event is received. If a timeout is configured, `None` may be yielded to signal | ||
| an idle event. The notifications list is a list of triples: | ||
| ``(channel, payload, pid)``. | ||
| ``NotificationManager.settimeout(timeout : int)`` | ||
| Set the amount of time to wait before the manager yields an idle event. | ||
| If zero, the manager will never wait and only yield notifications that are | ||
| immediately available. | ||
| If `None`, the manager will never emit idle events. | ||
| ``NotificationManager.gettimeout() -> [int, None]`` | ||
| Get the configured timeout; returns either `None`, or an `int`. | ||
| ``NotificationManager.connections`` | ||
| The set of connections that the manager is actively watching for | ||
| notifications. Connections may be added or removed from the set at any time. | ||
| ``NotificationManager.garbage`` | ||
| The set of connections that failed. Normally empty, but when a connection gets | ||
| an exceptional condition or explicitly raises an exception, it is removed from | ||
| the ``connections`` set, and placed in ``garbage``. | ||
| Zero Timeout | ||
| ------------ | ||
| When a timeout of zero, ``0``, is configured, the notification manager will | ||
| terminate early. Specifically, each connection will be polled for any pending | ||
| notifications, and once all of the collected notifications have been emitted | ||
| by the iterator, `StopIteration` will be raised. Notably, *no* idle events will | ||
| occur when the timeout is configured to zero. | ||
| Zero timeouts offer a means for the notification "queue" to be polled. Often, | ||
| this is the appropriate way to collect pending notifications on active | ||
| connections where using the connection exclusively for waiting is not | ||
| practical:: | ||
| >>> notifies = list(db.iternotifies(0)) | ||
| Or with a NotificationManager instance:: | ||
| >>> nm.settimeout(0) | ||
| >>> db_notifies = list(nm) | ||
| In both cases of zero timeout, the iterator may be promptly discarded without | ||
| losing any events. | ||
| Summary of Characteristics | ||
| -------------------------- | ||
| * The iterator will continue until the connections die. | ||
| * Objects yielded by the iterator are either `None`, an "idle event", or an | ||
| individual notification triple if using ``db.iternotifies()``, or a | ||
| ``(db, notifies)`` pair if using the base `NotificationManager`. | ||
| * When a connection dies or raises an exception, it will be removed from | ||
| the ``nm.connections`` set and added to the ``nm.garbage`` set. | ||
| * The NotificationManager instance will *not* hold any notifications | ||
| during an idle event. Idle events offer a break point in which the manager | ||
| may be discarded. | ||
| * A timeout of zero will cause the iterator to only yield the events | ||
| that are pending right now, and promptly end. However, the same manager | ||
| object may be used again. | ||
| * A notification triple is a tuple consisting of ``(channel, payload, pid)``. | ||
| * Connections may be added and removed from the ``nm.connections`` set at | ||
| any time. |
| Reference | ||
| ========= | ||
| :mod:`postgresql` | ||
| ----------------- | ||
| .. automodule:: postgresql | ||
| .. autodata:: version | ||
| .. autodata:: version_info | ||
| .. autofunction:: open | ||
| :mod:`postgresql.api` | ||
| --------------------- | ||
| .. automodule:: | ||
| postgresql.api | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.sys` | ||
| --------------------- | ||
| .. automodule:: | ||
| postgresql.sys | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.string` | ||
| ------------------------ | ||
| .. automodule:: | ||
| postgresql.string | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.exceptions` | ||
| ---------------------------- | ||
| .. automodule:: | ||
| postgresql.exceptions | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.temporal` | ||
| -------------------------- | ||
| .. automodule:: | ||
| postgresql.temporal | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.installation` | ||
| ------------------------------ | ||
| .. automodule:: | ||
| postgresql.installation | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.cluster` | ||
| ------------------------- | ||
| .. automodule:: | ||
| postgresql.cluster | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.copyman` | ||
| ------------------------- | ||
| .. automodule:: | ||
| postgresql.copyman | ||
| :members: | ||
| :show-inheritance: | ||
| :mod:`postgresql.alock` | ||
| ----------------------- | ||
| .. automodule:: | ||
| postgresql.alock | ||
| :members: | ||
| :show-inheritance: |
Sorry, the diff of this file is not supported yet
| /* | ||
| * basic.css | ||
| * ~~~~~~~~~ | ||
| * | ||
| * Sphinx stylesheet -- basic theme. | ||
| * | ||
| * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. | ||
| * :license: BSD, see LICENSE for details. | ||
| * | ||
| */ | ||
| /* -- main layout ----------------------------------------------------------- */ | ||
| div.clearer { | ||
| clear: both; | ||
| } | ||
| /* -- relbar ---------------------------------------------------------------- */ | ||
| div.related { | ||
| width: 100%; | ||
| font-size: 90%; | ||
| } | ||
| div.related h3 { | ||
| display: none; | ||
| } | ||
| div.related ul { | ||
| margin: 0; | ||
| padding: 0 0 0 10px; | ||
| list-style: none; | ||
| } | ||
| div.related li { | ||
| display: inline; | ||
| } | ||
| div.related li.right { | ||
| float: right; | ||
| margin-right: 5px; | ||
| } | ||
| /* -- sidebar --------------------------------------------------------------- */ | ||
| div.sphinxsidebarwrapper { | ||
| padding: 10px 5px 0 10px; | ||
| } | ||
| div.sphinxsidebar { | ||
| float: left; | ||
| width: 230px; | ||
| margin-left: -100%; | ||
| font-size: 90%; | ||
| } | ||
| div.sphinxsidebar ul { | ||
| list-style: none; | ||
| } | ||
| div.sphinxsidebar ul ul, | ||
| div.sphinxsidebar ul.want-points { | ||
| margin-left: 20px; | ||
| list-style: square; | ||
| } | ||
| div.sphinxsidebar ul ul { | ||
| margin-top: 0; | ||
| margin-bottom: 0; | ||
| } | ||
| div.sphinxsidebar form { | ||
| margin-top: 10px; | ||
| } | ||
| div.sphinxsidebar input { | ||
| border: 1px solid #98dbcc; | ||
| font-family: sans-serif; | ||
| font-size: 1em; | ||
| } | ||
| div.sphinxsidebar #searchbox input[type="text"] { | ||
| width: 170px; | ||
| } | ||
| div.sphinxsidebar #searchbox input[type="submit"] { | ||
| width: 30px; | ||
| } | ||
| img { | ||
| border: 0; | ||
| } | ||
| /* -- search page ----------------------------------------------------------- */ | ||
| ul.search { | ||
| margin: 10px 0 0 20px; | ||
| padding: 0; | ||
| } | ||
| ul.search li { | ||
| padding: 5px 0 5px 20px; | ||
| background-image: url(file.png); | ||
| background-repeat: no-repeat; | ||
| background-position: 0 7px; | ||
| } | ||
| ul.search li a { | ||
| font-weight: bold; | ||
| } | ||
| ul.search li div.context { | ||
| color: #888; | ||
| margin: 2px 0 0 30px; | ||
| text-align: left; | ||
| } | ||
| ul.keywordmatches li.goodmatch a { | ||
| font-weight: bold; | ||
| } | ||
| /* -- index page ------------------------------------------------------------ */ | ||
| table.contentstable { | ||
| width: 90%; | ||
| } | ||
| table.contentstable p.biglink { | ||
| line-height: 150%; | ||
| } | ||
| a.biglink { | ||
| font-size: 1.3em; | ||
| } | ||
| span.linkdescr { | ||
| font-style: italic; | ||
| padding-top: 5px; | ||
| font-size: 90%; | ||
| } | ||
| /* -- general index --------------------------------------------------------- */ | ||
| table.indextable { | ||
| width: 100%; | ||
| } | ||
| table.indextable td { | ||
| text-align: left; | ||
| vertical-align: top; | ||
| } | ||
| table.indextable dl, table.indextable dd { | ||
| margin-top: 0; | ||
| margin-bottom: 0; | ||
| } | ||
| table.indextable tr.pcap { | ||
| height: 10px; | ||
| } | ||
| table.indextable tr.cap { | ||
| margin-top: 10px; | ||
| background-color: #f2f2f2; | ||
| } | ||
| img.toggler { | ||
| margin-right: 3px; | ||
| margin-top: 3px; | ||
| cursor: pointer; | ||
| } | ||
| div.modindex-jumpbox { | ||
| border-top: 1px solid #ddd; | ||
| border-bottom: 1px solid #ddd; | ||
| margin: 1em 0 1em 0; | ||
| padding: 0.4em; | ||
| } | ||
| div.genindex-jumpbox { | ||
| border-top: 1px solid #ddd; | ||
| border-bottom: 1px solid #ddd; | ||
| margin: 1em 0 1em 0; | ||
| padding: 0.4em; | ||
| } | ||
| /* -- general body styles --------------------------------------------------- */ | ||
| a.headerlink { | ||
| visibility: hidden; | ||
| } | ||
| h1:hover > a.headerlink, | ||
| h2:hover > a.headerlink, | ||
| h3:hover > a.headerlink, | ||
| h4:hover > a.headerlink, | ||
| h5:hover > a.headerlink, | ||
| h6:hover > a.headerlink, | ||
| dt:hover > a.headerlink { | ||
| visibility: visible; | ||
| } | ||
| div.body p.caption { | ||
| text-align: inherit; | ||
| } | ||
| div.body td { | ||
| text-align: left; | ||
| } | ||
| .field-list ul { | ||
| padding-left: 1em; | ||
| } | ||
| .first { | ||
| margin-top: 0 !important; | ||
| } | ||
| p.rubric { | ||
| margin-top: 30px; | ||
| font-weight: bold; | ||
| } | ||
| img.align-left, .figure.align-left, object.align-left { | ||
| clear: left; | ||
| float: left; | ||
| margin-right: 1em; | ||
| } | ||
| img.align-right, .figure.align-right, object.align-right { | ||
| clear: right; | ||
| float: right; | ||
| margin-left: 1em; | ||
| } | ||
| img.align-center, .figure.align-center, object.align-center { | ||
| display: block; | ||
| margin-left: auto; | ||
| margin-right: auto; | ||
| } | ||
| .align-left { | ||
| text-align: left; | ||
| } | ||
| .align-center { | ||
| text-align: center; | ||
| } | ||
| .align-right { | ||
| text-align: right; | ||
| } | ||
| /* -- sidebars -------------------------------------------------------------- */ | ||
| div.sidebar { | ||
| margin: 0 0 0.5em 1em; | ||
| border: 1px solid #ddb; | ||
| padding: 7px 7px 0 7px; | ||
| background-color: #ffe; | ||
| width: 40%; | ||
| float: right; | ||
| } | ||
| p.sidebar-title { | ||
| font-weight: bold; | ||
| } | ||
| /* -- topics ---------------------------------------------------------------- */ | ||
| div.topic { | ||
| border: 1px solid #ccc; | ||
| padding: 7px 7px 0 7px; | ||
| margin: 10px 0 10px 0; | ||
| } | ||
| p.topic-title { | ||
| font-size: 1.1em; | ||
| font-weight: bold; | ||
| margin-top: 10px; | ||
| } | ||
| /* -- admonitions ----------------------------------------------------------- */ | ||
| div.admonition { | ||
| margin-top: 10px; | ||
| margin-bottom: 10px; | ||
| padding: 7px; | ||
| } | ||
| div.admonition dt { | ||
| font-weight: bold; | ||
| } | ||
| div.admonition dl { | ||
| margin-bottom: 0; | ||
| } | ||
| p.admonition-title { | ||
| margin: 0px 10px 5px 0px; | ||
| font-weight: bold; | ||
| } | ||
| div.body p.centered { | ||
| text-align: center; | ||
| margin-top: 25px; | ||
| } | ||
| /* -- tables ---------------------------------------------------------------- */ | ||
| table.docutils { | ||
| border: 0; | ||
| border-collapse: collapse; | ||
| } | ||
| table.docutils td, table.docutils th { | ||
| padding: 1px 8px 1px 5px; | ||
| border-top: 0; | ||
| border-left: 0; | ||
| border-right: 0; | ||
| border-bottom: 1px solid #aaa; | ||
| } | ||
| table.field-list td, table.field-list th { | ||
| border: 0 !important; | ||
| } | ||
| table.footnote td, table.footnote th { | ||
| border: 0 !important; | ||
| } | ||
| th { | ||
| text-align: left; | ||
| padding-right: 5px; | ||
| } | ||
| table.citation { | ||
| border-left: solid 1px gray; | ||
| margin-left: 1px; | ||
| } | ||
| table.citation td { | ||
| border-bottom: none; | ||
| } | ||
| /* -- other body styles ----------------------------------------------------- */ | ||
| ol.arabic { | ||
| list-style: decimal; | ||
| } | ||
| ol.loweralpha { | ||
| list-style: lower-alpha; | ||
| } | ||
| ol.upperalpha { | ||
| list-style: upper-alpha; | ||
| } | ||
| ol.lowerroman { | ||
| list-style: lower-roman; | ||
| } | ||
| ol.upperroman { | ||
| list-style: upper-roman; | ||
| } | ||
| dl { | ||
| margin-bottom: 15px; | ||
| } | ||
| dd p { | ||
| margin-top: 0px; | ||
| } | ||
| dd ul, dd table { | ||
| margin-bottom: 10px; | ||
| } | ||
| dd { | ||
| margin-top: 3px; | ||
| margin-bottom: 10px; | ||
| margin-left: 30px; | ||
| } | ||
| dt:target, .highlighted { | ||
| background-color: #fbe54e; | ||
| } | ||
| dl.glossary dt { | ||
| font-weight: bold; | ||
| font-size: 1.1em; | ||
| } | ||
| .field-list ul { | ||
| margin: 0; | ||
| padding-left: 1em; | ||
| } | ||
| .field-list p { | ||
| margin: 0; | ||
| } | ||
| .refcount { | ||
| color: #060; | ||
| } | ||
| .optional { | ||
| font-size: 1.3em; | ||
| } | ||
| .versionmodified { | ||
| font-style: italic; | ||
| } | ||
| .system-message { | ||
| background-color: #fda; | ||
| padding: 5px; | ||
| border: 3px solid red; | ||
| } | ||
| .footnote:target { | ||
| background-color: #ffa; | ||
| } | ||
| .line-block { | ||
| display: block; | ||
| margin-top: 1em; | ||
| margin-bottom: 1em; | ||
| } | ||
| .line-block .line-block { | ||
| margin-top: 0; | ||
| margin-bottom: 0; | ||
| margin-left: 1.5em; | ||
| } | ||
| .guilabel, .menuselection { | ||
| font-family: sans-serif; | ||
| } | ||
| .accelerator { | ||
| text-decoration: underline; | ||
| } | ||
| .classifier { | ||
| font-style: oblique; | ||
| } | ||
| abbr, acronym { | ||
| border-bottom: dotted 1px; | ||
| cursor: help; | ||
| } | ||
| /* -- code displays --------------------------------------------------------- */ | ||
| pre { | ||
| overflow: auto; | ||
| overflow-y: hidden; /* fixes display issues on Chrome browsers */ | ||
| } | ||
| td.linenos pre { | ||
| padding: 5px 0px; | ||
| border: 0; | ||
| background-color: transparent; | ||
| color: #aaa; | ||
| } | ||
| table.highlighttable { | ||
| margin-left: 0.5em; | ||
| } | ||
| table.highlighttable td { | ||
| padding: 0 0.5em 0 0.5em; | ||
| } | ||
| tt.descname { | ||
| background-color: transparent; | ||
| font-weight: bold; | ||
| font-size: 1.2em; | ||
| } | ||
| tt.descclassname { | ||
| background-color: transparent; | ||
| } | ||
| tt.xref, a tt { | ||
| background-color: transparent; | ||
| font-weight: bold; | ||
| } | ||
| h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { | ||
| background-color: transparent; | ||
| } | ||
| .viewcode-link { | ||
| float: right; | ||
| } | ||
| .viewcode-back { | ||
| float: right; | ||
| font-family: sans-serif; | ||
| } | ||
| div.viewcode-block:target { | ||
| margin: -1px -10px; | ||
| padding: 0 10px; | ||
| } | ||
| /* -- math display ---------------------------------------------------------- */ | ||
| img.math { | ||
| vertical-align: middle; | ||
| } | ||
| div.body div.math p { | ||
| text-align: center; | ||
| } | ||
| span.eqno { | ||
| float: right; | ||
| } | ||
| /* -- printout stylesheet --------------------------------------------------- */ | ||
| @media print { | ||
| div.document, | ||
| div.documentwrapper, | ||
| div.bodywrapper { | ||
| margin: 0 !important; | ||
| width: 100%; | ||
| } | ||
| div.sphinxsidebar, | ||
| div.related, | ||
| div.footer, | ||
| #top-link { | ||
| display: none; | ||
| } | ||
| } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| /* | ||
| * default.css_t | ||
| * ~~~~~~~~~~~~~ | ||
| * | ||
| * Sphinx stylesheet -- default theme. | ||
| * | ||
| * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. | ||
| * :license: BSD, see LICENSE for details. | ||
| * | ||
| */ | ||
| @import url("basic.css"); | ||
| /* -- page layout ----------------------------------------------------------- */ | ||
| body { | ||
| font-family: sans-serif; | ||
| font-size: 100%; | ||
| background-color: #11303d; | ||
| color: #000; | ||
| margin: 0; | ||
| padding: 0; | ||
| } | ||
| div.document { | ||
| background-color: #1c4e63; | ||
| } | ||
| div.documentwrapper { | ||
| float: left; | ||
| width: 100%; | ||
| } | ||
| div.bodywrapper { | ||
| margin: 0 0 0 230px; | ||
| } | ||
| div.body { | ||
| background-color: #ffffff; | ||
| color: #000000; | ||
| padding: 0 20px 30px 20px; | ||
| } | ||
| div.footer { | ||
| color: #ffffff; | ||
| width: 100%; | ||
| padding: 9px 0 9px 0; | ||
| text-align: center; | ||
| font-size: 75%; | ||
| } | ||
| div.footer a { | ||
| color: #ffffff; | ||
| text-decoration: underline; | ||
| } | ||
| div.related { | ||
| background-color: #133f52; | ||
| line-height: 30px; | ||
| color: #ffffff; | ||
| } | ||
| div.related a { | ||
| color: #ffffff; | ||
| } | ||
| div.sphinxsidebar { | ||
| } | ||
| div.sphinxsidebar h3 { | ||
| font-family: 'Trebuchet MS', sans-serif; | ||
| color: #ffffff; | ||
| font-size: 1.4em; | ||
| font-weight: normal; | ||
| margin: 0; | ||
| padding: 0; | ||
| } | ||
| div.sphinxsidebar h3 a { | ||
| color: #ffffff; | ||
| } | ||
| div.sphinxsidebar h4 { | ||
| font-family: 'Trebuchet MS', sans-serif; | ||
| color: #ffffff; | ||
| font-size: 1.3em; | ||
| font-weight: normal; | ||
| margin: 5px 0 0 0; | ||
| padding: 0; | ||
| } | ||
| div.sphinxsidebar p { | ||
| color: #ffffff; | ||
| } | ||
| div.sphinxsidebar p.topless { | ||
| margin: 5px 10px 10px 10px; | ||
| } | ||
| div.sphinxsidebar ul { | ||
| margin: 10px; | ||
| padding: 0; | ||
| color: #ffffff; | ||
| } | ||
| div.sphinxsidebar a { | ||
| color: #98dbcc; | ||
| } | ||
| div.sphinxsidebar input { | ||
| border: 1px solid #98dbcc; | ||
| font-family: sans-serif; | ||
| font-size: 1em; | ||
| } | ||
| /* -- hyperlink styles ------------------------------------------------------ */ | ||
| a { | ||
| color: #355f7c; | ||
| text-decoration: none; | ||
| } | ||
| a:visited { | ||
| color: #355f7c; | ||
| text-decoration: none; | ||
| } | ||
| a:hover { | ||
| text-decoration: underline; | ||
| } | ||
| /* -- body styles ----------------------------------------------------------- */ | ||
| div.body h1, | ||
| div.body h2, | ||
| div.body h3, | ||
| div.body h4, | ||
| div.body h5, | ||
| div.body h6 { | ||
| font-family: 'Trebuchet MS', sans-serif; | ||
| background-color: #f2f2f2; | ||
| font-weight: normal; | ||
| color: #20435c; | ||
| border-bottom: 1px solid #ccc; | ||
| margin: 20px -20px 10px -20px; | ||
| padding: 3px 0 3px 10px; | ||
| } | ||
| div.body h1 { margin-top: 0; font-size: 200%; } | ||
| div.body h2 { font-size: 160%; } | ||
| div.body h3 { font-size: 140%; } | ||
| div.body h4 { font-size: 120%; } | ||
| div.body h5 { font-size: 110%; } | ||
| div.body h6 { font-size: 100%; } | ||
| a.headerlink { | ||
| color: #c60f0f; | ||
| font-size: 0.8em; | ||
| padding: 0 4px 0 4px; | ||
| text-decoration: none; | ||
| } | ||
| a.headerlink:hover { | ||
| background-color: #c60f0f; | ||
| color: white; | ||
| } | ||
| div.body p, div.body dd, div.body li { | ||
| text-align: justify; | ||
| line-height: 130%; | ||
| } | ||
| div.admonition p.admonition-title + p { | ||
| display: inline; | ||
| } | ||
| div.admonition p { | ||
| margin-bottom: 5px; | ||
| } | ||
| div.admonition pre { | ||
| margin-bottom: 5px; | ||
| } | ||
| div.admonition ul, div.admonition ol { | ||
| margin-bottom: 5px; | ||
| } | ||
| div.note { | ||
| background-color: #eee; | ||
| border: 1px solid #ccc; | ||
| } | ||
| div.seealso { | ||
| background-color: #ffc; | ||
| border: 1px solid #ff6; | ||
| } | ||
| div.topic { | ||
| background-color: #eee; | ||
| } | ||
| div.warning { | ||
| background-color: #ffe4e4; | ||
| border: 1px solid #f66; | ||
| } | ||
| p.admonition-title { | ||
| display: inline; | ||
| } | ||
| p.admonition-title:after { | ||
| content: ":"; | ||
| } | ||
| pre { | ||
| padding: 5px; | ||
| background-color: #eeffcc; | ||
| color: #333333; | ||
| line-height: 120%; | ||
| border: 1px solid #ac9; | ||
| border-left: none; | ||
| border-right: none; | ||
| } | ||
| tt { | ||
| background-color: #ecf0f3; | ||
| padding: 0 1px 0 1px; | ||
| font-size: 0.95em; | ||
| } | ||
| th { | ||
| background-color: #ede; | ||
| } | ||
| .warning tt { | ||
| background: #efc2c2; | ||
| } | ||
| .note tt { | ||
| background: #d6d6d6; | ||
| } | ||
| .viewcode-back { | ||
| font-family: sans-serif; | ||
| } | ||
| div.viewcode-block:target { | ||
| background-color: #f4debf; | ||
| border-top: 1px solid #ac9; | ||
| border-bottom: 1px solid #ac9; | ||
| } |
| /* | ||
| * doctools.js | ||
| * ~~~~~~~~~~~ | ||
| * | ||
| * Sphinx JavaScript utilities for all documentation. | ||
| * | ||
| * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. | ||
| * :license: BSD, see LICENSE for details. | ||
| * | ||
| */ | ||
| /** | ||
| * select a different prefix for underscore | ||
| */ | ||
| $u = _.noConflict(); | ||
| /** | ||
| * make the code below compatible with browsers without | ||
| * an installed firebug like debugger | ||
| if (!window.console || !console.firebug) { | ||
| var names = ["log", "debug", "info", "warn", "error", "assert", "dir", | ||
| "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", | ||
| "profile", "profileEnd"]; | ||
| window.console = {}; | ||
| for (var i = 0; i < names.length; ++i) | ||
| window.console[names[i]] = function() {}; | ||
| } | ||
| */ | ||
| /** | ||
| * small helper function to urldecode strings | ||
| */ | ||
| jQuery.urldecode = function(x) { | ||
| return decodeURIComponent(x).replace(/\+/g, ' '); | ||
| } | ||
| /** | ||
| * small helper function to urlencode strings | ||
| */ | ||
| jQuery.urlencode = encodeURIComponent; | ||
| /** | ||
| * This function returns the parsed url parameters of the | ||
| * current request. Multiple values per key are supported, | ||
| * it will always return arrays of strings for the value parts. | ||
| */ | ||
| jQuery.getQueryParameters = function(s) { | ||
| if (typeof s == 'undefined') | ||
| s = document.location.search; | ||
| var parts = s.substr(s.indexOf('?') + 1).split('&'); | ||
| var result = {}; | ||
| for (var i = 0; i < parts.length; i++) { | ||
| var tmp = parts[i].split('=', 2); | ||
| var key = jQuery.urldecode(tmp[0]); | ||
| var value = jQuery.urldecode(tmp[1]); | ||
| if (key in result) | ||
| result[key].push(value); | ||
| else | ||
| result[key] = [value]; | ||
| } | ||
| return result; | ||
| }; | ||
| /** | ||
| * small function to check if an array contains | ||
| * a given item. | ||
| */ | ||
| jQuery.contains = function(arr, item) { | ||
| for (var i = 0; i < arr.length; i++) { | ||
| if (arr[i] == item) | ||
| return true; | ||
| } | ||
| return false; | ||
| }; | ||
| /** | ||
| * highlight a given string on a jquery object by wrapping it in | ||
| * span elements with the given class name. | ||
| */ | ||
| jQuery.fn.highlightText = function(text, className) { | ||
| function highlight(node) { | ||
| if (node.nodeType == 3) { | ||
| var val = node.nodeValue; | ||
| var pos = val.toLowerCase().indexOf(text); | ||
| if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { | ||
| var span = document.createElement("span"); | ||
| span.className = className; | ||
| span.appendChild(document.createTextNode(val.substr(pos, text.length))); | ||
| node.parentNode.insertBefore(span, node.parentNode.insertBefore( | ||
| document.createTextNode(val.substr(pos + text.length)), | ||
| node.nextSibling)); | ||
| node.nodeValue = val.substr(0, pos); | ||
| } | ||
| } | ||
| else if (!jQuery(node).is("button, select, textarea")) { | ||
| jQuery.each(node.childNodes, function() { | ||
| highlight(this); | ||
| }); | ||
| } | ||
| } | ||
| return this.each(function() { | ||
| highlight(this); | ||
| }); | ||
| }; | ||
| /** | ||
| * Small JavaScript module for the documentation. | ||
| */ | ||
| var Documentation = { | ||
| init : function() { | ||
| this.fixFirefoxAnchorBug(); | ||
| this.highlightSearchWords(); | ||
| this.initIndexTable(); | ||
| }, | ||
| /** | ||
| * i18n support | ||
| */ | ||
| TRANSLATIONS : {}, | ||
| PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, | ||
| LOCALE : 'unknown', | ||
| // gettext and ngettext don't access this so that the functions | ||
| // can safely bound to a different name (_ = Documentation.gettext) | ||
| gettext : function(string) { | ||
| var translated = Documentation.TRANSLATIONS[string]; | ||
| if (typeof translated == 'undefined') | ||
| return string; | ||
| return (typeof translated == 'string') ? translated : translated[0]; | ||
| }, | ||
| ngettext : function(singular, plural, n) { | ||
| var translated = Documentation.TRANSLATIONS[singular]; | ||
| if (typeof translated == 'undefined') | ||
| return (n == 1) ? singular : plural; | ||
| return translated[Documentation.PLURALEXPR(n)]; | ||
| }, | ||
| addTranslations : function(catalog) { | ||
| for (var key in catalog.messages) | ||
| this.TRANSLATIONS[key] = catalog.messages[key]; | ||
| this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); | ||
| this.LOCALE = catalog.locale; | ||
| }, | ||
| /** | ||
| * add context elements like header anchor links | ||
| */ | ||
| addContextElements : function() { | ||
| $('div[id] > :header:first').each(function() { | ||
| $('<a class="headerlink">\u00B6</a>'). | ||
| attr('href', '#' + this.id). | ||
| attr('title', _('Permalink to this headline')). | ||
| appendTo(this); | ||
| }); | ||
| $('dt[id]').each(function() { | ||
| $('<a class="headerlink">\u00B6</a>'). | ||
| attr('href', '#' + this.id). | ||
| attr('title', _('Permalink to this definition')). | ||
| appendTo(this); | ||
| }); | ||
| }, | ||
| /** | ||
| * workaround a firefox stupidity | ||
| */ | ||
| fixFirefoxAnchorBug : function() { | ||
| if (document.location.hash && $.browser.mozilla) | ||
| window.setTimeout(function() { | ||
| document.location.href += ''; | ||
| }, 10); | ||
| }, | ||
| /** | ||
| * highlight the search words provided in the url in the text | ||
| */ | ||
| highlightSearchWords : function() { | ||
| var params = $.getQueryParameters(); | ||
| var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; | ||
| if (terms.length) { | ||
| var body = $('div.body'); | ||
| window.setTimeout(function() { | ||
| $.each(terms, function() { | ||
| body.highlightText(this.toLowerCase(), 'highlighted'); | ||
| }); | ||
| }, 10); | ||
| $('<p class="highlight-link"><a href="javascript:Documentation.' + | ||
| 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>') | ||
| .appendTo($('#searchbox')); | ||
| } | ||
| }, | ||
| /** | ||
| * init the domain index toggle buttons | ||
| */ | ||
| initIndexTable : function() { | ||
| var togglers = $('img.toggler').click(function() { | ||
| var src = $(this).attr('src'); | ||
| var idnum = $(this).attr('id').substr(7); | ||
| $('tr.cg-' + idnum).toggle(); | ||
| if (src.substr(-9) == 'minus.png') | ||
| $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); | ||
| else | ||
| $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); | ||
| }).css('display', ''); | ||
| if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { | ||
| togglers.click(); | ||
| } | ||
| }, | ||
| /** | ||
| * helper function to hide the search marks again | ||
| */ | ||
| hideSearchWords : function() { | ||
| $('#searchbox .highlight-link').fadeOut(300); | ||
| $('span.highlighted').removeClass('highlighted'); | ||
| }, | ||
| /** | ||
| * make the url absolute | ||
| */ | ||
| makeURL : function(relativeURL) { | ||
| return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; | ||
| }, | ||
| /** | ||
| * get the current relative url | ||
| */ | ||
| getCurrentURL : function() { | ||
| var path = document.location.pathname; | ||
| var parts = path.split(/\//); | ||
| $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { | ||
| if (this == '..') | ||
| parts.pop(); | ||
| }); | ||
| var url = parts.join('/'); | ||
| return path.substring(url.lastIndexOf('/') + 1, path.length - 1); | ||
| } | ||
| }; | ||
| // quick alias for translations | ||
| _ = Documentation.gettext; | ||
| $(document).ready(function() { | ||
| Documentation.init(); | ||
| }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| .highlight .hll { background-color: #ffffcc } | ||
| .highlight { background: #eeffcc; } | ||
| .highlight .c { color: #408090; font-style: italic } /* Comment */ | ||
| .highlight .err { border: 1px solid #FF0000 } /* Error */ | ||
| .highlight .k { color: #007020; font-weight: bold } /* Keyword */ | ||
| .highlight .o { color: #666666 } /* Operator */ | ||
| .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ | ||
| .highlight .cp { color: #007020 } /* Comment.Preproc */ | ||
| .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ | ||
| .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ | ||
| .highlight .gd { color: #A00000 } /* Generic.Deleted */ | ||
| .highlight .ge { font-style: italic } /* Generic.Emph */ | ||
| .highlight .gr { color: #FF0000 } /* Generic.Error */ | ||
| .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ | ||
| .highlight .gi { color: #00A000 } /* Generic.Inserted */ | ||
| .highlight .go { color: #303030 } /* Generic.Output */ | ||
| .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ | ||
| .highlight .gs { font-weight: bold } /* Generic.Strong */ | ||
| .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ | ||
| .highlight .gt { color: #0040D0 } /* Generic.Traceback */ | ||
| .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ | ||
| .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ | ||
| .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ | ||
| .highlight .kp { color: #007020 } /* Keyword.Pseudo */ | ||
| .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ | ||
| .highlight .kt { color: #902000 } /* Keyword.Type */ | ||
| .highlight .m { color: #208050 } /* Literal.Number */ | ||
| .highlight .s { color: #4070a0 } /* Literal.String */ | ||
| .highlight .na { color: #4070a0 } /* Name.Attribute */ | ||
| .highlight .nb { color: #007020 } /* Name.Builtin */ | ||
| .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ | ||
| .highlight .no { color: #60add5 } /* Name.Constant */ | ||
| .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ | ||
| .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ | ||
| .highlight .ne { color: #007020 } /* Name.Exception */ | ||
| .highlight .nf { color: #06287e } /* Name.Function */ | ||
| .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ | ||
| .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ | ||
| .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ | ||
| .highlight .nv { color: #bb60d5 } /* Name.Variable */ | ||
| .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ | ||
| .highlight .w { color: #bbbbbb } /* Text.Whitespace */ | ||
| .highlight .mf { color: #208050 } /* Literal.Number.Float */ | ||
| .highlight .mh { color: #208050 } /* Literal.Number.Hex */ | ||
| .highlight .mi { color: #208050 } /* Literal.Number.Integer */ | ||
| .highlight .mo { color: #208050 } /* Literal.Number.Oct */ | ||
| .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ | ||
| .highlight .sc { color: #4070a0 } /* Literal.String.Char */ | ||
| .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ | ||
| .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ | ||
| .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ | ||
| .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ | ||
| .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ | ||
| .highlight .sx { color: #c65d09 } /* Literal.String.Other */ | ||
| .highlight .sr { color: #235388 } /* Literal.String.Regex */ | ||
| .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ | ||
| .highlight .ss { color: #517918 } /* Literal.String.Symbol */ | ||
| .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ | ||
| .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ | ||
| .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ | ||
| .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ | ||
| .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ |
| /* | ||
| * searchtools.js_t | ||
| * ~~~~~~~~~~~~~~~~ | ||
| * | ||
| * Sphinx JavaScript utilties for the full-text search. | ||
| * | ||
| * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. | ||
| * :license: BSD, see LICENSE for details. | ||
| * | ||
| */ | ||
| /** | ||
| * helper function to return a node containing the | ||
| * search summary for a given text. keywords is a list | ||
| * of stemmed words, hlwords is the list of normal, unstemmed | ||
| * words. the first one is used to find the occurance, the | ||
| * latter for highlighting it. | ||
| */ | ||
| jQuery.makeSearchSummary = function(text, keywords, hlwords) { | ||
| var textLower = text.toLowerCase(); | ||
| var start = 0; | ||
| $.each(keywords, function() { | ||
| var i = textLower.indexOf(this.toLowerCase()); | ||
| if (i > -1) | ||
| start = i; | ||
| }); | ||
| start = Math.max(start - 120, 0); | ||
| var excerpt = ((start > 0) ? '...' : '') + | ||
| $.trim(text.substr(start, 240)) + | ||
| ((start + 240 - text.length) ? '...' : ''); | ||
| var rv = $('<div class="context"></div>').text(excerpt); | ||
| $.each(hlwords, function() { | ||
| rv = rv.highlightText(this, 'highlighted'); | ||
| }); | ||
| return rv; | ||
| } | ||
| /** | ||
| * Porter Stemmer | ||
| */ | ||
| var Stemmer = function() { | ||
| var step2list = { | ||
| ational: 'ate', | ||
| tional: 'tion', | ||
| enci: 'ence', | ||
| anci: 'ance', | ||
| izer: 'ize', | ||
| bli: 'ble', | ||
| alli: 'al', | ||
| entli: 'ent', | ||
| eli: 'e', | ||
| ousli: 'ous', | ||
| ization: 'ize', | ||
| ation: 'ate', | ||
| ator: 'ate', | ||
| alism: 'al', | ||
| iveness: 'ive', | ||
| fulness: 'ful', | ||
| ousness: 'ous', | ||
| aliti: 'al', | ||
| iviti: 'ive', | ||
| biliti: 'ble', | ||
| logi: 'log' | ||
| }; | ||
| var step3list = { | ||
| icate: 'ic', | ||
| ative: '', | ||
| alize: 'al', | ||
| iciti: 'ic', | ||
| ical: 'ic', | ||
| ful: '', | ||
| ness: '' | ||
| }; | ||
| var c = "[^aeiou]"; // consonant | ||
| var v = "[aeiouy]"; // vowel | ||
| var C = c + "[^aeiouy]*"; // consonant sequence | ||
| var V = v + "[aeiou]*"; // vowel sequence | ||
| var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 | ||
| var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 | ||
| var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 | ||
| var s_v = "^(" + C + ")?" + v; // vowel in stem | ||
| this.stemWord = function (w) { | ||
| var stem; | ||
| var suffix; | ||
| var firstch; | ||
| var origword = w; | ||
| if (w.length < 3) | ||
| return w; | ||
| var re; | ||
| var re2; | ||
| var re3; | ||
| var re4; | ||
| firstch = w.substr(0,1); | ||
| if (firstch == "y") | ||
| w = firstch.toUpperCase() + w.substr(1); | ||
| // Step 1a | ||
| re = /^(.+?)(ss|i)es$/; | ||
| re2 = /^(.+?)([^s])s$/; | ||
| if (re.test(w)) | ||
| w = w.replace(re,"$1$2"); | ||
| else if (re2.test(w)) | ||
| w = w.replace(re2,"$1$2"); | ||
| // Step 1b | ||
| re = /^(.+?)eed$/; | ||
| re2 = /^(.+?)(ed|ing)$/; | ||
| if (re.test(w)) { | ||
| var fp = re.exec(w); | ||
| re = new RegExp(mgr0); | ||
| if (re.test(fp[1])) { | ||
| re = /.$/; | ||
| w = w.replace(re,""); | ||
| } | ||
| } | ||
| else if (re2.test(w)) { | ||
| var fp = re2.exec(w); | ||
| stem = fp[1]; | ||
| re2 = new RegExp(s_v); | ||
| if (re2.test(stem)) { | ||
| w = stem; | ||
| re2 = /(at|bl|iz)$/; | ||
| re3 = new RegExp("([^aeiouylsz])\\1$"); | ||
| re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); | ||
| if (re2.test(w)) | ||
| w = w + "e"; | ||
| else if (re3.test(w)) { | ||
| re = /.$/; | ||
| w = w.replace(re,""); | ||
| } | ||
| else if (re4.test(w)) | ||
| w = w + "e"; | ||
| } | ||
| } | ||
| // Step 1c | ||
| re = /^(.+?)y$/; | ||
| if (re.test(w)) { | ||
| var fp = re.exec(w); | ||
| stem = fp[1]; | ||
| re = new RegExp(s_v); | ||
| if (re.test(stem)) | ||
| w = stem + "i"; | ||
| } | ||
| // Step 2 | ||
| re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; | ||
| if (re.test(w)) { | ||
| var fp = re.exec(w); | ||
| stem = fp[1]; | ||
| suffix = fp[2]; | ||
| re = new RegExp(mgr0); | ||
| if (re.test(stem)) | ||
| w = stem + step2list[suffix]; | ||
| } | ||
| // Step 3 | ||
| re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; | ||
| if (re.test(w)) { | ||
| var fp = re.exec(w); | ||
| stem = fp[1]; | ||
| suffix = fp[2]; | ||
| re = new RegExp(mgr0); | ||
| if (re.test(stem)) | ||
| w = stem + step3list[suffix]; | ||
| } | ||
| // Step 4 | ||
| re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; | ||
| re2 = /^(.+?)(s|t)(ion)$/; | ||
| if (re.test(w)) { | ||
| var fp = re.exec(w); | ||
| stem = fp[1]; | ||
| re = new RegExp(mgr1); | ||
| if (re.test(stem)) | ||
| w = stem; | ||
| } | ||
| else if (re2.test(w)) { | ||
| var fp = re2.exec(w); | ||
| stem = fp[1] + fp[2]; | ||
| re2 = new RegExp(mgr1); | ||
| if (re2.test(stem)) | ||
| w = stem; | ||
| } | ||
| // Step 5 | ||
| re = /^(.+?)e$/; | ||
| if (re.test(w)) { | ||
| var fp = re.exec(w); | ||
| stem = fp[1]; | ||
| re = new RegExp(mgr1); | ||
| re2 = new RegExp(meq1); | ||
| re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); | ||
| if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) | ||
| w = stem; | ||
| } | ||
| re = /ll$/; | ||
| re2 = new RegExp(mgr1); | ||
| if (re.test(w) && re2.test(w)) { | ||
| re = /.$/; | ||
| w = w.replace(re,""); | ||
| } | ||
| // and turn initial Y back to y | ||
| if (firstch == "y") | ||
| w = firstch.toLowerCase() + w.substr(1); | ||
| return w; | ||
| } | ||
| } | ||
| /** | ||
| * Search Module | ||
| */ | ||
| var Search = { | ||
| _index : null, | ||
| _queued_query : null, | ||
| _pulse_status : -1, | ||
| init : function() { | ||
| var params = $.getQueryParameters(); | ||
| if (params.q) { | ||
| var query = params.q[0]; | ||
| $('input[name="q"]')[0].value = query; | ||
| this.performSearch(query); | ||
| } | ||
| }, | ||
| loadIndex : function(url) { | ||
| $.ajax({type: "GET", url: url, data: null, success: null, | ||
| dataType: "script", cache: true}); | ||
| }, | ||
| setIndex : function(index) { | ||
| var q; | ||
| this._index = index; | ||
| if ((q = this._queued_query) !== null) { | ||
| this._queued_query = null; | ||
| Search.query(q); | ||
| } | ||
| }, | ||
| hasIndex : function() { | ||
| return this._index !== null; | ||
| }, | ||
| deferQuery : function(query) { | ||
| this._queued_query = query; | ||
| }, | ||
| stopPulse : function() { | ||
| this._pulse_status = 0; | ||
| }, | ||
| startPulse : function() { | ||
| if (this._pulse_status >= 0) | ||
| return; | ||
| function pulse() { | ||
| Search._pulse_status = (Search._pulse_status + 1) % 4; | ||
| var dotString = ''; | ||
| for (var i = 0; i < Search._pulse_status; i++) | ||
| dotString += '.'; | ||
| Search.dots.text(dotString); | ||
| if (Search._pulse_status > -1) | ||
| window.setTimeout(pulse, 500); | ||
| }; | ||
| pulse(); | ||
| }, | ||
| /** | ||
| * perform a search for something | ||
| */ | ||
| performSearch : function(query) { | ||
| // create the required interface elements | ||
| this.out = $('#search-results'); | ||
| this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out); | ||
| this.dots = $('<span></span>').appendTo(this.title); | ||
| this.status = $('<p style="display: none"></p>').appendTo(this.out); | ||
| this.output = $('<ul class="search"/>').appendTo(this.out); | ||
| $('#search-progress').text(_('Preparing search...')); | ||
| this.startPulse(); | ||
| // index already loaded, the browser was quick! | ||
| if (this.hasIndex()) | ||
| this.query(query); | ||
| else | ||
| this.deferQuery(query); | ||
| }, | ||
| query : function(query) { | ||
| var stopwords = ["but","is","it","will","their","if","into","that","then","was","they","these","by","no","be","in","near","this","with","and","to","the","such","a","of","there","on","for","or","are","not","as","at"]; | ||
| // Stem the searchterms and add them to the correct list | ||
| var stemmer = new Stemmer(); | ||
| var searchterms = []; | ||
| var excluded = []; | ||
| var hlterms = []; | ||
| var tmp = query.split(/\s+/); | ||
| var objectterms = []; | ||
| for (var i = 0; i < tmp.length; i++) { | ||
| if (tmp[i] != "") { | ||
| objectterms.push(tmp[i].toLowerCase()); | ||
| } | ||
| if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) || | ||
| tmp[i] == "") { | ||
| // skip this "word" | ||
| continue; | ||
| } | ||
| // stem the word | ||
| var word = stemmer.stemWord(tmp[i]).toLowerCase(); | ||
| // select the correct list | ||
| if (word[0] == '-') { | ||
| var toAppend = excluded; | ||
| word = word.substr(1); | ||
| } | ||
| else { | ||
| var toAppend = searchterms; | ||
| hlterms.push(tmp[i].toLowerCase()); | ||
| } | ||
| // only add if not already in the list | ||
| if (!$.contains(toAppend, word)) | ||
| toAppend.push(word); | ||
| }; | ||
| var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" ")); | ||
| // console.debug('SEARCH: searching for:'); | ||
| // console.info('required: ', searchterms); | ||
| // console.info('excluded: ', excluded); | ||
| // prepare search | ||
| var filenames = this._index.filenames; | ||
| var titles = this._index.titles; | ||
| var terms = this._index.terms; | ||
| var fileMap = {}; | ||
| var files = null; | ||
| // different result priorities | ||
| var importantResults = []; | ||
| var objectResults = []; | ||
| var regularResults = []; | ||
| var unimportantResults = []; | ||
| $('#search-progress').empty(); | ||
| // lookup as object | ||
| for (var i = 0; i < objectterms.length; i++) { | ||
| var others = [].concat(objectterms.slice(0,i), | ||
| objectterms.slice(i+1, objectterms.length)) | ||
| var results = this.performObjectSearch(objectterms[i], others); | ||
| // Assume first word is most likely to be the object, | ||
| // other words more likely to be in description. | ||
| // Therefore put matches for earlier words first. | ||
| // (Results are eventually used in reverse order). | ||
| objectResults = results[0].concat(objectResults); | ||
| importantResults = results[1].concat(importantResults); | ||
| unimportantResults = results[2].concat(unimportantResults); | ||
| } | ||
| // perform the search on the required terms | ||
| for (var i = 0; i < searchterms.length; i++) { | ||
| var word = searchterms[i]; | ||
| // no match but word was a required one | ||
| if ((files = terms[word]) == null) | ||
| break; | ||
| if (files.length == undefined) { | ||
| files = [files]; | ||
| } | ||
| // create the mapping | ||
| for (var j = 0; j < files.length; j++) { | ||
| var file = files[j]; | ||
| if (file in fileMap) | ||
| fileMap[file].push(word); | ||
| else | ||
| fileMap[file] = [word]; | ||
| } | ||
| } | ||
| // now check if the files don't contain excluded terms | ||
| for (var file in fileMap) { | ||
| var valid = true; | ||
| // check if all requirements are matched | ||
| if (fileMap[file].length != searchterms.length) | ||
| continue; | ||
| // ensure that none of the excluded terms is in the | ||
| // search result. | ||
| for (var i = 0; i < excluded.length; i++) { | ||
| if (terms[excluded[i]] == file || | ||
| $.contains(terms[excluded[i]] || [], file)) { | ||
| valid = false; | ||
| break; | ||
| } | ||
| } | ||
| // if we have still a valid result we can add it | ||
| // to the result list | ||
| if (valid) | ||
| regularResults.push([filenames[file], titles[file], '', null]); | ||
| } | ||
| // delete unused variables in order to not waste | ||
| // memory until list is retrieved completely | ||
| delete filenames, titles, terms; | ||
| // now sort the regular results descending by title | ||
| regularResults.sort(function(a, b) { | ||
| var left = a[1].toLowerCase(); | ||
| var right = b[1].toLowerCase(); | ||
| return (left > right) ? -1 : ((left < right) ? 1 : 0); | ||
| }); | ||
| // combine all results | ||
| var results = unimportantResults.concat(regularResults) | ||
| .concat(objectResults).concat(importantResults); | ||
| // print the results | ||
| var resultCount = results.length; | ||
| function displayNextItem() { | ||
| // results left, load the summary and display it | ||
| if (results.length) { | ||
| var item = results.pop(); | ||
| var listItem = $('<li style="display:none"></li>'); | ||
| if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') { | ||
| // dirhtml builder | ||
| var dirname = item[0] + '/'; | ||
| if (dirname.match(/\/index\/$/)) { | ||
| dirname = dirname.substring(0, dirname.length-6); | ||
| } else if (dirname == 'index/') { | ||
| dirname = ''; | ||
| } | ||
| listItem.append($('<a/>').attr('href', | ||
| DOCUMENTATION_OPTIONS.URL_ROOT + dirname + | ||
| highlightstring + item[2]).html(item[1])); | ||
| } else { | ||
| // normal html builders | ||
| listItem.append($('<a/>').attr('href', | ||
| item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX + | ||
| highlightstring + item[2]).html(item[1])); | ||
| } | ||
| if (item[3]) { | ||
| listItem.append($('<span> (' + item[3] + ')</span>')); | ||
| Search.output.append(listItem); | ||
| listItem.slideDown(5, function() { | ||
| displayNextItem(); | ||
| }); | ||
| } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { | ||
| $.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + | ||
| item[0] + '.txt', function(data) { | ||
| if (data != '') { | ||
| listItem.append($.makeSearchSummary(data, searchterms, hlterms)); | ||
| Search.output.append(listItem); | ||
| } | ||
| listItem.slideDown(5, function() { | ||
| displayNextItem(); | ||
| }); | ||
| }, "text"); | ||
| } else { | ||
| // no source available, just display title | ||
| Search.output.append(listItem); | ||
| listItem.slideDown(5, function() { | ||
| displayNextItem(); | ||
| }); | ||
| } | ||
| } | ||
| // search finished, update title and status message | ||
| else { | ||
| Search.stopPulse(); | ||
| Search.title.text(_('Search Results')); | ||
| if (!resultCount) | ||
| Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.')); | ||
| else | ||
| Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount)); | ||
| Search.status.fadeIn(500); | ||
| } | ||
| } | ||
| displayNextItem(); | ||
| }, | ||
| performObjectSearch : function(object, otherterms) { | ||
| var filenames = this._index.filenames; | ||
| var objects = this._index.objects; | ||
| var objnames = this._index.objnames; | ||
| var titles = this._index.titles; | ||
| var importantResults = []; | ||
| var objectResults = []; | ||
| var unimportantResults = []; | ||
| for (var prefix in objects) { | ||
| for (var name in objects[prefix]) { | ||
| var fullname = (prefix ? prefix + '.' : '') + name; | ||
| if (fullname.toLowerCase().indexOf(object) > -1) { | ||
| var match = objects[prefix][name]; | ||
| var objname = objnames[match[1]][2]; | ||
| var title = titles[match[0]]; | ||
| // If more than one term searched for, we require other words to be | ||
| // found in the name/title/description | ||
| if (otherterms.length > 0) { | ||
| var haystack = (prefix + ' ' + name + ' ' + | ||
| objname + ' ' + title).toLowerCase(); | ||
| var allfound = true; | ||
| for (var i = 0; i < otherterms.length; i++) { | ||
| if (haystack.indexOf(otherterms[i]) == -1) { | ||
| allfound = false; | ||
| break; | ||
| } | ||
| } | ||
| if (!allfound) { | ||
| continue; | ||
| } | ||
| } | ||
| var descr = objname + _(', in ') + title; | ||
| anchor = match[3]; | ||
| if (anchor == '') | ||
| anchor = fullname; | ||
| else if (anchor == '-') | ||
| anchor = objnames[match[1]][1] + '-' + fullname; | ||
| result = [filenames[match[0]], fullname, '#'+anchor, descr]; | ||
| switch (match[2]) { | ||
| case 1: objectResults.push(result); break; | ||
| case 0: importantResults.push(result); break; | ||
| case 2: unimportantResults.push(result); break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| // sort results descending | ||
| objectResults.sort(function(a, b) { | ||
| return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0); | ||
| }); | ||
| importantResults.sort(function(a, b) { | ||
| return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0); | ||
| }); | ||
| unimportantResults.sort(function(a, b) { | ||
| return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0); | ||
| }); | ||
| return [importantResults, objectResults, unimportantResults] | ||
| } | ||
| } | ||
| $(document).ready(function() { | ||
| Search.init(); | ||
| }); |
| /* | ||
| * sidebar.js | ||
| * ~~~~~~~~~~ | ||
| * | ||
| * This script makes the Sphinx sidebar collapsible. | ||
| * | ||
| * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds | ||
| * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton | ||
| * used to collapse and expand the sidebar. | ||
| * | ||
| * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden | ||
| * and the width of the sidebar and the margin-left of the document | ||
| * are decreased. When the sidebar is expanded the opposite happens. | ||
| * This script saves a per-browser/per-session cookie used to | ||
| * remember the position of the sidebar among the pages. | ||
| * Once the browser is closed the cookie is deleted and the position | ||
| * reset to the default (expanded). | ||
| * | ||
| * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. | ||
| * :license: BSD, see LICENSE for details. | ||
| * | ||
| */ | ||
| $(function() { | ||
| // global elements used by the functions. | ||
| // the 'sidebarbutton' element is defined as global after its | ||
| // creation, in the add_sidebar_button function | ||
| var bodywrapper = $('.bodywrapper'); | ||
| var sidebar = $('.sphinxsidebar'); | ||
| var sidebarwrapper = $('.sphinxsidebarwrapper'); | ||
| // for some reason, the document has no sidebar; do not run into errors | ||
| if (!sidebar.length) return; | ||
| // original margin-left of the bodywrapper and width of the sidebar | ||
| // with the sidebar expanded | ||
| var bw_margin_expanded = bodywrapper.css('margin-left'); | ||
| var ssb_width_expanded = sidebar.width(); | ||
| // margin-left of the bodywrapper and width of the sidebar | ||
| // with the sidebar collapsed | ||
| var bw_margin_collapsed = '.8em'; | ||
| var ssb_width_collapsed = '.8em'; | ||
| // colors used by the current theme | ||
| var dark_color = $('.related').css('background-color'); | ||
| var light_color = $('.document').css('background-color'); | ||
| function sidebar_is_collapsed() { | ||
| return sidebarwrapper.is(':not(:visible)'); | ||
| } | ||
| function toggle_sidebar() { | ||
| if (sidebar_is_collapsed()) | ||
| expand_sidebar(); | ||
| else | ||
| collapse_sidebar(); | ||
| } | ||
| function collapse_sidebar() { | ||
| sidebarwrapper.hide(); | ||
| sidebar.css('width', ssb_width_collapsed); | ||
| bodywrapper.css('margin-left', bw_margin_collapsed); | ||
| sidebarbutton.css({ | ||
| 'margin-left': '0', | ||
| 'height': bodywrapper.height() | ||
| }); | ||
| sidebarbutton.find('span').text('»'); | ||
| sidebarbutton.attr('title', _('Expand sidebar')); | ||
| document.cookie = 'sidebar=collapsed'; | ||
| } | ||
| function expand_sidebar() { | ||
| bodywrapper.css('margin-left', bw_margin_expanded); | ||
| sidebar.css('width', ssb_width_expanded); | ||
| sidebarwrapper.show(); | ||
| sidebarbutton.css({ | ||
| 'margin-left': ssb_width_expanded-12, | ||
| 'height': bodywrapper.height() | ||
| }); | ||
| sidebarbutton.find('span').text('«'); | ||
| sidebarbutton.attr('title', _('Collapse sidebar')); | ||
| document.cookie = 'sidebar=expanded'; | ||
| } | ||
| function add_sidebar_button() { | ||
| sidebarwrapper.css({ | ||
| 'float': 'left', | ||
| 'margin-right': '0', | ||
| 'width': ssb_width_expanded - 28 | ||
| }); | ||
| // create the button | ||
| sidebar.append( | ||
| '<div id="sidebarbutton"><span>«</span></div>' | ||
| ); | ||
| var sidebarbutton = $('#sidebarbutton'); | ||
| light_color = sidebarbutton.css('background-color'); | ||
| // find the height of the viewport to center the '<<' in the page | ||
| var viewport_height; | ||
| if (window.innerHeight) | ||
| viewport_height = window.innerHeight; | ||
| else | ||
| viewport_height = $(window).height(); | ||
| sidebarbutton.find('span').css({ | ||
| 'display': 'block', | ||
| 'margin-top': (viewport_height - sidebar.position().top - 20) / 2 | ||
| }); | ||
| sidebarbutton.click(toggle_sidebar); | ||
| sidebarbutton.attr('title', _('Collapse sidebar')); | ||
| sidebarbutton.css({ | ||
| 'color': '#FFFFFF', | ||
| 'border-left': '1px solid ' + dark_color, | ||
| 'font-size': '1.2em', | ||
| 'cursor': 'pointer', | ||
| 'height': bodywrapper.height(), | ||
| 'padding-top': '1px', | ||
| 'margin-left': ssb_width_expanded - 12 | ||
| }); | ||
| sidebarbutton.hover( | ||
| function () { | ||
| $(this).css('background-color', dark_color); | ||
| }, | ||
| function () { | ||
| $(this).css('background-color', light_color); | ||
| } | ||
| ); | ||
| } | ||
| function set_position_from_cookie() { | ||
| if (!document.cookie) | ||
| return; | ||
| var items = document.cookie.split(';'); | ||
| for(var k=0; k<items.length; k++) { | ||
| var key_val = items[k].split('='); | ||
| var key = key_val[0]; | ||
| if (key == 'sidebar') { | ||
| var value = key_val[1]; | ||
| if ((value == 'collapsed') && (!sidebar_is_collapsed())) | ||
| collapse_sidebar(); | ||
| else if ((value == 'expanded') && (sidebar_is_collapsed())) | ||
| expand_sidebar(); | ||
| } | ||
| } | ||
| } | ||
| add_sidebar_button(); | ||
| var sidebarbutton = $('#sidebarbutton'); | ||
| set_position_from_cookie(); | ||
| }); |
| // Underscore.js 0.5.5 | ||
| // (c) 2009 Jeremy Ashkenas, DocumentCloud Inc. | ||
| // Underscore is freely distributable under the terms of the MIT license. | ||
| // Portions of Underscore are inspired by or borrowed from Prototype.js, | ||
| // Oliver Steele's Functional, and John Resig's Micro-Templating. | ||
| // For all details and documentation: | ||
| // http://documentcloud.github.com/underscore/ | ||
| (function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d, | ||
| a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c); | ||
| var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c, | ||
| d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck= | ||
| function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a, | ||
| function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a, | ||
| 0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d, | ||
| e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d= | ||
| a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)}); | ||
| return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length); | ||
| var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false; | ||
| if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length== | ||
| 0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&& | ||
| a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g, | ||
| " ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments); | ||
| o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})(); |
| th.field-name { | ||
| font-weight: normal; | ||
| background: inherit; | ||
| font-variant: small-caps; | ||
| font-size: small; | ||
| } | ||
| td.field-body ul li strong { | ||
| font-weight: normal; | ||
| border-bottom-width: 1px; | ||
| border-bottom-style: dashed; | ||
| border-bottom-color: darkgreen; | ||
| } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| /* | ||
| * websupport.js | ||
| * ~~~~~~~~~~~~~ | ||
| * | ||
| * sphinx.websupport utilties for all documentation. | ||
| * | ||
| * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. | ||
| * :license: BSD, see LICENSE for details. | ||
| * | ||
| */ | ||
| (function($) { | ||
| $.fn.autogrow = function() { | ||
| return this.each(function() { | ||
| var textarea = this; | ||
| $.fn.autogrow.resize(textarea); | ||
| $(textarea) | ||
| .focus(function() { | ||
| textarea.interval = setInterval(function() { | ||
| $.fn.autogrow.resize(textarea); | ||
| }, 500); | ||
| }) | ||
| .blur(function() { | ||
| clearInterval(textarea.interval); | ||
| }); | ||
| }); | ||
| }; | ||
| $.fn.autogrow.resize = function(textarea) { | ||
| var lineHeight = parseInt($(textarea).css('line-height'), 10); | ||
| var lines = textarea.value.split('\n'); | ||
| var columns = textarea.cols; | ||
| var lineCount = 0; | ||
| $.each(lines, function() { | ||
| lineCount += Math.ceil(this.length / columns) || 1; | ||
| }); | ||
| var height = lineHeight * (lineCount + 1); | ||
| $(textarea).css('height', height); | ||
| }; | ||
| })(jQuery); | ||
| (function($) { | ||
| var comp, by; | ||
| function init() { | ||
| initEvents(); | ||
| initComparator(); | ||
| } | ||
| function initEvents() { | ||
| $('a.comment-close').live("click", function(event) { | ||
| event.preventDefault(); | ||
| hide($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.vote').live("click", function(event) { | ||
| event.preventDefault(); | ||
| handleVote($(this)); | ||
| }); | ||
| $('a.reply').live("click", function(event) { | ||
| event.preventDefault(); | ||
| openReply($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.close-reply').live("click", function(event) { | ||
| event.preventDefault(); | ||
| closeReply($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.sort-option').live("click", function(event) { | ||
| event.preventDefault(); | ||
| handleReSort($(this)); | ||
| }); | ||
| $('a.show-proposal').live("click", function(event) { | ||
| event.preventDefault(); | ||
| showProposal($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.hide-proposal').live("click", function(event) { | ||
| event.preventDefault(); | ||
| hideProposal($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.show-propose-change').live("click", function(event) { | ||
| event.preventDefault(); | ||
| showProposeChange($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.hide-propose-change').live("click", function(event) { | ||
| event.preventDefault(); | ||
| hideProposeChange($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.accept-comment').live("click", function(event) { | ||
| event.preventDefault(); | ||
| acceptComment($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.delete-comment').live("click", function(event) { | ||
| event.preventDefault(); | ||
| deleteComment($(this).attr('id').substring(2)); | ||
| }); | ||
| $('a.comment-markup').live("click", function(event) { | ||
| event.preventDefault(); | ||
| toggleCommentMarkupBox($(this).attr('id').substring(2)); | ||
| }); | ||
| } | ||
| /** | ||
| * Set comp, which is a comparator function used for sorting and | ||
| * inserting comments into the list. | ||
| */ | ||
| function setComparator() { | ||
| // If the first three letters are "asc", sort in ascending order | ||
| // and remove the prefix. | ||
| if (by.substring(0,3) == 'asc') { | ||
| var i = by.substring(3); | ||
| comp = function(a, b) { return a[i] - b[i]; }; | ||
| } else { | ||
| // Otherwise sort in descending order. | ||
| comp = function(a, b) { return b[by] - a[by]; }; | ||
| } | ||
| // Reset link styles and format the selected sort option. | ||
| $('a.sel').attr('href', '#').removeClass('sel'); | ||
| $('a.by' + by).removeAttr('href').addClass('sel'); | ||
| } | ||
| /** | ||
| * Create a comp function. If the user has preferences stored in | ||
| * the sortBy cookie, use those, otherwise use the default. | ||
| */ | ||
| function initComparator() { | ||
| by = 'rating'; // Default to sort by rating. | ||
| // If the sortBy cookie is set, use that instead. | ||
| if (document.cookie.length > 0) { | ||
| var start = document.cookie.indexOf('sortBy='); | ||
| if (start != -1) { | ||
| start = start + 7; | ||
| var end = document.cookie.indexOf(";", start); | ||
| if (end == -1) { | ||
| end = document.cookie.length; | ||
| by = unescape(document.cookie.substring(start, end)); | ||
| } | ||
| } | ||
| } | ||
| setComparator(); | ||
| } | ||
| /** | ||
| * Show a comment div. | ||
| */ | ||
| function show(id) { | ||
| $('#ao' + id).hide(); | ||
| $('#ah' + id).show(); | ||
| var context = $.extend({id: id}, opts); | ||
| var popup = $(renderTemplate(popupTemplate, context)).hide(); | ||
| popup.find('textarea[name="proposal"]').hide(); | ||
| popup.find('a.by' + by).addClass('sel'); | ||
| var form = popup.find('#cf' + id); | ||
| form.submit(function(event) { | ||
| event.preventDefault(); | ||
| addComment(form); | ||
| }); | ||
| $('#s' + id).after(popup); | ||
| popup.slideDown('fast', function() { | ||
| getComments(id); | ||
| }); | ||
| } | ||
| /** | ||
| * Hide a comment div. | ||
| */ | ||
| function hide(id) { | ||
| $('#ah' + id).hide(); | ||
| $('#ao' + id).show(); | ||
| var div = $('#sc' + id); | ||
| div.slideUp('fast', function() { | ||
| div.remove(); | ||
| }); | ||
| } | ||
| /** | ||
| * Perform an ajax request to get comments for a node | ||
| * and insert the comments into the comments tree. | ||
| */ | ||
| function getComments(id) { | ||
| $.ajax({ | ||
| type: 'GET', | ||
| url: opts.getCommentsURL, | ||
| data: {node: id}, | ||
| success: function(data, textStatus, request) { | ||
| var ul = $('#cl' + id); | ||
| var speed = 100; | ||
| $('#cf' + id) | ||
| .find('textarea[name="proposal"]') | ||
| .data('source', data.source); | ||
| if (data.comments.length === 0) { | ||
| ul.html('<li>No comments yet.</li>'); | ||
| ul.data('empty', true); | ||
| } else { | ||
| // If there are comments, sort them and put them in the list. | ||
| var comments = sortComments(data.comments); | ||
| speed = data.comments.length * 100; | ||
| appendComments(comments, ul); | ||
| ul.data('empty', false); | ||
| } | ||
| $('#cn' + id).slideUp(speed + 200); | ||
| ul.slideDown(speed); | ||
| }, | ||
| error: function(request, textStatus, error) { | ||
| showError('Oops, there was a problem retrieving the comments.'); | ||
| }, | ||
| dataType: 'json' | ||
| }); | ||
| } | ||
| /** | ||
| * Add a comment via ajax and insert the comment into the comment tree. | ||
| */ | ||
| function addComment(form) { | ||
| var node_id = form.find('input[name="node"]').val(); | ||
| var parent_id = form.find('input[name="parent"]').val(); | ||
| var text = form.find('textarea[name="comment"]').val(); | ||
| var proposal = form.find('textarea[name="proposal"]').val(); | ||
| if (text == '') { | ||
| showError('Please enter a comment.'); | ||
| return; | ||
| } | ||
| // Disable the form that is being submitted. | ||
| form.find('textarea,input').attr('disabled', 'disabled'); | ||
| // Send the comment to the server. | ||
| $.ajax({ | ||
| type: "POST", | ||
| url: opts.addCommentURL, | ||
| dataType: 'json', | ||
| data: { | ||
| node: node_id, | ||
| parent: parent_id, | ||
| text: text, | ||
| proposal: proposal | ||
| }, | ||
| success: function(data, textStatus, error) { | ||
| // Reset the form. | ||
| if (node_id) { | ||
| hideProposeChange(node_id); | ||
| } | ||
| form.find('textarea') | ||
| .val('') | ||
| .add(form.find('input')) | ||
| .removeAttr('disabled'); | ||
| var ul = $('#cl' + (node_id || parent_id)); | ||
| if (ul.data('empty')) { | ||
| $(ul).empty(); | ||
| ul.data('empty', false); | ||
| } | ||
| insertComment(data.comment); | ||
| var ao = $('#ao' + node_id); | ||
| ao.find('img').attr({'src': opts.commentBrightImage}); | ||
| if (node_id) { | ||
| // if this was a "root" comment, remove the commenting box | ||
| // (the user can get it back by reopening the comment popup) | ||
| $('#ca' + node_id).slideUp(); | ||
| } | ||
| }, | ||
| error: function(request, textStatus, error) { | ||
| form.find('textarea,input').removeAttr('disabled'); | ||
| showError('Oops, there was a problem adding the comment.'); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Recursively append comments to the main comment list and children | ||
| * lists, creating the comment tree. | ||
| */ | ||
| function appendComments(comments, ul) { | ||
| $.each(comments, function() { | ||
| var div = createCommentDiv(this); | ||
| ul.append($(document.createElement('li')).html(div)); | ||
| appendComments(this.children, div.find('ul.comment-children')); | ||
| // To avoid stagnating data, don't store the comments children in data. | ||
| this.children = null; | ||
| div.data('comment', this); | ||
| }); | ||
| } | ||
| /** | ||
| * After adding a new comment, it must be inserted in the correct | ||
| * location in the comment tree. | ||
| */ | ||
| function insertComment(comment) { | ||
| var div = createCommentDiv(comment); | ||
| // To avoid stagnating data, don't store the comments children in data. | ||
| comment.children = null; | ||
| div.data('comment', comment); | ||
| var ul = $('#cl' + (comment.node || comment.parent)); | ||
| var siblings = getChildren(ul); | ||
| var li = $(document.createElement('li')); | ||
| li.hide(); | ||
| // Determine where in the parents children list to insert this comment. | ||
| for(i=0; i < siblings.length; i++) { | ||
| if (comp(comment, siblings[i]) <= 0) { | ||
| $('#cd' + siblings[i].id) | ||
| .parent() | ||
| .before(li.html(div)); | ||
| li.slideDown('fast'); | ||
| return; | ||
| } | ||
| } | ||
| // If we get here, this comment rates lower than all the others, | ||
| // or it is the only comment in the list. | ||
| ul.append(li.html(div)); | ||
| li.slideDown('fast'); | ||
| } | ||
| function acceptComment(id) { | ||
| $.ajax({ | ||
| type: 'POST', | ||
| url: opts.acceptCommentURL, | ||
| data: {id: id}, | ||
| success: function(data, textStatus, request) { | ||
| $('#cm' + id).fadeOut('fast'); | ||
| $('#cd' + id).removeClass('moderate'); | ||
| }, | ||
| error: function(request, textStatus, error) { | ||
| showError('Oops, there was a problem accepting the comment.'); | ||
| } | ||
| }); | ||
| } | ||
| function deleteComment(id) { | ||
| $.ajax({ | ||
| type: 'POST', | ||
| url: opts.deleteCommentURL, | ||
| data: {id: id}, | ||
| success: function(data, textStatus, request) { | ||
| var div = $('#cd' + id); | ||
| if (data == 'delete') { | ||
| // Moderator mode: remove the comment and all children immediately | ||
| div.slideUp('fast', function() { | ||
| div.remove(); | ||
| }); | ||
| return; | ||
| } | ||
| // User mode: only mark the comment as deleted | ||
| div | ||
| .find('span.user-id:first') | ||
| .text('[deleted]').end() | ||
| .find('div.comment-text:first') | ||
| .text('[deleted]').end() | ||
| .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id + | ||
| ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id) | ||
| .remove(); | ||
| var comment = div.data('comment'); | ||
| comment.username = '[deleted]'; | ||
| comment.text = '[deleted]'; | ||
| div.data('comment', comment); | ||
| }, | ||
| error: function(request, textStatus, error) { | ||
| showError('Oops, there was a problem deleting the comment.'); | ||
| } | ||
| }); | ||
| } | ||
| function showProposal(id) { | ||
| $('#sp' + id).hide(); | ||
| $('#hp' + id).show(); | ||
| $('#pr' + id).slideDown('fast'); | ||
| } | ||
| function hideProposal(id) { | ||
| $('#hp' + id).hide(); | ||
| $('#sp' + id).show(); | ||
| $('#pr' + id).slideUp('fast'); | ||
| } | ||
| function showProposeChange(id) { | ||
| $('#pc' + id).hide(); | ||
| $('#hc' + id).show(); | ||
| var textarea = $('#pt' + id); | ||
| textarea.val(textarea.data('source')); | ||
| $.fn.autogrow.resize(textarea[0]); | ||
| textarea.slideDown('fast'); | ||
| } | ||
| function hideProposeChange(id) { | ||
| $('#hc' + id).hide(); | ||
| $('#pc' + id).show(); | ||
| var textarea = $('#pt' + id); | ||
| textarea.val('').removeAttr('disabled'); | ||
| textarea.slideUp('fast'); | ||
| } | ||
| function toggleCommentMarkupBox(id) { | ||
| $('#mb' + id).toggle(); | ||
| } | ||
| /** Handle when the user clicks on a sort by link. */ | ||
| function handleReSort(link) { | ||
| var classes = link.attr('class').split(/\s+/); | ||
| for (var i=0; i<classes.length; i++) { | ||
| if (classes[i] != 'sort-option') { | ||
| by = classes[i].substring(2); | ||
| } | ||
| } | ||
| setComparator(); | ||
| // Save/update the sortBy cookie. | ||
| var expiration = new Date(); | ||
| expiration.setDate(expiration.getDate() + 365); | ||
| document.cookie= 'sortBy=' + escape(by) + | ||
| ';expires=' + expiration.toUTCString(); | ||
| $('ul.comment-ul').each(function(index, ul) { | ||
| var comments = getChildren($(ul), true); | ||
| comments = sortComments(comments); | ||
| appendComments(comments, $(ul).empty()); | ||
| }); | ||
| } | ||
| /** | ||
| * Function to process a vote when a user clicks an arrow. | ||
| */ | ||
| function handleVote(link) { | ||
| if (!opts.voting) { | ||
| showError("You'll need to login to vote."); | ||
| return; | ||
| } | ||
| var id = link.attr('id'); | ||
| if (!id) { | ||
| // Didn't click on one of the voting arrows. | ||
| return; | ||
| } | ||
| // If it is an unvote, the new vote value is 0, | ||
| // Otherwise it's 1 for an upvote, or -1 for a downvote. | ||
| var value = 0; | ||
| if (id.charAt(1) != 'u') { | ||
| value = id.charAt(0) == 'u' ? 1 : -1; | ||
| } | ||
| // The data to be sent to the server. | ||
| var d = { | ||
| comment_id: id.substring(2), | ||
| value: value | ||
| }; | ||
| // Swap the vote and unvote links. | ||
| link.hide(); | ||
| $('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id) | ||
| .show(); | ||
| // The div the comment is displayed in. | ||
| var div = $('div#cd' + d.comment_id); | ||
| var data = div.data('comment'); | ||
| // If this is not an unvote, and the other vote arrow has | ||
| // already been pressed, unpress it. | ||
| if ((d.value !== 0) && (data.vote === d.value * -1)) { | ||
| $('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide(); | ||
| $('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show(); | ||
| } | ||
| // Update the comments rating in the local data. | ||
| data.rating += (data.vote === 0) ? d.value : (d.value - data.vote); | ||
| data.vote = d.value; | ||
| div.data('comment', data); | ||
| // Change the rating text. | ||
| div.find('.rating:first') | ||
| .text(data.rating + ' point' + (data.rating == 1 ? '' : 's')); | ||
| // Send the vote information to the server. | ||
| $.ajax({ | ||
| type: "POST", | ||
| url: opts.processVoteURL, | ||
| data: d, | ||
| error: function(request, textStatus, error) { | ||
| showError('Oops, there was a problem casting that vote.'); | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Open a reply form used to reply to an existing comment. | ||
| */ | ||
| function openReply(id) { | ||
| // Swap out the reply link for the hide link | ||
| $('#rl' + id).hide(); | ||
| $('#cr' + id).show(); | ||
| // Add the reply li to the children ul. | ||
| var div = $(renderTemplate(replyTemplate, {id: id})).hide(); | ||
| $('#cl' + id) | ||
| .prepend(div) | ||
| // Setup the submit handler for the reply form. | ||
| .find('#rf' + id) | ||
| .submit(function(event) { | ||
| event.preventDefault(); | ||
| addComment($('#rf' + id)); | ||
| closeReply(id); | ||
| }) | ||
| .find('input[type=button]') | ||
| .click(function() { | ||
| closeReply(id); | ||
| }); | ||
| div.slideDown('fast', function() { | ||
| $('#rf' + id).find('textarea').focus(); | ||
| }); | ||
| } | ||
| /** | ||
| * Close the reply form opened with openReply. | ||
| */ | ||
| function closeReply(id) { | ||
| // Remove the reply div from the DOM. | ||
| $('#rd' + id).slideUp('fast', function() { | ||
| $(this).remove(); | ||
| }); | ||
| // Swap out the hide link for the reply link | ||
| $('#cr' + id).hide(); | ||
| $('#rl' + id).show(); | ||
| } | ||
| /** | ||
| * Recursively sort a tree of comments using the comp comparator. | ||
| */ | ||
| function sortComments(comments) { | ||
| comments.sort(comp); | ||
| $.each(comments, function() { | ||
| this.children = sortComments(this.children); | ||
| }); | ||
| return comments; | ||
| } | ||
| /** | ||
| * Get the children comments from a ul. If recursive is true, | ||
| * recursively include childrens' children. | ||
| */ | ||
| function getChildren(ul, recursive) { | ||
| var children = []; | ||
| ul.children().children("[id^='cd']") | ||
| .each(function() { | ||
| var comment = $(this).data('comment'); | ||
| if (recursive) | ||
| comment.children = getChildren($(this).find('#cl' + comment.id), true); | ||
| children.push(comment); | ||
| }); | ||
| return children; | ||
| } | ||
| /** Create a div to display a comment in. */ | ||
| function createCommentDiv(comment) { | ||
| if (!comment.displayed && !opts.moderator) { | ||
| return $('<div class="moderate">Thank you! Your comment will show up ' | ||
| + 'once it is has been approved by a moderator.</div>'); | ||
| } | ||
| // Prettify the comment rating. | ||
| comment.pretty_rating = comment.rating + ' point' + | ||
| (comment.rating == 1 ? '' : 's'); | ||
| // Make a class (for displaying not yet moderated comments differently) | ||
| comment.css_class = comment.displayed ? '' : ' moderate'; | ||
| // Create a div for this comment. | ||
| var context = $.extend({}, opts, comment); | ||
| var div = $(renderTemplate(commentTemplate, context)); | ||
| // If the user has voted on this comment, highlight the correct arrow. | ||
| if (comment.vote) { | ||
| var direction = (comment.vote == 1) ? 'u' : 'd'; | ||
| div.find('#' + direction + 'v' + comment.id).hide(); | ||
| div.find('#' + direction + 'u' + comment.id).show(); | ||
| } | ||
| if (opts.moderator || comment.text != '[deleted]') { | ||
| div.find('a.reply').show(); | ||
| if (comment.proposal_diff) | ||
| div.find('#sp' + comment.id).show(); | ||
| if (opts.moderator && !comment.displayed) | ||
| div.find('#cm' + comment.id).show(); | ||
| if (opts.moderator || (opts.username == comment.username)) | ||
| div.find('#dc' + comment.id).show(); | ||
| } | ||
| return div; | ||
| } | ||
| /** | ||
| * A simple template renderer. Placeholders such as <%id%> are replaced | ||
| * by context['id'] with items being escaped. Placeholders such as <#id#> | ||
| * are not escaped. | ||
| */ | ||
| function renderTemplate(template, context) { | ||
| var esc = $(document.createElement('div')); | ||
| function handle(ph, escape) { | ||
| var cur = context; | ||
| $.each(ph.split('.'), function() { | ||
| cur = cur[this]; | ||
| }); | ||
| return escape ? esc.text(cur || "").html() : cur; | ||
| } | ||
| return template.replace(/<([%#])([\w\.]*)\1>/g, function() { | ||
| return handle(arguments[2], arguments[1] == '%' ? true : false); | ||
| }); | ||
| } | ||
| /** Flash an error message briefly. */ | ||
| function showError(message) { | ||
| $(document.createElement('div')).attr({'class': 'popup-error'}) | ||
| .append($(document.createElement('div')) | ||
| .attr({'class': 'error-message'}).text(message)) | ||
| .appendTo('body') | ||
| .fadeIn("slow") | ||
| .delay(2000) | ||
| .fadeOut("slow"); | ||
| } | ||
| /** Add a link the user uses to open the comments popup. */ | ||
| $.fn.comment = function() { | ||
| return this.each(function() { | ||
| var id = $(this).attr('id').substring(1); | ||
| var count = COMMENT_METADATA[id]; | ||
| var title = count + ' comment' + (count == 1 ? '' : 's'); | ||
| var image = count > 0 ? opts.commentBrightImage : opts.commentImage; | ||
| var addcls = count == 0 ? ' nocomment' : ''; | ||
| $(this) | ||
| .append( | ||
| $(document.createElement('a')).attr({ | ||
| href: '#', | ||
| 'class': 'sphinx-comment-open' + addcls, | ||
| id: 'ao' + id | ||
| }) | ||
| .append($(document.createElement('img')).attr({ | ||
| src: image, | ||
| alt: 'comment', | ||
| title: title | ||
| })) | ||
| .click(function(event) { | ||
| event.preventDefault(); | ||
| show($(this).attr('id').substring(2)); | ||
| }) | ||
| ) | ||
| .append( | ||
| $(document.createElement('a')).attr({ | ||
| href: '#', | ||
| 'class': 'sphinx-comment-close hidden', | ||
| id: 'ah' + id | ||
| }) | ||
| .append($(document.createElement('img')).attr({ | ||
| src: opts.closeCommentImage, | ||
| alt: 'close', | ||
| title: 'close' | ||
| })) | ||
| .click(function(event) { | ||
| event.preventDefault(); | ||
| hide($(this).attr('id').substring(2)); | ||
| }) | ||
| ); | ||
| }); | ||
| }; | ||
| var opts = { | ||
| processVoteURL: '/_process_vote', | ||
| addCommentURL: '/_add_comment', | ||
| getCommentsURL: '/_get_comments', | ||
| acceptCommentURL: '/_accept_comment', | ||
| deleteCommentURL: '/_delete_comment', | ||
| commentImage: '/static/_static/comment.png', | ||
| closeCommentImage: '/static/_static/comment-close.png', | ||
| loadingImage: '/static/_static/ajax-loader.gif', | ||
| commentBrightImage: '/static/_static/comment-bright.png', | ||
| upArrow: '/static/_static/up.png', | ||
| downArrow: '/static/_static/down.png', | ||
| upArrowPressed: '/static/_static/up-pressed.png', | ||
| downArrowPressed: '/static/_static/down-pressed.png', | ||
| voting: false, | ||
| moderator: false | ||
| }; | ||
| if (typeof COMMENT_OPTIONS != "undefined") { | ||
| opts = jQuery.extend(opts, COMMENT_OPTIONS); | ||
| } | ||
| var popupTemplate = '\ | ||
| <div class="sphinx-comments" id="sc<%id%>">\ | ||
| <p class="sort-options">\ | ||
| Sort by:\ | ||
| <a href="#" class="sort-option byrating">best rated</a>\ | ||
| <a href="#" class="sort-option byascage">newest</a>\ | ||
| <a href="#" class="sort-option byage">oldest</a>\ | ||
| </p>\ | ||
| <div class="comment-header">Comments</div>\ | ||
| <div class="comment-loading" id="cn<%id%>">\ | ||
| loading comments... <img src="<%loadingImage%>" alt="" /></div>\ | ||
| <ul id="cl<%id%>" class="comment-ul"></ul>\ | ||
| <div id="ca<%id%>">\ | ||
| <p class="add-a-comment">Add a comment\ | ||
| (<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\ | ||
| <div class="comment-markup-box" id="mb<%id%>">\ | ||
| reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \ | ||
| <tt>``code``</tt>, \ | ||
| code blocks: <tt>::</tt> and an indented block after blank line</div>\ | ||
| <form method="post" id="cf<%id%>" class="comment-form" action="">\ | ||
| <textarea name="comment" cols="80"></textarea>\ | ||
| <p class="propose-button">\ | ||
| <a href="#" id="pc<%id%>" class="show-propose-change">\ | ||
| Propose a change ▹\ | ||
| </a>\ | ||
| <a href="#" id="hc<%id%>" class="hide-propose-change">\ | ||
| Propose a change ▿\ | ||
| </a>\ | ||
| </p>\ | ||
| <textarea name="proposal" id="pt<%id%>" cols="80"\ | ||
| spellcheck="false"></textarea>\ | ||
| <input type="submit" value="Add comment" />\ | ||
| <input type="hidden" name="node" value="<%id%>" />\ | ||
| <input type="hidden" name="parent" value="" />\ | ||
| </form>\ | ||
| </div>\ | ||
| </div>'; | ||
| var commentTemplate = '\ | ||
| <div id="cd<%id%>" class="sphinx-comment<%css_class%>">\ | ||
| <div class="vote">\ | ||
| <div class="arrow">\ | ||
| <a href="#" id="uv<%id%>" class="vote" title="vote up">\ | ||
| <img src="<%upArrow%>" />\ | ||
| </a>\ | ||
| <a href="#" id="uu<%id%>" class="un vote" title="vote up">\ | ||
| <img src="<%upArrowPressed%>" />\ | ||
| </a>\ | ||
| </div>\ | ||
| <div class="arrow">\ | ||
| <a href="#" id="dv<%id%>" class="vote" title="vote down">\ | ||
| <img src="<%downArrow%>" id="da<%id%>" />\ | ||
| </a>\ | ||
| <a href="#" id="du<%id%>" class="un vote" title="vote down">\ | ||
| <img src="<%downArrowPressed%>" />\ | ||
| </a>\ | ||
| </div>\ | ||
| </div>\ | ||
| <div class="comment-content">\ | ||
| <p class="tagline comment">\ | ||
| <span class="user-id"><%username%></span>\ | ||
| <span class="rating"><%pretty_rating%></span>\ | ||
| <span class="delta"><%time.delta%></span>\ | ||
| </p>\ | ||
| <div class="comment-text comment"><#text#></div>\ | ||
| <p class="comment-opts comment">\ | ||
| <a href="#" class="reply hidden" id="rl<%id%>">reply ▹</a>\ | ||
| <a href="#" class="close-reply" id="cr<%id%>">reply ▿</a>\ | ||
| <a href="#" id="sp<%id%>" class="show-proposal">proposal ▹</a>\ | ||
| <a href="#" id="hp<%id%>" class="hide-proposal">proposal ▿</a>\ | ||
| <a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\ | ||
| <span id="cm<%id%>" class="moderation hidden">\ | ||
| <a href="#" id="ac<%id%>" class="accept-comment">accept</a>\ | ||
| </span>\ | ||
| </p>\ | ||
| <pre class="proposal" id="pr<%id%>">\ | ||
| <#proposal_diff#>\ | ||
| </pre>\ | ||
| <ul class="comment-children" id="cl<%id%>"></ul>\ | ||
| </div>\ | ||
| <div class="clearleft"></div>\ | ||
| </div>\ | ||
| </div>'; | ||
| var replyTemplate = '\ | ||
| <li>\ | ||
| <div class="reply-div" id="rd<%id%>">\ | ||
| <form id="rf<%id%>">\ | ||
| <textarea name="comment" cols="80"></textarea>\ | ||
| <input type="submit" value="Add reply" />\ | ||
| <input type="button" value="Cancel" />\ | ||
| <input type="hidden" name="parent" value="<%id%>" />\ | ||
| <input type="hidden" name="node" value="" />\ | ||
| </form>\ | ||
| </div>\ | ||
| </li>'; | ||
| $(document).ready(function() { | ||
| init(); | ||
| }); | ||
| })(jQuery); | ||
| $(document).ready(function() { | ||
| // add comment anchors for all paragraphs that are commentable | ||
| $('.sphinx-has-comment').comment(); | ||
| // highlight search words in search results | ||
| $("div.context").each(function() { | ||
| var params = $.getQueryParameters(); | ||
| var terms = (params.q) ? params.q[0].split(/\s+/) : []; | ||
| var result = $(this); | ||
| $.each(terms, function() { | ||
| result.highlightText(this.toLowerCase(), 'highlighted'); | ||
| }); | ||
| }); | ||
| // directly open comment window if requested | ||
| var anchor = document.location.hash; | ||
| if (anchor.substring(0, 9) == '#comment-') { | ||
| $('#ao' + anchor.substring(9)).click(); | ||
| document.location.hash = '#s' + anchor.substring(9); | ||
| } | ||
| }); |
Sorry, the diff of this file is not supported yet
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Administration — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Driver" href="driver.html" /> | ||
| <link rel="prev" title="py-postgresql" href="index.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="driver.html" title="Driver" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="index.html" title="py-postgresql" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="administration"> | ||
| <h1>Administration<a class="headerlink" href="#administration" title="Permalink to this headline">¶</a></h1> | ||
| <p>This chapter covers the administration of py-postgresql. This includes | ||
| installation and other aspects of working with py-postgresql such as | ||
| environment variables and configuration files.</p> | ||
| <div class="section" id="installation"> | ||
| <h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2> | ||
| <p>py-postgresql uses Python’s distutils package to manage the build and | ||
| installation process of the package. The normal entry point for | ||
| this is the <tt class="docutils literal"><span class="pre">setup.py</span></tt> script contained in the root project directory.</p> | ||
| <p>After extracting the archive and changing the into the project’s directory, | ||
| installation is normally as simple as:</p> | ||
| <div class="highlight-python"><pre>$ python3 ./setup.py install</pre> | ||
| </div> | ||
| <p>However, if you need to install for use with a particular version of python, | ||
| just use the path of the executable that should be used:</p> | ||
| <div class="highlight-python"><pre>$ /usr/opt/bin/python3 ./setup.py install</pre> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="environment"> | ||
| <h2>Environment<a class="headerlink" href="#environment" title="Permalink to this headline">¶</a></h2> | ||
| <p>These environment variables effect the operation of the package:</p> | ||
| <blockquote> | ||
| <div><table border="1" class="docutils"> | ||
| <colgroup> | ||
| <col width="15%" /> | ||
| <col width="85%" /> | ||
| </colgroup> | ||
| <tbody valign="top"> | ||
| <tr class="row-odd"><td>PGINSTALLATION</td> | ||
| <td>The path to the <tt class="docutils literal"><span class="pre">pg_config</span></tt> executable of the installation to use by default.</td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Administration</a><ul> | ||
| <li><a class="reference internal" href="#installation">Installation</a></li> | ||
| <li><a class="reference internal" href="#environment">Environment</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="index.html" | ||
| title="previous chapter">py-postgresql</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="driver.html" | ||
| title="next chapter">Driver</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/admin.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="driver.html" title="Driver" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="index.html" title="py-postgresql" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Advisory Locks — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Cluster Management" href="cluster.html" /> | ||
| <link rel="prev" title="Notification Management" href="notifyman.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="cluster.html" title="Cluster Management" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="notifyman.html" title="Notification Management" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="advisory-locks"> | ||
| <span id="alock"></span><h1>Advisory Locks<a class="headerlink" href="#advisory-locks" title="Permalink to this headline">¶</a></h1> | ||
| <div class="admonition warning"> | ||
| <p class="first admonition-title">Warning</p> | ||
| <p class="last"><cite>postgresql.alock</cite> is a new feature in v1.0.</p> | ||
| </div> | ||
| <p><a class="reference external" href="http://www.postgresql.org/docs/current/static/explicit-locking.html#ADVISORY-LOCKS">Explicit Locking in PostgreSQL</a>.</p> | ||
| <p>PostgreSQL’s advisory locks offer a cooperative synchronization primitive. | ||
| These are used in cases where an application needs access to a resource, but | ||
| using table locks may cause interference with other operations that can be | ||
| safely performed alongside the application-level, exclusive operation.</p> | ||
| <p>Advisory locks can be used by directly executing the stored procedures in the | ||
| database or by using the <a class="reference internal" href="reference.html#postgresql.alock.ALock" title="postgresql.alock.ALock"><tt class="xref py py-class docutils literal"><span class="pre">postgresql.alock.ALock</span></tt></a> subclasses, which | ||
| provides a context manager that uses those stored procedures.</p> | ||
| <p>Currently, only two subclasses exist. Each represents the lock mode | ||
| supported by PostgreSQL’s advisory locks:</p> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li><tt class="xref py py-class docutils literal"><span class="pre">postgresql.alock.ShareLock</span></tt></li> | ||
| <li><tt class="xref py py-class docutils literal"><span class="pre">postgresql.alock.ExclusiveLock</span></tt></li> | ||
| </ul> | ||
| </div></blockquote> | ||
| <div class="section" id="acquiring-alocks"> | ||
| <h2>Acquiring ALocks<a class="headerlink" href="#acquiring-alocks" title="Permalink to this headline">¶</a></h2> | ||
| <p>An ALock instance represents a sequence of advisory locks. A single ALock can | ||
| acquire and release multiple advisory locks by creating the instance with | ||
| multiple lock identifiers:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql</span> <span class="kn">import</span> <span class="n">alock</span> | ||
| <span class="gp">>>> </span><span class="n">table1_oid</span> <span class="o">=</span> <span class="mi">192842</span> | ||
| <span class="gp">>>> </span><span class="n">table2_oid</span> <span class="o">=</span> <span class="mi">192849</span> | ||
| <span class="gp">>>> </span><span class="n">l</span> <span class="o">=</span> <span class="n">alock</span><span class="o">.</span><span class="n">ExclusiveLock</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="p">(</span><span class="n">table1_oid</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="n">table2_oid</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> | ||
| <span class="gp">>>> </span><span class="n">l</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span> | ||
| <span class="gp">>>> </span><span class="o">...</span> | ||
| <span class="gp">>>> </span><span class="n">l</span><span class="o">.</span><span class="n">release</span><span class="p">()</span> | ||
| </pre></div> | ||
| </div> | ||
| <p><a class="reference internal" href="reference.html#postgresql.alock.ALock" title="postgresql.alock.ALock"><tt class="xref py py-class docutils literal"><span class="pre">postgresql.alock.ALock</span></tt></a> is similar to <tt class="xref py py-class docutils literal"><span class="pre">threading.RLock</span></tt>; in | ||
| order for an ALock to be released, it must be released the number of times it | ||
| has been acquired. ALocks are associated with and survived by their session. | ||
| Much like how RLocks are associated with the thread they are acquired in: | ||
| acquiring an ALock again will merely increment its count.</p> | ||
| <p>PostgreSQL allows advisory locks to be identified using a pair of <cite>int4</cite> or a | ||
| single <cite>int8</cite>. ALock instances represent a <em>sequence</em> of those identifiers:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql</span> <span class="kn">import</span> <span class="n">alock</span> | ||
| <span class="gp">>>> </span><span class="n">ids</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span> | ||
| <span class="gp">>>> </span><span class="k">with</span> <span class="n">alock</span><span class="o">.</span><span class="n">ShareLock</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="o">*</span><span class="n">ids</span><span class="p">):</span> | ||
| <span class="gp">... </span> <span class="o">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Both types of identifiers may be used within the same ALock, and, regardless of | ||
| their type, will be aquired in the order that they were given to the class’ | ||
| constructor. In the above example, <tt class="docutils literal"><span class="pre">(0,0)</span></tt> is acquired first, then <tt class="docutils literal"><span class="pre">0</span></tt>, and | ||
| lastly <tt class="docutils literal"><span class="pre">1</span></tt>.</p> | ||
| </div> | ||
| <div class="section" id="alocks"> | ||
| <h2>ALocks<a class="headerlink" href="#alocks" title="Permalink to this headline">¶</a></h2> | ||
| <p><cite>postgresql.alock.ALock</cite> is abstract; it defines the interface and some common | ||
| functionality. The lock mode is selected by choosing the appropriate subclass.</p> | ||
| <p>There are two:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">postgresql.alock.ExclusiveLock(database,</span> <span class="pre">*identifiers)</span></tt></dt> | ||
| <dd>Instantiate an ALock object representing the <cite>identifiers</cite> for use with the | ||
| <cite>database</cite>. Exclusive locks will conflict with other exclusive locks and share | ||
| locks.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">postgresql.alock.ShareLock(database,</span> <span class="pre">*identifiers)</span></tt></dt> | ||
| <dd>Instantiate an ALock object representing the <cite>identifiers</cite> for use with the | ||
| <cite>database</cite>. Share locks can be acquired when a share lock with the same | ||
| identifier has been acquired by another backend. However, an exclusive lock | ||
| with the same identifier will conflict.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| <div class="section" id="alock-interface-points"> | ||
| <h3>ALock Interface Points<a class="headerlink" href="#alock-interface-points" title="Permalink to this headline">¶</a></h3> | ||
| <p>Methods and properties available on <a class="reference internal" href="reference.html#postgresql.alock.ALock" title="postgresql.alock.ALock"><tt class="xref py py-class docutils literal"><span class="pre">postgresql.alock.ALock</span></tt></a> instances:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">alock.acquire(blocking</span> <span class="pre">=</span> <span class="pre">True)</span></tt></dt> | ||
| <dd><p class="first">Acquire the advisory locks represented by the <tt class="docutils literal"><span class="pre">alock</span></tt> object. If blocking is | ||
| <cite>True</cite>, the default, the method will block until locks on <em>all</em> the | ||
| identifiers have been acquired.</p> | ||
| <p class="last">If blocking is <cite>False</cite>, acquisition may not block, and success will be | ||
| indicated by the returned object: <cite>True</cite> if <em>all</em> lock identifiers were | ||
| acquired and <cite>False</cite> if any of the lock identifiers could not be acquired.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">alock.release()</span></tt></dt> | ||
| <dd>Release the advisory locks represented by the <tt class="docutils literal"><span class="pre">alock</span></tt> object. If the lock | ||
| has not been acquired, a <cite>RuntimeError</cite> will be raised.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">alock.locked()</span></tt></dt> | ||
| <dd>Returns a boolean describing whether the locks are held or not. This will | ||
| return <cite>False</cite> if the lock connection has been closed.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">alock.__enter__()</span></tt></dt> | ||
| <dd>Alias to <tt class="docutils literal"><span class="pre">acquire</span></tt>; context manager protocol. Always blocking.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">alock.__exit__(typ,</span> <span class="pre">val,</span> <span class="pre">tb)</span></tt></dt> | ||
| <dd>Alias to <tt class="docutils literal"><span class="pre">release</span></tt>; context manager protocol.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Advisory Locks</a><ul> | ||
| <li><a class="reference internal" href="#acquiring-alocks">Acquiring ALocks</a></li> | ||
| <li><a class="reference internal" href="#alocks">ALocks</a><ul> | ||
| <li><a class="reference internal" href="#alock-interface-points">ALock Interface Points</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="notifyman.html" | ||
| title="previous chapter">Notification Management</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="cluster.html" | ||
| title="next chapter">Cluster Management</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/alock.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="cluster.html" title="Cluster Management" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="notifyman.html" title="Notification Management" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Commands — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Reference" href="reference.html" /> | ||
| <link rel="prev" title="Gotchas" href="gotchas.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="reference.html" title="Reference" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="gotchas.html" title="Gotchas" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="commands"> | ||
| <h1>Commands<a class="headerlink" href="#commands" title="Permalink to this headline">¶</a></h1> | ||
| <p>This chapter discusses the usage of the available console scripts.</p> | ||
| <div class="section" id="postgresql-bin-pg-python"> | ||
| <h2>postgresql.bin.pg_python<a class="headerlink" href="#postgresql-bin-pg-python" title="Permalink to this headline">¶</a></h2> | ||
| <p>The <tt class="docutils literal"><span class="pre">pg_python</span></tt> command provides a simple way to write Python scripts against a | ||
| single target database. It acts like the regular Python console command, but | ||
| takes standard PostgreSQL options as well to specify the client parameters | ||
| to make establish connection with. The Python environment is then augmented | ||
| with the following built-ins:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">db</span></tt></dt> | ||
| <dd>The PG-API connection object.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">xact</span></tt></dt> | ||
| <dd><tt class="docutils literal"><span class="pre">db.xact</span></tt>, the transaction creator.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">settings</span></tt></dt> | ||
| <dd><tt class="docutils literal"><span class="pre">db.settings</span></tt></dd> | ||
| <dt><tt class="docutils literal"><span class="pre">prepare</span></tt></dt> | ||
| <dd><tt class="docutils literal"><span class="pre">db.prepare</span></tt>, the statement creator.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">proc</span></tt></dt> | ||
| <dd><tt class="docutils literal"><span class="pre">db.proc</span></tt></dd> | ||
| <dt><tt class="docutils literal"><span class="pre">do</span></tt></dt> | ||
| <dd><tt class="docutils literal"><span class="pre">db.do</span></tt>, execute a single DO statement.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">sqlexec</span></tt></dt> | ||
| <dd><tt class="docutils literal"><span class="pre">db.execute</span></tt>, execute multiple SQL statements (<tt class="docutils literal"><span class="pre">None</span></tt> is always returned)</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| <div class="section" id="pg-python-usage"> | ||
| <h3>pg_python Usage<a class="headerlink" href="#pg-python-usage" title="Permalink to this headline">¶</a></h3> | ||
| <p>Usage: postgresql.bin.pg_python [connection options] [script] ...</p> | ||
| <dl class="docutils"> | ||
| <dt>Options:</dt> | ||
| <dd><table class="first last docutils option-list" frame="void" rules="none"> | ||
| <col class="option" /> | ||
| <col class="description" /> | ||
| <tbody valign="top"> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">--unix=<var>UNIX</var></span></kbd></td> | ||
| <td>path to filesystem socket</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">--ssl-mode=<var>SSLMODE</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>SSL requirement for connectivity: require, prefer, | ||
| allow, disable</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-s <var>SETTINGS</var></span>, <span class="option">--setting=<var>SETTINGS</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>run-time parameters to set upon connecting</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-I <var>PQ_IRI</var></span>, <span class="option">--iri=<var>PQ_IRI</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>database locator string | ||
| [pq://user:password@host:port/database?setting=value]</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-h <var>HOST</var></span>, <span class="option">--host=<var>HOST</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>database server host</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-p <var>PORT</var></span>, <span class="option">--port=<var>PORT</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>database server port</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-U <var>USER</var></span>, <span class="option">--username=<var>USER</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>user name to connect as</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">-W</span>, <span class="option">--password</span></kbd></td> | ||
| <td>prompt for password</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-d <var>DATABASE</var></span>, <span class="option">--database=<var>DATABASE</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>database’s name</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">--pq-trace=<var>PQ_TRACE</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>trace PQ protocol transmissions</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-C <var>PYTHON_CONTEXT</var></span>, <span class="option">--context=<var>PYTHON_CONTEXT</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>Python context code to run[<a class="reference external" href="file://,module">file://,module</a>:,<code>]</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">-m <var>PYTHON_MAIN</var></span></kbd></td> | ||
| <td>Python module to run as script(__main__)</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">-c <var>PYTHON_MAIN</var></span></kbd></td> | ||
| <td>Python expression to run(__main__)</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">--version</span></kbd></td> | ||
| <td>show program’s version number and exit</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">--help</span></kbd></td> | ||
| <td>show this help message and exit</td></tr> | ||
| </tbody> | ||
| </table> | ||
| </dd> | ||
| </dl> | ||
| </div> | ||
| <div class="section" id="interactive-console-backslash-commands"> | ||
| <h3>Interactive Console Backslash Commands<a class="headerlink" href="#interactive-console-backslash-commands" title="Permalink to this headline">¶</a></h3> | ||
| <p>Inspired by <tt class="docutils literal"><span class="pre">psql</span></tt>:</p> | ||
| <div class="highlight-python"><pre>>>> \? | ||
| Backslash Commands: | ||
| \? Show this help message. | ||
| \E Edit a file or a temporary script. | ||
| \e Edit and Execute the file directly in the context. | ||
| \i Execute a Python script within the interpreter's context. | ||
| \set Configure environment variables. \set without arguments to show all | ||
| \x Execute the Python command within this process.</pre> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="pg-python-examples"> | ||
| <h3>pg_python Examples<a class="headerlink" href="#pg-python-examples" title="Permalink to this headline">¶</a></h3> | ||
| <p>Module execution taking advantage of the new built-ins:</p> | ||
| <div class="highlight-python"><pre>$ python3 -m postgresql.bin.pg_python -h localhost -W -m timeit "prepare('SELECT 1').first()" | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| 1000 loops, best of 3: 1.35 msec per loop | ||
| $ python3 -m postgresql.bin.pg_python -h localhost -W -m timeit -s "ps=prepare('SELECT 1')" "ps.first()" | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| 1000 loops, best of 3: 442 usec per loop</pre> | ||
| </div> | ||
| <p>Simple interactive usage:</p> | ||
| <div class="highlight-python"><pre>$ python3 -m postgresql.bin.pg_python -h localhost -W | ||
| Password for pg_python[pq://jwp@localhost:5432]: | ||
| >>> ps = prepare('select 1') | ||
| >>> ps.first() | ||
| 1 | ||
| >>> c = ps() | ||
| >>> c.read() | ||
| [(1,)] | ||
| >>> ps.close() | ||
| >>> import sys | ||
| >>> sys.exit(0)</pre> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="postgresql-bin-pg-dotconf"> | ||
| <h2>postgresql.bin.pg_dotconf<a class="headerlink" href="#postgresql-bin-pg-dotconf" title="Permalink to this headline">¶</a></h2> | ||
| <p>pg_dotconf is used to modify a PostgreSQL cluster’s configuration file. | ||
| It provides a means to apply settings specified from the command line and from a | ||
| file referenced using the <tt class="docutils literal"><span class="pre">-f</span></tt> option.</p> | ||
| <div class="admonition warning"> | ||
| <p class="first admonition-title">Warning</p> | ||
| <p class="last"><tt class="docutils literal"><span class="pre">include</span></tt> directives in configuration files are <em>completely</em> ignored. If | ||
| modification of an included file is desired, the command must be applied to | ||
| that specific file.</p> | ||
| </div> | ||
| <div class="section" id="pg-dotconf-usage"> | ||
| <h3>pg_dotconf Usage<a class="headerlink" href="#pg-dotconf-usage" title="Permalink to this headline">¶</a></h3> | ||
| <p>Usage: postgresql.bin.pg_dotconf [–stdout] [-f filepath] postgresql.conf ([param=val]|[param])*</p> | ||
| <dl class="docutils"> | ||
| <dt>Options:</dt> | ||
| <dd><table class="first last docutils option-list" frame="void" rules="none"> | ||
| <col class="option" /> | ||
| <col class="description" /> | ||
| <tbody valign="top"> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">--version</span></kbd></td> | ||
| <td>show program’s version number and exit</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">-h</span>, <span class="option">--help</span></kbd></td> | ||
| <td>show this help message and exit</td></tr> | ||
| <tr><td class="option-group" colspan="2"> | ||
| <kbd><span class="option">-f <var>SETTINGS</var></span>, <span class="option">--file=<var>SETTINGS</var></span></kbd></td> | ||
| </tr> | ||
| <tr><td> </td><td>A file of settings to <em>apply</em> to the given | ||
| “postgresql.conf”</td></tr> | ||
| <tr><td class="option-group"> | ||
| <kbd><span class="option">--stdout</span></kbd></td> | ||
| <td>Redirect the product to standard output instead of | ||
| writing back to the “postgresql.conf” file</td></tr> | ||
| </tbody> | ||
| </table> | ||
| </dd> | ||
| </dl> | ||
| </div> | ||
| <div class="section" id="examples"> | ||
| <h3>Examples<a class="headerlink" href="#examples" title="Permalink to this headline">¶</a></h3> | ||
| <p>Modifying a simple configuration file:</p> | ||
| <div class="highlight-python"><pre>$ echo "setting = value" >pg.conf | ||
| # change 'setting' | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf setting=newvalue | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| # new settings are appended to the file | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf another_setting=value | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| another_setting = 'value' | ||
| # comment a setting | ||
| $ python3 -m postgresql.bin.pg_dotconf pg.conf another_setting | ||
| $ cat pg.conf | ||
| setting = 'newvalue' | ||
| #another_setting = 'value'</pre> | ||
| </div> | ||
| <p>When a setting is given on the command line, it must been seen as one argument | ||
| to the command, so it’s <em>very</em> important to avoid invocations like:</p> | ||
| <div class="highlight-python"><pre>$ python3 -m postgresql.bin.pg_dotconf pg.conf setting = value | ||
| ERROR: invalid setting, '=' after 'setting' | ||
| HINT: Settings must take the form 'setting=value' or 'setting_name_to_comment'. Settings must also be received as a single argument.</pre> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Commands</a><ul> | ||
| <li><a class="reference internal" href="#postgresql-bin-pg-python">postgresql.bin.pg_python</a><ul> | ||
| <li><a class="reference internal" href="#pg-python-usage">pg_python Usage</a></li> | ||
| <li><a class="reference internal" href="#interactive-console-backslash-commands">Interactive Console Backslash Commands</a></li> | ||
| <li><a class="reference internal" href="#pg-python-examples">pg_python Examples</a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#postgresql-bin-pg-dotconf">postgresql.bin.pg_dotconf</a><ul> | ||
| <li><a class="reference internal" href="#pg-dotconf-usage">pg_dotconf Usage</a></li> | ||
| <li><a class="reference internal" href="#examples">Examples</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="gotchas.html" | ||
| title="previous chapter">Gotchas</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="reference.html" | ||
| title="next chapter">Reference</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/bin.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="reference.html" title="Reference" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="gotchas.html" title="Gotchas" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Changes in v1.0 — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="prev" title="Changes in v1.1" href="changes-v1.1.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="changes-v1.1.html" title="Changes in v1.1" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="changes-in-v1-0"> | ||
| <h1>Changes in v1.0<a class="headerlink" href="#changes-in-v1-0" title="Permalink to this headline">¶</a></h1> | ||
| <div class="section" id="in-development"> | ||
| <h2>1.0.4 in development<a class="headerlink" href="#in-development" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li>Alter how changes are represented in documentation to simplify merging.</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="released-on-2011-09-24"> | ||
| <h2>1.0.3 released on 2011-09-24<a class="headerlink" href="#released-on-2011-09-24" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li>Use raise x from y to generalize exceptions. (Elvis Pranskevichus)</li> | ||
| <li>Alter postgresql.string.quote_ident to always quote. (Elvis Pranskevichus)</li> | ||
| <li>Add postgresql.string.quote_ident_if_necessary (Modification of Elvis Pranskevichus’ patch)</li> | ||
| <li>Many postgresql.string bug fixes (Elvis Pranskevichus)</li> | ||
| <li>Correct ResourceWarnings improving Python 3.2 support. (jwp)</li> | ||
| <li>Add test command to setup.py (Elvis Pranskevichus)</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="released-on-2010-09-18"> | ||
| <h2>1.0.2 released on 2010-09-18<a class="headerlink" href="#released-on-2010-09-18" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li>Add support for DOMAINs in registered composites. (Elvis Pranskevichus)</li> | ||
| <li>Properly raise StopIteration in Cursor.__next__. (Elvis Pranskevichus)</li> | ||
| <li>Add Cluster Management documentation.</li> | ||
| <li>Release savepoints after rolling them back.</li> | ||
| <li>Fix Startup() usage for Python 3.2.</li> | ||
| <li>Emit deprecation warning when ‘gid’ is given to xact().</li> | ||
| <li>Compensate for Python3.2’s ElementTree API changes.</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="released-on-2010-04-24"> | ||
| <h2>1.0.1 released on 2010-04-24<a class="headerlink" href="#released-on-2010-04-24" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li>Fix unpacking of array NULLs. (Elvis Pranskevichus)</li> | ||
| <li>Fix .first()’s handling of counts and commands. | ||
| Bad logic caused zero-counts to return the command tag.</li> | ||
| <li>Don’t interrupt and close a temporal connection if it’s not open.</li> | ||
| <li>Use the Driver’s typio attribute for TypeIO overrides. (Elvis Pranskevichus)</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="released-on-2010-03-27"> | ||
| <h2>1.0 released on 2010-03-27<a class="headerlink" href="#released-on-2010-03-27" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li><strong>DEPRECATION</strong>: Removed 2PC support documentation.</li> | ||
| <li><strong>DEPRECATION</strong>: Removed pg_python and pg_dotconf ‘scripts’. | ||
| They are still accessible by python3 -m postgresql.bin.pg_*</li> | ||
| <li>Add support for binary hstore.</li> | ||
| <li>Add support for user service files.</li> | ||
| <li>Implement a Copy manager for direct connection-to-connection COPY operations.</li> | ||
| <li>Added db.do() method for DO-statement support(convenience method).</li> | ||
| <li>Set the default client_min_messages level to WARNING. | ||
| NOTICEs are often not desired by programmers, and py-postgresql’s | ||
| high verbosity further irritates that case.</li> | ||
| <li>Added postgresql.project module to provide project information. | ||
| Project name, author, version, etc.</li> | ||
| <li>Increased default recvsize and chunksize for improved performance.</li> | ||
| <li>‘D’ messages are special cased as builtins.tuples instead of | ||
| protocol.element3.Tuple</li> | ||
| <li>Alter Statement.chunks() to return chunks of builtins.tuple. Being | ||
| an interface intended for speed, types.Row() impedes its performance.</li> | ||
| <li>Fix handling of infinity values with timestamptz, timestamp, and date. | ||
| [Bug reported by Axel Rau.]</li> | ||
| <li>Correct representation of PostgreSQL ARRAYs by properly recording | ||
| lowerbounds and upperbounds. Internally, sub-ARRAYs have their own | ||
| element lists.</li> | ||
| <li>Implement a NotificationManager for managing the NOTIFYs received | ||
| by a connection. The class can manage NOTIFYs from multiple | ||
| connections, whereas the db.wait() method is tailored for single targets.</li> | ||
| <li>Implement an ALock class for managing advisory locks using the | ||
| threading.Lock APIs. [Feedback from Valentine Gogichashvili]</li> | ||
| <li>Implement reference symbols. Allow libraries to define symbols that | ||
| are used to create queries that inherit the original symbol’s type and | ||
| execution method. <tt class="docutils literal"><span class="pre">db.prepare(db.prepare(...).first())</span></tt></li> | ||
| <li>Fix handling of unix domain sockets by pg.open and driver.connect. | ||
| [Reported by twitter.com/rintavarustus]</li> | ||
| <li>Fix typo/dropped parts of a raise LoadError in .lib. | ||
| [Reported by Vlad Pranskevichus]</li> | ||
| <li>Fix db.tracer and pg_python’s –pq-trace=</li> | ||
| <li>Fix count return from .first() method. Failed to provide an empty | ||
| tuple for the rformats of the bind statement. | ||
| [Reported by dou dou]</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Changes in v1.0</a><ul> | ||
| <li><a class="reference internal" href="#in-development">1.0.4 in development</a></li> | ||
| <li><a class="reference internal" href="#released-on-2011-09-24">1.0.3 released on 2011-09-24</a></li> | ||
| <li><a class="reference internal" href="#released-on-2010-09-18">1.0.2 released on 2010-09-18</a></li> | ||
| <li><a class="reference internal" href="#released-on-2010-04-24">1.0.1 released on 2010-04-24</a></li> | ||
| <li><a class="reference internal" href="#released-on-2010-03-27">1.0 released on 2010-03-27</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="changes-v1.1.html" | ||
| title="previous chapter">Changes in v1.1</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/changes-v1.0.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="changes-v1.1.html" title="Changes in v1.1" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Changes in v1.1 — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Changes in v1.0" href="changes-v1.0.html" /> | ||
| <link rel="prev" title="Reference" href="reference.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="changes-v1.0.html" title="Changes in v1.0" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="reference.html" title="Reference" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="changes-in-v1-1"> | ||
| <h1>Changes in v1.1<a class="headerlink" href="#changes-in-v1-1" title="Permalink to this headline">¶</a></h1> | ||
| <div class="section" id="id1"> | ||
| <h2>1.1.0<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li>Remove two-phase commit interfaces per deprecation in v1.0. | ||
| For proper two phase commit use, a lock manager must be employed that | ||
| the implementation did nothing to accommodate for.</li> | ||
| <li>Add support for unpacking anonymous records (Elvis)</li> | ||
| <li>Support PostgreSQL 9.2 (Elvis)</li> | ||
| <li>Python 3.3 Support (Elvis)</li> | ||
| <li>Add column execution method. (jwp)</li> | ||
| <li>Add one-shot statement interface. Connection.query.* (jwp)</li> | ||
| <li>Modify the inet/cidr support by relying on the ipaddress module introduced in Python 3.3 (Google’s ipaddr project) | ||
| The existing implementation relied on simple str() representation supported by the | ||
| socket module. Unfortunately, MS Windows’ socket library does not appear to support the | ||
| necessary functionality, or Python’s socket module does not expose it. ipaddress fixes | ||
| the problem.</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">The <cite>ipaddress</cite> module is now required for local inet and cidr. While it is | ||
| of “preliminary” status, the ipaddr project has been around for some time and | ||
| well supported. ipaddress appears to be the safest way forward for native | ||
| network types.</p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Changes in v1.1</a><ul> | ||
| <li><a class="reference internal" href="#id1">1.1.0</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="reference.html" | ||
| title="previous chapter">Reference</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="changes-v1.0.html" | ||
| title="next chapter">Changes in v1.0</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/changes-v1.1.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="changes-v1.0.html" title="Changes in v1.0" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="reference.html" title="Reference" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Client Parameters — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Gotchas" href="gotchas.html" /> | ||
| <link rel="prev" title="Categories and Libraries" href="lib.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="gotchas.html" title="Gotchas" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="lib.html" title="Categories and Libraries" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="client-parameters"> | ||
| <h1>Client Parameters<a class="headerlink" href="#client-parameters" title="Permalink to this headline">¶</a></h1> | ||
| <div class="admonition warning"> | ||
| <p class="first admonition-title">Warning</p> | ||
| <p class="last"><strong>The interfaces dealing with optparse are subject to change in 1.0</strong>.</p> | ||
| </div> | ||
| <p>There are various sources of parameters used by PostgreSQL client applications. | ||
| The <cite>postgresql.clientparameters</cite> module provides a means for collecting and | ||
| managing those parameters.</p> | ||
| <p>Connection creation interfaces in <cite>postgresql.driver</cite> are purposefully simple. | ||
| All parameters taken by those interfaces are keywords, and are taken | ||
| literally; if a parameter is not given, it will effectively be <cite>None</cite>. | ||
| libpq-based drivers tend differ as they inherit some default client parameters | ||
| from the environment. Doing this by default is undesirable as it can cause | ||
| trivial failures due to unexpected parameter inheritance. However, using these | ||
| parameters from the environment and other sources are simply expected in <em>some</em> | ||
| cases: <cite>postgresql.open</cite>, <cite>postgresql.bin.pg_python</cite>, and other high-level | ||
| utilities. The <cite>postgresql.clientparameters</cite> module provides a means to collect | ||
| them into one dictionary object for subsequent application to a connection | ||
| creation interface.</p> | ||
| <p><cite>postgresql.clientparameters</cite> is primarily useful to script authors that want to | ||
| provide an interface consistent with PostgreSQL commands like <tt class="docutils literal"><span class="pre">psql</span></tt>.</p> | ||
| <div class="section" id="collecting-parameters"> | ||
| <h2>Collecting Parameters<a class="headerlink" href="#collecting-parameters" title="Permalink to this headline">¶</a></h2> | ||
| <p>The primary entry points in <cite>postgresql.clientparameters</cite> are | ||
| <cite>postgresql.clientparameters.collect</cite> and | ||
| <cite>postgresql.clientparameters.resolve_password</cite>.</p> | ||
| <p>For most purposes, <tt class="docutils literal"><span class="pre">collect</span></tt> will suffice. By default, it will prompt for the | ||
| password if instructed to(<tt class="docutils literal"><span class="pre">-W</span></tt>). Therefore, <tt class="docutils literal"><span class="pre">resolve_password</span></tt> need not be | ||
| used in most cases:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">sys</span> | ||
| <span class="gp">>>> </span><span class="kn">import</span> <span class="nn">postgresql.clientparameters</span> <span class="kn">as</span> <span class="nn">pg_param</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">pg_param</span><span class="o">.</span><span class="n">DefaultParser</span><span class="p">()</span> | ||
| <span class="gp">>>> </span><span class="n">co</span><span class="p">,</span> <span class="n">ca</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">parse_args</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span> | ||
| <span class="gp">>>> </span><span class="n">params</span> <span class="o">=</span> <span class="n">pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">parsed_options</span> <span class="o">=</span> <span class="n">co</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The <cite>postgresql.clientparameters</cite> module is executable, so you can see the | ||
| results of the above snippet by:</p> | ||
| <div class="highlight-python"><pre>$ python -m postgresql.clientparameters -h localhost -U a_db_user -ssearch_path=public | ||
| {'host': 'localhost', | ||
| 'password': None, | ||
| 'port': 5432, | ||
| 'settings': {'search_path': 'public'}, | ||
| 'user': 'a_db_user'}</pre> | ||
| </div> | ||
| <div class="section" id="postgresql-clientparameters-collect"> | ||
| <h3><cite>postgresql.clientparameters.collect</cite><a class="headerlink" href="#postgresql-clientparameters-collect" title="Permalink to this headline">¶</a></h3> | ||
| <p>Build a client parameter dictionary from the environment and parsed command | ||
| line options. The following is a list of keyword arguments that <tt class="docutils literal"><span class="pre">collect</span></tt> will | ||
| accept:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">parsed_options</span></tt></dt> | ||
| <dd>Options parsed by <cite>postgresql.clientparameters.StandardParser</cite> or | ||
| <cite>postgresql.clientparameters.DefaultParser</cite> instances.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">no_defaults</span></tt></dt> | ||
| <dd>When <cite>True</cite>, don’t include defaults like <tt class="docutils literal"><span class="pre">pgpassfile</span></tt> and <tt class="docutils literal"><span class="pre">user</span></tt>. | ||
| Defaults to <cite>False</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">environ</span></tt></dt> | ||
| <dd>Environment variables to extract client parameter variables from. | ||
| Defaults to <cite>os.environ</cite> and expects a <cite>collections.Mapping</cite> interface.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">environ_prefix</span></tt></dt> | ||
| <dd>Environment variable prefix to use. Defaults to “PG”. This allows the | ||
| collection of non-standard environment variables whose keys are partially | ||
| consistent with the standard variants. e.g. “PG_SRC_USER”, “PG_SRC_HOST”, | ||
| etc.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">default_pg_sysconfdir</span></tt></dt> | ||
| <dd>The location of the pg_service.conf file. The <tt class="docutils literal"><span class="pre">PGSYSCONFDIR</span></tt> environment | ||
| variable will override this. When a default installation is present, | ||
| <tt class="docutils literal"><span class="pre">PGINSTALLATION</span></tt>, it should be set to this.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">pg_service_file</span></tt></dt> | ||
| <dd>Explicit location of the service file. This will override the “sysconfdir” | ||
| based path.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">prompt_title</span></tt></dt> | ||
| <dd>Descriptive title to use if a password prompt is needed. <cite>None</cite> to disable | ||
| password resolution entirely. Setting this to <cite>None</cite> will also disable | ||
| pgpassfile lookups, so it is necessary that further processing occurs when | ||
| this is <cite>None</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">parameters</span></tt></dt> | ||
| <dd>Base client parameters to use. These are set after the <em>defaults</em> are | ||
| collected. (The defaults that can be disabled by <tt class="docutils literal"><span class="pre">no_defaults</span></tt>).</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| <p>If <tt class="docutils literal"><span class="pre">prompt_title</span></tt> is not set to <cite>None</cite>, it will prompt for the password when | ||
| instructed to do by the <tt class="docutils literal"><span class="pre">prompt_password</span></tt> key in the parameters:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">postgresql.clientparameters</span> <span class="kn">as</span> <span class="nn">pg_param</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">prompt_title</span> <span class="o">=</span> <span class="s">'my_prompt!'</span><span class="p">,</span> <span class="n">parameters</span> <span class="o">=</span> <span class="p">{</span><span class="s">'prompt_password'</span><span class="p">:</span><span class="bp">True</span><span class="p">})</span> | ||
| <span class="go">Password for my_prompt![pq://jwp@localhost:5432]:</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> | ||
| <span class="go">{'host': 'localhost', 'user': 'jwp', 'password': 'secret', 'port': 5432}</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>If <cite>None</cite>, it will leave the necessary password resolution information in the | ||
| parameters dictionary for <tt class="docutils literal"><span class="pre">resolve_password</span></tt>:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">prompt_title</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">parameters</span> <span class="o">=</span> <span class="p">{</span><span class="s">'prompt_password'</span><span class="p">:</span><span class="bp">True</span><span class="p">})</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> | ||
| <span class="go">{'pgpassfile': '/Users/jwp/.pgpass', 'prompt_password': True, 'host': 'localhost', 'user': 'jwp', 'port': 5432}</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Of course, <tt class="docutils literal"><span class="pre">'prompt_password'</span></tt> is normally specified when <tt class="docutils literal"><span class="pre">parsed_options</span></tt> | ||
| received a <tt class="docutils literal"><span class="pre">-W</span></tt> option from the command line:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">op</span> <span class="o">=</span> <span class="n">pg_param</span><span class="o">.</span><span class="n">DefaultParser</span><span class="p">()</span> | ||
| <span class="gp">>>> </span><span class="n">co</span><span class="p">,</span> <span class="n">ca</span> <span class="o">=</span> <span class="n">op</span><span class="o">.</span><span class="n">parse_args</span><span class="p">([</span><span class="s">'-W'</span><span class="p">])</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">parsed_options</span> <span class="o">=</span> <span class="n">co</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">p</span><span class="o">=</span><span class="n">pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">parsed_options</span> <span class="o">=</span> <span class="n">co</span><span class="p">)</span> | ||
| <span class="go">Password for [pq://jwp@localhost:5432]:</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> | ||
| <span class="go">{'host': 'localhost', 'user': 'jwp', 'password': 'secret', 'port': 5432}</span> | ||
| <span class="go">>>></span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="postgresql-clientparameters-resolve-password"> | ||
| <h3><cite>postgresql.clientparameters.resolve_password</cite><a class="headerlink" href="#postgresql-clientparameters-resolve-password" title="Permalink to this headline">¶</a></h3> | ||
| <p>Resolve the password for the given client parameters dictionary returned by | ||
| <tt class="docutils literal"><span class="pre">collect</span></tt>. By default, this function need not be used as <tt class="docutils literal"><span class="pre">collect</span></tt> will | ||
| resolve the password by default. <cite>resolve_password</cite> accepts the following | ||
| arguments:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">parameters</span></tt></dt> | ||
| <dd>First positional argument. Normalized client parameters dictionary to update | ||
| in-place with the resolved password. If the ‘prompt_password’ key is in | ||
| <tt class="docutils literal"><span class="pre">parameters</span></tt>, it will prompt regardless(normally comes from <tt class="docutils literal"><span class="pre">-W</span></tt>).</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">getpass</span></tt></dt> | ||
| <dd>Function to call to prompt for the password. Defaults to <cite>getpass.getpass</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">prompt_title</span></tt></dt> | ||
| <dd>Additional title to use if a prompt is requested. This can also be specified | ||
| in the <tt class="docutils literal"><span class="pre">parameters</span></tt> as the <tt class="docutils literal"><span class="pre">prompt_title</span></tt> key. This <em>augments</em> the IRI | ||
| display on the prompt. Defaults to an empty string, <tt class="docutils literal"><span class="pre">''</span></tt>.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| <p>The resolution process is effected by the contents of the given <tt class="docutils literal"><span class="pre">parameters</span></tt>. | ||
| Notable keywords:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">prompt_password</span></tt></dt> | ||
| <dd>If present in the given parameters, the user will be prompted for the using | ||
| the given <tt class="docutils literal"><span class="pre">getpass</span></tt> function. This disables the password file lookup | ||
| process.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">prompt_title</span></tt></dt> | ||
| <dd>This states a default prompt title to use. If the <tt class="docutils literal"><span class="pre">prompt_title</span></tt> keyword | ||
| argument is given to <tt class="docutils literal"><span class="pre">resolve_password</span></tt>, this will not be used.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">pgpassfile</span></tt></dt> | ||
| <dd>The PostgreSQL password file to lookup the password in. If the <tt class="docutils literal"><span class="pre">password</span></tt> | ||
| parameter is present, this will not be used.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| <p>When resolution occurs, the <tt class="docutils literal"><span class="pre">prompt_password</span></tt>, <tt class="docutils literal"><span class="pre">prompt_title</span></tt>, and | ||
| <tt class="docutils literal"><span class="pre">pgpassfile</span></tt> keys are <em>removed</em> from the given parameters dictionary:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">p</span><span class="o">=</span><span class="n">pg_param</span><span class="o">.</span><span class="n">collect</span><span class="p">(</span><span class="n">prompt_title</span> <span class="o">=</span> <span class="bp">None</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> | ||
| <span class="go">{'pgpassfile': '/Users/jwp/.pgpass', 'host': 'localhost', 'user': 'jwp', 'port': 5432}</span> | ||
| <span class="gp">>>> </span><span class="n">pg_param</span><span class="o">.</span><span class="n">resolve_password</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">p</span> | ||
| <span class="go">{'host': 'localhost', 'password': 'secret', 'user': 'jwp', 'port': 5432}</span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="defaults"> | ||
| <h2>Defaults<a class="headerlink" href="#defaults" title="Permalink to this headline">¶</a></h2> | ||
| <p>The following is a list of default parameters provided by <tt class="docutils literal"><span class="pre">collect</span></tt> and the | ||
| sources of their values:</p> | ||
| <blockquote> | ||
| <div><table border="1" class="docutils"> | ||
| <colgroup> | ||
| <col width="23%" /> | ||
| <col width="77%" /> | ||
| </colgroup> | ||
| <thead valign="bottom"> | ||
| <tr class="row-odd"><th class="head">Key</th> | ||
| <th class="head">Value</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody valign="top"> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">'user'</span></tt></td> | ||
| <td><cite>getpass.getuser()</cite> or <tt class="docutils literal"><span class="pre">'postgres'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">'host'</span></tt></td> | ||
| <td><cite>postgresql.clientparameters.default_host</cite> (<tt class="docutils literal"><span class="pre">'localhost'</span></tt>)</td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">'port'</span></tt></td> | ||
| <td><cite>postgresql.clientparameters.default_port</cite> (<tt class="docutils literal"><span class="pre">5432</span></tt>)</td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">'pgpassfile'</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">"$HOME/.pgpassfile"</span></tt> or <tt class="docutils literal"><span class="pre">[PGDATA]</span></tt> + <tt class="docutils literal"><span class="pre">'pgpass.conf'</span></tt> (Win32)</td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">'sslcrtfile'</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">[PGDATA]</span></tt> + <tt class="docutils literal"><span class="pre">'postgresql.crt'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">'sslkeyfile'</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">[PGDATA]</span></tt> + <tt class="docutils literal"><span class="pre">'postgresql.key'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">'sslrootcrtfile'</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">[PGDATA]</span></tt> + <tt class="docutils literal"><span class="pre">'root.crt'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">'sslrootcrlfile'</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">[PGDATA]</span></tt> + <tt class="docutils literal"><span class="pre">'root.crl'</span></tt></td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div></blockquote> | ||
| <p><tt class="docutils literal"><span class="pre">[PGDATA]</span></tt> referenced in the above table is a directory whose path is platform | ||
| dependent. On most systems, it is <tt class="docutils literal"><span class="pre">"$HOME/.postgresql"</span></tt>, but on Windows based | ||
| systems it is <tt class="docutils literal"><span class="pre">"%APPDATA%\postgresql"</span></tt></p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">[PGDATA] is <em>not</em> an environment variable.</p> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="postgresql-environment-variables"> | ||
| <span id="pg-envvars"></span><h2>PostgreSQL Environment Variables<a class="headerlink" href="#postgresql-environment-variables" title="Permalink to this headline">¶</a></h2> | ||
| <p>The following is a list of environment variables that will be collected by the | ||
| <cite>postgresql.clientparameter.collect</cite> function using “PG” as the | ||
| <tt class="docutils literal"><span class="pre">environ_prefix</span></tt> and the keyword that it will be mapped to:</p> | ||
| <blockquote> | ||
| <div><table border="1" class="docutils"> | ||
| <colgroup> | ||
| <col width="36%" /> | ||
| <col width="64%" /> | ||
| </colgroup> | ||
| <thead valign="bottom"> | ||
| <tr class="row-odd"><th class="head">Environment Variable</th> | ||
| <th class="head">Keyword</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody valign="top"> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGUSER</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'user'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGDATABASE</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'database'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGHOST</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'host'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGPORT</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'port'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGPASSWORD</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'password'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGSSLMODE</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'sslmode'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGSSLKEY</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'sslkey'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGCONNECT_TIMEOUT</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'connect_timeout'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGREALM</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'kerberos4_realm'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGKRBSRVNAME</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'kerberos5_service'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGPASSFILE</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'pgpassfile'</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGTZ</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'settings'</span> <span class="pre">=</span> <span class="pre">{'timezone':</span> <span class="pre">}</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGDATESTYLE</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'settings'</span> <span class="pre">=</span> <span class="pre">{'datestyle':</span> <span class="pre">}</span></tt></td> | ||
| </tr> | ||
| <tr class="row-odd"><td><tt class="docutils literal"><span class="pre">PGCLIENTENCODING</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'settings'</span> <span class="pre">=</span> <span class="pre">{'client_encoding':</span> <span class="pre">}</span></tt></td> | ||
| </tr> | ||
| <tr class="row-even"><td><tt class="docutils literal"><span class="pre">PGGEQO</span></tt></td> | ||
| <td><tt class="docutils literal"><span class="pre">'settings'</span> <span class="pre">=</span> <span class="pre">{'geqo':</span> <span class="pre">}</span></tt></td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="postgresql-password-file"> | ||
| <span id="pg-passfile"></span><h2>PostgreSQL Password File<a class="headerlink" href="#postgresql-password-file" title="Permalink to this headline">¶</a></h2> | ||
| <p>The password file is a simple newline separated list of <tt class="docutils literal"><span class="pre">:</span></tt> separated fields. It | ||
| is located at <tt class="docutils literal"><span class="pre">$HOME/.pgpass</span></tt> for most systems and at | ||
| <tt class="docutils literal"><span class="pre">%APPDATA%\postgresql\pgpass.conf</span></tt> for Windows based systems. However, the | ||
| <tt class="docutils literal"><span class="pre">PGPASSFILE</span></tt> environment variable may be used to override that location.</p> | ||
| <p>The lines in the file must be in the following form:</p> | ||
| <div class="highlight-python"><pre>hostname:port:database:username:password</pre> | ||
| </div> | ||
| <p>A single asterisk, <tt class="docutils literal"><span class="pre">*</span></tt>, may be used to indicate that any value will match the | ||
| field. However, this only effects fields other than <tt class="docutils literal"><span class="pre">password</span></tt>.</p> | ||
| <p>See <a class="reference external" href="http://www.postgresql.org/docs/current/static/libpq-pgpass.html">http://www.postgresql.org/docs/current/static/libpq-pgpass.html</a> for more | ||
| details.</p> | ||
| <p>Client parameters produced by <tt class="docutils literal"><span class="pre">collect</span></tt> that have not been processed | ||
| by <tt class="docutils literal"><span class="pre">resolve_password</span></tt> will include a <tt class="docutils literal"><span class="pre">'pgpassfile'</span></tt> key. This is the value | ||
| that <tt class="docutils literal"><span class="pre">resolve_password</span></tt> will use to locate the pgpassfile to interrogate if a | ||
| password key is not present and it is not instructed to prompt for a password.</p> | ||
| <div class="admonition warning"> | ||
| <p class="first admonition-title">Warning</p> | ||
| <p class="last">Connection creation interfaces will <em>not</em> resolve <tt class="docutils literal"><span class="pre">'pgpassfile'</span></tt>, so it is | ||
| important that the parameters produced by <tt class="docutils literal"><span class="pre">collect()</span></tt> are properly processed | ||
| before an attempt is made to establish a connection.</p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Client Parameters</a><ul> | ||
| <li><a class="reference internal" href="#collecting-parameters">Collecting Parameters</a><ul> | ||
| <li><a class="reference internal" href="#postgresql-clientparameters-collect"><cite>postgresql.clientparameters.collect</cite></a></li> | ||
| <li><a class="reference internal" href="#postgresql-clientparameters-resolve-password"><cite>postgresql.clientparameters.resolve_password</cite></a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#defaults">Defaults</a></li> | ||
| <li><a class="reference internal" href="#postgresql-environment-variables">PostgreSQL Environment Variables</a></li> | ||
| <li><a class="reference internal" href="#postgresql-password-file">PostgreSQL Password File</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="lib.html" | ||
| title="previous chapter">Categories and Libraries</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="gotchas.html" | ||
| title="next chapter">Gotchas</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/clientparameters.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="gotchas.html" title="Gotchas" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="lib.html" title="Categories and Libraries" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Cluster Management — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Categories and Libraries" href="lib.html" /> | ||
| <link rel="prev" title="Advisory Locks" href="alock.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="lib.html" title="Categories and Libraries" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="alock.html" title="Advisory Locks" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="cluster-management"> | ||
| <span id="id1"></span><h1>Cluster Management<a class="headerlink" href="#cluster-management" title="Permalink to this headline">¶</a></h1> | ||
| <p>py-postgresql provides cluster management tools in order to give the user | ||
| fine-grained control over a PostgreSQL cluster and access to information about an | ||
| installation of PostgreSQL.</p> | ||
| <div class="section" id="installations"> | ||
| <span id="installation"></span><h2>Installations<a class="headerlink" href="#installations" title="Permalink to this headline">¶</a></h2> | ||
| <p><cite>postgresql.installation.Installation</cite> objects are primarily used to | ||
| access PostgreSQL installation information. Normally, they are created using a | ||
| dictionary constructed from the output of the <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-pgconfig.html">pg_config</a> executable:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">postgresql.installation</span> <span class="kn">import</span> <span class="n">Installation</span><span class="p">,</span> <span class="n">pg_config_dictionary</span> | ||
| <span class="n">pg_install</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">(</span><span class="n">pg_config_dictionary</span><span class="p">(</span><span class="s">'/usr/local/pgsql/bin/pg_config'</span><span class="p">))</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The extraction of <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-pgconfig.html">pg_config</a> information is isolated from Installation | ||
| instantiation in order to allow Installations to be created from arbitrary | ||
| dictionaries. This can be useful in cases where the installation layout is | ||
| inconsistent with the standard PostgreSQL installation layout, or if a faux | ||
| Installation needs to be created for testing purposes.</p> | ||
| <div class="section" id="installation-interface-points"> | ||
| <h3>Installation Interface Points<a class="headerlink" href="#installation-interface-points" title="Permalink to this headline">¶</a></h3> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">Installation(info)</span></tt></dt> | ||
| <dd><p class="first">Instantiate an Installation using the given information. Normally, this | ||
| information is extracted from a <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-pgconfig.html">pg_config</a> executable using | ||
| <cite>postgresql.installation.pg_config_dictionary</cite>:</p> | ||
| <div class="last highlight-python"><div class="highlight"><pre><span class="n">info</span> <span class="o">=</span> <span class="n">pg_config_dictionary</span><span class="p">(</span><span class="s">'/usr/local/pgsql/bin/pg_config'</span><span class="p">)</span> | ||
| <span class="n">pg_install</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">(</span><span class="n">info</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Installation.version</span></tt></dt> | ||
| <dd><p class="first">The installation’s version string:</p> | ||
| <div class="last highlight-python"><div class="highlight"><pre><span class="n">pg_install</span><span class="o">.</span><span class="n">version</span> | ||
| <span class="s">'PostgreSQL 9.0devel'</span> | ||
| </pre></div> | ||
| </div> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Installation.version_info</span></tt></dt> | ||
| <dd><p class="first">A tuple containing the version’s <tt class="docutils literal"><span class="pre">(major,</span> <span class="pre">minor,</span> <span class="pre">patch,</span> <span class="pre">state,</span> <span class="pre">level)</span></tt>. | ||
| Where <tt class="docutils literal"><span class="pre">major</span></tt>, <tt class="docutils literal"><span class="pre">minor</span></tt>, <tt class="docutils literal"><span class="pre">patch</span></tt>, and <tt class="docutils literal"><span class="pre">level</span></tt> are <cite>int</cite> objects, and | ||
| <tt class="docutils literal"><span class="pre">state</span></tt> is a <cite>str</cite> object:</p> | ||
| <div class="last highlight-python"><div class="highlight"><pre><span class="n">pg_install</span><span class="o">.</span><span class="n">version_info</span> | ||
| <span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s">'devel'</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Installation.ssl</span></tt></dt> | ||
| <dd>A <cite>bool</cite> indicating whether or not the installation has SSL support.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Installation.configure_options</span></tt></dt> | ||
| <dd><p class="first">The options given to the <tt class="docutils literal"><span class="pre">configure</span></tt> script that built the installation. The | ||
| options are represented using a dictionary object whose keys are normalized | ||
| long option names, and whose values are the option’s argument. If the option | ||
| takes no argument, <cite>True</cite> will be used as the value.</p> | ||
| <p>The normalization of the long option names consists of removing the preceding | ||
| dashes, lowering the string, and replacing any dashes with underscores. For | ||
| instance, <tt class="docutils literal"><span class="pre">--enable-debug</span></tt> will be <tt class="docutils literal"><span class="pre">enable_debug</span></tt>:</p> | ||
| <div class="last highlight-python"><div class="highlight"><pre><span class="n">pg_install</span><span class="o">.</span><span class="n">configure_options</span> | ||
| <span class="p">{</span><span class="s">'enable_debug'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> <span class="s">'with_libxml'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> | ||
| <span class="s">'enable_cassert'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> <span class="s">'with_libedit_preferred'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> | ||
| <span class="s">'prefix'</span><span class="p">:</span> <span class="s">'/src/build/pg90'</span><span class="p">,</span> <span class="s">'with_openssl'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> | ||
| <span class="s">'enable_integer_datetimes'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> <span class="s">'enable_depend'</span><span class="p">:</span> <span class="bp">True</span><span class="p">}</span> | ||
| </pre></div> | ||
| </div> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Installation.paths</span></tt></dt> | ||
| <dd><p class="first">The paths of the installation as a dictionary where the keys are the path | ||
| identifiers and the values are the absolute file system paths. For instance, | ||
| <tt class="docutils literal"><span class="pre">'bindir'</span></tt> is associated with <tt class="docutils literal"><span class="pre">$PREFIX/bin</span></tt>, <tt class="docutils literal"><span class="pre">'libdir'</span></tt> is associated | ||
| with <tt class="docutils literal"><span class="pre">$PREFIX/lib</span></tt>, etc. The paths included in this dictionary are | ||
| listed on the class’ attributes: <cite>Installation.pg_directories</cite> and | ||
| <cite>Installation.pg_executables</cite>.</p> | ||
| <p>The keys that point to installation directories are: <tt class="docutils literal"><span class="pre">bindir</span></tt>, <tt class="docutils literal"><span class="pre">docdir</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">includedir</span></tt>, <tt class="docutils literal"><span class="pre">pkgincludedir</span></tt>, <tt class="docutils literal"><span class="pre">includedir_server</span></tt>, <tt class="docutils literal"><span class="pre">libdir</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">pkglibdir</span></tt>, <tt class="docutils literal"><span class="pre">localedir</span></tt>, <tt class="docutils literal"><span class="pre">mandir</span></tt>, <tt class="docutils literal"><span class="pre">sharedir</span></tt>, and <tt class="docutils literal"><span class="pre">sysconfdir</span></tt>.</p> | ||
| <p>The keys that point to installation executables are: <tt class="docutils literal"><span class="pre">pg_config</span></tt>, <tt class="docutils literal"><span class="pre">psql</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">initdb</span></tt>, <tt class="docutils literal"><span class="pre">pg_resetxlog</span></tt>, <tt class="docutils literal"><span class="pre">pg_controldata</span></tt>, <tt class="docutils literal"><span class="pre">clusterdb</span></tt>, <tt class="docutils literal"><span class="pre">pg_ctl</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">pg_dump</span></tt>, <tt class="docutils literal"><span class="pre">pg_dumpall</span></tt>, <tt class="docutils literal"><span class="pre">postgres</span></tt>, <tt class="docutils literal"><span class="pre">postmaster</span></tt>, <tt class="docutils literal"><span class="pre">reindexdb</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">vacuumdb</span></tt>, <tt class="docutils literal"><span class="pre">ipcclean</span></tt>, <tt class="docutils literal"><span class="pre">createdb</span></tt>, <tt class="docutils literal"><span class="pre">ecpg</span></tt>, <tt class="docutils literal"><span class="pre">createuser</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">createlang</span></tt>, <tt class="docutils literal"><span class="pre">droplang</span></tt>, <tt class="docutils literal"><span class="pre">dropuser</span></tt>, and <tt class="docutils literal"><span class="pre">pg_restore</span></tt>.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">If the executable does not exist, the value will be <cite>None</cite> instead | ||
| of an absoluate path.</p> | ||
| </div> | ||
| <p>To get the path to the <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-psql.html">psql</a> executable:</p> | ||
| <div class="last highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">postgresql.installation</span> <span class="kn">import</span> <span class="n">Installation</span> | ||
| <span class="n">pg_install</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">(</span><span class="s">'/usr/local/pgsql/bin/pg_config'</span><span class="p">)</span> | ||
| <span class="n">psql_path</span> <span class="o">=</span> <span class="n">pg_install</span><span class="o">.</span><span class="n">paths</span><span class="p">[</span><span class="s">'psql'</span><span class="p">]</span> | ||
| </pre></div> | ||
| </div> | ||
| </dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="clusters"> | ||
| <h2>Clusters<a class="headerlink" href="#clusters" title="Permalink to this headline">¶</a></h2> | ||
| <p><cite>postgresql.cluster.Cluster</cite> is the class used to manage a PostgreSQL | ||
| cluster–a data directory created by <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-initdb.html">initdb</a>. A Cluster represents a data | ||
| directory with respect to a given installation of PostgreSQL, so | ||
| creating a <cite>postgresql.cluster.Cluster</cite> object requires a | ||
| <cite>postgresql.installation.Installation</cite>, and a | ||
| file system path to the data directory.</p> | ||
| <p>In part, a <cite>postgresql.cluster.Cluster</cite> is the Python programmer’s variant of | ||
| the <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-pg-ctl.html">pg_ctl</a> command. However, it goes beyond the basic process control | ||
| functionality and extends into initialization and configuration as well.</p> | ||
| <p>A Cluster manages the server process using the <cite>subprocess</cite> module and | ||
| signals. The <cite>subprocess.Popen</cite> object, <tt class="docutils literal"><span class="pre">Cluster.daemon_process</span></tt>, is | ||
| retained when the Cluster starts the server process itself. This gives | ||
| the Cluster access to the result code of server process when it exits, and the | ||
| ability to redirect stderr and stdout to a parameterized file object using | ||
| subprocess features.</p> | ||
| <p>Despite its use of <cite>subprocess</cite>, Clusters can control a server process | ||
| that was <em>not</em> started by the Cluster’s <tt class="docutils literal"><span class="pre">start</span></tt> method.</p> | ||
| <div class="section" id="initializing-clusters"> | ||
| <h3>Initializing Clusters<a class="headerlink" href="#initializing-clusters" title="Permalink to this headline">¶</a></h3> | ||
| <p><cite>postgresql.cluster.Cluster</cite> provides a method for initializing a | ||
| <cite>Cluster</cite>‘s data directory, <tt class="docutils literal"><span class="pre">init</span></tt>. This method provides a Python interface to | ||
| the PostgreSQL <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-initdb.html">initdb</a> command.</p> | ||
| <p><tt class="docutils literal"><span class="pre">init</span></tt> is a regular method and accepts a few keyword parameters. Normally, | ||
| parameters are directly mapped to <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-initdb.html">initdb</a> command options. However, <tt class="docutils literal"><span class="pre">password</span></tt> | ||
| makes use of initdb’s capability to read the superuser’s password from a file. | ||
| To do this, a temporary file is allocated internally by the method:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">postgresql.installation</span> <span class="kn">import</span> <span class="n">Installation</span><span class="p">,</span> <span class="n">pg_config_dictionary</span> | ||
| <span class="kn">from</span> <span class="nn">postgresql.cluster</span> <span class="kn">import</span> <span class="n">Cluster</span> | ||
| <span class="n">pg_install</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">(</span><span class="n">pg_config_dictionary</span><span class="p">(</span><span class="s">'/usr/local/pgsql/bin/pg_config'</span><span class="p">))</span> | ||
| <span class="n">pg_cluster</span> <span class="o">=</span> <span class="n">Cluster</span><span class="p">(</span><span class="n">pg_install</span><span class="p">,</span> <span class="s">'pg_data'</span><span class="p">)</span> | ||
| <span class="n">pg_cluster</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="n">user</span> <span class="o">=</span> <span class="s">'pg'</span><span class="p">,</span> <span class="n">password</span> <span class="o">=</span> <span class="s">'secret'</span><span class="p">,</span> <span class="n">encoding</span> <span class="o">=</span> <span class="s">'utf-8'</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The init method will block until the initdb command is complete. Once | ||
| initialized, the Cluster may be configured.</p> | ||
| </div> | ||
| <div class="section" id="configuring-clusters"> | ||
| <h3>Configuring Clusters<a class="headerlink" href="#configuring-clusters" title="Permalink to this headline">¶</a></h3> | ||
| <p>A Cluster’s <a class="reference external" href="http://www.postgresql.org/docs/current/static/runtime-config.html">configuration file</a> can be manipulated using the | ||
| <cite>Cluster.settings</cite> mapping. The mapping’s methods will always access the | ||
| configuration file, so it may be desirable to cache repeat reads. Also, if | ||
| multiple settings are being applied, using the <tt class="docutils literal"><span class="pre">update()</span></tt> method may be | ||
| important to avoid writing the entire file multiple times:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="n">pg_cluster</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s">'listen_addresses'</span> <span class="p">:</span> <span class="s">'localhost'</span><span class="p">,</span> <span class="s">'port'</span> <span class="p">:</span> <span class="s">'6543'</span><span class="p">})</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Similarly, to avoid opening and reading the entire file multiple times, | ||
| <cite>Cluster.settings.getset</cite> should be used to retrieve multiple settings:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="n">d</span> <span class="o">=</span> <span class="n">pg_cluster</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">getset</span><span class="p">(</span><span class="nb">set</span><span class="p">((</span><span class="s">'listen_addresses'</span><span class="p">,</span> <span class="s">'port'</span><span class="p">)))</span> | ||
| <span class="n">d</span> | ||
| <span class="p">{</span><span class="s">'listen_addresses'</span> <span class="p">:</span> <span class="s">'localhost'</span><span class="p">,</span> <span class="s">'port'</span> <span class="p">:</span> <span class="s">'6543'</span><span class="p">}</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Values contained in <tt class="docutils literal"><span class="pre">settings</span></tt> are always Python strings:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="k">assert</span> <span class="n">pg_cluster</span><span class="o">.</span><span class="n">settings</span><span class="p">[</span><span class="s">'max_connections'</span><span class="p">]</span><span class="o">.</span><span class="n">__class__</span> <span class="ow">is</span> <span class="nb">str</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The <tt class="docutils literal"><span class="pre">postgresql.conf</span></tt> file is only one part of the server configuration. | ||
| Structured access and manipulation of the <a class="reference external" href="http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html">pg_hba</a> file is not | ||
| supported. Clusters only provide the file path to the <a class="reference external" href="http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html">pg_hba</a> file:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="n">hba</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">pg_cluster</span><span class="o">.</span><span class="n">hba_file</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>If the configuration of the Cluster is altered while the server process is | ||
| running, it may be necessary to signal the process that configuration changes | ||
| have been made. This signal can be sent using the <tt class="docutils literal"><span class="pre">Cluster.reload()</span></tt> method. | ||
| <tt class="docutils literal"><span class="pre">Cluster.reload()</span></tt> will send a SIGHUP signal to the server process. However, | ||
| not all changes to configuration settings can go into effect after calling | ||
| <tt class="docutils literal"><span class="pre">Cluster.reload()</span></tt>. In those cases, the server process will need to be | ||
| shutdown and started again.</p> | ||
| </div> | ||
| <div class="section" id="controlling-clusters"> | ||
| <h3>Controlling Clusters<a class="headerlink" href="#controlling-clusters" title="Permalink to this headline">¶</a></h3> | ||
| <p>The server process of a Cluster object can be controlled with the <tt class="docutils literal"><span class="pre">start()</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">stop()</span></tt>, <tt class="docutils literal"><span class="pre">shutdown()</span></tt>, <tt class="docutils literal"><span class="pre">kill()</span></tt>, and <tt class="docutils literal"><span class="pre">restart()</span></tt> methods. | ||
| These methods start the server process, signal the server process, or, in the | ||
| case of restart, a combination of the two.</p> | ||
| <p>When a Cluster starts the server process, it’s ran as a subprocess. Therefore, | ||
| if the current process exits, the server process will exit as well. <tt class="docutils literal"><span class="pre">start()</span></tt> | ||
| does <em>not</em> automatically daemonize the server process.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">Under Microsoft Windows, above does not hold true. The server process | ||
| will continue running despite the exit of the parent process.</p> | ||
| </div> | ||
| <p>To terminate a server process, one of these three methods should be called: | ||
| <tt class="docutils literal"><span class="pre">stop</span></tt>, <tt class="docutils literal"><span class="pre">shutdown</span></tt>, or <tt class="docutils literal"><span class="pre">kill</span></tt>. <tt class="docutils literal"><span class="pre">stop</span></tt> is a graceful shutdown and will | ||
| <em>wait for all clients to disconnect</em> before shutting down. <tt class="docutils literal"><span class="pre">shutdown</span></tt> will | ||
| close any open connections and safely shutdown the server process. | ||
| <tt class="docutils literal"><span class="pre">kill</span></tt> will immediately terminate the server process leading to recovery upon | ||
| starting the server process again.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">Using <tt class="docutils literal"><span class="pre">kill</span></tt> may cause shared memory to be leaked.</p> | ||
| </div> | ||
| <p>Normally, <cite>Cluster.shutdown</cite> is the appropriate way to terminate a server | ||
| process.</p> | ||
| </div> | ||
| <div class="section" id="cluster-interface-points"> | ||
| <h3>Cluster Interface Points<a class="headerlink" href="#cluster-interface-points" title="Permalink to this headline">¶</a></h3> | ||
| <p>Methods and properties available on <cite>postgresql.cluster.Cluster</cite> instances:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster(installation,</span> <span class="pre">data_directory)</span></tt></dt> | ||
| <dd><p class="first">Create a <cite>postgresql.cluster.Cluster</cite> object for the specified | ||
| <cite>postgresql.installation.Installation</cite>, and <tt class="docutils literal"><span class="pre">data_directory</span></tt>.</p> | ||
| <p class="last">The <tt class="docutils literal"><span class="pre">data_directory</span></tt> must be an absoluate file system path. The directory | ||
| does <em>not</em> need to exist. The <tt class="docutils literal"><span class="pre">init()</span></tt> method may later be used to create | ||
| the cluster.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.installation</span></tt></dt> | ||
| <dd>The Cluster’s <cite>postgresql.installation.Installation</cite> instance.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.data_directory</span></tt></dt> | ||
| <dd>The absolute path to the PostgreSQL data directory. | ||
| This directory may not exist.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.init([encoding</span> <span class="pre">=</span> <span class="pre">None[,</span> <span class="pre">user</span> <span class="pre">=</span> <span class="pre">None[,</span> <span class="pre">password</span> <span class="pre">=</span> <span class="pre">None]]])</span></tt></dt> | ||
| <dd><p class="first">Run the <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-initdb.html">initdb</a> executable of the configured installation to initialize the | ||
| cluster at the configured data directory, <cite>Cluster.data_directory</cite>.</p> | ||
| <p><tt class="docutils literal"><span class="pre">encoding</span></tt> is mapped to <tt class="docutils literal"><span class="pre">-E</span></tt>, the default database encoding. By default, | ||
| the encoding is determined from the environment’s locale.</p> | ||
| <p><tt class="docutils literal"><span class="pre">user</span></tt> is mapped to <tt class="docutils literal"><span class="pre">-U</span></tt>, the database superuser name. By default, the | ||
| current user’s name.</p> | ||
| <p><tt class="docutils literal"><span class="pre">password</span></tt> is ultimately mapped to <tt class="docutils literal"><span class="pre">--pwfile</span></tt>. The argument given to the | ||
| long option is actually a path to the temporary file that holds the given | ||
| password.</p> | ||
| <p>Raises <cite>postgresql.cluster.InitDBError</cite> when <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-initdb.html">initdb</a> returns a non-zero result | ||
| code.</p> | ||
| <p class="last">Raises <cite>postgresql.cluster.ClusterInitializationError</cite> when there is no | ||
| <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-initdb.html">initdb</a> in the Installation.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.initialized()</span></tt></dt> | ||
| <dd>Whether or not the data directory exists, <em>and</em> if it looks like a PostgreSQL | ||
| data directory. Meaning, the directory must contain a <tt class="docutils literal"><span class="pre">postgresql.conf</span></tt> file | ||
| and a <tt class="docutils literal"><span class="pre">base</span></tt> directory.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.drop()</span></tt></dt> | ||
| <dd>Shutdown the Cluster’s server process and completely remove the | ||
| <cite>Cluster.data_directory</cite> from the file system.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.pid()</span></tt></dt> | ||
| <dd>The server’s process identifier as a Python <cite>int</cite>. <cite>None</cite> if there is no | ||
| server process running. | ||
| This is a method rather than a property as it may read the PID from a file | ||
| in cases where the server process was not started by the Cluster.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.start([logfile</span> <span class="pre">=</span> <span class="pre">None[,</span> <span class="pre">settings</span> <span class="pre">=</span> <span class="pre">None]])</span></tt></dt> | ||
| <dd><p class="first">Start the PostgreSQL server process for the Cluster if it is not | ||
| already running. This will execute <a class="reference external" href="http://www.postgresql.org/docs/current/static/app-postgres.html">postgres</a> as a subprocess.</p> | ||
| <p>If <tt class="docutils literal"><span class="pre">logfile</span></tt>, an opened and writable file object, is given, stderr and | ||
| stdout will be redirected to that file. By default, both stderr and stdout are | ||
| closed.</p> | ||
| <p class="last">If <tt class="docutils literal"><span class="pre">settings</span></tt> is given, the mapping or sequence of pairs will be used as | ||
| long options to the subprocess. For each item, <tt class="docutils literal"><span class="pre">--{key}={value}</span></tt> will be | ||
| given as an argument to the subprocess.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.running()</span></tt></dt> | ||
| <dd>Whether or not the cluster’s server process is running. Returns <cite>True</cite> or | ||
| <cite>False</cite>. Even if <cite>True</cite> is returned, it does <em>not</em> mean that the server | ||
| process is ready to accept connections.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.ready_for_connections()</span></tt></dt> | ||
| <dd><p class="first">Whether or not the Cluster is ready to accept connections. Usually called | ||
| after <cite>Cluster.start</cite>.</p> | ||
| <p class="last">Returns <cite>True</cite> when the Cluster can accept connections, <cite>False</cite> when it | ||
| cannot, and <cite>None</cite> if the Cluster’s server process is not running at all.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.wait_until_started([timeout</span> <span class="pre">=</span> <span class="pre">10[,</span> <span class="pre">delay</span> <span class="pre">=</span> <span class="pre">0.05]])</span></tt></dt> | ||
| <dd><p class="first">Blocks the process until the cluster is identified as being ready for | ||
| connections. Usually called after <tt class="docutils literal"><span class="pre">Cluster.start()</span></tt>.</p> | ||
| <p>Raises <cite>postgresql.cluster.ClusterNotRunningError</cite> if the server process is | ||
| not running at all.</p> | ||
| <p>Raises <cite>postgresql.cluster.ClusterTimeoutError</cite> if | ||
| <cite>Cluster.ready_for_connections()</cite> does not return <cite>True</cite> within the given | ||
| <cite>timeout</cite> period.</p> | ||
| <p>Raises <cite>postgresql.cluster.ClusterStartupError</cite> if the server process | ||
| terminates while polling for readiness.</p> | ||
| <p class="last"><tt class="docutils literal"><span class="pre">timeout</span></tt> and <tt class="docutils literal"><span class="pre">delay</span></tt> are both in seconds. Where <tt class="docutils literal"><span class="pre">timeout</span></tt> is the | ||
| maximum time to wait for the Cluster to be ready for connections, and | ||
| <tt class="docutils literal"><span class="pre">delay</span></tt> is the time to sleep between calls to | ||
| <cite>Cluster.ready_for_connections()</cite>.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.stop()</span></tt></dt> | ||
| <dd>Signal the cluster to shutdown when possible. The <em>server</em> will wait for all | ||
| clients to disconnect before shutting down.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.shutdown()</span></tt></dt> | ||
| <dd>Signal the cluster to shutdown immediately. Any open client connections will | ||
| be closed.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.kill()</span></tt></dt> | ||
| <dd>Signal the absolute destruction of the server process(SIGKILL). | ||
| <em>This will require recovery when the cluster is started again.</em> | ||
| <em>Shared memory may be leaked.</em></dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.wait_until_stopped([timeout</span> <span class="pre">=</span> <span class="pre">10[,</span> <span class="pre">delay</span> <span class="pre">=</span> <span class="pre">0.05]])</span></tt></dt> | ||
| <dd><p class="first">Blocks the process until the cluster is identified as being shutdown. Usually | ||
| called after <cite>Cluster.stop</cite> or <cite>Cluster.shutdown</cite>.</p> | ||
| <p class="last">Raises <cite>postgresql.cluster.ClusterTimeoutError</cite> if | ||
| <cite>Cluster.ready_for_connections</cite> does not return <cite>None</cite> within the given | ||
| <cite>timeout</cite> period.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.reload()</span></tt></dt> | ||
| <dd>Signal the server that it should reload its configuration files(SIGHUP). | ||
| Usually called after manipulating <cite>Cluster.settings</cite> or modifying the | ||
| contents of <cite>Cluster.hba_file</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.restart([logfile</span> <span class="pre">=</span> <span class="pre">None[,</span> <span class="pre">settings</span> <span class="pre">=</span> <span class="pre">None[,</span> <span class="pre">timeout</span> <span class="pre">=</span> <span class="pre">10]]])</span></tt></dt> | ||
| <dd><p class="first">Stop the server process, wait until it is stopped, start the server | ||
| process, and wait until it has started.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">This calls <tt class="docutils literal"><span class="pre">Cluster.stop()</span></tt>, so it will wait until clients | ||
| disconnect before starting up again.</p> | ||
| </div> | ||
| <p class="last">The <tt class="docutils literal"><span class="pre">logfile</span></tt> and <tt class="docutils literal"><span class="pre">settings</span></tt> parameters will be given to <cite>Cluster.start</cite>. | ||
| <tt class="docutils literal"><span class="pre">timeout</span></tt> will be given to <cite>Cluster.wait_until_stopped</cite> and | ||
| <cite>Cluster.wait_until_started</cite>.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.settings</span></tt></dt> | ||
| <dd><p class="first">A <cite>collections.Mapping</cite> interface to the <tt class="docutils literal"><span class="pre">postgresql.conf</span></tt> file of the | ||
| cluster.</p> | ||
| <p class="last">A notable extension to the mapping interface is the <tt class="docutils literal"><span class="pre">getset</span></tt> method. This | ||
| method will return a dictionary object containing the settings whose names | ||
| were contained in the <cite>set</cite> object given to the method. | ||
| This method should be used when multiple settings need to be retrieved from | ||
| the configuration file.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.hba_file</span></tt></dt> | ||
| <dd>The path to the cluster’s <a class="reference external" href="http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html">pg_hba</a> file. This property respects the HBA file | ||
| location setting in <tt class="docutils literal"><span class="pre">postgresql.conf</span></tt>. Usually, <tt class="docutils literal"><span class="pre">$PGDATA/pg_hba.conf</span></tt>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.daemon_path</span></tt></dt> | ||
| <dd>The path to the executable to use to start the server process.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">Cluster.daemon_process</span></tt></dt> | ||
| <dd>The <cite>subprocess.Popen</cite> instance of the server process. <cite>None</cite> if the server | ||
| process was not started or was not started using the Cluster object.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Cluster Management</a><ul> | ||
| <li><a class="reference internal" href="#installations">Installations</a><ul> | ||
| <li><a class="reference internal" href="#installation-interface-points">Installation Interface Points</a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#clusters">Clusters</a><ul> | ||
| <li><a class="reference internal" href="#initializing-clusters">Initializing Clusters</a></li> | ||
| <li><a class="reference internal" href="#configuring-clusters">Configuring Clusters</a></li> | ||
| <li><a class="reference internal" href="#controlling-clusters">Controlling Clusters</a></li> | ||
| <li><a class="reference internal" href="#cluster-interface-points">Cluster Interface Points</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="alock.html" | ||
| title="previous chapter">Advisory Locks</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="lib.html" | ||
| title="next chapter">Categories and Libraries</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/cluster.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="lib.html" title="Categories and Libraries" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="alock.html" title="Advisory Locks" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Copy Management — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Notification Management" href="notifyman.html" /> | ||
| <link rel="prev" title="Driver" href="driver.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="notifyman.html" title="Notification Management" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="driver.html" title="Driver" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="copy-management"> | ||
| <span id="pg-copyman"></span><h1>Copy Management<a class="headerlink" href="#copy-management" title="Permalink to this headline">¶</a></h1> | ||
| <p>The <cite>postgresql.copyman</cite> module provides a way to quickly move COPY data coming | ||
| from one connection to many connections. Alternatively, it can be sourced | ||
| by arbitrary iterators and target arbitrary callables.</p> | ||
| <p>Statement execution methods offer a way for running COPY operations | ||
| with iterators, but the cost of allocating objects for each row is too | ||
| significant for transferring gigabytes of COPY data from one connection to | ||
| another. The interfaces available on statement objects are primarily intended to | ||
| be used when transferring COPY data to and from arbitrary Python | ||
| objects.</p> | ||
| <p>Direct connection-to-connection COPY operations can be performed using the | ||
| high-level <cite>postgresql.copyman.transfer</cite> function:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql</span> <span class="kn">import</span> <span class="n">copyman</span> | ||
| <span class="gp">>>> </span><span class="n">send_stmt</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">destination</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"CREATE TEMP TABLE loading_table (i int8)"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receive_stmt</span> <span class="o">=</span> <span class="n">destination</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY loading_table FROM STDIN"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">total_rows</span><span class="p">,</span> <span class="n">total_bytes</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">transfer</span><span class="p">(</span><span class="n">send_stmt</span><span class="p">,</span> <span class="n">receive_stmt</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>However, if more control is needed, the <cite>postgresql.copyman.CopyManager</cite> class | ||
| should be used directly.</p> | ||
| <div class="section" id="copy-managers"> | ||
| <h2>Copy Managers<a class="headerlink" href="#copy-managers" title="Permalink to this headline">¶</a></h2> | ||
| <p>The <cite>postgresql.copyman.CopyManager</cite> class manages the Producer and the | ||
| Receivers involved in a COPY operation. Normally, | ||
| <cite>postgresql.copyman.StatementProducer</cite> and | ||
| <cite>postgresql.copyman.StatementReceiver</cite> instances. Naturally, a Producer is the | ||
| object that produces the COPY data to be given to the Manager’s Receivers.</p> | ||
| <p>Using a Manager directly means that there is a need for more control over | ||
| the operation. The Manager is both a context manager and an iterator. The | ||
| context manager interfaces handle initialization and finalization of the COPY | ||
| state, and the iterator provides an event loop emitting information about the | ||
| amount of COPY data transferred this cycle. Normal usage takes the form:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql</span> <span class="kn">import</span> <span class="n">copyman</span> | ||
| <span class="gp">>>> </span><span class="n">send_stmt</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">destination</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"CREATE TEMP TABLE loading_table (i int8)"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receive_stmt</span> <span class="o">=</span> <span class="n">destination</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY loading_table FROM STDIN"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">producer</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">StatementProducer</span><span class="p">(</span><span class="n">send_stmt</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receiver</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">StatementReceiver</span><span class="p">(</span><span class="n">receive_stmt</span><span class="p">)</span> | ||
| <span class="go">>>></span> | ||
| <span class="gp">>>> </span><span class="k">with</span> <span class="n">source</span><span class="o">.</span><span class="n">xact</span><span class="p">(),</span> <span class="n">destination</span><span class="o">.</span><span class="n">xact</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="k">with</span> <span class="n">copyman</span><span class="o">.</span><span class="n">CopyManager</span><span class="p">(</span><span class="n">producer</span><span class="p">,</span> <span class="n">receiver</span><span class="p">)</span> <span class="k">as</span> <span class="n">copy</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">for</span> <span class="n">num_messages</span><span class="p">,</span> <span class="n">num_bytes</span> <span class="ow">in</span> <span class="n">copy</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="n">update_rate</span><span class="p">(</span><span class="n">num_bytes</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>As an alternative to a for-loop inside a with-statement block, the <cite>run</cite> method | ||
| can be called to perform the operation:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="k">with</span> <span class="n">source</span><span class="o">.</span><span class="n">xact</span><span class="p">(),</span> <span class="n">destination</span><span class="o">.</span><span class="n">xact</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="n">copyman</span><span class="o">.</span><span class="n">CopyManager</span><span class="p">(</span><span class="n">producer</span><span class="p">,</span> <span class="n">receiver</span><span class="p">)</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>However, there is little benefit beyond using the high-level | ||
| <cite>postgresql.copyman.transfer</cite> function.</p> | ||
| <div class="section" id="manager-interface-points"> | ||
| <h3>Manager Interface Points<a class="headerlink" href="#manager-interface-points" title="Permalink to this headline">¶</a></h3> | ||
| <p>Primarily, the <cite>postgresql.copyman.CopyManager</cite> provides a context manager and | ||
| an iterator for controlling the COPY operation.</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.run()</span></tt></dt> | ||
| <dd>Perform the entire COPY operation.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.__enter__()</span></tt></dt> | ||
| <dd>Start the COPY operation. Connections taking part in the COPY should <strong>not</strong> | ||
| be used until <tt class="docutils literal"><span class="pre">__exit__</span></tt> is ran.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.__exit__(typ,</span> <span class="pre">val,</span> <span class="pre">tb)</span></tt></dt> | ||
| <dd>Finish the COPY operation. Fails in the case of an incomplete | ||
| COPY, or an untrapped exception. Either returns <cite>None</cite> or raises the generalized | ||
| exception, <cite>postgresql.copyman.CopyFail</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.__iter__()</span></tt></dt> | ||
| <dd>Returns the CopyManager instance.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.__next__()</span></tt></dt> | ||
| <dd><p class="first">Transfer the next chunk of COPY data to the receivers. Yields a tuple | ||
| consisting of the number of messages and bytes transferred, | ||
| <tt class="docutils literal"><span class="pre">(num_messages,</span> <span class="pre">num_bytes)</span></tt>. Raises <cite>StopIteration</cite> when complete.</p> | ||
| <p class="last">Raises <cite>postgresql.copyman.ReceiverFault</cite> when a Receiver raises an | ||
| exception. | ||
| Raises <cite>postgresql.copyman.ProducerFault</cite> when the Producer raises an | ||
| exception. The original exception is available via the exception’s | ||
| <tt class="docutils literal"><span class="pre">__context__</span></tt> attribute.</p> | ||
| </dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.reconcile(faulted_receiver)</span></tt></dt> | ||
| <dd>Reconcile a faulted receiver. When a receiver faults, it will no longer | ||
| be in the set of Receivers. This method is used to signal to the manager that the | ||
| problem has been corrected, and the receiver is again ready to receive.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.receivers</span></tt></dt> | ||
| <dd>The <cite>builtins.set</cite> of Receivers involved in the COPY operation.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyManager.producer</span></tt></dt> | ||
| <dd>The Producer emitting the data to be given to the Receivers.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="faults"> | ||
| <h2>Faults<a class="headerlink" href="#faults" title="Permalink to this headline">¶</a></h2> | ||
| <p>The CopyManager generalizes any exceptions that occur during transfer. While | ||
| inside the context manager, <cite>postgresql.copyman.Fault</cite> may be raised if a | ||
| Receiver or a Producer raises an exception. A <cite>postgresql.copyman.ProducerFault</cite> | ||
| in the case of the Producer, and <cite>postgresql.copyman.ReceiverFault</cite> in the case | ||
| of the Receivers.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">Faults are only raised by <cite>postgresql.copyman.CopyManager.__next__</cite>. The | ||
| <tt class="docutils literal"><span class="pre">run()</span></tt> method will only raise <cite>postgresql.copyman.CopyFail</cite>.</p> | ||
| </div> | ||
| <div class="section" id="receiver-faults"> | ||
| <h3>Receiver Faults<a class="headerlink" href="#receiver-faults" title="Permalink to this headline">¶</a></h3> | ||
| <p>The Manager assumes the Fault is fatal to a Receiver, and immediately removes | ||
| it from the set of target receivers. Additionally, if the Fault exception goes | ||
| untrapped, the copy will ultimately fail.</p> | ||
| <p>The Fault exception references the Manager that raised the exception, and the | ||
| actual exceptions that occurred associated with the Receiver that caused them.</p> | ||
| <p>In order to identify the exception that caused a Fault, the <tt class="docutils literal"><span class="pre">faults</span></tt> attribute | ||
| on the <cite>postgresql.copyman.ReceiverFault</cite> must be referenced:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql</span> <span class="kn">import</span> <span class="n">copyman</span> | ||
| <span class="gp">>>> </span><span class="n">send_stmt</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">destination</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"CREATE TEMP TABLE loading_table (i int8)"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receive_stmt</span> <span class="o">=</span> <span class="n">destination</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY loading_table FROM STDIN"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">producer</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">StatementProducer</span><span class="p">(</span><span class="n">send_stmt</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receiver</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">StatementReceiver</span><span class="p">(</span><span class="n">receive_stmt</span><span class="p">)</span> | ||
| <span class="go">>>></span> | ||
| <span class="gp">>>> </span><span class="k">with</span> <span class="n">source</span><span class="o">.</span><span class="n">xact</span><span class="p">(),</span> <span class="n">destination</span><span class="o">.</span><span class="n">xact</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="k">with</span> <span class="n">copyman</span><span class="o">.</span><span class="n">CopyManager</span><span class="p">(</span><span class="n">producer</span><span class="p">,</span> <span class="n">receiver</span><span class="p">)</span> <span class="k">as</span> <span class="n">copy</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">while</span> <span class="n">copy</span><span class="o">.</span><span class="n">receivers</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">try</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">for</span> <span class="n">num_messages</span><span class="p">,</span> <span class="n">num_bytes</span> <span class="ow">in</span> <span class="n">copy</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="n">update_rate</span><span class="p">(</span><span class="n">num_bytes</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="k">break</span> | ||
| <span class="gp">... </span> <span class="k">except</span> <span class="n">copyman</span><span class="o">.</span><span class="n">ReceiverFault</span> <span class="k">as</span> <span class="n">cf</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="c"># Access the original exception using the receiver as the key.</span> | ||
| <span class="gp">... </span> <span class="n">original_exception</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">faults</span><span class="p">[</span><span class="n">receiver</span><span class="p">]</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">unknown_failure</span><span class="p">(</span><span class="n">original_exception</span><span class="p">):</span> | ||
| <span class="gp">... </span> <span class="o">...</span> | ||
| <span class="gp">... </span> <span class="k">raise</span> | ||
| </pre></div> | ||
| </div> | ||
| <div class="section" id="receiverfault-properties"> | ||
| <h4>ReceiverFault Properties<a class="headerlink" href="#receiverfault-properties" title="Permalink to this headline">¶</a></h4> | ||
| <p>The following attributes exist on <cite>postgresql.copyman.ReceiverFault</cite> instances:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">ReceiverFault.manager</span></tt></dt> | ||
| <dd>The subject <cite>postgresql.copyman.CopyManager</cite> instance.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">ReceiverFault.faults</span></tt></dt> | ||
| <dd>A dictionary mapping the Receiver to the exception raised by that Receiver.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="reconciliation"> | ||
| <h4>Reconciliation<a class="headerlink" href="#reconciliation" title="Permalink to this headline">¶</a></h4> | ||
| <p>When a <cite>postgresql.copyman.ReceiverFault</cite> is raised, the Manager immediately | ||
| removes the Receiver so that the COPY operation can continue. Continuation of | ||
| the COPY can occur by trapping the exception and continuing the iteration of the | ||
| Manager. However, if the fault is recoverable, the | ||
| <cite>postgresql.copyman.CopyManager.reconcile</cite> method must be used to reintroduce the | ||
| Receiver into the Manager’s set. Faults must be trapped from within the | ||
| Manager’s context:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">socket</span> | ||
| <span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql</span> <span class="kn">import</span> <span class="n">copyman</span> | ||
| <span class="gp">>>> </span><span class="n">send_stmt</span> <span class="o">=</span> <span class="n">source</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY (SELECT i FROM generate_series(1, 1000000) AS g(i)) TO STDOUT"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">destination</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"CREATE TEMP TABLE loading_table (i int8)"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receive_stmt</span> <span class="o">=</span> <span class="n">destination</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"COPY loading_table FROM STDIN"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">producer</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">StatementProducer</span><span class="p">(</span><span class="n">send_stmt</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">receiver</span> <span class="o">=</span> <span class="n">copyman</span><span class="o">.</span><span class="n">StatementReceiver</span><span class="p">(</span><span class="n">receive_stmt</span><span class="p">)</span> | ||
| <span class="go">>>></span> | ||
| <span class="gp">>>> </span><span class="k">with</span> <span class="n">source</span><span class="o">.</span><span class="n">xact</span><span class="p">(),</span> <span class="n">destination</span><span class="o">.</span><span class="n">xact</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="k">with</span> <span class="n">copyman</span><span class="o">.</span><span class="n">CopyManager</span><span class="p">(</span><span class="n">producer</span><span class="p">,</span> <span class="n">receiver</span><span class="p">)</span> <span class="k">as</span> <span class="n">copy</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">while</span> <span class="n">copy</span><span class="o">.</span><span class="n">receivers</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">try</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">for</span> <span class="n">num_messages</span><span class="p">,</span> <span class="n">num_bytes</span> <span class="ow">in</span> <span class="n">copy</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="n">update_rate</span><span class="p">(</span><span class="n">num_bytes</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="k">except</span> <span class="n">copyman</span><span class="o">.</span><span class="n">ReceiverFault</span> <span class="k">as</span> <span class="n">cf</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">cf</span><span class="o">.</span><span class="n">faults</span><span class="p">[</span><span class="n">receiver</span><span class="p">],</span> <span class="n">socket</span><span class="o">.</span><span class="n">timeout</span><span class="p">):</span> | ||
| <span class="gp">... </span> <span class="n">copy</span><span class="o">.</span><span class="n">reconcile</span><span class="p">(</span><span class="n">receiver</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="k">else</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">raise</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Recovering from Faults does add significant complexity to a COPY operation, | ||
| so, often, it’s best to avoid conditions in which reconciliable Faults may | ||
| occur.</p> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="producer-faults"> | ||
| <h3>Producer Faults<a class="headerlink" href="#producer-faults" title="Permalink to this headline">¶</a></h3> | ||
| <p>Producer faults are normally fatal to the COPY operation and should rarely be | ||
| trapped. However, the Manager makes no state changes when a Producer faults, | ||
| so, unlike Receiver Faults, no reconciliation process is necessary; rather, | ||
| if it’s safe to continue, the Manager’s iterator should continue to be | ||
| processed.</p> | ||
| <div class="section" id="producerfault-properties"> | ||
| <h4>ProducerFault Properties<a class="headerlink" href="#producerfault-properties" title="Permalink to this headline">¶</a></h4> | ||
| <p>The following attributes exist on <cite>postgresql.copyman.ProducerFault</cite> instances:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">ReceiverFault.manager</span></tt></dt> | ||
| <dd>The subject <cite>postgresql.copyman.CopyManager</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">ReceiverFault.__context__</span></tt></dt> | ||
| <dd>The original exception raised by the Producer.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="failures"> | ||
| <h2>Failures<a class="headerlink" href="#failures" title="Permalink to this headline">¶</a></h2> | ||
| <p>When a COPY operation is aborted, either by an exception or by the iterator | ||
| being broken, a <cite>postgresql.copyman.CopyFail</cite> exception will be raised by the | ||
| Manager’s <tt class="docutils literal"><span class="pre">__exit__()</span></tt> method. The <cite>postgresql.copyman.CopyFail</cite> exception | ||
| offers to record any exceptions that occur during the exit of the context | ||
| managers of the Producer and the Receivers.</p> | ||
| <div class="section" id="copyfail-properties"> | ||
| <h3>CopyFail Properties<a class="headerlink" href="#copyfail-properties" title="Permalink to this headline">¶</a></h3> | ||
| <p>The following properties exist on <cite>postgresql.copyman.CopyFail</cite> exceptions:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyFail.manager</span></tt></dt> | ||
| <dd>The Manager whose COPY operation failed.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyFail.receiver_faults</span></tt></dt> | ||
| <dd>A dictionary mapping a <cite>postgresql.copyman.Receiver</cite> to the exception raised | ||
| by that Receiver’s <tt class="docutils literal"><span class="pre">__exit__</span></tt>. <cite>None</cite> if no exceptions were raised by the | ||
| Receivers.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">CopyFail.producer_fault</span></tt></dt> | ||
| <dd>The exception Raised by the <cite>postgresql.copyman.Producer</cite>. <cite>None</cite> if none.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="producers"> | ||
| <h2>Producers<a class="headerlink" href="#producers" title="Permalink to this headline">¶</a></h2> | ||
| <p>The following Producers are available:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">postgresql.copyman.StatementProducer(postgresql.api.Statement)</span></tt></dt> | ||
| <dd>Given a Statement producing COPY data, construct a Producer.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">postgresql.copyman.IteratorProducer(collections.Iterator)</span></tt></dt> | ||
| <dd>Given an Iterator producing <em>chunks</em> of COPY lines, construct a Producer to | ||
| manage the data coming from the iterator.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="receivers"> | ||
| <h2>Receivers<a class="headerlink" href="#receivers" title="Permalink to this headline">¶</a></h2> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">postgresql.copyman.StatementReceiver(postgresql.api.Statement)</span></tt></dt> | ||
| <dd>Given a Statement producing COPY data, construct a Producer.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">postgresql.copyman.CallReceiver(callable)</span></tt></dt> | ||
| <dd>Given a callable, construct a Receiver that will transmit COPY data in chunks | ||
| of lines. That is, the callable will be given a list of COPY lines for each | ||
| transfer cycle.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="terminology"> | ||
| <h2>Terminology<a class="headerlink" href="#terminology" title="Permalink to this headline">¶</a></h2> | ||
| <p>The following terms are regularly used to describe the implementation and | ||
| processes of the <cite>postgresql.copyman</cite> module:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt>Manager</dt> | ||
| <dd>The object used to manage data coming from a Producer and being given to the | ||
| Receivers. It also manages the necessary initialization and finalization steps | ||
| required by those factors.</dd> | ||
| <dt>Producer</dt> | ||
| <dd>The object used to produce the COPY data to be given to the Receivers. The | ||
| source.</dd> | ||
| <dt>Receiver</dt> | ||
| <dd>An object that consumes COPY data. A target.</dd> | ||
| <dt>Fault</dt> | ||
| <dd>Specifically, <cite>postgresql.copyman.Fault</cite> exceptions. A Fault is raised | ||
| when a Receiver or a Producer raises an exception during the COPY operation.</dd> | ||
| <dt>Reconciliation</dt> | ||
| <dd>Generally, the steps performed by the “reconcile” method on | ||
| <cite>postgresql.copyman.CopyManager</cite> instances. More precisely, the | ||
| necessary steps for a Receiver’s reintroduction into the COPY operation after | ||
| a Fault.</dd> | ||
| <dt>Failed Copy</dt> | ||
| <dd>A failed copy is an aborted COPY operation. This occurs in situations of | ||
| untrapped exceptions or an incomplete COPY. Specifically, the COPY will be | ||
| noted as failed in cases where the Manager’s iterator is <em>not</em> ran until | ||
| exhaustion.</dd> | ||
| <dt>Realignment</dt> | ||
| <dd>The process of providing compensating data to the Receivers so that the | ||
| connection will be on a message boundary. Occurs when the COPY operation | ||
| is aborted.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Copy Management</a><ul> | ||
| <li><a class="reference internal" href="#copy-managers">Copy Managers</a><ul> | ||
| <li><a class="reference internal" href="#manager-interface-points">Manager Interface Points</a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#faults">Faults</a><ul> | ||
| <li><a class="reference internal" href="#receiver-faults">Receiver Faults</a><ul> | ||
| <li><a class="reference internal" href="#receiverfault-properties">ReceiverFault Properties</a></li> | ||
| <li><a class="reference internal" href="#reconciliation">Reconciliation</a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#producer-faults">Producer Faults</a><ul> | ||
| <li><a class="reference internal" href="#producerfault-properties">ProducerFault Properties</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#failures">Failures</a><ul> | ||
| <li><a class="reference internal" href="#copyfail-properties">CopyFail Properties</a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#producers">Producers</a></li> | ||
| <li><a class="reference internal" href="#receivers">Receivers</a></li> | ||
| <li><a class="reference internal" href="#terminology">Terminology</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="driver.html" | ||
| title="previous chapter">Driver</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="notifyman.html" | ||
| title="next chapter">Notification Management</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/copyman.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="notifyman.html" title="Notification Management" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="driver.html" title="Driver" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Index — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="#" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1 id="index">Index</h1> | ||
| <div class="genindex-jumpbox"> | ||
| <a href="#A"><strong>A</strong></a> | ||
| | <a href="#B"><strong>B</strong></a> | ||
| | <a href="#C"><strong>C</strong></a> | ||
| | <a href="#D"><strong>D</strong></a> | ||
| | <a href="#E"><strong>E</strong></a> | ||
| | <a href="#F"><strong>F</strong></a> | ||
| | <a href="#H"><strong>H</strong></a> | ||
| | <a href="#I"><strong>I</strong></a> | ||
| | <a href="#L"><strong>L</strong></a> | ||
| | <a href="#M"><strong>M</strong></a> | ||
| | <a href="#N"><strong>N</strong></a> | ||
| | <a href="#O"><strong>O</strong></a> | ||
| | <a href="#P"><strong>P</strong></a> | ||
| | <a href="#Q"><strong>Q</strong></a> | ||
| | <a href="#R"><strong>R</strong></a> | ||
| | <a href="#S"><strong>S</strong></a> | ||
| | <a href="#T"><strong>T</strong></a> | ||
| | <a href="#U"><strong>U</strong></a> | ||
| | <a href="#V"><strong>V</strong></a> | ||
| | <a href="#W"><strong>W</strong></a> | ||
| | <a href="#X"><strong>X</strong></a> | ||
| </div> | ||
| <h2 id="A">A</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.alock.ALock">ALock (class in postgresql.alock)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.alock.ALock.acquire">ALock.acquire() (in module postgresql.alock)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.alock.ALock.locked">ALock.locked() (in module postgresql.alock)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.alock.ALock.release">ALock.release() (in module postgresql.alock)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.AuthenticationMethodError">AuthenticationMethodError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="B">B</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Database.backend_id">backend_id (postgresql.api.Database attribute)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="C">C</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.copyman.CallReceiver">CallReceiver (class in postgresql.copyman)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.CardinalityError">CardinalityError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Category">Category (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.CFError">CFError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.client_address">client_address (postgresql.api.Database attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.client_port">client_port (postgresql.api.Database attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ClientCannotConnectError">ClientCannotConnectError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection.closed">closed (postgresql.api.Connection attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster">Cluster (class in postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster">(class in postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.address">Cluster.address() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.connect">Cluster.connect() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.connection">Cluster.connection() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.connector">Cluster.connector() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.drop">Cluster.drop() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.drop">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.get_pid_from_file">Cluster.get_pid_from_file() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.init">Cluster.init() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.init">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.initialized">Cluster.initialized() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.kill">Cluster.kill() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.kill">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.ready_for_connections">Cluster.ready_for_connections() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.reload">Cluster.reload() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.restart">Cluster.restart() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.restart">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.running">Cluster.running() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.shutdown">Cluster.shutdown() (in module postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.start">Cluster.start() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.start">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.stop">Cluster.stop() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.stop">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.wait_until_started">Cluster.wait_until_started() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.wait_until_started">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.wait_until_stopped">Cluster.wait_until_stopped() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.wait_until_stopped">(in module postgresql.cluster)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.cluster.ClusterError">ClusterError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.ClusterInitializationError">ClusterInitializationError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.ClusterNotRunningError">ClusterNotRunningError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.ClusterStartupError">ClusterStartupError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.ClusterTimeoutError">ClusterTimeoutError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.ClusterWarning">ClusterWarning (class in postgresql.cluster)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Message.code">code (postgresql.api.Message attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.column_names">column_names (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.column_types">column_types (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection">Connection (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection.clone">Connection.clone() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection.close">Connection.close() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection.connect">Connection.connect() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ConnectionDoesNotExistError">ConnectionDoesNotExistError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ConnectionFailureError">ConnectionFailureError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connector">Connector (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection.connector">connector (postgresql.api.Connection attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ConnectTimeoutError">ConnectTimeoutError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.CopyFail">CopyFail</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.CopyManager">CopyManager (class in postgresql.copyman)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.CopyManager.reconcile">CopyManager.reconcile() (in module postgresql.copyman)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cursor">Cursor (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cursor.clone">Cursor.clone() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cursor.read">Cursor.read() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cursor.seek">Cursor.seek() (in module postgresql.api)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="D">D</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.daemon_path">daemon_path (postgresql.cluster.Cluster attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.data_directory">data_directory (postgresql.api.Cluster attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database">Database (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.cursor_from_id">Database.cursor_from_id() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.do">Database.do() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.execute">Database.execute() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.iternotifies">Database.iternotifies() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.listen">Database.listen() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.listening_channels">Database.listening_channels() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.notify">Database.notify() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.prepare">Database.prepare() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.proc">Database.proc() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.reset">Database.reset() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Database.statement_from_id">Database.statement_from_id() (in module postgresql.api)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Database.unlisten">Database.unlisten() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.installation.default">default() (in module postgresql.installation)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.default_buffer_size">default_buffer_size (in module postgresql.copyman)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.sys.default_errformat">default_errformat() (in module postgresql.sys)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.sys.default_msghook">default_msghook() (in module postgresql.sys)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.installation.default_pg_config">default_pg_config() (in module postgresql.installation)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Message.details">details (postgresql.api.Message attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cursor.direction">direction (postgresql.api.Cursor attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.Disconnection">Disconnection</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.DPDSEError">DPDSEError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Driver">Driver (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Driver.connect">Driver.connect() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.DriverError">DriverError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="E">E</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.EREError">EREError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ERIEError">ERIEError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.sys.errformat">errformat() (in module postgresql.sys)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.Error">Error</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.string.escape_ident">escape_ident() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.escape_literal">escape_literal() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.EscapeCharacterError">EscapeCharacterError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.Exception">Exception</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="F">F</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.FeatureError">FeatureError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="H">H</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.hba_file">hba_file (postgresql.cluster.Cluster attribute)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="I">I</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.ICVError">ICVError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.IgnoredClientParameterWarning">IgnoredClientParameterWarning (class in postgresql.exceptions)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.InconsistentCursorIsolationError">InconsistentCursorIsolationError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.InFailedTransactionError">InFailedTransactionError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.InitDBError">InitDBError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.InsecurityError">InsecurityError</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Installation">Installation (class in postgresql.api)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.installation.Installation">(class in postgresql.installation)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.installation">installation (postgresql.api.Cluster attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.IRError">IRError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.isolation">isolation (postgresql.api.Transaction attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ITSError">ITSError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="L">L</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.LoadError">LoadError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="M">M</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.map_errors_and_warnings">map_errors_and_warnings() (in module postgresql.exceptions)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Message">Message (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Message.message">message (postgresql.api.Message attribute)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Message.isconsistent">Message.isconsistent() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.alock.ALock.mode">mode (postgresql.alock.ALock attribute)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.mode">(postgresql.api.Transaction attribute)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.sys.msghook">msghook() (in module postgresql.sys)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="N">N</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.copyman.NullProducer">NullProducer (class in postgresql.copyman)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="O">O</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.OIError">OIError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ONIPSError">ONIPSError</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.open">open() (in module postgresql)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.OperationError">OperationError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="P">P</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Statement.parameter_types">parameter_types (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.pg_column_types">pg_column_types (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.installation.pg_config_dictionary">pg_config_dictionary() (in module postgresql.installation)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.pg_parameter_types">pg_parameter_types (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.temporal.pg_tmp">pg_tmp (in module postgresql.temporal)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.cluster.Cluster.pid">pid (postgresql.cluster.Cluster attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.PLEError">PLEError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.PLPGSQLError">PLPGSQLError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.PLPGSQLRaiseError">PLPGSQLRaiseError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql">postgresql (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.alock">postgresql.alock (module)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#module-postgresql.api">postgresql.api (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.cluster">postgresql.cluster (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.copyman">postgresql.copyman (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.exceptions">postgresql.exceptions (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.installation">postgresql.installation (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.string">postgresql.string (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.sys">postgresql.sys (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#module-postgresql.temporal">postgresql.temporal (module)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.ProducerFault">ProducerFault</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.ProtocolProducer">ProtocolProducer (class in postgresql.copyman)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.ProtocolProducer.recover">ProtocolProducer.recover() (in module postgresql.copyman)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="Q">Q</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.string.qname">qname() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Connection.query">query (postgresql.api.Connection attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.quote_ident">quote_ident() (in module postgresql.string)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.string.quote_ident_if_needed">quote_ident_if_needed() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.quote_literal">quote_literal() (in module postgresql.string)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="R">R</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.ReadOnlyTransactionError">ReadOnlyTransactionError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.ReceiverFault">ReceiverFault</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.sys.reset_errformat">reset_errformat() (in module postgresql.sys)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.sys.reset_msghook">reset_msghook() (in module postgresql.sys)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="S">S</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.exceptions.SavepointError">SavepointError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.SchemaAndDataStatementsError">SchemaAndDataStatementsError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.SEARVError">SEARVError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.ServerNotReadyError">ServerNotReadyError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Settings">Settings (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Cluster.settings">settings (postgresql.api.Cluster attribute)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.api.Database.settings">(postgresql.api.Database attribute)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.api.Settings.get">Settings.get() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Settings.getset">Settings.getset() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Settings.items">Settings.items() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Settings.keys">Settings.keys() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Settings.update">Settings.update() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Settings.values">Settings.values() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.SIOError">SIOError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Message.source">source (postgresql.api.Message attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.split">split() (in module postgresql.string)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.string.split_ident">split_ident() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.split_qname">split_qname() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.split_sql">split_sql() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.split_sql_str">split_sql_str() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.string.split_using">split_using() (in module postgresql.string)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.sql_column_types">sql_column_types (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.sql_parameter_types">sql_parameter_types (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.SREError">SREError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Installation.ssl">ssl (postgresql.api.Installation attribute)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.installation.Installation.ssl">(postgresql.installation.Installation attribute)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| <dt><a href="reference.html#postgresql.api.Statement">Statement (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.clone">Statement.clone() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.close">Statement.close() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.statement_id">statement_id (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.StoredProcedure">StoredProcedure (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Statement.string">string (postgresql.api.Statement attribute)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="T">T</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.temporal.Temporal">Temporal (class in postgresql.temporal)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.temporal.Temporal.cluster_dirname">Temporal.cluster_dirname() (in module postgresql.temporal)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Transaction">Transaction (class in postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.abort">Transaction.abort() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.begin">Transaction.begin() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.commit">Transaction.commit() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.rollback">Transaction.rollback() (in module postgresql.api)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Transaction.start">Transaction.start() (in module postgresql.api)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.copyman.transfer">transfer() (in module postgresql.copyman)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.TRError">TRError</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Installation.type">type (postgresql.api.Installation attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.TypeConversionWarning">TypeConversionWarning (class in postgresql.exceptions)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.exceptions.TypeIOError">TypeIOError</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="U">U</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.copyman.ulong_pack">ulong_pack() (in module postgresql.copyman)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.string.unsplit">unsplit() (in module postgresql.string)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="V">V</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.version">version (in module postgresql)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.api.Installation.version">(postgresql.api.Installation attribute)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.version_info">version_info (in module postgresql)</a> | ||
| </dt> | ||
| <dd><dl> | ||
| <dt><a href="reference.html#postgresql.api.Database.version_info">(postgresql.api.Database attribute)</a> | ||
| </dt> | ||
| <dt><a href="reference.html#postgresql.api.Installation.version_info">(postgresql.api.Installation attribute)</a> | ||
| </dt> | ||
| </dl></dd> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="W">W</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.copyman.WireState">WireState (class in postgresql.copyman)</a> | ||
| </dt> | ||
| </dl></td> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.copyman.WireState.update">WireState.update() (in module postgresql.copyman)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| <h2 id="X">X</h2> | ||
| <table style="width: 100%" class="indextable genindextable"><tr> | ||
| <td style="width: 33%" valign="top"><dl> | ||
| <dt><a href="reference.html#postgresql.api.Database.xact">xact (postgresql.api.Database attribute)</a> | ||
| </dt> | ||
| </dl></td> | ||
| </tr></table> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="#" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Gotchas — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Commands" href="bin.html" /> | ||
| <link rel="prev" title="Client Parameters" href="clientparameters.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="bin.html" title="Commands" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="clientparameters.html" title="Client Parameters" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="gotchas"> | ||
| <h1>Gotchas<a class="headerlink" href="#gotchas" title="Permalink to this headline">¶</a></h1> | ||
| <p>It is recognized that decisions were made that may not always be ideal for a | ||
| given user. In order to highlight those potential issues and hopefully bring | ||
| some sense into a confusing situation, this document was drawn.</p> | ||
| <div class="section" id="non-english-locales"> | ||
| <h2>Non-English Locales<a class="headerlink" href="#non-english-locales" title="Permalink to this headline">¶</a></h2> | ||
| <p>Many non-english locales are not supported due to the localization of the severity field | ||
| in messages and errors sent to the client. Internally, py-postgresql uses this to allow | ||
| client side filtering of messages and to identify FATAL connection errors that allow the | ||
| client to recognize that it should be expecting the connection to terminate.</p> | ||
| </div> | ||
| <div class="section" id="thread-safety"> | ||
| <h2>Thread Safety<a class="headerlink" href="#thread-safety" title="Permalink to this headline">¶</a></h2> | ||
| <p>py-postgresql connection operations are not thread safe.</p> | ||
| </div> | ||
| <div class="section" id="client-encoding-setting-should-be-altered-carefully"> | ||
| <h2><cite>client_encoding</cite> setting should be altered carefully<a class="headerlink" href="#client-encoding-setting-should-be-altered-carefully" title="Permalink to this headline">¶</a></h2> | ||
| <p><cite>postgresql.driver</cite>‘s streaming cursor implementation reads a fixed set of rows | ||
| when it queries the server for more. In order to optimize some situations, the | ||
| driver will send a request for more data, but makes no attempt to wait and | ||
| process the data as it is not yet needed. When the user comes back to read more | ||
| data from the cursor, it will then look at this new data. The problem being, if | ||
| <cite>client_encoding</cite> was switched, it may use the wrong codec to transform the | ||
| wire data into higher level Python objects(str).</p> | ||
| <p>To avoid this problem from ever happening, set the <cite>client_encoding</cite> early. | ||
| Furthermore, it is probably best to never change the <cite>client_encoding</cite> as the | ||
| driver automatically makes the necessary transformation to Python strings.</p> | ||
| </div> | ||
| <div class="section" id="the-user-and-password-is-correct-but-it-does-not-work-when-using-postgresql-driver"> | ||
| <h2>The user and password is correct, but it does not work when using <cite>postgresql.driver</cite><a class="headerlink" href="#the-user-and-password-is-correct-but-it-does-not-work-when-using-postgresql-driver" title="Permalink to this headline">¶</a></h2> | ||
| <p>This issue likely comes from the possibility that the information sent to the | ||
| server early in the negotiation phase may not be in an encoding that is | ||
| consistent with the server’s encoding.</p> | ||
| <p>One problem is that PostgreSQL does not provide the client with the server | ||
| encoding early enough in the negotiation phase, and, therefore, is unable to | ||
| process the password data in a way that is consistent with the server’s | ||
| expectations.</p> | ||
| <p>Another problem is that PostgreSQL takes much of the data in the startup message | ||
| as-is, so a decision about the best way to encode parameters is difficult.</p> | ||
| <p>The easy way to avoid <em>most</em> issues with this problem is to initialize the | ||
| database in the <cite>utf-8</cite> encoding. The driver defaults the expected server | ||
| encoding to <cite>utf-8</cite>. However, this can be overridden by creating the <cite>Connector</cite> | ||
| with a <cite>server_encoding</cite> parameter. Setting <cite>server_encoding</cite> to the proper | ||
| value of the target server will allow the driver to properly encode <em>some</em> of | ||
| the parameters. Also, any GUC parameters passed via the <cite>settings</cite> parameter | ||
| should use typed objects when possible to hint that the server encoding should | ||
| not be used on that parameter(<cite>bytes</cite>, for instance).</p> | ||
| </div> | ||
| <div class="section" id="backslash-characters-are-being-treated-literally"> | ||
| <h2>Backslash characters are being treated literally<a class="headerlink" href="#backslash-characters-are-being-treated-literally" title="Permalink to this headline">¶</a></h2> | ||
| <p>The driver enables standard compliant strings. Stop using non-standard features. | ||
| ;)</p> | ||
| <p>If support for non-standard strings was provided it would require to the | ||
| driver to provide subjective quote interfaces(eg, db.quote_literal). Doing so is | ||
| not desirable as it introduces difficulties for the driver <em>and</em> the user.</p> | ||
| </div> | ||
| <div class="section" id="types-without-binary-support-in-the-driver-are-unsupported-in-arrays-and-records"> | ||
| <h2>Types without binary support in the driver are unsupported in arrays and records<a class="headerlink" href="#types-without-binary-support-in-the-driver-are-unsupported-in-arrays-and-records" title="Permalink to this headline">¶</a></h2> | ||
| <p>When an array or composite type is identified, <cite>postgresql.protocol.typio</cite> | ||
| ultimately chooses the binary format for the transfer of the column or | ||
| parameter. When this is done, PostgreSQL will pack or expect <em>all</em> the values | ||
| in binary format as well. If that binary format is not supported and the type | ||
| is not an string, it will fail to unpack the row or pack the appropriate data for | ||
| the element or attribute.</p> | ||
| <p>In most cases issues related to this can be avoided with explicit casts to text.</p> | ||
| </div> | ||
| <div class="section" id="notices-warnings-and-other-messages-are-too-verbose"> | ||
| <h2>NOTICEs, WARNINGs, and other messages are too verbose<a class="headerlink" href="#notices-warnings-and-other-messages-are-too-verbose" title="Permalink to this headline">¶</a></h2> | ||
| <p>For many situations, the information provided with database messages is | ||
| far too verbose. However, considering that py-postgresql is a programmer’s | ||
| library, the default of high verbosity is taken with the express purpose of | ||
| allowing the programmer to “adjust the volume” until appropriate.</p> | ||
| <p>By default, py-postgresql adjusts the <tt class="docutils literal"><span class="pre">client_min_messages</span></tt> to only emit | ||
| messages at the WARNING level or higher–ERRORs, FATALs, and PANICs. | ||
| This reduces the number of messages generated by most connections dramatically.</p> | ||
| <p>If further customization is needed, the <a class="reference internal" href="driver.html#db-messages"><em>Database Messages</em></a> section has | ||
| information on overriding the default action taken with database messages.</p> | ||
| </div> | ||
| <div class="section" id="strange-typeerror-using-load-rows-or-load-chunks"> | ||
| <h2>Strange TypeError using load_rows() or load_chunks()<a class="headerlink" href="#strange-typeerror-using-load-rows-or-load-chunks" title="Permalink to this headline">¶</a></h2> | ||
| <p>When a prepared statement is directly executed using <tt class="docutils literal"><span class="pre">__call__()</span></tt>, it can easily | ||
| validate that the appropriate number of parameters are given to the function. | ||
| When <tt class="docutils literal"><span class="pre">load_rows()</span></tt> or <tt class="docutils literal"><span class="pre">load_chunks()</span></tt> is used, any tuple in the | ||
| the entire sequence can cause this TypeError during the loading process:</p> | ||
| <div class="highlight-python"><pre>TypeError: inconsistent items, N processors and M items in row</pre> | ||
| </div> | ||
| <p>This exception is raised by a generic processing routine whose functionality | ||
| is abstract in nature, so the message is abstract as well. It essentially means | ||
| that a tuple in the sequence given to the loading method had too many or too few | ||
| items.</p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Gotchas</a><ul> | ||
| <li><a class="reference internal" href="#non-english-locales">Non-English Locales</a></li> | ||
| <li><a class="reference internal" href="#thread-safety">Thread Safety</a></li> | ||
| <li><a class="reference internal" href="#client-encoding-setting-should-be-altered-carefully"><cite>client_encoding</cite> setting should be altered carefully</a></li> | ||
| <li><a class="reference internal" href="#the-user-and-password-is-correct-but-it-does-not-work-when-using-postgresql-driver">The user and password is correct, but it does not work when using <cite>postgresql.driver</cite></a></li> | ||
| <li><a class="reference internal" href="#backslash-characters-are-being-treated-literally">Backslash characters are being treated literally</a></li> | ||
| <li><a class="reference internal" href="#types-without-binary-support-in-the-driver-are-unsupported-in-arrays-and-records">Types without binary support in the driver are unsupported in arrays and records</a></li> | ||
| <li><a class="reference internal" href="#notices-warnings-and-other-messages-are-too-verbose">NOTICEs, WARNINGs, and other messages are too verbose</a></li> | ||
| <li><a class="reference internal" href="#strange-typeerror-using-load-rows-or-load-chunks">Strange TypeError using load_rows() or load_chunks()</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="clientparameters.html" | ||
| title="previous chapter">Client Parameters</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="bin.html" | ||
| title="next chapter">Commands</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/gotchas.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="bin.html" title="Commands" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="clientparameters.html" title="Client Parameters" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>py-postgresql — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="#" /> | ||
| <link rel="next" title="Administration" href="admin.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="admin.html" title="Administration" | ||
| accesskey="N">next</a> |</li> | ||
| <li><a href="#">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="py-postgresql"> | ||
| <h1>py-postgresql<a class="headerlink" href="#py-postgresql" title="Permalink to this headline">¶</a></h1> | ||
| <p>py-postgresql is a project dedicated to improving the Python client interfaces to PostgreSQL.</p> | ||
| <p>At its core, py-postgresql provides a PG-API, <cite>postgresql.api</cite>, and | ||
| DB-API 2.0 interface for using a PostgreSQL database.</p> | ||
| <div class="section" id="contents"> | ||
| <h2>Contents<a class="headerlink" href="#contents" title="Permalink to this headline">¶</a></h2> | ||
| <div class="toctree-wrapper compound"> | ||
| <ul> | ||
| <li class="toctree-l1"><a class="reference internal" href="admin.html">Administration</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="admin.html#installation">Installation</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="admin.html#environment">Environment</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="driver.html">Driver</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#establishing-a-connection">Establishing a Connection</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#connections">Connections</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#prepared-statements">Prepared Statements</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#cursors">Cursors</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#rows">Rows</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#queries">Queries</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#stored-procedures">Stored Procedures</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#transactions">Transactions</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#settings">Settings</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#type-support">Type Support</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="driver.html#database-messages">Database Messages</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="copyman.html">Copy Management</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="copyman.html#copy-managers">Copy Managers</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="copyman.html#faults">Faults</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="copyman.html#failures">Failures</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="copyman.html#producers">Producers</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="copyman.html#receivers">Receivers</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="copyman.html#terminology">Terminology</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="notifyman.html">Notification Management</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="notifyman.html#listening-on-a-single-connection">Listening on a Single Connection</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="notifyman.html#listening-on-multiple-connections">Listening on Multiple Connections</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="notifyman.html#notification-managers">Notification Managers</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="alock.html">Advisory Locks</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="alock.html#acquiring-alocks">Acquiring ALocks</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="alock.html#alocks">ALocks</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="cluster.html">Cluster Management</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="cluster.html#installations">Installations</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="cluster.html#clusters">Clusters</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="lib.html">Categories and Libraries</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#writing-libraries">Writing Libraries</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#using-libraries">Using Libraries</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#symbol-types">Symbol Types</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#symbol-execution-methods">Symbol Execution Methods</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#reference-symbols">Reference Symbols</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#distributing-and-usage">Distributing and Usage</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#audience-and-motivation">Audience and Motivation</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="lib.html#terminology">Terminology</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="clientparameters.html">Client Parameters</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="clientparameters.html#collecting-parameters">Collecting Parameters</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="clientparameters.html#defaults">Defaults</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="clientparameters.html#postgresql-environment-variables">PostgreSQL Environment Variables</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="clientparameters.html#postgresql-password-file">PostgreSQL Password File</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="gotchas.html">Gotchas</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#non-english-locales">Non-English Locales</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#thread-safety">Thread Safety</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#client-encoding-setting-should-be-altered-carefully"><cite>client_encoding</cite> setting should be altered carefully</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#the-user-and-password-is-correct-but-it-does-not-work-when-using-postgresql-driver">The user and password is correct, but it does not work when using <cite>postgresql.driver</cite></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#backslash-characters-are-being-treated-literally">Backslash characters are being treated literally</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#types-without-binary-support-in-the-driver-are-unsupported-in-arrays-and-records">Types without binary support in the driver are unsupported in arrays and records</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#notices-warnings-and-other-messages-are-too-verbose">NOTICEs, WARNINGs, and other messages are too verbose</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="gotchas.html#strange-typeerror-using-load-rows-or-load-chunks">Strange TypeError using load_rows() or load_chunks()</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="reference"> | ||
| <h2>Reference<a class="headerlink" href="#reference" title="Permalink to this headline">¶</a></h2> | ||
| <div class="toctree-wrapper compound"> | ||
| <ul> | ||
| <li class="toctree-l1"><a class="reference internal" href="bin.html">Commands</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="bin.html#postgresql-bin-pg-python">postgresql.bin.pg_python</a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="bin.html#postgresql-bin-pg-dotconf">postgresql.bin.pg_dotconf</a></li> | ||
| </ul> | ||
| </li> | ||
| <li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a><ul> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql"><tt class="docutils literal"><span class="pre">postgresql</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.api"><tt class="docutils literal"><span class="pre">postgresql.api</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.sys"><tt class="docutils literal"><span class="pre">postgresql.sys</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.string"><tt class="docutils literal"><span class="pre">postgresql.string</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.exceptions"><tt class="docutils literal"><span class="pre">postgresql.exceptions</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.temporal"><tt class="docutils literal"><span class="pre">postgresql.temporal</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.installation"><tt class="docutils literal"><span class="pre">postgresql.installation</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.cluster"><tt class="docutils literal"><span class="pre">postgresql.cluster</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.copyman"><tt class="docutils literal"><span class="pre">postgresql.copyman</span></tt></a></li> | ||
| <li class="toctree-l2"><a class="reference internal" href="reference.html#module-postgresql.alock"><tt class="docutils literal"><span class="pre">postgresql.alock</span></tt></a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="changes"> | ||
| <h2>Changes<a class="headerlink" href="#changes" title="Permalink to this headline">¶</a></h2> | ||
| <div class="toctree-wrapper compound"> | ||
| <ul> | ||
| <li class="toctree-l1"><a class="reference internal" href="changes-v1.1.html">Changes in v1.1</a></li> | ||
| <li class="toctree-l1"><a class="reference internal" href="changes-v1.0.html">Changes in v1.0</a></li> | ||
| </ul> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="sample-code"> | ||
| <h2>Sample Code<a class="headerlink" href="#sample-code" title="Permalink to this headline">¶</a></h2> | ||
| <p>Using <cite>postgresql.driver</cite>:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">postgresql</span> | ||
| <span class="gp">>>> </span><span class="n">db</span> <span class="o">=</span> <span class="n">postgresql</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s">"pq://user:password@host/name_of_database"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">"CREATE TABLE emp (emp_name text PRIMARY KEY, emp_salary numeric)"</span><span class="p">)</span> | ||
| <span class="go">>>></span> | ||
| <span class="gp">>>> </span><span class="c"># Create the statements.</span> | ||
| <span class="gp">>>> </span><span class="n">make_emp</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"INSERT INTO emp VALUES ($1, $2)"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">raise_emp</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"UPDATE emp SET emp_salary = emp_salary + $2 WHERE emp_name = $1"</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">get_emp_with_salary_lt</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="s">"SELECT emp_name FROM emp WHERE emp_salay < $1"</span><span class="p">)</span> | ||
| <span class="go">>>></span> | ||
| <span class="gp">>>> </span><span class="c"># Create some employees, but do it in a transaction--all or nothing.</span> | ||
| <span class="gp">>>> </span><span class="k">with</span> <span class="n">db</span><span class="o">.</span><span class="n">xact</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="n">make_emp</span><span class="p">(</span><span class="s">"John Doe"</span><span class="p">,</span> <span class="s">"150,000"</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="n">make_emp</span><span class="p">(</span><span class="s">"Jane Doe"</span><span class="p">,</span> <span class="s">"150,000"</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="n">make_emp</span><span class="p">(</span><span class="s">"Andrew Doe"</span><span class="p">,</span> <span class="s">"55,000"</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="n">make_emp</span><span class="p">(</span><span class="s">"Susan Doe"</span><span class="p">,</span> <span class="s">"60,000"</span><span class="p">)</span> | ||
| <span class="go">>>></span> | ||
| <span class="gp">>>> </span><span class="c"># Give some raises</span> | ||
| <span class="gp">>>> </span><span class="k">with</span> <span class="n">db</span><span class="o">.</span><span class="n">xact</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">get_emp_with_salary_lt</span><span class="p">(</span><span class="s">"125,000"</span><span class="p">):</span> | ||
| <span class="gp">... </span> <span class="k">print</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">"emp_name"</span><span class="p">])</span> | ||
| <span class="gp">... </span> <span class="n">raise_emp</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s">"emp_name"</span><span class="p">],</span> <span class="s">"10,000"</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Of course, if DB-API 2.0 is desired, the module is located at | ||
| <cite>postgresql.driver.dbapi20</cite>. DB-API extends PG-API, so the features | ||
| illustrated above are available on DB-API connections.</p> | ||
| <p>See <a class="reference internal" href="driver.html#db-interface"><em>Driver</em></a> for more information.</p> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="#">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">py-postgresql</a><ul> | ||
| <li><a class="reference internal" href="#contents">Contents</a><ul> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#reference">Reference</a><ul> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#changes">Changes</a><ul> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#sample-code">Sample Code</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="admin.html" | ||
| title="next chapter">Administration</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/index.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="admin.html" title="Administration" | ||
| >next</a> |</li> | ||
| <li><a href="#">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Categories and Libraries — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Client Parameters" href="clientparameters.html" /> | ||
| <link rel="prev" title="Cluster Management" href="cluster.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="clientparameters.html" title="Client Parameters" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="cluster.html" title="Cluster Management" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="categories-and-libraries"> | ||
| <h1>Categories and Libraries<a class="headerlink" href="#categories-and-libraries" title="Permalink to this headline">¶</a></h1> | ||
| <p>This chapter discusses the usage and implementation of connection categories and | ||
| libraries.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">First-time users are encouraged to read the <a class="reference internal" href="#audience-and-motivation">Audience and Motivation</a> | ||
| section first.</p> | ||
| </div> | ||
| <p>Libraries are a collection of SQL statements that can be bound to a | ||
| connection. Libraries are <em>normally</em> bound directly to the connection object as | ||
| an attribute using a name specified by the library.</p> | ||
| <p>Libraries provide a common way for SQL statements to be managed outside of the | ||
| code that uses them. When using ILFs, this increases the portability of the SQL | ||
| by keeping the statements isolated from the Python code in an accessible format | ||
| that can be easily used by other languages or systems — An ILF parser can be | ||
| implemented within a few dozen lines using basic text tools.</p> | ||
| <p>SQL statements defined by a Library are identified by their Symbol. These | ||
| symbols are named and annotated in order to allow the user to define how a | ||
| statement is to be used. The user may state the default execution method of | ||
| the statement object, or whether the symbol is to be preloaded at bind | ||
| time–these properties are Symbol Annotations.</p> | ||
| <p>The purpose of libraries are to provide a means to manage statements on | ||
| disk and at runtime. ILFs provide a means to reference a collection | ||
| of statements on disk, and, when loaded, the symbol bindings provides means to | ||
| reference a statement already prepared for use on a given connection.</p> | ||
| <p>The <cite>postgresql.lib</cite> package-module provides fundamental classes for supporting | ||
| categories and libraries.</p> | ||
| <div class="section" id="writing-libraries"> | ||
| <h2>Writing Libraries<a class="headerlink" href="#writing-libraries" title="Permalink to this headline">¶</a></h2> | ||
| <p>ILF files are the recommended way to build a library. These files use the | ||
| naming convention “lib{NAME}.sql”. The prefix and suffix are used describe the | ||
| purpose of the file and to provide a hint to editors that SQL highlighting | ||
| should be used. The format of an ILF takes the form:</p> | ||
| <div class="highlight-python"><pre><Preface> | ||
| [name:type:method] | ||
| <statement> | ||
| ...</pre> | ||
| </div> | ||
| <p>Where multiple symbols may be defined. The Preface that comes before the first | ||
| symbol is an arbitrary block of text that should be used to describe the library. | ||
| This block is free-form, and should be considered a good place for some | ||
| general documentation.</p> | ||
| <p>Symbols are named and described using the contents of section markers: | ||
| <tt class="docutils literal"><span class="pre">('['</span> <span class="pre">...</span> <span class="pre">']')</span></tt>. Section markers have three components: the symbol name, | ||
| the symbol type and the symbol method. Each of these components are separated | ||
| using a single colon, <tt class="docutils literal"><span class="pre">:</span></tt>. All components are optional except the Symbol name. | ||
| For example:</p> | ||
| <div class="highlight-python"><pre>[get_user_info] | ||
| SELECT * FROM user WHERE user_id = $1 | ||
| [get_user_info_v2::] | ||
| SELECT * FROM user WHERE user_id = $1</pre> | ||
| </div> | ||
| <p>In the above example, <tt class="docutils literal"><span class="pre">get_user_info</span></tt> and <tt class="docutils literal"><span class="pre">get_user_info_v2</span></tt> are identical. | ||
| Empty components indicate the default effect.</p> | ||
| <p>The second component in the section identifier is the symbol type. All Symbol | ||
| types are listed in <a class="reference internal" href="#symbol-types">Symbol Types</a>. This can be | ||
| used to specify what the section’s contents are or when to bind the | ||
| symbol:</p> | ||
| <div class="highlight-python"><pre>[get_user_info:preload] | ||
| SELECT * FROM user WHERE user_id = $1</pre> | ||
| </div> | ||
| <p>This provides the Binding with the knowledge that the statement should be | ||
| prepared when the Library is bound. Therefore, when this Symbol’s statement | ||
| is used for the first time, it will have already been prepared.</p> | ||
| <p>Another type is the <tt class="docutils literal"><span class="pre">const</span></tt> Symbol type. This defines a data Symbol whose | ||
| <em>statement results</em> will be resolved when the Library is bound:</p> | ||
| <div class="highlight-python"><pre>[user_type_ids:const] | ||
| SELECT user_type_id, user_type FROM user_types;</pre> | ||
| </div> | ||
| <p>Constant Symbols cannot take parameters as they are data properties. The | ||
| <em>result</em> of the above query is set to the Bindings’ <tt class="docutils literal"><span class="pre">user_type_ids</span></tt> | ||
| attribute:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">user_type_ids</span> | ||
| <span class="go"><sequence of (user_type_id, user_type)></span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Where <tt class="docutils literal"><span class="pre">lib</span></tt> in the above is a Binding of the Library containing the | ||
| <tt class="docutils literal"><span class="pre">user_type_ids</span></tt> Symbol.</p> | ||
| <p>Finally, procedures can be bound as symbols using the <tt class="docutils literal"><span class="pre">proc</span></tt> type:</p> | ||
| <div class="highlight-python"><pre>[remove_user:proc] | ||
| remove_user(bigint)</pre> | ||
| </div> | ||
| <p>All procedures symbols are loaded when the Library is bound. Procedure symbols | ||
| are special because the execution method is effectively specified by the | ||
| procedure itself.</p> | ||
| <p>The third component is the symbol <tt class="docutils literal"><span class="pre">method</span></tt>. This defines the execution method | ||
| of the statement and ultimately what is returned when the Symbol is called at | ||
| runtime. All the execution methods are listed in <a class="reference internal" href="#symbol-execution-methods">Symbol Execution Methods</a>.</p> | ||
| <p>The default execution method is the default execution method of | ||
| <cite>postgresql.api.PreparedStatement</cite> objects; return the entire result set in a | ||
| list object:</p> | ||
| <div class="highlight-python"><pre>[get_numbers] | ||
| SELECT i FROM generate_series(0, 100-1) AS g(i);</pre> | ||
| </div> | ||
| <p>When bound:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">get_numbers</span><span class="p">()</span> <span class="o">==</span> <span class="p">[(</span><span class="n">x</span><span class="p">,)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">)]</span> | ||
| <span class="go">True</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The transformation of range in the above is necessary as statements | ||
| return a sequence of row objects by default.</p> | ||
| <p>For large result-sets, fetching all the rows would be taxing on a system’s | ||
| memory. The <tt class="docutils literal"><span class="pre">rows</span></tt> and <tt class="docutils literal"><span class="pre">chunks</span></tt> methods provide an iterator to rows produced | ||
| by a statement using a stream:</p> | ||
| <div class="highlight-python"><pre>[get_some_rows::rows] | ||
| SELECT i FROM generate_series(0, 1000) AS g(i); | ||
| [get_some_chunks::chunks] | ||
| SELECT i FROM generate_series(0, 1000) AS g(i);</pre> | ||
| </div> | ||
| <p><tt class="docutils literal"><span class="pre">rows</span></tt> means that the Symbol will return an iterator producing individual rows | ||
| of the result, and <tt class="docutils literal"><span class="pre">chunks</span></tt> means that the Symbol will return an iterator | ||
| producing sequences of rows of the result.</p> | ||
| <p>When bound:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">chain</span> | ||
| <span class="gp">>>> </span><span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">get_some_rows</span><span class="p">())</span> <span class="o">==</span> <span class="nb">list</span><span class="p">(</span><span class="n">chain</span><span class="o">.</span><span class="n">from_iterable</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">get_some_chunks</span><span class="p">()))</span> | ||
| <span class="go">True</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Other methods include <tt class="docutils literal"><span class="pre">column</span></tt> and <tt class="docutils literal"><span class="pre">first</span></tt>. The column method provides a | ||
| means to designate that the symbol should return an iterator of the values in | ||
| the first column instead of an iterator to the rows:</p> | ||
| <div class="highlight-python"><pre>[another_generate_series_example::column] | ||
| SELECT i FROM generate_series(0, $1::int) AS g(i)</pre> | ||
| </div> | ||
| <p>In use:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">another_generate_series_example</span><span class="p">(</span><span class="mi">100</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span> <span class="o">==</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span> | ||
| <span class="go">True</span> | ||
| <span class="gp">>>> </span><span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">another_generate_series_example</span><span class="p">(</span><span class="mi">10</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span> | ||
| <span class="go">[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The <tt class="docutils literal"><span class="pre">first</span></tt> method provides direct access to simple results. | ||
| Specifically, the first column of the first row when there is only one column. | ||
| When there are multiple columns the first row is returned:</p> | ||
| <div class="highlight-python"><pre>[get_one::first] | ||
| SELECT 1 | ||
| [get_one_twice::first] | ||
| SELECT 1, 1</pre> | ||
| </div> | ||
| <p>In use:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">get_one</span><span class="p">()</span> <span class="o">==</span> <span class="mi">1</span> | ||
| <span class="go">True</span> | ||
| <span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">lib</span><span class="o">.</span><span class="n">get_one_twice</span><span class="p">()</span> <span class="o">==</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> | ||
| <span class="go">True</span> | ||
| </pre></div> | ||
| </div> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last"><tt class="docutils literal"><span class="pre">first</span></tt> should be used with care. When the result returns no rows, <cite>None</cite> | ||
| will be returned.</p> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="using-libraries"> | ||
| <h2>Using Libraries<a class="headerlink" href="#using-libraries" title="Permalink to this headline">¶</a></h2> | ||
| <p>After a library is created, it must be loaded before it can be bound using | ||
| programmer interfaces. The <cite>postgresql.lib.load</cite> interface provides the | ||
| primary entry point for loading libraries.</p> | ||
| <p>When <tt class="docutils literal"><span class="pre">load</span></tt> is given a string, it identifies if a directory separator is in | ||
| the string, if there is it will treat the string as a <em>path</em> to the ILF to be | ||
| loaded. If no separator is found, it will treat the string as the library | ||
| name fragment and look for “lib{NAME}.sql” in the directories listed in | ||
| <cite>postgresql.sys.libpath</cite>.</p> | ||
| <p>Once a <cite>postgresql.lib.Library</cite> instance has been acquired, it can then be | ||
| bound to a connection for use. <cite>postgresql.lib.Binding</cite> is used to create an | ||
| object that provides and manages the Bound Symbols:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">postgresql.lib</span> <span class="kn">as</span> <span class="nn">pg_lib</span> | ||
| <span class="gp">>>> </span><span class="n">lib</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">B</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">Binding</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">lib</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The <tt class="docutils literal"><span class="pre">B</span></tt> object in the above example provides the Library’s Symbols as | ||
| attributes which can be called to in order to execute the Symbol’s statement:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">B</span><span class="o">.</span><span class="n">symbol</span><span class="p">(</span><span class="n">param</span><span class="p">)</span> | ||
| <span class="gp">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>While it is sometimes necessary, manual creation of a Binding is discouraged. | ||
| Rather, <cite>postgresql.lib.Category</cite> objects should be used to manage the set of | ||
| Libraries to be bound to a connection.</p> | ||
| <div class="section" id="categories"> | ||
| <h3>Categories<a class="headerlink" href="#categories" title="Permalink to this headline">¶</a></h3> | ||
| <p>Libraries provide access to a collection of symbols; Bindings provide an | ||
| interface to the symbols with respect to a subject database. When a connection | ||
| is established, multiple Bindings may need to be created in order to fulfill | ||
| the requirements of the programmer. When a Binding is created, it exists in | ||
| isolation; this can be an inconvenience when access to both the Binding and | ||
| the Connection is necessary. Categories exist to provide a formal method for | ||
| defining the interface extensions on a <cite>postgresql.api.Database</cite> | ||
| instance(connection).</p> | ||
| <p>A Category is essentially a runtime-class for connections. It provides a | ||
| formal initialization procedure for connection objects at runtime. However, | ||
| the connection resource must be connected prior to category initialization.</p> | ||
| <p>Categories are sets of Libraries to be bound to a connection with optional name | ||
| substitutions. In order to create one directly, pass the Library instances to | ||
| <cite>postgresql.lib.Category</cite>:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">postgresql.lib</span> <span class="kn">as</span> <span class="nn">pg_lib</span> | ||
| <span class="gp">>>> </span><span class="n">cat</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">Category</span><span class="p">(</span><span class="n">lib1</span><span class="p">,</span> <span class="n">lib2</span><span class="p">,</span> <span class="n">libN</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Where <tt class="docutils literal"><span class="pre">lib1</span></tt>, <tt class="docutils literal"><span class="pre">lib2</span></tt>, <tt class="docutils literal"><span class="pre">libN</span></tt> are <cite>postgresql.lib.Library</cite> instances; | ||
| usually created by <cite>postgresql.lib.load</cite>. Once created, categories can then | ||
| used by passing the <tt class="docutils literal"><span class="pre">category</span></tt> keyword to connection creation interfaces:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">postgresql</span> | ||
| <span class="gp">>>> </span><span class="n">db</span> <span class="o">=</span> <span class="n">postgresql</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">category</span> <span class="o">=</span> <span class="n">cat</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The <tt class="docutils literal"><span class="pre">db</span></tt> object will now have Bindings for <tt class="docutils literal"><span class="pre">lib1</span></tt>, <tt class="docutils literal"><span class="pre">lib2</span></tt>, ..., and | ||
| <tt class="docutils literal"><span class="pre">libN</span></tt>.</p> | ||
| <p>Categories can alter the access point(attribute name) of Bindings. This is done | ||
| by instantiating the Category using keyword parameters:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">cat</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">Category</span><span class="p">(</span><span class="n">lib1</span><span class="p">,</span> <span class="n">lib2</span><span class="p">,</span> <span class="n">libname</span> <span class="o">=</span> <span class="n">libN</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>At this point, when a connection is established as the category <tt class="docutils literal"><span class="pre">cat</span></tt>, | ||
| <tt class="docutils literal"><span class="pre">libN</span></tt> will be bound to the connection object on the attribute <tt class="docutils literal"><span class="pre">libname</span></tt> | ||
| instead of the name defined by the library.</p> | ||
| <p>And a final illustration of Category usage:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">db</span> <span class="o">=</span> <span class="n">postgresql</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">category</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">Category</span><span class="p">(</span><span class="n">pg_lib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s">'name'</span><span class="p">)))</span> | ||
| <span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">name</span> | ||
| <span class="go"><Library></span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="symbol-types"> | ||
| <h2>Symbol Types<a class="headerlink" href="#symbol-types" title="Permalink to this headline">¶</a></h2> | ||
| <p>The symbol type determines how a symbol is going to be treated by the Binding. | ||
| For instance, <tt class="docutils literal"><span class="pre">const</span></tt> symbols are resolved when the Library is bound and | ||
| the statement object is immediately discarded. Here is a list of symbol types | ||
| that can be used in ILF libraries:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre"><default></span></tt> (Empty component)</dt> | ||
| <dd>The symbol’s statement will never change. This allows the Bound Symbol to | ||
| hold onto the <cite>postgresql.api.PreparedStatement</cite> object. When the symbol is | ||
| used again, it will refer to the existing prepared statement object.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">preload</span></tt></dt> | ||
| <dd>Like the default type, the Symbol is a simple statement, but it should be | ||
| loaded when the library is bound to the connection.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">const</span></tt></dt> | ||
| <dd>The statement takes no parameters and only needs to be executed once. This | ||
| will cause the statement to be executed when the library is bound and the | ||
| results of the statement will be set to the Binding using the symbol name so | ||
| that it may be used as a property by the user.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">proc</span></tt></dt> | ||
| <dd>The contents of the section is a procedure identifier. When this type is used | ||
| the symbol method <em>should not</em> be specified as the method annotation will be | ||
| automatically resolved based on the procedure’s signature.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">transient</span></tt></dt> | ||
| <dd>The Symbol is a statement that should <em>not</em> be retained. Specifically, it is | ||
| a statement object that will be discarded when the user discard the referenced | ||
| Symbol. Used in cases where the statement is used once or very infrequently.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="symbol-execution-methods"> | ||
| <h2>Symbol Execution Methods<a class="headerlink" href="#symbol-execution-methods" title="Permalink to this headline">¶</a></h2> | ||
| <p>The Symbol Execution Method provides a way to specify how a statement is going | ||
| to be used. Specifically, which <cite>postgresql.api.PreparedStatement</cite> method | ||
| should be executed when a Bound Symbol is called. The following is a list of | ||
| the symbol execution methods and the effect it will have when invoked:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre"><default></span></tt> (Empty component)</dt> | ||
| <dd>Returns the entire result set in a single list object. If the statement does | ||
| not return rows, a <tt class="docutils literal"><span class="pre">(command,</span> <span class="pre">count)</span></tt> pair will be returned.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">rows</span></tt></dt> | ||
| <dd>Returns an iterator producing each row in the result set.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">chunks</span></tt></dt> | ||
| <dd>Returns an iterator producing “chunks” of rows in the result set.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">first</span></tt></dt> | ||
| <dd>Returns the first column of the first row if there is one column in the result | ||
| set. If there are multiple columns in the result set, the first row is | ||
| returned. If query is non-RETURNING DML–insert, update, or delete, the row | ||
| count is returned.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">column</span></tt></dt> | ||
| <dd>Returns an iterator to values in the first column. (Equivalent to | ||
| executing a statement as <tt class="docutils literal"><span class="pre">map(operator.itemgetter(0),</span> <span class="pre">ps.rows())</span></tt>.)</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">declare</span></tt></dt> | ||
| <dd>Returns a scrollable cursor, <cite>postgresql.api.Cursor</cite>, to the result set.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">load_chunks</span></tt></dt> | ||
| <dd>Takes an iterable row-chunks to be given to the statement. Returns <cite>None</cite>. If | ||
| the statement is a <tt class="docutils literal"><span class="pre">COPY</span> <span class="pre">...</span> <span class="pre">FROM</span> <span class="pre">STDIN</span></tt>, the iterable must produce chunks | ||
| of COPY lines.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">load_rows</span></tt></dt> | ||
| <dd>Takes an iterable rows to be given as parameters. If the statement is a <tt class="docutils literal"><span class="pre">COPY</span> | ||
| <span class="pre">...</span> <span class="pre">FROM</span> <span class="pre">STDIN</span></tt>, the iterable must produce COPY lines.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="reference-symbols"> | ||
| <h2>Reference Symbols<a class="headerlink" href="#reference-symbols" title="Permalink to this headline">¶</a></h2> | ||
| <p>Reference Symbols provide a way to construct a Bound Symbol using the Symbol’s | ||
| query. When invoked, A Reference Symbol’s query is executed in order to produce | ||
| an SQL statement to be used as a Bound Symbol. In ILF files, a reference is | ||
| identified by its symbol name being prefixed with an ampersand:</p> | ||
| <div class="highlight-python"><pre>[&refsym::first] | ||
| SELECT 'SELECT 1::int4'::text</pre> | ||
| </div> | ||
| <p>Then executed:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="c"># Runs the 'refsym' SQL, and creates a Bound Symbol using the results.</span> | ||
| <span class="gp">>>> </span><span class="n">sym</span> <span class="o">=</span> <span class="n">lib</span><span class="o">.</span><span class="n">refsym</span><span class="p">()</span> | ||
| <span class="gp">>>> </span><span class="k">assert</span> <span class="n">sym</span><span class="p">()</span> <span class="o">==</span> <span class="mi">1</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The Reference Symbol’s type and execution method are inherited by the created | ||
| Bound Symbol. With one exception, <tt class="docutils literal"><span class="pre">const</span></tt> reference symbols are | ||
| special in that they immediately resolved into the target Bound Symbol.</p> | ||
| <p>A Reference Symbol’s source query <em>must</em> produce rows of text columns. Multiple | ||
| columns and multiple rows may be produced by the query, but they must be | ||
| character types as the results are promptly joined together with whitespace so | ||
| that the target statement may be prepared.</p> | ||
| <p>Reference Symbols are most likely to be used in dynamic DDL and DML situations, | ||
| or, somewhat more specifically, any query whose definition depends on a | ||
| generated column list.</p> | ||
| </div> | ||
| <div class="section" id="distributing-and-usage"> | ||
| <h2>Distributing and Usage<a class="headerlink" href="#distributing-and-usage" title="Permalink to this headline">¶</a></h2> | ||
| <p>For applications, distribution and management can easily be a custom | ||
| process. The application designates the library directory; the entry point | ||
| adds the path to the <cite>postgresql.sys.libpath</cite> list; a category is built; and, a | ||
| connection is made using the category.</p> | ||
| <p>For mere Python extensions, however, <tt class="docutils literal"><span class="pre">distutils</span></tt> has a feature that can | ||
| aid in ILF distribution. The <tt class="docutils literal"><span class="pre">package_data</span></tt> setup keyword can be used to | ||
| include ILF files alongside the Python modules that make up a project. See | ||
| <a class="reference external" href="http://docs.python.org/3.1/distutils/setupscript.html#installing-package-data">http://docs.python.org/3.1/distutils/setupscript.html#installing-package-data</a> | ||
| for more detailed information on the keyword parameter.</p> | ||
| <p>The recommended way to manage libraries for extending projects is to | ||
| create a package to contain them. For instance, consider the following layout:</p> | ||
| <div class="highlight-python"><pre>project/ | ||
| setup.py | ||
| pkg/ | ||
| __init__.py | ||
| lib/ | ||
| __init__.py | ||
| libthis.sql | ||
| libthat.sql</pre> | ||
| </div> | ||
| <p>The project’s SQL libraries are organized into a single package directory, | ||
| <tt class="docutils literal"><span class="pre">lib</span></tt>, so <tt class="docutils literal"><span class="pre">package_data</span></tt> would be configured:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="n">package_data</span> <span class="o">=</span> <span class="p">{</span><span class="s">'pkg.lib'</span><span class="p">:</span> <span class="p">[</span><span class="s">'*.sql'</span><span class="p">]}</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Subsequently, the <tt class="docutils literal"><span class="pre">lib</span></tt> package initialization script can then be used to | ||
| load the libraries, and create any categories(<tt class="docutils literal"><span class="pre">project/pkg/lib/__init__.py</span></tt>):</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os.path</span> | ||
| <span class="kn">import</span> <span class="nn">postgresql.lib</span> <span class="kn">as</span> <span class="nn">pg_lib</span> | ||
| <span class="kn">import</span> <span class="nn">postgresql.sys</span> <span class="kn">as</span> <span class="nn">pg_sys</span> | ||
| <span class="n">libdir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">)</span> | ||
| <span class="n">pg_sys</span><span class="o">.</span><span class="n">libpath</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">libdir</span><span class="p">)</span> | ||
| <span class="n">libthis</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s">'this'</span><span class="p">)</span> | ||
| <span class="n">libthat</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s">'that'</span><span class="p">)</span> | ||
| <span class="n">stdcat</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">Category</span><span class="p">(</span><span class="n">libthis</span><span class="p">,</span> <span class="n">libthat</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>However, it can be undesirable to add the package directory to the global | ||
| <cite>postgresql.sys.libpath</cite> search paths. Direct path loading can be used in those | ||
| cases:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os.path</span> | ||
| <span class="kn">import</span> <span class="nn">postgresql.lib</span> <span class="kn">as</span> <span class="nn">pg_lib</span> | ||
| <span class="n">libdir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">)</span> | ||
| <span class="n">libthis</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">libdir</span><span class="p">,</span> <span class="s">'libthis.sql'</span><span class="p">))</span> | ||
| <span class="n">libthat</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">libdir</span><span class="p">,</span> <span class="s">'libthat.sql'</span><span class="p">))</span> | ||
| <span class="n">stdcat</span> <span class="o">=</span> <span class="n">pg_lib</span><span class="o">.</span><span class="n">Category</span><span class="p">(</span><span class="n">libthis</span><span class="p">,</span> <span class="n">libthat</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Using the established project context, a connection would then be created as:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">pkg.lib</span> <span class="kn">import</span> <span class="n">stdcat</span> | ||
| <span class="kn">import</span> <span class="nn">postgresql</span> <span class="kn">as</span> <span class="nn">pg</span> | ||
| <span class="n">db</span> <span class="o">=</span> <span class="n">pg</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="o">...</span><span class="p">,</span> <span class="n">category</span> <span class="o">=</span> <span class="n">stdcat</span><span class="p">)</span> | ||
| <span class="c"># And execute some fictitious symbols.</span> | ||
| <span class="n">db</span><span class="o">.</span><span class="n">this</span><span class="o">.</span><span class="n">sym_from_libthis</span><span class="p">()</span> | ||
| <span class="n">db</span><span class="o">.</span><span class="n">that</span><span class="o">.</span><span class="n">sym_from_libthat</span><span class="p">(</span><span class="o">...</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| </div> | ||
| <div class="section" id="audience-and-motivation"> | ||
| <h2>Audience and Motivation<a class="headerlink" href="#audience-and-motivation" title="Permalink to this headline">¶</a></h2> | ||
| <p>This chapter covers advanced material. It is <strong>not</strong> recommended that categories | ||
| and libraries be used for trivial applications or introductory projects.</p> | ||
| <div class="admonition note"> | ||
| <p class="first admonition-title">Note</p> | ||
| <p class="last">Libraries and categories are not likely to be of interest to ORM or DB-API users.</p> | ||
| </div> | ||
| <p>With exception to ORMs or other similar abstractions, the most common pattern | ||
| for managing connections and statements is delegation:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">MyAppDB</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> | ||
| <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">connection</span><span class="p">):</span> | ||
| <span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="o">=</span> <span class="n">connection</span> | ||
| <span class="k">def</span> <span class="nf">my_operation</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">op_arg1</span><span class="p">,</span> <span class="n">op_arg2</span><span class="p">):</span> | ||
| <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span> | ||
| <span class="s">"SELECT my_operation_proc($1,$2)"</span><span class="p">,</span> | ||
| <span class="p">)(</span><span class="n">op_arg1</span><span class="p">,</span> <span class="n">op_arg2</span><span class="p">)</span> | ||
| <span class="o">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The straightforward nature is likeable, but the usage does not take advantage of | ||
| prepared statements. In order to do that an extra condition is necessary to see | ||
| if the statement has already been prepared:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="o">...</span> | ||
| <span class="k">def</span> <span class="nf">my_operation</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">op_arg1</span><span class="p">,</span> <span class="n">op_arg2</span><span class="p">):</span> | ||
| <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s">'_my_operation'</span><span class="p">):</span> | ||
| <span class="n">ps</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_my_operation</span> | ||
| <span class="k">else</span><span class="p">:</span> | ||
| <span class="n">ps</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_my_operation</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span> | ||
| <span class="s">"SELECT my_operation_proc($1, $2)"</span><span class="p">,</span> | ||
| <span class="p">)</span> | ||
| <span class="k">return</span> <span class="n">ps</span><span class="p">(</span><span class="n">op_arg1</span><span class="p">,</span> <span class="n">op_arg2</span><span class="p">)</span> | ||
| <span class="o">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>There are many variations that can implement the above. It works and it’s | ||
| simple, but it will be exhausting if repeated and error prone if the | ||
| initialization condition is not factored out. Additionally, if access to statement | ||
| metadata is needed, the above example is still lacking as it would require | ||
| execution of the statement and further protocol expectations to be established. | ||
| This is the province of libraries: direct database interface management.</p> | ||
| <p>Categories and Libraries are used to factor out and simplify | ||
| the above functionality so re-implementation is unnecessary. For example, an | ||
| ILF library containing the symbol:</p> | ||
| <div class="highlight-python"><pre>[my_operation] | ||
| SELECT my_operation_proc($1, $2) | ||
| [<other_symbol>] | ||
| ...</pre> | ||
| </div> | ||
| <p>Will provide the same functionality as the <tt class="docutils literal"><span class="pre">my_operation</span></tt> method in the | ||
| latter Python implementation.</p> | ||
| </div> | ||
| <div class="section" id="terminology"> | ||
| <h2>Terminology<a class="headerlink" href="#terminology" title="Permalink to this headline">¶</a></h2> | ||
| <p>The following terms are used throughout this chapter:</p> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt>Annotations</dt> | ||
| <dd>The information of about a Symbol describing what it is and how it should be | ||
| used.</dd> | ||
| <dt>Binding</dt> | ||
| <dd>An interface to the Symbols provided by a Library for use with a given | ||
| connection.</dd> | ||
| <dt>Bound Symbol</dt> | ||
| <dd>An interface to an individual Symbol ready for execution against the subject | ||
| database.</dd> | ||
| <dt>Bound Reference</dt> | ||
| <dd>An interface to an individual Reference Symbol that will produce a Bound | ||
| Symbol when executed.</dd> | ||
| <dt>ILF</dt> | ||
| <dd>INI-style Library Format. “lib{NAME}.sql” files.</dd> | ||
| <dt>Library</dt> | ||
| <dd>A collection of Symbols–mapping of names to SQL statements.</dd> | ||
| <dt>Local Symbol</dt> | ||
| <dd>A relative term used to denote a symbol that exists in the same library as | ||
| the subject symbol.</dd> | ||
| <dt>Preface</dt> | ||
| <dd>The block of text that comes before the first symbol in an ILF file.</dd> | ||
| <dt>Symbol</dt> | ||
| <dd>An named database operation provided by a Library. Usually, an SQL statement | ||
| with Annotations.</dd> | ||
| <dt>Reference Symbol</dt> | ||
| <dd>A Symbol whose SQL statement <em>produces</em> the source for a Bound Symbol.</dd> | ||
| <dt>Category</dt> | ||
| <dd>An object supporting a classification for connectors that provides database | ||
| initialization facilities for produced connections. For libraries, | ||
| <cite>postgresql.lib.Category</cite> objects are a set of Libraries, | ||
| <cite>postgresql.lib.Library</cite>.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Categories and Libraries</a><ul> | ||
| <li><a class="reference internal" href="#writing-libraries">Writing Libraries</a></li> | ||
| <li><a class="reference internal" href="#using-libraries">Using Libraries</a><ul> | ||
| <li><a class="reference internal" href="#categories">Categories</a></li> | ||
| </ul> | ||
| </li> | ||
| <li><a class="reference internal" href="#symbol-types">Symbol Types</a></li> | ||
| <li><a class="reference internal" href="#symbol-execution-methods">Symbol Execution Methods</a></li> | ||
| <li><a class="reference internal" href="#reference-symbols">Reference Symbols</a></li> | ||
| <li><a class="reference internal" href="#distributing-and-usage">Distributing and Usage</a></li> | ||
| <li><a class="reference internal" href="#audience-and-motivation">Audience and Motivation</a></li> | ||
| <li><a class="reference internal" href="#terminology">Terminology</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="cluster.html" | ||
| title="previous chapter">Cluster Management</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="clientparameters.html" | ||
| title="next chapter">Client Parameters</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/lib.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="clientparameters.html" title="Client Parameters" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="cluster.html" title="Cluster Management" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Notification Management — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="next" title="Advisory Locks" href="alock.html" /> | ||
| <link rel="prev" title="Copy Management" href="copyman.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="alock.html" title="Advisory Locks" | ||
| accesskey="N">next</a> |</li> | ||
| <li class="right" > | ||
| <a href="copyman.html" title="Copy Management" | ||
| accesskey="P">previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <div class="section" id="notification-management"> | ||
| <span id="notifyman"></span><h1>Notification Management<a class="headerlink" href="#notification-management" title="Permalink to this headline">¶</a></h1> | ||
| <p>Relevant SQL commands: <a class="reference external" href="http://postgresql.org/docs/current/static/sql-notify.html">NOTIFY</a>, | ||
| <a class="reference external" href="http://postgresql.org/docs/current/static/sql-listen.html">LISTEN</a>, | ||
| <a class="reference external" href="http://postgresql.org/docs/current/static/sql-unlisten.html">UNLISTEN</a>.</p> | ||
| <p>Asynchronous notifications offer a means for PostgreSQL to signal application | ||
| code. Often these notifications are used to signal cache invalidation. In 9.0 | ||
| and greater, notifications may include a “payload” in which arbitrary data may | ||
| be delivered on a channel being listened to.</p> | ||
| <p>By default, received notifications will merely be appended to an internal | ||
| list on the connection object. This list will remain empty for the duration | ||
| of a connection <em>unless</em> the connection begins listening to a channel that | ||
| receives notifications.</p> | ||
| <p>The <cite>postgresql.notifyman.NotificationManager</cite> class is used to wait for | ||
| messages to come in on a set of connections, pick up the messages, and deliver | ||
| the messages to the object’s user via the <cite>collections.Iterator</cite> protocol.</p> | ||
| <div class="section" id="listening-on-a-single-connection"> | ||
| <h2>Listening on a Single Connection<a class="headerlink" href="#listening-on-a-single-connection" title="Permalink to this headline">¶</a></h2> | ||
| <p>The <tt class="docutils literal"><span class="pre">db.iternotifies()</span></tt> method is a simplification of the notification manager. It | ||
| returns an iterator to the notifications received on the subject connection. | ||
| The iterator yields triples consisting of the <tt class="docutils literal"><span class="pre">channel</span></tt> being | ||
| notified, the <tt class="docutils literal"><span class="pre">payload</span></tt> sent with the notification, and the <tt class="docutils literal"><span class="pre">pid</span></tt> of the | ||
| backend that caused the notification:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="s">'for_rabbits'</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">db</span><span class="o">.</span><span class="n">notify</span><span class="p">(</span><span class="s">'for_rabbits'</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">db</span><span class="o">.</span><span class="n">iternotifies</span><span class="p">():</span> | ||
| <span class="gp">... </span> <span class="n">channel</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">pid</span> <span class="o">=</span> <span class="n">x</span> | ||
| <span class="gp">... </span> <span class="k">break</span> | ||
| <span class="gp">>>> </span><span class="k">assert</span> <span class="n">channel</span> <span class="o">==</span> <span class="s">'for_rabbits'</span> | ||
| <span class="go">True</span> | ||
| <span class="gp">>>> </span><span class="k">assert</span> <span class="n">payload</span> <span class="o">==</span> <span class="s">''</span> | ||
| <span class="go">True</span> | ||
| <span class="gp">>>> </span><span class="k">assert</span> <span class="n">pid</span> <span class="o">==</span> <span class="n">db</span><span class="o">.</span><span class="n">backend_id</span> | ||
| <span class="go">True</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The iterator, by default, will continue listening forever unless the connection | ||
| is terminated–thus the immediate <tt class="docutils literal"><span class="pre">break</span></tt> statement in the above loop. In | ||
| cases where some additional activity is necessary, a timeout parameter may be | ||
| given to the <tt class="docutils literal"><span class="pre">iternotifies</span></tt> method in order to allow “idle” events to occur | ||
| at the designated frequency:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">db</span><span class="o">.</span><span class="n">iternotifies</span><span class="p">(</span><span class="mf">0.5</span><span class="p">):</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">break</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The above example illustrates that idle events are represented using <cite>None</cite> | ||
| objects. Idle events are guaranteed to occur <em>approximately</em> at the | ||
| specified interval–the <tt class="docutils literal"><span class="pre">timeout</span></tt> keyword parameter. In addition to | ||
| providing a means to do other processing or polling, they also offer a safe | ||
| break point for the loop. Internally, the iterator produced by the | ||
| <tt class="docutils literal"><span class="pre">iternotifies</span></tt> method <em>is</em> a <cite>NotificationManager</cite>, which will localize the | ||
| notifications prior to emitting them via the iterator. | ||
| <em>It’s not safe to break out of the loop, unless an idle event is being handled.</em> | ||
| If the loop is broken while a regular event is being processed, some events may | ||
| remain in the iterator. In order to consume those events, the iterator <em>must</em> | ||
| be accessible.</p> | ||
| <p>The iterator will be exhausted when the connection is closed, but if the | ||
| connection is closed during the loop, any remaining notifications <em>will</em> | ||
| be emitted prior to the loop ending, so it is important to be prepared to | ||
| handle exceptions or check for a closed connection.</p> | ||
| <p>In situations where multiple connections need to be watched, direct use of the | ||
| <cite>NotificationManager</cite> is necessary.</p> | ||
| </div> | ||
| <div class="section" id="listening-on-multiple-connections"> | ||
| <h2>Listening on Multiple Connections<a class="headerlink" href="#listening-on-multiple-connections" title="Permalink to this headline">¶</a></h2> | ||
| <p>The <cite>postgresql.notifyman.NotificationManager</cite> class is used to manage | ||
| <em>connections</em> that are expecting to receive notifications. Instances are | ||
| iterators that yield the connection object and notifications received on the | ||
| connection or <cite>None</cite> in the case of an idle event. The manager emits events as | ||
| a pair; the connection object that received notifications, and <em>all</em> the | ||
| notifications picked up on that connection:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">postgresql.notifyman</span> <span class="kn">import</span> <span class="n">NotificationManager</span> | ||
| <span class="gp">>>> </span><span class="c"># Using ``nm`` to reference the manager from here on.</span> | ||
| <span class="gp">>>> </span><span class="n">nm</span> <span class="o">=</span> <span class="n">NotificationManager</span><span class="p">(</span><span class="n">db1</span><span class="p">,</span> <span class="n">db2</span><span class="p">,</span> <span class="o">...</span><span class="p">,</span> <span class="n">dbN</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">nm</span><span class="o">.</span><span class="n">settimeout</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">nm</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="c"># idle</span> | ||
| <span class="gp">... </span> <span class="k">break</span> | ||
| <span class="gp">...</span> | ||
| <span class="gp">... </span> <span class="n">db</span><span class="p">,</span> <span class="n">notifies</span> <span class="o">=</span> <span class="n">x</span> | ||
| <span class="gp">... </span> <span class="k">for</span> <span class="n">channel</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">pid</span> <span class="ow">in</span> <span class="n">notifies</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="o">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The manager will continue to wait for and emit events so long as there are | ||
| good connections available in the set; it is possible for connections to be | ||
| added and removed at any time. Although, in rare circumstances, discarded | ||
| connections may still have pending events if it not removed during an idle | ||
| event. The <tt class="docutils literal"><span class="pre">connections</span></tt> attribute on <cite>NotificationManager</cite> objects is a | ||
| set object that may be used directly in order to add and remove connections | ||
| from the manager:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">y</span> <span class="o">=</span> <span class="p">[]</span> | ||
| <span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">nm</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">y</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="n">nm</span><span class="o">.</span><span class="n">connections</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> | ||
| <span class="gp">... </span> <span class="k">del</span> <span class="n">y</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> | ||
| <span class="gp">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>The notification manager is resilient; if a connection dies, it will discard the | ||
| connection from the set, and add it to the set of bad connections, the | ||
| <tt class="docutils literal"><span class="pre">garbage</span></tt> attribute. In these cases, the idle event <em>should</em> be leveraged to | ||
| check for these failures if that’s a concern. It is the user’s | ||
| responsibility to explicitly handle the failure cases, and remove the bad | ||
| connections from the <tt class="docutils literal"><span class="pre">garbage</span></tt> set:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">nm</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">x</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">nm</span><span class="o">.</span><span class="n">garbage</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="n">recovered</span> <span class="o">=</span> <span class="n">take_out_trash</span><span class="p">(</span><span class="n">nm</span><span class="o">.</span><span class="n">garbage</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="n">nm</span><span class="o">.</span><span class="n">connections</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">recovered</span><span class="p">)</span> | ||
| <span class="gp">... </span> <span class="n">nm</span><span class="o">.</span><span class="n">garbage</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span> | ||
| <span class="gp">... </span> <span class="n">db</span><span class="p">,</span> <span class="n">notifies</span> <span class="o">=</span> <span class="n">x</span> | ||
| <span class="gp">... </span> <span class="k">for</span> <span class="n">channel</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">pid</span> <span class="ow">in</span> <span class="n">notifies</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="o">...</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Explicitly removing connections from the set can also be a means to gracefully | ||
| terminate the event loop:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">nm</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">x</span> <span class="ow">in</span> <span class="bp">None</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="k">if</span> <span class="n">done_listening</span> <span class="ow">is</span> <span class="bp">True</span><span class="p">:</span> | ||
| <span class="gp">... </span> <span class="n">nm</span><span class="o">.</span><span class="n">connections</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>However, doing so inside the loop is not a requirement; it is safe to remove a | ||
| connection from the set at any point.</p> | ||
| </div> | ||
| <div class="section" id="notification-managers"> | ||
| <h2>Notification Managers<a class="headerlink" href="#notification-managers" title="Permalink to this headline">¶</a></h2> | ||
| <p>The <cite>postgresql.notifyman.NotificationManager</cite> is an event loop that services | ||
| multiple connections. In cases where only one connection needs to be serviced, | ||
| the <cite>postgresql.api.Database.iternotifies</cite> method can be used to simplify the | ||
| process.</p> | ||
| <div class="section" id="notification-manager-constructors"> | ||
| <h3>Notification Manager Constructors<a class="headerlink" href="#notification-manager-constructors" title="Permalink to this headline">¶</a></h3> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager(*connections,</span> <span class="pre">timeout</span> <span class="pre">=</span> <span class="pre">None)</span></tt></dt> | ||
| <dd>Create a NotificationManager instance that manages the notifications coming | ||
| from the given set of connections. The <tt class="docutils literal"><span class="pre">timeout</span></tt> keyword is optional and | ||
| can be configured using the <tt class="docutils literal"><span class="pre">settimeout</span></tt> method as well.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="notification-manager-interface-points"> | ||
| <h3>Notification Manager Interface Points<a class="headerlink" href="#notification-manager-interface-points" title="Permalink to this headline">¶</a></h3> | ||
| <blockquote> | ||
| <div><dl class="docutils"> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager.__iter__()</span></tt></dt> | ||
| <dd>Returns the instance; it is an iterator.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager.__next__()</span></tt></dt> | ||
| <dd>Normally, yield the pair, connection and notifications list, when the next | ||
| event is received. If a timeout is configured, <cite>None</cite> may be yielded to signal | ||
| an idle event. The notifications list is a list of triples: | ||
| <tt class="docutils literal"><span class="pre">(channel,</span> <span class="pre">payload,</span> <span class="pre">pid)</span></tt>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager.settimeout(timeout</span> <span class="pre">:</span> <span class="pre">int)</span></tt></dt> | ||
| <dd>Set the amount of time to wait before the manager yields an idle event. | ||
| If zero, the manager will never wait and only yield notifications that are | ||
| immediately available. | ||
| If <cite>None</cite>, the manager will never emit idle events.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager.gettimeout()</span> <span class="pre">-></span> <span class="pre">[int,</span> <span class="pre">None]</span></tt></dt> | ||
| <dd>Get the configured timeout; returns either <cite>None</cite>, or an <cite>int</cite>.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager.connections</span></tt></dt> | ||
| <dd>The set of connections that the manager is actively watching for | ||
| notifications. Connections may be added or removed from the set at any time.</dd> | ||
| <dt><tt class="docutils literal"><span class="pre">NotificationManager.garbage</span></tt></dt> | ||
| <dd>The set of connections that failed. Normally empty, but when a connection gets | ||
| an exceptional condition or explicitly raises an exception, it is removed from | ||
| the <tt class="docutils literal"><span class="pre">connections</span></tt> set, and placed in <tt class="docutils literal"><span class="pre">garbage</span></tt>.</dd> | ||
| </dl> | ||
| </div></blockquote> | ||
| </div> | ||
| <div class="section" id="zero-timeout"> | ||
| <h3>Zero Timeout<a class="headerlink" href="#zero-timeout" title="Permalink to this headline">¶</a></h3> | ||
| <p>When a timeout of zero, <tt class="docutils literal"><span class="pre">0</span></tt>, is configured, the notification manager will | ||
| terminate early. Specifically, each connection will be polled for any pending | ||
| notifications, and once all of the collected notifications have been emitted | ||
| by the iterator, <cite>StopIteration</cite> will be raised. Notably, <em>no</em> idle events will | ||
| occur when the timeout is configured to zero.</p> | ||
| <p>Zero timeouts offer a means for the notification “queue” to be polled. Often, | ||
| this is the appropriate way to collect pending notifications on active | ||
| connections where using the connection exclusively for waiting is not | ||
| practical:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">notifies</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">iternotifies</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>Or with a NotificationManager instance:</p> | ||
| <div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">nm</span><span class="o">.</span><span class="n">settimeout</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> | ||
| <span class="gp">>>> </span><span class="n">db_notifies</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">nm</span><span class="p">)</span> | ||
| </pre></div> | ||
| </div> | ||
| <p>In both cases of zero timeout, the iterator may be promptly discarded without | ||
| losing any events.</p> | ||
| </div> | ||
| <div class="section" id="summary-of-characteristics"> | ||
| <h3>Summary of Characteristics<a class="headerlink" href="#summary-of-characteristics" title="Permalink to this headline">¶</a></h3> | ||
| <blockquote> | ||
| <div><ul class="simple"> | ||
| <li>The iterator will continue until the connections die.</li> | ||
| <li>Objects yielded by the iterator are either <cite>None</cite>, an “idle event”, or an | ||
| individual notification triple if using <tt class="docutils literal"><span class="pre">db.iternotifies()</span></tt>, or a | ||
| <tt class="docutils literal"><span class="pre">(db,</span> <span class="pre">notifies)</span></tt> pair if using the base <cite>NotificationManager</cite>.</li> | ||
| <li>When a connection dies or raises an exception, it will be removed from | ||
| the <tt class="docutils literal"><span class="pre">nm.connections</span></tt> set and added to the <tt class="docutils literal"><span class="pre">nm.garbage</span></tt> set.</li> | ||
| <li>The NotificationManager instance will <em>not</em> hold any notifications | ||
| during an idle event. Idle events offer a break point in which the manager | ||
| may be discarded.</li> | ||
| <li>A timeout of zero will cause the iterator to only yield the events | ||
| that are pending right now, and promptly end. However, the same manager | ||
| object may be used again.</li> | ||
| <li>A notification triple is a tuple consisting of <tt class="docutils literal"><span class="pre">(channel,</span> <span class="pre">payload,</span> <span class="pre">pid)</span></tt>.</li> | ||
| <li>Connections may be added and removed from the <tt class="docutils literal"><span class="pre">nm.connections</span></tt> set at | ||
| any time.</li> | ||
| </ul> | ||
| </div></blockquote> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <h3><a href="index.html">Table Of Contents</a></h3> | ||
| <ul> | ||
| <li><a class="reference internal" href="#">Notification Management</a><ul> | ||
| <li><a class="reference internal" href="#listening-on-a-single-connection">Listening on a Single Connection</a></li> | ||
| <li><a class="reference internal" href="#listening-on-multiple-connections">Listening on Multiple Connections</a></li> | ||
| <li><a class="reference internal" href="#notification-managers">Notification Managers</a><ul> | ||
| <li><a class="reference internal" href="#notification-manager-constructors">Notification Manager Constructors</a></li> | ||
| <li><a class="reference internal" href="#notification-manager-interface-points">Notification Manager Interface Points</a></li> | ||
| <li><a class="reference internal" href="#zero-timeout">Zero Timeout</a></li> | ||
| <li><a class="reference internal" href="#summary-of-characteristics">Summary of Characteristics</a></li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| </li> | ||
| </ul> | ||
| <h4>Previous topic</h4> | ||
| <p class="topless"><a href="copyman.html" | ||
| title="previous chapter">Copy Management</a></p> | ||
| <h4>Next topic</h4> | ||
| <p class="topless"><a href="alock.html" | ||
| title="next chapter">Advisory Locks</a></p> | ||
| <h3>This Page</h3> | ||
| <ul class="this-page-menu"> | ||
| <li><a href="_sources/notifyman.txt" | ||
| rel="nofollow">Show Source</a></li> | ||
| </ul> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li class="right" > | ||
| <a href="alock.html" title="Advisory Locks" | ||
| >next</a> |</li> | ||
| <li class="right" > | ||
| <a href="copyman.html" title="Copy Management" | ||
| >previous</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
Sorry, the diff of this file is not supported yet
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Python Module Index — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="#" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1>Python Module Index</h1> | ||
| <div class="modindex-jumpbox"> | ||
| <a href="#cap-p"><strong>p</strong></a> | ||
| </div> | ||
| <table class="indextable modindextable" cellspacing="0" cellpadding="2"> | ||
| <tr class="pcap"><td></td><td> </td><td></td></tr> | ||
| <tr class="cap" id="cap-p"><td></td><td> | ||
| <strong>p</strong></td><td></td></tr> | ||
| <tr> | ||
| <td><img src="_static/minus.png" class="toggler" | ||
| id="toggle-1" style="display: none" alt="-" /></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql"><tt class="xref">postgresql</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.alock"><tt class="xref">postgresql.alock</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.api"><tt class="xref">postgresql.api</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.cluster"><tt class="xref">postgresql.cluster</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.copyman"><tt class="xref">postgresql.copyman</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.exceptions"><tt class="xref">postgresql.exceptions</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.installation"><tt class="xref">postgresql.installation</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.string"><tt class="xref">postgresql.string</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.sys"><tt class="xref">postgresql.sys</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| <tr class="cg-1"> | ||
| <td></td> | ||
| <td> | ||
| <a href="reference.html#module-postgresql.temporal"><tt class="xref">postgresql.temporal</tt></a></td><td> | ||
| <em></em></td></tr> | ||
| </table> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| <div id="searchbox" style="display: none"> | ||
| <h3>Quick search</h3> | ||
| <form class="search" action="search.html" method="get"> | ||
| <input type="text" name="q" /> | ||
| <input type="submit" value="Go" /> | ||
| <input type="hidden" name="check_keywords" value="yes" /> | ||
| <input type="hidden" name="area" value="default" /> | ||
| </form> | ||
| <p class="searchtip" style="font-size: 90%"> | ||
| Enter search terms or a module, class or function name. | ||
| </p> | ||
| </div> | ||
| <script type="text/javascript">$('#searchbox').show(0);</script> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="#" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
Sorry, the diff of this file is too big to display
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | ||
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||
| <title>Search — py-postgresql 1.1.0 documentation</title> | ||
| <link rel="stylesheet" href="_static/default.css" type="text/css" /> | ||
| <link rel="stylesheet" href="_static/pygments.css" type="text/css" /> | ||
| <script type="text/javascript"> | ||
| var DOCUMENTATION_OPTIONS = { | ||
| URL_ROOT: '', | ||
| VERSION: '1.1.0', | ||
| COLLAPSE_INDEX: false, | ||
| FILE_SUFFIX: '.html', | ||
| HAS_SOURCE: true | ||
| }; | ||
| </script> | ||
| <script type="text/javascript" src="_static/jquery.js"></script> | ||
| <script type="text/javascript" src="_static/underscore.js"></script> | ||
| <script type="text/javascript" src="_static/doctools.js"></script> | ||
| <script type="text/javascript" src="_static/searchtools.js"></script> | ||
| <link rel="top" title="py-postgresql 1.1.0 documentation" href="index.html" /> | ||
| <script type="text/javascript"> | ||
| jQuery(function() { Search.loadIndex("searchindex.js"); }); | ||
| </script> | ||
| <link rel="stylesheet" href="_static/unsuck.css" type="text/css" /> | ||
| </head> | ||
| <body> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| accesskey="I">index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="document"> | ||
| <div class="documentwrapper"> | ||
| <div class="bodywrapper"> | ||
| <div class="body"> | ||
| <h1 id="search-documentation">Search</h1> | ||
| <div id="fallback" class="admonition warning"> | ||
| <script type="text/javascript">$('#fallback').hide();</script> | ||
| <p> | ||
| Please activate JavaScript to enable the search | ||
| functionality. | ||
| </p> | ||
| </div> | ||
| <p> | ||
| From here you can search these documents. Enter your search | ||
| words into the box below and click "search". Note that the search | ||
| function will automatically search for all of the words. Pages | ||
| containing fewer words won't appear in the result list. | ||
| </p> | ||
| <form action="" method="get"> | ||
| <input type="text" name="q" value="" /> | ||
| <input type="submit" value="search" /> | ||
| <span id="search-progress" style="padding-left: 10px"></span> | ||
| </form> | ||
| <div id="search-results"> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="sphinxsidebar"> | ||
| <div class="sphinxsidebarwrapper"> | ||
| </div> | ||
| </div> | ||
| <div class="clearer"></div> | ||
| </div> | ||
| <div class="related"> | ||
| <h3>Navigation</h3> | ||
| <ul> | ||
| <li class="right" style="margin-right: 10px"> | ||
| <a href="genindex.html" title="General Index" | ||
| >index</a></li> | ||
| <li class="right" > | ||
| <a href="py-modindex.html" title="Python Module Index" | ||
| >modules</a> |</li> | ||
| <li><a href="index.html">py-postgresql 1.1.0 documentation</a> »</li> | ||
| </ul> | ||
| </div> | ||
| <div class="footer"> | ||
| © Copyright Python+Postgres. | ||
| Last updated on Oct 08, 2012. | ||
| Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. | ||
| </div> | ||
| </body> | ||
| </html> |
| Search.setIndex({filenames:["copyman","alock","bin","notifyman","clientparameters","cluster","reference","driver","index","lib","gotchas","changes-v1.0","changes-v1.1","admin"],titles:["Copy Management","Advisory Locks","Commands","Notification Management","Client Parameters","Cluster Management","Reference","Driver","py-postgresql","Categories and Libraries","Gotchas","Changes in v1.0","Changes in v1.1","Administration"],terms:{"25p02":[7,6],"25p01":6,prior:[9,3,7],cidr:12,gigabyt:0,begin:[7,3,6],cluster_dirnam:6,datamodificationprohibitederror:6,enable_debug:5,deprecationwarn:6,mandir:5,addit:[7,3,4,6],featur:[9,1,8,6,7,5,10],jwp:[11,4,12,2],sensit:6,amount:[0,3,7],diskfullerror:6,"2201x":6,fact:7,timedelta:7,directori:[9,5,4,6,13],binari:[7,8,11,6,10],pass:[9,10,6,7],pg_restor:5,lowerbound:11,datatyp:7,pg_directori:5,operationerror:6,escapesequenceerror:6,backend_id:[7,3,6],prefac:9,lib:[9,5,11],server_encod:[7,10],howev:[0,1,9,3,4,7,5,10,13],t62000:7,benefit:0,what:[9,6,7],replac:[5,6],direct:[0,9,3,6,7,2,11],abil:[7,5,6],gener:[0,9,6,7,11,10],pg_config_dictionari:[5,6],kerberos4_realm:4,numericoid:7,valu:[9,8,2,4,6,7,5,11,10],non:[9,4,8,6,5,10],setof:7,augment:[4,2],now:[9,3,12],clusterwarn:6,sql_column_typ:[7,6],numericrangeerror:6,nomoresetsreturn:6,instruct:[7,4,6],path:[9,2,4,6,7,5,13],latter:[9,7],requir:[0,9,3,6,7,5,2,12,10],reindexdb:5,"final":[7,0,6,9],optpars:4,edit:2,around:[7,12],composit:[7,11,10],recogn:[7,10],sql:[7,9,3,6,2],could:1,dictionari:[0,5,4,6,7],befor:[9,5,3,4,7],zerodivisionerror:6,atabl:7,john:[7,8],necessari:[0,9,3,4,6,7,5,12,10],probabl:10,verbos:[7,8,11,10],current:[5,7,1,4,6],employee_salari:7,allow:[9,1,2,3,4,6,7,5,11,10],rule:[7,6],rolespecificationerror:6,compound:7,shut:5,different_channel:7,each:[0,1,9,3,6,7,5],createlang:5,rel:[9,6,7],server:[7,5,10,6,2],db_notifi:3,explicit:[7,1,4,10],forev:3,layout:[9,5],libthi:9,serial:7,between:[7,5,6],desir:[2,8,6,7,5,11,10],pgsslkei:4,with_libedit_pref:5,multipl:[9,1,8,2,3,6,7,5,11],tzinfo:7,implement:[0,9,6,7,11,12,10],pgsql:[5,6],"0l000":6,need:[0,1,9,3,4,6,7,5,10,13],indexerror:7,simpl:[9,2,4,6,7,12,13],random:7,author:[11,4],suffix:9,payload:[7,3,6],nullvaluenotallow:6,escapecharactererror:6,suffic:4,given:[0,1,2,3,4,6,9,7,5,11,10],ct_that:7,timestamp:[7,11],batch:7,assum:[0,6,7],alreadi:[9,5,6,7],val:[0,1,6,2],dst:[7,6],"case":[0,1,9,3,4,6,7,5,11,10],due:[7,4,10],negat:6,liter:[7,8,4,6,10],readi:[7,0,5,6,9],clusterstartuperror:[5,6],invert:7,applic:[9,1,3,4,6,7],style:9,correl:6,increas:[9,11],dynamicresultsetsreturnedwarn:6,appdata:4,qstr:6,t1968:7,leverag:[7,3],extract:[7,5,4,13],connect:[0,1,8,2,3,4,6,9,7,5,11,12,10],echo:2,abl:7,point:[0,1,9,3,4,6,7,5,13],sequenc:[9,1,6,7,5,10],trivial:[9,4],monetari:6,enable_integer_datetim:5,pgsysconfdir:4,underscor:5,pattern:9,clusternotrunningerror:[5,6],root:[7,4,13],server_set:7,caus:[0,1,9,3,4,6,7,5,11,10],pid:[7,5,3,6],onto:9,collect:[0,8,9,3,4,6,7,5],place:[9,3,4,6,7],unnecessari:[9,7],sharelock:1,maximum:5,oppos:[7,6],other:[9,1,3,4,6,7,8,10,13],microsoft:5,schemaanddatastatementserror:6,recov:[0,3,6],offset:6,normal:[0,9,3,4,6,7,5,13],argument:[7,5,4,6,2],creat:[0,1,8,9,3,6,7,5,11,10],connector:[9,10,6,7],pronam:6,pgkrbsrvname:4,primari:[9,8,4,6,7],loop:[0,3,6,2],configure_opt:5,wrapper:6,reverse_c:7,conveni:[7,11,6],parameter_typ:[7,6],pgdatestyl:4,num_messag:0,descriptor:[7,6],call:[0,9,4,6,7,5],seper:6,producer_fault:[0,6],convent:9,presum:7,look:[9,5,10,6,7],unabl:[6,10],want:4,dimens:7,"0x10d27d830":6,trust:[7,6],hstore:[7,11],index_from_kei:7,immutableruntimeparametererror:6,chapter:[9,13,7,2],duplicatecolumnerror:6,defaultpars:4,api:[0,9,3,6,7,8,2,11],sqlexec:2,cach:[7,5,3],msec:2,join:[9,6],content:[9,5,8,4,6],proc:[7,9,6,2],reconcil:[0,6],side:10,contrast:[7,6],"function":[0,1,9,4,6,7,5,12,10],pg90:5,facilit:[7,6],prompt_password:4,hostnam:[7,4],get_user_info:9,remov:[0,3,4,6,5,11,12],remot:[7,6],script:[9,2,4,5,11,13],publish:[7,6],appropri:[1,3,6,7,5,10],protocol:[9,1,2,3,6,7,11,10],destin:0,hook:[7,6],copyin:7,pg_dotconf:[8,11,2],undefinedparametererror:6,seen:[7,2],form:[0,9,2,4,6,7],unset:7,catalognameerror:6,expect:[9,3,4,6,7,10],channel:[7,3,6],die:3,did:[6,12],python_context:2,hello:7,table1_oid:1,rather:[7,0,5,6,9],cat:[9,2],"2202e":6,exclus:[7,1,3],reconcili:0,debug:[7,5],can:[0,1,9,3,4,6,7,5,11,10],foreignkeycreationerror:6,www:[4,6],exampl:[9,1,3,7,2],"while":[0,9,3,6,7,5,12],ipv4:7,ipv6:7,through:[7,6],producerfault:[0,6],end:[7,3,6],dramat:10,internal_queri:6,less:7,clientparamet:4,union:7,preload:9,xx9301423:7,table_nam:7,unterminatedcstringerror:6,obtain:6,johnson:7,collat:6,pgpassfil:[7,4],give:[7,5,8,6],fine:[7,5],auser:7,pg_controldata:5,instanc:[0,1,9,3,4,6,7,5,10],stringdatalengtherror:6,other_symbol:9,thread:[1,6,7,8,11,10],pgrealm:4,upon:[5,2],differ:[7,4,6],number:[0,1,2,6,7,10],ampersand:9,jane:8,main:7,machin:6,colon:9,releas:[7,1,11,6],yesterdai:7,regprocedur:6,formatt:6,origin:[0,11,6,7],although:3,resolut:[7,4],where:[0,1,8,9,3,6,7,5],strip:7,thrown:6,trap:[0,6,7],python_main:2,better:7,"class":[0,1,9,3,6,7,5,11],total:7,cursor:[9,6,7,8,11,10],practic:3,listen_address:[5,6],transform:[9,10,6,7],connectiondoesnotexisterror:[7,6],lifetim:7,ambiguousaliaserror:6,absolut:[7,5,6],measur:7,transact:[7,8,6,2],irerror:6,unknown_failur:0,sever:[7,6,10],databasedefinitionerror:6,integrityconstraintviolationerror:6,internal_posit:6,emps_by_ag:7,typeconversionwarn:6,another_set:2,lock:[8,1,11,6,12],lost:7,transmiss:[7,2],inappropri:7,writabl:5,extern:6,inclin:7,restricterror:6,max_connect:5,lose:3,header:6,repeat:[9,5,7],parametererror:[7,6],"__enter__":[0,1,7],recycl:6,work:[9,6,7,8,13,10],appendix:6,pg_tmp:6,outsid:[9,7],get:[7,5,3,6],wait_until_start:[5,6],certain:7,infrastructur:7,varchar:[7,6],dropus:5,implicitli:7,name_of_databas:8,potenti:[7,6,10],"default":[9,1,8,3,4,6,7,5,10,11,13],sc_number:7,codec:10,pend:[3,6],suppos:7,realign:0,add:[0,9,3,6,7,11,12],restor:[7,6],strang:[8,10],transfer:[0,10,6,7],gettimeout:3,forego:7,setting_name_to_com:2,right:3,append:[9,3,7,2],authent:[7,6],retain:[9,5],respect:[9,5,6],summari:3,safeti:[8,10],parsed_opt:4,loading_t:0,column:[9,10,12,6,7],sym_from_libthat:9,phase:[12,10],carefulli:[7,8,10],portabl:9,borrow:7,built:[9,5,6,2],invalidsavepointspecificationerror:6,scan:6,stringrighttruncationerror:6,find:6,clustererror:6,redirect:[5,2],format:[9,10,6,7],appear:[6,12],build:[9,5,4,13],transmit:0,qrow:7,column2:6,load:[9,10,6,7],column1:6,special:[9,11,6],were:[0,1,6,7,5,10],receiver_fault:[0,6],english:[8,10],typo:11,scrollabl:[9,7],type:[9,1,6,7,8,11,12,10],environ:[2,4,8,6,7,5,13],floatingpointerror:6,"__class__":5,ilf:9,ddl:9,keyerror:[7,6],parameter:[7,5],filepath:2,tool:[9,5,6],sql_statement_str:7,utf:[5,10],toe:6,attribut:[0,9,3,6,7,5,11,10],escape_liter:6,variat:9,conform:7,too:[0,8,10],"3b001":6,"3b000":6,bound:[9,6,7],"long":[7,5,3],doe:[0,9,8,6,7,5,12,10],aspect:13,core:8,connectionfailureerror:6,statementcompletionunknownerror:6,succ:6,update_r:0,onc:[9,5,3,6,7],asc:7,dou:11,portion:[7,6],listen:[7,8,3,6],updat:[9,8,3,4,6,7,5],intend:[0,11,6],somewhat:9,extens:[9,5,7],get_pid_from_fil:6,triggereddatachangeviol:6,grace:5,asynchron:[7,3],internalerror:6,"__contains__":7,checkerror:6,bpcharoid:7,construct:[7,0,5,6,9],area:6,extend:[9,5,8,6,7],oblig:7,own:11,modifyingsqldatanotpermittederror:6,aren:7,charact:[9,8,10,6,7],escape_id:6,command:[9,8,2,3,4,6,7,5,11],than:[7,5,4],filter:[7,10],init:[5,6],notabl:[7,5,3,4,6],definit:[9,7],default_pg_sysconfdir:4,quantiti:[7,6],hint:[7,9,10,6,2],come:[0,9,3,4,6,7,10],http:[9,4,6],sioerror:6,parent:5,reload:[5,6],privileg:6,opt:13,had:[7,10],languag:[9,6,7],queri:[9,6,7,8,11,12,10],rformat:11,don:[7,4,6,11],synchron:1,via:[10,0,3,6,7],doc:[9,4,6],recvsiz:11,sym:9,entir:[0,9,4,7,5,10],anyth:7,organ:9,refer:[0,9,3,6,7,8,11],signifi:6,dpdseobjecterror:6,pg_data:5,represent:[7,11,12],cio:6,bracket:7,pguser:[7,4],seri:6,descript:[7,4],user_type_id:9,ldap:7,data_directori:[5,6],command_option_map:6,declar:[9,6,7],illustr:[9,8,3,7],python3:[13,11,2],timetzoid:7,ipaddr:12,index:[7,6],infin:11,undefinedobjecterror:6,invalidsqlst:6,pg_config_path:6,correct:[0,8,10,11,7],org:[9,4,6],inet:12,hold:[9,5,3,7],proc_id:6,geqo:4,absenc:7,done:[9,10,7],pqv3:6,much:[1,10],"58p02":6,"58p01":6,statementnameerror:6,mind:7,cardinalityerror:6,unpack:[7,10,11,6,12],awai:6,timezon:[7,4],"0100c":6,purposefulli:[7,4],discourag:[9,7],xml:7,foreignkeyerror:6,interv:[7,3,6],even:[7,5,6],rowset:7,auto:7,asterisk:4,xmldocumenterror:6,unsupport:[8,6,10],featureerror:6,entri:[9,13,4,6,7],overhead:7,unknown:7,reappli:6,sourc:[7,0,4,6,9],locatorerror:6,"abstract":[9,1,10,7],wrap_socket:7,either:[0,3,6,7],"08p01":6,some:[9,1,3,4,7,8,12,10],convers:[7,6],proper:[10,6,12],thei:[9,1,3,4,6,7,5,11],substringerror:6,have:[9,1,3,4,6,7,5,11],iteratorproduc:0,alloc:[0,5],without:[10,7,8,3,2],text_search_config:6,indeterminatetypeerror:6,inherit:[9,4,6,11,7],popen:5,session:[1,6],undesir:[9,4,7],cursornameerror:6,consid:[9,10,6,7],manipul:[7,5],recursionerror:6,noactivetransactionforbrancherror:6,achiev:7,celementtre:7,getpass:[7,4],crashshutdownerror:6,pgport:4,interrupt:[7,11],correspond:[7,6],clear:3,interfac:[0,1,8,9,3,4,6,7,5,11,12,10],usenam:7,encod:[7,5,6,10],format_el:6,split_qnam:6,caller:7,notificationmanag:[3,11],consist:[0,3,4,6,7,5,10],pq_trace:2,enough:[7,10],ctest:7,data:[0,9,3,6,7,5,10],alia:1,save:7,few:[9,5,10,7],minor:[5,6],axel:11,should:[0,8,9,3,4,6,7,5,10,13],pgpass:[7,4],loaderror:[11,6],ultim:[0,5,10,7,9],pranskevichu:11,detail:[9,4,6,7],enter:7,characterist:[7,3],etc:[7,5,4,6,11],integ:[7,6],inform:[0,8,9,4,6,7,5,11,10],transpar:7,factor:[7,0,6,9],all:[9,1,8,2,3,4,6,7,5,10],design:[9,3,6,7],year:7,down:5,immedi:[0,5,3,6,9],advisori:[8,1,11,6],action:[7,6,10],ready_for_connect:[5,6],secur:[7,6],back:[7,10,11,6,2],indic:[9,1,4,6,7,5],indicatorparametervalueerror:6,savepoint:[7,11,6],target:[0,9,2,7,11,10],trace:[7,11,2],reflect:7,"2d000":6,line:[0,9,2,4,6,7],deal:[7,4,6],superus:5,kind:7,reconnect:6,pkglibdir:5,control:[0,5,6,7],channel_and_payload:[7,6],access:[0,1,9,3,6,7,5,11],emp:[7,8],destruct:5,reset_msghook:6,indicatoroverflowerror:6,product:2,modifi:[7,5,12,2],pg_driver:7,enable_cassert:5,print:[7,8,6],triggeredactionerror:6,determin:[9,5,7],primit:1,get_on:9,except:[0,9,3,6,7,8,11,10],would:[9,10,6,7],count:[9,1,11,7],tracer:11,respons:[3,6],timestamptz:[7,11],pgpassword:4,alter:[9,8,6,7,5,11,10],employee_hire_d:7,statementproduc:0,zerolengthstr:6,bug:11,tend:4,payload_data:7,ssl:[7,5,6,2],free:[9,7],chardata:7,"__exit__":[0,1,7],schema:6,channel1:7,section:[9,10,6,7],"42p01":6,substitut:9,panic:[7,10],warning_contain:6,beyond:[0,5],plan:6,"55p02":6,"55p03":6,xmlcontenterror:6,modul:[0,8,9,2,4,6,7,5,11,12],droplang:5,the_real_sekrat:7,likewis:7,col1:7,limit:[7,6],pgtz:4,credenti:[7,6],configur:[9,2,3,6,7,5,13],deleg:9,upperbound:11,driver_set:7,password:[2,4,8,6,7,5,10],step:[0,7],onipserror:6,pair:[9,1,3,6,7,5],jack:7,timestampoid:7,option:[9,2,3,4,6,7,5],suffoc:7,squar:7,text:[9,8,10,6,7],icverror:6,objectdefinitionerror:6,leak:5,goe:[0,5,7],setup:[9,11,13],well:[2,3,6,7,5,12,10],support:[9,1,8,6,7,5,11,12,10],situat:[10,0,3,7,9],iternotifi:[7,3,6],lead:[7,5],great:7,connectionerror:6,condit:[0,3,6,9],specifictypemismatch:6,notif:[7,8,3,6],remain:[7,3],critic:7,program:[6,2],notic:[7,8,11,6,10],another_generate_series_exampl:9,length:7,rlock:[1,6],textoid:7,itself:[9,5,6,7],choos:[1,10],error_contain:6,natur:[0,10,7,9],handl:[0,3,11,6,7],generate_seri:[7,0,6,9],"2b000":6,sslmode:[7,4,2],lookup:4,conjunct:7,devel:5,msg:[7,6],never:[10,9,3,6,7],larg:[9,7],cast:[7,10],pkg:9,pg_src_user:4,element:[7,11,6,10],bandwidth:7,vacuumdb:5,specifi:[9,2,3,4,6,7,5],equal:6,insufficientprivilegeerror:6,powerfunctionargumenterror:6,float8oid:7,object:[0,1,2,3,4,6,9,7,5,10],tabl:[0,1,4,6,7,8],sqlnotyetcompleteerror:6,arguabl:6,exit:[7,0,5,6,2],ipcclean:5,advanc:[9,6,7],chain:9,pg_column_typ:[7,6],from_end:[7,6],getset:[7,5,6],textrepresentationerror:6,my_operation_proc:9,usr:[5,13],just:[7,6,13],categori:[9,8,6,7],isinst:0,fundament:9,string:[9,8,2,4,6,7,5,11,10],dateoid:7,arrai:[7,8,11,10],googl:12,transactioninitiationerror:6,trimerror:6,myappdb:9,effect:[9,4,6,7,5,13],pgdata:[5,4],perform:[0,1,11,6,7],copi:[0,9,6,7,8,11],regularli:[0,7],output:[7,5,6,2],variou:[7,4,6],wrong:[6,10],durat:[3,6],receive_stmt:0,constructor:[7,1,3,6],take_out_trash:3,resourcewarn:11,fastest:7,typio:[11,10],errorlookup:6,insert:[9,8,7],friendli:7,date:[7,11],postmast:[5,6],decor:6,occur:[0,3,4,6,7],also:[0,2,3,4,6,7,5,10],my_oper:9,bind:[9,11,7],librari:[9,6,8,11,12,10],daemon:[5,6],wait_until_stop:[5,6],localedir:5,default_host:4,debra:7,motiv:[9,8],simplif:3,pq_iri:2,pg_config:[5,6,13],pg_cluster:5,duplicatedatabaseerror:6,obviou:6,solitari:7,preliminari:12,approxim:3,straightforward:9,provid:[0,1,8,2,3,4,6,9,7,5,11,10],materi:9,succe:7,avail:[0,1,8,2,3,6,7,5],fulli:6,variant:[5,4],msghook:[7,6],revoc:7,no_default:4,base:[9,3,4,6,7,5],overridden:10,pg_stat_act:[7,6],happen:[6,10],sql_parameter_typ:[7,6],prefix:[9,5,4],unless:[7,3,6],result:[9,5,4,6,7],compens:[0,11],sens:10,standard:[7,5,10,4,2],"42p10":6,guarante:[7,3,6],from:[0,1,8,2,3,4,6,9,7,5,11,10],inspir:2,sent:[7,5,3,6,10],trerror:6,copyout:7,load_chunk:[9,8,10,7],usernam:[7,4,2],dpdseerror:6,els:[0,9],column_typ:[7,6],"return":[0,1,2,3,4,6,9,7,5,11],world:7,assignmenterror:6,ambiguousparametererror:6,finish:0,"0lp01":6,individu:[9,3,6,7],alock:[8,1,11,6],global:9,bin:[2,4,8,5,11,13],precis:0,subclass:[1,6],subject:[0,9,3,4,6,7,10],feedback:11,contrib_hstor:7,information_schema:7,foobar:6,runtimeerror:1,"import":[0,1,8,2,3,4,6,9,7,5],windowerror:6,editor:9,"0x10df38e90":6,concern:3,schemanameerror:6,excess:7,temp:[0,7],otherwis:[7,6],usabl:7,overrid:[7,10,4,6,11],vlad:11,apply_tax:7,src:[7,5,6],"57p02":6,"57p03":6,limitvalueerror:6,"57p01":6,client_encod:[8,4,10],split:6,creator:[6,2],littl:0,notxmlerror:6,search_path:[7,4],guc:[7,10],"__iter__":[0,3],particular:[7,6,13],xmlcommenterror:6,equival:[9,6,7],activetransactionerror:6,extra:[9,7],map_errors_and_warn:6,nonstandarduseofescapecharactererror:6,make:[0,9,2,6,7,5,10],contraint:6,dash:5,messag:[0,2,3,6,7,8,11,10],lot:7,low:6,"39p02":6,"char":7,"39p01":6,strongli:7,isconsist:6,pg_parameter_typ:[7,6],barbara:7,page:7,splitted_it:6,pio:6,ignoredclientparameterwarn:6,held:[1,6],int2oid:7,model:7,thereof:6,network:12,first:[9,1,2,4,6,7,11],time:[9,1,2,3,6,7,5,12],fix:[11,12,10],help:[6,2],pginstal:[4,6,13],shorthand:7,stabil:6,exact:6,rare:[0,3],datestyl:4,hopefulli:10,whenc:[7,6],cover:[9,13],marker:9,statment:6,emp_nam:[8,6],stringdatarighttruncationwarn:6,yet:10,move:[0,7],employe:[7,8],columnreferenceerror:6,written:7,demand:7,care:[9,7],highlight:[9,10],absolu:5,interfer:1,confus:[7,10],str:[7,5,10,6,12],format_messag:6,impli:7,itserror:6,interest:[9,7],pq3:7,delet:9,lastli:1,exist:[0,1,9,6,7,5,12],bodi:[7,6],activ:[7,3],act:[7,2],ideal:[7,10],regardless:[7,1,4],unavail:[7,6],sampl:[7,8],invalid:[7,3,6,2],fill:7,faux:5,send:[7,5,10],fault:[0,8,6],reintroduc:0,file:[9,8,2,4,6,7,5,11,13],emit:[0,3,6,7,11,10],inconveni:9,facil:[9,7],traceback:7,plpgsqlraiseerror:6,implicit:7,denot:9,keyword:[9,3,4,6,7,5],"0f000":6,numer:[7,8,6],latest:7,with_func:6,block:[0,1,9,6,7,5],sysconfdir:[5,4],primarili:[0,5,4,6,7],tax:9,"2f002":6,"__call__":[7,10],default_msghook:6,original_except:0,tag:11,databas:[9,1,8,2,3,4,6,7,5,10],quote_ident_if_need:6,url:7,util:4,thi:[0,1,2,3,4,6,9,7,5,10,13],sslcrtfile:[7,4],appar:7,disconnect:[5,6],"boolean":1,standard_conforming_str:7,prerequisit:6,tupl:[0,3,6,7,5,11,10],relev:3,simpli:[7,4,6],libnam:9,old:7,doubl:7,withcheckoptionerror:6,gracefulli:[3,6],whether:[5,9,1,6,7],thu:3,lack:9,locatorspecificationerror:6,templat:7,"2f004":6,"2f005":6,objectinuseerror:6,"2f003":6,"2f000":6,"public":[7,4],processor:10,createdb:5,mcguffer:7,greater:[7,3],untrap:[0,6],paramet:[9,8,2,3,4,6,7,5,10],unlik:[0,7],memori:[9,5,7],postgersql:7,"0a000":6,sql_statements_str:7,bindir:5,most:[9,10,4,6,7],annot:9,esablish:6,cursordefinitionerror:6,duplicatefileerror:6,wrap:[7,6],nullproduc:6,pg_resetxlog:5,raise_emp:8,"const":9,tcp:6,cost:[0,7],buffer:[7,6],pg_sy:9,functool:7,outcom:7,orm:9,destroi:[7,6],emp_salari:8,noactivetransactionerror:6,read:[9,2,6,7,5,10],ttree:7,faulted_receiv:0,typeerror:[8,10],explicitli:[7,3,6],real:6,must:[0,1,2,3,4,6,9,7,5,12],delai:[5,6],acquisit:[1,6],envkei:6,dynam:9,sc_text:7,rintavarustu:11,behind:6,datetimefieldoverflowerror:6,crl:4,specfici:7,copyfail:[0,6],statement_from_id:[7,6],crt:4,aquir:1,srfcomposit:7,system:[9,5,4,6],sslkeyfil:[7,4],nativ:12,obj:6,compon:[9,6,7],"2bp01":6,simplifi:[9,3,11,7],my_queri:7,titl:4,why:6,provinc:9,cluster:[8,5,11,6,2],hous:6,environ_prefix:4,platform:4,andrew:8,wai:[0,9,3,6,7,5,2,12,10],creation:[9,4,7],offsetvalueerror:6,programm:[9,5,11,6,10],send_stmt:0,errcod:6,pg_lib:9,properli:[7,10,4,11],under:[7,5],third:9,default_port:4,transaction_isol:7,for_rabbit:3,channel_nam:7,duplicateschemaerror:6,pkgincludedir:5,pg_servic:4,pg_execut:5,logargumenterror:6,sleep:5,initi:[0,9,6,7,5,10],request:[7,4,6,10],distinct:[7,6],safe:[0,1,3,6,7,5,10],notifyman:3,deadlockerror:6,undefinedfunctionerror:6,them:[0,9,3,4,6,7,11],fileno:7,libpq:[7,4],sharedir:5,libpath:[9,6],infrequ:9,timestamptzoid:7,pg_catalog:6,"0x10dc0d290":6,resolv:[9,4],receiv:[0,2,3,4,6,7,8,11],ip4:7,still:[9,3,11,6],pgclientencod:4,client:[2,4,8,6,7,5,10],wherea:[7,11,6],libthat:9,ip6:7,context:[0,1,9,2,6,7],continu:[0,5,3],nullvaluenotallowederror:6,earli:[3,10],start:[0,5,6,7],col0:7,consol:2,imped:11,exactli:7,how:[9,1,11,7],"__setitem__":6,plpgsqltoomanyrowserror:6,soon:6,warn:[1,2,4,6,7,8,11,10],recent:7,postgr:[7,5,4,6],view:[7,6],associ:[5,0,1,6,7],issu:[7,6,10],"null":11,pool:6,pgdatabas:4,protocolreceiv:6,libdir:[9,5],srf:[7,6],item:[7,5,6,10],larger:7,xmloid:7,iter:[7,0,3,6,9],statement:[0,9,3,6,7,8,2,11,12,10],tio:6,load_row:[9,8,10,7],defin:[9,1,11,6,7],onli:[0,1,9,3,4,6,7,5,10],insecurityerror:6,describ:[0,1,7,9],usag:[0,9,2,6,7,8,11],cursorstateerror:6,out:[9,3,6,7],pg_python:[11,8,4,2],compliant:10,intervaloid:7,ctype:6,formal:9,clusterinitializationerror:[5,6],depend:[9,4,6,7],alongsid:[9,1],classif:[9,6],reduc:10,contain:[9,5,13,6,7],indexcorruptederror:6,anonym:12,a_statement_id:7,interven:7,servernotreadyerror:6,execut:[0,1,8,2,4,6,9,7,5,10,11,12,13],client_address:[7,6],column_nam:[7,6],syntaxerror:[7,6],pgconnect_timeout:4,select:[0,1,9,2,6,7,8],tempor:[8,11,6],client_min_messag:[7,11,10],func:7,match:4,bring:10,prefer:[7,2],relationship:7,db2:3,introductori:9,when:[0,1,8,2,3,4,6,9,7,5,11,10],idl:[7,3],filesystem:[6,2],sslrootcrlfil:[7,4],directli:[0,1,2,3,6,9,7,5,10],param:[9,4,2],db1:3,insuffici:6,"_my_oper":9,parametervalueerror:6,receiverfault:[0,6],scope:7,assert:[9,5,3,6],finer:7,kill:[5,6],schemadefinitionerror:6,typeio:11,make_emp:8,secret:[7,5,4],initdberror:[5,6],softwar:6,avoid:[0,5,10,7,2],newvalu:2,uniqueerror:[7,6],uncommit:6,altern:[0,6],caught:7,ran:[0,5,6,7],procedure_id:[7,6],subsequ:[9,4,6,7],made:[9,5,10,4,7],rau:11,detect:[7,6],pg_ctl:[5,6],startup:[7,11,6,10],intervalfieldoverflowerror:6,"__main__":2,refsym:9,element3:11,unquot:6,user_typ:9,callabl:[0,6,7],remove_us:9,again:[0,1,9,3,7,5],triggerprotocolerror:6,sslrootcrtfil:[7,4],distribut:[9,8],packet:7,inconsistentcursorisolationerror:6,establish:[9,2,4,6,7,8],"byte":[0,10,6,7],nullvalueeliminatedinsetfunctionwarn:6,involv:0,arbitrari:[0,9,3,6,7,5],bigint:[9,7],setupscript:9,struct:6,assign:7,bad:[3,11],includ:[9,2,3,4,6,7,5,13],displai:[7,4,6],key_or_index:7,fragment:9,twenti:7,note:[0,9,4,6,7,5,12],undefin:[7,6],syntact:7,per:[12,2],touch:6,noth:[8,6,12],initdb:[5,6],take:[0,9,2,6,7,5,10],backend_start:7,signific:[0,7],deliv:3,mk_pack:6,timetz:7,found:[9,6],parse_arg:4,ident:[9,6],compositeerror:6,instead:[9,2,6,7,5,11],produc:[0,9,3,4,6,7,8],tabledefinitionerror:6,"01p01":6,audienc:[9,8],commun:[7,6],datetimeformaterror:6,python:[0,8,9,2,4,6,7,5,10,11,12,13],quotat:6,typemismatcherror:6,fatal:[0,10,6,7],shutdown:[5,6],"try":[0,6,7],adjust:[7,10],a_db_us:4,craft:7,deriv:7,writelin:7,"0b000":6,castcharactervalueerror:6,suitabl:7,hba:[5,6],address:[7,6],anoth:[0,1,9,6,7,10],terminolog:[0,8,9],veri:[9,7,2],"__str__":6,properti:[0,1,9,6,7,5],state:[0,9,4,6,7,5],conflict:[7,1],unfortun:12,pg_instal:5,pwfile:5,daemon_process:5,delimit:7,which:[0,1,9,3,6,7],propag:7,narr:6,develop:11,op_arg2:9,dozen:9,sole:7,futur:7,structur:[7,5],those:[0,1,9,3,4,7,5,10],essenti:[9,10],metadata:[9,7],querycancelederror:6,pghost:4,complex:[0,6],foo:[7,6],decim:7,regist:11,timeout:[0,5,3,6,7],pg_param:4,twitter:11,complet:[7,0,5,6,2],elvi:[11,12],next:[0,3,6,7],cursor_from_id:[7,6],quickli:[0,7],op_arg1:9,susan:8,decis:[6,10],offer:[0,1,3,6,7],total_row:0,best:[0,10,6,2],forward:[7,6,12],abort:[0,6,7],stdout:[7,0,5,6,2],"static":[4,6],dirnam:9,stopiter:[0,3,11,6,7],undefinedtableerror:6,routin:[7,6,10],default_excformat:6,"__context__":0,len:[7,6],duplicatecursorerror:6,sslkei:4,acquir:[9,1,8,6,7],fail:[0,3,6,7,11,10],check:[7,3],plpgsqlnodatafounderror:6,ever:10,t1980:7,whitespac:9,widthbucketfunctionargumenterror:6,from_iter:9,tripl:[7,3,6],about:[0,9,6,7,5,10],undefinedfileerror:6,problem:[0,10,12,7],administr:[8,13],capabl:[5,6],connect_timeout:[7,4],default_statistics_target:7,preparedstat:9,seek:[7,6],prepar:[0,9,3,6,7,8,2,11,10],pg_dump:5,html:[9,4,6],effici:7,wait:[3,6,7,5,11,10],neg:7,clientcannotconnecterror:6,backend:[7,1,3,6],logfil:[5,6],xx400:6,self:[9,6],sighup:5,key_from_index:7,pointer:6,functionexecutednoreturnstatementerror:6,"new":[7,1,10,6,2],cferror:6,unus:6,authenticationspecificationerror:6,recoveri:[5,6],consum:[0,3,7],refresh:6,grantoroperationerror:6,here:[9,3,6,7],forc:7,recv_into:6,channels_and_payload:7,solut:6,project:[9,8,11,12,13],event:[0,3,7],ulong_pack:6,pg_hba:5,resolve_password:4,encourag:9,emploi:12,regularexpressionerror:6,readonlytransactionerror:6,nullvaluenoindicatorparamet:6,follow:[0,9,2,4,6,7],shot:[7,6,12],show:[7,6,2],logic:[11,6],further:[9,4,6,7,11,10],becom:6,version_info:[7,5,6],gid:11,get_numb:9,sub:11,ecpg:5,lambda:7,subprocess:[5,6],order:[0,1,9,3,6,7,5,10],notnullerror:6,yield:[0,3,6,7],manag:[0,1,8,9,3,4,6,7,5,11,12,13],user_id:9,regular:[5,3,6,2],store:[7,1,8,6],gogichashvili:11,clusterdb:5,"40p01":6,maxsplit:6,pick:3,uncaught:7,insid:[0,3,6,7],arrayelementerror:6,both:[0,1,9,3,7,5],branchalreadyactiveerror:6,enabl:[7,5,10],split_sql_str:6,typeioerror:6,builtin:[0,11,6,7],copy_emps_in:7,sreerror:6,share:[7,1,5],intervent:6,elementtre:11,hasattr:9,"0p000":6,connecttimeouterror:6,accommod:[7,6,12],good:[9,3],quote_liter:[6,10],dict:7,notat:7,p0001:6,stdin:[7,0,6,9],smith:7,fictiti:9,snippet:4,"42p20":6,duplicatepreparedstatementerror:6,float4oid:7,client_port:[7,6],"break":[0,3],higher:[7,6,10],bytea:7,get_emp_with_salary_lt:8,ct_thi:7,clustertimeouterror:[5,6],wrongobjecttypeerror:6,term:[0,9],byteaoid:7,unix:[7,11,2],stop:[7,5,6,10],statementprohibitederror:6,throughout:9,singl:[9,1,2,3,4,6,7,8,11],escap:[7,6],broken:[0,3],buffer_s:6,watch:3,coercionerror:6,"catch":6,cours:[7,8,4,6],ters:7,ssearch_path:4,comment:2,varcharoid:7,likeabl:9,internet:7,total_byt:0,name3:7,name2:7,record:[0,6,7,8,11,12,10],last:7,backward:[7,6],quot:[7,11,6,10],protocolproduc:6,certif:7,iri:[7,4,6,2],"transient":[9,6],recover:[0,7],untranslatablecharactererror:6,actual:[0,5,6,7],ipaddress:12,infailedtransactionerror:[7,6],pg_dumpal:5,mani:[0,9,6,7,11,10],identifi:[0,1,9,6,7,5,10],field:[4,6,10],mai:[0,1,9,3,4,6,7,5,10],t1970:7,set_config:7,method:[0,1,8,9,3,6,7,5,11,12,10],name1:7,map:[0,9,4,6,7,5],timeit:2,combin:5,pack:[7,6,10],contribut:7,mode:[7,1,6,2],often:[0,3,11,6,7],"42p04":6,"42p05":6,"42p06":6,"42p07":6,execnam:6,"42p02":6,"42p03":6,usual:[9,5,7],tailor:11,procedur:[9,1,8,6,7],"42p08":6,"42p09":6,distutil:[9,13],nodatawarn:6,temporari:[5,6,2],prompt_titl:[4,6],rais:[0,1,8,3,6,7,5,11,10],exceed:6,runtim:[9,6,7],keep:9,fals:[5,7,1,4,6],error:[7,9,10,6,2],unavailablelockerror:6,pg_:11,ani:[0,1,9,3,4,6,7,5,10],caten:6,toomanyconnectionserror:6,quote_ident_if_necessari:11,getlen:6,basic:[9,5,6],knowledg:[9,7],that_pkei:7,getaddrinfo:7,containingsqlnotpermittederror:6,reason:6,bool:[7,5],stai:6,modif:[11,2],"2200b":6,"2200c":6,custom:[9,10],"2200f":6,dollar:6,"2200d":6,easi:10,absent:7,whose:[0,9,4,7,5,10],run:[0,9,2,6,7,5],"2200n":6,errformat:6,"2200l":6,"2200m":6,deprec:[11,12],mst:7,invok:[9,6,7],"2200t":6,callreceiv:[0,6],similarli:5,t1985:7,package_data:9,authenticationmethoderror:6,version:[2,6,7,5,11,13],invoc:[7,6,2],reach:6,improv:[8,11],copymanag:[0,6],"10kb":6,quit:7,failur:[0,3,4,6,7,8],interact:[7,2],preparedstatementdefinitionerror:6,revers:7,lockfileexistserror:6,document:[9,11,6,10],p0002:6,p0003:6,p0000:6,casenotfounderror:6,with_openssl:5,separ:[9,4,6],exclusivelock:1,undefinedcolumnerror:6,newlin:4,convert:7,psql_path:5,therefor:[9,5,4,10],none:[0,2,3,4,6,9,7,5],sigterm:6,"__ne__":6,violat:6,"__next__":[0,3,11,7],libn:9,appli:[7,5,6,2],posit:[7,4,6],archiv:13,mechan:6,locat:[7,5,4,8,2],odd:6,sometim:[9,6,7],my_prompt:4,level:[0,1,4,6,7,5,11,10],unlisten:[7,3,6],wire:[6,10],aut:6,emp_salai:8,local:[9,8,3,6,7,5,12,10],inhibit:7,search:9,"0x10d27d170":6,compil:6,standardpars:4,doesn:7,privilegenotrevokedwarn:6,num_byt:0,ereerror:6,mere:[9,1,3,7],merg:11,del:3,patch:[5,11,6],leav:4,warninglookup:6,def:[9,7],tone:7,settimeout:3,incur:6,notifi:[7,3,11,6],period:5,syntax:[7,6],includedir_serv:5,chunksiz:11,same:[9,1,3,6,7],transactionerror:6,arg:[7,6],kerberos5_servic:4,xmlprocessinginstructionerror:6,stream:[9,10,6,7],open:[9,4,8,6,7,5,11],split_id:6,xx002:6,xx000:6,xx001:6,plpgsqlerror:6,smallint:7,conf:[5,4,6,2],t72000:7,backslash:[8,10,6,2],everi:6,soft:6,hba_fil:[5,6],statement_id:[7,6],oper:[0,1,9,6,7,10,11,13],interpol:[7,6],methodcal:7,timeoid:7,small:7,longer:[0,6,7],sure:[7,6],someth:7,reset_errformat:6,get_some_row:9,three:[9,5,6,7],functiondefinitionerror:6,duplicatefunctionerror:6,fetch:[9,6,7],comparison:6,boundari:[0,7],datetim:7,optim:10,repres:[1,3,6,7,5,11],cooper:1,default_buffer_s:6,retriev:5,transactionterminationerror:6,rollback:[7,6],garbag:[7,3,6],implicitzerobitpaddingwarn:6,with_libxml:5,prone:9,typ:[0,1,6],strip_and_int:7,xact:[0,2,6,7,8,11],sequenti:7,gotcha:[8,10],abc:6,memoryerror:6,socket:[12,0,11,7,2],privilegenotgrantedwarn:6,columnerror:6,expos:12,"2pc":11,lib2:9,drawn:10,surviv:1,lib1:9,inconsist:[5,10],fitti:7,you:[4,6,13],accord:6,columndefinitionerror:6,express:[7,10,2],safest:12,silent:6,stderr:[5,6],cannot:[9,5,6,7],present:[7,4],easili:[9,10,7],driverwarn:6,over:[0,5,7],dataerror:6,split_sql:6,intnam:7,partial:[7,4],"0f001":6,recommend:[9,7],"3f000":6,transactionresolutionunknownerror:6,reset:6,quote_id:[11,6],server_vers:7,"__init__":9,dbapi20:[7,8],versionstr:6,searvnameerror:6,psql:[5,4,2],adminshutdownerror:6,host:[7,8,4,6,2],port:[7,5,4,6,2],far:[7,10],symbol:[9,8,11],abov:[9,1,3,4,8,7,5],mkemp:7,full:[7,6],protocolerror:6,preced:5,zero:[5,3,11,6],like:[9,1,2,4,6,7,5,10],dedic:8,domain:[7,11],difficult:10,volum:10,get_user_info_v2:9,semant:7,name:[9,2,6,7,5,11],localhost:[7,5,4,6,2],part:[0,5,11,7],pars:[7,4,6],circumst:[7,3],second:[9,5,6,7],serializationerror:6,parser:9,copyman:[0,8,6],more:[0,9,4,6,7,8,10],mix:6,xlogdir:6,report:[7,11,6],aid:9,resili:3,unsplit:6,chunk:[0,11,7,9],pre:7,piec:7,test:[7,5,11],signatur:[9,7],wirest:6,"2201b":6,"2201e":6,"2201g":6,"2201f":6,closest:7,rang:[9,7],cursor_id:[7,6],int4oid:7,pleerror:6,"2201w":6,duplicateobjecterror:6,simul:7,grantorerror:6,formul:7,"float":7,duplicatealiaserror:6,encodingerror:6,empti:[9,3,4,6,7,11],mean:[0,2,3,4,6,9,7,5,10],window:[5,4,12],employee_dob:7,"short":7,disabl:[7,4,2],close:[1,2,3,6,7,5,11],excformat:6,major:[7,5,6],frequenc:3,overflowerror:6,taken:[7,4,10],itemgett:9,process:[0,2,3,4,6,9,7,5,10,13],srfprotocolerror:6,enable_depend:5,sym_from_libthi:9,known:7,chang:[0,9,2,4,8,7,5,10,11,12,13],"42p19":6,"42p18":6,roll:[7,11,6],prompt:[4,6,2],"42p13":6,"42p12":6,"42p11":6,queue:3,"42p17":6,"42p16":6,"42p15":6,"42p14":6,"22p02":6,"22p03":6,sigkil:[5,6],"22p01":6,"22p06":6,includedir:5,"22p04":6,"22p05":6,win32:4,transport:7,earlier:7,getus:[7,4],constant:[9,7],ambiguouscolumnerror:6,grain:[7,5],serializ:[7,6],"__file__":9,intern:[7,5,3,11,10],grief:7,attempt:[4,6,10],treat:[9,8,10,7],groupingerror:6,reservednameerror:6,ambiguousfunctionerror:6,searverror:6,specif:[0,9,3,6,7,2],difficulti:10,discard:[9,3,7],docdir:5,termin:[7,5,3,6,10],simplest:7,driver:[4,6,7,8,11,10],within:[0,1,9,2,7,5],resourc:[9,1,6],dbn:3,two:[5,7,1,6,12],dbm:6,nametoolongerror:6,binaryrepresentationerror:6,default_pg_config:6,ini:9,statu:12,int4:[9,1,7],advantag:[7,9,6,2],promptli:[9,3,7],valid:[6,10],int8:[0,1,7],info:[7,5,6],home:4,stripxx:7,reli:12,fulfil:9,dml:[9,7],despit:5,code:[9,8,2,3,6,7,5],pertain:6,badisolationforbrancherror:6,been:[0,1,2,3,4,6,9,7,5,12],fairli:6,alwai:[1,2,6,7,5,11,10],int8oid:7,pgsslmode:4,discuss:[9,7,2],furthermor:[7,10],cycl:0,"throw":6,commit:[7,6,12],readingdataprohibitederror:6,pggeqo:4,badcopyerror:6,sample_copi:7,qualiti:7,shown:7,usec:2,split_us:6,negoti:10,readingsqldatanotpermittederror:6,signal:[0,5,3,6],f0000:6,f0001:6,user:[9,8,2,3,4,6,7,5,11,10],success:[7,1],"int":[9,5,3,6,7],interrog:[7,4],instal:[9,4,8,6,7,5,13],pg_src_host:4,packag:[9,13,6,7],fit:7,referenc:[0,9,2,4,6,7],"3d000":6,genexpr:7,escapeocteterror:6,addition:[7,0,6,9],purpos:[9,4,6,7,5,10],integr:6,createus:5,possibl:[7,5,3,6,10],ignor:[6,2],togeth:[9,7],itertool:9,daemon_path:[5,6],irrit:11,"2200g":6,"0x10bc67990":6,later:5,poll:[5,3],against:[9,7,2],claus:7,tranact:6,surround:7,interpret:2,strive:6,write:[9,2,8,6,7,5],default_errformat:6,etre:7,facet:7,timezonedisplacementvalueerror:6,unanticip:7,com:[7,11],guard:7,until:[0,1,3,6,7,5,10],postgresql:[0,1,8,2,3,4,6,9,7,5,10,11,12,13],variabl:[7,8,13,4,2],scroll:7,listening_channel:[7,6],kei:[0,4,8,6,7,5],increment:1,done_listen:3,symmetri:7,after:[0,9,2,4,6,7,5,11,13],"0x10dfc94d0":6,dure:[10,0,3,7],get_one_twic:9,badaccessmodeforbrancherror:6,"true":[9,1,3,4,6,7,5],valentin:11,oid:[7,6],unexpect:4,storedprocedur:[7,6],prohibitedsqlstatementerror:6,clone:[7,6],employee_nam:7,product_cod:7,"switch":10,becaus:9,reintroduct:0,strict:6,escapecharacterconflicterror:6,sep:6,relai:7,set:[0,8,2,3,4,6,9,7,5,11,10],duplicatetableerror:6,accept:[7,5,4,6],"0devel":5,substanti:6,get_some_chunk:9,sec:6,table2_oid:1,see:[9,8,4,6,7],drop:[7,5,11,6],erieerror:6,connectionrejectionerror:6,mutabl:7,similar:[9,1,6,7],relat:[6,10],manual:9,row:[0,9,6,7,8,11,10],high:[0,4,6,7,11,10],drivererror:6,exhaust:[0,3,7,9],stdcat:9,servic:[7,3,4,11],oierror:6,speed:11,filter_notic:7,disk:9,datacorruptederror:6,pg_service_fil:4,incomplet:0,introduc:[12,10],lower:5,textual:7,transform_row:7,isol:[9,5,6,7],automat:[9,5,10,7],the_cursor_id:7,instanti:[5,9,1,6,7],list:[0,9,3,4,6,7,5,11],mutablemap:[7,6],common:[9,1,6,7],pg_proc:6,savepointerror:6,wast:7,restart:[5,6],argv:4,statementreceiv:0,qname:6},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","exception","Python exception"],"3":["py","function","Python function"],"4":["py","attribute","Python attribute"],"5":["py","data","Python data"]},objtypes:{"0":"py:module","1":"py:class","2":"py:exception","3":"py:function","4":"py:attribute","5":"py:data"},objects:{"":{postgresql:[6,0,1,""]},"postgresql.api.Connection":{clone:[6,3,1,""],close:[6,3,1,""],connect:[6,3,1,""],closed:[6,4,1,""],query:[6,4,1,""],connector:[6,4,1,""]},"postgresql.api.Installation":{type:[6,4,1,""],version_info:[6,4,1,""],version:[6,4,1,""],ssl:[6,4,1,""]},"postgresql.copyman.WireState":{update:[6,3,1,""]},"postgresql.temporal":{pg_tmp:[6,5,1,""],Temporal:[6,1,1,""]},"postgresql.installation.Installation":{ssl:[6,4,1,""]},"postgresql.installation":{Installation:[6,1,1,""],default_pg_config:[6,3,1,""],pg_config_dictionary:[6,3,1,""],"default":[6,3,1,""]},"postgresql.temporal.Temporal":{cluster_dirname:[6,3,1,""]},postgresql:{copyman:[6,0,1,""],alock:[6,0,1,""],open:[6,3,1,""],exceptions:[6,0,1,""],sys:[6,0,1,""],installation:[6,0,1,""],cluster:[6,0,1,""],api:[6,0,1,""],temporal:[6,0,1,""],string:[6,0,1,""],version_info:[6,5,1,""],version:[6,5,1,""]},"postgresql.api.Message":{source:[6,4,1,""],isconsistent:[6,3,1,""],details:[6,4,1,""],message:[6,4,1,""],code:[6,4,1,""]},"postgresql.copyman":{NullProducer:[6,1,1,""],CopyFail:[6,2,1,""],default_buffer_size:[6,5,1,""],transfer:[6,3,1,""],CopyManager:[6,1,1,""],ProtocolProducer:[6,1,1,""],ProducerFault:[6,2,1,""],ulong_pack:[6,3,1,""],ReceiverFault:[6,2,1,""],WireState:[6,1,1,""],CallReceiver:[6,1,1,""]},"postgresql.api.Settings":{get:[6,3,1,""],keys:[6,3,1,""],getset:[6,3,1,""],values:[6,3,1,""],update:[6,3,1,""],items:[6,3,1,""]},"postgresql.api.Statement":{statement_id:[6,4,1,""],clone:[6,3,1,""],close:[6,3,1,""],sql_column_types:[6,4,1,""],sql_parameter_types:[6,4,1,""],pg_parameter_types:[6,4,1,""],parameter_types:[6,4,1,""],string:[6,4,1,""],column_types:[6,4,1,""],column_names:[6,4,1,""],pg_column_types:[6,4,1,""]},"postgresql.string":{escape_ident:[6,3,1,""],unsplit:[6,3,1,""],split_qname:[6,3,1,""],quote_ident_if_needed:[6,3,1,""],split_using:[6,3,1,""],split_ident:[6,3,1,""],quote_literal:[6,3,1,""],split_sql_str:[6,3,1,""],split:[6,3,1,""],quote_ident:[6,3,1,""],escape_literal:[6,3,1,""],qname:[6,3,1,""],split_sql:[6,3,1,""]},"postgresql.api.Database":{proc:[6,3,1,""],backend_id:[6,4,1,""],iternotifies:[6,3,1,""],client_port:[6,4,1,""],execute:[6,3,1,""],listening_channels:[6,3,1,""],settings:[6,4,1,""],xact:[6,4,1,""],cursor_from_id:[6,3,1,""],unlisten:[6,3,1,""],statement_from_id:[6,3,1,""],client_address:[6,4,1,""],notify:[6,3,1,""],prepare:[6,3,1,""],version_info:[6,4,1,""],"do":[6,3,1,""],listen:[6,3,1,""],reset:[6,3,1,""]},"postgresql.exceptions":{OperationError:[6,2,1,""],Error:[6,2,1,""],SREError:[6,2,1,""],ServerNotReadyError:[6,2,1,""],ClientCannotConnectError:[6,2,1,""],ReadOnlyTransactionError:[6,2,1,""],ConnectionDoesNotExistError:[6,2,1,""],SEARVError:[6,2,1,""],TypeConversionWarning:[6,1,1,""],ICVError:[6,2,1,""],EscapeCharacterError:[6,2,1,""],SIOError:[6,2,1,""],ConnectionFailureError:[6,2,1,""],TypeIOError:[6,2,1,""],map_errors_and_warnings:[6,3,1,""],InconsistentCursorIsolationError:[6,2,1,""],InFailedTransactionError:[6,2,1,""],DriverError:[6,2,1,""],EREError:[6,2,1,""],Disconnection:[6,2,1,""],InsecurityError:[6,2,1,""],LoadError:[6,2,1,""],AuthenticationMethodError:[6,2,1,""],DPDSEError:[6,2,1,""],TRError:[6,2,1,""],ERIEError:[6,2,1,""],ONIPSError:[6,2,1,""],PLPGSQLError:[6,2,1,""],SchemaAndDataStatementsError:[6,2,1,""],CardinalityError:[6,2,1,""],SavepointError:[6,2,1,""],ITSError:[6,2,1,""],IgnoredClientParameterWarning:[6,1,1,""],PLEError:[6,2,1,""],FeatureError:[6,2,1,""],OIError:[6,2,1,""],CFError:[6,2,1,""],IRError:[6,2,1,""],ConnectTimeoutError:[6,2,1,""],Exception:[6,2,1,""],PLPGSQLRaiseError:[6,2,1,""]},"postgresql.alock":{ALock:[6,1,1,""]},"postgresql.copyman.CopyManager":{reconcile:[6,3,1,""]},"postgresql.api.Cursor":{clone:[6,3,1,""],direction:[6,4,1,""],read:[6,3,1,""],seek:[6,3,1,""]},"postgresql.copyman.ProtocolProducer":{recover:[6,3,1,""]},"postgresql.cluster.Cluster":{stop:[6,3,1,""],start:[6,3,1,""],wait_until_stopped:[6,3,1,""],daemon_path:[6,4,1,""],init:[6,3,1,""],shutdown:[6,3,1,""],initialized:[6,3,1,""],get_pid_from_file:[6,3,1,""],hba_file:[6,4,1,""],ready_for_connections:[6,3,1,""],kill:[6,3,1,""],connector:[6,3,1,""],reload:[6,3,1,""],restart:[6,3,1,""],drop:[6,3,1,""],connection:[6,3,1,""],address:[6,3,1,""],pid:[6,4,1,""],connect:[6,3,1,""],running:[6,3,1,""],wait_until_started:[6,3,1,""]},"postgresql.cluster":{ClusterStartupError:[6,2,1,""],Cluster:[6,1,1,""],ClusterInitializationError:[6,2,1,""],ClusterError:[6,2,1,""],ClusterNotRunningError:[6,2,1,""],ClusterWarning:[6,1,1,""],InitDBError:[6,2,1,""],ClusterTimeoutError:[6,2,1,""]},"postgresql.api":{Driver:[6,1,1,""],Message:[6,1,1,""],Settings:[6,1,1,""],Transaction:[6,1,1,""],Installation:[6,1,1,""],Cluster:[6,1,1,""],Statement:[6,1,1,""],Database:[6,1,1,""],Connection:[6,1,1,""],Category:[6,1,1,""],Cursor:[6,1,1,""],StoredProcedure:[6,1,1,""],Connector:[6,1,1,""]},"postgresql.api.Transaction":{rollback:[6,3,1,""],start:[6,3,1,""],commit:[6,3,1,""],begin:[6,3,1,""],abort:[6,3,1,""],mode:[6,4,1,""],isolation:[6,4,1,""]},"postgresql.api.Driver":{connect:[6,3,1,""]},"postgresql.alock.ALock":{mode:[6,4,1,""],release:[6,3,1,""],acquire:[6,3,1,""],locked:[6,3,1,""]},"postgresql.sys":{default_msghook:[6,3,1,""],errformat:[6,3,1,""],default_errformat:[6,3,1,""],reset_errformat:[6,3,1,""],msghook:[6,3,1,""],reset_msghook:[6,3,1,""]},"postgresql.api.Cluster":{kill:[6,3,1,""],installation:[6,4,1,""],start:[6,3,1,""],wait_until_stopped:[6,3,1,""],restart:[6,3,1,""],drop:[6,3,1,""],data_directory:[6,4,1,""],stop:[6,3,1,""],init:[6,3,1,""],settings:[6,4,1,""],wait_until_started:[6,3,1,""]}}}) |
Sorry, the diff of this file is too big to display
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
953257
-78.93%135
-30.77%23169
-10.09%