1
0
Fork 0

Adding upstream version 1.1.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 20:22:59 +01:00
parent 9c1e264be3
commit f19547bec9
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
22 changed files with 4449 additions and 0 deletions

47
.github/workflows/publish.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: Build and Publish Package
on:
pull_request:
branches:
- main
types:
- closed
jobs:
publish-package:
if: ${{ github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v') }}
runs-on: ubuntu-latest
steps:
- name: Check out harlequin-postgres main branch
uses: actions/checkout@v4
with:
ref: main
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.6.1
- name: Configure poetry
run: poetry config --no-interaction pypi-token.pypi ${{ secrets.HARLEQUIN_PG_PYPI_TOKEN }}
- name: Get harlequin-postgres Version
id: harlequin_pg_version
run: echo "harlequin_pg_version=$(poetry version --short)" >> $GITHUB_OUTPUT
- name: Build package
run: poetry build --no-interaction
- name: Publish package to PyPI
run: poetry publish --no-interaction
- name: Create a Github Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ steps.harlequin_pg_version.outputs.harlequin_pg_version }}
target_commitish: main
token: ${{ secrets.HARLEQUIN_PG_RELEASE_TOKEN }}
body_path: CHANGELOG.md
files: |
LICENSE
dist/*harlequin*.whl
dist/*harlequin*.tar.gz

57
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: Create Release Branch
on:
workflow_dispatch:
inputs:
newVersion:
description: A version number for this release (e.g., "0.1.0")
required: true
jobs:
prepare-release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Check out harlequin-postgres main branch
uses: actions/checkout@v4
with:
ref: main
- name: Set up Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.6.1
- name: Create release branch
run: |
git checkout -b release/v${{ github.event.inputs.newVersion }}
git push --set-upstream origin release/v${{ github.event.inputs.newVersion }}
- name: Bump version
run: poetry version ${{ github.event.inputs.newVersion }} --no-interaction
- name: Ensure package can be built
run: poetry build --no-interaction
- name: Update CHANGELOG
uses: thomaseizinger/keep-a-changelog-new-release@v1
with:
version: ${{ github.event.inputs.newVersion }}
- name: Commit Changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Bumps version to ${{ github.event.inputs.newVersion }}
- name: Create pull request into main
uses: thomaseizinger/create-pull-request@1.3.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
head: release/v${{ github.event.inputs.newVersion }}
base: main
title: v${{ github.event.inputs.newVersion }}
body: >
This PR was automatically generated. It bumps the version number
in pyproject.toml and updates CHANGELOG.md. You may have to close
this PR and reopen it to get the required checks to run.

163
.gitignore vendored Normal file
View file

@ -0,0 +1,163 @@
profile.html
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
Pipfile
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

95
CHANGELOG.md Normal file
View file

@ -0,0 +1,95 @@
# Harlequin-Postgres CHANGELOG
All notable changes to this project will be documented in this file.
## [Unreleased]
## [1.1.1] - 2025-02-05
- This adapter now supports `infinity` and `-infinity` dates and timestamps by loading their values as `date[time].max` or `date[time].min` ([tconbeer/harlequin#690](https://github.com/tconbeer/harlequin/issues/690)).
## [1.1.0] - 2025-01-27
- This adapter now lazy-loads the catalog, which will dramatically improve the catalog performance for large databases with thousands of objects.
- This adapter now implements interactions for catalog items, like dropping tables, setting the search path, etc.
## [1.0.0] - 2025-01-07
- Drops support for Python 3.8
- Adds support for Python 3.13
- Adds support for Harlequin 2.X
## [0.4.0] - 2024-08-20
- Upgrades client library to `psycopg3` (from `psycopg2`).
- Adds an implementation of `connection_id` to improve catalog and history persistence.
- Implements `cancel()` to interrupt in-flight queries.
## [0.3.0] - 2024-07-22
- Adds an implementation of `close` to gracefully close the connection pool on Harlequin shut-down.
- Adds support for Harlequin Transaction Modes and manual transactions.
## [0.2.2] - 2024-01-09
- Sorts databases, schemas, and relations alphabetically; sorts columns ordinally. ([#10](https://github.com/tconbeer/harlequin-postgres/issues/10) - thank you [@frankbreetz](https://github.com/frankbreetz)!)
## [0.2.1] - 2023-12-14
- Lowercases inserted values for keyword completions.
## [0.2.0] - 2023-12-14
### Features
- Implements get_completions for keywords, functions, and settings.
## [0.1.3] - 2023-11-28
### Bug fixes
- Implements connection pools instead of sharing a connection across threads.
## [0.1.2] - 2023-11-27
### Bug fixes
- Fixes issues with package metadata.
## [0.1.1] - 2023-11-27
### Bug fixes
- Fixes typo in release script.
## [0.1.0] - 2023-11-27
### Features
- Adds a basic Postgres adapter with most common connection options.
[Unreleased]: https://github.com/tconbeer/harlequin-postgres/compare/1.1.1...HEAD
[1.1.1]: https://github.com/tconbeer/harlequin-postgres/compare/1.1.0...1.1.1
[1.1.0]: https://github.com/tconbeer/harlequin-postgres/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/tconbeer/harlequin-postgres/compare/0.4.0...1.0.0
[0.4.0]: https://github.com/tconbeer/harlequin-postgres/compare/0.3.0...0.4.0
[0.3.0]: https://github.com/tconbeer/harlequin-postgres/compare/0.2.2...0.3.0
[0.2.2]: https://github.com/tconbeer/harlequin-postgres/compare/0.2.1...0.2.2
[0.2.1]: https://github.com/tconbeer/harlequin-postgres/compare/0.2.0...0.2.1
[0.2.0]: https://github.com/tconbeer/harlequin-postgres/compare/0.1.3...0.2.0
[0.1.3]: https://github.com/tconbeer/harlequin-postgres/compare/0.1.2...0.1.3
[0.1.2]: https://github.com/tconbeer/harlequin-postgres/compare/0.1.1...0.1.2
[0.1.1]: https://github.com/tconbeer/harlequin-postgres/compare/0.1.0...0.1.1
[0.1.0]: https://github.com/tconbeer/harlequin-postgres/compare/8611e628dc9d28b6a24817c761cd8a6da11a87ad...0.1.0

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Ted Conbeer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

25
Makefile Normal file
View file

@ -0,0 +1,25 @@
.PHONY: check
check:
ruff format .
ruff check . --fix
mypy
pytest
.PHONY: init
init:
docker-compose up -d
.PHONY: clean
clean:
docker-compose down
.PHONY: serve
serve:
harlequin -P None -a postgres "postgresql://postgres:for-testing@localhost:5432/postgres"
.PHONY: psql
psql:
PGPASSWORD=for-testing psql -h localhost -p 5432 -U postgres
profile.html: $(wildcard src/**/*.py)
pyinstrument -r html -o profile.html --from-path harlequin -a postgres "postgresql://postgres:for-testing@localhost:5432/postgres"

77
README.md Normal file
View file

@ -0,0 +1,77 @@
# harlequin-postgres
This repo provides the Harlequin adapter for Postgres.
## Installation
`harlequin-postgres` depends on `harlequin`, so installing this package will also install Harlequin.
### Using pip
To install this adapter into an activated virtual environment:
```bash
pip install harlequin-postgres
```
### Using poetry
```bash
poetry add harlequin-postgres
```
### Using pipx
If you do not already have Harlequin installed:
```bash
pip install harlequin-postgres
```
If you would like to add the Postgres adapter to an existing Harlequin installation:
```bash
pipx inject harlequin harlequin-postgres
```
### As an Extra
Alternatively, you can install Harlequin with the `postgres` extra:
```bash
pip install harlequin[postgres]
```
```bash
poetry add harlequin[postgres]
```
```bash
pipx install harlequin[postgres]
```
## Usage and Configuration
You can open Harlequin with the Postgres adapter by selecting it with the `-a` option and passing a [Posgres DSN](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING):
```bash
harlequin -a postgres "postgres://my-user:my-pass@localhost:5432/my-database"
```
You can also pass all or parts of the connection string as separate options. The following is equivalent to the above DSN:
```bash
harlequin -a postgres -h localhost -p 5432 -U my-user --password my-pass -d my-database
```
Many more options are available; to see the full list, run:
```bash
harlequin --help
```
## Manual Transactions
To use Manual transaction mode, click on the label in the Run Query Bar to toggle the transaction mode from Auto to Manual.
## Further Documentation
For more information, see the [Harlequin Docs](https://harlequin.sh/docs/postgres/index).

14
docker-compose.yml Normal file
View file

@ -0,0 +1,14 @@
services:
db:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: for-testing
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- 5432:5432
volumes:
pgdata:

1561
poetry.lock generated Normal file

File diff suppressed because it is too large Load diff

68
pyproject.toml Normal file
View file

@ -0,0 +1,68 @@
[tool.poetry]
name = "harlequin-postgres"
version = "1.1.1"
description = "A Harlequin adapter for Postgres."
authors = ["Ted Conbeer <tconbeer@users.noreply.github.com>"]
license = "MIT"
readme = "README.md"
packages = [
{ include = "harlequin_postgres", from = "src" },
]
[tool.poetry.plugins."harlequin.adapter"]
postgres = "harlequin_postgres:HarlequinPostgresAdapter"
[tool.poetry.dependencies]
python = ">=3.9,<3.14"
harlequin = ">=1.25,<3"
psycopg = { version = "^3.2", extras = ["binary", "pool"]}
[tool.poetry.group.dev.dependencies]
ruff = "^0.5"
pytest = "^7.4.3"
mypy = "^1.10.0"
pre-commit = "^3.5.0"
importlib_metadata = { version = ">=4.6.0", python = "<3.10.0" }
pyinstrument = "^4.6.1"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.ruff]
target-version = "py39"
[tool.ruff.lint]
select = ["A", "B", "E", "F", "I"]
[tool.mypy]
python_version = "3.9"
files = [
"src/**/*.py",
"tests/**/*.py",
]
mypy_path = "src:stubs"
show_column_numbers = true
# show error messages from unrelated files
follow_imports = "normal"
# be strict
disallow_untyped_calls = true
disallow_untyped_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
strict_optional = true
warn_return_any = true
warn_no_return = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_unused_configs = true
no_implicit_reexport = true
strict_equality = true

View file

@ -0,0 +1,3 @@
from harlequin_postgres.adapter import HarlequinPostgresAdapter
__all__ = ["HarlequinPostgresAdapter"]

View file

@ -0,0 +1,453 @@
from __future__ import annotations
from itertools import cycle
from typing import Any, Sequence
from harlequin import (
HarlequinAdapter,
HarlequinCompletion,
HarlequinConnection,
HarlequinCursor,
HarlequinTransactionMode,
)
from harlequin.catalog import Catalog, CatalogItem
from harlequin.exception import HarlequinConnectionError, HarlequinQueryError
from psycopg import Connection, Cursor, conninfo
from psycopg.errors import QueryCanceled
from psycopg.pq import TransactionStatus
from psycopg_pool import ConnectionPool
from textual_fastdatatable.backend import AutoBackendType
from harlequin_postgres.catalog import DatabaseCatalogItem
from harlequin_postgres.cli_options import POSTGRES_OPTIONS
from harlequin_postgres.completions import _get_completions
from harlequin_postgres.loaders import register_inf_loaders
class HarlequinPostgresCursor(HarlequinCursor):
def __init__(self, conn: HarlequinPostgresConnection, cur: Cursor) -> None:
self.conn = conn
self.cur = cur
# we need to copy the description from the cursor in case the results are
# fetched and the cursor is closed before columns() is called.
assert cur.description is not None
self.description = cur.description.copy()
self._limit: int | None = None
def columns(self) -> list[tuple[str, str]]:
return [
(col.name, self.conn._short_column_type_from_oid(col.type_code))
for col in self.description
]
def set_limit(self, limit: int) -> HarlequinPostgresCursor:
self._limit = limit
return self
def fetchall(self) -> AutoBackendType:
try:
if self._limit is None:
return self.cur.fetchall()
else:
return self.cur.fetchmany(self._limit)
except QueryCanceled:
return []
except Exception as e:
raise HarlequinQueryError(
msg=f"{e.__class__.__name__}: {e}",
title="Harlequin encountered an error while executing your query.",
) from e
finally:
self.cur.close()
class HarlequinPostgresConnection(HarlequinConnection):
def __init__(
self,
conn_str: Sequence[str],
*_: Any,
init_message: str = "",
options: dict[str, Any],
) -> None:
self.init_message = init_message
try:
self.conn_info = conninfo.conninfo_to_dict(
conninfo=conn_str[0] if conn_str else "", **options
)
except Exception as e:
raise HarlequinConnectionError(
msg=str(e),
title=(
"Harlequin could not connect to Postgres. "
"Invalid connection string."
),
) from e
try:
raw_timeout = self.conn_info.get("connect_timeout")
timeout = float(raw_timeout) if raw_timeout is not None else 30.0
except (TypeError, ValueError) as e:
raise HarlequinConnectionError(
msg=str(e),
title=(
"Harlequin could not connect to Postgres. "
"Invalid value for connection_timeout."
),
) from e
try:
self.pool: ConnectionPool = ConnectionPool(
conninfo=conn_str[0] if conn_str and conn_str[0] else "",
min_size=2,
max_size=5,
kwargs=options,
open=True,
timeout=timeout,
)
self._main_conn: Connection = self.pool.getconn()
except Exception as e:
raise HarlequinConnectionError(
msg=str(e), title="Harlequin could not connect to Postgres."
) from e
self._transaction_modes = cycle(
[
HarlequinTransactionMode(label="Auto"),
HarlequinTransactionMode(
label="Manual",
commit=self.commit,
rollback=self.rollback,
),
]
)
self.toggle_transaction_mode()
def execute(self, query: str) -> HarlequinCursor | None:
if (
self.transaction_mode.label != "Auto"
and self._main_conn.info.transaction_status == TransactionStatus.IDLE
):
cur = self._main_conn.cursor()
cur.execute(query="begin;")
cur.close()
try:
cur = self._main_conn.cursor()
cur.execute(query=query)
except QueryCanceled:
cur.close()
return None
except Exception as e:
cur.close()
self.rollback()
raise HarlequinQueryError(
msg=str(e),
title="Harlequin encountered an error while executing your query.",
) from e
else:
if cur.description is not None:
return HarlequinPostgresCursor(self, cur)
else:
cur.close()
return None
def cancel(self) -> None:
self._main_conn.cancel_safe()
def commit(self) -> None:
self._main_conn.commit()
def rollback(self) -> None:
self._main_conn.rollback()
def get_catalog(self) -> Catalog:
databases = self._get_databases()
db_items: list[CatalogItem] = [
DatabaseCatalogItem.from_label(label=db, connection=self)
for (db,) in databases
]
return Catalog(items=db_items)
def get_completions(self) -> list[HarlequinCompletion]:
conn: Connection = self.pool.getconn()
completions = _get_completions(conn)
self.pool.putconn(conn)
return completions
def close(self) -> None:
self.pool.putconn(self._main_conn)
self.pool.close()
@property
def transaction_mode(self) -> HarlequinTransactionMode:
return self._transaction_mode
def toggle_transaction_mode(self) -> HarlequinTransactionMode:
self._transaction_mode = next(self._transaction_modes)
self._sync_transaction_mode()
return self._transaction_mode
def _sync_transaction_mode(self) -> None:
"""
Sync this class's transaction mode with the main connection
"""
conn = self._main_conn
if self.transaction_mode.label == "Auto":
conn.autocommit = True
conn.commit()
else:
conn.autocommit = False
def _get_databases(self) -> list[tuple[str]]:
conn: Connection = self.pool.getconn()
with conn.cursor() as cur:
cur.execute(
"""
select datname
from pg_database
where
datistemplate is false
and datallowconn is true
order by datname asc
;"""
)
results: list[tuple[str]] = cur.fetchall()
self.pool.putconn(conn)
return results
def _get_schemas(self, dbname: str) -> list[tuple[str]]:
conn: Connection = self.pool.getconn()
with conn.cursor() as cur:
cur.execute(
f"""
select schema_name
from information_schema.schemata
where
catalog_name = '{dbname}'
and schema_name != 'information_schema'
and schema_name not like 'pg_%'
order by schema_name asc
;"""
)
results: list[tuple[str]] = cur.fetchall()
self.pool.putconn(conn)
return results
def _get_relations(self, dbname: str, schema: str) -> list[tuple[str, str]]:
conn: Connection = self.pool.getconn()
with conn.cursor() as cur:
cur.execute(
f"""
select table_name, table_type
from information_schema.tables
where
table_catalog = '{dbname}'
and table_schema = '{schema}'
order by table_name asc
;"""
)
results: list[tuple[str, str]] = cur.fetchall()
self.pool.putconn(conn)
return results
def _get_columns(
self, dbname: str, schema: str, relation: str
) -> list[tuple[str, str]]:
conn: Connection = self.pool.getconn()
with conn.cursor() as cur:
cur.execute(
f"""
select column_name, data_type
from information_schema.columns
where
table_catalog = '{dbname}'
and table_schema = '{schema}'
and table_name = '{relation}'
order by ordinal_position asc
;"""
)
results: list[tuple[str, str]] = cur.fetchall()
self.pool.putconn(conn)
return results
@staticmethod
def _short_column_type(type_name: str) -> str:
MAPPING = {
"bigint": "##",
"bigserial": "##",
"bit": "010",
"boolean": "t/f",
"box": "",
"bytea": "b",
"character": "s",
"cidr": "ip",
"circle": "",
"date": "d",
"double": "#.#",
"inet": "ip",
"integer": "#",
"interval": "|-|",
"json": "{}",
"jsonb": "b{}",
"line": "",
"lseg": "-",
"macaddr": "mac",
"macaddr8": "mac",
"money": "$$",
"numeric": "#.#",
"path": "",
"pg_lsn": "lsn",
"pg_snapshot": "snp",
"point": "",
"polygon": "",
"real": "#.#",
"smallint": "#",
"smallserial": "#",
"serial": "#",
"text": "s",
"time": "t",
"timestamp": "ts",
"tsquery": "tsq",
"tsvector": "tsv",
"txid_snapshot": "snp",
"uuid": "uid",
"xml": "xml",
"array": "[]",
}
return MAPPING.get(type_name.split("(")[0].split(" ")[0], "?")
@staticmethod
def _short_column_type_from_oid(oid: int) -> str:
MAPPING = {
16: "t/f",
17: "b",
18: "s",
19: "s",
20: "##",
21: "#",
22: "[#]",
23: "#",
25: "s",
26: "oid",
114: "{}",
142: "xml",
600: "",
601: "-",
602: "",
603: "",
604: "",
628: "",
651: "[ip]",
700: "#.#",
701: "#.#",
704: "|-|",
718: "",
790: "$$",
829: "mac",
869: "ip",
650: "ip",
774: "mac",
1000: "[t/f]",
1001: "[b]",
1002: "[s]",
1003: "[s]",
1009: "[s]",
1013: "[oid]",
1014: "[s]",
1015: "[s]",
1016: "[#]",
1021: "[#.#]",
1022: "[#.#]",
1028: "[oid]",
1040: "[mac]",
1041: "[ip]",
1042: "s",
1043: "s",
1082: "d",
1083: "t",
1114: "ts",
1115: "[ts]",
1182: "[d]",
1183: "[t]",
1184: "ts",
1185: "[ts]",
1186: "|-|",
1187: "[|-|]",
1231: "[#.#]",
1266: "t",
1270: "[t]",
1560: "010",
1562: "010",
1700: "#.#",
2950: "uid",
3614: "tsv",
3615: "tsq",
3802: "b{}",
}
return MAPPING.get(oid, "?")
class HarlequinPostgresAdapter(HarlequinAdapter):
ADAPTER_OPTIONS = POSTGRES_OPTIONS
IMPLEMENTS_CANCEL = True
def __init__(
self,
conn_str: Sequence[str],
host: str | None = None,
port: str | None = None,
dbname: str | None = None,
user: str | None = None,
password: str | None = None,
passfile: str | None = None,
require_auth: str | None = None,
channel_binding: str | None = None,
connect_timeout: int | float | None = None,
sslmode: str | None = None,
sslcert: str | None = None,
sslkey: str | None = None,
**_: Any,
) -> None:
self.conn_str = conn_str
self.options: dict[str, str | int | None] = {
"host": host,
"port": port,
"dbname": dbname,
"user": user,
"password": password,
"passfile": passfile,
"require_auth": require_auth,
"channel_binding": channel_binding,
"connect_timeout": connect_timeout, # type: ignore[dict-item]
"sslmode": sslmode,
"sslcert": sslcert,
"sslkey": sslkey,
}
@property
def connection_id(self) -> str | None:
"""
Use a simplified connection string, with only the host, port, and database
"""
try:
conn_info = conninfo.conninfo_to_dict(
conninfo=self.conn_str[0] if self.conn_str else "",
**self.options,
)
except Exception:
return None
host = conn_info.get("host", "localhost")
port = conn_info.get("port", "5432")
dbname = conn_info.get("dbname", "postgres")
return f"{host}:{port}/{dbname}"
def connect(self) -> HarlequinPostgresConnection:
if len(self.conn_str) > 1:
raise HarlequinConnectionError(
"Cannot provide multiple connection strings to the Postgres adapter. "
f"{self.conn_str}"
)
# before creating the connection, register updated type adapters, so
# all subsequent connections will use those adapters
register_inf_loaders()
conn = HarlequinPostgresConnection(self.conn_str, options=self.options)
return conn

