Compare commits

..

1587 Commits
2_5 ... master

Author SHA1 Message Date
dependabot[bot]
dcb302493a build(deps): bump pypa/cibuildwheel from 2.22.0 to 2.23.2
Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 2.22.0 to 2.23.2.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v2.22.0...v2.23.2)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-02 12:45:46 +01:00
Daniele Varrazzo
5509e01108
Merge pull request #1755 from bwoodsend/fix-macos-deployment-target
ci(macos): Avoid linking against Homebrew
2025-01-06 01:15:51 +01:00
Daniele Varrazzo
6cd0fbdc49 fix(macos): don't crash on undefined variable 2025-01-05 22:00:24 +01:00
Daniele Varrazzo
cee23d83e0 chore(macos): drop unneeded gettext from libpq building 2025-01-05 21:37:12 +01:00
Daniele Varrazzo
5bfba4c961 refactor: use pushd/popd instead of cd 2025-01-05 21:37:12 +01:00
Daniele Varrazzo
b943457896 test: drop brew curl to use the system one 2025-01-05 21:37:12 +01:00
Brénainn Woodsend
d0bc154f31 build(macos): Enable cross compiling libpq across macOS architectures
The GitHub Actions runners look like they're only 1 year away from the
last macOS x86_64 platform being removed. Get ahead of the game and
build x86_64 on arm64.
2025-01-05 20:44:25 +01:00
Daniele Varrazzo
1eac4fd4da test(macos): soften tests to account for macOS polling differences 2025-01-05 04:00:47 +01:00
Daniele Varrazzo
c8abc5ce61 ci(macos): no fast tests on macOS package building
We don't run complete tests in CI, so let's not waste this chance. The
overhead for complete tests is minimal compared to all the pipeline
boilerplate.
2025-01-05 04:00:00 +01:00
Daniele Varrazzo
65626ec565 ci(macos): add libpq build caching 2025-01-05 04:00:00 +01:00
Daniele Varrazzo
310bc75532 ci(macos): move libpq build script to BEFORE_ALL build step
This is is how it is organised in Linux.
2025-01-05 04:00:00 +01:00
Brénainn Woodsend
d43e5fe092 ci(macos): Avoid linking against homebrew
Homebrew binaries are always compiled for exactly the version they're
installed on making them very un-portable. When a wheel is "repaired" by
cibuildwheel, delocate-wheel pulls in _psycopg's dependencies
(libpq.dylib, libssl.dylib and libcrypto.dylib) which, on a GitHub
Actions macOS 14 runner, are provided by Homebrew and are therefore only
macOS >= 14 compatible. The resultant wheel is therefore incompatible
with all but the latest macOS versions.

Build all dependencies from source so that we can set the deployment
target to something sensible. Fixes #1753.
2025-01-04 21:23:15 +01:00
Daniele Varrazzo
3b684f91ca ci: rename merged artifact package
It doesn't contain binary packages only
2025-01-04 21:06:33 +01:00
dependabot[bot]
bf7fc6cfa4 build(deps): bump peter-evans/repository-dispatch from 2 to 3
Bumps [peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch) from 2 to 3.
- [Release notes](https://github.com/peter-evans/repository-dispatch/releases)
- [Commits](https://github.com/peter-evans/repository-dispatch/compare/v2...v3)

---
updated-dependencies:
- dependency-name: peter-evans/repository-dispatch
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-04 21:05:08 +01:00
Daniele Varrazzo
979d56a797 chore: update cibuildwheel to 2.22.0 2025-01-04 21:04:14 +01:00
dependabot[bot]
4903f1c5d6 build(deps): bump actions/cache from 3 to 4
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-04 21:02:30 +01:00
Daniele Varrazzo
1dc7b5b70b ci: add merge step to download all packages at once 2025-01-04 21:01:09 +01:00
Daniele Varrazzo
ed4ba11d17
Merge pull request #1772 from psycopg/ci-vcpkg
Package psycopg2-binary for windows using vcpkg libpq
2025-01-04 21:00:44 +01:00
Daniele Varrazzo
947f731400 ci: test against final Python 3.13 2025-01-04 19:06:56 +01:00
Daniele Varrazzo
b8d49e6280 test: skip module test on Windows
Life is too short to figure out why it fails.
2025-01-04 19:06:56 +01:00
Daniele Varrazzo
4dfa680a71 ci(macos): use the macos-13 runners
macos-12 is not supported anymore.
2025-01-04 19:06:56 +01:00
Daniele Varrazzo
f4282c6d87 chore: drop Postgres version parsing in setup.py
The macro is in the include files, no idea why parsing it from pg_config
was needed.
2025-01-04 19:06:56 +01:00
Daniele Varrazzo
a8765121d9 fix(ci): handle other pg_config options required by setup.py 2025-01-04 19:06:56 +01:00
Daniele Varrazzo
bb52bcf769 ci(windows): create the psycopg2-binary package in Github 2025-01-04 19:06:56 +01:00
Daniele Varrazzo
fa24c922e7 ci(windows): build binary packages using the vcpkg package 2025-01-04 19:06:56 +01:00
Daniele Varrazzo
3c7889b0e7 chore: drop appveyor CI integration 2025-01-04 19:06:56 +01:00
Daniele Varrazzo
e83754a414 ci: work around the envionment breaking guard 2024-10-15 13:49:08 +02:00
Daniele Varrazzo
a805acf59f chore: bump to version 2.9.10 2024-10-15 10:40:56 +02:00
Daniele Varrazzo
78561ac99d
Merge pull request #1728 from romank0/fetch-notifications-on-commit
Adds notifies processing during commit
2024-10-11 03:13:56 +02:00
Daniele Varrazzo
5283a835dc chore: add TransactionTimeout error, added in PostgreSQL 17
Url to fetch source changed from the official Postgres one to the Github
mirror because the former throttled us.
2024-10-11 02:41:31 +02:00
Daniele Varrazzo
f64dd397fd docs: add news entry about notifications on commit 2024-10-11 00:29:28 +02:00
Roman Konoval
cba6d39be0 removes duplication in tests 2024-10-11 00:26:05 +02:00
Roman Konoval
282360dd04 adds notifications processing after every PQexec 2024-10-11 00:26:05 +02:00
Roman Konoval
362cb00978 Adds notifies processing in pq_commit 2024-10-11 00:24:37 +02:00
Daniele Varrazzo
eaeeb76944
Merge pull request #1729 from edgarrmondragon/1692-py313-wheels
Build Python 3.13 wheels, drop support for Python 3.7
2024-10-11 00:17:47 +02:00
Daniele Varrazzo
4987362fb4 ci(windows): drop Python 3.8 packages
The runner image to build 3.8 package doesn't seem to have a currently
supported database, and the previously used 9.6 is no more supported on
current runners.
2024-10-10 15:48:48 +02:00
Daniele Varrazzo
8c9a35de38 ci: test with PostgreSQL 17 2024-10-09 19:46:48 +02:00
Daniele Varrazzo
563b55a725 docs: bump supported versions to Python 3.13 and Postgres 17 2024-10-08 17:08:02 +02:00
Daniele Varrazzo
dac8fa5632 ci(win): use PostgreSQL 13 for tests
By latest errors, it seems that Postgres 9.6 is no more supported on
VS2019 image. By documentation, it also seem that Postgres 13 is the
most recent supported database and not available in VS2015 image.
Therefore, drop Python 3.8 test (and likely build).

See https://www.appveyor.com/docs/services-databases/#postgresql
2024-10-08 17:04:40 +02:00
Edgar Ramírez-Mondragón
e1cf23d9c7
Drop Python 3.7 in other places 2024-10-05 01:41:20 -06:00
Edgar Ramírez-Mondragón
0eccfbec47
Ensure pg data dir exists 2024-10-05 01:35:47 -06:00
Edgar Ramírez-Mondragón
26f0f13b39
Use py executable in appveyor 2024-10-05 01:29:06 -06:00
Edgar Ramírez-Mondragón
a59079a4f2
Build Python 3.13 wheels 2024-10-04 22:40:03 -06:00
Anoosh Dsouza
f9780aa054 fixed a typo in doc/src/usage.rst file 2024-09-19 20:56:05 +02:00
0xTiger
658afe4cd9 docs: tiny grammar fix "a" -> "one" 2024-07-17 18:44:43 +02:00
Daniele Varrazzo
f79867c9f2 chore: bump to next dev version 2024-07-14 22:01:17 +02:00
Daniele Varrazzo
dc5249ba01
Merge pull request #1695 from befeleme/py3.13
Add support for Python 3.13
2024-07-14 21:58:10 +02:00
Daniele Varrazzo
7c2706a8b4 docs: note Python 3.13 support in news file 2024-07-14 21:57:27 +02:00
Karolina Surma
4a4b5acdc2 Declare the support for Python 3.13 in classifiers 2024-04-26 09:21:05 +02:00
Karolina Surma
efc5ad01e0 Add Python 3.13.0a6 to tox matrix 2024-04-26 09:21:05 +02:00
Karolina Surma
866bcef589 Add Python 3.13.0a6 to CI 2024-04-26 09:21:05 +02:00
Karolina Surma
3b9aa7cf9f Fix tests with Python 3.13
The textual representation of addresses has changed, adapt the code to
expect different values on Python 3.13+.
See: https://github.com/python/cpython/commit/f22bf8e3cf899896cf587099d292
2024-04-24 10:15:54 +02:00
Karolina Surma
829a7a2be9 _PyInterpreterState_Get() has become public in Python 3.13
Since 3.13.0a1 it has been renamed to PyInterpreterStateGet()
Source: https://github.com/python/cpython/pull/106321
2024-04-24 10:15:50 +02:00
Nick Zandbergen
a971c11d50 Update lobject_type.c
Add bytes as accepted input for documentation
2024-02-15 22:26:05 +00:00
dependabot[bot]
00870545b7 build(deps): bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-02 03:27:05 +00:00
dependabot[bot]
bf45060074 build(deps): bump actions/upload-artifact from 3 to 4
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-02 03:26:43 +00:00
Daniele Varrazzo
5fb59cd6ee Merge branch 'macos-arm64-py312' 2023-11-01 11:45:52 +01:00
Daniele Varrazzo
e0d1daf290 Merge branch 'wheel-312-win' 2023-11-01 11:45:35 +01:00
Rene Leonhardt
941ac9a724 chore: add support for Python 3.12 macOS arm64 wheels 2023-11-01 11:33:30 +01:00
Rene Leonhardt
4e473010a3
chore: let dependabot update GitHub actions 2023-10-30 09:19:50 +00:00
Rene Leonhardt
8947b00142 chore: update GitHub actions and Postgres image tags 2023-10-29 18:05:30 +00:00
Daniele Varrazzo
46191f1fde ci(windows): add Python 3.12 to the testing grid 2023-10-28 11:41:40 +02:00
Daniele Varrazzo
e73d2fa9f0 ci(win32): install the setuptools package to build in appveyor
Present so far, it wasn't installed in the first image containing Python 3.12.
2023-10-28 01:57:56 +02:00
Daniele Varrazzo
89005ac5b8 docs: add README blurb pointing to psycopg 3 on PyPI
See #1632.
2023-10-10 23:35:40 +02:00
Panagiotis H.M. Issaris
bfdffc2c57
chore: show a Changelog link on PyPI 2023-10-06 15:05:42 +01:00
Daniele Varrazzo
ad5bee7054 chore: bump version number to 2.9.9 2023-10-03 11:39:35 +02:00
Daniele Varrazzo
37d1de1c8f chore: add support for Python 3.12 2023-10-03 11:39:35 +02:00
Daniele Varrazzo
abf2723c0a chore: drop support for Python 3.6 2023-10-03 11:39:35 +02:00
Daniele Varrazzo
2da65a715c chore: drop leftover Python 2.7 import aliases from setup.py 2023-10-03 11:39:35 +02:00
Daniele Varrazzo
3fa60fd268 chore: bump doc requirement complained by dependabot 2023-10-03 11:39:32 +02:00
Daniele Varrazzo
1c1484e43b ci: better interaction with scaleway build server 2023-10-03 11:39:32 +02:00
Daniele Varrazzo
c81cec604f chore: bump to next dev release 2023-10-03 11:20:17 +02:00
Daniele Varrazzo
7fe8cb77ca chore: bump docs requirements dependabot complains about 2023-09-28 09:29:21 +02:00
Daniele Varrazzo
b39d5d6492 chore: bundle libpq 16
- https://github.com/psycopg/psycopg/issues/650
- https://github.com/psycopg/psycopg/discussions/528
2023-09-28 09:26:33 +02:00
Daniele Varrazzo
921510d5be docs: replace "compiled against" with "bundled with" in news file
Less confrontational...
2023-09-28 09:22:08 +02:00
Daniele Varrazzo
999d7a6d01 test: skip ssl test if libpq runtime > 16
Close #1619
2023-09-11 16:11:07 +01:00
Daniele Varrazzo
3eee3e336d ci: fix passing env vars to build scripts 2023-08-04 17:28:24 +01:00
Daniele Varrazzo
1e0086b1fe chore: bump version to 2.9.7 2023-08-04 17:22:46 +01:00
Daniele Varrazzo
4fe28d661a Merge branch 'dev/init-failure' 2023-08-04 17:20:50 +01:00
Daniele Varrazzo
14e06d8185 docs: mention module init errors fix in news file 2023-08-04 17:20:02 +01:00
Jacob Champion
959339cefb Return NULL on failed module initialization
Previously, any exceptions raised during initialization were swallowed
with a message like

    SystemError: initialization of _psycopg raised unreported exception

Fixes #1598.
2023-08-04 17:19:58 +01:00
Daniele Varrazzo
fb77bdca0b Merge branch 'dev/fix-meson-build' 2023-08-04 17:19:41 +01:00
Daniele Varrazzo
ef7053c070 docs: add pg_config improvement to news file 2023-08-04 17:18:59 +01:00
Jacob Champion
ea71fbcd46 setup.py: handle more corner cases for pg_config
- Differentiate between unexpected empty values and execution failure.
- Accept empty --cppflags and --ldflags output. Fixes #1599.
- Accept UTF-8 output from pg_config, for alternative client locales.
2023-08-04 17:18:56 +01:00
Daniele Varrazzo
0c5b5f4ec3 chore: bump cibuildwheel version to 2.14.1 2023-08-04 17:18:17 +01:00
Daniele Varrazzo
20fcfd6786 chore: upgrade libpq and openssl versions used in packaging 2023-08-04 17:18:17 +01:00
Xing Guo
329f43c762 Use except psycopg2.Error as e in example. 2023-07-27 10:09:03 +01:00
Daniele Varrazzo
9f020124f8 docs: don't show objects in side bar
Too wide, too ugly, useless to navigate.

Close #1587
2023-06-07 12:09:12 +02:00
Christoph Berg
8b17e218be Disable test_ssl_attribute on PG16+
PG15 changed the semantics of some ssl attributes (#1506), and a very
similar regression test failure has now been observed again with PG16.
Disable the test for now.
2023-05-29 17:42:42 +02:00
Brent Wilkins
c96f991a8d Updated from deprecated license_file parameter 2023-05-25 19:01:27 +02:00
Amirsoroush
3450d159b5 fix typo in Usage.html page in documentation 2023-04-23 22:47:26 +02:00
Daniele Varrazzo
5108191aa5 chore: upgrade docs build dependencies 2023-04-17 20:11:47 +02:00
Daniele Varrazzo
638be85eb6 docs: drop use of print statement, use the print() function instead
Close #1556
2023-04-17 20:07:17 +02:00
Daniele Varrazzo
0b01ded426 ci: drop github download script
Easier to do interactively, now that all the artifacts are packaged in
the same archive.
2023-04-03 05:10:36 +02:00
Daniele Varrazzo
46238ba351 ci: fix cache key by setting lib versions in job env 2023-04-03 05:07:01 +02:00
Daniele Varrazzo
51dd59ef9d chore: drop Python 3.6 from Windows packages 2023-04-03 05:06:13 +02:00
Daniele Varrazzo
333b3b7ac4 ci: use cibuildwheel to build linux wheel packages 2023-04-02 17:56:29 +02:00
Daniele Varrazzo
7a8f4d6222 chore: bump version to 2.9.6 2023-04-02 13:00:38 +02:00
Daniele Varrazzo
b747b5b0fd ci: bundle all build artifacts in a single directory 2023-04-02 12:59:29 +02:00
Daniele Varrazzo
1781e8b2c9 build: package openssl 1.1.1t with binary packages 2023-04-02 12:47:29 +02:00
Daniele Varrazzo
fdb204b4e3 docs: mention manylinux2014 packages in news file 2023-04-02 12:47:25 +02:00
Daniele Varrazzo
09b82e4094 ci: bump qemu action version to drop node deprecation warning 2023-03-30 17:09:23 +02:00
Daniele Varrazzo
97df29a312 ci: build macOS packages using cibuildwheel
Close #1558.
2023-03-30 13:31:30 +02:00
Daniele Varrazzo
daeec37fab
Merge pull request #1545 from AmirBitaraf/aarch64_manylinux2014_libpq
Move to manylinux2014 for aarch64, ppc64le builds.
2023-03-27 17:11:28 +02:00
Amir Bitaraf
c0666b0935 Modify LD_LIBRARY_PATH to support all architectures 2023-03-26 18:35:00 +01:00
Amir Bitaraf
cc21faa4f4 Move to manylinux2014 for aarch64, ppc64le builds. 2023-03-26 18:35:00 +01:00
Daniele Varrazzo
63947e2552 ci: drop test on Python 3.6
The image is not available anymore
2023-02-25 16:07:21 +01:00
Daniele Varrazzo
52df8371f3 ci: pin tox to v3
Not interested in fixing incompatibility changes.
2023-02-25 16:05:14 +01:00
Daniele Varrazzo
feeb989323 docs: use https url in license file
Close #1549.
2023-02-25 15:36:35 +01:00
Daniele Varrazzo
e8d92b74fd Merge branch 'py311-win32' 2022-11-07 23:42:28 +01:00
Daniele Varrazzo
026b5bf3ab ci: re-enable builds suspended for build win32 packages for Python 3.11 2022-11-07 23:41:50 +01:00
Daniele Varrazzo
02b5e226f4 ci: build packages for Python 3.11 for Workgroup... for Windows! 2022-11-07 22:38:07 +01:00
Daniele Varrazzo
57009707b1 ci: Test Python 3.11 on Appveyor 2022-11-07 22:32:56 +01:00
Daniele Varrazzo
3182ea2303 ci: adapt macOS arm64 build script to changes in Python 3.11 and PostgreSQL 15 2022-10-27 00:41:09 +02:00
Daniele Varrazzo
ea32730a39 Merge branch 'build-macos-py311' 2022-10-27 00:40:23 +02:00
Daniele Varrazzo
deb00e5454 ci: re-enable builds suspended to build macOS packages for Python 3.11 2022-10-27 00:39:11 +02:00
Daniele Varrazzo
8c824d0e47 Build packages for macOS x86_64 Python 3.11
The required images weren't available at the time of building the other
packages. See #1514.

The changeset includes temporary changes to skip other builds. They will
be reverted before merging.
2022-10-27 00:28:04 +02:00
Daniele Varrazzo
1bf8e77ea2 chore: remove macOS 3.11 build from build grid
Not available yet on Github: see build failure at
https://github.com/psycopg/psycopg2/actions/runs/3320363567/jobs/5486654852
2022-10-25 13:34:29 +02:00
Daniele Varrazzo
af3ee06ec0 chore: upgrade Github action versions 2022-10-25 13:04:28 +02:00
Daniele Varrazzo
963fb1190b chore: fix yaml syntax in Github Action workflow 2022-10-25 12:59:23 +02:00
Daniele Varrazzo
27a99dac72 chore: bump version number to release 2.9.5 2022-10-25 12:55:57 +02:00
Daniele Varrazzo
78690cfaf8 lint: reformat appveyor yaml 2022-10-25 12:54:34 +02:00
Daniele Varrazzo
259d15ae3e chore: build binary packages with OpenSSL 1.1.1q 2022-10-25 12:47:46 +02:00
Daniele Varrazzo
77039cad63 chore: fix directory where to find binary package after build 2022-10-25 12:47:02 +02:00
Daniele Varrazzo
e6e465c509 chore: build binary packages using libpq from PostgreSQL 15
fix #1497 as a side effect of using libpq 15.
2022-10-25 12:47:02 +02:00
Daniele Varrazzo
12700a5f02 Build packages for Python 3.11 2022-10-25 12:37:23 +02:00
Daniele Varrazzo
271dd1fce7 chore: move cache_rebuild file into appveyor dir 2022-10-25 12:24:10 +02:00
Daniele Varrazzo
e4b2a197c6 chore: bump to next dev version 2022-10-25 12:20:46 +02:00
Daniele Varrazzo
20bb486663 Merge branch 'doc_examples_executemanybatch' 2022-10-20 21:33:46 +02:00
Daniele Varrazzo
f401d0b738 docs: fix reST syntax and whitespace in executemany examples 2022-10-20 21:31:18 +02:00
Ion Alberdi
4912be0e7f [test_basic_types] Add test for array[%s] on NULL arrays
Add test to verifity the fix for #1507.
2022-10-11 13:02:22 +01:00
Hannes
aabac5df31
Add executemany & execute_batch examples 2022-10-10 19:08:46 +02:00
Daniele Varrazzo
a12dbc4357 docs: fix typos in release notes 2022-10-06 03:58:50 +01:00
Daniele Varrazzo
bc82c8f9cc fix: set default SYSCONFDIR to the quasi-standard /etc/postgresql-common
Fix #1365.
2022-10-06 03:49:25 +01:00
Daniele Varrazzo
c38aa27d7d chore: bump version number to release 2.9.4 2022-10-06 03:32:17 +01:00
Daniele Varrazzo
bd96594e2d docs: add link to release notes page to find which Python version is supported
Close #1418.
2022-10-06 03:27:40 +01:00
Daniele Varrazzo
182a51a33f chore: upgrade packaged libpq version and dependencies
appveyor.cache_rebuild reformatted for greppability.
2022-10-06 03:27:40 +01:00
Daniele Varrazzo
76b703e910 Merge branch 'pg15' 2022-10-06 02:59:28 +01:00
Daniele Varrazzo
29a65f756c chore: upgrade error codes to PostgreSQL 15 2022-10-06 02:26:09 +01:00
Daniele Varrazzo
6d815f5df9 test: adapt ssl test to libpq 15
See #1506, PostgreSQL bug 17625
(https://www.postgresql.org/message-id/17625-fc47c78b7d71b534%40postgresql.org)
2022-10-06 02:09:19 +01:00
Daniele Varrazzo
c7326f8da7 test: add PostgreSQL 15 to the test grid 2022-10-06 02:09:19 +01:00
Daniele Varrazzo
68d786b610 Merge branch 'fix-1487' 2022-10-06 02:09:06 +01:00
Daniele Varrazzo
7054e1aadf test: add test to verify register_range() with names requiring escape
Unlike for register_composite(), this works already.
2022-10-06 02:05:49 +01:00
Daniele Varrazzo
ac25d3bdc0 fix: look up for range types defined in schemas in the search path 2022-10-06 02:05:39 +01:00
Daniele Varrazzo
9535462ce9 fix: correctly handle composites with names or schema requiring escape 2022-10-06 01:56:28 +01:00
Daniele Varrazzo
d88e4c2a3c fix: handle types in the search path in register_composite()
Fix #1487.
2022-10-06 01:10:07 +01:00
Daniele Varrazzo
31a80410db chore: bump to next dev release 2022-10-06 00:21:27 +01:00
Daniele Varrazzo
d6c81b4ff0 docs: mention MacOS ARM wheel support 2022-10-05 19:48:04 +01:00
Magnus Watn
c6f30880a2 Remove Apple M1 bullet point from issue template
https://github.com/psycopg/psycopg2/issues/1286 is now closed.
2022-10-03 10:09:46 +01:00
Daniele Varrazzo
e3664380c4 build: fix starting Postgres in macOS build script
The brew command fails with:

    Could not enable service: 125: Domain does not support specified action
    Error: Failure while executing; `/bin/launchctl enable gui/501/homebrew.mxcl.postgresql@14` exited with 125.
2022-09-25 02:49:16 +01:00
Daniele Varrazzo
fdf957dcbd build: use "latest" version of github builders 2022-09-25 02:46:21 +01:00
Nikita Sobolev
3e7bb8d1aa Remove __nonzero__ method 2022-07-30 14:03:10 +02:00
Tim Tisdall
07c83ef8bb Link to the right PR for adding alpine wheels 2022-07-28 14:39:33 +02:00
Daniele Varrazzo
f07b3ad0a6 Merge branch 'build-macos-arm64' 2022-07-28 13:30:32 +02:00
Daniele Varrazzo
611c610041 docs: fixed quote_ident() example
Close #1481
2022-07-27 02:54:17 +02:00
Daniele Varrazzo
25c40f8ac3 build: add scripts to build macOS arm64 packages 2022-07-17 00:20:08 +01:00
Daniele Varrazzo
ba92a22bc9 test: drop test table if exist
It might be a residue of a psycopg 3 test run in the same db.
2022-07-16 23:58:43 +01:00
Rafi Shamim
3c58e96e10 Unskip tests that work on CockroachDB v22.1
CockroachDB supports named cursors in v22.1, so more tests pass.
2022-03-28 20:26:23 +02:00
Daniele Varrazzo
626078388a Use pip-tools to create the requirement file to build the docs
Docs building just broke. The requirement file had some version upper
boundary that caused problems between Sphinx and jinja2.
2022-03-26 02:45:40 +01:00
Daniele Varrazzo
c34bf2f2f9 Bump to release 2.9.3 2021-12-29 13:48:23 +01:00
Daniele Varrazzo
94ba06748f Merge branch 'musllinux' 2021-12-29 13:36:25 +01:00
Peter Lithammer
c5528da2dc
Mention Alpine/musl wheels in news file 2021-12-10 17:21:34 +01:00
Peter Lithammer
2dc137975a
Build musllinux wheels 2021-12-10 17:21:34 +01:00
Daniele Varrazzo
bc79abace1 Bump to next dev release 2021-12-10 14:28:04 +01:00
Daniele Varrazzo
846ae52ab2 Create parent directories too in artifacts download 2021-12-10 14:26:06 +01:00
Daniele Varrazzo
217f4120ca Strip debug symbols from binary packages
The _psycopg.so library goes down from 1.6mb to 300k in Linux packages.
2021-12-10 14:26:06 +01:00
John Vandenberg
4d4d2bc444 Include sys/time.h for gettimeofday
Fixes https://github.com/psycopg/psycopg2/issues/1397
2021-12-03 11:29:39 +01:00
John Vandenberg
4b637ec34a PyPy does not have PyDateTime_TimeZone_UTC
Fixes https://github.com/psycopg/psycopg2/issues/1398
2021-12-03 11:29:21 +01:00
Will Thompson
53bda13afa Fix typo in large object usage documentation 2021-11-21 16:10:42 +01:00
Daniele Varrazzo
8ef195f2ff Bump version number to release 2.9.2 2021-11-11 21:16:12 +01:00
Daniele Varrazzo
1b013b529b Merge branch 'py311' 2021-11-11 21:14:28 +01:00
Daniele Varrazzo
0a4a469669 Mention Python 3.11 preliminary support in the newsfile. 2021-11-11 21:13:38 +01:00
Cyril Jouve
5fb1305a14 support for python 3.11 2021-11-11 21:13:38 +01:00
Daniele Varrazzo
898cbff5a6 Build binary packages against PosgtgreSQL 14.1 lipq
Close #1388.
2021-11-11 21:11:59 +01:00
Daniele Varrazzo
7dd193a7f7 errorcodes map and errors classes updated to PostgreSQL 14. 2021-11-11 20:08:39 +01:00
Daniele Varrazzo
1a0c02a6f4 Raise an error for dates > 10K instead of returning Y9999
Close #1307.
2021-11-11 20:01:14 +01:00
Daniele Varrazzo
1454b14ae0 Fix Python 3.10 and PostgreSQL 14 compatibility notes 2021-11-05 18:37:58 +01:00
Daniele Varrazzo
8e186dd7e9 Merge branch 'py310' 2021-11-03 14:18:09 +01:00
Daniele Varrazzo
7236a1f851 Fix f-string in Appveyor package download script 2021-11-03 14:16:38 +01:00
Daniele Varrazzo
63d30aa397 Add Python 3.10 to Appveyor test grid 2021-11-03 14:16:38 +01:00
Daniele Varrazzo
6b80bd0648 Drop Windows exe package build 2021-11-03 14:16:38 +01:00
Daniele Varrazzo
5a96021612 Fix issue template markup 2021-10-30 22:57:12 +02:00
Daniele Varrazzo
4a46aa39a5 Build Python 3.10 packages of relase 2.9.1 2021-10-11 23:32:30 +02:00
Daniel Saxton
3430dcdee6 Fix doc typo 2021-09-22 12:56:08 +01:00
Daniele Varrazzo
1b255b7dc3 Fix up-date-date typo
Close #1336
2021-08-07 20:53:54 +01:00
Daniele Varrazzo
52c4d6fad4 Add psycopg version to issue templates 2021-07-17 14:26:54 +02:00
Daniele Varrazzo
ee3a069f1d Maintainer email fixed
gmail.org!
2021-07-16 14:50:08 +02:00
Daniele Varrazzo
9cfe80ea55 Drop unwanted issue template 2021-07-14 12:22:58 +02:00
Daniele Varrazzo
64b159676f Add issue templates 2021-07-14 12:22:00 +02:00
Daniele Varrazzo
8fe9861df5 Add docs anchor to reach the 'with' statement from psycopg3 docs 2021-07-14 02:32:22 +02:00
Daniele Varrazzo
39f12bbfc5 Don't build .exe packages anymore 2021-06-30 14:52:27 +01:00
Daniele Varrazzo
47b93efcf8 Note in the docs that now the table and fields names are escaped. 2021-06-17 16:52:44 +01:00
Daniele Varrazzo
7749898a94 Drop script to update docs on travis 2021-06-17 13:37:20 +01:00
Daniele Varrazzo
46bc175cc7 Trigger docs update to the website build workflow on GitHub Action 2021-06-17 12:54:36 +01:00
Daniele Varrazzo
dd9c6659bc Fix building docs for the website 2021-06-17 03:54:14 +01:00
Daniele Varrazzo
62490a6bcc Allow to specify the build to download from Appveyor 2021-06-17 03:54:14 +01:00
Daniele Varrazzo
c59ff6a4b7 Don't require the virtualenv binary to build the docs 2021-06-17 01:42:42 +01:00
Daniele Varrazzo
b241def64b Fix representation of sql.Placeholder
Fix also Placeholder tests, including an error which made an assert
always true, which made us miss the regression in #1291.
2021-06-17 00:28:14 +01:00
Daniele Varrazzo
2df79c5a5f Bump version number to 2.9.1 2021-06-17 00:06:04 +01:00
Daniele Varrazzo
dd2ff2af56 Fix regression with named sql.Placeholder
Close #1291.
2021-06-16 23:56:05 +01:00
Daniele Varrazzo
b46424447f Bump to next dev release 2021-06-16 23:56:05 +01:00
Daniele Varrazzo
bab166e2c1 Fix spelling in news file 2021-06-16 17:08:06 +01:00
Daniele Varrazzo
c5aa98d8bc Add note about cursor.callproc() and PostgreSQL procedures
Close #1155
2021-06-16 16:51:13 +01:00
Daniele Varrazzo
cbbf195a23 Tweak package paths in release docs 2021-06-16 16:38:12 +01:00
Daniele Varrazzo
2b7383c9f9 Build docs from the master branch 2021-06-16 16:37:59 +01:00
Daniele Varrazzo
50145014e8 Bump to versio 2.9 2021-06-16 13:28:31 +01:00
Daniele Varrazzo
9ac54b3615 Move appveyor build support to the scripts/build dir 2021-06-15 18:57:22 +01:00
Daniele Varrazzo
f5d6366287 Rename the github package download script for consistency 2021-06-15 18:54:45 +01:00
Daniele Varrazzo
bbc5fd3180 Drop obsolete file to build Windows packages 2021-06-15 18:42:25 +01:00
Daniele Varrazzo
9e5847222d Upgrade libpq to 13.3 and libssl to 1.1.1k on windows too 2021-06-15 18:42:25 +01:00
Daniele Varrazzo
cefb818105 Build manylinux2014 packages for i686/x86_64 platforms
The manylinux_2_24 tag leaves too many users without usable packages.
Using this tag requires to build libraries too or a libssh too old will
be used, with the segfault risks seen in the past.

OTOH building all the libraries on arm/ppc platforms proves very time
consuming and requires further tooling than what available in the image.
Because these packages are new it seems ok to use the manylinux_2_24
tag and use the package versions of libpq/libssl.
2021-06-15 18:42:25 +01:00
Daniele Varrazzo
37ab1d8877 Bump to a new dev version number to try to release new packages 2021-06-15 18:28:13 +01:00
Daniele Varrazzo
1d3a89a0bb Copyright year updated to 2021
ag -l Copyright | xargs sed -i \
    "s/\(.*copyright (C) [0-9]\+\)\(-[0-9]\+\)\?\(.*Psycopg Team.*\)/\1-$(date +%Y)\3/I"
2021-06-15 00:37:22 +01:00
Daniele Varrazzo
af05c3a1ec Merge branch 'timezone-seconds' 2021-06-15 00:25:55 +01:00
Daniele Varrazzo
1d3d5e905f Deprecate the psycopg2.tz module
Don't use its objects anymore in the tests (except for the tests for the
objects themselves).
2021-06-15 00:22:54 +01:00
Daniele Varrazzo
f28502663f Use datetime.timezone as default tzinfo_factory. 2021-06-15 00:17:14 +01:00
Daniele Varrazzo
2eac70786e Drop support for mx.DateTime objects
They are Python 2 only.
2021-06-14 23:05:48 +01:00
Daniele Varrazzo
476a969bd8 Handle correctly timestamps with fractions of minute in the timezone offset
Close #1272.
2021-06-14 22:25:02 +01:00
Daniele Varrazzo
5667026883 Use a stdlib timezone in TimestampFromTicks
This is the only use of `LocalTimezone` in psycopg2 code.
2021-06-14 19:22:59 +01:00
Daniele Varrazzo
521981584d Clean up the packaging procedure 2021-05-29 21:57:26 +01:00
Daniele Varrazzo
06c3c3a557 Merge branch 'packages' 2021-05-26 17:29:03 +01:00
Daniele Varrazzo
808007456d Document the new way of building packages 2021-05-26 17:28:14 +01:00
Daniele Varrazzo
a9db3228d3 One line about the new packages in the news file 2021-05-26 17:28:14 +01:00
Daniele Varrazzo
52cd94442c Add include and lib dirs from libpq --cppflags, --ldflags
They seem the right thing to fix MacOS build woes.

Inspired to #935, might close #1200.
2021-05-26 17:28:14 +01:00
Daniele Varrazzo
d116b80c5f Add script to download packages from appveyor 2021-05-26 17:28:14 +01:00
Daniele Varrazzo
e7ce6761e1 Use Appveyor to build Windows packages
The script was executed both by this repos' appveyor config (to run the
tests) and by the psycopg2-wheels config (to build the packages). Now
there are two different workflows to execute for tests and to build packages.

The only way to swap them is to change the project config it seems, in
<https://ci.appveyor.com/project/psycopg/psycopg2/settings>.
2021-05-26 17:26:00 +01:00
Daniele Varrazzo
efae570a07 Build MacOS packages on GitHub Actions 2021-05-26 17:23:40 +01:00
Daniele Varrazzo
d1c7e6a094 Add script to download packages from GitHub 2021-05-26 17:23:40 +01:00
Daniele Varrazzo
9b91b09f9c Enable qemu to build arm/ppc packages on github 2021-05-26 17:23:40 +01:00
Daniele Varrazzo
b5dd3aae86 Build packages for Python >= 3.6 2021-05-26 17:23:40 +01:00
Daniele Varrazzo
367ea40b1e Allow libpq tests to fail
They fail on image build when we delete the system library.
2021-05-26 17:23:40 +01:00
Daniele Varrazzo
ec531bee31 Create sdist packages
Adapted from the psycopg2-wheels project
2021-05-25 23:23:27 +01:00
Daniele Varrazzo
8a2deb39ed Escape table and column names in cursor.copy_from() and .copy_to() 2021-05-25 11:50:23 +01:00
Daniele Varrazzo
e5ad0ab2d9 'with' starts a transaction even on autocommit connections
Close #941
2021-05-24 14:13:19 +02:00
Daniele Varrazzo
d8e6426433 Fix formatting of last entries in the NEWS file 2021-05-24 14:11:06 +02:00
Daniele Varrazzo
506a10026a Remove configuration for unused VS versions in appveyor build 2021-05-24 11:17:01 +02:00
Daniele Varrazzo
cb12317d21 Drop use of obsolete alias PyMem_Del 2021-05-24 11:15:24 +02:00
Daniele Varrazzo
e7c5f95bf6 Merge branch 'github-actions' 2021-05-22 17:21:06 +02:00
Daniele Varrazzo
09d6e3cf64 Use GitHub Actions badge in the readme 2021-05-22 17:20:54 +02:00
Daniele Varrazzo
5d19c6ef7e Update GitHub Actions as on branch main_2_8
Drop Python version not supported on master.
Drop Travis workflow on master branch too.
2021-05-22 17:20:12 +02:00
Riccardo Magliocchetti
9dbe8c6757 ci: first stab at running CI as github actions
Props to Adam Chainz for sharing its setup.
2021-05-22 16:51:53 +02:00
Yusuke Hayashi
fed22d39e9 Fix typo 2021-05-22 14:30:11 +02:00
Daniele Varrazzo
19ddbc47ca Merge branch 'rm-2.7' 2021-05-20 16:59:43 +02:00
Daniele Varrazzo
cdc83d64db Add Python 3.9 to travis test grid, drop 2.7 2021-05-20 16:58:46 +02:00
Daniele Varrazzo
3db4abcfa4 Unbreak f-string wrong replacements 2021-05-20 16:49:05 +02:00
Daniele Varrazzo
8f40c648af Merge branch 'master' into rm-2.7 2021-05-20 16:36:55 +02:00
Chris Wilson
45599b2716 Add warning about send_feedback and cursor choice 2021-05-20 16:33:00 +02:00
Hans Ginzel
787a7b90ae cursor.rst typo: was creates
name attribute: “cursor was creates” → “was created”
2021-05-20 16:26:08 +02:00
Daniele Varrazzo
55aef83fa1 Merge branch 'sqlstate_errors' 2021-05-20 16:17:47 +02:00
Daniele Varrazzo
3487f627e2 Mention sqlstate reinit in NEWS file 2021-05-20 16:16:51 +02:00
Sandro Mani
f59d626fe3 Don't re-initialize psycoEncodings if already initialized 2021-05-20 16:14:24 +02:00
Sandro Mani
22575528be Don't abort if sqlstate_errors already initialized 2021-05-20 16:14:24 +02:00
Daniele Varrazzo
0f457a01d9 Fix NEWS typo 2021-05-20 13:12:46 +02:00
Daniele Varrazzo
8ea5d0c0b8 Fix segfault initialising Column object manually
Close #1252
2021-05-20 13:10:59 +02:00
Daniele Varrazzo
391386cfb9 Accept no param in connect()
More friendly towards ``connect(**parse_dsn())``, and what psycopg3 does.

Close #1250
2021-05-20 13:10:53 +02:00
Tim Gates
0d7953a521 docs: fix a few simple typos
There are small typos in:
- doc/src/faq.rst
- psycopg/cursor_type.c
- psycopg/xid_type.c
- scripts/make_errorcodes.py
- scripts/make_errors.py
- tests/dbapi20.py
- tests/test_connection.py

Fixes:
- Should read `publicly` rather than `publically`.
- Should read `unicode` rather than `uniconde`.
- Should read `supposed` rather than `suppsed`.
- Should read `something` rather than `somenthing`.
- Should read `portable` rather than `portible`.
- Should read `exhausted` rather than `exausted`.
- Should read `compliance` rather than `compiliance`.

Closes #1275
2021-05-20 12:22:47 +02:00
Rafi Shamim
73969ba3e7 Skip test_encrypt_server for CockroachDB 2021-04-21 12:56:54 +01:00
arulajmani
f469331af5 Skip test_9_6_diagnostics test for CRDB
Previously, the CRDB's pg server version was 9.5, which meant this test
wasn't run as it is skipped for versions 9.6 and before. Now that the
server version of CRDB is 13, this check no longer applies.

This patch explicitly skips test_9_6_diagnostics for CRDB. The reason
for this is the same as test_9_3_diagnostics, which is currently
skipped for CRDB.
2020-12-16 23:41:45 +00:00
Hugo van Kemenade
8830e30f73
Merge branch 'master' into rm-2.7 2020-11-18 18:10:16 +02:00
Hugo van Kemenade
c3b65d63b6 Upgrade f-strings with flynt -a and remove int() 2020-11-18 18:09:08 +02:00
Daniele Varrazzo
e85ef2298b Merge branch 'connection_exception' 2020-11-17 22:45:52 +00:00
Hugo van Kemenade
8d7f660309 Upgrade f-strings with flynt 2020-11-17 23:52:11 +02:00
Daniele Varrazzo
8449844af3 Merge branch 'pg13-win' 2020-11-17 21:07:52 +00:00
Hugo van Kemenade
d956eaa3b1 Drop support for EOL Python 2.7 2020-11-17 22:53:44 +02:00
Hugo van Kemenade
7babeccbec Upgrade Python syntax with pyupgrade --py36-plus 2020-11-17 22:22:11 +02:00
Hugo van Kemenade
6c48b63ae4 Drop support for EOL Python 2.7 2020-11-17 22:22:11 +02:00
Sergey Golitsynskiy
b05a581931 Fix typo in sample code: psycopg >> psycopg2 2020-11-17 20:19:26 +00:00
Hugo van Kemenade
694a20fb95
Drop support for EOL Python 3.5 (#1197) 2020-11-17 20:17:12 +00:00
Daniele Varrazzo
490c53bace
Merge pull request #1000 from hugovk/rm-3.4
Drop support for EOL Python 3.4
2020-11-17 16:28:47 +00:00
Justas Sadzevicius
cdca0a20e0 Classify connection exceptions as operational errors to better conform with PEP 249 2020-11-17 18:02:06 +02:00
Hugo van Kemenade
60ed2770f3
Merge branch 'master' into rm-3.4 2020-11-17 18:01:04 +02:00
Daniele Varrazzo
8764a85320 Mention Python 3.9 supported
See #1183
2020-11-16 11:53:30 +00:00
Jason Erickson
f1dfbd59af Build against PostgreSQL 13.0 and removed Py27/34
PostgreSQL 12 and 13 do not support older Microsoft Visual Studio compilers
and therefore we can not build against Python 2.7 and Python 3.4
2020-11-13 12:24:12 -07:00
Jason Erickson
e3f8cf0702 Remove old patch for Postgres 9.6 and OpenSSL 1.1 2020-11-13 12:22:38 -07:00
Hugo van Kemenade
d8aa60221d
Merge branch 'master' into rm-3.4 2020-11-13 21:22:26 +02:00
Jason Erickson
12b1432fe1 Build more OpenSSL binaries and add to path
More recent verions of the PostgreSQL source code requires some OpenSSL
binaries to be on the PATH.
2020-11-13 12:17:48 -07:00
Jason Erickson
f5e870dcc0 Combine included libraries into one parameter
build_ext only grabs one '-l' parameter, not multiple, which is weird as
one time I thought it did.
2020-11-13 12:05:20 -07:00
Daniele Varrazzo
87dc783bc6
Merge pull request #1190 from martinfrancois/master
Add support for PostgreSQL 13 (final)
2020-11-13 01:00:57 +00:00
martinfrancois
8c50af551d update supported postgresql versions to include 13 2020-11-13 00:40:14 +01:00
martinfrancois
b125d9dd66 add postgresql 13 to the build matrix 2020-11-13 00:40:14 +01:00
Hugo
d04a420bce Drop support for EOL Python 3.4 2020-11-10 08:44:42 +02:00
Daniele Varrazzo
f900fa4960 Bump to new major release development line on master 2020-11-09 23:17:56 +00:00
Daniele Varrazzo
7ad357599f Merge branch 'py39-appveyor' 2020-11-04 21:22:45 +01:00
Jason Erickson
31b37685b7 Settings for Py39/VS2019 builds + OpenSSL update 2020-11-04 21:21:58 +01:00
Jason Erickson
163dadb6c6 Add Strawberry Perl to the path 2020-11-04 21:21:58 +01:00
Jason Erickson
ec39e1e406 Add VC 2019 path location 2020-11-04 21:21:58 +01:00
Daniele Varrazzo
7cd7b97d5d First batch of changes to build on appveyor with Python 3.9 2020-11-04 21:20:27 +01:00
Jannis Vamvas
616dab7064 Remove semicolon from code example 2020-10-20 18:07:51 +02:00
Daniele Varrazzo
f54cf3b87b Bump to next dev release 2020-09-06 17:24:33 +01:00
Daniele Varrazzo
dd97344149 Suggest how to auto-generate tag name in release doc 2020-09-06 17:24:04 +01:00
Daniel Fortunov
171371da5a Minor spelling and grammar corrections for 195b254 2020-09-06 17:23:37 +01:00
Daniele Varrazzo
b203be11a6 Bump version to 2.8.6 2020-09-05 23:29:47 +01:00
Daniele Varrazzo
dc007e790a Metion ARM packages in news file 2020-09-05 22:07:26 +01:00
Daniele Varrazzo
dec28a21ac 'cursor.query' reports the query of the last COPY opearation too
Close #1141.
2020-09-05 21:47:35 +01:00
Daniele Varrazzo
dd1724c447 Errors mapping updated to PostgreSQL 13 2020-09-05 20:26:19 +01:00
Daniele Varrazzo
c203d681c4 Added duplicate values to errcodes module
Close #1133
2020-09-05 20:26:19 +01:00
Daniele Varrazzo
58c6a07e43 Errors fetch scripts ported to Python 3 2020-09-05 20:26:19 +01:00
Daniele Varrazzo
195b254937 Improve wording around transactions behaviour closing connections
The transaction is not rolled back by the connection, rather discarded
by the server.

Close #1135.
2020-09-05 19:16:50 +01:00
Daniele Varrazzo
0ee9d840a1 Document context manager usage in connection and cursor docs
Close #1143
2020-09-05 18:51:33 +01:00
Daniele Varrazzo
9387bd3c09 Mention building wheels package with OpenSSL 1.1.1g in news file 2020-09-05 18:04:45 +01:00
odidev
6de8c0c6d2 Add ARM64 jobs in Travis-CI
Signed-off-by: odidev <odidev@puresoftware.com>
2020-08-25 06:37:53 +00:00
Daniele Varrazzo
f7618f8bf5
Merge pull request #1120 from bashtanov/dictcursor-docs-improvement
DictCursor docs improvement
2020-08-24 01:56:17 +01:00
Daniele Varrazzo
3aadecebaa
Merge pull request #1131 from jouve/py3.10compat
use Py_SET_TYPE for compat with python 3.10
2020-08-24 01:54:57 +01:00
Daniele Varrazzo
90e8c80ed1 Merge branch 'docs/quick-start' 2020-08-24 01:48:50 +01:00
Daniele Varrazzo
82d679cdb3 A few corrections to the install page
Spacing, lines length, a spurious link targed, reST formatting.
2020-08-24 01:48:31 +01:00
Daniele Varrazzo
b0ddf6ea90 Merge branch 'cockroachdb-tests' 2020-08-18 20:55:13 +01:00
Daniele Varrazzo
423a663306 Python 2 compatibility 2020-08-17 23:50:04 +01:00
Daniele Varrazzo
f339bb30fb Added possibility to skip a test only on certain crdb versions 2020-08-17 23:08:05 +01:00
Daniele Varrazzo
5d2e51e76e Added ticket numbers for the tests skipped on crdb 2020-08-17 22:31:48 +01:00
Daniele Varrazzo
6d8382b7ed Added missing reasons for crdb skip
Added check to make sure a reason must be passed.
2020-08-17 21:27:25 +01:00
Edan Schwartz
9c30fdbc63 minor typo in docs 2020-08-10 09:18:45 -05:00
Edan Schwartz
ed3d44562d Move pyscopg-binary install docs to "quick start" section
This is the fastest way for most folks to get up-and-running
with psycopg. We've seen a lot of noise in the GH issues with people
failng to install the non-binary version. Hopefully this will
make life easier for people new to psycopg/python.

See https://github.com/psycopg/psycopg2/issues/1085#issuecomment-659028139
2020-08-07 15:05:45 -05:00
Daniele Varrazzo
513b0019b1 TeamCity commit hook test 2020-08-04 22:29:24 +01:00
Daniele Varrazzo
6eb4fab1db Added reason for skipping on CockroachDB 2020-07-27 23:03:26 +01:00
Cyril Jouve
442f300e91
use Py_SET_TYPE for compat with python 3.10 2020-07-26 15:41:53 +02:00
Daniele Varrazzo
5e957daa82 Types tests adapted to CockroachDB 2020-07-23 01:56:58 +01:00
Daniele Varrazzo
c8697e6c67 Several other tests skipped for CockroachDB
The only remaining test modules in this branch are test_types_basic/extra.
2020-07-22 02:43:19 +01:00
Daniele Varrazzo
a9153ac373 Some extra cursors test skipped on CockroachDB
Skip named cursor tests
2020-07-22 02:14:18 +01:00
Daniele Varrazzo
701637b5fa Skip a few date tests on CockroachDB
- Infinity gets converted to large dates in the past/future out of
  Python range
- Timestamps get an UTC timezone attached
2020-07-22 02:05:05 +01:00
Daniele Varrazzo
5ccd977e2b Cursor tests adapted to CockroachDB
Named cursor tests separated to skip all in one go
2020-07-21 22:23:27 +01:00
Daniele Varrazzo
9380f2a721 Get CockroachDB version from the connection info 2020-07-21 22:22:58 +01:00
Daniele Varrazzo
7e1e801899 Skip copy tests on CockroachDB 2020-07-21 22:22:55 +01:00
Daniele Varrazzo
e154cbe5aa Skip connection tests which cannot pass on CockroachDB
Features not supported seem:

- isolation level (always serializable)
- client encodings
- notices (maybe there is a way to generate them)
- 2 phase commit
- reset (because of the lack of transaction deferrable)
- backend pid
2020-07-21 22:22:23 +01:00
Daniele Varrazzo
bca72937d8 Expose libpq PG* vars as testconfig content 2020-07-21 22:21:44 +01:00
Daniele Varrazzo
f8c1cff6a3 Skip cancel tests on CockroachDB
One test moved to the async tests module, as it really belongs there.
2020-07-21 22:21:32 +01:00
Daniele Varrazzo
ee34198bf6 All the sync tests pass on CockroachDB
Added decorator to skip tests on crdb
2020-07-21 22:21:24 +01:00
Daniele Varrazzo
659910ee81 Allow most of the async tests to pass on CockroachDB
Added function to get crdb version from a connection
2020-07-21 01:43:57 +01:00
Daniele Varrazzo
cecff195fc
Merge pull request #1127 from rafiss/iso-level-finally-block
Handle failure in setup of IsolationLevelsTestCase
2020-07-08 20:35:01 +01:00
Rafi Shamim
a61f30b2d2 Handle failure in setup of IsolationLevelsTestCase
If the CREATE TABLE statement fails, the setup would fail
without committing or rolling back the active transaction, so the
transaction would hold onto its resources indefinitely.

Normally, the transaction would be closed when the connection is closed
in the `tearDown` function. However, `tearDown` is not called if there
was an error during `setUp` ([as specified by the `unittest` docs](https://docs.python.org/3/library/unittest.html#unittest.TestCase.tearDown)), so
we need to handle this case specially.
2020-07-07 18:48:44 -04:00
Alexey Bashtanov
96f0f63de2 dictcursor-docs-improvement 2020-06-18 15:40:45 +01:00
Daniele Varrazzo
779a1370ce
Merge pull request #1105 from rafiss/with-block-connection-test
Handle failure in setup of ConnectionTwoPhaseTest
2020-05-30 04:43:26 +12:00
Daniele Varrazzo
1092d437c0
Merge pull request #1111 from cjolif/master
use new URL for psycogreen
2020-05-29 01:37:06 +12:00
Christophe Jolif
1afbaf495e use new URL for psycogreen 2020-05-28 14:11:34 +02:00
Daniele Varrazzo
a9b814cb53
Merge pull request #1110 from UpGado/patch-1
Fix ctypes doc example AttributeError
2020-05-27 22:25:15 +12:00
Dio Gado
ac488acee3 Fix ctypes example AttributeError 2020-05-27 05:39:53 -04:00
Rafi Shamim
f935476b3f Handle failure in setup of ConnectionTwoPhaseTest
Previously, this test had a bug, because if the CREATE TABLE statement
failed, the setup would fail without committing or rolling back the
active transaction.
2020-05-12 12:48:35 -04:00
Daniele Varrazzo
14355e9c69
Merge pull request #1103 from franciscouzo/patch-1
Fix typo
2020-05-07 19:39:48 +12:00
Francisco Couzo
7fdf77065d
Fix typo 2020-05-07 04:11:50 -03:00
Daniele Varrazzo
690772f093 Merge branch 'mx-search' 2020-05-06 16:02:00 +12:00
Daniele Varrazzo
a75afe4d83 Mention fixing mx search in news file
Close #996.
2020-05-06 14:46:58 +12:00
Colin 't Hart
f9442744af Fixed search of mxDateTime headers
- Find mxDateTime.h automatically on path directories.
- Prefer mxDateTime.h found in venv over one found in /usr/include.
2020-05-06 14:42:10 +12:00
Daniele Varrazzo
1ec0bb5633 Mention python3-dev as possibly required dev package name
Close #1092.
2020-05-05 00:23:57 +12:00
Daniele Varrazzo
87279d5d03 Mention CALL on stored procedures using transaction in autocommit
Close #1072 - I prefer to mention them where there is a discussion of
the feature rather than in the method or const values section.
2020-05-05 00:19:38 +12:00
Daniele Varrazzo
accd1965bb Merge remote-tracking branch 'pombredanne/patch-1' 2020-05-04 23:55:29 +12:00
Daniele Varrazzo
d0216ce68d Merge branch 'client-encoding-leak' 2020-05-04 23:53:08 +12:00
Daniele Varrazzo
a35549d0ad Mention ticket #1101 closed in news file 2020-05-04 23:52:58 +12:00
Daniele Varrazzo
6043dac0ea Bump to next dev release 2020-05-04 23:50:05 +12:00
Kevin Michel
364b0e0563 Fix memory leak in conn_set_client_encoding
If the specified encoding is the same as the current one,
the early exit did not release the clean_enc string allocated
by clear_encoding_name.
2020-05-04 09:40:36 +02:00
Philippe Ombredanne
4c3e0e5f1d
Improve doc wording
Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
2020-04-28 22:37:59 +02:00
Philippe Ombredanne
75c659a5e7
Fix typo and improve grammar in doc
Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
2020-04-28 22:27:29 +02:00
Federico Di Gregorio
8b2450287e
Removed ZPL license (closes: #1087) 2020-04-28 18:53:14 +02:00
Daniele Varrazzo
cb3353be1f Releasing psycopg 2.8.5 2020-04-06 17:00:57 +12:00
Daniele Varrazzo
f2852a520a Merge branch 'add-aix-support' 2020-04-06 16:49:42 +12:00
Daniele Varrazzo
012a20b010 Mention AIX support in NEWS file 2020-04-06 16:46:44 +12:00
Jon Dufresne
fbba461052 Fix typo: occured → occurred 2020-04-06 16:40:45 +12:00
Daniele Varrazzo
62743c3be1 Fixed copy() on DictRow
Close #1073.
2020-04-06 14:10:02 +12:00
Abdirahim Musse
6de23eb793
fixup! feat: Add AIX support 2020-03-12 13:21:02 -05:00
Daniele Varrazzo
2bee47efac Merge branch 'column-slice' 2020-03-13 00:17:57 +13:00
Daniele Varrazzo
054123254e Column objects can be sliced
Close #1034.
2020-03-11 10:50:56 +13:00
Daniele Varrazzo
5d96b0c024 Merge branch 'cffi-in-docs' 2020-03-08 11:34:20 +00:00
Daniele Varrazzo
34615b7629 Better descriptions of the non-C porting in install docs 2020-03-08 11:33:31 +00:00
Daniele Varrazzo
34c54f3fc3 Merge branch 'logging-adapter' 2020-03-08 11:23:32 +00:00
Daniele Varrazzo
497ad5c7c0 Mention LoggingAdapter in news 2020-03-08 11:22:43 +00:00
Abdirahim Musse
de58332bdd
feat: Add AIX support 2020-03-05 12:34:25 -06:00
Daniele Varrazzo
12bc9d68c4 Added funding file 2020-02-22 18:54:05 +00:00
Daniele Varrazzo
9bcca1a7b0 Dropped customized doc template
It was meant to be used only by the website, not for the doc shipped
with the package.

[skip ci]
2020-01-27 04:32:31 +00:00
Daniele Varrazzo
f2d13ec809 Upload on https now 2020-01-27 02:58:58 +00:00
Daniele Varrazzo
e14e3385b4 Merge branch 'goodbye-initd' 2020-01-25 19:54:30 +00:00
Daniele Varrazzo
1c80c9d8d5 Trigger docs rebuild on push 2020-01-25 19:51:21 +00:00
Daniele Varrazzo
e9dc1df889 Added sql module basic usage section and classes hierarchy 2020-01-20 21:00:58 +00:00
Daniele Varrazzo
dbd6577d91 Fixed dependencies in docs build
Building without having built the library failed
2020-01-19 00:43:42 +00:00
Daniele Varrazzo
94a660aa6f Use a responsive theme for docs
With a pleasant ottanio background.
2020-01-18 23:56:44 +00:00
Daniele Varrazzo
584197f57d Hide the "made with sphinx" doc footer 2020-01-18 19:37:13 +00:00
Daniele Varrazzo
5e0b02afb2 Copyright bumped to 2020 2020-01-17 21:21:11 +00:00
Bjoern Boschman
93aa469f16 #1026 added support for logging.LoggerAdapter 2020-01-07 13:46:21 +00:00
Daniele Varrazzo
8a6b280d86 Use an ssh config file to configure package uploading
[skip ci]
2020-01-04 16:59:52 +01:00
Daniele Varrazzo
9bfde497e5 Copyright 2020 in the docs 2020-01-04 01:39:29 +01:00
Daniele Varrazzo
c3c24cd67b Website on https 2019-12-31 13:09:13 +01:00
Daniele Varrazzo
501b0412f6 CI resources moved to upload.psycopg.org 2019-12-31 09:59:32 +01:00
Daniele Varrazzo
9154d0920c Changed docs to point to psycopg.org 2019-12-30 18:12:46 +01:00
Daniele Varrazzo
3d29ace058 Document a release procedure not using initd server 2019-12-30 17:13:37 +01:00
Daniele Varrazzo
46022cb162 Merge branch 'py38-win' 2019-12-30 17:11:21 +01:00
Daniele Varrazzo
f4144615f7 Blacklist docutils 0.15 to build docs
It crashes because of https://sourceforge.net/p/docutils/bugs/353/
2019-12-29 23:54:18 +01:00
Daniele Varrazzo
c3b35ba510 Merge branch 'fix-1019' 2019-12-10 11:09:27 +00:00
Daniele Varrazzo
c20c13c493 Fixed use of cursor_factory attribute in connecion subclasses
Close #1019
2019-12-09 11:11:39 +00:00
Daniele Varrazzo
5c02fdaa0d Bump to next dev version 2019-12-09 11:10:58 +00:00
Daniele Varrazzo
9c32457c28 Added Python 3.8 build on Appveyor 2019-11-10 20:58:44 +00:00
Omer Katz
a1fd2da1dc
Mention the CFFI port to Psycopg2 in documentation.
The CFFI port works much better on PyPy and has been used in production before.
The documentation mentioned the Ctypes port but not the CFFI port.
I added it to the documentation.
2019-10-23 12:05:33 +03:00
Daniele Varrazzo
d70d3ee482 Bump to version 2.8.4 2019-10-20 01:25:21 +01:00
Daniele Varrazzo
16c07ba9c4 Mention the library versions packaged in the 2.8.4 wheel in the NEWS file 2019-10-20 01:19:47 +01:00
Daniele Varrazzo
cb7109dfa9 Merge branch 'fix-951' 2019-10-19 18:38:56 +01:00
Daniele Varrazzo
eb893e65f0 Mention fixing time.h include in NEWS
Mostly to remember why we did it.
2019-10-19 18:11:10 +01:00
Daniele Varrazzo
b0b09cbb24 Merge branch 'bugfix/940' 2019-10-19 18:04:02 +01:00
Daniele Varrazzo
63352d7da0 Mention bug 940 fixed in NEWS file 2019-10-19 18:02:32 +01:00
Jann Kleen
4097b4f2a0 Fix typo 'againts' 2019-10-19 17:58:37 +01:00
Daniele Varrazzo
8a18ff7699 Mention that with PgBouncer get_backend_pid() is not updated
Close #956
2019-10-19 17:57:31 +01:00
Daniele Varrazzo
850c585501 Added UltraJSON example
Close #972
2019-10-19 17:47:01 +01:00
Daniele Varrazzo
2f094841b2 Slow test is slow 2019-10-19 16:29:16 +01:00
Daniele Varrazzo
96156727c0 Allow parsing boolean both upper and lowercase
Reportedly useful on H2 databases.

Close #965
2019-10-19 16:28:10 +01:00
Daniele Varrazzo
5e9572aff8 Revert testing on Windows to libpq 11.4
Build broken by:

    d993e0fb82

Error at:

    https://ci.appveyor.com/project/psycopg/psycopg2/builds/28228647/job/490uo4qko6cguldl
2019-10-19 16:17:01 +01:00
Daniele Varrazzo
24a8d600bf Test on appveyior with libpq 11.5 and openssl 1.1.1d
Will mention the new libraries' support after testing with wheels
2019-10-19 16:10:15 +02:00
Daniele Varrazzo
b2a09fb404 Merge branch 'pg12' 2019-10-19 16:09:41 +02:00
Daniele Varrazzo
b029bd80d4 Merge branch 'py38' 2019-10-19 16:08:06 +02:00
Daniele Varrazzo
500f438033 Support for Python 3.8 mentioned in news file 2019-10-19 16:07:35 +02:00
Daniele Varrazzo
ade98c1359 Added Py 3.8 support to appveyor build
VS 14 is the one to use: https://wiki.python.org/moin/WindowsCompilers

Note that appveyor doesn't have Py 3.8 yet though.
2019-10-19 16:01:13 +02:00
Daniele Varrazzo
38a411dc07 Test Python 3.4 on xenial
Trusty is no more required, and PG 12 is not available there.
2019-10-19 15:50:57 +02:00
Daniele Varrazzo
214a8efe64 Test PG 11 and 12 on travis 2019-10-19 15:26:20 +02:00
Daniele Varrazzo
d5c7ec7ae8 Added Postgres 12 errors 2019-10-19 15:22:48 +02:00
Daniele Varrazzo
8f11821c17 Use travis test config variable 0/1 instead of blank strings
Travis web interface doesn't allow anymore to set an empty string as
variable value.
2019-10-19 15:18:38 +02:00
Daniele Varrazzo
58654990d6 Install postgres from pgdg on travis if available there 2019-10-19 14:38:49 +02:00
Daniele Varrazzo
0dec435856 Dropped download url from package metadata
Not really useful anymore as PyPI is the official download place.
2019-10-19 14:09:44 +02:00
Jon Dufresne
4e13acdc88 Add Python 3.8 to the test matrix
Python 3.8 was released on October 14th, 2019.

- Added 'Programming Language :: Python :: 3.8' trove classifier.
- Added 'py38' to the tox test matrix.
- Added 'python: 3.8' to the Travis test matrix.
- Removed 'dist: xenial' from Travis configuration; it is now the
  default.
- Removed 'dist: trusty' from Travis configuration; it is not longer
  necessary.
- Removed 'sudo' from Travis configuration; it is deprecated.

https://docs.python.org/3.8/whatsnew/3.8.html
2019-10-18 18:29:59 -07:00
Daniele Varrazzo
f08019e356 Added decorator to clean up the adaptation mappings after tests
Many tests were doing it manually, some weren't doing it and resulted in
failure if run in different order.

Close #948
2019-09-04 18:17:51 +01:00
Daniele Varrazzo
33d3c074fa Merge branch 'fix-961' 2019-09-04 13:22:16 +01:00
Daniele Varrazzo
80df0553a6 Fixed handling large Oid values
Oid is defined as unsigned 32. On some Python implementations (probably
the ones where maxint = 2 ** 31) this can cause int overflow for large
values (see #961). On my 64 box it doesn't seem the case.

Oid handling was sloppy here and there (messages, casts...): trying to
use uint everywhere, and added a couple of helper macros to treat Oid
consistently.

Close #961.
2019-09-04 12:30:18 +01:00
Samuel Marks
a47fcdd508
[psycopg/pqpath.c] sys/time.h include for non mac & Windows
Signed-off-by: Samuel Marks <807580+SamuelMarks@users.noreply.github.com>
2019-08-05 15:07:43 +10:00
Alexander Kukushkin
9097a5b989 Don't advance replication cursor when the message wasn't confirmed
Fixes https://github.com/psycopg/psycopg2/issues/940
2019-07-05 08:37:24 +02:00
Daniele Varrazzo
4d10f1235f Merge branch 'obscure-password-before-connect' 2019-06-24 12:14:29 +01:00
Daniele Varrazzo
6e972200a3 Mention ctrl-c swallowing fixed in news file 2019-06-24 12:13:47 +01:00
Daniele Varrazzo
3465ce282e Function to obscure password moved to connection_int 2019-06-24 12:11:12 +01:00
Daniele Varrazzo
f40ad0f3ae Obscure the dsn password before storing it into the connection
This avoids the need to juggle with exceptions in order to scrub the
password after a connection error, which may also swallow signals
(see #898).
2019-06-22 19:22:27 +01:00
Jon Dufresne
491296e0f5 Fix typo: "the the" 2019-06-21 11:26:47 +01:00
Daniele Varrazzo
ee056bc6e8 Bump to next dev version number 2019-06-21 11:26:29 +01:00
Kunal Marwaha
c32dbf357c typo: remove 'a' 2019-06-19 00:32:54 +01:00
Daniele Varrazzo
bc65c636ae Bump to version 2.8.3 2019-06-10 23:21:50 +01:00
Daniele Varrazzo
91a8962770 Added entry about how to ask questions
Also fixed mailing list link (although it doesn't seem there's a link to
a subscription page anymore, you have to go through the community
portal).

Close #930.
2019-06-10 23:18:11 +01:00
Daniele Varrazzo
be8e1a2632 Making my linter happy 2019-06-07 18:20:36 +01:00
Daniele Varrazzo
2635f43788 Merge branch 'fix-namedtuple-cache' 2019-06-07 18:19:47 +01:00
Daniele Varrazzo
0578c1ab92 Mention #928 fixed 2019-06-07 18:18:48 +01:00
Changaco
842e383c0c fix NamedTupleCursor._cached_make_nt 2019-06-04 14:30:30 +02:00
Changaco
527592a0a5 improve the NamedTupleCursor cache test 2019-06-04 13:45:37 +02:00
Daniele Varrazzo
668d507c34 Merge branch 'feature/smart-feedback' 2019-05-12 23:55:11 +09:00
Daniele Varrazzo
b79895186c Added news entry about smart replication feedback 2019-05-12 23:48:51 +09:00
Alexander Kukushkin
90755e6f13 Address code-review 2019-05-07 14:18:09 +02:00
Alexander Kukushkin
5eec11f232 Improve docs 2019-05-06 15:42:37 +02:00
Alexander Kukushkin
f827e49f55 Change the default value of keepalive_interval parameter to None
The previous default value was 10 seconds, what might cause silent
overwrite of the *status_interval* specified in the `start_replication()`
2019-05-06 15:26:21 +02:00
Alexander Kukushkin
6cff5a3e08 Smart replication feedback
This commit makes psycopg2 responsible for sending the status update
(feedback) messages to the server regardless of whether a synchronous or
asynchronous connection is used.

Feedback is sent every *status_update* (default value is 10) seconds,
which could be configured by passing a corresponding parameter to the
`start_replication()` or `start_replication_expert()` methods.
The actual feedback message is sent by the
`pq_read_replication_message()` when the *status_update* timeout is
reached.

The default behavior of the `send_feedback()` method is changed.
It doesn't send a feedback message on every call anymore but just
updates internal structures. There is still a way to *force* sending
a message if *force* or *reply* parameters are set.

The new approach has certain advantages:
1. The client can simply call the `send_feedback()` for every
   processed message and the library will take care of not overwhelming
   the server. Actually, in the synchronous mode it is even mandatory
   to confirm every processed message.
2. The library tracks internally the pointer of the last received
   message which is not keepalive. If the client confirmed the last
   message and after that server sends only keepalives with increasing
   *wal_end*, the library can safely move forward *flush* position to
   the *wal_end* and later automatically report it to the server.

Reporting of the *wal_end* received from keepalive messages is very
important. Not doing so casing:
1. Excessive disk usage, because the replication slot prevents from
   WAL being cleaned up.
2. The smart and fast shutdown of the server could last indefinitely
   because walsender waits until the client report *flush* position
   equal to the *wal_end*.

This implementation is only extending the existing API and therefore
should not break any of the existing code.
2019-05-06 10:27:44 +02:00
Daniele Varrazzo
f96982bdfd Merge remote-tracking branch 'origin/appveyor-py' 2019-05-01 16:30:09 +01:00
Daniele Varrazzo
ed7d8ea28c Appveyor: added package_name to options 2019-04-22 22:39:59 +01:00
Daniele Varrazzo
014097c1af Dropped command line config from appveyor scrips
Only use env vars, they were unused.

Use consistently a config object with properties instead of functions
(the one returning a binary are especially dangerous if parens are
forgotten).

Also add helpers to call the target python more succinctly.
2019-04-22 12:41:44 +01:00
Daniele Varrazzo
1b2c1d620f Run tests more quiet/faster building wheels
We are mostly interested it installed alright.
2019-04-22 11:24:29 +01:00
Daniele Varrazzo
285c64d101 Better dir names in appveyor build 2019-04-22 11:24:29 +01:00
Daniele Varrazzo
637a990e09 Added support for wheel building and uploading
To be used by the psycopg/psycopg2-wheels project.
2019-04-22 11:24:29 +01:00
Daniele Varrazzo
9eec303cf7 Configure postgres to run appveyor tests on ssl 2019-04-22 11:24:29 +01:00
Daniele Varrazzo
b1078b1b92 Setup build environment only before building 2019-04-22 11:24:29 +01:00
Daniele Varrazzo
1178501aaf appveyor: added logging level configuration 2019-04-22 11:24:29 +01:00
Daniele Varrazzo
5c72203180 Using pathlib to manipulate paths 2019-04-22 11:24:29 +01:00
Daniele Varrazzo
591476621c Dropped problematic init step
It was performed before repos cloned so no resource available (including
the script!)
2019-04-22 11:24:29 +01:00
Daniele Varrazzo
fda738c90d All together now, let's make this real 2019-04-22 02:54:56 +01:00
Daniele Varrazzo
5858b0b9b4 Test packages from Python 2019-04-22 02:54:56 +01:00
Daniele Varrazzo
169ce22228 Build psycopg from Python 2019-04-22 02:54:56 +01:00
Daniele Varrazzo
c875197432 Build libpq from Python 2019-04-22 02:54:56 +01:00
Daniele Varrazzo
73f6a0cd95 Build openssl from Python 2019-04-22 02:54:56 +01:00
Daniele Varrazzo
37ce131d2c Added setenv to log env vars changes 2019-04-22 02:54:56 +01:00
Daniele Varrazzo
00fc2820a0 Added script to implement appveyor functionality in Python
Only the init step for the moment.
2019-04-22 02:54:56 +01:00
Daniele Varrazzo
325aadbf2c Check return code of pthread_mutex_init
Close #901
2019-04-21 11:53:34 +01:00
Daniele Varrazzo
39b1994c26 Bump to next dev version number 2019-04-21 11:53:13 +01:00
Daniele Varrazzo
324cded166 Bumping to version 2.8.2 2019-04-14 15:11:31 +01:00
Daniele Varrazzo
6b740df704 Added FAQ entry about the change in binary packages in 2.8 2019-04-14 15:08:07 +01:00
Daniele Varrazzo
4821a6294e Merge branch 'openssl-1.1-windows' 2019-04-14 14:49:41 +01:00
Daniele Varrazzo
26b61e809f Mention building openssl 1.1 on windows in news file
Close #836.
2019-04-11 01:42:54 +01:00
Daniele Varrazzo
14bfc54344 Mention fix to repeated fields in RealDictCursor in news file 2019-04-11 00:54:55 +01:00
Daniele Varrazzo
72fe91c02e Build and test with openssl 1.1 on windows
Porting to openssl 1.1 by Matthew Brett, from the psycopg2-wheel repos.
2019-04-11 00:27:49 +01:00
Daniele Varrazzo
5e01c47818 Highlight in docs that the context manager doesn't close the connection
Code as in #889 is not robust, but the behaviour is actually
counter-intuitive.
2019-04-07 11:19:56 +01:00
Daniele Varrazzo
4058f363d6 More robust RealDictRow population
In the presence of repeated columns the mapping would have remained into
into the dictionary. Now it is removed.

Fix #884
2019-04-06 21:17:28 +01:00
Daniele Varrazzo
63e4bc961e Version bumped to next dev release 2019-04-06 21:16:42 +01:00
Daniele Varrazzo
3357477fde Fixed debug title level in news 2019-04-06 20:49:00 +01:00
Daniele Varrazzo
d2dce4dd17 Fixed link to RealDictRow from last news 2019-04-06 20:22:03 +01:00
Daniele Varrazzo
15d684134f Bumping to version 2.8.1 2019-04-06 20:12:10 +01:00
Daniele Varrazzo
5c4b8a3d1f Merge branch 'fix-886' 2019-04-06 20:09:47 +01:00
Daniele Varrazzo
cc815e8e8d RealDictRow inherits from OrderedDict
Now its state is unmodified, so apart from special-casing creation
and initial population can work unmodified, and all the desired
properties just work (modifiability, picklability...)

Close #886.
2019-04-06 19:43:31 +01:00
Daniele Varrazzo
21d16b6f67 Fixed RealDictCursor.pop()
Addresses #886, but there might be something else broken there.
2019-04-06 19:43:09 +01:00
Daniele Varrazzo
7b31b39fed Merge branch 'fix-887' 2019-04-06 10:51:03 +01:00
Daniele Varrazzo
46106e1b78 Test notifies are received ok polling an async cur 2019-04-05 19:04:48 +01:00
Daniele Varrazzo
755a128ffb Handle ok poll() without a cursor having executed queries
Close #887
2019-04-05 18:04:55 +01:00
Daniele Varrazzo
34d45aea87 Bump to next dev release 2019-04-05 18:02:30 +01:00
Daniele Varrazzo
c64d2448e8 Bumping to 2.8 for release 2019-04-03 10:44:07 +01:00
Daniele Varrazzo
544e157649 Fixed replication cursor docs warning indentation level 2019-04-01 10:54:01 +01:00
Daniele Varrazzo
ed74189acd Replication objects docs header level bumped up
Now it appears in the ToCs.
2019-04-01 10:40:44 +01:00
Daniele Varrazzo
813ca30953 Fixed notice about new wal_end attribute being on the cursor 2019-04-01 10:40:06 +01:00
Daniele Varrazzo
b76ff2fc33 Merge branch 'keepalive-save-wal-end'
Close #800
2019-03-30 21:29:39 +00:00
Daniele Varrazzo
b8bf6d9917 Added news entry about ReplicationMessage.wal_end 2019-03-30 21:23:20 +00:00
grunskis-bonial
ff91ad5186 Address code review feedback 2019-03-30 21:23:13 +00:00
Martins Grunskis
f946042a79 Store WAL end pointer in the replication cursor 2019-03-30 21:23:11 +00:00
Andrew Rabert
3eecf34bea Add time type conversion info to docs 2019-03-24 23:09:36 +00:00
Daniele Varrazzo
953bc66ca6 Allow tests to be ignored if dynamic binding failed 2019-03-18 19:49:16 +00:00
Daniele Varrazzo
5b4caadd23 Version number changed to release version 2.8 beta 2 packages 2019-03-18 14:59:04 +00:00
Daniele Varrazzo
8b7506f80d Merge branch 'naming' 2019-03-18 01:54:44 +00:00
Daniele Varrazzo
e569e49b8b Merge branch 'fix-829' 2019-03-18 01:53:59 +00:00
Daniele Varrazzo
f8f5a77838 Mention closed #829 in NEWS file 2019-03-18 01:51:29 +00:00
Daniele Varrazzo
0c581380c7 Allow incorrect result for pgconn_ptr test on OSX
I don't know why it returns 0 instead of the right value. At least it
doesn't segfault, so don't skip the test altogether.

The test is unrelated to this branch: will cherry-pick elsewhere (if I
remember it...)
2019-03-18 01:41:56 +00:00
Daniele Varrazzo
7571ec9368 Run tests on windows using the same library versions of the packages 2019-03-18 01:41:56 +00:00
Daniele Varrazzo
eedbb33226 Appveyor tests in order of sort what I care 2019-03-18 00:33:31 +00:00
Daniele Varrazzo
17b0c61338 Don't close connections from forked processes
On Py3 subprocessing will actually GC the objects and the FD is open,
resulting in connections closed in different processes.

The behaviour is verified in py 3.4 to 3.7 at least,
2019-03-18 00:32:40 +00:00
Daniele Varrazzo
62a078fe0c subprocess test function moved into a module
It won't work on windows if it's in the script: failing with errors
such as:

    AttributeError: 'module' object has no attribute 'process'

or:

    Can't get attribute 'process' on <module '__main__' (built-in)>
2019-03-17 23:55:04 +00:00
Daniele Varrazzo
7c5afd6977 Added test to reproduce ticket #829
Unrelated processes close the FD of the connection. This happens in
Python 3.6 but not 2.7. Let's see if travis shows where else it fails...
2019-03-17 23:06:55 +00:00
Daniele Varrazzo
458254c49e Windows doesn't like the name "connect" for a function 2019-03-17 22:26:02 +00:00
Daniele Varrazzo
dc5dd30526 Prefix 'psycopg_' changed to 'psyco_' 2019-03-17 18:45:25 +00:00
Daniele Varrazzo
e4d365705a Several function names shortened
There's not so much need for a strict convention for static functions.
Leaving some 'psyco_' prefix when the internal function and the
python-exposed function clashed.
2019-03-17 18:33:15 +00:00
Daniele Varrazzo
b4b470c29a Allow 0 as key in the pool
Close #848
2019-03-17 18:24:50 +00:00
Daniele Varrazzo
155c739863 Merge branch 'use-conn-pgres' 2019-03-17 04:43:58 +00:00
Daniele Varrazzo
a5c0a2215e Dropped whole "critical" story
It doesn't seem "critical" errors are used anymore. pq_set_critical()
wasn't called anywhere.
2019-03-17 03:49:34 +00:00
Daniele Varrazzo
17a074b30a Use the error on the connection instead of passing it explicitly around 2019-03-17 03:49:34 +00:00
Daniele Varrazzo
97220eadc6 Added helper methods to set a result into a connection/cursor 2019-03-17 03:49:34 +00:00
Daniele Varrazzo
e740c21ee6 Dropped pgconn argument from conn_setup() 2019-03-17 03:49:34 +00:00
Daniele Varrazzo
c15e4c1a85 Use the connection's PGresult to pass results through calls 2019-03-17 03:49:34 +00:00
Daniele Varrazzo
5957a7ee45 Fixed handling of internal query too large 2019-03-17 03:49:34 +00:00
Daniele Varrazzo
917335eacb Merge branch 'fix-856' 2019-03-17 03:48:40 +00:00
Daniele Varrazzo
963123812d Make sure to free the connection's pgres on delete 2019-03-17 02:25:45 +00:00
Daniele Varrazzo
734845b79a Added pq_get_result_async() replaced pg_get_last_result()
The new function keeps together PQconsumeInput() with PQisBusy(), in
order to handle the condition in which not all the results of a sequence
of statements arrive in the same roundtrip.

Added pointer to a PGresult to the connection to keep the state across
async communication: it can probably be used to simplify other code
paths where a result is brought forward manually.

Close #802
Close #855
Close #856
2019-03-17 01:20:06 +00:00
Daniele Varrazzo
761c3784c4 Retrieving the async cursor moved out of conn_poll() body 2019-03-16 20:05:40 +00:00
Daniele Varrazzo
e864050d07 Simplified interactions between asyc functions
Have advance_write calling flush itself, advance_read calling is_busy
itself, rather than calling them in the caller and passing the result.

Why we were doing the former on write I don't know. On read the paths
between async and green function was different but they got unified in
the previous commit.
2019-03-16 20:05:40 +00:00
Daniele Varrazzo
2a8fa4bef7 Dropped locking version of pq_is_busy()
The locking version was used for sync connections, the non-locking one
for green ones. However it only calls non-blocking functions, so it
doesn't really matter releasing the gil. So have only the non-locking
one.

Note that the name are sort of swapped: pq_is_busy() does now what
pq_is_busy_locked() used to do.
2019-03-16 20:05:40 +00:00
Daniele Varrazzo
5467f65122 Dropped no_begin handling in async execute
no_begin is only used with withhold named cursors, and it's not possible
to create named cursors on async connections.
2019-03-16 20:05:40 +00:00
Daniele Varrazzo
0935c9d8ca Dropped debug info for microprotocols/adapters initialization
Not useful anymore (guess they were when those layers were created).
Much shorter stream of messages on module init now.
2019-03-16 20:05:40 +00:00
Daniele Varrazzo
d61c902230 Shorter timeout in the async tests select 2019-03-16 20:05:40 +00:00
Daniele Varrazzo
b5c7c93092 Merge branch 'version-check-cleanup' 2019-03-16 19:55:17 +00:00
Daniele Varrazzo
e922e2a96e Py2/3 compatibility macro definitions rationalized 2019-03-16 19:54:40 +00:00
Daniele Varrazzo
fec0a5587d Fixed check for type == int on Py2 2019-03-16 19:54:40 +00:00
Daniele Varrazzo
b9d0808f95 Added PY_2, PY_3 macros and used uniformly 2019-03-16 19:54:40 +00:00
Daniele Varrazzo
8448b3b840 Dropped conditional compiling dealing with unsupported versions
Also dropped shameful use of PY_MINOR_VERSION.
2019-03-16 19:54:40 +00:00
Daniele Varrazzo
dfb301b42b Use PY2, PY3 for conditional code instead of sys.version_info 2019-03-16 19:54:40 +00:00
Daniele Varrazzo
f4a2630f1a Added PY2, PY3 to compat module 2019-03-16 19:54:40 +00:00
Daniele Varrazzo
4ace9544ff Merge branch 'fix-imports' 2019-03-16 19:53:45 +00:00
Daniele Varrazzo
e8135ee2cf Use errors module to catch a specific postgres error 2019-03-16 19:13:58 +00:00
Daniele Varrazzo
b0119fef81 Other import moved to top level in tests 2019-03-16 19:13:58 +00:00
Daniele Varrazzo
8cfe176a85 Dropped repeated conditional import of reload in test 2019-03-16 19:04:40 +00:00
Daniele Varrazzo
aaba4dcf87 TextIOBase moved to tests compat imports 2019-03-16 18:41:59 +00:00
Jon Dufresne
d90ad8627d Move imports to the top of the module across tests
Allows removing many duplicate imports and better follows PEP8
guidelines:

https://www.python.org/dev/peps/pep-0008/#imports

> Imports are always put at the top of the file, just after any module
> comments and docstrings, and before module globals and constants.
2019-03-16 18:03:41 +00:00
Jon Dufresne
194efc4375 Fix invalid exception handler: except e:
Fixes flake8 warning:

    ./tests/test_connection.py:390:16: F821 undefined name 'e'
    ./tests/test_connection.py:391:61: F821 undefined name 'e'
    ./tests/test_connection.py:408:16: F821 undefined name 'e'
    ./tests/test_connection.py:409:61: F821 undefined name 'e'

In the event of an unexpected error, let the exception bubble up the
stack for a more informative test failure message.
2019-03-16 17:59:18 +00:00
Jon Dufresne
432fdd7d32 Removed support for mxDateTime as the default date and time adapter
The use_pydatetime configuration option has been removed. Now, always
default to Python's builtin datetime. mxDatetime support continues to be
available as an alternative to Python's builtin datetime.
2019-03-16 16:36:49 +00:00
Jon Dufresne
8685120485 Remove unnecessary except ImportError for Python datetime types
The Python datetime module is available on all supported platforms. The
types are always available and never raise an ImportError.
2019-03-16 16:35:51 +00:00
Jon Dufresne
ad4c6a4673 Use unittest 'skip' feature to skip mxDateTimeTests
Rather than deleting, the class, use the skip feature. Provides a more
informative message during test output.

Never skip DatetimeTests as all supported Python environments have the
datetime module builtin.
2019-03-13 15:01:34 +00:00
Jon Dufresne
d411dc3a73 Remove unused use_pydatetime from setup.py
Looks to have been mistakenly reintroduced in
b537404487.
2019-03-13 15:00:25 +00:00
Jon Dufresne
6db347b5d7 Remove unused use_pg_dll from setup.py
Unused since 3076046b3f.
2019-03-13 11:20:27 +00:00
Jon Dufresne
3f890f8bbe Use True/False instead of 1/0 to represent bool values
Slightly more modern, readable, and Pythonic.
2019-03-13 11:13:36 +00:00
Jon Dufresne
afbbdd18b6 Remove unused variable
The variable i is immediately overwritten by the next line.
2019-03-13 11:13:24 +00:00
Jon Dufresne
03bb44dd2c Convert while 1: statements to while True:
A slightly more readable and modern syntax.
2019-03-13 11:13:05 +00:00
Jon Dufresne
18f5d5ad05 Remove unused imports from tests/test_ipaddress.py 2019-03-13 11:12:48 +00:00
Daniele Varrazzo
f2654d3573 Advertise openssl 1.0.2r and libpq 11.2 in wheels 2019-03-13 11:12:17 +00:00
Daniele Varrazzo
92ac3ba4fc Bumped to version 2.8 2019-03-05 17:33:16 +00:00
Daniele Varrazzo
3ae9dfd545 Better link from docs to "json and jsonb" data types 2019-03-05 17:31:45 +00:00
Daniele Varrazzo
c929f20048 Fixed building with Python 3.8
Not released yet, and using an internal API, so for the moment better
not declare it supported.

Close #854
2019-03-05 17:30:52 +00:00
Daniele Varrazzo
be7e1916d7 Dropped outdated setup.py comment 2019-02-26 23:48:20 +00:00
Grey Baker
7fadb75097 Add project_urls to setup.py, with links to source and documentation 2019-02-26 23:44:32 +00:00
David Fischer
147ff65e4a Fix typo 2019-02-26 11:33:48 +01:00
Daniele Varrazzo
b17670a27e Merge branch 'info-dsn-params' 2019-02-17 10:55:12 +00:00
Daniele Varrazzo
a68df50c7b Added ConnectionInfo.dsn_parameters attribute 2019-02-17 02:37:09 +00:00
Daniele Varrazzo
0eb4560771 Don't use versions such as 2.8.0 in docs
Use 2.8.
2019-02-17 01:51:06 +00:00
Daniele Varrazzo
599432552a Copyright year updated
ag -l Copyright | xargs sed -i \
        "s/\(.*copyright (C) [0-9]\+\)\(-[0-9]\+\)\?\(.*\)/\1-$(date +%Y)\3/I"
2019-02-17 01:36:36 +00:00
Daniele Varrazzo
d177fa9bd0 Allow building docs with Python 3
Use a .pth file to simplify finding the just-built psycopg package into the
docs building env.
2019-02-17 01:36:36 +00:00
Daniele Varrazzo
63ce5ca94f Fixed title level of sqlsate errors table in docs 2019-02-17 01:07:47 +00:00
Daniele Varrazzo
f70d6fd0ed Dropped text docs generation 2019-02-17 00:58:27 +00:00
Daniele Varrazzo
e5e8cec350 Added table of sqlstate exceptions in the docs
Note that the column-spanning cells break text docs. I don't think
anybody cares about them, so going to drop them.
2019-02-17 01:55:14 +01:00
Daniele Varrazzo
d08be18671 Merge branch 'libpq-ptrs' 2019-02-17 00:17:43 +01:00
Daniele Varrazzo
6bbfce7b89 Skip password encryption test if libpq < 10 2019-02-16 22:57:16 +01:00
Daniele Varrazzo
80b7b845d2 Added docs about pgconn_ptr, pgresult_ptr 2019-02-16 18:12:52 +01:00
Daniele Varrazzo
3b7c083c3d Skip tests involving ctypes on Windows
No idea about how to import libpq.
2019-02-16 18:12:52 +01:00
Daniele Varrazzo
7c7bbb9742 Added connection.pgconn_ptr and cursor.pgresult_ptr
Allow interacting with libpq in Python via ctypes.

See #782.
2019-02-16 18:12:52 +01:00
Daniele Varrazzo
1dd8c7435f Mention binary packages no longer installed by default in NEWS
Also fixed an unrelated typo.

[skip ci]
2019-02-16 16:10:03 +01:00
Daniele Varrazzo
495ff79f23 Preparing 2.8 beta release 2019-02-16 14:06:18 +01:00
Daniele Varrazzo
16b35ac77b Merge remote-tracking branch 'origin/errors-module-c' 2019-02-16 13:05:20 +01:00
Daniele Varrazzo
7c148ecee4 Improvements to errors module docs 2019-02-11 01:20:21 +00:00
Daniele Varrazzo
3de4d17519 Fixed use of StandardError in test
In Py3 it's gone.
2019-02-11 00:26:01 +00:00
Daniele Varrazzo
99f680b6fe Allow importing _psycopg even if the 'errors' module is not available 2019-02-10 04:25:06 +00:00
Daniele Varrazzo
30c1befa64 SQLSTATE error classes implemented in C
The module is only used to export them to Python.
2019-02-10 03:45:14 +00:00
Daniele Varrazzo
f1e73507d0 Merge remote-tracking branch 'origin/fast-namedtuple'
Close #838
2019-02-06 02:42:10 +00:00
Daniele Varrazzo
35ec7ad9c1 Use a proper LRU cache for namedtuples
Previous one didn't refresh by last use. Use the stdlib version for py3
and one of our own for py2.

Max size set to 512, which should be fine for everyone (tweaking is
still possible by monkeypatching, as the tests do, but I don't want to
make an interface of it).
2019-02-02 19:29:20 +00:00
Daniele Varrazzo
805527fcd6 Added caching of types generated by NamedTupleCursor
see #838
2019-02-02 14:22:25 +00:00
Daniele Varrazzo
3f20f7934a Merge branch 'drop-display-size' 2019-01-25 17:31:55 +00:00
Daniele Varrazzo
4298718978 Dropped PSYCOPG_DISPLAY_SIZE build parameter
Big and complex _pq_fetch_tuples simplified by moving per-column
calculation to a separate function.
2019-01-25 17:31:39 +00:00
Daniele Varrazzo
00cb2636f5 Merge branch 'module-init-cleanup' 2019-01-23 14:17:07 +00:00
Daniele Varrazzo
65a2a18a1b General cleanup of module init shenanigans
Pass around the module instead of its dict (getting the latter is fast
if needed), mark function raising with negative results, check all errors,
consistent names...
2019-01-23 09:46:18 +00:00
Daniele Varrazzo
66d5c6da07 Incref an object which will be held forever in a static var 2019-01-23 09:46:18 +00:00
Daniele Varrazzo
e9c476266c Decrement the refcount of temporary objects in module init failed
We are going to die anyway, but let's do it in style.
2019-01-22 19:40:42 +00:00
Daniele Varrazzo
63040e5134 Mention new OpenSSL version in wheel package 2019-01-22 12:25:03 +00:00
Daniele Varrazzo
1e6d5fb32d Merge branch 'execute-locks' 2019-01-22 12:24:41 +00:00
Daniele Varrazzo
c34c99aa7f Mention cursor locks cleanup in news file 2019-01-22 11:20:36 +00:00
Daniele Varrazzo
92e615a1a4 Assign the PGresult to the cursor in the execute critical section
Possible cause of the issue reported in #346 (in concurrent
environments).
2019-01-22 11:02:09 +00:00
Daniele Varrazzo
37891500d9 Split pq_execute into sync/async parts 2019-01-22 10:51:27 +00:00
Daniele Varrazzo
eab5d5d93f Date/time modules initialized in separate functions 2019-01-22 09:09:07 +00:00
Daniele Varrazzo
111a71ccee Dropped psyco_errors_fill()
Just use psyco_errors_init() for complete errors initialization
2019-01-21 20:18:53 +00:00
Daniele Varrazzo
1839806c3c Dropped project wide type to define encodings table 2019-01-21 20:18:53 +00:00
Daniele Varrazzo
8f17ccf784 Dropped C API interface
I guess it was unused as it only contained two init functions. The
Capsule should do things better now I guess.
2019-01-21 20:18:53 +00:00
Daniele Varrazzo
7b2e8f0aa4 Respect refcount with PyModule_AddObject()
The function steals a ref. The module is never destroyed so things work
fine but the refcount is wrong.
2019-01-21 20:18:53 +00:00
Daniele Varrazzo
549beeea84 Module constants definition moved in a separate function for clarity 2019-01-21 20:18:53 +00:00
Daniele Varrazzo
4246fdf809 Merge remote-tracking branch 'origin/code-cleanup' 2019-01-21 12:49:05 +00:00
Daniele Varrazzo
e67028f4bc Handle failed allocation in list adaptation 2019-01-21 02:49:38 +00:00
Daniele Varrazzo
7a3bce8fc3 Dropped funny handling of REPLICATION_* constants 2019-01-21 02:49:38 +00:00
Daniele Varrazzo
c77615adc9 _psyco_curs_execute() simplified
Dropped code duplications, more regular increc/decref pattern.

Check the return value of formatting named cursor: would have segfaulted
in case of error.
2019-01-21 02:49:38 +00:00
Daniele Varrazzo
594df09a63 More straightforward semantics for psyco_GetDecimalType
Raise an exception when returning NULL, leave the caller cleaning it.
2019-01-21 02:41:58 +00:00
Daniele Varrazzo
2ad2b27065 Dropped use of converter function to verify copy argument
They weren't really converters, and they confused the static checker
2019-01-21 02:41:58 +00:00
Daniele Varrazzo
3768d9047d Mark psyco_set_error as returning a borrowed object 2019-01-21 02:41:58 +00:00
Daniele Varrazzo
7a1fb9a2e4 Added utils.h file
utils.c functions definition moved out of psycopg.h

Some utility functions defined into psycopgmodule.c moved into utils.c.
2019-01-21 02:41:58 +00:00
Daniele Varrazzo
daff2ea1be Mark setter as raising on negative results
Fixed static check of psyco_conn_cursor().
2019-01-21 02:41:58 +00:00
Daniele Varrazzo
4644715164 Consider the case dereferencing weakref in conn_poll returns NULL
It shouldn't but handle the case to avoid a possible null pointer
dereferencing.
2019-01-21 02:41:58 +00:00
Daniele Varrazzo
5b28d7b9c9 Dropped possible wrong code path in conn_decode
It shouldn't happen for both cdecoder and pydecoder to be null,
but just in case...
2019-01-21 02:41:58 +00:00
Daniele Varrazzo
117f7d33f8 Wrap _Bytes_Resize into a function with clearer semantic
Limit the static checker hacking to a simpler function.
2019-01-21 02:00:04 +00:00
Daniele Varrazzo
f9b798aca9 Avoid unlikely leaks in case of memory errors in Bytes_Format 2019-01-21 02:00:04 +00:00
Daniele Varrazzo
2a05aa2c43 Move var setting into the only case using it
The original function was more complex than this. This refactoring
avoids a false positive in the static checker
2019-01-21 02:00:04 +00:00
Daniele Varrazzo
43d779966b Avoid using PyErr_BadInternalCall as the static checker doesn't get it 2019-01-21 02:00:04 +00:00
Daniele Varrazzo
003fc6dde1 Use the real definition of Py_LOCAL_INLINE 2019-01-21 02:00:04 +00:00
Daniele Varrazzo
fe915ac461 Bytes_Format: use a couple of macros instead of functions
The type was already checked upstream in the func body.
2019-01-21 02:00:04 +00:00
Daniele Varrazzo
15cba69a20 psycopg_escape_string: don't make me cringe
Just reformatted.
2019-01-21 02:00:04 +00:00
Daniele Varrazzo
79de02d7d5 Stricter use of PyArg_ParseTuple typed objects
The function expect PyObject *, not subclasses.
2019-01-21 02:00:04 +00:00
Daniele Varrazzo
3e66022912 Respect PyCFunction signature in METH_NOARGS functions
A second parameter does exist, although it's always NULL.
2019-01-21 02:00:04 +00:00
Daniele Varrazzo
5b08dc45b1 Merge remote-tracking branch 'origin/register-bytes'
Close #835
2019-01-19 15:32:46 +00:00
Daniele Varrazzo
49777de74c Added documentation for BYTES caster 2019-01-18 16:15:15 +00:00
Daniele Varrazzo
ddbe495d70 Added BYTESARRAY typecaster 2019-01-18 15:47:01 +00:00
Daniele Varrazzo
4ab4247189 Added test for BYTES typecaster 2019-01-18 15:10:17 +00:00
Daniele Varrazzo
fd31a7d41b Fixed typecast definition order
Didn't notice that the order matter: the last typecaster registered is
the effective one so let STRING win over UNICODE and BYTES.
2019-01-18 15:09:20 +00:00
Daniele Varrazzo
f713dc9fc1 Preliminary test for a BYTES adapter.
Allow returning unparsed bytes from databases with mixed encodings. See
issue #519.
2019-01-18 13:17:02 +00:00
Daniele Varrazzo
4a41c9a8cc
Merge pull request #828 from wbolster/patch-1
mention postgresql 11 in install docs
2019-01-08 12:21:18 +00:00
Daniele Varrazzo
07d9fb8718 Don't call CLEARPGRES on the cursor state without holding the gil
There is a chance it is executed by two different threads resulting in
issue #384.

I havent't found any other case that may lead to double free.
2019-01-02 13:15:00 +01:00
Daniele Varrazzo
ddcf808d56 Couple of objects into NEWS entries converted into links 2018-12-27 15:04:43 +01:00
Daniele Varrazzo
b26a0b149d Added # char to a few issues in news
Just a formatting thing #ocd #youdontcare #really.
2018-12-27 15:01:45 +01:00
Daniele Varrazzo
f3695e36c7 Merge remote-tracking branch 'eternalflow/execute-values-returning-clause-support' 2018-12-27 14:53:12 +01:00
Daniele Varrazzo
7c8d2f484e Mention execute_values() fetch in news 2018-12-27 14:51:18 +01:00
Daniele Varrazzo
bde9fc6dea Docs wordsmith for execute_values() fetch param 2018-12-27 14:42:58 +01:00
Daniele Varrazzo
6fdac46137 Some harmless adjustments in execute_values() code
No optional result, and create the list only if requred.
2018-12-27 14:39:13 +01:00
wouter bolsterlee
107f779061
mention postgresql 11 in install docs 2018-12-07 15:10:18 +01:00
Daniele Varrazzo
25fc044d13
Merge pull request #823 from jdufresne/dep-pool
Dropped deprecated PersistentConnectionPool
2018-12-05 11:32:20 +00:00
Daniele Varrazzo
de79aba66d
Merge pull request #819 from jdufresne/ctypes
Remove unnecessary test decorator 'skip_if_cant_cast'
2018-12-05 11:30:48 +00:00
Jon Dufresne
eb2d1766c6 Remove unnecessary test decorator 'skip_if_cant_cast'
ctypes is available and works on all supported Pythons. It has been
available since Python 2.5. The tests were written when Python 2.4 was
still supported.
2018-12-04 18:20:17 -08:00
Jon Dufresne
a1fdaebc30 Dropped deprecated PersistentConnectionPool
This class was deprecated in
27cd6c4880 (Dec 2, 2012), which was first
included in release 2.5. Enough time has passed for library uses to find
an alternative solution.

This class was untested.
2018-12-04 06:32:00 -08:00
Daniele Varrazzo
68bacbb194
Merge pull request #822 from jdufresne/decorate-all
Simplify 'decorate_all_tests' usage by decorating the test class
2018-12-04 14:22:02 +00:00
Daniele Varrazzo
672bdba679
Merge pull request #821 from jdufresne/skip-libpq
Remove workarounds for unsupported libpq < 9.1
2018-12-04 14:13:18 +00:00
Daniele Varrazzo
dc5298a919
Merge pull request #820 from jdufresne/appveyor
Remove Python 3.3 references from appveyor.yml
2018-12-04 14:11:53 +00:00
Daniele Varrazzo
b233778acd
Merge pull request #818 from jdufresne/bool-simplify
Simplify PyBool usage with Python convenience macros/functions
2018-12-04 14:07:48 +00:00
Jon Dufresne
a739c09f67 Simplify 'decorate_all_tests' usage by decorating the test class
Skip tests as early as possible by decorating the whole class with
unittest.skipIf instead of every test method individually.
2018-12-01 19:40:27 -08:00
Jon Dufresne
8b543eaa92 Remove Python 3.3 references from appveyor.yml
Python 3.3 has been unsupported since
c2d082e896.
2018-12-01 09:11:35 -08:00
Jon Dufresne
17dc5a85a3 Remove workarounds for unsupported libpq < 9.1
Per http://initd.org/psycopg/docs/install.html#prerequisites:

> PostgreSQL client library version from 9.1
2018-12-01 08:58:39 -08:00
Jon Dufresne
b796ca0c0a Simplify PyBool usage with Python convenience macros/functions
https://docs.python.org/3/c-api/bool.html
2018-11-30 17:09:30 -08:00
Ivan Kotelnikov
2e591e27f2 add versionchanged to docs 2018-11-24 20:51:18 +02:00
Ivan Kotelnikov
b40ac15efc rename param name to fetch 2018-11-24 20:51:18 +02:00
Ivan Kotelnikov
e2b99d3a8e write test for fetch_result flag 2018-11-22 12:30:37 +02:00
Ivan Kotelnikov
9a8d7d5a6a add RETURNING clause support in execute_values function 2018-11-21 16:38:13 +02:00
Daniele Varrazzo
483901ea7b Merge branch 'fix-591' 2018-11-16 19:17:24 +00:00
Daniele Varrazzo
73a680f45d Convert int subclasses to long before adapting
Fixes adaptation of int/long subclasses whose str() is not the number,
such IntEnum

Close #591

Note that I thought it would have needed a new adapter, so I considered
it a new feature. But it is more a shortcoming of the int adapter
failing to do something reasonable (poor Liskov, always mistreated) so I
may actually backport it if there is a new 2.7 release.
2018-11-16 18:16:03 +00:00
Daniele Varrazzo
654be4784c Dropped examples dir (and some leftover reference to the sandbox dir)
Close #645.
2018-11-16 17:06:06 +00:00
Daniele Varrazzo
f9d6430ae4 Mentioning binary packages fixes in news file 2018-11-10 23:48:47 +00:00
Daniele Varrazzo
3279ff7507 Mention get_native_connection() in the news file 2018-11-09 11:40:17 +00:00
Daniele Varrazzo
991b0e02c5 Fixed NEWS file after I actually re-read it for release. 2018-11-09 11:33:03 +00:00
Federico Di Gregorio
aee6f9352b
Merge pull request #805 from fogzot/feature-expose-pgconn
Feature expose pgconn
2018-11-08 15:57:23 +01:00
Federico Di Gregorio
01f8475f53
Merge branch 'master' into feature-expose-pgconn 2018-11-07 14:15:29 +01:00
Daniele Varrazzo
d1aa1585a1 Merge branch 'fix-788' 2018-10-30 10:50:25 +00:00
Daniele Varrazzo
a83696fc50 Fixed adaptation of lists of empty lists
...somehow. Postgres doesn't support them and converts them into a
simple empty array. However this is not really our concern: the syntax
we return is valid.

Close #788
2018-10-30 01:48:51 +00:00
Daniele Varrazzo
2f24a2e22d Use class decorators to decorate all tests
Test decorators changed so that they can be applied either to a method
or to a class. Of course their double nature is implemented by a
decorator.
2018-10-30 00:23:56 +00:00
Daniele Varrazzo
60935b9b3d Merge remote-tracking branch 'origin/fix-794' 2018-10-23 12:09:32 +01:00
Daniele Varrazzo
8fb0f694f7 Don't barf on Composite passed to execute_values()
Close #794
2018-10-23 01:57:48 +01:00
Daniele Varrazzo
05f9e231a0 Full flake8 3.5 cleanup 2018-10-23 00:39:14 +01:00
Daniele Varrazzo
1bb3d5cfe2 Dropped duplicate classes in errors module
Also using a more compact class registration using a decorator
2018-10-23 00:31:57 +01:00
Daniele Varrazzo
fae4284a64 Minimal formatting tweak to last news 2018-10-15 01:36:55 +01:00
Daniele Varrazzo
0236c68da9 Merge branch 'connection-info' 2018-10-15 01:24:00 +01:00
Daniele Varrazzo
c567556d71 Fixed NEWS file to mention the connection.info object 2018-10-15 01:23:51 +01:00
Daniele Varrazzo
b205764fdd Merge branch 'master' into errors-module 2018-10-15 00:58:32 +01:00
Daniele Varrazzo
e7227ce87b Added errors.lookup() function 2018-10-15 00:56:51 +01:00
Daniele Varrazzo
5da968d6f6 Added documentation for the errors module 2018-10-15 00:48:44 +01:00
Daniele Varrazzo
61df7bdd8d Errors module content updated to Postgres 11 2018-10-14 23:07:11 +01:00
Daniele Varrazzo
7a5edff6c6 errorcodes map update to PostgreSQL 11 2018-10-14 22:57:48 +01:00
Daniele Varrazzo
44bd2927c5 Use the connection.info properties instead of the legacy methods 2018-10-13 03:28:42 +01:00
Daniele Varrazzo
704e6797e7 Guard from some info functions not available in some libpq versions 2018-10-13 03:09:39 +01:00
Daniele Varrazzo
d138e42ee5 Added ConnectionInfo.parameter_status() 2018-10-13 02:40:17 +01:00
Daniele Varrazzo
9f6a3a5e96 Added ConnectionInfo.ssl_attribute() 2018-10-13 02:21:38 +01:00
Daniele Varrazzo
cb3d5f9d92 Added all the missing ConnectionInfo attributes 2018-10-13 01:36:07 +01:00
Daniele Varrazzo
4f7bbdca26 Added missing class signatures in the docs 2018-10-13 00:55:20 +01:00
Daniele Varrazzo
795522ff2b Merge branch 'fix-790' 2018-10-13 00:47:25 +01:00
Daniele Varrazzo
439dff974d Added ConnectionInfo.error_message 2018-10-13 00:47:04 +01:00
Daniele Varrazzo
d29aa1c437 Fixed refcount in connection's readonly and deferrable getters
Close #790
2018-10-12 23:32:13 +01:00
Daniele Varrazzo
1ac6359fef Added other members to the ConnectionInfo class
Starting deprecating softly some of the methods bloating the connection
class.
2018-10-12 04:18:59 +01:00
Daniele Varrazzo
0a04c8892d Added several ConnectionInfo attributes 2018-10-12 04:18:59 +01:00
Daniele Varrazzo
9ddf59959f Adding ConnectionInfo object documentation
I'm still fought whether docs should be in the C module or in the .rst.
I'd prefer the first because DRY, but writing multiline strings in C
really sucks.
2018-10-12 03:25:06 +01:00
Daniele Varrazzo
0e2b516a3c Moving host attribute to a connection.info object 2018-10-11 22:42:52 +01:00
Daniele Varrazzo
7619c91d62 Merge branch 'description-extra-attrs' 2018-10-11 04:39:14 +01:00
Daniele Varrazzo
6b3d3604bf Added docs for the Column object 2018-10-11 04:27:42 +01:00
Daniele Varrazzo
f99a8de6d0 Added table_oid, table_column on cursor.description items
Close #661
2018-10-11 03:37:09 +01:00
Daniele Varrazzo
b3b225a9da Added C implementation for a Column type
Currently behaving exactly like the previous (named)tuple.
2018-10-11 02:59:45 +01:00
Daniele Varrazzo
e00c4e2a7f Merge branch 'fix-copy-async-hangs' 2018-10-10 23:58:24 +01:00
Daniele Varrazzo
c314512115 Fixed infinite loop in pq_get_last_result after COPY
There will be an error downstream but we have to get out of this
function first.

Close #781
2018-10-10 23:57:34 +01:00
Daniele Varrazzo
c442b3ec46
Merge pull request #771 from jdufresne/distutils
Drop legacy distutils fallback in setup.py
2018-10-10 22:18:22 +01:00
Daniele Varrazzo
9c905741da Merge branch 'https' 2018-10-10 22:16:23 +01:00
Daniele Varrazzo
5010a65d77 Another url changed to https
Added after this MR.
2018-10-10 22:15:45 +01:00
Daniele Varrazzo
9148157697 Merge branch 'master' into https 2018-10-10 22:07:33 +01:00
Daniele Varrazzo
2e823273d6
Merge pull request #789 from jdufresne/argparse
Replace deprecated optparse usage with argparse
2018-10-10 22:05:16 +01:00
Daniele Varrazzo
cd9d74c462 Merge branch 'conn-get-host' 2018-10-10 22:03:36 +01:00
Daniele Varrazzo
382eeccab8 Small tweaks to connection.host docs 2018-10-10 22:02:20 +01:00
Daniele Varrazzo
f5f6b420b2 Merge remote-tracking branch 'origin/diag-schema-name-nonloc' 2018-10-10 21:46:51 +01:00
Jon Dufresne
488818eeb6 Replace deprecated optparse usage with argparse
Per https://docs.python.org/3/library/optparse.html

> Deprecated since version 3.2: The optparse module is deprecated and
> will not be developed further; development will continue with the
> argparse module.
2018-10-10 05:15:57 -07:00
Federico Di Gregorio
296c80d1f2 Commented out test to avoid beaking master 2018-10-10 11:05:02 +02:00
Federico Di Gregorio
1fe9f1ac5b Fixed test for issue #788 2018-10-10 09:35:18 +02:00
Federico Di Gregorio
ebcfbe03f9 Added test for issue #788 2018-10-10 09:14:56 +02:00
Federico Di Gregorio
7806fc736a Sandbox removed
The sandbox directory was there to test issues before we had full test
coverage and to try quick and dirty Python snippets before moving them to
the examples directory, sending them to mailing list or copying them to
the docs. Almost anything that was in sandbox is now in the examples
directory or has been refactored into a full test, or is so old that is
of no use anymore. So, adieu sandbox.
2018-10-09 00:00:12 +02:00
Federico Di Gregorio
e3c791cf60
Merge pull request #786 from alandmoore/master
Add documentation about the use of backslashes with LIKE
2018-10-08 23:50:33 +02:00
Alan D Moore
20647b7bcc Fix RST markup 2018-10-08 09:40:51 -05:00
Alan D Moore
67b94d0797 Added note about backslashes and LIKE
Added note about the use of LIKE with strings containing
backslashes.  Addresses concern in issue #785.
2018-10-08 09:36:16 -05:00
Federico Di Gregorio
f56392a245 Allow SPHINXBUILD on command line 2018-10-07 13:55:11 +02:00
Federico Di Gregorio
81addddaee Added connection.get_native_connection() 2018-10-07 13:54:24 +02:00
Marco De Paoli
1c553bb703 Added connection.host
Return the server host name of the current connect.
2018-10-06 15:19:01 +02:00
Daniele Varrazzo
4e0b2ec9c9 Added Diagnostics.severity_nonlocalized attribute
Close #783.
2018-10-04 16:13:46 +01:00
Daniele Varrazzo
9d83b03605 Merge branch 'identifier-sequence' 2018-10-04 13:22:46 +01:00
Daniele Varrazzo
4aa02b7855 sql.Identifier can wrap a sequence of strings to represent qualified names
Close #732.
2018-10-04 12:46:10 +01:00
Daniele Varrazzo
695c757dc3 Merge branch 'stringification-of-ranges' 2018-10-04 12:24:27 +01:00
Daniele Varrazzo
81d6f7a7ca Mention the better str(Range) in the docs. 2018-10-04 11:57:31 +01:00
Daniele Varrazzo
8bd7ad7bb5 Faster check for empty range in str() 2018-10-04 11:46:07 +01:00
Michel Albert
d317977205 Implement __str__ for range types 2018-09-30 10:15:55 +02:00
Federico Di Gregorio
ccae5cae34 Expose PGconn* raw pointer on the connection as a PyCapsule 2018-09-27 10:15:40 +02:00
Jon Dufresne
b07e34e0b8 Prefer https:// URLs when available 2018-09-22 19:02:33 -07:00
Jon Dufresne
9405d8cbc5 Drop legacy distutils in setup.py
distutils is not recommended for use and unnecessary for modern Python
environments. Use only setuptools instead. From
https://docs.python.org/3/library/distutils.html:

> Most Python users will not want to use this module directly, but
> instead use the cross-version tools maintained by the Python Packaging
> Authority. In particular, setuptools is an enhanced alternative to
> distutils ...
>
> The recommended pip installer runs all setup.py scripts with
> setuptools, even if the script itself only imports distutils. Refer to
> the Python Packaging User Guide for more information.
2018-09-15 16:05:05 -07:00
Daniele Varrazzo
6b6b1a6e8d Merge branch 'fix-bsd' 2018-09-07 23:58:19 +01:00
Daniele Varrazzo
0eaa0c9d4e Mention FreeBSD build fixed in news file 2018-09-07 23:57:34 +01:00
Dmitry Marakasov
5ec573c83b Remove obsolete and incorrect FreeBSD version condition
The FreeBSD-related condition which enables custom round() implementation is incorrect: one must include <sys/param.h> to get __FreeBSD_version value, and since it's not included here, the check succeeds while it shouldn't. Before it worked somehow, but since python 3.7 it results in conflicting declarations of round(). The condition is also no longer needed since FreeBSD 5.3 is unsupported for 12 years.
2018-09-07 23:57:33 +01:00
Daniel Hahler
6af55ee51c Improve doc for extras.wait_select 2018-09-05 16:45:33 +01:00
Andrew King
03fc3f9a2a Fix typo in install.rst 2018-09-05 16:42:59 +01:00
Jon Dufresne
c57fee2c92 Update intersphinx URLs to point to Python 3 docs
Python 3 docs are more up to date and reflect the future of Python.

Removed unused py3 marker.
2018-09-05 16:21:14 +01:00
Benjamin Peterson
f86229d98b Remove setup.py fallback that assumes postgres 7.4.0.
pyscopg2 only supports postgres >= 9.1 these days. Thus, taking this fallback will only lead to failure later down the line.
2018-09-05 16:18:18 +01:00
Daniele Varrazzo
344ce15261 Better testing of encryption function with libpq < 10 2018-08-17 02:09:22 +01:00
Daniele Varrazzo
782fa39647 Generating the whole errors file from script 2018-08-17 02:00:40 +01:00
Daniele Varrazzo
0bce58d0cd Dropped parsing sgml files for error codes
The errcodes.txt file contains all the errors for the currently
maintained server versions. There is only one error code missing,
probably unused, but adding it back anyway to keep the errcode module
unchanged.
2018-08-17 02:00:40 +01:00
Daniele Varrazzo
ce1ac3aea9 Read exceptions to raise from a Python module 2018-08-17 02:00:01 +01:00
Daniele Varrazzo
153b0983c1 Merge branch 'fix-746' 2018-07-25 16:29:57 +01:00
Daniele Varrazzo
97a4fb92c6 Fixed compile error on windows
Because const int + 1 is not const, right???

Also fixed other occurrences of magic numbers and failed DRY around
PyOS_snprintf() calls.
2018-07-24 21:16:36 +01:00
Daniele Varrazzo
466efe4461 Bump tests for selective closure of named cursor to pg 8.2
Previous versions don't support the features as they don't have the
pg_cursors view. But they are too old to care.
2018-07-24 21:16:36 +01:00
Daniele Varrazzo
6d8f4f9f0d Close named cursor if exist, even if we didn't run execute
Close #746
2018-07-24 21:16:36 +01:00
Daniele Varrazzo
0e89b9de2c Merge branch 'py37' 2018-07-13 19:12:23 +01:00
Daniele Varrazzo
a8b9c9971e Consider PG 9.3 a thing of the past.
Wow, it seems yesterday...

Previosly archived as a "past" version only in the prepare script. Test
script consistent now.

[skip ci]
2018-07-13 19:11:56 +01:00
Daniele Varrazzo
82f52db9b3 Fetch the correct testing postgres packages on xenial 2018-07-13 18:25:07 +01:00
Jon Dufresne
61e644049f Add testing and document support for Python 3.7
Python 3.7 was released on June 27, 2018.

https://docs.python.org/3/whatsnew/3.7.html
2018-07-12 18:07:25 -07:00
Daniele Varrazzo
6becf0ef55 Note the upgrade in wheel dependencies in NEWS file 2018-05-23 21:51:49 +01:00
Daniele Varrazzo
0aa7e21f91 Added note adivising against depending on the -wheels package 2018-05-23 21:43:48 +01:00
Daniele Varrazzo
a339ec3d8f Dropped license paragraph applying to removed files 2018-05-23 21:20:38 +01:00
Daniele Varrazzo
166ad21e5c Merge branch 'drop-2to3' 2018-05-21 03:36:32 +01:00
Daniele Varrazzo
0bb7d0db48 DictCursor and RealDictCursor rows maintain columns order
Close #177.
2018-05-21 03:14:08 +01:00
Daniele Varrazzo
7bdaf0affd Restored methods iter*() on dict cursors rows 2018-05-21 02:51:37 +01:00
Daniele Varrazzo
e8a831dda2 Merge branch 'master' into drop-2to3 2018-05-20 23:56:29 +01:00
Daniele Varrazzo
a0f7027ad5 Added tests to verify iter methods on dict cursors
ISTM the refactoring in #648 broke something
2018-05-20 23:55:18 +01:00
Daniele Varrazzo
82ae44ac3a DictCursor/RealDictCursor tests split 2018-05-20 23:35:26 +01:00
Daniele Varrazzo
f947c0e6be Merge branch 'encrypt-pass' 2018-05-20 22:33:07 +01:00
Daniele Varrazzo
9eb3e0cb79 encrypt_password() reported in the news file 2018-05-20 22:31:22 +01:00
Daniele Varrazzo
9cf658ec6e Fixed refcount handling in encrypt_password
Added tests to check bad types, which discovered the above problem: on
type error we would have decref'd on exit something that was only
borrowed (because we wouldn't have performed matching increfs).
2018-05-20 21:18:36 +01:00
Daniele Varrazzo
abca14d601 Fixed keywords support for encrypt_password and tests completed 2018-05-20 20:50:04 +01:00
Daniele Varrazzo
9e4f89a2a1 encrypt_password docs moved to extension module and updated 2018-05-20 20:13:04 +01:00
Daniele Varrazzo
a3063900ee Fixed code flow in encrypt_password()
Fixed several shortcomings highlighted in #576 and not fixed as
requested.

Also fixed broken behaviour of ignoring the algorithm if the connection
is missing.
2018-05-20 19:18:42 +01:00
Daniele Varrazzo
0161d54dbb Merge branch 'master' into encrypt-pass 2018-05-20 17:57:34 +01:00
Jon Dufresne
a8d4f37b19 Complete tox testing matrix
Now tests all supported Python environments as well. Allows testing the
full matrix of Python version with a single command.

Include the command make in the whitelist_externals configuration to
avoid the runtime warning:

  WARNING:test command found but not installed in testenv
    cmd: /usr/bin/make
    env: .../psycopg2/.tox/flake8
  Maybe you forgot to specify a dependency? See also the whitelist_externals envconfig setting.
2018-05-20 17:53:49 +01:00
Jon Dufresne
9ceffa1cc6 Update all pypi.python.org URLs to pypi.org
For details on the new PyPI, see the blog post:

https://pythoninsider.blogspot.ca/2018/04/new-pypi-launched-legacy-pypi-shutting.html
2018-05-20 17:22:37 +01:00
Daniele Varrazzo
10caf1bd74 Command to upload docs on pythonhosted dropped altogether 2018-05-20 17:21:26 +01:00
Daniele Varrazzo
a110d7dd70 Intersphinx urls to generate Python links updated
Previous urls warn about a redirect, so they are probably to go.
2018-05-20 17:21:26 +01:00
Daniele Varrazzo
3f0a7f9af4 Added license to the docs
Includes other docs improvements, such as the ones proposed in #711.
2018-05-20 17:03:08 +01:00
Daniele Varrazzo
068b15c57f Merge branch 'fix-716' 2018-05-20 17:00:13 +01:00
Daniele Varrazzo
aac8a20fc1 Merge branch 'fix-707' 2018-05-20 14:07:10 +01:00
Daniele Varrazzo
c4da939909 Don't raise an exception closing an unused named cursor
Close #716
2018-05-20 14:00:09 +01:00
Daniele Varrazzo
49d9edce01 Set minimal postgres version for intervalstyle test 2018-05-20 13:40:57 +01:00
Daniele Varrazzo
3f389593f5 Raise NotSupportedError fetching iso_8601 intervals
Previously it would have failed parsing and resulted in ValueError

Close #707
2018-05-20 13:22:38 +01:00
Daniele Varrazzo
098c00d73e Merge remote-tracking branch 'nested-array-nulls' 2018-05-20 12:51:13 +01:00
Daniele Varrazzo
8c969304fd Merge remote-tracking branch 'fix-211' 2018-05-20 12:50:22 +01:00
Daniele Varrazzo
dd7e5c906f Skipped test on db version not supporting unicode identifiers 2018-05-18 12:16:43 +01:00
Daniele Varrazzo
eb570488a4 Test databases from newest to oldest
This way we can spot when a feature was not supported yet by the first
test failing.
2018-05-18 12:16:03 +01:00
Daniele Varrazzo
bc84b6233e Allow non-ascii chars in namedtuple fields
They can be valid chars in Python 3. Or maybe not? In which case Python
will throw an exception, but that's fine.

Fix regression introduced fixing #211
2018-05-18 12:15:50 +01:00
Daniele Varrazzo
8dd00ee874 Hstore test fixed after adapting arrays dropped space after commas 2018-05-18 12:11:02 +01:00
Daniele Varrazzo
b5e4a040f8 Fixed adaptation of arrays of arrays of nulls
Close #325, close #706.
2018-05-18 12:10:20 +01:00
Daniele Varrazzo
548e281350
Merge pull request #715 from hroncok/py37
Travis CI: Run tests on Python 3.7
2018-05-18 12:07:03 +01:00
Miro Hrončok
b52ff10153 Travis CI: Run tests on Python 3.7
Also, switch to wheel, because eggs caused problems on 3.7:

    ValueError: bad marshal data (unknown type code)
2018-05-18 12:12:09 +02:00
Ashesh Vashi
36f0db81d2 Fixed the string format error reported by Travis-CI.
Reference: https://travis-ci.org/psycopg/psycopg2/jobs/376288585
2018-05-08 15:29:16 +05:30
Ashesh Vashi
1bec2bdc43
Merge branch 'master' into master 2018-05-08 15:17:59 +05:30
Daniele Varrazzo
90b26c3e23 Merge branch 'fix-679' 2018-02-21 12:05:06 +00:00
Daniele Varrazzo
ea923b63a4 Allow strings subclasses in ensure_bytes
Fix #679
2018-02-21 10:27:28 +00:00
Daniele Varrazzo
0a5db6ecf5 Merge branch 'expand-version' 2018-02-19 13:54:11 +00:00
Daniele Varrazzo
ede418a009 Report MSYS2 build probably fixed 2018-02-19 13:53:50 +00:00
Daniele Varrazzo
32f5a9fc1d Avoid quoting the string in the psycopg version macro
Use a macro trick to add the quotes. This seems more portable than
passing the quotes to the command line (see #658).

https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
2018-02-19 13:53:50 +00:00
Daniele Varrazzo
750ececf08 Merge branch 'fix-solaris-11' 2018-02-19 11:43:59 +00:00
Daniele Varrazzo
8670287928 Added Solaris 11 fix to news file 2018-02-19 11:43:37 +00:00
Mike Gerdts
f766d90704 Fixed building on SmartOS
timeradd is missing on Solaris 10, but is present as a macro in
<sys/time.h> on SmartOS, illumos, and likely Solaris 11.
2018-02-19 11:40:05 +00:00
Daniele Varrazzo
df952c149d Fixed pip invocation example to skip binary packages
Close #673
2018-02-09 16:12:29 +00:00
Daniele Varrazzo
5309da117d Autocommit shouldn't change deferrable on servers not supporting it
Regression on unsupported Postgres versions after fixing bug #580
2018-02-08 15:00:38 +00:00
Daniele Varrazzo
c52e49a9da Report Python 2.6 wheels no more available
[skip ci]
2018-01-29 12:58:28 +00:00
Daniele Varrazzo
1436ee308c Link psycopg2-binary package to PyPI in readme
Note: the package doesn't exist yet...
2018-01-29 03:31:49 +00:00
Daniele Varrazzo
9e6b22cc3b Merge branch 'namedtuple-invalid-identifiers' 2018-01-29 03:31:10 +00:00
Daniele Varrazzo
ddb87b7727 Convert fields names into valid Python identifiers in NamedTupleCursor
Close #211.
2018-01-29 03:30:46 +00:00
Daniele Varrazzo
3354bbd1b6 Merge branch 'openssl-1.0.2n' 2018-01-29 03:27:31 +00:00
Daniele Varrazzo
957fd79a27 Build using OpenSSL 1.0.2n 2018-01-29 03:27:08 +00:00
Daniele Varrazzo
8cc0d06e65 Define openssl and libpq versions in vars in appveyor build 2018-01-29 03:27:08 +00:00
Daniele Varrazzo
4845393c15 Build env vars on windows less verbose
Copied from psycopg2-wheels
2018-01-29 03:27:08 +00:00
Daniele Varrazzo
f85e405605 Merge branch 'separate-binary' 2018-01-29 03:24:45 +00:00
Daniele Varrazzo
f976c428d2 Mention new wheel packages in news file
Close #543.
2018-01-29 03:23:59 +00:00
Daniele Varrazzo
76f3e196d3 Silence warning on import failing a test 2018-01-29 03:23:59 +00:00
Daniele Varrazzo
5b69adf797 Document the psycopg2-binary package 2018-01-29 03:23:59 +00:00
Daniele Varrazzo
aa2c172706 Print info about the binary package on build failed
The idea is to release a package 'psycopg2-binary' to allow installing
binary, and leave the psycopg2 package to be source only, to avoid
pushing the unreliability of the wheel pacakge by default (see issue #543).

Version number bumped to test with new packages.
2018-01-29 03:22:59 +00:00
Daniele Varrazzo
8decf34ad7 Dropped warning about unsafe cursor names
It was long made secure
2018-01-25 22:00:40 +00:00
Daniele Varrazzo
da2aba1595 Merge branch 'fix-idempotence-check' 2018-01-11 02:41:38 +00:00
Daniele Varrazzo
74d2c4bef9 Fixed idempotence check changing connection characteristics 2018-01-11 02:23:27 +00:00
Daniele Varrazzo
6da3e7ee69 Merge branch 'mogrify-on-closed-cursor' 2018-01-11 00:16:01 +00:00
Daniele Varrazzo
ddef2e30cd 'key' docs in getconn() improved
Fix #569.
2018-01-11 00:14:36 +00:00
Daniele Varrazzo
a78ac3c125 Fixed test in asian time zones
Fix #652
2018-01-10 23:58:28 +00:00
Daniele Varrazzo
e0226fc46a 'cursor.mogrify()' can be called on closed cursors
Fix #579.
2018-01-11 08:55:31 +09:00
Daniele Varrazzo
04f1f06b9f Fixed stitch_text on Python 2 2018-01-10 22:49:00 +00:00
Daniele Varrazzo
bad9b8b383 Merge branch 'macro-accessors' 2018-01-10 22:47:59 +00:00
Daniele Varrazzo
b3a70e09e9 pypi3 fix noted in the news file 2018-01-10 22:44:37 +00:00
Daniele Varrazzo
77c703395b Moved datatime compatibility macros with others 2018-01-10 22:29:16 +00:00
Daniele Varrazzo
e50f3129c2
Merge pull request #651 from ronnix/patch-1
Fix typo in comment in utils.c
2017-12-14 13:45:09 +00:00
Ronan Amicel
b8f2f71819
Fix typo in comment in utils.c 2017-12-14 14:00:36 +01:00
Glyph
3fcb035126 define a "polyfill" inline for python 2 compatibility 2017-12-12 03:15:21 -08:00
Glyph
852884e086 use accessor macros for pypy3 compatibility 2017-12-12 03:06:18 -08:00
Jon Dufresne
be3b1ba1eb In tests, use compat.py where there is overlap 2017-12-11 20:27:52 -08:00
Jon Dufresne
8ad2098b74 Drop 2to3 build step; make all code compatible with all Pythons
Make all library code compatible with both Python 2 and Python 3. Helps
move to modern Python idioms. Can now write for Python 3 (with
workarounds for Python 2) instead of the other way around.

In the future, when it is eventually time to drop Python 2, the library
will be in a better position to remove workarounds

Added a very small comparability module compat.py where required. It
includes definitions for:

- text_type -- A type. str on Python 3. unicode on Python 2.
- string_types -- A tuple. Contains only str on Python 3. Contains str &
                  unicode on Python 2.
2017-12-11 20:26:58 -08:00
Jon Dufresne
f35465231f Drop the Python 2 style interface from DictRow
Now standardizes on the Python 3 interface for all uses. Makes behavior
of DictRow between Pythons more consistent and predictable.
2017-12-11 20:02:16 -08:00
Jon Dufresne
3a6a8e96fb User super() throughout DictRow class
Avoid calling parent method directly.
2017-12-11 19:01:38 -08:00
Daniele Varrazzo
2cd9a78a97 Gitignore env2/env3 envs too 2017-12-11 02:25:13 +00:00
Daniele Varrazzo
4be2b75816 Dropped PYTHONPATH propagation in 'make check'
Psycopg doesn't have other dependencies outside the stdlib so what's
there is probably just noise.
2017-12-11 02:22:02 +00:00
Daniele Varrazzo
f3d21c24fc
Merge pull request #644 from jdufresne/noinstall-tests
Avoid installing tests to site-packages
2017-12-11 02:20:56 +00:00
Jon Dufresne
389f6c08d9 Avoid installing tests to site-packages
For library end users, there is no need to install tests alongside the
package itself. This keeps the tests available for development without
adding extra packages to user's site-packages directory. Reduces the
size of the installed package. Avoids accidental execution of test code
by an installed package.
2017-12-10 10:55:58 -08:00
Jon Dufresne
c86e682153 Skip register_hstore(..., unicode=True) tests on Python 3
Per the functions documentation, this argument is not supported on
Python 3. Skip it during tests.

> :param unicode: if `!True`, keys and values returned from the database
> will be `!unicode` instead of `!str`. The option is not available on
> Python 3

Work towards moving tests outside of the installed package.
2017-12-10 10:51:07 -08:00
Jon Dufresne
1a8e992fcc Use relative imports throughout tests
The tests relied on Python2 relative import semantics. Python3 changed
import semantics to always search sys.path by default. To import using a
relative path it must have a leading dot.

Forward compatible with newer Pythons.

Works towards the goal of moving tests outside of the installed package.

For more information, see PEP-328:

https://www.python.org/dev/peps/pep-0328/
2017-12-10 10:51:07 -08:00
Jon Dufresne
9de46e416e Use print() function instead of print statement throughout project
Forward compatible with newer Pythons.
2017-12-10 10:51:07 -08:00
Jon Dufresne
ef64493b89 Fix use of "async" in test_cursor.py
"async" will be a keyword starting with Python 3.7. On Python 3.6, use
of "async" causes a deprecation warning. Use the alias "async_" instead.
2017-12-10 10:49:04 -08:00
Daniele Varrazzo
b42c35849b
Merge pull request #647 from jdufresne/drop-unused-scripts
Remove unused scripts maketypes.sh & buildtypes.py
2017-12-10 18:26:29 +00:00
Jon Dufresne
1047af03da Remove unused scripts maketypes.sh & buildtypes.py
Refs #645
2017-12-10 09:57:43 -08:00
Daniele Varrazzo
afd7c6c284
Merge pull request #646 from jdufresne/drop-deprecated
Drop long deprecated function register_tstz_w_secs()
2017-12-10 17:43:01 +00:00
Jon Dufresne
19b1efd629 Drop long deprecated function register_tstz_w_secs()
Deprecated in commit b263fbf274 on
2010-01-13. The deprecation warning was first released in version 2.2.2.

The function used to register an alternate type caster for TIMESTAMP
WITH TIME ZONE to deal with historical time zones with seconds in the
UTC offset. These are now correctly handled by the default type caster,
so currently the function doesn't do anything.
2017-12-10 07:57:11 -08:00
Daniele Varrazzo
ec0a3d59a8 Merge branch 'goodbye-psycopg1' 2017-12-04 12:12:37 +00:00
Daniele Varrazzo
861e389fcf Dropped psycopg1 module 2017-12-04 11:56:27 +00:00
Daniele Varrazzo
2218e73c28 Merge branch 'master' into ws 2017-12-02 14:47:29 +00:00
Daniele Varrazzo
7617e1dbf5 Dropped .sln file 2017-12-02 14:46:03 +00:00
Daniele Varrazzo
df646831d7 Merge remote-tracking branch 'jdufresne/egg-info' 2017-12-02 12:11:10 +00:00
Daniele Varrazzo
06396e5162 Merge remote-tracking branch 'jdufresne/import-unittest' 2017-12-02 12:10:26 +00:00
Daniele Varrazzo
aae5d6364f Merge remote-tracking branch 'jdufresne/leading0' 2017-12-02 12:07:57 +00:00
Daniele Varrazzo
5a3cf32fe5 Merge remote-tracking branch 'jdufresne/next-func' 2017-12-02 12:07:47 +00:00
Daniele Varrazzo
2c5cad1525 Merge remote-tracking branch 'jdufresne/more-json' 2017-12-02 12:07:06 +00:00
Daniele Varrazzo
8f6d744b5d Merge remote-tracking branch 'jdufresne/sorted' 2017-12-02 12:06:05 +00:00
Daniele Varrazzo
ccc3820f8e Merge remote-tracking branch 'jdufresne/script-to-py3' 2017-12-02 12:05:53 +00:00
Jon Dufresne
699be52e8b Remove unnecessary script_to_py3; make scripts compatible instead
Part of the work towards moving tests out of the installed package.
2017-12-01 22:50:16 -08:00
Jon Dufresne
94bb238b70 Remove sorted() workaround; available on all supported Pythons
Introduced in Python 2.4 and the oldest supported Python is 2.7.

https://docs.python.org/2/library/functions.html#sorted
2017-12-01 22:03:38 -08:00
Jon Dufresne
e335d6d223 Trim trailing whitespace from all files throughout project
Many editors automatically trim whitespace on save. By trimming all
 files in one go, makes future diffs cleaner without extraneous
 whitespace changes.
2017-12-01 21:42:14 -08:00
Jon Dufresne
d0c7126aa8 Remove test decorators for json module
The json module is available in all Python versions supported by
psycopg2. No need to check for its presence when executing tests.

Should have been included with d58844e548
but was missed.
2017-12-01 21:06:10 -08:00
Jon Dufresne
f5703dc3e5 Use builtin function next() throughout project
Available since Python 2.6. Use of .next() is deprecated and not
supported in Python 3. Forward compatible with modern Python.

https://docs.python.org/2/library/functions.html#next
2017-12-01 19:57:37 -08:00
Jon Dufresne
56ec575351 Drop leading 0's from numeric literals
Not compatible with Python3. Makes the code more forward compatible with
modern Pythons.

In Python2, it was an alternative syntax for octal.

$ python3
>>> 01
  File "<stdin>", line 1
    01
     ^
SyntaxError: invalid token
2017-12-01 19:00:53 -08:00
Jon Dufresne
fcc083dc12 Always import the system unittest
There is no need to import testutils.unittest instead of simply
unittest. They are simple aliases. Use system unittest to be more
regular, consistent as well as idiomatic with the wider Python
community.
2017-12-01 18:35:30 -08:00
Jon Dufresne
6a1546adde Add *.egg-info directories to .gitignore 2017-12-01 18:21:50 -08:00
Daniele Varrazzo
a51160317c Fixed NEWS file entries
- 2.6.3 has not been released (yet). Fixes for bug #420, bug #462 were
  relased in 2.7.
- Added missing report for bug #489 fixed in 2.7.
2017-12-01 16:29:29 +00:00
Daniele Varrazzo
f4aa40da09 Merge branch 'bug-633' 2017-11-29 15:42:29 +00:00
Daniele Varrazzo
65ed5478d1 Collect rowcount in executemany even when discarding results
Closes #633.
2017-11-29 15:42:04 +00:00
Daniele Varrazzo
727b952a32 Build and test packages with libpq 10.1 and OpenSSL 1.0.2m 2017-11-28 17:19:55 +00:00
Daniele Varrazzo
0d5b0f0287 Merge branch 'fix-libpq-version' 2017-11-28 17:19:30 +00:00
Daniele Varrazzo
87da2f898d Fixed __libpq_version__ for Postgres >= 10.1
The version should be considered as 10.0.1; the number was generated as
10.1.0 instead.

Version number bumped to test building new wheels packages.

Fix #632.
2017-11-28 17:19:01 +00:00
Daniele Varrazzo
3e52b5445b Merge branch 'rm-eol'
Fix #626, close #628.
2017-11-28 16:27:41 +00:00
Daniele Varrazzo
f939f39580 Use dict comprehensions 2017-11-28 16:11:06 +00:00
Daniele Varrazzo
c3ee9cac41 Dropped unused test functions 2017-11-28 16:11:06 +00:00
Daniele Varrazzo
a0229cff82 Documentation tweaked to omit Python 2.6 distinctions 2017-11-28 16:11:06 +00:00
Hugo
60b1517c55 Add news and update version check 2017-11-28 16:11:02 +00:00
Hugo
c2d082e896 Drop support for EOL Python 3.0-3.3 2017-11-28 16:06:55 +00:00
Hugo
ea76504cd1 Remove trailing semicolons 2017-11-28 16:06:55 +00:00
Hugo
283de27098 Remove redundant parentheses 2017-11-28 16:06:52 +00:00
Hugo
08b479bc10 __slots__ should be a tuple 2017-11-28 16:05:59 +00:00
Hugo
7282ef0d14 Rewrite list creation as list literal 2017-11-28 16:03:23 +00:00
Hugo
955526b200 Replace comparison with None with equality operator 2017-11-28 16:03:23 +00:00
Hugo
b69457ccdf Update to Exception as e, print() 2017-11-28 16:03:23 +00:00
Hugo
2f3c233f38 Simplify Boolean 2017-11-28 16:03:23 +00:00
Hugo
53c1c5dcc1 Remove redundant hasattr checks 2017-11-28 16:03:23 +00:00
Hugo
ffcc65d4f0 Drop support for EOL Python 2.6 2017-11-28 16:02:12 +00:00
Daniele Varrazzo
e7529e4823 Merge remote-tracking branch 'jdufresne/json-docs' 2017-11-28 15:22:09 +00:00
Daniele Varrazzo
f77057dd43 Merge remote-tracking branch 'jdufresne/with-statement' 2017-11-28 15:20:24 +00:00
Jon Dufresne
c1d3948be9 Update documentation to reflect JSON import behavior
The docs don't need to describe what will happen on Python versions
before 2.6 as they are unsupported by psycopg2.

Should have been included in commit
d58844e548, but was missed.
2017-11-28 06:38:44 -08:00
Jon Dufresne
4c95668c72 Remove "from __future__ import with_statement"
All versions of Python supported by psycopg2 have builtin support for
the with statement. The import is unnecessary noise.
2017-11-28 06:03:46 -08:00
Daniele Varrazzo
914ccbacb5 Merge branch 'python3_mintimeloggingconnection' 2017-11-28 03:23:42 +00:00
Daniele Varrazzo
b4f066bd43 Mention MinTimeLoggingCursor fix in NEWS file 2017-11-28 03:22:53 +00:00
Daniele Varrazzo
1959d2403f Merge branch 'solaris-support' 2017-11-28 03:16:04 +00:00
Daniele Varrazzo
a1831ef498 Mention solaris support in NEWS
Close #532.
2017-11-28 03:13:25 +00:00
Daniele Varrazzo
fc8574fdd8 Merge remote-tracking branch 'jdufresne/decimal' 2017-11-28 03:05:06 +00:00
Daniele Varrazzo
06d4788811 Merge remote-tracking branch 'jdufresne/json' 2017-11-28 03:04:59 +00:00
Daniele Varrazzo
e0ce35ef72 Merge remote-tracking branch 'jdufresne/skip-before' 2017-11-28 03:04:44 +00:00
Daniele Varrazzo
db0c081d03 Merge remote-tracking branch 'jdufresne/uuid' 2017-11-28 03:04:26 +00:00
Daniele Varrazzo
a39d794308 Merge remote-tracking branch 'jdufresne/iobase' 2017-11-28 03:04:03 +00:00
Daniele Varrazzo
7855f28785 Merge remote-tracking branch 'jdufresne/namedtuple' 2017-11-28 03:02:56 +00:00
Daniele Varrazzo
dda55dbf36 Moving to next major version on master
Opened maintenance branch `maint_2_7`
2017-11-28 03:02:03 +00:00
Daniele Varrazzo
afb42e7625 Merge remote-tracking branch 'jdufresne/py2' 2017-11-28 02:59:17 +00:00
Daniele Varrazzo
b4e658d29b Merge remote-tracking branch 'jdufresne/license' 2017-11-28 02:39:54 +00:00
Jon Dufresne
296abf735e Add some missing trove classifiers for general Python support 2017-11-27 07:30:50 -08:00
Jon Dufresne
048f1bb95a Remove workaround for decimal module
The decimal module is available on all Python versions supported by
psycopg2. It has been available since Python 2.4. No need to catch an
ImportError.

https://docs.python.org/2/library/decimal.html
2017-11-26 17:55:24 -08:00
Jon Dufresne
d58844e548 Clean up JSON workarounds for unsupported Python versions
All Python versions supported by psycopg2 have the json module. It was
added in Python 2.6. Can remove checks for availability, slightly
simplifying the code.
2017-11-26 17:11:27 -08:00
Jon Dufresne
dfc9932f27 Remove use of skip_before_python for unsupported Python versions
psycopg2 does not support Python < 2.6, remove all test guards for these
versions.
2017-11-26 16:43:18 -08:00
Jon Dufresne
582ec189cc Remove uuid workaround for older Pythons
uuid is available on all Python versions supported by psycopg2.
2017-11-26 14:46:53 -08:00
Jon Dufresne
f7d5d25651 Remove io.TextIOBase workaround for Python <= 2.5
io.TextIOBase is available on all Python versions supported by psycopg2.
Can remove all workarounds.
2017-11-26 14:32:35 -08:00
Jon Dufresne
05c28cce78 Remove workarounds for namedtuple on Python <= 2.5
namedtuple is available on all Python versions supported by psycopg2. It
was first introduced in Python 2.6. Can remove all workarounds and
special documentation.
2017-11-26 13:55:30 -08:00
Jon Dufresne
5ddac80cec Include license file in the generated wheel package
The wheel package format supports including the license file. This is
done using the [metadata] section in the setup.cfg file. For additional
information on this feature, see:

https://wheel.readthedocs.io/en/stable/index.html#including-the-license-in-the-generated-wheel-file
2017-11-26 10:42:30 -08:00
Daniele Varrazzo
858bc3d42a
Merge pull request #616 from jdufresne/modern-exceptions
Use modern except syntax throughout project
2017-11-21 11:45:34 +00:00
Jon Dufresne
390e43fcb1 Use modern except syntax throughout project
The syntax "except Exception, exc:" is deprecated. All Python versions
supported by psycopg2 support the newer, modern syntax. Forward
compatible with future Python versions.
2017-11-20 20:00:35 -08:00
Daniele Varrazzo
7a2dd85caa NEWS updated after last bugfix. 2017-11-16 16:07:34 +00:00
Federico Di Gregorio
13b0b9d3e3
Merge pull request #614 from fogzot/fix-613
Don't cast point arrays to float arrays (fixes: #613)
2017-11-16 10:09:28 +01:00
Federico Di Gregorio
5983b96c55 Don't cast point arrays to float arrays (fixes: #613) 2017-11-16 10:07:27 +01:00
Daniele Varrazzo
d88d8f9619 Added PostgreSQL 10 in the list of supported servers 2017-11-06 18:38:22 +00:00
Daniele Varrazzo
9614e7241b Further docs cleanup
Recent Sphinx versions seem overly aggressive in autodetecting python,
or I just didn't notice the errors, so be explicit in what language to
use with code examples.
2017-11-06 18:34:23 +00:00
Daniele Varrazzo
4f1505857b Parameters passing docs improved
Every point has an example and all the example show wrong/correct. Nice
rhythm.

Among the improvements, added point saying explicitly "thou shall not
quote placeholders".  Quoted placeholders will just fail except in the
most contrived cases (a statement raising an exception with all the
strings except with the attack ones...), and an example in the following
section explicitly notes "no quotes", but apparenty someone still thinks
this is not documented enough? (see issue #611) so let's just write it
plain and clear into the list of commandments.
2017-11-06 17:31:35 +00:00
Kevin Campbell
b804c092ac Patch for issue #609 for MinTimeLoggingConnection
On Python3 MinTimeLoggingConnection raises an exception as it tries to
mix strings and bytes
2017-11-03 17:30:06 +08:00
Daniele Varrazzo
dfee199351 Dropped suggestion for --no-binary :all: to skip wheels
:all: applies to the entire file. --no-binary psycopg2 is the solution.

See issue #543
2017-10-27 12:34:00 +01:00
My Karlsson
f54783ae6e Emulate timeradd and timersub on Solaris
Solaris does not have timeradd and timersub. Add solaris_support.c which
provides emulated versions of them on Solaris.
2017-10-26 20:21:30 +02:00
Daniele Varrazzo
46d8529dde Merge branch 'libpq-10-wheels' 2017-10-24 11:52:02 +01:00
Daniele Varrazzo
980145eaee Preparing release 2.7.3.2
Close #601, close #602.
2017-10-24 11:43:26 +01:00
Daniele Varrazzo
c6e90766e1 Merge branch 'libpq-10'
Fix #604
2017-10-24 11:31:26 +01:00
Daniele Varrazzo
f3f394ced9 Import recipe to build PG 10 libpq on win from wheel repos
Also build pg_config so the libpq version is correct at compile time
too.
2017-10-24 11:26:14 +01:00
Daniele Varrazzo
552e49a11d Test building PG 10 using the solution provided by Jason Erickson
https://github.com/psycopg/psycopg2-wheels/pull/3/
2017-10-24 11:26:14 +01:00
Daniele Varrazzo
0d90c173fb Test against PG 10.0 on Travis 2017-10-24 11:26:14 +01:00
Daniele Varrazzo
f1461d2d7e Parse PG 10 error codes from final version 2017-10-19 02:28:52 +01:00
Daniele Varrazzo
6ee8b4c9aa Bumping version to test libpq 10 wheel package 2017-10-18 22:25:42 +01:00
Daniele Varrazzo
582fd95986 Merge branch 'sphinx-1.6' 2017-10-18 21:58:08 +01:00
Daniele Varrazzo
e7587caee3 Dropped doc building warning
doctests have sure completely rotten however.
2017-10-18 21:57:17 +01:00
Daniele Varrazzo
4d68f6e414 Sphinx version do build docs updated to 1.6 2017-10-18 21:56:48 +01:00
Dmitry Shachnev
1ccb61fe18 Make dbapi_extension.py compatible with Sphinx 1.6
In Sphinx commit 1a821b89e9952fc2, the deprecated make_admonition()
function was removed. This commit updates the code to use the modern
API instead.
2017-10-12 13:10:41 +03:00
Ashesh Vashi
84d405894c Moving the encrypt_password method from the connection class to the
psycopgmodule, and exported it from psycopg2.extensions as per review
comments.
2017-09-14 23:42:54 +05:30
Ashesh Vashi
6e0edf7779 Merge remote-tracking branch 'psycopg2/master' 2017-09-11 18:26:34 +05:30
Daniele Varrazzo
3ec06b88f0 Construct proper human sentences to describe execute_values()
With bonus typos dropped.
2017-08-31 16:34:04 +01:00
Daniele Varrazzo
75198a46d4 Merge branch 'fix-wheel-libresolv' 2017-08-25 15:13:36 +01:00
Daniele Varrazzo
c45e219387 Preparing release 2.7.3.1 to fix wheel packages 2017-08-25 15:12:12 +01:00
Daniele Varrazzo
302b2f962f Bump version number to try fixing libc 2.26 libresolv problem
https://github.com/psycopg/psycopg2-wheels/issues/2

[skip-ci]
2017-08-25 12:24:37 +01:00
Daniele Varrazzo
22c7114168 Disable uploading docs on pythonhosted
The service is deprecated in favour of RTD. There is also no more way to
upload redirects there, so #581 cannot be fixed.

Official docs are on http://initd.org/psycopg/docs/
2017-08-23 13:42:49 +01:00
Daniele Varrazzo
2c836a2935 Fixed typo (found on stackoverflow... gh) 2017-07-27 12:10:11 +01:00
Daniele Varrazzo
df688d6b87 Bump to next development release 2017-07-24 16:25:16 +01:00
Daniele Varrazzo
cd3393b21c Bumped version number to 2.7.3 2017-07-24 15:06:09 +01:00
Daniele Varrazzo
9358725963 Merge branch 'fix-578' 2017-07-24 15:04:26 +01:00
Daniele Varrazzo
775de754cf Added back timestamptz[] default cast
It was registered as side effect of an excessive definition that got
cleaned up in 338dbe70a6.

Looking at other removed redundant type oids, this was the only one
missing from the `string_types` map.

Close #578.
2017-07-24 14:23:36 +01:00
Daniele Varrazzo
b7bd5eceed Bump to next development release 2017-07-22 16:13:10 +01:00
Daniele Varrazzo
cfa0509d7e Deal with E'' strings comparisons in a few other tests 2017-07-22 03:15:06 +01:00
Daniele Varrazzo
d619baf000 Skipped a couple of test with unsupported postgres features 2017-07-22 02:09:24 +01:00
Daniele Varrazzo
791f5fe969 Bump to version 2.7.2 2017-07-22 01:32:25 +01:00
Ashesh Vashi
e089d94c88 'encrypt_password' raises 'psycopg2.NotSupportedErorr' exception for
server version >= 10, when compiled using libpq version < 10, when no
algorithm is specified.
2017-07-17 11:46:50 +05:30
Ashesh Vashi
2c1966a7f6 When compiled with libpq version < 10, it raises 'psycopg2.NotSupportedError' (not, psycopg2.ProgrammingError). 2017-07-17 11:06:55 +05:30
Ashesh Vashi
78eb80d0cf Using 'Text_FromUTF8' macro for transforming the encrypted C string to
Python string to make it Python 3 compatible.
2017-07-17 10:54:52 +05:30
Ashesh Vashi
cfb0937605 Added support for preparing the encrypted password of a PostgreSQL
password using the libpq functions - 'PQencryptPasswordConn', and
'PQencryptPassword'.
2017-07-17 10:32:59 +05:30
Daniele Varrazzo
d2e86db8fb Merge branch 'fix-554' 2017-06-17 03:34:01 +01:00
Daniele Varrazzo
1a97445471 Accept Composable in start_replication_expert()
Close #554
2017-06-17 03:30:44 +01:00
Daniele Varrazzo
30d89da4fa Ignore spurious output in test with Python debug build 2017-06-17 03:20:09 +01:00
Daniele Varrazzo
d72efd2fa8 Merge branch 'fix-550' 2017-06-17 01:58:11 +01:00
Daniele Varrazzo
991f0988ee Use an import style reported not broken on Python 3.6
Couldn't reproduce the issue but it has been documented in #550.
2017-06-17 01:51:37 +01:00
Daniele Varrazzo
8ab16807c6 Merge branch 'fix-558' 2017-06-17 01:38:25 +01:00
Daniele Varrazzo
49ce622a86 Fixed parsing interval from micros on 32 bit
Using integers the wrong size. Faithfully segfaulting since 1970.
2017-06-17 01:36:39 +01:00
Daniele Varrazzo
2b5e131831 Merge branch 'fix-558' 2017-06-16 19:41:52 +01:00
Daniele Varrazzo
70a2d2238e Consider redshift interval supported after further tests 2017-06-16 19:39:18 +01:00
Daniele Varrazzo
324e56cfa3 Merge branch 'fix-562' 2017-06-16 02:32:31 +01:00
Daniele Varrazzo
789eb64f3a Added Json.prepare()
Close #562
2017-06-16 01:37:49 +01:00
Daniele Varrazzo
21ee8b62ef Merge branch 'mr-566' 2017-06-16 01:04:27 +01:00
Daniele Varrazzo
315f72862c Parse a number as microseconds when casting interval
Should close #558, but I'm curious to know if a number is returned
for interval < 1 day too (which wouldn't trigger the overflow, but will
finish parsing with part=0).
2017-06-16 00:54:38 +01:00
Sebastian Bank
30af82ef2f Document that executemany() is not logged with LoggingConnection 2017-06-15 23:27:28 +01:00
Daniele Varrazzo
eef198ac5e Report issue #541 fixed in the NEWS file 2017-06-15 23:25:19 +01:00
Daniele Varrazzo
8576d43006 Bump version number to test a new build 2017-06-15 23:07:43 +01:00
Daniele Varrazzo
9b4de93bdc Document incompatibility between wheel package and ssl module
Close #543.
2017-06-15 22:46:53 +01:00
Daniele Varrazzo
338dbe70a6 Dropped wrong associations of PG types to datetime object
The wrong associations are overwritten in the typecaster map by the
right ones, so they have been harmless to date, but only because of the
order of creation of the adapters.
2017-06-15 18:24:25 +01:00
Daniele Varrazzo
496cef80c4 Merge branch 'bug-551' 2017-06-15 17:46:04 +01:00
Daniele Varrazzo
7ae2cb5cd0 Don't force a valid return code for the test
Windows returns 22, Linux returns 1
2017-06-15 17:39:00 +01:00
Daniele Varrazzo
602c74faa6 Check return code from decoding the connection status
It fails on Py3 after receiving a SIGABRT. Because we don't handle it
here it will resurface later with nonsense such as:

    SystemError: <some function> returned a result with an error set

Close #551
2017-06-15 17:33:05 +01:00
Daniele Varrazzo
de843ef756 Added test to reproduce bug #551 2017-06-15 17:22:32 +01:00
山楂片
799c5aaf43 typo
s/fromat/format/g
2017-06-12 11:25:22 +01:00
Jason Erickson
9ac2b8c3a9 Force rebuild of cache for new OpenSSL/PostgreSQL
OpenSSL updated to 1.0.2l
PostgreSQL updated to 9.6.3
2017-06-08 20:11:20 -06:00
Jason Erickson
63cc9ea24b Build/Test against newer PostgreSQL/OpenSSL
Test against PostgreSQL 9.6 and build against newer libraries:
	OpenSSL: 1.0.2l
	PostgreSQL: 9.6.3
2017-06-08 20:11:17 -06:00
Jason Erickson
c837261ac1 Remove VC9 runtime dependency
Changed check in setup.py to only use vc9 manifest when built against
versions that use the MSVC 2008 compiler.  Resolves #541.

Note that as of VS 2010, a manifest is no longer needed according to this
comment, "...we are no longer deploying the VC dlls as Win32 assemblies.
They are regular dlls that can be loaded without a manifest."

https://connect.microsoft.com/VisualStudio/feedback/details/522121/crtassem-h-missing
2017-06-08 20:11:02 -06:00
Daniele Varrazzo
3d13a2cf25 Link the appveyor badge in the readme to the master branch builds
[skip-ci]
2017-06-08 20:07:11 +01:00
Daniele Varrazzo
7d9ef5f952 Run tests against PostgreSQL 10 beta1
Use the new Postgres verisoning schema: 10 is a major version, 10.0 a
patch release. See
https://wiki.postgresql.org/wiki/New_in_postgres_10#Change_in_Version_Numbering
2017-06-08 18:45:07 +01:00
Daniele Varrazzo
767118467f Merge branch 'errcodes-update' 2017-06-05 12:49:42 +01:00
Daniele Varrazzo
256910f8ff Updated docs about versions supported in errcodes 2017-06-05 12:34:17 +01:00
Daniele Varrazzo
89169e6e53 Error codes updated to PG 10 beta 1 2017-06-05 12:34:17 +01:00
Daniele Varrazzo
75d84f0b25 errcodes updated to PG 9.6 2017-06-05 12:18:21 +01:00
Daniele Varrazzo
165449c724 Added doc link to replication commands 2017-05-10 01:55:01 +01:00
Daniele Varrazzo
6e5abf33f2 Merge branch 'fix-547' 2017-04-19 01:34:39 +01:00
Daniele Varrazzo
9d7ff405ee Added news entries for the previous 2 merge requests 2017-04-19 01:16:08 +01:00
Daniele Varrazzo
a7e3f46431 Merge remote-tracking branch 'fix_lobject_factory' 2017-04-19 01:06:24 +01:00
Daniele Varrazzo
bd34c86aba Merge remote-tracking branch 'fix_lobject_mode' 2017-04-19 01:06:08 +01:00
Daniele Varrazzo
248e653c9e Fixed args parsing in ReplicationCursor.consume_stream()
Close #547.
2017-04-19 01:01:59 +01:00
Frazer McLean
9e5621698f Python < 3.2 doesn’t have assertIsInstance 2017-04-16 03:44:21 +02:00
Frazer McLean
7b3ea43e92 Handle lobject mode=None correctly 2017-04-16 03:20:31 +02:00
Frazer McLean
38cd720369 Fix name of lobject keyword argument 2017-04-16 03:12:18 +02:00
Daniele Varrazzo
4b4d2796b7 Merge branch 'fix-410' 2017-04-05 15:16:01 +01:00
Daniele Varrazzo
cd095ef0ee Added test to verify callback errors in named cursors
They work fine.
2017-04-05 14:54:07 +01:00
Daniele Varrazzo
a66c34a6d0 Don't clobber a Python exception with an unknown error
Close #410
2017-04-05 14:54:07 +01:00
Daniele Varrazzo
47f5e97759 Added test to verify #410
The 'unknown error' happens on query.
2017-04-05 14:54:07 +01:00
Daniele Varrazzo
3b48918bef Note that the fast executemany functions don't respect rowcount
See issue #540
2017-03-28 10:37:04 +01:00
Daniele Varrazzo
adf55babe8 Merge remote-tracking branch 'origin/fix-536' 2017-03-22 12:19:31 +00:00
Daniele Varrazzo
b94548f5a3 Fix curl not found on AppVeyor
http://help.appveyor.com/discussions/problems/6312-curl-command-not-found
2017-03-22 03:54:23 +00:00
Daniele Varrazzo
ee9948fa86 Expose *DATETIMETZ* objects in the extensions module 2017-03-22 03:42:12 +00:00
Daniele Varrazzo
57b1093b31 Find again mxDateTime includes in default locations 2017-03-22 03:36:08 +00:00
Daniele Varrazzo
7214c6652e Return objects with timezone parsing infinity timestamptz
Close #536.
2017-03-22 03:03:02 +00:00
Daniele Varrazzo
31f91e033f Dropped info that the features requires libpq >= 9.0
We are currently requiring libpq 9.1 at least, and the feature was
released in 2.7, which could have never been compiled with previos
libpq versions.
2017-03-20 19:08:18 +00:00
Daniele Varrazzo
1e0aef032f Dropped repeated doc links in the same paragraph
And some more sql docs cleanup.
2017-03-16 04:40:22 +00:00
Daniele Varrazzo
f9b36433fb Merge branch 'fix-528' 2017-03-16 04:24:17 +00:00
Daniele Varrazzo
ba0329fb40 replication connection init refactored to use psyco_make_dsn
Some extra bonus refactoring to improve the function readability (don't
reuse names for variables with different refcount rules, don't pass
separate obj/self, async pass-through...)
2017-03-16 03:55:22 +00:00
Daniele Varrazzo
9f160fd820 Obscure the password on url dsn too
Note that we don't leak anymore the password length.

Fix #528
2017-03-16 03:53:40 +00:00
Daniele Varrazzo
c7f5690426 Added docs about the usability of sql objects with copy_expert()
See issue #529.
2017-03-16 00:55:20 +00:00
Daniele Varrazzo
3bfbd3a0a5 Added test to verify sql objects work with copy_expert()
I'll be honest: I lucked out, I didn't think about this combination. But
maybe sheer luck, maybe using common code paths, it just works. Let's
make it stays so.
2017-03-16 00:55:20 +00:00
Daniele Varrazzo
103655d670 Password scrubbing refactored in a separate function 2017-03-15 16:04:45 +00:00
Daniele Varrazzo
cc047a445a Added tests to verify the password is obscured
The url test fails: see issue #528
2017-03-15 16:00:40 +00:00
Daniele Varrazzo
7187d6408a Merge branch 'fix-443' 2017-03-14 14:41:48 +00:00
Daniele Varrazzo
3626e961f8 Reported bug #443 fixed *again*
Also see ticket #527.
2017-03-14 14:16:02 +00:00
Daniele Varrazzo
8e28444897 Bunch of test tweaks to make the test grid green 2017-03-14 14:15:52 +00:00
Daniele Varrazzo
7c2333dd81 Connection state fixed noted in the news 2017-03-14 14:15:52 +00:00
Greg Ward
12317557da Always raise OperationalError when connection was closed externally.
From the DB-API (https://www.python.org/dev/peps/pep-0249/):

  OperationalError

  Exception raised for errors that are related to the database's
  operation and not necessarily under the control of the programmer,
  e.g. an unexpected disconnect occurs, [...]

Additionally, psycopg2 was inconsistent, at least in the async case:
depending on how the "connection closed" error was reported from the
kernel to libpq, it would sometimes raise OperationalError and
sometimes DatabaseError. Now it always raises OperationalError.
2017-03-14 12:14:00 +00:00
Greg Ward
b203a7c775 Always detect when a connection is closed behind psycopg2's back.
There's a race condition that only seems to happen over Unix-domain
sockets. Sometimes, the closed socket is reported by the kernel to
libpq like this (captured with strace):

  sendto(3, "Q\0\0\0\34select pg_backend_pid()\0", 29, MSG_NOSIGNAL, NULL, 0) = 29
  recvfrom(3, "E\0\0\0mSFATAL\0C57P01\0Mterminating "..., 16384, 0, NULL, NULL) = 110
  recvfrom(3, 0x12d0330, 16384, 0, 0, 0)  = -1 ECONNRESET (Connection reset by peer)

That is, psycopg2/libpq sees no error when sending the first query
after the connection is closed, but gets an error reading the result.
In that case, everything worked fine.

But sometimes, the error manifests like this:

  sendto(3, "Q\0\0\0\34select pg_backend_pid()\0", 29, MSG_NOSIGNAL, NULL, 0) = -1 EPIPE (Broken pipe)
  recvfrom(3, "E\0\0\0mSFATAL\0C57P01\0Mterminating "..., 16384, 0, NULL, NULL) = 110
  recvfrom(3, "", 16274, 0, NULL, NULL)   = 0
  recvfrom(3, "", 16274, 0, NULL, NULL)   = 0

i.e. libpq received an error when sending the query. This manifests as
a slightly different exception from a slightly different place. More
importantly, in this case connection.closed is left at 0 rather than
being set to 2, and that is the bug I'm fixing here.

Note that we see almost identical behaviour for sync and async
connections, and the fixes are the same. So I added extremely similar
test cases.

Finally, there is still a bug here: for async connections, we
sometimes raise DatabaseError (incorrect) and sometimes raise
OperationalError (correct). Will fix that next.
2017-03-14 12:08:03 +00:00
Daniele Varrazzo
3c124a0b87 Flake8 complaints 2017-03-14 12:06:46 +00:00
Daniele Varrazzo
ef9f9f5fff Improved notes to release psycopg packages 2017-03-13 16:50:57 +00:00
Daniele Varrazzo
5730aa9a40 Less stuff in the readme, more in the docs 2017-03-13 12:13:47 +00:00
Daniele Varrazzo
8ed0196d02 Bump to next dev release 2017-03-13 11:50:34 +00:00
Daniele Varrazzo
09c48c76c3 Bump to version 2.7.1 2017-03-11 17:03:22 +00:00
Daniele Varrazzo
b075c7169c Report ticket 518 fixed
The fix is actually implemented in the openssl1 branch of
https://github.com/psycopg/psycopg2-wheels
2017-03-11 17:00:58 +00:00
Jon Nelson
c661695b28 correct minor grammatical issue with deprecation warning 2017-03-03 13:54:22 +00:00
Daniele Varrazzo
06fbd0ee02 Dropped "what's new in 2.7.1" from docs index 2017-03-03 13:50:57 +00:00
Daniele Varrazzo
e3f56718d2 Added install section to specify how to skip wheels 2017-03-03 13:49:19 +00:00
Daniele Varrazzo
d007dc3249 Merge branch 'fix-520' 2017-03-02 19:36:45 +00:00
Daniele Varrazzo
a5382d7b72 Skip the tests according to the earliest of libpq built/linked. 2017-03-02 19:32:44 +00:00
Daniele Varrazzo
26bd5df048 Don't use PG_INT64_TYPE
Only defined in Postgres 9.3

Should close #520, but let's wait for the CI response (build on
Windows etc.)
2017-03-02 19:32:39 +00:00
Daniele Varrazzo
3a441467c0 Merge branch 'no-unittest2'
Close #516
2017-03-02 12:41:33 +00:00
Daniele Varrazzo
6be94f1927 Merge branch 'fix-517' 2017-03-02 12:22:27 +00:00
Daniele Varrazzo
5a65ff5cf4 Don't try to use unittest2
Modules importing unittest directly would miss the monkeypatch: see
ticket #516.
2017-03-01 20:44:04 +00:00
Daniele Varrazzo
44d8edfd8c Ignore None arguments passed to make_dsn()
Close #517.
2017-03-01 20:12:13 +00:00
Daniele Varrazzo
455f51c36c Added docs about making a release
Drop previous script which didn't include the CI-generated packages.

[skip ci]
2017-03-01 15:59:15 +00:00
Daniele Varrazzo
6f7e570a0a Bump away from 2.7
[skip ci]
2017-03-01 15:56:54 +00:00
Daniele Varrazzo
51591e2c23 Merge branch 'fix-512' 2017-03-01 02:14:40 +00:00
Daniele Varrazzo
3638d349ba Skip test on PG version with bad interval rounding
On these ancient versions:

    =# select '999999:00:00.1'::interval;
                interval
    --------------------------------
     41666 days 15:00:00.0999999046
2017-03-01 02:14:35 +00:00
Daniele Varrazzo
b0e6045b63 Bump to version 2.7
Refer to pep 440 for version numbering, which superseded pep 386. We are
not changing numbering scheme: the version numbers we have used (when we
have been consistent) would have been valid in both schemes.
2017-02-28 11:57:08 +00:00
Daniele Varrazzo
a2bc3c7bcb Fixed doc typo
Close #515
2017-02-28 11:28:11 +00:00
Daniele Varrazzo
c871c49f55 Dropped reference to "isolation level autocommit" in docs 2017-02-24 16:53:32 +00:00
Daniele Varrazzo
72f74d1f41 Dropped compiler warning on Windows 2017-02-24 13:33:42 +00:00
Daniele Varrazzo
451e1e2e73 Merge branch 'fix-512' 2017-02-24 13:33:36 +00:00
Daniele Varrazzo
691df4952b Handle overflow in interval parsing 2017-02-24 13:23:56 +00:00
Daniele Varrazzo
3b665d35d5 Make sure to use 64 bits in interval parsing accumulators 2017-02-24 12:10:54 +00:00
Daniele Varrazzo
834e9996da Parse interval only using integers
(almost... except for micros rounding)

While this is probably an improvement on the previous implementation,
I am largely waving a dead chicken at windows, which keeps failing to
pass the seconds overflow test. If it doesn't pass now either I'll start
blaming Python's timedelta.
2017-02-24 03:48:41 +01:00
Daniele Varrazzo
e351606b69 Display Appveyor build status of master branch 2017-02-24 02:49:45 +01:00
Daniele Varrazzo
a15dfbbd4f Try to fix the same problem in windows
Previous commit doesn't pass on Windows: it looks like window's floor()
has an integer overflow.
2017-02-24 02:41:34 +01:00
Daniele Varrazzo
14fe3ad8c9 Fixed integer overflow in interval typecaster
Close #512.
2017-02-24 02:10:27 +01:00
Daniele Varrazzo
f5bd6063fc Fixed link to attribute in news 2017-02-16 20:25:58 +00:00
Daniele Varrazzo
a3193aca2a Bump version number 2017-02-16 20:25:58 +00:00
Daniele Varrazzo
355d62f084 Url to download VC fix file moved to this repos 2017-02-16 18:31:49 +00:00
Daniele Varrazzo
1cb2721a67 Bumping to 2.7 beta 2 2017-02-16 18:26:37 +00:00
Daniele Varrazzo
559dbe7b53 Merge branch 'test-windows' 2017-02-16 18:23:23 +00:00
Daniele Varrazzo
30efe59af7 Document installation from wheel packages 2017-02-16 18:22:41 +00:00
Daniele Varrazzo
afcae0a61b Download external packages in .zip instead of .tar.gz
7z barfs every now and then with tar files
(https://ci.appveyor.com/project/psycopg/psycopg2/build/job/oh1ux3ih7baia0uu)
2017-02-16 17:35:16 +00:00
Daniele Varrazzo
089ceb96a8 Download postgres from github instead of ftp.postgresql.org
There may be some misconfigured mirror, download fails randomly, e.g.
https://ci.appveyor.com/project/psycopg/psycopg2/build/job/9j792s03tghrb7sr
2017-02-16 16:32:17 +00:00
Daniele Varrazzo
7819d0fc6c Windows testing tweaks, badge on README 2017-02-16 16:16:16 +00:00
Daniele Varrazzo
535ff672c0 Added AppVeyor configuration to test building on Windows 2017-02-16 15:43:11 +00:00
Daniele Varrazzo
82adf8a162 Merge branch 'session-attributes' 2017-02-16 14:50:21 +00:00
Daniele Varrazzo
61101888e4 Revert default_transaction_* to default only if set
When moving from autocommit True -> False reset only the server
parameters that were actually specified by psycopg to honour the
serssion characteristics.
2017-02-16 13:15:14 +00:00
Daniele Varrazzo
d7bba865f3 Check for deferrable unsupported applied to attribute too 2017-02-16 13:14:45 +00:00
Daniele Varrazzo
d50ed48807 Added readonly and deferrable attributes 2017-02-16 12:46:35 +00:00
Daniele Varrazzo
b5d80b609d Revert pre-2.7b1 behaviour of silent rollback on conn.set_isolation_level()
Legacy method is legacy.
2017-02-16 12:46:35 +00:00
Daniele Varrazzo
20c9c17457 connection.isolation_level is now writable 2017-02-16 12:46:35 +00:00
Daniele Varrazzo
fb1a47c064 Link COPY from docs index to our docs instead of postgres ones 2017-02-16 12:46:12 +00:00
Daniele Varrazzo
6c79f936bd SQL links not bold in the docs
Consistent with the SQL representation not linked.
2017-02-16 12:38:04 +00:00
Daniele Varrazzo
75747606d3 Merge branch 'pull-507' 2017-02-11 20:34:37 +00:00
Jason Erickson
32e81a27b5 Allowed inittype.h's defs all versions of MSVC
Apparently only MSVC 2015 x64 had defined these types.  Changed check to
work for all versions of MSVC.  Does not affect 2015x64.
2017-02-10 10:14:17 -07:00
Jason Erickson
7493ea24f2 Defined inttypes.h for older MSVC compilers
Older MSVC compilers do not support the C99 standard
2017-02-09 22:27:18 -07:00
Jason Erickson
d52e9100d2 Added support for MSVC compiler
Added function 'timeradd'.
Changed second parameter of 'gettimeofday' to void since not used in
function and MSVC timezone definition is not a struct).
2017-02-09 20:57:54 -07:00
Jason Erickson
83cf908c88 Fixed MSVC compiler error and warning
MSVC doesn't like referencing new initialized variables in the variable
declaration section.
2017-02-09 20:54:29 -07:00
Daniele Varrazzo
ee4887b4c5 Download testing servers from upload instead of tarballs 2017-02-08 18:37:40 +00:00
Daniele Varrazzo
4b78ca4405 Fixed generation of download url from beta version 2017-02-08 18:09:15 +00:00
Daniele Varrazzo
21fbe2bd2a Fixed argument name in executemany docs 2017-02-08 14:01:57 +00:00
Daniele Varrazzo
b4b8b5f164 Bump version number 2017-02-08 13:56:50 +00:00
Daniele Varrazzo
6f83c9c87a Bump version to 2.7 beta 1 2017-02-08 10:31:27 +00:00
Daniele Varrazzo
d2cafe2684 Dropped references to prepare in cur.execute[many] docs
They were copied from the DBAPI spec but that's not how psycopg works.
2017-02-08 10:31:19 +00:00
Daniele Varrazzo
d2cd1236a8 Dropped compiler warning about signed/unsigned comparisons 2017-02-08 08:44:08 +00:00
Daniele Varrazzo
3e12522bc9 Don't convert '{}'::unknown into an empty list
Close #506.
2017-02-08 08:43:53 +00:00
Daniele Varrazzo
791befca18 Use pydll to poke into extension library
Causes an error in Py 3.6 in debug mode.

Close #505
2017-02-07 12:29:06 +00:00
Daniele Varrazzo
7210287e76 Stop a docstring generating a warning
Valid reST, slightly less valid Python.
2017-02-07 12:29:05 +00:00
Daniele Varrazzo
28c489f17e Merge branch 'no-set-default-session' 2017-02-07 00:58:54 +00:00
Daniele Varrazzo
3ff350cd24 Merge branch 'test-dinosaurs' 2017-02-07 00:58:48 +00:00
Daniele Varrazzo
7485fabe4f Fixed BEGIN; SET TRANSACTION with PG 7.4 2017-02-07 00:58:29 +00:00
Daniele Varrazzo
705dda2cba Dropped support for Python 3.1 2017-02-06 23:03:48 +00:00
Daniele Varrazzo
7b11b95908 Skipped a couple of tests failing on old dbs
I don't even know why - worth investigating.
2017-02-06 21:40:05 +00:00
Daniele Varrazzo
7f593d5eb0 Skip tests with server not supporting NULL in array 2017-02-06 21:40:05 +00:00
Daniele Varrazzo
2e18b42db0 Don't test with server not implementing INSERT with VALUES list 2017-02-06 21:40:05 +00:00
Daniele Varrazzo
3873c6c09f Deal consistently with E'' quotes in tests 2017-02-06 21:40:05 +00:00
Daniele Varrazzo
d23fe42873 Work around a race condition in async cancel test 2017-02-06 21:40:05 +00:00
Daniele Varrazzo
e599da6308 assertDsnEqual moved as TestSuite method 2017-02-06 21:40:05 +00:00
Daniele Varrazzo
f5cad47909 Run the test suite with postgres versions not available on travis 2017-02-06 21:40:05 +00:00
Daniele Varrazzo
e9c5f66450 build-manylinux script moved to build-wheels project 2017-02-06 19:12:17 +00:00
Daniele Varrazzo
9f467231d9 Merge branch 'conform-subclass-adapter' 2017-02-05 12:13:52 +01:00
Daniele Varrazzo
c6af16c3ae Slower timeout for a test that sometimes fail
At least it should fail with an error after 2 seconds, not waiting for
Travis timeout of 10 minutes.
2017-02-05 12:06:55 +01:00
Daniele Varrazzo
30a833f57a Dropped compiler warning in debug mode 2017-02-05 12:06:55 +01:00
Daniele Varrazzo
3fbff5d848 Give precedence to '__conform__()' over superclasses choosing adapter
Close #456
2017-02-05 11:54:50 +01:00
Daniele Varrazzo
c54a614c6e Added documentation about the changes in transaction control 2017-02-04 15:55:59 +00:00
Daniele Varrazzo
9054eeccc0 Set default_transaction_* GUC if session state is changed in autocomit 2017-02-04 15:19:41 +00:00
Daniele Varrazzo
665e9dc665 Exposing ISOLATION_LEVEL_DEFAULT to Python
This is now the state that is returned to Python if nothing has been
explicitly set.
2017-02-04 14:43:54 +00:00
Federico Di Gregorio
9448576ba6 Merge pull request #504 from fogzot/pgversion-fix
Fixed version regexp to match "10devel"
2017-02-04 14:32:06 +01:00
Daniele Varrazzo
c60682c230 Reuse set_session to implement autocommit, set_isolation_level 2017-02-04 13:26:43 +00:00
Federico Di Gregorio
8b96bcddff Fixed version regexp to match "10devel"
Also normalized the result and made sure that if PostgreSQL ever starts
using just integer version numbers (as in "10") everything still works.
2017-02-04 14:21:07 +01:00
Daniele Varrazzo
8527144173 Better separation between interface and state change code
The state change function has a C callable signature.
2017-02-04 13:01:11 +00:00
Daniele Varrazzo
ca59fd8b3f Test looking the transactions characteristics instead of the default
So we test the effect, not the implementation. Tests pass on master too
this way, three tests fail in this branch, related to autocommit
(sort-of-obviously).
2017-02-04 10:57:30 +00:00
Daniele Varrazzo
c1e016e597 Don't use default_transaction_* for session characteristics
Store the state in the connection object and set the params on BEGIN

Some tests fail: a few can be fixed reading transaction_* instead of
default_transaction_*; but the behaviour of tx characteristics with
autocommit is effectively changed. It may be addressed by setting
default_transaction_* if autocommit is set.
2017-02-04 02:38:56 +00:00
Daniele Varrazzo
9863637f30 Dropped compiler warning in debug mode 2017-02-04 02:32:26 +00:00
Daniele Varrazzo
de8b335d80 Merge branch 'master' into sql-compose 2017-02-03 04:56:02 +00:00
Daniele Varrazzo
ca42306d79 Misplaced NEWS entry fixed. 2017-02-03 04:52:49 +00:00
Daniele Varrazzo
1911b250e3 Merge branch 'async-keyword'
Close #495
2017-02-03 04:45:17 +00:00
Daniele Varrazzo
44c3b77691 Added docs for async_ alias 2017-02-03 04:43:49 +00:00
Daniele Varrazzo
ce9be69615 Added async_ as an alias for async
Added in argument for psycopg2.connect() and connection.__init__, and
for the connection.async attribute.
2017-02-03 04:43:49 +00:00
Daniele Varrazzo
8baf6aa372 Convert warnings into errors on test 2017-02-03 04:41:32 +00:00
Daniele Varrazzo
6e89db020c Merge branch 'fast-executemany' 2017-02-03 04:40:34 +00:00
Daniele Varrazzo
95226baa9b Further minimal performance tweaks to execute_values 2017-02-02 17:44:25 +00:00
Daniele Varrazzo
dc1b4fff90 Avoid an useless encode/decode roundtrip in execute_values()
Tests moved into a separate module.
2017-02-02 17:29:17 +00:00
Daniele Varrazzo
d2fdc5ca9f Better docs for fast executemany functions.
Issue #502.
2017-02-02 16:02:33 +00:00
Daniele Varrazzo
d8b1fbd905 Further skipping of slow tests 2017-02-02 03:02:29 +00:00
Daniele Varrazzo
626e57acda Merge branch 'fast-executemany' 2017-02-02 02:40:28 +00:00
Daniele Varrazzo
27652ed3b0 Added notes about using execute_batch with prepared statements 2017-02-02 02:40:03 +00:00
Daniele Varrazzo
ad6506ff69 Merge branch 'manylinux' 2017-02-02 02:15:15 +00:00
Daniele Varrazzo
88a21689ce Added note about finding slow tests 2017-02-02 02:09:59 +00:00
Daniele Varrazzo
f24de0357f Allow skipping the slow test
It's not so much about tests being slow: some just get stuck and timeout
travis.

Skipped all tests taking about more than 0.2s to run on my laptop.
Fast testing takes about 8s instead of 24.
2017-02-02 01:53:50 +00:00
Daniele Varrazzo
9ca51e0ed9 Use the server on the host to test 2017-02-01 17:33:12 +00:00
Daniele Varrazzo
815869375b Merge back manylinux build script from the psycopg2-wheels project 2017-02-01 17:05:47 +00:00
Daniele Varrazzo
9bac37baf7 Fixed execute_values with unicode
Also added unicode tests.
2017-02-01 02:47:59 +00:00
Daniele Varrazzo
2e2dcd536b Fixed fast execute functions with Python 3 2017-02-01 02:36:54 +00:00
Daniele Varrazzo
26952ecee4 Fixed sql docs style with newer Docutils versions 2017-02-01 02:00:20 +00:00
Daniele Varrazzo
a95fd3df1a Added execute_batch and execute_values functions 2017-02-01 01:59:47 +00:00
Daniele Varrazzo
8ac839ce95 Merge branch 'fix-iter-warning' 2017-01-05 15:27:26 +00:00
NotSqrt
9ffb61214c Fix DeprecationWarning: generator '__iter__' raised StopIteration
Closes #498
2017-01-04 09:45:53 +01:00
Daniele Varrazzo
8341792c5b Added script to create manylinux1 wheels
See issue #425
2017-01-04 04:43:54 +01:00
Daniele Varrazzo
651f1b6c97 Consider Python 3.6 and Postgres 9.6 supported 2017-01-03 19:12:44 +01:00
Daniele Varrazzo
a8a3a298f8 Autonumbered args not available in Python 2.6 2017-01-03 17:53:02 +01:00
Daniele Varrazzo
71a168797c Several improvements to the sql objects
Comparable, iterable, content accessible
2017-01-03 17:27:01 +01:00
Daniele Varrazzo
a76e665567 Use {} instead of %s placeholders in SQL composition 2017-01-03 15:02:34 +01:00
Daniele Varrazzo
49461c2c39 More doc love for the sql module 2017-01-01 18:15:01 +01:00
Daniele Varrazzo
9926942260 Added missing doc file 2017-01-01 16:01:55 +01:00
Daniele Varrazzo
077328c1a2 Using the new name of the old doc template 2017-01-01 16:01:09 +01:00
Daniele Varrazzo
d97399daa5 sql module docs wordsmithing 2017-01-01 09:23:26 +01:00
Daniele Varrazzo
cf40bff2e2 Dropped sql.compose
Use a SQL % operator instead.
2017-01-01 08:39:02 +01:00
Daniele Varrazzo
4a55b8018a Adding sql module documentation 2017-01-01 08:12:05 +01:00
Daniele Varrazzo
41b9bfe401 Added test for sql percents treatment 2017-01-01 06:37:09 +01:00
Daniele Varrazzo
828415d476 Typo: composible -> composable 2017-01-01 06:32:18 +01:00
Daniele Varrazzo
ad2643266f Fixed sql.compose with no args and added tests 2017-01-01 06:26:54 +01:00
Daniele Varrazzo
8c020ca47a Fixed sql.Composed representation 2017-01-01 06:26:42 +01:00
Daniele Varrazzo
600416aafc Fixed sql stuff in Py3 2017-01-01 05:59:21 +01:00
Daniele Varrazzo
c4a67fc1c1 Added sql.compose() implementation 2017-01-01 05:23:42 +01:00
Daniele Varrazzo
f11e6d82b0 Added basic sql module implementation 2017-01-01 05:23:15 +01:00
Daniele Varrazzo
fad5100079 Adding some boilerplate for the new module 2017-01-01 03:53:08 +01:00
Daniele Varrazzo
21f38a4c07 Don't try to write bytes in the LoggingConnection file
Close #483
2016-12-29 22:42:25 +01:00
Daniele Varrazzo
449bd4485f Merge branch 'fast-codecs' 2016-12-29 22:15:46 +01:00
Daniele Varrazzo
f3e47a72ed Brag about encoding/decoding speedup 2016-12-29 22:11:58 +01:00
Daniele Varrazzo
cb5293be1f Use the proper API functions to look up codec functions 2016-12-29 22:11:58 +01:00
Daniele Varrazzo
3295beb777 Don't look up for Python encoding
Store the encode/decode functions for the right codec in the connection.
The Python encoding name has been dropped of the connection to avoid the
temptation to use it...
2016-12-29 22:11:58 +01:00
Daniele Varrazzo
a81f12f9bd Don't set tp_compare on Python 3
The slot is unused in Py < 3.5, and replaced by pg_as_async in Py 3.5.
2016-12-29 21:43:04 +01:00
Daniele Varrazzo
dfe547856e Use -1 instead of 0 to say "calculate the length" in many funcs
0 is a valid length, isn't it?
2016-12-27 00:29:01 +01:00
Daniele Varrazzo
a255e4e1c6 Store python encoding and decoding functions in the connection
Unused for now: will be used instead of 'pyenc', which is to be dropped.
2016-12-27 00:29:01 +01:00
Daniele Varrazzo
17a74cc771 Setting connection encoding refactored
Code paths to read encoding on connection and to store the new
connection in the structure after changing it in the backend unified
into a single function.
2016-12-26 16:51:22 +01:00
Daniele Varrazzo
f439ca61d6 conn->codec rename to pyenc 2016-12-26 12:25:13 +01:00
Daniele Varrazzo
7caba160b7 Merge branch 'master' into fast-codecs 2016-12-26 12:06:21 +01:00
Daniele Varrazzo
e9577e9b89 Merge branch 'named-callproc' 2016-12-26 04:57:07 +01:00
Daniele Varrazzo
c46b6ea719 Fixed travis test: unset green mode 2016-12-26 04:31:18 +01:00
Daniele Varrazzo
64342fcff0 Less verbose travis tests 2016-12-26 04:13:41 +01:00
Daniele Varrazzo
ffeb7001eb Fixed refcount problems in named callproc 2016-12-26 04:12:18 +01:00
Daniele Varrazzo
d13521a6ce Mention named callproc in news, fixed docs. 2016-12-26 03:39:28 +01:00
Daniele Varrazzo
1957389bea Merge branch 'master' into named-callproc 2016-12-26 03:19:02 +01:00
Daniele Varrazzo
a53b39efe8 Dropped internal escape identifier function
Using libpq one as now it's guaranteed to be present.
2016-12-26 03:11:36 +01:00
Daniele Varrazzo
faaef61c27 Merge branch 'master' into named-callproc 2016-12-26 01:49:42 +01:00
Daniele Varrazzo
17698c4815 Fixed REst error in newsfile 2016-12-25 21:17:24 +01:00
Daniele Varrazzo
4c99cadabe Fixed intersphinx links to Pyton docs 2016-12-25 21:17:14 +01:00
Luke Nezda
dcb198e8b7 fix wait_select sample to be extras not extensions 2016-12-25 20:49:24 +01:00
Tim Graham
35b4a01b6d Fix "invalid escape sequence" warning in Python 3.6
http://bugs.python.org/issue27364
2016-12-25 20:43:29 +01:00
Daniele Varrazzo
1c3e2be224 Merge branch 'fix-453' 2016-12-25 19:56:40 +01:00
Daniele Varrazzo
d48d4bab05 Added empty options in setup.cfg
Setuptools removes them from the sdist, see #453
2016-12-25 19:46:09 +01:00
Daniele Varrazzo
c9798ecb15 Merge branch 'dont_set_datestyle_in_replication_mode' 2016-12-25 19:28:23 +01:00
Daniele Varrazzo
c22093ddd4 Skip replication tests in green mode 2016-12-25 19:00:30 +01:00
Daniele Varrazzo
874705db42 Configure Travis to test replication 2016-12-25 18:37:26 +01:00
Daniele Varrazzo
b73115ac41 Added test to verify bug #482 2016-12-25 18:30:27 +01:00
Daniele Varrazzo
e27579292a Avoid deadlock on close if set datestyle failed 2016-12-25 17:45:01 +01:00
Daniele Varrazzo
c2d405116b Dropped testing print 2016-12-25 17:44:25 +01:00
Daniele Varrazzo
b77de74f72 Merge branch 'master' into dont_set_datestyle_in_replication_mode 2016-12-25 16:31:33 +01:00
Daniele Varrazzo
f451d35aae Merge branch 'travis' 2016-12-24 04:51:30 +01:00
Daniele Varrazzo
feebc8f689 Don't use separate databases for tests
I got this wrong: I thought parallel test ran in the same VM; they are
isolated instead.
2016-12-24 04:42:55 +01:00
Daniele Varrazzo
1463bdb86d Added build badge to readme 2016-12-24 04:28:34 +01:00
Daniele Varrazzo
6758ce5eef Test Python versions in a more relevant order 2016-12-24 04:27:51 +01:00
Daniele Varrazzo
def22982fb Run the tests against all the available server versions 2016-12-24 04:12:03 +01:00
Daniele Varrazzo
11ad1005e0 Added python3 supported versions 2016-12-24 01:09:57 +01:00
Daniele Varrazzo
a478ba9a47 Fixed tests failing on Python 2.6 2016-12-24 01:03:57 +01:00
Daniele Varrazzo
b3cd125d27 Create the hstore extension in the trevis db 2016-12-24 00:18:09 +01:00
Daniele Varrazzo
0be783c454 Disable email notification
Mmm... it seems it's going to be a long night...
2016-12-24 00:12:32 +01:00
Daniele Varrazzo
3971ee6d1f Testing CI with Travis 2016-12-24 00:07:23 +01:00
Christoph Moench-Tegeder
fb1dbc2a9b do not "SET datestyle" on replication connections
A replication connection - marked by the use of the keyword "replication"
in the DSN - does not support SET commands. Trying to sent "SET datestyle"
will result in an exception.
2016-10-21 15:32:11 +02:00
Daniele Varrazzo
121cf3b8f8 Optimize UTF8 and Latin1 decoding
Cache a pointer to a fast decoding function when the connection encoding
is set so skip a repeated codec lookup for every string.
2016-10-12 01:10:31 +01:00
Daniele Varrazzo
584c7e6890 Dropped compiler warning in debug mode 2016-10-12 00:28:25 +01:00
Daniele Varrazzo
51aa166d52 Merge branch 'networking-improvement' 2016-10-11 04:55:09 +01:00
Daniele Varrazzo
643ba70bad Added ipaddress objects conversion
Close #387
2016-10-11 04:54:41 +01:00
Daniele Varrazzo
706ad2f177 Conver network array types into array of strings by default 2016-10-11 02:31:45 +01:00
Daniele Varrazzo
86198c1c21 inet adapters deprecated
Close #343
2016-10-11 02:17:56 +01:00
Daniele Varrazzo
05627ac0f9 Fix unicode mogrify test on python 2 2016-10-11 00:22:23 +01:00
Daniele Varrazzo
91d2158de7 Python source cleanup using flake8 2016-10-11 00:11:55 +01:00
Daniele Varrazzo
4458c9b4c9 Merge branch 'drop-libpq-pre-91' 2016-08-15 02:58:36 +01:00
Daniele Varrazzo
b3792c7f02 Mention dropping Pre 9.1 libpq support in NEWS file 2016-08-15 02:57:49 +01:00
Daniele Varrazzo
5ddc952dbb Dropped ifdef guards against obsolete libpq versions
One of them was actually wrong: lobject_type.c wouldn't have compiled
pre 8.3 (broken in 6e841a41, 2 years ago).
2016-08-15 02:55:44 +01:00
Daniele Varrazzo
3d4f6df0de Enforce dependency on libpq version >= 9.1
PGRES_COPY_BOTH was introduced in 9.1: we can ifdef the hell out of
pgpath, but we may as well bury the dead horses instead of beating
them.

They smell funny, too.
2016-08-15 02:55:43 +01:00
Daniele Varrazzo
b006190312 Merge branch 'drop-py25' 2016-08-15 02:51:10 +01:00
Daniele Varrazzo
47a312cf83 Mention dropping Py 2.5 support in NEWS file 2016-08-15 02:39:26 +01:00
Daniele Varrazzo
78649f8e90 Dropped use of b() "macro" and 2to3 fixer
Just use the b"" strings syntax supported from python 2.6.
2016-08-15 01:56:36 +01:00
Daniele Varrazzo
3b41c3a6f3 Stop compiling with Python 2.5 2016-08-15 01:06:42 +01:00
Daniele Varrazzo
1d950748af Merge branch 'replication-protocol' 2016-08-14 21:09:54 +01:00
Daniele Varrazzo
01c552baa3 Mention replication support in the NEWS file 2016-08-14 21:09:00 +01:00
Daniele Varrazzo
e0883f1967 Name the db in the replication test like the unit test one 2016-08-14 19:57:29 +01:00
Daniele Varrazzo
e5390fed98 Use inttypes.h definitions 2016-08-14 19:48:31 +01:00
Daniele Varrazzo
12ecb4b2ce Dropped import of postgres internal/c.h
Stops warning (caused by command line definition of PG_VERSION, so it
could have been avoided otherwise), but the file comment says:

    Note that the definitions here are not intended to be exposed to clients
    of the frontend interface libraries --- so we don't worry much about
    polluting the namespace with lots of stuff...

so it doesn't seem a good idea gulping it.
2016-08-14 19:36:48 +01:00
Daniele Varrazzo
e779fec5f9 Merge branch 'nul-terminator' 2016-08-07 02:51:27 +01:00
Daniele Varrazzo
478f43f0c8 Mention NULL characters guard in NEWS file
Fix #420.
2016-08-07 02:51:06 +01:00
Daniele Varrazzo
bd95269c69 Merge branch 'master' into nul-terminator 2016-08-07 02:49:13 +01:00
SpootDev
edd51aac25 spelling fix 2016-08-07 02:44:08 +01:00
Daniele Varrazzo
ab671146de Merge branch 'range-picklable' 2016-08-07 02:40:05 +01:00
Daniele Varrazzo
ec1e578e4b Report range picklable in NEWS file
Fix #462

Conflicts:
	NEWS
2016-08-07 02:39:26 +01:00
Jonathan Ross Rogers
cde19c4d59 Make Range pickleable 2016-08-07 02:38:52 +01:00
Daniele Varrazzo
86434548a7 Replication docs massaging, mostly formatting 2016-08-07 02:23:02 +01:00
Daniele Varrazzo
9a4f8f915f Reshuffling and indexing of replication docs 2016-08-07 02:07:16 +01:00
Daniele Varrazzo
2a4d6027a4 Merge branch 'master' into replication-protocol
Conflicts:
	tests/testconfig.py
2016-08-07 01:53:21 +01:00
Alexander Schrijver
03824a1dba Throw an exception when a NUL character is used as a parameter. 2016-07-18 22:56:55 +02:00
Daniele Varrazzo
90ee1ebba5 errorcodes map updated to PostgreSQL 9.5. 2016-07-01 20:14:30 +01:00
Daniele Varrazzo
7566af145b Merge branch 'conn-get-parameters' 2016-07-01 20:12:01 +01:00
Daniele Varrazzo
00de4052d1 Mention get_dsn_parameters() in news, improved docs metadata 2016-07-01 20:10:56 +01:00
Daniele Varrazzo
e41bff8ca4 Merge branch 'bug-424' 2016-07-01 19:28:02 +01:00
Daniele Varrazzo
80fd14463b Mention closing bug #424 in the news 2016-07-01 19:27:31 +01:00
Daniele Varrazzo
5bcaf11f9d Allow adapting bytes using QuotedString on Python 3 too
Close #365.
2016-07-01 19:14:00 +01:00
Daniele Varrazzo
70af49c0a2 Fixed encoding tests on Py3 2016-07-01 18:50:24 +01:00
Daniele Varrazzo
9c156d41bb Docs wrapping 2016-07-01 18:03:49 +01:00
Daniele Varrazzo
1442655d3c Merge branch 'qstring-writable-encoding' 2016-07-01 18:03:12 +01:00
Daniele Varrazzo
4a450b63c4 Don't hope to encode stuff in an arbitrary encoding
libpq's PQescapeString will use the same encoding it has seen before in
a connection (static_client_encoding).

So I think I'll leave this feature here for people who know what is
doing, but won't really document it as a feature: it can't really work
in a generic way (unless adding some disgusting hack like creating a
fake connection with the encoding we want to call PQescapeStringConn
instead of PQescapeString).
2016-07-01 18:02:20 +01:00
Daniele Varrazzo
2e8e61b8d4 Test moved to the right module, cleanup, but same problem 2016-07-01 18:01:16 +01:00
Daniele Varrazzo
bada1f1f8e Work in progress on writable encoding
Would help using adapt(unicode) to quote strings without a connection,
see ticket #331.

Currently in heisenbug state: if test_connection_wins_anyway and
test_encoding_default run (in this order), the latter fail because the
returned value is "'\xe8 '", with an extra space. Skipping the first
test, the second succeed.

The bad value is returned by the libpq:

    ql = PQescapeString(to+eq+1, from, len);

just returns len = 2 and an extra space in the string... meh.
2016-07-01 18:00:05 +01:00
Daniele Varrazzo
c29b5cd46a Fixed build on win32
Fix #422.
2016-07-01 02:24:49 +01:00
Daniele Varrazzo
7aedc61d41 Fixed segfault on repr() for uninitialized connections
Close #361.
2016-07-01 02:11:21 +01:00
Daniele Varrazzo
b7330283bc Wordsmithing on COPY commands
Address somehow issue #397.
2016-07-01 01:40:25 +01:00
Daniele Varrazzo
52753b23e8 Document that the libpq must be available at runtime
Fix issue #408.
2016-07-01 01:19:28 +01:00
Greg Ward
3ed2c54790 Fix scattered grammar/spelling errors in comments, debug output, etc. 2016-06-30 21:09:15 +01:00
Oleksandr Shulgin
d5443c65fd Fix TODOs in ReplicationMessage inline docs 2016-04-21 15:32:05 +02:00
Gabriel Kihlman
5ce00f8e5b Avoid a possible null deref, tz might be NULL.
Found by clang static analyzer.
2016-04-18 17:28:50 +02:00
Daniele Varrazzo
732ea90a4f Merge pull request #373 from nonZero/patch-1
Suggest installing psycopg2 in windows using pip
2016-03-10 12:25:23 +00:00
Daniele Varrazzo
4fa1b983e7 Merge pull request #415 from bmwiedemann/master
dont claim copyright for future years
2016-03-10 12:22:59 +00:00
Daniele Varrazzo
caa3e491f2 Merge pull request #416 from dargor/doc_typos
Typo.
2016-03-10 12:22:01 +00:00
Daniele Varrazzo
3033361883 Merge branch 'py35' 2016-03-10 12:14:11 +00:00
Daniele Varrazzo
4fb236e688 Start advertising Py 3.5 support 2016-03-10 12:13:57 +00:00
Daniele Varrazzo
65ec7e8bcb Fixed read() exception propagation in copy_from
Close issue #412.
2016-03-10 12:13:52 +00:00
Daniele Varrazzo
82ef9cfadd Merge branch 'msvc-2015-fix' 2016-03-10 12:12:40 +00:00
Daniele Varrazzo
48260c6406 Py 3.5 MSVC 2015 build fixed noted in news
Close issue #380.
2016-03-10 12:12:24 +00:00
Christian Ullrich
654eeec24c Work around late initialization in distutils._msvccompiler. 2016-03-10 12:12:19 +00:00
Daniele Varrazzo
1b7cebc41e Merge branch 'setuptools' 2016-03-10 12:11:29 +00:00
Daniele Varrazzo
006693421d Fixed 'make sdist' to work with setuptools 2016-03-10 12:10:51 +00:00
Daniele Varrazzo
2d91864977 setuptools in the news 2016-03-10 12:09:20 +00:00
Jason Erickson
22fe6e7aad Modify setup.py to support setuptools/wheel
To support creation of whl files for PyPI, setuptools need to be imported
instead of distutils.  Created try/except case to fall back to integrated
distutils if setuptools is not installed.
2016-03-10 12:09:15 +00:00
Daniele Varrazzo
8611d91b35 Fixed build on Python 2.5 2016-03-10 12:06:28 +00:00
Daniele Varrazzo
244f233e1c Fixed manifest trying to include Makefiles from build env 2016-03-10 12:05:57 +00:00
Daniele Varrazzo
eb687103b4 Skip null array test on Postgres versions not supporting it 2016-03-10 12:04:41 +00:00
Daniele Varrazzo
499366ba2d Merge branch 'patch-328' 2016-03-10 12:02:39 +00:00
Daniele Varrazzo
c13956dc10 Fixed compiler warnings about Py_ssize_t printf format 2016-03-10 12:02:23 +00:00
Jason Erickson
d0309333b7 Removed added Dprintf statements
Removed extra Dprintf statements added to trouble large objects
2016-03-10 12:02:06 +00:00
Jason Erickson
2cdc8d61a2 Fix Windows 64bit lobject support for very (>2GB) large objects
The type 'long' with Windows Visual C is 32bits in size for both 32bit and 64bit platforms.  Changed type of variables that could be > 2GB from long to Py_ssize_t.
2016-03-10 12:02:00 +00:00
Gabriel Linder
88d3d7fc7e Typo. 2016-03-09 21:51:02 +01:00
Bernhard M. Wiedemann
d829a75f2e dont claim copyright for future years
otherwise, when building from unchanged source in 2018,
it would claim Copyright 2018
which is not true

Being able to reproduce identical output from identical input
is important to Linux distributions
2016-03-09 16:33:54 +01:00
Oleksandr Shulgin
a7887fab07 Merge remote-tracking branch 'zalando/feature/replication-protocol' into feature/replication-protocol-c-connection-object 2016-03-08 18:56:58 +01:00
Oleksandr Shulgin
3f10b4dd31 Remove duplicated doc for make_dsn() 2016-03-08 18:52:29 +01:00
Oleksandr Shulgin
b21c8f7a4e Move replication-related imports to extras.py 2016-03-08 18:52:29 +01:00
Oleksandr Shulgin
2de2ed7c63 Remove some dead code 2016-03-08 18:52:29 +01:00
Oleksandr Shulgin
1d52f34e60 We don't need to expose cursor_init(), call tp_init() on the type instead. 2016-03-08 18:52:21 +01:00
Oleksandr Shulgin
da6e061ee8 Use python-defined make_dsn() for ReplicationConnection class 2016-03-08 18:52:21 +01:00
Oleksandr Shulgin
cb7032554e Merge branch 'master' into feature/replication-protocol-c-connection-object 2016-03-04 10:52:10 +01:00
Daniele Varrazzo
ab5d8f4190 Style the dsn arg in connect() as a normal optional parameter
Plus some more connect() docs wordsmithing.
2016-03-03 17:28:56 +00:00
Daniele Varrazzo
d43b74681f Merge branch 'make_dsn'
Close issue #363 instead of the proposed merge request.
2016-03-03 17:10:39 +00:00
Daniele Varrazzo
e33073576c Brag about make_dsn in the NEWS file 2016-03-03 17:09:15 +00:00
Daniele Varrazzo
c9fd828f8a Allow make_dsn to take no parameter
The behaviour of connect() is unchanged: either dsn or params must be
specified.
2016-03-03 17:09:15 +00:00
Daniele Varrazzo
7aab934ae5 Validate output result from make_dsn()
The output is not necessarily munged anyway: if no keyword is passed,
validate the input but return it untouched.
2016-03-03 17:09:15 +00:00
Daniele Varrazzo
7155d06cdc Test that the empty dsn is a valid make_dsn input 2016-03-03 17:09:15 +00:00
Daniele Varrazzo
6893295a87 Added docs about make_dsn
connect() docs updated to document the arguments merging.
2016-03-03 17:09:15 +00:00
Daniele Varrazzo
52087a79d9 Added test suite specific for make_dsn 2016-03-03 15:31:37 +00:00
Daniele Varrazzo
2c55a1bd53 Verify that the dsn is not manipulated by make_dsn if not necessary 2016-03-03 15:07:38 +00:00
Daniele Varrazzo
1c4523f0ac Implementation of make_dsn in Python
This is equivalent to what proposed in #363, but with a much simpler
implementation.
2016-03-03 04:33:59 +00:00
Daniele Varrazzo
d40f81865f Added parse_dsn() docstring 2016-03-03 03:25:47 +00:00
Daniele Varrazzo
01856333c4 Some order in the extensions doc
Classes, coroutine functions and extra functions grouped under separate
headings.
2016-03-03 03:21:59 +00:00
Federico Di Gregorio
3df2c6a2b7 Merge pull request #403 from kpinc/fix
Improve sentence.
2016-02-03 09:51:09 +01:00
Karl O. Pinc
3a54e83737 Improve sentence. 2016-02-02 12:48:16 -06:00
Federico Di Gregorio
b737757eac Merge pull request #375 from kwotuveang3k4bk/patch-1
Update psycopg1.py
2016-01-31 12:55:52 +01:00
Oleksandr Shulgin
5d33b39829 Fix error test for invalid START_REPLICATION command. 2016-01-21 15:56:27 +01:00
Oleksandr Shulgin
09a4bb70a1 Allow retrying start_replication after syntax or data error. 2016-01-05 12:31:57 +01:00
Daniele Varrazzo
452fd56e04 Merge branch 'bug-382' 2015-12-16 12:04:14 +00:00
Daniele Varrazzo
5fd0f6c4ee Fixed race condition on import in errorcodes.lookup
Fixes #382.
2015-12-16 12:03:10 +00:00
mrmilosz
0772d187e9 Return input tuple in cur.callproc, factor code to use PQescapeIdentifier in single place 2015-12-13 01:10:03 -05:00
Daniele Varrazzo
92109e4bba Correctly handle an empty error message from PQescapeIdentifier 2015-12-12 17:52:56 -05:00
Daniele Varrazzo
54e5349f53 Set an exception in case of PQescapeIdentifier error
Ifdeffed surface reduced.
2015-12-12 17:52:56 -05:00
Daniele Varrazzo
4003b7c977 Fixed callproc return value refcount
Temporary anyway: I want to go back returning a list (or dict).
2015-12-12 17:51:45 -05:00
Daniele Varrazzo
021f6d22ad More straightforward param refcount handling in callproc 2015-12-12 17:51:45 -05:00
Daniele Varrazzo
7302f348bc Added test with objects without length as callproc param 2015-12-12 17:51:08 -05:00
Daniele Varrazzo
d297976d6d Raise TypeError if the dict in callproc param contains non-strings
Check-and-conversion chain fixed and simplified. 'spname' was a
reference leak.
2015-12-12 17:51:08 -05:00
Daniele Varrazzo
a3eed9c9f5 Added guard on params with no length on callproc 2015-12-12 17:51:08 -05:00
Daniele Varrazzo
04ce14b251 Avoid clobbering the exceptions raised by other calls 2015-12-12 17:49:59 -05:00
mrmilosz
c205f140a0 callproc: tests, docs, and comment/error-reporting touchups. 2015-12-12 17:49:59 -05:00
mrmilosz
37a80e9de8 callproc: checking for libpq 9.0+ on compile. yes: use PQescapeIdentifier. no: error 2015-12-12 17:49:44 -05:00
mrmilosz
3948e909e4 callproc: now more compliant with local coding standards. 2015-12-12 17:49:44 -05:00
mrmilosz
e9bb4a86f9 cursor.callproc: added a missing memory check 2015-12-12 17:49:25 -05:00
mrmilosz
31c95c0922 callproc using a dict now uses connection encoding and sanitizes parameter names 2015-12-12 17:49:25 -05:00
mrmilosz
1205bf9c2b callproc using a dict now has a type check to make sure the keys are strings. 2015-12-12 17:49:25 -05:00
mrmilosz
23d279945f cursor.callproc now also accepts dict for PostgreSQL 9+ "named notation" 2015-12-12 17:49:25 -05:00
Jan Janßen
b3def74002 Update psycopg1.py 2015-11-10 17:02:59 +01:00
Udi Oron
cf83470891 Suggest installing psycopg2 in windows using pip
pip is becoming the standard method for installing python packages, and now binary wheels are a better and easier option for users:
https://github.com/psycopg/psycopg2/issues/368
2015-11-10 00:35:02 +02:00
Oleksandr Shulgin
051e6d1364 Add skip_before_libpq for test_get_dsn_parameters 2015-10-30 13:02:45 +01:00
Oleksandr Shulgin
e61db578cf Add dbname=replication for physical replication type. 2015-10-30 13:00:55 +01:00
Oleksandr Shulgin
602fefcae3 Fix typo in a new test name 2015-10-30 11:38:28 +01:00
Oleksandr Shulgin
a4cbb088fe Add connection.get_dsn_parameters() 2015-10-30 11:10:41 +01:00
Oleksandr Shulgin
fbcf99ad07 Move replication connection to C level. 2015-10-27 18:21:24 +01:00
Oleksandr Shulgin
433fb957cb Merge branch 'feature/connect2' into feature/replication-protocol 2015-10-27 17:37:18 +01:00
Oleksandr Shulgin
7aba8b3ed0 Rework psycopg2.connect() interface. 2015-10-27 17:35:57 +01:00
Oleksandr Shulgin
4b9a6f48f3 Merge branch 'master' into feature/replication-protocol 2015-10-27 12:16:41 +01:00
Oleksandr Shulgin
fe4cb0d493 Fix stale Dprintfs in pqpath.c referring to 'status' 2015-10-26 17:40:39 +01:00
Oleksandr Shulgin
8b79bf43ac Drop ReplicationCursor.flush_feedback(), rectify pq_*_replication_*() interface. 2015-10-23 18:30:18 +02:00
Oleksandr Shulgin
dd6bcbd04f Improve async replication example. 2015-10-23 17:51:03 +02:00
Oleksandr Shulgin
e69dafbecc Move the decode parameter to start_replication().
It makes more sense this way, because otherwise it must be passed to every call
of `read_message()`.
2015-10-23 11:31:55 +02:00
Oleksandr Shulgin
76c7f4a0b5 Use direct call to consume() callable in pq_copy_both() 2015-10-22 16:17:08 +02:00
Oleksandr Shulgin
22cbfb26d6 Actually add replication tests to the test suite. 2015-10-20 13:05:43 +02:00
Oleksandr Shulgin
089e745af6 Fix cursor_init() declaration for use in replication_cursor_type.c 2015-10-20 12:55:43 +02:00
Oleksandr Shulgin
b3f8e9adb5 Fix send_time printf format in replmsg_repr(). 2015-10-20 12:54:22 +02:00
Oleksandr Shulgin
23abe4f501 Add quick start to the replication doc, minor doc fixes. 2015-10-20 12:36:13 +02:00
Oleksandr Shulgin
0bb81fc848 Properly subclass ReplicationCursor on C level. 2015-10-19 20:00:39 +02:00
Oleksandr Shulgin
7aea2cef6e Improve async replication test. 2015-10-19 17:02:18 +02:00
Oleksandr Shulgin
4ab7cf0157 Replace stop_replication with requirement for an exception. 2015-10-19 15:42:42 +02:00
Oleksandr Shulgin
0435320f34 Fix PSYCOPG2_TEST_REPL_DSN handling. 2015-10-16 16:36:03 +02:00
Oleksandr Shulgin
cf4f2411bf Fix async replication and test. 2015-10-15 18:01:43 +02:00
Oleksandr Shulgin
d14fea31a3 Use quote_ident from psycopg2.extensions 2015-10-15 12:56:21 +02:00
Oleksandr Shulgin
8e518d4954 Merge branch 'master' into feature/replication-protocol 2015-10-15 12:27:43 +02:00
Daniele Varrazzo
6763578cc0 Merge branch 'extensions-quote-ident' 2015-10-15 11:08:34 +01:00
Daniele Varrazzo
109409bc95 Mention quote_ident() in NEWS file 2015-10-15 11:06:44 +01:00
Oleksandr Shulgin
89bb6b0711 Proper unicode handling in quote_ident. 2015-10-15 11:52:18 +02:00
Oleksandr Shulgin
9ab38ee8c5 Add psyco_curs_datetime_init 2015-10-14 18:39:48 +02:00
Oleksandr Shulgin
28a1a00d1c Remove commented copy_both code in pqfetch. 2015-10-14 18:39:20 +02:00
Oleksandr Shulgin
e3097ec956 Fix select/timeout indication in async replication example 2015-10-14 17:42:53 +02:00
Oleksandr Shulgin
822d671e8b Clear repl_stop flag after the consume loop. 2015-10-14 17:40:39 +02:00
Oleksandr Shulgin
e05b4fd267 Add checks on replication state, have to have a separate check for consume loop. 2015-10-14 17:36:50 +02:00
Oleksandr Shulgin
9295bce154 Add psycopg2.extensions.quote_ident. 2015-10-14 17:00:25 +02:00
Oleksandr Shulgin
a0b42a12ff Update stop_repl, require replication consumer to be a callable. 2015-10-14 15:15:07 +02:00
Oleksandr Shulgin
fea2260fc5 Fix stop_replication: always raise outside the loop. 2015-10-14 12:50:08 +02:00
Oleksandr Shulgin
54079072db Fix ReplicationTest: no NotSupportedError now. 2015-10-14 12:43:26 +02:00
Oleksandr Shulgin
6ad299945f Remove IDENTIFY_SYSTEM wrapper method (it can't work with async anyway). 2015-10-13 18:05:33 +02:00
Oleksandr Shulgin
ea2b87eade Fix create_replication_slot doc signature 2015-10-13 11:01:13 +02:00
Oleksandr Shulgin
0233620c26 Rework replication connection/cursor classes 2015-10-01 19:33:27 +02:00
Oleksandr Shulgin
cac83da5db Use parse_dsn in ReplicationConnectionBase 2015-10-01 19:33:24 +02:00
Oleksandr Shulgin
95ee218c6d Update replication connection/cursor interface and docs. 2015-10-01 19:33:20 +02:00
Oleksandr Shulgin
937a7a9024 Cleanup start replication wrt. slot type a bit. 2015-10-01 19:33:16 +02:00
Oleksandr Shulgin
f872a2aabb Remove typedef for uint32, include internal/c.h 2015-10-01 19:33:12 +02:00
Oleksandr Shulgin
862eda10c2 Merge remote-tracking branch 'origin/master' into repl 2015-10-01 19:29:17 +02:00
Daniele Varrazzo
c73c1c5771 Decref the ssl module after importing 2015-10-01 17:04:29 +01:00
Daniele Varrazzo
f635547ec6 The wait_select callback can cancel a query using Ctrl-C
Fixes #333.
2015-10-01 15:26:13 +01:00
Daniele Varrazzo
9e6c3322d8 Fixed PersistentConnectionPool on Python 3
Fixes ticket #348.
2015-10-01 14:44:14 +01:00
ClodoaldoPinto
98f2aad4ba Typo correction 2015-10-01 14:31:31 +01:00
Daniele Varrazzo
ade7dba27c MSVC 2015 compiler support added to news file 2015-10-01 14:30:17 +01:00
Daniele Varrazzo
7e94ce1f14 Drop spurious notices in test
Getting some "rehashing catalog" debug messages in PG 9.4
2015-10-01 13:31:13 +01:00
Daniele Varrazzo
14246a5689 Merge branch 'parse-dsn' 2015-10-01 13:29:10 +01:00
Daniele Varrazzo
58918801d6 Added parse_dsn() to news file 2015-10-01 13:26:11 +01:00
Daniele Varrazzo
5afeee3613 Added unicode support to parse_dsn
Also added support for the argument as a keyword.
2015-10-01 13:20:11 +01:00
Daniele Varrazzo
71d96293ab Fixed parse_dsn tests on Python 3
On Python 3 there is no Exception.message attribute.
2015-10-01 12:03:00 +01:00
Daniele Varrazzo
d3bbd19ccb Separate parse_dsn test in a test case of their own 2015-10-01 11:52:42 +01:00
Daniele Varrazzo
d1af12187c Merge branch 'master' into parse-dsn 2015-10-01 11:39:51 +01:00
Daniele Varrazzo
6803341f21 Report NotSupportedError for PGRES_COPY_BOTH and PGRES_SINGLE_TUPLE
Fixes #352.
2015-09-30 12:28:07 +01:00
Daniele Varrazzo
0e3f5214c5 Report the server response status on errors with no message
Suggested by Craig Ringer in pull request #353, should also give more
information for other cases we were reported on flaky servers (AWS,
digital ocean...), see bug #281.
2015-09-30 12:28:07 +01:00
Federico Di Gregorio
4e92322d74 Merge pull request #350 from Photonios/master
Fixes for MSVC 2015 (Python 3.5)
2015-09-23 11:50:25 +02:00
Photonios
71925fcc00 Fix for MSVC 2015: round has been added to this version 2015-09-22 18:26:14 +02:00
Photonios
ac25ba0a3f Fix for MSVC 2015: isnan is supported in this version 2015-09-22 18:25:53 +02:00
Oleksandr Shulgin
26fe1f230f Fix use of PQconsumeInput() in pq_read_replication_message()
The libpq's PQconsumeInput() returns 0 in case of an error only, but
we need to know if it was able to actually read something.  Work
around this by setting an internal flag before retry.
2015-07-07 19:04:32 +02:00
Oleksandr Shulgin
eac16d048a Fix missing GC flag in ReplicationMessage type 2015-07-03 15:44:45 +02:00
Oleksandr Shulgin
06f18237f7 Fix missing free in replmsg_dealloc 2015-07-03 11:40:00 +02:00
Oleksandr Shulgin
9c1f2acf3e Check return value of PQsocket
When connection is closed by the server, we might get -1 there.
2015-07-02 14:39:51 +02:00
Oleksandr Shulgin
dab41c699a Fix PQconsumeInput usage.
Only call when no data is available in the internal buffer.
2015-07-02 14:34:09 +02:00
Oleksandr Shulgin
9386653d72 Update docs on ReplicationCursor 2015-07-01 14:08:32 +02:00
Oleksandr Shulgin
0d731aa12e Comment on special handling of PGRES_COPY_BOTH 2015-06-30 16:34:17 +02:00
Oleksandr Shulgin
318706f28c Update docs for Replication protocol 2015-06-30 16:17:31 +02:00
Oleksandr Shulgin
058db56430 Merge remote-tracking branch 'zalando/feature/replication-protocol' into feature/replication-protocol 2015-06-30 10:40:52 +02:00
Oleksandr Shulgin
61e52ce879 Rework replication protocol
This change exposes lower level functions for operating the
(logical) replication protocol, while keeping the high-level
start_replication function that does all the job for you in
case of a synchronous connection.

A number of other changes and fixes are put into this commit.
2015-06-30 10:38:18 +02:00
Oleksandr Shulgin
e3c3a2c19e Merge branch 'master' into feature/replication-message-object
Conflicts:
	lib/extensions.py
2015-06-30 10:30:32 +02:00
Oleksandr Shulgin
9ed90b1216 Refer cursor from ReplicationMessage object. At the same time, for the sync use LSN instead of msg reference in cursor. 2015-06-11 14:52:01 +02:00
Oleksandr Shulgin
35a3262fe3 Expose ReplicationMessage type in extras 2015-06-11 12:20:52 +02:00
Oleksandr Shulgin
9fc5bf4436 Add handling of send_time field in replmsg 2015-06-10 18:21:06 +02:00
Oleksandr Shulgin
1ac385d1fb Fix logical decoding plugin options adaptation on python3 2015-06-10 13:39:35 +02:00
Oleksandr Shulgin
453830f80c Add ReplicationMessage object 2015-06-05 17:44:09 +02:00
Oleksandr Shulgin
f7b84ce843 Add {libpq,win32}_support.* to the .cproj file 2015-06-04 11:01:09 +02:00
Oleksandr Shulgin
50df864f8c Add timersub for Win32. Fix gettimeofday on MinGW. 2015-06-04 11:00:08 +02:00
Oleksandr Shulgin
f14521f8cb Add libpq_support.c and win32_support.c
Move libpq-specific code for streaming replication support into a
separate file.  Also provide gettimeofday() on Win32, implementation
copied from Postgres core.
2015-06-03 14:10:20 +02:00
Daniele Varrazzo
925fdf5731 Fixed doc about libpq version availability 2015-06-02 17:11:09 +01:00
btubbs
06b4b1de94 Notify example should pop the oldest message in conn.notifies, not the newest. 2015-06-02 17:07:10 +01:00
Daniele Varrazzo
6002c524d6 Merge branch 'notice-lists-replaceable' 2015-06-02 17:04:25 +01:00
Daniele Varrazzo
1f330e9cac Allow connection.notices and notifies to be replaced.
Close #326
2015-06-02 17:02:04 +01:00
Oleksandr Shulgin
44b705f88f Improve identify_system: don't hardcode column names 2015-06-02 16:52:48 +02:00
Daniele Varrazzo
2ad82b973b Pending notice list converted into a forward list
This allows inserting the elements in order without using list.insert().
2015-06-02 14:25:46 +01:00
Daniele Varrazzo
b326a27774 Dropped unneeded constness on the notice message
That's a strdup result, we 0wn it.
2015-06-02 14:24:48 +01:00
Daniele Varrazzo
0a7261268b Dropped unused notice_filter connection member 2015-06-02 13:11:46 +01:00
Oleksandr Shulgin
d6041271bc Separate parse_dsn test on URI, for libpq >= 9.2 2015-06-02 14:02:29 +02:00
Pete Hollobon
5712f30169 Change "non desiderable" to "undesirable" in docs
"desiderable" is considered obsolete
2015-06-02 13:00:25 +01:00
Daniele Varrazzo
7e5715617e Merge branch 'adapt-list-of-none' 2015-06-02 12:49:15 +01:00
Daniele Varrazzo
b0058c0cc8 Fixed adaptation of lists of None
Note: lists of lists of None are not supported yet.
2015-06-02 12:48:24 +01:00
Oleksandr Shulgin
cc08e14162 Merge branch 'master' into feature/parse-dsn
Conflicts:
	lib/extensions.py
2015-06-02 12:42:03 +02:00
Daniele Varrazzo
8d4ac25b56 Merge branch 'libpq-version' 2015-06-02 11:20:28 +01:00
Daniele Varrazzo
c2955fb8fc Version function/constant docs improved 2015-06-02 11:20:02 +01:00
Daniele Varrazzo
5a21da43ee Mention libpq version inspection in news file 2015-06-02 11:19:55 +01:00
Daniele Varrazzo
73d17e3c5e Dropped PG_VERSION_HEX constant
At PostgreSQL 10.0 it would have become awkward.
2015-06-02 10:54:08 +01:00
Oleksandr Shulgin
80da76d43f Get rid of postgres internal includes; check for Win32 for htonl() 2015-06-02 11:42:56 +02:00
Oleksandr Shulgin
ffd98a82c0 Add test for libpq_version 2015-06-02 11:12:16 +02:00
Oleksandr Shulgin
4bb6f9cef2 Add libpq version discovery 2015-06-01 18:05:11 +02:00
Oleksandr Shulgin
3200cd77bf One more parse_dsn test for unquoted space 2015-06-01 15:18:03 +02:00
Oleksandr Shulgin
6a2f21aa14 Move parse_dsn to extensions, add tests 2015-06-01 15:11:12 +02:00
Oleksandr Shulgin
e32e1b834e Add support for streaming replication protocol
Introduce ReplicationConnection and ReplicationCursor classes, that
incapsulate initiation of special type of PostgreSQL connection and
handling of special replication commands only available in this special
connection mode.

The handling of stream of replication data from the server is modelled
largely after the existing support for "COPY table TO file" command and
pg_recvlogical tool supplied with PostgreSQL (though, it can also be
used for physical replication.)
2015-06-01 11:45:04 +02:00
Oleksandr Shulgin
6c57e4a648 Add parse_dsn module function
Calls PQconninfoParse to parse the dsn into a list of keyword and value
structs, then constructs a dictionary from that.  Can be useful when one
needs to alter some part of the the connection string reliably, but
doesn't want to get into all the details of parsing a dsn string:
quoting, URL format, etc.
2015-06-01 10:16:07 +02:00
Daniele Varrazzo
d66165232e OpenSSL deadlock fix noted in NEWSfile 2015-05-03 12:27:37 +01:00
Jan Urbański
a59704cf93 Make sure libcrypto threadsafety callbacks are properly set up
Multithreaded programs using libcrypto (part of OpenSSL) need to set up
callbacks to ensure safe execution. Both Python and libpq set up those
callbacks, which might lead to a conflict.

To avoid leaving dangling function pointers when being unloaded, libpq sets up
and removes the callbacks every time a SSL connection it opened and closed. If
another Python thread is performing unrelated SSL operations (like connecting
to a HTTPS server), this might lead to deadlocks, as described in
http://www.postgresql.org/message-id/871tlzrlkq.fsf@wulczer.org

Even if the problem will be remediated in libpq, it's still useful to have it
fixed in psycopg2. The solution is to use Python's own libcrypto callbacks and
completely disable handling them in libpq.
2015-05-03 12:27:36 +01:00
Daniele Varrazzo
1b7e3c6da4 Improve docs about connection's with only closing the transaction 2015-05-03 12:01:06 +01:00
Daniele Varrazzo
ad3e91a56f Unlock the connection after PQflush error
Apparently this has never happened... anyway the code path was wrong.

Fixes #294.
2015-05-03 12:01:05 +01:00
Daniele Varrazzo
4078b89521 Added makefile target to upload docs 2015-05-03 10:30:33 +01:00
Daniele Varrazzo
1d006ccbe9 Added note about table names to be escaped in copy_*() methods. 2015-05-03 10:30:28 +01:00
Hyunjun Kim
4eee1207f9 Fix several typos 2015-05-03 10:30:21 +01:00
Daniele Varrazzo
2cab752443 Fix to MinTimeLoggingCursor.callproc() noted in NEWSfile 2015-05-03 10:30:16 +01:00
andrew deryabin
41639c7610 Fixed MinTimeLoggingCursor.callproc() 2015-05-03 10:30:11 +01:00
Daniele Varrazzo
f27ca25d2e Wordsmith on connection.set_session()
Fixes #310.
2015-05-03 10:30:05 +01:00
Daniele Varrazzo
70fbc8bf1f Fixed connection.poll() docstring
Fixes #312
2015-05-03 10:29:57 +01:00
Daniele Varrazzo
0b523927bc Docs build process and docs cleaned up 2015-04-28 09:32:58 +01:00
Daniele Varrazzo
1e8be5bd09 Added missing files needed to build the docs
Fixes #291
2015-04-28 08:38:57 +01:00
Daniele Varrazzo
c62c292053 Bump to next dev version number for the master branch 2015-04-28 08:38:41 +01:00
Daniele Varrazzo
5efe7131ff Version bumped for release 2.6 2015-02-09 09:43:55 +00:00
Daniele Varrazzo
6d63973e08 More portable way to establish Python 32/64 build 2015-02-08 22:52:50 +00:00
Daniele Varrazzo
569fd0975b Python 3.1 bytes.decode() doesn't support keyword arguments
Sucker.
2015-02-08 19:43:09 +00:00
Daniele Varrazzo
296caa4556 More tests tweaks
Named cursors on old server versions have a different prefetch behaviour.
This has hidden me the supported range of the 24:00 time format.
Let's have another go at full testing...
2015-02-08 12:51:36 +00:00
Daniele Varrazzo
7ea56b112e Make Column picklable on Python >= 3.3
Also expose the type from the extensions module, not from the main
module.
2015-02-08 11:27:10 +00:00
Daniele Varrazzo
6177823811 Don't test date 24:00 before PG 8.4 2015-02-08 10:30:48 +00:00
Daniele Varrazzo
2a2f306f7b Added NEWS note about picklable cursor.desciption 2015-02-08 02:32:47 +00:00
Owen Raccuglia
5af5fb4cc6 Allow pickling of cursor.description
This is for people using dtuple.py; a dtuple.DatabaseTuple instance
keeps a reference to cursor.description, which is not picklable because
psycopg2 doesn't export the Column namedtuple it uses.

This commit exports the Column namedtuple, and includes a test to verify
the pickle/unpickle works after exporting Column.
2015-02-08 02:31:33 +00:00
Daniele Varrazzo
54ebf90fc6 Document that LO64 is only available on Py 64 builds 2015-02-08 02:21:22 +00:00
Daniele Varrazzo
f15e9d0cc8 Fixed link in NEWS entry 2015-02-08 02:14:00 +00:00
Daniele Varrazzo
e490e3bfa3 Accept overflow errors testing for LO64 funcs
It is raised on 32 bits by PyArg_ParseTuple. We may work around on
truncate (maybe parsing a py_ssize_t) but we would have the same problem
on seek as the offset is signed.
2015-02-08 02:04:41 +00:00
Daniele Varrazzo
7ce7fef322 Propagate read error messages in COPY FROM
Fix ticket #270.
2015-02-08 01:42:21 +00:00
Daniele Varrazzo
d3c1ad5945 Convert Postgres time 24:00 into 00:00
Fix ticket #278.
2015-02-08 00:41:50 +00:00
Daniele Varrazzo
2332f2c99e Merge branch 'timetz' 2014-12-25 15:09:15 +01:00
Daniele Varrazzo
b5ac992944 Merge branch 'lo64' 2014-12-25 15:08:02 +01:00
Daniele Varrazzo
7139187381 Large object 64 bit API quoted in news file 2014-12-25 15:07:34 +01:00
Daniele Varrazzo
a338da9c19 Fixed typo in tests 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
c008f9d1ce Added documentation about the lo64 support 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
bc5e2aeead Keep into account psycopg build in lo64 tests 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
2f862972c9 Guard against overflows when using the lo32 api
If psycopg supports lo64 but the server doesn't the user may pass values
that would overflow the api range, resulting in:

    lo.seek((2<<30))
    *** OperationalError: ERROR:  invalid seek offset: -2147483648

Also improved the error messages and guard against INT_MIN for negative
seek offsets.
2014-12-25 15:06:18 +01:00
Daniele Varrazzo
79df47a146 Fixed mismatched types in debug print 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
44219bf366 Don't try and compile lo64 support on 32 bits Python
We can't fit more than 31 bits in a long anyway.
2014-12-25 15:06:18 +01:00
Daniele Varrazzo
b2327b0fc7 Add the flag 'lo64' to the version if psycopg supports the lo_*64 api 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
0205d6ca2e Use ifdef instead of if to check LO64 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
91eabf5fcb Fixed check for PG version
It would have failed in PostgreSQL 10.0.
2014-12-25 15:06:18 +01:00
Blake Rouse
e5bbde9554 Check server_version before using lo_*64 functions. If less tahn 9.3 old none 64bit functions will be use. 2014-12-25 15:06:18 +01:00
Blake Rouse
cd67d3d2fe Modify truncate to use lo_truncate64. Use HAVE_LO64 define to use new lo_*64 methods. Check size of offset and length for versions without LO64. 2014-12-25 15:06:18 +01:00
Blake Rouse
e13ec67da3 Use lseek64 and ltell64 to support large object greater than 2gb in size. 2014-12-25 15:06:18 +01:00
Daniele Varrazzo
6bccb05c90 timetz adaptation documented 2014-12-25 14:57:31 +01:00
Federico Di Gregorio
85ba098cd8 Merge pull request #273 from eriklee/master
Correct exausted -> exhausted typo in exception
2014-11-17 22:36:47 +01:00
Erik Lee
e9f54a2d6e Correct exausted -> exhausted typo 2014-11-17 17:01:00 +00:00
Federico Di Gregorio
096e0729d5 Merge pull request #272 from yoloseem/timetz
Cast time into timetz when the tzinfo field is set.
2014-11-13 10:07:02 +01:00
Hyunjun Kim
4dbda02145 Cast time into timetz when the tzinfo field is set. 2014-11-13 17:32:06 +09:00
Federico Di Gregorio
0d553269d5 Merge pull request #271 from tokheim/master
Correction to type adaption example

It is OK for an adapted object to return the escaped string on 
__str__ calls but getquoted() is the canonical method.
2014-11-03 21:21:10 +01:00
Asmund Tokheim
ab4afd0e2f Correction to type adaption example, making it more transparent 2014-11-02 14:15:51 +01:00
Daniele Varrazzo
1b48033345 Don't try to close the server cursor in error state
`close()` is implicitly called by `__exit__()`, so an exit on error
would run a query on a inerr connection, causing another exception
hiding the original one. The fix is on `close()`, not on `__exit__()`,
because the semantic of the latter is simply to call the former.

Closes #262.
2014-09-16 06:57:34 +01:00
Daniele Varrazzo
48a32b766b In 2010 I couldn't speak English 2014-09-16 06:57:34 +01:00
Tomer Chachamu
6de7315210 Fix typo in docs 2014-09-01 16:29:38 +01:00
Daniele Varrazzo
b4d38c455c Don't need to build the env for a sdist
After 2.5 we are not releasing the html docs in the sdist anymore.
2014-09-01 16:29:38 +01:00
Daniele Varrazzo
7faa06ce0b Added scripts to release and upload docs 2014-09-01 16:29:38 +01:00
Daniele Varrazzo
9fdfa86200 Release notes cleanup before releasing 2.4.5 2014-08-31 03:06:50 +01:00
Daniele Varrazzo
6210af2763 Fixed excessively strict notices test
Failing with PG 9.4 because it generates other debug messages during the
test run (rehashing catalog cache).
2014-08-31 03:06:33 +01:00
Daniele Varrazzo
8e06a51884 Added plural version of the tickets role 2014-08-31 03:05:03 +01:00
Daniele Varrazzo
7d81c48849 Point tickets to GitHub instead of Lighthouse
Keep into account the numbers reshuffling: Lighthouse bugs with a number
matching a GitHub merge request are shifted ahead.
2014-08-31 03:05:03 +01:00
Daniele Varrazzo
37d80f2c03 Use the readme as PyPI desctiption 2014-08-31 02:59:49 +01:00
Daniele Varrazzo
6705e4051d Dropped creation of errcodes with missing spec field
On further inspection these names are just aliases for values already
defined: we don't need the duplication.
2014-08-28 02:17:57 +01:00
Daniele Varrazzo
ccc30e1877 Clear adapters in test to maintain reference count 2014-08-28 02:17:54 +01:00
Daniele Varrazzo
2d601ef157 Fixed memory leak with large objects
Deallocating closed large objects failed to decrement the connection
refcount. The fact the lobject is closed doesn't matter for refcount.
Issue detected by the always useful scripts/refcounter.py

With an extra bit of unrequested whitespace love.
2014-08-28 02:17:52 +01:00
Daniele Varrazzo
ea54aa77ed Added test to verify _psycopg can be imported 2014-08-28 02:17:49 +01:00
Daniele Varrazzo
54d904138d Don't import psycopg2.tz into the C extension
This makes possible to import _psycopg directly, after adding the
package directory to the pythonpath. This enables hacks such as:

    sys.path.insert(0, '/path/to/psycopg2')
    import _psycopg
    sys.modules['psycopg2._psycopg'] = _psycopg
    sys.path.pop(0)

which can work around e.g. the problem of #201, freeze that cannot
freeze psycopg2. Well, freeze cannot freeze it because it's just not
designed to deal with C extensions. At least now the frozen application
can hack the pythonpath and work around the limitation by importing
_psycopg as above and then doing the rest of the imports normally.

Keeping long-lived references to python objects is bad anyway: the
tz module couldn't be reloaded before.
2014-08-28 02:17:46 +01:00
Daniele Varrazzo
df9fbc515d Direct link to the install docs in the readme 2014-08-24 23:33:14 +01:00
Daniele Varrazzo
f7ee006bef Use virtualenv as build environment for the docs 2014-08-24 23:11:07 +01:00
Daniele Varrazzo
4a4e0d8f9a Self-updating copyright year in docs 2014-08-24 23:07:22 +01:00
Daniele Varrazzo
c1da93a7b2 Document we known 9.4 errorcodes 2014-08-24 22:11:21 +01:00
Daniele Varrazzo
b8b15637aa Take the PYTHONPATH into account when building the docs 2014-08-24 22:11:02 +01:00
Daniele Varrazzo
2ad67ee56e Move the extras module up in the docs
It is more interesting than `tz` and `pool`.
2014-08-24 22:10:24 +01:00
Daniele Varrazzo
843de765a1 Fixed doc example about Error attributes
Catch the Error, not everything!

Also, whitespaces.
2014-08-24 22:08:33 +01:00
Daniele Varrazzo
afdb7422fb Merge branch 'clean-text-files' 2014-08-24 02:06:27 +01:00
Daniele Varrazzo
c0e94ad01f Dropped outdated HACKING file 2014-08-24 02:06:09 +01:00
Daniele Varrazzo
2be26804d3 Dropped content from the INSTALL file
The docs have it right.
2014-08-24 02:06:09 +01:00
Daniele Varrazzo
d8bbaf0481 Added info about running the test suite in the docs
They were in the INSTALL file, which is quite out-of-date now.
Also fixed a couple of other things.
2014-08-24 02:06:09 +01:00
Daniele Varrazzo
353b36c657 Readme cleaned up and converted to reST
Dropped outdated info and references to the INSTALL, which is less
up-to-date than the docs.

Converted to reST to have it prettier on GitHub.
2014-08-24 02:06:09 +01:00
Daniele Varrazzo
0ea7798122 Merge branch 'drop-flags' 2014-08-24 02:05:23 +01:00
Daniele Varrazzo
1d729ab40e Dropped HAVE_PQFREEMEM flag
It was necessary before PG 7.4, in versions which have long been unsupported.
2014-08-24 01:43:12 +01:00
Daniele Varrazzo
68a4308c3d Dropped PSYCOPG_NEW_BOOLEAN flag
Introduced in 2.0 beta 8, 2006 A.D. Went absolutely untouched in 8 years
of refactoring, when Python 2.5 and PostgreSQL 8.1 roamed the earth.

I would say it has stood the test of the time.
2014-08-24 01:25:02 +01:00
Daniele Varrazzo
6e841a41e6 Dropped PSYCOPG_EXTENSIONS flag
Building without extensions has been long broken and nobody really cares
about a pure-DBAPI implementation (which could be created using a wrapper
instead).
2014-08-23 19:30:48 +01:00
Daniele Varrazzo
6a5f778361 Merge branch 'withhold-transactions' 2014-08-21 05:55:11 +01:00
Daniele Varrazzo
d20c03310d Document WITH HOLD corrections. 2014-08-21 05:53:07 +01:00
Alexey Borzenkov
13b0852619 Allow using named with hold cursors in autocommit 2014-08-21 05:35:11 +01:00
Daniele Varrazzo
c81522079e Added test to verify withhold cursors work in autocommit 2014-08-21 05:35:11 +01:00
Alexey Borzenkov
478e66f761 No implicit transaction on named cursor close
Also, don't start an implicit transaction when fetching with
named with hold cursor, since it already returns results
from a previously committed transaction.
2014-08-21 05:35:10 +01:00
Daniele Varrazzo
283a422b4d Added test to verify withhold transaction behaviour
A withhold cursor can read its data when the transaction is closed, so
it shouldn't start a new one upon movement/close.
2014-08-21 05:35:10 +01:00
Daniele Varrazzo
a2b01cdf42 Dropped simple type wrapper functions
These functions don't need to exist: exposing the type in the module is
enough. It is actually better as one may use isinstance and such.
2014-08-15 02:54:31 +01:00
Daniele Varrazzo
1b322a9b19 Fixed segfault in List function
This function is never called: it segfaults 100%. To be removed.
2014-08-15 02:54:25 +01:00
Daniele Varrazzo
95165cef7d Dropped almost-no-op customized objects repr()
The default repr is enough: it prints <TypeName at 0xADDR> instead of
<TypeName object at 0xADDR>.

The only people being hurt by this change are the ones using doctests:
they deserve it.
2014-08-15 02:54:10 +01:00
Daniele Varrazzo
669e787919 Name the types after the module they are exposed from 2014-08-15 01:47:19 +01:00
Daniele Varrazzo
31d07e5029 Scrape PostgreSQL 9.4 error codes table too
No new error code found as of 9.4 beta2.
2014-08-13 02:44:59 +01:00
Daniele Varrazzo
41a083cec3 Convert pool arguments to int
Failing to do so may cause dangerous misbehaviours such as an unbounded
pool (because of lame comparison operators in Python 2).

Fix ticket #220.
2014-08-13 02:39:16 +01:00
Daniele Varrazzo
c475a0db95 Document PostgreSQL 9.4 as supported
Actually there is a test failing in the test suite in PG 9.4beta2, but
it's probably because the default logging level is to DEBUG. Will wait
for the final release to check if the test is to be fixed. All other
tests pass no problem.
2014-08-13 02:09:04 +01:00
Daniele Varrazzo
0b95194f74 Merge branch 'jsonb' 2014-08-13 02:03:11 +01:00
Daniele Varrazzo
e225aad042 Habemus jsonb 2014-08-13 02:02:06 +01:00
Daniele Varrazzo
f40ad93a37 Added jsonb docs 2014-08-13 02:02:04 +01:00
Daniele Varrazzo
9d547469b8 Add register_default_jsonb() and register the type 2014-08-13 02:02:01 +01:00
Daniele Varrazzo
6bca443e37 Added name param to register_json() 2014-08-13 02:01:55 +01:00
Daniele Varrazzo
634fc004fb Added wishful test suite for jsonb type 2014-08-13 02:01:51 +01:00
Daniele Varrazzo
44281d6692 Fix supported Py/PG versions in docs 2014-08-04 22:39:52 +01:00
Daniele Varrazzo
6d6fd9acf7 Parse errocodes for PG 9.3 too
There is no new errcode defined so no need to release this as a change,
only change the docs.
2014-07-31 13:35:04 +01:00
Daniele Varrazzo
40dca9924d Add a few missing errcodes
They are used in the code but not defined in the SGML docs so the script
failed to parse them.
2014-07-31 13:34:53 +01:00
Daniele Varrazzo
081bf843d2 Parse the error codes from the text file if available
The text file was added in PG 9.1. It contains a few errors not available
in the SGML.
2014-07-31 13:33:36 +01:00
Daniele Varrazzo
56adc590ff Fixed segfault if COPY statements are executed
Close ticket #219
2014-06-06 21:42:21 +02:00
Daniele Varrazzo
115ceea1eb Don't ignore silently the cursor.callproc argument without a length 2014-06-06 21:42:21 +02:00
Daniele Varrazzo
e076e935b9 Added test with objects without length as callproc param 2014-06-06 21:42:20 +02:00
Chris Mildebrandt
693dedf4da cleanup remaining GPL license text 2014-05-20 09:50:53 -07:00
Chris Mildebrandt
67354ed14f cleanup remaining GPL license text 2014-05-20 09:42:41 -07:00
Jason Erickson
8746b0c6b7 Skip test_cleanup_on_badconn_close on Windows
The Windows server version of PostgreSQL uses a function called pgkill in the
file kill.c in place of the UNIX kill function.  This pgkill function
simulates some of the SIGHUP like commands by passing signals through a named
pipe.  Because it is passing the signal through a pipe, the server doesn't get
the kill signal immediately and therefore fails the test on
test_connection.ConnectionTests.test_cleanup_on_badconn_close.
Ideally, the test should check to see if the server is running on Windows, not
the psycopg.
2014-05-19 12:15:53 +01:00
Jason Erickson
c5f2e29dde Added select.select timeout on AsyncTests.wait
On Windows, the select.select() hangs/waits forever on the
test_async_connection_error_message() test.  Adding a 10 second timeout
allows the tests to continue.
2014-05-19 12:15:52 +01:00
Daniele Varrazzo
97290955f6 Python 3.4 declared supported 2014-05-13 14:36:28 +01:00
Daniele Varrazzo
d0b35adeb6 Parse the rowcount as long 2014-05-13 14:34:10 +01:00
Daniele Varrazzo
35545e7374 Skip rowcount on copy test on postgres < 8.2
It looks like the server doesn't send the message.
2014-05-13 14:34:09 +01:00
Daniele Varrazzo
81b5f1fb26 Copy operations correctly set the cursor.rowcount attribute
Fixes ticket #180.
2014-05-05 23:53:50 +01:00
Daniele Varrazzo
abd975ae40 set_session() params documented in a more Python-friendly way 2014-05-05 23:06:23 +01:00
Daniele Varrazzo
69605e54ec Fixed explicit connection.cursor(cursor_factory=None)
Fixes issue #210.
2014-04-30 17:57:55 +01:00
Daniele Varrazzo
03b8b1e97a Merge branch 'connection-closed'
NEWS for released 2.5.3 reordered.
2014-04-05 16:11:19 +01:00
Daniele Varrazzo
09fb131f1a Don't specify 0 or 1 in closed docs
There's also 2 which means broken. But I prefer to leave that as
implementation detail.
2014-04-05 16:03:19 +01:00
Daniele Varrazzo
489658cfc5 Close the connection if discovered bad on poll() 2014-04-05 16:03:19 +01:00
Daniele Varrazzo
1654687d1b Check the connection is really bad on exception before closing it
We end up here without a pgres sometimes (e.g. from lobject errors)
2014-04-05 16:03:06 +01:00
Daniele Varrazzo
3752880b7b Fixed attempt of closing an already closed lobject on dealloc
This results in a "null without exception set" in the corrent state, which
is caused by the connection being unexpectedly closed anyway.
2014-04-05 16:03:06 +01:00
Daniele Varrazzo
2e55b35d5d Don't set an exception witout GIL closing lobjects with a bad conn
We ended up in this branch only for an excessively aggressive closing
of the transaction that now I'm going to fix.
2014-04-05 16:03:06 +01:00
Daniele Varrazzo
696d123550 Close a connection if PQexec returned NULL
This happens for Socket connections, not for TCP ones, where a result
containing an error is returned and correctly handled by pq_raise()

Closes ticket #196 but not #192: poll() still doesn't change the
connection closed.
2014-04-05 16:03:06 +01:00
Daniele Varrazzo
a31c1a1722 Allow get_transaction_status on closed connections
It's a local operation and the libpq functions has a NULL guard.
2014-04-05 16:02:43 +01:00
Daniele Varrazzo
9036299d54 Avoid printing the typecast name in debug statement
The way we were doing it is unsafe and causes assertion failures on Py3.

Fixes ticket #188
2014-04-04 19:25:09 +01:00
Daniele Varrazzo
ca98167ae4 Fixed use of Python object with refcount 0 in cursor_init
Caused segfault running test_cursor.CursorTests.test_invalid_name under
Python 3.4 built in debug mode.
2014-04-04 19:20:08 +01:00
Daniele Varrazzo
81443c3a65 Work around pip issue #1630 breaking 'pip -e git+url'
https://github.com/pypa/pip/issues/1630

Fixes ticket #18 (opened in 2010!)
2014-04-04 18:07:05 +01:00
Daniele Varrazzo
33f2301772 Clarify in the docs that mogrify() and query always return bytes 2014-04-03 02:46:54 +01:00
Daniele Varrazzo
e9661bcde5 Fixed bug number typo in NEWS file 2014-04-03 02:45:57 +01:00
Daniele Varrazzo
a8fdc74090 Fixed overflow opening a lobject with an oid not fitting in a signed int
Fixes 🎫`203`.
2014-04-03 02:35:56 +01:00
Daniele Varrazzo
dfacc483b5 Dropped unneeded pass in test 2014-04-03 02:32:05 +01:00
Daniele Varrazzo
25e3a5f744 Explicit the fact that closed connections have undefined status 2014-04-03 02:07:38 +01:00
Daniele Varrazzo
e7fc7f31b9 Fixed dsn and closed attributes in failing connection subclasses.
From ticket #192 discussion.
2014-04-03 01:42:35 +01:00
Erwin de Keijzer
0258e90ef0 Fixed DNS typo in examples 2014-03-24 18:36:33 +01:00
Daniele Varrazzo
7b82be936d Don't segfault on uninitialized cursor
It can happen with bad cursor subclasses not calling super's init. Raise
an exception instead of segfaulting.

Closes #195
2014-02-26 19:41:59 +00:00
Daniele Varrazzo
618f7e41de Use the do-while 0 idiom for cursor guards macro 2014-02-26 19:31:27 +00:00
Daniele Varrazzo
3c893606f5 Merge branch 'ticket-194' 2014-02-24 15:20:13 +00:00
Daniele Varrazzo
79e84e432a Bug #194 confirmed fixed: newsfile updated. 2014-02-24 15:20:01 +00:00
Daniele Varrazzo
63e36e22d2 Set the connection async before polling for connection
It should fix ticket #194
2014-02-24 15:20:01 +00:00
Daniele Varrazzo
ca99579b76 Set the connection async earlier in green mode
The moment it is called shouldn't have really changed, but it's more
explicit when it happens. Previously it was sort of obfuscated behind a
roundtrip through the green callback and poll.
2014-02-24 15:20:01 +00:00
Daniele Varrazzo
283dbccf56 Merge branch 'range_sort' 2014-02-22 23:02:19 +00:00
Daniele Varrazzo
dd9e476353 Fixed error message on range parsing failed 2014-02-22 23:02:07 +00:00
Daniele Varrazzo
8d2744c550 Mention Range order in the news file 2014-02-22 23:01:22 +00:00
Daniele Varrazzo
212f4e3538 Docs wordsmithing about Range order 2014-02-22 23:01:02 +00:00
Daniele Varrazzo
8937c635df Hardcode the list of attributes to be used in comparison
Comparing Range subclasses may lead to surprises.
2014-02-22 21:52:44 +00:00
Daniele Varrazzo
4545d1636c Added implementation for Range gt and ge operators
Using a common implementation for all the operators. Note that lt is the
one used by sort so it's nice it's the fastest.
2014-02-22 21:51:28 +00:00
Daniele Varrazzo
6192a4fb17 Added str() for the Json adapter
Fixes ticket #191.
2014-02-22 20:45:35 +00:00
Chris Withers
6cd0647da9 documentation changes now that Range objects can be ordered 2014-02-18 21:24:59 +00:00
Chris Withers
e60266c4c5 New implementation of Range sorting that works for Python 2.5 to 3.3, at least. 2014-02-18 20:55:00 +00:00
Chris Withers
bae508ffa6 Coding style changes. 2014-02-14 07:46:32 +00:00
Chris Withers
d469c32503 Provide a stable and consistent sort order for Range objects.
This matches postgres server-side behaviour and helps client applications that need to sort based on the primary key of tables where the primary key is or contains a range.
2014-02-12 08:11:59 +00:00
Daniele Varrazzo
66f85b5832 Merge branch 'outputres' 2014-01-14 21:54:28 +00:00
Daniele Varrazzo
a35b743af7 Mention outputres fix in NEWS file 2014-01-14 21:52:42 +00:00
Daniele Varrazzo
4ed9dc1435 Added doc notes about how to avoid JSON parsing
Added FAQ too as it has bitten more than one user
(see tickets #172, #190).
2014-01-14 18:33:05 +00:00
James Emerton
58c98deebb Fallback when get_ext_fullpath() is unavailable 2014-01-10 13:41:16 -08:00
James Emerton
9100ad3e8f Use get_ext_fullpath() for -outputresource
The manifest fixup was relying on the extension name being "_psycopg.pyd" which effectively prevents building with --debug as the extension name becomes "_psycopg_d.pyd" in this instance.
2014-01-10 11:56:14 -08:00
Daniele Varrazzo
85b1914ad6 Fixed dealloc of lobject->smode
I put it by mistake into the in the self->conn checked block in the
previous commit.
2013-11-27 13:00:16 +00:00
Daniele Varrazzo
e11d0d39ec Check connection type in lobject init
Fixes ticket #187.
2013-11-27 12:44:28 +00:00
Daniele Varrazzo
6ab1ec1c37 Typo fixes and improvements to new_array_type() docs 2013-10-21 15:27:31 +01:00
Daniele Varrazzo
bc70902ea5 Use bytestrings in infinite dates adapter example
Returning strings would result in unclear tracebacks on Py3 (see ticket #163).
2013-10-21 14:30:25 +01:00
Daniele Varrazzo
2e3833f7fb Really test named cursors in test_scroll_named() 2013-10-16 19:10:21 +01:00
Daniele Varrazzo
5c99d2a456 Document that named cursors don't raise an exception going out-of-bound
See issue #174 for the details.
2013-10-16 19:10:20 +01:00
Daniele Varrazzo
a0a63e3ac7 Document that using %, (, ) in the placeholder name is not supported 2013-10-16 17:50:11 +01:00
Daniele Varrazzo
1e623a951c Meaningful connection errors report a meaningful message
Fixes issue #173.
2013-10-16 17:50:10 +01:00
Daniele Varrazzo
345077d5f7 Fixed pickling of exceptions with no pgerror/pgcode set
Fixes ticket #170.
2013-07-19 16:05:59 +01:00
Daniele Varrazzo
81e8b869d0 Fixed titles in newsfile
The first title at the same level of the main releases helps getting a
more regular ToC in the docs main page.
2013-07-19 16:02:31 +01:00
Daniele Varrazzo
497247a528 Fixed doc index entry for infinite dates 2013-06-23 02:14:01 +01:00
Daniele Varrazzo
921b676471 Untrack the connection before closing to avoid possible double-free
From Gangadharan S.A. Fixes issue #166.
2013-06-20 16:35:43 +01:00
Daniele Varrazzo
83c5d12cf1 Added doc example to convert date.max to infinity
See issue #163.
2013-06-18 15:00:30 +01:00
Daniele Varrazzo
ea08f7e7c7 Merge branch 'range_eq_typerror' 2013-06-18 14:14:01 +01:00
Daniele Varrazzo
1361189b99 Mention the Range eq fix in the NEWS file 2013-06-18 14:13:00 +01:00
Daniele Varrazzo
d50ea3d82b Uniform Range eq tests style 2013-06-18 14:10:49 +01:00
Chris Withers
28276e3eb1 cater for comparison of subclasses 2013-05-26 22:20:07 +01:00
Chris Withers
b6a9e0ffaf raising an exception here rather than returning False causes problems with SQLAlchemy's internal state tracking 2013-05-26 21:58:39 +01:00
Chris Withers
8bb44f3444 more useful error message when comparing ranges with non-ranges 2013-05-26 21:20:40 +01:00
Daniele Varrazzo
1ef234ebfc Added regression test for infinity parsing in dates
...and a couple of typos.
2013-05-11 02:19:59 +01:00
Daniele Varrazzo
c796bc2cbd Added test to verify copysize handling in copy_expert
Not an original psycopg2 bug but present in pure python implementation,
e.g. ctypes issue #25 and cffi issue #5.

https://github.com/mvantellingen/psycopg2-ctypes/issues/25
https://github.com/chtd/psycopg2cffi/pull/5
2013-05-06 10:48:10 +01:00
Daniele Varrazzo
a44db81d9b Skip tests on python implementations without getrefcount()
PyPy is one of these.
2013-05-06 10:39:24 +01:00
Daniele Varrazzo
bbe0bf955c A few docs fixes to the usage page 2013-05-01 22:40:19 +01:00
Daniele Varrazzo
1ff3ea0745 Dropped a lot of words from the front matter
Replaced with links to the types adaptation table and the extension docs.
2013-04-26 10:06:26 +01:00
Piotr Kasprzyk
31b6ec63f8 Fix multiple misspellings 2013-04-26 09:59:40 +01:00
Daniele Varrazzo
2eba97de70 Merge branch 'classifiers' 2013-04-21 21:44:57 +01:00
Daniele Varrazzo
4547753df0 Added explicit Python 2 and Python 3 classifiers
Not sure, but I suspect the "python3" page on PyPy in only based
on the Language :: Python :: 3 classifier, not the more specific ones
2013-04-21 21:43:55 +01:00
Saul Shanabrook
4de8b9577e Explicit Python Version Support
Used supported versions from http://initd.org/psycopg/docs/install.html
2013-04-21 21:35:58 +01:00
Daniele Varrazzo
fc2ca0d2e9 Make sure to return a bytes string from numeric range adapter 2013-04-21 20:30:50 +01:00
Daniele Varrazzo
d159dfea9d Merge branch 'solaris-round' 2013-04-21 18:39:30 +01:00
Daniele Varrazzo
fdc5dc750c Mention Solaris round fix in NEWS file 2013-04-21 18:37:19 +01:00
Daniele Varrazzo
e335eb98ce Long ifdef reformatted for readibility 2013-04-20 02:21:58 +01:00
Daniele Varrazzo
5d86d07618 Testing external script independent from psycopg implementation
Patch needed to run the test suite on psycopg2cffi or psycopg2ct.
2013-04-19 23:01:28 +01:00
Daniel Enman
558f7ad929 Remove extra || 2013-04-18 17:12:14 -03:00
Daniel Enman
cda0b6a8eb Solaris 10+, and illumos distros have round() 2013-04-18 16:59:26 -03:00
Daniele Varrazzo
711c092a79 The UUID adapter returns bytes instead of str in Python 3
Also added __conform__ method to the adapter.
2013-04-07 22:19:04 +01:00
Daniele Varrazzo
61d496b2ed Script to test ticket #58 moved into sandbox
We don't need it distributed in the sdist
2013-04-07 22:02:52 +01:00
Daniele Varrazzo
04c09b7b38 Dropped GPL license from source
It doesn't apply: leaving the LGPL only.
2013-04-07 22:02:45 +01:00
Daniele Varrazzo
1af4bd83c4 Stop distributing the compiled documentation with the source 2013-04-07 22:02:38 +01:00
Daniele Varrazzo
af7347473e Dropped stale entries from MANIFEST.in 2013-04-07 22:02:32 +01:00
Daniele Varrazzo
f2fbf18a05 Dropped psycopg 1 changelog
Also MANIFEST.in cleaned up from stale entries
2013-04-07 22:01:38 +01:00
Daniele Varrazzo
6d2f2676ad Bump to next dev version 2013-04-07 19:43:52 +01:00
249 changed files with 20736 additions and 74811 deletions

4
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
github:
- dvarrazzo
custom:
- "https://www.paypal.me/dvarrazzo"

View File

@ -0,0 +1,23 @@
---
name: Problem installing psycopg2
about: Report a case in which psycopg2 failed to install on your platform
title: ''
labels: ''
assignees: ''
---
**This is a bug tracker**
If you have a question, such has "how do you do X with Python/PostgreSQL/psycopg2" please [write to the mailing list](https://lists.postgresql.org/manage/) or [open a question](https://github.com/psycopg/psycopg2/discussions) instead.
**Before opening this ticket, please confirm that:**
- [ ] I am running the latest version of pip, i.e. typing ``pip --version`` you get [this version](https://pypi.org/project/pip/).
- [ ] I have read the [installation documentation](https://www.psycopg.org/docs/install.html) and the [frequently asked questions](https://www.psycopg.org/docs/faq.html)
- [ ] If install failed, I typed `pg_config` on the command line and I obtained an output instead of an error.
**Please complete the following information:**
- OS:
- Psycopg version:
- Python version:
- PostgreSQL version:
- pip version

View File

@ -0,0 +1,27 @@
---
name: Problem using psycopg2
about: Report a case in which psycopg2 is not working as expected
title: ''
labels: ''
assignees: ''
---
**This is a bug tracker**
If you have a question, such has "how do you do X with Python/PostgreSQL/psycopg2" please [write to the mailing list](https://lists.postgresql.org/manage/) or [open a question](https://github.com/psycopg/psycopg2/discussions) instead.
**Please complete the following information:**
- OS:
- Psycopg version:
- Python version:
- PostgreSQL version:
- pip version
**Describe the bug**
Please let us know:
1: what you did
2: what you expected to happen
3: what happened instead
If possible, provide a script reproducing the issue.

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

18
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: Build documentation
on:
push:
branches:
# This should match the DOC_BRANCH value in the psycopg-website Makefile
- master
jobs:
docs:
runs-on: ubuntu-latest
steps:
- name: Trigger docs build
uses: peter-evans/repository-dispatch@v3
with:
repository: psycopg/psycopg-website
event-type: psycopg2-commit
token: ${{ secrets.ACCESS_TOKEN }}

266
.github/workflows/packages.yml vendored Normal file
View File

@ -0,0 +1,266 @@
---
name: Build packages
on:
- workflow_dispatch
env:
PIP_BREAK_SYSTEM_PACKAGES: "1"
LIBPQ_VERSION: "16.0"
OPENSSL_VERSION: "1.1.1w"
jobs:
sdist: # {{{
if: true
strategy:
fail-fast: false
matrix:
include:
- package_name: psycopg2
- package_name: psycopg2-binary
runs-on: ubuntu-latest
steps:
- name: Checkout repos
uses: actions/checkout@v4
- name: Build sdist
run: ./scripts/build/build_sdist.sh
env:
PACKAGE_NAME: ${{ matrix.package_name }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: sdist-${{ matrix.package_name }}
path: |
dist/*.tar.gz
env:
PSYCOPG2_TESTDB: postgres
PSYCOPG2_TESTDB_HOST: 172.17.0.1
PSYCOPG2_TESTDB_USER: postgres
PSYCOPG2_TESTDB_PASSWORD: password
PSYCOPG2_TEST_FAST: 1
services:
postgresql:
image: postgres:16
env:
POSTGRES_PASSWORD: password
ports:
- 5432:5432
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
# }}}
linux: # {{{
if: true
strategy:
fail-fast: false
matrix:
platform: [manylinux, musllinux]
arch: [x86_64, i686, aarch64, ppc64le]
pyver: [cp38, cp39, cp310, cp311, cp312, cp313]
runs-on: ubuntu-latest
steps:
- name: Checkout repos
uses: actions/checkout@v4
- name: Set up QEMU for multi-arch build
uses: docker/setup-qemu-action@v3
- name: Cache libpq build
uses: actions/cache@v4
with:
path: /tmp/libpq.build
key: libpq-${{ env.LIBPQ_VERSION }}-${{ matrix.platform }}-${{ matrix.arch }}
- name: Build wheels
uses: pypa/cibuildwheel@v2.23.2
env:
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_MANYLINUX_I686_IMAGE: manylinux2014
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014
CIBW_MANYLINUX_PPC64LE_IMAGE: manylinux2014
CIBW_BUILD: ${{matrix.pyver}}-${{matrix.platform}}_${{matrix.arch}}
CIBW_ARCHS_LINUX: auto aarch64 ppc64le
CIBW_BEFORE_ALL_LINUX: ./scripts/build/wheel_linux_before_all.sh
CIBW_REPAIR_WHEEL_COMMAND: >-
./scripts/build/strip_wheel.sh {wheel}
&& auditwheel repair -w {dest_dir} {wheel}
CIBW_TEST_COMMAND: >-
export PYTHONPATH={project} &&
python -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')"
CIBW_ENVIRONMENT_PASS_LINUX: LIBPQ_VERSION OPENSSL_VERSION
CIBW_ENVIRONMENT: >-
PACKAGE_NAME=psycopg2-binary
LIBPQ_BUILD_PREFIX=/host/tmp/libpq.build
PATH="$LIBPQ_BUILD_PREFIX/bin:$PATH"
LD_LIBRARY_PATH="$LIBPQ_BUILD_PREFIX/lib:$LIBPQ_BUILD_PREFIX/lib64"
PSYCOPG2_TESTDB=postgres
PSYCOPG2_TESTDB_HOST=172.17.0.1
PSYCOPG2_TESTDB_USER=postgres
PSYCOPG2_TESTDB_PASSWORD=password
PSYCOPG2_TEST_FAST=1
- uses: actions/upload-artifact@v4
with:
name: linux-${{matrix.pyver}}-${{matrix.platform}}_${{matrix.arch}}
path: ./wheelhouse/*.whl
services:
postgresql:
image: postgres:16
env:
POSTGRES_PASSWORD: password
ports:
- 5432:5432
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
# }}}
macos: # {{{
runs-on: macos-latest
if: true
strategy:
fail-fast: false
matrix:
# These archs require an Apple M1 runner: [arm64, universal2]
arch: [x86_64, arm64]
pyver: [cp39, cp310, cp311, cp312, cp313]
steps:
- name: Checkout repos
uses: actions/checkout@v4
- name: Cache libpq build
uses: actions/cache@v4
with:
path: /tmp/libpq.build
key: libpq-${{ env.LIBPQ_VERSION }}-macos-${{ matrix.arch }}
- name: Build wheels
uses: pypa/cibuildwheel@v2.23.2
env:
CIBW_BUILD: ${{matrix.pyver}}-macosx_${{matrix.arch}}
CIBW_ARCHS_MACOS: ${{matrix.arch}}
MACOSX_ARCHITECTURE: ${{matrix.arch}}
CIBW_BEFORE_ALL_MACOS: ./scripts/build/wheel_macos_before_all.sh
CIBW_TEST_COMMAND: >-
export PYTHONPATH={project} &&
python -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')"
CIBW_ENVIRONMENT: >-
PG_VERSION=16
PACKAGE_NAME=psycopg2-binary
PSYCOPG2_TESTDB=postgres
PATH="/tmp/libpq.build/bin:$PATH"
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: macos-${{matrix.pyver}}-macos-${{matrix.arch}}
path: ./wheelhouse/*.whl
# }}}
windows: # {{{
runs-on: windows-latest
if: true
strategy:
fail-fast: false
matrix:
arch: [win_amd64]
pyver: [cp38, cp39, cp310, cp311, cp312, cp313]
package_name: [psycopg2, psycopg2-binary]
defaults:
run:
shell: bash
steps:
# there are some other libpq in PATH
- name: Drop spurious libpq in the path
run: rm -rf c:/tools/php C:/Strawberry/c/bin
- name: Checkout repo
uses: actions/checkout@v4
- name: Start PostgreSQL service for test
run: |
$PgSvc = Get-Service "postgresql*"
Set-Service $PgSvc.Name -StartupType manual
$PgSvc.Start()
shell: powershell
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
script: |
const path = require('path')
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
core.addPath(path.join(process.env.VCPKG_INSTALLATION_ROOT, 'installed/x64-windows-release/lib'));
core.addPath(path.join(process.env.VCPKG_INSTALLATION_ROOT, 'installed/x64-windows-release/bin'));
- name: Create the binary package source tree
run: >-
sed -i 's/^setup(name="psycopg2"/setup(name="${{matrix.package_name}}"/'
setup.py
if: ${{ matrix.package_name != 'psycopg2' }}
- name: Build wheels
uses: pypa/cibuildwheel@v2.23.2
env:
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" # cache vcpkg
CIBW_BUILD: ${{matrix.pyver}}-${{matrix.arch}}
CIBW_ARCHS_WINDOWS: AMD64 x86
CIBW_BEFORE_BUILD_WINDOWS: '.\scripts\build\wheel_win32_before_build.bat'
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >-
delvewheel repair -w {dest_dir}
--no-mangle "libiconv-2.dll;libwinpthread-1.dll" {wheel}
CIBW_TEST_COMMAND: >-
set PYTHONPATH={project} &&
python -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')"
# Note: no fast test because we don't run Windows tests
CIBW_ENVIRONMENT_WINDOWS: >-
PSYCOPG2_TESTDB=postgres
PSYCOPG2_TESTDB_USER=postgres
PSYCOPG2_TESTDB_HOST=localhost
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: windows-${{ matrix.package_name }}-${{matrix.pyver}}-${{matrix.arch}}
path: ./wheelhouse/*.whl
# }}}
merge: # {{{
runs-on: ubuntu-latest
needs:
- sdist
- linux
- macos
- windows
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
with:
name: psycopg2-artifacts
delete-merged: true
# }}}

79
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,79 @@
name: Tests
env:
PIP_BREAK_SYSTEM_PACKAGES: "1"
on:
push:
pull_request:
jobs:
linux:
runs-on: ubuntu-latest
if: true
strategy:
fail-fast: false
matrix:
include:
- {python: "3.8", postgres: "12"}
- {python: "3.9", postgres: "13"}
- {python: "3.10", postgres: "14"}
- {python: "3.11", postgres: "15"}
- {python: "3.12", postgres: "16"}
- {python: "3.13", postgres: "17"}
# Opposite extremes of the supported Py/PG range, other architecture
- {python: "3.8", postgres: "17", architecture: "x86"}
- {python: "3.9", postgres: "16", architecture: "x86"}
- {python: "3.10", postgres: "15", architecture: "x86"}
- {python: "3.11", postgres: "14", architecture: "x86"}
- {python: "3.12", postgres: "13", architecture: "x86"}
- {python: "3.13", postgres: "12", architecture: "x86"}
env:
PSYCOPG2_TESTDB: postgres
PSYCOPG2_TESTDB_HOST: 127.0.0.1
PSYCOPG2_TESTDB_USER: postgres
PSYCOPG2_TESTDB_PASSWORD: password
services:
postgresql:
image: postgres:${{ matrix.postgres }}
env:
POSTGRES_PASSWORD: password
ports:
- 5432:5432
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
# Can enable to test an unreleased libpq version.
- name: install libpq 16
if: false
run: |
set -x
rel=$(lsb_release -c -s)
echo "deb http://apt.postgresql.org/pub/repos/apt ${rel}-pgdg main 16" \
| sudo tee -a /etc/apt/sources.list.d/pgdg.list
sudo apt-get -qq update
pqver=$(apt-cache show libpq5 | grep ^Version: | head -1 \
| awk '{print $2}')
sudo apt-get -qq -y install "libpq-dev=${pqver}" "libpq5=${pqver}"
- name: Install tox
run: pip install "tox < 4"
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- name: Run tests
env:
MATRIX_PYTHON: ${{ matrix.python }}
run: tox -e ${MATRIX_PYTHON%-dev}
timeout-minutes: 5

13
.gitignore vendored
View File

@ -4,10 +4,15 @@ MANIFEST
*.pidb *.pidb
*.pyc *.pyc
*.sw[po] *.sw[po]
*.egg-info/
dist/* dist/*
build/* /build
doc/src/_build/*
doc/html/*
doc/psycopg2.txt
env env
env?
.idea
.tox .tox
.vscode/
/rel
/wheels
/packages
/wheelhouse

View File

@ -1,13 +0,0 @@
language: python
python:
- 2.6
- 2.7
before_script:
- psql -c 'create database psycopg2_test;' -U postgres
install:
- python setup.py install
script: make check

105
INSTALL
View File

@ -1,103 +1,4 @@
Compiling and installing psycopg Installation instructions are included in the docs.
********************************
** Important note: if you plan to use psycopg2 in a multithreaded application,
make sure that your libpq has been compiled with the --with-thread-safety
option. psycopg2 will work correctly even with a non-thread-safe libpq but
libpq will leak memory.
psycopg2 uses distutils for its build process, so most of the process is
executed by the setup.py script. Before building psycopg look at
setup.cfg file and change any settings to follow your system (or taste);
then:
python setup.py build
to build in the local directory; and:
python setup.py install
to install system-wide.
Common errors and build problems
================================
One of the most common errors is trying to build psycopg without the right
development headers for PostgreSQL, Python or both. If you get errors, look
for the following messages and then take the appropriate action:
libpq-fe.h: No such file or directory
PostgreSQL headers are not properly installed on your system or are
installed in a non default path. First make sure they are installed, then
check setup.cfg and make sure pg_config points to a valid pg_config
executable. If you don't have a working pg_config try to play with the
include_dirs variable (and note that a working pg_config is better.)
Running the test suite
======================
The included Makefile allows to run all the tests included in the
distribution. Just use:
make
make check
The tests are run against a database called psycopg2_test on unix socket
and standard port. You can configure a different database to run the test
by setting the environment variables:
- PSYCOPG2_TESTDB
- PSYCOPG2_TESTDB_HOST
- PSYCOPG2_TESTDB_PORT
- PSYCOPG2_TESTDB_USER
The database should be created before running the tests.
The standard Python unittest is used to run the tests. But if unittest2 is
found it will be used instead, with the result of having more informations
about skipped tests.
Building the documentation
==========================
In order to build the documentation included in the distribution, use
make env
make docs
The first command will install all the dependencies (Sphinx, Docutils) in
an 'env' directory in the project tree. The second command will build both
the html format (in the 'doc/html' directory) and in plain text
(doc/psycopg2.txt)
Using setuptools and EasyInstall
================================
If setuptools are installed on your system you can easily create an egg for
psycopg and install it. Download the source distribution (if you're reading
this file you probably already have) and then edit setup.cfg to your taste
and build from the source distribution top-level directory using:
easy_install .
Compiling under Windows with mingw32
====================================
You can compile psycopg under Windows platform with mingw32
(http://www.mingw.org/) compiler. MinGW is also shipped with IDEs such as
Dev-C++ (http://www.bloodshed.net/devcpp.html) and Code::Blocks
(http://www.codeblocks.org). gcc binaries should be in your PATH.
You need a PostgreSQL with include and libary files installed. At least v8.0
is required.
First you need to create a libpython2X.a as described in
http://starship.python.net/crew/kernr/mingw32/Notes.html. Then run:
python setup.py build_ext --compiler=mingw32 install
Please check the 'doc/src/install.rst' file or online at
<https://www.psycopg.org/docs/install.html>.

15
LICENSE
View File

@ -1,5 +1,5 @@
psycopg2 and the LGPL psycopg2 and the LGPL
===================== ---------------------
psycopg2 is free software: you can redistribute it and/or modify it psycopg2 is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published under the terms of the GNU Lesser General Public License as published
@ -25,19 +25,14 @@ statement from all source files in the program, then also delete it here.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with psycopg2 (see the doc/ directory.) along with psycopg2 (see the doc/ directory.)
If not, see <http://www.gnu.org/licenses/>. If not, see <https://www.gnu.org/licenses/>.
Alternative licenses Alternative licenses
==================== --------------------
If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e., The following BSD-like license applies (at your option) to the files following
every file inside the ZPsycopgDA directory) user the ZPL license as the pattern ``psycopg/adapter*.{h,c}`` and ``psycopg/microprotocol*.{h,c}``:
published on the Zope web site, http://www.zope.org/Resources/ZPL.
Also, the following BSD-like license applies (at your option) to the
files following the pattern psycopg/adapter*.{h,c} and
psycopg/microprotocol*.{h,c}:
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it including commercial applications, and to alter it and redistribute it

View File

@ -1,16 +1,9 @@
recursive-include psycopg *.c *.h *.manifest recursive-include psycopg *.c *.h *.manifest
recursive-include lib *.py recursive-include lib *.py
recursive-include tests *.py recursive-include tests *.py
recursive-include ZPsycopgDA *.py *.gif *.dtml include doc/README.rst doc/SUCCESS doc/COPYING.LESSER doc/pep-0249.txt
recursive-include psycopg2da * include doc/Makefile doc/requirements.txt
recursive-include examples *.py somehackers.jpg whereareyou.jpg
recursive-include debian *
recursive-include doc README HACKING SUCCESS COPYING* ChangeLog-1.x pep-0249.txt
recursive-include doc *.txt *.html *.css *.js Makefile
recursive-include doc/src *.rst *.py *.css Makefile recursive-include doc/src *.rst *.py *.css Makefile
recursive-include doc/html *
prune doc/src/_build
recursive-include scripts *.py *.sh recursive-include scripts *.py *.sh
include scripts/maketypes.sh scripts/buildtypes.py include AUTHORS README.rst INSTALL LICENSE NEWS
include AUTHORS README INSTALL LICENSE NEWS ChangeLog include MANIFEST.in setup.py setup.cfg Makefile
include PKG-INFO MANIFEST.in MANIFEST setup.py setup.cfg Makefile

View File

@ -6,12 +6,11 @@
# #
# Build the documentation:: # Build the documentation::
# #
# make env # make env (once)
# make docs # make docs
# #
# Create a source package:: # Create a source package::
# #
# make env # required to build the documentation
# make sdist # make sdist
# #
# Run the test:: # Run the test::
@ -21,9 +20,6 @@
PYTHON := python$(PYTHON_VERSION) PYTHON := python$(PYTHON_VERSION)
PYTHON_VERSION ?= $(shell $(PYTHON) -c 'import sys; print ("%d.%d" % sys.version_info[:2])') PYTHON_VERSION ?= $(shell $(PYTHON) -c 'import sys; print ("%d.%d" % sys.version_info[:2])')
BUILD_DIR = $(shell pwd)/build/lib.$(PYTHON_VERSION) BUILD_DIR = $(shell pwd)/build/lib.$(PYTHON_VERSION)
ENV_DIR = $(shell pwd)/env/py-$(PYTHON_VERSION)
ENV_BIN = $(ENV_DIR)/bin
ENV_LIB = $(ENV_DIR)/lib
SOURCE_C := $(wildcard psycopg/*.c psycopg/*.h) SOURCE_C := $(wildcard psycopg/*.c psycopg/*.h)
SOURCE_PY := $(wildcard lib/*.py) SOURCE_PY := $(wildcard lib/*.py)
@ -33,8 +29,7 @@ SOURCE := $(SOURCE_C) $(SOURCE_PY) $(SOURCE_TESTS) $(SOURCE_DOC)
PACKAGE := $(BUILD_DIR)/psycopg2 PACKAGE := $(BUILD_DIR)/psycopg2
PLATLIB := $(PACKAGE)/_psycopg.so PLATLIB := $(PACKAGE)/_psycopg.so
PURELIB := $(patsubst lib/%,$(PACKAGE)/%,$(SOURCE_PY)) \ PURELIB := $(patsubst lib/%,$(PACKAGE)/%,$(SOURCE_PY))
$(patsubst tests/%,$(PACKAGE)/tests/%,$(SOURCE_TESTS))
BUILD_OPT := --build-lib=$(BUILD_DIR) BUILD_OPT := --build-lib=$(BUILD_DIR)
BUILD_EXT_OPT := --build-lib=$(BUILD_DIR) BUILD_EXT_OPT := --build-lib=$(BUILD_DIR)
@ -47,10 +42,7 @@ endif
VERSION := $(shell grep PSYCOPG_VERSION setup.py | head -1 | sed -e "s/.*'\(.*\)'/\1/") VERSION := $(shell grep PSYCOPG_VERSION setup.py | head -1 | sed -e "s/.*'\(.*\)'/\1/")
SDIST := dist/psycopg2-$(VERSION).tar.gz SDIST := dist/psycopg2-$(VERSION).tar.gz
EASY_INSTALL = PYTHONPATH=$(ENV_LIB) $(ENV_BIN)/easy_install-$(PYTHON_VERSION) -d $(ENV_LIB) -s $(ENV_BIN) .PHONY: check clean
EZ_SETUP = $(ENV_BIN)/ez_setup.py
.PHONY: env check clean
default: package default: package
@ -58,36 +50,20 @@ all: package sdist
package: $(PLATLIB) $(PURELIB) package: $(PLATLIB) $(PURELIB)
docs: docs-html docs-txt docs: docs-html
docs-html: doc/html/genindex.html docs-html: doc/html/genindex.html
docs-txt: doc/psycopg2.txt
# for PyPI documentation # for PyPI documentation
docs-zip: doc/docs.zip docs-zip: doc/docs.zip
sdist: $(SDIST) sdist: $(SDIST)
# The environment is currently required to build the documentation. env:
# It is not clean by 'make clean' $(MAKE) -C doc $@
env: easy_install
mkdir -p $(ENV_BIN)
mkdir -p $(ENV_LIB)
$(EASY_INSTALL) docutils
$(EASY_INSTALL) sphinx
easy_install: ez_setup
PYTHONPATH=$(ENV_LIB) $(PYTHON) $(EZ_SETUP) -d $(ENV_LIB) -s $(ENV_BIN) setuptools
ez_setup:
mkdir -p $(ENV_BIN)
mkdir -p $(ENV_LIB)
wget -O $(EZ_SETUP) http://peak.telecommunity.com/dist/ez_setup.py
check: check:
PYTHONPATH=$(BUILD_DIR):$(PYTHONPATH) $(PYTHON) -c "from psycopg2 import tests; tests.unittest.main(defaultTest='tests.test_suite')" --verbose PYTHONPATH=$(BUILD_DIR) $(PYTHON) -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')" --verbose
testdb: testdb:
@echo "* Creating $(TESTDB)" @echo "* Creating $(TESTDB)"
@ -113,24 +89,16 @@ $(PACKAGE)/tests/%.py: tests/%.py
$(PYTHON) setup.py build_py $(BUILD_OPT) $(PYTHON) setup.py build_py $(BUILD_OPT)
touch $@ touch $@
$(SDIST): docs MANIFEST $(SOURCE) $(SDIST): $(SOURCE)
$(PYTHON) setup.py sdist $(SDIST_OPT) $(PYTHON) setup.py sdist $(SDIST_OPT)
MANIFEST: MANIFEST.in $(SOURCE)
# Run twice as MANIFEST.in includes MANIFEST
$(PYTHON) setup.py sdist --manifest-only
$(PYTHON) setup.py sdist --manifest-only
# docs depend on the build as it partly use introspection. # docs depend on the build as it partly use introspection.
doc/html/genindex.html: $(PLATLIB) $(PURELIB) $(SOURCE_DOC) doc/html/genindex.html: $(PLATLIB) $(PURELIB) $(SOURCE_DOC)
PYTHONPATH=$(ENV_LIB):$(BUILD_DIR) $(MAKE) SPHINXBUILD=$(ENV_BIN)/sphinx-build -C doc html $(MAKE) -C doc html
doc/psycopg2.txt: $(PLATLIB) $(PURELIB) $(SOURCE_DOC)
PYTHONPATH=$(ENV_LIB):$(BUILD_DIR) $(MAKE) SPHINXBUILD=$(ENV_BIN)/sphinx-build -C doc text
doc/docs.zip: doc/html/genindex.html doc/docs.zip: doc/html/genindex.html
(cd doc/html && zip -r ../docs.zip *) (cd doc/html && zip -r ../docs.zip *)
clean: clean:
rm -rf build MANIFEST rm -rf build
$(MAKE) -C doc clean $(MAKE) -C doc clean

613
NEWS
View File

@ -1,3 +1,591 @@
Current release
---------------
What's new in psycopg 2.9.10
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Add support for Python 3.13.
- Receive notifications on commit (:ticket:`#1728`).
- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
PostgreSQL 17.
- Drop support for Python 3.7.
What's new in psycopg 2.9.9
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Add support for Python 3.12.
- Drop support for Python 3.6.
What's new in psycopg 2.9.8
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Wheel package bundled with PostgreSQL 16 libpq in order to add support for
recent features, such as ``sslcertmode``.
What's new in psycopg 2.9.7
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix propagation of exceptions raised during module initialization
(:ticket:`#1598`).
- Fix building when pg_config returns an empty string (:ticket:`#1599`).
- Wheel package bundled with OpenSSL 1.1.1v.
What's new in psycopg 2.9.6
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Package manylinux 2014 for aarch64 and ppc64le platforms, in order to
include libpq 15 in the binary package (:ticket:`#1396`).
- Wheel package bundled with OpenSSL 1.1.1t.
What's new in psycopg 2.9.5
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Add support for Python 3.11.
- Add support for rowcount in MERGE statements in binary packages
(:ticket:`#1497`).
- Wheel package bundled with OpenSSL 1.1.1r and PostgreSQL 15 libpq.
What's new in psycopg 2.9.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix `~psycopg2.extras.register_composite()`,
`~psycopg2.extras.register_range()` with customized :sql:`search_path`
(:ticket:`#1487`).
- Handle correctly composite types with names or in schemas requiring escape.
- Find ``pg_service.conf`` file in the ``/etc/postgresql-common`` directory in
binary packages (:ticket:`#1365`).
- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
PostgreSQL 15.
- Wheel package bundled with OpenSSL 1.1.1q and PostgreSQL 14.4 libpq.
What's new in psycopg 2.9.3
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Alpine (musl) wheels now available (:ticket:`#1392`).
- macOS arm64 (Apple M1) wheels now available (:ticket:`1482`).
What's new in psycopg 2.9.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Raise `ValueError` for dates >= Y10k (:ticket:`#1307`).
- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
PostgreSQL 14.
- Add preliminary support for Python 3.11 (:tickets:`#1376, #1386`).
- Wheel package bundled with OpenSSL 1.1.1l and PostgreSQL 14.1 libpq
(:ticket:`#1388`).
What's new in psycopg 2.9.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix regression with named `~psycopg2.sql.Placeholder` (:ticket:`#1291`).
What's new in psycopg 2.9
-------------------------
- ``with connection`` starts a transaction on autocommit transactions too
(:ticket:`#941`).
- Timezones with fractional minutes are supported on Python 3.7 and following
(:ticket:`#1272`).
- Escape table and column names in `~cursor.copy_from()` and
`~cursor.copy_to()`.
- Connection exceptions with sqlstate ``08XXX`` reclassified as
`~psycopg2.OperationalError` (a subclass of the previously used
`~psycopg2.DatabaseError`) (:ticket:`#1148`).
- Include library dirs required from libpq to work around MacOS build problems
(:ticket:`#1200`).
Other changes:
- Dropped support for Python 2.7, 3.4, 3.5 (:tickets:`#1198, #1000, #1197`).
- Dropped support for mx.DateTime.
- Use `datetime.timezone` objects by default in datetime objects instead of
`~psycopg2.tz.FixedOffsetTimezone`.
- The `psycopg2.tz` module is deprecated and scheduled to be dropped in the
next major release.
- Provide :pep:`599` wheels packages (manylinux2014 tag) for i686 and x86_64
platforms.
- Provide :pep:`600` wheels packages (manylinux_2_24 tag) for aarch64 and
ppc64le platforms.
- Wheel package bundled with OpenSSL 1.1.1k and PostgreSQL 13.3 libpq.
- Build system for Linux/MacOS binary packages moved to GitHub Actions.
What's new in psycopg 2.8.7
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Accept empty params as `~psycopg2.connect()` (:ticket:`#1250`).
- Fix attributes refcount in `Column` initialisation (:ticket:`#1252`).
- Allow re-initialisation of static variables in the C module (:ticket:`#1267`).
What's new in psycopg 2.8.6
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed memory leak changing connection encoding to the current one
(:ticket:`#1101`).
- Fixed search of mxDateTime headers in virtualenvs (:ticket:`#996`).
- Added missing values from errorcodes (:ticket:`#1133`).
- `cursor.query` reports the query of the last :sql:`COPY` operation too
(:ticket:`#1141`).
- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
PostgreSQL 13.
- Added wheel packages for ARM architecture (:ticket:`#1125`).
- Wheel package bundled with OpenSSL 1.1.1g.
What's new in psycopg 2.8.5
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed use of `!connection_factory` and `!cursor_factory` together
(:ticket:`#1019`).
- Added support for `~logging.LoggerAdapter` in
`~psycopg2.extras.LoggingConnection` (:ticket:`#1026`).
- `~psycopg2.extensions.Column` objects in `cursor.description` can be sliced
(:ticket:`#1034`).
- Added AIX support (:ticket:`#1061`).
- Fixed `~copy.copy()` of `~psycopg2.extras.DictCursor` rows (:ticket:`#1073`).
What's new in psycopg 2.8.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed building with Python 3.8 (:ticket:`#854`).
- Don't swallow keyboard interrupts on connect when a password is specified
in the connection string (:ticket:`#898`).
- Don't advance replication cursor when the message wasn't confirmed
(:ticket:`#940`).
- Fixed inclusion of ``time.h`` on linux (:ticket:`#951`).
- Fixed int overflow for large values in `~psycopg2.extensions.Column.table_oid`
and `~psycopg2.extensions.Column.type_code` (:ticket:`#961`).
- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
PostgreSQL 12.
- Wheel package bundled with OpenSSL 1.1.1d and PostgreSQL at least 11.4.
What's new in psycopg 2.8.3
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added *interval_status* parameter to
`~psycopg2.extras.ReplicationCursor.start_replication()` method and other
facilities to send automatic replication keepalives at periodic intervals
(:ticket:`#913`).
- Fixed namedtuples caching introduced in 2.8 (:ticket:`#928`).
What's new in psycopg 2.8.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed `~psycopg2.extras.RealDictCursor` when there are repeated columns
(:ticket:`#884`).
- Binary packages built with openssl 1.1.1b. Should fix concurrency problems
(:tickets:`#543, #836`).
What's new in psycopg 2.8.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed `~psycopg2.extras.RealDictRow` modifiability (:ticket:`#886`).
- Fixed "there's no async cursor" error polling a connection with no cursor
(:ticket:`#887`).
What's new in psycopg 2.8
-------------------------
New features:
- Added `~psycopg2.errors` module. Every PostgreSQL error is converted into
a specific exception class (:ticket:`#682`).
- Added `~psycopg2.extensions.encrypt_password()` function (:ticket:`#576`).
- Added `~psycopg2.extensions.BYTES` adapter to manage databases with mixed
encodings on Python 3 (:ticket:`#835`).
- Added `~psycopg2.extensions.Column.table_oid` and
`~psycopg2.extensions.Column.table_column` attributes on `cursor.description`
items (:ticket:`#661`).
- Added `connection.info` object to retrieve various PostgreSQL connection
information (:ticket:`#726`).
- Added `~connection.get_native_connection()` to expose the raw ``PGconn``
structure to C extensions via Capsule (:ticket:`#782`).
- Added `~connection.pgconn_ptr` and `~cursor.pgresult_ptr` to expose raw
C structures to Python and interact with libpq via ctypes (:ticket:`#782`).
- `~psycopg2.sql.Identifier` can represent qualified names in SQL composition
(:ticket:`#732`).
- Added `!ReplicationCursor`.\ `~psycopg2.extras.ReplicationCursor.wal_end`
attribute (:ticket:`#800`).
- Added *fetch* parameter to `~psycopg2.extras.execute_values()` function
(:ticket:`#813`).
- `!str()` on `~psycopg2.extras.Range` produces a human-readable representation
(:ticket:`#773`).
- `~psycopg2.extras.DictCursor` and `~psycopg2.extras.RealDictCursor` rows
maintain columns order (:ticket:`#177`).
- Added `~psycopg2.extensions.Diagnostics.severity_nonlocalized` attribute on
the `~psycopg2.extensions.Diagnostics` object (:ticket:`#783`).
- More efficient `~psycopg2.extras.NamedTupleCursor` (:ticket:`#838`).
Bug fixes:
- Fixed connections occasionally broken by the unrelated use of the
multiprocessing module (:ticket:`#829`).
- Fixed async communication blocking if results are returned in different
chunks, e.g. with notices interspersed to the results (:ticket:`#856`).
- Fixed adaptation of numeric subclasses such as `~enum.IntEnum`
(:ticket:`#591`).
Other changes:
- Dropped support for Python 2.6, 3.2, 3.3.
- Dropped `psycopg1` module.
- Dropped deprecated `!register_tstz_w_secs()` (was previously a no-op).
- Dropped deprecated `!PersistentConnectionPool`. This pool class was mostly
designed to interact with Zope. Use `!ZPsycopgDA.pool` instead.
- Binary packages no longer installed by default. The 'psycopg2-binary'
package must be used explicitly.
- Dropped `!PSYCOPG_DISPLAY_SIZE` build parameter.
- Dropped support for mxDateTime as the default date and time adapter.
mxDatetime support continues to be available as an alternative to Python's
builtin datetime.
- No longer use 2to3 during installation for Python 2 & 3 compatibility. All
source files are now compatible with Python 2 & 3 as is.
- The `!psycopg2.test` package is no longer installed by ``python setup.py
install``.
- Wheel package bundled with OpenSSL 1.0.2r and PostgreSQL 11.2 libpq.
What's new in psycopg 2.7.7
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Cleanup of the cursor results assignment code, which might have solved
double free and inconsistencies in concurrent usage (:tickets:`#346, #384`).
- Wheel package bundled with OpenSSL 1.0.2q.
What's new in psycopg 2.7.6.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed binary package broken on OS X 10.12 (:ticket:`#807`).
- Wheel package bundled with PostgreSQL 11.1 libpq.
What's new in psycopg 2.7.6
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Close named cursors if exist, even if `~cursor.execute()` wasn't called
(:ticket:`#746`).
- Fixed building on modern FreeBSD versions with Python 3.7 (:ticket:`#755`).
- Fixed hang trying to :sql:`COPY` via `~cursor.execute()` in asynchronous
connections (:ticket:`#781`).
- Fixed adaptation of arrays of empty arrays (:ticket:`#788`).
- Fixed segfault accessing the connection's `~connection.readonly` and
`~connection.deferrable` attributes repeatedly (:ticket:`#790`).
- `~psycopg2.extras.execute_values()` accepts `~psycopg2.sql.Composable`
objects (:ticket:`#794`).
- `~psycopg2.errorcodes` map updated to PostgreSQL 11.
- Wheel package bundled with PostgreSQL 10.5 libpq and OpenSSL 1.0.2p.
What's new in psycopg 2.7.5
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Allow non-ascii chars in namedtuple fields (regression introduced fixing
:ticket:`#211`).
- Fixed adaptation of arrays of arrays of nulls (:ticket:`#325`).
- Fixed building on Solaris 11 and derivatives such as SmartOS and illumos
(:ticket:`#677`).
- Maybe fixed building on MSYS2 (as reported in :ticket:`#658`).
- Allow string subclasses in connection and other places (:ticket:`#679`).
- Don't raise an exception closing an unused named cursor (:ticket:`#716`).
- Wheel package bundled with PostgreSQL 10.4 libpq and OpenSSL 1.0.2o.
What's new in psycopg 2.7.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Moving away from installing the wheel package by default.
Packages installed from wheel raise a warning on import. Added package
``psycopg2-binary`` to install from wheel instead (:ticket:`#543`).
- Convert fields names into valid Python identifiers in
`~psycopg2.extras.NamedTupleCursor` (:ticket:`#211`).
- Fixed Solaris 10 support (:ticket:`#532`).
- `cursor.mogrify()` can be called on closed cursors (:ticket:`#579`).
- Fixed setting session characteristics in corner cases on autocommit
connections (:ticket:`#580`).
- Fixed `~psycopg2.extras.MinTimeLoggingCursor` on Python 3 (:ticket:`#609`).
- Fixed parsing of array of points as floats (:ticket:`#613`).
- Fixed `~psycopg2.__libpq_version__` building with libpq >= 10.1
(:ticket:`#632`).
- Fixed `~cursor.rowcount` after `~cursor.executemany()` with :sql:`RETURNING`
statements (:ticket:`#633`).
- Fixed compatibility problem with pypy3 (:ticket:`#649`).
- Wheel packages bundled with PostgreSQL 10.1 libpq and OpenSSL 1.0.2n.
- Wheel packages for Python 2.6 no more available (support dropped from
wheel building infrastructure).
What's new in psycopg 2.7.3.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Wheel package bundled with PostgreSQL 10.0 libpq and OpenSSL 1.0.2l
(:tickets:`#601, #602`).
What's new in psycopg 2.7.3.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Dropped libresolv from wheel package to avoid incompatibility with
glibc 2.26 (wheels ticket #2).
What's new in psycopg 2.7.3
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Restored default :sql:`timestamptz[]` typecasting to Python `!datetime`.
Regression introduced in Psycopg 2.7.2 (:ticket:`#578`).
What's new in psycopg 2.7.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed inconsistent state in externally closed connections
(:tickets:`#263, #311, #443`). Was fixed in 2.6.2 but not included in
2.7 by mistake.
- Fixed Python exceptions propagation in green callback (:ticket:`#410`).
- Don't display the password in `connection.dsn` when the connection
string is specified as an URI (:ticket:`#528`).
- Return objects with timezone parsing "infinity" :sql:`timestamptz`
(:ticket:`#536`).
- Dropped dependency on VC9 runtime on Windows binary packages
(:ticket:`#541`).
- Fixed segfault in `~connection.lobject()` when *mode*\=\ `!None`
(:ticket:`#544`).
- Fixed `~connection.lobject()` keyword argument *lobject_factory*
(:ticket:`#545`).
- Fixed `~psycopg2.extras.ReplicationCursor.consume_stream()`
*keepalive_interval* argument (:ticket:`#547`).
- Maybe fixed random import error on Python 3.6 in multiprocess
environment (:ticket:`#550`).
- Fixed random `!SystemError` upon receiving abort signal (:ticket:`#551`).
- Accept `~psycopg2.sql.Composable` objects in
`~psycopg2.extras.ReplicationCursor.start_replication_expert()`
(:ticket:`#554`).
- Parse intervals returned as microseconds from Redshift (:ticket:`#558`).
- Added `~psycopg2.extras.Json` `!prepare()` method to consider connection
params when adapting (:ticket:`#562`).
- `~psycopg2.errorcodes` map updated to PostgreSQL 10 beta 1.
What's new in psycopg 2.7.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Ignore `!None` arguments passed to `~psycopg2.connect()` and
`~psycopg2.extensions.make_dsn()` (:ticket:`#517`).
- OpenSSL upgraded from major version 0.9.8 to 1.0.2 in the Linux wheel
packages (:ticket:`#518`).
- Fixed build with libpq versions < 9.3 (:ticket:`#520`).
What's new in psycopg 2.7
-------------------------
New features:
- Added `~psycopg2.sql` module to generate SQL dynamically (:ticket:`#308`).
- Added :ref:`replication-support` (:ticket:`#322`). Main authors are
Oleksandr Shulgin and Craig Ringer, who deserve a huge thank you.
- Added `~psycopg2.extensions.parse_dsn()` and
`~psycopg2.extensions.make_dsn()` functions (:tickets:`#321, #363`).
`~psycopg2.connect()` now can take both *dsn* and keyword arguments, merging
them together.
- Added `~psycopg2.__libpq_version__` and
`~psycopg2.extensions.libpq_version()` to inspect the version of the
``libpq`` library the module was bundled with
(:tickets:`#35, #323`).
- The attributes `~connection.notices` and `~connection.notifies` can be
customized replacing them with any object exposing an `!append()` method
(:ticket:`#326`).
- Adapt network types to `ipaddress` objects when available. When not
enabled, convert arrays of network types to lists by default. The old `!Inet`
adapter is deprecated (:tickets:`#317, #343, #387`).
- Added `~psycopg2.extensions.quote_ident()` function (:ticket:`#359`).
- Added `~connection.get_dsn_parameters()` connection method (:ticket:`#364`).
- `~cursor.callproc()` now accepts a dictionary of parameters (:ticket:`#381`).
- Give precedence to `!__conform__()` over superclasses to choose an object
adapter (:ticket:`#456`).
- Using Python C API decoding functions and codecs caching for faster
unicode encoding/decoding (:ticket:`#473`).
- `~cursor.executemany()` slowness addressed by
`~psycopg2.extras.execute_batch()` and `~psycopg2.extras.execute_values()`
(:ticket:`#491`).
- Added ``async_`` as an alias for ``async`` to support Python 3.7 where
``async`` will become a keyword (:ticket:`#495`).
- Unless in autocommit, do not use :sql:`default_transaction_*` settings to
control the session characteristics as it may create problems with external
connection pools such as pgbouncer; use :sql:`BEGIN` options instead
(:ticket:`#503`).
- `~connection.isolation_level` is now writable and entirely separated from
`~connection.autocommit`; added `~connection.readonly`,
`~connection.deferrable` writable attributes.
Bug fixes:
- Throw an exception trying to pass ``NULL`` chars as parameters
(:ticket:`#420`).
- Fixed error caused by missing decoding `~psycopg2.extras.LoggingConnection`
(:ticket:`#483`).
- Fixed integer overflow in :sql:`interval` seconds (:ticket:`#512`).
- Make `~psycopg2.extras.Range` objects picklable (:ticket:`#462`).
- Fixed version parsing and building with PostgreSQL 10 (:ticket:`#489`).
Other changes:
- Dropped support for Python 2.5 and 3.1.
- Dropped support for client library older than PostgreSQL 9.1 (but older
server versions are still supported).
- `~connection.isolation_level` doesn't read from the database but will return
`~psycopg2.extensions.ISOLATION_LEVEL_DEFAULT` if no value was set on the
connection.
- Empty arrays no more converted into lists if they don't have a type attached
(:ticket:`#506`)
What's new in psycopg 2.6.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed inconsistent state in externally closed connections
(:tickets:`#263, #311, #443`).
- Report the server response status on errors (such as :ticket:`#281`).
- Raise `!NotSupportedError` on unhandled server response status
(:ticket:`#352`).
- Allow overriding string adapter encoding with no connection (:ticket:`#331`).
- The `~psycopg2.extras.wait_select` callback allows interrupting a
long-running query in an interactive shell using :kbd:`Ctrl-C`
(:ticket:`#333`).
- Fixed `!PersistentConnectionPool` on Python 3 (:ticket:`#348`).
- Fixed segfault on `repr()` of an unitialized connection (:ticket:`#361`).
- Allow adapting bytes using `~psycopg2.extensions.QuotedString` on Python 3
(:ticket:`#365`).
- Added support for setuptools/wheel (:ticket:`#370`).
- Fix build on Windows with Python 3.5, VS 2015 (:ticket:`#380`).
- Fixed `!errorcodes.lookup` initialization thread-safety (:ticket:`#382`).
- Fixed `!read()` exception propagation in copy_from (:ticket:`#412`).
- Fixed possible NULL TZ decref (:ticket:`#424`).
- `~psycopg2.errorcodes` map updated to PostgreSQL 9.5.
What's new in psycopg 2.6.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Lists consisting of only `None` are escaped correctly (:ticket:`#285`).
- Fixed deadlock in multithread programs using OpenSSL (:ticket:`#290`).
- Correctly unlock the connection after error in flush (:ticket:`#294`).
- Fixed `!MinTimeLoggingCursor.callproc()` (:ticket:`#309`).
- Added support for MSVC 2015 compiler (:ticket:`#350`).
What's new in psycopg 2.6
-------------------------
New features:
- Added support for large objects larger than 2GB. Many thanks to Blake Rouse
and the MAAS Team for the feature development.
- Python `time` objects with a tzinfo specified and PostgreSQL :sql:`timetz`
data are converted into each other (:ticket:`#272`).
Bug fixes:
- Json adapter's `!str()` returns the adapted content instead of the `!repr()`
(:ticket:`#191`).
What's new in psycopg 2.5.5
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Named cursors used as context manager don't swallow the exception on exit
(:ticket:`#262`).
- `cursor.description` can be pickled (:ticket:`#265`).
- Propagate read error messages in COPY FROM (:ticket:`#270`).
- PostgreSQL time 24:00 is converted to Python 00:00 (:ticket:`#278`).
What's new in psycopg 2.5.4
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added :sql:`jsonb` support for PostgreSQL 9.4 (:ticket:`#226`).
- Fixed segfault if COPY statements are passed to `~cursor.execute()` instead
of using the proper methods (:ticket:`#219`).
- Force conversion of pool arguments to integer to avoid potentially unbounded
pools (:ticket:`#220`).
- Cursors :sql:`WITH HOLD` don't begin a new transaction upon move/fetch/close
(:ticket:`#228`).
- Cursors :sql:`WITH HOLD` can be used in autocommit (:ticket:`#229`).
- `~cursor.callproc()` doesn't silently ignore an argument without a length.
- Fixed memory leak with large objects (:ticket:`#256`).
- Make sure the internal ``_psycopg.so`` module can be imported stand-alone (to
allow modules juggling such as the one described in :ticket:`#201`).
What's new in psycopg 2.5.3
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Work around `pip issue #1630 <https://github.com/pypa/pip/issues/1630>`__
making installation via ``pip -e git+url`` impossible (:ticket:`#18`).
- Copy operations correctly set the `cursor.rowcount` attribute
(:ticket:`#180`).
- It is now possible to call `get_transaction_status()` on closed connections.
- Fixed unsafe access to object names causing assertion failures in
Python 3 debug builds (:ticket:`#188`).
- Mark the connection closed if found broken on `poll()` (from :ticket:`#192`
discussion)
- Fixed handling of dsn and closed attributes in connection subclasses
failing to connect (from :ticket:`#192` discussion).
- Added arbitrary but stable order to `Range` objects, thanks to
Chris Withers (:ticket:`#193`).
- Avoid blocking async connections on connect (:ticket:`#194`). Thanks to
Adam Petrovich for the bug report and diagnosis.
- Don't segfault using poorly defined cursor subclasses which forgot to call
the superclass init (:ticket:`#195`).
- Mark the connection closed when a Socket connection is broken, as it
happens for TCP connections instead (:ticket:`#196`).
- Fixed overflow opening a lobject with an oid not fitting in a signed int
(:ticket:`#203`).
- Fixed handling of explicit default ``cursor_factory=None`` in
`connection.cursor()` (:ticket:`#210`).
- Fixed possible segfault in named cursors creation.
- Fixed debug build on Windows, thanks to James Emerton.
What's new in psycopg 2.5.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed segfault pickling the exception raised on connection error
(:ticket:`#170`).
- Meaningful connection errors report a meaningful message, thanks to
Alexey Borzenkov (:ticket:`#173`).
- Manually creating `lobject` with the wrong parameter doesn't segfault
(:ticket:`#187`).
What's new in psycopg 2.5.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed build on Solaris 10 and 11 where the round() function is already
declared (:ticket:`#146`).
- Fixed comparison of `Range` with non-range objects (:ticket:`#164`).
Thanks to Chris Withers for the patch.
- Fixed double-free on connection dealloc (:ticket:`#166`). Thanks to
Gangadharan S.A. for the report and fix suggestion.
What's new in psycopg 2.5 What's new in psycopg 2.5
------------------------- -------------------------
@ -33,7 +621,7 @@ Other changes:
- Dropped support for Python 2.4. Please use Psycopg 2.4.x if you need it. - Dropped support for Python 2.4. Please use Psycopg 2.4.x if you need it.
- `~psycopg2.errorcodes` map updated to PostgreSQL 9.2. - `~psycopg2.errorcodes` map updated to PostgreSQL 9.2.
- Dropped Zope adapter from source repository. ZPsycopgDA now has its own - Dropped Zope adapter from source repository. ZPsycopgDA now has its own
project at <http://github.com/psycopg/ZPsycopgDA>. project at <https://github.com/psycopg/ZPsycopgDA>.
What's new in psycopg 2.4.6 What's new in psycopg 2.4.6
@ -51,7 +639,7 @@ What's new in psycopg 2.4.6
- 'register_hstore()', 'register_composite()', 'tpc_recover()' work with - 'register_hstore()', 'register_composite()', 'tpc_recover()' work with
RealDictConnection and Cursor (:ticket:`#114`). RealDictConnection and Cursor (:ticket:`#114`).
- Fixed broken pool for Zope and connections re-init across ZSQL methods - Fixed broken pool for Zope and connections re-init across ZSQL methods
in the same request (tickets #123, #125, #142). in the same request (:tickets:`#123, #125, #142`).
- connect() raises an exception instead of swallowing keyword arguments - connect() raises an exception instead of swallowing keyword arguments
when a connection string is specified as well (:ticket:`#131`). when a connection string is specified as well (:ticket:`#131`).
- Discard any result produced by 'executemany()' (:ticket:`#133`). - Discard any result produced by 'executemany()' (:ticket:`#133`).
@ -73,7 +661,7 @@ What's new in psycopg 2.4.5
- Error and its subclasses are picklable, useful for multiprocessing - Error and its subclasses are picklable, useful for multiprocessing
interaction (:ticket:`#90`). interaction (:ticket:`#90`).
- Better efficiency and formatting of timezone offset objects thanks - Better efficiency and formatting of timezone offset objects thanks
to Menno Smits (tickets #94, #95). to Menno Smits (:tickets:`#94, #95`).
- Fixed 'rownumber' during iteration on cursor subclasses. - Fixed 'rownumber' during iteration on cursor subclasses.
Regression introduced in 2.4.4 (:ticket:`#100`). Regression introduced in 2.4.4 (:ticket:`#100`).
- Added support for 'inet' arrays. - Added support for 'inet' arrays.
@ -181,7 +769,7 @@ New features and changes:
ISO885916, LATIN10, SHIFT_JIS_2004. ISO885916, LATIN10, SHIFT_JIS_2004.
- Dropped repeated dictionary lookups with unicode query/parameters. - Dropped repeated dictionary lookups with unicode query/parameters.
- Improvements to the named cusors: - Improvements to the named cursors:
- More efficient iteration on named cursors, fetching 'itersize' - More efficient iteration on named cursors, fetching 'itersize'
records at time from the backend. records at time from the backend.
@ -244,7 +832,7 @@ Main new features:
- `dict` to `hstore` adapter and `hstore` to `dict` typecaster, using both - `dict` to `hstore` adapter and `hstore` to `dict` typecaster, using both
9.0 and pre-9.0 syntax. 9.0 and pre-9.0 syntax.
- Two-phase commit protocol support as per DBAPI specification. - Two-phase commit protocol support as per DBAPI specification.
- Support for payload in notifications received from the backed. - Support for payload in notifications received from the backend.
- `namedtuple`-returning cursor. - `namedtuple`-returning cursor.
- Query execution cancel. - Query execution cancel.
@ -284,7 +872,7 @@ Bux fixes:
The old register_tstz_w_secs() function is deprecated and will raise a The old register_tstz_w_secs() function is deprecated and will raise a
warning if called. warning if called.
- Exceptions raised by the column iterator are propagated. - Exceptions raised by the column iterator are propagated.
- Exceptions raised by executemany() interators are propagated. - Exceptions raised by executemany() iterators are propagated.
What's new in psycopg 2.2.1 What's new in psycopg 2.2.1
@ -401,7 +989,7 @@ New features:
Bug fixes: Bug fixes:
- Fixed exeception in setup.py. - Fixed exception in setup.py.
- More robust detection of PostgreSQL development versions. - More robust detection of PostgreSQL development versions.
- Fixed exception in RealDictCursor, introduced in 2.0.10. - Fixed exception in RealDictCursor, introduced in 2.0.10.
@ -657,7 +1245,7 @@ What's new in psycopg 2.0 beta 7
What's new in psycopg 2.0 beta 6 What's new in psycopg 2.0 beta 6
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Support for named cursors (see examples/fetch.py). * Support for named cursors.
* Safer parsing of time intervals. * Safer parsing of time intervals.
@ -687,7 +1275,7 @@ What's new in psycopg 2.0 beta 5
* All classes have been renamed to exist in the psycopg2._psycopg module, * All classes have been renamed to exist in the psycopg2._psycopg module,
to fix problems with automatic documentation generators like epydoc. to fix problems with automatic documentation generators like epydoc.
* NOTIFY is correctly trapped (see examples/notify.py for example code.) * NOTIFY is correctly trapped.
What's new in psycopg 2.0 beta 4 What's new in psycopg 2.0 beta 4
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -783,7 +1371,7 @@ What's new in psycopg 1.99.11
* changed 'tuple_factory' cursor attribute name to 'row_factory'. * changed 'tuple_factory' cursor attribute name to 'row_factory'.
* the .cursor attribute is gone and connections and cursors are propely * the .cursor attribute is gone and connections and cursors are properly
gc-managed. gc-managed.
* fixes to the async core. * fixes to the async core.
@ -804,8 +1392,7 @@ What's new in psycopg 1.99.10
What's new in psycopg 1.99.9 What's new in psycopg 1.99.9
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Added simple pooling code (psycopg.pool module); see the reworked * Added simple pooling code (psycopg.pool module).
examples/threads.py for example code.
* Added DECIMAL typecaster to convert postgresql DECIMAL and NUMERIC * Added DECIMAL typecaster to convert postgresql DECIMAL and NUMERIC
types (i.e, all types with an OID of NUMERICOID.) Note that the types (i.e, all types with an OID of NUMERICOID.) Note that the
@ -832,7 +1419,7 @@ What's new in psycopg 1.99.8
* now cursors support .fileno() and .isready() methods, to be used in * now cursors support .fileno() and .isready() methods, to be used in
select() calls. select() calls.
* .copy_from() and .copy_in() methods are back in (still using the old * .copy_from() and .copy_in() methods are back in (still using the old
protocol, will be updated to use new one in next releasae.) protocol, will be updated to use new one in next release.)
* fixed memory corruption bug reported on win32 platform. * fixed memory corruption bug reported on win32 platform.
What's new in psycopg 1.99.7 What's new in psycopg 1.99.7

38
README
View File

@ -1,38 +0,0 @@
psycopg2 - Python-PostgreSQL Database Adapter
********************************************
psycopg2 is a PostgreSQL database adapter for the Python programming
language. psycopg2 was written with the aim of being very small and fast,
and stable as a rock.
psycopg2 is different from the other database adapter because it was
designed for heavily multi-threaded applications that create and destroy
lots of cursors and make a conspicuous number of concurrent INSERTs or
UPDATEs. psycopg2 also provides full asynchronous operations and support
for coroutine libraries.
psycopg2 can compile and run on Linux, FreeBSD, Solaris, MacOS X and
Windows architecture. It supports Python versions from 2.4 onwards and
PostgreSQL versions from 7.4 onwards.
psycopg2 is free software ("free as in freedom" but I like beer too.)
It is licensed under the GNU Lesser General Public License, version 3 or
later plus an exception to allow OpenSSL (libpq) linking; see LICENSE for
more details.
Documentation
-------------
Start by reading the INSTALL file. More information about psycopg2 extensions
to the DBAPI-2.0 is available in the files located in the doc/ direcory.
Example code can be found in the examples/ directory. If you make any changes
to the code make sure to run the unit tests localed in tests/.
Online documentation can be found at: http://initd.org/psycopg/
If you stumble upon any bugs, please tell us at: http://psycopg.lighthouseapp.com/
Contributors
------------
For a list of contributors to the project, see the AUTHORS file.

80
README.rst Normal file
View File

@ -0,0 +1,80 @@
psycopg2 - Python-PostgreSQL Database Adapter
=============================================
Psycopg is the most popular PostgreSQL database adapter for the Python
programming language. Its main features are the complete implementation of
the Python DB API 2.0 specification and the thread safety (several threads can
share the same connection). It was designed for heavily multi-threaded
applications that create and destroy lots of cursors and make a large number
of concurrent "INSERT"s or "UPDATE"s.
Psycopg 2 is mostly implemented in C as a libpq wrapper, resulting in being
both efficient and secure. It features client-side and server-side cursors,
asynchronous communication and notifications, "COPY TO/COPY FROM" support.
Many Python types are supported out-of-the-box and adapted to matching
PostgreSQL data types; adaptation can be extended and customized thanks to a
flexible objects adaptation system.
Psycopg 2 is both Unicode and Python 3 friendly.
.. Note::
The psycopg2 package is still widely used and actively maintained, but it
is not expected to receive new features.
`Psycopg 3`__ is the evolution of psycopg2 and is where `new features are
being developed`__: if you are starting a new project you should probably
start from 3!
.. __: https://pypi.org/project/psycopg/
.. __: https://www.psycopg.org/psycopg3/docs/index.html
Documentation
-------------
Documentation is included in the ``doc`` directory and is `available online`__.
.. __: https://www.psycopg.org/docs/
For any other resource (source code repository, bug tracker, mailing list)
please check the `project homepage`__.
.. __: https://psycopg.org/
Installation
------------
Building Psycopg requires a few prerequisites (a C compiler, some development
packages): please check the install_ and the faq_ documents in the ``doc`` dir
or online for the details.
If prerequisites are met, you can install psycopg like any other Python
package, using ``pip`` to download it from PyPI_::
$ pip install psycopg2
or using ``setup.py`` if you have downloaded the source package locally::
$ python setup.py build
$ sudo python setup.py install
You can also obtain a stand-alone package, not requiring a compiler or
external libraries, by installing the `psycopg2-binary`_ package from PyPI::
$ pip install psycopg2-binary
The binary package is a practical choice for development and testing but in
production it is advised to use the package built from sources.
.. _PyPI: https://pypi.org/project/psycopg2/
.. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/
.. _install: https://www.psycopg.org/docs/install.html#install-from-source
.. _faq: https://www.psycopg.org/docs/faq.html#faq-compile
:Build status: |gh-actions|
.. |gh-actions| image:: https://github.com/psycopg/psycopg2/actions/workflows/tests.yml/badge.svg
:target: https://github.com/psycopg/psycopg2/actions/workflows/tests.yml
:alt: Build status

8
doc/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
env
src/_build/*
html/*
psycopg2.txt
src/sqlstate_errors.rst
# Added by psycopg-website to customize published docs
src/_templates/layout.html

View File

@ -1,676 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,7 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
General information
*******************
Some help to people wanting to hack on psycopg. First of all, note that
*every* function in the psycopg module source code is prefixed by one of the
following words:
psyco is used for function directly callable from python (i.e., functions
in the psycopg module itself.) the only notable exception is the
source code for the module itself, that uses "psyco" even for C-only
functions.
conn is used for functions related to connection objects.
curs is used for functions related to cursor objects.
typecast is used for typecasters and utility function related to
typecaster creation and registration.
Pythonic definition of types and functions available from python are defined
in *_type.c files. Internal functions, callable only from C are located in
*_int.c files and extensions to the DBAPI can be found in the *_ext.c files.
Patches
*******
If you submit a patch, please send a diff generated with the "-u" switch.
Also note that I don't like that much cosmetic changes (like renaming
already existing variables) and I will rewrap the patch to 78 columns
anyway, so it is much better if you do that beforehand.
The type system
***************
Simple types, like integers and strings, are converted to python base types
(the conversion functions are in typecast_base.c). Complex types are
converted to ad-hoc types, defined in the typeobj_*.{c,h} files. The
conversion function are in the other typecast_*.c files. typecast.c defines
the basic utility functions (available through the psycopg module) used when
defining new typecasters from C and python.

View File

@ -1,23 +1,39 @@
.PHONY: help clean html text doctest .PHONY: env help clean html package doctest
docs: html text docs: html
check: doctest check: doctest
help: # The environment is currently required to build the documentation.
cd src && $(MAKE) $@ # It is not clean by 'make clean'
html: PYTHON := python$(PYTHON_VERSION)
cd src && $(MAKE) $@ PYTHON_VERSION ?= $(shell $(PYTHON) -c 'import sys; print("%d.%d" % sys.version_info[:2])')
BUILD_DIR = $(shell pwd)/../build/lib.$(PYTHON_VERSION)
SPHINXBUILD ?= $$(pwd)/env/bin/sphinx-build
SPHOPTS = SPHINXBUILD=$(SPHINXBUILD)
html: package src/sqlstate_errors.rst
$(MAKE) $(SPHOPTS) -C src $@
cp -r src/_build/html . cp -r src/_build/html .
text: src/sqlstate_errors.rst: ../psycopg/sqlstate_errors.h $(BUILD_DIR)
cd src && $(MAKE) $@ ./env/bin/python src/tools/make_sqlstate_docs.py $< > $@
cd src && tools/stitch_text.py index.rst _build/text > ../psycopg2.txt
$(BUILD_DIR):
$(MAKE) PYTHON=$(PYTHON) -C .. package
doctest: doctest:
cd src && $(MAKE) $@ $(MAKE) PYTHON=$(PYTHON) -C .. package
$(MAKE) $(SPHOPTS) -C src $@
clean: clean:
cd src && $(MAKE) $@ $(MAKE) $(SPHOPTS) -C src $@
rm -rf html psycopg2.txt rm -rf html src/sqlstate_errors.rst
env: requirements.txt
$(PYTHON) -m venv env
./env/bin/pip install -r requirements.txt
echo "$$(pwd)/../build/lib.$(PYTHON_VERSION)" \
> env/lib/python$(PYTHON_VERSION)/site-packages/psycopg.pth

View File

@ -1,42 +0,0 @@
How to build psycopg documentation
----------------------------------
- Install Sphinx, maybe in a virtualenv. Tested with Sphinx 0.6.4::
~$ virtualenv pd
New python executable in pd/bin/python
Installing setuptools............done.
~$ cd pd
~/pd$ source bin/activate
(pd)~/pd$
- Install Sphinx in the env::
(pd)~/pd$ easy_install sphinx
Searching for sphinx
Reading http://pypi.python.org/simple/sphinx/
Reading http://sphinx.pocoo.org/
Best match: Sphinx 0.6.4
...
Finished processing dependencies for sphinx
- Build psycopg2 and ensure the package can be imported (it will be used for
reading the version number, autodocs etc.)::
(pd)~/pd/psycopg2$ python setup.py build
(pd)~/pd/psycopg2$ python setup.py install
running install
...
creating ~/pd/lib/python2.6/site-packages/psycopg2
...
- Move to the ``doc`` dir and run ``make`` from there::
(pd)~/pd/psycopg2$ cd doc/
(pd)~/pd/psycopg2/doc$ make
Running Sphinx v0.6.4
...
You should have the rendered documentation in ``./html`` and the text file
``psycopg2.txt`` now.

20
doc/README.rst Normal file
View File

@ -0,0 +1,20 @@
How to build psycopg documentation
----------------------------------
Building the documentation usually requires building the library too for
introspection, so you will need the same prerequisites_. The only extra
prerequisite is virtualenv_: the packages needed to build the docs will be
installed when building the env.
.. _prerequisites: https://www.psycopg.org/docs/install.html#install-from-source
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
Build the env once with::
make env
Then you can build the documentation with::
make
You should find the rendered documentation in the ``html`` directory.

View File

@ -23,7 +23,7 @@ Date: 23 Oct 2001 09:53:11 +0600
We use psycopg and psycopg zope adapter since fisrt public We use psycopg and psycopg zope adapter since fisrt public
release (it seems version 0.4). Now it works on 3 our sites and in intranet release (it seems version 0.4). Now it works on 3 our sites and in intranet
applications. We had few problems, but all problems were quckly applications. We had few problems, but all problems were quickly
solved. The strong side of psycopg is that it's code is well organized solved. The strong side of psycopg is that it's code is well organized
and easy to understand. When I found a problem with non-ISO datestyle in first and easy to understand. When I found a problem with non-ISO datestyle in first
version of psycopg, it took for me 15 or 20 minutes to learn code and version of psycopg, it took for me 15 or 20 minutes to learn code and

View File

@ -255,7 +255,7 @@ Cursor Objects
display_size, internal_size, precision, scale, display_size, internal_size, precision, scale,
null_ok). The first two items (name and type_code) are null_ok). The first two items (name and type_code) are
mandatory, the other five are optional and must be set to mandatory, the other five are optional and must be set to
None if meaningfull values are not provided. None if meaningful values are not provided.
This attribute will be None for operations that This attribute will be None for operations that
do not return rows or if the cursor has not had an do not return rows or if the cursor has not had an

68
doc/release.rst Normal file
View File

@ -0,0 +1,68 @@
How to make a psycopg2 release
==============================
- Edit ``setup.py`` and set a stable version release. Use PEP 440 to choose
version numbers, e.g.
- ``2.7``: a new major release, new features
- ``2.7.1``: a bugfix release
- ``2.7.1.1``: a release to fix packaging problems
- ``2.7.2.dev0``: version held during development, non-public test packages...
- ``2.8b1``: a beta for public tests
In the rest of this document we assume you have exported the version number
into an environment variable, e.g.::
$ export VERSION=2.8.4
- Push psycopg2 to master or to the maint branch. Make sure tests on `GitHub
Actions`__.
.. __: https://github.com/psycopg/psycopg2/actions/workflows/tests.yml
- Create a signed tag with the content of the relevant NEWS bit and push it.
E.g.::
# Tag name will be 2_8_4
$ git tag -a -s ${VERSION//\./_}
Psycopg 2.8.4 released
What's new in psycopg 2.8.4
---------------------------
New features:
- Fixed bug blah (:ticket:`#42`).
...
- Create the packages:
- On GitHub Actions run manually a `package build workflow`__.
.. __: https://github.com/psycopg/psycopg2/actions/workflows/packages.yml
- When the workflows have finished download the packages from the job
artifacts.
- Only for stable packages: upload the signed packages on PyPI::
$ twine upload -s wheelhouse/psycopg2-${VERSION}/*
- Create a release and release notes in the psycopg website, announce to
psycopg and pgsql-announce mailing lists.
- Edit ``setup.py`` changing the version again (e.g. go to ``2.8.5.dev0``).
Releasing test packages
-----------------------
Test packages may be uploaded on the `PyPI testing site`__ using::
$ twine upload -s -r testpypi wheelhouse/psycopg2-${VERSION}/*
assuming `proper configuration`__ of ``~/.pypirc``.
.. __: https://test.pypi.org/project/psycopg2/
.. __: https://wiki.python.org/moin/TestPyPI

2
doc/requirements.in Normal file
View File

@ -0,0 +1,2 @@
Sphinx
sphinx-better-theme

50
doc/requirements.txt Normal file
View File

@ -0,0 +1,50 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements.in
#
alabaster==0.7.13
# via sphinx
babel==2.12.1
# via sphinx
certifi>=2023.7.22
# via requests
charset-normalizer==3.1.0
# via requests
docutils==0.19
# via sphinx
idna==3.4
# via requests
imagesize==1.4.1
# via sphinx
jinja2==3.1.2
# via sphinx
markupsafe==2.1.2
# via jinja2
packaging==23.1
# via sphinx
pygments==2.15.0
# via sphinx
requests==2.31.0
# via sphinx
snowballstemmer==2.2.0
# via sphinx
sphinx==6.1.3
# via -r requirements.in
sphinx-better-theme==0.1.5
# via -r requirements.in
sphinxcontrib-applehelp==1.0.4
# via sphinx
sphinxcontrib-devhelp==1.0.2
# via sphinx
sphinxcontrib-htmlhelp==2.0.1
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
urllib3==1.26.17
# via requests

View File

@ -1,5 +1,3 @@
@import url("default.css");
blockquote { blockquote {
font-style: italic; font-style: italic;
} }
@ -14,11 +12,18 @@ div.dbapi-extension {
border: 1px solid #aaf; border: 1px solid #aaf;
} }
code.sql,
tt.sql { tt.sql {
font-size: 1em; font-size: 1em;
background-color: transparent; background-color: transparent;
} }
a > code.sql,
a > tt.sql {
font-weight: normal;
}
a > code.sql:hover,
a > tt.sql:hover { a > tt.sql:hover {
text-decoration: underline; text-decoration: underline;
} }
@ -30,3 +35,102 @@ dl.faq dt {
table.data-types div.line-block { table.data-types div.line-block {
margin-bottom: 0; margin-bottom: 0;
} }
/* better theme customisation */
body {
background-color: #216464;
}
header, .related, .document, footer {
background-color: white;
}
header h1 {
font-size: 150%;
margin-bottom: 0;
padding: 0.5rem 10px 0.5rem 10px;
}
h1, h2, h3 {
font-weight: normal;
}
.body h1, .body h2, .body h3 {
color: #074848;
}
h1 {
font-size: 200%;
}
h2 {
font-size: 160%;
}
h3 {
font-size: 140%;
}
footer#pagefooter {
margin-bottom: 1rem;
font-size: 85%;
color: #444;
}
#rellinks, #breadcrumbs {
padding-right: 10px;
padding-left: 10px;
}
.sphinxsidebar {
padding-left: 10px;
}
.bodywrapper {
padding-right: 10px;
}
div.body h1, div.body h2, div.body h3 {
background-color: #f2f2f2;
border-bottom: 1px solid #d0d0d0;
}
div.body p.rubric {
border-bottom: 1px solid #d0d0d0;
}
body .sphinxsidebar .search {
margin-top: 0;
}
html pre {
background-color: #efc;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
a, a:visited {
color: #0b6868;
}
th {
background-color: #ede;
}
code.xref, a code {
font-weight: bold;
}
code.descname {
font-weight: bold;
font-size: 120%;
}
@media (max-width: 820px) {
body {
background-color: white;
}
}

View File

@ -0,0 +1,6 @@
{# Add a title over the search box #}
{%- if pagename != "search" %}
<h3>Quick search</h3>
{%- include "!searchbox.html" %}
{%- endif %}

View File

@ -12,7 +12,7 @@ More advanced topics
conn.commit() conn.commit()
def wait(conn): def wait(conn):
while 1: while True:
state = conn.poll() state = conn.poll()
if state == psycopg2.extensions.POLL_OK: if state == psycopg2.extensions.POLL_OK:
break break
@ -47,7 +47,7 @@ it is the class where query building, execution and result type-casting into
Python variables happens. Python variables happens.
The `~psycopg2.extras` module contains several examples of :ref:`connection The `~psycopg2.extras` module contains several examples of :ref:`connection
and cursor sublcasses <cursor-subclasses>`. and cursor subclasses <cursor-subclasses>`.
.. note:: .. note::
@ -145,7 +145,9 @@ geometric type:
... self.y = y ... self.y = y
>>> def adapt_point(point): >>> def adapt_point(point):
... return AsIs("'(%s, %s)'" % (adapt(point.x), adapt(point.y))) ... x = adapt(point.x).getquoted()
... y = adapt(point.y).getquoted()
... return AsIs("'(%s, %s)'" % (x, y))
>>> register_adapter(Point, adapt_point) >>> register_adapter(Point, adapt_point)
@ -154,7 +156,7 @@ geometric type:
.. |point| replace:: :sql:`point` .. |point| replace:: :sql:`point`
.. _point: http://www.postgresql.org/docs/current/static/datatype-geometric.html#DATATYPE-GEOMETRIC .. _point: https://www.postgresql.org/docs/current/static/datatype-geometric.html#DATATYPE-GEOMETRIC
The above function call results in the SQL command:: The above function call results in the SQL command::
@ -224,7 +226,7 @@ read:
>>> cur.execute("SELECT '(10.2,20.3)'::point") >>> cur.execute("SELECT '(10.2,20.3)'::point")
>>> point = cur.fetchone()[0] >>> point = cur.fetchone()[0]
>>> print type(point), point.x, point.y >>> print(type(point), point.x, point.y)
<class 'Point'> 10.2 20.3 <class 'Point'> 10.2 20.3
A typecaster created by `!new_type()` can be also used with A typecaster created by `!new_type()` can be also used with
@ -257,9 +259,9 @@ documentation), you should keep the connection in `~connection.autocommit`
mode if you wish to receive or send notifications in a timely manner. mode if you wish to receive or send notifications in a timely manner.
.. |LISTEN| replace:: :sql:`LISTEN` .. |LISTEN| replace:: :sql:`LISTEN`
.. _LISTEN: http://www.postgresql.org/docs/current/static/sql-listen.html .. _LISTEN: https://www.postgresql.org/docs/current/static/sql-listen.html
.. |NOTIFY| replace:: :sql:`NOTIFY` .. |NOTIFY| replace:: :sql:`NOTIFY`
.. _NOTIFY: http://www.postgresql.org/docs/current/static/sql-notify.html .. _NOTIFY: https://www.postgresql.org/docs/current/static/sql-notify.html
Notifications are received after every query execution. If the user is Notifications are received after every query execution. If the user is
interested in receiving notifications but not in performing any query, the interested in receiving notifications but not in performing any query, the
@ -268,7 +270,7 @@ wasting resources.
A simple application could poll the connection from time to time to check if A simple application could poll the connection from time to time to check if
something new has arrived. A better strategy is to use some I/O completion something new has arrived. A better strategy is to use some I/O completion
function such as :py:func:`~select.select` to sleep until awaken from the kernel when there is function such as :py:func:`~select.select` to sleep until awakened by the kernel when there is
some data to read on the connection, thereby using no CPU unless there is some data to read on the connection, thereby using no CPU unless there is
something to read:: something to read::
@ -282,18 +284,20 @@ something to read::
curs = conn.cursor() curs = conn.cursor()
curs.execute("LISTEN test;") curs.execute("LISTEN test;")
print "Waiting for notifications on channel 'test'" print("Waiting for notifications on channel 'test'")
while 1: while True:
if select.select([conn],[],[],5) == ([],[],[]): if select.select([conn],[],[],5) == ([],[],[]):
print "Timeout" print("Timeout")
else: else:
conn.poll() conn.poll()
while conn.notifies: while conn.notifies:
notify = conn.notifies.pop() notify = conn.notifies.pop(0)
print "Got NOTIFY:", notify.pid, notify.channel, notify.payload print("Got NOTIFY:", notify.pid, notify.channel, notify.payload)
Running the script and executing a command such as :sql:`NOTIFY test, 'hello'` Running the script and executing a command such as :sql:`NOTIFY test, 'hello'`
in a separate :program:`psql` shell, the output may look similar to:: in a separate :program:`psql` shell, the output may look similar to:
.. code-block:: none
Waiting for notifications on channel 'test' Waiting for notifications on channel 'test'
Timeout Timeout
@ -310,6 +314,10 @@ received from a previous version server will have the
Added `~psycopg2.extensions.Notify` object and handling notification Added `~psycopg2.extensions.Notify` object and handling notification
payload. payload.
.. versionchanged:: 2.7
The `~connection.notifies` attribute is writable: it is possible to
replace it with any object exposing an `!append()` method. An useful
example would be to use a `~collections.deque` object.
.. index:: .. index::
@ -320,7 +328,7 @@ received from a previous version server will have the
Asynchronous support Asynchronous support
-------------------- --------------------
.. versionadded:: 2.2.0 .. versionadded:: 2.2
Psycopg can issue asynchronous queries to a PostgreSQL database. An asynchronous Psycopg can issue asynchronous queries to a PostgreSQL database. An asynchronous
communication style is established passing the parameter *async*\=1 to the communication style is established passing the parameter *async*\=1 to the
@ -339,7 +347,7 @@ together with the Python :py:func:`~select.select` function in order to carry on
asynchronous operations with Psycopg:: asynchronous operations with Psycopg::
def wait(conn): def wait(conn):
while 1: while True:
state = conn.poll() state = conn.poll()
if state == psycopg2.extensions.POLL_OK: if state == psycopg2.extensions.POLL_OK:
break break
@ -367,7 +375,7 @@ completely non-blocking connection attempt: see the libpq documentation for
|PQconnectStart|_. |PQconnectStart|_.
.. |PQconnectStart| replace:: `!PQconnectStart()` .. |PQconnectStart| replace:: `!PQconnectStart()`
.. _PQconnectStart: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS .. _PQconnectStart: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNECTSTARTPARAMS
The same loop should be also used to perform nonblocking queries: after The same loop should be also used to perform nonblocking queries: after
sending a query via `~cursor.execute()` or `~cursor.callproc()`, call sending a query via `~cursor.execute()` or `~cursor.callproc()`, call
@ -417,7 +425,7 @@ this will be probably implemented in a future release.
Support for coroutine libraries Support for coroutine libraries
------------------------------- -------------------------------
.. versionadded:: 2.2.0 .. versionadded:: 2.2
Psycopg can be used together with coroutine_\-based libraries and participate Psycopg can be used together with coroutine_\-based libraries and participate
in cooperative multithreading. in cooperative multithreading.
@ -460,7 +468,7 @@ example callback (using `!select()` to block) is provided as
`psycopg2.extras.wait_select()`: it boils down to something similar to:: `psycopg2.extras.wait_select()`: it boils down to something similar to::
def wait_select(conn): def wait_select(conn):
while 1: while True:
state = conn.poll() state = conn.poll()
if state == extensions.POLL_OK: if state == extensions.POLL_OK:
break break
@ -476,14 +484,14 @@ psycopg2 scope, as the callback can be tied to the libraries' implementation
details. You can check the `psycogreen`_ project for further informations and details. You can check the `psycogreen`_ project for further informations and
resources about the topic. resources about the topic.
.. _coroutine: http://en.wikipedia.org/wiki/Coroutine .. _coroutine: https://en.wikipedia.org/wiki/Coroutine
.. _greenlet: http://pypi.python.org/pypi/greenlet .. _greenlet: https://pypi.org/project/greenlet/
.. _green threads: http://en.wikipedia.org/wiki/Green_threads .. _green threads: https://en.wikipedia.org/wiki/Green_threads
.. _Eventlet: http://eventlet.net/ .. _Eventlet: https://eventlet.net/
.. _gevent: http://www.gevent.org/ .. _gevent: http://www.gevent.org/
.. _SQLAlchemy: http://www.sqlalchemy.org/ .. _SQLAlchemy: https://www.sqlalchemy.org/
.. _psycogreen: http://bitbucket.org/dvarrazzo/psycogreen/ .. _psycogreen: https://github.com/psycopg/psycogreen/
.. __: http://www.postgresql.org/docs/current/static/libpq-async.html .. __: https://www.postgresql.org/docs/current/static/libpq-async.html
.. warning:: .. warning::
@ -503,3 +511,89 @@ resources about the topic.
conn.commit() conn.commit()
cur.close() cur.close()
conn.close() conn.close()
.. index::
single: Replication
.. _replication-support:
Replication protocol support
----------------------------
.. versionadded:: 2.7
Modern PostgreSQL servers (version 9.0 and above) support replication. The
replication protocol is built on top of the client-server protocol and can be
operated using ``libpq``, as such it can be also operated by ``psycopg2``.
The replication protocol can be operated on both synchronous and
:ref:`asynchronous <async-support>` connections.
Server version 9.4 adds a new feature called *Logical Replication*.
.. seealso::
- PostgreSQL `Streaming Replication Protocol`__
.. __: https://www.postgresql.org/docs/current/static/protocol-replication.html
Logical replication Quick-Start
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You must be using PostgreSQL server version 9.4 or above to run this quick
start.
Make sure that replication connections are permitted for user ``postgres`` in
``pg_hba.conf`` and reload the server configuration. You also need to set
``wal_level=logical`` and ``max_wal_senders``, ``max_replication_slots`` to
value greater than zero in ``postgresql.conf`` (these changes require a server
restart). Create a database ``psycopg2_test``.
Then run the following code to quickly try the replication support out. This
is not production code -- it's only intended as a simple demo of logical
replication::
from __future__ import print_function
import sys
import psycopg2
import psycopg2.extras
conn = psycopg2.connect('dbname=psycopg2_test user=postgres',
connection_factory=psycopg2.extras.LogicalReplicationConnection)
cur = conn.cursor()
try:
# test_decoding produces textual output
cur.start_replication(slot_name='pytest', decode=True)
except psycopg2.ProgrammingError:
cur.create_replication_slot('pytest', output_plugin='test_decoding')
cur.start_replication(slot_name='pytest', decode=True)
class DemoConsumer(object):
def __call__(self, msg):
print(msg.payload)
msg.cursor.send_feedback(flush_lsn=msg.data_start)
democonsumer = DemoConsumer()
print("Starting streaming, press Control-C to end...", file=sys.stderr)
try:
cur.consume_stream(democonsumer)
except KeyboardInterrupt:
cur.close()
conn.close()
print("The slot 'pytest' still exists. Drop it with "
"SELECT pg_drop_replication_slot('pytest'); if no longer needed.",
file=sys.stderr)
print("WARNING: Transaction logs will accumulate in pg_xlog "
"until the slot is dropped.", file=sys.stderr)
You can now make changes to the ``psycopg2_test`` database using a normal
psycopg2 session, ``psql``, etc. and see the logical decoding stream printed
by this demo client.
This will continue running until terminated with ``Control-C``.
For the details see :ref:`replication-objects`.

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# #
# Psycopg documentation build configuration file, created by # Psycopg documentation build configuration file, created by
# sphinx-quickstart on Sun Feb 7 13:48:41 2010. # sphinx-quickstart on Sun Feb 7 13:48:41 2010.
@ -11,7 +10,9 @@
# All configuration values have a default; values that are commented out # All configuration values have a default; values that are commented out
# serve to show the default. # serve to show the default.
import sys, os import os
import sys
from better import better_theme_path
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
@ -22,11 +23,16 @@ sys.path.append(os.path.abspath('tools/lib'))
# Add any Sphinx extension module names here, as strings. They can be extensions # Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', extensions = [
'sphinx.ext.doctest', 'sphinx.ext.intersphinx' ] 'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.ifconfig',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
]
# Specific extensions for Psycopg documentation. # Specific extensions for Psycopg documentation.
extensions += [ 'dbapi_extension', 'sql_role', 'ticket_role' ] extensions += ['dbapi_extension', 'sql_role', 'ticket_role']
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']
@ -35,14 +41,16 @@ templates_path = ['_templates']
source_suffix = '.rst' source_suffix = '.rst'
# The encoding of source files. # The encoding of source files.
#source_encoding = 'utf-8' # source_encoding = 'utf-8'
# The master toctree document. # The master toctree document.
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
project = u'Psycopg' project = 'Psycopg'
copyright = u'2001-2013, Federico Di Gregorio. Documentation by Daniele Varrazzo' copyright = (
'2001-2021, Federico Di Gregorio, Daniele Varrazzo, The Psycopg Team'
)
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
@ -54,32 +62,32 @@ version = '2.0'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
try: try:
import psycopg2 import psycopg2
except ImportError:
print("WARNING: couldn't import psycopg to read version.")
release = version
else:
release = psycopg2.__version__.split()[0] release = psycopg2.__version__.split()[0]
version = '.'.join(release.split('.')[:2]) version = '.'.join(release.split('.')[:2])
except ImportError:
print "WARNING: couldn't import psycopg to read version."
release = version
intersphinx_mapping = { intersphinx_mapping = {'py': ('https://docs.python.org/3', None)}
'py': ('http://docs.python.org/', None),
'py3': ('http://docs.python.org/3.2', None),
}
# Pattern to generate links to the bug tracker # Pattern to generate links to the bug tracker
ticket_url = 'http://psycopg.lighthouseapp.com/projects/62710/tickets/%s' ticket_url = 'https://github.com/psycopg/psycopg2/issues/%s'
ticket_remap_until = 25
ticket_remap_offset = 230
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
#language = None # language = None
# There are two options for replacing |today|: either, you set today to some # There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used: # non-false value, then it is used:
#today = '' # today = ''
# Else, today_fmt is used as the format for a strftime call. # Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y' # today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build. # List of documents that shouldn't be included in the build.
#unused_docs = [] # unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched # List of directories, relative to source directory, that shouldn't be searched
# for source files. # for source files.
@ -89,21 +97,25 @@ exclude_trees = ['_build', 'html']
default_role = 'obj' default_role = 'obj'
# If true, '()' will be appended to :func: etc. cross-reference text. # If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True # add_function_parentheses = True
# If true, the current module name will be prepended to all description # If true, the current module name will be prepended to all description
# unit titles (such as .. function::). # unit titles (such as .. function::).
#add_module_names = True # add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the # If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default. # output. They are ignored by default.
#show_authors = False # show_authors = False
# Using 'python' instead of the default gives warnings if parsing an example
# fails, instead of defaulting to none
highlight_language = 'python'
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx' pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting. # A list of ignored prefixes for module index sorting.
#modindex_common_prefix = [] # modindex_common_prefix = []
# Include TODO items in the documentation # Include TODO items in the documentation
todo_include_todos = False todo_include_todos = False
@ -111,12 +123,10 @@ todo_include_todos = False
rst_epilog = """ rst_epilog = """
.. |DBAPI| replace:: DB API 2.0 .. |DBAPI| replace:: DB API 2.0
.. _DBAPI: http://www.python.org/dev/peps/pep-0249/ .. _DBAPI: https://www.python.org/dev/peps/pep-0249/
.. _transaction isolation level: .. _transaction isolation level:
http://www.postgresql.org/docs/current/static/transaction-iso.html https://www.postgresql.org/docs/current/static/transaction-iso.html
.. _mx.DateTime: http://www.egenix.com/products/python/mxBase/mxDateTime/
.. |MVCC| replace:: :abbr:`MVCC (Multiversion concurrency control)` .. |MVCC| replace:: :abbr:`MVCC (Multiversion concurrency control)`
""" """
@ -125,35 +135,41 @@ rst_epilog = """
# The theme to use for HTML and HTML Help pages. Major themes that come with # The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'. # Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default' html_theme = 'better'
# The stylesheet to use with HTML output: this will include the original one # The stylesheet to use with HTML output: this will include the original one
# adding a few classes. # adding a few classes.
html_style = 'psycopg.css' # html_style = 'psycopg.css'
# Hide the sphinx footer
html_show_sphinx = False
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the
# documentation. # documentation.
#html_theme_options = {} html_theme_options = {
'linktotheme': False,
'cssfiles': ['_static/psycopg.css'],
}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = [] html_theme_path = [better_theme_path]
# The name for this set of Sphinx documents. If None, it defaults to # The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation". # "<project> v<release> documentation".
#html_title = None # html_title = None
# A shorter title for the navigation bar. Default is the same as html_title. # A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None html_short_title = 'Home'
# The name of an image file (relative to this directory) to place at the top # The name of an image file (relative to this directory) to place at the top
# of the sidebar. # of the sidebar.
#html_logo = None # html_logo = None
# The name of an image file (within the static path) to use as favicon of the # The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
#html_favicon = None # html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
@ -162,38 +178,41 @@ html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format. # using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y' # html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to # If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities. # typographically correct entities.
#html_use_smartypants = True # html_use_smartypants = True
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
#html_sidebars = {} # no need for the prev/next topic link using better theme: they are on top
html_sidebars = {
'**': ['localtoc.html', 'searchbox.html'],
}
# Additional templates that should be rendered to pages, maps page names to # Additional templates that should be rendered to pages, maps page names to
# template names. # template names.
#html_additional_pages = {} # html_additional_pages = {}
# If false, no module index is generated. # If false, no module index is generated.
#html_use_modindex = True # html_use_modindex = True
# If false, no index is generated. # If false, no index is generated.
#html_use_index = True # html_use_index = True
# If true, the index is split into individual pages for each letter. # If true, the index is split into individual pages for each letter.
#html_split_index = False # html_split_index = False
# If true, links to the reST sources are added to the pages. # If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True # html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will # If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the # contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served. # base URL from which the finished HTML is served.
#html_use_opensearch = '' # html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = '' # html_file_suffix = ''
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'psycopgdoc' htmlhelp_basename = 'psycopgdoc'
@ -202,35 +221,41 @@ htmlhelp_basename = 'psycopgdoc'
# -- Options for LaTeX output -------------------------------------------------- # -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4'). # The paper size ('letter' or 'a4').
#latex_paper_size = 'letter' # latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt'). # The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt' # latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]). # (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [ latex_documents = [
('index', 'psycopg.tex', u'Psycopg Documentation', (
u'Federico Di Gregorio', 'manual'), 'index',
'psycopg.tex',
'Psycopg Documentation',
'Federico Di Gregorio',
'manual',
)
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
# the title page. # the title page.
#latex_logo = None # latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts, # For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters. # not chapters.
#latex_use_parts = False # latex_use_parts = False
# Additional stuff for the LaTeX preamble. # Additional stuff for the LaTeX preamble.
#latex_preamble = '' # latex_preamble = ''
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
#latex_appendices = [] # latex_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#latex_use_modindex = True # latex_use_modindex = True
toc_object_entries = False
doctest_global_setup = """ doctest_global_setup = """

View File

@ -21,6 +21,28 @@ The ``connection`` class
Connections are thread safe and can be shared among many threads. See Connections are thread safe and can be shared among many threads. See
:ref:`thread-safety` for details. :ref:`thread-safety` for details.
Connections can be used as context managers. Note that a context wraps a
transaction: if the context exits with success the transaction is
committed, if it exits with an exception the transaction is rolled back.
Note that the connection is not closed by the context and it can be used
for several contexts.
.. code:: python
conn = psycopg2.connect(DSN)
with conn:
with conn.cursor() as curs:
curs.execute(SQL1)
with conn:
with conn.cursor() as curs:
curs.execute(SQL2)
# leaving contexts doesn't close the connection
conn.close()
.. method:: cursor(name=None, cursor_factory=None, scrollable=None, withhold=False) .. method:: cursor(name=None, cursor_factory=None, scrollable=None, withhold=False)
Return a new `cursor` object using the connection. Return a new `cursor` object using the connection.
@ -41,11 +63,6 @@ The ``connection`` class
previously only valid PostgreSQL identifiers were accepted as previously only valid PostgreSQL identifiers were accepted as
cursor name. cursor name.
.. warning::
It is unsafe to expose the *name* to an untrusted source, for
instance you shouldn't allow *name* to be read from a HTML form.
Consider it as part of the query, not as a query parameter.
The *cursor_factory* argument can be used to create non-standard The *cursor_factory* argument can be used to create non-standard
cursors. The class returned must be a subclass of cursors. The class returned must be a subclass of
`psycopg2.extensions.cursor`. See :ref:`subclassing-cursor` for `psycopg2.extensions.cursor`. See :ref:`subclassing-cursor` for
@ -122,7 +139,7 @@ The ``connection`` class
with a `~connection.commit()`/`~connection.rollback()` before with a `~connection.commit()`/`~connection.rollback()` before
closing. closing.
.. _PgBouncer: http://pgbouncer.projects.postgresql.org/ .. _PgBouncer: http://www.pgbouncer.org/
.. index:: .. index::
@ -203,7 +220,7 @@ The ``connection`` class
.. seealso:: the |PREPARE TRANSACTION|_ PostgreSQL command. .. seealso:: the |PREPARE TRANSACTION|_ PostgreSQL command.
.. |PREPARE TRANSACTION| replace:: :sql:`PREPARE TRANSACTION` .. |PREPARE TRANSACTION| replace:: :sql:`PREPARE TRANSACTION`
.. _PREPARE TRANSACTION: http://www.postgresql.org/docs/current/static/sql-prepare-transaction.html .. _PREPARE TRANSACTION: https://www.postgresql.org/docs/current/static/sql-prepare-transaction.html
.. index:: .. index::
@ -229,7 +246,7 @@ The ``connection`` class
.. seealso:: the |COMMIT PREPARED|_ PostgreSQL command. .. seealso:: the |COMMIT PREPARED|_ PostgreSQL command.
.. |COMMIT PREPARED| replace:: :sql:`COMMIT PREPARED` .. |COMMIT PREPARED| replace:: :sql:`COMMIT PREPARED`
.. _COMMIT PREPARED: http://www.postgresql.org/docs/current/static/sql-commit-prepared.html .. _COMMIT PREPARED: https://www.postgresql.org/docs/current/static/sql-commit-prepared.html
.. index:: .. index::
@ -251,7 +268,7 @@ The ``connection`` class
.. seealso:: the |ROLLBACK PREPARED|_ PostgreSQL command. .. seealso:: the |ROLLBACK PREPARED|_ PostgreSQL command.
.. |ROLLBACK PREPARED| replace:: :sql:`ROLLBACK PREPARED` .. |ROLLBACK PREPARED| replace:: :sql:`ROLLBACK PREPARED`
.. _ROLLBACK PREPARED: http://www.postgresql.org/docs/current/static/sql-rollback-prepared.html .. _ROLLBACK PREPARED: https://www.postgresql.org/docs/current/static/sql-rollback-prepared.html
.. index:: .. index::
@ -272,7 +289,7 @@ The ``connection`` class
transactions initiated by a program using such driver should be transactions initiated by a program using such driver should be
unpacked correctly. unpacked correctly.
.. __: http://jdbc.postgresql.org/ .. __: https://jdbc.postgresql.org/
Xids returned by `!tpc_recover()` also have extra attributes Xids returned by `!tpc_recover()` also have extra attributes
`~psycopg2.extensions.Xid.prepared`, `~psycopg2.extensions.Xid.owner`, `~psycopg2.extensions.Xid.prepared`, `~psycopg2.extensions.Xid.owner`,
@ -282,7 +299,7 @@ The ``connection`` class
.. seealso:: the |pg_prepared_xacts|_ system view. .. seealso:: the |pg_prepared_xacts|_ system view.
.. |pg_prepared_xacts| replace:: `pg_prepared_xacts` .. |pg_prepared_xacts| replace:: `pg_prepared_xacts`
.. _pg_prepared_xacts: http://www.postgresql.org/docs/current/static/view-pg-prepared-xacts.html .. _pg_prepared_xacts: https://www.postgresql.org/docs/current/static/view-pg-prepared-xacts.html
@ -295,8 +312,8 @@ The ``connection`` class
.. attribute:: closed .. attribute:: closed
Read-only attribute reporting whether the database connection is open Read-only integer attribute: 0 if the connection is open, nonzero if
(0) or closed (1). it is closed or broken.
.. method:: cancel .. method:: cancel
@ -314,7 +331,7 @@ The ``connection`` class
|PQcancel|_. |PQcancel|_.
.. |PQcancel| replace:: `!PQcancel()` .. |PQcancel| replace:: `!PQcancel()`
.. _PQcancel: http://www.postgresql.org/docs/current/static/libpq-cancel.html#LIBPQ-PQCANCEL .. _PQcancel: https://www.postgresql.org/docs/current/static/libpq-cancel.html#LIBPQ-PQCANCEL
.. versionadded:: 2.3 .. versionadded:: 2.3
@ -330,10 +347,10 @@ The ``connection`` class
available for recover. available for recover.
.. |RESET| replace:: :sql:`RESET` .. |RESET| replace:: :sql:`RESET`
.. _RESET: http://www.postgresql.org/docs/current/static/sql-reset.html .. _RESET: https://www.postgresql.org/docs/current/static/sql-reset.html
.. |SET SESSION AUTHORIZATION| replace:: :sql:`SET SESSION AUTHORIZATION` .. |SET SESSION AUTHORIZATION| replace:: :sql:`SET SESSION AUTHORIZATION`
.. __: http://www.postgresql.org/docs/current/static/sql-set-session-authorization.html .. __: https://www.postgresql.org/docs/current/static/sql-set-session-authorization.html
.. versionadded:: 2.0.12 .. versionadded:: 2.0.12
@ -343,25 +360,28 @@ The ``connection`` class
Read-only string containing the connection string used by the Read-only string containing the connection string used by the
connection. connection.
If a password was specified in the connection string it will be
obscured.
.. rubric:: Transaction control methods and attributes.
.. index:: .. index::
pair: Transaction; Autocommit pair: Transaction; Autocommit
pair: Transaction; Isolation level pair: Transaction; Isolation level
.. method:: set_session([isolation_level,] [readonly,] [deferrable,] [autocommit]) .. method:: set_session(isolation_level=None, readonly=None, deferrable=None, autocommit=None)
Set one or more parameters for the next transactions or statements in Set one or more parameters for the next transactions or statements in
the current session. See |SET TRANSACTION|_ for further details. the current session.
.. |SET TRANSACTION| replace:: :sql:`SET TRANSACTION`
.. _SET TRANSACTION: http://www.postgresql.org/docs/current/static/sql-set-transaction.html
:param isolation_level: set the `isolation level`_ for the next :param isolation_level: set the `isolation level`_ for the next
transactions/statements. The value can be one of the transactions/statements. The value can be one of the literal
:ref:`constants <isolation-level-constants>` defined in the values ``READ UNCOMMITTED``, ``READ COMMITTED``, ``REPEATABLE
`~psycopg2.extensions` module or one of the literal values READ``, ``SERIALIZABLE`` or the equivalent :ref:`constant
``READ UNCOMMITTED``, ``READ COMMITTED``, ``REPEATABLE READ``, <isolation-level-constants>` defined in the `~psycopg2.extensions`
``SERIALIZABLE``. module.
:param readonly: if `!True`, set the connection to read only; :param readonly: if `!True`, set the connection to read only;
read/write if `!False`. read/write if `!False`.
:param deferrable: if `!True`, set the connection to deferrable; :param deferrable: if `!True`, set the connection to deferrable;
@ -370,35 +390,59 @@ The ``connection`` class
PostgreSQL session setting but an alias for setting the PostgreSQL session setting but an alias for setting the
`autocommit` attribute. `autocommit` attribute.
.. _isolation level:
https://www.postgresql.org/docs/current/static/transaction-iso.html
Arguments set to `!None` (the default for all) will not be changed.
The parameters *isolation_level*, *readonly* and *deferrable* also The parameters *isolation_level*, *readonly* and *deferrable* also
accept the string ``DEFAULT`` as a value: the effect is to reset the accept the string ``DEFAULT`` as a value: the effect is to reset the
parameter to the server default. parameter to the server default. Defaults are defined by the server
configuration: see values for |default_transaction_isolation|__,
.. _isolation level:
http://www.postgresql.org/docs/current/static/transaction-iso.html
The function must be invoked with no transaction in progress. At every
function invocation, only the specified parameters are changed.
The default for the values are defined by the server configuration:
see values for |default_transaction_isolation|__,
|default_transaction_read_only|__, |default_transaction_deferrable|__. |default_transaction_read_only|__, |default_transaction_deferrable|__.
.. |default_transaction_isolation| replace:: :sql:`default_transaction_isolation` .. |default_transaction_isolation| replace:: :sql:`default_transaction_isolation`
.. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-ISOLATION .. __: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-ISOLATION
.. |default_transaction_read_only| replace:: :sql:`default_transaction_read_only` .. |default_transaction_read_only| replace:: :sql:`default_transaction_read_only`
.. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-READ-ONLY .. __: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-READ-ONLY
.. |default_transaction_deferrable| replace:: :sql:`default_transaction_deferrable` .. |default_transaction_deferrable| replace:: :sql:`default_transaction_deferrable`
.. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-DEFERRABLE .. __: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-DEFAULT-TRANSACTION-DEFERRABLE
.. note:: The function must be invoked with no transaction in progress.
There is currently no builtin method to read the current value for .. seealso:: |SET TRANSACTION|_ for further details about the behaviour
the parameters: use :sql:`SHOW default_transaction_...` to read of the transaction parameters in the server.
the values from the backend.
.. |SET TRANSACTION| replace:: :sql:`SET TRANSACTION`
.. _SET TRANSACTION: https://www.postgresql.org/docs/current/static/sql-set-transaction.html
.. versionadded:: 2.4.2 .. versionadded:: 2.4.2
.. versionchanged:: 2.7
Before this version, the function would have set
:sql:`default_transaction_*` attribute in the current session;
this implementation has the problem of not playing well with
external connection pooling working at transaction level and not
resetting the state of the session: changing the default
transaction would pollute the connections in the pool and create
problems to other applications using the same pool.
Starting from 2.7, if the connection is not autocommit, the
transaction characteristics are issued together with :sql:`BEGIN`
and will leave the :sql:`default_transaction_*` settings untouched.
For example::
conn.set_session(readonly=True)
will not change :sql:`default_transaction_read_only`, but
following transaction will start with a :sql:`BEGIN READ ONLY`.
Conversely, using::
conn.set_session(readonly=True, autocommit=True)
will set :sql:`default_transaction_read_only` to :sql:`on` and
rely on the server to apply the read only state to whatever
transaction, implicit or explicit, is executed in the connection.
.. attribute:: autocommit .. attribute:: autocommit
@ -418,8 +462,8 @@ The ``connection`` class
By default, any query execution, including a simple :sql:`SELECT` By default, any query execution, including a simple :sql:`SELECT`
will start a transaction: for long-running programs, if no further will start a transaction: for long-running programs, if no further
action is taken, the session will remain "idle in transaction", a action is taken, the session will remain "idle in transaction", an
condition non desiderable for several reasons (locks are held by undesirable condition for several reasons (locks are held by
the session, tables bloat...). For long lived scripts, either the session, tables bloat...). For long lived scripts, either
ensure to terminate a transaction as soon as possible or use an ensure to terminate a transaction as soon as possible or use an
autocommit connection. autocommit connection.
@ -428,31 +472,83 @@ The ``connection`` class
.. attribute:: isolation_level .. attribute:: isolation_level
Return or set the `transaction isolation level`_ for the current
session. The value is one of the :ref:`isolation-level-constants`
defined in the `psycopg2.extensions` module. On set it is also
possible to use one of the literal values ``READ UNCOMMITTED``, ``READ
COMMITTED``, ``REPEATABLE READ``, ``SERIALIZABLE``, ``DEFAULT``.
.. versionchanged:: 2.7
the property is writable.
.. versionchanged:: 2.7
the default value for `!isolation_level` is
`~psycopg2.extensions.ISOLATION_LEVEL_DEFAULT`; previously the
property would have queried the server and returned the real value
applied. To know this value you can run a query such as :sql:`show
transaction_isolation`. Usually the default value is `READ
COMMITTED`, but this may be changed in the server configuration.
This value is now entirely separate from the `autocommit`
property: in previous version, if `!autocommit` was set to `!True`
this property would have returned
`~psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT`; it will now
return the server isolation level.
.. attribute:: readonly
Return or set the read-only status for the current session. Available
values are `!True` (new transactions will be in read-only mode),
`!False` (new transactions will be writable), `!None` (use the default
configured for the server by :sql:`default_transaction_read_only`).
.. versionadded:: 2.7
.. attribute:: deferrable
Return or set the `deferrable status`__ for the current session.
Available values are `!True` (new transactions will be in deferrable
mode), `!False` (new transactions will be in non deferrable mode),
`!None` (use the default configured for the server by
:sql:`default_transaction_deferrable`).
.. __: `SET TRANSACTION`_
.. versionadded:: 2.7
.. method:: set_isolation_level(level) .. method:: set_isolation_level(level)
.. note:: .. note::
From version 2.4.2, `set_session()` and `autocommit`, offer This is a legacy method mixing `~conn.isolation_level` and
finer control on the transaction characteristics. `~conn.autocommit`. Using the respective properties is a better
option.
Read or set the `transaction isolation level`_ for the current session. Set the `transaction isolation level`_ for the current session.
The level defines the different phenomena that can happen in the The level defines the different phenomena that can happen in the
database between concurrent transactions. database between concurrent transactions.
The value set or read is an integer: symbolic constants are defined in The value set is an integer: symbolic constants are defined in
the module `psycopg2.extensions`: see the module `psycopg2.extensions`: see
:ref:`isolation-level-constants` for the available values. :ref:`isolation-level-constants` for the available values.
The default level is :sql:`READ COMMITTED`: at this level a The default level is `~psycopg2.extensions.ISOLATION_LEVEL_DEFAULT`:
transaction is automatically started the first time a database command at this level a transaction is automatically started the first time a
is executed. If you want an *autocommit* mode, switch to database command is executed. If you want an *autocommit* mode,
`~psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT` before switch to `~psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT` before
executing any command:: executing any command::
>>> conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) >>> conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
See also :ref:`transactions-control`. See also :ref:`transactions-control`.
.. index:: .. index::
pair: Client; Encoding pair: Client; Encoding
@ -463,7 +559,7 @@ The ``connection`` class
is the encoding defined by the database. It should be one of the is the encoding defined by the database. It should be one of the
`characters set supported by PostgreSQL`__ `characters set supported by PostgreSQL`__
.. __: http://www.postgresql.org/docs/current/static/multibyte.html .. __: https://www.postgresql.org/docs/current/static/multibyte.html
.. index:: .. index::
@ -475,21 +571,29 @@ The ``connection`` class
the session. the session.
.. doctest:: .. doctest::
:options: NORMALIZE_WHITESPACE :options: +NORMALIZE_WHITESPACE
>>> cur.execute("CREATE TABLE foo (id serial PRIMARY KEY);") >>> cur.execute("CREATE TABLE foo (id serial PRIMARY KEY);")
>>> pprint(conn.notices) >>> pprint(conn.notices)
['NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"\n', ['NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"\n',
'NOTICE: CREATE TABLE will create implicit sequence "foo_id_seq" for serial column "foo.id"\n'] 'NOTICE: CREATE TABLE will create implicit sequence "foo_id_seq" for serial column "foo.id"\n']
.. versionchanged:: 2.7
The `!notices` attribute is writable: the user may replace it
with any Python object exposing an `!append()` method. If
appending raises an exception the notice is silently
dropped.
To avoid a leak in case excessive notices are generated, only the last To avoid a leak in case excessive notices are generated, only the last
50 messages are kept. 50 messages are kept. This check is only in place if the `!notices`
attribute is a list: if any other object is used it will be up to the
user to guard from leakage.
You can configure what messages to receive using `PostgreSQL logging You can configure what messages to receive using `PostgreSQL logging
configuration parameters`__ such as ``log_statement``, configuration parameters`__ such as ``log_statement``,
``client_min_messages``, ``log_min_duration_statement`` etc. ``client_min_messages``, ``log_min_duration_statement`` etc.
.. __: http://www.postgresql.org/docs/current/static/runtime-config-logging.html .. __: https://www.postgresql.org/docs/current/static/runtime-config-logging.html
.. attribute:: notifies .. attribute:: notifies
@ -505,6 +609,12 @@ The ``connection`` class
the payload was not accessible. To keep backward compatibility, the payload was not accessible. To keep backward compatibility,
`!Notify` objects can still be accessed as 2 items tuples. `!Notify` objects can still be accessed as 2 items tuples.
.. versionchanged:: 2.7
The `!notifies` attribute is writable: the user may replace it
with any Python object exposing an `!append()` method. If
appending raises an exception the notification is silently
dropped.
.. attribute:: cursor_factory .. attribute:: cursor_factory
@ -515,92 +625,14 @@ The ``connection`` class
.. index:: .. index::
pair: Backend; PID pair: Connection; Info
.. method:: get_backend_pid() .. attribute:: info
Returns the process ID (PID) of the backend server process handling A `~psycopg2.extensions.ConnectionInfo` object exposing information
this connection. about the native libpq connection.
Note that the PID belongs to a process executing on the database .. versionadded:: 2.8
server host, not the local host!
.. seealso:: libpq docs for `PQbackendPID()`__ for details.
.. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQBACKENDPID
.. versionadded:: 2.0.8
.. index::
pair: Server; Parameters
.. method:: get_parameter_status(parameter)
Look up a current parameter setting of the server.
Potential values for ``parameter`` are: ``server_version``,
``server_encoding``, ``client_encoding``, ``is_superuser``,
``session_authorization``, ``DateStyle``, ``TimeZone``,
``integer_datetimes``, and ``standard_conforming_strings``.
If server did not report requested parameter, return `!None`.
.. seealso:: libpq docs for `PQparameterStatus()`__ for details.
.. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPARAMETERSTATUS
.. versionadded:: 2.0.12
.. index::
pair: Transaction; Status
.. method:: get_transaction_status()
Return the current session transaction status as an integer. Symbolic
constants for the values are defined in the module
`psycopg2.extensions`: see :ref:`transaction-status-constants`
for the available values.
.. seealso:: libpq docs for `PQtransactionStatus()`__ for details.
.. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQTRANSACTIONSTATUS
.. index::
pair: Protocol; Version
.. attribute:: protocol_version
A read-only integer representing frontend/backend protocol being used.
Currently Psycopg supports only protocol 3, which allows connection
to PostgreSQL server from version 7.4. Psycopg versions previous than
2.3 support both protocols 2 and 3.
.. seealso:: libpq docs for `PQprotocolVersion()`__ for details.
.. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPROTOCOLVERSION
.. versionadded:: 2.0.12
.. index::
pair: Server; Version
.. attribute:: server_version
A read-only integer representing the backend version.
The number is formed by converting the major, minor, and revision
numbers into two-decimal-digit numbers and appending them together.
For example, version 8.1.5 will be returned as ``80105``.
.. seealso:: libpq docs for `PQserverVersion()`__ for details.
.. __: http://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQSERVERVERSION
.. versionadded:: 2.0.12
.. index:: .. index::
@ -613,6 +645,8 @@ The ``connection`` class
`psycopg2.extensions`: see :ref:`connection-status-constants` `psycopg2.extensions`: see :ref:`connection-status-constants`
for the available values. for the available values.
The status is undefined for `closed` connections.
.. method:: lobject([oid [, mode [, new_oid [, new_file [, lobject_factory]]]]]) .. method:: lobject([oid [, mode [, new_oid [, new_file [, lobject_factory]]]]])
@ -627,13 +661,13 @@ The ``connection`` class
:param new_oid: Create a new object using the specified OID. The :param new_oid: Create a new object using the specified OID. The
function raises `~psycopg2.OperationalError` if the OID is already function raises `~psycopg2.OperationalError` if the OID is already
in use. Default is 0, meaning assign a new one automatically. in use. Default is 0, meaning assign a new one automatically.
:param new_file: The name of a file to be imported in the the database :param new_file: The name of a file to be imported in the database
(using the |lo_import|_ function) (using the |lo_import|_ function)
:param lobject_factory: Subclass of :param lobject_factory: Subclass of
`~psycopg2.extensions.lobject` to be instantiated. `~psycopg2.extensions.lobject` to be instantiated.
.. |lo_import| replace:: `!lo_import()` .. |lo_import| replace:: `!lo_import()`
.. _lo_import: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-IMPORT .. _lo_import: https://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-IMPORT
Available values for *mode* are: Available values for *mode* are:
@ -658,17 +692,21 @@ The ``connection`` class
support. support.
.. rubric:: Methods related to asynchronous support. .. rubric:: Methods related to asynchronous support
.. versionadded:: 2.2.0 .. versionadded:: 2.2
.. seealso:: :ref:`async-support` and :ref:`green-support`. .. seealso:: :ref:`async-support` and :ref:`green-support`.
.. attribute:: async .. attribute:: async
async_
Read only attribute: 1 if the connection is asynchronous, 0 otherwise. Read only attribute: 1 if the connection is asynchronous, 0 otherwise.
.. versionchanged:: 2.7 added the `!async_` alias for Python versions
where `!async` is a keyword.
.. method:: poll() .. method:: poll()
@ -678,7 +716,7 @@ The ``connection`` class
Return one of the constants defined in :ref:`poll-constants`. If it Return one of the constants defined in :ref:`poll-constants`. If it
returns `~psycopg2.extensions.POLL_OK` then the connection has been returns `~psycopg2.extensions.POLL_OK` then the connection has been
estabilished or the query results are available on the client. established or the query results are available on the client.
Otherwise wait until the file descriptor returned by `fileno()` is Otherwise wait until the file descriptor returned by `fileno()` is
ready to read or to write, as explained in :ref:`async-support`. ready to read or to write, as explained in :ref:`async-support`.
`poll()` should be also used by the function installed by `poll()` should be also used by the function installed by
@ -700,6 +738,178 @@ The ``connection`` class
Return `!True` if the connection is executing an asynchronous operation. Return `!True` if the connection is executing an asynchronous operation.
.. rubric:: Interoperation with other C API modules
.. attribute:: pgconn_ptr
Return the internal `!PGconn*` as integer. Useful to pass the libpq
raw connection structure to C functions, e.g. via `ctypes`::
>>> import ctypes
>>> import ctypes.util
>>> libpq = ctypes.pydll.LoadLibrary(ctypes.util.find_library('pq'))
>>> libpq.PQserverVersion.argtypes = [ctypes.c_void_p]
>>> libpq.PQserverVersion.restype = ctypes.c_int
>>> libpq.PQserverVersion(conn.pgconn_ptr)
90611
.. versionadded:: 2.8
.. method:: get_native_connection()
Return the internal `!PGconn*` wrapped in a PyCapsule object. This is
only useful for passing the `libpq` raw connection associated to this
connection object to other C-level modules that may have a use for it.
.. seealso:: Python C API `Capsules`__ docs.
.. __: https://docs.python.org/3.1/c-api/capsule.html
.. versionadded:: 2.8
.. rubric:: informative methods of the native connection
.. note::
These methods are better accessed using the `~connection.info`
attributes and may be dropped in future versions.
.. index::
pair: Transaction; Status
.. method:: get_transaction_status()
Also available as `~connection.info`\ `!.`\
`~psycopg2.extensions.ConnectionInfo.transaction_status`.
Return the current session transaction status as an integer. Symbolic
constants for the values are defined in the module
`psycopg2.extensions`: see :ref:`transaction-status-constants`
for the available values.
.. seealso:: libpq docs for `PQtransactionStatus()`__ for details.
.. __: https://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQTRANSACTIONSTATUS
.. index::
pair: Protocol; Version
.. attribute:: protocol_version
Also available as `~connection.info`\ `!.`\
`~psycopg2.extensions.ConnectionInfo.protocol_version`.
A read-only integer representing frontend/backend protocol being used.
Currently Psycopg supports only protocol 3, which allows connection
to PostgreSQL server from version 7.4. Psycopg versions previous than
2.3 support both protocols 2 and 3.
.. seealso:: libpq docs for `PQprotocolVersion()`__ for details.
.. __: https://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPROTOCOLVERSION
.. versionadded:: 2.0.12
.. index::
pair: Server; Version
.. attribute:: server_version
Also available as `~connection.info`\ `!.`\
`~psycopg2.extensions.ConnectionInfo.server_version`.
A read-only integer representing the backend version.
The number is formed by converting the major, minor, and revision
numbers into two-decimal-digit numbers and appending them together.
For example, version 8.1.5 will be returned as ``80105``.
.. seealso:: libpq docs for `PQserverVersion()`__ for details.
.. __: https://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQSERVERVERSION
.. versionadded:: 2.0.12
.. index::
pair: Backend; PID
.. method:: get_backend_pid()
Also available as `~connection.info`\ `!.`\
`~psycopg2.extensions.ConnectionInfo.backend_pid`.
Returns the process ID (PID) of the backend server process *you
connected to*. Note that if you use a connection pool service such as
PgBouncer_ this value will not be updated if your connection is
switched to a different backend.
Note that the PID belongs to a process executing on the database
server host, not the local host!
.. seealso:: libpq docs for `PQbackendPID()`__ for details.
.. __: https://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQBACKENDPID
.. versionadded:: 2.0.8
.. index::
pair: Server; Parameters
.. method:: get_parameter_status(parameter)
Also available as `~connection.info`\ `!.`\
`~psycopg2.extensions.ConnectionInfo.parameter_status()`.
Look up a current parameter setting of the server.
Potential values for ``parameter`` are: ``server_version``,
``server_encoding``, ``client_encoding``, ``is_superuser``,
``session_authorization``, ``DateStyle``, ``TimeZone``,
``integer_datetimes``, and ``standard_conforming_strings``.
If server did not report requested parameter, return `!None`.
.. seealso:: libpq docs for `PQparameterStatus()`__ for details.
.. __: https://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPARAMETERSTATUS
.. versionadded:: 2.0.12
.. index::
pair: Connection; Parameters
.. method:: get_dsn_parameters()
Also available as `~connection.info`\ `!.`\
`~psycopg2.extensions.ConnectionInfo.dsn_parameters`.
Get the effective dsn parameters for the connection as a dictionary.
The *password* parameter is removed from the result.
Example::
>>> conn.get_dsn_parameters()
{'dbname': 'test', 'user': 'postgres', 'port': '5432', 'sslmode': 'prefer'}
Requires libpq >= 9.3.
.. seealso:: libpq docs for `PQconninfo()`__ for details.
.. __: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNINFO
.. versionadded:: 2.7
.. testcode:: .. testcode::
:hide: :hide:

View File

@ -34,49 +34,62 @@ The ``cursor`` class
many cursors from the same connection and should use each cursor from many cursors from the same connection and should use each cursor from
a single thread. See :ref:`thread-safety` for details. a single thread. See :ref:`thread-safety` for details.
Cursors can be used as context managers: leaving the context will close
the cursor.
.. code:: python
with conn.cursor() as curs:
curs.execute(SQL)
# the cursor is now closed
.. attribute:: description .. attribute:: description
This read-only attribute is a sequence of 7-item sequences. Read-only attribute describing the result of a query. It is a
sequence of `~psycopg2.extensions.Column` instances, each one
describing one result column in order. The attribute is `!None` for
operations that do not return rows or if the cursor has not had an
operation invoked via the |execute*|_ methods yet.
Each of these sequences is a named tuple (a regular tuple if For compatibility with the DB-API, every object can be unpacked as a
:func:`collections.namedtuple` is not available) containing information 7-items sequence: the attributes retuned this way are the following.
describing one result column: For further details and other attributes available check the
`~psycopg2.extensions.Column` documentation.
0. `!name`: the name of the column returned. 0. `~psycopg2.extensions.Column.name`: the name of the column returned.
1. `!type_code`: the PostgreSQL OID of the column. You can use the
|pg_type|_ system table to get more informations about the type.
This is the value used by Psycopg to decide what Python type use
to represent the value. See also
:ref:`type-casting-from-sql-to-python`.
2. `!display_size`: the actual length of the column in bytes.
Obtaining this value is computationally intensive, so it is
always `!None` unless the :envvar:`PSYCOPG_DISPLAY_SIZE` parameter
is set at compile time. See also PQgetlength_.
3. `!internal_size`: the size in bytes of the column associated to
this column on the server. Set to a negative value for
variable-size types See also PQfsize_.
4. `!precision`: total number of significant digits in columns of
type |NUMERIC|_. `!None` for other types.
5. `!scale`: count of decimal digits in the fractional part in
columns of type |NUMERIC|. `!None` for other types.
6. `!null_ok`: always `!None` as not easy to retrieve from the libpq.
This attribute will be `!None` for operations that do not return rows 1. `~psycopg2.extensions.Column.type_code`: the PostgreSQL OID of the
or if the cursor has not had an operation invoked via the column.
|execute*|_ methods yet.
.. |pg_type| replace:: :sql:`pg_type` 2. `~psycopg2.extensions.Column.display_size`: the actual length of
.. _pg_type: http://www.postgresql.org/docs/current/static/catalog-pg-type.html the column in bytes.
.. _PQgetlength: http://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQGETLENGTH
.. _PQfsize: http://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQFSIZE 3. `~psycopg2.extensions.Column.internal_size`: the size in bytes of
.. _NUMERIC: http://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL the column associated to this column on the server.
.. |NUMERIC| replace:: :sql:`NUMERIC`
4. `~psycopg2.extensions.Column.precision`: total number of
significant digits in columns of type |NUMERIC|. `!None`
for other types.
5. `~psycopg2.extensions.Column.scale`: count of decimal digits in
the fractional part in columns of type |NUMERIC|. `!None`
for other types.
6. `~psycopg2.extensions.Column.null_ok`: always `!None` as not easy
to retrieve from the libpq.
.. versionchanged:: 2.4 .. versionchanged:: 2.4
if possible, columns descriptions are named tuple instead of if possible, columns descriptions are named tuple instead of
regular tuples. regular tuples.
.. versionchanged:: 2.8
columns descriptions are instances of `!Column`, exposing extra
attributes.
.. |NUMERIC| replace:: :sql:`NUMERIC`
.. method:: close() .. method:: close()
Close the cursor now (rather than whenever `del` is executed). Close the cursor now (rather than whenever `del` is executed).
@ -111,7 +124,7 @@ The ``cursor`` class
.. attribute:: name .. attribute:: name
Read-only attribute containing the name of the cursor if it was Read-only attribute containing the name of the cursor if it was
creates as named cursor by `connection.cursor()`, or `!None` if created as named cursor by `connection.cursor()`, or `!None` if
it is a client side cursor. See :ref:`server-side-cursors`. it is a client side cursor. See :ref:`server-side-cursors`.
.. extension:: .. extension::
@ -129,7 +142,7 @@ The ``cursor`` class
backward scroll (see the |declare-notes|__). backward scroll (see the |declare-notes|__).
.. |declare-notes| replace:: :sql:`DECLARE` notes .. |declare-notes| replace:: :sql:`DECLARE` notes
.. __: http://www.postgresql.org/docs/current/static/sql-declare.html#SQL-DECLARE-NOTES .. __: https://www.postgresql.org/docs/current/static/sql-declare.html#SQL-DECLARE-NOTES
.. note:: .. note::
@ -171,9 +184,9 @@ The ``cursor`` class
.. rubric:: Commands execution methods .. rubric:: Commands execution methods
.. method:: execute(operation [, parameters]) .. method:: execute(query, vars=None)
Prepare and execute a database operation (query or command). Execute a database operation (query or command).
Parameters may be provided as sequence or mapping and will be bound to Parameters may be provided as sequence or mapping and will be bound to
variables in the operation. Variables are specified either with variables in the operation. Variables are specified either with
@ -184,11 +197,10 @@ The ``cursor`` class
values can be retrieved using |fetch*|_ methods. values can be retrieved using |fetch*|_ methods.
.. method:: executemany(operation, seq_of_parameters) .. method:: executemany(query, vars_list)
Prepare a database operation (query or command) and then execute it Execute a database operation (query or command) against all parameter
against all parameter tuples or mappings found in the sequence tuples or mappings found in the sequence *vars_list*.
`seq_of_parameters`.
The function is mostly useful for commands that update the database: The function is mostly useful for commands that update the database:
any result set returned by the query is discarded. any result set returned by the query is discarded.
@ -196,18 +208,47 @@ The ``cursor`` class
Parameters are bounded to the query using the same rules described in Parameters are bounded to the query using the same rules described in
the `~cursor.execute()` method. the `~cursor.execute()` method.
.. code:: python
>>> nums = ((1,), (5,), (10,))
>>> cur.executemany("INSERT INTO test (num) VALUES (%s)", nums)
>>> tuples = ((123, "foo"), (42, "bar"), (23, "baz"))
>>> cur.executemany("INSERT INTO test (num, data) VALUES (%s, %s)", tuples)
.. warning::
In its current implementation this method is not faster than
executing `~cursor.execute()` in a loop. For better performance
you can use the functions described in :ref:`fast-exec`.
.. method:: callproc(procname [, parameters]) .. method:: callproc(procname [, parameters])
Call a stored database procedure with the given name. The sequence of Call a stored database procedure with the given name. The sequence of
parameters must contain one entry for each argument that the procedure parameters must contain one entry for each argument that the procedure
expects. The result of the call is returned as modified copy of the expects. Overloaded procedures are supported. Named parameters can be
input sequence. Input parameters are left untouched, output and used by supplying the parameters as a dictionary.
input/output parameters replaced with possibly new values.
The procedure may also provide a result set as output. This must then This function is, at present, not DBAPI-compliant. The return value is
be made available through the standard |fetch*|_ methods. supposed to consist of the sequence of parameters with modified output
and input/output parameters. In future versions, the DBAPI-compliant
return value may be implemented, but for now the function returns None.
The procedure may provide a result set as output. This is then made
available through the standard |fetch*|_ methods.
.. versionchanged:: 2.7
added support for named arguments.
.. note::
`!callproc()` can only be used with PostgreSQL functions__, not
with the procedures__ introduced in PostgreSQL 11, which require
the :sql:`CALL` statement to run. Please use a normal
`execute()` to run them.
.. __: https://www.postgresql.org/docs/current/sql-createfunction.html
.. __: https://www.postgresql.org/docs/current/sql-createprocedure.html
.. method:: mogrify(operation [, parameters]) .. method:: mogrify(operation [, parameters])
@ -215,6 +256,8 @@ The ``cursor`` class
exactly the one that would be sent to the database running the exactly the one that would be sent to the database running the
`~cursor.execute()` method or similar. `~cursor.execute()` method or similar.
The returned string is always a bytes string.
>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar')) >>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')" "INSERT INTO test (num, data) VALUES (42, E'bar')"
@ -249,7 +292,7 @@ The ``cursor`` class
>>> cur.execute("SELECT * FROM test;") >>> cur.execute("SELECT * FROM test;")
>>> for record in cur: >>> for record in cur:
... print record ... print(record)
... ...
(1, 100, "abc'def") (1, 100, "abc'def")
(2, None, 'dada') (2, None, 'dada')
@ -332,10 +375,6 @@ The ``cursor`` class
`~psycopg2.ProgrammingError` is raised and the cursor position is `~psycopg2.ProgrammingError` is raised and the cursor position is
not changed. not changed.
The method can be used both for client-side cursors and
:ref:`server-side cursors <server-side-cursors>`. Server-side cursors
can usually scroll backwards only if declared `~cursor.scrollable`.
.. note:: .. note::
According to the |DBAPI|_, the exception raised for a cursor out According to the |DBAPI|_, the exception raised for a cursor out
@ -347,6 +386,13 @@ The ``cursor`` class
except (ProgrammingError, IndexError), exc: except (ProgrammingError, IndexError), exc:
deal_with_it(exc) deal_with_it(exc)
The method can be used both for client-side cursors and
:ref:`server-side cursors <server-side-cursors>`. Server-side cursors
can usually scroll backwards only if declared `~cursor.scrollable`.
Moving out-of-bound in a server-side cursor doesn't result in an
exception, if the backend doesn't raise any (Postgres doesn't tell us
in a reliable way if we went out of bound).
.. attribute:: arraysize .. attribute:: arraysize
@ -415,17 +461,17 @@ The ``cursor`` class
more flexibility. more flexibility.
.. |CREATE-TABLE| replace:: :sql:`CREATE TABLE` .. |CREATE-TABLE| replace:: :sql:`CREATE TABLE`
.. __: http://www.postgresql.org/docs/current/static/sql-createtable.html .. __: https://www.postgresql.org/docs/current/static/sql-createtable.html
.. |INSERT-RETURNING| replace:: :sql:`INSERT ... RETURNING` .. |INSERT-RETURNING| replace:: :sql:`INSERT ... RETURNING`
.. __: http://www.postgresql.org/docs/current/static/sql-insert.html .. __: https://www.postgresql.org/docs/current/static/sql-insert.html
.. attribute:: query .. attribute:: query
Read-only attribute containing the body of the last query sent to the Read-only attribute containing the body of the last query sent to the
backend (including bound arguments). `!None` if no query has been backend (including bound arguments) as bytes string. `!None` if no
executed yet: query has been executed yet:
>>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar')) >>> cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
>>> cur.query >>> cur.query
@ -470,8 +516,10 @@ The ``cursor`` class
The time zone factory used to handle data types such as The time zone factory used to handle data types such as
:sql:`TIMESTAMP WITH TIME ZONE`. It should be a `~datetime.tzinfo` :sql:`TIMESTAMP WITH TIME ZONE`. It should be a `~datetime.tzinfo`
object. A few implementations are available in the `psycopg2.tz` object. Default is `datetime.timezone`.
module.
.. versionchanged:: 2.9
previosly the default factory was `psycopg2.tz.FixedOffsetTimezone`.
.. method:: nextset() .. method:: nextset()
@ -489,6 +537,9 @@ The ``cursor`` class
.. rubric:: COPY-related methods .. rubric:: COPY-related methods
Efficiently copy data from file-like objects to the database and back. See
:ref:`copy` for an overview.
.. extension:: .. extension::
The :sql:`COPY` command is a PostgreSQL extension to the SQL standard. The :sql:`COPY` command is a PostgreSQL extension to the SQL standard.
@ -497,7 +548,7 @@ The ``cursor`` class
.. method:: copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None) .. method:: copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None)
Read data *from* the file-like object *file* appending them to Read data *from* the file-like object *file* appending them to
the table named *table*. See :ref:`copy` for an overview. the table named *table*.
:param file: file-like object to read data from. It must have both :param file: file-like object to read data from. It must have both
`!read()` and `!readline()` methods. `!read()` and `!readline()` methods.
@ -527,6 +578,11 @@ The ``cursor`` class
are encoded in the connection `~connection.encoding` when sent to are encoded in the connection `~connection.encoding` when sent to
the backend. the backend.
.. versionchanged:: 2.9
the table and fields names are now quoted. If you need to specify
a schema-qualified table please use `copy_expert()`.
.. method:: copy_to(file, table, sep='\\t', null='\\\\N', columns=None) .. method:: copy_to(file, table, sep='\\t', null='\\\\N', columns=None)
Write the content of the table named *table* *to* the file-like Write the content of the table named *table* *to* the file-like
@ -556,6 +612,10 @@ The ``cursor`` class
are decoded in the connection `~connection.encoding` when read are decoded in the connection `~connection.encoding` when read
from the backend. from the backend.
.. versionchanged:: 2.9
the table and fields names are now quoted. If you need to specify
a schema-qualified table please use `copy_expert()`.
.. method:: copy_expert(sql, file, size=8192) .. method:: copy_expert(sql, file, size=8192)
@ -570,7 +630,10 @@ The ``cursor`` class
The *sql* statement should be in the form :samp:`COPY {table} TO The *sql* statement should be in the form :samp:`COPY {table} TO
STDOUT` to export :samp:`{table}` to the *file* object passed as STDOUT` to export :samp:`{table}` to the *file* object passed as
argument or :samp:`COPY {table} FROM STDIN` to import the content of argument or :samp:`COPY {table} FROM STDIN` to import the content of
the *file* object into :samp:`{table}`. the *file* object into :samp:`{table}`. If you need to compose a
:sql:`COPY` statement dynamically (because table, fields, or query
parameters are in Python variables) you may use the objects provided
by the `psycopg2.sql` module.
*file* must be a readable file-like object (as required by *file* must be a readable file-like object (as required by
`~cursor.copy_from()`) for *sql* statement :sql:`COPY ... FROM STDIN` `~cursor.copy_from()`) for *sql* statement :sql:`COPY ... FROM STDIN`
@ -586,7 +649,7 @@ The ``cursor`` class
... ...
.. |COPY| replace:: :sql:`COPY` .. |COPY| replace:: :sql:`COPY`
.. __: http://www.postgresql.org/docs/current/static/sql-copy.html .. __: https://www.postgresql.org/docs/current/static/sql-copy.html
.. versionadded:: 2.0.6 .. versionadded:: 2.0.6
@ -595,6 +658,24 @@ The ``cursor`` class
using Unicode data instead of bytes. using Unicode data instead of bytes.
.. rubric:: Interoperation with other C API modules
.. attribute:: pgresult_ptr
Return the cursor's internal `!PGresult*` as integer. Useful to pass
the libpq raw result structure to C functions, e.g. via `ctypes`::
>>> import ctypes
>>> libpq = ctypes.pydll.LoadLibrary(ctypes.util.find_library('pq'))
>>> libpq.PQcmdStatus.argtypes = [ctypes.c_void_p]
>>> libpq.PQcmdStatus.restype = ctypes.c_char_p
>>> curs.execute("select 'x'")
>>> libpq.PQcmdStatus(curs.pgresult_ptr)
b'SELECT 1'
.. versionadded:: 2.8
.. testcode:: .. testcode::
:hide: :hide:

View File

@ -39,7 +39,7 @@ From PostgreSQL documentation:
.. seealso:: `PostgreSQL Error Codes table`__ .. seealso:: `PostgreSQL Error Codes table`__
.. __: http://www.postgresql.org/docs/current/static/errcodes-appendix.html#ERRCODES-TABLE .. __: https://www.postgresql.org/docs/current/static/errcodes-appendix.html#ERRCODES-TABLE
An example of the available constants defined in the module: An example of the available constants defined in the module:
@ -49,8 +49,8 @@ An example of the available constants defined in the module:
>>> errorcodes.UNDEFINED_TABLE >>> errorcodes.UNDEFINED_TABLE
'42P01' '42P01'
Constants representing all the error values documented by PostgreSQL versions Constants representing all the error values defined by PostgreSQL versions
between 8.1 and 9.2 are included in the module. between 8.1 and 15 are included in the module.
.. autofunction:: lookup(code) .. autofunction:: lookup(code)
@ -59,7 +59,7 @@ between 8.1 and 9.2 are included in the module.
>>> try: >>> try:
... cur.execute("SELECT ouch FROM aargh;") ... cur.execute("SELECT ouch FROM aargh;")
... except Exception, e: ... except Exception as e:
... pass ... pass
... ...
>>> errorcodes.lookup(e.pgcode[:2]) >>> errorcodes.lookup(e.pgcode[:2])

89
doc/src/errors.rst Normal file
View File

@ -0,0 +1,89 @@
`psycopg2.errors` -- Exception classes mapping PostgreSQL errors
================================================================
.. sectionauthor:: Daniele Varrazzo <daniele.varrazzo@gmail.com>
.. index::
single: Error; Class
.. module:: psycopg2.errors
.. versionadded:: 2.8
.. versionchanged:: 2.8.4 added errors introduced in PostgreSQL 12
.. versionchanged:: 2.8.6 added errors introduced in PostgreSQL 13
.. versionchanged:: 2.9.2 added errors introduced in PostgreSQL 14
.. versionchanged:: 2.9.4 added errors introduced in PostgreSQL 15
.. versionchanged:: 2.9.10 added errors introduced in PostgreSQL 17
This module exposes the classes psycopg raises upon receiving an error from
the database with a :sql:`SQLSTATE` value attached (available in the
`~psycopg2.Error.pgcode` attribute). The content of the module is generated
from the PostgreSQL source code and includes classes for every error defined
by PostgreSQL in versions between 9.1 and 15.
Every class in the module is named after what referred as "condition name" `in
the documentation`__, converted to CamelCase: e.g. the error 22012,
``division_by_zero`` is exposed by this module as the class `!DivisionByZero`.
.. __: https://www.postgresql.org/docs/current/static/errcodes-appendix.html#ERRCODES-TABLE
Every exception class is a subclass of one of the :ref:`standard DB-API
exception <dbapi-exceptions>` and expose the `~psycopg2.Error` interface.
Each class' superclass is what used to be raised by psycopg in versions before
the introduction of this module, so everything should be compatible with
previously written code catching one the DB-API class: if your code used to
catch `!IntegrityError` to detect a duplicate entry, it will keep on working
even if a more specialised subclass such as `UniqueViolation` is raised.
The new classes allow a more idiomatic way to check and process a specific
error among the many the database may return. For instance, in order to check
that a table is locked, the following code could have been used previously:
.. code-block:: python
try:
cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT")
except psycopg2.OperationalError as e:
if e.pgcode == psycopg2.errorcodes.LOCK_NOT_AVAILABLE:
locked = True
else:
raise
While this method is still available, the specialised class allows for a more
idiomatic error handler:
.. code-block:: python
try:
cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT")
except psycopg2.errors.LockNotAvailable:
locked = True
.. autofunction:: lookup
.. code-block:: python
try:
cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT")
except psycopg2.errors.lookup("55P03"):
locked = True
SQLSTATE exception classes
--------------------------
The following table contains the list of all the SQLSTATE classes exposed by
the module.
Note that, for completeness, the module also exposes all the
:ref:`DB-API-defined exceptions <dbapi-exceptions>` and :ref:`a few
psycopg-specific ones <extension-exceptions>` exposed by the `!extensions`
module, which are not listed here.
.. include:: sqlstate_errors.rst

View File

@ -12,6 +12,12 @@
The module contains a few objects and function extending the minimum set of The module contains a few objects and function extending the minimum set of
functionalities defined by the |DBAPI|_. functionalities defined by the |DBAPI|_.
Classes definitions
-------------------
Instances of these classes are usually returned by factory functions or
attributes. Their definitions are exposed here to allow subclassing,
introspection etc.
.. class:: connection(dsn, async=False) .. class:: connection(dsn, async=False)
@ -23,9 +29,12 @@ functionalities defined by the |DBAPI|_.
For a complete description of the class, see `connection`. For a complete description of the class, see `connection`.
.. versionchanged:: 2.7
*async_* can be used as alias for *async*.
.. class:: cursor(conn, name=None) .. class:: cursor(conn, name=None)
It is the class usually returnded by the `connection.cursor()` It is the class usually returned by the `connection.cursor()`
method. It is exposed by the `extensions` module in order to allow method. It is exposed by the `extensions` module in order to allow
subclassing to extend its behaviour: the subclass should be passed to the subclassing to extend its behaviour: the subclass should be passed to the
`!cursor()` method using the `cursor_factory` parameter. See `!cursor()` method using the `cursor_factory` parameter. See
@ -33,6 +42,7 @@ functionalities defined by the |DBAPI|_.
For a complete description of the class, see `cursor`. For a complete description of the class, see `cursor`.
.. class:: lobject(conn [, oid [, mode [, new_oid [, new_file ]]]]) .. class:: lobject(conn [, oid [, mode [, new_oid [, new_file ]]]])
Wrapper for a PostgreSQL large object. See :ref:`large-objects` for an Wrapper for a PostgreSQL large object. See :ref:`large-objects` for an
@ -47,11 +57,13 @@ functionalities defined by the |DBAPI|_.
Database OID of the object. Database OID of the object.
.. attribute:: mode .. attribute:: mode
The mode the database was open. See `connection.lobject()` for a The mode the database was open. See `connection.lobject()` for a
description of the available modes. description of the available modes.
.. method:: read(bytes=-1) .. method:: read(bytes=-1)
Read a chunk of data from the current file position. If -1 (default) Read a chunk of data from the current file position. If -1 (default)
@ -64,6 +76,7 @@ functionalities defined by the |DBAPI|_.
.. versionchanged:: 2.4 .. versionchanged:: 2.4
added Unicode support. added Unicode support.
.. method:: write(str) .. method:: write(str)
Write a string to the large object. Return the number of bytes Write a string to the large object. Return the number of bytes
@ -73,6 +86,7 @@ functionalities defined by the |DBAPI|_.
.. versionchanged:: 2.4 .. versionchanged:: 2.4
added Unicode support. added Unicode support.
.. method:: export(file_name) .. method:: export(file_name)
Export the large object content to the file system. Export the large object content to the file system.
@ -80,35 +94,52 @@ functionalities defined by the |DBAPI|_.
The method uses the efficient |lo_export|_ libpq function. The method uses the efficient |lo_export|_ libpq function.
.. |lo_export| replace:: `!lo_export()` .. |lo_export| replace:: `!lo_export()`
.. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT .. _lo_export: https://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT
.. method:: seek(offset, whence=0) .. method:: seek(offset, whence=0)
Set the lobject current position. Set the lobject current position.
.. versionchanged:: 2.6
added support for *offset* > 2GB.
.. method:: tell() .. method:: tell()
Return the lobject current position. Return the lobject current position.
.. method:: truncate(len=0) .. versionadded:: 2.2
.. versionadded:: 2.2.0 .. versionchanged:: 2.6
added support for return value > 2GB.
.. method:: truncate(len=0)
Truncate the lobject to the given size. Truncate the lobject to the given size.
The method will only be available if Psycopg has been built against libpq The method will only be available if Psycopg has been built against
from PostgreSQL 8.3 or later and can only be used with PostgreSQL servers libpq from PostgreSQL 8.3 or later and can only be used with
running these versions. It uses the |lo_truncate|_ libpq function. PostgreSQL servers running these versions. It uses the |lo_truncate|_
libpq function.
.. |lo_truncate| replace:: `!lo_truncate()` .. |lo_truncate| replace:: `!lo_truncate()`
.. _lo_truncate: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE .. _lo_truncate: https://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE
.. versionadded:: 2.2
.. versionchanged:: 2.6
added support for *len* > 2GB.
.. warning:: .. warning::
If Psycopg is built with |lo_truncate| support (i.e. if the If Psycopg is built with |lo_truncate| support or with the 64 bits API
:program:`pg_config` used during setup is version >= 8.3), but at support (resp. from PostgreSQL versions 8.3 and 9.3) but at runtime an
runtime an older libpq is found, Psycopg will fail to import. See older version of the dynamic library is found, the ``psycopg2`` module
:ref:`the lo_truncate FAQ <faq-lo_truncate>` about the problem. will fail to import. See :ref:`the lo_truncate FAQ <faq-lo_truncate>`
about the problem.
.. method:: close() .. method:: close()
@ -123,6 +154,130 @@ functionalities defined by the |DBAPI|_.
Close the object and remove it from the database. Close the object and remove it from the database.
.. autoclass:: ConnectionInfo(connection)
.. versionadded:: 2.8
.. autoattribute:: dbname
.. autoattribute:: user
.. autoattribute:: password
.. autoattribute:: host
.. autoattribute:: port
.. autoattribute:: options
.. autoattribute:: dsn_parameters
Example::
>>> conn.info.dsn_parameters
{'dbname': 'test', 'user': 'postgres', 'port': '5432', 'sslmode': 'prefer'}
Requires libpq >= 9.3.
.. autoattribute:: status
.. autoattribute:: transaction_status
.. automethod:: parameter_status(name)
.. autoattribute:: protocol_version
Currently Psycopg supports only protocol 3, which allows connection
to PostgreSQL server from version 7.4. Psycopg versions previous than
2.3 support both protocols 2 and 3.
.. autoattribute:: server_version
The number is formed by converting the major, minor, and revision
numbers into two-decimal-digit numbers and appending them together.
After PostgreSQL 10 the minor version was dropped, so the second group
of digits is always ``00``. For example, version 9.3.5 will be
returned as ``90305``, version 10.2 as ``100002``.
.. autoattribute:: error_message
.. autoattribute:: socket
.. autoattribute:: backend_pid
.. autoattribute:: needs_password
.. autoattribute:: used_password
.. autoattribute:: ssl_in_use
.. automethod:: ssl_attribute(name)
.. autoattribute:: ssl_attribute_names
.. class:: Column(\*args, \*\*kwargs)
Description of one result column, exposed as items of the
`cursor.description` sequence.
.. versionadded:: 2.8
in previous version the `!description` attribute was a sequence of
simple tuples or namedtuples.
.. attribute:: name
The name of the column returned.
.. attribute:: type_code
The PostgreSQL OID of the column. You can use the |pg_type|_ system
table to get more informations about the type. This is the value used
by Psycopg to decide what Python type use to represent the value. See
also :ref:`type-casting-from-sql-to-python`.
.. attribute:: display_size
Supposed to be the actual length of the column in bytes. Obtaining
this value is computationally intensive, so it is always `!None`.
.. versionchanged:: 2.8
It was previously possible to obtain this value using a compiler
flag at builtin.
.. attribute:: internal_size
The size in bytes of the column associated to this column on the
server. Set to a negative value for variable-size types See also
PQfsize_.
.. attribute:: precision
Total number of significant digits in columns of type |NUMERIC|_.
`!None` for other types.
.. attribute:: scale
Count of decimal digits in the fractional part in columns of type
|NUMERIC|. `!None` for other types.
.. attribute:: null_ok
Always `!None` as not easy to retrieve from the libpq.
.. attribute:: table_oid
The oid of the table from which the column was fetched (matching
:sql:`pg_class.oid`). `!None` if the column is not a simple reference
to a table column. See also PQftable_.
.. versionadded:: 2.8
.. attribute:: table_column
The number of the column (within its table) making up the result
(matching :sql:`pg_attribute.attnum`, so it will start from 1).
`!None` if the column is not a simple reference to a table column. See
also PQftablecol_.
.. versionadded:: 2.8
.. |pg_type| replace:: :sql:`pg_type`
.. _pg_type: https://www.postgresql.org/docs/current/static/catalog-pg-type.html
.. _PQgetlength: https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQGETLENGTH
.. _PQfsize: https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQFSIZE
.. _PQftable: https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQFTABLE
.. _PQftablecol: https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQFTABLECOL
.. _NUMERIC: https://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL
.. |NUMERIC| replace:: :sql:`NUMERIC`
.. autoclass:: Notify(pid, channel, payload='') .. autoclass:: Notify(pid, channel, payload='')
:members: pid, channel, payload :members: pid, channel, payload
@ -155,6 +310,7 @@ functionalities defined by the |DBAPI|_.
message_primary message_primary
schema_name schema_name
severity severity
severity_nonlocalized
source_file source_file
source_function source_function
source_line source_line
@ -167,14 +323,9 @@ functionalities defined by the |DBAPI|_.
not all the fields are available for all the errors and for all the not all the fields are available for all the errors and for all the
server versions. server versions.
.. versionadded:: 2.8
The `!severity_nonlocalized` attribute.
.. autofunction:: set_wait_callback(f)
.. versionadded:: 2.2.0
.. autofunction:: get_wait_callback()
.. versionadded:: 2.2.0
.. _sql-adaptation-objects: .. _sql-adaptation-objects:
@ -189,7 +340,7 @@ deal with Python objects adaptation:
.. function:: adapt(obj) .. function:: adapt(obj)
Return the SQL representation of *obj* as a string. Raise a Return the SQL representation of *obj* as an `ISQLQuote`. Raise a
`~psycopg2.ProgrammingError` if how to adapt the object is unknown. `~psycopg2.ProgrammingError` if how to adapt the object is unknown.
In order to allow new objects to be adapted, register a new adapter for it In order to allow new objects to be adapted, register a new adapter for it
using the `register_adapter()` function. using the `register_adapter()` function.
@ -203,7 +354,7 @@ deal with Python objects adaptation:
Register a new adapter for the objects of class *class*. Register a new adapter for the objects of class *class*.
*adapter* should be a function taking a single argument (the object *adapter* should be a function taking a single argument (the object
to adapt) and returning an object conforming the `ISQLQuote` to adapt) and returning an object conforming to the `ISQLQuote`
protocol (e.g. exposing a `!getquoted()` method). The `AsIs` is protocol (e.g. exposing a `!getquoted()` method). The `AsIs` is
often useful for this task. often useful for this task.
@ -262,9 +413,9 @@ deal with Python objects adaptation:
.. method:: getquoted() .. method:: getquoted()
Return the string enclosed in single quotes. Any single quote Return the string enclosed in single quotes. Any single quote appearing
appearing in the the string is escaped by doubling it according to SQL in the string is escaped by doubling it according to SQL string
string constants syntax. Backslashes are escaped too. constants syntax. Backslashes are escaped too.
>>> QuotedString(r"O'Reilly").getquoted() >>> QuotedString(r"O'Reilly").getquoted()
"'O''Reilly'" "'O''Reilly'"
@ -302,13 +453,6 @@ deal with Python objects adaptation:
Specialized adapters for Python datetime objects. Specialized adapters for Python datetime objects.
.. class:: DateFromMx
TimeFromMx
TimestampFromMx
IntervalFromMx
Specialized adapters for `mx.DateTime`_ objects.
.. data:: adapters .. data:: adapters
Dictionary of the currently registered object adapters. Use Dictionary of the currently registered object adapters. Use
@ -352,8 +496,8 @@ details.
`register_type()` to be used. `register_type()` to be used.
:param oids: tuple of OIDs of the PostgreSQL type to convert. It should :param oids: tuple of OIDs of the PostgreSQL type to convert. It should
probably be the oid of the array type (e.g. the ``typarray`` field in probably contain the oid of the array type (e.g. the ``typarray``
the ``pg_type`` table. field in the ``pg_type`` table).
:param name: the name of the new type adapter. :param name: the name of the new type adapter.
:param base_caster: a Psycopg typecaster, e.g. created using the :param base_caster: a Psycopg typecaster, e.g. created using the
`new_type()` function. The caster should be able to parse a single `new_type()` function. The caster should be able to parse a single
@ -366,11 +510,12 @@ details.
.. note:: .. note::
The function can be used to create a generic array typecaster, The function can be used to create a generic array typecaster,
returning a list of strings: just use the `~psycopg2.STRING` as base returning a list of strings: just use `psycopg2.STRING` as base
typecaster. For instance, if you want to receive from the database an typecaster. For instance, if you want to receive an array of
array of :sql:`macaddr`, each address represented by string, you can :sql:`macaddr` from the database, each address represented by string,
use:: you can use::
# select typarray from pg_type where typname = 'macaddr' -> 1040
psycopg2.extensions.register_type( psycopg2.extensions.register_type(
psycopg2.extensions.new_array_type( psycopg2.extensions.new_array_type(
(1040,), 'MACADDR[]', psycopg2.STRING)) (1040,), 'MACADDR[]', psycopg2.STRING))
@ -395,24 +540,31 @@ details.
.. data:: encodings .. data:: encodings
Mapping from `PostgreSQL encoding`__ names to `Python codec`__ names. Mapping from `PostgreSQL encoding`__ to `Python encoding`__ names.
Used by Psycopg when adapting or casting unicode strings. See Used by Psycopg when adapting or casting unicode strings. See
:ref:`unicode-handling`. :ref:`unicode-handling`.
.. __: http://www.postgresql.org/docs/current/static/multibyte.html .. __: https://www.postgresql.org/docs/current/static/multibyte.html
.. __: http://docs.python.org/library/codecs.html#standard-encodings .. __: https://docs.python.org/library/codecs.html#standard-encodings
.. index:: .. index::
single: Exceptions; Additional single: Exceptions; Additional
.. _extension-exceptions:
Additional exceptions Additional exceptions
--------------------- ---------------------
The module exports a few exceptions in addition to the :ref:`standard ones The module exports a few exceptions in addition to the :ref:`standard ones
<dbapi-exceptions>` defined by the |DBAPI|_. <dbapi-exceptions>` defined by the |DBAPI|_.
.. note::
From psycopg 2.8 these error classes are also exposed by the
`psycopg2.errors` module.
.. exception:: QueryCanceledError .. exception:: QueryCanceledError
(subclasses `~psycopg2.OperationalError`) (subclasses `~psycopg2.OperationalError`)
@ -427,13 +579,143 @@ The module exports a few exceptions in addition to the :ref:`standard ones
(subclasses `~psycopg2.OperationalError`) (subclasses `~psycopg2.OperationalError`)
Error causing transaction rollback (deadlocks, serialisation failures, Error causing transaction rollback (deadlocks, serialization failures,
etc). It can be trapped specifically to detect a deadlock. etc). It can be trapped specifically to detect a deadlock.
.. versionadded:: 2.0.7 .. versionadded:: 2.0.7
.. _coroutines-functions:
Coroutines support functions
----------------------------
These functions are used to set and retrieve the callback function for
:ref:`cooperation with coroutine libraries <green-support>`.
.. versionadded:: 2.2
.. autofunction:: set_wait_callback(f)
.. autofunction:: get_wait_callback()
Other functions
---------------
.. function:: libpq_version()
Return the version number of the ``libpq`` dynamic library loaded as an
integer, in the same format of `~connection.server_version`.
Raise `~psycopg2.NotSupportedError` if the ``psycopg2`` module was
compiled with a ``libpq`` version lesser than 9.1 (which can be detected
by the `~psycopg2.__libpq_version__` constant).
.. versionadded:: 2.7
.. seealso:: libpq docs for `PQlibVersion()`__.
.. __: https://www.postgresql.org/docs/current/static/libpq-misc.html#LIBPQ-PQLIBVERSION
.. function:: make_dsn(dsn=None, \*\*kwargs)
Create a valid connection string from arguments.
Put together the arguments in *kwargs* into a connection string. If *dsn*
is specified too, merge the arguments coming from both the sources. If the
same argument name is specified in both the sources, the *kwargs* value
overrides the *dsn* value.
The input arguments are validated: the output should always be a valid
connection string (as far as `parse_dsn()` is concerned). If not raise
`~psycopg2.ProgrammingError`.
Example::
>>> from psycopg2.extensions import make_dsn
>>> make_dsn('dbname=foo host=example.com', password="s3cr3t")
'host=example.com password=s3cr3t dbname=foo'
.. versionadded:: 2.7
.. function:: parse_dsn(dsn)
Parse connection string into a dictionary of keywords and values.
Parsing is delegated to the libpq: different versions of the client
library may support different formats or parameters (for example,
`connection URIs`__ are only supported from libpq 9.2). Raise
`~psycopg2.ProgrammingError` if the *dsn* is not valid.
.. __: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
Example::
>>> from psycopg2.extensions import parse_dsn
>>> parse_dsn('dbname=test user=postgres password=secret')
{'password': 'secret', 'user': 'postgres', 'dbname': 'test'}
>>> parse_dsn("postgresql://someone@example.com/somedb?connect_timeout=10")
{'host': 'example.com', 'user': 'someone', 'dbname': 'somedb', 'connect_timeout': '10'}
.. versionadded:: 2.7
.. seealso:: libpq docs for `PQconninfoParse()`__.
.. __: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PQCONNINFOPARSE
.. function:: quote_ident(str, scope)
Return quoted identifier according to PostgreSQL quoting rules.
The *scope* must be a `connection` or a `cursor`, the underlying
connection encoding is used for any necessary character conversion.
.. versionadded:: 2.7
.. seealso:: libpq docs for `PQescapeIdentifier()`__
.. __: https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQESCAPEIDENTIFIER
.. method:: encrypt_password(password, user, scope=None, algorithm=None)
Return the encrypted form of a PostgreSQL password.
:param password: the cleartext password to encrypt
:param user: the name of the user to use the password for
:param scope: the scope to encrypt the password into; if *algorithm* is
``md5`` it can be `!None`
:type scope: `connection` or `cursor`
:param algorithm: the password encryption algorithm to use
The *algorithm* ``md5`` is always supported. Other algorithms are only
supported if the client libpq version is at least 10 and may require a
compatible server version: check the `PostgreSQL encryption
documentation`__ to know the algorithms supported by your server.
.. __: https://www.postgresql.org/docs/current/static/encryption-options.html
Using `!None` as *algorithm* will result in querying the server to know the
current server password encryption setting, which is a blocking operation:
query the server separately and specify a value for *algorithm* if you
want to maintain a non-blocking behaviour.
.. versionadded:: 2.8
.. seealso:: PostgreSQL docs for the `password_encryption`__ setting, libpq `PQencryptPasswordConn()`__, `PQencryptPassword()`__ functions.
.. __: https://www.postgresql.org/docs/current/static/runtime-config-connection.html#GUC-PASSWORD-ENCRYPTION
.. __: https://www.postgresql.org/docs/current/static/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN
.. __: https://www.postgresql.org/docs/current/static/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORD
.. index:: .. index::
pair: Isolation level; Constants pair: Isolation level; Constants
@ -443,15 +725,16 @@ Isolation level constants
------------------------- -------------------------
Psycopg2 `connection` objects hold informations about the PostgreSQL Psycopg2 `connection` objects hold informations about the PostgreSQL
`transaction isolation level`_. The current transaction level can be read `transaction isolation level`_. By default Psycopg doesn't change the default
from the `~connection.isolation_level` attribute. The default isolation configuration of the server (`ISOLATION_LEVEL_DEFAULT`); the default for
level is :sql:`READ COMMITTED`. A different isolation level con be set PostgreSQL servers is typically :sql:`READ COMMITTED`, but this may be changed
through the `~connection.set_isolation_level()` method. The level can be in the server configuration files. A different isolation level can be set
set to one of the following constants: through the `~connection.set_isolation_level()` or `~connection.set_session()`
methods. The level can be set to one of the following constants:
.. data:: ISOLATION_LEVEL_AUTOCOMMIT .. data:: ISOLATION_LEVEL_AUTOCOMMIT
No transaction is started when command are issued and no No transaction is started when commands are executed and no
`~connection.commit()` or `~connection.rollback()` is required. `~connection.commit()` or `~connection.rollback()` is required.
Some PostgreSQL command such as :sql:`CREATE DATABASE` or :sql:`VACUUM` Some PostgreSQL command such as :sql:`CREATE DATABASE` or :sql:`VACUUM`
can't run into a transaction: to run such command use:: can't run into a transaction: to run such command use::
@ -468,8 +751,8 @@ set to one of the following constants:
.. data:: ISOLATION_LEVEL_READ_COMMITTED .. data:: ISOLATION_LEVEL_READ_COMMITTED
This is usually the the default PostgreSQL value, but a different default This is usually the default PostgreSQL value, but a different default may
may be set in the database configuration. be set in the database configuration.
A new transaction is started at the first `~cursor.execute()` command on a A new transaction is started at the first `~cursor.execute()` command on a
cursor and at each new `!execute()` after a `~connection.commit()` or a cursor and at each new `!execute()` after a `~connection.commit()` or a
@ -482,7 +765,7 @@ set to one of the following constants:
.. seealso:: `Read Committed Isolation Level`__ in PostgreSQL .. seealso:: `Read Committed Isolation Level`__ in PostgreSQL
documentation. documentation.
.. __: http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-READ-COMMITTED .. __: https://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-READ-COMMITTED
.. data:: ISOLATION_LEVEL_REPEATABLE_READ .. data:: ISOLATION_LEVEL_REPEATABLE_READ
@ -506,7 +789,7 @@ set to one of the following constants:
.. seealso:: `Repeatable Read Isolation Level`__ in PostgreSQL .. seealso:: `Repeatable Read Isolation Level`__ in PostgreSQL
documentation. documentation.
.. __: http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-REPEATABLE-READ .. __: https://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-REPEATABLE-READ
.. data:: ISOLATION_LEVEL_SERIALIZABLE .. data:: ISOLATION_LEVEL_SERIALIZABLE
@ -515,7 +798,7 @@ set to one of the following constants:
:sql:`SERIALIZABLE` isolation level. This is the strictest transactions :sql:`SERIALIZABLE` isolation level. This is the strictest transactions
isolation level, equivalent to having the transactions executed serially isolation level, equivalent to having the transactions executed serially
rather than concurrently. However applications using this level must be rather than concurrently. However applications using this level must be
prepared to retry reansactions due to serialization failures. prepared to retry transactions due to serialization failures.
Starting from PostgreSQL 9.1, this mode monitors for conditions which Starting from PostgreSQL 9.1, this mode monitors for conditions which
could make execution of a concurrent set of serializable transactions could make execution of a concurrent set of serializable transactions
@ -525,8 +808,18 @@ set to one of the following constants:
.. seealso:: `Serializable Isolation Level`__ in PostgreSQL documentation. .. seealso:: `Serializable Isolation Level`__ in PostgreSQL documentation.
.. __: http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-SERIALIZABLE .. __: https://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-SERIALIZABLE
.. data:: ISOLATION_LEVEL_DEFAULT
A new transaction is started at the first `~cursor.execute()` command, but
the isolation level is not explicitly selected by Psycopg: the server will
use whatever level is defined in its configuration or by statements
executed within the session outside Pyscopg control. If you want to know
what the value is you can use a query such as :sql:`show
transaction_isolation`.
.. versionadded:: 2.7
.. index:: .. index::
@ -538,7 +831,7 @@ Transaction status constants
---------------------------- ----------------------------
These values represent the possible status of a transaction: the current value These values represent the possible status of a transaction: the current value
can be read using the `connection.get_transaction_status()` method. can be read using the `connection.info.transaction_status` property.
.. data:: TRANSACTION_STATUS_IDLE .. data:: TRANSACTION_STATUS_IDLE
@ -609,7 +902,7 @@ internal usage and Python code should not rely on them.
Poll constants Poll constants
-------------- --------------
.. versionadded:: 2.2.0 .. versionadded:: 2.2
These values can be returned by `connection.poll()` during asynchronous These values can be returned by `connection.poll()` during asynchronous
connection and communication. They match the values in the libpq enum connection and communication. They match the values in the libpq enum
@ -658,6 +951,7 @@ Python objects. All the typecasters are automatically registered, except
from the database. See :ref:`unicode-handling` for details. from the database. See :ref:`unicode-handling` for details.
.. data:: BOOLEAN .. data:: BOOLEAN
BYTES
DATE DATE
DECIMAL DECIMAL
FLOAT FLOAT
@ -674,6 +968,7 @@ from the database. See :ref:`unicode-handling` for details.
.. data:: BINARYARRAY .. data:: BINARYARRAY
BOOLEANARRAY BOOLEANARRAY
BYTESARRAY
DATEARRAY DATEARRAY
DATETIMEARRAY DATETIMEARRAY
DECIMALARRAY DECIMALARRAY
@ -690,31 +985,26 @@ from the database. See :ref:`unicode-handling` for details.
.. data:: PYDATE .. data:: PYDATE
PYDATETIME PYDATETIME
PYDATETIMETZ
PYINTERVAL PYINTERVAL
PYTIME PYTIME
PYDATEARRAY PYDATEARRAY
PYDATETIMEARRAY PYDATETIMEARRAY
PYDATETIMETZARRAY
PYINTERVALARRAY PYINTERVALARRAY
PYTIMEARRAY PYTIMEARRAY
Typecasters to convert time-related data types to Python `!datetime` Typecasters to convert time-related data types to Python `!datetime`
objects. objects.
.. data:: MXDATE .. versionchanged:: 2.2
MXDATETIME
MXINTERVAL
MXTIME
MXDATEARRAY
MXDATETIMEARRAY
MXINTERVALARRAY
MXTIMEARRAY
Typecasters to convert time-related data types to `mx.DateTime`_ objects.
Only available if Psycopg was compiled with `!mx` support.
.. versionchanged:: 2.2.0
previously the `DECIMAL` typecaster and the specific time-related previously the `DECIMAL` typecaster and the specific time-related
typecasters (`!PY*` and `!MX*`) were not exposed by the `extensions` typecasters (`!PY*` and `!MX*`) were not exposed by the `extensions`
module. In older versions they can be imported from the implementation module. In older versions they can be imported from the implementation
module `!psycopg2._psycopg`. module `!psycopg2._psycopg`.
.. versionadded:: 2.7.2
the `!*DATETIMETZ*` objects.
.. versionadded:: 2.8
the `!BYTES` and `BYTESARRAY` objects.

View File

@ -41,8 +41,8 @@ If you want to use a `!connection` subclass you can pass it as the
Dictionary-like cursor Dictionary-like cursor
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
The dict cursors allow to access to the retrieved records using an iterface The dict cursors allow to access to the attributes of retrieved records
similar to the Python dictionaries instead of the tuples. using an interface similar to the Python dictionaries instead of the tuples.
>>> dict_cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) >>> dict_cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
>>> dict_cur.execute("INSERT INTO test (num, data) VALUES(%s, %s)", >>> dict_cur.execute("INSERT INTO test (num, data) VALUES(%s, %s)",
@ -99,20 +99,6 @@ Real dictionary cursor
.. versionadded:: 2.3 .. versionadded:: 2.3
These objects require :py:func:`collections.namedtuple` to be found, so it is
available out-of-the-box only from Python 2.6. Anyway, the namedtuple
implementation is compatible with previous Python versions, so all you
have to do is to `download it`__ and make it available where we
expect it to be... ::
from somewhere import namedtuple
import collections
collections.namedtuple = namedtuple
from psycopg.extras import NamedTupleConnection
# ...
.. __: http://code.activestate.com/recipes/500261-named-tuples/
.. autoclass:: NamedTupleCursor .. autoclass:: NamedTupleCursor
.. autoclass:: NamedTupleConnection .. autoclass:: NamedTupleConnection
@ -136,6 +122,11 @@ Logging cursor
.. autoclass:: LoggingCursor .. autoclass:: LoggingCursor
.. note::
Queries that are executed with `cursor.executemany()` are not logged.
.. autoclass:: MinTimeLoggingConnection .. autoclass:: MinTimeLoggingConnection
:members: initialize,filter :members: initialize,filter
@ -143,6 +134,417 @@ Logging cursor
.. _replication-objects:
Replication support objects
---------------------------
See :ref:`replication-support` for an introduction to the topic.
The following replication types are defined:
.. data:: REPLICATION_LOGICAL
.. data:: REPLICATION_PHYSICAL
.. index::
pair: Connection; replication
.. autoclass:: LogicalReplicationConnection
This connection factory class can be used to open a special type of
connection that is used for logical replication.
Example::
from psycopg2.extras import LogicalReplicationConnection
log_conn = psycopg2.connect(dsn, connection_factory=LogicalReplicationConnection)
log_cur = log_conn.cursor()
.. autoclass:: PhysicalReplicationConnection
This connection factory class can be used to open a special type of
connection that is used for physical replication.
Example::
from psycopg2.extras import PhysicalReplicationConnection
phys_conn = psycopg2.connect(dsn, connection_factory=PhysicalReplicationConnection)
phys_cur = phys_conn.cursor()
Both `LogicalReplicationConnection` and `PhysicalReplicationConnection` use
`ReplicationCursor` for actual communication with the server.
.. index::
pair: Message; replication
The individual messages in the replication stream are represented by
`ReplicationMessage` objects (both logical and physical type):
.. autoclass:: ReplicationMessage
.. attribute:: payload
The actual data received from the server.
An instance of either `bytes()` or `unicode()`, depending on the value
of `decode` option passed to `~ReplicationCursor.start_replication()`
on the connection. See `~ReplicationCursor.read_message()` for
details.
.. attribute:: data_size
The raw size of the message payload (before possible unicode
conversion).
.. attribute:: data_start
LSN position of the start of the message.
.. attribute:: wal_end
LSN position of the current end of WAL on the server.
.. attribute:: send_time
A `~datetime` object representing the server timestamp at the moment
when the message was sent.
.. attribute:: cursor
A reference to the corresponding `ReplicationCursor` object.
.. index::
pair: Cursor; replication
.. autoclass:: ReplicationCursor
.. method:: create_replication_slot(slot_name, slot_type=None, output_plugin=None)
Create streaming replication slot.
:param slot_name: name of the replication slot to be created
:param slot_type: type of replication: should be either
`REPLICATION_LOGICAL` or `REPLICATION_PHYSICAL`
:param output_plugin: name of the logical decoding output plugin to be
used by the slot; required for logical
replication connections, disallowed for physical
Example::
log_cur.create_replication_slot("logical1", "test_decoding")
phys_cur.create_replication_slot("physical1")
# either logical or physical replication connection
cur.create_replication_slot("slot1", slot_type=REPLICATION_LOGICAL)
When creating a slot on a logical replication connection, a logical
replication slot is created by default. Logical replication requires
name of the logical decoding output plugin to be specified.
When creating a slot on a physical replication connection, a physical
replication slot is created by default. No output plugin parameter is
required or allowed when creating a physical replication slot.
In either case the type of slot being created can be specified
explicitly using *slot_type* parameter.
Replication slots are a feature of PostgreSQL server starting with
version 9.4.
.. method:: drop_replication_slot(slot_name)
Drop streaming replication slot.
:param slot_name: name of the replication slot to drop
Example::
# either logical or physical replication connection
cur.drop_replication_slot("slot1")
Replication slots are a feature of PostgreSQL server starting with
version 9.4.
.. method:: start_replication(slot_name=None, slot_type=None, start_lsn=0, timeline=0, options=None, decode=False, status_interval=10)
Start replication on the connection.
:param slot_name: name of the replication slot to use; required for
logical replication, physical replication can work
with or without a slot
:param slot_type: type of replication: should be either
`REPLICATION_LOGICAL` or `REPLICATION_PHYSICAL`
:param start_lsn: the optional LSN position to start replicating from,
can be an integer or a string of hexadecimal digits
in the form ``XXX/XXX``
:param timeline: WAL history timeline to start streaming from (optional,
can only be used with physical replication)
:param options: a dictionary of options to pass to logical replication
slot (not allowed with physical replication)
:param decode: a flag indicating that unicode conversion should be
performed on messages received from the server
:param status_interval: time between feedback packets sent to the server
If a *slot_name* is specified, the slot must exist on the server and
its type must match the replication type used.
If not specified using *slot_type* parameter, the type of replication
is defined by the type of replication connection. Logical replication
is only allowed on logical replication connection, but physical
replication can be used with both types of connection.
On the other hand, physical replication doesn't require a named
replication slot to be used, only logical replication does. In any
case logical replication and replication slots are a feature of
PostgreSQL server starting with version 9.4. Physical replication can
be used starting with 9.0.
If *start_lsn* is specified, the requested stream will start from that
LSN. The default is `!None` which passes the LSN ``0/0`` causing
replay to begin at the last point for which the server got flush
confirmation from the client, or the oldest available point for a new
slot.
The server might produce an error if a WAL file for the given LSN has
already been recycled or it may silently start streaming from a later
position: the client can verify the actual position using information
provided by the `ReplicationMessage` attributes. The exact server
behavior depends on the type of replication and use of slots.
The *timeline* parameter can only be specified with physical
replication and only starting with server version 9.3.
A dictionary of *options* may be passed to the logical decoding plugin
on a logical replication slot. The set of supported options depends
on the output plugin that was used to create the slot. Must be
`!None` for physical replication.
If *decode* is set to `!True` the messages received from the server
would be converted according to the connection `~connection.encoding`.
*This parameter should not be set with physical replication or with
logical replication plugins that produce binary output.*
Replication stream should periodically send feedback to the database
to prevent disconnect via timeout. Feedback is automatically sent when
`read_message()` is called or during run of the `consume_stream()`.
To specify the feedback interval use *status_interval* parameter.
The value of this parameter must be set to at least 1 second, but
it can have a fractional part.
This function constructs a |START_REPLICATION|_ command and calls
`start_replication_expert()` internally.
After starting the replication, to actually consume the incoming
server messages use `consume_stream()` or implement a loop around
`read_message()` in case of :ref:`asynchronous connection
<async-support>`.
.. versionchanged:: 2.8.3
added the *status_interval* parameter.
.. |START_REPLICATION| replace:: :sql:`START_REPLICATION`
.. _START_REPLICATION: https://www.postgresql.org/docs/current/static/protocol-replication.html
.. method:: start_replication_expert(command, decode=False, status_interval=10)
Start replication on the connection using provided
|START_REPLICATION|_ command.
:param command: The full replication command. It can be a string or a
`~psycopg2.sql.Composable` instance for dynamic generation.
:param decode: a flag indicating that unicode conversion should be
performed on messages received from the server.
:param status_interval: time between feedback packets sent to the server
.. versionchanged:: 2.8.3
added the *status_interval* parameter.
.. method:: consume_stream(consume, keepalive_interval=None)
:param consume: a callable object with signature :samp:`consume({msg})`
:param keepalive_interval: interval (in seconds) to send keepalive
messages to the server
This method can only be used with synchronous connection. For
asynchronous connections see `read_message()`.
Before using this method to consume the stream call
`start_replication()` first.
This method enters an endless loop reading messages from the server
and passing them to ``consume()`` one at a time, then waiting for more
messages from the server. In order to make this method break out of
the loop and return, ``consume()`` can throw a `StopReplication`
exception. Any unhandled exception will make it break out of the loop
as well.
The *msg* object passed to ``consume()`` is an instance of
`ReplicationMessage` class. See `read_message()` for details about
message decoding.
This method also sends feedback messages to the server every
*keepalive_interval* (in seconds). The value of this parameter must
be set to at least 1 second, but it can have a fractional part.
If the *keepalive_interval* is not specified, the value of
*status_interval* specified in the `start_replication()` or
`start_replication_expert()` will be used.
The client must confirm every processed message by calling
`send_feedback()` method on the corresponding replication cursor. A
reference to the cursor is provided in the `ReplicationMessage` as an
attribute.
The following example is a sketch implementation of ``consume()``
callable for logical replication::
class LogicalStreamConsumer(object):
# ...
def __call__(self, msg):
self.process_message(msg.payload)
msg.cursor.send_feedback(flush_lsn=msg.data_start)
consumer = LogicalStreamConsumer()
cur.consume_stream(consumer)
.. warning::
When using replication with slots, failure to constantly consume
*and* report success to the server appropriately can eventually
lead to "disk full" condition on the server, because the server
retains all the WAL segments that might be needed to stream the
changes via all of the currently open replication slots.
.. versionchanged:: 2.8.3
changed the default value of the *keepalive_interval* parameter to `!None`.
.. method:: send_feedback(write_lsn=0, flush_lsn=0, apply_lsn=0, reply=False, force=False)
:param write_lsn: a LSN position up to which the client has written the data locally
:param flush_lsn: a LSN position up to which the client has processed the
data reliably (the server is allowed to discard all
and every data that predates this LSN)
:param apply_lsn: a LSN position up to which the warm standby server
has applied the changes (physical replication
master-slave protocol only)
:param reply: request the server to send back a keepalive message immediately
:param force: force sending a feedback message regardless of status_interval timeout
Use this method to report to the server that all messages up to a
certain LSN position have been processed on the client and may be
discarded on the server.
If the *reply* or *force* parameters are not set, this method will
just update internal structures without sending the feedback message
to the server. The library sends feedback message automatically
when *status_interval* timeout is reached. For this to work, you must
call `send_feedback()` on the same Cursor that you called `start_replication()`
on (the one in `message.cursor`) or your feedback will be lost.
.. versionchanged:: 2.8.3
added the *force* parameter.
Low-level replication cursor methods for :ref:`asynchronous connection
<async-support>` operation.
With the synchronous connection a call to `consume_stream()` handles all
the complexity of handling the incoming messages and sending keepalive
replies, but at times it might be beneficial to use low-level interface
for better control, in particular to `~select` on multiple sockets. The
following methods are provided for asynchronous operation:
.. method:: read_message()
Try to read the next message from the server without blocking and
return an instance of `ReplicationMessage` or `!None`, in case there
are no more data messages from the server at the moment.
This method should be used in a loop with asynchronous connections
(after calling `start_replication()` once). For synchronous
connections see `consume_stream()`.
The returned message's `~ReplicationMessage.payload` is an instance of
`!unicode` decoded according to connection `~connection.encoding`
*iff* *decode* was set to `!True` in the initial call to
`start_replication()` on this connection, otherwise it is an instance
of `!bytes` with no decoding.
It is expected that the calling code will call this method repeatedly
in order to consume all of the messages that might have been buffered
until `!None` is returned. After receiving `!None` from this method
the caller should use `~select.select()` or `~select.poll()` on the
corresponding connection to block the process until there is more data
from the server.
Last, but not least, this method sends feedback messages when
*status_interval* timeout is reached or when keepalive message with
reply request arrived from the server.
.. method:: fileno()
Call the corresponding connection's `~connection.fileno()` method and
return the result.
This is a convenience method which allows replication cursor to be
used directly in `~select.select()` or `~select.poll()` calls.
.. attribute:: io_timestamp
A `~datetime` object representing the timestamp at the moment of last
communication with the server (a data or keepalive message in either
direction).
.. attribute:: feedback_timestamp
A `~datetime` object representing the timestamp at the moment when
the last feedback message sent to the server.
.. versionadded:: 2.8.3
.. attribute:: wal_end
LSN position of the current end of WAL on the server at the
moment of last data or keepalive message received from the
server.
.. versionadded:: 2.8
An actual example of asynchronous operation might look like this::
from select import select
from datetime import datetime
def consume(msg):
# ...
msg.cursor.send_feedback(flush_lsn=msg.data_start)
status_interval = 10.0
while True:
msg = cur.read_message()
if msg:
consume(msg)
else:
now = datetime.now()
timeout = status_interval - (now - cur.feedback_timestamp).total_seconds()
try:
sel = select([cur], [], [], max(0, timeout))
except InterruptedError:
pass # recalculate timeout and continue
.. index::
pair: Cursor; Replication
.. autoclass:: StopReplication
.. index:: .. index::
single: Data types; Additional single: Data types; Additional
@ -160,25 +562,26 @@ JSON_ adaptation
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
.. versionadded:: 2.5 .. versionadded:: 2.5
.. versionchanged:: 2.5.4
added |jsonb| support. In previous versions |jsonb| values are returned
as strings. See :ref:`the FAQ <faq-jsonb-adapt>` for a workaround.
Psycopg can adapt Python objects to and from the PostgreSQL |pgjson|_ type. Psycopg can adapt Python objects to and from the PostgreSQL |jsons|_
With PostgreSQL 9.2 adaptation is available out-of-the-box. To use JSON data types. With PostgreSQL 9.2 and following versions adaptation is
with previous database versions (either with the `9.1 json extension`__, but available out-of-the-box. To use JSON data with previous database versions
even if you want to convert text fields to JSON) you can use (either with the `9.1 json extension`__, but even if you want to convert text
`register_json()`. fields to JSON) you can use the `register_json()` function.
.. __: http://people.planetpostgresql.org/andrew/index.php?/archives/255-JSON-for-PG-9.2-...-and-now-for-9.1!.html .. __: http://people.planetpostgresql.org/andrew/index.php?/archives/255-JSON-for-PG-9.2-...-and-now-for-9.1!.html
The Python library used to convert Python objects to JSON depends on the The Python :py:mod:`json` module is used by default to convert Python objects
language version: with Python 2.6 and following the :py:mod:`json` module from to JSON and to parse data from the database.
the standard library is used; with previous versions the `simplejson`_ module
is used if available. Note that the last `!simplejson` version supporting
Python 2.4 is the 2.0.9.
.. _JSON: http://www.json.org/ .. _JSON: https://www.json.org/
.. |pgjson| replace:: :sql:`json` .. |json| replace:: :sql:`json`
.. _pgjson: http://www.postgresql.org/docs/current/static/datatype-json.html .. |jsonb| replace:: :sql:`jsonb`
.. _simplejson: http://pypi.python.org/pypi/simplejson/ .. |jsons| replace:: |json| and |jsonb|
.. _jsons: https://www.postgresql.org/docs/current/static/datatype-json.html
In order to pass a Python object to the database as query argument you can use In order to pass a Python object to the database as query argument you can use
the `Json` adapter:: the `Json` adapter::
@ -186,8 +589,22 @@ the `Json` adapter::
curs.execute("insert into mytable (jsondata) values (%s)", curs.execute("insert into mytable (jsondata) values (%s)",
[Json({'a': 100})]) [Json({'a': 100})])
Reading from the database, |pgjson| values will be automatically converted to Reading from the database, |json| and |jsonb| values will be automatically
Python objects. converted to Python objects.
.. note::
If you are using the PostgreSQL :sql:`json` data type but you want to read
it as string in Python instead of having it parsed, your can either cast
the column to :sql:`text` in the query (it is an efficient operation, that
doesn't involve a copy)::
cur.execute("select jsondata::text from mytable")
or you can register a no-op `!loads()` function with
`register_default_json()`::
psycopg2.extras.register_default_json(loads=lambda x: x)
.. note:: .. note::
@ -204,7 +621,7 @@ Python objects.
effects. effects.
If you want to customize the adaptation from Python to PostgreSQL you can If you want to customize the adaptation from Python to PostgreSQL you can
either provide a custom `!dumps()` function to `!Json`:: either provide a custom `!dumps()` function to `Json`::
curs.execute("insert into mytable (jsondata) values (%s)", curs.execute("insert into mytable (jsondata) values (%s)",
[Json({'a': 100}, dumps=simplejson.dumps)]) [Json({'a': 100}, dumps=simplejson.dumps)])
@ -219,13 +636,22 @@ or you can subclass it overriding the `~Json.dumps()` method::
[MyJson({'a': 100})]) [MyJson({'a': 100})])
Customizing the conversion from PostgreSQL to Python can be done passing a Customizing the conversion from PostgreSQL to Python can be done passing a
custom `!loads()` function to `register_json()` (or `register_default_json()` custom `!loads()` function to `register_json()`. For the builtin data types
for PostgreSQL 9.2). For example, if you want to convert the float values (|json| from PostgreSQL 9.2, |jsonb| from PostgreSQL 9.4) use
from :sql:`json` into :py:class:`~decimal.Decimal` you can use:: `register_default_json()` and `register_default_jsonb()`. For example, if you
want to convert the float values from :sql:`json` into
:py:class:`~decimal.Decimal` you can use::
loads = lambda x: json.loads(x, parse_float=Decimal) loads = lambda x: json.loads(x, parse_float=Decimal)
psycopg2.extras.register_json(conn, loads=loads) psycopg2.extras.register_json(conn, loads=loads)
Or, if you want to use an alternative JSON module implementation, such as the
faster UltraJSON_, you can use::
psycopg2.extras.register_default_json(loads=ujson.loads, globally=True)
psycopg2.extras.register_default_jsonb(loads=ujson.loads, globally=True)
.. _UltraJSON: https://pypi.org/project/ujson/
.. autoclass:: Json .. autoclass:: Json
@ -234,8 +660,15 @@ from :sql:`json` into :py:class:`~decimal.Decimal` you can use::
.. autofunction:: register_json .. autofunction:: register_json
.. versionchanged:: 2.5.4
added the *name* parameter to enable :sql:`jsonb` support.
.. autofunction:: register_default_json .. autofunction:: register_default_json
.. autofunction:: register_default_jsonb
.. versionadded:: 2.5.4
.. index:: .. index::
@ -274,7 +707,7 @@ can be enabled using the `register_hstore()` function.
.. |hstore| replace:: :sql:`hstore` .. |hstore| replace:: :sql:`hstore`
.. _hstore: http://www.postgresql.org/docs/current/static/hstore.html .. _hstore: https://www.postgresql.org/docs/current/static/hstore.html
@ -296,7 +729,7 @@ after a table row type) into a Python named tuple, or into a regular tuple if
:py:func:`collections.namedtuple` is not found. :py:func:`collections.namedtuple` is not found.
.. |CREATE TYPE| replace:: :sql:`CREATE TYPE` .. |CREATE TYPE| replace:: :sql:`CREATE TYPE`
.. _CREATE TYPE: http://www.postgresql.org/docs/current/static/sql-createtype.html .. _CREATE TYPE: https://www.postgresql.org/docs/current/static/sql-createtype.html
.. doctest:: .. doctest::
@ -410,7 +843,7 @@ PostgreSQL |range|_ types. Builtin |range| types are supported out-of-the-box;
user-defined |range| types can be adapted using `register_range()`. user-defined |range| types can be adapted using `register_range()`.
.. |range| replace:: :sql:`range` .. |range| replace:: :sql:`range`
.. _range: http://www.postgresql.org/docs/current/static/rangetypes.html .. _range: https://www.postgresql.org/docs/current/static/rangetypes.html
.. autoclass:: Range .. autoclass:: Range
@ -419,12 +852,20 @@ user-defined |range| types can be adapted using `register_range()`.
features: it doesn't perform normalization and doesn't implement all the features: it doesn't perform normalization and doesn't implement all the
operators__ supported by the database. operators__ supported by the database.
.. __: http://www.postgresql.org/docs/current/static/functions-range.html#RANGE-OPERATORS-TABLE .. __: https://www.postgresql.org/docs/current/static/functions-range.html#RANGE-OPERATORS-TABLE
`!Range` objects are immutable, hashable, and support the ``in`` operator `!Range` objects are immutable, hashable, and support the ``in`` operator
(checking if an element is within the range). They can be tested for (checking if an element is within the range). They can be tested for
equivalence but not for ordering. Empty ranges evaluate to `!False` in equivalence. Empty ranges evaluate to `!False` in boolean context,
boolean context, nonempty evaluate to `!True`. nonempty evaluate to `!True`.
.. versionchanged:: 2.5.3
`!Range` objects can be sorted although, as on the server-side, this
ordering is not particularly meangingful. It is only meant to be used
by programs assuming objects using `!Range` as primary key can be
sorted on them. In previous versions comparing `!Range`\s raises
`!TypeError`.
Although it is possible to instantiate `!Range` objects, the class doesn't Although it is possible to instantiate `!Range` objects, the class doesn't
have an adapter registered, so you cannot normally pass these instances as have an adapter registered, so you cannot normally pass these instances as
@ -453,6 +894,17 @@ automatically casted into instances of these classes.
.. autoclass:: DateTimeRange .. autoclass:: DateTimeRange
.. autoclass:: DateTimeTZRange .. autoclass:: DateTimeTZRange
.. note::
Python lacks a representation for :sql:`infinity` date so Psycopg converts
the value to `date.max` and such. When written into the database these
dates will assume their literal value (e.g. :sql:`9999-12-31` instead of
:sql:`infinity`). Check :ref:`infinite-dates-handling` for an example of
an alternative adapter to map `date.max` to :sql:`infinity`. An
alternative dates adapter will be used automatically by the `DateRange`
adapter and so on.
Custom |range| types (created with |CREATE TYPE|_ :sql:`... AS RANGE`) can be Custom |range| types (created with |CREATE TYPE|_ :sql:`... AS RANGE`) can be
adapted to a custom `Range` subclass: adapted to a custom `Range` subclass:
@ -516,12 +968,29 @@ UUID data type
.. index:: .. index::
pair: INET; Data types pair: INET; Data types
pair: CIDR; Data types
pair: MACADDR; Data types
:sql:`inet` data type .. _adapt-network:
^^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 2.0.9 Networking data types
.. versionchanged:: 2.4.5 added inet array support. ^^^^^^^^^^^^^^^^^^^^^
By default Psycopg casts the PostgreSQL networking data types (:sql:`inet`,
:sql:`cidr`, :sql:`macaddr`) into ordinary strings; array of such types are
converted into lists of strings.
.. versionchanged:: 2.7
in previous version array of networking types were not treated as arrays.
.. autofunction:: register_ipaddress
.. autofunction:: register_inet
.. deprecated:: 2.7
this function will not receive further development and may disappear in
future versions.
.. doctest:: .. doctest::
@ -536,24 +1005,78 @@ UUID data type
'192.168.0.1/24' '192.168.0.1/24'
.. autofunction:: register_inet
.. autoclass:: Inet .. autoclass:: Inet
.. deprecated:: 2.7
this object will not receive further development and may disappear in
future versions.
.. index::
single: Time zones; Fractional
Fractional time zones .. _fast-exec:
---------------------
.. autofunction:: register_tstz_w_secs Fast execution helpers
----------------------
.. versionadded:: 2.0.9 The current implementation of `~cursor.executemany()` is (using an extremely
charitable understatement) not particularly performing. These functions can
be used to speed up the repeated execution of a statement against a set of
parameters. By reducing the number of server roundtrips the performance can be
`orders of magnitude better`__ than using `!executemany()`.
.. __: https://github.com/psycopg/psycopg2/issues/491#issuecomment-276551038
.. autofunction:: execute_batch
.. code:: python
>>> nums = ((1,), (5,), (10,))
>>> execute_batch(cur, "INSERT INTO test (num) VALUES (%s)", nums)
>>> tuples = ((123, "foo"), (42, "bar"), (23, "baz"))
>>> execute_batch(cur, "INSERT INTO test (num, data) VALUES (%s, %s)", tuples)
.. versionadded:: 2.7
.. note::
`!execute_batch()` can be also used in conjunction with PostgreSQL
prepared statements using |PREPARE|_, |EXECUTE|_, |DEALLOCATE|_.
Instead of executing::
execute_batch(cur,
"big and complex SQL with %s %s params",
params_list)
it is possible to execute something like::
cur.execute("PREPARE stmt AS big and complex SQL with $1 $2 params")
execute_batch(cur, "EXECUTE stmt (%s, %s)", params_list)
cur.execute("DEALLOCATE stmt")
which may bring further performance benefits: if the operation to perform
is complex, every single execution will be faster as the query plan is
already cached; furthermore the amount of data to send on the server will
be lesser (one |EXECUTE| per param set instead of the whole, likely
longer, statement).
.. |PREPARE| replace:: :sql:`PREPARE`
.. _PREPARE: https://www.postgresql.org/docs/current/static/sql-prepare.html
.. |EXECUTE| replace:: :sql:`EXECUTE`
.. _EXECUTE: https://www.postgresql.org/docs/current/static/sql-execute.html
.. |DEALLOCATE| replace:: :sql:`DEALLOCATE`
.. _DEALLOCATE: https://www.postgresql.org/docs/current/static/sql-deallocate.html
.. autofunction:: execute_values
.. versionadded:: 2.7
.. versionchanged:: 2.8
added the *fetch* parameter.
.. versionchanged:: 2.2.2
function is no-op: see :ref:`tz-handling`.
.. index:: .. index::
pair: Example; Coroutine; pair: Example; Coroutine;
@ -565,3 +1088,6 @@ Coroutine support
.. autofunction:: wait_select(conn) .. autofunction:: wait_select(conn)
.. versionchanged:: 2.6.2
allow to cancel a query using :kbd:`Ctrl-C`, see
:ref:`the FAQ <faq-interrupt-query>` for an example.

View File

@ -7,6 +7,30 @@ Here are a few gotchas you may encounter using `psycopg2`. Feel free to
suggest new entries! suggest new entries!
Meta
----
.. _faq-question:
.. cssclass:: faq
How do I ask a question?
- Have you first checked if your question is answered already in the
documentation?
- If your question is about installing psycopg, have you checked the
:ref:`install FAQ <faq-compile>` and the :ref:`install docs
<installation>`?
- Have you googled for your error message?
- If you haven't found an answer yet, please write to the `Mailing List`_.
- If you haven't found a bug, DO NOT write to the bug tracker to ask
questions. You will only get piro grumpy.
.. _mailing list: https://www.postgresql.org/list/psycopg/
.. _faq-transactions: .. _faq-transactions:
Problems with transactions handling Problems with transactions handling
@ -40,7 +64,7 @@ I receive the error *current transaction is aborted, commands ignored until end
PostgreSQL supports nested transactions using the |SAVEPOINT|_ command). PostgreSQL supports nested transactions using the |SAVEPOINT|_ command).
.. |SAVEPOINT| replace:: :sql:`SAVEPOINT` .. |SAVEPOINT| replace:: :sql:`SAVEPOINT`
.. _SAVEPOINT: http://www.postgresql.org/docs/current/static/sql-savepoint.html .. _SAVEPOINT: https://www.postgresql.org/docs/current/static/sql-savepoint.html
.. _faq-transaction-aborted-multiprocess: .. _faq-transaction-aborted-multiprocess:
@ -73,7 +97,7 @@ Why does `!cursor.execute()` raise the exception *can't adapt*?
I can't pass an integer or a float parameter to my query: it says *a number is required*, but *it is* a number! I can't pass an integer or a float parameter to my query: it says *a number is required*, but *it is* a number!
In your query string, you always have to use ``%s`` placeholders, In your query string, you always have to use ``%s`` placeholders,
event when passing a number. All Python objects are converted by Psycopg even when passing a number. All Python objects are converted by Psycopg
in their SQL representation, so they get passed to the query as strings. in their SQL representation, so they get passed to the query as strings.
See :ref:`query-parameters`. :: See :ref:`query-parameters`. ::
@ -108,6 +132,19 @@ My database is Unicode, but I receive all the strings as UTF-8 `!str`. Can I rec
See :ref:`unicode-handling` for the gory details. See :ref:`unicode-handling` for the gory details.
.. _faq-bytes:
.. cssclass:: faq
My database is in mixed encoding. My program was working on Python 2 but Python 3 fails decoding the strings. How do I avoid decoding?
From psycopg 2.8 you can use the following adapters to always return bytes
from strings::
psycopg2.extensions.register_type(psycopg2.extensions.BYTES)
psycopg2.extensions.register_type(psycopg2.extensions.BYTESARRAY)
See :ref:`unicode-handling` for an example.
.. _faq-float: .. _faq-float:
.. cssclass:: faq .. cssclass:: faq
@ -121,10 +158,54 @@ Psycopg converts :sql:`decimal`\/\ :sql:`numeric` database types into Python `!D
psycopg2.extensions.register_type(DEC2FLOAT) psycopg2.extensions.register_type(DEC2FLOAT)
See :ref:`type-casting-from-sql-to-python` to read the relevant See :ref:`type-casting-from-sql-to-python` to read the relevant
documentation. If you find `!psycopg2.extensions.DECIMAL` not avalable, use documentation. If you find `!psycopg2.extensions.DECIMAL` not available, use
`!psycopg2._psycopg.DECIMAL` instead. `!psycopg2._psycopg.DECIMAL` instead.
.. _faq-json-adapt:
.. cssclass:: faq
Psycopg automatically converts PostgreSQL :sql:`json` data into Python objects. How can I receive strings instead?
The easiest way to avoid JSON parsing is to register a no-op function with
`~psycopg2.extras.register_default_json()`::
psycopg2.extras.register_default_json(loads=lambda x: x)
See :ref:`adapt-json` for further details.
.. _faq-jsonb-adapt:
.. cssclass:: faq
Psycopg converts :sql:`json` values into Python objects but :sql:`jsonb` values are returned as strings. Can :sql:`jsonb` be converted automatically?
Automatic conversion of :sql:`jsonb` values is supported from Psycopg
release 2.5.4. For previous versions you can register the :sql:`json`
typecaster on the :sql:`jsonb` oids (which are known and not supposed to
change in future PostgreSQL versions)::
psycopg2.extras.register_json(oid=3802, array_oid=3807, globally=True)
See :ref:`adapt-json` for further details.
.. _faq-identifier:
.. cssclass:: faq
How can I pass field/table names to a query?
The arguments in the `~cursor.execute()` methods can only represent data
to pass to the query: they cannot represent a table or field name::
# This doesn't work
cur.execute("insert into %s values (%s)", ["my_table", 42])
If you want to build a query dynamically you can use the objects exposed
by the `psycopg2.sql` module::
cur.execute(
sql.SQL("insert into %s values (%%s)") % [sql.Identifier("my_table")],
[42])
.. _faq-bytea-9.0: .. _faq-bytea-9.0:
.. cssclass:: faq .. cssclass:: faq
@ -140,8 +221,8 @@ Transferring binary data from PostgreSQL 9.0 doesn't work.
session before reading binary data; session before reading binary data;
- upgrade the libpq library on the client to at least 9.0. - upgrade the libpq library on the client to at least 9.0.
.. __: http://www.postgresql.org/docs/current/static/datatype-binary.html .. __: https://www.postgresql.org/docs/current/static/datatype-binary.html
.. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-BYTEA-OUTPUT .. __: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-BYTEA-OUTPUT
.. _faq-array: .. _faq-array:
@ -190,24 +271,64 @@ When should I save and re-use a connection as opposed to creating a new one as n
What are the advantages or disadvantages of using named cursors? What are the advantages or disadvantages of using named cursors?
The only disadvantages is that they use up resources on the server and The only disadvantages is that they use up resources on the server and
that there is a little overhead because a at least two queries (one to that there is a little overhead because at least two queries (one to
create the cursor and one to fetch the initial result set) are issued to create the cursor and one to fetch the initial result set) are issued to
the backend. The advantage is that data is fetched one chunk at a time: the backend. The advantage is that data is fetched one chunk at a time:
using small `~cursor.fetchmany()` values it is possible to use very using small `~cursor.fetchmany()` values it is possible to use very
little memory on the client and to skip or discard parts of the result set. little memory on the client and to skip or discard parts of the result set.
.. _faq-interrupt-query:
.. cssclass:: faq
How do I interrupt a long-running query in an interactive shell?
Normally the interactive shell becomes unresponsive to :kbd:`Ctrl-C` when
running a query. Using a connection in green mode allows Python to
receive and handle the interrupt, although it may leave the connection
broken, if the async callback doesn't handle the `!KeyboardInterrupt`
correctly.
Starting from psycopg 2.6.2, the `~psycopg2.extras.wait_select` callback
can handle a :kbd:`Ctrl-C` correctly. For previous versions, you can use
`this implementation`__.
.. __: https://www.psycopg.org/articles/2014/07/20/cancelling-postgresql-statements-python/
.. code-block:: pycon
>>> psycopg2.extensions.set_wait_callback(psycopg2.extras.wait_select)
>>> cnn = psycopg2.connect('')
>>> cur = cnn.cursor()
>>> cur.execute("select pg_sleep(10)")
^C
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
QueryCanceledError: canceling statement due to user request
>>> cnn.rollback()
>>> # You can use the connection and cursor again from here
.. _faq-compile: .. _faq-compile:
Problems compiling and deploying psycopg2 Problems compiling and installing psycopg2
----------------------------------------- ------------------------------------------
.. _faq-wheels:
.. cssclass:: faq
Psycopg 2.8 fails to install, Psycopg 2.7 was working fine.
With Psycopg 2.7 you were installing binary packages, but they have proven
unreliable so now you have to install them explicitly using the
``psycopg2-binary`` package. See :ref:`binary-packages` for all the
details.
.. _faq-python-h: .. _faq-python-h:
.. cssclass:: faq .. cssclass:: faq
I can't compile `!psycopg2`: the compiler says *error: Python.h: No such file or directory*. What am I missing? I can't compile `!psycopg2`: the compiler says *error: Python.h: No such file or directory*. What am I missing?
You need to install a Python development package: it is usually called You need to install a Python development package: it is usually called
``python-dev``. ``python-dev`` or ``python3-dev`` according to your Python version.
.. _faq-libpq-fe-h: .. _faq-libpq-fe-h:
@ -222,19 +343,28 @@ I can't compile `!psycopg2`: the compiler says *error: libpq-fe.h: No such file
.. cssclass:: faq .. cssclass:: faq
`!psycopg2` raises `!ImportError` with message *_psycopg.so: undefined symbol: lo_truncate* when imported. `!psycopg2` raises `!ImportError` with message *_psycopg.so: undefined symbol: lo_truncate* when imported.
This means that Psycopg has been compiled with |lo_truncate|_ support, This means that Psycopg was compiled with |lo_truncate|_ support (*i.e.*
which means that the libpq used at compile time was version >= 8.3, but at the libpq used at compile time was version >= 8.3) but at runtime an older
runtime an older libpq library is found. You can use:: libpq dynamic library is found.
Fast-forward several years, if the message reports *undefined symbol:
lo_truncate64* it means that Psycopg was built with large objects 64 bits
API support (*i.e.* the libpq used at compile time was at least 9.3) but
at runtime an older libpq dynamic library is found.
You can use:
.. code-block:: shell
$ ldd /path/to/packages/psycopg2/_psycopg.so | grep libpq $ ldd /path/to/packages/psycopg2/_psycopg.so | grep libpq
to find what is the version used at runtime. to find what is the libpq dynamic library used at runtime.
You can avoid the problem by using the same version of the You can avoid the problem by using the same version of the
:program:`pg_config` at install time and the libpq at runtime. :program:`pg_config` at install time and the libpq at runtime.
.. |lo_truncate| replace:: `!lo_truncate()` .. |lo_truncate| replace:: `!lo_truncate()`
.. _lo_truncate: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE .. _lo_truncate: https://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE
.. _faq-import-mod_wsgi: .. _faq-import-mod_wsgi:
@ -248,6 +378,5 @@ Psycopg raises *ImportError: cannot import name tz* on import in mod_wsgi / ASP,
use the WSGIPythonEggs__ directive. use the WSGIPythonEggs__ directive.
.. _egg: http://peak.telecommunity.com/DevCenter/PythonEggs .. _egg: http://peak.telecommunity.com/DevCenter/PythonEggs
.. __: http://stackoverflow.com/questions/2192323/what-is-the-python-egg-cache-python-egg-cache .. __: https://stackoverflow.com/questions/2192323/what-is-the-python-egg-cache-python-egg-cache
.. __: http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPythonEggs .. __: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIPythonEggs.html

View File

@ -14,27 +14,19 @@ of concurrent :sql:`INSERT`\s or :sql:`UPDATE`\s.
Psycopg 2 is mostly implemented in C as a libpq_ wrapper, resulting in being Psycopg 2 is mostly implemented in C as a libpq_ wrapper, resulting in being
both efficient and secure. It features client-side and :ref:`server-side both efficient and secure. It features client-side and :ref:`server-side
<server-side-cursors>` cursors, :ref:`asynchronous communication <server-side-cursors>` cursors, :ref:`asynchronous communication
<async-support>` and :ref:`notifications <async-notify>`, |COPY-TO-FROM|__ <async-support>` and :ref:`notifications <async-notify>`, :ref:`COPY <copy>`
support, and a flexible :ref:`objects adaptation system support. Many Python types are supported out-of-the-box and :ref:`adapted to
<python-types-adaptation>`. Many basic Python types are supported matching PostgreSQL data types <python-types-adaptation>`; adaptation can be
out-of-the-box and mapped to matching PostgreSQL data types, such as strings extended and customized thanks to a flexible :ref:`objects adaptation system
(both byte strings and Unicode), numbers (ints, longs, floats, decimals), <adapting-new-types>`.
booleans and date/time objects (both built-in and `mx.DateTime`_), several
types of :ref:`binary objects <adapt-binary>`. Also available are mappings
between lists and PostgreSQL arrays of any supported type, between
:ref:`dictionaries and PostgreSQL hstore <adapt-hstore>`, between
:ref:`tuples/namedtuples and PostgreSQL composite types <adapt-composite>`,
and between Python objects and :ref:`JSON <adapt-json>`.
Psycopg 2 is both Unicode and Python 3 friendly. Psycopg 2 is both Unicode and Python 3 friendly.
.. _Psycopg: http://initd.org/psycopg/ .. _Psycopg: https://psycopg.org/
.. _PostgreSQL: http://www.postgresql.org/ .. _PostgreSQL: https://www.postgresql.org/
.. _Python: http://www.python.org/ .. _Python: https://www.python.org/
.. _libpq: http://www.postgresql.org/docs/current/static/libpq.html .. _libpq: https://www.postgresql.org/docs/current/static/libpq.html
.. |COPY-TO-FROM| replace:: :sql:`COPY TO/COPY FROM`
.. __: http://www.postgresql.org/docs/current/static/sql-copy.html
.. rubric:: Contents .. rubric:: Contents
@ -49,12 +41,15 @@ Psycopg 2 is both Unicode and Python 3 friendly.
cursor cursor
advanced advanced
extensions extensions
extras
errors
sql
tz tz
pool pool
extras
errorcodes errorcodes
faq faq
news news
license
.. ifconfig:: builder != 'text' .. ifconfig:: builder != 'text'
@ -62,6 +57,7 @@ Psycopg 2 is both Unicode and Python 3 friendly.
.. rubric:: Indices and tables .. rubric:: Indices and tables
* :ref:`genindex` * :ref:`genindex`
* :ref:`modindex`
* :ref:`search` * :ref:`search`
@ -72,4 +68,3 @@ Psycopg 2 is both Unicode and Python 3 friendly.
**To Do items in the documentation** **To Do items in the documentation**
.. todolist:: .. todolist::

View File

@ -1,4 +1,6 @@
Introduction .. _installation:
Installation
============ ============
.. sectionauthor:: Daniele Varrazzo <daniele.varrazzo@gmail.com> .. sectionauthor:: Daniele Varrazzo <daniele.varrazzo@gmail.com>
@ -6,120 +8,161 @@ Introduction
Psycopg is a PostgreSQL_ adapter for the Python_ programming language. It is a Psycopg is a PostgreSQL_ adapter for the Python_ programming language. It is a
wrapper for the libpq_, the official PostgreSQL client library. wrapper for the libpq_, the official PostgreSQL client library.
The `psycopg2` package is the current mature implementation of the adapter: it .. _PostgreSQL: https://www.postgresql.org/
is a C extension and as such it is only compatible with CPython_. If you want .. _Python: https://www.python.org/
to use Psycopg on a different Python implementation (PyPy, Jython, IronPython)
there is an experimental `porting of Psycopg for Ctypes`__, but it is not as
mature as the C implementation yet. .. index::
single: Install; from PyPI
single: Install; wheel
single: Wheel
.. _binary-packages:
Quick Install
-------------
For most operating systems, the quickest way to install Psycopg is using the
wheel_ package available on PyPI_:
.. code-block:: console
$ pip install psycopg2-binary
This will install a pre-compiled binary version of the module which does not
require the build or runtime prerequisites described below. Make sure to use
an up-to-date version of :program:`pip` (you can upgrade it using something
like ``pip install -U pip``).
You may then import the ``psycopg2`` package, as usual:
.. code-block:: python
import psycopg2
# Connect to your postgres DB
conn = psycopg2.connect("dbname=test user=postgres")
# Open a cursor to perform database operations
cur = conn.cursor()
# Execute a query
cur.execute("SELECT * FROM my_data")
# Retrieve query results
records = cur.fetchall()
.. _PyPI: https://pypi.org/project/psycopg2-binary/
.. _wheel: https://pythonwheels.com/
psycopg vs psycopg-binary
^^^^^^^^^^^^^^^^^^^^^^^^^
The ``psycopg2-binary`` package is meant for beginners to start playing
with Python and PostgreSQL without the need to meet the build
requirements.
If you are the maintainer of a published package depending on `!psycopg2`
you shouldn't use ``psycopg2-binary`` as a module dependency. **For
production use you are advised to use the source distribution.**
The binary packages come with their own versions of a few C libraries,
among which ``libpq`` and ``libssl``, which will be used regardless of other
libraries available on the client: upgrading the system libraries will not
upgrade the libraries used by `!psycopg2`. Please build `!psycopg2` from
source if you want to maintain binary upgradeability.
.. warning::
The `!psycopg2` wheel package comes packaged, among the others, with its
own ``libssl`` binary. This may create conflicts with other extension
modules binding with ``libssl`` as well, for instance with the Python
`ssl` module: in some cases, under concurrency, the interaction between
the two libraries may result in a segfault. In case of doubts you are
advised to use a package built from source.
.. index::
single: Install; disable wheel
single: Wheel; disable
.. _disable-wheel:
Change in binary packages between Psycopg 2.7 and 2.8
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In version 2.7.x, :command:`pip install psycopg2` would have tried to install
automatically the binary package of Psycopg. Because of concurrency problems
binary packages have displayed, ``psycopg2-binary`` has become a separate
package, and from 2.8 it has become the only way to install the binary
package.
If you are using Psycopg 2.7 and you want to disable the use of wheel binary
packages, relying on the system libraries available on your client, you
can use the :command:`pip` |--no-binary option|__, e.g.:
.. code-block:: console
$ pip install --no-binary :all: psycopg2
.. |--no-binary option| replace:: ``--no-binary`` option
.. __: https://pip.pypa.io/en/stable/reference/pip_install/#install-no-binary
which can be specified in your :file:`requirements.txt` files too, e.g. use:
.. code-block:: none
psycopg2>=2.7,<2.8 --no-binary psycopg2
to use the last bugfix release of the `!psycopg2` 2.7 package, specifying to
always compile it from source. Of course in this case you will have to meet
the :ref:`build prerequisites <build-prerequisites>`.
.. index::
single: Prerequisites
Prerequisites
-------------
The current `!psycopg2` implementation supports: The current `!psycopg2` implementation supports:
- Python 2 versions from 2.5 to 2.7 ..
- Python 3 versions from 3.1 to 3.3 NOTE: keep consistent with setup.py and the /features/ page.
- PostgreSQL versions from 7.4 to 9.2
.. _PostgreSQL: http://www.postgresql.org/
.. _Python: http://www.python.org/
.. _libpq: http://www.postgresql.org/docs/current/static/libpq.html
.. _CPython: http://en.wikipedia.org/wiki/CPython
.. _Ctypes: http://docs.python.org/library/ctypes.html
.. __: https://github.com/mvantellingen/psycopg2-ctypes
- Python versions from 3.8 to 3.13
- PostgreSQL server versions from 7.4 to 17
- PostgreSQL client library version from 9.1
.. note:: .. note::
`!psycopg2` usually depends at runtime on the libpq dynamic library. Not all the psycopg2 versions support all the supported Python versions.
However it can connect to PostgreSQL servers of any supported version,
independently of the version of the libpq used: just install the most Please see the :ref:`release notes <news>` to verify when the support for
recent libpq version or the most practical, without trying to match it to a new Python version was added and when the support for an old Python
the version of the PostgreSQL server you will have to connect to. version was removed.
Installation .. _build-prerequisites:
============
If possible, and usually it is, please :ref:`install Psycopg from a package Build prerequisites
<install-from-package>` available for your distribution or operating system. ^^^^^^^^^^^^^^^^^^^
Compiling from source is a very easy task, however `!psycopg2` is a C The build prerequisites are to be met in order to install Psycopg from source
extension module and as such it requires a few more things in place respect to code, from a source distribution package, GitHub_ or from PyPI.
a pure Python module. So, if you don't have experience compiling Python
extension packages, *above all if you are a Windows or a Mac OS user*, please
use a pre-compiled package and go straight to the :ref:`module usage <usage>`
avoid bothering with the gory details.
.. _GitHub: https://github.com/psycopg/psycopg2
Psycopg is a C wrapper around the libpq_ PostgreSQL client library. To install
.. _install-from-package: it from sources you will need:
Install from a package
----------------------
.. index::
pair: Install; Linux
**Linux**
Psycopg is available already packaged in many Linux distributions: look
for a package such as ``python-psycopg2`` using the package manager of
your choice.
On Debian, Ubuntu and other deb-based distributions you should just need::
sudo apt-get install python-psycopg2
to install the package with all its dependencies.
.. index::
pair: Install; Mac OS X
**Mac OS X**
Psycopg is available as a `fink package`__ in the *unstable* tree: you may
install it with::
fink install psycopg2-py27
.. __: http://pdb.finkproject.org/pdb/package.php/psycopg2-py27
The library is also available on `MacPorts`__ try::
sudo port install py27-psycopg2
.. __: http://www.macports.org/
.. index::
pair: Install; Windows
**Microsoft Windows**
Jason Erickson maintains a packaged `Windows port of Psycopg`__ with
installation executable. Download. Double click. Done.
.. __: http://www.stickpeople.com/projects/python/win-psycopg/
.. index::
single: Install; from source
.. _install-from-source:
Install from source
-------------------
These notes illustrate how to compile Psycopg on Linux. If you want to compile
Psycopg on other platforms you may have to adjust some details accordingly.
.. _requirements:
Psycopg is a C wrapper to the libpq PostgreSQL client library. To install it
from sources you will need:
- A C compiler. - A C compiler.
- The Python header files. They are usually installed in a package such as - The Python header files. They are usually installed in a package such as
**python-dev**. A message such as *error: Python.h: No such file or **python-dev** or **python3-dev**. A message such as *error: Python.h: No
directory* is an indication that the Python headers are missing. such file or directory* is an indication that the Python headers are
missing.
- The libpq header files. They are usually installed in a package such as - The libpq header files. They are usually installed in a package such as
**libpq-dev**. If you get an *error: libpq-fe.h: No such file or directory* **libpq-dev**. If you get an *error: libpq-fe.h: No such file or directory*
@ -131,12 +174,40 @@ from sources you will need:
running ``pg_config --version``: if it returns an error or an unexpected running ``pg_config --version``: if it returns an error or an unexpected
version number then locate the directory containing the :program:`pg_config` version number then locate the directory containing the :program:`pg_config`
shipped with the right libpq version (usually shipped with the right libpq version (usually
``/usr/lib/postgresql/X.Y/bin/``) and add it to the :envvar:`PATH`:: ``/usr/lib/postgresql/X.Y/bin/``) and add it to the :envvar:`PATH`:
.. code-block:: console
$ export PATH=/usr/lib/postgresql/X.Y/bin/:$PATH $ export PATH=/usr/lib/postgresql/X.Y/bin/:$PATH
You only need it to compile and install `!psycopg2`, not for its regular You only need :program:`pg_config` to compile `!psycopg2`, not for its
usage. regular usage.
Once everything is in place it's just a matter of running the standard:
.. code-block:: console
$ pip install psycopg2
or, from the directory containing the source code:
.. code-block:: console
$ python setup.py build
$ python setup.py install
Runtime requirements
^^^^^^^^^^^^^^^^^^^^
Unless you compile `!psycopg2` as a static library, or you install it from a
self-contained wheel package, it will need the libpq_ library at runtime
(usually distributed in a ``libpq.so`` or ``libpq.dll`` file). `!psycopg2`
relies on the host OS to find the library if the library is installed in a
standard location there is usually no problem; if the library is in a
non-standard location you will have to tell Psycopg how to find it,
which is OS-dependent (for instance setting a suitable
:envvar:`LD_LIBRARY_PATH` on Linux).
.. note:: .. note::
@ -146,61 +217,40 @@ from sources you will need:
:program:`ldd`) if the module ``psycopg2/_psycopg.so`` is linked to the :program:`ldd`) if the module ``psycopg2/_psycopg.so`` is linked to the
right ``libpq.so``. right ``libpq.so``.
.. note::
Whatever version of libpq `!psycopg2` is compiled with, it will be
.. index:: possible to connect to PostgreSQL servers of any supported version: just
single: Install; from PyPI install the most recent libpq version or the most practical, without
trying to match it to the version of the PostgreSQL server you will have
.. _package-manager: to connect to.
Use a Python package manager
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If the above requirements are satisfied, you can use :program:`easy_install`,
:program:`pip` or whatever the Python package manager of the week::
$ pip install psycopg2
Please refer to your package manager documentation about performing a local or
global installation, :program:`virtualenv` (fully supported by recent Psycopg
versions), using different Python versions and other nuances.
.. index:: .. index::
single: setup.py single: setup.py
single: setup.cfg single: setup.cfg
.. _source-package: Non-standard builds
-------------------
Use the source package
^^^^^^^^^^^^^^^^^^^^^^
You can download a copy of Psycopg source files from the `Psycopg download
page`__. Once unpackaged, to compile and install the package you can run::
$ python setup.py build
$ sudo python setup.py install
If you have less standard requirements such as: If you have less standard requirements such as:
- creating a :ref:`debug build <debug-build>`, - creating a :ref:`debug build <debug-build>`,
- using :program:`pg_config` not in the :envvar:`PATH`, - using :program:`pg_config` not in the :envvar:`PATH`,
- supporting ``mx.DateTime``,
then take a look at the ``setup.cfg`` file. then take a look at the ``setup.cfg`` file.
Some of the options available in ``setup.cfg`` are also available as command Some of the options available in ``setup.cfg`` are also available as command
line arguments of the ``build_ext`` sub-command. For instance you can specify line arguments of the ``build_ext`` sub-command. For instance you can specify
an alternate :program:`pg_config` version using:: an alternate :program:`pg_config` location using:
.. code-block:: console
$ python setup.py build_ext --pg-config /path/to/pg_config build $ python setup.py build_ext --pg-config /path/to/pg_config build
Use ``python setup.py build_ext --help`` to get a list of the options Use ``python setup.py build_ext --help`` to get a list of the options
supported. supported.
.. __: http://initd.org/psycopg/download/
.. index:: .. index::
single: debug single: debug
@ -209,30 +259,83 @@ supported.
.. _debug-build: .. _debug-build:
Creating a debug build Creating a debug build
---------------------- ^^^^^^^^^^^^^^^^^^^^^^
In case of problems, Psycopg can be configured to emit detailed debug In case of problems, Psycopg can be configured to emit detailed debug
messages, which can be very useful for diagnostics and to report a bug. In messages, which can be very useful for diagnostics and to report a bug. In
order to create a debug package: order to create a debug package:
- `Download`__ and unpack the Psycopg source package. - `Download`__ and unpack the Psycopg *source package* (the ``.tar.gz``
package).
- Edit the ``setup.cfg`` file adding the ``PSYCOPG_DEBUG`` flag to the - Edit the ``setup.cfg`` file adding the ``PSYCOPG_DEBUG`` flag to the
``define`` option. ``define`` option.
- :ref:`Compile and install <source-package>` the package. - :ref:`Compile and install <build-prerequisites>` the package.
- Set the :envvar:`PSYCOPG_DEBUG` variable:: - Set the :envvar:`PSYCOPG_DEBUG` environment variable:
.. code-block:: console
$ export PSYCOPG_DEBUG=1 $ export PSYCOPG_DEBUG=1
- Run your program (making sure that the `!psycopg2` package imported is the - Run your program (making sure that the `!psycopg2` package imported is the
one you just compiled and not e.g. the system one): you will have a copious one you just compiled and not e.g. the system one): you will have a copious
stream of informations printed on stdout. stream of informations printed on stderr.
.. __: http://initd.org/psycopg/download/ .. __: https://pypi.org/project/psycopg2/#files
Non-standard Python Implementation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The `psycopg2` package is the current mature implementation of the adapter: it
is a C extension and as such it is only compatible with CPython_. If you want
to use Psycopg on a different Python implementation (PyPy, Jython, IronPython)
there is a couple of alternative:
- a `Ctypes port`__, but it is not as mature as the C implementation yet
and it is not as feature-complete;
- a `CFFI port`__ which is currently more used and reported more efficient on
PyPy, but please be careful of its version numbers because they are not
aligned to the official psycopg2 ones and some features may differ.
.. _PostgreSQL: https://www.postgresql.org/
.. _Python: https://www.python.org/
.. _libpq: https://www.postgresql.org/docs/current/static/libpq.html
.. _CPython: https://en.wikipedia.org/wiki/CPython
.. _Ctypes: https://docs.python.org/library/ctypes.html
.. __: https://github.com/mvantellingen/psycopg2-ctypes
.. __: https://github.com/chtd/psycopg2cffi
.. index::
single: tests
.. _test-suite:
Running the test suite
----------------------
Once `!psycopg2` is installed you can run the test suite to verify it is
working correctly. From the source directory, you can run:
.. code-block:: console
$ python -c "import tests; tests.unittest.main(defaultTest='tests.test_suite')" --verbose
The tests run against a database called ``psycopg2_test`` on UNIX socket and
the standard port. You can configure a different database to run the test by
setting the environment variables:
- :envvar:`PSYCOPG2_TESTDB`
- :envvar:`PSYCOPG2_TESTDB_HOST`
- :envvar:`PSYCOPG2_TESTDB_PORT`
- :envvar:`PSYCOPG2_TESTDB_USER`
The database should already exist before running the tests.
.. _other-problems: .. _other-problems:
@ -241,18 +344,21 @@ If you still have problems
Try the following. *In order:* Try the following. *In order:*
- Read again the :ref:`requirements <requirements>`. - Read again the :ref:`build-prerequisites`.
- Read the :ref:`FAQ <faq-compile>`. - Read the :ref:`FAQ <faq-compile>`.
- Google for `!psycopg2` *your error message*. Especially useful the week - Google for `!psycopg2` *your error message*. Especially useful the week
after the release of a new OS X version. after the release of a new OS X version.
- Write to the `Mailing List`__. - Write to the `Mailing List`_.
- If you think that you have discovered a bug, test failure or missing feature
please raise a ticket in the `bug tracker`_.
- Complain on your blog or on Twitter that `!psycopg2` is the worst package - Complain on your blog or on Twitter that `!psycopg2` is the worst package
ever and about the quality time you have wasted figuring out the correct ever and about the quality time you have wasted figuring out the correct
:envvar:`ARCHFLAGS`. Especially useful from the Starbucks near you. :envvar:`ARCHFLAGS`. Especially useful from the Starbucks near you.
.. __: http://mail.postgresql.org/mj/mj_wwwusr/domain=postgresql.org?func=lists-long-full&extra=psycopg .. _mailing list: https://www.postgresql.org/list/psycopg/
.. _bug tracker: https://github.com/psycopg/psycopg2/issues

7
doc/src/license.rst Normal file
View File

@ -0,0 +1,7 @@
.. index::
single: License
License
=======
.. include:: ../../LICENSE

View File

@ -17,47 +17,44 @@ The module interface respects the standard defined in the |DBAPI|_.
single: DSN (Database Source Name) single: DSN (Database Source Name)
.. function:: .. function::
connect(dsn, connection_factory=None, cursor_factory=None, async=False) connect(dsn=None, connection_factory=None, cursor_factory=None, async=False, \*\*kwargs)
connect(\*\*kwargs, connection_factory=None, cursor_factory=None, async=False)
Create a new database session and return a new `connection` object. Create a new database session and return a new `connection` object.
The connection parameters can be specified either as a `libpq connection The connection parameters can be specified as a `libpq connection
string`__ using the *dsn* parameter:: string`__ using the *dsn* parameter::
conn = psycopg2.connect("dbname=test user=postgres password=secret") conn = psycopg2.connect("dbname=test user=postgres password=secret")
or using a set of keyword arguments:: or using a set of keyword arguments::
conn = psycopg2.connect(database="test", user="postgres", password="secret") conn = psycopg2.connect(dbname="test", user="postgres", password="secret")
The two call styles are mutually exclusive: you cannot specify connection or using a mix of both: if the same parameter name is specified in both
parameters as keyword arguments together with a connection string; only sources, the *kwargs* value will have precedence over the *dsn* value.
the parameters not needed for the database connection (*i.e.* Note that either the *dsn* or at least one connection-related keyword
*connection_factory*, *cursor_factory*, and *async*) are supported argument is required.
together with the *dsn* argument.
The basic connection parameters are: The basic connection parameters are:
- `!dbname` -- the database name (only in the *dsn* string) - `!dbname` -- the database name (`!database` is a deprecated alias)
- `!database` -- the database name (only as keyword argument)
- `!user` -- user name used to authenticate - `!user` -- user name used to authenticate
- `!password` -- password used to authenticate - `!password` -- password used to authenticate
- `!host` -- database host address (defaults to UNIX socket if not provided) - `!host` -- database host address (defaults to UNIX socket if not provided)
- `!port` -- connection port number (defaults to 5432 if not provided) - `!port` -- connection port number (defaults to 5432 if not provided)
Any other connection parameter supported by the client library/server can Any other connection parameter supported by the client library/server can
be passed either in the connection string or as keywords. The PostgreSQL be passed either in the connection string or as a keyword. The PostgreSQL
documentation contains the complete list of the `supported parameters`__. documentation contains the complete list of the `supported parameters`__.
Also note that the same parameters can be passed to the client library Also note that the same parameters can be passed to the client library
using `environment variables`__. using `environment variables`__.
.. __: .. __:
.. _connstring: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING .. _connstring: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
.. __: .. __:
.. _connparams: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS .. _connparams: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-PARAMKEYWORDS
.. __: .. __:
.. _connenvvars: http://www.postgresql.org/docs/current/static/libpq-envars.html .. _connenvvars: https://www.postgresql.org/docs/current/static/libpq-envars.html
Using the *connection_factory* parameter a different class or Using the *connection_factory* parameter a different class or
connections factory can be specified. It should be a callable object connections factory can be specified. It should be a callable object
@ -67,7 +64,8 @@ The module interface respects the standard defined in the |DBAPI|_.
cursors you can use this parameter instead of subclassing a connection. cursors you can use this parameter instead of subclassing a connection.
Using *async*\=\ `!True` an asynchronous connection will be created: see Using *async*\=\ `!True` an asynchronous connection will be created: see
:ref:`async-support` to know about advantages and limitations. :ref:`async-support` to know about advantages and limitations. *async_* is
a valid alias for the Python version where ``async`` is a keyword.
.. versionchanged:: 2.4.3 .. versionchanged:: 2.4.3
any keyword argument is passed to the connection. Previously only the any keyword argument is passed to the connection. Previously only the
@ -76,8 +74,15 @@ The module interface respects the standard defined in the |DBAPI|_.
.. versionchanged:: 2.5 .. versionchanged:: 2.5
added the *cursor_factory* parameter. added the *cursor_factory* parameter.
.. versionchanged:: 2.7
both *dsn* and keyword arguments can be specified.
.. versionchanged:: 2.7
added *async_* alias.
.. seealso:: .. seealso::
- `~psycopg2.extensions.parse_dsn`
- libpq `connection string syntax`__ - libpq `connection string syntax`__
- libpq supported `connection parameters`__ - libpq supported `connection parameters`__
- libpq supported `environment variables`__ - libpq supported `environment variables`__
@ -88,9 +93,8 @@ The module interface respects the standard defined in the |DBAPI|_.
.. extension:: .. extension::
The parameters *connection_factory* and *async* are Psycopg extensions The non-connection-related keyword parameters are Psycopg extensions
to the |DBAPI|. to the |DBAPI|_.
.. data:: apilevel .. data:: apilevel
@ -109,6 +113,14 @@ The module interface respects the standard defined in the |DBAPI|_.
by the interface. For `psycopg2` is ``pyformat``. See also by the interface. For `psycopg2` is ``pyformat``. See also
:ref:`query-parameters`. :ref:`query-parameters`.
.. data:: __libpq_version__
Integer constant reporting the version of the ``libpq`` library this
``psycopg2`` module was compiled with (in the same format of
`~psycopg2.extensions.ConnectionInfo.server_version`). If this value is
greater or equal than ``90100`` then you may query the version of the
actually loaded library using the `~psycopg2.extensions.libpq_version()`
function.
.. index:: .. index::
@ -125,14 +137,15 @@ available through the following exceptions:
.. exception:: Warning .. exception:: Warning
Exception raised for important warnings like data truncations while Exception raised for important warnings like data truncations while
inserting, etc. It is a subclass of the Python `~exceptions.StandardError`. inserting, etc. It is a subclass of the Python `StandardError`
(`Exception` on Python 3).
.. exception:: Error .. exception:: Error
Exception that is the base class of all other error exceptions. You can Exception that is the base class of all other error exceptions. You can
use this to catch all errors with one single `!except` statement. Warnings use this to catch all errors with one single `!except` statement. Warnings
are not considered errors and thus not use this class as base. It are not considered errors and thus not use this class as base. It
is a subclass of the Python `!StandardError`. is a subclass of the Python `StandardError` (`Exception` on Python 3).
.. attribute:: pgerror .. attribute:: pgerror
@ -150,15 +163,16 @@ available through the following exceptions:
>>> try: >>> try:
... cur.execute("SELECT * FROM barf") ... cur.execute("SELECT * FROM barf")
... except Exception, e: ... except psycopg2.Error as e:
... pass ... pass
>>> e.pgcode >>> e.pgcode
'42P01' '42P01'
>>> print e.pgerror >>> print(e.pgerror)
ERROR: relation "barf" does not exist ERROR: relation "barf" does not exist
LINE 1: SELECT * FROM barf LINE 1: SELECT * FROM barf
^ ^
.. attribute:: cursor .. attribute:: cursor
The cursor the exception was raised from; `None` if not applicable. The cursor the exception was raised from; `None` if not applicable.
@ -170,7 +184,7 @@ available through the following exceptions:
>>> try: >>> try:
... cur.execute("SELECT * FROM barf") ... cur.execute("SELECT * FROM barf")
... except Exception, e: ... except psycopg2.Error as e:
... pass ... pass
>>> e.diag.severity >>> e.diag.severity
@ -238,13 +252,14 @@ available through the following exceptions:
.. extension:: .. extension::
Psycopg may raise a few other, more specialized, exceptions: currently Psycopg actually raises a different exception for each :sql:`SQLSTATE`
`~psycopg2.extensions.QueryCanceledError` and error returned by the database: the classes are available in the
`~psycopg2.extensions.TransactionRollbackError` are defined. These `psycopg2.errors` module. Every exception class is a subclass of one of
exceptions are not exposed by the main `!psycopg2` module but are the exception classes defined here though, so they don't need to be
made available by the `~psycopg2.extensions` module. All the trapped specifically: trapping `!Error` or `!DatabaseError` is usually
additional exceptions are subclasses of standard |DBAPI| exceptions, so what needed to write a generic error handler; trapping a specific error
trapping them specifically is not required. such as `!NotNullViolation` can be useful to write specific exception
handlers.
This is the exception inheritance layout: This is the exception inheritance layout:
@ -258,8 +273,6 @@ This is the exception inheritance layout:
\|__ `DatabaseError` \|__ `DatabaseError`
\|__ `DataError` \|__ `DataError`
\|__ `OperationalError` \|__ `OperationalError`
\| \|__ `psycopg2.extensions.QueryCanceledError`
\| \|__ `psycopg2.extensions.TransactionRollbackError`
\|__ `IntegrityError` \|__ `IntegrityError`
\|__ `InternalError` \|__ `InternalError`
\|__ `ProgrammingError` \|__ `ProgrammingError`

View File

@ -1,3 +1,9 @@
.. index::
single: Release notes
single: News
.. _news:
Release notes Release notes
============= =============

View File

@ -24,13 +24,18 @@ directly in the client application.
.. method:: getconn(key=None) .. method:: getconn(key=None)
Get a free connection and assign it to *key* if not `!None`. Get a free connection from the pool.
The *key* parameter is optional: if used, the connection will be
associated to the key and calling `!getconn()` with the same key again
will return the same connection.
.. method:: putconn(conn, key=None, close=False) .. method:: putconn(conn, key=None, close=False)
Put away a connection. Put away a connection.
If *close* is `!True`, discard the connection from the pool. If *close* is `!True`, discard the connection from the pool.
*key* should be used consistently with `getconn()`.
.. method:: closeall .. method:: closeall
@ -53,12 +58,3 @@ be used.
.. autoclass:: ThreadedConnectionPool .. autoclass:: ThreadedConnectionPool
.. note:: This pool class can be safely used in multi-threaded applications. .. note:: This pool class can be safely used in multi-threaded applications.
.. autoclass:: PersistentConnectionPool
.. note::
This pool class is mostly designed to interact with Zope and probably
not useful in generic applications.

147
doc/src/sql.rst Normal file
View File

@ -0,0 +1,147 @@
`psycopg2.sql` -- SQL string composition
========================================
.. sectionauthor:: Daniele Varrazzo <daniele.varrazzo@gmail.com>
.. module:: psycopg2.sql
.. versionadded:: 2.7
The module contains objects and functions useful to generate SQL dynamically,
in a convenient and safe way. SQL identifiers (e.g. names of tables and
fields) cannot be passed to the `~cursor.execute()` method like query
arguments::
# This will not work
table_name = 'my_table'
cur.execute("insert into %s values (%s, %s)", [table_name, 10, 20])
The SQL query should be composed before the arguments are merged, for
instance::
# This works, but it is not optimal
table_name = 'my_table'
cur.execute(
"insert into %s values (%%s, %%s)" % table_name,
[10, 20])
This sort of works, but it is an accident waiting to happen: the table name
may be an invalid SQL literal and need quoting; even more serious is the
security problem in case the table name comes from an untrusted source. The
name should be escaped using `~psycopg2.extensions.quote_ident()`::
# This works, but it is not optimal
table_name = 'my_table'
cur.execute(
"insert into %s values (%%s, %%s)" % ext.quote_ident(table_name, cur),
[10, 20])
This is now safe, but it somewhat ad-hoc. In case, for some reason, it is
necessary to include a value in the query string (as opposite as in a value)
the merging rule is still different (`~psycopg2.extensions.adapt()` should be
used...). It is also still relatively dangerous: if `!quote_ident()` is
forgotten somewhere, the program will usually work, but will eventually crash
in the presence of a table or field name with containing characters to escape,
or will present a potentially exploitable weakness.
The objects exposed by the `!psycopg2.sql` module allow generating SQL
statements on the fly, separating clearly the variable parts of the statement
from the query parameters::
from psycopg2 import sql
cur.execute(
sql.SQL("insert into {} values (%s, %s)")
.format(sql.Identifier('my_table')),
[10, 20])
Module usage
------------
Usually you should express the template of your query as an `SQL` instance
with `{}`\-style placeholders and use `~SQL.format()` to merge the variable
parts into them, all of which must be `Composable` subclasses. You can still
have `%s`\ -style placeholders in your query and pass values to
`~cursor.execute()`: such value placeholders will be untouched by
`!format()`::
query = sql.SQL("select {field} from {table} where {pkey} = %s").format(
field=sql.Identifier('my_name'),
table=sql.Identifier('some_table'),
pkey=sql.Identifier('id'))
The resulting object is meant to be passed directly to cursor methods such as
`~cursor.execute()`, `~cursor.executemany()`, `~cursor.copy_expert()`, but can
also be used to compose a query as a Python string, using the
`~Composable.as_string()` method::
cur.execute(query, (42,))
If part of your query is a variable sequence of arguments, such as a
comma-separated list of field names, you can use the `SQL.join()` method to
pass them to the query::
query = sql.SQL("select {fields} from {table}").format(
fields=sql.SQL(',').join([
sql.Identifier('field1'),
sql.Identifier('field2'),
sql.Identifier('field3'),
]),
table=sql.Identifier('some_table'))
`!sql` objects
--------------
The `!sql` objects are in the following inheritance hierarchy:
| `Composable`: the base class exposing the common interface
| ``|__`` `SQL`: a literal snippet of an SQL query
| ``|__`` `Identifier`: a PostgreSQL identifier or dot-separated sequence of identifiers
| ``|__`` `Literal`: a value hardcoded into a query
| ``|__`` `Placeholder`: a `%s`\ -style placeholder whose value will be added later e.g. by `~cursor.execute()`
| ``|__`` `Composed`: a sequence of `!Composable` instances.
.. autoclass:: Composable
.. automethod:: as_string
.. autoclass:: SQL
.. autoattribute:: string
.. automethod:: format
.. automethod:: join
.. autoclass:: Identifier
.. versionchanged:: 2.8
added support for multiple strings.
.. autoattribute:: strings
.. versionadded:: 2.8
previous verions only had a `!string` attribute. The attribute
still exists but is deprecate and will only work if the
`!Identifier` wraps a single string.
.. autoclass:: Literal
.. autoattribute:: wrapped
.. autoclass:: Placeholder
.. autoattribute:: name
.. autoclass:: Composed
.. autoattribute:: seq
.. automethod:: join

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
""" """
extension extension
~~~~~~~~~ ~~~~~~~~~
@ -12,7 +11,7 @@
from docutils import nodes from docutils import nodes
from sphinx.locale import _ from sphinx.locale import _
from sphinx.util.compat import Directive, make_admonition from docutils.parsers.rst import Directive
class extension_node(nodes.Admonition, nodes.Element): pass class extension_node(nodes.Admonition, nodes.Element): pass
@ -29,12 +28,11 @@ class Extension(Directive):
option_spec = {} option_spec = {}
def run(self): def run(self):
nodes = make_admonition(extension_node, node = extension_node('\n'.join(self.content))
self.name, [_('DB API extension')], self.options, node += nodes.title(_('DB API extension'), _('DB API extension'))
self.content, self.lineno, self.content_offset, self.state.nested_parse(self.content, self.content_offset, node)
self.block_text, self.state, self.state_machine) node['classes'].append('dbapi-extension')
nodes[0]['classes'].append('dbapi-extension') return [node]
return nodes
def visit_extension_node(self, node): def visit_extension_node(self, node):
@ -50,4 +48,3 @@ def setup(app):
text=(visit_extension_node, depart_extension_node)) text=(visit_extension_node, depart_extension_node))
app.add_directive('extension', Extension) app.add_directive('extension', Extension)

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
""" """
sql role sql role
~~~~~~~~ ~~~~~~~~
@ -18,4 +17,3 @@ def sql_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
def setup(app): def setup(app):
roles.register_local_role('sql', sql_role) roles.register_local_role('sql', sql_role)

View File

@ -1,39 +1,57 @@
# -*- coding: utf-8 -*-
""" """
ticket role ticket role
~~~~~~~~~~~ ~~~~~~~~~~~
An interpreted text role to link docs to lighthouse issues. An interpreted text role to link docs to tickets issues.
:copyright: Copyright 2013 by Daniele Varrazzo. :copyright: Copyright 2013 by Daniele Varrazzo.
""" """
import re
from docutils import nodes, utils from docutils import nodes, utils
from docutils.parsers.rst import roles from docutils.parsers.rst import roles
def ticket_role(name, rawtext, text, lineno, inliner, options={}, content=[]): def ticket_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
try: cfg = inliner.document.settings.env.app.config
num = int(text.replace('#', '')) if cfg.ticket_url is None:
except ValueError:
msg = inliner.reporter.error(
"ticket number must be... a number, got '%s'" % text)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
url_pattern = inliner.document.settings.env.app.config.ticket_url
if url_pattern is None:
msg = inliner.reporter.warning( msg = inliner.reporter.warning(
"ticket not configured: please configure ticket_url in conf.py") "ticket not configured: please configure ticket_url in conf.py")
prb = inliner.problematic(rawtext, rawtext, msg) prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg] return [prb], [msg]
url = url_pattern % num rv = [nodes.Text(name + ' ')]
tokens = re.findall(r'(#?\d+)|([^\d#]+)', text)
for ticket, noise in tokens:
if ticket:
num = int(ticket.replace('#', ''))
# Push numbers of the oldel tickets ahead.
# We moved the tickets from a different tracker to GitHub and the
# latter already had a few ticket numbers taken (as merge
# requests).
remap_until = cfg.ticket_remap_until
remap_offset = cfg.ticket_remap_offset
if remap_until and remap_offset:
if num <= remap_until:
num += remap_offset
url = cfg.ticket_url % num
roles.set_classes(options) roles.set_classes(options)
node = nodes.reference(rawtext, 'ticket ' + utils.unescape(text), node = nodes.reference(ticket, utils.unescape(ticket),
refuri=url, **options) refuri=url, **options)
return [node], []
rv.append(node)
else:
assert noise
rv.append(nodes.Text(noise))
return rv, []
def setup(app): def setup(app):
app.add_config_value('ticket_url', None, 'env') app.add_config_value('ticket_url', None, 'env')
app.add_config_value('ticket_remap_until', None, 'env')
app.add_config_value('ticket_remap_offset', None, 'env')
app.add_role('ticket', ticket_role) app.add_role('ticket', ticket_role)
app.add_role('tickets', ticket_role)

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
"""Create the docs table of the sqlstate errors.
"""
import re
import sys
from collections import namedtuple
from psycopg2._psycopg import sqlstate_errors
def main():
sqlclasses = {}
clsfile = sys.argv[1]
with open(clsfile) as f:
for l in f:
m = re.match(r'/\* Class (..) - (.+) \*/', l)
if m is not None:
sqlclasses[m.group(1)] = m.group(2)
Line = namedtuple('Line', 'colstate colexc colbase sqlstate')
lines = [Line('SQLSTATE', 'Exception', 'Base exception', None)]
for k in sorted(sqlstate_errors):
exc = sqlstate_errors[k]
lines.append(Line(
f"``{k}``", f"`!{exc.__name__}`",
f"`!{get_base_exception(exc).__name__}`", k))
widths = [max(len(l[c]) for l in lines) for c in range(3)]
h = Line(*(['=' * w for w in widths] + [None]))
lines.insert(0, h)
lines.insert(2, h)
lines.append(h)
h1 = '-' * (sum(widths) + len(widths) - 1)
sqlclass = None
for l in lines:
cls = l.sqlstate[:2] if l.sqlstate else None
if cls and cls != sqlclass:
print(f"**Class {cls}**: {sqlclasses[cls]}")
print(h1)
sqlclass = cls
print("%-*s %-*s %-*s" % (
widths[0], l.colstate, widths[1], l.colexc, widths[2], l.colbase))
def get_base_exception(exc):
for cls in exc.__mro__:
if cls.__module__ == 'psycopg2':
return cls
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,63 +0,0 @@
#! /usr/bin/env python
"""A script to stitch together the generated text files in the correct order.
"""
import os
import sys
def main():
if len(sys.argv) != 3:
sys.stderr.write("usage: %s index.rst text-dir\n")
return 2
_, index, txt_dir = sys.argv
for fb in iter_file_base(index):
emit(fb, txt_dir)
return 0
def iter_file_base(fn):
f = open(fn)
if sys.version_info[0] >= 3:
have_line = iter(f).__next__
else:
have_line = iter(f).next
while not have_line().startswith('.. toctree'):
pass
while have_line().strip().startswith(':'):
pass
yield os.path.splitext(os.path.basename(fn))[0]
n = 0
while True:
line = have_line()
if line.isspace():
continue
if line.startswith(".."):
break
n += 1
yield line.strip()
f.close()
if n < 5:
# maybe format changed?
raise Exception("Not enough files found. Format change in index.rst?")
def emit(basename, txt_dir):
f = open(os.path.join(txt_dir, basename + ".txt"))
for line in f:
line = line.replace("``", "'")
sys.stdout.write(line)
f.close()
# some space between sections
sys.stdout.write("\n\n")
if __name__ == '__main__':
sys.exit(main())

View File

@ -5,6 +5,10 @@
.. module:: psycopg2.tz .. module:: psycopg2.tz
.. deprecated:: 2.9
The module will be dropped in psycopg 2.10. Use `datetime.timezone`
instead.
This module holds two different tzinfo implementations that can be used as the This module holds two different tzinfo implementations that can be used as the
`tzinfo` argument to `~datetime.datetime` constructors, directly passed to `tzinfo` argument to `~datetime.datetime` constructors, directly passed to
Psycopg functions or used to set the `cursor.tzinfo_factory` attribute in Psycopg functions or used to set the `cursor.tzinfo_factory` attribute in
@ -13,4 +17,3 @@ cursors.
.. autoclass:: psycopg2.tz.FixedOffsetTimezone .. autoclass:: psycopg2.tz.FixedOffsetTimezone
.. autoclass:: psycopg2.tz.LocalTimezone .. autoclass:: psycopg2.tz.LocalTimezone

View File

@ -48,7 +48,7 @@ The main entry points of Psycopg are:
- The class `connection` encapsulates a database session. It allows to: - The class `connection` encapsulates a database session. It allows to:
- create new `cursor`\s using the `~connection.cursor()` method to - create new `cursor` instances using the `~connection.cursor()` method to
execute database commands and queries, execute database commands and queries,
- terminate transactions using the methods `~connection.commit()` or - terminate transactions using the methods `~connection.commit()` or
@ -73,68 +73,97 @@ The main entry points of Psycopg are:
Passing parameters to SQL queries Passing parameters to SQL queries
--------------------------------- ---------------------------------
Psycopg casts Python variables to SQL literals by type. Many standard Python types Psycopg converts Python variables to SQL values using their types: the Python
are already `adapted to the correct SQL representation`__. type determines the function used to convert the object into a string
representation suitable for PostgreSQL. Many standard Python types are
already `adapted to the correct SQL representation`__.
.. __: python-types-adaptation_ .. __: python-types-adaptation_
Example: the Python function call:: Passing parameters to an SQL statement happens in functions such as
`cursor.execute()` by using ``%s`` placeholders in the SQL statement, and
passing a sequence of values as the second argument of the function. For
example the Python function call::
>>> cur.execute( >>> cur.execute("""
... """INSERT INTO some_table (an_int, a_date, a_string) ... INSERT INTO some_table (an_int, a_date, a_string)
... VALUES (%s, %s, %s);""", ... VALUES (%s, %s, %s);
... """,
... (10, datetime.date(2005, 11, 18), "O'Reilly")) ... (10, datetime.date(2005, 11, 18), "O'Reilly"))
is converted into the SQL command:: is converted into a SQL command similar to:
.. code-block:: sql
INSERT INTO some_table (an_int, a_date, a_string) INSERT INTO some_table (an_int, a_date, a_string)
VALUES (10, '2005-11-18', 'O''Reilly'); VALUES (10, '2005-11-18', 'O''Reilly');
Named arguments are supported too using :samp:`%({name})s` placeholders. Named arguments are supported too using :samp:`%({name})s` placeholders in the
Using named arguments the values can be passed to the query in any order and query and specifying the values into a mapping. Using named arguments allows
many placeholders can use the same values:: to specify the values in any order and to repeat the same value in several
places in the query::
>>> cur.execute( >>> cur.execute("""
... """INSERT INTO some_table (an_int, a_date, another_date, a_string) ... INSERT INTO some_table (an_int, a_date, another_date, a_string)
... VALUES (%(int)s, %(date)s, %(date)s, %(str)s);""", ... VALUES (%(int)s, %(date)s, %(date)s, %(str)s);
... """,
... {'int': 10, 'str': "O'Reilly", 'date': datetime.date(2005, 11, 18)}) ... {'int': 10, 'str': "O'Reilly", 'date': datetime.date(2005, 11, 18)})
Using characters ``%``, ``(``, ``)`` in the argument names is not supported.
When parameters are used, in order to include a literal ``%`` in the query you When parameters are used, in order to include a literal ``%`` in the query you
can use the ``%%`` string. can use the ``%%`` string::
>>> cur.execute("SELECT (%s % 2) = 0 AS even", (10,)) # WRONG
>>> cur.execute("SELECT (%s %% 2) = 0 AS even", (10,)) # correct
While the mechanism resembles regular Python strings manipulation, there are a While the mechanism resembles regular Python strings manipulation, there are a
few subtle differences you should care about when passing parameters to a few subtle differences you should care about when passing parameters to a
query: query.
- The Python string operator ``%`` is not used: the `~cursor.execute()` - The Python string operator ``%`` *must not be used*: the `~cursor.execute()`
method accepts a tuple or dictionary of values as second parameter. method accepts a tuple or dictionary of values as second parameter.
|sql-warn|__. |sql-warn|__:
.. |sql-warn| replace:: **Never** use ``%`` or ``+`` to merge values .. |sql-warn| replace:: **Never** use ``%`` or ``+`` to merge values
into queries into queries
.. __: sql-injection_ .. __: sql-injection_
- The variables placeholder must *always be a* ``%s``, even if a different >>> cur.execute("INSERT INTO numbers VALUES (%s, %s)" % (10, 20)) # WRONG
placeholder (such as a ``%d`` for integers or ``%f`` for floats) may look >>> cur.execute("INSERT INTO numbers VALUES (%s, %s)", (10, 20)) # correct
more appropriate::
>>> cur.execute("INSERT INTO numbers VALUES (%d)", (42,)) # WRONG
>>> cur.execute("INSERT INTO numbers VALUES (%s)", (42,)) # correct
- For positional variables binding, *the second argument must always be a - For positional variables binding, *the second argument must always be a
sequence*, even if it contains a single variable. And remember that Python sequence*, even if it contains a single variable (remember that Python
requires a comma to create a single element tuple:: requires a comma to create a single element tuple)::
>>> cur.execute("INSERT INTO foo VALUES (%s)", "bar") # WRONG >>> cur.execute("INSERT INTO foo VALUES (%s)", "bar") # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar")) # WRONG >>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar")) # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct >>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct
>>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # correct >>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # correct
- Only variable values should be bound via this method: it shouldn't be used - The placeholder *must not be quoted*. Psycopg will add quotes where needed::
to set table or field names. For these elements, ordinary string formatting
should be used before running `~cursor.execute()`.
>>> cur.execute("INSERT INTO numbers VALUES ('%s')", (10,)) # WRONG
>>> cur.execute("INSERT INTO numbers VALUES (%s)", (10,)) # correct
- The variables placeholder *must always be a* ``%s``, even if a different
placeholder (such as a ``%d`` for integers or ``%f`` for floats) may look
more appropriate::
>>> cur.execute("INSERT INTO numbers VALUES (%d)", (10,)) # WRONG
>>> cur.execute("INSERT INTO numbers VALUES (%s)", (10,)) # correct
- Only query values should be bound via this method: it shouldn't be used to
merge table or field names to the query (Psycopg will try quoting the table
name as a string value, generating invalid SQL). If you need to generate
dynamically SQL queries (for instance choosing dynamically a table name)
you can use the facilities provided by the `psycopg2.sql` module::
>>> cur.execute("INSERT INTO %s VALUES (%s)", ('numbers', 10)) # WRONG
>>> cur.execute( # correct
... SQL("INSERT INTO {} VALUES (%s)").format(Identifier('numbers')),
... (10,))
.. index:: Security, SQL injection .. index:: Security, SQL injection
@ -144,13 +173,15 @@ query:
The problem with the query parameters The problem with the query parameters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The SQL representation for many data types is often not the same of the Python The SQL representation of many data types is often different from their Python
string representation. The classic example is with single quotes in string representation. The typical example is with single quotes in strings:
strings: SQL uses them as string constants bounds and requires them to be in SQL single quotes are used as string literal delimiters, so the ones
escaped, whereas in Python single quotes can be left unescaped in strings appearing inside the string itself must be escaped, whereas in Python single
bounded by double quotes. For this reason a naïve approach to the composition quotes can be left unescaped if the string is delimited by double quotes.
of query strings, e.g. using string concatenation, is a recipe for terrible
problems:: Because of the difference, sometime subtle, between the data types
representations, a naïve approach to query strings composition, such as using
Python strings concatenation, is a recipe for *terrible* problems::
>>> SQL = "INSERT INTO authors (name) VALUES ('%s');" # NEVER DO THIS >>> SQL = "INSERT INTO authors (name) VALUES ('%s');" # NEVER DO THIS
>>> data = ("O'Reilly", ) >>> data = ("O'Reilly", )
@ -159,16 +190,16 @@ problems::
LINE 1: INSERT INTO authors (name) VALUES ('O'Reilly') LINE 1: INSERT INTO authors (name) VALUES ('O'Reilly')
^ ^
If the variable containing the data to be sent to the database comes from an If the variables containing the data to send to the database come from an
untrusted source (e.g. a form published on a web site) an attacker could untrusted source (such as a form published on a web site) an attacker could
easily craft a malformed string, either gaining access to unauthorized data or easily craft a malformed string, either gaining access to unauthorized data or
performing destructive operations on the database. This form of attack is performing destructive operations on the database. This form of attack is
called `SQL injection`_ and is known to be one of the most widespread forms of called `SQL injection`_ and is known to be one of the most widespread forms of
attack to servers. Before continuing, please print `this page`__ as a memo and attack to database servers. Before continuing, please print `this page`__ as a
hang it onto your desk. memo and hang it onto your desk.
.. _SQL injection: http://en.wikipedia.org/wiki/SQL_injection .. _SQL injection: https://en.wikipedia.org/wiki/SQL_injection
.. __: http://xkcd.com/327/ .. __: https://xkcd.com/327/
Psycopg can `automatically convert Python objects to and from SQL Psycopg can `automatically convert Python objects to and from SQL
literals`__: using this feature your code will be more robust and literals`__: using this feature your code will be more robust and
@ -190,6 +221,27 @@ argument of the `~cursor.execute()` method::
>>> cur.execute(SQL, data) # Note: no % operator >>> cur.execute(SQL, data) # Note: no % operator
Values containing backslashes and LIKE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unlike in Python, the backslash (`\\`) is not used as an escape
character *except* in patterns used with `LIKE` and `ILIKE` where they
are needed to escape the `%` and `_` characters.
This can lead to confusing situations::
>>> path = r'C:\Users\Bobby.Tables'
>>> cur.execute('INSERT INTO mytable(path) VALUES (%s)', (path,))
>>> cur.execute('SELECT * FROM mytable WHERE path LIKE %s', (path,))
>>> cur.fetchall()
[]
The solution is to specify an `ESCAPE` character of `''` (empty string)
in your `LIKE` query::
>>> cur.execute("SELECT * FROM mytable WHERE path LIKE %s ESCAPE ''", (path,))
.. index:: .. index::
single: Adaptation single: Adaptation
@ -242,7 +294,8 @@ types:
+--------------------+-------------------------+--------------------------+ +--------------------+-------------------------+--------------------------+
| `!date` | :sql:`date` | :ref:`adapt-date` | | `!date` | :sql:`date` | :ref:`adapt-date` |
+--------------------+-------------------------+ | +--------------------+-------------------------+ |
| `!time` | :sql:`time` | | | `!time` | | :sql:`time` | |
| | | :sql:`timetz` | |
+--------------------+-------------------------+ | +--------------------+-------------------------+ |
| `!datetime` | | :sql:`timestamp` | | | `!datetime` | | :sql:`timestamp` | |
| | | :sql:`timestamptz` | | | | | :sql:`timestamptz` | |
@ -260,7 +313,10 @@ types:
+--------------------+-------------------------+--------------------------+ +--------------------+-------------------------+--------------------------+
| Anything\ |tm| | :sql:`json` | :ref:`adapt-json` | | Anything\ |tm| | :sql:`json` | :ref:`adapt-json` |
+--------------------+-------------------------+--------------------------+ +--------------------+-------------------------+--------------------------+
| `uuid` | :sql:`uuid` | :ref:`adapt-uuid` | | `~uuid.UUID` | :sql:`uuid` | :ref:`adapt-uuid` |
+--------------------+-------------------------+--------------------------+
| `ipaddress` | | :sql:`inet` | :ref:`adapt-network` |
| objects | | :sql:`cidr` | |
+--------------------+-------------------------+--------------------------+ +--------------------+-------------------------+--------------------------+
.. |tm| unicode:: U+2122 .. |tm| unicode:: U+2122
@ -298,8 +354,8 @@ proper SQL literals::
Numbers adaptation Numbers adaptation
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
Numeric objects: `int`, `long`, `float`, `~decimal.Decimal` are converted in Python numeric objects `int`, `long`, `float`, `~decimal.Decimal` are
the PostgreSQL numerical representation:: converted into a PostgreSQL numerical representation::
>>> cur.mogrify("SELECT %s, %s, %s, %s;", (10, 10L, 10.0, Decimal("10.00"))) >>> cur.mogrify("SELECT %s, %s, %s, %s;", (10, 10L, 10.0, Decimal("10.00")))
'SELECT 10, 10, 10.0, 10.00;' 'SELECT 10, 10, 10.0, 10.00;'
@ -311,12 +367,12 @@ converted into `!Decimal`.
.. note:: .. note::
Sometimes you may prefer to receive :sql:`numeric` data as `!float` Sometimes you may prefer to receive :sql:`numeric` data as `!float`
insted, for performance reason or ease of manipulation: you can configure instead, for performance reason or ease of manipulation: you can configure
an adapter to :ref:`cast PostgreSQL numeric to Python float <faq-float>`. an adapter to :ref:`cast PostgreSQL numeric to Python float <faq-float>`.
This of course may imply a loss of precision. This of course may imply a loss of precision.
.. seealso:: `PostgreSQL numeric types .. seealso:: `PostgreSQL numeric types
<http://www.postgresql.org/docs/current/static/datatype-numeric.html>`__ <https://www.postgresql.org/docs/current/static/datatype-numeric.html>`__
.. index:: .. index::
@ -348,33 +404,33 @@ Unicode handling
Psycopg can exchange Unicode data with a PostgreSQL database. Python Psycopg can exchange Unicode data with a PostgreSQL database. Python
`!unicode` objects are automatically *encoded* in the client encoding `!unicode` objects are automatically *encoded* in the client encoding
defined on the database connection (the `PostgreSQL encoding`__, available in defined on the database connection (the `PostgreSQL encoding`__, available in
`connection.encoding`, is translated into a `Python codec`__ using the `connection.encoding`, is translated into a `Python encoding`__ using the
`~psycopg2.extensions.encodings` mapping):: `~psycopg2.extensions.encodings` mapping)::
>>> print u, type(u) >>> print(u, type(u))
àèìòù€ <type 'unicode'> àèìòù€ <type 'unicode'>
>>> cur.execute("INSERT INTO test (num, data) VALUES (%s,%s);", (74, u)) >>> cur.execute("INSERT INTO test (num, data) VALUES (%s,%s);", (74, u))
.. __: http://www.postgresql.org/docs/current/static/multibyte.html .. __: https://www.postgresql.org/docs/current/static/multibyte.html
.. __: http://docs.python.org/library/codecs.html#standard-encodings .. __: https://docs.python.org/library/codecs.html
When reading data from the database, in Python 2 the strings returned are When reading data from the database, in Python 2 the strings returned are
usually 8 bit `!str` objects encoded in the database client encoding:: usually 8 bit `!str` objects encoded in the database client encoding::
>>> print conn.encoding >>> print(conn.encoding)
UTF8 UTF8
>>> cur.execute("SELECT data FROM test WHERE num = 74") >>> cur.execute("SELECT data FROM test WHERE num = 74")
>>> x = cur.fetchone()[0] >>> x = cur.fetchone()[0]
>>> print x, type(x), repr(x) >>> print(x, type(x), repr(x))
àèìòù€ <type 'str'> '\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9\xe2\x82\xac' àèìòù€ <type 'str'> '\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9\xe2\x82\xac'
>>> conn.set_client_encoding('LATIN9') >>> conn.set_client_encoding('LATIN9')
>>> cur.execute("SELECT data FROM test WHERE num = 74") >>> cur.execute("SELECT data FROM test WHERE num = 74")
>>> x = cur.fetchone()[0] >>> x = cur.fetchone()[0]
>>> print type(x), repr(x) >>> print(type(x), repr(x))
<type 'str'> '\xe0\xe8\xec\xf2\xf9\xa4' <type 'str'> '\xe0\xe8\xec\xf2\xf9\xa4'
In Python 3 instead the strings are automatically *decoded* in the connection In Python 3 instead the strings are automatically *decoded* in the connection
@ -386,7 +442,7 @@ In Python 2 you must register a :ref:`typecaster
>>> cur.execute("SELECT data FROM test WHERE num = 74") >>> cur.execute("SELECT data FROM test WHERE num = 74")
>>> x = cur.fetchone()[0] >>> x = cur.fetchone()[0]
>>> print x, type(x), repr(x) >>> print(x, type(x), repr(x))
àèìòù€ <type 'unicode'> u'\xe0\xe8\xec\xf2\xf9\u20ac' àèìòù€ <type 'unicode'> u'\xe0\xe8\xec\xf2\xf9\u20ac'
In the above example, the `~psycopg2.extensions.UNICODE` typecaster is In the above example, the `~psycopg2.extensions.UNICODE` typecaster is
@ -401,13 +457,29 @@ the connection or globally: see the function
Unicode, you can register the related typecasters globally as soon as Unicode, you can register the related typecasters globally as soon as
Psycopg is imported:: Psycopg is imported::
import psycopg2
import psycopg2.extensions import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
and forget about this story. and forget about this story.
.. note::
In some cases, on Python 3, you may want to receive `!bytes` instead of
`!str`, without undergoing to any decoding. This is especially the case if
the data in the database is in mixed encoding. The
`~psycopg2.extensions.BYTES` caster is what you neeed::
import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.BYTES, conn)
psycopg2.extensions.register_type(psycopg2.extensions.BYTESARRAY, conn)
cur = conn.cursor()
cur.execute("select %s::text", (u"€",))
cur.fetchone()[0]
b'\xe2\x82\xac'
.. versionadded: 2.8
.. index:: .. index::
single: Buffer; Adaptation single: Buffer; Adaptation
@ -422,17 +494,15 @@ the connection or globally: see the function
Binary adaptation Binary adaptation
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
Binary types: Python types representing binary objects are converted into Python types representing binary objects are converted into PostgreSQL binary
PostgreSQL binary string syntax, suitable for :sql:`bytea` fields. Such string syntax, suitable for :sql:`bytea` fields. Such types are `buffer`
types are `buffer` (only available in Python 2), `memoryview` (available (only available in Python 2), `memoryview`, `bytearray`, and `bytes` (only in
from Python 2.7), `bytearray` (available from Python 2.6) and `bytes` Python 3: the name is available in Python 2 but it's only an alias for the
(only from Python 3: the name is available from Python 2.6 but it's only an type `!str`). Any object implementing the `Revised Buffer Protocol`__ should
alias for the type `!str`). Any object implementing the `Revised Buffer be usable as binary type. Received data is returned as `!buffer` (in Python 2)
Protocol`__ should be usable as binary type where the protocol is supported
(i.e. from Python 2.6). Received data is returned as `!buffer` (in Python 2)
or `!memoryview` (in Python 3). or `!memoryview` (in Python 3).
.. __: http://www.python.org/dev/peps/pep-3118/ .. __: https://www.python.org/dev/peps/pep-3118/
.. versionchanged:: 2.4 .. versionchanged:: 2.4
only strings were supported before. only strings were supported before.
@ -461,8 +531,8 @@ or `!memoryview` (in Python 3).
server configuration file or in the client session (using a query such as server configuration file or in the client session (using a query such as
``SET bytea_output TO escape;``) before receiving binary data. ``SET bytea_output TO escape;``) before receiving binary data.
.. __: http://www.postgresql.org/docs/current/static/datatype-binary.html .. __: https://www.postgresql.org/docs/current/static/datatype-binary.html
.. __: http://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-BYTEA-OUTPUT .. __: https://www.postgresql.org/docs/current/static/runtime-config-client.html#GUC-BYTEA-OUTPUT
.. index:: .. index::
@ -470,18 +540,16 @@ or `!memoryview` (in Python 3).
single: Date objects; Adaptation single: Date objects; Adaptation
single: Time objects; Adaptation single: Time objects; Adaptation
single: Interval objects; Adaptation single: Interval objects; Adaptation
single: mx.DateTime; Adaptation
.. _adapt-date: .. _adapt-date:
Date/Time objects adaptation Date/Time objects adaptation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Date and time objects: builtin `~datetime.datetime`, `~datetime.date`, Python builtin `~datetime.datetime`, `~datetime.date`,
`~datetime.time`, `~datetime.timedelta` are converted into PostgreSQL's `~datetime.time`, `~datetime.timedelta` are converted into PostgreSQL's
:sql:`timestamp[tz]`, :sql:`date`, :sql:`time`, :sql:`interval` data types. :sql:`timestamp[tz]`, :sql:`date`, :sql:`time[tz]`, :sql:`interval` data types.
Time zones are supported too. The Egenix `mx.DateTime`_ objects are adapted Time zones are supported too.
the same way::
>>> dt = datetime.datetime.now() >>> dt = datetime.datetime.now()
>>> dt >>> dt
@ -494,7 +562,8 @@ the same way::
"SELECT '38 days 6027.425337 seconds';" "SELECT '38 days 6027.425337 seconds';"
.. seealso:: `PostgreSQL date/time types .. seealso:: `PostgreSQL date/time types
<http://www.postgresql.org/docs/current/static/datatype-datetime.html>`__ <https://www.postgresql.org/docs/current/static/datatype-datetime.html>`__
.. index:: .. index::
single: Time Zones single: Time Zones
@ -505,29 +574,95 @@ Time zones handling
''''''''''''''''''' '''''''''''''''''''
The PostgreSQL type :sql:`timestamp with time zone` (a.k.a. The PostgreSQL type :sql:`timestamp with time zone` (a.k.a.
:sql:`timestamptz`) is converted into Python `~datetime.datetime` objects with :sql:`timestamptz`) is converted into Python `~datetime.datetime` objects.
a `~datetime.datetime.tzinfo` attribute set to a
`~psycopg2.tz.FixedOffsetTimezone` instance.
>>> cur.execute("SET TIME ZONE 'Europe/Rome';") # UTC + 1 hour >>> cur.execute("SET TIME ZONE 'Europe/Rome'") # UTC + 1 hour
>>> cur.execute("SELECT '2010-01-01 10:30:45'::timestamptz;") >>> cur.execute("SELECT '2010-01-01 10:30:45'::timestamptz")
>>> cur.fetchone()[0]
datetime.datetime(2010, 1, 1, 10, 30, 45,
tzinfo=datetime.timezone(datetime.timedelta(seconds=3600)))
.. note::
Before Python 3.7, the `datetime` module only supported timezones with an
integer number of minutes. A few historical time zones had seconds in the
UTC offset: these time zones will have the offset rounded to the nearest
minute, with an error of up to 30 seconds, on Python versions before 3.7.
>>> cur.execute("SET TIME ZONE 'Asia/Calcutta'") # offset was +5:21:10
>>> cur.execute("SELECT '1900-01-01 10:30:45'::timestamptz")
>>> cur.fetchone()[0].tzinfo >>> cur.fetchone()[0].tzinfo
psycopg2.tz.FixedOffsetTimezone(offset=60, name=None) # On Python 3.6: 5h, 21m
datetime.timezone(datetime.timedelta(0, 19260))
Note that only time zones with an integer number of minutes are supported: # On Python 3.7 and following: 5h, 21m, 10s
this is a limitation of the Python `datetime` module. A few historical time datetime.timezone(datetime.timedelta(seconds=19270))
zones had seconds in the UTC offset: these time zones will have the offset
rounded to the nearest minute, with an error of up to 30 seconds.
>>> cur.execute("SET TIME ZONE 'Asia/Calcutta';") # offset was +5:53:20
>>> cur.execute("SELECT '1930-01-01 10:30:45'::timestamptz;")
>>> cur.fetchone()[0].tzinfo
psycopg2.tz.FixedOffsetTimezone(offset=353, name=None)
.. versionchanged:: 2.2.2 .. versionchanged:: 2.2.2
timezones with seconds are supported (with rounding). Previously such timezones with seconds are supported (with rounding). Previously such
timezones raised an error. In order to deal with them in previous timezones raised an error.
versions use `psycopg2.extras.register_tstz_w_secs()`.
.. versionchanged:: 2.9
timezones with seconds are supported without rounding.
.. versionchanged:: 2.9
use `datetime.timezone` as default tzinfo object instead of
`~psycopg2.tz.FixedOffsetTimezone`.
.. index::
double: Date objects; Infinite
.. _infinite-dates-handling:
Infinite dates handling
'''''''''''''''''''''''
PostgreSQL can store the representation of an "infinite" date, timestamp, or
interval. Infinite dates are not available to Python, so these objects are
mapped to `!date.max`, `!datetime.max`, `!interval.max`. Unfortunately the
mapping cannot be bidirectional so these dates will be stored back into the
database with their values, such as :sql:`9999-12-31`.
It is possible to create an alternative adapter for dates and other objects
to map `date.max` to :sql:`infinity`, for instance::
class InfDateAdapter:
def __init__(self, wrapped):
self.wrapped = wrapped
def getquoted(self):
if self.wrapped == datetime.date.max:
return b"'infinity'::date"
elif self.wrapped == datetime.date.min:
return b"'-infinity'::date"
else:
return psycopg2.extensions.DateFromPy(self.wrapped).getquoted()
psycopg2.extensions.register_adapter(datetime.date, InfDateAdapter)
Of course it will not be possible to write the value of `date.max` in the
database anymore: :sql:`infinity` will be stored instead.
.. _time-handling:
Time handling
'''''''''''''
The PostgreSQL :sql:`time` and Python `~datetime.time` types are not
fully bidirectional.
Within PostgreSQL, the :sql:`time` type's maximum value of ``24:00:00`` is
treated as 24-hours later than the minimum value of ``00:00:00``.
>>> cur.execute("SELECT '24:00:00'::time - '00:00:00'::time")
>>> cur.fetchone()[0]
datetime.timedelta(days=1)
However, Python's `!time` only supports times until ``23:59:59``.
Retrieving a value of ``24:00:00`` results in a `!time` of ``00:00:00``.
>>> cur.execute("SELECT '24:00:00'::time, '00:00:00'::time")
>>> cur.fetchone()
(datetime.time(0, 0), datetime.time(0, 0))
.. _adapt-list: .. _adapt-list:
@ -555,12 +690,12 @@ Python lists are converted into PostgreSQL :sql:`ARRAY`\ s::
Furthermore :sql:`ANY` can also work with empty lists, whereas :sql:`IN ()` Furthermore :sql:`ANY` can also work with empty lists, whereas :sql:`IN ()`
is a SQL syntax error. is a SQL syntax error.
.. __: http://www.postgresql.org/docs/current/static/functions-subquery.html#FUNCTIONS-SUBQUERY-ANY-SOME .. __: https://www.postgresql.org/docs/current/static/functions-subquery.html#FUNCTIONS-SUBQUERY-ANY-SOME
.. note:: .. note::
Reading back from PostgreSQL, arrays are converted to lists of Python Reading back from PostgreSQL, arrays are converted to lists of Python
objects as expected, but only if the items are of a known known type. objects as expected, but only if the items are of a known type.
Arrays of unknown types are returned as represented by the database (e.g. Arrays of unknown types are returned as represented by the database (e.g.
``{a,b,c}``). If you want to convert the items into Python objects you can ``{a,b,c}``). If you want to convert the items into Python objects you can
easily create a typecaster for :ref:`array of unknown types easily create a typecaster for :ref:`array of unknown types
@ -576,7 +711,7 @@ Tuples adaptation
double: Tuple; Adaptation double: Tuple; Adaptation
single: IN operator single: IN operator
Python tuples are converted in a syntax suitable for the SQL :sql:`IN` Python tuples are converted into a syntax suitable for the SQL :sql:`IN`
operator and to represent a composite type:: operator and to represent a composite type::
>>> cur.mogrify("SELECT %s IN %s;", (10, (10, 20, 30))) >>> cur.mogrify("SELECT %s IN %s;", (10, (10, 20, 30)))
@ -623,24 +758,30 @@ until a call to the `~connection.rollback()` method.
The connection is responsible for terminating its transaction, calling either The connection is responsible for terminating its transaction, calling either
the `~connection.commit()` or `~connection.rollback()` method. Committed the `~connection.commit()` or `~connection.rollback()` method. Committed
changes are immediately made persistent into the database. Closing the changes are immediately made persistent in the database. If the connection
connection using the `~connection.close()` method or destroying the is closed (using the `~connection.close()` method) or destroyed (using `!del`
connection object (using `!del` or letting it fall out of scope) or by letting it fall out of scope) while a transaction is in progress, the
will result in an implicit rollback. server will discard the transaction. However doing so is not advisable:
middleware such as PgBouncer_ may see the connection closed uncleanly and
dispose of it.
.. _PgBouncer: http://www.pgbouncer.org/
It is possible to set the connection in *autocommit* mode: this way all the It is possible to set the connection in *autocommit* mode: this way all the
commands executed will be immediately committed and no rollback is possible. A commands executed will be immediately committed and no rollback is possible. A
few commands (e.g. :sql:`CREATE DATABASE`, :sql:`VACUUM`...) require to be run few commands (e.g. :sql:`CREATE DATABASE`, :sql:`VACUUM`, :sql:`CALL` on
`stored procedures`__ using transaction control...) require to be run
outside any transaction: in order to be able to run these commands from outside any transaction: in order to be able to run these commands from
Psycopg, the connection must be in autocommit mode: you can use the Psycopg, the connection must be in autocommit mode: you can use the
`~connection.autocommit` property (`~connection.set_isolation_level()` in `~connection.autocommit` property.
older versions).
.. __: https://www.postgresql.org/docs/current/xproc.html
.. warning:: .. warning::
By default even a simple :sql:`SELECT` will start a transaction: in By default even a simple :sql:`SELECT` will start a transaction: in
long-running programs, if no further action is taken, the session will long-running programs, if no further action is taken, the session will
remain "idle in transaction", a condition non desiderable for several remain "idle in transaction", an undesirable condition for several
reasons (locks are held by the session, tables bloat...). For long lived reasons (locks are held by the session, tables bloat...). For long lived
scripts, either make sure to terminate a transaction as soon as possible or scripts, either make sure to terminate a transaction as soon as possible or
use an autocommit connection. use an autocommit connection.
@ -654,6 +795,8 @@ the details.
.. index:: .. index::
single: with statement single: with statement
.. _with:
``with`` statement ``with`` statement
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
@ -666,13 +809,41 @@ managers* and can be used with the ``with`` statement::
When a connection exits the ``with`` block, if no exception has been raised by When a connection exits the ``with`` block, if no exception has been raised by
the block, the transaction is committed. In case of exception the transaction the block, the transaction is committed. In case of exception the transaction
is rolled back. In no case the connection is closed: a connection can be used is rolled back.
in more than a ``with`` statement and each ``with`` block is effectively
wrapped in a transaction.
When a cursor exits the ``with`` block it is closed, releasing any resource When a cursor exits the ``with`` block it is closed, releasing any resource
eventually associated with it. The state of the transaction is not affected. eventually associated with it. The state of the transaction is not affected.
A connection can be used in more than one ``with`` statement
and each ``with`` block is effectively wrapped in a separate transaction::
conn = psycopg2.connect(DSN)
with conn:
with conn.cursor() as curs:
curs.execute(SQL1)
with conn:
with conn.cursor() as curs:
curs.execute(SQL2)
conn.close()
.. warning::
Unlike file objects or other resources, exiting the connection's
``with`` block **doesn't close the connection**, but only the transaction
associated to it. If you want to make sure the connection is closed after
a certain point, you should still use a try-catch block::
conn = psycopg2.connect(DSN)
try:
# connection usage
finally:
conn.close()
.. versionchanged:: 2.9
``with connection`` starts a transaction also on autocommit connections.
.. index:: .. index::
@ -689,7 +860,7 @@ Server side cursors
When a database query is executed, the Psycopg `cursor` usually fetches When a database query is executed, the Psycopg `cursor` usually fetches
all the records returned by the backend, transferring them to the client all the records returned by the backend, transferring them to the client
process. If the query returned an huge amount of data, a proportionally large process. If the query returns a huge amount of data, a proportionally large
amount of memory will be allocated by the client. amount of memory will be allocated by the client.
If the dataset is too large to be practically handled on the client side, it is If the dataset is too large to be practically handled on the client side, it is
@ -719,8 +890,8 @@ you may decrease this value if you are dealing with huge records.
Named cursors are usually created :sql:`WITHOUT HOLD`, meaning they live only Named cursors are usually created :sql:`WITHOUT HOLD`, meaning they live only
as long as the current transaction. Trying to fetch from a named cursor after as long as the current transaction. Trying to fetch from a named cursor after
a `~connection.commit()` or to create a named cursor when the `connection` a `~connection.commit()` or to create a named cursor when the connection
transaction isolation level is set to `AUTOCOMMIT` will result in an exception. is in `~connection.autocommit` mode will result in an exception.
It is possible to create a :sql:`WITH HOLD` cursor by specifying a `!True` It is possible to create a :sql:`WITH HOLD` cursor by specifying a `!True`
value for the `withhold` parameter to `~connection.cursor()` or by setting the value for the `withhold` parameter to `~connection.cursor()` or by setting the
`~cursor.withhold` attribute to `!True` before calling `~cursor.execute()` on `~cursor.withhold` attribute to `!True` before calling `~cursor.execute()` on
@ -735,7 +906,9 @@ lifetime extends well after `~connection.commit()`, calling
It is also possible to use a named cursor to consume a cursor created It is also possible to use a named cursor to consume a cursor created
in some other way than using the |DECLARE| executed by in some other way than using the |DECLARE| executed by
`~cursor.execute()`. For example, you may have a PL/pgSQL function `~cursor.execute()`. For example, you may have a PL/pgSQL function
returning a cursor:: returning a cursor:
.. code-block:: postgres
CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS $$ CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS $$
BEGIN BEGIN
@ -763,7 +936,7 @@ lifetime extends well after `~connection.commit()`, calling
.. |DECLARE| replace:: :sql:`DECLARE` .. |DECLARE| replace:: :sql:`DECLARE`
.. _DECLARE: http://www.postgresql.org/docs/current/static/sql-declare.html .. _DECLARE: https://www.postgresql.org/docs/current/static/sql-declare.html
@ -793,7 +966,7 @@ forked processes`__, so when using a module such as `multiprocessing` or a
forking web deploy method such as FastCGI make sure to create the connections forking web deploy method such as FastCGI make sure to create the connections
*after* the fork. *after* the fork.
.. __: http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT .. __: https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT
Connections shouldn't be shared either by different green threads: see Connections shouldn't be shared either by different green threads: see
:ref:`green-support` for further details. :ref:`green-support` for further details.
@ -810,11 +983,19 @@ Using COPY TO and COPY FROM
Psycopg `cursor` objects provide an interface to the efficient Psycopg `cursor` objects provide an interface to the efficient
PostgreSQL |COPY|__ command to move data from files to tables and back. PostgreSQL |COPY|__ command to move data from files to tables and back.
Currently no adaptation is provided between Python and PostgreSQL types on
|COPY|: the file can be any Python file-like object but its format must be in
the format accepted by `PostgreSQL COPY command`__ (data format, escaped
characters, etc).
.. __: COPY_
The methods exposed are: The methods exposed are:
`~cursor.copy_from()` `~cursor.copy_from()`
Reads data *from* a file-like object appending them to a database table Reads data *from* a file-like object appending them to a database table
(:sql:`COPY table FROM file` syntax). The source file must have both (:sql:`COPY table FROM file` syntax). The source file must provide both
`!read()` and `!readline()` method. `!read()` and `!readline()` method.
`~cursor.copy_to()` `~cursor.copy_to()`
@ -829,7 +1010,7 @@ Please refer to the documentation of the single methods for details and
examples. examples.
.. |COPY| replace:: :sql:`COPY` .. |COPY| replace:: :sql:`COPY`
.. __: http://www.postgresql.org/docs/current/static/sql-copy.html .. __: https://www.postgresql.org/docs/current/static/sql-copy.html
@ -846,7 +1027,7 @@ access to user data that is stored in a special large-object structure. They
are useful with data values too large to be manipulated conveniently as a are useful with data values too large to be manipulated conveniently as a
whole. whole.
.. __: http://www.postgresql.org/docs/current/static/largeobjects.html .. __: https://www.postgresql.org/docs/current/static/largeobjects.html
Psycopg allows access to the large object using the Psycopg allows access to the large object using the
`~psycopg2.extensions.lobject` class. Objects are generated using the `~psycopg2.extensions.lobject` class. Objects are generated using the
@ -857,9 +1038,23 @@ Psycopg large object support efficient import/export with file system files
using the |lo_import|_ and |lo_export|_ libpq functions. using the |lo_import|_ and |lo_export|_ libpq functions.
.. |lo_import| replace:: `!lo_import()` .. |lo_import| replace:: `!lo_import()`
.. _lo_import: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-IMPORT .. _lo_import: https://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-IMPORT
.. |lo_export| replace:: `!lo_export()` .. |lo_export| replace:: `!lo_export()`
.. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT .. _lo_export: https://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT
.. versionchanged:: 2.6
added support for large objects greater than 2GB. Note that the support is
enabled only if all the following conditions are verified:
- the Python build is 64 bits;
- the extension was built against at least libpq 9.3;
- the server version is at least PostgreSQL 9.3
(`~connection.server_version` must be >= ``90300``).
If Psycopg was built with 64 bits large objects support (i.e. the first
two conditions above are verified), the `psycopg2.__version__` constant
will contain the ``lo64`` flag. If any of the condition is not met
several `!lobject` methods will fail if the arguments exceed 2GB.
@ -909,6 +1104,5 @@ transactions produced by a Java program.
For further details see the documentation for the above methods. For further details see the documentation for the above methods.
.. __: http://www.opengroup.org/bookstore/catalog/c193.htm .. __: https://publications.opengroup.org/c193
.. __: http://jdbc.postgresql.org/ .. __: https://jdbc.postgresql.org/

View File

@ -1,89 +0,0 @@
# binary.py - working with binary data
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_binary (id int4, name text, img bytea)")
except:
conn.rollback()
curs.execute("DROP TABLE test_binary")
curs.execute("CREATE TABLE test_binary (id int4, name text, img bytea)")
conn.commit()
# first we try two inserts, one with an explicit Binary call and the other
# using a buffer on a file object.
data1 = {'id':1, 'name':'somehackers.jpg',
'img':psycopg2.Binary(open('somehackers.jpg').read())}
data2 = {'id':2, 'name':'whereareyou.jpg',
'img':buffer(open('whereareyou.jpg').read())}
curs.execute("""INSERT INTO test_binary
VALUES (%(id)s, %(name)s, %(img)s)""", data1)
curs.execute("""INSERT INTO test_binary
VALUES (%(id)s, %(name)s, %(img)s)""", data2)
# now we try to extract the images as simple text strings
print "Extracting the images as strings..."
curs.execute("SELECT * FROM test_binary")
for row in curs.fetchall():
name, ext = row[1].split('.')
new_name = name + '_S.' + ext
print " writing %s to %s ..." % (name+'.'+ext, new_name),
open(new_name, 'wb').write(row[2])
print "done"
print " python type of image data is", type(row[2])
# extract exactly the same data but using a binary cursor
print "Extracting the images using a binary cursor:"
curs.execute("""DECLARE zot CURSOR FOR
SELECT img, name FROM test_binary FOR READ ONLY""")
curs.execute("""FETCH ALL FROM zot""")
for row in curs.fetchall():
name, ext = row[1].split('.')
new_name = name + '_B.' + ext
print " writing %s to %s ..." % (name+'.'+ext, new_name),
open(new_name, 'wb').write(row[0])
print "done"
print " python type of image data is", type(row[0])
# this rollback is required because we can't drop a table with a binary cusor
# declared and still open
conn.rollback()
curs.execute("DROP TABLE test_binary")
conn.commit()
print "\nNow try to load the new images, to check it worked!"

View File

@ -1,177 +0,0 @@
# copy_from.py -- example about copy_from
#
# Copyright (C) 2002 Tom Jenkins <tjenkins@devis.com>
# Copyright (C) 2005 Federico Di Gregorio <fog@initd.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import os
import StringIO
import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)")
except:
conn.rollback()
curs.execute("DROP TABLE test_copy")
curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)")
conn.commit()
# copy_from with default arguments, from open file
io = open('copy_from.txt', 'wr')
data = ['Tom\tJenkins\t37\n',
'Madonna\t\\N\t45\n',
'Federico\tDi Gregorio\t\\N\n']
io.writelines(data)
io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy')
print "1) Copy %d records from file object " % len(data) + \
"using defaults (sep: \\t and null = \\N)"
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select returned %d rows" % len(rows)
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
curs.execute("delete from test_copy")
conn.commit()
# copy_from using custom separator, from open file
io = open('copy_from.txt', 'wr')
data = ['Tom:Jenkins:37\n',
'Madonna:\N:45\n',
'Federico:Di Gregorio:\N\n']
io.writelines(data)
io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy', ':')
print "2) Copy %d records from file object using sep = :" % len(data)
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select returned %d rows" % len(rows)
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
curs.execute("delete from test_copy")
conn.commit()
# copy_from using custom null identifier, from open file
io = open('copy_from.txt', 'wr')
data = ['Tom\tJenkins\t37\n',
'Madonna\tNULL\t45\n',
'Federico\tDi Gregorio\tNULL\n']
io.writelines(data)
io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy', null='NULL')
print "3) Copy %d records from file object using null = NULL" % len(data)
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select using cursor returned %d rows" % len(rows)
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
curs.execute("delete from test_copy")
conn.commit()
# copy_from using custom separator and null identifier
io = open('copy_from.txt', 'wr')
data = ['Tom:Jenkins:37\n', 'Madonna:NULL:45\n', 'Federico:Di Gregorio:NULL\n']
io.writelines(data)
io.close()
io = open('copy_from.txt', 'r')
curs.copy_from(io, 'test_copy', ':', 'NULL')
print "4) Copy %d records from file object " % len(data) + \
"using sep = : and null = NULL"
io.close()
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select using cursor returned %d rows" % len(rows)
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
curs.execute("delete from test_copy")
conn.commit()
# anything can be used as a file if it has .read() and .readline() methods
data = StringIO.StringIO()
data.write('\n'.join(['Tom\tJenkins\t37',
'Madonna\t\N\t45',
'Federico\tDi Gregorio\t\N']))
data.seek(0)
curs.copy_from(data, 'test_copy')
print "5) Copy 3 records from StringIO object using defaults"
curs.execute("SELECT * FROM test_copy")
rows = curs.fetchall()
print " Select using cursor returned %d rows" % len(rows)
for r in rows:
print " %s %s\t%s" % (r[0], r[1], r[2])
curs.execute("delete from test_copy")
conn.commit()
# simple error test
print "6) About to raise an error"
data = StringIO.StringIO()
data.write('\n'.join(['Tom\tJenkins\t37',
'Madonna\t\N\t45',
'Federico\tDi Gregorio\taaa']))
data.seek(0)
try:
curs.copy_from(data, 'test_copy')
except StandardError, err:
conn.rollback()
print " Caught error (as expected):\n", err
conn.rollback()
curs.execute("DROP TABLE test_copy")
os.unlink('copy_from.txt')
conn.commit()

View File

@ -1,103 +0,0 @@
# copy_to.py -- example about copy_to
#
# Copyright (C) 2002 Tom Jenkins <tjenkins@devis.com>
# Copyright (C) 2005 Federico Di Gregorio <fog@initd.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import os
import StringIO
import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)")
except:
conn.rollback()
curs.execute("DROP TABLE test_copy")
curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)")
conn.commit()
# demostrate copy_to functionality
data = [('Tom', 'Jenkins', '37'),
('Madonna', None, '45'),
('Federico', 'Di Gregorio', None)]
query = "INSERT INTO test_copy VALUES (%s, %s, %s)"
curs.executemany(query, data)
conn.commit()
# copy_to using defaults
io = open('copy_to.txt', 'w')
curs.copy_to(io, 'test_copy')
print "1) Copy %d records into file object using defaults: " % len (data) + \
"sep = \\t and null = \\N"
io.close()
rows = open('copy_to.txt', 'r').readlines()
print " File has %d rows:" % len(rows)
for r in rows:
print " ", r,
# copy_to using custom separator
io = open('copy_to.txt', 'w')
curs.copy_to(io, 'test_copy', ':')
print "2) Copy %d records into file object using sep = :" % len(data)
io.close()
rows = open('copy_to.txt', 'r').readlines()
print " File has %d rows:" % len(rows)
for r in rows:
print " ", r,
# copy_to using custom null identifier
io = open('copy_to.txt', 'w')
curs.copy_to(io, 'test_copy', null='NULL')
print "3) Copy %d records into file object using null = NULL" % len(data)
io.close()
rows = open('copy_to.txt', 'r').readlines()
print " File has %d rows:" % len(rows)
for r in rows:
print " ", r,
# copy_to using custom separator and null identifier
io = open('copy_to.txt', 'w')
curs.copy_to(io, 'test_copy', ':', 'NULL')
print "4) Copy %d records into file object using sep = : and null ) NULL" % \
len(data)
io.close()
rows = open('copy_to.txt', 'r').readlines()
print " File has %d rows:" % len(rows)
for r in rows:
print " ", r,
curs.execute("DROP TABLE test_copy")
os.unlink('copy_to.txt')
conn.commit()

View File

@ -1,63 +0,0 @@
# cursor.py - how to subclass the cursor type
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
import psycopg2.extensions
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dsn:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
class NoDataError(psycopg2.ProgrammingError):
"""Exception that will be raised by our cursor."""
pass
class Cursor(psycopg2.extensions.cursor):
"""A custom cursor."""
def fetchone(self):
"""Like fetchone but raise an exception if no data is available.
Note that to have .fetchmany() and .fetchall() to raise the same
exception we'll have to override them too; even if internally psycopg
uses the same function to fetch rows, the code path from Python is
different.
"""
d = psycopg2.extensions.cursor.fetchone(self)
if d is None:
raise NoDataError("no more data")
return d
curs = conn.cursor(cursor_factory=Cursor)
curs.execute("SELECT 1 AS foo")
print "Result of fetchone():", curs.fetchone()
# now let's raise the exception
try:
curs.fetchone()
except NoDataError, err:
print "Exception caught:", err
conn.rollback()

View File

@ -1,144 +0,0 @@
"""
This example/recipe has been contributed by Valentino Volonghi (dialtone)
Mapping arbitrary objects to a PostgreSQL database with psycopg2
- Problem
You need to store arbitrary objects in a PostgreSQL database without being
intrusive for your classes (don't want inheritance from an 'Item' or
'Persistent' object).
- Solution
"""
from datetime import datetime
import psycopg2
from psycopg2.extensions import adapt, register_adapter
try:
sorted()
except:
def sorted(seq):
seq.sort()
return seq
# Here is the adapter for every object that we may ever need to
# insert in the database. It receives the original object and does
# its job on that instance
class ObjectMapper(object):
def __init__(self, orig, curs=None):
self.orig = orig
self.tmp = {}
self.items, self.fields = self._gatherState()
def _gatherState(self):
adaptee_name = self.orig.__class__.__name__
fields = sorted([(field, getattr(self.orig, field))
for field in persistent_fields[adaptee_name]])
items = []
for item, value in fields:
items.append(item)
return items, fields
def getTableName(self):
return self.orig.__class__.__name__
def getMappedValues(self):
tmp = []
for i in self.items:
tmp.append("%%(%s)s"%i)
return ", ".join(tmp)
def getValuesDict(self):
return dict(self.fields)
def getFields(self):
return self.items
def generateInsert(self):
qry = "INSERT INTO"
qry += " " + self.getTableName() + " ("
qry += ", ".join(self.getFields()) + ") VALUES ("
qry += self.getMappedValues() + ")"
return qry, self.getValuesDict()
# Here are the objects
class Album(object):
id = 0
def __init__(self):
self.creation_time = datetime.now()
self.album_id = self.id
Album.id = Album.id + 1
self.binary_data = buffer('12312312312121')
class Order(object):
id = 0
def __init__(self):
self.items = ['rice','chocolate']
self.price = 34
self.order_id = self.id
Order.id = Order.id + 1
register_adapter(Album, ObjectMapper)
register_adapter(Order, ObjectMapper)
# Describe what is needed to save on each object
# This is actually just configuration, you can use xml with a parser if you
# like to have plenty of wasted CPU cycles ;P.
persistent_fields = {'Album': ['album_id', 'creation_time', 'binary_data'],
'Order': ['order_id', 'items', 'price']
}
print adapt(Album()).generateInsert()
print adapt(Album()).generateInsert()
print adapt(Album()).generateInsert()
print adapt(Order()).generateInsert()
print adapt(Order()).generateInsert()
print adapt(Order()).generateInsert()
"""
- Discussion
Psycopg 2 has a great new feature: adaptation. The big thing about
adaptation is that it enables the programmer to glue most of the
code out there without many difficulties.
This recipe tries to focus attention on a way to generate SQL queries to
insert completely new objects inside a database. As you can see objects do
not know anything about the code that is handling them. We specify all the
fields that we need for each object through the persistent_fields dict.
The most important lines of this recipe are:
register_adapter(Album, ObjectMapper)
register_adapter(Order, ObjectMapper)
In these lines we notify the system that when we call adapt with an Album instance
as an argument we want it to istantiate ObjectMapper passing the Album instance
as argument (self.orig in the ObjectMapper class).
The output is something like this (for each call to generateInsert):
('INSERT INTO Album (album_id, binary_data, creation_time) VALUES
(%(album_id)s, %(binary_data)s, %(creation_time)s)',
{'binary_data': <read-only buffer for 0x402de070, ...>,
'creation_time': datetime.datetime(2004, 9, 10, 20, 48, 29, 633728),
'album_id': 1}
)
This is a tuple of {SQL_QUERY, FILLING_DICT}, and all the quoting/converting
stuff (from python's datetime to postgres s and from python's buffer to
postgres' blob) is handled with the same adaptation process hunder the hood
by psycopg2.
At last, just notice that ObjectMapper is working for both Album and Order
instances without any glitches at all, and both classes could have easily been
coming from closed source libraries or C coded ones (which are not easily
modified), whereas a common pattern in todays ORMs or OODBs is to provide
a basic 'Persistent' object that already knows how to store itself in the
database.
"""

View File

@ -1,65 +0,0 @@
# dict.py - using DictCUrsor/DictRow
#
# Copyright (C) 2005-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
import psycopg2.extras
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dsn:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
curs.execute("SELECT 1 AS foo, 'cip' AS bar, date(now()) as zot")
print "Cursor's row factory is", curs.row_factory
data = curs.fetchone()
print "The type of the data row is", type(data)
print "Some data accessed both as tuple and dict:"
print " ", data['foo'], data['bar'], data['zot']
print " ", data[0], data[1], data[2]
# execute another query and demostrate we can still access the row
curs.execute("SELECT 2 AS foo")
print "The type of the data row is", type(data)
print "Some more data accessed both as tuple and dict:"
print " ", data['foo'], data['bar'], data['zot']
print " ", data[0], data[1], data[2]
curs = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
curs.execute("SELECT 1 AS foo, 'cip' AS bar, date(now()) as zot")
print "Cursor's row factory is", curs.row_factory
data = curs.fetchone()
print "The type of the data row is", type(data)
print "Some data accessed both as tuple and dict:"
print " ", data['foo'], data['bar'], data['zot']
print " ", "No access using indices: this is a specialized cursor."
# execute another query and demostrate we can still access the row
curs.execute("SELECT 2 AS foo")
print "The type of the data row is", type(data)
print "Some more data accessed both as tuple and dict:"
print " ", data['foo'], data['bar'], data['zot']
print " ", "No access using indices: this is a specialized cursor."

View File

@ -1,99 +0,0 @@
# datetime.py - example of using date and time types
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
import mx.DateTime
import datetime
from psycopg2.extensions import adapt
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
curs = conn.cursor()
try:
curs.execute("""CREATE TABLE test_dt (
k int4, d date, t time, dt timestamp, z interval)""")
except:
conn.rollback()
curs.execute("DROP TABLE test_dt")
curs.execute("""CREATE TABLE test_dt (
k int4, d date, t time, dt timestamp, z interval)""")
conn.commit()
# build and insert some data using mx.DateTime
mx1 = (
1,
mx.DateTime.Date(2004, 10, 19),
mx.DateTime.Time(0, 11, 17.015),
mx.DateTime.Timestamp(2004, 10, 19, 0, 11, 17.5),
mx.DateTime.DateTimeDelta(13, 15, 17, 59.9))
from psycopg2.extensions import adapt
import psycopg2.extras
print adapt(mx1)
print "Inserting mx.DateTime values..."
curs.execute("INSERT INTO test_dt VALUES (%s, %s, %s, %s, %s)", mx1)
# build and insert some values using the datetime adapters
dt1 = (
2,
datetime.date(2004, 10, 19),
datetime.time(0, 11, 17, 15000),
datetime.datetime(2004, 10, 19, 0, 11, 17, 500000),
datetime.timedelta(13, 15*3600+17*60+59, 900000))
print "Inserting Python datetime values..."
curs.execute("INSERT INTO test_dt VALUES (%s, %s, %s, %s, %s)", dt1)
# now extract the row from database and print them
print "Extracting values inserted with mx.DateTime wrappers:"
curs.execute("SELECT d, t, dt, z FROM test_dt WHERE k = 1")
for n, x in zip(mx1[1:], curs.fetchone()):
try:
# this will work only if psycopg has been compiled with datetime
# as the default typecaster for date/time values
s = repr(n) + "\n -> " + str(adapt(n)) + \
"\n -> " + repr(x) + "\n -> " + x.isoformat()
except:
s = repr(n) + "\n -> " + str(adapt(n)) + \
"\n -> " + repr(x) + "\n -> " + str(x)
print s
print
print "Extracting values inserted with Python datetime wrappers:"
curs.execute("SELECT d, t, dt, z FROM test_dt WHERE k = 2")
for n, x in zip(dt1[1:], curs.fetchone()):
try:
# this will work only if psycopg has been compiled with datetime
# as the default typecaster for date/time values
s = repr(n) + "\n -> " + repr(x) + "\n -> " + x.isoformat()
except:
s = repr(n) + "\n -> " + repr(x) + "\n -> " + str(x)
print s
print
curs.execute("DROP TABLE test_dt")
conn.commit()

View File

@ -1,105 +0,0 @@
# encoding.py - show to change client enkoding (and test it works)
# -*- encoding: utf8 -*-
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
import psycopg2.extensions
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Initial encoding for this connection is", conn.encoding
print "\n** This example is supposed to be run in a UNICODE terminal! **\n"
print "Available encodings:"
encs = psycopg2.extensions.encodings.items()
encs.sort()
for a, b in encs:
print " ", a, "<->", b
print "Using STRING typecaster"
print "Setting backend encoding to LATIN1 and executing queries:"
conn.set_client_encoding('LATIN1')
curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", ('àèìòù',))
x = curs.fetchone()[0]
print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0]
print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x)
print "Setting backend encoding to UTF8 and executing queries:"
conn.set_client_encoding('UNICODE')
curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),))
x = curs.fetchone()[0]
print " ->", x, type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0]
print " ->", x, type(x)
print "Using UNICODE typecaster"
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
print "Setting backend encoding to LATIN1 and executing queries:"
conn.set_client_encoding('LATIN1')
curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", ('àèìòù',))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
print "Setting backend encoding to UTF8 and executing queries:"
conn.set_client_encoding('UNICODE')
curs = conn.cursor()
curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
print "Executing full UNICODE queries"
print "Setting backend encoding to LATIN1 and executing queries:"
conn.set_client_encoding('LATIN1')
curs = conn.cursor()
curs.execute(u"SELECT %s::TEXT AS foo", ('àèìòù',))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
print "Setting backend encoding to UTF8 and executing queries:"
conn.set_client_encoding('UNICODE')
curs = conn.cursor()
curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)
curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù',))
x = curs.fetchone()[0]
print " ->", x.encode('utf-8'), ":", type(x)

View File

@ -1,80 +0,0 @@
# fetch.py -- example about declaring cursors
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_fetch (val int4)")
except:
conn.rollback()
curs.execute("DROP TABLE test_fetch")
curs.execute("CREATE TABLE test_fetch (val int4)")
conn.commit()
# we use this function to format the output
def flatten(l):
"""Flattens list of tuples l."""
return map(lambda x: x[0], l)
# insert 20 rows in the table
for i in range(20):
curs.execute("INSERT INTO test_fetch VALUES(%s)", (i,))
conn.commit()
# does some nice tricks with the transaction and postgres cursors
# (remember to always commit or rollback before a DECLARE)
#
# we don't need to DECLARE ourselves, psycopg now supports named
# cursors (but we leave the code here, comments, as an example of
# what psycopg is doing under the hood)
#
#curs.execute("DECLARE crs CURSOR FOR SELECT * FROM test_fetch")
#curs.execute("FETCH 10 FROM crs")
#print "First 10 rows:", flatten(curs.fetchall())
#curs.execute("MOVE -5 FROM crs")
#print "Moved back cursor by 5 rows (to row 5.)"
#curs.execute("FETCH 10 FROM crs")
#print "Another 10 rows:", flatten(curs.fetchall())
#curs.execute("FETCH 10 FROM crs")
#print "The remaining rows:", flatten(curs.fetchall())
ncurs = conn.cursor("crs")
ncurs.execute("SELECT * FROM test_fetch")
print "First 10 rows:", flatten(ncurs.fetchmany(10))
ncurs.scroll(-5)
print "Moved back cursor by 5 rows (to row 5.)"
print "Another 10 rows:", flatten(ncurs.fetchmany(10))
print "Another one:", list(ncurs.fetchone())
print "The remaining rows:", flatten(ncurs.fetchall())
conn.rollback()
curs.execute("DROP TABLE test_fetch")
conn.commit()

View File

@ -1,59 +0,0 @@
# lastrowid.py - example of using .lastrowid attribute
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys, psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_oid (name text, surname text)")
except:
conn.rollback()
curs.execute("DROP TABLE test_oid")
curs.execute("CREATE TABLE test_oid (name text, surname text)")
conn.commit()
data = ({'name':'Federico', 'surname':'Di Gregorio'},
{'name':'Pierluigi', 'surname':'Di Nunzio'})
curs.execute("""INSERT INTO test_oid
VALUES (%(name)s, %(surname)s)""", data[0])
foid = curs.lastrowid
print "Oid for %(name)s %(surname)s" % data[0], "is", foid
curs.execute("""INSERT INTO test_oid
VALUES (%(name)s, %(surname)s)""", data[1])
moid = curs.lastrowid
print "Oid for %(name)s %(surname)s" % data[1], "is", moid
curs.execute("SELECT * FROM test_oid WHERE oid = %s", (foid,))
print "Oid", foid, "selected %s %s" % curs.fetchone()
curs.execute("SELECT * FROM test_oid WHERE oid = %s", (moid,))
print "Oid", moid, "selected %s %s" % curs.fetchone()
curs.execute("DROP TABLE test_oid")
conn.commit()

View File

@ -1,91 +0,0 @@
# lobject.py - lobject example
#
# Copyright (C) 2001-2006 Federico Di Gregorio <fog@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
# this will create a large object with a new random oid, we'll
# use it to make some basic tests about read/write and seek.
lobj = conn.lobject()
loid = lobj.oid
print "Created a new large object with oid", loid
print "Manually importing some binary data into the object:"
data = open("somehackers.jpg").read()
len = lobj.write(data)
print " imported", len, "bytes of data"
conn.commit()
print "Trying to (re)open large object with oid", loid
lobj = conn.lobject(loid)
print "Manually exporting the data from the lobject:"
data1 = lobj.read()
len = lobj.tell()
lobj.seek(0, 0)
data2 = lobj.read()
if data1 != data2:
print "ERROR: read after seek returned different data"
open("somehackers_lobject1.jpg", 'wb').write(data1)
print " written", len, "bytes of data to somehackers_lobject1.jpg"
lobj.unlink()
print "Large object with oid", loid, "removed"
conn.commit()
# now we try to use the import and export functions to do the same
lobj = conn.lobject(0, 'n', 0, "somehackers.jpg")
loid = lobj.oid
print "Imported a new large object with oid", loid
conn.commit()
print "Trying to (re)open large object with oid", loid
lobj = conn.lobject(loid, 'n')
print "Using export() to export the data from the large object:"
lobj.export("somehackers_lobject2.jpg")
print " exported large object to somehackers_lobject2.jpg"
lobj.unlink()
print "Large object with oid", loid, "removed"
conn.commit()
# this will create a very large object with a new random oid.
lobj = conn.lobject()
loid = lobj.oid
print "Created a new large object with oid", loid
print "Manually importing a lot of data into the object:"
data = "data" * 1000000
len = lobj.write(data)
print " imported", len, "bytes of data"
conn.rollback()
print "\nNow try to load the new images, to check it worked!"

View File

@ -1,47 +0,0 @@
# mogrify.py - test all possible simple type mogrifications
# -*- encoding: latin1 -*-
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details..
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys, psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
curs.execute("SELECT %(foo)s AS foo", {'foo':'bar'})
curs.execute("SELECT %(foo)s AS foo", {'foo':None})
curs.execute("SELECT %(foo)s AS foo", {'foo':True})
curs.execute("SELECT %(foo)s AS foo", {'foo':42})
curs.execute("SELECT %(foo)s AS foo", {'foo':u'yatt<EFBFBD>!'})
curs.execute("SELECT %(foo)s AS foo", {'foo':u'bar'})
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':'bar'})
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':None})
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':True})
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':42})
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':u'yatt<EFBFBD>!'})
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':u'bar'})
conn.rollback()

View File

@ -1,126 +0,0 @@
"""
Using a tuple as a bound variable in "SELECT ... IN (...)" clauses
in PostgreSQL using psycopg2
Some time ago someone asked on the psycopg mailing list how to have a
bound variable expand to the right SQL for an SELECT IN clause:
SELECT * FROM atable WHERE afield IN (value1, value2, value3)
with the values to be used in the IN clause to be passed to the cursor
.execute() method in a tuple as a bound variable, i.e.:
in_values = ("value1", "value2", "value3")
curs.execute("SELECT ... IN %s", (in_values,))
psycopg 1 does support typecasting from Python to PostgreSQL (and back)
only for simple types and this problem has no elegant solution (short or
writing a wrapper class returning the pre-quoted text in an __str__
method.
But psycopg2 offers a simple and elegant solution by partially
implementing the Object Adaptation from PEP 246. psycopg2 moves
the type-casting logic into external adapters and a somehow
broken adapt() function.
While the original adapt() takes 3 arguments, psycopg2's one only takes
1: the bound variable to be adapted. The result is an object supporting
a not-yet well defined protocol that we can call ISQLQuote:
class ISQLQuote:
def getquoted(self):
"Returns a quoted string representing the bound variable."
def getbinary(self):
"Returns a binary quoted string representing the bound variable."
def getbuffer(self):
"Returns the wrapped object itself."
__str__ = getquoted
Then one of the functions (usually .getquoted()) is called by psycopg2 at
the right time to obtain the right, sql-quoted representation for the
corresponding bound variable.
The nice part is that the default, built-in adapters, derived from
psycopg 1 tyecasting code can be overridden by the programmer, simply
replacing them in the psycopg.extensions.adapters dictionary.
Then the solution to the original problem is now obvious: write an
adapter that adapts tuple objects into the right SQL string, by calling
recursively adapt() on each element.
psycopg2 development can be tracked on the psycopg mailing list:
http://lists.initd.org/mailman/listinfo/psycopg
"""
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
import psycopg2
import psycopg2.extensions
from psycopg2.extensions import adapt as psycoadapt
from psycopg2.extensions import register_adapter
class AsIs(object):
"""An adapter that just return the object 'as is'.
psycopg 1.99.9 has some optimizations that make impossible to call
adapt() without adding some basic adapters externally. This limitation
will be lifted in a future release.
"""
def __init__(self, obj):
self.__obj = obj
def getquoted(self):
return self.__obj
class SQL_IN(object):
"""Adapt a tuple to an SQL quotable object."""
def __init__(self, seq):
self._seq = seq
def prepare(self, conn):
pass
def getquoted(self):
# this is the important line: note how every object in the
# list is adapted and then how getquoted() is called on it
qobjs = [str(psycoadapt(o).getquoted()) for o in self._seq]
return '(' + ', '.join(qobjs) + ')'
__str__ = getquoted
# add our new adapter class to psycopg list of adapters
register_adapter(tuple, SQL_IN)
register_adapter(float, AsIs)
register_adapter(int, AsIs)
# usually we would call:
#
# conn = psycopg.connect("...")
# curs = conn.cursor()
# curs.execute("SELECT ...", (("this", "is", "the", "tuple"),))
#
# but we have no connection to a database right now, so we just check
# the SQL_IN class by calling psycopg's adapt() directly:
if __name__ == '__main__':
print "Note how the string will be SQL-quoted, but the number will not:"
print psycoadapt(("this is an 'sql quoted' str\\ing", 1, 2.0))

View File

@ -1,45 +0,0 @@
# notify.py - example of getting notifies
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import select
import psycopg2
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
curs = conn.cursor()
curs.execute("listen test")
print "Waiting for 'NOTIFY test'"
while 1:
if select.select([conn],[],[],5)==([],[],[]):
print "Timeout"
else:
conn.poll()
while conn.notifies:
print "Got NOTIFY:", conn.notifies.pop()

View File

@ -1,54 +0,0 @@
# simple.py - very simple example of plain DBAPI-2.0 usage
#
# currently used as test-me-stress-me script for psycopg 2.0
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
class SimpleQuoter(object):
def sqlquote(x=None):
return "'bar'"
import sys
import psycopg2
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
curs.execute("SELECT 1 AS foo")
print curs.fetchone()
curs.execute("SELECT 1 AS foo")
print curs.fetchmany()
curs.execute("SELECT 1 AS foo")
print curs.fetchall()
conn.rollback()
sys.exit(0)
curs.execute("SELECT 1 AS foo", async=1)
curs.execute("SELECT %(foo)s AS foo", {'foo':'bar'})
curs.execute("SELECT %(foo)s AS foo", {'foo':None})
curs.execute("SELECT %(foo)f AS foo", {'foo':42})
curs.execute("SELECT %(foo)s AS foo", {'foo':SimpleQuoter()})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,161 +0,0 @@
# threads.py -- example of multiple threads using psycopg
# -*- encoding: latin1 -*-
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## some others parameters
INSERT_THREADS = ('A', 'B', 'C')
SELECT_THREADS = ('1', '2')
ROWS = 1000
COMMIT_STEP = 20
SELECT_SIZE = 10000
SELECT_STEP = 500
SELECT_DIV = 250
# the available modes are:
# 0 - one connection for all inserts and one for all select threads
# 1 - connections generated using the connection pool
MODE = 1
## don't modify anything below this line (except for experimenting)
import sys, psycopg2, threading
from psycopg2.pool import ThreadedConnectionPool
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
if len(sys.argv) > 1:
DSN = sys.argv[1]
if len(sys.argv) > 2:
MODE = int(sys.argv[2])
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
curs = conn.cursor()
try:
curs.execute("""CREATE TABLE test_threads (
name text, value1 int4, value2 float)""")
except:
conn.rollback()
curs.execute("DROP TABLE test_threads")
curs.execute("""CREATE TABLE test_threads (
name text, value1 int4, value2 float)""")
conn.commit()
## this function inserts a big number of rows and creates and destroys
## a large number of cursors
def insert_func(conn_or_pool, rows):
name = threading.currentThread().getName()
if MODE == 0:
conn = conn_or_pool
else:
conn = conn_or_pool.getconn()
for i in range(rows):
if divmod(i, COMMIT_STEP)[1] == 0:
conn.commit()
if MODE == 1:
conn_or_pool.putconn(conn)
s = name + ": COMMIT STEP " + str(i)
print s
if MODE == 1:
conn = conn_or_pool.getconn()
c = conn.cursor()
try:
c.execute("INSERT INTO test_threads VALUES (%s, %s, %s)",
(str(i), i, float(i)))
except psycopg2.ProgrammingError, err:
print name, ": an error occurred; skipping this insert"
print err
conn.commit()
## a nice select function that prints the current number of rows in the
## database (and transfer them, putting some pressure on the network)
def select_func(conn_or_pool, z):
name = threading.currentThread().getName()
if MODE == 0:
conn = conn_or_pool
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
for i in range(SELECT_SIZE):
if divmod(i, SELECT_STEP)[1] == 0:
try:
if MODE == 1:
conn = conn_or_pool.getconn()
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
c = conn.cursor()
c.execute("SELECT * FROM test_threads WHERE value2 < %s",
(int(i/z),))
l = c.fetchall()
if MODE == 1:
conn_or_pool.putconn(conn)
s = name + ": number of rows fetched: " + str(len(l))
print s
except psycopg2.ProgrammingError, err:
print name, ": an error occurred; skipping this select"
print err
## create the connection pool or the connections
if MODE == 0:
conn_insert = psycopg2.connect(DSN)
conn_select = psycopg2.connect(DSN)
else:
m = len(INSERT_THREADS) + len(SELECT_THREADS)
n = m/2
conn_insert = conn_select = ThreadedConnectionPool(n, m, DSN)
## create the threads
threads = []
print "Creating INSERT threads:"
for name in INSERT_THREADS:
t = threading.Thread(None, insert_func, 'Thread-'+name,
(conn_insert, ROWS))
t.setDaemon(0)
threads.append(t)
print "Creating SELECT threads:"
for name in SELECT_THREADS:
t = threading.Thread(None, select_func, 'Thread-'+name,
(conn_select, SELECT_DIV))
t.setDaemon(0)
threads.append(t)
## really start the threads now
for t in threads:
t.start()
# and wait for them to finish
for t in threads:
t.join()
print t.getName(), "exited OK"
conn.commit()
curs.execute("SELECT count(name) FROM test_threads")
print "Inserted", curs.fetchone()[0], "rows."
curs.execute("DROP TABLE test_threads")
conn.commit()

View File

@ -1,67 +0,0 @@
# typecast.py - example of per-cursor and per-connection typecasters.
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
class SimpleQuoter(object):
def sqlquote(x=None):
return "'bar'"
import sys
import psycopg2
import psycopg2.extensions
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Encoding for this connection is", conn.encoding
curs = conn.cursor()
curs.execute("SELECT 'text'::text AS foo")
textoid = curs.description[0][1]
print "Oid for the text datatype is", textoid
def castA(s, curs):
if s is not None: return "(A) " + s
TYPEA = psycopg2.extensions.new_type((textoid,), "TYPEA", castA)
def castB(s, curs):
if s is not None: return "(B) " + s
TYPEB = psycopg2.extensions.new_type((textoid,), "TYPEB", castB)
curs = conn.cursor()
curs.execute("SELECT 'some text.'::text AS foo")
print "Some text from plain connection:", curs.fetchone()[0]
psycopg2.extensions.register_type(TYPEA, conn)
curs = conn.cursor()
curs.execute("SELECT 'some text.'::text AS foo")
print "Some text from connection with typecaster:", curs.fetchone()[0]
curs = conn.cursor()
psycopg2.extensions.register_type(TYPEB, curs)
curs.execute("SELECT 'some text.'::text AS foo")
print "Some text from cursor with typecaster:", curs.fetchone()[0]
curs = conn.cursor()
curs.execute("SELECT 'some text.'::text AS foo")
print "Some text from connection with typecaster again:", curs.fetchone()[0]

View File

@ -1,69 +0,0 @@
# tz.py - example of datetime objects with time zones
# -*- encoding: utf8 -*-
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
import datetime
from psycopg2.tz import ZERO, LOCAL, FixedOffsetTimezone
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_tz (t timestamp with time zone)")
except:
conn.rollback()
curs.execute("DROP TABLE test_tz")
curs.execute("CREATE TABLE test_tz (t timestamp with time zone)")
conn.commit()
d = datetime.datetime(1971, 10, 19, 22, 30, 0, tzinfo=LOCAL)
curs.execute("INSERT INTO test_tz VALUES (%s)", (d,))
print "Inserted timestamp with timezone:", d
print "Time zone:", d.tzinfo.tzname(d), "offset:", d.tzinfo.utcoffset(d)
tz = FixedOffsetTimezone(-5*60, "EST")
d = datetime.datetime(1971, 10, 19, 22, 30, 0, tzinfo=tz)
curs.execute("INSERT INTO test_tz VALUES (%s)", (d,))
print "Inserted timestamp with timezone:", d
print "Time zone:", d.tzinfo.tzname(d), "offset:", d.tzinfo.utcoffset(d)
curs.execute("SELECT * FROM test_tz")
d = curs.fetchone()[0]
curs.execute("INSERT INTO test_tz VALUES (%s)", (d,))
print "Inserted SELECTed timestamp:", d
print "Time zone:", d.tzinfo.tzname(d), "offset:", d.tzinfo.utcoffset(d)
curs.execute("SELECT * FROM test_tz")
for d in curs:
u = d[0].utcoffset() or ZERO
print "UTC time: ", d[0] - u
print "Local time:", d[0]
print "Time zone:", d[0].tzinfo.tzname(d[0]), d[0].tzinfo.utcoffset(d[0])
curs.execute("DROP TABLE test_tz")
conn.commit()

View File

@ -1,126 +0,0 @@
# usercast.py -- example of user defined typecasters
# -*- encoding: latin-1 -*-
#
# Copyright (C) 2001-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
## put in DSN your DSN string
DSN = 'dbname=test'
## don't modify anything below this line (except for experimenting)
import sys
import psycopg2
import psycopg2.extensions
import whrandom
# importing psycopg.extras will give us a nice tuple adapter: this is wrong
# because the adapter is meant to be used in SQL IN clauses while we use
# tuples to represent points but it works and the example is about Rect, not
# "Point"
import psycopg2.extras
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg2.connect(DSN)
print "Initial encoding for this connection is", conn.encoding
curs = conn.cursor()
try:
curs.execute("CREATE TABLE test_cast (p1 point, p2 point, b box)")
except:
conn.rollback()
curs.execute("DROP TABLE test_cast")
curs.execute("CREATE TABLE test_cast (p1 point, p2 point, b box)")
conn.commit()
# this is the callable object we use as a typecast (the typecast is
# usually a function, but we use a class, just to demonstrate the
# flexibility of the psycopg casting system
class Rect(object):
"""Very simple rectangle.
Note that we use this type as a data holder, as an adapter of itself for
the ISQLQuote protocol used by psycopg's adapt() (see __confrom__ below)
and eventually as a type-caster for the data extracted from the database
(that's why __init__ takes the curs argument.)
"""
def __init__(self, s=None, curs=None):
"""Init the rectangle from the optional string s."""
self.x = self.y = self.width = self.height = 0.0
if s: self.from_string(s)
def __conform__(self, proto):
"""This is a terrible hack, just ignore proto and return self."""
if proto == psycopg2.extensions.ISQLQuote:
return self
def from_points(self, x0, y0, x1, y1):
"""Init the rectangle from points."""
if x0 > x1: (x0, x1) = (x1, x0)
if y0 > y1: (y0, y1) = (y1, y0)
self.x = x0
self.y = y0
self.width = x1 - x0
self.height = y1 - y0
def from_string(self, s):
"""Init the rectangle from a string."""
seq = eval(s)
self.from_points(seq[0][0], seq[0][1], seq[1][0], seq[1][1])
def getquoted(self):
"""Format self as a string usable by the db to represent a box."""
s = "'((%d,%d),(%d,%d))'" % (
self.x, self.y, self.x + self.width, self.y + self.height)
return s
def show(self):
"""Format a description of the box."""
s = "X: %d\tY: %d\tWidth: %d\tHeight: %d" % (
self.x, self.y, self.width, self.height)
return s
# here we select from the empty table, just to grab the description
curs.execute("SELECT b FROM test_cast WHERE 0=1")
boxoid = curs.description[0][1]
print "Oid for the box datatype is", boxoid
# and build the user cast object
BOX = psycopg2.extensions.new_type((boxoid,), "BOX", Rect)
psycopg2.extensions.register_type(BOX)
# now insert 100 random data (2 points and a box in each row)
for i in range(100):
p1 = (whrandom.randint(0,100), whrandom.randint(0,100))
p2 = (whrandom.randint(0,100), whrandom.randint(0,100))
b = Rect()
b.from_points(whrandom.randint(0,100), whrandom.randint(0,100),
whrandom.randint(0,100), whrandom.randint(0,100))
curs.execute("INSERT INTO test_cast VALUES ('%(p1)s', '%(p2)s', %(box)s)",
{'box':b, 'p1':p1, 'p2':p2})
print "Added 100 boxed to the database"
# select and print all boxes with at least one point inside
curs.execute("SELECT b FROM test_cast WHERE p1 @ b OR p2 @ b")
boxes = curs.fetchall()
print "Found %d boxes with at least a point inside:" % len(boxes)
for box in boxes:
print " ", box[0].show()
curs.execute("DROP TABLE test_cast")
conn.commit()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -6,10 +6,10 @@ provide new-style classes for connection and cursor objects and other sweet
candies. Like the original, psycopg 2 was written with the aim of being very candies. Like the original, psycopg 2 was written with the aim of being very
small and fast, and stable as a rock. small and fast, and stable as a rock.
Homepage: http://initd.org/projects/psycopg2 Homepage: https://psycopg.org/
.. _PostgreSQL: http://www.postgresql.org/ .. _PostgreSQL: https://www.postgresql.org/
.. _Python: http://www.python.org/ .. _Python: https://www.python.org/
:Groups: :Groups:
* `Connections creation`: connect * `Connections creation`: connect
@ -18,7 +18,8 @@ Homepage: http://initd.org/projects/psycopg2
""" """
# psycopg/__init__.py - initialization of the psycopg module # psycopg/__init__.py - initialization of the psycopg module
# #
# Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> # Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -43,69 +44,44 @@ Homepage: http://initd.org/projects/psycopg2
# Note: the first internal import should be _psycopg, otherwise the real cause # Note: the first internal import should be _psycopg, otherwise the real cause
# of a failed loading of the C module may get hidden, see # of a failed loading of the C module may get hidden, see
# http://archives.postgresql.org/psycopg/2011-02/msg00044.php # https://archives.postgresql.org/psycopg/2011-02/msg00044.php
# Import the DBAPI-2.0 stuff into top-level module. # Import the DBAPI-2.0 stuff into top-level module.
from psycopg2._psycopg import BINARY, NUMBER, STRING, DATETIME, ROWID from psycopg2._psycopg import ( # noqa
BINARY, NUMBER, STRING, DATETIME, ROWID,
from psycopg2._psycopg import Binary, Date, Time, Timestamp Binary, Date, Time, Timestamp,
from psycopg2._psycopg import DateFromTicks, TimeFromTicks, TimestampFromTicks DateFromTicks, TimeFromTicks, TimestampFromTicks,
from psycopg2._psycopg import Error, Warning, DataError, DatabaseError, ProgrammingError Error, Warning, DataError, DatabaseError, ProgrammingError, IntegrityError,
from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError InterfaceError, InternalError, NotSupportedError, OperationalError,
from psycopg2._psycopg import NotSupportedError, OperationalError
from psycopg2._psycopg import _connect, apilevel, threadsafety, paramstyle _connect, apilevel, threadsafety, paramstyle,
from psycopg2._psycopg import __version__ __version__, __libpq_version__,
)
from psycopg2 import tz
# Register default adapters. # Register default adapters.
import psycopg2.extensions as _ext from psycopg2 import extensions as _ext
_ext.register_adapter(tuple, _ext.SQL_IN) _ext.register_adapter(tuple, _ext.SQL_IN)
_ext.register_adapter(type(None), _ext.NoneAdapter) _ext.register_adapter(type(None), _ext.NoneAdapter)
# Register the Decimal adapter here instead of in the C layer. # Register the Decimal adapter here instead of in the C layer.
# This way a new class is registered for each sub-interpreter. # This way a new class is registered for each sub-interpreter.
# See ticket #52 # See ticket #52
try: from decimal import Decimal # noqa
from decimal import Decimal from psycopg2._psycopg import Decimal as Adapter # noqa
except ImportError: _ext.register_adapter(Decimal, Adapter)
pass del Decimal, Adapter
else:
from psycopg2._psycopg import Decimal as Adapter
_ext.register_adapter(Decimal, Adapter)
del Decimal, Adapter
import re
def _param_escape(s,
re_escape=re.compile(r"([\\'])"),
re_space=re.compile(r'\s')):
"""
Apply the escaping rule required by PQconnectdb
"""
if not s: return "''"
s = re_escape.sub(r'\\\1', s)
if re_space.search(s):
s = "'" + s + "'"
return s
del re
def connect(dsn=None, def connect(dsn=None, connection_factory=None, cursor_factory=None, **kwargs):
database=None, user=None, password=None, host=None, port=None,
connection_factory=None, cursor_factory=None, async=False, **kwargs):
""" """
Create a new database connection. Create a new database connection.
The connection parameters can be specified either as a string: The connection parameters can be specified as a string:
conn = psycopg2.connect("dbname=test user=postgres password=secret") conn = psycopg2.connect("dbname=test user=postgres password=secret")
@ -113,9 +89,9 @@ def connect(dsn=None,
conn = psycopg2.connect(database="test", user="postgres", password="secret") conn = psycopg2.connect(database="test", user="postgres", password="secret")
The basic connection parameters are: Or as a mix of both. The basic connection parameters are:
- *dbname*: the database name (only in dsn string) - *dbname*: the database name
- *database*: the database name (only as keyword argument) - *database*: the database name (only as keyword argument)
- *user*: user name used to authenticate - *user*: user name used to authenticate
- *password*: password used to authenticate - *password*: password used to authenticate
@ -129,39 +105,21 @@ def connect(dsn=None,
Using the *cursor_factory* parameter, a new default cursor factory will be Using the *cursor_factory* parameter, a new default cursor factory will be
used by cursor(). used by cursor().
Using *async*=True an asynchronous connection will be created. Using *async*=True an asynchronous connection will be created. *async_* is
a valid alias (for Python versions where ``async`` is a keyword).
Any other keyword parameter will be passed to the underlying client Any other keyword parameter will be passed to the underlying client
library: the list of supported parameters depends on the library version. library: the list of supported parameters depends on the library version.
""" """
items = [] kwasync = {}
if database is not None: if 'async' in kwargs:
items.append(('dbname', database)) kwasync['async'] = kwargs.pop('async')
if user is not None: if 'async_' in kwargs:
items.append(('user', user)) kwasync['async_'] = kwargs.pop('async_')
if password is not None:
items.append(('password', password))
if host is not None:
items.append(('host', host))
if port is not None:
items.append(('port', port))
items.extend([(k, v) for (k, v) in kwargs.iteritems() if v is not None]) dsn = _ext.make_dsn(dsn, **kwargs)
conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
if dsn is not None and items:
raise TypeError(
"'%s' is an invalid keyword argument when the dsn is specified"
% items[0][0])
if dsn is None:
if not items:
raise TypeError('missing dsn and no parameters')
else:
dsn = " ".join(["%s=%s" % (k, _param_escape(str(v)))
for (k, v) in items])
conn = _connect(dsn, connection_factory=connection_factory, async=async)
if cursor_factory is not None: if cursor_factory is not None:
conn.cursor_factory = cursor_factory conn.cursor_factory = cursor_factory

90
lib/_ipaddress.py Normal file
View File

@ -0,0 +1,90 @@
"""Implementation of the ipaddres-based network types adaptation
"""
# psycopg/_ipaddress.py - Ipaddres-based network types adaptation
#
# Copyright (C) 2016-2019 Daniele Varrazzo <daniele.varrazzo@gmail.com>
# Copyright (C) 2020-2021 The Psycopg Team
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# In addition, as a special exception, the copyright holders give
# permission to link this program with the OpenSSL library (or with
# modified versions of OpenSSL that use the same license as OpenSSL),
# and distribute linked combinations including the two.
#
# You must obey the GNU Lesser General Public License in all respects for
# all of the code used other than OpenSSL.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
from psycopg2.extensions import (
new_type, new_array_type, register_type, register_adapter, QuotedString)
# The module is imported on register_ipaddress
ipaddress = None
# The typecasters are created only once
_casters = None
def register_ipaddress(conn_or_curs=None):
"""
Register conversion support between `ipaddress` objects and `network types`__.
:param conn_or_curs: the scope where to register the type casters.
If `!None` register them globally.
After the function is called, PostgreSQL :sql:`inet` values will be
converted into `~ipaddress.IPv4Interface` or `~ipaddress.IPv6Interface`
objects, :sql:`cidr` values into into `~ipaddress.IPv4Network` or
`~ipaddress.IPv6Network`.
.. __: https://www.postgresql.org/docs/current/static/datatype-net-types.html
"""
global ipaddress
import ipaddress
global _casters
if _casters is None:
_casters = _make_casters()
for c in _casters:
register_type(c, conn_or_curs)
for t in [ipaddress.IPv4Interface, ipaddress.IPv6Interface,
ipaddress.IPv4Network, ipaddress.IPv6Network]:
register_adapter(t, adapt_ipaddress)
def _make_casters():
inet = new_type((869,), 'INET', cast_interface)
ainet = new_array_type((1041,), 'INET[]', inet)
cidr = new_type((650,), 'CIDR', cast_network)
acidr = new_array_type((651,), 'CIDR[]', cidr)
return [inet, ainet, cidr, acidr]
def cast_interface(s, cur=None):
if s is None:
return None
# Py2 version force the use of unicode. meh.
return ipaddress.ip_interface(str(s))
def cast_network(s, cur=None):
if s is None:
return None
return ipaddress.ip_network(str(s))
def adapt_ipaddress(obj):
return QuotedString(str(obj))

View File

@ -7,7 +7,8 @@ extensions importing register_json from extras.
# psycopg/_json.py - Implementation of the JSON adaptation objects # psycopg/_json.py - Implementation of the JSON adaptation objects
# #
# Copyright (C) 2012 Daniele Varrazzo <daniele.varrazzo@gmail.com> # Copyright (C) 2012-2019 Daniele Varrazzo <daniele.varrazzo@gmail.com>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -27,47 +28,35 @@ extensions importing register_json from extras.
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details. # License for more details.
import sys import json
from psycopg2._psycopg import ISQLQuote, QuotedString from psycopg2._psycopg import ISQLQuote, QuotedString
from psycopg2._psycopg import new_type, new_array_type, register_type from psycopg2._psycopg import new_type, new_array_type, register_type
# import the best json implementation available
if sys.version_info[:2] >= (2,6):
import json
else:
try:
import simplejson as json
except ImportError:
json = None
# oids from PostgreSQL 9.2 # oids from PostgreSQL 9.2
JSON_OID = 114 JSON_OID = 114
JSONARRAY_OID = 199 JSONARRAY_OID = 199
class Json(object): # oids from PostgreSQL 9.4
JSONB_OID = 3802
JSONBARRAY_OID = 3807
class Json:
""" """
An `~psycopg2.extensions.ISQLQuote` wrapper to adapt a Python object to An `~psycopg2.extensions.ISQLQuote` wrapper to adapt a Python object to
:sql:`json` data type. :sql:`json` data type.
`!Json` can be used to wrap any object supported by the provided *dumps* `!Json` can be used to wrap any object supported by the provided *dumps*
function. If none is provided, the standard :py:func:`json.dumps()` is function. If none is provided, the standard :py:func:`json.dumps()` is
used (`!simplejson` for Python < 2.6; used.
`~psycopg2.extensions.ISQLQuote.getquoted()` will raise `!ImportError` if
the module is not available).
""" """
def __init__(self, adapted, dumps=None): def __init__(self, adapted, dumps=None):
self.adapted = adapted self.adapted = adapted
self._conn = None
if dumps is not None: self._dumps = dumps or json.dumps
self._dumps = dumps
elif json is not None:
self._dumps = json.dumps
else:
self._dumps = None
def __conform__(self, proto): def __conform__(self, proto):
if proto is ISQLQuote: if proto is ISQLQuote:
@ -80,21 +69,25 @@ class Json(object):
provided in the constructor. You can override this method to create a provided in the constructor. You can override this method to create a
customized JSON wrapper. customized JSON wrapper.
""" """
dumps = self._dumps return self._dumps(obj)
if dumps is not None:
return dumps(obj) def prepare(self, conn):
else: self._conn = conn
raise ImportError(
"json module not available: "
"you should provide a dumps function")
def getquoted(self): def getquoted(self):
s = self.dumps(self.adapted) s = self.dumps(self.adapted)
return QuotedString(s).getquoted() qs = QuotedString(s)
if self._conn is not None:
qs.prepare(self._conn)
return qs.getquoted()
def __str__(self):
# getquoted is binary
return self.getquoted().decode('ascii', 'replace')
def register_json(conn_or_curs=None, globally=False, loads=None, def register_json(conn_or_curs=None, globally=False, loads=None,
oid=None, array_oid=None): oid=None, array_oid=None, name='json'):
"""Create and register typecasters converting :sql:`json` type to Python objects. """Create and register typecasters converting :sql:`json` type to Python objects.
:param conn_or_curs: a connection or cursor used to find the :sql:`json` :param conn_or_curs: a connection or cursor used to find the :sql:`json`
@ -110,17 +103,19 @@ def register_json(conn_or_curs=None, globally=False, loads=None,
queried on *conn_or_curs* queried on *conn_or_curs*
:param array_oid: the OID of the :sql:`json[]` array type if known; :param array_oid: the OID of the :sql:`json[]` array type if known;
if not, it will be queried on *conn_or_curs* if not, it will be queried on *conn_or_curs*
:param name: the name of the data type to look for in *conn_or_curs*
The connection or cursor passed to the function will be used to query the The connection or cursor passed to the function will be used to query the
database and look for the OID of the :sql:`json` type. No query is database and look for the OID of the :sql:`json` type (or an alternative
performed if *oid* and *array_oid* are provided. Raise type if *name* if provided). No query is performed if *oid* and *array_oid*
`~psycopg2.ProgrammingError` if the type is not found. are provided. Raise `~psycopg2.ProgrammingError` if the type is not found.
""" """
if oid is None: if oid is None:
oid, array_oid = _get_json_oids(conn_or_curs) oid, array_oid = _get_json_oids(conn_or_curs, name)
JSON, JSONARRAY = _create_json_typecasters(oid, array_oid, loads) JSON, JSONARRAY = _create_json_typecasters(
oid, array_oid, loads=loads, name=name.upper())
register_type(JSON, not globally and conn_or_curs or None) register_type(JSON, not globally and conn_or_curs or None)
@ -129,6 +124,7 @@ def register_json(conn_or_curs=None, globally=False, loads=None,
return JSON, JSONARRAY return JSON, JSONARRAY
def register_default_json(conn_or_curs=None, globally=False, loads=None): def register_default_json(conn_or_curs=None, globally=False, loads=None):
""" """
Create and register :sql:`json` typecasters for PostgreSQL 9.2 and following. Create and register :sql:`json` typecasters for PostgreSQL 9.2 and following.
@ -141,12 +137,23 @@ def register_default_json(conn_or_curs=None, globally=False, loads=None):
return register_json(conn_or_curs=conn_or_curs, globally=globally, return register_json(conn_or_curs=conn_or_curs, globally=globally,
loads=loads, oid=JSON_OID, array_oid=JSONARRAY_OID) loads=loads, oid=JSON_OID, array_oid=JSONARRAY_OID)
def _create_json_typecasters(oid, array_oid, loads=None):
def register_default_jsonb(conn_or_curs=None, globally=False, loads=None):
"""
Create and register :sql:`jsonb` typecasters for PostgreSQL 9.4 and following.
As in `register_default_json()`, the function allows to register a
customized *loads* function for the :sql:`jsonb` type at its known oid for
PostgreSQL 9.4 and following versions. All the parameters have the same
meaning of `register_json()`.
"""
return register_json(conn_or_curs=conn_or_curs, globally=globally,
loads=loads, oid=JSONB_OID, array_oid=JSONBARRAY_OID, name='jsonb')
def _create_json_typecasters(oid, array_oid, loads=None, name='JSON'):
"""Create typecasters for json data type.""" """Create typecasters for json data type."""
if loads is None: if loads is None:
if json is None:
raise ImportError("no json module available")
else:
loads = json.loads loads = json.loads
def typecast_json(s, cur): def typecast_json(s, cur):
@ -154,15 +161,16 @@ def _create_json_typecasters(oid, array_oid, loads=None):
return None return None
return loads(s) return loads(s)
JSON = new_type((oid, ), 'JSON', typecast_json) JSON = new_type((oid, ), name, typecast_json)
if array_oid is not None: if array_oid is not None:
JSONARRAY = new_array_type((array_oid, ), "JSONARRAY", JSON) JSONARRAY = new_array_type((array_oid, ), f"{name}ARRAY", JSON)
else: else:
JSONARRAY = None JSONARRAY = None
return JSON, JSONARRAY return JSON, JSONARRAY
def _get_json_oids(conn_or_curs):
def _get_json_oids(conn_or_curs, name='json'):
# lazy imports # lazy imports
from psycopg2.extensions import STATUS_IN_TRANSACTION from psycopg2.extensions import STATUS_IN_TRANSACTION
from psycopg2.extras import _solve_conn_curs from psycopg2.extras import _solve_conn_curs
@ -173,22 +181,19 @@ def _get_json_oids(conn_or_curs):
conn_status = conn.status conn_status = conn.status
# column typarray not available before PG 8.3 # column typarray not available before PG 8.3
typarray = conn.server_version >= 80300 and "typarray" or "NULL" typarray = conn.info.server_version >= 80300 and "typarray" or "NULL"
# get the oid for the hstore # get the oid for the hstore
curs.execute( curs.execute(
"SELECT t.oid, %s FROM pg_type t WHERE t.typname = 'json';" "SELECT t.oid, %s FROM pg_type t WHERE t.typname = %%s;"
% typarray) % typarray, (name,))
r = curs.fetchone() r = curs.fetchone()
# revert the status of the connection as before the command # revert the status of the connection as before the command
if (conn_status != STATUS_IN_TRANSACTION and not conn.autocommit): if conn_status != STATUS_IN_TRANSACTION and not conn.autocommit:
conn.rollback() conn.rollback()
if not r: if not r:
raise conn.ProgrammingError("json data type not found") raise conn.ProgrammingError(f"{name} data type not found")
return r return r

View File

@ -4,7 +4,8 @@
# psycopg/_range.py - Implementation of the Range type and adaptation # psycopg/_range.py - Implementation of the Range type and adaptation
# #
# Copyright (C) 2012 Daniele Varrazzo <daniele.varrazzo@gmail.com> # Copyright (C) 2012-2019 Daniele Varrazzo <daniele.varrazzo@gmail.com>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -27,10 +28,11 @@
import re import re
from psycopg2._psycopg import ProgrammingError, InterfaceError from psycopg2._psycopg import ProgrammingError, InterfaceError
from psycopg2.extensions import ISQLQuote, adapt, register_adapter, b from psycopg2.extensions import ISQLQuote, adapt, register_adapter
from psycopg2.extensions import new_type, new_array_type, register_type from psycopg2.extensions import new_type, new_array_type, register_type
class Range(object):
class Range:
"""Python representation for a PostgreSQL |range|_ type. """Python representation for a PostgreSQL |range|_ type.
:param lower: lower bound for the range. `!None` means unbound :param lower: lower bound for the range. `!None` means unbound
@ -45,7 +47,7 @@ class Range(object):
def __init__(self, lower=None, upper=None, bounds='[)', empty=False): def __init__(self, lower=None, upper=None, bounds='[)', empty=False):
if not empty: if not empty:
if bounds not in ('[)', '(]', '()', '[]'): if bounds not in ('[)', '(]', '()', '[]'):
raise ValueError("bound flags not valid: %r" % bounds) raise ValueError(f"bound flags not valid: {bounds!r}")
self._lower = lower self._lower = lower
self._upper = upper self._upper = upper
@ -55,11 +57,24 @@ class Range(object):
def __repr__(self): def __repr__(self):
if self._bounds is None: if self._bounds is None:
return "%s(empty=True)" % self.__class__.__name__ return f"{self.__class__.__name__}(empty=True)"
else: else:
return "%s(%r, %r, %r)" % (self.__class__.__name__, return "{}({!r}, {!r}, {!r})".format(self.__class__.__name__,
self._lower, self._upper, self._bounds) self._lower, self._upper, self._bounds)
def __str__(self):
if self._bounds is None:
return 'empty'
items = [
self._bounds[0],
str(self._lower),
', ',
str(self._upper),
self._bounds[1]
]
return ''.join(items)
@property @property
def lower(self): def lower(self):
"""The lower bound of the range. `!None` if empty or unbound.""" """The lower bound of the range. `!None` if empty or unbound."""
@ -78,49 +93,59 @@ class Range(object):
@property @property
def lower_inf(self): def lower_inf(self):
"""`!True` if the range doesn't have a lower bound.""" """`!True` if the range doesn't have a lower bound."""
if self._bounds is None: return False if self._bounds is None:
return False
return self._lower is None return self._lower is None
@property @property
def upper_inf(self): def upper_inf(self):
"""`!True` if the range doesn't have an upper bound.""" """`!True` if the range doesn't have an upper bound."""
if self._bounds is None: return False if self._bounds is None:
return False
return self._upper is None return self._upper is None
@property @property
def lower_inc(self): def lower_inc(self):
"""`!True` if the lower bound is included in the range.""" """`!True` if the lower bound is included in the range."""
if self._bounds is None: return False if self._bounds is None or self._lower is None:
if self._lower is None: return False return False
return self._bounds[0] == '[' return self._bounds[0] == '['
@property @property
def upper_inc(self): def upper_inc(self):
"""`!True` if the upper bound is included in the range.""" """`!True` if the upper bound is included in the range."""
if self._bounds is None: return False if self._bounds is None or self._upper is None:
if self._upper is None: return False return False
return self._bounds[1] == ']' return self._bounds[1] == ']'
def __contains__(self, x): def __contains__(self, x):
if self._bounds is None: return False if self._bounds is None:
return False
if self._lower is not None: if self._lower is not None:
if self._bounds[0] == '[': if self._bounds[0] == '[':
if x < self._lower: return False if x < self._lower:
return False
else: else:
if x <= self._lower: return False if x <= self._lower:
return False
if self._upper is not None: if self._upper is not None:
if self._bounds[1] == ']': if self._bounds[1] == ']':
if x > self._upper: return False if x > self._upper:
return False
else: else:
if x >= self._upper: return False if x >= self._upper:
return False
return True return True
def __nonzero__(self): def __bool__(self):
return self._bounds is not None return self._bounds is not None
def __eq__(self, other): def __eq__(self, other):
if not isinstance(other, Range):
return False
return (self._lower == other._lower return (self._lower == other._lower
and self._upper == other._upper and self._upper == other._upper
and self._bounds == other._bounds) and self._bounds == other._bounds)
@ -131,12 +156,51 @@ class Range(object):
def __hash__(self): def __hash__(self):
return hash((self._lower, self._upper, self._bounds)) return hash((self._lower, self._upper, self._bounds))
def __lt__(self, other): # as the postgres docs describe for the server-side stuff,
raise TypeError( # ordering is rather arbitrary, but will remain stable
'Range objects cannot be ordered; please refer to the PostgreSQL' # and consistent.
' documentation to perform this operation in the database')
__le__ = __gt__ = __ge__ = __lt__ def __lt__(self, other):
if not isinstance(other, Range):
return NotImplemented
for attr in ('_lower', '_upper', '_bounds'):
self_value = getattr(self, attr)
other_value = getattr(other, attr)
if self_value == other_value:
pass
elif self_value is None:
return True
elif other_value is None:
return False
else:
return self_value < other_value
return False
def __le__(self, other):
if self == other:
return True
else:
return self.__lt__(other)
def __gt__(self, other):
if isinstance(other, Range):
return other.__lt__(self)
else:
return NotImplemented
def __ge__(self, other):
if self == other:
return True
else:
return self.__gt__(other)
def __getstate__(self):
return {slot: getattr(self, slot)
for slot in self.__slots__ if hasattr(self, slot)}
def __setstate__(self, state):
for slot, value in state.items():
setattr(self, slot, value)
def register_range(pgrange, pyrange, conn_or_curs, globally=False): def register_range(pgrange, pyrange, conn_or_curs, globally=False):
@ -170,7 +234,7 @@ def register_range(pgrange, pyrange, conn_or_curs, globally=False):
return caster return caster
class RangeAdapter(object): class RangeAdapter:
"""`ISQLQuote` adapter for `Range` subclasses. """`ISQLQuote` adapter for `Range` subclasses.
This is an abstract class: concrete classes must set a `name` class This is an abstract class: concrete classes must set a `name` class
@ -196,7 +260,7 @@ class RangeAdapter(object):
r = self.adapted r = self.adapted
if r.isempty: if r.isempty:
return b("'empty'::" + self.name) return b"'empty'::" + self.name.encode('utf8')
if r.lower is not None: if r.lower is not None:
a = adapt(r.lower) a = adapt(r.lower)
@ -204,7 +268,7 @@ class RangeAdapter(object):
a.prepare(self._conn) a.prepare(self._conn)
lower = a.getquoted() lower = a.getquoted()
else: else:
lower = b('NULL') lower = b'NULL'
if r.upper is not None: if r.upper is not None:
a = adapt(r.upper) a = adapt(r.upper)
@ -212,13 +276,13 @@ class RangeAdapter(object):
a.prepare(self._conn) a.prepare(self._conn)
upper = a.getquoted() upper = a.getquoted()
else: else:
upper = b('NULL') upper = b'NULL'
return b(self.name + '(') + lower + b(', ') + upper \ return self.name.encode('utf8') + b'(' + lower + b', ' + upper \
+ b(", '%s')" % r._bounds) + b", '" + r._bounds.encode('utf8') + b"')"
class RangeCaster(object): class RangeCaster:
"""Helper class to convert between `Range` and PostgreSQL range types. """Helper class to convert between `Range` and PostgreSQL range types.
Objects of this class are usually created by `register_range()`. Manual Objects of this class are usually created by `register_range()`. Manual
@ -246,12 +310,13 @@ class RangeCaster(object):
# an implementation detail and is not documented. It is currently used # an implementation detail and is not documented. It is currently used
# for the numeric ranges. # for the numeric ranges.
self.adapter = None self.adapter = None
if isinstance(pgrange, basestring): if isinstance(pgrange, str):
self.adapter = type(pgrange, (RangeAdapter,), {}) self.adapter = type(pgrange, (RangeAdapter,), {})
self.adapter.name = pgrange self.adapter.name = pgrange
else: else:
try: try:
if issubclass(pgrange, RangeAdapter) and pgrange is not RangeAdapter: if issubclass(pgrange, RangeAdapter) \
and pgrange is not RangeAdapter:
self.adapter = pgrange self.adapter = pgrange
except TypeError: except TypeError:
pass pass
@ -262,7 +327,7 @@ class RangeCaster(object):
self.range = None self.range = None
try: try:
if isinstance(pyrange, basestring): if isinstance(pyrange, str):
self.range = type(pyrange, (Range,), {}) self.range = type(pyrange, (Range,), {})
if issubclass(pyrange, Range) and pyrange is not Range: if issubclass(pyrange, Range) and pyrange is not Range:
self.range = pyrange self.range = pyrange
@ -283,9 +348,9 @@ class RangeCaster(object):
from psycopg2.extras import _solve_conn_curs from psycopg2.extras import _solve_conn_curs
conn, curs = _solve_conn_curs(conn_or_curs) conn, curs = _solve_conn_curs(conn_or_curs)
if conn.server_version < 90200: if conn.info.server_version < 90200:
raise ProgrammingError("range types not available in version %s" raise ProgrammingError("range types not available in version %s"
% conn.server_version) % conn.info.server_version)
# Store the transaction status of the connection to revert it after use # Store the transaction status of the connection to revert it after use
conn_status = conn.status conn_status = conn.status
@ -298,33 +363,54 @@ class RangeCaster(object):
schema = 'public' schema = 'public'
# get the type oid and attributes # get the type oid and attributes
try:
curs.execute("""\ curs.execute("""\
select rngtypid, rngsubtype, select rngtypid, rngsubtype, typarray
(select typarray from pg_type where oid = rngtypid)
from pg_range r from pg_range r
join pg_type t on t.oid = rngtypid join pg_type t on t.oid = rngtypid
join pg_namespace ns on ns.oid = typnamespace join pg_namespace ns on ns.oid = typnamespace
where typname = %s and ns.nspname = %s; where typname = %s and ns.nspname = %s;
""", (tname, schema)) """, (tname, schema))
except ProgrammingError:
if not conn.autocommit:
conn.rollback()
raise
else:
rec = curs.fetchone() rec = curs.fetchone()
if not rec:
# The above algorithm doesn't work for customized seach_path
# (#1487) The implementation below works better, but, to guarantee
# backwards compatibility, use it only if the original one failed.
try:
savepoint = False
# Because we executed statements earlier, we are either INTRANS
# or we are IDLE only if the transaction is autocommit, in
# which case we don't need the savepoint anyway.
if conn.status == STATUS_IN_TRANSACTION:
curs.execute("SAVEPOINT register_type")
savepoint = True
curs.execute("""\
SELECT rngtypid, rngsubtype, typarray, typname, nspname
from pg_range r
join pg_type t on t.oid = rngtypid
join pg_namespace ns on ns.oid = typnamespace
WHERE t.oid = %s::regtype
""", (name, ))
except ProgrammingError:
pass
else:
rec = curs.fetchone()
if rec:
tname, schema = rec[3:]
finally:
if savepoint:
curs.execute("ROLLBACK TO SAVEPOINT register_type")
# revert the status of the connection as before the command # revert the status of the connection as before the command
if (conn_status != STATUS_IN_TRANSACTION if conn_status != STATUS_IN_TRANSACTION and not conn.autocommit:
and not conn.autocommit):
conn.rollback() conn.rollback()
if not rec: if not rec:
raise ProgrammingError( raise ProgrammingError(
"PostgreSQL type '%s' not found" % name) f"PostgreSQL range '{name}' not found")
type, subtype, array = rec type, subtype, array = rec[:3]
return RangeCaster(name, pyrange, return RangeCaster(name, pyrange,
oid=type, subtype_oid=subtype, array_oid=array) oid=type, subtype_oid=subtype, array_oid=array)
@ -354,7 +440,7 @@ where typname = %s and ns.nspname = %s;
m = self._re_range.match(s) m = self._re_range.match(s)
if m is None: if m is None:
raise InterfaceError("failed to parse range: %s") raise InterfaceError(f"failed to parse range: '{s}'")
lower = m.group(3) lower = m.group(3)
if lower is None: if lower is None:
@ -392,14 +478,17 @@ class NumericRange(Range):
""" """
pass pass
class DateRange(Range): class DateRange(Range):
"""Represents :sql:`daterange` values.""" """Represents :sql:`daterange` values."""
pass pass
class DateTimeRange(Range): class DateTimeRange(Range):
"""Represents :sql:`tsrange` values.""" """Represents :sql:`tsrange` values."""
pass pass
class DateTimeTZRange(Range): class DateTimeTZRange(Range):
"""Represents :sql:`tstzrange` values.""" """Represents :sql:`tstzrange` values."""
pass pass
@ -415,7 +504,7 @@ class NumberRangeAdapter(RangeAdapter):
def getquoted(self): def getquoted(self):
r = self.adapted r = self.adapted
if r.isempty: if r.isempty:
return "'empty'" return b"'empty'"
if not r.lower_inf: if not r.lower_inf:
# not exactly: we are relying that none of these object is really # not exactly: we are relying that none of these object is really
@ -431,13 +520,12 @@ class NumberRangeAdapter(RangeAdapter):
else: else:
upper = '' upper = ''
return b("'%s%s,%s%s'" % ( return (f"'{r._bounds[0]}{lower},{upper}{r._bounds[1]}'").encode('ascii')
r._bounds[0], lower, upper, r._bounds[1]))
# TODO: probably won't work with infs, nans and other tricky cases. # TODO: probably won't work with infs, nans and other tricky cases.
register_adapter(NumericRange, NumberRangeAdapter) register_adapter(NumericRange, NumberRangeAdapter)
# Register globally typecasters and adapters for builtin range types. # Register globally typecasters and adapters for builtin range types.
# note: the adapter is registered more than once, but this is harmless. # note: the adapter is registered more than once, but this is harmless.
@ -464,5 +552,3 @@ tsrange_caster._register()
tstzrange_caster = RangeCaster('tstzrange', DateTimeTZRange, tstzrange_caster = RangeCaster('tstzrange', DateTimeTZRange,
oid=3910, subtype_oid=1184, array_oid=3911) oid=3910, subtype_oid=1184, array_oid=3911)
tstzrange_caster._register() tstzrange_caster._register()

View File

@ -1,10 +1,11 @@
"""Error codes for PostgresSQL """Error codes for PostgreSQL
This module contains symbolic names for all PostgreSQL error codes. This module contains symbolic names for all PostgreSQL error codes.
""" """
# psycopg2/errorcodes.py - PostgreSQL error codes # psycopg2/errorcodes.py - PostgreSQL error codes
# #
# Copyright (C) 2006-2010 Johan Dahlin <jdahlin@async.com.br> # Copyright (C) 2006-2019 Johan Dahlin <jdahlin@async.com.br>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -26,9 +27,10 @@ This module contains symbolic names for all PostgreSQL error codes.
# #
# Based on: # Based on:
# #
# http://www.postgresql.org/docs/current/static/errcodes-appendix.html # https://www.postgresql.org/docs/current/static/errcodes-appendix.html
# #
def lookup(code, _cache={}): def lookup(code, _cache={}):
"""Lookup an error code or class code and return its symbolic name. """Lookup an error code or class code and return its symbolic name.
@ -38,11 +40,18 @@ def lookup(code, _cache={}):
return _cache[code] return _cache[code]
# Generate the lookup map at first usage. # Generate the lookup map at first usage.
for k, v in globals().iteritems(): tmp = {}
for k, v in globals().items():
if isinstance(v, str) and len(v) in (2, 5): if isinstance(v, str) and len(v) in (2, 5):
_cache[v] = k # Strip trailing underscore used to disambiguate duplicate values
tmp[v] = k.rstrip("_")
return lookup(code) assert tmp
# Atomic update, to avoid race condition on import (bug #382)
_cache.update(tmp)
return _cache[code]
# autogenerated data: do not edit below this point. # autogenerated data: do not edit below this point.
@ -86,6 +95,7 @@ CLASS_PROGRAM_LIMIT_EXCEEDED = '54'
CLASS_OBJECT_NOT_IN_PREREQUISITE_STATE = '55' CLASS_OBJECT_NOT_IN_PREREQUISITE_STATE = '55'
CLASS_OPERATOR_INTERVENTION = '57' CLASS_OPERATOR_INTERVENTION = '57'
CLASS_SYSTEM_ERROR = '58' CLASS_SYSTEM_ERROR = '58'
CLASS_SNAPSHOT_FAILURE = '72'
CLASS_CONFIGURATION_FILE_ERROR = 'F0' CLASS_CONFIGURATION_FILE_ERROR = 'F0'
CLASS_FOREIGN_DATA_WRAPPER_ERROR = 'HV' CLASS_FOREIGN_DATA_WRAPPER_ERROR = 'HV'
CLASS_PL_PGSQL_ERROR = 'P0' CLASS_PL_PGSQL_ERROR = 'P0'
@ -97,7 +107,7 @@ SUCCESSFUL_COMPLETION = '00000'
# Class 01 - Warning # Class 01 - Warning
WARNING = '01000' WARNING = '01000'
NULL_VALUE_ELIMINATED_IN_SET_FUNCTION = '01003' NULL_VALUE_ELIMINATED_IN_SET_FUNCTION = '01003'
STRING_DATA_RIGHT_TRUNCATION = '01004' STRING_DATA_RIGHT_TRUNCATION_ = '01004'
PRIVILEGE_NOT_REVOKED = '01006' PRIVILEGE_NOT_REVOKED = '01006'
PRIVILEGE_NOT_GRANTED = '01007' PRIVILEGE_NOT_GRANTED = '01007'
IMPLICIT_ZERO_BIT_PADDING = '01008' IMPLICIT_ZERO_BIT_PADDING = '01008'
@ -155,7 +165,7 @@ DATA_EXCEPTION = '22000'
STRING_DATA_RIGHT_TRUNCATION = '22001' STRING_DATA_RIGHT_TRUNCATION = '22001'
NULL_VALUE_NO_INDICATOR_PARAMETER = '22002' NULL_VALUE_NO_INDICATOR_PARAMETER = '22002'
NUMERIC_VALUE_OUT_OF_RANGE = '22003' NUMERIC_VALUE_OUT_OF_RANGE = '22003'
NULL_VALUE_NOT_ALLOWED = '22004' NULL_VALUE_NOT_ALLOWED_ = '22004'
ERROR_IN_ASSIGNMENT = '22005' ERROR_IN_ASSIGNMENT = '22005'
INVALID_DATETIME_FORMAT = '22007' INVALID_DATETIME_FORMAT = '22007'
DATETIME_FIELD_OVERFLOW = '22008' DATETIME_FIELD_OVERFLOW = '22008'
@ -165,6 +175,7 @@ INVALID_USE_OF_ESCAPE_CHARACTER = '2200C'
INVALID_ESCAPE_OCTET = '2200D' INVALID_ESCAPE_OCTET = '2200D'
ZERO_LENGTH_CHARACTER_STRING = '2200F' ZERO_LENGTH_CHARACTER_STRING = '2200F'
MOST_SPECIFIC_TYPE_MISMATCH = '2200G' MOST_SPECIFIC_TYPE_MISMATCH = '2200G'
SEQUENCE_GENERATOR_LIMIT_EXCEEDED = '2200H'
NOT_AN_XML_DOCUMENT = '2200L' NOT_AN_XML_DOCUMENT = '2200L'
INVALID_XML_DOCUMENT = '2200M' INVALID_XML_DOCUMENT = '2200M'
INVALID_XML_CONTENT = '2200N' INVALID_XML_CONTENT = '2200N'
@ -173,6 +184,7 @@ INVALID_XML_PROCESSING_INSTRUCTION = '2200T'
INVALID_INDICATOR_PARAMETER_VALUE = '22010' INVALID_INDICATOR_PARAMETER_VALUE = '22010'
SUBSTRING_ERROR = '22011' SUBSTRING_ERROR = '22011'
DIVISION_BY_ZERO = '22012' DIVISION_BY_ZERO = '22012'
INVALID_PRECEDING_OR_FOLLOWING_SIZE = '22013'
INVALID_ARGUMENT_FOR_NTILE_FUNCTION = '22014' INVALID_ARGUMENT_FOR_NTILE_FUNCTION = '22014'
INTERVAL_FIELD_OVERFLOW = '22015' INTERVAL_FIELD_OVERFLOW = '22015'
INVALID_ARGUMENT_FOR_NTH_VALUE_FUNCTION = '22016' INVALID_ARGUMENT_FOR_NTH_VALUE_FUNCTION = '22016'
@ -193,6 +205,25 @@ INVALID_ESCAPE_SEQUENCE = '22025'
STRING_DATA_LENGTH_MISMATCH = '22026' STRING_DATA_LENGTH_MISMATCH = '22026'
TRIM_ERROR = '22027' TRIM_ERROR = '22027'
ARRAY_SUBSCRIPT_ERROR = '2202E' ARRAY_SUBSCRIPT_ERROR = '2202E'
INVALID_TABLESAMPLE_REPEAT = '2202G'
INVALID_TABLESAMPLE_ARGUMENT = '2202H'
DUPLICATE_JSON_OBJECT_KEY_VALUE = '22030'
INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION = '22031'
INVALID_JSON_TEXT = '22032'
INVALID_SQL_JSON_SUBSCRIPT = '22033'
MORE_THAN_ONE_SQL_JSON_ITEM = '22034'
NO_SQL_JSON_ITEM = '22035'
NON_NUMERIC_SQL_JSON_ITEM = '22036'
NON_UNIQUE_KEYS_IN_A_JSON_OBJECT = '22037'
SINGLETON_SQL_JSON_ITEM_REQUIRED = '22038'
SQL_JSON_ARRAY_NOT_FOUND = '22039'
SQL_JSON_MEMBER_NOT_FOUND = '2203A'
SQL_JSON_NUMBER_NOT_FOUND = '2203B'
SQL_JSON_OBJECT_NOT_FOUND = '2203C'
TOO_MANY_JSON_ARRAY_ELEMENTS = '2203D'
TOO_MANY_JSON_OBJECT_MEMBERS = '2203E'
SQL_JSON_SCALAR_REQUIRED = '2203F'
SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE = '2203G'
FLOATING_POINT_EXCEPTION = '22P01' FLOATING_POINT_EXCEPTION = '22P01'
INVALID_TEXT_REPRESENTATION = '22P02' INVALID_TEXT_REPRESENTATION = '22P02'
INVALID_BINARY_REPRESENTATION = '22P03' INVALID_BINARY_REPRESENTATION = '22P03'
@ -224,6 +255,8 @@ SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED = '25007'
HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL = '25008' HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL = '25008'
NO_ACTIVE_SQL_TRANSACTION = '25P01' NO_ACTIVE_SQL_TRANSACTION = '25P01'
IN_FAILED_SQL_TRANSACTION = '25P02' IN_FAILED_SQL_TRANSACTION = '25P02'
IDLE_IN_TRANSACTION_SESSION_TIMEOUT = '25P03'
TRANSACTION_TIMEOUT = '25P04'
# Class 26 - Invalid SQL Statement Name # Class 26 - Invalid SQL Statement Name
INVALID_SQL_STATEMENT_NAME = '26000' INVALID_SQL_STATEMENT_NAME = '26000'
@ -244,9 +277,9 @@ INVALID_TRANSACTION_TERMINATION = '2D000'
# Class 2F - SQL Routine Exception # Class 2F - SQL Routine Exception
SQL_ROUTINE_EXCEPTION = '2F000' SQL_ROUTINE_EXCEPTION = '2F000'
MODIFYING_SQL_DATA_NOT_PERMITTED = '2F002' MODIFYING_SQL_DATA_NOT_PERMITTED_ = '2F002'
PROHIBITED_SQL_STATEMENT_ATTEMPTED = '2F003' PROHIBITED_SQL_STATEMENT_ATTEMPTED_ = '2F003'
READING_SQL_DATA_NOT_PERMITTED = '2F004' READING_SQL_DATA_NOT_PERMITTED_ = '2F004'
FUNCTION_EXECUTED_NO_RETURN_STATEMENT = '2F005' FUNCTION_EXECUTED_NO_RETURN_STATEMENT = '2F005'
# Class 34 - Invalid Cursor Name # Class 34 - Invalid Cursor Name
@ -265,6 +298,7 @@ INVALID_SQLSTATE_RETURNED = '39001'
NULL_VALUE_NOT_ALLOWED = '39004' NULL_VALUE_NOT_ALLOWED = '39004'
TRIGGER_PROTOCOL_VIOLATED = '39P01' TRIGGER_PROTOCOL_VIOLATED = '39P01'
SRF_PROTOCOL_VIOLATED = '39P02' SRF_PROTOCOL_VIOLATED = '39P02'
EVENT_TRIGGER_PROTOCOL_VIOLATED = '39P03'
# Class 3B - Savepoint Exception # Class 3B - Savepoint Exception
SAVEPOINT_EXCEPTION = '3B000' SAVEPOINT_EXCEPTION = '3B000'
@ -304,6 +338,7 @@ WRONG_OBJECT_TYPE = '42809'
INVALID_FOREIGN_KEY = '42830' INVALID_FOREIGN_KEY = '42830'
CANNOT_COERCE = '42846' CANNOT_COERCE = '42846'
UNDEFINED_FUNCTION = '42883' UNDEFINED_FUNCTION = '42883'
GENERATED_ALWAYS = '428C9'
RESERVED_NAME = '42939' RESERVED_NAME = '42939'
UNDEFINED_TABLE = '42P01' UNDEFINED_TABLE = '42P01'
UNDEFINED_PARAMETER = '42P02' UNDEFINED_PARAMETER = '42P02'
@ -349,6 +384,7 @@ OBJECT_NOT_IN_PREREQUISITE_STATE = '55000'
OBJECT_IN_USE = '55006' OBJECT_IN_USE = '55006'
CANT_CHANGE_RUNTIME_PARAM = '55P02' CANT_CHANGE_RUNTIME_PARAM = '55P02'
LOCK_NOT_AVAILABLE = '55P03' LOCK_NOT_AVAILABLE = '55P03'
UNSAFE_NEW_ENUM_VALUE_USAGE = '55P04'
# Class 57 - Operator Intervention # Class 57 - Operator Intervention
OPERATOR_INTERVENTION = '57000' OPERATOR_INTERVENTION = '57000'
@ -357,6 +393,7 @@ ADMIN_SHUTDOWN = '57P01'
CRASH_SHUTDOWN = '57P02' CRASH_SHUTDOWN = '57P02'
CANNOT_CONNECT_NOW = '57P03' CANNOT_CONNECT_NOW = '57P03'
DATABASE_DROPPED = '57P04' DATABASE_DROPPED = '57P04'
IDLE_SESSION_TIMEOUT = '57P05'
# Class 58 - System Error (errors external to PostgreSQL itself) # Class 58 - System Error (errors external to PostgreSQL itself)
SYSTEM_ERROR = '58000' SYSTEM_ERROR = '58000'
@ -364,6 +401,9 @@ IO_ERROR = '58030'
UNDEFINED_FILE = '58P01' UNDEFINED_FILE = '58P01'
DUPLICATE_FILE = '58P02' DUPLICATE_FILE = '58P02'
# Class 72 - Snapshot Failure
SNAPSHOT_TOO_OLD = '72000'
# Class F0 - Configuration File Error # Class F0 - Configuration File Error
CONFIG_FILE_ERROR = 'F0000' CONFIG_FILE_ERROR = 'F0000'
LOCK_FILE_EXISTS = 'F0001' LOCK_FILE_EXISTS = 'F0001'
@ -402,6 +442,7 @@ PLPGSQL_ERROR = 'P0000'
RAISE_EXCEPTION = 'P0001' RAISE_EXCEPTION = 'P0001'
NO_DATA_FOUND = 'P0002' NO_DATA_FOUND = 'P0002'
TOO_MANY_ROWS = 'P0003' TOO_MANY_ROWS = 'P0003'
ASSERT_FAILURE = 'P0004'
# Class XX - Internal Error # Class XX - Internal Error
INTERNAL_ERROR = 'XX000' INTERNAL_ERROR = 'XX000'

38
lib/errors.py Normal file
View File

@ -0,0 +1,38 @@
"""Error classes for PostgreSQL error codes
"""
# psycopg/errors.py - SQLSTATE and DB-API exceptions
#
# Copyright (C) 2018-2019 Daniele Varrazzo <daniele.varrazzo@gmail.com>
# Copyright (C) 2020-2021 The Psycopg Team
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# In addition, as a special exception, the copyright holders give
# permission to link this program with the OpenSSL library (or with
# modified versions of OpenSSL that use the same license as OpenSSL),
# and distribute linked combinations including the two.
#
# You must obey the GNU Lesser General Public License in all respects for
# all of the code used other than OpenSSL.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
#
# NOTE: the exceptions are injected into this module by the C extention.
#
def lookup(code):
"""Lookup an error code and return its exception class.
Raise `!KeyError` if the code is not found.
"""
from psycopg2._psycopg import sqlstate_errors # avoid circular import
return sqlstate_errors[code]

View File

@ -8,11 +8,12 @@ This module holds all the extensions to the DBAPI-2.0 provided by psycopg.
- `adapt()` -- exposes the PEP-246_ compatible adapting mechanism used - `adapt()` -- exposes the PEP-246_ compatible adapting mechanism used
by psycopg to adapt Python types to PostgreSQL ones by psycopg to adapt Python types to PostgreSQL ones
.. _PEP-246: http://www.python.org/peps/pep-0246.html .. _PEP-246: https://www.python.org/dev/peps/pep-0246/
""" """
# psycopg/extensions.py - DBAPI-2.0 extensions specific to psycopg # psycopg/extensions.py - DBAPI-2.0 extensions specific to psycopg
# #
# Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> # Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -32,40 +33,28 @@ This module holds all the extensions to the DBAPI-2.0 provided by psycopg.
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details. # License for more details.
from psycopg2._psycopg import UNICODE, INTEGER, LONGINTEGER, BOOLEAN, FLOAT import re as _re
from psycopg2._psycopg import TIME, DATE, INTERVAL, DECIMAL
from psycopg2._psycopg import BINARYARRAY, BOOLEANARRAY, DATEARRAY, DATETIMEARRAY
from psycopg2._psycopg import DECIMALARRAY, FLOATARRAY, INTEGERARRAY, INTERVALARRAY
from psycopg2._psycopg import LONGINTEGERARRAY, ROWIDARRAY, STRINGARRAY, TIMEARRAY
from psycopg2._psycopg import UNICODEARRAY
from psycopg2._psycopg import Binary, Boolean, Int, Float, QuotedString, AsIs from psycopg2._psycopg import ( # noqa
try: BINARYARRAY, BOOLEAN, BOOLEANARRAY, BYTES, BYTESARRAY, DATE, DATEARRAY,
from psycopg2._psycopg import MXDATE, MXDATETIME, MXINTERVAL, MXTIME DATETIMEARRAY, DECIMAL, DECIMALARRAY, FLOAT, FLOATARRAY, INTEGER,
from psycopg2._psycopg import MXDATEARRAY, MXDATETIMEARRAY, MXINTERVALARRAY, MXTIMEARRAY INTEGERARRAY, INTERVAL, INTERVALARRAY, LONGINTEGER, LONGINTEGERARRAY,
from psycopg2._psycopg import DateFromMx, TimeFromMx, TimestampFromMx ROWIDARRAY, STRINGARRAY, TIME, TIMEARRAY, UNICODE, UNICODEARRAY,
from psycopg2._psycopg import IntervalFromMx AsIs, Binary, Boolean, Float, Int, QuotedString, )
except ImportError:
pass
try: from psycopg2._psycopg import ( # noqa
from psycopg2._psycopg import PYDATE, PYDATETIME, PYINTERVAL, PYTIME PYDATE, PYDATETIME, PYDATETIMETZ, PYINTERVAL, PYTIME, PYDATEARRAY,
from psycopg2._psycopg import PYDATEARRAY, PYDATETIMEARRAY, PYINTERVALARRAY, PYTIMEARRAY PYDATETIMEARRAY, PYDATETIMETZARRAY, PYINTERVALARRAY, PYTIMEARRAY,
from psycopg2._psycopg import DateFromPy, TimeFromPy, TimestampFromPy DateFromPy, TimeFromPy, TimestampFromPy, IntervalFromPy, )
from psycopg2._psycopg import IntervalFromPy
except ImportError:
pass
from psycopg2._psycopg import adapt, adapters, encodings, connection, cursor, lobject, Xid from psycopg2._psycopg import ( # noqa
from psycopg2._psycopg import string_types, binary_types, new_type, new_array_type, register_type adapt, adapters, encodings, connection, cursor,
from psycopg2._psycopg import ISQLQuote, Notify, Diagnostics lobject, Xid, libpq_version, parse_dsn, quote_ident,
string_types, binary_types, new_type, new_array_type, register_type,
ISQLQuote, Notify, Diagnostics, Column, ConnectionInfo,
QueryCanceledError, TransactionRollbackError,
set_wait_callback, get_wait_callback, encrypt_password, )
from psycopg2._psycopg import QueryCanceledError, TransactionRollbackError
try:
from psycopg2._psycopg import set_wait_callback, get_wait_callback
except ImportError:
pass
"""Isolation level values.""" """Isolation level values."""
ISOLATION_LEVEL_AUTOCOMMIT = 0 ISOLATION_LEVEL_AUTOCOMMIT = 0
@ -73,6 +62,8 @@ ISOLATION_LEVEL_READ_UNCOMMITTED = 4
ISOLATION_LEVEL_READ_COMMITTED = 1 ISOLATION_LEVEL_READ_COMMITTED = 1
ISOLATION_LEVEL_REPEATABLE_READ = 2 ISOLATION_LEVEL_REPEATABLE_READ = 2
ISOLATION_LEVEL_SERIALIZABLE = 3 ISOLATION_LEVEL_SERIALIZABLE = 3
ISOLATION_LEVEL_DEFAULT = None
"""psycopg connection status values.""" """psycopg connection status values."""
STATUS_SETUP = 0 STATUS_SETUP = 0
@ -82,15 +73,17 @@ STATUS_SYNC = 3 # currently unused
STATUS_ASYNC = 4 # currently unused STATUS_ASYNC = 4 # currently unused
STATUS_PREPARED = 5 STATUS_PREPARED = 5
# This is a usefull mnemonic to check if the connection is in a transaction # This is a useful mnemonic to check if the connection is in a transaction
STATUS_IN_TRANSACTION = STATUS_BEGIN STATUS_IN_TRANSACTION = STATUS_BEGIN
"""psycopg asynchronous connection polling values""" """psycopg asynchronous connection polling values"""
POLL_OK = 0 POLL_OK = 0
POLL_READ = 1 POLL_READ = 1
POLL_WRITE = 2 POLL_WRITE = 2
POLL_ERROR = 3 POLL_ERROR = 3
"""Backend transaction status values.""" """Backend transaction status values."""
TRANSACTION_STATUS_IDLE = 0 TRANSACTION_STATUS_IDLE = 0
TRANSACTION_STATUS_ACTIVE = 1 TRANSACTION_STATUS_ACTIVE = 1
@ -98,15 +91,6 @@ TRANSACTION_STATUS_INTRANS = 2
TRANSACTION_STATUS_INERROR = 3 TRANSACTION_STATUS_INERROR = 3
TRANSACTION_STATUS_UNKNOWN = 4 TRANSACTION_STATUS_UNKNOWN = 4
import sys as _sys
# Return bytes from a string
if _sys.version_info[0] < 3:
def b(s):
return s
else:
def b(s):
return s.encode('utf8')
def register_adapter(typ, callable): def register_adapter(typ, callable):
"""Register 'callable' as an ISQLQuote adapter for type 'typ'.""" """Register 'callable' as an ISQLQuote adapter for type 'typ'."""
@ -114,7 +98,7 @@ def register_adapter(typ, callable):
# The SQL_IN class is the official adapter for tuples starting from 2.0.6. # The SQL_IN class is the official adapter for tuples starting from 2.0.6.
class SQL_IN(object): class SQL_IN:
"""Adapt any iterable to an SQL quotable object.""" """Adapt any iterable to an SQL quotable object."""
def __init__(self, seq): def __init__(self, seq):
self._seq = seq self._seq = seq
@ -132,13 +116,13 @@ class SQL_IN(object):
if hasattr(obj, 'prepare'): if hasattr(obj, 'prepare'):
obj.prepare(self._conn) obj.prepare(self._conn)
qobjs = [o.getquoted() for o in pobjs] qobjs = [o.getquoted() for o in pobjs]
return b('(') + b(', ').join(qobjs) + b(')') return b'(' + b', '.join(qobjs) + b')'
def __str__(self): def __str__(self):
return str(self.getquoted()) return str(self.getquoted())
class NoneAdapter(object): class NoneAdapter:
"""Adapt None to NULL. """Adapt None to NULL.
This adapter is not used normally as a fast path in mogrify uses NULL, This adapter is not used normally as a fast path in mogrify uses NULL,
@ -147,30 +131,82 @@ class NoneAdapter(object):
def __init__(self, obj): def __init__(self, obj):
pass pass
def getquoted(self, _null=b("NULL")): def getquoted(self, _null=b"NULL"):
return _null return _null
def make_dsn(dsn=None, **kwargs):
"""Convert a set of keywords into a connection strings."""
if dsn is None and not kwargs:
return ''
# If no kwarg is specified don't mung the dsn, but verify it
if not kwargs:
parse_dsn(dsn)
return dsn
# Override the dsn with the parameters
if 'database' in kwargs:
if 'dbname' in kwargs:
raise TypeError(
"you can't specify both 'database' and 'dbname' arguments")
kwargs['dbname'] = kwargs.pop('database')
# Drop the None arguments
kwargs = {k: v for (k, v) in kwargs.items() if v is not None}
if dsn is not None:
tmp = parse_dsn(dsn)
tmp.update(kwargs)
kwargs = tmp
dsn = " ".join(["{}={}".format(k, _param_escape(str(v)))
for (k, v) in kwargs.items()])
# verify that the returned dsn is valid
parse_dsn(dsn)
return dsn
def _param_escape(s,
re_escape=_re.compile(r"([\\'])"),
re_space=_re.compile(r'\s')):
"""
Apply the escaping rule required by PQconnectdb
"""
if not s:
return "''"
s = re_escape.sub(r'\\\1', s)
if re_space.search(s):
s = "'" + s + "'"
return s
# Create default json typecasters for PostgreSQL 9.2 oids # Create default json typecasters for PostgreSQL 9.2 oids
from psycopg2._json import register_default_json from psycopg2._json import register_default_json, register_default_jsonb # noqa
try: try:
JSON, JSONARRAY = register_default_json() JSON, JSONARRAY = register_default_json()
JSONB, JSONBARRAY = register_default_jsonb()
except ImportError: except ImportError:
pass pass
del register_default_json del register_default_json, register_default_jsonb
# Create default Range typecasters # Create default Range typecasters
from psycopg2. _range import Range from psycopg2. _range import Range # noqa
del Range del Range
# Add the "cleaned" version of the encodings to the key. # Add the "cleaned" version of the encodings to the key.
# When the encoding is set its name is cleaned up from - and _ and turned # When the encoding is set its name is cleaned up from - and _ and turned
# uppercase, so an encoding not respecting these rules wouldn't be found in the # uppercase, so an encoding not respecting these rules wouldn't be found in the
# encodings keys and would raise an exception with the unicode typecaster # encodings keys and would raise an exception with the unicode typecaster
for k, v in encodings.items(): for k, v in list(encodings.items()):
k = k.replace('_', '').replace('-', '').upper() k = k.replace('_', '').replace('-', '').upper()
encodings[k] = v encodings[k] = v

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,8 @@ This module implements thread-safe (and not) connection pools.
""" """
# psycopg/pool.py - pooling code for psycopg # psycopg/pool.py - pooling code for psycopg
# #
# Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> # Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -25,14 +26,14 @@ This module implements thread-safe (and not) connection pools.
# License for more details. # License for more details.
import psycopg2 import psycopg2
import psycopg2.extensions as _ext from psycopg2 import extensions as _ext
class PoolError(psycopg2.Error): class PoolError(psycopg2.Error):
pass pass
class AbstractConnectionPool(object): class AbstractConnectionPool:
"""Generic key-based pooling code.""" """Generic key-based pooling code."""
def __init__(self, minconn, maxconn, *args, **kwargs): def __init__(self, minconn, maxconn, *args, **kwargs):
@ -42,8 +43,8 @@ class AbstractConnectionPool(object):
with given parameters. The connection pool will support a maximum of with given parameters. The connection pool will support a maximum of
about 'maxconn' connections. about 'maxconn' connections.
""" """
self.minconn = minconn self.minconn = int(minconn)
self.maxconn = maxconn self.maxconn = int(maxconn)
self.closed = False self.closed = False
self._args = args self._args = args
@ -74,8 +75,10 @@ class AbstractConnectionPool(object):
def _getconn(self, key=None): def _getconn(self, key=None):
"""Get a free connection and assign it to 'key' if not None.""" """Get a free connection and assign it to 'key' if not None."""
if self.closed: raise PoolError("connection pool is closed") if self.closed:
if key is None: key = self._getkey() raise PoolError("connection pool is closed")
if key is None:
key = self._getkey()
if key in self._used: if key in self._used:
return self._used[key] return self._used[key]
@ -86,22 +89,24 @@ class AbstractConnectionPool(object):
return conn return conn
else: else:
if len(self._used) == self.maxconn: if len(self._used) == self.maxconn:
raise PoolError("connection pool exausted") raise PoolError("connection pool exhausted")
return self._connect(key) return self._connect(key)
def _putconn(self, conn, key=None, close=False): def _putconn(self, conn, key=None, close=False):
"""Put away a connection.""" """Put away a connection."""
if self.closed: raise PoolError("connection pool is closed") if self.closed:
if key is None: key = self._rused.get(id(conn)) raise PoolError("connection pool is closed")
if not key: if key is None:
key = self._rused.get(id(conn))
if key is None:
raise PoolError("trying to put unkeyed connection") raise PoolError("trying to put unkeyed connection")
if len(self._pool) < self.minconn and not close: if len(self._pool) < self.minconn and not close:
# Return the connection into a consistent state before putting # Return the connection into a consistent state before putting
# it back into the pool # it back into the pool
if not conn.closed: if not conn.closed:
status = conn.get_transaction_status() status = conn.info.transaction_status
if status == _ext.TRANSACTION_STATUS_UNKNOWN: if status == _ext.TRANSACTION_STATUS_UNKNOWN:
# server connection lost # server connection lost
conn.close() conn.close()
@ -129,11 +134,12 @@ class AbstractConnectionPool(object):
an already closed connection. If you call .closeall() make sure an already closed connection. If you call .closeall() make sure
your code can deal with it. your code can deal with it.
""" """
if self.closed: raise PoolError("connection pool is closed") if self.closed:
raise PoolError("connection pool is closed")
for conn in self._pool + list(self._used.values()): for conn in self._pool + list(self._used.values()):
try: try:
conn.close() conn.close()
except: except Exception:
pass pass
self.closed = True self.closed = True
@ -179,57 +185,3 @@ class ThreadedConnectionPool(AbstractConnectionPool):
self._closeall() self._closeall()
finally: finally:
self._lock.release() self._lock.release()
class PersistentConnectionPool(AbstractConnectionPool):
"""A pool that assigns persistent connections to different threads.
Note that this connection pool generates by itself the required keys
using the current thread id. This means that until a thread puts away
a connection it will always get the same connection object by successive
`!getconn()` calls. This also means that a thread can't use more than one
single connection from the pool.
"""
def __init__(self, minconn, maxconn, *args, **kwargs):
"""Initialize the threading lock."""
import warnings
warnings.warn("deprecated: use ZPsycopgDA.pool implementation",
DeprecationWarning)
import threading
AbstractConnectionPool.__init__(
self, minconn, maxconn, *args, **kwargs)
self._lock = threading.Lock()
# we we'll need the thread module, to determine thread ids, so we
# import it here and copy it in an instance variable
import thread
self.__thread = thread
def getconn(self):
"""Generate thread id and return a connection."""
key = self.__thread.get_ident()
self._lock.acquire()
try:
return self._getconn(key)
finally:
self._lock.release()
def putconn(self, conn=None, close=False):
"""Put away an unused connection."""
key = self.__thread.get_ident()
self._lock.acquire()
try:
if not conn: conn = self._used[key]
self._putconn(conn, key, close)
finally:
self._lock.release()
def closeall(self):
"""Close all connections (even the one currently in use.)"""
self._lock.acquire()
try:
self._closeall()
finally:
self._lock.release()

View File

@ -1,95 +0,0 @@
"""psycopg 1.1.x compatibility module
This module uses the new style connection and cursor types to build a psycopg
1.1.1.x compatibility layer. It should be considered a temporary hack to run
old code while porting to psycopg 2. Import it as follows::
from psycopg2 import psycopg1 as psycopg
"""
# psycopg/psycopg1.py - psycopg 1.1.x compatibility module
#
# Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# In addition, as a special exception, the copyright holders give
# permission to link this program with the OpenSSL library (or with
# modified versions of OpenSSL that use the same license as OpenSSL),
# and distribute linked combinations including the two.
#
# You must obey the GNU Lesser General Public License in all respects for
# all of the code used other than OpenSSL.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
import _psycopg as _2psycopg
from psycopg2.extensions import cursor as _2cursor
from psycopg2.extensions import connection as _2connection
from psycopg2 import *
import psycopg2.extensions as _ext
_2connect = connect
def connect(*args, **kwargs):
"""connect(dsn, ...) -> new psycopg 1.1.x compatible connection object"""
kwargs['connection_factory'] = connection
conn = _2connect(*args, **kwargs)
conn.set_isolation_level(_ext.ISOLATION_LEVEL_READ_COMMITTED)
return conn
class connection(_2connection):
"""psycopg 1.1.x connection."""
def cursor(self):
"""cursor() -> new psycopg 1.1.x compatible cursor object"""
return _2connection.cursor(self, cursor_factory=cursor)
def autocommit(self, on_off=1):
"""autocommit(on_off=1) -> switch autocommit on (1) or off (0)"""
if on_off > 0:
self.set_isolation_level(_ext.ISOLATION_LEVEL_AUTOCOMMIT)
else:
self.set_isolation_level(_ext.ISOLATION_LEVEL_READ_COMMITTED)
class cursor(_2cursor):
"""psycopg 1.1.x cursor.
Note that this cursor implements the exact procedure used by psycopg 1 to
build dictionaries out of result rows. The DictCursor in the
psycopg.extras modules implements a much better and faster algorithm.
"""
def __build_dict(self, row):
res = {}
for i in range(len(self.description)):
res[self.description[i][0]] = row[i]
return res
def dictfetchone(self):
row = _2cursor.fetchone(self)
if row:
return self.__build_dict(row)
else:
return row
def dictfetchmany(self, size):
res = []
rows = _2cursor.fetchmany(self, size)
for row in rows:
res.append(self.__build_dict(row))
return res
def dictfetchall(self):
res = []
rows = _2cursor.fetchall(self)
for row in rows:
res.append(self.__build_dict(row))
return res

455
lib/sql.py Normal file
View File

@ -0,0 +1,455 @@
"""SQL composition utility module
"""
# psycopg/sql.py - SQL composition utility module
#
# Copyright (C) 2016-2019 Daniele Varrazzo <daniele.varrazzo@gmail.com>
# Copyright (C) 2020-2021 The Psycopg Team
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# In addition, as a special exception, the copyright holders give
# permission to link this program with the OpenSSL library (or with
# modified versions of OpenSSL that use the same license as OpenSSL),
# and distribute linked combinations including the two.
#
# You must obey the GNU Lesser General Public License in all respects for
# all of the code used other than OpenSSL.
#
# psycopg2 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
# License for more details.
import string
from psycopg2 import extensions as ext
_formatter = string.Formatter()
class Composable:
"""
Abstract base class for objects that can be used to compose an SQL string.
`!Composable` objects can be passed directly to `~cursor.execute()`,
`~cursor.executemany()`, `~cursor.copy_expert()` in place of the query
string.
`!Composable` objects can be joined using the ``+`` operator: the result
will be a `Composed` instance containing the objects joined. The operator
``*`` is also supported with an integer argument: the result is a
`!Composed` instance containing the left argument repeated as many times as
requested.
"""
def __init__(self, wrapped):
self._wrapped = wrapped
def __repr__(self):
return f"{self.__class__.__name__}({self._wrapped!r})"
def as_string(self, context):
"""
Return the string value of the object.
:param context: the context to evaluate the string into.
:type context: `connection` or `cursor`
The method is automatically invoked by `~cursor.execute()`,
`~cursor.executemany()`, `~cursor.copy_expert()` if a `!Composable` is
passed instead of the query string.
"""
raise NotImplementedError
def __add__(self, other):
if isinstance(other, Composed):
return Composed([self]) + other
if isinstance(other, Composable):
return Composed([self]) + Composed([other])
else:
return NotImplemented
def __mul__(self, n):
return Composed([self] * n)
def __eq__(self, other):
return type(self) is type(other) and self._wrapped == other._wrapped
def __ne__(self, other):
return not self.__eq__(other)
class Composed(Composable):
"""
A `Composable` object made of a sequence of `!Composable`.
The object is usually created using `!Composable` operators and methods.
However it is possible to create a `!Composed` directly specifying a
sequence of `!Composable` as arguments.
Example::
>>> comp = sql.Composed(
... [sql.SQL("insert into "), sql.Identifier("table")])
>>> print(comp.as_string(conn))
insert into "table"
`!Composed` objects are iterable (so they can be used in `SQL.join` for
instance).
"""
def __init__(self, seq):
wrapped = []
for i in seq:
if not isinstance(i, Composable):
raise TypeError(
f"Composed elements must be Composable, got {i!r} instead")
wrapped.append(i)
super().__init__(wrapped)
@property
def seq(self):
"""The list of the content of the `!Composed`."""
return list(self._wrapped)
def as_string(self, context):
rv = []
for i in self._wrapped:
rv.append(i.as_string(context))
return ''.join(rv)
def __iter__(self):
return iter(self._wrapped)
def __add__(self, other):
if isinstance(other, Composed):
return Composed(self._wrapped + other._wrapped)
if isinstance(other, Composable):
return Composed(self._wrapped + [other])
else:
return NotImplemented
def join(self, joiner):
"""
Return a new `!Composed` interposing the *joiner* with the `!Composed` items.
The *joiner* must be a `SQL` or a string which will be interpreted as
an `SQL`.
Example::
>>> fields = sql.Identifier('foo') + sql.Identifier('bar') # a Composed
>>> print(fields.join(', ').as_string(conn))
"foo", "bar"
"""
if isinstance(joiner, str):
joiner = SQL(joiner)
elif not isinstance(joiner, SQL):
raise TypeError(
"Composed.join() argument must be a string or an SQL")
return joiner.join(self)
class SQL(Composable):
"""
A `Composable` representing a snippet of SQL statement.
`!SQL` exposes `join()` and `format()` methods useful to create a template
where to merge variable parts of a query (for instance field or table
names).
The *string* doesn't undergo any form of escaping, so it is not suitable to
represent variable identifiers or values: you should only use it to pass
constant strings representing templates or snippets of SQL statements; use
other objects such as `Identifier` or `Literal` to represent variable
parts.
Example::
>>> query = sql.SQL("select {0} from {1}").format(
... sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
... sql.Identifier('table'))
>>> print(query.as_string(conn))
select "foo", "bar" from "table"
"""
def __init__(self, string):
if not isinstance(string, str):
raise TypeError("SQL values must be strings")
super().__init__(string)
@property
def string(self):
"""The string wrapped by the `!SQL` object."""
return self._wrapped
def as_string(self, context):
return self._wrapped
def format(self, *args, **kwargs):
"""
Merge `Composable` objects into a template.
:param `Composable` args: parameters to replace to numbered
(``{0}``, ``{1}``) or auto-numbered (``{}``) placeholders
:param `Composable` kwargs: parameters to replace to named (``{name}``)
placeholders
:return: the union of the `!SQL` string with placeholders replaced
:rtype: `Composed`
The method is similar to the Python `str.format()` method: the string
template supports auto-numbered (``{}``), numbered (``{0}``,
``{1}``...), and named placeholders (``{name}``), with positional
arguments replacing the numbered placeholders and keywords replacing
the named ones. However placeholder modifiers (``{0!r}``, ``{0:<10}``)
are not supported. Only `!Composable` objects can be passed to the
template.
Example::
>>> print(sql.SQL("select * from {} where {} = %s")
... .format(sql.Identifier('people'), sql.Identifier('id'))
... .as_string(conn))
select * from "people" where "id" = %s
>>> print(sql.SQL("select * from {tbl} where {pkey} = %s")
... .format(tbl=sql.Identifier('people'), pkey=sql.Identifier('id'))
... .as_string(conn))
select * from "people" where "id" = %s
"""
rv = []
autonum = 0
for pre, name, spec, conv in _formatter.parse(self._wrapped):
if spec:
raise ValueError("no format specification supported by SQL")
if conv:
raise ValueError("no format conversion supported by SQL")
if pre:
rv.append(SQL(pre))
if name is None:
continue
if name.isdigit():
if autonum:
raise ValueError(
"cannot switch from automatic field numbering to manual")
rv.append(args[int(name)])
autonum = None
elif not name:
if autonum is None:
raise ValueError(
"cannot switch from manual field numbering to automatic")
rv.append(args[autonum])
autonum += 1
else:
rv.append(kwargs[name])
return Composed(rv)
def join(self, seq):
"""
Join a sequence of `Composable`.
:param seq: the elements to join.
:type seq: iterable of `!Composable`
Use the `!SQL` object's *string* to separate the elements in *seq*.
Note that `Composed` objects are iterable too, so they can be used as
argument for this method.
Example::
>>> snip = sql.SQL(', ').join(
... sql.Identifier(n) for n in ['foo', 'bar', 'baz'])
>>> print(snip.as_string(conn))
"foo", "bar", "baz"
"""
rv = []
it = iter(seq)
try:
rv.append(next(it))
except StopIteration:
pass
else:
for i in it:
rv.append(self)
rv.append(i)
return Composed(rv)
class Identifier(Composable):
"""
A `Composable` representing an SQL identifier or a dot-separated sequence.
Identifiers usually represent names of database objects, such as tables or
fields. PostgreSQL identifiers follow `different rules`__ than SQL string
literals for escaping (e.g. they use double quotes instead of single).
.. __: https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html# \
SQL-SYNTAX-IDENTIFIERS
Example::
>>> t1 = sql.Identifier("foo")
>>> t2 = sql.Identifier("ba'r")
>>> t3 = sql.Identifier('ba"z')
>>> print(sql.SQL(', ').join([t1, t2, t3]).as_string(conn))
"foo", "ba'r", "ba""z"
Multiple strings can be passed to the object to represent a qualified name,
i.e. a dot-separated sequence of identifiers.
Example::
>>> query = sql.SQL("select {} from {}").format(
... sql.Identifier("table", "field"),
... sql.Identifier("schema", "table"))
>>> print(query.as_string(conn))
select "table"."field" from "schema"."table"
"""
def __init__(self, *strings):
if not strings:
raise TypeError("Identifier cannot be empty")
for s in strings:
if not isinstance(s, str):
raise TypeError("SQL identifier parts must be strings")
super().__init__(strings)
@property
def strings(self):
"""A tuple with the strings wrapped by the `Identifier`."""
return self._wrapped
@property
def string(self):
"""The string wrapped by the `Identifier`.
"""
if len(self._wrapped) == 1:
return self._wrapped[0]
else:
raise AttributeError(
"the Identifier wraps more than one than one string")
def __repr__(self):
return f"{self.__class__.__name__}({', '.join(map(repr, self._wrapped))})"
def as_string(self, context):
return '.'.join(ext.quote_ident(s, context) for s in self._wrapped)
class Literal(Composable):
"""
A `Composable` representing an SQL value to include in a query.
Usually you will want to include placeholders in the query and pass values
as `~cursor.execute()` arguments. If however you really really need to
include a literal value in the query you can use this object.
The string returned by `!as_string()` follows the normal :ref:`adaptation
rules <python-types-adaptation>` for Python objects.
Example::
>>> s1 = sql.Literal("foo")
>>> s2 = sql.Literal("ba'r")
>>> s3 = sql.Literal(42)
>>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn))
'foo', 'ba''r', 42
"""
@property
def wrapped(self):
"""The object wrapped by the `!Literal`."""
return self._wrapped
def as_string(self, context):
# is it a connection or cursor?
if isinstance(context, ext.connection):
conn = context
elif isinstance(context, ext.cursor):
conn = context.connection
else:
raise TypeError("context must be a connection or a cursor")
a = ext.adapt(self._wrapped)
if hasattr(a, 'prepare'):
a.prepare(conn)
rv = a.getquoted()
if isinstance(rv, bytes):
rv = rv.decode(ext.encodings[conn.encoding])
return rv
class Placeholder(Composable):
"""A `Composable` representing a placeholder for query parameters.
If the name is specified, generate a named placeholder (e.g. ``%(name)s``),
otherwise generate a positional placeholder (e.g. ``%s``).
The object is useful to generate SQL queries with a variable number of
arguments.
Examples::
>>> names = ['foo', 'bar', 'baz']
>>> q1 = sql.SQL("insert into table ({}) values ({})").format(
... sql.SQL(', ').join(map(sql.Identifier, names)),
... sql.SQL(', ').join(sql.Placeholder() * len(names)))
>>> print(q1.as_string(conn))
insert into table ("foo", "bar", "baz") values (%s, %s, %s)
>>> q2 = sql.SQL("insert into table ({}) values ({})").format(
... sql.SQL(', ').join(map(sql.Identifier, names)),
... sql.SQL(', ').join(map(sql.Placeholder, names)))
>>> print(q2.as_string(conn))
insert into table ("foo", "bar", "baz") values (%(foo)s, %(bar)s, %(baz)s)
"""
def __init__(self, name=None):
if isinstance(name, str):
if ')' in name:
raise ValueError(f"invalid name: {name!r}")
elif name is not None:
raise TypeError(f"expected string or None as name, got {name!r}")
super().__init__(name)
@property
def name(self):
"""The name of the `!Placeholder`."""
return self._wrapped
def __repr__(self):
if self._wrapped is None:
return f"{self.__class__.__name__}()"
else:
return f"{self.__class__.__name__}({self._wrapped!r})"
def as_string(self, context):
if self._wrapped is not None:
return f"%({self._wrapped})s"
else:
return "%s"
# Literals
NULL = SQL("NULL")
DEFAULT = SQL("DEFAULT")

View File

@ -6,7 +6,8 @@ functions or used to set the .tzinfo_factory attribute in cursors.
""" """
# psycopg/tz.py - tzinfo implementation # psycopg/tz.py - tzinfo implementation
# #
# Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> # Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
# Copyright (C) 2020-2021 The Psycopg Team
# #
# psycopg2 is free software: you can redistribute it and/or modify it # psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@ -31,6 +32,7 @@ import time
ZERO = datetime.timedelta(0) ZERO = datetime.timedelta(0)
class FixedOffsetTimezone(datetime.tzinfo): class FixedOffsetTimezone(datetime.tzinfo):
"""Fixed offset in minutes east from UTC. """Fixed offset in minutes east from UTC.
@ -43,7 +45,12 @@ class FixedOffsetTimezone(datetime.tzinfo):
offset and name that instance will be returned. This saves memory and offset and name that instance will be returned. This saves memory and
improves comparability. improves comparability.
.. __: http://docs.python.org/library/datetime.html#datetime-tzinfo .. versionchanged:: 2.9
The constructor can take either a timedelta or a number of minutes of
offset. Previously only minutes were supported.
.. __: https://docs.python.org/library/datetime.html
""" """
_name = None _name = None
_offset = ZERO _offset = ZERO
@ -52,7 +59,9 @@ class FixedOffsetTimezone(datetime.tzinfo):
def __init__(self, offset=None, name=None): def __init__(self, offset=None, name=None):
if offset is not None: if offset is not None:
self._offset = datetime.timedelta(minutes = offset) if not isinstance(offset, datetime.timedelta):
offset = datetime.timedelta(minutes=offset)
self._offset = offset
if name is not None: if name is not None:
self._name = name self._name = name
@ -63,18 +72,28 @@ class FixedOffsetTimezone(datetime.tzinfo):
try: try:
return cls._cache[key] return cls._cache[key]
except KeyError: except KeyError:
tz = super(FixedOffsetTimezone, cls).__new__(cls, offset, name) tz = super().__new__(cls, offset, name)
cls._cache[key] = tz cls._cache[key] = tz
return tz return tz
def __repr__(self): def __repr__(self):
offset_mins = self._offset.seconds // 60 + self._offset.days * 24 * 60
return "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=%r)" \ return "psycopg2.tz.FixedOffsetTimezone(offset=%r, name=%r)" \
% (offset_mins, self._name) % (self._offset, self._name)
def __eq__(self, other):
if isinstance(other, FixedOffsetTimezone):
return self._offset == other._offset
else:
return NotImplemented
def __ne__(self, other):
if isinstance(other, FixedOffsetTimezone):
return self._offset != other._offset
else:
return NotImplemented
def __getinitargs__(self): def __getinitargs__(self):
offset_mins = self._offset.seconds // 60 + self._offset.days * 24 * 60 return self._offset, self._name
return (offset_mins, self._name)
def utcoffset(self, dt): def utcoffset(self, dt):
return self._offset return self._offset
@ -82,26 +101,29 @@ class FixedOffsetTimezone(datetime.tzinfo):
def tzname(self, dt): def tzname(self, dt):
if self._name is not None: if self._name is not None:
return self._name return self._name
else:
seconds = self._offset.seconds + self._offset.days * 86400 minutes, seconds = divmod(self._offset.total_seconds(), 60)
hours, seconds = divmod(seconds, 3600) hours, minutes = divmod(minutes, 60)
minutes = seconds/60 rv = "%+03d" % hours
if minutes: if minutes or seconds:
return "%+03d:%d" % (hours, minutes) rv += ":%02d" % minutes
else: if seconds:
return "%+03d" % hours rv += ":%02d" % seconds
return rv
def dst(self, dt): def dst(self, dt):
return ZERO return ZERO
STDOFFSET = datetime.timedelta(seconds = -time.timezone) STDOFFSET = datetime.timedelta(seconds=-time.timezone)
if time.daylight: if time.daylight:
DSTOFFSET = datetime.timedelta(seconds = -time.altzone) DSTOFFSET = datetime.timedelta(seconds=-time.altzone)
else: else:
DSTOFFSET = STDOFFSET DSTOFFSET = STDOFFSET
DSTDIFF = DSTOFFSET - STDOFFSET DSTDIFF = DSTOFFSET - STDOFFSET
class LocalTimezone(datetime.tzinfo): class LocalTimezone(datetime.tzinfo):
"""Platform idea of local timezone. """Platform idea of local timezone.
@ -130,6 +152,7 @@ class LocalTimezone(datetime.tzinfo):
tt = time.localtime(stamp) tt = time.localtime(stamp)
return tt.tm_isdst > 0 return tt.tm_isdst > 0
LOCAL = LocalTimezone() LOCAL = LocalTimezone()
# TODO: pre-generate some interesting time zones? # TODO: pre-generate some interesting time zones?

View File

@ -1,6 +1,7 @@
/* adapter_asis.c - adapt types as they are /* adapter_asis.c - adapt types as they are
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -44,14 +45,12 @@ asis_getquoted(asisObject *self, PyObject *args)
} }
else { else {
rv = PyObject_Str(self->wrapped); rv = PyObject_Str(self->wrapped);
#if PY_MAJOR_VERSION > 2 /* unicode to bytes */
/* unicode to bytes in Py3 */
if (rv) { if (rv) {
PyObject *tmp = PyUnicode_AsUTF8String(rv); PyObject *tmp = PyUnicode_AsUTF8String(rv);
Py_DECREF(rv); Py_DECREF(rv);
rv = tmp; rv = tmp;
} }
#endif
} }
return rv; return rv;
@ -60,7 +59,7 @@ asis_getquoted(asisObject *self, PyObject *args)
static PyObject * static PyObject *
asis_str(asisObject *self) asis_str(asisObject *self)
{ {
return psycopg_ensure_text(asis_getquoted(self, NULL)); return psyco_ensure_text(asis_getquoted(self, NULL));
} }
static PyObject * static PyObject *
@ -149,12 +148,6 @@ asis_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
static PyObject *
asis_repr(asisObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.AsIs object at %p>", self);
}
/* object type */ /* object type */
@ -163,14 +156,14 @@ asis_repr(asisObject *self)
PyTypeObject asisType = { PyTypeObject asisType = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"psycopg2._psycopg.AsIs", "psycopg2.extensions.AsIs",
sizeof(asisObject), 0, sizeof(asisObject), 0,
asis_dealloc, /*tp_dealloc*/ asis_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)asis_repr, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -200,17 +193,3 @@ PyTypeObject asisType = {
0, /*tp_alloc*/ 0, /*tp_alloc*/
asis_new, /*tp_new*/ asis_new, /*tp_new*/
}; };
/** module-level functions **/
PyObject *
psyco_AsIs(PyObject *module, PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
return PyObject_CallFunctionObjArgs((PyObject *)&asisType, obj, NULL);
}

View File

@ -1,6 +1,7 @@
/* adapter_asis.h - definition for the psycopg AsIs type wrapper /* adapter_asis.h - definition for the psycopg AsIs type wrapper
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -40,12 +41,6 @@ typedef struct {
} asisObject; } asisObject;
/* functions exported to psycopgmodule.c */
HIDDEN PyObject *psyco_AsIs(PyObject *module, PyObject *args);
#define psyco_AsIs_doc \
"AsIs(obj) -> new AsIs wrapper object"
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,6 +1,7 @@
/* adapter_binary.c - Binary objects /* adapter_binary.c - Binary objects
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -39,17 +40,12 @@ static unsigned char *
binary_escape(unsigned char *from, size_t from_length, binary_escape(unsigned char *from, size_t from_length,
size_t *to_length, PGconn *conn) size_t *to_length, PGconn *conn)
{ {
#if PG_VERSION_HEX >= 0x080104
if (conn) if (conn)
return PQescapeByteaConn(conn, from, from_length, to_length); return PQescapeByteaConn(conn, from, from_length, to_length);
else else
#endif
return PQescapeBytea(from, from_length, to_length); return PQescapeBytea(from, from_length, to_length);
} }
#define HAS_BUFFER (PY_MAJOR_VERSION < 3)
#define HAS_MEMORYVIEW (PY_MAJOR_VERSION > 2 || PY_MINOR_VERSION >= 6)
/* binary_quote - do the quote process on plain and unicode strings */ /* binary_quote - do the quote process on plain and unicode strings */
static PyObject * static PyObject *
@ -60,10 +56,8 @@ binary_quote(binaryObject *self)
Py_ssize_t buffer_len; Py_ssize_t buffer_len;
size_t len = 0; size_t len = 0;
PyObject *rv = NULL; PyObject *rv = NULL;
#if HAS_MEMORYVIEW
Py_buffer view; Py_buffer view;
int got_view = 0; int got_view = 0;
#endif
/* Allow Binary(None) to work */ /* Allow Binary(None) to work */
if (self->wrapped == Py_None) { if (self->wrapped == Py_None) {
@ -73,8 +67,6 @@ binary_quote(binaryObject *self)
} }
/* if we got a plain string or a buffer we escape it and save the buffer */ /* if we got a plain string or a buffer we escape it and save the buffer */
#if HAS_MEMORYVIEW
if (PyObject_CheckBuffer(self->wrapped)) { if (PyObject_CheckBuffer(self->wrapped)) {
if (0 > PyObject_GetBuffer(self->wrapped, &view, PyBUF_CONTIG_RO)) { if (0 > PyObject_GetBuffer(self->wrapped, &view, PyBUF_CONTIG_RO)) {
goto exit; goto exit;
@ -83,16 +75,6 @@ binary_quote(binaryObject *self)
buffer = (const char *)(view.buf); buffer = (const char *)(view.buf);
buffer_len = view.len; buffer_len = view.len;
} }
#endif
#if HAS_BUFFER
if (!buffer && (Bytes_Check(self->wrapped) || PyBuffer_Check(self->wrapped))) {
if (PyObject_AsReadBuffer(self->wrapped, (const void **)&buffer,
&buffer_len) < 0) {
goto exit;
}
}
#endif
if (!buffer) { if (!buffer) {
goto exit; goto exit;
@ -116,9 +98,7 @@ binary_quote(binaryObject *self)
exit: exit:
if (to) { PQfreemem(to); } if (to) { PQfreemem(to); }
#if HAS_MEMORYVIEW
if (got_view) { PyBuffer_Release(&view); } if (got_view) { PyBuffer_Release(&view); }
#endif
/* if the wrapped object is not bytes or a buffer, this is an error */ /* if the wrapped object is not bytes or a buffer, this is an error */
if (!rv && !PyErr_Occurred()) { if (!rv && !PyErr_Occurred()) {
@ -144,7 +124,7 @@ binary_getquoted(binaryObject *self, PyObject *args)
static PyObject * static PyObject *
binary_str(binaryObject *self) binary_str(binaryObject *self)
{ {
return psycopg_ensure_text(binary_getquoted(self, NULL)); return psyco_ensure_text(binary_getquoted(self, NULL));
} }
static PyObject * static PyObject *
@ -254,11 +234,6 @@ binary_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
static PyObject *
binary_repr(binaryObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.Binary object at %p>", self);
}
/* object type */ /* object type */
@ -267,14 +242,14 @@ binary_repr(binaryObject *self)
PyTypeObject binaryType = { PyTypeObject binaryType = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"psycopg2._psycopg.Binary", "psycopg2.extensions.Binary",
sizeof(binaryObject), 0, sizeof(binaryObject), 0,
binary_dealloc, /*tp_dealloc*/ binary_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)binary_repr, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -304,17 +279,3 @@ PyTypeObject binaryType = {
0, /*tp_alloc*/ 0, /*tp_alloc*/
binary_new, /*tp_new*/ binary_new, /*tp_new*/
}; };
/** module-level functions **/
PyObject *
psyco_Binary(PyObject *module, PyObject *args)
{
PyObject *str;
if (!PyArg_ParseTuple(args, "O", &str))
return NULL;
return PyObject_CallFunctionObjArgs((PyObject *)&binaryType, str, NULL);
}

View File

@ -1,6 +1,7 @@
/* adapter_binary.h - definition for the Binary type /* adapter_binary.h - definition for the Binary type
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -40,13 +41,6 @@ typedef struct {
PyObject *conn; PyObject *conn;
} binaryObject; } binaryObject;
/* functions exported to psycopgmodule.c */
HIDDEN PyObject *psyco_Binary(PyObject *module, PyObject *args);
#define psyco_Binary_doc \
"Binary(buffer) -> new binary object\n\n" \
"Build an object capable to hold a bynary string value."
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,6 +1,7 @@
/* adapter_datetime.c - python date/time objects /* adapter_datetime.c - python date/time objects
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -35,14 +36,9 @@
#include <string.h> #include <string.h>
extern HIDDEN PyObject *pyPsycopgTzModule; RAISES_NEG int
extern HIDDEN PyObject *pyPsycopgTzLOCAL; adapter_datetime_init(void)
int
psyco_adapter_datetime_init(void)
{ {
Dprintf("psyco_adapter_datetime_init: datetime init");
PyDateTime_IMPORT; PyDateTime_IMPORT;
if (!PyDateTimeAPI) { if (!PyDateTimeAPI) {
@ -65,7 +61,10 @@ _pydatetime_string_date_time(pydatetimeObject *self)
char *fmt = NULL; char *fmt = NULL;
switch (self->type) { switch (self->type) {
case PSYCO_DATETIME_TIME: case PSYCO_DATETIME_TIME:
fmt = "'%s'::time"; tz = PyObject_GetAttrString(self->wrapped, "tzinfo");
if (!tz) { goto error; }
fmt = (tz == Py_None) ? "'%s'::time" : "'%s'::timetz";
Py_DECREF(tz);
break; break;
case PSYCO_DATETIME_DATE: case PSYCO_DATETIME_DATE:
fmt = "'%s'::date"; fmt = "'%s'::date";
@ -78,7 +77,7 @@ _pydatetime_string_date_time(pydatetimeObject *self)
break; break;
} }
if (!(iso = psycopg_ensure_bytes( if (!(iso = psyco_ensure_bytes(
PyObject_CallMethod(self->wrapped, "isoformat", NULL)))) { PyObject_CallMethod(self->wrapped, "isoformat", NULL)))) {
goto error; goto error;
} }
@ -100,7 +99,7 @@ _pydatetime_string_delta(pydatetimeObject *self)
char buffer[8]; char buffer[8];
int i; int i;
int a = obj->microseconds; int a = PyDateTime_DELTA_GET_MICROSECONDS(obj);
for (i=0; i < 6 ; i++) { for (i=0; i < 6 ; i++) {
buffer[5-i] = '0' + (a % 10); buffer[5-i] = '0' + (a % 10);
@ -109,7 +108,9 @@ _pydatetime_string_delta(pydatetimeObject *self)
buffer[6] = '\0'; buffer[6] = '\0';
return Bytes_FromFormat("'%d days %d.%s seconds'::interval", return Bytes_FromFormat("'%d days %d.%s seconds'::interval",
obj->days, obj->seconds, buffer); PyDateTime_DELTA_GET_DAYS(obj),
PyDateTime_DELTA_GET_SECONDS(obj),
buffer);
} }
static PyObject * static PyObject *
@ -126,7 +127,7 @@ pydatetime_getquoted(pydatetimeObject *self, PyObject *args)
static PyObject * static PyObject *
pydatetime_str(pydatetimeObject *self) pydatetime_str(pydatetimeObject *self)
{ {
return psycopg_ensure_text(pydatetime_getquoted(self, NULL)); return psyco_ensure_text(pydatetime_getquoted(self, NULL));
} }
static PyObject * static PyObject *
@ -214,12 +215,6 @@ pydatetime_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
static PyObject *
pydatetime_repr(pydatetimeObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.datetime object at %p>",
self);
}
/* object type */ /* object type */
@ -235,7 +230,7 @@ PyTypeObject pydatetimeType = {
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)pydatetime_repr, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -269,8 +264,6 @@ PyTypeObject pydatetimeType = {
/** module-level functions **/ /** module-level functions **/
#ifdef PSYCOPG_DEFAULT_PYDATETIME
PyObject * PyObject *
psyco_Date(PyObject *self, PyObject *args) psyco_Date(PyObject *self, PyObject *args)
{ {
@ -430,6 +423,8 @@ psyco_TimeFromTicks(PyObject *self, PyObject *args)
PyObject * PyObject *
psyco_TimestampFromTicks(PyObject *self, PyObject *args) psyco_TimestampFromTicks(PyObject *self, PyObject *args)
{ {
pydatetimeObject *wrapper = NULL;
PyObject *dt_aware = NULL;
PyObject *res = NULL; PyObject *res = NULL;
struct tm tm; struct tm tm;
time_t t; time_t t;
@ -440,21 +435,37 @@ psyco_TimestampFromTicks(PyObject *self, PyObject *args)
t = (time_t)floor(ticks); t = (time_t)floor(ticks);
ticks -= (double)t; ticks -= (double)t;
if (localtime_r(&t, &tm)) { if (!localtime_r(&t, &tm)) {
res = _psyco_Timestamp(
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks,
pyPsycopgTzLOCAL);
}
else {
PyErr_SetString(InterfaceError, "failed localtime call"); PyErr_SetString(InterfaceError, "failed localtime call");
goto exit;
} }
/* Convert the tm to a wrapper containing a naive datetime.datetime */
if (!(wrapper = (pydatetimeObject *)_psyco_Timestamp(
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks, NULL))) {
goto exit;
}
/* Localize the datetime and assign it back to the wrapper */
if (!(dt_aware = PyObject_CallMethod(
wrapper->wrapped, "astimezone", NULL))) {
goto exit;
}
Py_CLEAR(wrapper->wrapped);
wrapper->wrapped = dt_aware;
dt_aware = NULL;
/* the wrapper is ready to be returned */
res = (PyObject *)wrapper;
wrapper = NULL;
exit:
Py_XDECREF(dt_aware);
Py_XDECREF(wrapper);
return res; return res;
} }
#endif
PyObject * PyObject *
psyco_DateFromPy(PyObject *self, PyObject *args) psyco_DateFromPy(PyObject *self, PyObject *args)
{ {

View File

@ -1,6 +1,7 @@
/* adapter_datetime.h - definition for the python date/time types /* adapter_datetime.h - definition for the python date/time types
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -45,10 +46,7 @@ typedef struct {
} pydatetimeObject; } pydatetimeObject;
HIDDEN int psyco_adapter_datetime_init(void); RAISES_NEG HIDDEN int adapter_datetime_init(void);
/* functions exported to psycopgmodule.c */
#ifdef PSYCOPG_DEFAULT_PYDATETIME
HIDDEN PyObject *psyco_Date(PyObject *module, PyObject *args); HIDDEN PyObject *psyco_Date(PyObject *module, PyObject *args);
#define psyco_Date_doc \ #define psyco_Date_doc \
@ -86,8 +84,6 @@ HIDDEN PyObject *psyco_TimestampFromTicks(PyObject *module, PyObject *args);
"Ticks are the number of seconds since the epoch; see the documentation " \ "Ticks are the number of seconds since the epoch; see the documentation " \
"of the standard Python time module for details)." "of the standard Python time module for details)."
#endif /* PSYCOPG_DEFAULT_PYDATETIME */
HIDDEN PyObject *psyco_DateFromPy(PyObject *module, PyObject *args); HIDDEN PyObject *psyco_DateFromPy(PyObject *module, PyObject *args);
#define psyco_DateFromPy_doc \ #define psyco_DateFromPy_doc \
"DateFromPy(datetime.date) -> new wrapper" "DateFromPy(datetime.date) -> new wrapper"

View File

@ -1,6 +1,7 @@
/* adapter_list.c - python list objects /* adapter_list.c - python list objects
* *
* Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2004-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -38,55 +39,134 @@ list_quote(listObject *self)
{ {
/* adapt the list by calling adapt() recursively and then wrapping /* adapt the list by calling adapt() recursively and then wrapping
everything into "ARRAY[]" */ everything into "ARRAY[]" */
PyObject *tmp = NULL, *str = NULL, *joined = NULL, *res = NULL; PyObject *res = NULL;
PyObject **qs = NULL;
Py_ssize_t bufsize = 0;
char *buf = NULL, *ptr;
/* list consisting of only NULL don't work with the ARRAY[] construct
* so we use the {NULL,...} syntax. The same syntax is also necessary
* to convert array of arrays containing only nulls. */
int all_nulls = 1;
Py_ssize_t i, len; Py_ssize_t i, len;
len = PyList_GET_SIZE(self->wrapped); len = PyList_GET_SIZE(self->wrapped);
/* empty arrays are converted to NULLs (still searching for a way to /* empty arrays are converted to NULLs (still searching for a way to
insert an empty array in postgresql */ insert an empty array in postgresql */
if (len == 0) return Bytes_FromString("'{}'"); if (len == 0) {
/* it cannot be ARRAY[] because it would make empty lists unusable
* in any() without a cast. But we may convert it into ARRAY[] below */
res = Bytes_FromString("'{}'");
goto exit;
}
tmp = PyTuple_New(len); if (!(qs = PyMem_New(PyObject *, len))) {
PyErr_NoMemory();
goto exit;
}
memset(qs, 0, len * sizeof(PyObject *));
for (i=0; i<len; i++) { for (i = 0; i < len; i++) {
PyObject *quoted;
PyObject *wrapped = PyList_GET_ITEM(self->wrapped, i); PyObject *wrapped = PyList_GET_ITEM(self->wrapped, i);
if (wrapped == Py_None) { if (wrapped == Py_None) {
Py_INCREF(psyco_null); Py_INCREF(psyco_null);
quoted = psyco_null; qs[i] = psyco_null;
} }
else { else {
quoted = microprotocol_getquoted(wrapped, if (!(qs[i] = microprotocol_getquoted(
(connectionObject*)self->connection); wrapped, (connectionObject*)self->connection))) {
if (quoted == NULL) goto error; goto exit;
} }
/* here we don't loose a refcnt: SET_ITEM does not change the /* Lists of arrays containing only nulls are also not supported
reference count and we are just transferring ownership of the tmp * by the ARRAY construct so we should do some special casing */
object to the tuple */ if (PyList_Check(wrapped)) {
PyTuple_SET_ITEM(tmp, i, quoted); if (Bytes_AS_STRING(qs[i])[0] == 'A') {
all_nulls = 0;
}
else if (0 == strcmp(Bytes_AS_STRING(qs[i]), "'{}'")) {
/* case of issue #788: '{{}}' is not supported but
* array[array[]] is */
all_nulls = 0;
Py_CLEAR(qs[i]);
if (!(qs[i] = Bytes_FromString("ARRAY[]"))) {
goto exit;
}
}
}
else {
all_nulls = 0;
}
}
bufsize += Bytes_GET_SIZE(qs[i]) + 1; /* this, and a comma */
} }
/* now that we have a tuple of adapted objects we just need to join them /* Create an array literal, usually ARRAY[...] but if the contents are
and put "ARRAY[] around the result */ * all NULL or array of NULL we must use the '{...}' syntax
str = Bytes_FromString(", "); */
joined = PyObject_CallMethod(str, "join", "(O)", tmp); if (!(ptr = buf = PyMem_Malloc(bufsize + 8))) {
if (joined == NULL) goto error; PyErr_NoMemory();
goto exit;
}
res = Bytes_FromFormat("ARRAY[%s]", Bytes_AsString(joined)); if (!all_nulls) {
strcpy(ptr, "ARRAY[");
ptr += 6;
for (i = 0; i < len; i++) {
Py_ssize_t sl;
sl = Bytes_GET_SIZE(qs[i]);
memcpy(ptr, Bytes_AS_STRING(qs[i]), sl);
ptr += sl;
*ptr++ = ',';
}
*(ptr - 1) = ']';
}
else {
*ptr++ = '\'';
*ptr++ = '{';
for (i = 0; i < len; i++) {
/* in case all the adapted things are nulls (or array of nulls),
* the quoted string is either NULL or an array of the form
* '{NULL,...}', in which case we have to strip the extra quotes */
char *s;
Py_ssize_t sl;
s = Bytes_AS_STRING(qs[i]);
sl = Bytes_GET_SIZE(qs[i]);
if (s[0] != '\'') {
memcpy(ptr, s, sl);
ptr += sl;
}
else {
memcpy(ptr, s + 1, sl - 2);
ptr += sl - 2;
}
*ptr++ = ',';
}
*(ptr - 1) = '}';
*ptr++ = '\'';
}
res = Bytes_FromStringAndSize(buf, ptr - buf);
exit:
if (qs) {
for (i = 0; i < len; i++) {
PyObject *q = qs[i];
Py_XDECREF(q);
}
PyMem_Free(qs);
}
PyMem_Free(buf);
error:
Py_XDECREF(tmp);
Py_XDECREF(str);
Py_XDECREF(joined);
return res; return res;
} }
static PyObject * static PyObject *
list_str(listObject *self) list_str(listObject *self)
{ {
return psycopg_ensure_text(list_quote(self)); return psyco_ensure_text(list_quote(self));
} }
static PyObject * static PyObject *
@ -215,11 +295,6 @@ list_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
static PyObject *
list_repr(listObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.List object at %p>", self);
}
/* object type */ /* object type */
@ -235,7 +310,7 @@ PyTypeObject listType = {
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)list_repr, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -265,17 +340,3 @@ PyTypeObject listType = {
0, /*tp_alloc*/ 0, /*tp_alloc*/
list_new, /*tp_new*/ list_new, /*tp_new*/
}; };
/** module-level functions **/
PyObject *
psyco_List(PyObject *module, PyObject *args)
{
PyObject *str;
if (!PyArg_ParseTuple(args, "O", &str))
return NULL;
return PyObject_CallFunctionObjArgs((PyObject *)&listType, "O", str, NULL);
}

View File

@ -1,6 +1,7 @@
/* adapter_list.h - definition for the python list types /* adapter_list.h - definition for the python list types
* *
* Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2004-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -39,10 +40,6 @@ typedef struct {
PyObject *connection; PyObject *connection;
} listObject; } listObject;
HIDDEN PyObject *psyco_List(PyObject *module, PyObject *args);
#define psyco_List_doc \
"List(list, enc) -> new quoted list"
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,434 +0,0 @@
/* adapter_mxdatetime.c - mx date/time objects
*
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org>
*
* This file is part of psycopg.
*
* psycopg2 is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link this program with the OpenSSL library (or with
* modified versions of OpenSSL that use the same license as OpenSSL),
* and distribute linked combinations including the two.
*
* You must obey the GNU Lesser General Public License in all respects for
* all of the code used other than OpenSSL.
*
* psycopg2 is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#define PSYCOPG_MODULE
#include "psycopg/psycopg.h"
#include "psycopg/adapter_mxdatetime.h"
#include "psycopg/microprotocols_proto.h"
#include <mxDateTime.h>
#include <string.h>
/* Return 0 on success, -1 on failure, but don't set an exception */
int
psyco_adapter_mxdatetime_init(void)
{
Dprintf("psyco_adapter_mxdatetime_init: mx.DateTime init");
if (mxDateTime_ImportModuleAndAPI()) {
Dprintf("psyco_adapter_mxdatetime_init: mx.DateTime initialization failed");
PyErr_Clear();
return -1;
}
return 0;
}
/* mxdatetime_str, mxdatetime_getquoted - return result of quoting */
static PyObject *
mxdatetime_str(mxdatetimeObject *self)
{
mxDateTimeObject *dt;
mxDateTimeDeltaObject *dtd;
char buf[128] = { 0, };
switch (self->type) {
case PSYCO_MXDATETIME_DATE:
dt = (mxDateTimeObject *)self->wrapped;
if (dt->year >= 1)
PyOS_snprintf(buf, sizeof(buf) - 1, "'%04ld-%02d-%02d'::date",
dt->year, (int)dt->month, (int)dt->day);
else
PyOS_snprintf(buf, sizeof(buf) - 1, "'%04ld-%02d-%02d BC'::date",
1 - dt->year, (int)dt->month, (int)dt->day);
break;
case PSYCO_MXDATETIME_TIMESTAMP:
dt = (mxDateTimeObject *)self->wrapped;
if (dt->year >= 1)
PyOS_snprintf(buf, sizeof(buf) - 1,
"'%04ld-%02d-%02dT%02d:%02d:%09.6f'::timestamp",
dt->year, (int)dt->month, (int)dt->day,
(int)dt->hour, (int)dt->minute, dt->second);
else
PyOS_snprintf(buf, sizeof(buf) - 1,
"'%04ld-%02d-%02dT%02d:%02d:%09.6f BC'::timestamp",
1 - dt->year, (int)dt->month, (int)dt->day,
(int)dt->hour, (int)dt->minute, dt->second);
break;
case PSYCO_MXDATETIME_TIME:
case PSYCO_MXDATETIME_INTERVAL:
/* given the limitation of the mx.DateTime module that uses the same
type for both time and delta values we need to do some black magic
and make sure we're not using an adapt()ed interval as a simple
time */
dtd = (mxDateTimeDeltaObject *)self->wrapped;
if (0 <= dtd->seconds && dtd->seconds < 24*3600) {
PyOS_snprintf(buf, sizeof(buf) - 1, "'%02d:%02d:%09.6f'::time",
(int)dtd->hour, (int)dtd->minute, dtd->second);
} else {
double ss = dtd->hour*3600.0 + dtd->minute*60.0 + dtd->second;
if (dtd->seconds >= 0)
PyOS_snprintf(buf, sizeof(buf) - 1, "'%ld days %.6f seconds'::interval",
dtd->day, ss);
else
PyOS_snprintf(buf, sizeof(buf) - 1, "'-%ld days -%.6f seconds'::interval",
dtd->day, ss);
}
break;
}
return PyString_FromString(buf);
}
static PyObject *
mxdatetime_getquoted(mxdatetimeObject *self, PyObject *args)
{
return mxdatetime_str(self);
}
static PyObject *
mxdatetime_conform(mxdatetimeObject *self, PyObject *args)
{
PyObject *res, *proto;
if (!PyArg_ParseTuple(args, "O", &proto)) return NULL;
if (proto == (PyObject*)&isqlquoteType)
res = (PyObject*)self;
else
res = Py_None;
Py_INCREF(res);
return res;
}
/** the MxDateTime object **/
/* object member list */
static struct PyMemberDef mxdatetimeObject_members[] = {
{"adapted", T_OBJECT, offsetof(mxdatetimeObject, wrapped), READONLY},
{"type", T_INT, offsetof(mxdatetimeObject, type), READONLY},
{NULL}
};
/* object method table */
static PyMethodDef mxdatetimeObject_methods[] = {
{"getquoted", (PyCFunction)mxdatetime_getquoted, METH_NOARGS,
"getquoted() -> wrapped object value as SQL date/time"},
{"__conform__", (PyCFunction)mxdatetime_conform, METH_VARARGS, NULL},
{NULL} /* Sentinel */
};
/* initialization and finalization methods */
static int
mxdatetime_setup(mxdatetimeObject *self, PyObject *obj, int type)
{
Dprintf("mxdatetime_setup: init mxdatetime object at %p, refcnt = "
FORMAT_CODE_PY_SSIZE_T,
self, Py_REFCNT(self)
);
self->type = type;
Py_INCREF(obj);
self->wrapped = obj;
Dprintf("mxdatetime_setup: good mxdatetime object at %p, refcnt = "
FORMAT_CODE_PY_SSIZE_T,
self, Py_REFCNT(self)
);
return 0;
}
static void
mxdatetime_dealloc(PyObject* obj)
{
mxdatetimeObject *self = (mxdatetimeObject *)obj;
Py_CLEAR(self->wrapped);
Dprintf("mxdatetime_dealloc: deleted mxdatetime object at %p, refcnt = "
FORMAT_CODE_PY_SSIZE_T,
obj, Py_REFCNT(obj)
);
Py_TYPE(obj)->tp_free(obj);
}
static int
mxdatetime_init(PyObject *obj, PyObject *args, PyObject *kwds)
{
PyObject *mx;
int type = -1; /* raise an error if type was not passed! */
if (!PyArg_ParseTuple(args, "O|i", &mx, &type))
return -1;
return mxdatetime_setup((mxdatetimeObject *)obj, mx, type);
}
static PyObject *
mxdatetime_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
return type->tp_alloc(type, 0);
}
static PyObject *
mxdatetime_repr(mxdatetimeObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.MxDateTime object at %p>",
self);
}
/* object type */
#define mxdatetimeType_doc \
"MxDateTime(mx, type) -> new mx.DateTime wrapper object"
PyTypeObject mxdatetimeType = {
PyVarObject_HEAD_INIT(NULL, 0)
"psycopg2._psycopg.MxDateTime",
sizeof(mxdatetimeObject), 0,
mxdatetime_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)mxdatetime_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
(reprfunc)mxdatetime_str, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
mxdatetimeType_doc, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
mxdatetimeObject_methods, /*tp_methods*/
mxdatetimeObject_members, /*tp_members*/
0, /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
mxdatetime_init, /*tp_init*/
0, /*tp_alloc*/
mxdatetime_new, /*tp_new*/
};
/** module-level functions **/
#ifdef PSYCOPG_DEFAULT_MXDATETIME
PyObject *
psyco_Date(PyObject *self, PyObject *args)
{
PyObject *res, *mx;
int year, month, day;
if (!PyArg_ParseTuple(args, "iii", &year, &month, &day))
return NULL;
mx = mxDateTime.DateTime_FromDateAndTime(year, month, day, 0, 0, 0.0);
if (mx == NULL) return NULL;
res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_DATE);
Py_DECREF(mx);
return res;
}
PyObject *
psyco_Time(PyObject *self, PyObject *args)
{
PyObject *res, *mx;
int hours, minutes=0;
double seconds=0.0;
if (!PyArg_ParseTuple(args, "iid", &hours, &minutes, &seconds))
return NULL;
mx = mxDateTime.DateTimeDelta_FromTime(hours, minutes, seconds);
if (mx == NULL) return NULL;
res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_TIME);
Py_DECREF(mx);
return res;
}
PyObject *
psyco_Timestamp(PyObject *self, PyObject *args)
{
PyObject *res, *mx;
int year, month, day;
int hour=0, minute=0; /* default to midnight */
double second=0.0;
if (!PyArg_ParseTuple(args, "lii|iid", &year, &month, &day,
&hour, &minute, &second))
return NULL;
mx = mxDateTime.DateTime_FromDateAndTime(year, month, day,
hour, minute, second);
if (mx == NULL) return NULL;
res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_TIMESTAMP);
Py_DECREF(mx);
return res;
}
PyObject *
psyco_DateFromTicks(PyObject *self, PyObject *args)
{
PyObject *res, *mx;
double ticks;
if (!PyArg_ParseTuple(args,"d", &ticks))
return NULL;
if (!(mx = mxDateTime.DateTime_FromTicks(ticks)))
return NULL;
res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_DATE);
Py_DECREF(mx);
return res;
}
PyObject *
psyco_TimeFromTicks(PyObject *self, PyObject *args)
{
PyObject *res, *mx, *dt;
double ticks;
if (!PyArg_ParseTuple(args,"d", &ticks))
return NULL;
if (!(dt = mxDateTime.DateTime_FromTicks(ticks)))
return NULL;
if (!(mx = mxDateTime.DateTimeDelta_FromDaysAndSeconds(
0, ((mxDateTimeObject*)dt)->abstime)))
{
Py_DECREF(dt);
return NULL;
}
Py_DECREF(dt);
res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_TIME);
Py_DECREF(mx);
return res;
}
PyObject *
psyco_TimestampFromTicks(PyObject *self, PyObject *args)
{
PyObject *mx, *res;
double ticks;
if (!PyArg_ParseTuple(args, "d", &ticks))
return NULL;
if (!(mx = mxDateTime.DateTime_FromTicks(ticks)))
return NULL;
res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_TIMESTAMP);
Py_DECREF(mx);
return res;
}
#endif
PyObject *
psyco_DateFromMx(PyObject *self, PyObject *args)
{
PyObject *mx;
if (!PyArg_ParseTuple(args, "O!", mxDateTime.DateTime_Type, &mx))
return NULL;
return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_DATE);
}
PyObject *
psyco_TimeFromMx(PyObject *self, PyObject *args)
{
PyObject *mx;
if (!PyArg_ParseTuple(args, "O!", mxDateTime.DateTimeDelta_Type, &mx))
return NULL;
return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_TIME);
}
PyObject *
psyco_TimestampFromMx(PyObject *self, PyObject *args)
{
PyObject *mx;
if (!PyArg_ParseTuple(args, "O!", mxDateTime.DateTime_Type, &mx))
return NULL;
return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_TIMESTAMP);
}
PyObject *
psyco_IntervalFromMx(PyObject *self, PyObject *args)
{
PyObject *mx;
if (!PyArg_ParseTuple(args, "O!", mxDateTime.DateTime_Type, &mx))
return NULL;
return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx,
PSYCO_MXDATETIME_INTERVAL);
}

View File

@ -1,98 +0,0 @@
/* adapter_mxdatetime.h - definition for the mx date/time types
*
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org>
*
* This file is part of psycopg.
*
* psycopg2 is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link this program with the OpenSSL library (or with
* modified versions of OpenSSL that use the same license as OpenSSL),
* and distribute linked combinations including the two.
*
* You must obey the GNU Lesser General Public License in all respects for
* all of the code used other than OpenSSL.
*
* psycopg2 is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#ifndef PSYCOPG_MXDATETIME_H
#define PSYCOPG_MXDATETIME_H 1
#ifdef __cplusplus
extern "C" {
#endif
extern HIDDEN PyTypeObject mxdatetimeType;
typedef struct {
PyObject_HEAD
PyObject *wrapped;
int type;
#define PSYCO_MXDATETIME_TIME 0
#define PSYCO_MXDATETIME_DATE 1
#define PSYCO_MXDATETIME_TIMESTAMP 2
#define PSYCO_MXDATETIME_INTERVAL 3
} mxdatetimeObject;
/* functions exported to psycopgmodule.c */
#ifdef PSYCOPG_DEFAULT_MXDATETIME
HIDDEN PyObject *psyco_Date(PyObject *module, PyObject *args);
#define psyco_Date_doc \
"Date(year, month, day) -> new date"
HIDDEN PyObject *psyco_Time(PyObject *module, PyObject *args);
#define psyco_Time_doc \
"Time(hour, minutes, seconds) -> new time"
HIDDEN PyObject *psyco_Timestamp(PyObject *module, PyObject *args);
#define psyco_Timestamp_doc \
"Time(year, month, day, hour, minutes, seconds) -> new timestamp"
HIDDEN PyObject *psyco_DateFromTicks(PyObject *module, PyObject *args);
#define psyco_DateFromTicks_doc \
"DateFromTicks(ticks) -> new date"
HIDDEN PyObject *psyco_TimeFromTicks(PyObject *module, PyObject *args);
#define psyco_TimeFromTicks_doc \
"TimeFromTicks(ticks) -> new time"
HIDDEN PyObject *psyco_TimestampFromTicks(PyObject *module, PyObject *args);
#define psyco_TimestampFromTicks_doc \
"TimestampFromTicks(ticks) -> new timestamp"
#endif /* PSYCOPG_DEFAULT_MXDATETIME */
HIDDEN int psyco_adapter_mxdatetime_init(void);
HIDDEN PyObject *psyco_DateFromMx(PyObject *module, PyObject *args);
#define psyco_DateFromMx_doc \
"DateFromMx(mx) -> new date"
HIDDEN PyObject *psyco_TimeFromMx(PyObject *module, PyObject *args);
#define psyco_TimeFromMx_doc \
"TimeFromMx(mx) -> new time"
HIDDEN PyObject *psyco_TimestampFromMx(PyObject *module, PyObject *args);
#define psyco_TimestampFromMx_doc \
"TimestampFromMx(mx) -> new timestamp"
HIDDEN PyObject *psyco_IntervalFromMx(PyObject *module, PyObject *args);
#define psyco_IntervalFromMx_doc \
"IntervalFromMx(mx) -> new interval"
#ifdef __cplusplus
}
#endif
#endif /* !defined(PSYCOPG_MXDATETIME_H) */

View File

@ -1,6 +1,7 @@
/* adapter_pboolean.c - psycopg boolean type wrapper implementation /* adapter_pboolean.c - psycopg boolean type wrapper implementation
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -37,27 +38,18 @@
static PyObject * static PyObject *
pboolean_getquoted(pbooleanObject *self, PyObject *args) pboolean_getquoted(pbooleanObject *self, PyObject *args)
{ {
#ifdef PSYCOPG_NEW_BOOLEAN
if (PyObject_IsTrue(self->wrapped)) { if (PyObject_IsTrue(self->wrapped)) {
return Bytes_FromString("true"); return Bytes_FromString("true");
} }
else { else {
return Bytes_FromString("false"); return Bytes_FromString("false");
} }
#else
if (PyObject_IsTrue(self->wrapped)) {
return Bytes_FromString("'t'");
}
else {
return Bytes_FromString("'f'");
}
#endif
} }
static PyObject * static PyObject *
pboolean_str(pbooleanObject *self) pboolean_str(pbooleanObject *self)
{ {
return psycopg_ensure_text(pboolean_getquoted(self, NULL)); return psyco_ensure_text(pboolean_getquoted(self, NULL));
} }
static PyObject * static PyObject *
@ -146,13 +138,6 @@ pboolean_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
static PyObject *
pboolean_repr(pbooleanObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.Boolean object at %p>",
self);
}
/* object type */ /* object type */
@ -161,14 +146,14 @@ pboolean_repr(pbooleanObject *self)
PyTypeObject pbooleanType = { PyTypeObject pbooleanType = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"psycopg2._psycopg.Boolean", "psycopg2.extensions.Boolean",
sizeof(pbooleanObject), 0, sizeof(pbooleanObject), 0,
pboolean_dealloc, /*tp_dealloc*/ pboolean_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)pboolean_repr, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -198,17 +183,3 @@ PyTypeObject pbooleanType = {
0, /*tp_alloc*/ 0, /*tp_alloc*/
pboolean_new, /*tp_new*/ pboolean_new, /*tp_new*/
}; };
/** module-level functions **/
PyObject *
psyco_Boolean(PyObject *module, PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
return PyObject_CallFunctionObjArgs((PyObject *)&pbooleanType, obj, NULL);
}

View File

@ -1,6 +1,7 @@
/* adapter_pboolean.h - definition for the psycopg boolean type wrapper /* adapter_pboolean.h - definition for the psycopg boolean type wrapper
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -40,12 +41,6 @@ typedef struct {
} pbooleanObject; } pbooleanObject;
/* functions exported to psycopgmodule.c */
HIDDEN PyObject *psyco_Boolean(PyObject *module, PyObject *args);
#define psyco_Boolean_doc \
"Boolean(obj) -> new boolean value"
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,6 +1,7 @@
/* adapter_pdecimal.c - psycopg Decimal type wrapper implementation /* adapter_pdecimal.c - psycopg Decimal type wrapper implementation
* *
* Copyright (C) 2003-2010 Federico Di Gregorio <fog@debian.org> * Copyright (C) 2003-2019 Federico Di Gregorio <fog@debian.org>
* Copyright (C) 2020-2021 The Psycopg Team
* *
* This file is part of psycopg. * This file is part of psycopg.
* *
@ -80,8 +81,7 @@ pdecimal_getquoted(pdecimalObject *self, PyObject *args)
/* res may be unicode and may suffer for issue #57 */ /* res may be unicode and may suffer for issue #57 */
output: output:
#if PY_MAJOR_VERSION > 2 /* unicode to bytes */
/* unicode to bytes in Py3 */
{ {
PyObject *tmp = PyUnicode_AsUTF8String(res); PyObject *tmp = PyUnicode_AsUTF8String(res);
Py_DECREF(res); Py_DECREF(res);
@ -89,7 +89,6 @@ output:
goto end; goto end;
} }
} }
#endif
if ('-' == Bytes_AS_STRING(res)[0]) { if ('-' == Bytes_AS_STRING(res)[0]) {
/* Prepend a space in front of negative numbers (ticket #57) */ /* Prepend a space in front of negative numbers (ticket #57) */
@ -113,7 +112,7 @@ end:
static PyObject * static PyObject *
pdecimal_str(pdecimalObject *self) pdecimal_str(pdecimalObject *self)
{ {
return psycopg_ensure_text(pdecimal_getquoted(self, NULL)); return psyco_ensure_text(pdecimal_getquoted(self, NULL));
} }
static PyObject * static PyObject *
@ -202,13 +201,6 @@ pdecimal_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return type->tp_alloc(type, 0); return type->tp_alloc(type, 0);
} }
static PyObject *
pdecimal_repr(pdecimalObject *self)
{
return PyString_FromFormat("<psycopg2._psycopg.Decimal object at %p>",
self);
}
/* object type */ /* object type */
@ -224,7 +216,7 @@ PyTypeObject pdecimalType = {
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
(reprfunc)pdecimal_repr, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -254,17 +246,3 @@ PyTypeObject pdecimalType = {
0, /*tp_alloc*/ 0, /*tp_alloc*/
pdecimal_new, /*tp_new*/ pdecimal_new, /*tp_new*/
}; };
/** module-level functions **/
PyObject *
psyco_Decimal(PyObject *module, PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O", &obj))
return NULL;
return PyObject_CallFunctionObjArgs((PyObject *)&pdecimalType, obj, NULL);
}

Some files were not shown because too many files have changed in this diff Show More