Full Code of taocpp/taopq for AI

main 0f28919fd7aa cached
146 files
586.6 KB
153.0k tokens
1002 symbols
1 requests
Download .txt
Showing preview only (627K chars total). Download the full file or copy to clipboard to get everything.
Repository: taocpp/taopq
Branch: main
Commit: 0f28919fd7aa
Files: 146
Total size: 586.6 KB

Directory structure:
gitextract_iares_uf/

├── .clang-format
├── .clang-tidy
├── .github/
│   ├── conan/
│   │   ├── conanfile.py
│   │   └── profiles/
│   │       ├── clangcl
│   │       └── msvc
│   └── workflows/
│       ├── clang-analyze.yml
│       ├── clang-format.yml
│       ├── clang-tidy.yml
│       ├── code-coverage.yml
│       ├── linux.yml
│       ├── macos.yml
│       ├── sanitizer.yml
│       └── windows.yml
├── .gitignore
├── CMakeLists.txt
├── CMakePresets.json
├── LICENSE_1_0.txt
├── Makefile
├── README.md
├── doc/
│   ├── Aggregate-Support.md
│   ├── Binary-Data.md
│   ├── Bulk-Transfer.md
│   ├── Connection-Pool.md
│   ├── Connection.md
│   ├── Error-Handling.md
│   ├── Getting-Started.md
│   ├── Installation.md
│   ├── Large-Object.md
│   ├── Parameter-Type-Conversion.md
│   ├── Performance.md
│   ├── Requirements.md
│   ├── Result-Type-Conversion.md
│   ├── Result.md
│   ├── Statement.md
│   ├── TOC.md
│   └── Transaction.md
├── example/
│   ├── CMakeLists.txt
│   └── get_version/
│       ├── CMakeLists.txt
│       └── main.cpp
├── include/
│   └── tao/
│       ├── pq/
│       │   ├── access_mode.hpp
│       │   ├── binary.hpp
│       │   ├── bind.hpp
│       │   ├── connection.hpp
│       │   ├── connection_pool.hpp
│       │   ├── connection_status.hpp
│       │   ├── exception.hpp
│       │   ├── field.hpp
│       │   ├── internal/
│       │   │   ├── aggregate.hpp
│       │   │   ├── demangle.hpp
│       │   │   ├── exclusive_scan.hpp
│       │   │   ├── format_as.hpp
│       │   │   ├── from_chars.hpp
│       │   │   ├── gen.hpp
│       │   │   ├── parameter_traits_helper.hpp
│       │   │   ├── poll.hpp
│       │   │   ├── pool.hpp
│       │   │   ├── resize_uninitialized.hpp
│       │   │   ├── strtox.hpp
│       │   │   ├── unreachable.hpp
│       │   │   └── zsv.hpp
│       │   ├── is_aggregate.hpp
│       │   ├── is_array.hpp
│       │   ├── isolation_level.hpp
│       │   ├── large_object.hpp
│       │   ├── log.hpp
│       │   ├── notification.hpp
│       │   ├── null.hpp
│       │   ├── oid.hpp
│       │   ├── parameter.hpp
│       │   ├── parameter_traits.hpp
│       │   ├── parameter_traits_aggregate.hpp
│       │   ├── parameter_traits_array.hpp
│       │   ├── parameter_traits_optional.hpp
│       │   ├── parameter_traits_pair.hpp
│       │   ├── parameter_traits_tuple.hpp
│       │   ├── pipeline.hpp
│       │   ├── pipeline_status.hpp
│       │   ├── poll.hpp
│       │   ├── result.hpp
│       │   ├── result_status.hpp
│       │   ├── result_traits.hpp
│       │   ├── result_traits_aggregate.hpp
│       │   ├── result_traits_array.hpp
│       │   ├── result_traits_optional.hpp
│       │   ├── result_traits_pair.hpp
│       │   ├── result_traits_tuple.hpp
│       │   ├── row.hpp
│       │   ├── table_field.hpp
│       │   ├── table_reader.hpp
│       │   ├── table_row.hpp
│       │   ├── table_writer.hpp
│       │   ├── transaction.hpp
│       │   ├── transaction_base.hpp
│       │   ├── transaction_status.hpp
│       │   └── version.hpp
│       └── pq.hpp
├── src/
│   └── lib/
│       └── pq/
│           ├── connection.cpp
│           ├── connection_pool.cpp
│           ├── exception.cpp
│           ├── field.cpp
│           ├── internal/
│           │   ├── demangle.cpp
│           │   ├── poll.cpp
│           │   └── strtox.cpp
│           ├── large_object.cpp
│           ├── parameter_traits.cpp
│           ├── pipeline.cpp
│           ├── result.cpp
│           ├── result_traits.cpp
│           ├── result_traits_array.cpp
│           ├── row.cpp
│           ├── table_field.cpp
│           ├── table_reader.cpp
│           ├── table_row.cpp
│           ├── table_writer.cpp
│           ├── transaction.cpp
│           └── transaction_base.cpp
└── test/
    ├── CMakeLists.txt
    ├── integration/
    │   ├── aggregate.cpp
    │   ├── array.cpp
    │   ├── basic_datatypes.cpp
    │   ├── chunk_mode.cpp
    │   ├── connection.cpp
    │   ├── connection_pool.cpp
    │   ├── example.cpp
    │   ├── exception.cpp
    │   ├── large_object.cpp
    │   ├── log.cpp
    │   ├── notifications.cpp
    │   ├── parameter.cpp
    │   ├── password.cpp
    │   ├── pipeline_mode.cpp
    │   ├── result.cpp
    │   ├── row.cpp
    │   ├── single_row_mode.cpp
    │   ├── table_reader.cpp
    │   ├── table_writer.cpp
    │   ├── traits.cpp
    │   └── transaction.cpp
    ├── unit/
    │   ├── getenv.cpp
    │   ├── parameter_type.cpp
    │   ├── resize_uninitialized.cpp
    │   ├── result_type.cpp
    │   └── strtox.cpp
    └── utils/
        ├── compare.hpp
        ├── getenv.hpp
        └── macros.hpp

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
# The Art of C++
# https://github.com/taocpp

# Copyright (c) 2016-2026 Dr. Colin Hirsch and Daniel Frey
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

# This is our official .clang-format style for https://github.com/taocpp
#
# clang-format -i -style=file $(find . -name '[^.]*.[hc]pp')

Language: Cpp
Standard: Latest

AccessModifierOffset: -3
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
    AfterClass: true
    AfterControlStatement: false
    AfterEnum : true
    AfterFunction : true
    AfterNamespace : true
    AfterStruct : true
    AfterUnion : true
    AfterExternBlock: true
    BeforeCatch : true
    BeforeElse : true
    IndentBraces : false
    SplitEmptyFunction: false
    SplitEmptyRecord: false
    SplitEmptyNamespace: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: false
ColumnLimit: 0
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 3
ContinuationIndentWidth: 3
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 3
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
PointerAlignment: Left
ReflowComments: false
SortIncludes: true
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Never
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: true
SpacesInSquareBrackets: true
TabWidth: 8
UseTab: Never


================================================
FILE: .clang-tidy
================================================
# The Art of C++
# https://github.com/taocpp

# Copyright (c) 2016-2026 Dr. Colin Hirsch and Daniel Frey
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

# Note: The misc-include-cleaner is generally useful,
# but produces false positives with Oid/InvalidOid and libpq-fe.h.
# For that reason it is disabled, but it should be enabled
# manually from time to time.

Checks: >-
  bugprone-*,
  -bugprone-easily-swappable-parameters,
  cppcoreguidelines-slicing,
  cppcoreguidelines-special-member-functions,
  google-build-explicit-make-pair,
  google-build-namespaces,
  google-default-arguments,
  google-global-names-in-headers,
  google-readability-casting,
  llvm-*,
  misc-*,
  -misc-include-cleaner,
  -misc-non-private-member-variables-in-classes,
  -misc-unused-alias-decls,
  modernize-*,
  -modernize-avoid-c-arrays,
  -modernize-concat-nested-namespaces,
  -modernize-raw-string-literal,
  performance-*,
  readability-*,
  -readability-avoid-const-params-in-decls,
  -readability-function-cognitive-complexity,
  -readability-identifier-length,
  -readability-magic-numbers,
  -readability-non-const-parameter,

CheckOptions:
  - { key: readability-identifier-naming.ClassCase,     value: lower_case }
  - { key: readability-identifier-naming.FunctionCase,  value: lower_case }
  - { key: readability-identifier-naming.ParameterCase, value: lower_case }
  - { key: readability-identifier-naming.StructCase,    value: lower_case }
  - { key: readability-identifier-naming.VariableCase,  value: lower_case }

WarningsAsErrors: '*'


================================================
FILE: .github/conan/conanfile.py
================================================
from conan import ConanFile
from conan.tools.cmake import CMakeDeps, CMakeToolchain, cmake_layout

class TaopqRequirements(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    default_options = {
        "libpq/*:with_openssl": False,
        "libpq/*:with_icu": False,
        "libpq/*:with_zlib": False,
        "libpq/*:with_zstd": False,
        "libpq/*:with_libxml2": False,
        "libpq/*:with_lz4": False,
        "libpq/*:with_xslt": False,
        "libpq/*:with_readline": False
    }

    def layout(self):
        cmake_layout(self)

    def requirements(self):
        self.requires("libpq/[*]")

    def generate(self):
        tc = CMakeToolchain(self)
        tc.generate()

        deps = CMakeDeps(self)
        deps.set_property("libpq", "cmake_file_name", "PostgreSQL")
        deps.set_property("libpq", "cmake_target_name", "PostgreSQL::PostgreSQL")
        deps.set_property("libpq", "cmake_additional_variables_prefixes", ["PostgreSQL",])
        deps.generate()


================================================
FILE: .github/conan/profiles/clangcl
================================================
[settings]
os=Windows
arch=x86_64
build_type=Release
compiler=clang
compiler.version=19
compiler.cppstd=20
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.runtime_version=v144

libpq/*:compiler=msvc
libpq/*:compiler.version=194
libpq/*:compiler.cppstd=20
libpq/*:compiler.runtime=dynamic
libpq/*:compiler.runtime_type=Release

[conf]
tools.cmake.cmaketoolchain:generator=Ninja
tools.meson.mesontoolchain:backend=ninja
tools.build:compiler_executables={"c": "clang-cl.exe", "cpp": "clang-cl.exe"}
libpq/*:tools.build:compiler_executables={"c": "cl.exe", "cpp": "cl.exe"}


================================================
FILE: .github/conan/profiles/msvc
================================================
 [settings]
arch=x86_64
build_type=Release
compiler=msvc
compiler.cppstd=20
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.version=194
os=Windows

[conf]
tools.cmake.cmaketoolchain:generator=Ninja
tools.meson.mesontoolchain:backend=ninja


================================================
FILE: .github/workflows/clang-analyze.yml
================================================
name: clang-analyze

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  clang-analyze:
    runs-on: ubuntu-24.04

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: clang-tools libpq-dev
        version: 1.0

    - name: Configure CMake Project
      run: scan-build cmake --preset unixlike-release-dev

    - name: Build project files
      run: scan-build cmake --build --preset unixlike-release-dev


================================================
FILE: .github/workflows/clang-format.yml
================================================
name: clang-format

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  clang-format:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v5
    - uses: DoozyX/clang-format-lint-action@v0.20
      with:
        extensions: 'hpp,cpp'


================================================
FILE: .github/workflows/clang-tidy.yml
================================================
name: clang-tidy

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  clang-tidy:
    runs-on: ubuntu-24.04

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev clang-tidy
        version: 3.0

    - name: Configure CMake Project
      run: cmake --preset unixlike-debug-dev -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF

    - name: Build project files
      run: cmake --build --preset unixlike-debug-dev

    - name: Run clang-tidy
      run: run-clang-tidy -p build/unixlike-debug-dev/


================================================
FILE: .github/workflows/code-coverage.yml
================================================
name: code-coverage

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  code-coverage:
    runs-on: ubuntu-24.04

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev
        version: 1.0

    - name: Exclude example folder from code coverage
      run: |
        printf "ignore:\n  - example/**\n" >> .codecov.yml

    - name: Configure CMake Project
      run: cmake --preset unixlike-release-dev -DCMAKE_CXX_FLAGS="-coverage" -DBUILD_EXAMPLES=OFF

    - name: Build project files
      run: cmake --build --preset unixlike-release-dev

    - name: Run tests
      run: cmake --build --preset unixlike-release-dev --target test

    - uses: codecov/codecov-action@v5
      with:
        token: ${{ secrets.CODECOV_TOKEN }}


================================================
FILE: .github/workflows/linux.yml
================================================
name: Linux

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  linux-next:
    strategy:
      matrix:
        compiler:
          - g++-13
          - g++-14
          - g++-15
          - g++-16
          - clang++-18

    runs-on: ubuntu-24.04

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      CXX: ${{ matrix.compiler }}
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev libc++-dev
        version: 2.0

    - name: Install GCC-15
      if: matrix.compiler == 'g++-15'
      run: |
        sudo add-apt-repository ppa:ubuntu-toolchain-r/test
        sudo apt-get update
        sudo apt-get install -y g++-15

    - name: Install GCC-16
      if: matrix.compiler == 'g++-16'
      run: |
        sudo add-apt-repository ppa:ubuntu-toolchain-r/test
        sudo apt-get update
        sudo apt-get install -y g++-16

    - name: Configure CMake Project
      run: cmake --preset unixlike-release-dev -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/taopq-install

    - name: Build project files
      run: cmake --build --preset unixlike-release-dev

    - name: Run tests
      run: cmake --build --preset unixlike-release-dev --target test

    - name: Run examples
      run: cmake --build --preset unixlike-release-dev --target examples
      env:
        PGDATABASE: ${{ env.TAOPQ_TEST_DATABASE }}

    - name: Install Taocpp TaoPQ
      run: cmake --build --preset unixlike-release-dev --target install

  linux-gcc-old-abi:
    runs-on: ubuntu-24.04

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      CXX: g++
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev libc++-dev
        version: 2.0

    - name: Configure CMake Project
      run: cmake --preset unixlike-release-dev -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/taopq-install -DCMAKE_CXX_FLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"

    - name: Build project files
      run: cmake --build --preset unixlike-release-dev

    - name: Run tests
      run: cmake --build --preset unixlike-release-dev --target test

  linux-clang-extra:
    strategy:
      matrix:
        flags: ["-stdlib=libc++","-fms-extensions"]

    runs-on: ubuntu-24.04

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      CXX: clang++
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev libc++-dev
        version: 2.0

    - name: Configure CMake Project
      run: cmake --preset unixlike-release-dev -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/taopq-install -DCMAKE_CXX_FLAGS="${{ matrix.flags }}"

    - name: Build project files
      run: cmake --build --preset unixlike-release-dev

    - name: Run tests
      run: cmake --build --preset unixlike-release-dev --target test

  linux-makefile:
    runs-on: ubuntu-24.04

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres
      CXX: g++-13

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev libc++-dev
        version: 2.0

    - name: Build project files with Makefile
      run: make -j$(nproc)

    - name: Run tests with Makefile
      run: make test
      env:
        PGDATABASE: ${{ env.TAOPQ_TEST_DATABASE }}


================================================
FILE: .github/workflows/macos.yml
================================================
name: macOS

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  xcode-macos-15:
    runs-on: macos-15
    env:
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5
    - uses: ikalnytskyi/action-setup-postgres@v8
    - uses: conan-io/setup-conan@v1
      with:
        cache_packages: true

    - name: Install dependencies with Conan
      run: conan install ${{ github.workspace }}/.github/conan/conanfile.py -s compiler.cppstd=20 --build=missing --lockfile-partial

    - name: Configure CMake Project
      run: cmake --preset unixlike-release-dev -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/taopq-install -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/.github/conan/build/Release/generators/conan_toolchain.cmake

    - name: Build project files
      run: cmake --build --preset unixlike-release-dev

    - name: Run tests
      run: cmake --build --preset unixlike-release-dev --target test

    - name: Run examples
      run: cmake --build --preset unixlike-release-dev --target examples
      env:
        PGDATABASE: ${{ env.TAOPQ_TEST_DATABASE }}

    - name: Install Taocpp TaoPQ
      run: cmake --build --preset unixlike-release-dev --target install


================================================
FILE: .github/workflows/sanitizer.yml
================================================
name: Sanitizer

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  sanitizer:
    strategy:
      matrix:
        sanitizer: [address, undefined, thread, leak]

    runs-on: ubuntu-24.04

    services:
      postgres:
        image: postgres:latest
        env:
          POSTGRES_DB: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        ports:
          - 5432:5432
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    env:
      CXX: clang++
      CC: clang
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5

    - uses: awalsh128/cache-apt-pkgs-action@latest
      with:
        packages: libpq-dev
        version: 1.0

    - name: Configure CMake Project
      run: cmake --preset unixlike-debug-dev -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/taopq-install -DCMAKE_CXX_FLAGS="-fsanitize=${{ matrix.sanitizer }}"

    - name: Build project files
      run: cmake --build --preset unixlike-debug-dev

    - name: Run tests
      run: cmake --build --preset unixlike-debug-dev --target test


================================================
FILE: .github/workflows/windows.yml
================================================
name: Windows

on:
  push:
    paths-ignore:
      - 'README.md'
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'README.md'
      - 'doc/**'

jobs:
  vs2022:
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        cxx: [ "msvc", "clangcl" ]

    env:
      TAOPQ_TEST_DATABASE: host=localhost dbname=postgres user=postgres password=postgres

    steps:
    - uses: actions/checkout@v5

    - name: Set up PostgreSQL
      uses: ikalnytskyi/action-setup-postgres@v8

    - name: Set up MSVC dev cmd (x64)
      uses: ilammy/msvc-dev-cmd@v1
      with:
        arch: x64

    - name: Set up Conan
      uses: conan-io/setup-conan@v1
      with:
        cache_packages: true
        config_urls: .github/conan

    - name: Install dependencies with Conan MSVC
      run: conan install ${{ github.workspace }}/.github/conan/conanfile.py --build=missing -pr ${{ matrix.cxx }} --lockfile-partial

    - name: CMake Configure
      shell: pwsh
      run: cmake --preset ${{ matrix.cxx }}-release-dev -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/taopq-install -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/.github/conan/build/Release/generators/conan_toolchain.cmake

    - name: Build project files
      run: cmake --build --preset ${{ matrix.cxx }}-release-dev

    - name: Run tests
      run: cmake --build --preset ${{ matrix.cxx }}-release-dev --target test

    - name: Run examples
      run: cmake --build --preset ${{ matrix.cxx }}-release-dev --target examples
      env:
        PGDATABASE: ${{ env.TAOPQ_TEST_DATABASE }}

    - name: Install Taocpp TaoPQ
      run: cmake --build --preset ${{ matrix.cxx }}-release-dev --target install


================================================
FILE: .gitignore
================================================
*~
build
dummy.txt


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)

# Read version from version.hpp
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/version.hpp" taopq_VERSION_DATA)
string(REGEX MATCH "#define TAO_PQ_VERSION \"([^\"]+)\"" _ ${taopq_VERSION_DATA})
set(taopq_VERSION "${CMAKE_MATCH_1}")

project(taopq
  VERSION ${taopq_VERSION}
  LANGUAGES CXX
  DESCRIPTION "A lightweight C++ client library for accessing a PostgreSQL database"
  HOMEPAGE_URL "https://github.com/taocpp/taopq"
)

option(BUILD_EXAMPLES "Build taopq examples" ON)

find_package(PostgreSQL REQUIRED)

add_library(${PROJECT_NAME})
add_library(taocpp::taopq ALIAS ${PROJECT_NAME})

target_sources(${PROJECT_NAME}
  PRIVATE
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/connection.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/connection_pool.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/exception.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/field.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/internal/demangle.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/internal/poll.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/internal/strtox.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/large_object.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/parameter_traits.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/pipeline.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/result.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/result_traits.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/result_traits_array.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/row.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/table_field.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/table_reader.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/table_row.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/table_writer.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/transaction.cpp
  ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/pq/transaction_base.cpp
  PUBLIC FILE_SET HEADERS
  BASE_DIRS include
  FILES
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/access_mode.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/binary.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/bind.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/connection.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/connection_pool.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/connection_status.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/exception.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/field.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/aggregate.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/demangle.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/exclusive_scan.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/format_as.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/from_chars.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/gen.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/parameter_traits_helper.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/poll.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/pool.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/resize_uninitialized.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/strtox.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/unreachable.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/internal/zsv.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/is_aggregate.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/is_array.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/isolation_level.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/large_object.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/log.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/notification.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/null.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/oid.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter_traits.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter_traits_aggregate.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter_traits_array.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter_traits_optional.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter_traits_pair.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/parameter_traits_tuple.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/pipeline.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/pipeline_status.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/poll.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_status.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_traits.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_traits_aggregate.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_traits_array.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_traits_optional.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_traits_pair.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/result_traits_tuple.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/row.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/table_field.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/table_reader.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/table_row.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/table_writer.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/transaction.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/transaction_base.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/transaction_status.hpp
  ${CMAKE_CURRENT_SOURCE_DIR}/include/tao/pq/version.hpp
)

target_include_directories(${PROJECT_NAME}
  PUBLIC
    $<INSTALL_INTERFACE:include>
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/src
)

target_link_libraries(${PROJECT_NAME} PUBLIC PostgreSQL::PostgreSQL)
if(WIN32)
  target_link_libraries(${PROJECT_NAME} PUBLIC ws2_32)
endif()

target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)

set_target_properties(${PROJECT_NAME} PROPERTIES
  OUTPUT_NAME taopq
  VERSION ${PROJECT_VERSION}
  SOVERSION ${PROJECT_VERSION_MAJOR}
  CXX_VISIBILITY_PRESET hidden
  VISIBILITY_INLINES_HIDDEN ON
  EXPORT_NAME taopq
)

if(PROJECT_IS_TOP_LEVEL)
  include(GNUInstallDirs)
  include(CMakePackageConfigHelpers)

  install(TARGETS taopq
    EXPORT taopq-targets
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    FILE_SET HEADERS
  )

  install(FILES LICENSE_1_0.txt DESTINATION ${CMAKE_INSTALL_DOCDIR})

  install(EXPORT taopq-targets
    FILE ${PROJECT_NAME}Targets.cmake
    NAMESPACE taocpp::
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/taopq
  )

  write_basic_package_version_file(
    ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY SameMajorVersion
  )

  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"include(CMakeFindDependencyMacro)
find_dependency(PostgreSQL REQUIRED CONFIG)
include(\"\${CMAKE_CURRENT_LIST_DIR}/taopqTargets.cmake\")
")

  install(FILES
    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/taopq
  )

  export(EXPORT taopq-targets
    FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake"
    NAMESPACE taocpp::
  )
endif()

if(BUILD_TESTING AND PROJECT_IS_TOP_LEVEL)
  enable_testing()
  add_subdirectory(test)
endif()

if(BUILD_EXAMPLES AND PROJECT_IS_TOP_LEVEL)
  add_subdirectory(example)
endif()

================================================
FILE: CMakePresets.json
================================================
{
  "version": 6,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 21,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "default",
      "hidden": true,
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/${presetName}",
      "cacheVariables": {
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
      }
    },
    {
      "name": "dev-flags-gcc-clang",
      "hidden": true,
      "cacheVariables": {
        "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Werror -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wnull-dereference -Wno-sign-conversion",
        "BUILD_TESTING": "ON",
        "BUILD_EXAMPLES": "ON"
      }
    },
    {
      "name": "dev-flags-msvc",
      "hidden": true,
      "cacheVariables": {
        "CMAKE_CXX_FLAGS": "/EHsc /W4 /WX /permissive-",
        "BUILD_TESTING": "ON",
        "BUILD_EXAMPLES": "ON"
      }
    },
    {
      "name": "debug",
      "inherits": "default",
      "displayName": "Debug",
      "description": "Debug build",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "name": "release",
      "inherits": "default",
      "displayName": "Release",
      "description": "Release build with optimizations",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    },
    {
      "name": "unixlike-debug",
      "inherits": "debug",
      "displayName": "Unix Like Compiler Debug",
      "description": "Debug build using GCC or Clang"
    },
    {
      "name": "unixlike-release",
      "inherits": "release",
      "displayName": "Unix Like Compiler Release",
      "description": "Release build using GCC or Clang"
    },
    {
      "name": "unixlike-debug-dev",
      "inherits": ["debug", "dev-flags-gcc-clang"],
      "displayName": "Unix Like Compiler Debug (Dev with -Werror)",
      "description": "Debug build using Clang or GCC with warnings as errors"
    },
    {
      "name": "unixlike-release-dev",
      "inherits": ["release", "dev-flags-gcc-clang"],
      "displayName": "Unix Like Compiler Release (Dev with -Werror)",
      "description": "Release build using Clang or GCC with warnings as errors"
    },
    {
      "name": "clangcl-debug",
      "inherits": "debug",
      "displayName": "MSVC Debug",
      "description": "Debug build using MSVC",
      "generator": "Ninja",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "clang-cl",
        "CMAKE_CXX_COMPILER": "clang-cl"
      },
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Windows"
      }
    },
    {
      "name": "clangcl-release",
      "inherits": "release",
      "displayName": "MSVC Release",
      "description": "Ninja",
      "generator": "Ninja",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "clang-cl",
        "CMAKE_CXX_COMPILER": "clang-cl"
      },
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Windows"
      }
    },
    {
      "name": "msvc-debug",
      "inherits": "debug",
      "displayName": "MSVC Debug",
      "description": "Ninja",
      "generator": "Ninja",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "cl",
        "CMAKE_CXX_COMPILER": "cl"
      },
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Windows"
      }
    },
    {
      "name": "msvc-release",
      "inherits": "release",
      "displayName": "MSVC Release",
      "description": "Release build using MSVC",
      "generator": "Ninja",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "cl",
        "CMAKE_CXX_COMPILER": "cl"
      },
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Windows"
      }
    },
    {
      "name": "msvc-debug-dev",
      "inherits": ["msvc-debug", "dev-flags-msvc"],
      "displayName": "MSVC Debug (Dev with /WX)",
      "description": "Debug build using MSVC with warnings as errors"
    },
    {
      "name": "msvc-release-dev",
      "inherits": ["msvc-release", "dev-flags-msvc"],
      "displayName": "MSVC Release (Dev with /WX)",
      "description": "Release build using MSVC with warnings as errors"
    },
    {
      "name": "clangcl-debug-dev",
      "inherits": ["clangcl-debug", "dev-flags-msvc"],
      "displayName": "ClangCL Debug (Dev with /WX)",
      "description": "Debug build using ClangCL with warnings as errors"
    },
    {
      "name": "clangcl-release-dev",
      "inherits": ["clangcl-release", "dev-flags-msvc"],
      "displayName": "ClangCL Release (Dev with /WX)"
    }
  ],
  "buildPresets": [
    {
      "name": "debug",
      "configurePreset": "debug",
      "displayName": "Debug Build",
      "description": "Build in Debug mode"
    },
    {
      "name": "release",
      "configurePreset": "release",
      "displayName": "Release Build",
      "description": "Build in Release mode"
    },
    {
      "name": "unixlike-debug",
      "configurePreset": "unixlike-debug",
      "displayName": "Unix Like Compiler Debug Build"
    },
    {
      "name": "unixlike-release",
      "configurePreset": "unixlike-release",
      "displayName": "Unix Like Compiler Release Build"
    },
    {
      "name": "unixlike-debug-dev",
      "configurePreset": "unixlike-debug-dev",
      "displayName": "Unix Like Compiler Debug Build (Dev)"
    },
    {
      "name": "unixlike-release-dev",
      "configurePreset": "unixlike-release-dev",
      "displayName": "Unix Like Compiler Release Build (Dev)"
    },
    {
      "name": "msvc-debug",
      "configurePreset": "msvc-debug",
      "displayName": "MSVC Debug Build"
    },
    {
      "name": "msvc-release",
      "configurePreset": "msvc-release",
      "displayName": "MSVC Release Build"
    },
    {
      "name": "msvc-debug-dev",
      "configurePreset": "msvc-debug-dev",
      "displayName": "MSVC Debug Build (Dev)"
    },
    {
      "name": "msvc-release-dev",
      "configurePreset": "msvc-release-dev",
      "displayName": "MSVC Release Build (Dev)"
    },
    {
      "name": "clangcl-debug",
      "configurePreset": "clangcl-debug",
      "displayName": "MSVC Clang Debug Build"
    },
    {
      "name": "clangcl-release",
      "configurePreset": "clangcl-release",
      "displayName": "MSVC Clang Release Build"
    },
    {
      "name": "clangcl-debug-dev",
      "configurePreset": "clangcl-debug-dev",
      "displayName": "ClangCL Debug Build (Dev)"
    },
    {
      "name": "clangcl-release-dev",
      "configurePreset": "clangcl-release-dev",
      "displayName": "ClangCL Release Build (Dev)"
    }
  ],
  "testPresets": [
    {
      "name": "debug",
      "configurePreset": "debug",
      "displayName": "Test Debug",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "release",
      "configurePreset": "release",
      "displayName": "Test Release",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "unixlike-release",
      "configurePreset": "unixlike-release",
      "displayName": "Test Unix Like Compiler Release",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "unixlike-debug",
      "configurePreset": "unixlike-debug",
      "displayName": "Test Unix Like Compiler Debug",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "unixlike-debug-dev",
      "configurePreset": "unixlike-debug-dev",
      "displayName": "Test Unix Like Compiler Debug (Dev)",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "unixlike-release-dev",
      "configurePreset": "unixlike-release-dev",
      "displayName": "Test Unix Like Compiler Release (Dev)",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "msvc-debug-dev",
      "configurePreset": "msvc-debug-dev",
      "displayName": "Test MSVC Debug (Dev)",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "msvc-release-dev",
      "configurePreset": "msvc-release-dev",
      "displayName": "Test MSVC Release (Dev)",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "clangcl-debug-dev",
      "configurePreset": "clangcl-debug-dev",
      "displayName": "Test ClangCL Debug (Dev)",
      "output": {
        "outputOnFailure": true
      }
    },
    {
      "name": "clangcl-release-dev",
      "configurePreset": "clangcl-release-dev",
      "displayName": "Test ClangCL Release (Dev)",
      "output": {
        "outputOnFailure": true
      }
    }
  ]
}

================================================
FILE: LICENSE_1_0.txt
================================================
Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:

The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.

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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


================================================
FILE: Makefile
================================================
# The Art of C++
# https://github.com/taocpp

# Copyright (c) 2016-2026 Daniel Frey
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

.SUFFIXES:
.SECONDARY:

ifeq ($(OS),Windows_NT)
UNAME_S := $(OS)
ifeq ($(shell gcc -dumpmachine),mingw32)
MINGW_CXXFLAGS = -U__STRICT_ANSI__
endif
else
UNAME_S := $(shell uname -s)
endif

# For Darwin (Mac OS X / macOS) we assume that the default compiler
# clang++ is used; when $(CXX) is some version of g++, then
# $(CXXSTD) has to be set to -std=c++20 (or newer) so
# that -stdlib=libc++ is not automatically added.

ifeq ($(CXXSTD),)
CXXSTD := -std=c++20
ifeq ($(UNAME_S),Darwin)
CXXSTD += -stdlib=libc++
endif
endif

# Ensure strict standard compliance and no warnings, can be
# changed if desired.

BUILDDIR ?= build

INCFLAGS ?= -Iinclude -Itest $(patsubst %,-I%,$(shell pg_config --includedir))
CPPFLAGS ?= -pedantic
CXXFLAGS ?= -Wall -Wextra -Wshadow -Werror -O3 $(MINGW_CXXFLAGS)
LDFLAGS ?= -rdynamic $(patsubst %,-L%,$(shell pg_config --libdir))
LIBS ?= -lpq

CLANG_TIDY ?= clang-tidy

HEADERS := $(shell find include -name '*.hpp')
SOURCES := $(shell find src -name '*.cpp')
TESTSOURCES := $(shell find test -name '*.cpp')
DEPENDS := $(SOURCES:%.cpp=$(BUILDDIR)/%.d) $(TESTSOURCES:%.cpp=$(BUILDDIR)/%.d)
BINARIES := $(SOURCES:%.cpp=$(BUILDDIR)/%) $(TESTSOURCES:%.cpp=$(BUILDDIR)/%)

UNIT_TESTS := $(filter $(BUILDDIR)/test/%,$(BINARIES))

LIBSOURCES := $(filter src/lib/%,$(SOURCES))
LIBNAME := taopq

.PHONY: all
all: check

.PHONY: compile
compile: $(UNIT_TESTS)

.PHONY: check
check: $(UNIT_TESTS)
	@set -e; for T in $(UNIT_TESTS); do echo $$T; $$T; done

$(BUILDDIR)/%.clang-tidy: % .clang-tidy
	$(CLANG_TIDY) -quiet $< -- $(CXXSTD) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) 2>/dev/null
	@mkdir -p $(@D)
	@touch $@

.PHONY: clang-tidy
clang-tidy: $(HEADERS:%=$(BUILDDIR)/%.clang-tidy) $(SOURCES:%=$(BUILDDIR)/%.clang-tidy)
	@echo "All $(words $(HEADERS) $(SOURCES)) clang-tidy tests passed."

.PHONY: clean
clean:
	@rm -rf $(BUILDDIR)/*
	@find . -name '*~' -delete

$(BUILDDIR)/%.d: %.cpp Makefile
	@mkdir -p $(@D)
	$(CXX) $(CXXSTD) $(INCFLAGS) $(CPPFLAGS) -MM -MQ $@ $< -o $@

$(BUILDDIR)/%.o: %.cpp $(BUILDDIR)/%.d
	$(CXX) $(CXXSTD) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

$(BUILDDIR)/lib/lib$(LIBNAME).a: $(LIBSOURCES:%.cpp=$(BUILDDIR)/%.o)
	@mkdir -p $(@D)
	$(AR) -rcs $@ $^

.PHONY: lib
lib: $(BUILDDIR)/lib/lib$(LIBNAME).a

$(BUILDDIR)/%: $(BUILDDIR)/%.o $(BUILDDIR)/lib/lib$(LIBNAME).a
	@mkdir -p $(@D)
	$(CXX) $(CXXSTD) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@

ifeq ($(findstring $(MAKECMDGOALS),clean),)
-include $(DEPENDS)
endif


================================================
FILE: README.md
================================================
# Welcome to taoPQ

[![Windows CI](https://github.com/taocpp/taopq/workflows/Windows/badge.svg)](https://github.com/taocpp/taopq/actions?query=workflow%3AWindows)
[![macOS CI](https://github.com/taocpp/taopq/workflows/macOS/badge.svg)](https://github.com/taocpp/taopq/actions?query=workflow%3AmacOS)
[![Linux CI](https://github.com/taocpp/taopq/workflows/Linux/badge.svg)](https://github.com/taocpp/taopq/actions?query=workflow%3ALinux)
<br>
[![clang-analyze](https://github.com/taocpp/taopq/workflows/clang-analyze/badge.svg)](https://github.com/taocpp/taopq/actions?query=workflow%3Aclang-analyze)
[![clang-tidy](https://github.com/taocpp/taopq/workflows/clang-tidy/badge.svg)](https://github.com/taocpp/taopq/actions?query=workflow%3Aclang-tidy)
[![Sanitizer](https://github.com/taocpp/taopq/workflows/Sanitizer/badge.svg)](https://github.com/taocpp/taopq/actions?query=workflow%3ASanitizer)
[![Codecov](https://codecov.io/gh/taocpp/taopq/graph/badge.svg?token=jrFgbSi3wY)](https://codecov.io/gh/taocpp/taopq)

taoPQ is a lightweight C++ client library for accessing a [PostgreSQL➚](https://www.postgresql.org/) database.
It has no dependencies beyond [`libpq`➚](https://www.postgresql.org/docs/current/libpq.html), the C application programmer's interface to PostgreSQL.

## Introduction

The library provides support for database connections, transactions, nested transactions, prepared statements, large objects, connection pools, pipeline mode, high-speed bulk data transfer, and more.
An extensible traits mechanism is used to convert C++ types into SQL statement parameters, and conversely to convert query results into arbitrary C++ types.
The following example shows the basic look and feel of the library.

```c++
#include <iostream>
#include <tao/pq.hpp>

int main()
{
   // open a connection to the database
   const auto conn = tao::pq::connection::create( "dbname=template1" );

   // execute statements
   conn->execute( "DROP TABLE IF EXISTS users" );
   conn->execute( "CREATE TABLE users ( name TEXT PRIMARY KEY, age INTEGER NOT NULL )" );

   // prepare statements
   conn->prepare( "insert_user", "INSERT INTO users ( name, age ) VALUES ( $1, $2 )" );

   {
      // begin transaction
      const auto tr = conn->transaction();

      // execute previously prepared statements
      tr->execute( "insert_user", "Daniel", 42 );
      tr->execute( "insert_user", "Tom", 41 );
      tr->execute( "insert_user", "Jerry", 29 );

      // commit transaction
      tr->commit();
   }

   // query data
   const auto users = conn->execute( "SELECT name, age FROM users WHERE age >= $1", 40 );

   // iterate and convert results
   for( const auto& row : users ) {
      std::cout << row[ "name" ].as< std::string >() << " is "
                << row[ "age" ].as< unsigned >() << " years old.\n";
   }
}
```

## Documentation

* [Table of Content](doc/TOC.md)
* [Requirements](doc/Requirements.md)
* [Installation](doc/Installation.md)
* [Getting Started](doc/Getting-Started.md)
* [Connection](doc/Connection.md)
* [Transaction](doc/Transaction.md)
* [Statement](doc/Statement.md)
* [Result](doc/Result.md)

## Contact

For questions and suggestions regarding taoPQ, success or failure stories, and any other kind of feedback, please feel free to open a [discussion](https://github.com/taocpp/taopq/discussions), an [issue](https://github.com/taocpp/taopq/issues) or a [pull request](https://github.com/taocpp/taopq/pulls) on GitHub or contact the authors at `taocpp(at)icemx.net`.

## The Art of C++

taoPQ is part of [The Art of C++](https://taocpp.github.io/).

[<img alt="colinh" src="https://avatars.githubusercontent.com/u/113184" width="120">](https://github.com/colinh)
[<img alt="d-frey" src="https://avatars.githubusercontent.com/u/3956325" width="120">](https://github.com/d-frey)
[<img alt="uilianries" src="https://avatars.githubusercontent.com/u/4870173" width="120">](https://github.com/uilianries)

## License

<a href="https://opensource.org/licenses/BSL-1.0"><img align="right" src="https://opensource.org/wp-content/uploads/2009/06/OSIApproved.svg" width="150" hspace="20" alt="Open Source Initiative"></a>

Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch

taoPQ is certified [Open Source➚](http://www.opensource.org/docs/definition.html) software.
It is [licensed➚](https://pdimov.github.io/blog/2020/09/06/why-use-the-boost-license/) under the terms of the [Boost Software License, Version 1.0➚](https://www.boost.org/LICENSE_1_0.txt) reproduced here.

> Boost Software License - Version 1.0 - August 17th, 2003
>
> Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:
>
> The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.
>
> 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

[The Art of C++]: https://taocpp.github.io/


================================================
FILE: doc/Aggregate-Support.md
================================================
# Aggregate Support

taoPQ allows the direct use of "simple" aggregates as parameters and result types.

## Requirements

An aggregate data type `T` suitable for taoPQ support must meet the following requirements:

* [`std::is_aggregate_v< T >`➚](https://en.cppreference.com/w/cpp/types/is_aggregate) must yield `true`.
* [`std::is_empty_v< T >`➚](https://en.cppreference.com/w/cpp/types/is_empty) must yield `false`.
* [`std::is_union_v< T >`➚](https://en.cppreference.com/w/cpp/types/is_union) must yield `false`.
* `T` must not have any base classes.
* `T` must not have more than 99 member variables. (this limit can be raised, open an [issue](https://github.com/taocpp/taopq/issues) if necessary)

## Registration

We currently require explicit registration of aggregate data types.
This is done as a precaution, and to avoid conflicts with other data types.

A data type `T` can be registered as both a parameter and a result type by specializing `tao::pq::is_aggregate` as follows:

```c++
template<>
inline constexpr bool tao::pq::is_aggregate< T > = true;
```

If necessary, you can control independently whether a data type is suitable as a parameter or a result type by specializing `tao::pq::is_aggregate_parameter` and `tao::pq::is_aggregate_result` as follows:

```c++
template<>
inline constexpr bool tao::pq::is_aggregate_parameter< T > = true;

template<>
inline constexpr bool tao::pq::is_aggregate_result< T > = true;
```

## Direct Result Conversion

An aggregate data type `T` that is registered as a result type enables the direct conversion of a `tao::pq::row` to `T`.
This is convenient when retrieving results and iterating over them, it enables you to write:

```c++
const auto result = conn->execute( "SELECT ... FROM ..." ); // some query
for( const T t : result ) {
   // use t
}
```

:interrobang: Compilers might complain about extra copies and that you should use `const T&`, but that would not work and there are no extra copies.

## Example

The following is a short, but complete example of how to use aggregates with taoPQ:

```c++
#include <iostream>
#include <tao/pq.hpp>

// an aggregate
struct user
{
   std::string name;
   unsigned age;
   std::string planet;
};

template<>
inline constexpr bool tao::pq::is_aggregate< user > = true;

int main()
{
   // open a connection to the database
   const auto conn = tao::pq::connection::create( "dbname=template1" );

   // execute statements
   conn->execute( "DROP TABLE IF EXISTS users" );
   conn->execute( "CREATE TABLE users ( name TEXT PRIMARY KEY, age INTEGER NOT NULL, planet TEXT NOT NULL )" );

   // prepare statements
   conn->prepare( "insert_user", "INSERT INTO users ( name, age, planet ) VALUES ( $1, $2, $3 )" );

   // execute previously prepared statements
   conn->execute( "insert_user", user{ "R. Daneel Olivaw", 19230, "Earth" } );
   conn->execute( "insert_user", user{ "R. Giskard Reventlov", 42, "Aurora" } );

   // query and convert data
   for( const user u : conn->execute( "SELECT name, age, planet FROM users" ) ) {
      std::cout << u.name << " from " << u.planet << " was " << u.age << " years old.\n";
   }
}
```

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Binary-Data.md
================================================
# Binary Data

PostgreSQL stores binary data either as a field with the [`BYTEA`➚](https://www.postgresql.org/docs/current/datatype-binary.html) data type or as a [large object➚](https://www.postgresql.org/docs/current/largeobjects.html).

Large Objects in taoPQ have their own representation discussed in the [Large Object](Large-Object.md) chapter.

## The [`BYTEA`➚](https://www.postgresql.org/docs/current/datatype-binary.html) Data Type

In PostgreSQL strings are a sequence of bytes that is valid in a given encoding.
One or more bytes can represent individual characters or code points.
This means that not all sequences of bytes are a valid string and therefore binary data can generally not be represented by PostgreSQL as a string.

Binary data is different from strings, as binary data is a collection of an arbitrary sequence of bytes.
Any byte is treated independently of its surrounding bytes and can have any value, including '\0'.
It is therefore crucial to represent binary data with the dedicated [`BYTEA`➚](https://www.postgresql.org/docs/current/datatype-binary.html) data type.

## C++ Binary Data

The individual bytes are represented by [`std::byte`➚](https://en.cppreference.com/w/cpp/types/byte).
As there is no one-size-fits-all data type to handle binary data in C++, we allow several options.

We mostly represent binary data with `tao::pq::binary` and `tao::pq::binary_view`.
These are type aliases for [`std::vector<std::byte>`➚](https://en.cppreference.com/w/cpp/container/vector) and [`std::span<std::byte>`➚](https://en.cppreference.com/w/cpp/container/span), respectively.

## Passing Binary Data

When you pass binary data to taoPQ, we only require a view to be passed.
As a view is a non-owning data type, constructing an instance of it is cheap.

If you have other data types, you can create a binary data view by using

```c++
auto tao::pq::to_binary_view( const auto* data, const std::size_t size ) noexcept -> tao::pq::binary_view;

auto tao::pq::to_binary_view( const auto& data ) noexcept
{
   return pq::to_binary_view( std::data( data ), std::size( data ) );
}
```

The former function requires (and checks) that `T` has a size of 1 byte.
If you want to store larger `T`s as binary data you need to manually convert the pointer and size appropriately.

The second method requires the data type `T` to be a suitable candidate for [`std::data()`➚](https://en.cppreference.com/w/cpp/iterator/data) and [`std::size()`➚](https://en.cppreference.com/w/cpp/iterator/size), which requires the data to be stored in a contiguous block of memory.
We do not offer any convenience methods to create binary data from distributed data structures, i.e. `std::list<std::byte>` is not supported.

## Receiving Binary Data

When receiving binary data, a non-owning view is insufficient, hence we return `tao::pq::binary`.
In some cases other alternatives are offered, i.e. you may provide a buffer that the data is written to.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Bulk-Transfer.md
================================================
# Bulk Transfer

**TODO**

## Synopsis

Don't be intimidated by the size of the API, as you can see several methods are just single-line convenience forwarders.

We will first give the synopsis of everything, afterwards we will break down the API into small logical portions.

```c++
namespace tao::pq
{
   namespace internal
   {
      class zsv;  // zero-terminated string view
   }

   class transaction;

   class table_writer final
   {
   public:
      template< typename... As >
      table_writer( const std::shared_ptr< transaction >& transaction, const internal::zsv statement, As&&... as );

      ~table_writer();

      table_writer( const table_writer& ) = delete;
      table_writer( table_writer&& ) = delete;
      void operator=( const table_writer& ) = delete;
      void operator=( table_writer&& ) = delete;

      void insert_raw( const std::string_view data );

      template< typename... As >
      void insert( As&&... as );

      auto commit() -> std::size_t;
   };

   using null_t = decltype( null );

   class table_row;
   class table_field;

   class table_reader final
   {
   private:
      class const_iterator;

   public:
      template< typename... As >
      table_reader( const std::shared_ptr< transaction >& transaction, const internal::zsv statement, As&&... as );

      ~table_reader() = default;

      table_reader( const table_reader& ) = delete;
      table_reader( table_reader&& ) = delete;
      void operator=( const table_reader& ) = delete;
      void operator=( table_reader&& ) = delete;

      auto columns() const noexcept -> std::size_t;

      auto get_raw_data() -> std::string_view;
      bool parse_data() noexcept;

      bool get_row();
      bool has_data() const noexcept;

      auto raw_data() const noexcept
         -> const std::vector< const char* >&;

      auto row() noexcept -> table_row;

      auto begin() -> const_iterator;
      auto end() noexcept -> const_iterator;

      auto cbegin() -> const_iterator;
      auto cend() noexcept -> const_iterator;

      template< typename T >
      auto as_container() -> T;

      // convenience conversions to standard containers
      template< typename... Ts >
      auto vector()
      {
         return as_container< std::vector< Ts... > >();
      }

      template< typename... Ts >
      auto list()
      {
         return as_container< std::list< Ts... > >();
      }

      template< typename... Ts >
      auto set()
      {
         return as_container< std::set< Ts... > >();
      }

      template< typename... Ts >
      auto multiset()
      {
         return as_container< std::multiset< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_set()
      {
         return as_container< std::unordered_set< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_multiset()
      {
         return as_container< std::unordered_multiset< Ts... > >();
      }

      template< typename... Ts >
      auto map()
      {
         return as_container< std::map< Ts... > >();
      }

      template< typename... Ts >
      auto multimap()
      {
         return as_container< std::multimap< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_map()
      {
         return as_container< std::unordered_map< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_multimap()
      {
         return as_container< std::unordered_multimap< Ts... > >();
      }
   };

   class table_row
   {
   private:
      // satisfies LegacyRandomAccessIterator, see
      // https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator
      class const_iterator;

   public:
      auto slice( const std::size_t offset, const std::size_t in_columns ) const -> table_row;

      auto columns() const noexcept -> std::size_t;

      // iteration
      auto begin() const -> const_iterator;
      auto end() const -> const_iterator;

      auto cbegin() const -> const_iterator;
      auto cend() const -> const_iterator;

      bool is_null( const std::size_t column ) const;
      auto get( const std::size_t column ) const -> const char*;

      template< typename T >
      auto get( const std::size_t column ) const -> T;

      template< typename T >
      auto optional( const std::size_t column ) const
      {
         return get< std::optional< T > >( column );
      }

      template< typename T >
      auto as() const -> T;

      template< typename T >
      auto optional() const
      {
         return as< std::optional< T > >();
      }

      template< typename T, typename U >
      auto pair() const
      {
         return as< std::pair< T, U > >();
      }

      template< typename... Ts >
      auto tuple() const
      {
         return as< std::tuple< Ts... > >();
      }

      auto at( const std::size_t column ) const -> table_field;
      auto operator[]( const std::size_t column ) const noexcept -> table_field;

      friend void swap( table_row& lhs, table_row& rhs ) noexcept;
   };

   class table_field
   {
   public:
      auto index() const -> std::size_t;

      bool is_null() const;
      auto get() const -> const char*;

      template< typename T >
      auto as() const -> T;

      template< typename T >
      auto optional() const
      {
         return as< std::optional< T > >();
      }
   };

   bool operator==( const table_field& f, null_t )
   {
      return f.is_null();
   }

   bool operator==( null_t, const table_field& f )
   {
      return f.is_null();
   }

   bool operator!=( const table_field& f, null_t )
   {
      return !f.is_null();
   }

   bool operator!=( null_t, const table_field& f )
   {
      return !f.is_null();
   }
}
```

**TODO**

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Connection-Pool.md
================================================
# Connection Pool

Opening a new connection to the database server typically consists of several time-consuming steps.
A physical channel such as a socket or a named pipe must be established, the initial handshake with the server must occur, if encryption protocols (SSL) are enabled those need to be established, the connection string information must be parsed, the connection must be authenticated by the server, checks must be run for enlisting in the current transactions, and so on.

In practice, most applications use only one or a few different configurations for connections.
This means that during application execution, many identical connections will be repeatedly opened and closed.
To minimize the cost of opening connections, taoPQ provides connection pools.

Connection pools reduces the number of times that new connections must be opened.
They manage connections by keeping alive a set of active connections and borrowing them to the application on demand.
The connection pool maintains ownership of the connections when they are not used by the application.

## Synopsis

```c++
namespace tao::pq
{
   namespace internal
   {
      class zsv;  // zero-terminated string view
   }

   namespace poll
   {
      enum class status
      {
         timeout,
         readable,
         writable,
         again
      };

      using callback = status( const int socket,
                               const bool wait_for_write,
                               const int timeout_ms );
   }

   class connection;

   class connection_pool final
      : public std::enable_shared_from_this< connection_pool >
   {
   public:
      // create a new connection pool
      static auto create( const std::string& connection_info,
                          std::function< tao::pq::poll::callback > poll_cb = /*unspecified*/ )
         -> std::shared_ptr< connection_pool >;

      // non-copyable, non-movable
      connection_pool( const connection_pool& ) = delete;
      connection_pool( connection_pool&& ) = delete;
      void operator=( const connection_pool& ) = delete;
      void operator=( connection_pool&& ) = delete;

      virtual ~connection_pool() = default;

      // timeout handling
      auto timeout() const noexcept
         -> const std::optional< std::chrono::milliseconds >&;

      void set_timeout( const std::chrono::milliseconds timeout );
      void reset_timeout() noexcept;

      // customizable poll()-callback
      auto poll_callback() const noexcept
         -> const std::function< tao::pq::poll::callback >&;

      void set_poll_callback( std::function< tao::pq::poll::callback > poll_cb ) noexcept;
      void reset_poll_callback();

      // borrow a connection
      auto connection() const noexcept
         -> std::shared_ptr< pq::connection >;

      // direct statement execution
      template< typename... As >
      auto execute( const internal::zsv statement, As&&... as )
      {
         return connection()->execute( statement, std::forward< As >( as )... );
      }

      // checks whether the pool contains idle connections
      auto empty() const noexcept
        -> bool;

      // number of idle connections
      auto size() const noexcept
        -> std::size_t;

      // number of borrowed connections
      auto attached() const noexcept
        -> std::size_t;

      // cleanup
      void erase_invalid();
   };
}
```

:point_up: Note that `tao::pq::internal::zsv` is explained in the [Statement](Statement.md) chapter.

## Creating Connection Pools

A connection pool is created by calling `tao::pq::connection_pool`'s static `create()`-method.

```c++
auto tao::pq::connection_pool::create( const std::string& connection_info )
    -> std::shared_ptr< tao::pq::connection_pool >;