View file

@ -0,0 +1,253 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
from harlequin.catalog import InteractiveCatalogItem
from harlequin_postgres.interactions import (
execute_drop_database_statement,
execute_drop_foreign_table_statement,
execute_drop_schema_statement,
execute_drop_table_statement,
execute_drop_view_statement,
execute_use_statement,
insert_columns_at_cursor,
show_select_star,
)
if TYPE_CHECKING:
from harlequin_postgres.adapter import HarlequinPostgresConnection
@dataclass
class ColumnCatalogItem(InteractiveCatalogItem["HarlequinPostgresConnection"]):
parent: "RelationCatalogItem" | None = None
@classmethod
def from_parent(
cls,
parent: "RelationCatalogItem",
label: str,
type_label: str,
) -> "ColumnCatalogItem":
column_qualified_identifier = f'{parent.qualified_identifier}."{label}"'
column_query_name = f'"{label}"'
return cls(
qualified_identifier=column_qualified_identifier,
query_name=column_query_name,
label=label,
type_label=type_label,
connection=parent.connection,
parent=parent,
loaded=True,
)
@dataclass
class RelationCatalogItem(InteractiveCatalogItem["HarlequinPostgresConnection"]):
INTERACTIONS = [
("Insert Columns at Cursor", insert_columns_at_cursor),
("Preview Data", show_select_star),
]
parent: "SchemaCatalogItem" | None = None
def fetch_children(self) -> list[ColumnCatalogItem]:
if self.parent is None or self.parent.parent is None or self.connection is None:
return []
result = self.connection._get_columns(
self.parent.parent.label, self.parent.label, self.label
)
return [
ColumnCatalogItem.from_parent(
parent=self,
label=column_name,
type_label=self.connection._short_column_type(column_type),
)
for column_name, column_type in result
]
class ViewCatalogItem(RelationCatalogItem):
INTERACTIONS = RelationCatalogItem.INTERACTIONS + [
("Drop View", execute_drop_view_statement),
]
@classmethod
def from_parent(
cls,
parent: "SchemaCatalogItem",
label: str,
) -> "ViewCatalogItem":
relation_query_name = f'"{parent.label}"."{label}"'
relation_qualified_identifier = f'{parent.qualified_identifier}."{label}"'
return cls(
qualified_identifier=relation_qualified_identifier,
query_name=relation_query_name,
label=label,
type_label="v",
connection=parent.connection,
parent=parent,
)
class TableCatalogItem(RelationCatalogItem):
INTERACTIONS = RelationCatalogItem.INTERACTIONS + [
("Drop Table", execute_drop_table_statement),
]
@classmethod
def from_parent(
cls,
parent: "SchemaCatalogItem",
label: str,
) -> "TableCatalogItem":
relation_query_name = f'"{parent.label}"."{label}"'
relation_qualified_identifier = f'{parent.qualified_identifier}."{label}"'
return cls(
qualified_identifier=relation_qualified_identifier,
query_name=relation_query_name,
label=label,
type_label="t",
connection=parent.connection,
parent=parent,
)
class TempTableCatalogItem(TableCatalogItem):
INTERACTIONS = RelationCatalogItem.INTERACTIONS + [
("Drop Table", execute_drop_table_statement),
]
@classmethod
def from_parent(
cls,
parent: "SchemaCatalogItem",
label: str,
) -> "TempTableCatalogItem":
relation_query_name = f'"{parent.label}"."{label}"'
relation_qualified_identifier = f'{parent.qualified_identifier}."{label}"'
return cls(
qualified_identifier=relation_qualified_identifier,
query_name=relation_query_name,
label=label,
type_label="tmp",
connection=parent.connection,
parent=parent,
)
class ForeignCatalogItem(TableCatalogItem):
INTERACTIONS = RelationCatalogItem.INTERACTIONS + [
("Drop Table", execute_drop_foreign_table_statement),
]
@classmethod
def from_parent(
cls,
parent: "SchemaCatalogItem",
label: str,
) -> "ForeignCatalogItem":
relation_query_name = f'"{parent.label}"."{label}"'
relation_qualified_identifier = f'{parent.qualified_identifier}."{label}"'
return cls(
qualified_identifier=relation_qualified_identifier,
query_name=relation_query_name,
label=label,
type_label="f",
connection=parent.connection,
parent=parent,
)
@dataclass
class SchemaCatalogItem(InteractiveCatalogItem["HarlequinPostgresConnection"]):
INTERACTIONS = [
("Set Search Path", execute_use_statement),
("Drop Schema", execute_drop_schema_statement),
]
parent: "DatabaseCatalogItem" | None = None
@classmethod
def from_parent(
cls,
parent: "DatabaseCatalogItem",
label: str,
) -> "SchemaCatalogItem":
schema_identifier = f'"{label}"'
return cls(
qualified_identifier=schema_identifier,
query_name=schema_identifier,
label=label,
type_label="sch",
connection=parent.connection,
parent=parent,
)
def fetch_children(self) -> list[RelationCatalogItem]:
if self.parent is None or self.connection is None:
return []
children: list[RelationCatalogItem] = []
result = self.connection._get_relations(self.parent.label, self.label)
for table_label, table_type in result:
if table_type == "VIEW":
children.append(
ViewCatalogItem.from_parent(
parent=self,
label=table_label,
)
)
elif table_type == "LOCAL TEMPORARY":
children.append(
TempTableCatalogItem.from_parent(
parent=self,
label=table_label,
)
)
elif table_type == "FOREIGN":
children.append(
ForeignCatalogItem.from_parent(
parent=self,
label=table_label,
)
)
else:
children.append(
TableCatalogItem.from_parent(
parent=self,
label=table_label,
)
)
return children
class DatabaseCatalogItem(InteractiveCatalogItem["HarlequinPostgresConnection"]):
INTERACTIONS = [
("Drop Database", execute_drop_database_statement),
]
@classmethod
def from_label(
cls, label: str, connection: "HarlequinPostgresConnection"
) -> "DatabaseCatalogItem":
database_identifier = f'"{label}"'
return cls(
qualified_identifier=database_identifier,
query_name=database_identifier,
label=label,
type_label="db",
connection=connection,
)
def fetch_children(self) -> list[SchemaCatalogItem]:
if self.connection is None:
return []
schemas = self.connection._get_schemas(self.label)
return [
SchemaCatalogItem.from_parent(
parent=self,
label=schema_label,
)
for (schema_label,) in schemas
]

View file

@ -0,0 +1,157 @@
from __future__ import annotations
from harlequin.options import (
FlagOption, # noqa
ListOption, # noqa
PathOption, # noqa
SelectOption, # noqa
TextOption,
)
host = TextOption(
name="host",
description=(
"Specifies the host name of the machine on which the server is running. "
"If the value begins with a slash, it is used as the directory for the "
"Unix-domain socket."
),
short_decls=["-h"],
default="localhost",
)
port = TextOption(
name="port",
description=(
"Port number to connect to at the server host, or socket file name extension "
"for Unix-domain connections."
),
short_decls=["-p"],
default="5432",
)
dbname = TextOption(
name="dbname",
description=("The database name to use when connecting with the Postgres server."),
short_decls=["-d"],
default="postgres",
)
user = TextOption(
name="user",
description=("PostgreSQL user name to connect as."),
short_decls=["-u", "--username", "-U"],
)
password = TextOption(
name="password",
description=("Password to be used if the server demands password authentication."),
)
passfile = PathOption(
name="passfile",
description=(
"Specifies the name of the file used to store passwords. Defaults to "
r"~/.pgpass, or %APPDATA%\postgresql\pgpass.conf on Windows. (No error is "
"reported if this file does not exist.)"
),
resolve_path=True,
exists=False,
file_okay=True,
dir_okay=False,
)
require_auth = SelectOption(
name="require_auth",
description=(
"Specifies the authentication method that the client requires from the server. "
"If the server does not use the required method to authenticate the client, or "
"if the authentication handshake is not fully completed by the server, the "
"connection will fail."
),
choices=["password", "md5", "gss", "sspi", "scram-sha-256", "none"],
)
channel_binding = SelectOption(
name="channel_binding",
description=(
"This option controls the client's use of channel binding. A setting of "
"require means that the connection must employ channel binding, prefer "
"means that the client will choose channel binding if available, and "
"disable prevents the use of channel binding. The default is prefer if "
"PostgreSQL is compiled with SSL support; otherwise the default is disable."
),
choices=["require", "prefer", "disable"],
)
def _int_validator(s: str | None) -> tuple[bool, str]:
if s is None:
return True, ""
try:
_ = int(s)
except ValueError:
return False, f"Cannot convert {s} to an int!"
else:
return True, ""
connect_timeout = TextOption(
name="connect_timeout",
description=(
"Maximum time to wait while connecting, in seconds (write as an integer, "
"e.g., 10)."
),
validator=_int_validator,
)
sslmode = SelectOption(
name="sslmode",
description=(
"Determines whether or with what priority a secure SSL TCP/IP connection will "
"be negotiated with the server."
),
choices=["disable", "allow", "prefer", "require", "verify-ca", "verify-full"],
default="prefer",
)
sslcert = PathOption(
name="sslcert",
description=(
"Specifies the file name of the client SSL certificate. "
"Ignored if an SSL connection is not made."
),
default="~/.postgresql/postgresql.crt",
)
sslkey = TextOption(
name="sslkey",
description=(
"Specifies the location for the secret key used for the client certificate. "
"It can either specify a file name that will be used instead of the default "
"~/.postgresql/postgresql.key, or it can specify a key obtained from an "
"external engine. An external engine specification should consist of a "
"colon-separated engine name and an engine-specific key identifier. This "
"parameter is ignored if an SSL connection is not made."
),
)
POSTGRES_OPTIONS = [
host,
port,
dbname,
user,
password,
passfile,
require_auth,
channel_binding,
connect_timeout,
sslmode,
sslcert,
sslkey,
]

View file

