summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects/postgresql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/dialects/postgresql')
-rw-r--r--lib/sqlalchemy/dialects/postgresql/__init__.py2
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py99
-rw-r--r--lib/sqlalchemy/dialects/postgresql/json.py7
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py26
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py49
5 files changed, 126 insertions, 57 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/__init__.py b/lib/sqlalchemy/dialects/postgresql/__init__.py
index 1cff8e3a0..01a846314 100644
--- a/lib/sqlalchemy/dialects/postgresql/__init__.py
+++ b/lib/sqlalchemy/dialects/postgresql/__init__.py
@@ -5,7 +5,7 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-from . import base, psycopg2, pg8000, pypostgresql, zxjdbc
+from . import base, psycopg2, pg8000, pypostgresql, zxjdbc, psycopg2cffi
base.dialect = psycopg2.dialect
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index baa640eaa..1935d0cad 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -48,7 +48,7 @@ Transaction Isolation Level
---------------------------
All Postgresql dialects support setting of transaction isolation level
-both via a dialect-specific parameter ``isolation_level``
+both via a dialect-specific parameter :paramref:`.create_engine.isolation_level`
accepted by :func:`.create_engine`,
as well as the ``isolation_level`` argument as passed to
:meth:`.Connection.execution_options`. When using a non-psycopg2 dialect,
@@ -266,7 +266,7 @@ will emit to the database::
The Postgresql text search functions such as ``to_tsquery()``
and ``to_tsvector()`` are available
-explicitly using the standard :attr:`.func` construct. For example::
+explicitly using the standard :data:`.func` construct. For example::
select([
func.to_tsvector('fat cats ate rats').match('cat & rat')
@@ -299,7 +299,7 @@ not re-compute the column on demand.
In order to provide for this explicit query planning, or to use different
search strategies, the ``match`` method accepts a ``postgresql_regconfig``
-keyword argument.
+keyword argument::
select([mytable.c.id]).where(
mytable.c.title.match('somestring', postgresql_regconfig='english')
@@ -311,7 +311,7 @@ Emits the equivalent of::
WHERE mytable.title @@ to_tsquery('english', 'somestring')
One can also specifically pass in a `'regconfig'` value to the
-``to_tsvector()`` command as the initial argument.
+``to_tsvector()`` command as the initial argument::
select([mytable.c.id]).where(
func.to_tsvector('english', mytable.c.title )\
@@ -483,7 +483,7 @@ import re
from ... import sql, schema, exc, util
from ...engine import default, reflection
-from ...sql import compiler, expression, operators
+from ...sql import compiler, expression, operators, default_comparator
from ... import types as sqltypes
try:
@@ -680,10 +680,10 @@ class _Slice(expression.ColumnElement):
type = sqltypes.NULLTYPE
def __init__(self, slice_, source_comparator):
- self.start = source_comparator._check_literal(
+ self.start = default_comparator._check_literal(
source_comparator.expr,
operators.getitem, slice_.start)
- self.stop = source_comparator._check_literal(
+ self.stop = default_comparator._check_literal(
source_comparator.expr,
operators.getitem, slice_.stop)
@@ -876,8 +876,9 @@ class ARRAY(sqltypes.Concatenable, sqltypes.TypeEngine):
index += shift_indexes
return_type = self.type.item_type
- return self._binary_operate(self.expr, operators.getitem, index,
- result_type=return_type)
+ return default_comparator._binary_operate(
+ self.expr, operators.getitem, index,
+ result_type=return_type)
def any(self, other, operator=operators.eq):
"""Return ``other operator ANY (array)`` clause.
@@ -1424,7 +1425,8 @@ class PGDDLCompiler(compiler.DDLCompiler):
else:
colspec += " SERIAL"
else:
- colspec += " " + self.dialect.type_compiler.process(column.type)
+ colspec += " " + self.dialect.type_compiler.process(column.type,
+ type_expression=column)
default = self.get_column_default_string(column)
if default is not None:
colspec += " DEFAULT " + default
@@ -1476,8 +1478,13 @@ class PGDDLCompiler(compiler.DDLCompiler):
if not isinstance(expr, expression.ColumnClause)
else expr,
include_table=False, literal_binds=True) +
- (c.key in ops and (' ' + ops[c.key]) or '')
- for expr, c in zip(index.expressions, index.columns)])
+ (
+ (' ' + ops[expr.key])
+ if hasattr(expr, 'key')
+ and expr.key in ops else ''
+ )
+ for expr in index.expressions
+ ])
)
whereclause = index.dialect_options["postgresql"]["where"]
@@ -1539,94 +1546,93 @@ class PGDDLCompiler(compiler.DDLCompiler):
class PGTypeCompiler(compiler.GenericTypeCompiler):
-
- def visit_TSVECTOR(self, type):
+ def visit_TSVECTOR(self, type, **kw):
return "TSVECTOR"
- def visit_INET(self, type_):
+ def visit_INET(self, type_, **kw):
return "INET"
- def visit_CIDR(self, type_):
+ def visit_CIDR(self, type_, **kw):
return "CIDR"
- def visit_MACADDR(self, type_):
+ def visit_MACADDR(self, type_, **kw):
return "MACADDR"
- def visit_OID(self, type_):
+ def visit_OID(self, type_, **kw):
return "OID"
- def visit_FLOAT(self, type_):
+ def visit_FLOAT(self, type_, **kw):
if not type_.precision:
return "FLOAT"
else:
return "FLOAT(%(precision)s)" % {'precision': type_.precision}
- def visit_DOUBLE_PRECISION(self, type_):
+ def visit_DOUBLE_PRECISION(self, type_, **kw):
return "DOUBLE PRECISION"
- def visit_BIGINT(self, type_):
+ def visit_BIGINT(self, type_, **kw):
return "BIGINT"
- def visit_HSTORE(self, type_):
+ def visit_HSTORE(self, type_, **kw):
return "HSTORE"
- def visit_JSON(self, type_):
+ def visit_JSON(self, type_, **kw):
return "JSON"
- def visit_JSONB(self, type_):
+ def visit_JSONB(self, type_, **kw):
return "JSONB"
- def visit_INT4RANGE(self, type_):
+ def visit_INT4RANGE(self, type_, **kw):
return "INT4RANGE"
- def visit_INT8RANGE(self, type_):
+ def visit_INT8RANGE(self, type_, **kw):
return "INT8RANGE"
- def visit_NUMRANGE(self, type_):
+ def visit_NUMRANGE(self, type_, **kw):
return "NUMRANGE"
- def visit_DATERANGE(self, type_):
+ def visit_DATERANGE(self, type_, **kw):
return "DATERANGE"
- def visit_TSRANGE(self, type_):
+ def visit_TSRANGE(self, type_, **kw):
return "TSRANGE"
- def visit_TSTZRANGE(self, type_):
+ def visit_TSTZRANGE(self, type_, **kw):
return "TSTZRANGE"
- def visit_datetime(self, type_):
- return self.visit_TIMESTAMP(type_)
+ def visit_datetime(self, type_, **kw):
+ return self.visit_TIMESTAMP(type_, **kw)
- def visit_enum(self, type_):
+ def visit_enum(self, type_, **kw):
if not type_.native_enum or not self.dialect.supports_native_enum:
- return super(PGTypeCompiler, self).visit_enum(type_)
+ return super(PGTypeCompiler, self).visit_enum(type_, **kw)
else:
- return self.visit_ENUM(type_)
+ return self.visit_ENUM(type_, **kw)
- def visit_ENUM(self, type_):
+ def visit_ENUM(self, type_, **kw):
return self.dialect.identifier_preparer.format_type(type_)
- def visit_TIMESTAMP(self, type_):
+ def visit_TIMESTAMP(self, type_, **kw):
return "TIMESTAMP%s %s" % (
getattr(type_, 'precision', None) and "(%d)" %
type_.precision or "",
(type_.timezone and "WITH" or "WITHOUT") + " TIME ZONE"
)
- def visit_TIME(self, type_):
+ def visit_TIME(self, type_, **kw):
return "TIME%s %s" % (
getattr(type_, 'precision', None) and "(%d)" %
type_.precision or "",
(type_.timezone and "WITH" or "WITHOUT") + " TIME ZONE"
)
- def visit_INTERVAL(self, type_):
+ def visit_INTERVAL(self, type_, **kw):
if type_.precision is not None:
return "INTERVAL(%d)" % type_.precision
else:
return "INTERVAL"
- def visit_BIT(self, type_):
+ def visit_BIT(self, type_, **kw):
if type_.varying:
compiled = "BIT VARYING"
if type_.length is not None:
@@ -1635,16 +1641,16 @@ class PGTypeCompiler(compiler.GenericTypeCompiler):
compiled = "BIT(%d)" % type_.length
return compiled
- def visit_UUID(self, type_):
+ def visit_UUID(self, type_, **kw):
return "UUID"
- def visit_large_binary(self, type_):
- return self.visit_BYTEA(type_)
+ def visit_large_binary(self, type_, **kw):
+ return self.visit_BYTEA(type_, **kw)
- def visit_BYTEA(self, type_):
+ def visit_BYTEA(self, type_, **kw):
return "BYTEA"
- def visit_ARRAY(self, type_):
+ def visit_ARRAY(self, type_, **kw):
return self.process(type_.item_type) + ('[]' * (type_.dimensions
if type_.dimensions
is not None else 1))
@@ -1942,7 +1948,8 @@ class PGDialect(default.DefaultDialect):
cursor = connection.execute(
sql.text(
"select relname from pg_class c join pg_namespace n on "
- "n.oid=c.relnamespace where n.nspname=current_schema() "
+ "n.oid=c.relnamespace where "
+ "pg_catalog.pg_table_is_visible(c.oid) "
"and relname=:name",
bindparams=[
sql.bindparam('name', util.text_type(table_name),
diff --git a/lib/sqlalchemy/dialects/postgresql/json.py b/lib/sqlalchemy/dialects/postgresql/json.py
index 250bf5e9d..f38c4a56a 100644
--- a/lib/sqlalchemy/dialects/postgresql/json.py
+++ b/lib/sqlalchemy/dialects/postgresql/json.py
@@ -12,7 +12,7 @@ from .base import ischema_names
from ... import types as sqltypes
from ...sql.operators import custom_op
from ... import sql
-from ...sql import elements
+from ...sql import elements, default_comparator
from ... import util
__all__ = ('JSON', 'JSONElement', 'JSONB')
@@ -46,7 +46,8 @@ class JSONElement(elements.BinaryExpression):
self._json_opstring = opstring
operator = custom_op(opstring, precedence=5)
- right = left._check_literal(left, operator, right)
+ right = default_comparator._check_literal(
+ left, operator, right)
super(JSONElement, self).__init__(
left, right, operator, type_=result_type)
@@ -77,7 +78,7 @@ class JSONElement(elements.BinaryExpression):
def cast(self, type_):
"""Convert this :class:`.JSONElement` to apply both the 'astext' operator
- as well as an explicit type cast when evaulated.
+ as well as an explicit type cast when evaluated.
E.g.::
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index f67b2e3b0..5246abf1c 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -66,12 +66,13 @@ in ``/tmp``, or whatever socket directory was specified when PostgreSQL
was built. This value can be overridden by passing a pathname to psycopg2,
using ``host`` as an additional keyword argument::
- create_engine("postgresql+psycopg2://user:password@/dbname?host=/var/lib/postgresql")
+ create_engine("postgresql+psycopg2://user:password@/dbname?\
+host=/var/lib/postgresql")
See also:
-`PQconnectdbParams <http://www.postgresql.org/docs/9.1/static\
-/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS>`_
+`PQconnectdbParams <http://www.postgresql.org/docs/9.1/static/\
+libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS>`_
Per-Statement/Connection Execution Options
-------------------------------------------
@@ -237,7 +238,7 @@ The psycopg2 dialect supports these constants for isolation level:
* ``AUTOCOMMIT``
.. versionadded:: 0.8.2 support for AUTOCOMMIT isolation level when using
- psycopg2.
+ psycopg2.
.. seealso::
@@ -511,9 +512,19 @@ class PGDialect_psycopg2(PGDialect):
import psycopg2
return psycopg2
+ @classmethod
+ def _psycopg2_extensions(cls):
+ from psycopg2 import extensions
+ return extensions
+
+ @classmethod
+ def _psycopg2_extras(cls):
+ from psycopg2 import extras
+ return extras
+
@util.memoized_property
def _isolation_lookup(self):
- from psycopg2 import extensions
+ extensions = self._psycopg2_extensions()
return {
'AUTOCOMMIT': extensions.ISOLATION_LEVEL_AUTOCOMMIT,
'READ COMMITTED': extensions.ISOLATION_LEVEL_READ_COMMITTED,
@@ -535,7 +546,8 @@ class PGDialect_psycopg2(PGDialect):
connection.set_isolation_level(level)
def on_connect(self):
- from psycopg2 import extras, extensions
+ extras = self._psycopg2_extras()
+ extensions = self._psycopg2_extensions()
fns = []
if self.client_encoding is not None:
@@ -585,7 +597,7 @@ class PGDialect_psycopg2(PGDialect):
@util.memoized_instancemethod
def _hstore_oids(self, conn):
if self.psycopg2_version >= (2, 4):
- from psycopg2 import extras
+ extras = self._psycopg2_extras()
oids = extras.HstoreAdapter.get_oids(conn)
if oids is not None and oids[0]:
return oids[0:2]
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py b/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py
new file mode 100644
index 000000000..f5c475d90
--- /dev/null
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2cffi.py
@@ -0,0 +1,49 @@
+# testing/engines.py
+# Copyright (C) 2005-2015 the SQLAlchemy authors and contributors
+# <see AUTHORS file>
+#
+# This module is part of SQLAlchemy and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+"""
+.. dialect:: postgresql+psycopg2cffi
+ :name: psycopg2cffi
+ :dbapi: psycopg2cffi
+ :connectstring: \
+postgresql+psycopg2cffi://user:password@host:port/dbname\
+[?key=value&key=value...]
+ :url: http://pypi.python.org/pypi/psycopg2cffi/
+
+``psycopg2cffi`` is an adaptation of ``psycopg2``, using CFFI for the C
+layer. This makes it suitable for use in e.g. PyPy. Documentation
+is as per ``psycopg2``.
+
+.. versionadded:: 1.0.0
+
+.. seealso::
+
+ :mod:`sqlalchemy.dialects.postgresql.psycopg2`
+
+"""
+from .psycopg2 import PGDialect_psycopg2
+
+
+class PGDialect_psycopg2cffi(PGDialect_psycopg2):
+ driver = 'psycopg2cffi'
+ supports_unicode_statements = True
+
+ @classmethod
+ def dbapi(cls):
+ return __import__('psycopg2cffi')
+
+ @classmethod
+ def _psycopg2_extensions(cls):
+ root = __import__('psycopg2cffi', fromlist=['extensions'])
+ return root.extensions
+
+ @classmethod
+ def _psycopg2_extras(cls):
+ root = __import__('psycopg2cffi', fromlist=['extras'])
+ return root.extras
+
+
+dialect = PGDialect_psycopg2cffi