```

It takes a mandatory parameter, the [connection string➚](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING), that is used when new connections are opened by the pool.

The second, optional parameter can be used to specify the default `poll()`-callback for connections, see [Customizable `poll()`-callback](Connection.md#customizable-poll-callback).

## Borrowing Connections

When you need a connection, you simply call the `connection()`-method.

```c++
auto tao::pq::connection_pool::connection()
    -> std::shared_ptr< tao::pq::connection >;
```

This will either open a new connection when the pool is empty, or it will give you a reused connection from the pool.
As long as you retain ownership of the returned shared pointer, it is yours to work with.
When the last remaining shared pointer is destroyed or assigned another value, the connection is returned to the pool.

## Executing Statements

You can [execute statements](Statement.md) on a connection pool directly, which is equivalent to borrowing a temporary connection (as if calling the `connection()`-method) and executing the statement on that [connection](Connection.md).
After the statement was executed, the temporary connection is returned to the pool.

## Cleanup

The connection pool will implicitly discard connections that are in a failed state when they are returned to the pool or when they are retrieved from the pool.

In some environments you might need to periodically clean up the connection pool to get rid of connections that are no longer valid.
In order to do so, just call the `erase_invalid()`-method, which will check the status of each pooled connection and discard the invalid ones.

```c++
void tao::pq::connection_pool::erase_invalid();
```

## Customizable `poll()`-callback

The default implementation for polling uses `poll()` or `WSAPoll()`, depending on your system.
This callback can be customized to support other I/O frameworks, e.g. Boost.Asio.

To access the current default callback for borrowed connections you can call the `poll_callback()`-method.

```c++
auto poll_callback() const noexcept
   -> const std::function< tao::pq::poll::callback >&;
```

Setting the default `poll()`-callback for borrowed connections is done by calling the `set_poll_callback()`-method.

```c++
void set_poll_callback( std::function< tao::pq::poll::callback > poll_cb ) noexcept;
```

You can revert the current default `poll()`-callback for borrowed connections to the default by calling the `reset_poll_callback()`-method.

```c++
void reset_poll_callback();
```

## Thread Safety

The connection pool's borrowing mechanism is thread-safe, i.e. multiple threads can make calls to the `connection()`-method or return connections simultaneously.
You can also call the `erase_invalid()`-method at any time.

Internally, the connection pool uses a [mutex➚](https://en.cppreference.com/w/cpp/thread/mutex) to serialize the above operations.
We minimized the work in the [critical sections➚](https://en.wikipedia.org/wiki/Critical_section) as far as possible.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Connection.md
================================================
# Connection

All communication with a database server is handled through a connection, represented by the `tao::pq::connection` type in taoPQ.
A connection object takes care of tracking [transactions](Transaction.md), [error handling](Error-Handling.md), and it has its own set of prepared statements.

## Synopsis

```c++
namespace tao::pq
{
   namespace internal
   {
      class zsv;  // zero-terminated string view
   }

   namespace poll
   {
      enum class status
      {
         timeout,
         readable,
         writable,
         again
      };

      using callback = status( const int socket,
                               const bool wait_for_write,
                               const int timeout_ms );
   }

   enum class isolation_level
   {
      default_isolation_level,
      serializable,
      repeatable_read,
      read_committed,
      read_uncommitted
   };

   enum class access_mode
   {
      default_access_mode,
      read_write,
      read_only
   };

   class notification final
   {
   public:
      auto channel() const noexcept -> const char*;
      auto payload() const noexcept -> const char*;

      auto underlying_raw_ptr() noexcept -> PGnotify*;
      auto underlying_raw_ptr() const noexcept -> const PGnotify*;
   };

   class transaction;

   class connection final
      : public std::enable_shared_from_this< connection >
   {
   public:
      // create a new connection
      static auto create( const std::string& connection_info,
                          std::function< tao::pq::poll::callback > poll_cb = /*unspecified*/ )
         -> std::shared_ptr< connection >;

      // non-copyable, non-movable
      connection( const connection& ) = delete;
      connection( connection&& ) = delete;
      void operator=( const connection& ) = delete;
      void operator=( connection&& ) = delete;

      ~connection() = default;

      // query status
      bool is_open() const noexcept;
      bool is_idle() const noexcept;

      // create transactions
      auto direct()
         -> std::shared_ptr< pq::transaction >;

      auto transaction()
         -> std::shared_ptr< pq::transaction >;

      auto transaction( const access_mode am,
                        const isolation_level il = isolation_level::default_isolation_level )
         -> std::shared_ptr< pq::transaction >;

      auto transaction( const isolation_level il,
                        const access_mode am = access_mode::default_access_mode )
         -> std::shared_ptr< pq::transaction >;

      // timeout handling
      auto timeout() const noexcept
         -> const std::optional< std::chrono::milliseconds >&;

      void set_timeout( const std::chrono::milliseconds timeout );
      void reset_timeout() noexcept;

      // prepared statements
      void prepare( const std::string& name, const std::string& statement );
      void deallocate( const std::string& name );

      // direct statement execution
      template< typename... As >
      auto execute( const internal::zsv statement, As&&... as )
      {
         return direct()->execute( statement, std::forward< As >( as )... );
      }

      // listen/notify support
      void listen( const std::string_view channel );
      void listen( const std::string_view channel, const std::function< void( const char* ) >& handler );

      void unlisten( const std::string_view channel );

      void notify( const std::string_view channel );
      void notify( const std::string_view channel, const std::string_view payload );

      auto notification_handler()
         -> std::function< void( const notification& ) >;

      void set_notification_handler( const std::function< void( const notification& ) >& handler );
      void reset_notification_handler() noexcept;

      auto notification_handler( const std::string_view channel )
         -> std::function< void( const char* ) >;

      void set_notification_handler( const std::string_view channel, const std::function< void( const char* ) >& handler );
      void reset_notification_handler( const std::string_view channel ) noexcept;

      void handle_notifications();
      void get_notifications();

      // customizable poll()-callback
      auto poll_callback() const noexcept
         -> const std::function< tao::pq::poll::callback >&;

      void set_poll_callback( std::function< tao::pq::poll::callback > poll_cb ) noexcept;
      void reset_poll_callback();

      // access underlying connection pointer from libpq
      auto underlying_raw_ptr() noexcept -> PGconn*;
      auto underlying_raw_ptr() const noexcept -> const PGconn*;

      // access the socket used by libpq
      auto socket() const -> int;

      // error message
      auto error_message() const -> std::string;
   };
}
```

:point_up: Note that `tao::pq::internal::zsv` is explained in the [Statement](Statement.md) chapter.

## Creating a Connection

A connection is created by calling `tao::pq::connection`'s static `create()`-method.

```c++
auto tao::pq::connection::create( const std::string& connection_info,
                                  std::function< tao::pq::poll::callback > poll_cb = /*unspecified*/ )
    -> std::shared_ptr< tao::pq::connection >;
```

It takes a mandatory parameter, the [connection string➚](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING), that is passed to the underlying `libpq` for opening the database connection.
The connection string contains parameters and options, such as the server address or the database name.
Connection parameters that are not specified in the connection string might also be set via [environment variables➚](https://www.postgresql.org/docs/current/libpq-envars.html).

The second, optional parameter can be used to specify a `poll()`-callback, see [Customizable `poll()`-callback](#customizable-poll-callback).

The method returns a `std::shared_ptr<tao::pq::connection>` or, in case of an error, throws an exception.
When the last reference to a connection is deleted, i.e. the last shared pointer referencing it is deleted or reset, the connection is closed via its destructor which takes care of freeing underlying resources.
The shared pointer might also be stored internally in other objects of taoPQ, i.e. a transaction.
This ensures, that the connection is kept alive as long as there are dependent objects like an active transaction, see below.

## Creating Transactions

You can create [transactions](Transaction.md) by calling either the `direct()`-method or the `transaction()`-method.
Both methods register the newly created transaction as the active transaction of a connection.
A connection can only have one active transaction at any given time.
Further details on how to use transactions are discussed in the [Transaction](Transaction.md) chapter.

### Creating a "Direct" Transaction

The `direct()`-method creates an auto-commit transaction proxy, i.e. all statements executed on this transaction are immediately committed to the database.

```c++
auto tao::pq::connection::direct()
    -> std::shared_ptr< tao::pq::transaction >;
```

:point_up: This is not a real transaction from the database's point of view, therefore calling the `commit()`- or `rollback()`-method on the transaction has no immediate effect on the database.
However, calling either the `commit()`- or `rollback()`-method will end the transaction's logical lifetime and it will unregister itself from the connection.

### Creating a Database Transaction

The `transaction()`-method begins a real [database transaction➚](https://www.postgresql.org/docs/current/tutorial-transactions.html).

```c++
auto tao::pq::connection::transaction()
    -> std::shared_ptr< tao::pq::transaction >;

auto tao::pq::connection::transaction( const tao::pq::isolation_level il,
                                       const tao::pq::access_mode am = tao::pq::access_mode::default_access_mode )
    -> std::shared_ptr< tao::pq::transaction >;

auto tao::pq::connection::transaction( const tao::pq::access_mode am,
                                       const tao::pq::isolation_level il = tao::pq::isolation_level::default_isolation_level )
    -> std::shared_ptr< tao::pq::transaction >;