@ -0,0 +1,74 @@
from __future__ import annotations
import csv
from pathlib import Path
from harlequin import HarlequinCompletion
from psycopg import Connection
def _get_completions(conn: Connection) -> list[HarlequinCompletion]:
completions: list[HarlequinCompletion] = []
# source: https://www.postgresql.org/docs/current/sql-keywords-appendix.html
keyword_path = Path(__file__).parent / "keywords.tsv"
with keyword_path.open("r") as f:
keyword_reader = csv.reader(
f,
delimiter="\t",
)
_header = next(keyword_reader)
for keyword, kind, _, _, _ in keyword_reader:
completions.append(
HarlequinCompletion(
label=keyword.lower(),
type_label="kw",
value=keyword.lower(),
priority=100 if kind.startswith("reserved") else 1000,
context=None,
)
)
with conn.cursor() as cur:
cur.execute(
r"""
select distinct
routine_name as label,
case when routine_type is null then 'agg' else 'fn' end as type_label,
case
when routine_schema = 'pg_catalog' --
then null
else routine_schema
end as context
from information_schema.routines
where
length(routine_name) < 37
and routine_name not ilike '\_%'
and routine_name not ilike 'pg\_%'
and routine_name not ilike 'binary\_upgrade\_%'
;"""
)
results = cur.fetchall()
for label, type_label, context in results:
completions.append(
HarlequinCompletion(
label=label,
type_label=type_label,
value=label,
priority=1000,
context=context,
)
)
with conn.cursor() as cur:
cur.execute("""select distinct name as label from pg_settings""")
results = cur.fetchall()
for (label,) in results:
completions.append(
HarlequinCompletion(
label=label, type_label="set", value=label, priority=2000, context=None
)
)
return sorted(completions)

View file

@ -0,0 +1,143 @@
from __future__ import annotations
from textwrap import dedent
from typing import TYPE_CHECKING, Literal, Sequence
from harlequin.catalog import CatalogItem
from harlequin.exception import HarlequinQueryError
if TYPE_CHECKING:
from harlequin.driver import HarlequinDriver
from harlequin_duckdb.catalog import (
ColumnCatalogItem,
DatabaseCatalogItem,
RelationCatalogItem,
SchemaCatalogItem,
)
def execute_use_statement(
item: "SchemaCatalogItem",
driver: "HarlequinDriver",
) -> None:
if item.connection is None:
return
try:
item.connection.execute(f"set search_path to {item.qualified_identifier}")
except HarlequinQueryError:
driver.notify("Could not switch context", severity="error")
raise
else:
driver.notify(f"Editor context switched to {item.label}")
def execute_drop_schema_statement(
item: "SchemaCatalogItem",
driver: "HarlequinDriver",
) -> None:
def _drop_schema() -> None:
if item.connection is None:
return
try:
item.connection.execute(f"drop schema {item.qualified_identifier} cascade")
except HarlequinQueryError:
driver.notify(f"Could not drop schema {item.label}", severity="error")
raise
else:
driver.notify(f"Dropped schema {item.label}")
driver.refresh_catalog()
if item.children or item.fetch_children():
driver.confirm_and_execute(callback=_drop_schema)
else:
_drop_schema()
def execute_drop_database_statement(
item: "DatabaseCatalogItem",
driver: "HarlequinDriver",
) -> None:
def _drop_database() -> None:
if item.connection is None:
return
try:
item.connection.execute(f"drop database {item.qualified_identifier}")
except HarlequinQueryError:
driver.notify(f"Could not drop database {item.label}", severity="error")
raise
else:
driver.notify(f"Dropped database {item.label}")
driver.refresh_catalog()
if item.children or item.fetch_children():
driver.confirm_and_execute(callback=_drop_database)
else:
_drop_database()
def execute_drop_relation_statement(
item: "RelationCatalogItem",
driver: "HarlequinDriver",
relation_type: Literal["view", "table", "foreign table"],
) -> None:
def _drop_relation() -> None:
if item.connection is None:
return
try:
item.connection.execute(f"drop {relation_type} {item.qualified_identifier}")
except HarlequinQueryError:
driver.notify(
f"Could not drop {relation_type} {item.label}", severity="error"
)
raise
else:
driver.notify(f"Dropped {relation_type} {item.label}")
driver.refresh_catalog()
driver.confirm_and_execute(callback=_drop_relation)
def execute_drop_table_statement(
item: "RelationCatalogItem", driver: "HarlequinDriver"
) -> None:
execute_drop_relation_statement(item=item, driver=driver, relation_type="table")
def execute_drop_foreign_table_statement(
item: "RelationCatalogItem", driver: "HarlequinDriver"
) -> None:
execute_drop_relation_statement(
item=item, driver=driver, relation_type="foreign table"
)
def execute_drop_view_statement(
item: "RelationCatalogItem", driver: "HarlequinDriver"
) -> None:
execute_drop_relation_statement(item=item, driver=driver, relation_type="view")
def show_select_star(
item: "RelationCatalogItem",
driver: "HarlequinDriver",
) -> None:
driver.insert_text_in_new_buffer(
dedent(
f"""
select *
from {item.qualified_identifier}
limit 100
""".strip("\n")
)
)
def insert_columns_at_cursor(
item: "RelationCatalogItem",
driver: "HarlequinDriver",
) -> None:
if item.loaded:
cols: Sequence["CatalogItem" | "ColumnCatalogItem"] = item.children
else:
cols = item.fetch_children()
driver.insert_text_at_selection(text=",\n".join(c.query_name for c in cols))

View file

@ -0,0 +1,842 @@
Key Word PostgreSQL SQL:2023 SQL:2016 SQL-92
A non-reserved non-reserved
ABORT non-reserved
ABS reserved reserved
ABSENT non-reserved reserved reserved
ABSOLUTE non-reserved non-reserved non-reserved reserved
ACCESS non-reserved
ACCORDING non-reserved non-reserved
ACOS reserved reserved
ACTION non-reserved non-reserved non-reserved reserved
ADA non-reserved non-reserved non-reserved
ADD non-reserved non-reserved non-reserved reserved
ADMIN non-reserved non-reserved non-reserved
AFTER non-reserved non-reserved non-reserved
AGGREGATE non-reserved
ALL reserved reserved reserved reserved
ALLOCATE reserved reserved reserved
ALSO non-reserved
ALTER non-reserved reserved reserved reserved
ALWAYS non-reserved non-reserved non-reserved
ANALYSE reserved
ANALYZE reserved
AND reserved reserved reserved reserved
ANY reserved reserved reserved reserved
ANY_VALUE reserved
ARE reserved reserved reserved
ARRAY reserved, requires AS reserved reserved
ARRAY_AGG reserved reserved
ARRAY_MAX_CARDINALITY reserved reserved
AS reserved, requires AS reserved reserved reserved
ASC reserved non-reserved non-reserved reserved
ASENSITIVE non-reserved reserved reserved
ASIN reserved reserved
ASSERTION non-reserved non-reserved non-reserved reserved
ASSIGNMENT non-reserved non-reserved non-reserved
ASYMMETRIC reserved reserved reserved
AT non-reserved reserved reserved reserved
ATAN reserved reserved
ATOMIC non-reserved reserved reserved
ATTACH non-reserved
ATTRIBUTE non-reserved non-reserved non-reserved
ATTRIBUTES non-reserved non-reserved
AUTHORIZATION reserved (can be function or type) reserved reserved reserved
AVG reserved reserved reserved
BACKWARD non-reserved
BASE64 non-reserved non-reserved
BEFORE non-reserved non-reserved non-reserved
BEGIN non-reserved reserved reserved reserved
BEGIN_FRAME reserved reserved
BEGIN_PARTITION reserved reserved
BERNOULLI non-reserved non-reserved
BETWEEN non-reserved (cannot be function or type) reserved reserved reserved
BIGINT non-reserved (cannot be function or type) reserved reserved
BINARY reserved (can be function or type) reserved reserved
BIT non-reserved (cannot be function or type) reserved
BIT_LENGTH reserved
BLOB reserved reserved
BLOCKED non-reserved non-reserved
BOM non-reserved non-reserved
BOOLEAN non-reserved (cannot be function or type) reserved reserved
BOTH reserved reserved reserved reserved
BREADTH non-reserved non-reserved non-reserved
BTRIM reserved
BY non-reserved reserved reserved reserved
C non-reserved non-reserved non-reserved
CACHE non-reserved
CALL non-reserved reserved reserved
CALLED non-reserved reserved reserved
CARDINALITY reserved reserved
CASCADE non-reserved non-reserved non-reserved reserved
CASCADED non-reserved reserved reserved reserved
CASE reserved reserved reserved reserved
CAST reserved reserved reserved reserved
CATALOG non-reserved non-reserved non-reserved reserved
CATALOG_NAME non-reserved non-reserved non-reserved
CEIL reserved reserved
CEILING reserved reserved
CHAIN non-reserved non-reserved non-reserved
CHAINING non-reserved non-reserved
CHAR non-reserved (cannot be function or type), requires AS reserved reserved reserved
CHARACTER non-reserved (cannot be function or type), requires AS reserved reserved reserved
CHARACTERISTICS non-reserved non-reserved non-reserved
CHARACTERS non-reserved non-reserved
CHARACTER_LENGTH reserved reserved reserved
CHARACTER_SET_CATALOG non-reserved non-reserved non-reserved
CHARACTER_SET_NAME non-reserved non-reserved non-reserved
CHARACTER_SET_SCHEMA non-reserved non-reserved non-reserved
CHAR_LENGTH reserved reserved reserved
CHECK reserved reserved reserved reserved
CHECKPOINT non-reserved
CLASS non-reserved
CLASSIFIER reserved reserved
CLASS_ORIGIN non-reserved non-reserved non-reserved
CLOB reserved reserved
CLOSE non-reserved reserved reserved reserved
CLUSTER non-reserved
COALESCE non-reserved (cannot be function or type) reserved reserved reserved
COBOL non-reserved non-reserved non-reserved
COLLATE reserved reserved reserved reserved
COLLATION reserved (can be function or type) non-reserved non-reserved reserved
COLLATION_CATALOG non-reserved non-reserved non-reserved
COLLATION_NAME non-reserved non-reserved non-reserved
COLLATION_SCHEMA non-reserved non-reserved non-reserved
COLLECT reserved reserved
COLUMN reserved reserved reserved reserved
COLUMNS non-reserved non-reserved non-reserved
COLUMN_NAME non-reserved non-reserved non-reserved
COMMAND_FUNCTION non-reserved non-reserved non-reserved
COMMAND_FUNCTION_CODE non-reserved non-reserved
COMMENT non-reserved
COMMENTS non-reserved
COMMIT non-reserved reserved reserved reserved
COMMITTED non-reserved non-reserved non-reserved non-reserved
COMPRESSION non-reserved
CONCURRENTLY reserved (can be function or type)
CONDITION reserved reserved
CONDITIONAL non-reserved non-reserved
CONDITION_NUMBER non-reserved non-reserved non-reserved
CONFIGURATION non-reserved
CONFLICT non-reserved
CONNECT reserved reserved reserved
CONNECTION non-reserved non-reserved non-reserved reserved
CONNECTION_NAME non-reserved non-reserved non-reserved
CONSTRAINT reserved reserved reserved reserved
CONSTRAINTS non-reserved non-reserved non-reserved reserved
CONSTRAINT_CATALOG non-reserved non-reserved non-reserved
CONSTRAINT_NAME non-reserved non-reserved non-reserved
CONSTRAINT_SCHEMA non-reserved non-reserved non-reserved
CONSTRUCTOR non-reserved non-reserved
CONTAINS reserved reserved
CONTENT non-reserved non-reserved non-reserved
CONTINUE non-reserved non-reserved non-reserved reserved
CONTROL non-reserved non-reserved
CONVERSION non-reserved
CONVERT reserved reserved reserved
COPARTITION non-reserved
COPY non-reserved reserved reserved
CORR reserved reserved
CORRESPONDING reserved reserved reserved
COS reserved reserved
COSH reserved reserved
COST non-reserved
COUNT reserved reserved reserved
COVAR_POP reserved reserved
COVAR_SAMP reserved reserved
CREATE reserved, requires AS reserved reserved reserved
CROSS reserved (can be function or type) reserved reserved reserved
CSV non-reserved
CUBE non-reserved reserved reserved
CUME_DIST reserved reserved
CURRENT non-reserved reserved reserved reserved
CURRENT_CATALOG reserved reserved reserved
CURRENT_DATE reserved reserved reserved reserved
CURRENT_DEFAULT_TRANSFORM_GROUP reserved reserved
CURRENT_PATH reserved reserved
CURRENT_ROLE reserved reserved reserved
CURRENT_ROW reserved reserved
CURRENT_SCHEMA reserved (can be function or type) reserved reserved
CURRENT_TIME reserved reserved reserved reserved
CURRENT_TIMESTAMP reserved reserved reserved reserved
CURRENT_TRANSFORM_GROUP_FOR_TYPE reserved reserved
CURRENT_USER reserved reserved reserved reserved
CURSOR non-reserved reserved reserved reserved
CURSOR_NAME non-reserved non-reserved non-reserved
CYCLE non-reserved reserved reserved
DATA non-reserved non-reserved non-reserved non-reserved
DATABASE non-reserved
DATALINK reserved reserved
DATE reserved reserved reserved
DATETIME_INTERVAL_CODE non-reserved non-reserved non-reserved
DATETIME_INTERVAL_PRECISION non-reserved non-reserved non-reserved
DAY non-reserved, requires AS reserved reserved reserved
DB non-reserved non-reserved
DEALLOCATE non-reserved reserved reserved reserved
DEC non-reserved (cannot be function or type) reserved reserved reserved
DECFLOAT reserved reserved
DECIMAL non-reserved (cannot be function or type) reserved reserved reserved
DECLARE non-reserved reserved reserved reserved
DEFAULT reserved reserved reserved reserved
DEFAULTS non-reserved non-reserved non-reserved
DEFERRABLE reserved non-reserved non-reserved reserved
DEFERRED non-reserved non-reserved non-reserved reserved
DEFINE reserved reserved
DEFINED non-reserved non-reserved
DEFINER non-reserved non-reserved non-reserved
DEGREE non-reserved non-reserved
DELETE non-reserved reserved reserved reserved
DELIMITER non-reserved
DELIMITERS non-reserved
DENSE_RANK reserved reserved
DEPENDS non-reserved
DEPTH non-reserved non-reserved non-reserved
DEREF reserved reserved
DERIVED non-reserved non-reserved
DESC reserved non-reserved non-reserved reserved
DESCRIBE reserved reserved reserved
DESCRIPTOR non-reserved non-reserved reserved
DETACH non-reserved
DETERMINISTIC reserved reserved
DIAGNOSTICS non-reserved non-reserved reserved
DICTIONARY non-reserved
DISABLE non-reserved
DISCARD non-reserved
DISCONNECT reserved reserved reserved
DISPATCH non-reserved non-reserved
DISTINCT reserved reserved reserved reserved
DLNEWCOPY reserved reserved
DLPREVIOUSCOPY reserved reserved
DLURLCOMPLETE reserved reserved
DLURLCOMPLETEONLY reserved reserved
DLURLCOMPLETEWRITE reserved reserved
DLURLPATH reserved reserved
DLURLPATHONLY reserved reserved
DLURLPATHWRITE reserved reserved
DLURLSCHEME reserved reserved
DLURLSERVER reserved reserved
DLVALUE reserved reserved
DO reserved
DOCUMENT non-reserved non-reserved non-reserved
DOMAIN non-reserved non-reserved non-reserved reserved
DOUBLE non-reserved reserved reserved reserved
DROP non-reserved reserved reserved reserved
DYNAMIC reserved reserved
DYNAMIC_FUNCTION non-reserved non-reserved non-reserved
DYNAMIC_FUNCTION_CODE non-reserved non-reserved
EACH non-reserved reserved reserved
ELEMENT reserved reserved
ELSE reserved reserved reserved reserved
EMPTY reserved reserved
ENABLE non-reserved
ENCODING non-reserved non-reserved non-reserved
ENCRYPTED non-reserved
END reserved reserved reserved reserved
END-EXEC reserved reserved reserved
END_FRAME reserved reserved
END_PARTITION reserved reserved
ENFORCED non-reserved non-reserved
ENUM non-reserved
EQUALS reserved reserved
ERROR non-reserved non-reserved
ESCAPE non-reserved reserved reserved reserved
EVENT non-reserved
EVERY reserved reserved
EXCEPT reserved, requires AS reserved reserved reserved
EXCEPTION reserved
EXCLUDE non-reserved non-reserved non-reserved
EXCLUDING non-reserved non-reserved non-reserved
EXCLUSIVE non-reserved
EXEC reserved reserved reserved
EXECUTE non-reserved reserved reserved reserved
EXISTS non-reserved (cannot be function or type) reserved reserved reserved
EXP reserved reserved
EXPLAIN non-reserved
EXPRESSION non-reserved non-reserved non-reserved
EXTENSION non-reserved
EXTERNAL non-reserved reserved reserved reserved
EXTRACT non-reserved (cannot be function or type) reserved reserved reserved
FALSE reserved reserved reserved reserved
FAMILY non-reserved
FETCH reserved, requires AS reserved reserved reserved
FILE non-reserved non-reserved
FILTER non-reserved, requires AS reserved reserved
FINAL non-reserved non-reserved
FINALIZE non-reserved
FINISH non-reserved non-reserved
FIRST non-reserved non-reserved non-reserved reserved
FIRST_VALUE reserved reserved
FLAG non-reserved non-reserved
FLOAT non-reserved (cannot be function or type) reserved reserved reserved
FLOOR reserved reserved
FOLLOWING non-reserved non-reserved non-reserved
FOR reserved, requires AS reserved reserved reserved
FORCE non-reserved
FOREIGN reserved reserved reserved reserved
FORMAT non-reserved non-reserved non-reserved
FORTRAN non-reserved non-reserved non-reserved
FORWARD non-reserved
FOUND non-reserved non-reserved reserved
FRAME_ROW reserved reserved
FREE reserved reserved
FREEZE reserved (can be function or type)
FROM reserved, requires AS reserved reserved reserved
FS non-reserved non-reserved
FULFILL non-reserved non-reserved
FULL reserved (can be function or type) reserved reserved reserved
FUNCTION non-reserved reserved reserved
FUNCTIONS non-reserved
FUSION reserved reserved
G non-reserved non-reserved
GENERAL non-reserved non-reserved
GENERATED non-reserved non-reserved non-reserved
GET reserved reserved reserved
GLOBAL non-reserved reserved reserved reserved
GO non-reserved non-reserved reserved
GOTO non-reserved non-reserved reserved
GRANT reserved, requires AS reserved reserved reserved
GRANTED non-reserved non-reserved non-reserved
GREATEST non-reserved (cannot be function or type) reserved
GROUP reserved, requires AS reserved reserved reserved
GROUPING non-reserved (cannot be function or type) reserved reserved
GROUPS non-reserved reserved reserved
HANDLER non-reserved
HAVING reserved, requires AS reserved reserved reserved
HEADER non-reserved
HEX non-reserved non-reserved
HIERARCHY non-reserved non-reserved
HOLD non-reserved reserved reserved
HOUR non-reserved, requires AS reserved reserved reserved
ID non-reserved non-reserved
IDENTITY non-reserved reserved reserved reserved
IF non-reserved
IGNORE non-reserved non-reserved
ILIKE reserved (can be function or type)
IMMEDIATE non-reserved non-reserved non-reserved reserved
IMMEDIATELY non-reserved non-reserved
IMMUTABLE non-reserved
IMPLEMENTATION non-reserved non-reserved
IMPLICIT non-reserved
IMPORT non-reserved reserved reserved
IN reserved reserved reserved reserved
INCLUDE non-reserved
INCLUDING non-reserved non-reserved non-reserved
INCREMENT non-reserved non-reserved non-reserved
INDENT non-reserved non-reserved non-reserved
INDEX non-reserved
INDEXES non-reserved
INDICATOR reserved reserved reserved
INHERIT non-reserved
INHERITS non-reserved
INITIAL reserved reserved
INITIALLY reserved non-reserved non-reserved reserved
INLINE non-reserved
INNER reserved (can be function or type) reserved reserved reserved
INOUT non-reserved (cannot be function or type) reserved reserved
INPUT non-reserved non-reserved non-reserved reserved
INSENSITIVE non-reserved reserved reserved reserved
INSERT non-reserved reserved reserved reserved
INSTANCE non-reserved non-reserved
INSTANTIABLE non-reserved non-reserved
INSTEAD non-reserved non-reserved non-reserved
INT non-reserved (cannot be function or type) reserved reserved reserved
INTEGER non-reserved (cannot be function or type) reserved reserved reserved
INTEGRITY non-reserved non-reserved
INTERSECT reserved, requires AS reserved reserved reserved
INTERSECTION reserved reserved
INTERVAL non-reserved (cannot be function or type) reserved reserved reserved
INTO reserved, requires AS reserved reserved reserved
INVOKER non-reserved non-reserved non-reserved
IS reserved (can be function or type) reserved reserved reserved
ISNULL reserved (can be function or type), requires AS
ISOLATION non-reserved non-reserved non-reserved reserved
JOIN reserved (can be function or type) reserved reserved reserved
JSON non-reserved reserved
JSON_ARRAY non-reserved (cannot be function or type) reserved reserved
JSON_ARRAYAGG non-reserved (cannot be function or type) reserved reserved
JSON_EXISTS reserved reserved
JSON_OBJECT non-reserved (cannot be function or type) reserved reserved
JSON_OBJECTAGG non-reserved (cannot be function or type) reserved reserved
JSON_QUERY reserved reserved
JSON_SCALAR reserved
JSON_SERIALIZE reserved
JSON_TABLE reserved reserved
JSON_TABLE_PRIMITIVE reserved reserved
JSON_VALUE reserved reserved
K non-reserved non-reserved
KEEP non-reserved non-reserved
KEY non-reserved non-reserved non-reserved reserved
KEYS non-reserved non-reserved non-reserved
KEY_MEMBER non-reserved non-reserved
KEY_TYPE non-reserved non-reserved
LABEL non-reserved
LAG reserved reserved
LANGUAGE non-reserved reserved reserved reserved
LARGE non-reserved reserved reserved
LAST non-reserved non-reserved non-reserved reserved
LAST_VALUE reserved reserved
LATERAL reserved reserved reserved
LEAD reserved reserved
LEADING reserved reserved reserved reserved
LEAKPROOF non-reserved
LEAST non-reserved (cannot be function or type) reserved
LEFT reserved (can be function or type) reserved reserved reserved
LENGTH non-reserved non-reserved non-reserved
LEVEL non-reserved non-reserved non-reserved reserved
LIBRARY non-reserved non-reserved
LIKE reserved (can be function or type) reserved reserved reserved
LIKE_REGEX reserved reserved
LIMIT reserved, requires AS non-reserved non-reserved
LINK non-reserved non-reserved
LISTAGG reserved reserved
LISTEN non-reserved
LN reserved reserved
LOAD non-reserved
LOCAL non-reserved reserved reserved reserved
LOCALTIME reserved reserved reserved
LOCALTIMESTAMP reserved reserved reserved
LOCATION non-reserved non-reserved non-reserved
LOCATOR non-reserved non-reserved
LOCK non-reserved
LOCKED non-reserved
LOG reserved reserved
LOG10 reserved reserved
LOGGED non-reserved
LOWER reserved reserved reserved
LPAD reserved
LTRIM reserved
M non-reserved non-reserved
MAP non-reserved non-reserved
MAPPING non-reserved non-reserved non-reserved
MATCH non-reserved reserved reserved reserved
MATCHED non-reserved non-reserved non-reserved
MATCHES reserved reserved
MATCH_NUMBER reserved reserved
MATCH_RECOGNIZE reserved reserved
MATERIALIZED non-reserved
MAX reserved reserved reserved
MAXVALUE non-reserved non-reserved non-reserved
MEASURES non-reserved non-reserved
MEMBER reserved reserved
MERGE non-reserved reserved reserved
MESSAGE_LENGTH non-reserved non-reserved non-reserved
MESSAGE_OCTET_LENGTH non-reserved non-reserved non-reserved
MESSAGE_TEXT non-reserved non-reserved non-reserved
METHOD non-reserved reserved reserved
MIN reserved reserved reserved
MINUTE non-reserved, requires AS reserved reserved reserved
MINVALUE non-reserved non-reserved non-reserved
MOD reserved reserved
MODE non-reserved
MODIFIES reserved reserved
MODULE reserved reserved reserved
MONTH non-reserved, requires AS reserved reserved reserved
MORE non-reserved non-reserved non-reserved
MOVE non-reserved
MULTISET reserved reserved
MUMPS non-reserved non-reserved non-reserved
NAME non-reserved non-reserved non-reserved non-reserved
NAMES non-reserved non-reserved non-reserved reserved
NAMESPACE non-reserved non-reserved
NATIONAL non-reserved (cannot be function or type) reserved reserved reserved
NATURAL reserved (can be function or type) reserved reserved reserved
NCHAR non-reserved (cannot be function or type) reserved reserved reserved
NCLOB reserved reserved
NESTED non-reserved non-reserved
NESTING non-reserved non-reserved
NEW non-reserved reserved reserved
NEXT non-reserved non-reserved non-reserved reserved
NFC non-reserved non-reserved non-reserved
NFD non-reserved non-reserved non-reserved
NFKC non-reserved non-reserved non-reserved
NFKD non-reserved non-reserved non-reserved
NIL non-reserved non-reserved
NO non-reserved reserved reserved reserved
NONE non-reserved (cannot be function or type) reserved reserved
NORMALIZE non-reserved (cannot be function or type) reserved reserved
NORMALIZED non-reserved non-reserved non-reserved
NOT reserved reserved reserved reserved
NOTHING non-reserved
NOTIFY non-reserved
NOTNULL reserved (can be function or type), requires AS
NOWAIT non-reserved
NTH_VALUE reserved reserved
NTILE reserved reserved
NULL reserved reserved reserved reserved
NULLABLE non-reserved non-reserved non-reserved
NULLIF non-reserved (cannot be function or type) reserved reserved reserved
NULLS non-reserved non-reserved non-reserved
NULL_ORDERING non-reserved non-reserved
NUMBER non-reserved non-reserved non-reserved
NUMERIC non-reserved (cannot be function or type) reserved reserved reserved
OBJECT non-reserved non-reserved non-reserved
OCCURRENCE non-reserved non-reserved
OCCURRENCES_REGEX reserved reserved
OCTETS non-reserved non-reserved
OCTET_LENGTH reserved reserved reserved
OF non-reserved reserved reserved reserved
OFF non-reserved non-reserved non-reserved
OFFSET reserved, requires AS reserved reserved
OIDS non-reserved
OLD non-reserved reserved reserved
OMIT reserved reserved
ON reserved, requires AS reserved reserved reserved
ONE reserved reserved
ONLY reserved reserved reserved reserved
OPEN reserved reserved reserved
OPERATOR non-reserved
OPTION non-reserved non-reserved non-reserved reserved
OPTIONS non-reserved non-reserved non-reserved
OR reserved reserved reserved reserved
ORDER reserved, requires AS reserved reserved reserved
ORDERING non-reserved non-reserved
ORDINALITY non-reserved non-reserved non-reserved
OTHERS non-reserved non-reserved non-reserved
OUT non-reserved (cannot be function or type) reserved reserved
OUTER reserved (can be function or type) reserved reserved reserved
OUTPUT non-reserved non-reserved reserved
OVER non-reserved, requires AS reserved reserved
OVERFLOW non-reserved non-reserved
OVERLAPS reserved (can be function or type), requires AS reserved reserved reserved
OVERLAY non-reserved (cannot be function or type) reserved reserved
OVERRIDING non-reserved non-reserved non-reserved
OWNED non-reserved
OWNER non-reserved
P non-reserved non-reserved
PAD non-reserved non-reserved reserved
PARALLEL non-reserved
PARAMETER non-reserved reserved reserved
PARAMETER_MODE non-reserved non-reserved
PARAMETER_NAME non-reserved non-reserved
PARAMETER_ORDINAL_POSITION non-reserved non-reserved
PARAMETER_SPECIFIC_CATALOG non-reserved non-reserved
PARAMETER_SPECIFIC_NAME non-reserved non-reserved
PARAMETER_SPECIFIC_SCHEMA non-reserved non-reserved
PARSER non-reserved
PARTIAL non-reserved non-reserved non-reserved reserved
PARTITION non-reserved reserved reserved
PASCAL non-reserved non-reserved non-reserved
PASS non-reserved non-reserved
PASSING non-reserved non-reserved non-reserved
PASSTHROUGH non-reserved non-reserved
PASSWORD non-reserved
PAST non-reserved non-reserved
PATH non-reserved non-reserved
PATTERN reserved reserved
PER reserved reserved
PERCENT reserved reserved
PERCENTILE_CONT reserved reserved
PERCENTILE_DISC reserved reserved
PERCENT_RANK reserved reserved
PERIOD reserved reserved
PERMISSION non-reserved non-reserved
PERMUTE non-reserved non-reserved
PIPE non-reserved non-reserved
PLACING reserved non-reserved non-reserved
PLAN non-reserved non-reserved
PLANS non-reserved
PLI non-reserved non-reserved non-reserved
POLICY non-reserved
PORTION reserved reserved
POSITION non-reserved (cannot be function or type) reserved reserved reserved
POSITION_REGEX reserved reserved
POWER reserved reserved
PRECEDES reserved reserved
PRECEDING non-reserved non-reserved non-reserved
PRECISION non-reserved (cannot be function or type), requires AS reserved reserved reserved
PREPARE non-reserved reserved reserved reserved
PREPARED non-reserved
PRESERVE non-reserved non-reserved non-reserved reserved
PREV non-reserved non-reserved
PRIMARY reserved reserved reserved reserved
PRIOR non-reserved non-reserved non-reserved reserved
PRIVATE non-reserved non-reserved
PRIVILEGES non-reserved non-reserved non-reserved reserved
PROCEDURAL non-reserved
PROCEDURE non-reserved reserved reserved reserved
PROCEDURES non-reserved
PROGRAM non-reserved
PRUNE non-reserved non-reserved
PTF reserved reserved
PUBLIC non-reserved non-reserved reserved
PUBLICATION non-reserved
QUOTE non-reserved
QUOTES non-reserved non-reserved
RANGE non-reserved reserved reserved
RANK reserved reserved
READ non-reserved non-reserved non-reserved reserved
READS reserved reserved
REAL non-reserved (cannot be function or type) reserved reserved reserved
REASSIGN non-reserved
RECHECK non-reserved
RECOVERY non-reserved non-reserved
RECURSIVE non-reserved reserved reserved
REF non-reserved reserved reserved
REFERENCES reserved reserved reserved reserved
REFERENCING non-reserved reserved reserved
REFRESH non-reserved
REGR_AVGX reserved reserved
REGR_AVGY reserved reserved
REGR_COUNT reserved reserved
REGR_INTERCEPT reserved reserved
REGR_R2 reserved reserved
REGR_SLOPE reserved reserved
REGR_SXX reserved reserved
REGR_SXY reserved reserved
REGR_SYY reserved reserved
REINDEX non-reserved
RELATIVE non-reserved non-reserved non-reserved reserved
RELEASE non-reserved reserved reserved
RENAME non-reserved
REPEATABLE non-reserved non-reserved non-reserved non-reserved
REPLACE non-reserved
REPLICA non-reserved
REQUIRING non-reserved non-reserved
RESET non-reserved
RESPECT non-reserved non-reserved
RESTART non-reserved non-reserved non-reserved
RESTORE non-reserved non-reserved
RESTRICT non-reserved non-reserved non-reserved reserved
RESULT reserved reserved
RETURN non-reserved reserved reserved
RETURNED_CARDINALITY non-reserved non-reserved
RETURNED_LENGTH non-reserved non-reserved non-reserved
RETURNED_OCTET_LENGTH non-reserved non-reserved non-reserved
RETURNED_SQLSTATE non-reserved non-reserved non-reserved
RETURNING reserved, requires AS non-reserved non-reserved
RETURNS non-reserved reserved reserved
REVOKE non-reserved reserved reserved reserved
RIGHT reserved (can be function or type) reserved reserved reserved
ROLE non-reserved non-reserved non-reserved
ROLLBACK non-reserved reserved reserved reserved
ROLLUP non-reserved reserved reserved
ROUTINE non-reserved non-reserved non-reserved
ROUTINES non-reserved
ROUTINE_CATALOG non-reserved non-reserved
ROUTINE_NAME non-reserved non-reserved
ROUTINE_SCHEMA non-reserved non-reserved
ROW non-reserved (cannot be function or type) reserved reserved
ROWS non-reserved reserved reserved reserved
ROW_COUNT non-reserved non-reserved non-reserved
ROW_NUMBER reserved reserved
RPAD reserved
RTRIM reserved
RULE non-reserved
RUNNING reserved reserved
SAVEPOINT non-reserved reserved reserved
SCALAR non-reserved non-reserved non-reserved
SCALE non-reserved non-reserved non-reserved
SCHEMA non-reserved non-reserved non-reserved reserved
SCHEMAS non-reserved
SCHEMA_NAME non-reserved non-reserved non-reserved
SCOPE reserved reserved
SCOPE_CATALOG non-reserved non-reserved
SCOPE_NAME non-reserved non-reserved
SCOPE_SCHEMA non-reserved non-reserved
SCROLL non-reserved reserved reserved reserved
SEARCH non-reserved reserved reserved
SECOND non-reserved, requires AS reserved reserved reserved
SECTION non-reserved non-reserved reserved
SECURITY non-reserved non-reserved non-reserved
SEEK reserved reserved
SELECT reserved reserved reserved reserved
SELECTIVE non-reserved non-reserved
SELF non-reserved non-reserved
SEMANTICS non-reserved non-reserved
SENSITIVE reserved reserved
SEQUENCE non-reserved non-reserved non-reserved
SEQUENCES non-reserved
SERIALIZABLE non-reserved non-reserved non-reserved non-reserved
SERVER non-reserved non-reserved non-reserved
SERVER_NAME non-reserved non-reserved non-reserved
SESSION non-reserved non-reserved non-reserved reserved
SESSION_USER reserved reserved reserved reserved
SET non-reserved reserved reserved reserved
SETOF non-reserved (cannot be function or type)
SETS non-reserved non-reserved non-reserved
SHARE non-reserved
SHOW non-reserved reserved reserved
SIMILAR reserved (can be function or type) reserved reserved
SIMPLE non-reserved non-reserved non-reserved
SIN reserved reserved
SINH reserved reserved
SIZE non-reserved non-reserved reserved
SKIP non-reserved reserved reserved
SMALLINT non-reserved (cannot be function or type) reserved reserved reserved
SNAPSHOT non-reserved
SOME reserved reserved reserved reserved
SORT_DIRECTION non-reserved non-reserved
SOURCE non-reserved non-reserved
SPACE non-reserved non-reserved reserved
SPECIFIC reserved reserved
SPECIFICTYPE reserved reserved
SPECIFIC_NAME non-reserved non-reserved
SQL non-reserved reserved reserved reserved
SQLCODE reserved
SQLERROR reserved
SQLEXCEPTION reserved reserved
SQLSTATE reserved reserved reserved
SQLWARNING reserved reserved
SQRT reserved reserved
STABLE non-reserved
STANDALONE non-reserved non-reserved non-reserved
START non-reserved reserved reserved
STATE non-reserved non-reserved
STATEMENT non-reserved non-reserved non-reserved
STATIC reserved reserved
STATISTICS non-reserved
STDDEV_POP reserved reserved
STDDEV_SAMP reserved reserved
STDIN non-reserved
STDOUT non-reserved
STORAGE non-reserved
STORED non-reserved
STRICT non-reserved
STRING non-reserved non-reserved
STRIP non-reserved non-reserved non-reserved
STRUCTURE non-reserved non-reserved
STYLE non-reserved non-reserved
SUBCLASS_ORIGIN non-reserved non-reserved non-reserved
SUBMULTISET reserved reserved
SUBSCRIPTION non-reserved
SUBSET reserved reserved
SUBSTRING non-reserved (cannot be function or type) reserved reserved reserved
SUBSTRING_REGEX reserved reserved
SUCCEEDS reserved reserved
SUM reserved reserved reserved
SUPPORT non-reserved
SYMMETRIC reserved reserved reserved
SYSID non-reserved
SYSTEM non-reserved reserved reserved
SYSTEM_TIME reserved reserved
SYSTEM_USER reserved reserved reserved reserved
T non-reserved non-reserved
TABLE reserved reserved reserved reserved
TABLES non-reserved
TABLESAMPLE reserved (can be function or type) reserved reserved
TABLESPACE non-reserved
TABLE_NAME non-reserved non-reserved non-reserved
TAN reserved reserved
TANH reserved reserved
TEMP non-reserved
TEMPLATE non-reserved
TEMPORARY non-reserved non-reserved non-reserved reserved
TEXT non-reserved
THEN reserved reserved reserved reserved
THROUGH non-reserved non-reserved
TIES non-reserved non-reserved non-reserved
TIME non-reserved (cannot be function or type) reserved reserved reserved
TIMESTAMP non-reserved (cannot be function or type) reserved reserved reserved
TIMEZONE_HOUR reserved reserved reserved
TIMEZONE_MINUTE reserved reserved reserved
TO reserved, requires AS reserved reserved reserved
TOKEN non-reserved non-reserved
TOP_LEVEL_COUNT non-reserved non-reserved
TRAILING reserved reserved reserved reserved
TRANSACTION non-reserved non-reserved non-reserved reserved
TRANSACTIONS_COMMITTED non-reserved non-reserved
TRANSACTIONS_ROLLED_BACK non-reserved non-reserved
TRANSACTION_ACTIVE non-reserved non-reserved
TRANSFORM non-reserved non-reserved non-reserved
TRANSFORMS non-reserved non-reserved
TRANSLATE reserved reserved reserved
TRANSLATE_REGEX reserved reserved
TRANSLATION reserved reserved reserved
TREAT non-reserved (cannot be function or type) reserved reserved
TRIGGER non-reserved reserved reserved
TRIGGER_CATALOG non-reserved non-reserved
TRIGGER_NAME non-reserved non-reserved
TRIGGER_SCHEMA non-reserved non-reserved
TRIM non-reserved (cannot be function or type) reserved reserved reserved
TRIM_ARRAY reserved reserved
TRUE reserved reserved reserved reserved
TRUNCATE non-reserved reserved reserved
TRUSTED non-reserved
TYPE non-reserved non-reserved non-reserved non-reserved
TYPES non-reserved
UESCAPE non-reserved reserved reserved
UNBOUNDED non-reserved non-reserved non-reserved
UNCOMMITTED non-reserved non-reserved non-reserved non-reserved
UNCONDITIONAL non-reserved non-reserved
UNDER non-reserved non-reserved
UNENCRYPTED non-reserved
UNION reserved, requires AS reserved reserved reserved
UNIQUE reserved reserved reserved reserved
UNKNOWN non-reserved reserved reserved reserved
UNLINK non-reserved non-reserved
UNLISTEN non-reserved
UNLOGGED non-reserved
UNMATCHED non-reserved non-reserved
UNNAMED non-reserved non-reserved non-reserved
UNNEST reserved reserved
UNTIL non-reserved
UNTYPED non-reserved non-reserved
UPDATE non-reserved reserved reserved reserved
UPPER reserved reserved reserved
URI non-reserved non-reserved
USAGE non-reserved non-reserved reserved
USER reserved reserved reserved reserved
USER_DEFINED_TYPE_CATALOG non-reserved non-reserved
USER_DEFINED_TYPE_CODE non-reserved non-reserved
USER_DEFINED_TYPE_NAME non-reserved non-reserved
USER_DEFINED_TYPE_SCHEMA non-reserved non-reserved
USING reserved reserved reserved reserved
UTF16 non-reserved non-reserved
UTF32 non-reserved non-reserved
UTF8 non-reserved non-reserved
VACUUM non-reserved
VALID non-reserved non-reserved non-reserved
VALIDATE non-reserved
VALIDATOR non-reserved
VALUE non-reserved reserved reserved reserved
VALUES non-reserved (cannot be function or type) reserved reserved reserved
VALUE_OF reserved reserved
VARBINARY reserved reserved
VARCHAR non-reserved (cannot be function or type) reserved reserved reserved
VARIADIC reserved
VARYING non-reserved, requires AS reserved reserved reserved
VAR_POP reserved reserved
VAR_SAMP reserved reserved
VERBOSE reserved (can be function or type)
VERSION non-reserved non-reserved non-reserved
VERSIONING reserved reserved
VIEW non-reserved non-reserved non-reserved reserved
VIEWS non-reserved
VOLATILE non-reserved
WHEN reserved reserved reserved reserved
WHENEVER reserved reserved reserved
WHERE reserved, requires AS reserved reserved reserved
WHITESPACE non-reserved non-reserved non-reserved
WIDTH_BUCKET reserved reserved
WINDOW reserved, requires AS reserved reserved
WITH reserved, requires AS reserved reserved reserved
WITHIN non-reserved, requires AS reserved reserved
WITHOUT non-reserved, requires AS reserved reserved
WORK non-reserved non-reserved non-reserved reserved
WRAPPER non-reserved non-reserved non-reserved
WRITE non-reserved non-reserved non-reserved reserved
XML non-reserved reserved reserved
XMLAGG reserved reserved
XMLATTRIBUTES non-reserved (cannot be function or type) reserved reserved
XMLBINARY reserved reserved
XMLCAST reserved reserved
XMLCOMMENT reserved reserved
XMLCONCAT non-reserved (cannot be function or type) reserved reserved
XMLDECLARATION non-reserved non-reserved
XMLDOCUMENT reserved reserved
XMLELEMENT non-reserved (cannot be function or type) reserved reserved
XMLEXISTS non-reserved (cannot be function or type) reserved reserved
XMLFOREST non-reserved (cannot be function or type) reserved reserved
XMLITERATE reserved reserved
XMLNAMESPACES non-reserved (cannot be function or type) reserved reserved
XMLPARSE non-reserved (cannot be function or type) reserved reserved
XMLPI non-reserved (cannot be function or type) reserved reserved
XMLQUERY reserved reserved
XMLROOT non-reserved (cannot be function or type)
XMLSCHEMA non-reserved non-reserved
XMLSERIALIZE non-reserved (cannot be function or type) reserved reserved
XMLTABLE non-reserved (cannot be function or type) reserved reserved
XMLTEXT reserved reserved
XMLVALIDATE reserved reserved
YEAR non-reserved, requires AS reserved reserved reserved
YES non-reserved non-reserved non-reserved
ZONE non-reserved non-reserved non-reserved reserved
1 Key Word PostgreSQL SQL:2023 SQL:2016 SQL-92
2 A non-reserved non-reserved
3 ABORT non-reserved
4 ABS reserved reserved
5 ABSENT non-reserved reserved reserved
6 ABSOLUTE non-reserved non-reserved non-reserved reserved
7 ACCESS non-reserved
8 ACCORDING non-reserved non-reserved
9 ACOS reserved reserved
10 ACTION non-reserved non-reserved non-reserved reserved
11 ADA non-reserved non-reserved non-reserved
12 ADD non-reserved non-reserved non-reserved reserved
13 ADMIN non-reserved non-reserved non-reserved
14 AFTER non-reserved non-reserved non-reserved
15 AGGREGATE non-reserved
16 ALL reserved reserved reserved reserved
17 ALLOCATE reserved reserved reserved
18 ALSO non-reserved
19 ALTER non-reserved reserved reserved reserved
20 ALWAYS non-reserved non-reserved non-reserved
21 ANALYSE reserved
22 ANALYZE reserved
23 AND reserved reserved reserved reserved
24 ANY reserved reserved reserved reserved
25 ANY_VALUE reserved
26 ARE reserved reserved reserved
27 ARRAY reserved, requires AS reserved reserved
28 ARRAY_AGG reserved reserved
29 ARRAY_​MAX_​CARDINALITY reserved reserved
30 AS reserved, requires AS reserved reserved reserved
31 ASC reserved non-reserved non-reserved reserved
32 ASENSITIVE non-reserved reserved reserved
33 ASIN reserved reserved
34 ASSERTION non-reserved non-reserved non-reserved reserved
35 ASSIGNMENT non-reserved non-reserved non-reserved
36 ASYMMETRIC reserved reserved reserved
37 AT non-reserved reserved reserved reserved
38 ATAN reserved reserved
39 ATOMIC non-reserved reserved reserved
40 ATTACH non-reserved
41 ATTRIBUTE non-reserved non-reserved non-reserved
42 ATTRIBUTES non-reserved non-reserved
43 AUTHORIZATION reserved (can be function or type) reserved reserved reserved
44 AVG reserved reserved reserved
45 BACKWARD non-reserved
46 BASE64 non-reserved non-reserved
47 BEFORE non-reserved non-reserved non-reserved
48 BEGIN non-reserved reserved reserved reserved
49 BEGIN_FRAME reserved reserved
50 BEGIN_PARTITION reserved reserved
51 BERNOULLI non-reserved non-reserved
52 BETWEEN non-reserved (cannot be function or type) reserved reserved reserved
53 BIGINT non-reserved (cannot be function or type) reserved reserved
54 BINARY reserved (can be function or type) reserved reserved
55 BIT non-reserved (cannot be function or type) reserved
56 BIT_LENGTH reserved
57 BLOB reserved reserved
58 BLOCKED non-reserved non-reserved
59 BOM non-reserved non-reserved
60 BOOLEAN non-reserved (cannot be function or type) reserved reserved
61 BOTH reserved reserved reserved reserved
62 BREADTH non-reserved non-reserved non-reserved
63 BTRIM reserved
64 BY non-reserved reserved reserved reserved
65 C non-reserved non-reserved non-reserved
66 CACHE non-reserved
67 CALL non-reserved reserved reserved
68 CALLED non-reserved reserved reserved
69 CARDINALITY reserved reserved
70 CASCADE non-reserved non-reserved non-reserved reserved
71 CASCADED non-reserved reserved reserved reserved
72 CASE reserved reserved reserved reserved
73 CAST reserved reserved reserved reserved
74 CATALOG non-reserved non-reserved non-reserved reserved
75 CATALOG_NAME non-reserved non-reserved non-reserved
76 CEIL reserved reserved
77 CEILING reserved reserved
78 CHAIN non-reserved non-reserved non-reserved
79 CHAINING non-reserved non-reserved
80 CHAR non-reserved (cannot be function or type), requires AS reserved reserved reserved
81 CHARACTER non-reserved (cannot be function or type), requires AS reserved reserved reserved
82 CHARACTERISTICS non-reserved non-reserved non-reserved
83 CHARACTERS non-reserved non-reserved
84 CHARACTER_LENGTH reserved reserved reserved
85 CHARACTER_​SET_​CATALOG non-reserved non-reserved non-reserved
86 CHARACTER_SET_NAME non-reserved non-reserved non-reserved
87 CHARACTER_SET_SCHEMA non-reserved non-reserved non-reserved
88 CHAR_LENGTH reserved reserved reserved
89 CHECK reserved reserved reserved reserved
90 CHECKPOINT non-reserved
91 CLASS non-reserved
92 CLASSIFIER reserved reserved
93 CLASS_ORIGIN non-reserved non-reserved non-reserved
94 CLOB reserved reserved
95 CLOSE non-reserved reserved reserved reserved
96 CLUSTER non-reserved
97 COALESCE non-reserved (cannot be function or type) reserved reserved reserved
98 COBOL non-reserved non-reserved non-reserved
99 COLLATE reserved reserved reserved reserved
100 COLLATION reserved (can be function or type) non-reserved non-reserved reserved
101 COLLATION_CATALOG non-reserved non-reserved non-reserved
102 COLLATION_NAME non-reserved non-reserved non-reserved
103 COLLATION_SCHEMA non-reserved non-reserved non-reserved
104 COLLECT reserved reserved
105 COLUMN reserved reserved reserved reserved
106 COLUMNS non-reserved non-reserved non-reserved
107 COLUMN_NAME non-reserved non-reserved non-reserved
108 COMMAND_FUNCTION non-reserved non-reserved non-reserved
109 COMMAND_​FUNCTION_​CODE non-reserved non-reserved
110 COMMENT non-reserved
111 COMMENTS non-reserved
112 COMMIT non-reserved reserved reserved reserved
113 COMMITTED non-reserved non-reserved non-reserved non-reserved
114 COMPRESSION non-reserved
115 CONCURRENTLY reserved (can be function or type)
116 CONDITION reserved reserved
117 CONDITIONAL non-reserved non-reserved
118 CONDITION_NUMBER non-reserved non-reserved non-reserved
119 CONFIGURATION non-reserved
120 CONFLICT non-reserved
121 CONNECT reserved reserved reserved
122 CONNECTION non-reserved non-reserved non-reserved reserved
123 CONNECTION_NAME non-reserved non-reserved non-reserved
124 CONSTRAINT reserved reserved reserved reserved
125 CONSTRAINTS non-reserved non-reserved non-reserved reserved
126 CONSTRAINT_CATALOG non-reserved non-reserved non-reserved
127 CONSTRAINT_NAME non-reserved non-reserved non-reserved
128 CONSTRAINT_SCHEMA non-reserved non-reserved non-reserved
129 CONSTRUCTOR non-reserved non-reserved
130 CONTAINS reserved reserved
131 CONTENT non-reserved non-reserved non-reserved
132 CONTINUE non-reserved non-reserved non-reserved reserved
133 CONTROL non-reserved non-reserved
134 CONVERSION non-reserved
135 CONVERT reserved reserved reserved
136 COPARTITION non-reserved
137 COPY non-reserved reserved reserved
138 CORR reserved reserved
139 CORRESPONDING reserved reserved reserved
140 COS reserved reserved
141 COSH reserved reserved
142 COST non-reserved
143 COUNT reserved reserved reserved
144 COVAR_POP reserved reserved
145 COVAR_SAMP reserved reserved
146 CREATE reserved, requires AS reserved reserved reserved
147 CROSS reserved (can be function or type) reserved reserved reserved
148 CSV non-reserved
149 CUBE non-reserved reserved reserved
150 CUME_DIST reserved reserved
151 CURRENT non-reserved reserved reserved reserved
152 CURRENT_CATALOG reserved reserved reserved
153 CURRENT_DATE reserved reserved reserved reserved
154 CURRENT_​DEFAULT_​TRANSFORM_​GROUP reserved reserved
155 CURRENT_PATH reserved reserved
156 CURRENT_ROLE reserved reserved reserved
157 CURRENT_ROW reserved reserved
158 CURRENT_SCHEMA reserved (can be function or type) reserved reserved
159 CURRENT_TIME reserved reserved reserved reserved
160 CURRENT_TIMESTAMP reserved reserved reserved reserved
161 CURRENT_​TRANSFORM_​GROUP_​FOR_​TYPE reserved reserved
162 CURRENT_USER reserved reserved reserved reserved
163 CURSOR non-reserved reserved reserved reserved
164 CURSOR_NAME non-reserved non-reserved non-reserved
165 CYCLE non-reserved reserved reserved
166 DATA non-reserved non-reserved non-reserved non-reserved
167 DATABASE non-reserved
168 DATALINK reserved reserved
169 DATE reserved reserved reserved
170 DATETIME_​INTERVAL_​CODE non-reserved non-reserved non-reserved
171 DATETIME_​INTERVAL_​PRECISION non-reserved non-reserved non-reserved
172 DAY non-reserved, requires AS reserved reserved reserved
173 DB non-reserved non-reserved
174 DEALLOCATE non-reserved reserved reserved reserved
175 DEC non-reserved (cannot be function or type) reserved reserved reserved
176 DECFLOAT reserved reserved
177 DECIMAL non-reserved (cannot be function or type) reserved reserved reserved
178 DECLARE non-reserved reserved reserved reserved
179 DEFAULT reserved reserved reserved reserved
180 DEFAULTS non-reserved non-reserved non-reserved
181 DEFERRABLE reserved non-reserved non-reserved reserved
182 DEFERRED non-reserved non-reserved non-reserved reserved
183 DEFINE reserved reserved
184 DEFINED non-reserved non-reserved
185 DEFINER non-reserved non-reserved non-reserved
186 DEGREE non-reserved non-reserved
187 DELETE non-reserved reserved reserved reserved
188 DELIMITER non-reserved
189 DELIMITERS non-reserved
190 DENSE_RANK reserved reserved
191 DEPENDS non-reserved
192 DEPTH non-reserved non-reserved non-reserved
193 DEREF reserved reserved
194 DERIVED non-reserved non-reserved
195 DESC reserved non-reserved non-reserved reserved
196 DESCRIBE reserved reserved reserved
197 DESCRIPTOR non-reserved non-reserved reserved
198 DETACH non-reserved
199 DETERMINISTIC reserved reserved
200 DIAGNOSTICS non-reserved non-reserved reserved
201 DICTIONARY non-reserved
202 DISABLE non-reserved
203 DISCARD non-reserved
204 DISCONNECT reserved reserved reserved
205 DISPATCH non-reserved non-reserved
206 DISTINCT reserved reserved reserved reserved
207 DLNEWCOPY reserved reserved
208 DLPREVIOUSCOPY reserved reserved
209 DLURLCOMPLETE reserved reserved
210 DLURLCOMPLETEONLY reserved reserved
211 DLURLCOMPLETEWRITE reserved reserved
212 DLURLPATH reserved reserved
213 DLURLPATHONLY reserved reserved
214 DLURLPATHWRITE reserved reserved
215 DLURLSCHEME reserved reserved
216 DLURLSERVER reserved reserved
217 DLVALUE reserved reserved
218 DO reserved
219 DOCUMENT non-reserved non-reserved non-reserved
220 DOMAIN non-reserved non-reserved non-reserved reserved
221 DOUBLE non-reserved reserved reserved reserved
222 DROP non-reserved reserved reserved reserved
223 DYNAMIC reserved reserved
224 DYNAMIC_FUNCTION non-reserved non-reserved non-reserved
225 DYNAMIC_​FUNCTION_​CODE non-reserved non-reserved
226 EACH non-reserved reserved reserved
227 ELEMENT reserved reserved
228 ELSE reserved reserved reserved reserved
229 EMPTY reserved reserved
230 ENABLE non-reserved
231 ENCODING non-reserved non-reserved non-reserved
232 ENCRYPTED non-reserved
233 END reserved reserved reserved reserved
234 END-EXEC reserved reserved reserved
235 END_FRAME reserved reserved
236 END_PARTITION reserved reserved
237 ENFORCED non-reserved non-reserved
238 ENUM non-reserved
239 EQUALS reserved reserved
240 ERROR non-reserved non-reserved
241 ESCAPE non-reserved reserved reserved reserved
242 EVENT non-reserved
243 EVERY reserved reserved
244 EXCEPT reserved, requires AS reserved reserved reserved
245 EXCEPTION reserved
246 EXCLUDE non-reserved non-reserved non-reserved
247 EXCLUDING non-reserved non-reserved non-reserved
248 EXCLUSIVE non-reserved
249 EXEC reserved reserved reserved
250 EXECUTE non-reserved reserved reserved reserved
251 EXISTS non-reserved (cannot be function or type) reserved reserved reserved
252 EXP reserved reserved
253 EXPLAIN non-reserved
254 EXPRESSION non-reserved non-reserved non-reserved
255 EXTENSION non-reserved
256 EXTERNAL non-reserved reserved reserved reserved
257 EXTRACT non-reserved (cannot be function or type) reserved reserved reserved
258 FALSE reserved reserved reserved reserved
259 FAMILY non-reserved
260 FETCH reserved, requires AS reserved reserved reserved
261 FILE non-reserved non-reserved
262 FILTER non-reserved, requires AS reserved reserved
263 FINAL non-reserved non-reserved
264 FINALIZE non-reserved
265 FINISH non-reserved non-reserved
266 FIRST non-reserved non-reserved non-reserved reserved
267 FIRST_VALUE reserved reserved
268 FLAG non-reserved non-reserved
269 FLOAT non-reserved (cannot be function or type) reserved reserved reserved
270 FLOOR reserved reserved
271 FOLLOWING non-reserved non-reserved non-reserved
272 FOR reserved, requires AS reserved reserved reserved
273 FORCE non-reserved
274 FOREIGN reserved reserved reserved reserved
275 FORMAT non-reserved non-reserved non-reserved
276 FORTRAN non-reserved non-reserved non-reserved
277 FORWARD non-reserved
278 FOUND non-reserved non-reserved reserved
279 FRAME_ROW reserved reserved
280 FREE reserved reserved
281 FREEZE reserved (can be function or type)
282 FROM reserved, requires AS reserved reserved reserved
283 FS non-reserved non-reserved
284 FULFILL non-reserved non-reserved
285 FULL reserved (can be function or type) reserved reserved reserved
286 FUNCTION non-reserved reserved reserved
287 FUNCTIONS non-reserved
288 FUSION reserved reserved
289 G non-reserved non-reserved
290 GENERAL non-reserved non-reserved
291 GENERATED non-reserved non-reserved non-reserved
292 GET reserved reserved reserved
293 GLOBAL non-reserved reserved reserved reserved
294 GO non-reserved non-reserved reserved
295 GOTO non-reserved non-reserved reserved
296 GRANT reserved, requires AS reserved reserved reserved
297 GRANTED non-reserved non-reserved non-reserved
298 GREATEST non-reserved (cannot be function or type) reserved
299 GROUP reserved, requires AS reserved reserved reserved
300 GROUPING non-reserved (cannot be function or type) reserved reserved
301 GROUPS non-reserved reserved reserved
302 HANDLER non-reserved
303 HAVING reserved, requires AS reserved reserved reserved
304 HEADER non-reserved
305 HEX non-reserved non-reserved
306 HIERARCHY non-reserved non-reserved
307 HOLD non-reserved reserved reserved
308 HOUR non-reserved, requires AS reserved reserved reserved
309 ID non-reserved non-reserved
310 IDENTITY non-reserved reserved reserved reserved
311 IF non-reserved
312 IGNORE non-reserved non-reserved
313 ILIKE reserved (can be function or type)
314 IMMEDIATE non-reserved non-reserved non-reserved reserved
315 IMMEDIATELY non-reserved non-reserved
316 IMMUTABLE non-reserved
317 IMPLEMENTATION non-reserved non-reserved
318 IMPLICIT non-reserved
319 IMPORT non-reserved reserved reserved
320 IN reserved reserved reserved reserved
321 INCLUDE non-reserved
322 INCLUDING non-reserved non-reserved non-reserved
323 INCREMENT non-reserved non-reserved non-reserved
324 INDENT non-reserved non-reserved non-reserved
325 INDEX non-reserved
326 INDEXES non-reserved
327 INDICATOR reserved reserved reserved
328 INHERIT non-reserved
329 INHERITS non-reserved
330 INITIAL reserved reserved
331 INITIALLY reserved non-reserved non-reserved reserved
332 INLINE non-reserved
333 INNER reserved (can be function or type) reserved reserved reserved
334 INOUT non-reserved (cannot be function or type) reserved reserved
335 INPUT non-reserved non-reserved non-reserved reserved
336 INSENSITIVE non-reserved reserved reserved reserved
337 INSERT non-reserved reserved reserved reserved
338 INSTANCE non-reserved non-reserved
339 INSTANTIABLE non-reserved non-reserved
340 INSTEAD non-reserved non-reserved non-reserved
341 INT non-reserved (cannot be function or type) reserved reserved reserved
342 INTEGER non-reserved (cannot be function or type) reserved reserved reserved
343 INTEGRITY non-reserved non-reserved
344 INTERSECT reserved, requires AS reserved reserved reserved
345 INTERSECTION reserved reserved
346 INTERVAL non-reserved (cannot be function or type) reserved reserved reserved
347 INTO reserved, requires AS reserved reserved reserved
348 INVOKER non-reserved non-reserved non-reserved
349 IS reserved (can be function or type) reserved reserved reserved
350 ISNULL reserved (can be function or type), requires AS
351 ISOLATION non-reserved non-reserved non-reserved reserved
352 JOIN reserved (can be function or type) reserved reserved reserved
353 JSON non-reserved reserved
354 JSON_ARRAY non-reserved (cannot be function or type) reserved reserved
355 JSON_ARRAYAGG non-reserved (cannot be function or type) reserved reserved
356 JSON_EXISTS reserved reserved
357 JSON_OBJECT non-reserved (cannot be function or type) reserved reserved
358 JSON_OBJECTAGG non-reserved (cannot be function or type) reserved reserved
359 JSON_QUERY reserved reserved
360 JSON_SCALAR reserved
361 JSON_SERIALIZE reserved
362 JSON_TABLE reserved reserved
363 JSON_TABLE_PRIMITIVE reserved reserved
364 JSON_VALUE reserved reserved
365 K non-reserved non-reserved
366 KEEP non-reserved non-reserved
367 KEY non-reserved non-reserved non-reserved reserved
368 KEYS non-reserved non-reserved non-reserved
369 KEY_MEMBER non-reserved non-reserved
370 KEY_TYPE non-reserved non-reserved
371 LABEL non-reserved
372 LAG reserved reserved
373 LANGUAGE non-reserved reserved reserved reserved
374 LARGE non-reserved reserved reserved
375 LAST non-reserved non-reserved non-reserved reserved
376 LAST_VALUE reserved reserved
377 LATERAL reserved reserved reserved
378 LEAD reserved reserved
379 LEADING reserved reserved reserved reserved
380 LEAKPROOF non-reserved
381 LEAST non-reserved (cannot be function or type) reserved
382 LEFT reserved (can be function or type) reserved reserved reserved
383 LENGTH non-reserved non-reserved non-reserved
384 LEVEL non-reserved non-reserved non-reserved reserved
385 LIBRARY non-reserved non-reserved
386 LIKE reserved (can be function or type) reserved reserved reserved
387 LIKE_REGEX reserved reserved
388 LIMIT reserved, requires AS non-reserved non-reserved
389 LINK non-reserved non-reserved
390 LISTAGG reserved reserved
391 LISTEN non-reserved
392 LN reserved reserved
393 LOAD non-reserved
394 LOCAL non-reserved reserved reserved reserved
395 LOCALTIME reserved reserved reserved
396 LOCALTIMESTAMP reserved reserved reserved
397 LOCATION non-reserved non-reserved non-reserved
398 LOCATOR non-reserved non-reserved
399 LOCK non-reserved
400 LOCKED non-reserved
401 LOG reserved reserved
402 LOG10 reserved reserved
403 LOGGED non-reserved
404 LOWER reserved reserved reserved
405 LPAD reserved
406 LTRIM reserved
407 M non-reserved non-reserved
408 MAP non-reserved non-reserved
409 MAPPING non-reserved non-reserved non-reserved
410 MATCH non-reserved reserved reserved reserved
411 MATCHED non-reserved non-reserved non-reserved
412 MATCHES reserved reserved
413 MATCH_NUMBER reserved reserved
414 MATCH_RECOGNIZE reserved reserved
415 MATERIALIZED non-reserved
416 MAX reserved reserved reserved
417 MAXVALUE non-reserved non-reserved non-reserved
418 MEASURES non-reserved non-reserved
419 MEMBER reserved reserved
420 MERGE non-reserved reserved reserved
421 MESSAGE_LENGTH non-reserved non-reserved non-reserved
422 MESSAGE_OCTET_LENGTH non-reserved non-reserved non-reserved
423 MESSAGE_TEXT non-reserved non-reserved non-reserved
424 METHOD non-reserved reserved reserved
425 MIN reserved reserved reserved
426 MINUTE non-reserved, requires AS reserved reserved reserved
427 MINVALUE non-reserved non-reserved non-reserved
428 MOD reserved reserved
429 MODE non-reserved
430 MODIFIES reserved reserved
431 MODULE reserved reserved reserved
432 MONTH non-reserved, requires AS reserved reserved reserved
433 MORE non-reserved non-reserved non-reserved
434 MOVE non-reserved
435 MULTISET reserved reserved
436 MUMPS non-reserved non-reserved non-reserved
437 NAME non-reserved non-reserved non-reserved non-reserved
438 NAMES non-reserved non-reserved non-reserved reserved
439 NAMESPACE non-reserved non-reserved
440 NATIONAL non-reserved (cannot be function or type) reserved reserved reserved
441 NATURAL reserved (can be function or type) reserved reserved reserved
442 NCHAR non-reserved (cannot be function or type) reserved reserved reserved
443 NCLOB reserved reserved
444 NESTED non-reserved non-reserved
445 NESTING non-reserved non-reserved
446 NEW non-reserved reserved reserved
447 NEXT non-reserved non-reserved non-reserved reserved
448 NFC non-reserved non-reserved non-reserved
449 NFD non-reserved non-reserved non-reserved
450 NFKC non-reserved non-reserved non-reserved
451 NFKD non-reserved non-reserved non-reserved
452 NIL non-reserved non-reserved
453 NO non-reserved reserved reserved reserved
454 NONE non-reserved (cannot be function or type) reserved reserved
455 NORMALIZE non-reserved (cannot be function or type) reserved reserved
456 NORMALIZED non-reserved non-reserved non-reserved
457 NOT reserved reserved reserved reserved
458 NOTHING non-reserved
459 NOTIFY non-reserved
460 NOTNULL reserved (can be function or type), requires AS
461 NOWAIT non-reserved
462 NTH_VALUE reserved reserved
463 NTILE reserved reserved
464 NULL reserved reserved reserved reserved
465 NULLABLE non-reserved non-reserved non-reserved
466 NULLIF non-reserved (cannot be function or type) reserved reserved reserved
467 NULLS non-reserved non-reserved non-reserved
468 NULL_ORDERING non-reserved non-reserved
469 NUMBER non-reserved non-reserved non-reserved
470 NUMERIC non-reserved (cannot be function or type) reserved reserved reserved
471 OBJECT non-reserved non-reserved non-reserved
472 OCCURRENCE non-reserved non-reserved
473 OCCURRENCES_REGEX reserved reserved
474 OCTETS non-reserved non-reserved
475 OCTET_LENGTH reserved reserved reserved
476 OF non-reserved reserved reserved reserved
477 OFF non-reserved non-reserved non-reserved
478 OFFSET reserved, requires AS reserved reserved
479 OIDS non-reserved
480 OLD non-reserved reserved reserved
481 OMIT reserved reserved
482 ON reserved, requires AS reserved reserved reserved
483 ONE reserved reserved
484 ONLY reserved reserved reserved reserved
485 OPEN reserved reserved reserved
486 OPERATOR non-reserved
487 OPTION non-reserved non-reserved non-reserved reserved
488 OPTIONS non-reserved non-reserved non-reserved
489 OR reserved reserved reserved reserved
490 ORDER reserved, requires AS reserved reserved reserved
491 ORDERING non-reserved non-reserved
492 ORDINALITY non-reserved non-reserved non-reserved
493 OTHERS non-reserved non-reserved non-reserved
494 OUT non-reserved (cannot be function or type) reserved reserved
495 OUTER reserved (can be function or type) reserved reserved reserved
496 OUTPUT non-reserved non-reserved reserved
497 OVER non-reserved, requires AS reserved reserved
498 OVERFLOW non-reserved non-reserved
499 OVERLAPS reserved (can be function or type), requires AS reserved reserved reserved
500 OVERLAY non-reserved (cannot be function or type) reserved reserved
501 OVERRIDING non-reserved non-reserved non-reserved
502 OWNED non-reserved
503 OWNER non-reserved
504 P non-reserved non-reserved
505 PAD non-reserved non-reserved reserved
506 PARALLEL non-reserved
507 PARAMETER non-reserved reserved reserved
508 PARAMETER_MODE non-reserved non-reserved
509 PARAMETER_NAME non-reserved non-reserved
510 PARAMETER_​ORDINAL_​POSITION non-reserved non-reserved
511 PARAMETER_​SPECIFIC_​CATALOG non-reserved non-reserved
512 PARAMETER_​SPECIFIC_​NAME non-reserved non-reserved
513 PARAMETER_​SPECIFIC_​SCHEMA non-reserved non-reserved
514 PARSER non-reserved
515 PARTIAL non-reserved non-reserved non-reserved reserved
516 PARTITION non-reserved reserved reserved
517 PASCAL non-reserved non-reserved non-reserved
518 PASS non-reserved non-reserved
519 PASSING non-reserved non-reserved non-reserved
520 PASSTHROUGH non-reserved non-reserved
521 PASSWORD non-reserved
522 PAST non-reserved non-reserved
523 PATH non-reserved non-reserved
524 PATTERN reserved reserved
525 PER reserved reserved
526 PERCENT reserved reserved
527 PERCENTILE_CONT reserved reserved
528 PERCENTILE_DISC reserved reserved
529 PERCENT_RANK reserved reserved
530 PERIOD reserved reserved
531 PERMISSION non-reserved non-reserved
532 PERMUTE non-reserved non-reserved
533 PIPE non-reserved non-reserved
534 PLACING reserved non-reserved non-reserved
535 PLAN non-reserved non-reserved
536 PLANS non-reserved
537 PLI non-reserved non-reserved non-reserved
538 POLICY non-reserved
539 PORTION reserved reserved
540 POSITION non-reserved (cannot be function or type) reserved reserved reserved
541 POSITION_REGEX reserved reserved
542 POWER reserved reserved
543 PRECEDES reserved reserved
544 PRECEDING non-reserved non-reserved non-reserved
545 PRECISION non-reserved (cannot be function or type), requires AS reserved reserved reserved
546 PREPARE non-reserved reserved reserved reserved
547 PREPARED non-reserved
548 PRESERVE non-reserved non-reserved non-reserved reserved
549 PREV non-reserved non-reserved
550 PRIMARY reserved reserved reserved reserved
551 PRIOR non-reserved non-reserved non-reserved reserved
552 PRIVATE non-reserved non-reserved
553 PRIVILEGES non-reserved non-reserved non-reserved reserved
554 PROCEDURAL non-reserved
555 PROCEDURE non-reserved reserved reserved reserved
556 PROCEDURES non-reserved
557 PROGRAM non-reserved
558 PRUNE non-reserved non-reserved
559 PTF reserved reserved
560 PUBLIC non-reserved non-reserved reserved
561 PUBLICATION non-reserved
562 QUOTE non-reserved
563 QUOTES non-reserved non-reserved
564 RANGE non-reserved reserved reserved
565 RANK reserved reserved
566 READ non-reserved non-reserved non-reserved reserved
567 READS reserved reserved
568 REAL non-reserved (cannot be function or type) reserved reserved reserved
569 REASSIGN non-reserved
570 RECHECK non-reserved
571 RECOVERY non-reserved non-reserved
572 RECURSIVE non-reserved reserved reserved
573 REF non-reserved reserved reserved
574 REFERENCES reserved reserved reserved reserved
575 REFERENCING non-reserved reserved reserved
576 REFRESH non-reserved
577 REGR_AVGX reserved reserved
578 REGR_AVGY reserved reserved
579 REGR_COUNT reserved reserved
580 REGR_INTERCEPT reserved reserved
581 REGR_R2 reserved reserved
582 REGR_SLOPE reserved reserved
583 REGR_SXX reserved reserved
584 REGR_SXY reserved reserved
585 REGR_SYY reserved reserved
586 REINDEX non-reserved
587 RELATIVE non-reserved non-reserved non-reserved reserved
588 RELEASE non-reserved reserved reserved
589 RENAME non-reserved
590 REPEATABLE non-reserved non-reserved non-reserved non-reserved
591 REPLACE non-reserved
592 REPLICA non-reserved
593 REQUIRING non-reserved non-reserved
594 RESET non-reserved
595 RESPECT non-reserved non-reserved
596 RESTART non-reserved non-reserved non-reserved
597 RESTORE non-reserved non-reserved
598 RESTRICT non-reserved non-reserved non-reserved reserved
599 RESULT reserved reserved
600 RETURN non-reserved reserved reserved
601 RETURNED_CARDINALITY non-reserved non-reserved
602 RETURNED_LENGTH non-reserved non-reserved non-reserved
603 RETURNED_​OCTET_​LENGTH non-reserved non-reserved non-reserved
604 RETURNED_SQLSTATE non-reserved non-reserved non-reserved
605 RETURNING reserved, requires AS non-reserved non-reserved
606 RETURNS non-reserved reserved reserved
607 REVOKE non-reserved reserved reserved reserved
608 RIGHT reserved (can be function or type) reserved reserved reserved
609 ROLE non-reserved non-reserved non-reserved
610 ROLLBACK non-reserved reserved reserved reserved
611 ROLLUP non-reserved reserved reserved
612 ROUTINE non-reserved non-reserved non-reserved
613 ROUTINES non-reserved
614 ROUTINE_CATALOG non-reserved non-reserved
615 ROUTINE_NAME non-reserved non-reserved
616 ROUTINE_SCHEMA non-reserved non-reserved
617 ROW non-reserved (cannot be function or type) reserved reserved
618 ROWS non-reserved reserved reserved reserved
619 ROW_COUNT non-reserved non-reserved non-reserved
620 ROW_NUMBER reserved reserved
621 RPAD reserved
622 RTRIM reserved
623 RULE non-reserved
624 RUNNING reserved reserved
625 SAVEPOINT non-reserved reserved reserved
626 SCALAR non-reserved non-reserved non-reserved
627 SCALE non-reserved non-reserved non-reserved
628 SCHEMA non-reserved non-reserved non-reserved reserved
629 SCHEMAS non-reserved
630 SCHEMA_NAME non-reserved non-reserved non-reserved
631 SCOPE reserved reserved
632 SCOPE_CATALOG non-reserved non-reserved
633 SCOPE_NAME non-reserved non-reserved
634 SCOPE_SCHEMA non-reserved non-reserved
635 SCROLL non-reserved reserved reserved reserved
636 SEARCH non-reserved reserved reserved
637 SECOND non-reserved, requires AS reserved reserved reserved
638 SECTION non-reserved non-reserved reserved
639 SECURITY non-reserved non-reserved non-reserved
640 SEEK reserved reserved
641 SELECT reserved reserved reserved reserved
642 SELECTIVE non-reserved non-reserved
643 SELF non-reserved non-reserved
644 SEMANTICS non-reserved non-reserved
645 SENSITIVE reserved reserved
646 SEQUENCE non-reserved non-reserved non-reserved
647 SEQUENCES non-reserved
648 SERIALIZABLE non-reserved non-reserved non-reserved non-reserved
649 SERVER non-reserved non-reserved non-reserved
650 SERVER_NAME non-reserved non-reserved non-reserved
651 SESSION non-reserved non-reserved non-reserved reserved
652 SESSION_USER reserved reserved reserved reserved
653 SET non-reserved reserved reserved reserved
654 SETOF non-reserved (cannot be function or type)
655 SETS non-reserved non-reserved non-reserved
656 SHARE non-reserved
657 SHOW non-reserved reserved reserved
658 SIMILAR reserved (can be function or type) reserved reserved
659 SIMPLE non-reserved non-reserved non-reserved
660 SIN reserved reserved
661 SINH reserved reserved
662 SIZE non-reserved non-reserved reserved
663 SKIP non-reserved reserved reserved
664 SMALLINT non-reserved (cannot be function or type) reserved reserved reserved
665 SNAPSHOT non-reserved
666 SOME reserved reserved reserved reserved
667 SORT_DIRECTION non-reserved non-reserved
668 SOURCE non-reserved non-reserved
669 SPACE non-reserved non-reserved reserved
670 SPECIFIC reserved reserved
671 SPECIFICTYPE reserved reserved
672 SPECIFIC_NAME non-reserved non-reserved
673 SQL non-reserved reserved reserved reserved
674 SQLCODE reserved
675 SQLERROR reserved
676 SQLEXCEPTION reserved reserved
677 SQLSTATE reserved reserved reserved
678 SQLWARNING reserved reserved
679 SQRT reserved reserved
680 STABLE non-reserved
681 STANDALONE non-reserved non-reserved non-reserved
682 START non-reserved reserved reserved
683 STATE non-reserved non-reserved
684 STATEMENT non-reserved non-reserved non-reserved
685 STATIC reserved reserved
686 STATISTICS non-reserved
687 STDDEV_POP reserved reserved
688 STDDEV_SAMP reserved reserved
689 STDIN non-reserved
690 STDOUT non-reserved
691 STORAGE non-reserved
692 STORED non-reserved
693 STRICT non-reserved
694 STRING non-reserved non-reserved
695 STRIP non-reserved non-reserved non-reserved
696 STRUCTURE non-reserved non-reserved
697 STYLE non-reserved non-reserved
698 SUBCLASS_ORIGIN non-reserved non-reserved non-reserved
699 SUBMULTISET reserved reserved
700 SUBSCRIPTION non-reserved
701 SUBSET reserved reserved
702 SUBSTRING non-reserved (cannot be function or type) reserved reserved reserved
703 SUBSTRING_REGEX reserved reserved
704 SUCCEEDS reserved reserved
705 SUM reserved reserved reserved
706 SUPPORT non-reserved
707 SYMMETRIC reserved reserved reserved
708 SYSID non-reserved
709 SYSTEM non-reserved reserved reserved
710 SYSTEM_TIME reserved reserved
711 SYSTEM_USER reserved reserved reserved reserved
712 T non-reserved non-reserved
713 TABLE reserved reserved reserved reserved
714 TABLES non-reserved
715 TABLESAMPLE reserved (can be function or type) reserved reserved
716 TABLESPACE non-reserved
717 TABLE_NAME non-reserved non-reserved non-reserved
718 TAN reserved reserved
719 TANH reserved reserved
720 TEMP non-reserved
721 TEMPLATE non-reserved
722 TEMPORARY non-reserved non-reserved non-reserved reserved
723 TEXT non-reserved
724 THEN reserved reserved reserved reserved
725 THROUGH non-reserved non-reserved
726 TIES non-reserved non-reserved non-reserved
727 TIME non-reserved (cannot be function or type) reserved reserved reserved
728 TIMESTAMP non-reserved (cannot be function or type) reserved reserved reserved
729 TIMEZONE_HOUR reserved reserved reserved
730 TIMEZONE_MINUTE reserved reserved reserved
731 TO reserved, requires AS reserved reserved reserved
732 TOKEN non-reserved non-reserved
733 TOP_LEVEL_COUNT non-reserved non-reserved
734 TRAILING reserved reserved reserved reserved
735 TRANSACTION non-reserved non-reserved non-reserved reserved
736 TRANSACTIONS_​COMMITTED non-reserved non-reserved
737 TRANSACTIONS_​ROLLED_​BACK non-reserved non-reserved
738 TRANSACTION_ACTIVE non-reserved non-reserved
739 TRANSFORM non-reserved non-reserved non-reserved
740 TRANSFORMS non-reserved non-reserved
741 TRANSLATE reserved reserved reserved
742 TRANSLATE_REGEX reserved reserved
743 TRANSLATION reserved reserved reserved
744 TREAT non-reserved (cannot be function or type) reserved reserved
745 TRIGGER non-reserved reserved reserved
746 TRIGGER_CATALOG non-reserved non-reserved
747 TRIGGER_NAME non-reserved non-reserved
748 TRIGGER_SCHEMA non-reserved non-reserved
749 TRIM non-reserved (cannot be function or type) reserved reserved reserved
750 TRIM_ARRAY reserved reserved
751 TRUE reserved reserved reserved reserved
752 TRUNCATE non-reserved reserved reserved
753 TRUSTED non-reserved
754 TYPE non-reserved non-reserved non-reserved non-reserved
755 TYPES non-reserved
756 UESCAPE non-reserved reserved reserved
757 UNBOUNDED non-reserved non-reserved non-reserved
758 UNCOMMITTED non-reserved non-reserved non-reserved non-reserved
759 UNCONDITIONAL non-reserved non-reserved
760 UNDER non-reserved non-reserved
761 UNENCRYPTED non-reserved
762 UNION reserved, requires AS reserved reserved reserved
763 UNIQUE reserved reserved reserved reserved
764 UNKNOWN non-reserved reserved reserved reserved
765 UNLINK non-reserved non-reserved
766 UNLISTEN non-reserved
767 UNLOGGED non-reserved
768 UNMATCHED non-reserved non-reserved
769 UNNAMED non-reserved non-reserved non-reserved
770 UNNEST reserved reserved
771 UNTIL non-reserved
772 UNTYPED non-reserved non-reserved
773 UPDATE non-reserved reserved reserved reserved
774 UPPER reserved reserved reserved
775 URI non-reserved non-reserved
776 USAGE non-reserved non-reserved reserved
777 USER reserved reserved reserved reserved
778 USER_​DEFINED_​TYPE_​CATALOG non-reserved non-reserved
779 USER_​DEFINED_​TYPE_​CODE non-reserved non-reserved
780 USER_​DEFINED_​TYPE_​NAME non-reserved non-reserved
781 USER_​DEFINED_​TYPE_​SCHEMA non-reserved non-reserved
782 USING reserved reserved reserved reserved
783 UTF16 non-reserved non-reserved
784 UTF32 non-reserved non-reserved
785 UTF8 non-reserved non-reserved
786 VACUUM non-reserved
787 VALID non-reserved non-reserved non-reserved
788 VALIDATE non-reserved
789 VALIDATOR non-reserved
790 VALUE non-reserved reserved reserved reserved
791 VALUES non-reserved (cannot be function or type) reserved reserved reserved
792 VALUE_OF reserved reserved
793 VARBINARY reserved reserved
794 VARCHAR non-reserved (cannot be function or type) reserved reserved reserved
795 VARIADIC reserved
796 VARYING non-reserved, requires AS reserved reserved reserved
797 VAR_POP reserved reserved
798 VAR_SAMP reserved reserved
799 VERBOSE reserved (can be function or type)
800 VERSION non-reserved non-reserved non-reserved
801 VERSIONING reserved reserved
802 VIEW non-reserved non-reserved non-reserved reserved
803 VIEWS non-reserved
804 VOLATILE non-reserved
805 WHEN reserved reserved reserved reserved
806 WHENEVER reserved reserved reserved
807 WHERE reserved, requires AS reserved reserved reserved
808 WHITESPACE non-reserved non-reserved non-reserved
809 WIDTH_BUCKET reserved reserved
810 WINDOW reserved, requires AS reserved reserved
811 WITH reserved, requires AS reserved reserved reserved
812 WITHIN non-reserved, requires AS reserved reserved
813 WITHOUT non-reserved, requires AS reserved reserved
814 WORK non-reserved non-reserved non-reserved reserved
815 WRAPPER non-reserved non-reserved non-reserved
816 WRITE non-reserved non-reserved non-reserved reserved
817 XML non-reserved reserved reserved
818 XMLAGG reserved reserved
819 XMLATTRIBUTES non-reserved (cannot be function or type) reserved reserved
820 XMLBINARY reserved reserved
821 XMLCAST reserved reserved
822 XMLCOMMENT reserved reserved
823 XMLCONCAT non-reserved (cannot be function or type) reserved reserved
824 XMLDECLARATION non-reserved non-reserved
825 XMLDOCUMENT reserved reserved
826 XMLELEMENT non-reserved (cannot be function or type) reserved reserved
827 XMLEXISTS non-reserved (cannot be function or type) reserved reserved
828 XMLFOREST non-reserved (cannot be function or type) reserved reserved
829 XMLITERATE reserved reserved
830 XMLNAMESPACES non-reserved (cannot be function or type) reserved reserved
831 XMLPARSE non-reserved (cannot be function or type) reserved reserved
832 XMLPI non-reserved (cannot be function or type) reserved reserved
833 XMLQUERY reserved reserved
834 XMLROOT non-reserved (cannot be function or type)
835 XMLSCHEMA non-reserved non-reserved
836 XMLSERIALIZE non-reserved (cannot be function or type) reserved reserved
837 XMLTABLE non-reserved (cannot be function or type) reserved reserved
838 XMLTEXT reserved reserved
839 XMLVALIDATE reserved reserved
840 YEAR non-reserved, requires AS reserved reserved reserved
841 YES non-reserved non-reserved non-reserved
842 ZONE non-reserved non-reserved non-reserved reserved