```

You may specify two optional parameters, the [isolation level➚](https://www.postgresql.org/docs/current/transaction-iso.html) and the [access mode➚](https://www.postgresql.org/docs/current/sql-set-transaction.html).

When `tao::pq::isolation_level::default_isolation_level` or `tao::pq::access_mode::default_access_mode` are used the transaction inherits its isolation level or access mode from the session, as described in the [PostgreSQL documentation➚](https://www.postgresql.org/docs/current/sql-set-transaction.html).

## Executing Statements

You can [execute statements](Statement.md) on a connection object directly, which is equivalent to creating a temporary direct transaction (as if calling the `direct()`-method) and executing the statement on that [transaction](Transaction.md).

## Prepared Statements

Prepared statements only last for the duration of a connection, and are bound to a connection, i.e. the set of prepared statements is independent for each connection.

You can [prepare➚](https://www.postgresql.org/docs/current/sql-prepare.html) a statement by calling the `prepare()`-method.

```c++
void tao::pq::connection::prepare( const std::string& name, const std::string& statement );
```

It takes two parameters, the name of the prepared statement and the SQL statement itself.
taoPQ limits the name to classic C-style identifiers, i.e. a non-empty sequence of digits, underscores, and lowercase and uppercase Latin letters.
A valid identifier must begin with a non-digit character.
Identifiers are case-sensitive (lowercase and uppercase letters are distinct).

A previously prepared statement can be [deallocated➚](https://www.postgresql.org/docs/current/sql-deallocate.html), although this is rare in pratice.
To deallocate a prepared statement, call the `deallocate()`-method.

```c++
void tao::pq::connection::deallocate( const std::string& name );
```

Using the `prepare()`- and `deallocate()`-methods makes taoPQ's connection object aware of the names of the prepared statements.
This allows the [execution](Statement.md) of those prepared statements transparently via an `execute()`-method.

### Manually Prepared Statements

You can manually prepare statements by executing [`PREPARE`➚](https://www.postgresql.org/docs/current/sql-prepare.html) statements directly via an `execute()`-method.
While those prepared statements live on the same connection, there are some important differences.
You can only execute those prepared statements by executing [`EXECUTE`➚](https://www.postgresql.org/docs/current/sql-execute.html) statements directly via an `execute()`-method, and you can only deallocate them by executing [`DEALLOCATE`➚](https://www.postgresql.org/docs/current/sql-deallocate.html) statements directly via an `execute()`-method.

:point_up: We advise to use the methods offered by taoPQ's connection type.

## Checking Status

You can check a connection's status by calling the `is_open()`- or `is_idle()`-methods.

```c++
bool tao::pq::connection::is_open() const noexcept;
bool tao::pq::connection::is_idle() const noexcept;
```

The first method returns `true` when the connection is still open and usable, and `false` otherwise, i.e. if the connection is in a failed state.
For further details, check the documentation for the underlying [`PQstatus()`➚](https://www.postgresql.org/docs/current/libpq-status.html)-function provided by `libpq`.

The second method returns `true` when the connection is open and is in the idle state, and `false` otherwise.
For further details, check the documentation for the underlying [`PQtransactionStatus()`➚](https://www.postgresql.org/docs/current/libpq-status.html)-function provided by `libpq`.

## Notification Framework

PostgreSQL provides a simple [interprocess communication mechanism➚](https://www.postgresql.org/docs/current/sql-notify.html) for a collection of applications accessing the same database.

### Sending Messages

You can send events with the `notify()`-method, providing a channel name and optionally a payload as the second parameter.

```c++
void tao::pq::connection::notify( const std::string_view channel );
void tao::pq::connection::notify( const std::string_view channel, const std::string_view payload );
```

:point_up: The channel name is case sensitive when using taoPQ's methods.

### Receiving Messages

You can subscribe to channels to receive messages using the `listen()`-method, or unsubscribe by calling the `unlisten()`-method.

```c++
void tao::pq::connection::listen( const std::string_view channel );
void tao::pq::connection::unlisten( const std::string_view channel );
```

Note that subscriptions are per connection.

### Handling Messages

Processing received messages requires you to register a notification handler.
Each connection has its own notification handler.
The notification handler is managed by a `std::function< void( const tao::pq::notification& >` object.

The currently active notification handler is returned by the `notification_handler()`-method.

```c++
auto tao::pq::connection::notification_handler()
   -> std::function< void( const tao::pq::notification& ) >;
```

If no notification handler is set, the [`std::function`➚](https://en.cppreference.com/w/cpp/utility/functional/function) will be empty.

Setting a notification handler is done by calling the `set_notification_handler()`-method.

```c++
void tao::pq::connection::set_notification_handler( const std::function< void( const tao::pq::notification& ) >& handler );
```

If you want to deregister the current notification handler, you can call the `reset_notification_handler()`-method.

```c++
void tao::pq::connection::reset_notification_handler() noexcept;
```

### Per Channel Handlers

Besides the above general notification handler, there is also the option to register a per channel handler.
Per channel handlers only receive the payload as a parameter.

```c++
auto tao::pq::connection::notification_handler( const std::string_view channel )
   -> std::function< void( const char* ) >;

void tao::pq::connection::set_notification_handler( const std::string_view channel,
                                                    const std::function< void( const char* ) >& handler );
void tao::pq::connection::reset_notification_handler( const std::string_view channel ) noexcept;
```

When you subscribe to a channel with the `listen()`-method, you can optionally register a channel handler.

```c++
void tao::pq::connection::listen( const std::string_view channel,
                                  const std::function< void( const char* ) >& handler );
```

This registers the handler first by calling `set_notification_handler( channel, handler )`, then calls `listen( channel )`.

### Asynchronous Notifications

taoPQ calls the registered notification handler(s) after successful execution by calling the `handle_notifications()`-method.
As a user, you rarely need to call the `handle_notifications()`-method manually.

```c++
void tao::pq::connection::handle_notifications();
```

When you don't have any statement to execute, you can call the `get_notifications()`-method which will actively query the server for new events.

```c++
void tao::pq::connection::get_notifications();
```

### Event Loop

**TODO** Support event loops? How?

## Customizable `poll()`-callback

The default implementation for polling uses `poll()` or `WSAPoll()`, depending on your system.
This callback can be customized to support other I/O frameworks, e.g. Boost.Asio.

To access the currently active callback you can call the `poll_callback()`-method.

```c++
auto poll_callback() const noexcept
   -> const std::function< tao::pq::poll::callback >&;
```

Setting the `poll()`-callback is done by calling the `set_poll_callback()`-method.

```c++
void set_poll_callback( std::function< tao::pq::poll::callback > poll_cb ) noexcept;
```

You can revert the current `poll()`-callback to the default by calling the `reset_poll_callback()`-method.

```c++
void reset_poll_callback();
```

## Underlying Connection Pointer

If you need to access the underlying raw connection pointer from `libpq`, you can call the `underlying_raw_ptr()`-method.

```c++
auto tao::pq::connection::underlying_raw_ptr() noexcept -> PGconn*;
auto tao::pq::connection::underlying_raw_ptr() const noexcept -> const PGconn*;
```

## Error Messages

You can retrieve the last error message (if applicable) by calling the `error_message()`-method.

```c++
auto tao::pq::connection::error_message() const -> std::string;
```

When taoPQ throws an exception this is usually done internally and the message is part of the exception's `what()` message.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Error-Handling.md
================================================
# Error Handling

## SQL errors

When an SQL statement is [executed](Statement.md) and the execution fails, an exception is thrown.
The base class for the exceptions thrown in this case is `tao::pq::sql_error`, which is derived from `tao::pq::error`, which in turn is derived from [`std::runtime_error`➚](https://en.cppreference.com/w/cpp/error/runtime_error).

```c++
namespace tao::pq
{
   struct error
      : std::runtime_error
   {
      using std::runtime_error::runtime_error;
   };

   struct sql_error
      : error
   {
      std::string sqlstate;

      // ctor...
   };
}
```

The exception's `what()`-method will return the error message returned from the server.

## SQLSTATE

Depending on the [SQLSTATE➚](https://en.wikipedia.org/wiki/SQLSTATE) returned from the server as documented in [Appendix A➚](https://www.postgresql.org/docs/current/errcodes-appendix.html) of the PostgreSQL documentation, we throw an accordingly named exception class.

### Class of Error

The first two characters of the error code denote the class of errors, while the last three characters indicate a specific condition within that class.
Thus, an application that does not recognize the specific error code might still be able to infer what to do from the error class.

For each class of errors, there is an exception class derived from `tao::pq::sql_error`.
As an example, if the class is "02" ("no data"), the exception class that is thrown is either derived from `tao::pq::no_data` if a more specific error condition is recognized, or `tao::pq::no_data` itself will be the exception class that is thrown if only the class itself is recognized by taoPQ.

### Specific Error Conditions

If a specific error condition is recognized, an exception named after [Appendix A➚](https://www.postgresql.org/docs/current/errcodes-appendix.html) will be thrown, derived from the exception class of the class of error.

There are some cases in which the name can not be simply taken from that table, as they are used multiple times in different classes of errors.
In those cases the exception class is a class template and you need to add the class of error as a template parameter.

Specifically, this is necessary to distinguish the following exceptions:

* `tao::pq::string_data_right_truncation< tao::pq::warning >` (SQLSTATE "01004")
* `tao::pq::string_data_right_truncation< tao::pq::data_exception >` (SQLSTATE "22001")

and these exceptions from class "sql routine exception":

* `tao::pq::modifying_sql_data_not_permitted< tao::pq::sql_routine_exception >` (SQLSTATE "2F002")
* `tao::pq::prohibited_sql_statement_attempted< tao::pq::sql_routine_exception >` (SQLSTATE "2F003")
* `tao::pq::reading_sql_data_not_permitted< tao::pq::sql_routine_exception >` (SQLSTATE "2F004")

vs these exceptions from class "external routine exception":

* `tao::pq::modifying_sql_data_not_permitted< tao::pq::external_routine_exception >` (SQLSTATE "38002")
* `tao::pq::prohibited_sql_statement_attempted< tao::pq::external_routine_exception >` (SQLSTATE "38003")
* `tao::pq::reading_sql_data_not_permitted< tao::pq::external_routine_exception >` (SQLSTATE "38004")

## Connection Errors

PostgreSQL only delivers an SQLSTATE when a statement is executed.
In other situations, e.g. when opening a connection fails, no SQLSTATE is available.
We throw an exception of type `tao::pq::connection_error` in that case, with a dummy SQLSTATE of "08000".

The same exception can also be thrown when calling the connection's `get_notifications()`-method when the connection is broken.

## Other Exceptions

**TODO**

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Getting-Started.md
================================================
# Getting Started

Before we start with taoPQ, we'd like to point you to the excellent [PostgreSQL documentation➚](https://www.postgresql.org/docs/current/index.html).
We will assume that you are familiar with PostgreSQL and SQL in general, so we will *not* explain what a certain SQL statement does in the database.

Getting started with taoPQ is really simple, a minimalistic program looks as follows:

```c++
#include <iostream>
#include <string>

#include <tao/pq.hpp>

int main()
{
   const auto connection = tao::pq::connection::create( "dbname=template1" );
   const auto result = connection->execute( "SELECT version()" );
   std::cout << result.as< std::string >() << std::endl;
   return 0;
}
```

Let's go through the above code and explain some basic principles, slowly expanding our knowledge of taoPQ.

To use taoPQ, you include the top-level header with `#include <tao/pq.hpp>`.
The individual include files in `tao/pq/` are not meant to be included directly.

Starting with `tao::pq::connection::create("dbname=template1")`, we can see that the `tao::pq::connection` class has a static `create()`-method.
You provide a single parameter, the [connection string➚](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING), and the method then returns a `std::shared_ptr<tao::pq::connection>` that holds the connection object it opened.
The reason why connections (and several other objects in taoPQ) are handled via smart pointers will be explained later.
Note that you can use `auto` as shown above to simplify your code.

A connection has an `execute()`-method which can be used to run SQL statements.
The `execute()`-method returns a result object directly, meaning `tao::pq::result` objects are not handled via smart pointers.

As the statement we just executed was a `SELECT` statement, the result contains a set of rows containing the data returned from the `SELECT` statement.
The above shows a simple way of converting a result set that contains only a single row with a single column into a C++ `std::string`.
Of course there are other, more sophisticated ways to retrieve and convert result data when you received multiple rows with multiple columns, those will be shown later.

Congratulations, you now can write simple programs with taoPQ.

## Next Steps

The following chapters are good next steps to get to know taoPQ:

* The [Connection](Connection.md) chapter goes into more details on the methods offered by `tao::pq::connection`, introduces transactions, and explains why some objects in taoPQ are handled via smart pointers.
* The [Transaction](Transaction.md) chapter explains in more detail how taoPQ handles transactions, makes sure that you don't mess up the transaction ordering and nesting, and which transaction types are supported.
* The [Statement](Statement.md) chapter gives more information on how to send statements and parameters.
* The [Result](Result.md) chapter explains what types of results exist, how you can access the data they contain, and how to convert results into C++ types, including containers.

* The [Installation](Installation.md) chapter explains how to install taoPQ.
* The [Requirements](Requirements.md) chapter lists our requirements and assumptions about the used server and protocol versions, encoding support, etc.

## Advanced Topics

* The [Error Handling](Error-Handling.md) chapter gives some general hints as to how we manage error scenarios and how those are communicated to the application.
* The [Parameter Type Conversion](Parameter-Type-Conversion.md) chapter explains what C++ data types can be used as parameters when executing SQL statements, how NULL values are mapped to C++ data types, and how you can extend the supported types by registering your own types.
* The [Result Type Conversion](Result-Type-Conversion.md) chapter explains what C++ data types can be extracted from results, how you can extend the supported types by registering your own types, and how to use `tao::pq::result`'s API elegantly and efficiently.
* The [Binary Data](Binary-Data.md) chapter explains the support for PostgreSQL's [`BYTEA`➚](https://www.postgresql.org/docs/current/datatype-binary.html) data type in taoPQ and some design decisions regarding the C++ interface.

* The [Connection Pool](Connection-Pool.md) chapter explains how a connection pool might help your application, especially when you use multi-threading. Our connection pool offers some novel features that ease the handling of borrowed connections significantly.
* The [Bulk Transfer](Bulk-Transfer.md) chapter explains how we support high-speed [bulk data transfer➚](https://www.postgresql.org/docs/current/sql-copy.html) to or from the server.
* The [Large Object](Large-Object.md) chapter provides access to PostgreSQL's [large object➚](https://www.postgresql.org/docs/current/largeobjects.html) facility.
* The [Performance](Performance.md) chapter gives hints on how to improve your application's performance, as well as explaining some gotchas you might encounter when using taoPQ.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Installation.md
================================================
# Installation

## Using CMake

Since CMake 3.11, the feature [FetchContent➚](https://cmake.org/cmake/help/latest/module/FetchContent.html) can be used to download and build project dependencies.
This mechanism makes our development much easier, but it lacks in terms of reproducibility, so be careful if you are using it for production. Also, we will use `FetchContent_MakeAvailable` which is available since CMake 3.14:

```cmake
cmake_minimum_required(VERSION 3.14)
project(example CXX)

include(FetchContent)
find_package(PostgreSQL REQUIRED)

FetchContent_Declare(
   taocpp-taopq
   GIT_REPOSITORY https://github.com/taocpp/taopq
   GIT_TAG main
)
FetchContent_MakeAvailable(taocpp-taopq)


add_library(example main.cpp)
target_link_libraries(example taocpp::taopq)
set_property(TARGET example PROPERTY CXX_STANDARD 20)
```

Now, we just need to execute CMake as usual:

```sh
cmake .
cmake --build .
```

The CMake client will download taoPQ source files based on the `main` branch, but is highly recommended using a commit or tag to keep the reproducibility.
Besides that, PostgreSQL (libpq) is a pre-requirement. You can extend the `CMakeLists.txt` to download and build libpq too, or just consume from your system.
When executing the build step, taoPQ will be built first, as its target is required by our application, after that, the example application will be built and linked to both libpq and taoPQ.

---

## Using Conan

You can install pre-built binaries for taoPQ or build it from source using [Conan](https://conan.io/). Use the following command:

```bash
conan install --requires="taocpp-taopq/[*]" --build=missing
```

The taoPQ Conan recipe is kept up to date by Conan maintainers and community contributors.
If the version is out of date, please [create an issue or pull request](https://github.com/conan-io/conan-center-index) on the ConanCenterIndex repository.


This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Large-Object.md
================================================
# Large Object

PostgreSQL has a [large object➚](https://www.postgresql.org/docs/current/largeobjects.html) facility, which provides stream-style access to user data that is stored in a special large-object structure.
Streaming access is useful when working with data values that are too large to manipulate conveniently as a whole.

## Synopsis

```c++
namespace tao::pq
{
   enum class oid : Oid  // Oid defined by libpq
   {
      invalid = InvalidOid,  // InvalidOid defined by libpq

      // undisclosed additional values
   };

   class transaction;

   class large_object final
   {
   public:
      static auto create( const std::shared_ptr< transaction >& transaction,
                          const oid desired_id = oid::invalid ) -> oid;

      static void remove( const std::shared_ptr< transaction >& transaction,
                          const oid id );

      static auto import_file( const std::shared_ptr< transaction >& transaction,
                               const char* filename,
                               const oid desired_id = oid::invalid ) -> oid;

      static void export_file( const std::shared_ptr< transaction >& transaction,
                               const oid id,
                               const char* filename );

      large_object( const std::shared_ptr< transaction >& transaction,
                    const oid id,
                    const std::ios_base::openmode m );

      large_object( const large_object& ) = delete;
      large_object( large_object&& other ) noexcept;

      ~large_object();

      void operator=( const large_object& ) = delete;
      auto operator=( large_object&& rhs ) -> large_object&;

      void close();

      auto read( char* data, const std::size_t size ) -> std::size_t;
      auto read( std::byte* data, const std::size_t size ) -> std::size_t;

      void write( const char* data, const std::size_t size );
      void write( const std::byte* data, const std::size_t size );

      void write( const char* data );

      template< typename T = binary >
      auto read( const std::size_t size ) -> T;

      template< typename... Ts >
      void write( Ts&&... ts );

      void resize( const std::int64_t size );

      auto seek( const std::int64_t offset, const std::ios_base::seekdir whence ) -> std::int64_t;

      auto tell() const -> std::int64_t;
   };
}
```

:point_up: All large object manipulation using these functions must take place within an SQL transaction block, since large object file descriptors are only valid for the duration of a transaction.

## Creating a Large Object

To [create➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-CREATE) a new large object, call

```c++
static auto tao::pq::large_object::create( const std::shared_ptr<tao::pq::transaction>& transaction,
                                           const tao::pq::oid desired_id = tao::pq::oid::invalid ) -> tao::pq::oid;
```

If no desired oid is given, the server will return the oid that was assigned to the new large object.
If you specify a desired oid and that oid is already used, or if any other error occurs, an exception will be thrown.

## Removing a Large Object

To [remove➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-UNLINK) a large object from the database, call

```c++
static void tao::pq::large_object::remove( const std::shared_ptr<tao::pq::transaction>& transaction, const tao::pq::oid id );
```

## Importing a Large Object

To [import➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-IMPORT) an operating system file as a large object, call

```c++
static auto tao::pq::large_object::import_file( const std::shared_ptr<tao::pq::transaction>& transaction,
                                                const char* filename,
                                                const tao::pq::oid desired_id = tao::pq::oid::invalid ) -> tao::pq::oid;
```

If no desired oid is given, the server will return the oid that was assigned to the new large object.
If you specify a desired oid and that oid is already used, or if any other error occurs, an exception will be thrown.

## Exporting a Large Object

To [export➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-EXPORT) a large object into an operating system file, call

```c++
static void tao::pq::large_object::export_file( const std::shared_ptr<tao::pq::transaction>& transaction,
                                                const tao::pq::oid id,
                                                const char* filename );
```

If an error occurs an exception will be thrown.

## Opening an Existing Large Object

To [open➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-OPEN) an existing large object for reading or writing, call

```c++
tao::pq::large_object::large_object( const std::shared_ptr<tao::pq::transaction>& transaction,
                                     const tao::pq::oid id,
                                     const std::ios_base::openmode m );
```

The mode `m` bits control whether the object is opened for reading (`std::ios_base::in`), writing (`std::ios_base::out`), or both.
If an error occurs an exception will be thrown.

The destructor will take care of [closing➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-CLOSE) the large object descriptor.

## Writing Data to a Large Object

To [write➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-WRITE) data to a large object, several methods are available.

```c++
void tao::pq::large_object::write( const char* data, const std::size_t size );
void tao::pq::large_object::write( const std::byte* data, const std::size_t size );

void tao::pq::large_object::write( const char* data );

template< typename... Ts >
void tao::pq::large_object::write( Ts&&... ts );
```

The first three methods write a chunk of data starting at `data` that is `size` bytes long to the large object.

The fourth method expects a zero-terminated string, which will be written to the large object.

The fifth method template forwards its arguments to a call to [`tao::pq::to_binary_view()`](Binary-Data.md), then writes the binary data to the large object.
This allows all data types that are accepted by `tao::pq::to_binary_view()` to be written seamlessly into large objects.

If an error occurs an exception will be thrown.

## Reading Data from a Large Object

To [read➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-READ) data from a large object, several methods are available.

```c++
auto tao::pq::large_object::read( char* data, const std::size_t size ) -> std::size_t;
auto tao::pq::large_object::read( std::byte* data, const std::size_t size ) -> std::size_t;

template< typename T = tao::pq::binary >
auto tao::pq::large_object::read( const std::size_t size ) -> T;
```

The first three methods read up to `size` bytes from the large object into `data`.
The methods will return the number of bytes actually read; this will be less than `size` if the end of the large object is reached first.

The fourth method will create a new object of type `T` and read up to `size` bytes from the large object.
`T` must be one of the following types:

* `std::string`
* [`tao::pq::binary`](Binary-Data.md) aka `std::vector<std::byte>`

:point_up: Although the `size` parameter of the above methods is declared as `std::size_t`, the methods will reject values larger than `INT_MAX`.
In practice, it's best to transfer data in chunks of at most a few megabytes anyway.

If an error occurs an exception will be thrown.

## Seeking in a Large Object

To change the [current read or write➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-SEEK) location associated with a large object, call

```c++
auto tao::pq::large_object::seek( const std::int64_t offset, const std::ios_base::seekdir whence ) -> std::int64_t;
```

This method moves the current location pointer for the large object to the new location specified by `offset`.
The valid values for `whence` are `std::ios_base::beg` (seek from object start), `std::ios_base::cur` (seek from current position), and `std::ios_base::end` (seek from object end).
The return value is the new location pointer.

If an error occurs an exception will be thrown.

## Obtaining the Seek Position of a Large Object

To [obtain➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-TELL) the current read or write location of a large object, call

```c++
auto tao::pq::large_object::tell() const -> std::int64_t;
```

If an error occurs an exception will be thrown.

## Truncating a Large Object

To [truncate➚](https://www.postgresql.org/docs/current/lo-interfaces.html#LO-TRUNCATE) a large object to a given size, call

```c++
void tao::pq::large_object::resize( const std::int64_t size );
```

If `size` is greater than the large object's current length, the large object is extended to the specified length with null bytes ('\0').

If an error occurs an exception will be thrown.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Parameter-Type-Conversion.md
================================================
# Parameter Type Conversion

When [executing statements](Statement.md), you can pass any number of parameters after the statement itself to the `execute()`-method.
Each parameter then gets converted through the parameter traits class template into one or more positional parameters for the SQL statement.
By default, the following C++ types are available for use as parameters.

## NULL

If you want to pass NULL to the database, you pass `tao::pq::null`.

## Fundamental Types

* Booleans
  * `bool`
* Character
  * `char`
* Integral Types
  * `signed char` (8-bit signed integer)
  * `unsigned char` (8-bit unsigned integer)
  * `short`
  * `unsigned short`
  * `int`
  * `unsigned int`
  * `long`
  * `unsigned long`
  * `long long`
  * `unsigned long long`
* Floating Point Types
  * `float`
  * `double`
  * `long double`
* Strings
  * `const char*`
  * `std::string`
  * `std::string_view`
* [Binary](Binary-Data.md) ([`BYTEA`➚](https://www.postgresql.org/docs/current/datatype-binary.html))
  * `std::vector< std::byte >`
  * `std::span< std::byte >`
* [`ARRAY`➚](https://www.postgresql.org/docs/current/arrays.html)
  * `std::array< T, N >`
  * `std::list< T >`
  * `std::set< T >`
  * `std::unordered_set< T >`
  * `std::vector< T >`

## `std::optional< T >`

Represents a [nullable➚](https://en.wikipedia.org/wiki/Nullable_type) type.

If the optional is not empty, then the parameters from `T` are generated.
If the optional is empty, it is equivalent to one or more `tao::pq::null` parameter(s).
The number of NULL values generated depends on the number of parameters that `T` would generate.

## `std::pair< T, U >`

Generates all parameters from `T`, then all parameters from `U`, in that order.
Note that this generates at least two parameters, possibly more.
Pairs can be nested, e.g. `std::pair<std::pair<int,int>,int>` would generate three parameters.

## `std::tuple< Ts... >`

As a generalisation of pairs, tuples generate all parameters for their individual elements, in order.

## Aggregates

Any suitable aggregate data type can be used as a parameter when registered with taoPQ.

```c++
struct my_aggregate
{
   std::string name;
   unsigned age;
   std::string address;
   bool is_pet_owner;
};

template<>
inline constexpr bool tao::pq::is_aggregate< my_aggregate > = true;
```

See [Aggregate Support](Aggregate.md) for more information.

## Custom Data Types

Custom data types can be registered in two different ways, by using a `to_taopq()` function or method, or by specializing the `tao::pq::parameter_traits` class template.

### `to_taopq()`

You can use a function or method called `to_taopq()`, any value returned will then be fed into the parameters as outlined above.
Usually, that means a simple conversion will return a single known type, more complicated types return a `std::tuple` to return multiple parameters for the SQL statement.
There are multiple places where this function or method can be placed.

#### Intrusive Placement

If you have control over a class type, you can add a method called `to_taopq()` that can be called with no parameters.
The method can be marked `const` and/or `noexcept` as applicable.

```c++
class my_int_wrapper
{
private:
   int value;

public:
   explicit my_int_wrapper( int v ) : value( v ) {}

   auto to_taopq() const noexcept
   {
      return value;
   }
};
```

You can now pass values of type `my_int_wrapper` as parameters to call taoPQ's `execute()`-methods.

If your class has more members, you can return multiple values:

```c++
class my_coordinates
{
private:
   double x,y,z;

public:
   //  ctors, etc.

   auto to_taopq() const noexcept
   {
      return std::tie( x, y, z );
   }
};
```

The above means that each time you pass a `my_coordinates` instance as a parameter to an `execute()`-method, three positional parameters are added and can be referenced from the SQL statement.

#### Non-Intrusive Placement

If you can't modify the class you could specialize `tao::pq::bind<...>` and place a static `to_taopq()`-method inside the specialization, or provide a free function called `to_taopq()` instead.
Those functions must accept a single parameter of the class you want to register.

Example for the specialization of `tao::pq::bind<...>`:

```c++
struct some_coordinates
{
   double x,y,z;
};

template<>
struct tao::pq::bind< some_coordinates >
{
   static auto to_taopq( const some_coordinates& v ) noexcept
   {
      return std::tie( v.x, v.y, v.z );
   }
};
```

Example for the free function:

```c++
struct some_coordinates
{
   double x,y,z;
};

auto to_taopq( const some_coordinates& v ) noexcept
{
   return std::tie( v.x, v.y, v.z );
}
```

The free function is found either by [ADL➚](https://en.cppreference.com/w/cpp/language/adl) or in namespace `tao::pq`.

:point_up: Note that any returned value in the above examples can itself be a registered custom type.
taoPQ will simply expand parameters recursively.

### `tao::pq::parameter_traits< T >`

If the above custom data type registration via `to_taopq()` is somehow not sufficient, you can specialize the `tao::pq::parameter_traits` class template.
For now please consult the source code or ask the developers.

TODO: Write proper documentation.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Performance.md
================================================
# Performance

**TODO**

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Requirements.md
================================================
# Requirements

## Operating System Support

* We support:
  * [Windows➚](https://en.wikipedia.org/wiki/Microsoft_Windows).
  * [macOS➚](https://en.wikipedia.org/wiki/MacOS).
  * [Linux➚](https://en.wikipedia.org/wiki/Linux).
* Other systems might work.

## Compiler Support

* We support:
  * [Visual Studio➚](https://en.wikipedia.org/wiki/Microsoft_Visual_Studio) version 2022 or newer.
  * [Xcode➚](https://en.wikipedia.org/wiki/Xcode) version 15 or newer.
  * [GCC➚](https://gcc.gnu.org/) version 13 or newer.
  * [Clang➚](https://clang.llvm.org/) version 16 or newer.
* Other compilers might work.

## Language Requirements

* We require [C++20➚](https://en.wikipedia.org/wiki/C%2B%2B20) or newer.
* We require exception support. The `-fno-exceptions` option is not supported.
* We require RTTI support. The `-fno-rtti` option is not supported.

## Compiler Options/Warnings

* We support Clang's [`-fms-extensions`➚](https://clang.llvm.org/docs/MSVCCompatibility.html) option.
* We support the `/W4` option on [Visual Studio➚](https://docs.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level).
* We support the `-pedantic`, `-Wall`, and `-Wextra` options on [GCC➚](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) and [Clang➚](https://clang.llvm.org/docs/DiagnosticsReference.html).

:point_up: Note that we *support* these options, we don't *require* them to be used.
You can decide which options you want to use in your project, we just try to not get in the way by making sure that our code doesn't generate any of those warnings.

## Database Requirements

* We expect the database to use UTF-8 encoding.
* We expect the database to send `BYTEA` data in [`bytea` hex format➚](https://www.postgresql.org/docs/current/datatype-binary.html).
* We expect the database connection to use [protocol version 3➚](https://www.postgresql.org/docs/current/protocol.html).

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Result-Type-Conversion.md
================================================
# Result Type Conversion

Depending on what type of [statement](Statement.md) was executed, you receive a [result](Result.md) containing a query result set.
Those results then offer conversions to C++ data types through various methods, e.g. `tao::pq::row::as<T>()`.
This chapter discusses the data types that are available by default and how to register your own custom data types when needed.

## Fundamental Types

By default, the following C++ types are available for use as result types.

* Booleans
  * `bool`
* Character
  * `char`
* Integral Types
  * `signed char` (8-bit signed integer)
  * `unsigned char` (8-bit unsigned integer)
  * `short`
  * `unsigned short`
  * `int`
  * `unsigned int`
  * `long`
  * `unsigned long`
  * `long long`
  * `unsigned long long`
* Floating Point Types
  * `float`
  * `double`
  * `long double`
* Strings
  * `const char*`
  * `std::string`
  * `std::string_view`
* [Binary](Binary-Data.md) ([`BYTEA`➚](https://www.postgresql.org/docs/current/datatype-binary.html))
  * `std::vector< std::byte >`
* [`ARRAY`➚](https://www.postgresql.org/docs/current/arrays.html)
  * `std::list< T >`
  * `std::set< T >`
  * `std::unordered_set< T >`
  * `std::vector< T >`

## `std::optional< T >`

Represents a [nullable➚](https://en.wikipedia.org/wiki/Nullable_type) type.

If the result field is NULL, an empty optional is returned.
If the result field is not NULL, the value is converted to `T` and returned in the optional.

## `std::pair< T, U >`

Returns a `std::pair< T, U >`, hence convertes two (or more) neighboring fields from the result's row.
It can read more than two fields when `T` or `U` themselves read more than one field, i.e. converting to `std::pair<int,std::pair<int,int>>` will read three fields from the result's row.

## `std::tuple< Ts... >`

As a generalisation of pairs, tuples read all fields for their individual elements, in order.

## Aggregates

Any suitable aggregate data type can be used as a result type when registered with taoPQ.

```c++
struct my_aggregate
{
   std::string name;
   unsigned age;
   std::string address;
   bool is_pet_owner;
};

template<>
inline constexpr bool tao::pq::is_aggregate< my_aggregate > = true;
```

See [Aggregate Support](Aggregate-Support.md) for more information.

## Custom Data Types

Custom data types can be registered in two different ways, by using a `from_taopq()` function or method, or by specializing the `tao::pq::result_traits` class template.

### `from_taopq()`

You can use a function or method called `from_taopq()`, which takes one or more suitable parameters and returns a new instance of your type.
There are multiple places where this function or method can be placed.

#### Intrusive Placement

If you have control over a class type, you can add a static method called `from_taopq()`.
The method can be marked `noexcept` if applicable.

```c++
class my_int_wrapper
{
private:
   int value;

public:
   explicit my_int_wrapper( int v ) : value( v ) {}

   static auto from_taopq( const int v ) noexcept
   {
      return my_int_wrapper( v );
   }
};
```

taoPQ will find the class' method, analyze the methods parameters and convert the result's row accordingly.
The method must have at least one parameter, each parameter will read the required number of fields.

#### Non-Intrusive Placement

If you can't modify the class you could specialize `tao::pq::bind<...>` and place a static `from_taopq()`-method inside the specialization.
The method behaves identical to the intrusive version.

Example for the specialization of `tao::pq::bind<...>`:

```c++
struct some_coordinates
{
   double x,y,z;
};

template<>
struct tao::pq::bind< some_coordinates >
{
   static auto from_taopq( const double x, const double y, const double z ) noexcept
   {
      return some_coordinates{ x, y, z };
   }
};
```

:point_up: Note that unlike [`to_taopq()`](Parameter-Type-Conversion.md), there is no free function version for `from_taopq()` available.
This is due to the fact that the custom data type is not a parameter, but rather the returned value.
The parameter list can therefore be identical for multiple custom data types and this could leads to conflicting overloads.
Also, [ADL➚](https://en.cppreference.com/w/cpp/language/adl) would be unavailable as only the parameters' types are considered for ADL.

### `tao::pq::result_traits< T >`

If the above custom data type registration via `from_taopq()` is somehow not sufficient, you can specialize the `tao::pq::result_traits` class template.
For now please consult the source code or ask the developers.

TODO: Write proper documentation.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Result.md
================================================
# Result

When [executing statements](Statement.md) you receive a result object.
A result comes in two flavours, depending on what statement was executed.

When executing a [query statement➚](https://www.postgresql.org/docs/current/queries-overview.html), the database returns a result set, i.e. any number of rows containing one or more fields of data.

When executing non-query statements, you can usually only extract the number of affected rows.

Query results can be iterated or conveniently converted into a C++ data structure.
Predefined types include most arithmetic C++ data types, STL containers, `std::pair`/`std::tuple`, and `std::optional` for [nullable➚](https://en.wikipedia.org/wiki/Nullable_type) values.
Again custom types can be added with custom conversion functions.

## Synopsis

Don't be intimidated by the size of the API, as you can see several methods are just single-line convenience forwarders.

We will first give the synopsis of everything, afterwards we will break down the API into small logical portions.

```c++
namespace tao::pq
{
   namespace internal
   {
      class zsv;  // zero-terminated string view
   }

   using null_t = decltype( null );

   class row;
   class field;

   class result final
   {
   private:
      // satisfies LegacyRandomAccessIterator, see
      // https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator
      class const_iterator;

   public:
      // non-query result access
      bool has_rows_affected() const noexcept;
      auto rows_affected() const -> std::size_t;

      // information about the returned fields
      auto columns() const noexcept -> std::size_t;

      auto name( const std::size_t column ) const -> std::string;
      auto index( const internal::zsv in_name ) const -> std::size_t;

      // size of the result set
      bool empty() const;
      auto size() const -> std::size_t;

      // iteration
      auto begin() const -> const_iterator;
      auto end() const -> const_iterator;

      auto cbegin() const -> const_iterator;
      auto cend() const -> const_iterator;

      // get basic information about a field
      bool is_null( const std::size_t row, const std::size_t column ) const;
      auto get( const std::size_t row, const std::size_t column ) const -> const char*;

      // access rows
      auto operator[]( const std::size_t row ) const noexcept -> pq::row;
      auto at( const std::size_t row ) const -> pq::row;

      // convenience conversions for whole result sets

      // expects size()==1, converts the only row to T
      template< typename T >
      auto as() const -> T;

      template< typename T >
      auto optional() const -> std::optional< T >;

      // convenience conversions to pair/tuple
      template< typename T, typename U >
      auto pair() const
      {
         return as< std::pair< T, U > >();
      }

      template< typename... Ts >
      auto tuple() const
      {
         return as< std::tuple< Ts... > >();
      }

      // convert each row into T::value_type and add to a container of type T
      template< typename T >
      auto as_container() const -> T;

      // convenience conversions to standard containers
      template< typename... Ts >
      auto vector() const
      {
         return as_container< std::vector< Ts... > >();
      }

      template< typename... Ts >
      auto list() const
      {
         return as_container< std::list< Ts... > >();
      }

      template< typename... Ts >
      auto set() const
      {
         return as_container< std::set< Ts... > >();
      }

      template< typename... Ts >
      auto multiset() const
      {
         return as_container< std::multiset< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_set() const
      {
         return as_container< std::unordered_set< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_multiset() const
      {
         return as_container< std::unordered_multiset< Ts... > >();
      }

      template< typename... Ts >
      auto map() const
      {
         return as_container< std::map< Ts... > >();
      }

      template< typename... Ts >
      auto multimap() const
      {
         return as_container< std::multimap< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_map() const
      {
         return as_container< std::unordered_map< Ts... > >();
      }

      template< typename... Ts >
      auto unordered_multimap() const
      {
         return as_container< std::unordered_multimap< Ts... > >();
      }

      // access underlying result pointer from libpq
      auto underlying_raw_ptr() noexcept -> PGresult*;
      auto underlying_raw_ptr() const noexcept -> const PGresult*;
   };

   class row
   {
   private:
      // satisfies LegacyRandomAccessIterator, see
      // https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator
      class const_iterator;

   public:
      auto slice( const std::size_t offset, const std::size_t in_columns ) const -> row;

      auto columns() const noexcept -> std::size_t;

      auto name( const std::size_t column ) const -> std::string;
      auto index( const internal::zsv in_name ) const -> std::size_t;

      // iteration
      auto begin() const -> const_iterator;
      auto end() const -> const_iterator;

      auto cbegin() const -> const_iterator;
      auto cend() const -> const_iterator;

      bool is_null( const std::size_t column ) const;
      auto get( const std::size_t column ) const -> const char*;

      template< typename T >
      auto get( const std::size_t column ) const -> T;

      template< typename T >
      auto optional( const std::size_t column ) const
      {
         return get< std::optional< T > >( column );
      }

      template< typename T >
      auto as() const -> T;

      template< typename T >
      auto optional() const
      {
         return as< std::optional< T > >();
      }

      template< typename T, typename U >
      auto pair() const
      {
         return as< std::pair< T, U > >();
      }

      template< typename... Ts >
      auto tuple() const
      {
         return as< std::tuple< Ts... > >();
      }

      auto at( const std::size_t column ) const -> field;
      auto operator[]( const std::size_t column ) const noexcept -> field;

      auto at( const internal::zsv in_name ) const -> field;
      auto operator[]( const internal::zsv in_name ) const -> field;

      friend void swap( row& lhs, row& rhs ) noexcept;
   };

   class field
   {
   public:
      auto name() const -> std::string;
      auto index() const -> std::size_t;

      bool is_null() const;
      auto get() const -> const char*;

      template< typename T >
      auto as() const -> T;

      template< typename T >
      auto optional() const
      {
         return as< std::optional< T > >();
      }
   };

   bool operator==( const field& f, null_t )
   {
      return f.is_null();
   }

   bool operator==( null_t, const field& f )
   {
      return f.is_null();
   }

   bool operator!=( const field& f, null_t )
   {
      return !f.is_null();
   }

   bool operator!=( null_t, const field& f )
   {
      return !f.is_null();
   }
}
```

## Non-Query Results

For non-query results, i.e. when you called an `INSERT`-, `UPDATE`-, or `DELETE`-statement, you really only need the `rows_affected()`-method.
In generic programming, when you might not know what kind of result you have, you can check whether or not a result is a non-query result by calling the `has_rows_affected()`-method.

```c++
bool tao::pq::result::has_rows_affected() const;
auto tao::pq::result::rows_affected() const -> std::size_t;
```

## Query Results

[Query results➚](https://www.postgresql.org/docs/current/queries-overview.html) are non-mutable data sets, they are cheap to copy, move, or assign and you can iterate over the data multiple times in random order.
Likewise, rows are also non-mutable, as well as fields.
This also means iterators will behave as constant iterators.

Query results act similar to a random-access container.
The don't fully implement the [container requirements➚](https://en.cppreference.com/w/cpp/named_req/Container), but a reasonable subset of those are provided.

:point_up: Rows and fields are non-owning, meaning they are only valid as long as the query result instance is still valid.

### Basics

You can query the container's size, i.e. the number of rows it contains, by calling the `size()`-method.
The `empty()`-method will, of course, return whether the size of the container is zero or not.

```c++
bool tao::pq::result::empty() const;
auto tao::pq::result::size() const -> std::size_t;
```

The number of columns, column order, and the column name is the same for all rows of a result set.
You can query the number of columns by calling the `columns()`-method.
You can retrieve the name of a column using the `name()`-method, or the column index by using the `index()`-method.

```c++
auto tao::pq::result::columns() const -> std::size_t;
auto tao::pq::result::name( std::size_t column ) const -> std::string;
auto tao::pq::result::index( tao::pq::internal::zsv name ) const -> std::size_t;
```

Direct access to the data is provided by the `is_null()`- and the `get()`-methods.
The latter returns the raw string as returned by `libpq`, it is a low level access method that is rarely used directly.

```c++
bool tao::pq::result::is_null( std::size_t row, std::size_t column ) const;
auto tao::pq::result::get( std::size_t row, std::size_t column ) const -> const char*;
```

### Row Access

You can iterate over the container's elements, the rows, with the usual methods.
This is what the `begin()`- and `end()`-methods are for, also allowing for the convenient use of [range-based for loops➚](https://en.cppreference.com/w/cpp/language/range-for).

```c++
auto tao::pq::result::begin() const -> tao::pq::result::const_iterator;
auto tao::pq::result::end() const -> tao::pq::result::const_iterator;
```

The identical `cbegin()`- and `cend()`-methods are provided for completeness.

Here's an example of how to iterate all rows:

```c++
const tao::pq::result result = ...;
for( const auto& row : result ) {
   // use row to access your data
}
```

or more traditionally:

```c++
const tao::pq::result result = ...;
for( auto it = std::begin( result ); it != std::end( result ); ++it ) {
   // use *it to access your row's data
}
```

Alternatively, you can use an index to access the rows.

```c++
const tao::pq::result result = ...;
for( std::size_t i = 0; i < result.size(); ++i ) {
   // use result[ i ] or result.at( i ) to access your row's data
}
```

This is enabled by the accessors, the `at()`-method and the `[]`-operator.

```c++
auto tao::pq::result::at( std::size_t index ) const -> tao::pq::row;
auto tao::pq::result::operator[]( std::size_t index ) const noexcept -> tao::pq::row;
```

More conversion methods will be discussed later, after we covered the basics for rows and fields.

### Field Access

Given a row, you can query information about the fields with the same methods as for the result itself.

```c++
auto tao::pq::row::columns() const -> std::size_t;
auto tao::pq::row::name( std::size_t column ) const -> std::string;
auto tao::pq::row::index( tao::pq::internal::zsv name ) const -> std::size_t;
```

Direct access to the data is provided by the `is_null()`- and the `get()`-methods.
The latter returns the raw string as returned by `libpq`, it is a low level access method that is rarely used directly.

```c++
bool tao::pq::row::is_null( std::size_t column ) const;
auto tao::pq::row::get( std::size_t column ) const -> const char*;
```

You can iterate over the row's elements, the fields, with the usual methods.
This is what the `begin()`- and `end()`-methods are for, also allowing for the convenient use of [range-based for loops➚](https://en.cppreference.com/w/cpp/language/range-for).

```c++
auto tao::pq::row::begin() const -> tao::pq::row::const_iterator;
auto tao::pq::row::end() const -> tao::pq::row::const_iterator;
```

The identical `cbegin()`- and `cend()`-methods are provided for completeness.

Here's an example of how to iterate all fields:

```c++
const tao::pq::result result = ...;
for( const auto& row : result ) {
   for( const auto& field : row ) {
      // use field to access your data
   }
}
```

or more traditionally:

```c++
const tao::pq::result result = ...;
for( auto it = std::begin( result ); it != std::end( result ); ++it ) {
   for( auto jt = std::begin( *it ); jt != std::end( *it ); ++jt ) {
      // use *jt to access your fields's data
   }
}
```

Alternatively, you can use an index to access the fields.

```c++
const tao::pq::result result = ...;
for( std::size_t i = 0; i < result.size(); ++i ) {
   for( std::size_t j = 0; j < result[ i ].columns(); ++j ) {
      // use result[ i ][ j ] or result.at( i ).at( j ) to access your field's data
   }
}
```

This is enabled by the accessors, the `at()`-method and the `[]`-operator.

```c++
auto tao::pq::row::at( std::size_t index ) const -> tao::pq::field;
auto tao::pq::row::operator[]( std::size_t index ) const noexcept -> tao::pq::field;
```

More conversion methods will be discussed later, after we covered the basics for fields.

### Fields

You can query a field's name by calling the `name()`-method.

```c++
auto tao::pq::field::name() const -> std::string;
```

Direct access to the data is provided by the `is_null()`- and the `get()`-methods.
The latter returns the raw string as returned by `libpq`, it is a low level access method that is rarely used directly.

```c++
bool tao::pq::field::is_null() const;
auto tao::pq::field::get() const -> const char*;
```

Now that we covered the basics, we can retrieve the actual data and convert it to the data types we need.

## Field Data Conversion

A field can be converted to any data type `T` that is a single field wide.
What we mean by that is, that `tao::pq::result_traits_size< T >` yields 1.
This is the case for `const char*`, `std::string`, `int`, etc.

In order to convert a field to the data type you want, you can use the `as()`-method.

```c++
template< typename T >
auto tao::pq::field::as() const -> T;
```

The conversion is handled by the `tao::pq::result_traits` class template, which is documented in the [result type conversion](Result-Type-Conversion.md) chapter.

A field also has a convenience method to convert directly into a `std::optional<T>`.

```c++
template< typename T >
auto tao::pq::field::optional() const
{
   return as< std::optional< T > >();
}
```

## Row Data Conversion

**TODO** Finish this up for rows and results...

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/Statement.md
================================================
# Statement

:warning: Before showing you how to execute statements with taoPQ, we'd like to take a moment to talk about [SQL injection➚](https://en.wikipedia.org/wiki/SQL_injection).
SQL injection is a large family of security issues that has plagued the internet for decades.
We designed taoPQ to allow you to *safely* and *conveniently* write code that does not allow SQL injection.
With that said, let's start executing statements with taoPQ.

## `execute()`

All statements are executed by calling an `execute()`-method, either on a transaction, connection, or connection pool directly.
The synopsis of the execute methods of those types (`Type` being `tao::pq::transaction`, `tao::pq::connection`, or `tao::pq::connection_pool`) is:

```c++
template< typename... As >
auto Type::execute( const tao::pq::internal::zsv statement, As&&... as ) -> tao::pq::result;
```

For the purpose of this chapter, it makes no difference which `Type` is used.
The method takes the statement itself as its first parameter plus additional parameters that will be passed to the statement.
It returns a `tao::pq::result` that is documented in the [Result](Result.md) chapter.
In case of an error, i.e. if the statement execution failed, an exception is thrown as documented in the [Error Handling](Error-Handling.md) chapter.

### `tao::pq::internal::zsv`

The `tao::pq::internal::zsv` type (zero-terminated string view) that is used for the `statement` parameter ensures that you pass a zero-terminated string.
It is a non-owning type which has non-explicit constructor overloads for `const char*` and `const std::string&`.
For safety reasons, there is another overload for `std::nullptr_t` that is deleted.
Note that we do not accept `std::string_view`, as the underlying C-API of `libpq` requires a zero-terminated string.

## Positional Parameters

To reference the parameters you supplied in the statement, you use [positional parameters➚](https://www.postgresql.org/docs/current/sql-expressions.html).
Positional parameters are of the form `$n` where `n` is a number starting at 1.
Here's an example of how you can insert a row with two columns into the database:

```c++
tr->execute( "INSERT INTO user ( name, age ) VALUES ( $1, $2 )", "Daniel", 42 );
```

The actual data is separated from the statement itself.
The use of positional parameters makes passing strings and other types safe, as there is no need for manually escaping the data.
Our library now knows what is the actual SQL statement you want to send and what is the data you want to send.
This protects you from SQL injections and it is also quiet convenient.
The way the data is now transferred between the client and the server is also more efficient.

:warning: The only thing you have to remember is to **never** concatenate strings together to create the SQL statement including the data manually.
As this is such an important point, we will illustrate how it should **not** be done:

```c++
auto find_user( const std::string& name )
{
   return connection->execute( "SELECT FROM user WHERE name = '" + name + "'" );
   //                                                         ~~~~~~~~~~~~~~       WRONG!!!
}
```

:no_entry: Never concatenate SQL statements manually!
Consider `name` to be an input field coming from untrusted user input.
What happens, if a user enters the following "name":

`Robert'; DELETE FROM user WHERE name <> 'Little Bobby Tables`

Yupp, all users other than [`Little Bobby Tables`➚](https://xkcd.com/327/) have just been deleted from the database.

You might have seen other libraries where you should [escape the data explicitly➚](https://www.postgresql.org/docs/current/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING), something like:

```c++
auto find_user( const std::string& name )
{
   return connection->execute( "SELECT FROM user WHERE name = '" + connection->escape( name ) + "'" );
}
```

This is cumbersome and error-prone.
It is easy to forget calling the escape method, which the compiler will *not* catch for you, and for non-strings, the code needs to call explicit conversion methods to string.
This turns longer SQL statements into a long, ugly mess.

Positional parameters solve all of those problems and therefore taoPQ does not even offer any escaping methods.
To be safe and to make your life easier, with taoPQ always use positional parameters:

```c++
auto find_user( const std::string& name )
{
   return connection->execute( "SELECT FROM user WHERE name = $1", name );
}
```

## Multi-Query Commands

Some SQL client libraries allow multi-query commands, i.e. the command string can include multiple SQL statements.
In `libpq`, this is supported by the [`PQexec()`➚](https://www.postgresql.org/docs/current/libpq-exec.html)-function.
As an extra defense against SQL injection, taoPQ *never* calls the `PQexec()`-function.
We allow at most one SQL command in the given statement passed to an `execute()`-method.

## Prepared Statements

In the [Connection](Connection.md) chapter we have shown how you can prepare (and deallocate) prepared statements.
In order to execute prepared statements, you simply pass the name of the prepared statement to the `execute()`-method instead of the actual SQL statement.
This might look like this:

```c++
connection->prepare( "insert_user", "INSERT INTO user ( name, age ) VALUES ( $1, $2 )" );

connection->execute( "insert_user", "Daniel", 42 );
connection->execute( "insert_user", "Tom", 41 );
connection->execute( "insert_user", "Jerry", 29 );
```

This is both more efficient and also allows you to change the statements in a central place if need be, without touching any of the places where it is actually used.

You might want to wrap calls to a (prepared) statement into an application-specific wrapper, that way you add C++'s type safety for the rest of the application calling that method (and also receiving the result).

Another idea that we already used in practice is to read the SQL statements from a configuration file.
When you then need to change a statement, e.g. to work around a performance issue with the database or because you renamed a column in the database, all you need to do is adapt the configuration.
No need to recompile the application.

## Type Conversion

The above example also shows that you can use different data types as parameters.
Besides basic types like strings or integers, you can also use more complex types like `std::tuple` which will decay into multiple parameters.
You can even register your own data types to generate one or more parameters from them.
The [Parameter Type Conversion](Parameter-Type-Conversion.md) chapter explains which data types are supported out-of-the-box, and how you can register your own custom data types.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: doc/TOC.md
================================================
# Table of Content

* [Requirements](Requirements.md)
  * [Operating System Support](Requirements.md#operator-system-support)
  * [Compiler Support](Requirements.md#compiler-support)
  * [Language Requirements](Requirements.md#language-requirements)
  * [Compiler Options/Warnings](Requirements.md#compiler-optionswarnings)
  * [Database Requirements](Requirements.md#database-requirements)
* [Installation](Installation.md)
  * **TODO** after properly rewriting this chapter
* [Getting Started](Getting-Started.md)
  * [Next Steps](Getting-Started.md#next-steps)
  * [Advanced Topics](Getting-Started.md#advanced-topics)
* [Connection Pool](Connection-Pool.md)
  * [Synopsis](Connection-Pool.md#synopsis)
  * [Creating Connection Pools](Connection-Pool.md#creating-connection-pools)
  * [Borrowing Connections](Connection-Pool.md#borrowing-connections)
  * [Executing Statements](Connection-Pool.md#executing-statements)
  * [Cleanup](Connection-Pool.md#cleanup)
  * [Thread Safety](Connection-Pool.md#thread-safety)
* [Connection](Connection.md)
  * [Synopsis](Connection.md#synopsis)
  * [Creating a Connection](Connection.md#creating-a-connection)
  * [Creating Transactions](Connection.md#creating-transactions)
    * [Creating a "Direct" Transaction](Connection.md#creating-a-direct-transaction)
    * [Creating a Database Transaction](Connection.md#creating-a-database-transaction)
  * [Executing Statements](Connection.md#executing-statements)
  * [Prepared Statements](Connection.md#prepared-statements)
    * [Manually Prepared Statements](Connection.md#manually-prepared-statements)
  * [Checking Status](Connection.md#checking-status)
  * [Notification Framework](Connection.md#notification-framework)
    * [Sending Messages](Connection.md#sending-messages)
    * [Receiving Messages](Connection.md#receiving-messages)
    * [Handling Messages](Connection.md#handling-messages)
    * [Per Channel Handlers](Connection.md#per-channel-handlers)
    * [Asynchronous Notifications](Connection.md#asynchronous-notifications)
    * [Event Loop](Connection.md#event-loop)
  * [Underlying Connection Pointer](Connection.md#underlying-connection-pointer)
  * [Error Messages](Connection.md#error-messages)
* [Transaction](Transaction.md)
  * [Synopsis](Transaction.md#synopsis)
  * [Creating Transactions](Transaction.md#creating-transactions)
  * [Statement Execution](Transaction.md#statement-execution)
  * [Terminate Transaction](Transaction.md#terminate-transaction)
    * [Commit a Transaction](Transaction.md#commit-a-transaction)
    * [Abort a Transaction](Transaction.md#abort-a-transaction)
  * [Transaction Ordering](Transaction.md#transaction-ordering)
  * [Direct Transactions](Transaction.md#direct-transactions)
  * [Manual Transaction Handling](Transaction.md#manual-transaction-handling)
  * [Accessing the Connection](Transaction.md#accessing-the-connection)
* [Statement](Statement.md)
  * [`execute()`](Statement.md#execute)
    * [`tao::pq::internal::zsv`](Statement.md#taopqinternalzsv)
  * [Positional Parameters](Statement.md#positional-parameters)
  * [Multi-Query Commands](Statement.md#multi-query-commands)
  * [Prepared Statements](Statement.md#prepared-statements)
  * [Type Conversion](Statement.md#type-conversion)
* [Parameter Type Conversion](Parameter-Type-Conversion.md)
  * [NULL](Parameter-Type-Conversion.md#null)
  * [Fundamental Types](Parameter-Type-Conversion.md#fundamental-types)
  * [`std::optional< T >`](Parameter-Type-Conversion.md#stdoptional-t-)
  * [`std::pair< T, U >`](Parameter-Type-Conversion.md#stdpair-t-u-)
  * [`std::tuple< Ts... >`](Parameter-Type-Conversion.md#stdtuple-ts-)
  * [Aggregates](Parameter-Type-Conversion.md#aggregates)
  * [Custom Data Types](Parameter-Type-Conversion.md#custom-data-types)
    * [`to_taopq()`](Parameter-Type-Conversion.md#to_taopq-)
      * [Intrusive Placement](Parameter-Type-Conversion.md#intrusive-placement)
      * [Non-Intrusive Placement](Parameter-Type-Conversion.md#non-intrusive-placement)
    * [`tao::pq::parameter_traits< T >`](Parameter-Type-Conversion.md#taopqparameter_traits-t-)
* [Result](Result.md)
  * [Synopsis](Result.md#synopsis)
  * [Non-Query Results](Result.md#non-query-results)
  * [Query Results](Result.md#query-results)
    * [Basics](Result.md#basics)
    * [Row Access](Result.md#row-access)
    * [Field Access](Result.md#field-access)
    * [Fields](Result.md#fields)
  * [Field Data Conversion](Result.md#field-data-conversion)
  * [Row Data Conversion](Result.md#row-data-conversion)
* [Result Type Conversion](Result-Type-Conversion.md)
  * [Fundamental Types](Result-Type-Conversion.md#fundamental-types)
  * [`std::optional< T >`](Result-Type-Conversion.md#stdoptional-t-)
  * [`std::pair< T, U >`](Result-Type-Conversion.md#stdpair-t-u-)
  * [`std::tuple< Ts... >`](Result-Type-Conversion.md#stdtuple-ts-)
  * [Aggregates](Result-Type-Conversion.md#aggregates)
  * [Custom Data Types](Result-Type-Conversion.md#custom-data-types)
    * [`from_taopq()`](Result-Type-Conversion.md#from_taopq)
      * [Intrusive Placement](Result-Type-Conversion.md#intrusive-placement)
      * [Non-Intrusive Placement](Result-Type-Conversion.md#non-intrusive-placement)
    * [`tao::pq::result_traits< T >`](Result-Type-Conversion.md#taopqresult_traits-t-)
* [Aggregate Support](Aggregate-Support.md)
  * [Status](Aggregate-Support.md#status)
  * [Requirements](Aggregate-Support.md#requirements)
  * [Registration](Aggregate-Support.md#registration)
  * [Direct Result Conversion](Aggregate-Support.md#direct-result-conversion)
  * [Example](Aggregate-Support.md#example)
* [Error Handling](Error-Handling.md)
  * [SQLSTATE](Error-Handling.md#sqlstate)
    * [Class of Error](Error-Handling.md#class-of-error)
    * [Specific Error Conditions](Error-Handling.md#specific-error-conditions)
  * [Connection Errors](Error-Handling.md#connection-errors)
  * [Other Exceptions](Error-Handling.md#other-exceptions)
* [Binary Data](Binary-Data.md)
  * [The `BYTEA` Data Type](Binary-Data.md#the-bytea-data-type)
  * [C++ Binary Data](Binary-Data.md#c-binary-data)
  * [Passing Binary Data](Binary-Data.md#passing-binary-data)
  * [Receiving Binary Data](Binary-Data.md#receiving-binary-data)
* [Bulk Transfer](Bulk-Transfer.md)
  * [Synopsis](Bulk-Transfer.md#synopsis)
* [Large Object](Large-Object.md)
  * [Synopsis](Large-Object.md#synopsis)
  * [Creating a Large Object](Large-Object.md#creating-a-large-object)
  * [Removing a Large Object](Large-Object.md#removing-a-large-object)
  * [Importing a Large Object](Large-Object.md#importing-a-large-object)
  * [Exporting a Large Object](Large-Object.md#exporting-a-large-object)
  * [Opening an Existing Large Object](Large-Object.md#opening-an-existing-large-object)
  * [Writing Data to a Large Object](Large-Object.md#writing-data-to-a-large-object)
  * [Reading Data from a Large Object](Large-Object.md#reading-data-from-a-large-object)
  * [Seeking in a Large Object](Large-Object.md#seeking-in-a-large-object)
  * [Obtaining the Seek Position of a Large Object](Large-Object.md#obtaining-the-seek-position-of-a-large-object)
  * [Truncating a Large Object](Large-Object.md#truncating-a-large-object)
* [Performance](Performance.md)


================================================
FILE: doc/Transaction.md
================================================
# Transaction

Before we continue with our own documentation, we'd like to once again point you to the excellent [PostgreSQL documentation➚](https://www.postgresql.org/docs/current/tutorial-transactions.html) on transactions.
We will assume that you are familiar with how transactions work on PostgreSQL and in general, so we will *not* repeat this here.

## Synopsis

```c++
namespace tao::pq
{
   namespace internal
   {
      class zsv;  // zero-terminated string view
   }

   class connection;
   class result;

   class transaction
      : public std::enable_shared_from_this< transaction >
   {
   public:
      // non-copyable, non-movable
      transaction( const transaction& ) = delete;
      transaction( transaction&& ) = delete;
      void operator=( const transaction& ) = delete;
      void operator=( transaction&& ) = delete;

      virtual ~transaction() = default;

      // create transactions
      auto subtransaction()
         -> std::shared_ptr< transaction >;

      // asynchronous statement execution
      template< typename... As >
      void send( const internal::zsv statement, As&&... as );

      // asynchronous result retrieval
      auto get_result() -> result;

      // synchronous statement execution
      template< typename... As >
      auto execute( const internal::zsv statement, As&&... as )
      {
         send( statement, std::forward< As >( as )... );
         return get_result();
      }

      // finalize
      void commit();
      void rollback();

      // access connection
      auto connection() const noexcept
         -> const std::shared_ptr< pq::connection >&;
   };
}
```

:point_up: Note that `tao::pq::internal::zsv` is explained in the [Statement](Statement.md) chapter.

## Creating Transactions

In taoPQ, you create a top-level transaction from a connection, the methods available to do so are described in the [Connection](Connection.md) chapter.
In short, you create a normal transaction with the connection's `transaction()`-method or a "direct transaction" with the connection's `direct()`-method.
Both return a shared pointer to a `tao::pq::transaction`-derived object.

From any transaction, you can create a subtransaction by calling the `subtransaction()`-method.

```c++
auto tao::pq::transaction::subtransaction()
   -> std::shared_ptr< tao::pq::transaction >;
```

It returns just another `tao::pq::transaction`-derived object from which you may create further, nested subtransactions if needed.

All transactions then offer the above, unified interface.

## Statement Execution

On all transactions you can execute SQL statements.
If you execute a statement on a connection object directly, is creates an implicit direct transaction and forwards the execution to that temporary transaction.
The actual statement execution, i.e. the `execute()`-method, is described in the [Statement](Statement.md) chapter.

## Terminate Transaction

Transaction can be terminated in one of two ways.

### Commit a Transaction

In order to commit a transaction you call the `commit()`-method.

```c++
void tao::pq::transaction::commit();
```

All changes made by the transaction become visible to others and are guaranteed to be durable if a crash occurs.

### Abort a Transaction

In order to abort a transaction you call the `rollback()`-method.

```c++
void tao::pq::transaction::rollback();
```

Rolls back the current transaction and causes all the updates made by the transaction to be discarded.

## Transaction Ordering

Any transactions created via taoPQ is registered in the connection object as the currently active transaction.
At any given time, a connection can only have a single active transaction.
If you attempt to use a transaction object in the wrong order, taoPQ will notice and throw an appropriate `std::logic_error` exception.

:point_up: Note that the correct order depends on the *logical* lifetime of transactions.
The logical lifetime of a transactions ends when you explicitly call either the `commit()`- or the `rollback()`-method, or if the object's lifetime ends.
The destructor will automatically perform a call to the `rollback()`-method if the lifetime was not ended explicitly.
This comes in handy when exceptions are thrown and the destructor call happens due to the associated stack unwinding.

## Direct Transactions

Without an active transaction PostgreSQL works in ["autocommit"➚](https://www.postgresql.org/docs/current/sql-begin.html) mode.
This means that each statement is executed in its own internal transaction and a commit is implicitly performed at the end of the statement (if execution was successful, otherwise a rollback is done).
A "direct transaction" represents this concept in taoPQ.

A direct transaction is special, as the `commit()`- and `rollback()`-methods are available, but normally not needed.
Specifically, you don't need to call the `commit()`-method in order to make the changes you made permanent.
However, calling the `commit()`-method ends the logical lifetime of the transaction and the transaction deregisters itself from the connection.
In generic code you might receive a transaction from somewhere else and you might call the `commit()`-method regardless of whether the underlying transaction is a direct transaction or a normal transaction.

In case you need to know whether a given transaction object is a direct transaction or not, you can call the `is_direct()`-method.

```c++
bool tao::pq::transaction::is_direct() const noexcept;
```

Opening a subtransaction from a direct connection is possible and simply starts a normal transaction on the connection object.

## Manual Transaction Handling

You can manually begin, commit, or rollback transactions by executing [`BEGIN`➚](https://www.postgresql.org/docs/current/sql-begin.html), [`COMMIT`➚](https://www.postgresql.org/docs/current/sql-commit.html), or [`ROLLBACK`➚](https://www.postgresql.org/docs/current/sql-rollback.html) statements directly via the `execute()`-method.
Likewise, you can manually create, commit, or rollback subtransactions by executing [`SAVEPOINT`➚](https://www.postgresql.org/docs/current/sql-savepoint.html), [`RELEASE SAVEPOINT`➚](https://www.postgresql.org/docs/current/sql-release-savepoint.html), or [`ROLLBACK TO SAVEPOINT`➚](https://www.postgresql.org/docs/current/sql-rollback-to.html) statements directly via the `execute()`-method.

:point_up: We strongly advise against manual transaction handling, as it will not be tracked by taoPQ and might confuse our library's transaction ordering framework.
We advise to use the methods offered by taoPQ instead of manually handling transactions.

## Accessing the Connection

If you need to access the connection that a transaction is bound to, you can call the `connection()`-method.

```c++
auto tao::pq::transaction::connection() const noexcept
   -> const std::shared_ptr< tao::pq::connection >&;
```

:point_up: Note that the shared pointer will be empty if the logical lifetime of the transaction ended.

---

This document is part of [taoPQ](https://github.com/taocpp/taopq).

Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch<br>
Distributed under the Boost Software License, Version 1.0<br>
See accompanying file [LICENSE_1_0.txt](../LICENSE_1_0.txt) or copy at https://www.boost.org/LICENSE_1_0.txt


================================================
FILE: example/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)

add_subdirectory(get_version)

set(EXAMPLE_TARGETS
  taopq_example_get_version
)

add_custom_target(examples
  COMMENT "Run all examples"
  DEPENDS ${EXAMPLE_TARGETS}
)

foreach(tgt IN LISTS EXAMPLE_TARGETS)
  add_custom_command(TARGET examples POST_BUILD
    COMMAND "$<TARGET_FILE:${tgt}>"
    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
    COMMENT "Running ${tgt}"
    VERBATIM
  )
endforeach()

================================================
FILE: example/get_version/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)
project(taopq_example_get_version CXX)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE taocpp::taopq)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20 c_std_11)


================================================
FILE: example/get_version/main.cpp
================================================
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <tao/pq.hpp>

static std::string get_env( std::string_view name )
{
#if defined( _MSC_VER )
   std::size_t required = 1024;
   std::vector< char > buffer( required );
   const auto err = ::getenv_s( &required, buffer.data(), buffer.size(), std::string( name ).c_str() );
   if( err != 0 ) {
      return {};
   }
   return std::string( buffer.data() );
#else
   if( const char* v = std::getenv( std::string( name ).c_str() ) ) {
      return std::string( v );
   }
   return {};
#endif
}

int main()
{
   const auto database = get_env( "PGDATABASE" );
   const auto connection = tao::pq::connection::create( database );
   const auto result = connection->execute( "SELECT version()" );
   std::cout << "PostgreSQL version: " << result.as< std::string >() << std::endl;
   return EXIT_SUCCESS;
}


================================================
FILE: include/tao/pq/access_mode.hpp
================================================
// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_ACCESS_MODE_HPP
#define TAO_PQ_ACCESS_MODE_HPP

#include <cstdint>
#include <string_view>

#include <tao/pq/internal/format_as.hpp>

namespace tao::pq
{
   enum class access_mode : std::uint8_t
   {
      default_access_mode,
      read_write,
      read_only
   };

   [[nodiscard]] constexpr auto taopq_format_as( const access_mode am ) noexcept -> std::string_view
   {
      switch( am ) {
         case access_mode::default_access_mode:
            return "default_access_mode";

         case access_mode::read_write:
            return "read_write";

         case access_mode::read_only:
            return "read_only";

         default:
            return "<unknown>";
      }
   }

}  // namespace tao::pq

#endif


================================================
FILE: include/tao/pq/binary.hpp
================================================
// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_BINARY_HPP
#define TAO_PQ_BINARY_HPP

#include <cstddef>
#include <span>
#include <vector>

namespace tao::pq
{
   using binary = std::vector< std::byte >;
   using binary_view = std::span< const std::byte >;

   [[nodiscard]] auto to_binary_view( const auto* data, const std::size_t size ) noexcept -> binary_view
      requires( sizeof( *data ) == 1 )
   {
      return { reinterpret_cast< const std::byte* >( data ), size };
   }

   [[nodiscard]] auto to_binary_view( const auto& value ) noexcept -> binary_view
   {
      return pq::to_binary_view( std::data( value ), std::size( value ) );
   }

   [[nodiscard]] auto to_binary( const auto* data, const std::size_t size ) -> binary
      requires( sizeof( *data ) == 1 )
   {
      const auto* ptr = reinterpret_cast< const std::byte* >( data );
      return { ptr, ptr + size };
   }

   [[nodiscard]] auto to_binary( const auto& value ) -> binary
   {
      return pq::to_binary( std::data( value ), std::size( value ) );
   }

}  // namespace tao::pq

#endif


================================================
FILE: include/tao/pq/bind.hpp
================================================
// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_BIND_HPP
#define TAO_PQ_BIND_HPP

namespace tao::pq
{
   template< typename >
   struct bind;

}  // namespace tao::pq

#endif


================================================
FILE: include/tao/pq/connection.hpp
================================================
// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_CONNECTION_HPP
#define TAO_PQ_CONNECTION_HPP

#include <chrono>
#include <cstddef>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <utility>

#include <libpq-fe.h>

#include <tao/pq/access_mode.hpp>
#include <tao/pq/connection_status.hpp>
#include <tao/pq/internal/poll.hpp>
#include <tao/pq/internal/zsv.hpp>
#include <tao/pq/isolation_level.hpp>
#include <tao/pq/log.hpp>
#include <tao/pq/notification.hpp>
#include <tao/pq/parameter.hpp>
#include <tao/pq/pipeline_status.hpp>
#include <tao/pq/poll.hpp>
#include <tao/pq/transaction.hpp>
#include <tao/pq/transaction_base.hpp>
#include <tao/pq/transaction_status.hpp>

namespace tao::pq
{
   class connection_pool;
   class pipeline;
   class table_reader;
   class table_writer;

   namespace internal
   {
      class top_level_transaction;
      class top_level_subtransaction;
      class nested_subtransaction;

   }  // namespace internal

   class connection final
      : public std::enable_shared_from_this< connection >
   {
   private:
      friend class connection_pool;
      friend class table_reader;
      friend class table_writer;
      friend class transaction;
      friend class transaction_base;

      friend class internal::top_level_transaction;
      friend class internal::top_level_subtransaction;
      friend class internal::nested_subtransaction;

      std::unique_ptr< PGconn, decltype( &PQfinish ) > m_pgconn;
      transaction_base* m_current_transaction;
      std::optional< std::chrono::milliseconds > m_timeout;
      std::set< std::string, std::less<> > m_prepared_statements;
      std::function< poll::callback > m_poll;
      std::function< void( const notification& ) > m_notification_handler;
      std::map< std::string, std::function< void( const char* ) >, std::less<> > m_notification_handlers;
      std::shared_ptr< log > m_log;

      [[nodiscard]] auto escape_identifier( const std::string_view identifier ) const -> std::unique_ptr< char, decltype( &PQfreemem ) >;

      [[nodiscard]] auto attempt_rollback() const noexcept -> bool;

      static void check_prepared_name( const std::string_view name );

      void send_params( const char* statement,
                        const int n_params,
                        const Oid types[],
                        const char* const values[],
                        const int lengths[],
                        const int formats[] );

      [[nodiscard]] auto timeout_end( const std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now() ) const noexcept -> std::chrono::steady_clock::time_point
      {
         return m_timeout ? ( start + *m_timeout ) : start;
      }

      void wait( const bool wait_for_write, const std::chrono::steady_clock::time_point end );
      void cancel();

      [[nodiscard]] auto get_result( const std::chrono::steady_clock::time_point end ) -> std::unique_ptr< PGresult, decltype( &PQclear ) >;
      [[nodiscard]] auto get_fatal_error( const std::chrono::steady_clock::time_point end ) -> std::unique_ptr< PGresult, decltype( &PQclear ) >;
      void consume_empty_result( const std::chrono::steady_clock::time_point end );

      [[nodiscard]] auto get_copy_data( char*& buffer, const std::chrono::steady_clock::time_point end ) -> std::size_t;
      [[nodiscard]] auto get_copy_data( char*& buffer ) -> std::size_t;

      void put_copy_data( const char* buffer, const std::size_t size );
      void put_copy_end( const char* error_message = nullptr );

      void clear_copy_data( const std::chrono::steady_clock::time_point end );

      // pass-key idiom
      class private_key final
      {
         private_key() = default;
         friend class connection;
         friend class connection_pool;
      };

   public:
      connection( const private_key /*unused*/, const std::string& connection_info );

      connection( const connection& ) = delete;
      connection( connection&& ) = delete;
      void operator=( const connection& ) = delete;
      void operator=( connection&& ) = delete;

      ~connection() = default;

      [[nodiscard]] static auto create( const std::string& connection_info ) -> std::shared_ptr< connection >;

      [[nodiscard]] auto error_message() const -> const char*;

      [[nodiscard]] auto poll_callback() const noexcept -> decltype( auto )
      {
         return m_poll;
      }

      void set_poll_callback( std::function< poll::callback > poll_cb ) noexcept
      {
         m_poll = std::move( poll_cb );
      }

      void reset_poll_callback()
      {
         m_poll = internal::poll;
      }

      [[nodiscard]] auto notification_handler() const noexcept -> decltype( auto )
      {
         return m_notification_handler;
      }

      void set_notification_handler( std::function< void( const notification& ) > handler ) noexcept
      {
         m_notification_handler = std::move( handler );
      }

      void reset_notification_handler() noexcept
      {
         m_notification_handler = nullptr;
      }

      [[nodiscard]] auto notification_handler( const std::string_view channel ) const -> std::function< void( const char* payload ) >;

      void set_notification_handler( const std::string_view channel, const std::function< void( const char* payload ) >& handler );

      void reset_notification_handler( const std::string_view channel ) noexcept;

      [[nodiscard]] auto log_handler() const noexcept -> decltype( auto )
      {
         return m_log;
      }

      void set_log_handler( const std::shared_ptr< pq::log >& log ) noexcept
      {
         m_log = log;
      }

      void reset_log_handler() noexcept
      {
         m_log = nullptr;
      }

      [[nodiscard]] auto status() const noexcept -> connection_status;
      [[nodiscard]] auto transaction_status() const noexcept -> pq::transaction_status;

      [[nodiscard]] auto pipeline_status() const noexcept -> pq::pipeline_status;
      void enter_pipeline_mode();
      void exit_pipeline_mode();

      void pipeline_sync();

      [[nodiscard]] auto is_open() const noexcept -> bool
      {
         return status() == connection_status::ok;
      }

      [[nodiscard]] auto is_idle() const noexcept -> bool
      {
         return transaction_status() == transaction_status::idle;
      }

      [[nodiscard]] auto is_busy() const noexcept -> bool;

      [[nodiscard]] auto flush() -> bool;

      void consume_input();

      [[nodiscard]] auto direct() -> std::shared_ptr< pq::transaction >;

      [[nodiscard]] auto transaction() -> std::shared_ptr< pq::transaction >;
      [[nodiscard]] auto transaction( const access_mode am, const isolation_level il = isolation_level::default_isolation_level ) -> std::shared_ptr< pq::transaction >;
      [[nodiscard]] auto transaction( const isolation_level il, const access_mode am = access_mode::default_access_mode ) -> std::shared_ptr< pq::transaction >;

      [[nodiscard]] auto pipeline() -> std::shared_ptr< pq::pipeline >;

      void prepare( std::string name, const internal::zsv statement );
      void deallocate( const std::string_view name );

      template< parameter_type... As >
      auto execute( const internal::zsv statement, As&&... as )
      {
         return direct()->execute( statement, std::forward< As >( as )... );
      }

      void listen( const std::string_view channel );
      void listen( const std::string_view channel, const std::function< void( const char* payload ) >& handler );
      void unlisten( const std::string_view channel );

      void notify( const std::string_view channel );
      void notify( const std::string_view channel, const std::string_view payload );

      void handle_notifications();
      void get_notifications();

      [[nodiscard]] auto socket() const -> int;

      [[nodiscard]] auto timeout() const noexcept -> decltype( auto )
      {
         return m_timeout;
      }

      void set_timeout( const std::chrono::milliseconds timeout ) noexcept
      {
         m_timeout = timeout;
      }

      void reset_timeout() noexcept
      {
         m_timeout = std::nullopt;
      }

      [[nodiscard]] auto password( const internal::zsv passwd, const internal::zsv user, const internal::zsv algorithm = "scram-sha-256" ) -> std::string;

      [[nodiscard]] auto underlying_raw_ptr() noexcept -> PGconn*
      {
         return m_pgconn.get();
      }

      [[nodiscard]] auto underlying_raw_ptr() const noexcept -> const PGconn*
      {
         return m_pgconn.get();
      }
   };

}  // namespace tao::pq

#endif


================================================
FILE: include/tao/pq/connection_pool.hpp
================================================
// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_CONNECTION_POOL_HPP
#define TAO_PQ_CONNECTION_POOL_HPP

#include <chrono>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

#include <tao/pq/connection.hpp>
#include <tao/pq/internal/poll.hpp>
#include <tao/pq/internal/pool.hpp>
#include <tao/pq/internal/zsv.hpp>
#include <tao/pq/parameter.hpp>
#include <tao/pq/poll.hpp>
#include <tao/pq/result.hpp>

namespace tao::pq
{
   class connection_pool
      : public internal::pool< pq::connection >
   {
   private:
      const std::string m_connection_info;
      std::optional< std::chrono::milliseconds > m_timeout;
      std::function< poll::callback > m_poll;

   protected:
      [[nodiscard]] auto v_create() const -> std::unique_ptr< pq::connection > override;

      [[nodiscard]] auto v_is_valid( pq::connection& c ) const noexcept -> bool override
      {
         return c.is_idle();
      }

   private:
      // pass-key idiom
      class private_key final
      {
         private_key() = default;
         friend class connection_pool;
      };

   public:
      connection_pool( const private_key /*unused*/, const std::string_view connection_info );

      void get() const = delete;

      template< typename T = connection_pool >
      [[nodiscard]] static auto create( const std::string_view connection_info ) -> std::shared_ptr< T >
      {
         return std::make_shared< T >( private_key(), connection_info );
      }

      [[nodiscard]] auto timeout() const noexcept -> decltype( auto )
      {
         return m_timeout;
      }

      void set_timeout( const std::chrono::milliseconds timeout ) noexcept
      {
         m_timeout = timeout;
      }

      void reset_timeout() noexcept
      {
         m_timeout = std::nullopt;
      }

      [[nodiscard]] auto poll_callback() const noexcept -> decltype( auto )
      {
         return m_poll;
      }

      void set_poll_callback( std::function< poll::callback > poll_cb ) noexcept
      {
         m_poll = std::move( poll_cb );
      }

      void reset_poll_callback()
      {
         m_poll = internal::poll;
      }

      [[nodiscard]] auto connection() -> std::shared_ptr< pq::connection >;

      template< parameter_type... As >
      auto execute( const internal::zsv statement, As&&... as )
      {
         return connection()->direct()->execute( statement, std::forward< As >( as )... );
      }
   };

}  // namespace tao::pq

#endif


================================================
FILE: include/tao/pq/connection_status.hpp
================================================
// Copyright (c) 2022-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_CONNECTION_STATUS_HPP
#define TAO_PQ_CONNECTION_STATUS_HPP

#include <cstdint>
#include <string_view>

#include <libpq-fe.h>

#include <tao/pq/internal/format_as.hpp>

namespace tao::pq
{
   enum class connection_status : std::uint8_t
   {
      ok = CONNECTION_OK,
      bad = CONNECTION_BAD
   };

   [[nodiscard]] constexpr auto taopq_format_as( const connection_status cs ) noexcept -> std::string_view
   {
      switch( cs ) {
         case connection_status::ok:
            return "ok";

         case connection_status::bad:
            return "bad";

         default:
            return "<unknown>";
      }
   }

}  // namespace tao::pq

#endif


================================================
FILE: include/tao/pq/exception.hpp
================================================
// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)

#ifndef TAO_PQ_EXCEPTION_HPP
#define TAO_PQ_EXCEPTION_HPP

#include <stdexcept>
#include <string>
#include <string_view>

#include <libpq-fe.h>

namespace tao::pq
{
   struct error
      : std::runtime_error
   {
      using std::runtime_error::runtime_error;
   };

   struct timeout_reached
      : error
   {
      using error::error;
   };

   struct network_error
      : error
   {
      using error::error;
   };

   // https://www.postgresql.org/docs/current/errcodes-appendix.html
   struct sql_error
      : error
   {
      std::string sqlstate;

      sql_error( const char* what, const std::string_view in_sqlstate );
   };

   // when a condition name from PostgreSQL is ambiguous,
   // we qualify the error class via a template parameter
   template< typename >
   struct string_data_right_truncation;

   template< typename >
   struct modifying_sql_data_not_permitted;

   template< typename >
   struct prohibited_sql_statement_attempted;

   template< typename >
   struct reading_sql_data_not_permitted;

   struct success  // 00xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct warning  // 01xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct null_value_eliminated_in_set_function  // 01003
      : warning
   {
      using warning::warning;
   };

   template<>
   struct string_data_right_truncation< warning >  // 01004
      : warning
   {
      using warning::warning;
   };

   struct privilege_not_revoked  // 01006
      : warning
   {
      using warning::warning;
   };

   struct privilege_not_granted  // 01007
      : warning
   {
      using warning::warning;
   };

   struct implicit_zero_bit_padding  // 01008
      : warning
   {
      using warning::warning;
   };

   struct dynamic_result_sets_returned  // 0100C
      : warning
   {
      using warning::warning;
   };

   struct deprecated_feature  // 01P01
      : warning
   {
      using warning::warning;
   };

   struct no_data  // 02xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct no_additional_dynamic_result_sets_returned  // 02001
      : no_data
   {
      using no_data::no_data;
   };

   struct sql_statement_not_yet_complete  // 03xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct connection_error  // 08xxx
      : sql_error
   {
      using sql_error::sql_error;

      explicit connection_error( const char* what );
   };

   struct sqlclient_unable_to_establish_sqlconnection  // 08001
      : connection_error
   {
      using connection_error::connection_error;
   };

   struct connection_does_not_exist  // 08003
      : connection_error
   {
      using connection_error::connection_error;
   };

   struct sqlserver_rejected_establishment_of_sqlconnection  // 08004
      : connection_error
   {
      using connection_error::connection_error;
   };

   struct connection_failure  // 08006
      : connection_error
   {
      using connection_error::connection_error;
   };

   struct transaction_resolution_unknown  // 08007
      : connection_error
   {
      using connection_error::connection_error;
   };

   struct protocol_violation  // 08P01
      : connection_error
   {
      using connection_error::connection_error;
   };

   struct triggered_action_exception  // 09xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct feature_not_supported  // 0Axxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_transaction_initiation  // 0Bxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct locator_exception  // 0Fxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_locator_specification  // 0F001
      : locator_exception
   {
      using locator_exception::locator_exception;
   };

   struct invalid_grantor  // 0Lxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_grant_operation  // 0LP01
      : invalid_grantor
   {
      using invalid_grantor::invalid_grantor;
   };

   struct invalid_role_specification  // 0Pxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct diagnostics_exception  // 0Zxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct stacked_diagnostics_accessed_without_active_handler  // 0Z002
      : diagnostics_exception
   {
      using diagnostics_exception::diagnostics_exception;
   };

   struct case_not_found  // 20xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct cardinality_violation  // 21xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct data_exception  // 22xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct array_subscript_error  // 2202E
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct character_not_in_repertoire  // 22021
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct datetime_field_overflow  // 22008
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct division_by_zero  // 22012
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct error_in_assignment  // 22005
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct escape_character_conflict  // 2200B
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct indicator_overflow  // 22022
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct interval_field_overflow  // 22015
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_argument_for_logarithm  // 2201E
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_argument_for_ntile_function  // 22014
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_argument_for_nth_value_function  // 22016
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_argument_for_power_function  // 2201F
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_argument_for_width_bucket_function  // 2201G
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_character_value_for_cast  // 22018
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_datetime_format  // 22007
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_escape_character  // 22019
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_escape_octet  // 2200D
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_escape_sequence  // 22025
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct nonstandard_use_of_escape_character  // 22P06
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_indicator_parameter_value  // 22010
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_parameter_value  // 22023
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_preceding_or_following_size  // 22013
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_regular_expression  // 2201B
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_row_count_in_limit_clause  // 2201W
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_row_count_in_result_offset_clause  // 2201X
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_tablesample_argument  // 2202H
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_tablesample_repeat  // 2202G
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_time_zone_displacement_value  // 22009
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_use_of_escape_character  // 2200C
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct most_specific_type_mismatch  // 2200G
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct null_value_not_allowed  // 22004
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct null_value_no_indicator_parameter  // 22002
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct numeric_value_out_of_range  // 22003
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct sequence_generator_limit_exceeded  // 2200H
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct string_data_length_mismatch  // 22026
      : data_exception
   {
      using data_exception::data_exception;
   };

   template<>
   struct string_data_right_truncation< data_exception >  // 22001
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct substring_error  // 22011
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct trim_error  // 22027
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct unterminated_c_string  // 22024
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct zero_length_character_string  // 2200F
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct floating_point_exception  // 22P01
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_text_representation  // 22P02
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_binary_representation  // 22P03
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct bad_copy_file_format  // 22P04
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct untranslatable_character  // 22P05
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct not_an_xml_document  // 2200L
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_xml_document  // 2200M
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_xml_content  // 2200N
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_xml_comment  // 2200S
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_xml_processing_instruction  // 2200T
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct duplicate_json_object_key_value  // 22030
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_argument_for_sql_json_datetime_function  // 22031
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_json_text  // 22032
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct invalid_sql_json_subscript  // 22033
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct more_than_one_sql_json_item  // 22034
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct no_sql_json_item  // 22035
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct non_numeric_sql_json_item  // 22036
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct non_unique_keys_in_a_json_object  // 22037
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct singleton_sql_json_item_required  // 22038
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct sql_json_array_not_found  // 22039
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct sql_json_member_not_found  // 2203A
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct sql_json_number_not_found  // 2203B
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct sql_json_object_not_found  // 2203C
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct too_many_json_array_elements  // 2203D
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct too_many_json_object_members  // 2203E
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct sql_json_scalar_required  // 2203F
      : data_exception
   {
      using data_exception::data_exception;
   };

   struct integrity_constraint_violation  // 23xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct restrict_violation  // 23001
      : integrity_constraint_violation
   {
      using integrity_constraint_violation::integrity_constraint_violation;
   };

   struct not_null_violation  // 23502
      : integrity_constraint_violation
   {
      using integrity_constraint_violation::integrity_constraint_violation;
   };

   struct foreign_key_violation  // 23503
      : integrity_constraint_violation
   {
      using integrity_constraint_violation::integrity_constraint_violation;
   };

   struct unique_violation  // 23505
      : integrity_constraint_violation
   {
      using integrity_constraint_violation::integrity_constraint_violation;
   };

   struct check_violation  // 23514
      : integrity_constraint_violation
   {
      using integrity_constraint_violation::integrity_constraint_violation;
   };

   struct exclusion_violation  // 23P01
      : integrity_constraint_violation
   {
      using integrity_constraint_violation::integrity_constraint_violation;
   };

   struct invalid_cursor_state  // 24xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_transaction_state  // 25xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct active_sql_transaction  // 25001
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct branch_transaction_already_active  // 25002
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct held_cursor_requires_same_isolation_level  // 25008
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct inappropriate_access_mode_for_branch_transaction  // 25003
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct inappropriate_isolation_level_for_branch_transaction  // 25004
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct no_active_sql_transaction_for_branch_transaction  // 25005
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct read_only_sql_transaction  // 25006
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct schema_and_data_statement_mixing_not_supported  // 25007
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct no_active_sql_transaction  // 25P01
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct in_failed_sql_transaction  // 25P02
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct idle_in_transaction_session_timeout  // 25P03
      : invalid_transaction_state
   {
      using invalid_transaction_state::invalid_transaction_state;
   };

   struct invalid_sql_statement_name  // 26xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct triggered_data_change_violation  // 27xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_authorization_specification  // 28xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_password  // 28P01
      : invalid_authorization_specification
   {
      using invalid_authorization_specification::invalid_authorization_specification;
   };

   struct dependent_privilege_descriptors_still_exist  // 2Bxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct dependent_objects_still_exist  // 2BP01
      : dependent_privilege_descriptors_still_exist
   {
      using dependent_privilege_descriptors_still_exist::dependent_privilege_descriptors_still_exist;
   };

   struct invalid_transaction_termination  // 2Dxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct sql_routine_exception  // 2Fxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   template<>
   struct modifying_sql_data_not_permitted< sql_routine_exception >  // 2F002
      : sql_routine_exception
   {
      using sql_routine_exception::sql_routine_exception;
   };

   template<>
   struct prohibited_sql_statement_attempted< sql_routine_exception >  // 2F003
      : sql_routine_exception
   {
      using sql_routine_exception::sql_routine_exception;
   };

   template<>
   struct reading_sql_data_not_permitted< sql_routine_exception >  // 2F004
      : sql_routine_exception
   {
      using sql_routine_exception::sql_routine_exception;
   };

   struct function_executed_no_return_statement  // 2F005
      : sql_routine_exception
   {
      using sql_routine_exception::sql_routine_exception;
   };

   struct invalid_cursor_name  // 34xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct external_routine_exception  // 38xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct containing_sql_not_permitted  // 38001
      : external_routine_exception
   {
      using external_routine_exception::external_routine_exception;
   };

   template<>
   struct modifying_sql_data_not_permitted< external_routine_exception >  // 38002
      : external_routine_exception
   {
      using external_routine_exception::external_routine_exception;
   };

   template<>
   struct prohibited_sql_statement_attempted< external_routine_exception >  // 38003
      : external_routine_exception
   {
      using external_routine_exception::external_routine_exception;
   };

   template<>
   struct reading_sql_data_not_permitted< external_routine_exception >  // 38004
      : external_routine_exception
   {
      using external_routine_exception::external_routine_exception;
   };

   struct external_routine_invocation_exception  // 39xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_sqlstate_returned  // 39001
      : external_routine_invocation_exception
   {
      using external_routine_invocation_exception::external_routine_invocation_exception;
   };

   struct external_null_value_not_allowed  // 39004
      : external_routine_invocation_exception
   {
      using external_routine_invocation_exception::external_routine_invocation_exception;
   };

   struct trigger_protocol_violated  // 39P01
      : external_routine_invocation_exception
   {
      using external_routine_invocation_exception::external_routine_invocation_exception;
   };

   struct srf_protocol_violated  // 39P02
      : external_routine_invocation_exception
   {
      using external_routine_invocation_exception::external_routine_invocation_exception;
   };

   struct event_trigger_protocol_violated  // 39P03
      : external_routine_invocation_exception
   {
      using external_routine_invocation_exception::external_routine_invocation_exception;
   };

   struct savepoint_exception  // 3Bxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_savepoint_specification  // 3B001
      : savepoint_exception
   {
      using savepoint_exception::savepoint_exception;
   };

   struct invalid_catalog_name  // 3Dxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct invalid_schema_name  // 3Fxxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct transaction_rollback  // 40xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct serialization_failure  // 40001
      : transaction_rollback
   {
      using transaction_rollback::transaction_rollback;
   };

   struct transaction_integrity_constraint_violation  // 40002
      : transaction_rollback
   {
      using transaction_rollback::transaction_rollback;
   };

   struct statement_completion_unknown  // 40003
      : transaction_rollback
   {
      using transaction_rollback::transaction_rollback;
   };

   struct deadlock_detected  // 40P01
      : transaction_rollback
   {
      using transaction_rollback::transaction_rollback;
   };

   struct syntax_error_or_access_rule_violation  // 42xxx
      : sql_error
   {
      using sql_error::sql_error;
   };

   struct insufficient_privilege  // 42501
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct syntax_error  // 42601
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct invalid_name  // 42602
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct invalid_column_definition  // 42611
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct name_too_long  // 42622
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct duplicate_column  // 42701
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct ambiguous_column  // 42702
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct undefined_column  // 42703
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct undefined_object  // 42704
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct duplicate_object  // 42710
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct duplicate_alias  // 42712
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct duplicate_function  // 42723
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct ambiguous_function  // 42725
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct grouping_error  // 42803
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct datatype_mismatch  // 42804
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct wrong_object_type  // 42809
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct invalid_foreign_key  // 42830
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct cannot_coerce  // 42846
      : syntax_error_or_access_rule_violation
   {
      using syntax_error_or_access_rule_violation::syntax_error_or_access_rule_violation;
   };

   struct undefined_function  //
Download .txt
gitextract_iares_uf/

├── .clang-format
├── .clang-tidy
├── .github/
│   ├── conan/
│   │   ├── conanfile.py
│   │   └── profiles/
│   │       ├── clangcl
│   │       └── msvc
│   └── workflows/
│       ├── clang-analyze.yml
│       ├── clang-format.yml
│       ├── clang-tidy.yml
│       ├── code-coverage.yml
│       ├── linux.yml
│       ├── macos.yml
│       ├── sanitizer.yml
│       └── windows.yml
├── .gitignore
├── CMakeLists.txt
├── CMakePresets.json
├── LICENSE_1_0.txt
├── Makefile
├── README.md
├── doc/
│   ├── Aggregate-Support.md
│   ├── Binary-Data.md
│   ├── Bulk-Transfer.md
│   ├── Connection-Pool.md
│   ├── Connection.md
│   ├── Error-Handling.md
│   ├── Getting-Started.md
│   ├── Installation.md
│   ├── Large-Object.md
│   ├── Parameter-Type-Conversion.md
│   ├── Performance.md
│   ├── Requirements.md
│   ├── Result-Type-Conversion.md
│   ├── Result.md
│   ├── Statement.md
│   ├── TOC.md
│   └── Transaction.md
├── example/
│   ├── CMakeLists.txt
│   └── get_version/
│       ├── CMakeLists.txt
│       └── main.cpp
├── include/
│   └── tao/
│       ├── pq/
│       │   ├── access_mode.hpp
│       │   ├── binary.hpp
│       │   ├── bind.hpp
│       │   ├── connection.hpp
│       │   ├── connection_pool.hpp
│       │   ├── connection_status.hpp
│       │   ├── exception.hpp
│       │   ├── field.hpp
│       │   ├── internal/
│       │   │   ├── aggregate.hpp
│       │   │   ├── demangle.hpp
│       │   │   ├── exclusive_scan.hpp
│       │   │   ├── format_as.hpp
│       │   │   ├── from_chars.hpp
│       │   │   ├── gen.hpp
│       │   │   ├── parameter_traits_helper.hpp
│       │   │   ├── poll.hpp
│       │   │   ├── pool.hpp
│       │   │   ├── resize_uninitialized.hpp
│       │   │   ├── strtox.hpp
│       │   │   ├── unreachable.hpp
│       │   │   └── zsv.hpp
│       │   ├── is_aggregate.hpp
│       │   ├── is_array.hpp
│       │   ├── isolation_level.hpp
│       │   ├── large_object.hpp
│       │   ├── log.hpp
│       │   ├── notification.hpp
│       │   ├── null.hpp
│       │   ├── oid.hpp
│       │   ├── parameter.hpp
│       │   ├── parameter_traits.hpp
│       │   ├── parameter_traits_aggregate.hpp
│       │   ├── parameter_traits_array.hpp
│       │   ├── parameter_traits_optional.hpp
│       │   ├── parameter_traits_pair.hpp
│       │   ├── parameter_traits_tuple.hpp
│       │   ├── pipeline.hpp
│       │   ├── pipeline_status.hpp
│       │   ├── poll.hpp
│       │   ├── result.hpp
│       │   ├── result_status.hpp
│       │   ├── result_traits.hpp
│       │   ├── result_traits_aggregate.hpp
│       │   ├── result_traits_array.hpp
│       │   ├── result_traits_optional.hpp
│       │   ├── result_traits_pair.hpp
│       │   ├── result_traits_tuple.hpp
│       │   ├── row.hpp
│       │   ├── table_field.hpp
│       │   ├── table_reader.hpp
│       │   ├── table_row.hpp
│       │   ├── table_writer.hpp
│       │   ├── transaction.hpp
│       │   ├── transaction_base.hpp
│       │   ├── transaction_status.hpp
│       │   └── version.hpp
│       └── pq.hpp
├── src/
│   └── lib/
│       └── pq/
│           ├── connection.cpp
│           ├── connection_pool.cpp
│           ├── exception.cpp
│           ├── field.cpp
│           ├── internal/
│           │   ├── demangle.cpp
│           │   ├── poll.cpp
│           │   └── strtox.cpp
│           ├── large_object.cpp
│           ├── parameter_traits.cpp
│           ├── pipeline.cpp
│           ├── result.cpp
│           ├── result_traits.cpp
│           ├── result_traits_array.cpp
│           ├── row.cpp
│           ├── table_field.cpp
│           ├── table_reader.cpp
│           ├── table_row.cpp
│           ├── table_writer.cpp
│           ├── transaction.cpp
│           └── transaction_base.cpp
└── test/
    ├── CMakeLists.txt
    ├── integration/
    │   ├── aggregate.cpp
    │   ├── array.cpp
    │   ├── basic_datatypes.cpp
    │   ├── chunk_mode.cpp
    │   ├── connection.cpp
    │   ├── connection_pool.cpp
    │   ├── example.cpp
    │   ├── exception.cpp
    │   ├── large_object.cpp
    │   ├── log.cpp
    │   ├── notifications.cpp
    │   ├── parameter.cpp
    │   ├── password.cpp
    │   ├── pipeline_mode.cpp
    │   ├── result.cpp
    │   ├── row.cpp
    │   ├── single_row_mode.cpp
    │   ├── table_reader.cpp
    │   ├── table_writer.cpp
    │   ├── traits.cpp
    │   └── transaction.cpp
    ├── unit/
    │   ├── getenv.cpp
    │   ├── parameter_type.cpp
    │   ├── resize_uninitialized.cpp
    │   ├── result_type.cpp
    │   └── strtox.cpp
    └── utils/
        ├── compare.hpp
        ├── getenv.hpp
        └── macros.hpp
Download .txt
SYMBOL INDEX (1002 symbols across 104 files)

FILE: .github/conan/conanfile.py
  class TaopqRequirements (line 4) | class TaopqRequirements(ConanFile):
    method layout (line 17) | def layout(self):
    method requirements (line 20) | def requirements(self):
    method generate (line 23) | def generate(self):

FILE: example/get_version/main.cpp
  function get_env (line 8) | static std::string get_env( std::string_view name )
  function main (line 26) | int main()

FILE: include/tao/pq/access_mode.hpp
  type tao::pq (line 13) | namespace tao::pq
    type access_mode (line 15) | enum class access_mode : std::uint8_t
    function taopq_format_as (line 22) | [[nodiscard]] constexpr auto taopq_format_as( const access_mode am ) n...

FILE: include/tao/pq/binary.hpp
  type tao::pq (line 12) | namespace tao::pq
    function to_binary_view (line 17) | [[nodiscard]] auto to_binary_view( const auto* data, const std::size_t...
    function to_binary_view (line 23) | [[nodiscard]] auto to_binary_view( const auto& value ) noexcept -> bin...
    function to_binary (line 28) | [[nodiscard]] auto to_binary( const auto* data, const std::size_t size...
    function to_binary (line 35) | [[nodiscard]] auto to_binary( const auto& value ) -> binary

FILE: include/tao/pq/bind.hpp
  type tao::pq (line 8) | namespace tao::pq
    type bind (line 11) | struct bind

FILE: include/tao/pq/connection.hpp
  type tao::pq (line 35) | namespace tao::pq
    class connection_pool (line 37) | class connection_pool
    class pipeline (line 38) | class pipeline
    class table_reader (line 39) | class table_reader
    class table_writer (line 40) | class table_writer
    type internal (line 42) | namespace internal
      class top_level_transaction (line 44) | class top_level_transaction
      class top_level_subtransaction (line 45) | class top_level_subtransaction
      class nested_subtransaction (line 46) | class nested_subtransaction
    class connection (line 50) | class connection final
      method timeout_end (line 86) | [[nodiscard]] auto timeout_end( const std::chrono::steady_clock::tim...
      class private_key (line 107) | class private_key final
        method private_key (line 109) | private_key() = default;
      method connection (line 117) | connection( const connection& ) = delete;
      method connection (line 118) | connection( connection&& ) = delete;
      method poll_callback (line 128) | [[nodiscard]] auto poll_callback() const noexcept -> decltype( auto )
      method set_poll_callback (line 133) | void set_poll_callback( std::function< poll::callback > poll_cb ) no...
      method reset_poll_callback (line 138) | void reset_poll_callback()
      method notification_handler (line 143) | [[nodiscard]] auto notification_handler() const noexcept -> decltype...
      method set_notification_handler (line 148) | void set_notification_handler( std::function< void( const notificati...
      method reset_notification_handler (line 153) | void reset_notification_handler() noexcept
      method log_handler (line 164) | [[nodiscard]] auto log_handler() const noexcept -> decltype( auto )
      method set_log_handler (line 169) | void set_log_handler( const std::shared_ptr< pq::log >& log ) noexcept
      method reset_log_handler (line 174) | void reset_log_handler() noexcept
      method is_open (line 188) | [[nodiscard]] auto is_open() const noexcept -> bool
      method is_idle (line 193) | [[nodiscard]] auto is_idle() const noexcept -> bool
      method execute (line 216) | auto execute( const internal::zsv statement, As&&... as )
      method timeout (line 233) | [[nodiscard]] auto timeout() const noexcept -> decltype( auto )
      method set_timeout (line 238) | void set_timeout( const std::chrono::milliseconds timeout ) noexcept
      method reset_timeout (line 243) | void reset_timeout() noexcept
      method underlying_raw_ptr (line 250) | [[nodiscard]] auto underlying_raw_ptr() noexcept -> PGconn*
      method underlying_raw_ptr (line 255) | [[nodiscard]] auto underlying_raw_ptr() const noexcept -> const PGconn*

FILE: include/tao/pq/connection_pool.hpp
  type tao::pq (line 24) | namespace tao::pq
    class connection_pool (line 26) | class connection_pool
      method v_is_valid (line 37) | [[nodiscard]] auto v_is_valid( pq::connection& c ) const noexcept ->...
      class private_key (line 44) | class private_key final
        method private_key (line 46) | private_key() = default;
      method get (line 53) | void get() const = delete;
      method create (line 56) | [[nodiscard]] static auto create( const std::string_view connection_...
      method timeout (line 61) | [[nodiscard]] auto timeout() const noexcept -> decltype( auto )
      method set_timeout (line 66) | void set_timeout( const std::chrono::milliseconds timeout ) noexcept
      method reset_timeout (line 71) | void reset_timeout() noexcept
      method poll_callback (line 76) | [[nodiscard]] auto poll_callback() const noexcept -> decltype( auto )
      method set_poll_callback (line 81) | void set_poll_callback( std::function< poll::callback > poll_cb ) no...
      method reset_poll_callback (line 86) | void reset_poll_callback()
      method execute (line 94) | auto execute( const internal::zsv statement, As&&... as )

FILE: include/tao/pq/connection_status.hpp
  type tao::pq (line 15) | namespace tao::pq
    type connection_status (line 17) | enum class connection_status : std::uint8_t
    function taopq_format_as (line 23) | [[nodiscard]] constexpr auto taopq_format_as( const connection_status ...

FILE: include/tao/pq/exception.hpp
  type tao::pq (line 14) | namespace tao::pq
    type error (line 16) | struct error
    type timeout_reached (line 22) | struct timeout_reached
    type network_error (line 28) | struct network_error
    type sql_error (line 35) | struct sql_error
    type string_data_right_truncation (line 46) | struct string_data_right_truncation
    type modifying_sql_data_not_permitted (line 49) | struct modifying_sql_data_not_permitted
    type prohibited_sql_statement_attempted (line 52) | struct prohibited_sql_statement_attempted
    type reading_sql_data_not_permitted (line 55) | struct reading_sql_data_not_permitted
    type success (line 57) | struct success  // 00xxx
    type warning (line 63) | struct warning  // 01xxx
    type null_value_eliminated_in_set_function (line 69) | struct null_value_eliminated_in_set_function  // 01003
    type string_data_right_truncation< warning > (line 76) | struct string_data_right_truncation< warning >  // 01004
    type privilege_not_revoked (line 82) | struct privilege_not_revoked  // 01006
    type privilege_not_granted (line 88) | struct privilege_not_granted  // 01007
    type implicit_zero_bit_padding (line 94) | struct implicit_zero_bit_padding  // 01008
    type dynamic_result_sets_returned (line 100) | struct dynamic_result_sets_returned  // 0100C
    type deprecated_feature (line 106) | struct deprecated_feature  // 01P01
    type no_data (line 112) | struct no_data  // 02xxx
    type no_additional_dynamic_result_sets_returned (line 118) | struct no_additional_dynamic_result_sets_returned  // 02001
    type sql_statement_not_yet_complete (line 124) | struct sql_statement_not_yet_complete  // 03xxx
    type connection_error (line 130) | struct connection_error  // 08xxx
    type sqlclient_unable_to_establish_sqlconnection (line 138) | struct sqlclient_unable_to_establish_sqlconnection  // 08001
    type connection_does_not_exist (line 144) | struct connection_does_not_exist  // 08003
    type sqlserver_rejected_establishment_of_sqlconnection (line 150) | struct sqlserver_rejected_establishment_of_sqlconnection  // 08004
    type connection_failure (line 156) | struct connection_failure  // 08006
    type transaction_resolution_unknown (line 162) | struct transaction_resolution_unknown  // 08007
    type protocol_violation (line 168) | struct protocol_violation  // 08P01
    type triggered_action_exception (line 174) | struct triggered_action_exception  // 09xxx
    type feature_not_supported (line 180) | struct feature_not_supported  // 0Axxx
    type invalid_transaction_initiation (line 186) | struct invalid_transaction_initiation  // 0Bxxx
    type locator_exception (line 192) | struct locator_exception  // 0Fxxx
    type invalid_locator_specification (line 198) | struct invalid_locator_specification  // 0F001
    type invalid_grantor (line 204) | struct invalid_grantor  // 0Lxxx
    type invalid_grant_operation (line 210) | struct invalid_grant_operation  // 0LP01
    type invalid_role_specification (line 216) | struct invalid_role_specification  // 0Pxxx
    type diagnostics_exception (line 222) | struct diagnostics_exception  // 0Zxxx
    type stacked_diagnostics_accessed_without_active_handler (line 228) | struct stacked_diagnostics_accessed_without_active_handler  // 0Z002
    type case_not_found (line 234) | struct case_not_found  // 20xxx
    type cardinality_violation (line 240) | struct cardinality_violation  // 21xxx
    type data_exception (line 246) | struct data_exception  // 22xxx
    type array_subscript_error (line 252) | struct array_subscript_error  // 2202E
    type character_not_in_repertoire (line 258) | struct character_not_in_repertoire  // 22021
    type datetime_field_overflow (line 264) | struct datetime_field_overflow  // 22008
    type division_by_zero (line 270) | struct division_by_zero  // 22012
    type error_in_assignment (line 276) | struct error_in_assignment  // 22005
    type escape_character_conflict (line 282) | struct escape_character_conflict  // 2200B
    type indicator_overflow (line 288) | struct indicator_overflow  // 22022
    type interval_field_overflow (line 294) | struct interval_field_overflow  // 22015
    type invalid_argument_for_logarithm (line 300) | struct invalid_argument_for_logarithm  // 2201E
    type invalid_argument_for_ntile_function (line 306) | struct invalid_argument_for_ntile_function  // 22014
    type invalid_argument_for_nth_value_function (line 312) | struct invalid_argument_for_nth_value_function  // 22016
    type invalid_argument_for_power_function (line 318) | struct invalid_argument_for_power_function  // 2201F
    type invalid_argument_for_width_bucket_function (line 324) | struct invalid_argument_for_width_bucket_function  // 2201G
    type invalid_character_value_for_cast (line 330) | struct invalid_character_value_for_cast  // 22018
    type invalid_datetime_format (line 336) | struct invalid_datetime_format  // 22007
    type invalid_escape_character (line 342) | struct invalid_escape_character  // 22019
    type invalid_escape_octet (line 348) | struct invalid_escape_octet  // 2200D
    type invalid_escape_sequence (line 354) | struct invalid_escape_sequence  // 22025
    type nonstandard_use_of_escape_character (line 360) | struct nonstandard_use_of_escape_character  // 22P06
    type invalid_indicator_parameter_value (line 366) | struct invalid_indicator_parameter_value  // 22010
    type invalid_parameter_value (line 372) | struct invalid_parameter_value  // 22023
    type invalid_preceding_or_following_size (line 378) | struct invalid_preceding_or_following_size  // 22013
    type invalid_regular_expression (line 384) | struct invalid_regular_expression  // 2201B
    type invalid_row_count_in_limit_clause (line 390) | struct invalid_row_count_in_limit_clause  // 2201W
    type invalid_row_count_in_result_offset_clause (line 396) | struct invalid_row_count_in_result_offset_clause  // 2201X
    type invalid_tablesample_argument (line 402) | struct invalid_tablesample_argument  // 2202H
    type invalid_tablesample_repeat (line 408) | struct invalid_tablesample_repeat  // 2202G
    type invalid_time_zone_displacement_value (line 414) | struct invalid_time_zone_displacement_value  // 22009
    type invalid_use_of_escape_character (line 420) | struct invalid_use_of_escape_character  // 2200C
    type most_specific_type_mismatch (line 426) | struct most_specific_type_mismatch  // 2200G
    type null_value_not_allowed (line 432) | struct null_value_not_allowed  // 22004
    type null_value_no_indicator_parameter (line 438) | struct null_value_no_indicator_parameter  // 22002
    type numeric_value_out_of_range (line 444) | struct numeric_value_out_of_range  // 22003
    type sequence_generator_limit_exceeded (line 450) | struct sequence_generator_limit_exceeded  // 2200H
    type string_data_length_mismatch (line 456) | struct string_data_length_mismatch  // 22026
    type string_data_right_truncation< data_exception > (line 463) | struct string_data_right_truncation< data_exception >  // 22001
    type substring_error (line 469) | struct substring_error  // 22011
    type trim_error (line 475) | struct trim_error  // 22027
    type unterminated_c_string (line 481) | struct unterminated_c_string  // 22024
    type zero_length_character_string (line 487) | struct zero_length_character_string  // 2200F
    type floating_point_exception (line 493) | struct floating_point_exception  // 22P01
    type invalid_text_representation (line 499) | struct invalid_text_representation  // 22P02
    type invalid_binary_representation (line 505) | struct invalid_binary_representation  // 22P03
    type bad_copy_file_format (line 511) | struct bad_copy_file_format  // 22P04
    type untranslatable_character (line 517) | struct untranslatable_character  // 22P05
    type not_an_xml_document (line 523) | struct not_an_xml_document  // 2200L
    type invalid_xml_document (line 529) | struct invalid_xml_document  // 2200M
    type invalid_xml_content (line 535) | struct invalid_xml_content  // 2200N
    type invalid_xml_comment (line 541) | struct invalid_xml_comment  // 2200S
    type invalid_xml_processing_instruction (line 547) | struct invalid_xml_processing_instruction  // 2200T
    type duplicate_json_object_key_value (line 553) | struct duplicate_json_object_key_value  // 22030
    type invalid_argument_for_sql_json_datetime_function (line 559) | struct invalid_argument_for_sql_json_datetime_function  // 22031
    type invalid_json_text (line 565) | struct invalid_json_text  // 22032
    type invalid_sql_json_subscript (line 571) | struct invalid_sql_json_subscript  // 22033
    type more_than_one_sql_json_item (line 577) | struct more_than_one_sql_json_item  // 22034
    type no_sql_json_item (line 583) | struct no_sql_json_item  // 22035
    type non_numeric_sql_json_item (line 589) | struct non_numeric_sql_json_item  // 22036
    type non_unique_keys_in_a_json_object (line 595) | struct non_unique_keys_in_a_json_object  // 22037
    type singleton_sql_json_item_required (line 601) | struct singleton_sql_json_item_required  // 22038
    type sql_json_array_not_found (line 607) | struct sql_json_array_not_found  // 22039
    type sql_json_member_not_found (line 613) | struct sql_json_member_not_found  // 2203A
    type sql_json_number_not_found (line 619) | struct sql_json_number_not_found  // 2203B
    type sql_json_object_not_found (line 625) | struct sql_json_object_not_found  // 2203C
    type too_many_json_array_elements (line 631) | struct too_many_json_array_elements  // 2203D
    type too_many_json_object_members (line 637) | struct too_many_json_object_members  // 2203E
    type sql_json_scalar_required (line 643) | struct sql_json_scalar_required  // 2203F
    type integrity_constraint_violation (line 649) | struct integrity_constraint_violation  // 23xxx
    type restrict_violation (line 655) | struct restrict_violation  // 23001
    type not_null_violation (line 661) | struct not_null_violation  // 23502
    type foreign_key_violation (line 667) | struct foreign_key_violation  // 23503
    type unique_violation (line 673) | struct unique_violation  // 23505
    type check_violation (line 679) | struct check_violation  // 23514
    type exclusion_violation (line 685) | struct exclusion_violation  // 23P01
    type invalid_cursor_state (line 691) | struct invalid_cursor_state  // 24xxx
    type invalid_transaction_state (line 697) | struct invalid_transaction_state  // 25xxx
    type active_sql_transaction (line 703) | struct active_sql_transaction  // 25001
    type branch_transaction_already_active (line 709) | struct branch_transaction_already_active  // 25002
    type held_cursor_requires_same_isolation_level (line 715) | struct held_cursor_requires_same_isolation_level  // 25008
    type inappropriate_access_mode_for_branch_transaction (line 721) | struct inappropriate_access_mode_for_branch_transaction  // 25003
    type inappropriate_isolation_level_for_branch_transaction (line 727) | struct inappropriate_isolation_level_for_branch_transaction  // 25004
    type no_active_sql_transaction_for_branch_transaction (line 733) | struct no_active_sql_transaction_for_branch_transaction  // 25005
    type read_only_sql_transaction (line 739) | struct read_only_sql_transaction  // 25006
    type schema_and_data_statement_mixing_not_supported (line 745) | struct schema_and_data_statement_mixing_not_supported  // 25007
    type no_active_sql_transaction (line 751) | struct no_active_sql_transaction  // 25P01
    type in_failed_sql_transaction (line 757) | struct in_failed_sql_transaction  // 25P02
    type idle_in_transaction_session_timeout (line 763) | struct idle_in_transaction_session_timeout  // 25P03
    type invalid_sql_statement_name (line 769) | struct invalid_sql_statement_name  // 26xxx
    type triggered_data_change_violation (line 775) | struct triggered_data_change_violation  // 27xxx
    type invalid_authorization_specification (line 781) | struct invalid_authorization_specification  // 28xxx
    type invalid_password (line 787) | struct invalid_password  // 28P01
    type dependent_privilege_descriptors_still_exist (line 793) | struct dependent_privilege_descriptors_still_exist  // 2Bxxx
    type dependent_objects_still_exist (line 799) | struct dependent_objects_still_exist  // 2BP01
    type invalid_transaction_termination (line 805) | struct invalid_transaction_termination  // 2Dxxx
    type sql_routine_exception (line 811) | struct sql_routine_exception  // 2Fxxx
    type modifying_sql_data_not_permitted< sql_routine_exception > (line 818) | struct modifying_sql_data_not_permitted< sql_routine_exception >  // 2...
    type prohibited_sql_statement_attempted< sql_routine_exception > (line 825) | struct prohibited_sql_statement_attempted< sql_routine_exception >  //...
    type reading_sql_data_not_permitted< sql_routine_exception > (line 832) | struct reading_sql_data_not_permitted< sql_routine_exception >  // 2F004
    type function_executed_no_return_statement (line 838) | struct function_executed_no_return_statement  // 2F005
    type invalid_cursor_name (line 844) | struct invalid_cursor_name  // 34xxx
    type external_routine_exception (line 850) | struct external_routine_exception  // 38xxx
    type containing_sql_not_permitted (line 856) | struct containing_sql_not_permitted  // 38001
    type modifying_sql_data_not_permitted< external_routine_exception > (line 863) | struct modifying_sql_data_not_permitted< external_routine_exception > ...
    type prohibited_sql_statement_attempted< external_routine_exception > (line 870) | struct prohibited_sql_statement_attempted< external_routine_exception ...
    type reading_sql_data_not_permitted< external_routine_exception > (line 877) | struct reading_sql_data_not_permitted< external_routine_exception >  /...
    type external_routine_invocation_exception (line 883) | struct external_routine_invocation_exception  // 39xxx
    type invalid_sqlstate_returned (line 889) | struct invalid_sqlstate_returned  // 39001
    type external_null_value_not_allowed (line 895) | struct external_null_value_not_allowed  // 39004
    type trigger_protocol_violated (line 901) | struct trigger_protocol_violated  // 39P01
    type srf_protocol_violated (line 907) | struct srf_protocol_violated  // 39P02
    type event_trigger_protocol_violated (line 913) | struct event_trigger_protocol_violated  // 39P03
    type savepoint_exception (line 919) | struct savepoint_exception  // 3Bxxx
    type invalid_savepoint_specification (line 925) | struct invalid_savepoint_specification  // 3B001
    type invalid_catalog_name (line 931) | struct invalid_catalog_name  // 3Dxxx
    type invalid_schema_name (line 937) | struct invalid_schema_name  // 3Fxxx
    type transaction_rollback (line 943) | struct transaction_rollback  // 40xxx
    type serialization_failure (line 949) | struct serialization_failure  // 40001
    type transaction_integrity_constraint_violation (line 955) | struct transaction_integrity_constraint_violation  // 40002
    type statement_completion_unknown (line 961) | struct statement_completion_unknown  // 40003
    type deadlock_detected (line 967) | struct deadlock_detected  // 40P01
    type syntax_error_or_access_rule_violation (line 973) | struct syntax_error_or_access_rule_violation  // 42xxx
    type insufficient_privilege (line 979) | struct insufficient_privilege  // 42501
    type syntax_error (line 985) | struct syntax_error  // 42601
    type invalid_name (line 991) | struct invalid_name  // 42602
    type invalid_column_definition (line 997) | struct invalid_column_definition  // 42611
    type name_too_long (line 1003) | struct name_too_long  // 42622
    type duplicate_column (line 1009) | struct duplicate_column  // 42701
    type ambiguous_column (line 1015) | struct ambiguous_column  // 42702
    type undefined_column (line 1021) | struct undefined_column  // 42703
    type undefined_object (line 1027) | struct undefined_object  // 42704
    type duplicate_object (line 1033) | struct duplicate_object  // 42710
    type duplicate_alias (line 1039) | struct duplicate_alias  // 42712
    type duplicate_function (line 1045) | struct duplicate_function  // 42723
    type ambiguous_function (line 1051) | struct ambiguous_function  // 42725
    type grouping_error (line 1057) | struct grouping_error  // 42803
    type datatype_mismatch (line 1063) | struct datatype_mismatch  // 42804
    type wrong_object_type (line 1069) | struct wrong_object_type  // 42809
    type invalid_foreign_key (line 1075) | struct invalid_foreign_key  // 42830
    type cannot_coerce (line 1081) | struct cannot_coerce  // 42846
    type undefined_function (line 1087) | struct undefined_function  // 42883
    type generated_always (line 1093) | struct generated_always  // 428C9
    type reserved_name (line 1099) | struct reserved_name  // 42939
    type undefined_table (line 1105) | struct undefined_table  // 42P01
    type undefined_parameter (line 1111) | struct undefined_parameter  // 42P02
    type duplicate_cursor (line 1117) | struct duplicate_cursor  // 42P03
    type duplicate_database (line 1123) | struct duplicate_database  // 42P04
    type duplicate_prepared_statement (line 1129) | struct duplicate_prepared_statement  // 42P05
    type duplicate_schema (line 1135) | struct duplicate_schema  // 42P06
    type duplicate_table (line 1141) | struct duplicate_table  // 42P07
    type ambiguous_parameter (line 1147) | struct ambiguous_parameter  // 42P08
    type ambiguous_alias (line 1153) | struct ambiguous_alias  // 42P09
    type invalid_column_reference (line 1159) | struct invalid_column_reference  // 42P10
    type invalid_cursor_definition (line 1165) | struct invalid_cursor_definition  // 42P11
    type invalid_database_definition (line 1171) | struct invalid_database_definition  // 42P12
    type invalid_function_definition (line 1177) | struct invalid_function_definition  // 42P13
    type invalid_prepared_statement_definition (line 1183) | struct invalid_prepared_statement_definition  // 42P14
    type invalid_schema_definition (line 1189) | struct invalid_schema_definition  // 42P15
    type invalid_table_definition (line 1195) | struct invalid_table_definition  // 42P16
    type invalid_object_definition (line 1201) | struct invalid_object_definition  // 42P17
    type indeterminate_datatype (line 1207) | struct indeterminate_datatype  // 42P18
    type invalid_recursion (line 1213) | struct invalid_recursion  // 42P19
    type windowing_error (line 1219) | struct windowing_error  // 42P20
    type collation_mismatch (line 1225) | struct collation_mismatch  // 42P21
    type indeterminate_collation (line 1231) | struct indeterminate_collation  // 42P22
    type with_check_option_violation (line 1237) | struct with_check_option_violation  // 44xxx
    type insufficient_resources (line 1243) | struct insufficient_resources  // 53xxx
    type disk_full (line 1249) | struct disk_full  // 53100
    type out_of_memory (line 1255) | struct out_of_memory  // 53200
    type too_many_connections (line 1261) | struct too_many_connections  // 53300
    type configuration_limit_exceeded (line 1267) | struct configuration_limit_exceeded  // 53400
    type program_limit_exceeded (line 1273) | struct program_limit_exceeded  // 54xxx
    type statement_too_complex (line 1279) | struct statement_too_complex  // 54001
    type too_many_columns (line 1285) | struct too_many_columns  // 54011
    type too_many_arguments (line 1291) | struct too_many_arguments  // 54023
    type object_not_in_prerequisite_state (line 1297) | struct object_not_in_prerequisite_state  // 55xxx
    type object_in_use (line 1303) | struct object_in_use  // 55006
    type cant_change_runtime_param (line 1309) | struct cant_change_runtime_param  // 55P02
    type lock_not_available (line 1315) | struct lock_not_available  // 55P03
    type unsafe_new_enum_value_usage (line 1321) | struct unsafe_new_enum_value_usage  // 55P04
    type operator_intervention (line 1327) | struct operator_intervention  // 57xxx
    type query_canceled (line 1333) | struct query_canceled  // 57014
    type admin_shutdown (line 1339) | struct admin_shutdown  // 57P01
    type crash_shutdown (line 1345) | struct crash_shutdown  // 57P02
    type cannot_connect_now (line 1351) | struct cannot_connect_now  // 57P03
    type database_dropped (line 1357) | struct database_dropped  // 57P04
    type system_error (line 1363) | struct system_error  // 58xxx
    type io_error (line 1369) | struct io_error  // 58030
    type undefined_file (line 1375) | struct undefined_file  // 58P01
    type duplicate_file (line 1381) | struct duplicate_file  // 58P02
    type snapshot_too_old (line 1387) | struct snapshot_too_old  // 72xxx
    type config_file_error (line 1393) | struct config_file_error  // F0xxx
    type lock_file_exists (line 1399) | struct lock_file_exists  // F0001
    type fdw_error (line 1405) | struct fdw_error  // HVxxx
    type fdw_out_of_memory (line 1411) | struct fdw_out_of_memory  // HV001
    type fdw_dynamic_parameter_value_needed (line 1417) | struct fdw_dynamic_parameter_value_needed  // HV002
    type fdw_invalid_data_type (line 1423) | struct fdw_invalid_data_type  // HV004
    type fdw_column_name_not_found (line 1429) | struct fdw_column_name_not_found  // HV005
    type fdw_invalid_data_type_descriptors (line 1435) | struct fdw_invalid_data_type_descriptors  // HV006
    type fdw_invalid_column_name (line 1441) | struct fdw_invalid_column_name  // HV007
    type fdw_invalid_column_number (line 1447) | struct fdw_invalid_column_number  // HV008
    type fdw_invalid_use_of_null_pointer (line 1453) | struct fdw_invalid_use_of_null_pointer  // HV009
    type fdw_invalid_string_format (line 1459) | struct fdw_invalid_string_format  // HV00A
    type fdw_invalid_handle (line 1465) | struct fdw_invalid_handle  // HV00B
    type fdw_invalid_option_index (line 1471) | struct fdw_invalid_option_index  // HV00C
    type fdw_invalid_option_name (line 1477) | struct fdw_invalid_option_name  // HV00D
    type fdw_option_name_not_found (line 1483) | struct fdw_option_name_not_found  // HV00J
    type fdw_reply_handle (line 1489) | struct fdw_reply_handle  // HV00K
    type fdw_unable_to_create_execution (line 1495) | struct fdw_unable_to_create_execution  // HV00L
    type fdw_unable_to_create_reply (line 1501) | struct fdw_unable_to_create_reply  // HV00M
    type fdw_unable_to_establish_connection (line 1507) | struct fdw_unable_to_establish_connection  // HV00N
    type fdw_no_schemas (line 1513) | struct fdw_no_schemas  // HV00P
    type fdw_schema_not_found (line 1519) | struct fdw_schema_not_found  // HV00Q
    type fdw_table_not_found (line 1525) | struct fdw_table_not_found  // HV00R
    type fdw_function_sequence_error (line 1531) | struct fdw_function_sequence_error  // HV010
    type fdw_too_many_handles (line 1537) | struct fdw_too_many_handles  // HV014
    type fdw_inconsistent_descriptor_information (line 1543) | struct fdw_inconsistent_descriptor_information  // HV021
    type fdw_invalid_attribute_value (line 1549) | struct fdw_invalid_attribute_value  // HV024
    type fdw_invalid_string_length_or_buffer_length (line 1555) | struct fdw_invalid_string_length_or_buffer_length  // HV090
    type fdw_invalid_descriptor_field_identifier (line 1561) | struct fdw_invalid_descriptor_field_identifier  // HV091
    type plpgsql_error (line 1567) | struct plpgsql_error  // P0xxx
    type raise_exception (line 1573) | struct raise_exception  // P0001
    type no_data_found (line 1579) | struct no_data_found  // P0002
    type too_many_rows (line 1585) | struct too_many_rows  // P0003
    type assert_failure (line 1591) | struct assert_failure  // P0004
    type internal_error (line 1597) | struct internal_error  // XXxxx
    type data_corrupted (line 1603) | struct data_corrupted  // XX001
    type index_corrupted (line 1609) | struct index_corrupted  // XX002
    type internal (line 1615) | namespace internal

FILE: include/tao/pq/field.hpp
  type tao::pq (line 16) | namespace tao::pq
    class row (line 18) | class row
    class field (line 20) | class field
      method field (line 28) | field() = default;
      method field (line 30) | field( const row& row, const std::size_t column ) noexcept
      method optional (line 48) | [[nodiscard]] auto optional() const
      method swap (line 58) | void swap( field& lhs, field& rhs ) noexcept

FILE: include/tao/pq/internal/aggregate.hpp
  type tao::pq::internal (line 16) | namespace tao::pq::internal
    function tie_aggregate (line 25) | constexpr auto tie_aggregate( const T& value ) noexcept
    type convert_to_any (line 35) | struct convert_to_any
    function tie_aggregate (line 91) | constexpr auto tie_aggregate( const T& value ) noexcept

FILE: include/tao/pq/internal/demangle.hpp
  type tao::pq::internal (line 11) | namespace tao::pq::internal
    function demangle (line 15) | [[nodiscard]] inline auto demangle( const std::type_info& type_info )
    function demangle (line 21) | [[nodiscard]] auto demangle()

FILE: include/tao/pq/internal/exclusive_scan.hpp
  type tao::pq::internal (line 11) | namespace tao::pq::internal
    type exclusive_scan (line 14) | struct exclusive_scan
  type exclusive_scan< std::integer_sequence< T, Ns... >, std::index_sequence< Is... > > (line 17) | struct exclusive_scan< std::integer_sequence< T, Ns... >, std::index_seq...

FILE: include/tao/pq/internal/format_as.hpp
  type std::formatter< T > (line 14) | struct std::formatter< T > : std::formatter< decltype( taopq_format_as( ...
    method format (line 16) | auto format( const T& v, auto& ctx ) const

FILE: include/tao/pq/internal/from_chars.hpp
  type tao::pq::internal (line 17) | namespace tao::pq::internal
    function from_chars (line 20) | [[nodiscard]] auto from_chars( const std::string_view value ) -> T

FILE: include/tao/pq/internal/gen.hpp
  type tao::pq::internal (line 13) | namespace tao::pq::internal
    type make (line 16) | struct make
  type make< std::index_sequence< Is... >,
                std::index_sequence< Js... >,
                std::index_sequence< Ns... > > (line 21) | struct make< std::index_sequence< Is... >,

FILE: include/tao/pq/internal/parameter_traits_helper.hpp
  type tao::pq::internal (line 16) | namespace tao::pq::internal
    type char_pointer_helper (line 18) | struct char_pointer_helper
      method char_pointer_helper (line 24) | explicit char_pointer_helper( const char* p ) noexcept
      method type (line 32) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 38) | [[nodiscard]] constexpr auto value() const noexcept -> const char*
      method length (line 44) | [[nodiscard]] static constexpr auto length() noexcept -> int
      method format (line 50) | [[nodiscard]] static constexpr auto format() noexcept -> int
    type buffer_helper (line 57) | struct buffer_helper
      method type (line 67) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 73) | [[nodiscard]] auto value() const noexcept -> const char*
      method length (line 79) | [[nodiscard]] static constexpr auto length() noexcept -> int
      method format (line 85) | [[nodiscard]] static constexpr auto format() noexcept -> int
      method element (line 91) | void element( std::string& data ) const
      method copy_to (line 97) | void copy_to( std::string& data ) const
    type to_chars_helper (line 104) | struct to_chars_helper
      method to_chars_helper (line 107) | explicit to_chars_helper( const auto v ) noexcept

FILE: include/tao/pq/internal/poll.hpp
  type tao::pq::internal (line 10) | namespace tao::pq::internal

FILE: include/tao/pq/internal/pool.hpp
  type tao::pq::internal (line 16) | namespace tao::pq::internal
    class pool (line 19) | class pool
      type deleter (line 27) | struct deleter final
        method deleter (line 31) | deleter() = default;
        method deleter (line 33) | explicit deleter( std::weak_ptr< pool >&& p ) noexcept
      method pool (line 48) | pool() = default;
      method push (line 55) | void push( std::unique_ptr< T >& up ) noexcept
      method pull (line 65) | [[nodiscard]] auto pull() noexcept
      method pool (line 77) | pool( const pool& ) = delete;
      method pool (line 78) | pool( pool&& ) = delete;
      method attach (line 82) | static void attach( const std::shared_ptr< T >& sp, std::weak_ptr< p...
      method detach (line 95) | static void detach( const std::shared_ptr< T >& sp ) noexcept
      method create (line 106) | [[nodiscard]] auto create() -> std::shared_ptr< T >
      method get (line 114) | [[nodiscard]] auto get() -> std::shared_ptr< T >
      method empty (line 128) | [[nodiscard]] auto empty() const noexcept -> bool
      method size (line 134) | [[nodiscard]] auto size() const noexcept -> std::size_t
      method attached (line 140) | [[nodiscard]] auto attached() const noexcept -> std::size_t
      method erase_invalid (line 145) | void erase_invalid()

FILE: include/tao/pq/internal/resize_uninitialized.hpp
  type tao::pq::internal (line 12) | namespace tao::pq::internal
    type odr_helper (line 19) | struct odr_helper
    type string_proxy (line 27) | struct string_proxy
      method resize_uninitialized_proxy (line 30) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 46) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 59) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 73) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type string_proxy< std::string, &std::string::__set_size > (line 39) | struct string_proxy< std::string, &std::string::__set_size >
    type string_proxy (line 44) | struct string_proxy
      method resize_uninitialized_proxy (line 30) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 46) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 59) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 73) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type string_proxy< std::string, &std::string::_M_set_length > (line 52) | struct string_proxy< std::string, &std::string::_M_set_length >
    type string_proxy (line 57) | struct string_proxy
      method resize_uninitialized_proxy (line 30) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 46) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 59) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 73) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type string_proxy< std::string, &std::string::_M_rep > (line 66) | struct string_proxy< std::string, &std::string::_M_rep >
    type string_proxy (line 71) | struct string_proxy
      method resize_uninitialized_proxy (line 30) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 46) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 59) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 73) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type string_proxy< std::string, &std::string::_Eos > (line 79) | struct string_proxy< std::string, &std::string::_Eos >
    type vector_proxy (line 90) | struct vector_proxy
      method resize_uninitialized_proxy (line 92) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 115) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 134) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type vector_proxy< std::vector< std::byte >, &std::vector< std::byte >::__end_ > (line 106) | struct vector_proxy< std::vector< std::byte >, &std::vector< std::byte...
    type vector_proxy (line 113) | struct vector_proxy
      method resize_uninitialized_proxy (line 92) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 115) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 134) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type vector_proxy (line 132) | struct vector_proxy
      method resize_uninitialized_proxy (line 92) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 115) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
      method resize_uninitialized_proxy (line 134) | void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept
    type no_init_byte (line 150) | struct no_init_byte
      method no_init_byte (line 153) | no_init_byte() noexcept {}
    function resize_uninitialized_proxy (line 159) | inline void resize_uninitialized_proxy( std::vector< std::byte >& v, c...
    function resize_uninitialized (line 170) | void resize_uninitialized( std::string& v, const std::size_t n )
    function resize_uninitialized (line 184) | void resize_uninitialized( std::vector< std::byte >& v, const std::siz...
  type vector_proxy< std::vector< std::byte >,
                                    std::vector< std::byte >::_Base,
                                    &std::vector< std::byte >::_M_impl,
                                    &decltype( std::declval< std::vector< std::byte > >()._M_impl )::_M_finish > (line 122) | struct vector_proxy< std::vector< std::byte >,
  type vector_proxy< std::vector< std::byte >,
                                    &std::vector< std::byte >::_Mypair,
                                    &decltype( std::declval< std::vector< std::byte > >()._Mypair )::_Myval2,
                                    &decltype( std::declval< std::vector< std::byte > >()._Mypair._Myval2 )::_Mylast > (line 141) | struct vector_proxy< std::vector< std::byte >,

FILE: include/tao/pq/internal/strtox.hpp
  type tao::pq::internal (line 8) | namespace tao::pq::internal

FILE: include/tao/pq/internal/zsv.hpp
  type tao::pq::internal (line 12) | namespace tao::pq::internal
    type zsv (line 15) | struct zsv
      method zsv (line 19) | zsv( std::nullptr_t ) = delete;
      method zsv (line 21) | constexpr zsv( const char* v ) noexcept
      method zsv (line 25) | zsv( const std::string& v ) noexcept

FILE: include/tao/pq/is_aggregate.hpp
  type tao::pq (line 8) | namespace tao::pq

FILE: include/tao/pq/is_array.hpp
  type tao::pq (line 17) | namespace tao::pq
    type internal (line 19) | namespace internal
    type internal (line 44) | namespace internal
    type internal (line 66) | namespace internal

FILE: include/tao/pq/isolation_level.hpp
  type tao::pq (line 13) | namespace tao::pq
    type isolation_level (line 15) | enum class isolation_level : std::uint8_t
    function taopq_format_as (line 24) | [[nodiscard]] constexpr auto taopq_format_as( const isolation_level il...

FILE: include/tao/pq/large_object.hpp
  type tao::pq (line 18) | namespace tao::pq
    class transaction (line 20) | class transaction
    class large_object (line 22) | class large_object final
      method large_object (line 38) | large_object( const large_object& ) = delete;
      method read (line 51) | [[nodiscard]] auto read( std::byte* data, const std::size_t size ) -...
      method write (line 56) | void write( const std::byte* data, const std::size_t size )
      method write (line 64) | void write( const char* data )
      method write (line 70) | void write( Ts&&... ts )

FILE: include/tao/pq/log.hpp
  type tao::pq (line 15) | namespace tao::pq
    class connection (line 17) | class connection
    class transaction (line 18) | class transaction
    type log (line 20) | struct log
      type connection_pool_t (line 22) | struct connection_pool_t
      type connection_t (line 28) | struct connection_t
      type transaction_t (line 122) | struct transaction_t

FILE: include/tao/pq/notification.hpp
  type tao::pq (line 13) | namespace tao::pq
    class connection (line 15) | class connection
    class notification (line 17) | class notification final
      method notification (line 24) | explicit notification( PGnotify* notify ) noexcept
      method channel (line 31) | [[nodiscard]] auto channel() const noexcept -> const char*
      method payload (line 36) | [[nodiscard]] auto payload() const noexcept -> const char*
      method underlying_raw_ptr (line 41) | [[nodiscard]] auto underlying_raw_ptr() noexcept -> PGnotify*
      method underlying_raw_ptr (line 46) | [[nodiscard]] auto underlying_raw_ptr() const noexcept -> const PGno...

FILE: include/tao/pq/null.hpp
  type tao::pq (line 8) | namespace tao::pq
    type null_t (line 10) | struct null_t final
      method null_t (line 12) | explicit constexpr null_t( int /*unused*/ ) {}

FILE: include/tao/pq/oid.hpp
  type tao::pq (line 10) | namespace tao::pq
    type oid (line 14) | enum class oid : Oid  // NOLINT(performance-enum-size)

FILE: include/tao/pq/parameter.hpp
  type tao::pq (line 18) | namespace tao::pq
    class transaction (line 20) | class transaction
    class parameter (line 23) | class parameter
      type vbase (line 54) | struct vbase
        method vbase (line 56) | vbase() noexcept = default;
        method vbase (line 59) | vbase( const vbase& ) = delete;
        method vbase (line 60) | vbase( vbase&& ) = delete;
      type binder (line 67) | struct binder : vbase
        method binder (line 71) | explicit binder( const T& t ) noexcept( noexcept( parameter_traits...
      type holder (line 77) | struct holder : vbase
        method holder (line 82) | explicit holder( T&& t ) noexcept( noexcept( parameter_traits< T >...
      method fill (line 103) | void fill( const auto& t, std::index_sequence< Is... > /*unused*/ )
      method bind_impl (line 112) | void bind_impl( A&& a )
      method bind_impl (line 132) | void bind_impl( const parameter< N >& p )
      method bind_impl (line 150) | void bind_impl( parameter< N >& p )
      method parameter (line 160) | explicit parameter( As&&... as ) noexcept( noexcept( std::declval< p...
      method parameter (line 179) | explicit parameter( const parameter& p )
      method parameter (line 184) | explicit parameter( parameter&& p ) = delete;
      method bind (line 190) | void bind( As&&... as ) noexcept( sizeof...( As ) == 0 )
      method reset (line 196) | void reset( As&&... as ) noexcept( noexcept( std::declval< parameter...
    type internal (line 25) | namespace internal
    class parameter (line 51) | class parameter
      type vbase (line 54) | struct vbase
        method vbase (line 56) | vbase() noexcept = default;
        method vbase (line 59) | vbase( const vbase& ) = delete;
        method vbase (line 60) | vbase( vbase&& ) = delete;
      type binder (line 67) | struct binder : vbase
        method binder (line 71) | explicit binder( const T& t ) noexcept( noexcept( parameter_traits...
      type holder (line 77) | struct holder : vbase
        method holder (line 82) | explicit holder( T&& t ) noexcept( noexcept( parameter_traits< T >...
      method fill (line 103) | void fill( const auto& t, std::index_sequence< Is... > /*unused*/ )
      method bind_impl (line 112) | void bind_impl( A&& a )
      method bind_impl (line 132) | void bind_impl( const parameter< N >& p )
      method bind_impl (line 150) | void bind_impl( parameter< N >& p )
      method parameter (line 160) | explicit parameter( As&&... as ) noexcept( noexcept( std::declval< p...
      method parameter (line 179) | explicit parameter( const parameter& p )
      method parameter (line 184) | explicit parameter( parameter&& p ) = delete;
      method bind (line 190) | void bind( As&&... as ) noexcept( sizeof...( As ) == 0 )
      method reset (line 196) | void reset( As&&... as ) noexcept( noexcept( std::declval< parameter...

FILE: include/tao/pq/parameter_traits.hpp
  type tao::pq (line 27) | namespace tao::pq
    type parameter_traits (line 30) | struct parameter_traits
    type internal (line 32) | namespace internal
      function snprintf (line 41) | void snprintf( char ( &buffer )[ N ], const char* format, const auto...
      type parameter_holder (line 478) | struct parameter_holder
        method parameter_holder (line 483) | explicit parameter_holder( const T& t ) noexcept( noexcept( result...
    type parameter_traits< null_t > (line 86) | struct parameter_traits< null_t >
      method parameter_traits (line 88) | explicit parameter_traits( null_t /*unused*/ ) noexcept
      method type (line 95) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 101) | [[nodiscard]] static constexpr auto value() noexcept -> const char*
      method length (line 107) | [[nodiscard]] static constexpr auto length() noexcept -> int
      method format (line 113) | [[nodiscard]] static constexpr auto format() noexcept -> int
      method element (line 119) | static void element( std::string& data )
      method copy_to (line 125) | static void copy_to( std::string& data )
    type parameter_traits< bool > (line 132) | struct parameter_traits< bool >
      method parameter_traits (line 137) | explicit parameter_traits( const bool v ) noexcept
      method element (line 142) | void element( std::string& data ) const
      method copy_to (line 148) | void copy_to( std::string& data ) const
    type parameter_traits< char > (line 155) | struct parameter_traits< char >
      method parameter_traits (line 159) | explicit parameter_traits( const char v ) noexcept
      method type (line 167) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 173) | [[nodiscard]] auto value() const noexcept -> const char*
      method length (line 179) | [[nodiscard]] static constexpr auto length() noexcept -> int
      method format (line 185) | [[nodiscard]] static constexpr auto format() noexcept -> int
      method element (line 191) | void element( std::string& data ) const
      method copy_to (line 197) | void copy_to( std::string& data ) const
    type parameter_traits< signed char > (line 204) | struct parameter_traits< signed char >
    type parameter_traits< unsigned char > (line 211) | struct parameter_traits< unsigned char >
    type parameter_traits< short > (line 218) | struct parameter_traits< short >
    type parameter_traits< unsigned short > (line 225) | struct parameter_traits< unsigned short >
    type parameter_traits< int > (line 232) | struct parameter_traits< int >
    type parameter_traits< unsigned int > (line 239) | struct parameter_traits< unsigned int >
    type parameter_traits< long > (line 246) | struct parameter_traits< long >
    type parameter_traits< unsigned long > (line 253) | struct parameter_traits< unsigned long >
    type parameter_traits< long long > (line 260) | struct parameter_traits< long long >
    type parameter_traits< unsigned long long > (line 267) | struct parameter_traits< unsigned long long >
    type parameter_traits< float > (line 274) | struct parameter_traits< float >
      method parameter_traits (line 277) | explicit parameter_traits( const float v ) noexcept
    type parameter_traits< double > (line 284) | struct parameter_traits< double >
      method parameter_traits (line 287) | explicit parameter_traits( const double v ) noexcept
    type parameter_traits< long double > (line 294) | struct parameter_traits< long double >
      method parameter_traits (line 297) | explicit parameter_traits( const long double v ) noexcept
    type parameter_traits< const char* > (line 304) | struct parameter_traits< const char* >
      method element (line 310) | void element( std::string& data ) const
      method copy_to (line 316) | void copy_to( std::string& data ) const
    type parameter_traits< std::string_view > (line 326) | struct parameter_traits< std::string_view >
      method parameter_traits (line 332) | explicit parameter_traits( const std::string_view v ) noexcept
      method type (line 340) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 346) | [[nodiscard]] auto value() const noexcept -> const char*
      method length (line 352) | [[nodiscard]] auto length() const noexcept -> int
      method format (line 358) | [[nodiscard]] static constexpr auto format() noexcept -> int
      method element (line 364) | void element( std::string& data ) const
      method copy_to (line 370) | void copy_to( std::string& data ) const
    type parameter_traits< std::string > (line 377) | struct parameter_traits< std::string >
    type parameter_traits< std::span< const std::byte, Extent > > (line 384) | struct parameter_traits< std::span< const std::byte, Extent > >
      method parameter_traits (line 390) | explicit parameter_traits( const std::span< const std::byte, Extent ...
      method type (line 398) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 404) | [[nodiscard]] constexpr auto value() const noexcept -> const char*
      method length (line 410) | [[nodiscard]] constexpr auto length() const noexcept -> int
      method format (line 416) | [[nodiscard]] static constexpr auto format() noexcept -> int
      method element (line 422) | void element( std::string& data ) const
      method copy_to (line 438) | void copy_to( std::string& data ) const
    type parameter_traits< std::span< std::byte, Extent > > (line 445) | struct parameter_traits< std::span< std::byte, Extent > >
    type parameter_traits< std::vector< std::byte, Allocator > > (line 452) | struct parameter_traits< std::vector< std::byte, Allocator > >
    function to_taopq (line 459) | [[nodiscard]] auto to_taopq( const auto& t ) noexcept( noexcept( t.to_...
    function to_taopq (line 467) | [[nodiscard]] auto to_taopq( const T& t ) noexcept( noexcept( bind< T ...
    type internal (line 475) | namespace internal
      function snprintf (line 41) | void snprintf( char ( &buffer )[ N ], const char* format, const auto...
      type parameter_holder (line 478) | struct parameter_holder
        method parameter_holder (line 483) | explicit parameter_holder( const T& t ) noexcept( noexcept( result...
    type parameter_traits< T > (line 492) | struct parameter_traits< T >
      method parameter_traits (line 500) | explicit parameter_traits( const T& t ) noexcept( noexcept( internal...

FILE: include/tao/pq/parameter_traits_aggregate.hpp
  type tao::pq (line 12) | namespace tao::pq
    type internal (line 14) | namespace internal
      type parameter_tie_aggregate (line 17) | struct parameter_tie_aggregate
        method parameter_tie_aggregate (line 22) | explicit parameter_tie_aggregate( const T& t ) noexcept
    type parameter_traits< T > (line 31) | struct parameter_traits< T >
      method parameter_traits (line 37) | explicit parameter_traits( const T& t ) noexcept( noexcept( internal...

FILE: include/tao/pq/parameter_traits_array.hpp
  type tao::pq (line 15) | namespace tao::pq
    type internal (line 17) | namespace internal
      function to_array (line 23) | void to_array( std::string& data, const T& v )
      function to_array (line 30) | void to_array( std::string& data, const T& v )
    type parameter_traits< T > (line 48) | struct parameter_traits< T >
      method parameter_traits (line 54) | explicit parameter_traits( const T& v )
      method type (line 63) | [[nodiscard]] static constexpr auto type() noexcept -> oid
      method value (line 69) | [[nodiscard]] auto value() const noexcept -> const char*
      method length (line 75) | [[nodiscard]] static constexpr auto length() noexcept -> int
      method format (line 81) | [[nodiscard]] static constexpr auto format() noexcept -> int
      method element (line 87) | void element( std::string& data ) const
      method copy_to (line 93) | void copy_to( std::string& data ) const

FILE: include/tao/pq/parameter_traits_optional.hpp
  type tao::pq::parameter_traits< std::optional< T > > (line 18) | struct tao::pq::parameter_traits< std::optional< T > >
    method parameter_traits (line 25) | explicit parameter_traits( const std::optional< T >& v ) noexcept( noe...
    method parameter_traits (line 32) | explicit parameter_traits( std::optional< T >&& v ) noexcept( noexcept...
    method type (line 43) | [[nodiscard]] static constexpr auto type() noexcept -> oid
    method value (line 49) | [[nodiscard]] constexpr auto value() const noexcept( noexcept( m_forwa...
    method length (line 55) | [[nodiscard]] constexpr auto length() const noexcept( noexcept( m_forw...
    method format (line 61) | [[nodiscard]] static constexpr auto format() noexcept -> int
    method element (line 67) | void element( std::string& data ) const
    method copy_to (line 78) | void copy_to( std::string& data ) const

FILE: include/tao/pq/parameter_traits_pair.hpp
  type tao::pq::parameter_traits< std::pair< T, U > > (line 18) | struct tao::pq::parameter_traits< std::pair< T, U > >
    method parameter_traits (line 30) | explicit parameter_traits( const std::pair< T, U >& pair ) noexcept( n...
    method parameter_traits (line 34) | explicit parameter_traits( std::pair< T, U >&& pair ) noexcept( noexce...
    method type (line 42) | [[nodiscard]] constexpr auto type() const noexcept( noexcept( std::get...
    method value (line 48) | [[nodiscard]] constexpr auto value() const noexcept( noexcept( std::ge...
    method length (line 54) | [[nodiscard]] constexpr auto length() const noexcept( noexcept( std::g...
    method format (line 60) | [[nodiscard]] constexpr auto format() const noexcept( noexcept( std::g...
    method copy_to (line 66) | void copy_to( std::string& data ) const

FILE: include/tao/pq/parameter_traits_tuple.hpp
  type tao::pq::parameter_traits< std::tuple< Ts... > > (line 20) | struct tao::pq::parameter_traits< std::tuple< Ts... > >
    method parameter_traits (line 29) | explicit parameter_traits( const std::tuple< Ts... >& tuple ) noexcept...
    method parameter_traits (line 33) | explicit parameter_traits( std::tuple< Ts... >&& tuple ) noexcept( noe...
    method type (line 41) | [[nodiscard]] constexpr auto type() const noexcept( noexcept( std::get...
    method value (line 47) | [[nodiscard]] constexpr auto value() const noexcept( noexcept( std::ge...
    method length (line 53) | [[nodiscard]] constexpr auto length() const noexcept( noexcept( std::g...
    method format (line 59) | [[nodiscard]] constexpr auto format() const noexcept( noexcept( std::g...
    method element (line 66) | void element( std::string& data ) const
    method copy_to (line 72) | void copy_to( std::string& data ) const

FILE: include/tao/pq/pipeline.hpp
  type tao::pq (line 13) | namespace tao::pq
    class connection (line 15) | class connection
    class transaction (line 16) | class transaction
    class pipeline (line 18) | class pipeline
      class private_key (line 27) | class private_key final
        method private_key (line 29) | private_key() = default;
      method pipeline (line 48) | pipeline( const pipeline& ) = delete;
      method pipeline (line 49) | pipeline( pipeline&& ) = delete;

FILE: include/tao/pq/pipeline_status.hpp
  type tao::pq (line 15) | namespace tao::pq
    type pipeline_status (line 17) | enum class pipeline_status : std::uint8_t
    function taopq_format_as (line 24) | [[nodiscard]] constexpr auto taopq_format_as( const pipeline_status ps...

FILE: include/tao/pq/poll.hpp
  type tao::pq::poll (line 13) | namespace tao::pq::poll
    type status (line 15) | enum class status : std::uint8_t
    function taopq_format_as (line 23) | [[nodiscard]] constexpr auto taopq_format_as( const status st ) noexce...

FILE: include/tao/pq/result.hpp
  type tao::pq (line 32) | namespace tao::pq
    class connection (line 34) | class connection
    class table_reader (line 35) | class table_reader
    class table_writer (line 36) | class table_writer
    class transaction_base (line 37) | class transaction_base
    class result (line 39) | class result final
      method columns (line 60) | [[nodiscard]] auto columns() const noexcept -> std::size_t
      method size (line 68) | [[nodiscard]] auto size() const noexcept -> std::size_t
      method empty (line 74) | [[nodiscard]] auto empty() const noexcept -> bool
      class const_iterator (line 80) | class const_iterator
        method const_iterator (line 86) | explicit const_iterator( const row& r ) noexcept
        method const_iterator (line 97) | const_iterator() = default;
        method swap (line 152) | void swap( const_iterator& lhs, const_iterator& rhs ) noexcept
      method cbegin (line 198) | [[nodiscard]] auto cbegin() const noexcept
      method cend (line 203) | [[nodiscard]] auto cend() const noexcept
      method as (line 219) | [[nodiscard]] auto as() const -> T
      method optional (line 234) | [[nodiscard]] auto optional() const -> std::optional< T >
      method pair (line 249) | [[nodiscard]] auto pair() const
      method tuple (line 255) | [[nodiscard]] auto tuple() const
      method as_container (line 262) | [[nodiscard]] auto as_container() const -> T
      method vector (line 277) | [[nodiscard]] auto vector() const
      method list (line 284) | [[nodiscard]] auto list() const
      method set (line 291) | [[nodiscard]] auto set() const
      method multiset (line 298) | [[nodiscard]] auto multiset() const
      method unordered_set (line 305) | [[nodiscard]] auto unordered_set() const
      method unordered_multiset (line 312) | [[nodiscard]] auto unordered_multiset() const
      method map (line 319) | [[nodiscard]] auto map() const
      method multimap (line 326) | [[nodiscard]] auto multimap() const
      method unordered_map (line 333) | [[nodiscard]] auto unordered_map() const
      method unordered_multimap (line 340) | [[nodiscard]] auto unordered_multimap() const
      method underlying_raw_ptr (line 345) | [[nodiscard]] auto underlying_raw_ptr() noexcept -> PGresult*
      method underlying_raw_ptr (line 350) | [[nodiscard]] auto underlying_raw_ptr() const noexcept -> const PGre...

FILE: include/tao/pq/result_status.hpp
  type tao::pq (line 15) | namespace tao::pq
    type result_status (line 17) | enum class result_status : std::uint8_t
    function taopq_format_as (line 35) | [[nodiscard]] constexpr auto taopq_format_as( const result_status rs )...

FILE: include/tao/pq/result_traits.hpp
  type tao::pq (line 19) | namespace tao::pq
    type result_traits (line 22) | struct result_traits
    class row (line 36) | class row
    type result_traits< const char* > (line 47) | struct result_traits< const char* >
      method from (line 49) | [[nodiscard]] static auto from( const char* value )
    type result_traits< std::string_view > (line 56) | struct result_traits< std::string_view >
      method from (line 58) | [[nodiscard]] static auto from( const char* value ) -> std::string_view
    type result_traits< bool > (line 65) | struct result_traits< bool >
    type result_traits< char > (line 71) | struct result_traits< char >
    type result_traits< signed char > (line 77) | struct result_traits< signed char >
    type result_traits< unsigned char > (line 83) | struct result_traits< unsigned char >
    type result_traits< short > (line 89) | struct result_traits< short >
    type result_traits< unsigned short > (line 95) | struct result_traits< unsigned short >
    type result_traits< int > (line 101) | struct result_traits< int >
    type result_traits< unsigned > (line 107) | struct result_traits< unsigned >
    type result_traits< long > (line 113) | struct result_traits< long >
    type result_traits< unsigned long > (line 119) | struct result_traits< unsigned long >
    type result_traits< long long > (line 125) | struct result_traits< long long >
    type result_traits< unsigned long long > (line 131) | struct result_traits< unsigned long long >
    type result_traits< float > (line 137) | struct result_traits< float >
    type result_traits< double > (line 143) | struct result_traits< double >
    type result_traits< long double > (line 149) | struct result_traits< long double >
    type result_traits< std::string > (line 155) | struct result_traits< std::string >
      method from (line 157) | [[nodiscard]] static auto from( const char* value ) -> std::string
    type result_traits< binary > (line 164) | struct result_traits< binary >
    type internal (line 169) | namespace internal
      type from_taopq (line 172) | struct from_taopq
    type result_traits< T > (line 201) | struct result_traits< T >
    type result_traits< T > (line 207) | struct result_traits< T >
  type from_taopq< T, R, R( As... ) > (line 175) | struct from_taopq< T, R, R( As... ) >
    method from (line 180) | [[nodiscard]] static auto from( const Row& row, std::index_sequence< N...
    method from (line 186) | [[nodiscard]] static auto from( const Row& row ) -> R
  type from_taopq< T, R, R( As... ) noexcept > (line 193) | struct from_taopq< T, R, R( As... ) noexcept >

FILE: include/tao/pq/result_traits_aggregate.hpp
  type tao::pq (line 18) | namespace tao::pq
    type internal (line 20) | namespace internal
      type decay_tuple (line 23) | struct decay_tuple
      type aggregate_result (line 32) | struct aggregate_result
    type result_traits< T > (line 56) | struct result_traits< T >
  type decay_tuple< std::tuple< Ts... > > (line 26) | struct decay_tuple< std::tuple< Ts... > >
  type aggregate_result< T, std::tuple< Ts... > > (line 35) | struct aggregate_result< T, std::tuple< Ts... > >
    method from (line 40) | [[nodiscard]] static auto from( const Row& row, std::index_sequence< N...
    method from (line 46) | [[nodiscard]] static auto from( const Row& row )

FILE: include/tao/pq/result_traits_array.hpp
  type tao::pq (line 14) | namespace tao::pq
    type internal (line 16) | namespace internal
      function parse (line 25) | [[nodiscard]] auto parse( const char*& value ) -> T
      function parse (line 46) | [[nodiscard]] auto parse( const char*& value ) -> T
    type result_traits< T > (line 83) | struct result_traits< T >
      method from (line 85) | static auto from( const char* value ) -> T

FILE: include/tao/pq/result_traits_optional.hpp
  type tao::pq::result_traits< std::optional< T > > (line 14) | struct tao::pq::result_traits< std::optional< T > >
    method null (line 18) | [[nodiscard]] static auto null() noexcept -> std::optional< T >
    method from (line 23) | [[nodiscard]] static auto from( const char* value ) -> std::optional< T >
    method from (line 29) | [[nodiscard]] static auto from( const Row& row ) -> std::optional< T >

FILE: include/tao/pq/result_traits_pair.hpp
  type tao::pq::result_traits< std::pair< T, U > > (line 15) | struct tao::pq::result_traits< std::pair< T, U > >
    method from (line 23) | [[nodiscard]] static auto from( const Row& row )

FILE: include/tao/pq/result_traits_tuple.hpp
  type tao::pq::result_traits< std::tuple<> > (line 17) | struct tao::pq::result_traits< std::tuple<> >
  type tao::pq::result_traits< std::tuple< T > > (line 23) | struct tao::pq::result_traits< std::tuple< T > >
    method null (line 29) | [[nodiscard]] static auto null()
    method from (line 35) | [[nodiscard]] static auto from( const char* value )
  type tao::pq::result_traits< std::tuple< Ts... > > (line 43) | struct tao::pq::result_traits< std::tuple< Ts... > >
    method from (line 48) | [[nodiscard]] static auto from( const Row& row, std::index_sequence< N...
    method from (line 54) | [[nodiscard]] static auto from( const Row& row )

FILE: include/tao/pq/row.hpp
  type tao::pq (line 24) | namespace tao::pq
    class result (line 26) | class result
    class row (line 28) | class row
      method row (line 39) | row() = default;
      method row (line 41) | row( const result& in_result, const std::size_t in_row, const std::s...
      method columns (line 53) | [[nodiscard]] auto columns() const noexcept -> std::size_t
      class const_iterator (line 62) | class const_iterator
        method const_iterator (line 68) | explicit const_iterator( const field& f ) noexcept
        method const_iterator (line 79) | const_iterator() = default;
        method swap (line 134) | void swap( const_iterator& lhs, const_iterator& rhs ) noexcept
      method cbegin (line 180) | [[nodiscard]] auto cbegin() const noexcept
      method cend (line 185) | [[nodiscard]] auto cend() const noexcept
      method get (line 194) | [[nodiscard]] auto get( const std::size_t column ) const -> T
      method get (line 205) | [[nodiscard]] auto get( const std::size_t column ) const -> T
      method optional (line 211) | [[nodiscard]] auto optional( const std::size_t column ) const
      method as (line 217) | [[nodiscard]] auto as() const -> T
      method optional (line 233) | [[nodiscard]] auto optional() const
      method pair (line 239) | [[nodiscard]] auto pair() const
      method tuple (line 245) | [[nodiscard]] auto tuple() const
      method at (line 257) | [[nodiscard]] auto at( const internal::zsv in_name ) const -> field
      method swap (line 268) | void swap( row& lhs, row& rhs ) noexcept

FILE: include/tao/pq/table_field.hpp
  type tao::pq (line 15) | namespace tao::pq
    class table_row (line 17) | class table_row
    class table_field (line 19) | class table_field
      method table_field (line 27) | table_field() = default;
      method table_field (line 29) | table_field( const table_row& row, const std::size_t column ) noexcept
      method optional (line 46) | [[nodiscard]] auto optional() const
      method swap (line 56) | void swap( table_field& lhs, table_field& rhs ) noexcept

FILE: include/tao/pq/table_reader.hpp
  type tao::pq (line 27) | namespace tao::pq
    class table_reader (line 29) | class table_reader final
      method table_reader (line 42) | table_reader( const std::shared_ptr< transaction >& transaction, con...
      method table_reader (line 54) | table_reader( const table_reader& ) = delete;
      method table_reader (line 55) | table_reader( table_reader&& ) = delete;
      method columns (line 59) | [[nodiscard]] auto columns() const noexcept -> std::size_t
      method get_row (line 69) | [[nodiscard]] auto get_row() -> bool
      method has_data (line 75) | [[nodiscard]] auto has_data() const noexcept -> bool
      method raw_data (line 80) | [[nodiscard]] auto raw_data() const noexcept -> const std::vector< c...
      method row (line 85) | [[nodiscard]] auto row() noexcept -> table_row
      class const_iterator (line 92) | class const_iterator
        method const_iterator (line 98) | const_iterator( const table_row& r ) noexcept
        method swap (line 126) | void swap( const_iterator& lhs, const_iterator& rhs ) noexcept
      method cbegin (line 141) | [[nodiscard]] auto cbegin()
      method cend (line 146) | [[nodiscard]] auto cend() noexcept
      method as_container (line 153) | [[nodiscard]] auto as_container() -> T
      method vector (line 164) | [[nodiscard]] auto vector()
      method list (line 171) | [[nodiscard]] auto list()
      method set (line 178) | [[nodiscard]] auto set()
      method multiset (line 185) | [[nodiscard]] auto multiset()
      method unordered_set (line 192) | [[nodiscard]] auto unordered_set()
      method unordered_multiset (line 199) | [[nodiscard]] auto unordered_multiset()
      method map (line 206) | [[nodiscard]] auto map()
      method multimap (line 213) | [[nodiscard]] auto multimap()
      method unordered_map (line 220) | [[nodiscard]] auto unordered_map()
      method unordered_multimap (line 227) | [[nodiscard]] auto unordered_multimap()

FILE: include/tao/pq/table_row.hpp
  type tao::pq (line 21) | namespace tao::pq
    class table_reader (line 23) | class table_reader
    class table_row (line 25) | class table_row
      method table_row (line 35) | table_row( table_reader& in_reader, const std::size_t in_offset, con...
      method columns (line 46) | [[nodiscard]] auto columns() const noexcept -> std::size_t
      class const_iterator (line 52) | class const_iterator
        method const_iterator (line 58) | explicit const_iterator( const table_field& f ) noexcept
        method const_iterator (line 69) | const_iterator() = default;
        method swap (line 124) | void swap( const_iterator& lhs, const_iterator& rhs ) noexcept
      method cbegin (line 170) | [[nodiscard]] auto cbegin() const noexcept
      method cend (line 175) | [[nodiscard]] auto cend() const noexcept
      method get (line 184) | [[nodiscard]] auto get( const std::size_t column ) const -> T
      method get (line 199) | [[nodiscard]] auto get( const std::size_t column ) const -> T
      method optional (line 205) | [[nodiscard]] auto optional( const std::size_t column ) const
      method as (line 211) | [[nodiscard]] auto as() const -> T
      method optional (line 220) | [[nodiscard]] auto optional() const
      method pair (line 226) | [[nodiscard]] auto pair() const
      method tuple (line 232) | [[nodiscard]] auto tuple() const
      method swap (line 244) | void swap( table_row& lhs, table_row& rhs ) noexcept

FILE: include/tao/pq/table_writer.hpp
  type tao::pq (line 24) | namespace tao::pq
    class table_writer (line 26) | class table_writer final
      method insert_indexed (line 35) | void insert_indexed( std::index_sequence< Os... > /*unused*/,
      method insert_traits (line 46) | void insert_traits( const Ts&... ts )
      method insert_indexed (line 55) | void insert_indexed( std::index_sequence< Os... > /*unused*/,
      method insert_traits (line 66) | void insert_traits( const Ts&... ts )
      method table_writer (line 78) | table_writer( const std::shared_ptr< transaction >& transaction, con...
      method table_writer (line 88) | table_writer( const table_writer& ) = delete;
      method table_writer (line 89) | table_writer( table_writer&& ) = delete;
      method insert (line 97) | void insert( As&&... as )

FILE: include/tao/pq/transaction.hpp
  type tao::pq (line 18) | namespace tao::pq
    class pipeline (line 20) | class pipeline
    class transaction (line 22) | class transaction
      method execute (line 42) | auto execute( const internal::zsv statement, As&&... as )
    type internal (line 53) | namespace internal
      class subtransaction_base (line 55) | class subtransaction_base
        method subtransaction_base (line 62) | explicit subtransaction_base( const std::shared_ptr< pq::connectio...
        method v_is_direct (line 76) | [[nodiscard]] auto v_is_direct() const noexcept -> bool final
        method v_reset (line 81) | void v_reset() noexcept final
        method subtransaction_base (line 88) | subtransaction_base( const subtransaction_base& ) = delete;
        method subtransaction_base (line 89) | subtransaction_base( subtransaction_base&& ) = delete;
      class transaction_guard (line 95) | class transaction_guard final
        method transaction_guard (line 99) | explicit transaction_guard( const std::shared_ptr< pq::connection ...
        method v_commit (line 105) | void v_commit() override {}
        method v_rollback (line 106) | void v_rollback() override {}

FILE: include/tao/pq/transaction_base.hpp
  type tao::pq (line 25) | namespace tao::pq
    class connection (line 27) | class connection
    class table_reader (line 28) | class table_reader
    class table_writer (line 29) | class table_writer
    class transaction_base (line 31) | class transaction_base
      method transaction_base (line 45) | transaction_base( const transaction_base& ) = delete;
      method transaction_base (line 46) | transaction_base( transaction_base&& ) = delete;
      method send_indexed (line 64) | void send_indexed( const char* statement,
      method send_traits (line 77) | void send_traits( const char* statement, const Ts&... ts )
      method send_indexed (line 86) | void send_indexed( const char* statement,
      method send_traits (line 99) | void send_traits( const char* statement, const Ts&... ts )
      method connection (line 108) | [[nodiscard]] auto connection() const noexcept -> const std::shared_...
      method send (line 113) | void send( const internal::zsv statement )
      method send (line 119) | void send( const internal::zsv statement, As&&... as )
      method send (line 126) | void send( const internal::zsv statement, As&&... as )
      method send (line 133) | void send( const internal::zsv statement, A&& p )

FILE: include/tao/pq/transaction_status.hpp
  type tao::pq (line 15) | namespace tao::pq
    type transaction_status (line 17) | enum class transaction_status : std::uint8_t
    function taopq_format_as (line 26) | [[nodiscard]] constexpr auto taopq_format_as( const transaction_status...

FILE: src/lib/pq/connection.cpp
  type tao::pq (line 34) | namespace tao::pq
    type internal (line 36) | namespace internal
      class transaction_base (line 38) | class transaction_base
        method transaction_base (line 42) | explicit transaction_base( const std::shared_ptr< pq::connection >...
        method v_reset (line 58) | void v_reset() noexcept final
        method transaction_base (line 65) | transaction_base( const transaction_base& ) = delete;
        method transaction_base (line 66) | transaction_base( transaction_base&& ) = delete;
      class autocommit_transaction (line 71) | class autocommit_transaction final
        method autocommit_transaction (line 75) | explicit autocommit_transaction( const std::shared_ptr< pq::connec...
        method v_is_direct (line 80) | [[nodiscard]] auto v_is_direct() const noexcept -> bool override
        method v_commit (line 85) | void v_commit() override
        method v_rollback (line 88) | void v_rollback() override
      function isolation_level_extension (line 94) | [[nodiscard]] inline auto isolation_level_extension( const isolation...
      function access_mode_extension (line 111) | [[nodiscard]] inline auto access_mode_extension( const access_mode a...
      class top_level_transaction (line 126) | class top_level_transaction final
        method top_level_transaction (line 130) | top_level_transaction( const std::shared_ptr< pq::connection >& co...
        method top_level_transaction (line 143) | top_level_transaction( const top_level_transaction& ) = delete;
        method top_level_transaction (line 144) | top_level_transaction( top_level_transaction&& ) = delete;
        method v_is_direct (line 149) | [[nodiscard]] auto v_is_direct() const noexcept -> bool override
        method v_commit (line 154) | void v_commit() override
        method v_rollback (line 159) | void v_rollback() override
      function is_identifier (line 167) | [[nodiscard]] constexpr auto is_identifier( const std::string_view v...

FILE: src/lib/pq/connection_pool.cpp
  type tao::pq (line 13) | namespace tao::pq

FILE: src/lib/pq/exception.cpp
  type tao::pq (line 12) | namespace tao::pq
    type internal (line 23) | namespace internal
      function throw_sqlstate (line 25) | void throw_sqlstate( PGresult* pgresult )
      function throw_sqlstate (line 35) | void throw_sqlstate( const char* error_message, const std::string_vi...

FILE: src/lib/pq/field.cpp
  type tao::pq (line 12) | namespace tao::pq

FILE: src/lib/pq/internal/demangle.cpp
  type tao::pq::internal (line 15) | namespace tao::pq::internal
    function demangle (line 17) | auto demangle( const char* const symbol ) -> std::string

FILE: src/lib/pq/internal/poll.cpp
  type tao::pq::internal (line 23) | namespace tao::pq::internal
    function errno_result_to_string (line 28) | [[nodiscard, maybe_unused]] auto errno_result_to_string( const int e, ...
    function errno_result_to_string (line 36) | [[nodiscard, maybe_unused]] auto errno_result_to_string( const int /*u...
    function errno_to_string (line 41) | [[nodiscard]] auto errno_to_string( const int e ) -> std::string
    function poll (line 58) | auto poll( const int socket, const bool wait_for_write, const int time...

FILE: src/lib/pq/internal/strtox.cpp
  type tao::pq::internal (line 15) | namespace tao::pq::internal
    function failure_message (line 29) | [[nodiscard]] auto failure_message( const char* input ) -> std::string
    function str_to_floating_point (line 56) | [[nodiscard]] auto str_to_floating_point( const char* input ) -> T
    function strtof (line 87) | [[nodiscard]] auto strtof( const char* input ) -> float
    function strtod (line 92) | [[nodiscard]] auto strtod( const char* input ) -> double
    function strtold (line 97) | [[nodiscard]] auto strtold( const char* input ) -> long double

FILE: src/lib/pq/large_object.cpp
  type tao::pq (line 27) | namespace tao::pq
    function to_mode (line 31) | [[nodiscard]] constexpr auto to_mode( const std::ios_base::openmode m ...

FILE: src/lib/pq/parameter_traits.cpp
  type tao::pq::internal (line 10) | namespace tao::pq::internal
    function array_append (line 12) | void array_append( std::string& buffer, std::string_view data )
    function table_writer_append (line 40) | void table_writer_append( std::string& buffer, std::string_view data )

FILE: src/lib/pq/pipeline.cpp
  type tao::pq (line 11) | namespace tao::pq

FILE: src/lib/pq/result.cpp
  type tao::pq (line 20) | namespace tao::pq

FILE: src/lib/pq/result_traits.cpp
  type tao::pq (line 18) | namespace tao::pq
    function unhex (line 22) | [[nodiscard]] auto unhex( const char c ) -> int
    function unescape_bytea (line 33) | [[nodiscard]] auto unescape_bytea( const char* value ) -> binary

FILE: src/lib/pq/result_traits_array.cpp
  type tao::pq::internal (line 13) | namespace tao::pq::internal
    function parse_quoted (line 15) | auto parse_quoted( const char*& value ) -> std::string
    function parse_unquoted (line 38) | auto parse_unquoted( const char*& value ) -> std::string

FILE: src/lib/pq/row.cpp
  type tao::pq (line 16) | namespace tao::pq

FILE: src/lib/pq/table_field.cpp
  type tao::pq (line 11) | namespace tao::pq

FILE: src/lib/pq/table_reader.cpp
  type tao::pq (line 21) | namespace tao::pq

FILE: src/lib/pq/table_row.cpp
  type tao::pq (line 13) | namespace tao::pq

FILE: src/lib/pq/table_writer.cpp
  type tao::pq (line 20) | namespace tao::pq

FILE: src/lib/pq/transaction.cpp
  type tao::pq (line 18) | namespace tao::pq
    type internal (line 20) | namespace internal
      class top_level_subtransaction (line 22) | class top_level_subtransaction final
        method top_level_subtransaction (line 26) | explicit top_level_subtransaction( const std::shared_ptr< pq::conn...
        method top_level_subtransaction (line 39) | top_level_subtransaction( const top_level_subtransaction& ) = delete;
        method top_level_subtransaction (line 40) | top_level_subtransaction( top_level_subtransaction&& ) = delete;
        method v_commit (line 45) | void v_commit() override
        method v_rollback (line 50) | void v_rollback() override
      class nested_subtransaction (line 56) | class nested_subtransaction final
        method nested_subtransaction (line 60) | explicit nested_subtransaction( const std::shared_ptr< pq::connect...
        method nested_subtransaction (line 75) | nested_subtransaction( const nested_subtransaction& ) = delete;
        method nested_subtransaction (line 76) | nested_subtransaction( nested_subtransaction&& ) = delete;
        method v_commit (line 81) | void v_commit() override
        method v_rollback (line 88) | void v_rollback() override

FILE: src/lib/pq/transaction_base.cpp
  type tao::pq (line 19) | namespace tao::pq

FILE: test/integration/aggregate.cpp
  type example (line 14) | namespace example
    type user (line 16) | struct user
  function run (line 30) | void run()
  function main (line 55) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/array.cpp
  function run (line 22) | void run()
  function main (line 153) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/basic_datatypes.cpp
  function prepare_datatype (line 23) | auto prepare_datatype( const std::string& datatype ) -> bool
  function check_null (line 35) | void check_null( const std::string& datatype )
  function check (line 49) | void check( const std::string& datatype, const T& value )
  function check (line 77) | auto check( const std::string& datatype )
  function check (line 92) | auto check( const std::string& datatype )
  function check_bytea (line 102) | void check_bytea( const auto& t )
  function run (line 110) | void run()
  function main (line 389) | auto main() -> int

FILE: test/integration/chunk_mode.cpp
  function main (line 16) | auto main() -> int
  function run (line 25) | void run()
  function main (line 99) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/connection.cpp
  function my_poll (line 20) | auto my_poll( const int /*unused*/, const bool /*unused*/, const int /*u...
  function run (line 26) | void run()
  function main (line 163) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/connection_pool.cpp
  class limited_connection_pool (line 21) | class limited_connection_pool
    type guard (line 24) | struct guard
      method guard (line 28) | explicit guard( std::atomic< std::size_t >& counter ) noexcept
      method guard (line 34) | guard( const guard& ) = delete;
      method guard (line 35) | guard( guard&& ) = delete;
    method v_create (line 49) | [[nodiscard]] auto v_create() const -> std::unique_ptr< tao::pq::conne...
  function my_poll (line 60) | auto my_poll( const int /*unused*/, const bool /*unused*/, const int /*u...
  function run (line 66) | void run()
  function main (line 151) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/example.cpp
  function run (line 16) | void run()
  function main (line 56) | auto main() -> int

FILE: test/integration/exception.cpp
  function run (line 15) | void run()
  function main (line 36) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/large_object.cpp
  function test (line 22) | void test( const std::shared_ptr< tao::pq::connection >& connection, con...
  function run (line 36) | void run()
  function main (line 139) | auto main() -> int

FILE: test/integration/log.cpp
  function to_millis (line 18) | [[nodiscard]] auto to_millis( std::chrono::steady_clock::time_point end ...
  function run (line 23) | void run()
  function main (line 136) | auto main() -> int

FILE: test/integration/notifications.cpp
  function handle_notification (line 24) | void handle_notification( const tao::pq::notification& n )
  function handle_foo_notification (line 32) | void handle_foo_notification( const char* payload )
  function run (line 38) | void run()
  function main (line 82) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/parameter.cpp
  function run (line 16) | void run()
  function main (line 93) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/password.cpp
  function run (line 17) | void run()
  function main (line 36) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/pipeline_mode.cpp
  function run (line 16) | void run()
  function main (line 175) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/result.cpp
  function run (line 20) | void run()  // NOLINT(readability-function-size)
  function main (line 183) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/row.cpp
  function run (line 19) | void run()
  function main (line 104) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/single_row_mode.cpp
  function run (line 16) | void run()
  function main (line 57) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/table_reader.cpp
  function run (line 19) | void run()
  function main (line 121) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/table_writer.cpp
  function run (line 18) | void run()
  function main (line 96) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/integration/traits.cpp
  type example (line 15) | namespace example
    type user (line 17) | struct user
      method user (line 21) | explicit user( const int i ) noexcept
      method to_taopq (line 25) | [[nodiscard]] auto to_taopq() const noexcept
      method user (line 31) | user( const int in_a, const int in_b, const int in_c, const int in_d...
      method from_taopq (line 36) | [[nodiscard]] static auto from_taopq( const int in_a, const int in_b...
    type user2 (line 42) | struct user2
      method user2 (line 46) | explicit user2( int i ) noexcept
      method user2 (line 50) | user2( const int in_a, const int in_b, const int in_c, const int in_...
    type user3 (line 55) | struct user3
      method user3 (line 59) | explicit user3( int i ) noexcept
      method user3 (line 63) | user3( const int in_a, const int in_b, const int in_c, const int in_...
    function to_taopq (line 68) | [[nodiscard]] auto to_taopq( const user3& v ) noexcept  // NOLINT(misc...
  type tao::pq::bind< example::user2 > (line 76) | struct tao::pq::bind< example::user2 >
    method to_taopq (line 78) | [[nodiscard]] static auto to_taopq( const example::user2& v ) noexcept
    method from_taopq (line 83) | [[nodiscard]] static auto from_taopq( const int a, const int b, const ...
  function run (line 91) | void run()
  function main (line 169) | auto main() -> int  //NOLINT(bugprone-exception-escape)

FILE: test/integration/transaction.cpp
  function check_nested (line 18) | void check_nested( const std::shared_ptr< Connection >& connection, cons...
  function run (line 56) | void run()
  function main (line 129) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/unit/getenv.cpp
  function run (line 13) | void run()
  function main (line 25) | auto main() -> int

FILE: test/unit/parameter_type.cpp
  type example (line 87) | namespace example
    type user (line 89) | struct user
    type user2 (line 96) | struct user2
  function main (line 111) | auto main() -> int

FILE: test/unit/resize_uninitialized.cpp
  function test (line 17) | void test( std::string& s, const std::size_t size )
  function run (line 24) | void run()
  function main (line 70) | auto main() -> int

FILE: test/unit/result_type.cpp
  type example (line 85) | namespace example
    type user (line 87) | struct user
    type user2 (line 94) | struct user2
  function main (line 109) | auto main() -> int

FILE: test/unit/strtox.cpp
  function main (line 6) | auto main() -> int {}
  function reject_floating_point (line 24) | void reject_floating_point( const char* input )
  function run (line 55) | void run()
  function main (line 127) | auto main() -> int  // NOLINT(bugprone-exception-escape)

FILE: test/utils/compare.hpp
  type tao::pq::internal (line 12) | namespace tao::pq::internal
    function compare (line 15) | [[nodiscard]] auto compare( const T& lhs, const U& rhs ) noexcept -> bool

FILE: test/utils/getenv.hpp
  type tao::pq::internal (line 19) | namespace tao::pq::internal
    function getenv (line 23) | [[nodiscard]] inline auto getenv( const std::string& name ) -> std::st...
    function getenv (line 34) | [[nodiscard]] inline auto getenv( const std::string& name, const std::...
    function getenv (line 47) | [[nodiscard]] inline auto getenv( const std::string& name ) -> std::st...
    function getenv (line 53) | [[nodiscard]] inline auto getenv( const std::string& name, const std::...
Condensed preview — 146 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (632K chars).
[
  {
    "path": ".clang-format",
    "chars": 2682,
    "preview": "# The Art of C++\n# https://github.com/taocpp\n\n# Copyright (c) 2016-2026 Dr. Colin Hirsch and Daniel Frey\n# Distributed u"
  },
  {
    "path": ".clang-tidy",
    "chars": 1644,
    "preview": "# The Art of C++\n# https://github.com/taocpp\n\n# Copyright (c) 2016-2026 Dr. Colin Hirsch and Daniel Frey\n# Distributed u"
  },
  {
    "path": ".github/conan/conanfile.py",
    "chars": 1006,
    "preview": "from conan import ConanFile\nfrom conan.tools.cmake import CMakeDeps, CMakeToolchain, cmake_layout\n\nclass TaopqRequiremen"
  },
  {
    "path": ".github/conan/profiles/clangcl",
    "chars": 586,
    "preview": "[settings]\nos=Windows\narch=x86_64\nbuild_type=Release\ncompiler=clang\ncompiler.version=19\ncompiler.cppstd=20\ncompiler.runt"
  },
  {
    "path": ".github/conan/profiles/msvc",
    "chars": 255,
    "preview": " [settings]\narch=x86_64\nbuild_type=Release\ncompiler=msvc\ncompiler.cppstd=20\ncompiler.runtime=dynamic\ncompiler.runtime_ty"
  },
  {
    "path": ".github/workflows/clang-analyze.yml",
    "chars": 572,
    "preview": "name: clang-analyze\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore"
  },
  {
    "path": ".github/workflows/clang-format.yml",
    "chars": 344,
    "preview": "name: clang-format\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:"
  },
  {
    "path": ".github/workflows/clang-tidy.yml",
    "chars": 663,
    "preview": "name: clang-tidy\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n "
  },
  {
    "path": ".github/workflows/code-coverage.yml",
    "chars": 1427,
    "preview": "name: code-coverage\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore"
  },
  {
    "path": ".github/workflows/linux.yml",
    "chars": 5355,
    "preview": "name: Linux\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      "
  },
  {
    "path": ".github/workflows/macos.yml",
    "chars": 1345,
    "preview": "name: macOS\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n      "
  },
  {
    "path": ".github/workflows/sanitizer.yml",
    "chars": 1374,
    "preview": "name: Sanitizer\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n  "
  },
  {
    "path": ".github/workflows/windows.yml",
    "chars": 1688,
    "preview": "name: Windows\n\non:\n  push:\n    paths-ignore:\n      - 'README.md'\n      - 'doc/**'\n  pull_request:\n    paths-ignore:\n    "
  },
  {
    "path": ".gitignore",
    "chars": 19,
    "preview": "*~\nbuild\ndummy.txt\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 7565,
    "preview": "cmake_minimum_required(VERSION 3.15)\n\n# Read version from version.hpp\nfile(READ \"${CMAKE_CURRENT_SOURCE_DIR}/include/tao"
  },
  {
    "path": "CMakePresets.json",
    "chars": 8678,
    "preview": "{\n  \"version\": 6,\n  \"cmakeMinimumRequired\": {\n    \"major\": 3,\n    \"minor\": 21,\n    \"patch\": 0\n  },\n  \"configurePresets\":"
  },
  {
    "path": "LICENSE_1_0.txt",
    "chars": 1338,
    "preview": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or"
  },
  {
    "path": "Makefile",
    "chars": 2708,
    "preview": "# The Art of C++\n# https://github.com/taocpp\n\n# Copyright (c) 2016-2026 Daniel Frey\n# Distributed under the Boost Softwa"
  },
  {
    "path": "README.md",
    "chars": 5891,
    "preview": "# Welcome to taoPQ\n\n[![Windows CI](https://github.com/taocpp/taopq/workflows/Windows/badge.svg)](https://github.com/taoc"
  },
  {
    "path": "doc/Aggregate-Support.md",
    "chars": 3442,
    "preview": "# Aggregate Support\n\ntaoPQ allows the direct use of \"simple\" aggregates as parameters and result types.\n\n## Requirements"
  },
  {
    "path": "doc/Binary-Data.md",
    "chars": 3258,
    "preview": "# Binary Data\n\nPostgreSQL stores binary data either as a field with the [`BYTEA`➚](https://www.postgresql.org/docs/curre"
  },
  {
    "path": "doc/Bulk-Transfer.md",
    "chars": 6039,
    "preview": "# Bulk Transfer\n\n**TODO**\n\n## Synopsis\n\nDon't be intimidated by the size of the API, as you can see several methods are "
  },
  {
    "path": "doc/Connection-Pool.md",
    "chars": 7137,
    "preview": "# Connection Pool\n\nOpening a new connection to the database server typically consists of several time-consuming steps.\nA"
  },
  {
    "path": "doc/Connection.md",
    "chars": 17134,
    "preview": "# Connection\n\nAll communication with a database server is handled through a connection, represented by the `tao::pq::con"
  },
  {
    "path": "doc/Error-Handling.md",
    "chars": 3889,
    "preview": "# Error Handling\n\n## SQL errors\n\nWhen an SQL statement is [executed](Statement.md) and the execution fails, an exception"
  },
  {
    "path": "doc/Getting-Started.md",
    "chars": 5353,
    "preview": "# Getting Started\n\nBefore we start with taoPQ, we'd like to point you to the excellent [PostgreSQL documentation➚](https"
  },
  {
    "path": "doc/Installation.md",
    "chars": 2190,
    "preview": "# Installation\n\n## Using CMake\n\nSince CMake 3.11, the feature [FetchContent➚](https://cmake.org/cmake/help/latest/module"
  },
  {
    "path": "doc/Large-Object.md",
    "chars": 9296,
    "preview": "# Large Object\n\nPostgreSQL has a [large object➚](https://www.postgresql.org/docs/current/largeobjects.html) facility, wh"
  },
  {
    "path": "doc/Parameter-Type-Conversion.md",
    "chars": 5522,
    "preview": "# Parameter Type Conversion\n\nWhen [executing statements](Statement.md), you can pass any number of parameters after the "
  },
  {
    "path": "doc/Performance.md",
    "chars": 330,
    "preview": "# Performance\n\n**TODO**\n\n---\n\nThis document is part of [taoPQ](https://github.com/taocpp/taopq).\n\nCopyright (c) 2021-202"
  },
  {
    "path": "doc/Requirements.md",
    "chars": 2202,
    "preview": "# Requirements\n\n## Operating System Support\n\n* We support:\n  * [Windows➚](https://en.wikipedia.org/wiki/Microsoft_Window"
  },
  {
    "path": "doc/Result-Type-Conversion.md",
    "chars": 4920,
    "preview": "# Result Type Conversion\n\nDepending on what type of [statement](Statement.md) was executed, you receive a [result](Resul"
  },
  {
    "path": "doc/Result.md",
    "chars": 14972,
    "preview": "# Result\n\nWhen [executing statements](Statement.md) you receive a result object.\nA result comes in two flavours, dependi"
  },
  {
    "path": "doc/Statement.md",
    "chars": 7035,
    "preview": "# Statement\n\n:warning: Before showing you how to execute statements with taoPQ, we'd like to take a moment to talk about"
  },
  {
    "path": "doc/TOC.md",
    "chars": 7212,
    "preview": "# Table of Content\n\n* [Requirements](Requirements.md)\n  * [Operating System Support](Requirements.md#operator-system-sup"
  },
  {
    "path": "doc/Transaction.md",
    "chars": 7297,
    "preview": "# Transaction\n\nBefore we continue with our own documentation, we'd like to once again point you to the excellent [Postgr"
  },
  {
    "path": "example/CMakeLists.txt",
    "chars": 440,
    "preview": "cmake_minimum_required(VERSION 3.15)\n\nadd_subdirectory(get_version)\n\nset(EXAMPLE_TARGETS\n  taopq_example_get_version\n)\n\n"
  },
  {
    "path": "example/get_version/CMakeLists.txt",
    "chars": 248,
    "preview": "cmake_minimum_required(VERSION 3.15)\nproject(taopq_example_get_version CXX)\n\nadd_executable(${PROJECT_NAME} main.cpp)\nta"
  },
  {
    "path": "example/get_version/main.cpp",
    "chars": 880,
    "preview": "#include <cstdlib>\n#include <iostream>\n#include <string>\n#include <vector>\n\n#include <tao/pq.hpp>\n\nstatic std::string ge"
  },
  {
    "path": "include/tao/pq/access_mode.hpp",
    "chars": 955,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/binary.hpp",
    "chars": 1248,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/bind.hpp",
    "chars": 357,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/connection.hpp",
    "chars": 8830,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/connection_pool.hpp",
    "chars": 2682,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/connection_status.hpp",
    "chars": 887,
    "preview": "// Copyright (c) 2022-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/exception.hpp",
    "chars": 37608,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/field.hpp",
    "chars": 1608,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/aggregate.hpp",
    "chars": 4880,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/demangle.hpp",
    "chars": 722,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/exclusive_scan.hpp",
    "chars": 955,
    "preview": "// Copyright (c) 2019-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/format_as.hpp",
    "chars": 902,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/from_chars.hpp",
    "chars": 1378,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/gen.hpp",
    "chars": 1461,
    "preview": "// Copyright (c) 2019-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/parameter_traits_helper.hpp",
    "chars": 2757,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/poll.hpp",
    "chars": 500,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/pool.hpp",
    "chars": 4609,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/resize_uninitialized.hpp",
    "chars": 6541,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/strtox.hpp",
    "chars": 547,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/unreachable.hpp",
    "chars": 480,
    "preview": "// Copyright (c) 2020-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/internal/zsv.hpp",
    "chars": 891,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/is_aggregate.hpp",
    "chars": 593,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/is_array.hpp",
    "chars": 2217,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/isolation_level.hpp",
    "chars": 1239,
    "preview": "// Copyright (c) 2020-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/large_object.hpp",
    "chars": 2895,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/log.hpp",
    "chars": 4305,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/notification.hpp",
    "chars": 1211,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/null.hpp",
    "chars": 443,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/oid.hpp",
    "chars": 498,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter.hpp",
    "chars": 6183,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter_traits.hpp",
    "chars": 13999,
    "preview": "// Copyright (c) 2020-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter_traits_aggregate.hpp",
    "chars": 1567,
    "preview": "// Copyright (c) 2020-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter_traits_array.hpp",
    "chars": 2542,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter_traits_optional.hpp",
    "chars": 2378,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter_traits_pair.hpp",
    "chars": 2774,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/parameter_traits_tuple.hpp",
    "chars": 3040,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/pipeline.hpp",
    "chars": 1464,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/pipeline_status.hpp",
    "chars": 985,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/poll.hpp",
    "chars": 1052,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result.hpp",
    "chars": 10172,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_status.hpp",
    "chars": 2179,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_traits.hpp",
    "chars": 5503,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_traits_aggregate.hpp",
    "chars": 1846,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_traits_array.hpp",
    "chars": 2917,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_traits_optional.hpp",
    "chars": 1087,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_traits_pair.hpp",
    "chars": 855,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/result_traits_tuple.hpp",
    "chars": 1724,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/row.hpp",
    "chars": 8172,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/table_field.hpp",
    "chars": 1608,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/table_reader.hpp",
    "chars": 6676,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/table_row.hpp",
    "chars": 7530,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/table_writer.hpp",
    "chars": 3430,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/transaction.hpp",
    "chars": 3102,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/transaction_base.hpp",
    "chars": 5490,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/transaction_status.hpp",
    "chars": 1243,
    "preview": "// Copyright (c) 2022-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq/version.hpp",
    "chars": 403,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "include/tao/pq.hpp",
    "chars": 1337,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/connection.cpp",
    "chars": 23295,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/connection_pool.cpp",
    "chars": 1137,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/exception.cpp",
    "chars": 41768,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/field.cpp",
    "chars": 731,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/internal/demangle.cpp",
    "chars": 748,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/internal/poll.cpp",
    "chars": 3617,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/internal/strtox.cpp",
    "chars": 3232,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/large_object.cpp",
    "chars": 6780,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/parameter_traits.cpp",
    "chars": 1638,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/pipeline.cpp",
    "chars": 1112,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/result.cpp",
    "chars": 4192,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/result_traits.cpp",
    "chars": 4404,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/result_traits_array.cpp",
    "chars": 1346,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/row.cpp",
    "chars": 2753,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/table_field.cpp",
    "chars": 651,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/table_reader.cpp",
    "chars": 4975,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/table_row.cpp",
    "chars": 1837,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/table_writer.cpp",
    "chars": 2362,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/transaction.cpp",
    "chars": 4365,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "src/lib/pq/transaction_base.cpp",
    "chars": 3853,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/CMakeLists.txt",
    "chars": 1816,
    "preview": "cmake_minimum_required(VERSION 3.15)\n\noption(BUILD_INTEGRATION_TESTS \"Build integration tests that require a live Postgr"
  },
  {
    "path": "test/integration/aggregate.cpp",
    "chars": 1836,
    "preview": "// Copyright (c) 2020-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/array.cpp",
    "chars": 6989,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/basic_datatypes.cpp",
    "chars": 16030,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/chunk_mode.cpp",
    "chars": 3164,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/connection.cpp",
    "chars": 6945,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/connection_pool.cpp",
    "chars": 5369,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/example.cpp",
    "chars": 1998,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/exception.cpp",
    "chars": 1629,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/large_object.cpp",
    "chars": 5564,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/log.cpp",
    "chars": 6708,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/notifications.cpp",
    "chars": 2772,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/parameter.cpp",
    "chars": 2989,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/password.cpp",
    "chars": 1458,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/pipeline_mode.cpp",
    "chars": 5834,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/result.cpp",
    "chars": 10413,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/row.cpp",
    "chars": 4320,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/single_row_mode.cpp",
    "chars": 2234,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/table_reader.cpp",
    "chars": 6100,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/table_writer.cpp",
    "chars": 4708,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/traits.cpp",
    "chars": 6654,
    "preview": "// Copyright (c) 2020-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/integration/transaction.cpp",
    "chars": 7234,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/unit/getenv.cpp",
    "chars": 1052,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/unit/parameter_type.cpp",
    "chars": 4222,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/unit/resize_uninitialized.cpp",
    "chars": 2375,
    "preview": "// Copyright (c) 2021-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/unit/result_type.cpp",
    "chars": 4010,
    "preview": "// Copyright (c) 2023-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/unit/strtox.cpp",
    "chars": 6112,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/utils/compare.hpp",
    "chars": 801,
    "preview": "// Copyright (c) 2024-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/utils/getenv.hpp",
    "chars": 1976,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  },
  {
    "path": "test/utils/macros.hpp",
    "chars": 3222,
    "preview": "// Copyright (c) 2016-2026 Daniel Frey and Dr. Colin Hirsch\n// Distributed under the Boost Software License, Version 1.0"
  }
]

About this extraction

This page contains the full source code of the taocpp/taopq GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 146 files (586.6 KB), approximately 153.0k tokens, and a symbol index with 1002 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!