View file

@ -0,0 +1,106 @@
from __future__ import annotations
from datetime import date, datetime
from typing import TYPE_CHECKING
import psycopg
from psycopg.errors import DataError
# Subclass existing adapters so that the base case is handled normally.
from psycopg.types.datetime import (
DateBinaryLoader,
DateLoader,
TimestampBinaryLoader,
TimestampLoader,
TimestamptzBinaryLoader,
TimestamptzLoader,
)
if TYPE_CHECKING:
from psycopg.adapt import Buffer, Loader
class InfDateLoader(DateLoader):
def load(self, data: "Buffer") -> date:
if data == b"infinity":
return date.max
elif data == b"-infinity":
return date.min
else:
return super().load(data)
class InfDateBinaryLoader(DateBinaryLoader):
def load(self, data: "Buffer") -> date:
try:
return super().load(data)
except DataError as e:
if "date too small" in str(e):
return date.min
elif "date too large" in str(e):
return date.max
raise e
class InfTimestampLoader(TimestampLoader):
def load(self, data: "Buffer") -> datetime:
if data == b"infinity":
return datetime.max
elif data == b"-infinity":
return datetime.min
else:
return super().load(data)
class InfTimestampBinaryLoader(TimestampBinaryLoader):
def load(self, data: "Buffer") -> datetime:
try:
return super().load(data)
except DataError as e:
if "timestamp too small" in str(e):
return datetime.min
elif "timestamp too large" in str(e):
return datetime.max
raise e
class InfTimestamptzLoader(TimestamptzLoader):
def load(self, data: "Buffer") -> datetime:
if data == b"infinity":
return datetime.max
elif data == b"-infinity":
return datetime.min
else:
return super().load(data)
class InfTimestamptzBinaryLoader(TimestamptzBinaryLoader):
def load(self, data: "Buffer") -> datetime:
try:
return super().load(data)
except DataError as e:
if "timestamp too small" in str(e):
return datetime.min
elif "timestamp too large" in str(e):
return datetime.max
raise e
INF_LOADERS: list[tuple[str, type["Loader"]]] = [
("date", InfDateLoader),
("date", InfDateBinaryLoader),
("timestamp", InfTimestampLoader),
("timestamp", InfTimestampBinaryLoader),
("timestamptz", InfTimestamptzLoader),
("timestamptz", InfTimestamptzBinaryLoader),
]
def register_inf_loaders() -> None:
"""
Register updated date/datetime loaders in the global types
registry, so that any connections created afterwards will use
the updated loaders (that allow infinity date/timestamps)
"""
for type_name, loader in INF_LOADERS:
psycopg.adapters.register_loader(type_name, loader)

View file

40
tests/conftest.py Normal file
View file

@ -0,0 +1,40 @@
from __future__ import annotations
import sys
from typing import Generator
import psycopg
import pytest
from harlequin_postgres.adapter import (
HarlequinPostgresAdapter,
HarlequinPostgresConnection,
)
if sys.version_info < (3, 10):
pass
else:
pass
TEST_DB_CONN = "postgresql://postgres:for-testing@localhost:5432"
@pytest.fixture
def connection() -> Generator[HarlequinPostgresConnection, None, None]:
pgconn = psycopg.connect(conninfo=TEST_DB_CONN, dbname="postgres")
pgconn.autocommit = True
cur = pgconn.cursor()
cur.execute("drop database if exists test;")
cur.execute("create database test;")
cur.close()
pgconn.close()
conn = HarlequinPostgresAdapter(
conn_str=(f"{TEST_DB_CONN}",), dbname="test"
).connect()
yield conn
conn.close()
pgconn = psycopg.connect(conninfo=TEST_DB_CONN, dbname="postgres")
pgconn.autocommit = True
cur = pgconn.cursor()
cur.execute("drop database if exists test;")
cur.close()
pgconn.close()

158
tests/test_adapter.py Normal file
View file

@ -0,0 +1,158 @@
from __future__ import annotations
import sys
from datetime import date, datetime
import pytest
from harlequin.adapter import HarlequinAdapter, HarlequinConnection, HarlequinCursor
from harlequin.catalog import Catalog, CatalogItem
from harlequin.exception import HarlequinConnectionError, HarlequinQueryError
from harlequin_postgres.adapter import (
HarlequinPostgresAdapter,
HarlequinPostgresConnection,
)
from textual_fastdatatable.backend import create_backend
if sys.version_info < (3, 10):
from importlib_metadata import entry_points
else:
from importlib.metadata import entry_points
TEST_DB_CONN = "postgresql://postgres:for-testing@localhost:5432"
def test_plugin_discovery() -> None:
PLUGIN_NAME = "postgres"
eps = entry_points(group="harlequin.adapter")
assert eps[PLUGIN_NAME]
adapter_cls = eps[PLUGIN_NAME].load()
assert issubclass(adapter_cls, HarlequinAdapter)
assert adapter_cls == HarlequinPostgresAdapter
def test_connect() -> None:
conn = HarlequinPostgresAdapter(conn_str=(TEST_DB_CONN,)).connect()
assert isinstance(conn, HarlequinConnection)
def test_init_extra_kwargs() -> None:
assert HarlequinPostgresAdapter(
conn_str=(TEST_DB_CONN,), foo=1, bar="baz"
).connect()
@pytest.mark.parametrize(
"conn_str",
[
("foo",),
("host=foo",),
("postgresql://admin:pass@foo:5432/db",),
],
)
def test_connect_raises_connection_error(conn_str: tuple[str]) -> None:
with pytest.raises(HarlequinConnectionError):
_ = HarlequinPostgresAdapter(conn_str=conn_str, connect_timeout=0.1).connect()
@pytest.mark.parametrize(
"conn_str,options,expected",
[
(("",), {}, "localhost:5432/postgres"),
(("host=foo",), {}, "foo:5432/postgres"),
(("postgresql://foo",), {}, "foo:5432/postgres"),
(("postgresql://foo",), {"port": 5431}, "foo:5431/postgres"),
(("postgresql://foo/mydb",), {"port": 5431}, "foo:5431/mydb"),
(("postgresql://admin:pass@foo/mydb",), {"port": 5431}, "foo:5431/mydb"),
(("postgresql://admin:pass@foo:5431/mydb",), {}, "foo:5431/mydb"),
],
)
def test_connection_id(
conn_str: tuple[str], options: dict[str, int | float | str | None], expected: str
) -> None:
adapter = HarlequinPostgresAdapter(
conn_str=conn_str,
**options, # type: ignore[arg-type]
)
assert adapter.connection_id == expected
def test_get_catalog(connection: HarlequinPostgresConnection) -> None:
catalog = connection.get_catalog()
assert isinstance(catalog, Catalog)
assert catalog.items
assert isinstance(catalog.items[0], CatalogItem)
def test_get_completions(connection: HarlequinPostgresConnection) -> None:
completions = connection.get_completions()
test_labels = ["atomic", "greatest", "point_right", "autovacuum"]
filtered = list(filter(lambda x: x.label in test_labels, completions))
assert len(filtered) == 4
value_filtered = list(filter(lambda x: x.value in test_labels, completions))
assert len(value_filtered) == 4
def test_execute_ddl(connection: HarlequinPostgresConnection) -> None:
cur = connection.execute("create table foo (a int)")
assert cur is None
def test_execute_select(connection: HarlequinPostgresConnection) -> None:
cur = connection.execute("select 1 as a")
assert isinstance(cur, HarlequinCursor)
assert cur.columns() == [("a", "#")]
data = cur.fetchall()
backend = create_backend(data)
assert backend.column_count == 1
assert backend.row_count == 1
def test_execute_select_dupe_cols(connection: HarlequinPostgresConnection) -> None:
cur = connection.execute("select 1 as a, 2 as a, 3 as a")
assert isinstance(cur, HarlequinCursor)
assert len(cur.columns()) == 3
data = cur.fetchall()
backend = create_backend(data)
assert backend.column_count == 3
assert backend.row_count == 1
def test_set_limit(connection: HarlequinPostgresConnection) -> None:
cur = connection.execute("select 1 as a union all select 2 union all select 3")
assert isinstance(cur, HarlequinCursor)
cur = cur.set_limit(2)
assert isinstance(cur, HarlequinCursor)
data = cur.fetchall()
backend = create_backend(data)
assert backend.column_count == 1
assert backend.row_count == 2
def test_execute_raises_query_error(connection: HarlequinPostgresConnection) -> None:
with pytest.raises(HarlequinQueryError):
_ = connection.execute("sel;")
def test_inf_timestamps(connection: HarlequinPostgresConnection) -> None:
cur = connection.execute(
"""select
'infinity'::date,
'infinity'::timestamp,
'infinity'::timestamptz,
'-infinity'::date,
'-infinity'::timestamp,
'-infinity'::timestamptz
"""
)
assert cur is not None
data = cur.fetchall()
assert data == [
(
date.max,
datetime.max,
datetime.max,
date.min,
datetime.min,
datetime.min,
)
]

92
tests/test_catalog.py Normal file
View file

@ -0,0 +1,92 @@
import pytest
from harlequin.catalog import InteractiveCatalogItem
from harlequin_postgres.adapter import HarlequinPostgresConnection
from harlequin_postgres.catalog import (
ColumnCatalogItem,
DatabaseCatalogItem,
RelationCatalogItem,
SchemaCatalogItem,
TableCatalogItem,
ViewCatalogItem,
)
@pytest.fixture
def connection_with_objects(
connection: HarlequinPostgresConnection,
) -> HarlequinPostgresConnection:
connection.execute("create schema one")
connection.execute("create table one.foo as select 1 as a, '2' as b")
connection.execute("create table one.bar as select 1 as a, '2' as b")
connection.execute("create table one.baz as select 1 as a, '2' as b")
connection.execute("create schema two")
connection.execute("create view two.qux as select * from one.foo")
connection.execute("create schema three")
# the original connection fixture will clean this up.
return connection
def test_catalog(connection_with_objects: HarlequinPostgresConnection) -> None:
conn = connection_with_objects
catalog = conn.get_catalog()
# at least two databases, postgres and test
assert len(catalog.items) >= 2
[test_db_item] = filter(lambda item: item.label == "test", catalog.items)
assert isinstance(test_db_item, InteractiveCatalogItem)
assert isinstance(test_db_item, DatabaseCatalogItem)
assert not test_db_item.children
assert not test_db_item.loaded
schema_items = test_db_item.fetch_children()
assert all(isinstance(item, SchemaCatalogItem) for item in schema_items)
[schema_one_item] = filter(lambda item: item.label == "one", schema_items)
assert isinstance(schema_one_item, SchemaCatalogItem)
assert not schema_one_item.children
assert not schema_one_item.loaded
table_items = schema_one_item.fetch_children()
assert all(isinstance(item, RelationCatalogItem) for item in table_items)
[foo_item] = filter(lambda item: item.label == "foo", table_items)
assert isinstance(foo_item, TableCatalogItem)
assert not foo_item.children
assert not foo_item.loaded
foo_column_items = foo_item.fetch_children()
assert all(isinstance(item, ColumnCatalogItem) for item in foo_column_items)
[schema_two_item] = filter(lambda item: item.label == "two", schema_items)
assert isinstance(schema_two_item, SchemaCatalogItem)
assert not schema_two_item.children
assert not schema_two_item.loaded
view_items = schema_two_item.fetch_children()
assert all(isinstance(item, ViewCatalogItem) for item in view_items)
[qux_item] = filter(lambda item: item.label == "qux", view_items)
assert isinstance(qux_item, ViewCatalogItem)
assert not qux_item.children
assert not qux_item.loaded
qux_column_items = qux_item.fetch_children()
assert all(isinstance(item, ColumnCatalogItem) for item in qux_column_items)
assert [item.label for item in foo_column_items] == [
item.label for item in qux_column_items
]
# ensure calling fetch_children on cols doesn't raise
children_items = foo_column_items[0].fetch_children()
assert not children_items
[schema_three_item] = filter(lambda item: item.label == "three", schema_items)
assert isinstance(schema_two_item, SchemaCatalogItem)
assert not schema_two_item.children
assert not schema_two_item.loaded
three_children = schema_three_item.fetch_children()
assert not three_children