[
  {
    "path": ".clang-format",
    "content": "---\nLanguage: Cpp\nColumnLimit: 110\nIndentWidth: 4\nBreakBeforeBraces: Custom\nBraceWrapping:\n  AfterCaseLabel: true\n  AfterClass: true\n  AfterControlStatement: true\n  AfterEnum: true\n  AfterFunction: true\n  AfterNamespace: false\n  AfterStruct: true\n  AfterUnion: true\n  AfterExternBlock: false\n  BeforeCatch: true\n  BeforeElse: true\n  IndentBraces: false\n  SplitEmptyFunction: true\n  SplitEmptyRecord: true\n  SplitEmptyNamespace: true\nAccessModifierOffset: -4\nBinPackArguments: false\nBinPackParameters: false\nAlignAfterOpenBracket: BlockIndent\nPointerAlignment: Left\nIncludeBlocks: Regroup\nIncludeCategories:\n  - Regex: '^<boost/mysql/impl/.*'\n    Priority: -10\n    SortPriority: 3\n  - Regex: '^<boost/mysql/detail/.*>|^<boost/mysql/impl/.*'\n    Priority: -9\n    SortPriority: 2\n  - Regex: '^<boost/mysql.*\\.hpp>'\n    Priority: -8\n    SortPriority: 1\n  - Regex: '^<boost/.*\\.hpp>'\n    Priority: -7\n    SortPriority: 4\n  - Regex: \"^<.*\"\n    Priority: -6\n    SortPriority: 5\n  - Regex: \".*\"\n    Priority: -5\n    SortPriority: 6\nIndentCaseLabels: false\nAllowShortCaseLabelsOnASingleLine: true\nAllowAllArgumentsOnNextLine: false\nAllowAllParametersOfDeclarationOnNextLine: false\nAllowShortIfStatementsOnASingleLine: Never\nAllowShortLoopsOnASingleLine: false\nAlignArrayOfStructures: Left\nDerivePointerAlignment: false\nPenaltyBreakAssignment: 2000000\nPenaltyBreakBeforeFirstCallParameter: 0\nPenaltyBreakOpenParenthesis: 0\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyBreakTemplateDeclaration: 10\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 200000000\n\n# Defaults (based on Google)\nAlignConsecutiveMacros: false\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Left\nAlignOperands: true\nAlignTrailingComments: true\nAllowAllConstructorInitializersOnNextLine: true\nAllowShortBlocksOnASingleLine: Never\nAllowShortFunctionsOnASingleLine: All\nAllowShortLambdasOnASingleLine: All\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: true\nAlwaysBreakTemplateDeclarations: Yes\nBreakBeforeBinaryOperators: None\nBreakBeforeInheritanceComma: false\nBreakInheritanceList: BeforeColon\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nBreakConstructorInitializers: BeforeColon\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nCommentPragmas: '(^ IWYU pragma:)|(^\\\\copydoc )|(^ ?\\\\n)'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDeriveLineEnding: true\nDisableFormat: false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nForEachMacros:\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeIsMainRegex: null\nIncludeIsMainSourceRegex: \"\"\nIndentGotoLabels: true\nIndentPPDirectives: None\nIndentWrappedFunctionNames: false\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: false\nMacroBlockBegin: \"\"\nMacroBlockEnd: \"\"\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: None\nObjCBinPackProtocolList: Never\nObjCBlockIndentWidth: 2\nObjCSpaceAfterProperty: false\nObjCSpaceBeforeProtocolList: true\nRawStringFormats:\n  - Language: Cpp\n    Delimiters:\n      - cc\n      - CC\n      - cpp\n      - Cpp\n      - CPP\n      - \"c++\"\n      - \"C++\"\n    CanonicalDelimiter: \"\"\n    BasedOnStyle: google\n  - Language: TextProto\n    Delimiters:\n      - pb\n      - PB\n      - proto\n      - PROTO\n    EnclosingFunctions:\n      - EqualsProto\n      - EquivToProto\n      - PARSE_PARTIAL_TEXT_PROTO\n      - PARSE_TEST_PROTO\n      - PARSE_TEXT_PROTO\n      - ParseTextOrDie\n      - ParseTextProtoOrDie\n    CanonicalDelimiter: \"\"\n    BasedOnStyle: google\nReflowComments: true\nSortIncludes: true\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: false\nSpaceAfterLogicalNot: false\nSpaceAfterTemplateKeyword: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceInEmptyBlock: false\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 2\nSpacesInAngles: false\nSpacesInConditionalStatement: false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nSpaceBeforeSquareBrackets: false\nStandard: Auto\nStatementMacros:\n  - Q_UNUSED\n  - QT_REQUIRE_VERSION\nTabWidth: 8\nUseCRLF: false\nUseTab: Never\n---\n\n"
  },
  {
    "path": ".clangd",
    "content": "Diagnostics:\n  ClangTidy:\n    Remove: bugprone-unused-return-value"
  },
  {
    "path": ".codecov.yml",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Change how pull request comments look\ncomment:\n  layout: \"reach,diff,files,footer\"\ncodecov:\n  disable_default_path_fixes: true\n"
  },
  {
    "path": ".dockerignore",
    "content": ".cache/\n.cproject\n.project\n.settings/\n.pydevproject\nprivate/\nbuild*/\nout/\n.vs/\n.vscode/\ncompile_commands.json\n.cache/\ndoc/\ninclude/\n__build*/\n"
  },
  {
    "path": ".drone.star",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n_triggers = { \"branch\": [ \"master\", \"develop\" ] }\n_win_container_tag = 'e7bd656c3515263f9b3c69a2d73d045f6a0fed72'\n\n\ndef _image(name):\n    return 'ghcr.io/anarthal/cpp-ci-containers/{}'.format(name)\n\ndef _win_image(name):\n    return 'ghcr.io/anarthal-containers/{}:{}'.format(name, _win_container_tag)\n\n\ndef _b2_command(\n    source_dir,\n    toolset,\n    cxxstd,\n    variant,\n    server_host='127.0.0.1',\n    stdlib='native',\n    address_model='64',\n    separate_compilation=1,\n    use_ts_executor=0,\n    address_sanitizer=0,\n    undefined_sanitizer=0,\n    valgrind=0,\n    fail_if_no_openssl=1\n):\n    return 'python tools/ci/main.py ' + \\\n                '--source-dir=\"{}\" '.format(source_dir) + \\\n                'b2 ' + \\\n                '--server-host={} '.format(server_host) + \\\n                '--toolset={} '.format(toolset) + \\\n                '--cxxstd={} '.format(cxxstd) + \\\n                '--variant={} '.format(variant) + \\\n                '--stdlib={} '.format(stdlib) + \\\n                '--address-model={} '.format(address_model) + \\\n                '--separate-compilation={} '.format(separate_compilation) + \\\n                '--use-ts-executor={} '.format(use_ts_executor) + \\\n                '--address-sanitizer={} '.format(address_sanitizer) + \\\n                '--undefined-sanitizer={} '.format(undefined_sanitizer) + \\\n                '--valgrind={} '.format(valgrind) + \\\n                '--fail-if-no-openssl={} '.format(fail_if_no_openssl)\n\n\ndef _cmake_command(\n    source_dir,\n    server_host='127.0.0.1',\n    generator='Ninja',\n    cmake_build_type='Debug',\n    build_shared_libs=0,\n    cxxstd='20',\n    install_test=1\n):\n    return 'python tools/ci/main.py ' + \\\n                '--source-dir=\"{}\" '.format(source_dir) + \\\n                'cmake ' + \\\n                '--server-host={} '.format(server_host) + \\\n                '--generator=\"{}\" '.format(generator) + \\\n                '--cmake-build-type={} '.format(cmake_build_type) + \\\n                '--build-shared-libs={} '.format(build_shared_libs) + \\\n                '--cxxstd={} '.format(cxxstd) + \\\n                '--install-test={} '.format(install_test)\n\n\ndef _find_package_b2_command(source_dir, generator):\n    return 'python tools/ci/main.py ' + \\\n                '--source-dir=\"{}\" '.format(source_dir) + \\\n                'find-package-b2 ' + \\\n                '--generator=\"{}\" '.format(generator)\n\n\ndef _pipeline(\n    name,\n    image,\n    os,\n    command,\n    db,\n    arch='amd64',\n    disable_aslr=False\n):\n    steps = []\n    if disable_aslr:\n        steps.append({\n            \"name\": \"Disable ASLR\",\n            \"image\": image,\n            \"pull\": \"if-not-exists\",\n            \"privileged\": True,\n            \"commands\": [\"echo 0 | tee /proc/sys/kernel/randomize_va_space\"]\n        })\n    steps.append({\n        \"name\": \"Build and run\",\n        \"image\": image,\n        \"pull\": \"if-not-exists\",\n        \"privileged\": arch == \"arm64\", # TSAN tests fail otherwise (personality syscall)\n        \"volumes\":[{\n            \"name\": \"mysql-socket\",\n            \"path\": \"/var/run/mysqld\"\n        }] if db != None else [],\n        \"commands\": [command]\n    })\n\n    return {\n        \"name\": name,\n        \"kind\": \"pipeline\",\n        \"type\": \"docker\",\n        \"trigger\": _triggers,\n        \"platform\": {\n            \"os\": os,\n            \"arch\": arch\n        },\n        \"clone\": {\n            \"retries\": 5\n        },\n        \"node\": {},\n        \"steps\": steps,\n        \"services\": [{\n            \"name\": \"mysql\",\n            \"image\": \"ghcr.io/anarthal/cpp-ci-containers/{}\".format(db),\n            \"volumes\": [{\n                \"name\": \"mysql-socket\",\n                \"path\": \"/var/run/mysqld\"\n            }]\n        }] if db != None else [],\n        \"volumes\": [{\n            \"name\": \"mysql-socket\",\n            \"temp\": {}\n        }] if db != None else []\n    }\n\n\ndef linux_b2(\n    name,\n    image,\n    toolset,\n    cxxstd,\n    variant='debug,release',\n    stdlib='native',\n    address_model='64',\n    separate_compilation=1,\n    use_ts_executor = 0,\n    address_sanitizer=0,\n    undefined_sanitizer=0,\n    valgrind=0,\n    arch='amd64',\n    fail_if_no_openssl=1,\n    db='mysql-8_4_1:1',\n):\n    command = _b2_command(\n        source_dir='$(pwd)',\n        toolset=toolset,\n        cxxstd=cxxstd,\n        variant=variant,\n        stdlib=stdlib,\n        address_model=address_model,\n        server_host='mysql',\n        separate_compilation=separate_compilation,\n        use_ts_executor=use_ts_executor,\n        address_sanitizer=address_sanitizer,\n        undefined_sanitizer=undefined_sanitizer,\n        valgrind=valgrind,\n        fail_if_no_openssl=fail_if_no_openssl\n    )\n    return _pipeline(\n        name=name,\n        image=image,\n        os='linux',\n        command=command,\n        db=db,\n        arch=arch,\n        disable_aslr=True\n    )\n\n\ndef windows_b2(\n    name,\n    image,\n    toolset,\n    cxxstd,\n    variant,\n    address_model = '64',\n    use_ts_executor = 0\n):\n    command = _b2_command(\n        source_dir='$Env:DRONE_WORKSPACE',\n        toolset=toolset,\n        cxxstd=cxxstd,\n        variant=variant,\n        address_model=address_model,\n        server_host='127.0.0.1',\n        use_ts_executor=use_ts_executor\n    )\n    return _pipeline(name=name, image=image, os='windows', command=command, db=None)\n\n\ndef linux_cmake(\n    name,\n    image,\n    db='mysql-8_4_1:1',\n    build_shared_libs=0,\n    cmake_build_type='Debug',\n    cxxstd='20',\n    install_test=1\n):\n    command = _cmake_command(\n        source_dir='$(pwd)',\n        build_shared_libs=build_shared_libs,\n        cmake_build_type=cmake_build_type,\n        cxxstd=cxxstd,\n        server_host='mysql',\n        install_test=install_test\n    )\n    return _pipeline(name=name, image=image, os='linux', command=command, db=db)\n\n\ndef linux_cmake_noopenssl(name):\n    command = 'python tools/ci/main.py ' + \\\n                '--source-dir=$(pwd) ' + \\\n                'cmake-noopenssl ' + \\\n                '--generator=Ninja '\n    return _pipeline(name=name, image=_image('build-noopenssl:1'), os='linux', command=command, db=None)\n\n\ndef linux_cmake_nointeg(name):\n    command = 'python tools/ci/main.py ' + \\\n                '--source-dir=$(pwd) ' + \\\n                'cmake-nointeg ' + \\\n                '--generator=Ninja '\n    return _pipeline(name=name, image=_image('build-gcc13:1'), os='linux', command=command, db=None)\n\n\ndef windows_cmake(\n    name,\n    build_shared_libs=0\n):\n    command = _cmake_command(\n        source_dir='$Env:DRONE_WORKSPACE',\n        build_shared_libs=build_shared_libs,\n        generator='Visual Studio 17 2022',\n        server_host='127.0.0.1'\n    )\n    return _pipeline(\n        name=name,\n        image=_win_image('build-msvc14_3'),\n        os='windows',\n        command=command,\n        db=None\n    )\n\n\ndef find_package_b2_linux(name):\n    command = _find_package_b2_command(source_dir='$(pwd)', generator='Ninja')\n    return _pipeline(name=name, image=_image('build-gcc13:1'), os='linux', command=command, db=None)\n\n\ndef find_package_b2_windows(name):\n    command = _find_package_b2_command(source_dir='$Env:DRONE_WORKSPACE', generator='Visual Studio 17 2022')\n    return _pipeline(name=name, image=_win_image('build-msvc14_3'), os='windows', command=command, db=None)\n\n\ndef bench(name):\n    command = 'python tools/ci/main.py ' + \\\n                '--source-dir=\"$(pwd)\" ' + \\\n                'bench ' + \\\n                '--server-host=mysql ' + \\\n                '--connection-pool-iters=1 ' + \\\n                '--protocol-iters=1 '\n    return _pipeline(name=name, image=_image('build-bench:1'), os='linux', command=command, db='mysql-8_4_1:1')\n\n\ndef docs(name):\n    return _pipeline(\n        name=name,\n        image=_image('build-docs'),\n        os='linux',\n        command='python tools/ci/main.py --source-dir=$(pwd) docs',\n        db=None\n    )\n\n\ndef main(ctx):\n    return [\n        # CMake Linux\n        linux_cmake('Linux CMake MySQL 5.x',      _image('build-gcc14:1'), db='mysql-5_7_41:1',   build_shared_libs=0),\n        linux_cmake('Linux CMake MariaDB',        _image('build-gcc14:1'), db='mariadb-11_4_2:1', build_shared_libs=1),\n        linux_cmake('Linux CMake cmake 3.8',      _image('build-cmake3_8:3'), cxxstd='11', install_test=0),\n        linux_cmake('Linux CMake gcc Release',    _image('build-gcc14:1'), cmake_build_type='Release'),\n        linux_cmake('Linux CMake gcc MinSizeRel', _image('build-gcc14:1'), cmake_build_type='MinSizeRel'),\n        linux_cmake_noopenssl('Linux CMake no OpenSSL'),\n        linux_cmake_nointeg('Linux CMake without integration tests'),\n\n        # CMake Windows\n        windows_cmake('Windows CMake static', build_shared_libs=0),\n        windows_cmake('Windows CMake shared', build_shared_libs=1),\n\n        # find_package with B2 distribution\n        find_package_b2_linux('Linux find_package b2 distribution'),\n        find_package_b2_windows('Windows find_package b2 distribution'),\n\n        # B2 Linux. Please try to keep this below 3 configurations per build so CI doesn't take forever\n        # Default Ubuntu compilers:\n        #   Ubuntu 16.04: gcc5,  clang 3.8\n        #   Ubuntu 18.04: gcc7,  clang 7\n        #   Ubuntu 20.04: gcc9,  clang 10\n        #   Ubuntu 22.04: gcc11, clang 14\n        #   Ubuntu 24.04: gcc13, clang 18\n        linux_b2('Linux B2 clang-4',              _image('build-clang4:1'),        toolset='clang-4',   cxxstd='14'),\n        linux_b2('Linux B2 clang-5-honly-dbg',    _image('build-clang5:1'),        toolset='clang-5',   cxxstd='14', separate_compilation=0),\n        linux_b2('Linux B2 clang-6',              _image('build-clang5:1'),        toolset='clang-5',   cxxstd='14'),\n        linux_b2('Linux B2 clang-7',              _image('build-clang7:2'),        toolset='clang-7',   cxxstd='14,17'),\n        linux_b2('Linux B2 clang-8',              _image('build-clang8:2'),        toolset='clang-8',   cxxstd='14', variant='debug', address_sanitizer=1, undefined_sanitizer=1),\n        linux_b2('Linux B2 clang-9',              _image('build-clang9:2'),        toolset='clang-9',   cxxstd='17', variant='release'),\n        linux_b2('Linux B2 clang-10',             _image('build-clang10:2'),       toolset='clang-10',  cxxstd='17,20', variant='debug'),\n        linux_b2('Linux B2 clang-11',             _image('build-clang11:2'),       toolset='clang-11',  cxxstd='20'),\n        linux_b2('Linux B2 clang-12',             _image('build-clang12:2'),       toolset='clang-12',  cxxstd='20', variant='debug', stdlib='libc++', address_sanitizer=1, undefined_sanitizer=1),\n        linux_b2('Linux B2 clang-13',             _image('build-clang13:1'),       toolset='clang-13',  cxxstd='20', db='mysql-9_4_0:1'),\n        linux_b2('Linux B2 clang-14',             _image('build-clang14:1'),       toolset='clang-14',  cxxstd='20', variant='debug'),\n        linux_b2('Linux B2 clang-15',             _image('build-clang15:1'),       toolset='clang-15',  cxxstd='20', variant='debug'),\n        linux_b2('Linux B2 clang-16',             _image('build-clang16:1'),       toolset='clang-16',  cxxstd='20', variant='debug', address_sanitizer=1, undefined_sanitizer=1),\n        linux_b2('Linux B2 clang-17-honly-rls',   _image('build-clang17:1'),       toolset='clang-17',  cxxstd='20', variant='release', separate_compilation=0),\n        linux_b2('Linux B2 clang-18-honly-dbg',   _image('build-clang18:1'),       toolset='clang-18',  cxxstd='20', variant='debug', separate_compilation=0),\n        linux_b2('Linux B2 clang-19-libc++',      _image('build-clang19:1'),       toolset='clang-19',  cxxstd='23', stdlib='libc++'),\n        linux_b2('Linux B2 clang-20',             _image('build-clang20:1'),       toolset='clang-20',  cxxstd='23'),\n        linux_b2('Linux B2 clang-sanit',          _image('build-clang20:1'),       toolset='clang-20',  cxxstd='20', variant='debug', address_sanitizer=1, undefined_sanitizer=1),\n        linux_b2('Linux B2 clang-i386-sanit',     _image('build-clang16-i386:1'),  toolset='clang-16',  cxxstd='20', variant='debug', address_model='32', address_sanitizer=1, undefined_sanitizer=1),\n\n        linux_b2('Linux B2 gcc-5',                _image('build-gcc5:1'),          toolset='gcc-5',     cxxstd='11'), # gcc-5 C++14 doesn't like my constexpr field_view\n        linux_b2('Linux B2 gcc-5-ts-executor',    _image('build-gcc5:1'),          toolset='gcc-5',     cxxstd='11', use_ts_executor=1),\n        linux_b2('Linux B2 gcc-6-honly-dbg',      _image('build-gcc6:1'),          toolset='gcc-6',     cxxstd='14', variant='debug', separate_compilation=0),\n        linux_b2('Linux B2 gcc-7',                _image('build-gcc7:1'),          toolset='gcc-7',     cxxstd='14,17', variant='debug'),\n        linux_b2('Linux B2 gcc-8',                _image('build-gcc8:1'),          toolset='gcc-8',     cxxstd='17'),\n        linux_b2('Linux B2 gcc-9',                _image('build-gcc9:1'),          toolset='gcc-9',     cxxstd='14,17', variant='debug'),\n        linux_b2('Linux B2 gcc-10',               _image('build-gcc10:1'),         toolset='gcc-10',    cxxstd='17'),\n        linux_b2('Linux B2 gcc-11',               _image('build-gcc11:1'),         toolset='gcc-11',    cxxstd='20'),\n        linux_b2('Linux B2 gcc-12',               _image('build-gcc12:1'),         toolset='gcc-12',    cxxstd='20,23', variant='debug'),\n        linux_b2('Linux B2 gcc-13',               _image('build-gcc13:1'),         toolset='gcc-13',    cxxstd='20', db='mysql-9_4_0:1'),\n        linux_b2('Linux B2 gcc-14',               _image('build-gcc14:1'),         toolset='gcc-14',    cxxstd='23'),\n        linux_b2('Linux B2 gcc-15',               _image('build-gcc15:1'),         toolset='gcc-15',    cxxstd='23'),\n        linux_b2('Linux B2 gcc-sanit',            _image('build-gcc14:1'),         toolset='gcc-14',    cxxstd='23', variant='debug', address_sanitizer=1, undefined_sanitizer=1),\n        linux_b2('Linux B2 gcc-valgrind',         _image('build-gcc14:1'),         toolset='gcc-14',    cxxstd='23', variant='debug', valgrind=1),\n        linux_b2('Linux B2 gcc-11-arm64',         _image('build-gcc11:1'),         toolset='gcc-11',    cxxstd='20', arch='arm64', variant='release'),\n        linux_b2('Linux B2 gcc-11-arm64-sanit',   _image('build-gcc11:1'),         toolset='gcc-11',    cxxstd='20', arch='arm64', variant='debug'),\n        linux_b2('Linux B2 noopenssl',            _image('build-noopenssl:1'),     toolset='gcc',       cxxstd='11', fail_if_no_openssl=0),\n\n        # B2 Windows\n        windows_b2('Windows B2 msvc14.1 32-bit',      _win_image('build-msvc14_1'), toolset='msvc-14.1', cxxstd='11,14,17', variant='release',       address_model='32'),\n        windows_b2('Windows B2 msvc14.1 64-bit',      _win_image('build-msvc14_1'), toolset='msvc-14.1', cxxstd='14,17',    variant='release'),\n        windows_b2('Windows B2 msvc14.2',             _win_image('build-msvc14_2'), toolset='msvc-14.2', cxxstd='14,17',    variant='release'),\n        windows_b2('Windows B2 msvc14.3',             _win_image('build-msvc14_3'), toolset='msvc-14.3', cxxstd='17,20',    variant='debug,release'),\n        windows_b2('Windows B2 msvc14.3-ts-executor', _win_image('build-msvc14_3'), toolset='msvc-14.3', cxxstd='20',       variant='release',       use_ts_executor=1),\n\n        # Benchmarks\n        bench('Benchmarks'),\n\n        # Docs\n        docs('Linux docs')\n    ]\n\n"
  },
  {
    "path": ".github/workflows/build-code.yml",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nname: Build\n\non:\n  push:\n    branches: [develop, master]\n    tags: ['*']\n  pull_request:\n  workflow_dispatch:\n\n\njobs:\n  osx:\n    runs-on: macos-latest\n    steps:\n      - uses: actions/checkout@v4\n      - run: |\n          unlink /usr/local/bin/python || echo \"/usr/local/bin/python not found\"\n          ln -s /usr/local/bin/python3 /usr/local/bin/python\n          cp tools/user-config-osx-gha.jam ~/user-config.jam\n          python -m pip install requests\n          source tools/setup_db_osx.sh\n          python tools/ci/main.py \\\n            --source-dir=$(pwd) \\\n            b2 \\\n            --toolset=clang \\\n            --cxxstd=20 \\\n            --variant=debug,release\n"
  },
  {
    "path": ".github/workflows/coverage.yml",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nname: coverage\n\non:\n  push:\n    branches: [develop, master]\n    tags: [\"*\"]\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  coverage:\n    runs-on: ubuntu-latest\n    container:\n      image: ghcr.io/anarthal/cpp-ci-containers/build-gcc14-lcov:1\n      volumes:\n        - /var/run/mysqld:/var/run/mysqld\n    services:\n      mysql:\n        image: ghcr.io/anarthal/cpp-ci-containers/mysql-8_4_1:1\n        ports:\n          - 3306:3306\n        volumes:\n          - /var/run/mysqld:/var/run/mysqld\n    steps:\n      - name: Fetch code\n        uses: actions/checkout@v4\n\n      - name: Build code\n        run: |\n          python tools/ci/main.py \\\n            --source-dir=$(pwd) \\\n            b2 \\\n            --server-host=mysql \\\n            --toolset=gcc \\\n            --cxxstd=20 \\\n            --variant=debug \\\n            --disable-local-sockets=off,on \\\n            --coverage=1\n\n      - name: Generate coverage reports\n        shell: bash\n        run: |\n          cd ~/boost-root/bin.v2\n          lcov \\\n            --rc branch_coverage=0 \\\n            --rc geninfo_unexecuted_blocks=1 \\\n            --ignore-errors mismatch \\\n            --gcov-tool gcov-14 \\\n            --directory . \\\n            --capture \\\n            --output-file all.info\n          lcov \\\n            --rc branch_coverage=0 \\\n            --output-file coverage.info \\\n            --extract all.info '*/boost/mysql*'\n          sed \"s|^SF:$HOME/boost-root/|SF:include/|g\" coverage.info > $GITHUB_WORKSPACE/coverage.info\n\n      - name: Upload coverage reports\n        uses: codecov/codecov-action@v4\n        with:\n          verbose: true\n          fail_ci_if_error: true\n          token: ${{ secrets.CODECOV_TOKEN }}\n          plugins: noop # Don't run gcov again, codecov doesn't know about the filtering we perform\n          file: coverage.info\n          disable_search: true # Don't upload unwanted files\n          disable_file_fixes: true # Default fixes make reports unusable\n\n"
  },
  {
    "path": ".github/workflows/docker-windows.yml",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nname: Build Docker Windows images\n\non:\n  workflow_dispatch:\n  push:\n    paths:\n      - tools/docker/build-msvc.dockerfile\n\n\njobs:\n  docker-windows:\n    strategy:\n      matrix:\n        include:\n          - { image: build-msvc14_1, base-image: \"cppalliance/dronevs2017:1\" }\n          - { image: build-msvc14_2, base-image: \"cppalliance/dronevs2019:1\" }\n          - { image: build-msvc14_3, base-image: \"cppalliance/dronevs2022:1\" }\n\n    permissions:\n      contents: read\n      packages: write\n\n    runs-on: windows-2019\n\n    defaults:\n      run:\n        shell: bash\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Log in to the Container registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: anarthal-containers\n          password: ${{ secrets.ANARTHAL_CONTAINERS_TOKEN }}\n      \n      - name: Build and push Docker image\n        run: |\n          FULL_IMAGE=ghcr.io/anarthal-containers/${{ matrix.image }}\n          docker build -f tools/docker/build-msvc.dockerfile --build-arg BASE_IMAGE=${{ matrix.base-image }} -t $FULL_IMAGE:$GITHUB_SHA -t $FULL_IMAGE:latest .\n          docker push $FULL_IMAGE --all-tags"
  },
  {
    "path": ".github/workflows/fuzz.yml",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nname: fuzz\n\non:\n  push:\n    branches: [develop, master]\n    tags: ['*']\n  pull_request:\n  workflow_dispatch:\n  schedule:\n    - cron: \"25 00 * * *\"\n\njobs:\n  fuzz:\n    runs-on: ubuntu-latest\n    container:\n      image: ghcr.io/anarthal/cpp-ci-containers/build-clang18:1\n      volumes:\n        - /var/run/mysqld:/var/run/mysqld\n    services:\n      mysql:\n        image: ghcr.io/anarthal/cpp-ci-containers/mysql-8_4_1:1\n        ports:\n          - 3306:3306\n        volumes:\n          - /var/run/mysqld:/var/run/mysqld\n    steps:\n      - name: Fetch code\n        uses: actions/checkout@v4\n\n      - name: Restore corpus\n        uses: actions/cache@v4\n        with:\n          path: /tmp/corpus.tar.gz\n          key: corpus-${{ github.run_id }}\n          restore-keys: corpus-\n        \n      # Note: this will take care of using the corpus and updating it\n      - name: Build and run the fuzzer\n        run: |\n          python tools/ci/main.py \\\n            --source-dir=$(pwd) \\\n            fuzz \\\n            --server-host=mysql\n\n      - name: Archive any crashes as an artifact\n        uses: actions/upload-artifact@v4\n        if: always()\n        with:\n          name: crashes\n          path: |\n            ~/boost-root/crash-*\n            ~/boost-root/leak-*\n            ~/boost-root/timeout-*\n          if-no-files-found: ignore\n"
  },
  {
    "path": ".gitignore",
    "content": "/__build/\n.cproject\n.project\n.settings/\n.pydevproject\n/private/\nCMakeSettings.json\nout/\n.vs/\ndoc/html/\ndoc/qbk/reference.qbk\n.vscode/\ncompile_commands.json\n.cache/\n__build*__/\n__pycache__/\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\ncmake_minimum_required(VERSION 3.8...3.22)\n\n# Project\nproject(boost_mysql VERSION \"${BOOST_SUPERPROJECT_VERSION}\" LANGUAGES CXX)\n\n# Library\nadd_library(boost_mysql INTERFACE)\nadd_library(Boost::mysql ALIAS boost_mysql)\n\n# Dependencies. If non-Boost dependencies are not found, we just bail out\nfind_package(Threads)\nif(NOT Threads_FOUND)\n    message(STATUS \"Boost.MySQL has been disabled, because the required package Threads hasn't been found\")\n    return()\nendif()\nfind_package(OpenSSL)\nif(NOT OpenSSL_FOUND)\n    message(STATUS \"Boost.MySQL has been disabled, because the required package OpenSSL hasn't been found\")\n    return()\nendif()\n\n# This is generated by boostdep.\n# Note that Boost::pfr is not listed because it's a peer dependency\ntarget_link_libraries(\n    boost_mysql\n    INTERFACE\n    Boost::asio\n    Boost::assert\n    Boost::charconv\n    Boost::compat\n    Boost::config\n    Boost::container\n    Boost::core\n    Boost::describe\n    Boost::endian\n    Boost::intrusive\n    Boost::mp11\n    Boost::optional\n    Boost::system\n    Boost::throw_exception\n    Boost::variant2\n    Threads::Threads\n    OpenSSL::Crypto\n    OpenSSL::SSL\n)\n\n# Includes & features\ntarget_include_directories(boost_mysql INTERFACE include)\ntarget_compile_features(boost_mysql INTERFACE cxx_std_11)\n\n# Don't run integration testing unless explicitly requested, since these require a running MySQL server\noption(BOOST_MYSQL_INTEGRATION_TESTS OFF \"Whether to build and run integration tests or not\")\nmark_as_advanced(BOOST_MYSQL_INTEGRATION_TESTS)\n\n# List of server features that the CI DB server does not support.\n# Disables running some integration tests and examples\nset(BOOST_MYSQL_DISABLED_SERVER_FEATURES \"\" CACHE STRING\n    \"A CMake list of server features not supported by the CI server, for integration tests\"\n)\nmark_as_advanced(BOOST_MYSQL_DISABLED_SERVER_FEATURES)\n\n# Don't build benchmarks unless explicitly requested, since these require the official\n# MySQL and MariaDB client libraries\noption(BOOST_MYSQL_BENCH OFF \"Whether to build the benchmarks\")\nmark_as_advanced(BOOST_MYSQL_BENCH)\n\n# Examples and tests\nif(BUILD_TESTING)\n    # Contains some functions to share code between examples and tests\n    include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils.cmake)\n\n    # Custom target tests; required by the Boost superproject\n    if(NOT TARGET tests)\n        add_custom_target(tests)\n    endif()\n\n    # Tests\n    add_subdirectory(test)\n    \n    # All examples require a real server to run\n    if (BOOST_MYSQL_INTEGRATION_TESTS)\n        add_subdirectory(example)\n    endif()\nendif()\n\nif (BOOST_MYSQL_BENCH)\n    include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/utils.cmake)\n    add_subdirectory(bench)\nendif()\n"
  },
  {
    "path": "LICENSE_1_0.txt",
    "content": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Boost.MySQL\n\nBranch | Windows/Linux Build | OSX build | Coverage | Documentation\n-------|---------------------|-----------|--------- | -------------\n[`master`](https://github.com/boostorg/mysql/tree/master)   | [![Build Status](https://drone.cpp.al/api/badges/boostorg/mysql/status.svg)](https://drone.cpp.al/boostorg/mysql)                        | [![Build Status](https://github.com/boostorg/mysql/actions/workflows/build-code.yml/badge.svg)](https://github.com/boostorg/mysql)                | [![codecov](https://codecov.io/gh/boostorg/mysql/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/mysql/branch/master)   | [Docs for master](https://www.boost.org/doc/libs/master/libs/mysql/doc/html/index.html)\n[`develop`](https://github.com/boostorg/mysql/tree/develop) | [![Build Status](https://drone.cpp.al/api/badges/boostorg/mysql/status.svg?ref=refs/heads/develop)](https://drone.cpp.al/boostorg/mysql) | [![Build Status](https://github.com/boostorg/mysql/actions/workflows/build-code.yml/badge.svg?branch=develop)](https://github.com/boostorg/mysql) | [![codecov](https://codecov.io/gh/boostorg/mysql/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/mysql/branch/develop) | [Docs for develop](https://www.boost.org/doc/libs/develop/libs/mysql/doc/html/index.html)\n\nBoost.MySQL is a C++11 client for MySQL and MariaDB database servers, based on Boost.Asio.\nBoost.MySQL is part of Boost.\n\n## Breaking changes in Boost 1.85\n\nBoost.MySQL now requires linking with Boost.Charconv, which is a compiled library.\nIf you're getting link errors, link your executable to the `Boost::charconv` CMake target.\nNo C++ code changes are required.\n\n## Feedback\n\nDo you have any suggestion? Would you like to share a bad or good experience while using the library?\nPlease comment [on this issue](https://github.com/boostorg/mysql/issues/140).\n\n## Why another MySQL C++ client?\n\n- It is fully compatible with Boost.Asio and integrates well with any other\n  library in the Boost.Asio ecosystem (like Boost.Beast).\n- It supports Boost.Asio's universal asynchronous model, which means you can\n  go asynchronous using callbacks, futures or coroutines (including C++20 coroutines).\n- It is written in C++11 and takes advantage of it.\n- It is header only.\n\n## Using the library\n\nTo use this library, you need:\n\n- Boost 1.82 or higher (Boost.MySQL doesn't work with standalone Asio).\n- A C++11 capable compiler.\n- OpenSSL.\n\nThe library is header-only, but it depends on other Boost header-only libraries and on OpenSSL.\nTo use the library, install Boost the way you would normally do (e.g. via `b2 install`), and create\na `CMakeLists.txt` like this (replace `main` by your executable name and `main.cpp` by your list of source files):\n\n```cmake\nproject(boost_mysql_example LANGUAGES CXX)\n\nfind_package(Boost REQUIRED COMPONENTS charconv)\nfind_package(Threads REQUIRED)\nfind_package(OpenSSL REQUIRED)\n\nadd_executable(main main.cpp)\ntarget_link_libraries(main PRIVATE Boost::charconv Threads::Threads OpenSSL::Crypto OpenSSL::SSL)\n```\n\n## Tested with\n\nBoost.MySQL has been tested with the following compilers:\n\n- gcc 5 to 15.\n- clang 4 to 20.\n- msvc 14.1, 14.2 and 14.3.\n\nAnd with the following databases:\n\n- MySQL v5.7.41.\n- MySQL v8.4.1.\n- MariaDB v11.4.2.\n\n## Features\n\n- Text queries (execution of text SQL queries and data retrieval).\n  MySQL refers to this as the \"text protocol\", as all information is passed using text\n  (as opposed to prepared statements, see below).\n- Prepared statements. MySQL refers to this as the \"binary protocol\", as the result\n  of executing a prepared statement is sent in binary format rather than in text.\n- Stored procedures.\n- Authentication methods (authentication plugins): mysql_native_password and\n  caching_sha2_password. These are the default methods in MySQL 5/MariaDB and MySQL 8,\n  respectively.\n- Encrypted connections (TLS).\n- TCP and UNIX socket transports.\n- Connection pools.\n- Friendly client-side generated SQL.\n- (Experimental) pipelines.\n"
  },
  {
    "path": "bench/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Utility target\nadd_custom_target(boost_mysql_bench)\n\n# Find libraries required by the official clients\nfind_package(OpenSSL REQUIRED)\n\n# Find libmysqlclient. This script has only been tested on Ubuntu Linux, where benchmarks are performed.\nfind_path(LIBMYSQLCLIENT_INCLUDE_DIR mysql/mysql.h)\nif (NOT LIBMYSQLCLIENT_INCLUDE_DIR)\n    message(FATAL_ERROR \"Could not find libmysqlclient includes\")\nendif()\nfind_library(LIBMYSQLCLIENT_LIBRARY mysqlclient)\nif (NOT LIBMYSQLCLIENT_LIBRARY)\n    message(FATAL_ERROR \"Could not find the libmysqlclient library binary\")\nendif()\nadd_library(boost_mysql_libmysqlclient SHARED IMPORTED)\nset_property(TARGET boost_mysql_libmysqlclient PROPERTY IMPORTED_LOCATION ${LIBMYSQLCLIENT_LIBRARY})\ntarget_include_directories(boost_mysql_libmysqlclient INTERFACE ${LIBMYSQLCLIENT_INCLUDE_DIR})\ntarget_link_libraries(boost_mysql_libmysqlclient INTERFACE OpenSSL::SSL OpenSSL::Crypto)\n\n# Find libmariadb\nfind_path(LIBMARIADB_INCLUDE_DIR mariadb/mysql.h)\nif (NOT LIBMARIADB_INCLUDE_DIR)\n    message(FATAL_ERROR \"Could not find libmariadb includes\")\nendif()\nfind_library(LIBMARIADB_LIBRARY mariadb)\nif (NOT LIBMARIADB_LIBRARY)\n    message(FATAL_ERROR \"Could not find the libmariadb library binary\")\nendif()\nadd_library(boost_mysql_libmariadb SHARED IMPORTED)\nset_property(TARGET boost_mysql_libmariadb PROPERTY IMPORTED_LOCATION ${LIBMARIADB_LIBRARY})\ntarget_include_directories(boost_mysql_libmariadb INTERFACE ${LIBMARIADB_INCLUDE_DIR})\ntarget_link_libraries(boost_mysql_libmariadb INTERFACE OpenSSL::SSL OpenSSL::Crypto)\n\n# Adds a benchmark target - pass the libraries to link to as extra args\nfunction (add_bench cpp_name)\n    set(target_name \"boost_mysql_bench_${cpp_name}\")\n    add_executable(${target_name} ${cpp_name}.cpp)\n    target_link_libraries(${target_name} PUBLIC ${ARGN})\n    boost_mysql_common_target_settings(${target_name})\n    add_dependencies(boost_mysql_bench ${target_name})\nendfunction()\n\n# We use the header-only version here because it's slightly faster\n# and to avoid dependencies to the test CMake scripts\n\n# Connection pool\nadd_bench(connection_pool boost_mysql)\n\n# Protocol benchmarks\nadd_bench(one_small_row_boost boost_mysql)\nadd_bench(one_small_row_libmysqlclient boost_mysql_libmysqlclient)\nadd_bench(one_small_row_libmariadb boost_mysql_libmariadb)\n\nadd_bench(one_big_row_boost boost_mysql)\nadd_bench(one_big_row_libmysqlclient boost_mysql_libmysqlclient)\nadd_bench(one_big_row_libmariadb boost_mysql_libmariadb)\n\nadd_bench(many_rows_boost boost_mysql)\nadd_bench(many_rows_libmysqlclient boost_mysql_libmysqlclient)\nadd_bench(many_rows_libmariadb boost_mysql_libmariadb)\n\nadd_bench(stmt_params_boost boost_mysql)\nadd_bench(stmt_params_libmysqlclient boost_mysql_libmysqlclient)\nadd_bench(stmt_params_libmariadb boost_mysql_libmariadb)\n"
  },
  {
    "path": "bench/bench.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Benchmark data processing\\n\",\n    \"\\n\",\n    \"Contains the code required to plot the figures in the docs.\\n\",\n    \"\\n\",\n    \"* Build the benchmarks with CMake, using the `BOOST_MYSQL_BENCH` CMake option and the `boost_mysql_bench` CMake target.\\n\",\n    \"* Run the benchmarks with `tools/ci/run_benchmarks.py`, which leaves a .txt file with the results in the current directory.\\n\",\n    \"* Run this notebook to generate the graphs.\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import pandas as pd\\n\",\n    \"from matplotlib import pyplot as plt\\n\",\n    \"\\n\",\n    \"df = pd.read_csv('../private/benchmark-results.txt', header=None) # Update file path as required\\n\",\n    \"df = df.set_index(df.index.map(lambda x: x % df.groupby(0).size()[0]))\\n\",\n    \"df = df.pivot(columns=[0], values=[1])\\n\",\n    \"df.columns = df.columns.get_level_values(0)\\n\",\n    \"df\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"def plot_result(df: pd.DataFrame, bench: str, title: str, ax):\\n\",\n    \"    cols = [f'{bench}_boost', f'{bench}_libmysqlclient', f'{bench}_libmariadb']\\n\",\n    \"    df = df[cols].rename(columns={\\n\",\n    \"        f'{bench}_boost': 'Boost.MySQL',\\n\",\n    \"        f'{bench}_libmysqlclient': 'libmysqlclient',\\n\",\n    \"        f'{bench}_libmariadb': 'libmariadb'\\n\",\n    \"    })\\n\",\n    \"    mean_val = round(df.mean().mean())\\n\",\n    \"    df.plot.box(ylim=(mean_val-150, mean_val+150), ax=ax, title=title, ylabel='Time (ms)')\\n\",\n    \"\\n\",\n    \"\\n\",\n    \"fig, _ = plt.subplots(2, 2, figsize=(15, 15))\\n\",\n    \"\\n\",\n    \"plot_result(df, bench='one_small_row', title='Reading one small row', ax=fig.axes[0])\\n\",\n    \"plot_result(df, bench='one_big_row', title='Reading one big row', ax=fig.axes[1])\\n\",\n    \"plot_result(df, bench='many_rows', title='Reading 5k rows', ax=fig.axes[2])\\n\",\n    \"plot_result(df, bench='stmt_params', title='Statement with params', ax=fig.axes[3])\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"base\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.8.3\"\n  },\n  \"orig_nbformat\": 4\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "bench/connection_pool.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/connection.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/coroutine.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <iostream>\n\nusing boost::mysql::error_code;\nusing std::chrono::steady_clock;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\nnamespace {\n\nstatic constexpr std::size_t num_parallel = 100;\nstatic constexpr std::size_t total = num_parallel * 100;\nstatic constexpr const char* default_unix_path = \"/var/run/mysqld/mysqld.sock\";\n\nclass coordinator\n{\n    bool finished_{};\n    std::size_t remaining_queries_{total};\n    std::size_t outstanding_tasks_{num_parallel};\n    steady_clock::time_point tp_start_;\n    steady_clock::time_point tp_finish_;\n    mysql::connection_pool* pool_{};\n\npublic:\n    coordinator(mysql::connection_pool* pool = nullptr) : pool_(pool) {}\n    std::chrono::milliseconds ellapsed() const\n    {\n        return std::chrono::duration_cast<std::chrono::milliseconds>(tp_finish_ - tp_start_);\n    }\n    void record_start() { tp_start_ = steady_clock::now(); }\n    void on_finish()\n    {\n        if (--outstanding_tasks_ == 0)\n        {\n            tp_finish_ = steady_clock::now();\n            if (pool_)\n                pool_->cancel();\n        }\n    }\n    bool on_loop_finish()\n    {\n        if (--remaining_queries_ == 0)\n            finished_ = true;\n        return !finished_;\n    }\n\n    bool check_ec(error_code ec, const mysql::diagnostics& diag)\n    {\n        if (ec)\n        {\n            finished_ = true;\n            std::cout << ec << \", \" << diag.server_message() << std::endl;\n        }\n        return !finished_;\n    }\n};\n\nclass task_nopool\n{\n    mysql::any_connection conn_;\n    mysql::results r_;\n    mysql::diagnostics diag_;\n    coordinator* coord_{};\n    const mysql::connect_params* params_;\n    mysql::statement stmt_;\n    asio::coroutine coro_;\n\npublic:\n    task_nopool(asio::any_io_executor ex, coordinator& coord, const mysql::connect_params& params)\n        : conn_(ex), coord_(&coord), params_(&params)\n    {\n    }\n\n    void resume(error_code ec = {})\n    {\n        // Error checking\n        if (!coord_->check_ec(ec, diag_))\n        {\n            coord_->on_finish();\n            return;\n        }\n\n        BOOST_ASIO_CORO_REENTER(coro_)\n        {\n            while (true)\n            {\n                BOOST_ASIO_CORO_YIELD\n                conn_.async_connect(*params_, diag_, [this](error_code ec) { resume(ec); });\n\n                BOOST_ASIO_CORO_YIELD\n                conn_.async_prepare_statement(\n                    \"SELECT data FROM lightweight_data WHERE id = ?\",\n                    diag_,\n                    [this](error_code ec, boost::mysql::statement s) {\n                        stmt_ = s;\n                        resume(ec);\n                    }\n                );\n\n                BOOST_ASIO_CORO_YIELD\n                conn_.async_execute(stmt_.bind(2), r_, diag_, [this](error_code ec) { resume(ec); });\n\n                BOOST_ASIO_CORO_YIELD\n                conn_.async_close(diag_, [this](error_code ec) { resume(ec); });\n\n                if (!coord_->on_loop_finish())\n                {\n                    coord_->on_finish();\n                    return;\n                }\n            }\n        }\n    }\n};\n\nclass task_pool\n{\n    mysql::connection_pool* pool_;\n    mysql::results r_;\n    mysql::diagnostics diag_;\n    coordinator* coord_{};\n    mysql::pooled_connection conn_;\n    asio::coroutine coro_;\n    mysql::statement stmt_;\n\n    void on_finish()\n    {\n        conn_ = mysql::pooled_connection();\n        coord_->on_finish();\n    }\n\npublic:\n    task_pool(mysql::connection_pool& pool, coordinator& coord) : pool_(&pool), coord_(&coord) {}\n\n    void resume(error_code ec = {})\n    {\n        // Error checking\n        if (!coord_->check_ec(ec, diag_))\n        {\n            on_finish();\n            return;\n        }\n\n        BOOST_ASIO_CORO_REENTER(coro_)\n        {\n            while (true)\n            {\n                BOOST_ASIO_CORO_YIELD\n                pool_->async_get_connection(diag_, [this](error_code ec, mysql::pooled_connection c) {\n                    conn_ = std::move(c);\n                    resume(ec);\n                });\n\n                BOOST_ASIO_CORO_YIELD\n                conn_->async_prepare_statement(\n                    \"SELECT data FROM lightweight_data WHERE id = ?\",\n                    diag_,\n                    [this](error_code ec, boost::mysql::statement s) {\n                        stmt_ = s;\n                        resume(ec);\n                    }\n                );\n\n                BOOST_ASIO_CORO_YIELD\n                conn_->async_execute(stmt_.bind(2), r_, diag_, [this](error_code ec) { resume(ec); });\n\n                conn_ = boost::mysql::pooled_connection();\n\n                if (!coord_->on_loop_finish())\n                {\n                    on_finish();\n                    return;\n                }\n            }\n        }\n    }\n};\n\nvoid run_nopool(mysql::any_address server_addr, bool use_ssl)\n{\n    // Setup\n    asio::io_context ctx;\n    mysql::connect_params params;\n    params.server_address = std::move(server_addr);\n    params.username = \"root\";\n    params.password = \"\";\n    params.database = \"boost_mysql_bench\";\n    params.ssl = use_ssl ? mysql::ssl_mode::require : mysql::ssl_mode::disable;\n    std::vector<task_nopool> conns;\n    coordinator coord;\n\n    // Create connections\n    for (std::size_t i = 0; i < num_parallel; ++i)\n        conns.emplace_back(ctx.get_executor(), coord, params);\n\n    // Launch\n    coord.record_start();\n    for (auto& conn : conns)\n        conn.resume(error_code());\n\n    // Run\n    ctx.run();\n\n    // Print elapsed time\n    std::cout << coord.ellapsed().count() << std::flush;\n}\n\nvoid run_pool(mysql::any_address server_addr, bool use_ssl)\n{\n    // Setup\n    asio::io_context ctx;\n    mysql::pool_params params;\n    params.server_address = std::move(server_addr);\n    params.username = \"root\";\n    params.password = \"\";\n    params.database = \"boost_mysql_bench\";\n    params.max_size = num_parallel;\n    params.ssl = use_ssl ? mysql::ssl_mode::require : mysql::ssl_mode::disable;\n\n    mysql::connection_pool pool(ctx, std::move(params));\n    pool.async_run(asio::detached);\n\n    std::vector<task_pool> conns;\n    coordinator coord(&pool);\n\n    // Create connections\n    for (std::size_t i = 0; i < num_parallel; ++i)\n        conns.emplace_back(pool, coord);\n\n    // Launch\n    coord.record_start();\n    for (auto& conn : conns)\n        conn.resume(error_code());\n\n    // Run\n    ctx.run();\n\n    // Print elapsed time\n    std::cout << coord.ellapsed().count() << std::flush;\n}\n\nstatic constexpr const char* options[] = {\n    \"nopool-tcp\",\n    \"nopool-tcpssl\",\n    \"nopool-unix\",\n    \"pool-tcp\",\n    \"pool-tcpssl\",\n    \"pool-unix\",\n};\n\nvoid usage(const char* progname)\n{\n    std::cerr << \"Usage: \" << progname << \" <benchmark-type> <server-addr>\\nAvailable options:\\n\";\n    for (const char* opt : options)\n        std::cerr << \"    \" << opt << \"\\n\";\n    exit(1);\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 3)\n    {\n        usage(argv[0]);\n    }\n\n    mysql::string_view opt = argv[1];\n    mysql::string_view addr = argv[2];\n    boost::mysql::host_and_port tcp_addr;\n\n    if (opt == \"nopool-tcp\")\n    {\n        tcp_addr.host = addr;\n        run_nopool(std::move(tcp_addr), false);\n    }\n    else if (opt == \"nopool-tcpssl\")\n    {\n        tcp_addr.host = addr;\n        run_nopool(std::move(tcp_addr), true);\n    }\n    else if (opt == \"nopool-unix\")\n    {\n        run_nopool(mysql::unix_path{default_unix_path}, false);\n    }\n    else if (opt == \"pool-tcp\")\n    {\n        tcp_addr.host = addr;\n        run_pool(std::move(tcp_addr), false);\n    }\n    else if (opt == \"pool-tcpssl\")\n    {\n        tcp_addr.host = addr;\n        run_pool(std::move(tcp_addr), true);\n    }\n    else if (opt == \"pool-unix\")\n    {\n        run_pool(mysql::unix_path{default_unix_path}, false);\n    }\n    else\n        usage(argv[0]);\n}\n"
  },
  {
    "path": "bench/db_setup.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\n-- Database\nDROP DATABASE IF EXISTS boost_mysql_bench;\nCREATE DATABASE boost_mysql_bench;\nUSE boost_mysql_bench;\n\n-- Required for the WITH RECURSIVE and the amount of rows we're generating\nSET SESSION cte_max_recursion_depth = 15000;\n\n-- Having this prevents sporadic CI failures\nSET global max_connections = 5000;\n\n-- An arbitrary value to pass to RAND(@seed). RAND(@i) generates a\n-- deterministic sequence, vs RAND(@seed)\nSET @seed = 3;\n\n-- Table, with a column per major type\nCREATE TABLE test_data(\n    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    s8 TINYINT NOT NULL,\n    u8 TINYINT UNSIGNED NOT NULL,\n    s16 SMALLINT NOT NULL,\n    u16 SMALLINT UNSIGNED NOT NULL,\n    s32 INT NOT NULL,\n    u32 INT UNSIGNED NOT NULL,\n    s64 BIGINT NOT NULL,\n    u64 BIGINT UNSIGNED NOT NULL,\n    s1 VARCHAR(256),\n    s2 TEXT,\n    b1 VARBINARY(256),\n    b2 BLOB,\n    flt FLOAT,\n    dbl DOUBLE,\n    dt DATE,\n    dtime DATETIME,\n    t TIME\n);\n\n-- Generate 10000 random rows\nINSERT INTO test_data(\n    s8,\n    u8,\n    s16,\n    u16,\n    s32,\n    u32,\n    s64,\n    u64,\n    s1,\n    s2,\n    b1,\n    b2,\n    flt,\n    dbl,\n    dt,\n    dtime,\n    t\n)\nWITH RECURSIVE cte AS (\n    SELECT 0 num\n    UNION ALL\n    SELECT num + 1 FROM cte\n    WHERE num < 5000\n) SELECT\n    FLOOR(RAND(@seed)*(0x7f+0x80+1)-0x80),\n    FLOOR(RAND(@seed)*(0xff+1)),\n    FLOOR(RAND(@seed)*(0x7fff+0x8000+1)-0x8000),\n    FLOOR(RAND(@seed)*(0xffff+1)),\n    FLOOR(RAND(@seed)*(0x7fffffff+0x80000000+1)-0x80000000),\n    FLOOR(RAND(@seed)*(0xffffffff+1)),\n    FLOOR(RAND(@seed)*(0x7fffffffffffffff+0x8000000000000000)-0x7fffffffffffffff),\n    FLOOR(RAND(@seed)*(0xffffffffffffffff)),\n    REPEAT('a', 180),\n    REPEAT('b', FLOOR(RAND(@seed)*(54000-36000+1)+36000)),\n    REPEAT('c', 180),\n    REPEAT('d', FLOOR(RAND(@seed)*(54000-36000+1)+36000)),\n    RAND(@seed),\n    RAND(@seed),\n    DATE_ADD('2020-01-01', INTERVAL FLOOR(RAND(@seed)*(5000+5000+1)-5000) DAY),\n    DATE_ADD('2010-03-20', INTERVAL FLOOR(RAND(@seed)*(3600*24*365*20+3600*24*365*20+1)-3600*24*365*20) SECOND),\n    SEC_TO_TIME(RAND(@seed) + FLOOR(RAND(@seed)*(839*3600+839*3600+1)-839*3600))\nFROM cte;\n\n-- A lightweight table, for the connection_pool benchmarks\nCREATE TABLE lightweight_data(\n    id INT NOT NULL PRIMARY KEY,\n    data VARCHAR(100) NOT NULL\n);\n\nINSERT INTO lightweight_data VALUES\n    (1, \"Data piece 1\"),\n    (2, \"Another data piece\"),\n    (3, \"Final data piece\")\n;\n"
  },
  {
    "path": "bench/many_rows_boost.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include <cassert>\n#include <chrono>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\n\nint main()\n{\n    // Setup\n    asio::io_context ctx;\n    mysql::any_connection conn(ctx);\n    mysql::execution_state st;\n\n    // Connect\n    mysql::connect_params params;\n    params.server_address.emplace_unix_path(\"/var/run/mysqld/mysqld.sock\");\n    params.username = \"root\";\n    params.password = \"\";\n    params.database = \"boost_mysql_bench\";\n    params.ssl = mysql::ssl_mode::disable;\n    conn.connect(params);\n\n    // Prepare the statement\n    auto stmt = conn.prepare_statement(\"SELECT * FROM test_data\");\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    // start_execution won't copy the strings in the rows (as opposed to execute),\n    // so it's preferable when we have big rows, like here\n    conn.start_execution(stmt.bind(), st);\n    while (!st.complete())\n        num_rows += conn.read_some_rows(st).size();\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // We expect many rows\n    return num_rows == 0 ? EXIT_FAILURE : EXIT_SUCCESS;\n}"
  },
  {
    "path": "bench/many_rows_libmariadb.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mariadb/mysql.h>\n#include <string>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str = \"SELECT * FROM test_data\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Prepare the bind objects\n    long long int out_id = 0;\n    MYSQL_BIND binds[18]{};\n    binds[0].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[0].buffer = &out_id;\n    binds[0].buffer_length = 8;\n\n    signed char s8{};\n    binds[1].buffer_type = MYSQL_TYPE_TINY;\n    binds[1].buffer = &s8;\n    binds[1].buffer_length = 1;\n    binds[1].is_unsigned = 0;\n\n    unsigned char u8{};\n    binds[2].buffer_type = MYSQL_TYPE_TINY;\n    binds[2].buffer = &u8;\n    binds[2].buffer_length = 1;\n    binds[2].is_unsigned = 1;\n\n    short s16{};\n    binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    binds[3].buffer = &s16;\n    binds[3].buffer_length = 2;\n    binds[3].is_unsigned = 0;\n\n    unsigned short u16{};\n    binds[4].buffer_type = MYSQL_TYPE_SHORT;\n    binds[4].buffer = &u16;\n    binds[4].buffer_length = 2;\n    binds[4].is_unsigned = 1;\n\n    int s32{};\n    binds[5].buffer_type = MYSQL_TYPE_LONG;\n    binds[5].buffer = &s32;\n    binds[5].buffer_length = 4;\n    binds[5].is_unsigned = 0;\n\n    unsigned u32{};\n    binds[6].buffer_type = MYSQL_TYPE_LONG;\n    binds[6].buffer = &u32;\n    binds[6].buffer_length = 4;\n    binds[6].is_unsigned = 1;\n\n    long long s64{};\n    binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[7].buffer = &s64;\n    binds[7].buffer_length = 8;\n    binds[7].is_unsigned = 0;\n\n    unsigned long long u64{};\n    binds[8].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[8].buffer = &u64;\n    binds[8].buffer_length = 8;\n    binds[8].is_unsigned = 1;\n\n    char s1[255]{};\n    binds[9].buffer_type = MYSQL_TYPE_STRING;\n    binds[9].buffer = s1;\n    binds[9].buffer_length = sizeof(s1);\n\n    std::string s2;\n    unsigned long s2_length = 0u;\n    my_bool s2_truncated{};\n    binds[10].buffer_type = MYSQL_TYPE_STRING;\n    binds[10].buffer = s2.data();\n    binds[10].buffer_length = s2_length;\n    binds[10].length = &s2_length;\n    binds[10].error = &s2_truncated;\n\n    char b1[255]{};\n    binds[11].buffer_type = MYSQL_TYPE_BLOB;\n    binds[11].buffer = b1;\n    binds[11].buffer_length = sizeof(b1);\n\n    std::string b2;\n    unsigned long b2_length = 0u;\n    my_bool b2_truncated{};\n    binds[12].buffer_type = MYSQL_TYPE_BLOB;\n    binds[12].buffer = b2.data();\n    binds[12].buffer_length = b2_length;\n    binds[12].length = &b2_length;\n    binds[12].error = &b2_truncated;\n\n    float flt{};\n    binds[13].buffer_type = MYSQL_TYPE_FLOAT;\n    binds[13].buffer = &flt;\n    binds[13].buffer_length = 4;\n\n    double dbl{};\n    binds[14].buffer_type = MYSQL_TYPE_DOUBLE;\n    binds[14].buffer = &dbl;\n    binds[14].buffer_length = 8;\n\n    MYSQL_TIME dt{};\n    binds[15].buffer_type = MYSQL_TYPE_DATE;\n    binds[15].buffer = &dt;\n    binds[15].buffer_length = sizeof(dt);\n\n    MYSQL_TIME dtime{};\n    binds[16].buffer_type = MYSQL_TYPE_DATETIME;\n    binds[16].buffer = &dtime;\n    binds[16].buffer_length = sizeof(dtime);\n\n    MYSQL_TIME t{};\n    binds[17].buffer_type = MYSQL_TYPE_TIME;\n    binds[17].buffer = &t;\n    binds[17].buffer_length = sizeof(t);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    // Execute the statement\n    if (mysql_stmt_execute(stmt))\n    {\n        fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Bind output\n    if (mysql_stmt_bind_result(stmt, binds))\n    {\n        fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Read the rows\n    while (true)\n    {\n        auto status = mysql_stmt_fetch(stmt);\n\n        if (status == MYSQL_DATA_TRUNCATED)\n        {\n            // On truncation, resize the buffer and read again\n            if (s2_length > s2.size())\n            {\n                s2.resize(s2_length);\n                binds[10].buffer = s2.data();\n                binds[10].buffer_length = s2_length;\n                if (mysql_stmt_fetch_column(stmt, &binds[10], 10, 0))\n                {\n                    fprintf(stderr, \"Error fetching s2: %s\\n\", mysql_stmt_error(stmt));\n                    exit(1);\n                }\n            }\n\n            if (b2_length > b2.size())\n            {\n                b2.resize(b2_length);\n                binds[12].buffer = b2.data();\n                binds[12].buffer_length = b2_length;\n                if (mysql_stmt_fetch_column(stmt, &binds[12], 12, 0))\n                {\n                    fprintf(stderr, \"Error fetching b2: %s\\n\", mysql_stmt_error(stmt));\n                    exit(1);\n                }\n            }\n\n            ++num_rows;\n        }\n        else if (status == MYSQL_NO_DATA)\n        {\n            break;\n        }\n        else if (status == 1)\n        {\n            fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n        else\n        {\n            ++num_rows;\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We expect many rows\n    return num_rows == 0 ? EXIT_FAILURE : EXIT_SUCCESS;\n}"
  },
  {
    "path": "bench/many_rows_libmysqlclient.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mysql/field_types.h>\n#include <mysql/mysql.h>\n#include <mysql/mysql_com.h>\n#include <string>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    unsigned mode = SSL_MODE_DISABLED;\n    if (mysql_options(con, MYSQL_OPT_SSL_MODE, &mode))\n    {\n        fprintf(stderr, \"Error in mysql_options: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str = \"SELECT * FROM test_data\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Prepare the bind objects\n    long long int out_id = 0;\n    MYSQL_BIND binds[18]{};\n    binds[0].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[0].buffer = &out_id;\n    binds[0].buffer_length = 8;\n\n    signed char s8{};\n    binds[1].buffer_type = MYSQL_TYPE_TINY;\n    binds[1].buffer = &s8;\n    binds[1].buffer_length = 1;\n    binds[1].is_unsigned = 0;\n\n    unsigned char u8{};\n    binds[2].buffer_type = MYSQL_TYPE_TINY;\n    binds[2].buffer = &u8;\n    binds[2].buffer_length = 1;\n    binds[2].is_unsigned = 1;\n\n    short s16{};\n    binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    binds[3].buffer = &s16;\n    binds[3].buffer_length = 2;\n    binds[3].is_unsigned = 0;\n\n    unsigned short u16{};\n    binds[4].buffer_type = MYSQL_TYPE_SHORT;\n    binds[4].buffer = &u16;\n    binds[4].buffer_length = 2;\n    binds[4].is_unsigned = 1;\n\n    int s32{};\n    binds[5].buffer_type = MYSQL_TYPE_LONG;\n    binds[5].buffer = &s32;\n    binds[5].buffer_length = 4;\n    binds[5].is_unsigned = 0;\n\n    unsigned u32{};\n    binds[6].buffer_type = MYSQL_TYPE_LONG;\n    binds[6].buffer = &u32;\n    binds[6].buffer_length = 4;\n    binds[6].is_unsigned = 1;\n\n    long long s64{};\n    binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[7].buffer = &s64;\n    binds[7].buffer_length = 8;\n    binds[7].is_unsigned = 0;\n\n    unsigned long long u64{};\n    binds[8].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[8].buffer = &u64;\n    binds[8].buffer_length = 8;\n    binds[8].is_unsigned = 1;\n\n    char s1[255]{};\n    binds[9].buffer_type = MYSQL_TYPE_STRING;\n    binds[9].buffer = s1;\n    binds[9].buffer_length = sizeof(s1);\n\n    std::string s2;\n    unsigned long s2_length = 0u;\n    bool s2_truncated{};\n    binds[10].buffer_type = MYSQL_TYPE_STRING;\n    binds[10].buffer = s2.data();\n    binds[10].buffer_length = s2_length;\n    binds[10].length = &s2_length;\n    binds[10].error = &s2_truncated;\n\n    char b1[255]{};\n    binds[11].buffer_type = MYSQL_TYPE_BLOB;\n    binds[11].buffer = b1;\n    binds[11].buffer_length = sizeof(b1);\n\n    std::string b2;\n    unsigned long b2_length = 0u;\n    bool b2_truncated{};\n    binds[12].buffer_type = MYSQL_TYPE_BLOB;\n    binds[12].buffer = b2.data();\n    binds[12].buffer_length = b2_length;\n    binds[12].length = &b2_length;\n    binds[12].error = &b2_truncated;\n\n    float flt{};\n    binds[13].buffer_type = MYSQL_TYPE_FLOAT;\n    binds[13].buffer = &flt;\n    binds[13].buffer_length = 4;\n\n    double dbl{};\n    binds[14].buffer_type = MYSQL_TYPE_DOUBLE;\n    binds[14].buffer = &dbl;\n    binds[14].buffer_length = 8;\n\n    MYSQL_TIME dt{};\n    binds[15].buffer_type = MYSQL_TYPE_DATE;\n    binds[15].buffer = &dt;\n    binds[15].buffer_length = sizeof(dt);\n\n    MYSQL_TIME dtime{};\n    binds[16].buffer_type = MYSQL_TYPE_DATETIME;\n    binds[16].buffer = &dtime;\n    binds[16].buffer_length = sizeof(dtime);\n\n    MYSQL_TIME t{};\n    binds[17].buffer_type = MYSQL_TYPE_TIME;\n    binds[17].buffer = &t;\n    binds[17].buffer_length = sizeof(t);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    // Execute the statement\n    if (mysql_stmt_execute(stmt))\n    {\n        fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Bind output\n    if (mysql_stmt_bind_result(stmt, binds))\n    {\n        fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    while (true)\n    {\n        auto status = mysql_stmt_fetch(stmt);\n\n        // On truncation, resize the buffer and read again\n        if (status == MYSQL_DATA_TRUNCATED)\n        {\n            if (s2_length > s2.size())\n            {\n                s2.resize(s2_length);\n                binds[10].buffer = s2.data();\n                binds[10].buffer_length = s2_length;\n                if (mysql_stmt_fetch_column(stmt, &binds[10], 10, 0))\n                {\n                    fprintf(stderr, \"Error fetching s2: %s\\n\", mysql_stmt_error(stmt));\n                    exit(1);\n                }\n            }\n\n            if (b2_length > b2.size())\n            {\n                b2.resize(b2_length);\n                binds[12].buffer = b2.data();\n                binds[12].buffer_length = b2_length;\n                if (mysql_stmt_fetch_column(stmt, &binds[12], 12, 0))\n                {\n                    fprintf(stderr, \"Error fetching b2: %s\\n\", mysql_stmt_error(stmt));\n                    exit(1);\n                }\n            }\n\n            ++num_rows;\n        }\n        else if (status == MYSQL_NO_DATA)\n        {\n            break;\n        }\n        else if (status == 1)\n        {\n            fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n        else\n        {\n            ++num_rows;\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We expect many rows\n    return num_rows == 0 ? EXIT_FAILURE : EXIT_SUCCESS;\n}"
  },
  {
    "path": "bench/one_big_row_boost.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include <cassert>\n#include <chrono>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n\nusing namespace std;\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\n\nint main()\n{\n    // Setup\n    asio::io_context ctx;\n    mysql::any_connection conn(ctx);\n    mysql::execution_state st;\n\n    // Connect\n    mysql::connect_params params;\n    params.server_address.emplace_unix_path(\"/var/run/mysqld/mysqld.sock\");\n    params.username = \"root\";\n    params.password = \"\";\n    params.database = \"boost_mysql_bench\";\n    params.ssl = mysql::ssl_mode::disable;\n    conn.connect(params);\n\n    // Prepare the statement\n    auto stmt = conn.prepare_statement(\"SELECT * FROM test_data WHERE id = 1\");\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 10000; ++i)\n    {\n        // start_execution won't copy the strings in the rows (as opposed to execute),\n        // so it's preferable when we have big rows, like here\n        conn.start_execution(stmt.bind(), st);\n        while (!st.complete())\n            num_rows += conn.read_some_rows(st).size();\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // We expect one row per iteration\n    return num_rows == 10000 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/one_big_row_libmariadb.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mariadb/mysql.h>\n#include <string>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str = \"SELECT * FROM test_data WHERE id = 1\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Prepare the bind objects\n    long long int out_id = 0;\n    MYSQL_BIND binds[18]{};\n    binds[0].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[0].buffer = &out_id;\n    binds[0].buffer_length = 8;\n\n    signed char s8{};\n    binds[1].buffer_type = MYSQL_TYPE_TINY;\n    binds[1].buffer = &s8;\n    binds[1].buffer_length = 1;\n    binds[1].is_unsigned = 0;\n\n    unsigned char u8{};\n    binds[2].buffer_type = MYSQL_TYPE_TINY;\n    binds[2].buffer = &u8;\n    binds[2].buffer_length = 1;\n    binds[2].is_unsigned = 1;\n\n    short s16{};\n    binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    binds[3].buffer = &s16;\n    binds[3].buffer_length = 2;\n    binds[3].is_unsigned = 0;\n\n    unsigned short u16{};\n    binds[4].buffer_type = MYSQL_TYPE_SHORT;\n    binds[4].buffer = &u16;\n    binds[4].buffer_length = 2;\n    binds[4].is_unsigned = 1;\n\n    int s32{};\n    binds[5].buffer_type = MYSQL_TYPE_LONG;\n    binds[5].buffer = &s32;\n    binds[5].buffer_length = 4;\n    binds[5].is_unsigned = 0;\n\n    unsigned u32{};\n    binds[6].buffer_type = MYSQL_TYPE_LONG;\n    binds[6].buffer = &u32;\n    binds[6].buffer_length = 4;\n    binds[6].is_unsigned = 1;\n\n    long long s64{};\n    binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[7].buffer = &s64;\n    binds[7].buffer_length = 8;\n    binds[7].is_unsigned = 0;\n\n    unsigned long long u64{};\n    binds[8].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[8].buffer = &u64;\n    binds[8].buffer_length = 8;\n    binds[8].is_unsigned = 1;\n\n    char s1[255]{};\n    binds[9].buffer_type = MYSQL_TYPE_STRING;\n    binds[9].buffer = s1;\n    binds[9].buffer_length = sizeof(s1);\n\n    std::string s2;\n    unsigned long s2_length = 0u;\n    my_bool s2_truncated{};\n    binds[10].buffer_type = MYSQL_TYPE_STRING;\n    binds[10].buffer = s2.data();\n    binds[10].buffer_length = s2_length;\n    binds[10].length = &s2_length;\n    binds[10].error = &s2_truncated;\n\n    char b1[255]{};\n    binds[11].buffer_type = MYSQL_TYPE_BLOB;\n    binds[11].buffer = b1;\n    binds[11].buffer_length = sizeof(b1);\n\n    std::string b2;\n    unsigned long b2_length = 0u;\n    my_bool b2_truncated{};\n    binds[12].buffer_type = MYSQL_TYPE_BLOB;\n    binds[12].buffer = b2.data();\n    binds[12].buffer_length = b2_length;\n    binds[12].length = &b2_length;\n    binds[12].error = &b2_truncated;\n\n    float flt{};\n    binds[13].buffer_type = MYSQL_TYPE_FLOAT;\n    binds[13].buffer = &flt;\n    binds[13].buffer_length = 4;\n\n    double dbl{};\n    binds[14].buffer_type = MYSQL_TYPE_DOUBLE;\n    binds[14].buffer = &dbl;\n    binds[14].buffer_length = 8;\n\n    MYSQL_TIME dt{};\n    binds[15].buffer_type = MYSQL_TYPE_DATE;\n    binds[15].buffer = &dt;\n    binds[15].buffer_length = sizeof(dt);\n\n    MYSQL_TIME dtime{};\n    binds[16].buffer_type = MYSQL_TYPE_DATETIME;\n    binds[16].buffer = &dtime;\n    binds[16].buffer_length = sizeof(dtime);\n\n    MYSQL_TIME t{};\n    binds[17].buffer_type = MYSQL_TYPE_TIME;\n    binds[17].buffer = &t;\n    binds[17].buffer_length = sizeof(t);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 10000; ++i)\n    {\n        // Execute the statement\n        if (mysql_stmt_execute(stmt))\n        {\n            fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Bind output\n        if (mysql_stmt_bind_result(stmt, binds))\n        {\n            fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Read the rows\n        while (true)\n        {\n            auto status = mysql_stmt_fetch(stmt);\n\n            // On truncation, resize the buffer and read again\n            if (status == MYSQL_DATA_TRUNCATED)\n            {\n                if (s2_length > s2.size())\n                {\n                    s2.resize(s2_length);\n                    binds[10].buffer = s2.data();\n                    binds[10].buffer_length = s2_length;\n                    if (mysql_stmt_fetch_column(stmt, &binds[10], 10, 0))\n                    {\n                        fprintf(stderr, \"Error fetching s2: %s\\n\", mysql_stmt_error(stmt));\n                        exit(1);\n                    }\n                }\n\n                if (b2_length > b2.size())\n                {\n                    b2.resize(b2_length);\n                    binds[12].buffer = b2.data();\n                    binds[12].buffer_length = b2_length;\n                    if (mysql_stmt_fetch_column(stmt, &binds[12], 12, 0))\n                    {\n                        fprintf(stderr, \"Error fetching b2: %s\\n\", mysql_stmt_error(stmt));\n                        exit(1);\n                    }\n                }\n\n                ++num_rows;\n            }\n            else if (status == MYSQL_NO_DATA)\n            {\n                break;\n            }\n            else if (status == 1)\n            {\n                fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n                exit(1);\n            }\n            else\n            {\n                ++num_rows;\n            }\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We expect one row per iteration\n    return num_rows == 10000 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/one_big_row_libmysqlclient.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mysql/field_types.h>\n#include <mysql/mysql.h>\n#include <mysql/mysql_com.h>\n#include <string>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    unsigned mode = SSL_MODE_DISABLED;\n    if (mysql_options(con, MYSQL_OPT_SSL_MODE, &mode))\n    {\n        fprintf(stderr, \"Error in mysql_options: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str = \"SELECT * FROM test_data WHERE id = 1\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Prepare the bind objects\n    long long int out_id = 0;\n    MYSQL_BIND binds[18]{};\n    binds[0].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[0].buffer = &out_id;\n    binds[0].buffer_length = 8;\n\n    signed char s8{};\n    binds[1].buffer_type = MYSQL_TYPE_TINY;\n    binds[1].buffer = &s8;\n    binds[1].buffer_length = 1;\n    binds[1].is_unsigned = 0;\n\n    unsigned char u8{};\n    binds[2].buffer_type = MYSQL_TYPE_TINY;\n    binds[2].buffer = &u8;\n    binds[2].buffer_length = 1;\n    binds[2].is_unsigned = 1;\n\n    short s16{};\n    binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    binds[3].buffer = &s16;\n    binds[3].buffer_length = 2;\n    binds[3].is_unsigned = 0;\n\n    unsigned short u16{};\n    binds[4].buffer_type = MYSQL_TYPE_SHORT;\n    binds[4].buffer = &u16;\n    binds[4].buffer_length = 2;\n    binds[4].is_unsigned = 1;\n\n    int s32{};\n    binds[5].buffer_type = MYSQL_TYPE_LONG;\n    binds[5].buffer = &s32;\n    binds[5].buffer_length = 4;\n    binds[5].is_unsigned = 0;\n\n    unsigned u32{};\n    binds[6].buffer_type = MYSQL_TYPE_LONG;\n    binds[6].buffer = &u32;\n    binds[6].buffer_length = 4;\n    binds[6].is_unsigned = 1;\n\n    long long s64{};\n    binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[7].buffer = &s64;\n    binds[7].buffer_length = 8;\n    binds[7].is_unsigned = 0;\n\n    unsigned long long u64{};\n    binds[8].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[8].buffer = &u64;\n    binds[8].buffer_length = 8;\n    binds[8].is_unsigned = 1;\n\n    char s1[255]{};\n    binds[9].buffer_type = MYSQL_TYPE_STRING;\n    binds[9].buffer = s1;\n    binds[9].buffer_length = sizeof(s1);\n\n    std::string s2;\n    unsigned long s2_length = 0u;\n    bool s2_truncated{};\n    binds[10].buffer_type = MYSQL_TYPE_STRING;\n    binds[10].buffer = s2.data();\n    binds[10].buffer_length = s2_length;\n    binds[10].length = &s2_length;\n    binds[10].error = &s2_truncated;\n\n    char b1[255]{};\n    binds[11].buffer_type = MYSQL_TYPE_BLOB;\n    binds[11].buffer = b1;\n    binds[11].buffer_length = sizeof(b1);\n\n    std::string b2;\n    unsigned long b2_length = 0u;\n    bool b2_truncated{};\n    binds[12].buffer_type = MYSQL_TYPE_BLOB;\n    binds[12].buffer = b2.data();\n    binds[12].buffer_length = b2_length;\n    binds[12].length = &b2_length;\n    binds[12].error = &b2_truncated;\n\n    float flt{};\n    binds[13].buffer_type = MYSQL_TYPE_FLOAT;\n    binds[13].buffer = &flt;\n    binds[13].buffer_length = 4;\n\n    double dbl{};\n    binds[14].buffer_type = MYSQL_TYPE_DOUBLE;\n    binds[14].buffer = &dbl;\n    binds[14].buffer_length = 8;\n\n    MYSQL_TIME dt{};\n    binds[15].buffer_type = MYSQL_TYPE_DATE;\n    binds[15].buffer = &dt;\n    binds[15].buffer_length = sizeof(dt);\n\n    MYSQL_TIME dtime{};\n    binds[16].buffer_type = MYSQL_TYPE_DATETIME;\n    binds[16].buffer = &dtime;\n    binds[16].buffer_length = sizeof(dtime);\n\n    MYSQL_TIME t{};\n    binds[17].buffer_type = MYSQL_TYPE_TIME;\n    binds[17].buffer = &t;\n    binds[17].buffer_length = sizeof(t);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 10000; ++i)\n    {\n        // Execute the statement\n        if (mysql_stmt_execute(stmt))\n        {\n            fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Bind output\n        if (mysql_stmt_bind_result(stmt, binds))\n        {\n            fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Read the rows\n        while (true)\n        {\n            auto status = mysql_stmt_fetch(stmt);\n\n            if (status == MYSQL_DATA_TRUNCATED)\n            {\n                // On truncation, resize the buffer and read again\n                if (s2_length > s2.size())\n                {\n                    s2.resize(s2_length);\n                    binds[10].buffer = s2.data();\n                    binds[10].buffer_length = s2_length;\n                    if (mysql_stmt_fetch_column(stmt, &binds[10], 10, 0))\n                    {\n                        fprintf(stderr, \"Error fetching s2: %s\\n\", mysql_stmt_error(stmt));\n                        exit(1);\n                    }\n                }\n\n                if (b2_length > b2.size())\n                {\n                    b2.resize(b2_length);\n                    binds[12].buffer = b2.data();\n                    binds[12].buffer_length = b2_length;\n                    if (mysql_stmt_fetch_column(stmt, &binds[12], 12, 0))\n                    {\n                        fprintf(stderr, \"Error fetching b2: %s\\n\", mysql_stmt_error(stmt));\n                        exit(1);\n                    }\n                }\n\n                ++num_rows;\n            }\n            else if (status == MYSQL_NO_DATA)\n            {\n                break;\n            }\n            else if (status == 1)\n            {\n                fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n                exit(1);\n            }\n            else\n            {\n                ++num_rows;\n            }\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We expect one row per iteration\n    return num_rows == 10000 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/one_small_row_boost.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include <chrono>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <string>\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\n\nint main()\n{\n    // Setup\n    asio::io_context ctx;\n    mysql::any_connection conn(ctx);\n    mysql::results r;\n\n    // Connect\n    mysql::connect_params params;\n    params.server_address.emplace_unix_path(\"/var/run/mysqld/mysqld.sock\");\n    params.username = \"root\";\n    params.password = \"\";\n    params.database = \"boost_mysql_bench\";\n    params.ssl = mysql::ssl_mode::disable;\n    conn.connect(params);\n\n    // Prepare the statement. Exclude the big TEXT/BLOB fields.\n    auto stmt = conn.prepare_statement(\n        \"SELECT s8, u8, s16, u16, s32, u32, s64, u64, s1, b1, flt, dbl, dt, dtime, t \"\n        \"FROM test_data WHERE id = 1\"\n    );\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 10000; ++i)\n    {\n        // Since the rows are small, using execute is recommended\n        conn.execute(stmt.bind(), r);\n        num_rows += r.rows().size();\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // We expect one row per iteration\n    return num_rows == 10000 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/one_small_row_libmariadb.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mariadb/mysql.h>\n\nusing namespace std;\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement. Exclude the big TEXT/BLOB fields\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str =\n        \"SELECT s8, u8, s16, u16, s32, u32, s64, u64, s1, b1, flt, dbl, dt, dtime, t \"\n        \"FROM test_data WHERE id = 1\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Prepare the bind objects\n    MYSQL_BIND binds[15]{};\n\n    signed char s8{};\n    binds[0].buffer_type = MYSQL_TYPE_TINY;\n    binds[0].buffer = &s8;\n    binds[0].buffer_length = 1;\n    binds[0].is_unsigned = 0;\n\n    unsigned char u8{};\n    binds[1].buffer_type = MYSQL_TYPE_TINY;\n    binds[1].buffer = &u8;\n    binds[1].buffer_length = 1;\n    binds[1].is_unsigned = 1;\n\n    short s16{};\n    binds[2].buffer_type = MYSQL_TYPE_SHORT;\n    binds[2].buffer = &s16;\n    binds[2].buffer_length = 2;\n    binds[2].is_unsigned = 0;\n\n    unsigned short u16{};\n    binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    binds[3].buffer = &u16;\n    binds[3].buffer_length = 2;\n    binds[3].is_unsigned = 1;\n\n    int s32{};\n    binds[4].buffer_type = MYSQL_TYPE_LONG;\n    binds[4].buffer = &s32;\n    binds[4].buffer_length = 4;\n    binds[4].is_unsigned = 0;\n\n    unsigned u32{};\n    binds[5].buffer_type = MYSQL_TYPE_LONG;\n    binds[5].buffer = &u32;\n    binds[5].buffer_length = 4;\n    binds[5].is_unsigned = 1;\n\n    long long s64{};\n    binds[6].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[6].buffer = &s64;\n    binds[6].buffer_length = 8;\n    binds[6].is_unsigned = 0;\n\n    unsigned long long u64{};\n    binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[7].buffer = &u64;\n    binds[7].buffer_length = 8;\n    binds[7].is_unsigned = 1;\n\n    char s1[255]{};\n    binds[8].buffer_type = MYSQL_TYPE_STRING;\n    binds[8].buffer = s1;\n    binds[8].buffer_length = sizeof(s1);\n\n    char b1[255]{};\n    binds[9].buffer_type = MYSQL_TYPE_BLOB;\n    binds[9].buffer = b1;\n    binds[9].buffer_length = sizeof(b1);\n\n    float flt{};\n    binds[10].buffer_type = MYSQL_TYPE_FLOAT;\n    binds[10].buffer = &flt;\n    binds[10].buffer_length = 4;\n\n    double dbl{};\n    binds[11].buffer_type = MYSQL_TYPE_DOUBLE;\n    binds[11].buffer = &dbl;\n    binds[11].buffer_length = 8;\n\n    MYSQL_TIME dt{};\n    binds[12].buffer_type = MYSQL_TYPE_DATE;\n    binds[12].buffer = &dt;\n    binds[12].buffer_length = sizeof(dt);\n\n    MYSQL_TIME dtime{};\n    binds[13].buffer_type = MYSQL_TYPE_DATETIME;\n    binds[13].buffer = &dtime;\n    binds[13].buffer_length = sizeof(dtime);\n\n    MYSQL_TIME t{};\n    binds[14].buffer_type = MYSQL_TYPE_TIME;\n    binds[14].buffer = &t;\n    binds[14].buffer_length = sizeof(t);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 10000; ++i)\n    {\n        // Execute the statement\n        if (mysql_stmt_execute(stmt))\n        {\n            fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Bind output\n        if (mysql_stmt_bind_result(stmt, binds))\n        {\n            fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Read the rows\n        while (true)\n        {\n            auto status = mysql_stmt_fetch(stmt);\n\n            if (status == MYSQL_DATA_TRUNCATED)\n            {\n                // No truncation is expected here, since we don't have big strings/blobs\n                fprintf(stderr, \"Data truncation error\\n\");\n                exit(1);\n            }\n            else if (status == MYSQL_NO_DATA)\n            {\n                break;\n            }\n            else if (status == 1)\n            {\n                fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n                exit(1);\n            }\n            else\n            {\n                ++num_rows;\n            }\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We expect one row per iteration\n    return num_rows == 10000 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/one_small_row_libmysqlclient.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mysql/field_types.h>\n#include <mysql/mysql.h>\n#include <mysql/mysql_com.h>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    unsigned mode = SSL_MODE_DISABLED;\n    if (mysql_options(con, MYSQL_OPT_SSL_MODE, &mode))\n    {\n        fprintf(stderr, \"Error in mysql_options: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement. Exclude the big TEXT/BLOB fields\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str =\n        \"SELECT s8, u8, s16, u16, s32, u32, s64, u64, s1, b1, flt, dbl, dt, dtime, t \"\n        \"FROM test_data WHERE id = 1\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Prepare the bind objects\n    MYSQL_BIND binds[15]{};\n\n    signed char s8{};\n    binds[0].buffer_type = MYSQL_TYPE_TINY;\n    binds[0].buffer = &s8;\n    binds[0].buffer_length = 1;\n    binds[0].is_unsigned = 0;\n\n    unsigned char u8{};\n    binds[1].buffer_type = MYSQL_TYPE_TINY;\n    binds[1].buffer = &u8;\n    binds[1].buffer_length = 1;\n    binds[1].is_unsigned = 1;\n\n    short s16{};\n    binds[2].buffer_type = MYSQL_TYPE_SHORT;\n    binds[2].buffer = &s16;\n    binds[2].buffer_length = 2;\n    binds[2].is_unsigned = 0;\n\n    unsigned short u16{};\n    binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    binds[3].buffer = &u16;\n    binds[3].buffer_length = 2;\n    binds[3].is_unsigned = 1;\n\n    int s32{};\n    binds[4].buffer_type = MYSQL_TYPE_LONG;\n    binds[4].buffer = &s32;\n    binds[4].buffer_length = 4;\n    binds[4].is_unsigned = 0;\n\n    unsigned u32{};\n    binds[5].buffer_type = MYSQL_TYPE_LONG;\n    binds[5].buffer = &u32;\n    binds[5].buffer_length = 4;\n    binds[5].is_unsigned = 1;\n\n    long long s64{};\n    binds[6].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[6].buffer = &s64;\n    binds[6].buffer_length = 8;\n    binds[6].is_unsigned = 0;\n\n    unsigned long long u64{};\n    binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    binds[7].buffer = &u64;\n    binds[7].buffer_length = 8;\n    binds[7].is_unsigned = 1;\n\n    char s1[255]{};\n    binds[8].buffer_type = MYSQL_TYPE_STRING;\n    binds[8].buffer = s1;\n    binds[8].buffer_length = sizeof(s1);\n\n    char b1[255]{};\n    binds[9].buffer_type = MYSQL_TYPE_BLOB;\n    binds[9].buffer = b1;\n    binds[9].buffer_length = sizeof(b1);\n\n    float flt{};\n    binds[10].buffer_type = MYSQL_TYPE_FLOAT;\n    binds[10].buffer = &flt;\n    binds[10].buffer_length = 4;\n\n    double dbl{};\n    binds[11].buffer_type = MYSQL_TYPE_DOUBLE;\n    binds[11].buffer = &dbl;\n    binds[11].buffer_length = 8;\n\n    MYSQL_TIME dt{};\n    binds[12].buffer_type = MYSQL_TYPE_DATE;\n    binds[12].buffer = &dt;\n    binds[12].buffer_length = sizeof(dt);\n\n    MYSQL_TIME dtime{};\n    binds[13].buffer_type = MYSQL_TYPE_DATETIME;\n    binds[13].buffer = &dtime;\n    binds[13].buffer_length = sizeof(dtime);\n\n    MYSQL_TIME t{};\n    binds[14].buffer_type = MYSQL_TYPE_TIME;\n    binds[14].buffer = &t;\n    binds[14].buffer_length = sizeof(t);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 10000; ++i)\n    {\n        // Execute the statement\n        if (mysql_stmt_execute(stmt))\n        {\n            fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Bind output\n        if (mysql_stmt_bind_result(stmt, binds))\n        {\n            fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Read the rows\n        while (true)\n        {\n            auto status = mysql_stmt_fetch(stmt);\n\n            if (status == MYSQL_DATA_TRUNCATED)\n            {\n                // No truncation is expected here, since we don't have big strings/blobs\n                fprintf(stderr, \"Data truncation error\\n\");\n                exit(1);\n            }\n            else if (status == MYSQL_NO_DATA)\n            {\n                break;\n            }\n            else if (status == 1)\n            {\n                fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n                exit(1);\n            }\n            else\n            {\n                ++num_rows;\n            }\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We expect one row per iteration\n    return num_rows == 10000 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/stmt_params_boost.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include <chrono>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <string>\n#include <vector>\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\n\nint main()\n{\n    // Setup\n    asio::io_context ctx;\n    mysql::any_connection conn(ctx);\n    mysql::results r;\n\n    // Connect\n    mysql::connect_params params;\n    params.server_address.emplace_unix_path(\"/var/run/mysqld/mysqld.sock\");\n    params.username = \"root\";\n    params.password = \"\";\n    params.database = \"boost_mysql_bench\";\n    params.ssl = mysql::ssl_mode::disable;\n    conn.connect(params);\n\n    // Prepare the statement. It should have many parameters and be a lightweight query.\n    // This SELECT is lighter than an INSERT.\n    auto stmt = conn.prepare_statement(\n        \"SELECT id FROM test_data WHERE id = 1 AND s8 = ? AND u8 = ? AND s16 = ? AND u16 = ? AND \"\n        \"s32 = ? AND u32 = ? AND s64 = ? AND u64 = ? AND s1 = ? AND s2 = ? AND b1 = ? AND \"\n        \"b2 = ? AND flt = ? AND dbl = ? AND dt = ? AND dtime = ? AND t = ?\"\n    );\n\n    // Statement params\n    signed char s8 = 64;\n    unsigned char u8 = 172;\n    short s16 = -129;\n    unsigned short u16 = 0xfe21;\n    int s32 = 42;\n    unsigned u32 = 0xfe8173;\n    long long s64 = -1;\n    unsigned long long u64 = 98302402;\n    std::string s1(200, 'a');\n    std::string s2(36000, 'b');\n    std::vector<unsigned char> b1(200, 5);\n    std::vector<unsigned char> b2(35000, 7);\n    float flt = 3.14e10;\n    double dbl = 7.1e-150;\n    mysql::date dt(2010, 6, 20);\n    mysql::datetime dtime(2020, 3, 21, 10, 40, 10, 123456);\n    mysql::time t = std::chrono::hours(126) + std::chrono::minutes(18) + std::chrono::seconds(40) +\n                    std::chrono::microseconds(123456);\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 1000; ++i)\n    {\n        // No rows will be matched, so execute() works\n        conn.execute(\n            stmt.bind(\n                s8,\n                u8,\n                s16,\n                u16,\n                s32,\n                u32,\n                s64,\n                u64,\n                mysql::string_view(s1),\n                mysql::string_view(s2),\n                mysql::blob_view(b1),\n                mysql::blob_view(b2),\n                flt,\n                dbl,\n                dt,\n                dtime,\n                t\n            ),\n            r\n        );\n        num_rows += r.rows().size();\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // We don't expect any row to be matched\n    return num_rows == 0 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/stmt_params_libmariadb.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <cassert>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mariadb/mysql.h>\n#include <string>\n#include <vector>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement. It should have many parameters and be a lightweight query.\n    // This SELECT is lighter than an INSERT.\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str =\n        \"SELECT id FROM test_data WHERE id = 1 AND s8 = ? AND u8 = ? AND s16 = ? AND u16 = ? AND \"\n        \"s32 = ? AND u32 = ? AND s64 = ? AND u64 = ? AND s1 = ? AND s2 = ? AND b1 = ? AND \"\n        \"b2 = ? AND flt = ? AND dbl = ? AND dt = ? AND dtime = ? AND t = ?\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Statement params\n    signed char s8 = 64;\n    unsigned char u8 = 172;\n    short s16 = -129;\n    unsigned short u16 = 0xfe21;\n    int s32 = 42;\n    unsigned u32 = 0xfe8173;\n    long long s64 = -1;\n    unsigned long long u64 = 98302402;\n    std::string s1(200, 'a');\n    std::string s2(36000, 'b');\n    std::vector<unsigned char> b1(200, 5);\n    std::vector<unsigned char> b2(35000, 7);\n    float flt = 3.14e10;\n    double dbl = 7.1e-150;\n    MYSQL_TIME dt{}, dtime{}, t{};\n\n    dt.year = 2010;\n    dt.month = 6;\n    dt.day = 20;\n\n    dtime.year = 2020;\n    dtime.month = 3;\n    dtime.day = 21;\n    dtime.hour = 10;\n    dtime.minute = 40;\n    dtime.second = 10;\n    dtime.second_part = 123456;\n\n    t.hour = 126;\n    t.minute = 18;\n    t.second = 40;\n    t.second_part = 123456;\n\n    // Prepare the bind objects\n    MYSQL_BIND in_binds[17]{};\n    in_binds[0].buffer_type = MYSQL_TYPE_TINY;\n    in_binds[0].buffer = &s8;\n    in_binds[0].buffer_length = 1;\n    in_binds[0].is_unsigned = 0;\n\n    in_binds[1].buffer_type = MYSQL_TYPE_TINY;\n    in_binds[1].buffer = &u8;\n    in_binds[1].buffer_length = 1;\n    in_binds[1].is_unsigned = 1;\n\n    in_binds[2].buffer_type = MYSQL_TYPE_SHORT;\n    in_binds[2].buffer = &s16;\n    in_binds[2].buffer_length = 2;\n    in_binds[2].is_unsigned = 0;\n\n    in_binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    in_binds[3].buffer = &u16;\n    in_binds[3].buffer_length = 2;\n    in_binds[3].is_unsigned = 1;\n\n    in_binds[4].buffer_type = MYSQL_TYPE_LONG;\n    in_binds[4].buffer = &s32;\n    in_binds[4].buffer_length = 4;\n    in_binds[4].is_unsigned = 0;\n\n    in_binds[5].buffer_type = MYSQL_TYPE_LONG;\n    in_binds[5].buffer = &u32;\n    in_binds[5].buffer_length = 4;\n    in_binds[5].is_unsigned = 1;\n\n    in_binds[6].buffer_type = MYSQL_TYPE_LONGLONG;\n    in_binds[6].buffer = &s64;\n    in_binds[6].buffer_length = 8;\n    in_binds[6].is_unsigned = 0;\n\n    in_binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    in_binds[7].buffer = &u64;\n    in_binds[7].buffer_length = 8;\n    in_binds[7].is_unsigned = 1;\n\n    in_binds[8].buffer_type = MYSQL_TYPE_STRING;\n    in_binds[8].buffer = s1.data();\n    in_binds[8].buffer_length = s1.size();\n\n    in_binds[9].buffer_type = MYSQL_TYPE_STRING;\n    in_binds[9].buffer = s2.data();\n    in_binds[9].buffer_length = s2.size();\n\n    in_binds[10].buffer_type = MYSQL_TYPE_BLOB;\n    in_binds[10].buffer = b1.data();\n    in_binds[10].buffer_length = b1.size();\n\n    in_binds[11].buffer_type = MYSQL_TYPE_BLOB;\n    in_binds[11].buffer = b2.data();\n    in_binds[11].buffer_length = b2.size();\n\n    in_binds[12].buffer_type = MYSQL_TYPE_FLOAT;\n    in_binds[12].buffer = &flt;\n    in_binds[12].buffer_length = 4;\n\n    in_binds[13].buffer_type = MYSQL_TYPE_DOUBLE;\n    in_binds[13].buffer = &dbl;\n    in_binds[13].buffer_length = 8;\n\n    in_binds[14].buffer_type = MYSQL_TYPE_DATE;\n    in_binds[14].buffer = &dt;\n    in_binds[14].buffer_length = sizeof(dt);\n\n    in_binds[15].buffer_type = MYSQL_TYPE_DATETIME;\n    in_binds[15].buffer = &dtime;\n    in_binds[15].buffer_length = sizeof(dtime);\n\n    in_binds[16].buffer_type = MYSQL_TYPE_TIME;\n    in_binds[16].buffer = &t;\n    in_binds[16].buffer_length = sizeof(t);\n\n    // Prepare the output bind objects (only one parameter)\n    long long int out_id = 0;\n    MYSQL_BIND out_binds[1]{};\n    out_binds[0].buffer_type = MYSQL_TYPE_LONGLONG;\n    out_binds[0].buffer = &out_id;\n    out_binds[0].buffer_length = 8;\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 1000; ++i)\n    {\n        // Bind the params\n        if (mysql_stmt_bind_param(stmt, in_binds))\n        {\n            fprintf(stderr, \"Error binding params: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Execute the statement\n        if (mysql_stmt_execute(stmt))\n        {\n            fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Bind output\n        if (mysql_stmt_bind_result(stmt, out_binds))\n        {\n            fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Read the rows\n        while (true)\n        {\n            auto status = mysql_stmt_fetch(stmt);\n            if (status == MYSQL_DATA_TRUNCATED)\n            {\n                // No truncation is expected here\n                fprintf(stderr, \"Data truncation error\\n\");\n                exit(1);\n            }\n            else if (status == MYSQL_NO_DATA)\n            {\n                break;\n            }\n            else if (status == 1)\n            {\n                fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n                exit(1);\n            }\n            else\n            {\n                ++num_rows;\n            }\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We don't expect any rows to be matched\n    return num_rows == 0 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "bench/stmt_params_libmysqlclient.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n#include <mysql/field_types.h>\n#include <mysql/mysql.h>\n#include <mysql/mysql_time.h>\n#include <string>\n#include <vector>\n\nint main()\n{\n    // Initialize\n    if (mysql_library_init(0, NULL, NULL))\n    {\n        fprintf(stderr, \"could not initialize MySQL client library\\n\");\n        exit(1);\n    }\n    MYSQL* con = mysql_init(NULL);\n    if (con == NULL)\n    {\n        fprintf(stderr, \"Error initializing connection: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    // Connect\n    unsigned mode = SSL_MODE_DISABLED;\n    if (mysql_options(con, MYSQL_OPT_SSL_MODE, &mode))\n    {\n        fprintf(stderr, \"Error in mysql_options: %s\\n\", mysql_error(con));\n        exit(1);\n    }\n\n    if (mysql_real_connect(con, NULL, \"root\", \"\", \"boost_mysql_bench\", 0, \"/var/run/mysqld/mysqld.sock\", 0) ==\n        NULL)\n    {\n        fprintf(stderr, \"%s\\n\", mysql_error(con));\n        mysql_close(con);\n        exit(1);\n    }\n\n    // Prepare the statement. It should have many parameters and be a lightweight query.\n    // This SELECT is lighter than an INSERT.\n    MYSQL_STMT* stmt;\n    stmt = mysql_stmt_init(con);\n    if (!stmt)\n    {\n        printf(\"Could not initialize statement\\n\");\n        exit(1);\n    }\n    constexpr const char* stmt_str =\n        \"SELECT id FROM test_data WHERE id = 1 AND s8 = ? AND u8 = ? AND s16 = ? AND u16 = ? AND \"\n        \"s32 = ? AND u32 = ? AND s64 = ? AND u64 = ? AND s1 = ? AND s2 = ? AND b1 = ? AND \"\n        \"b2 = ? AND flt = ? AND dbl = ? AND dt = ? AND dtime = ? AND t = ?\";\n    if (mysql_stmt_prepare(stmt, stmt_str, strlen(stmt_str)))\n    {\n        fprintf(stderr, \"Error preparing statement: %s\\n\", mysql_stmt_error(stmt));\n        exit(1);\n    }\n\n    // Statement params\n    signed char s8 = 64;\n    unsigned char u8 = 172;\n    short s16 = -129;\n    unsigned short u16 = 0xfe21;\n    int s32 = 42;\n    unsigned u32 = 0xfe8173;\n    long long s64 = -1;\n    unsigned long long u64 = 98302402;\n    std::string s1(200, 'a');\n    std::string s2(36000, 'b');\n    std::vector<unsigned char> b1(200, 5);\n    std::vector<unsigned char> b2(35000, 7);\n    float flt = 3.14e10;\n    double dbl = 7.1e-150;\n    MYSQL_TIME dt{}, dtime{}, t{};\n\n    dt.year = 2010;\n    dt.month = 6;\n    dt.day = 20;\n\n    dtime.year = 2020;\n    dtime.month = 3;\n    dtime.day = 21;\n    dtime.hour = 10;\n    dtime.minute = 40;\n    dtime.second = 10;\n    dtime.second_part = 123456;\n\n    t.hour = 126;\n    t.minute = 18;\n    t.second = 40;\n    t.second_part = 123456;\n\n    // Prepare the bind objects\n    MYSQL_BIND in_binds[17]{};\n    in_binds[0].buffer_type = MYSQL_TYPE_TINY;\n    in_binds[0].buffer = &s8;\n    in_binds[0].buffer_length = 1;\n    in_binds[0].is_unsigned = 0;\n\n    in_binds[1].buffer_type = MYSQL_TYPE_TINY;\n    in_binds[1].buffer = &u8;\n    in_binds[1].buffer_length = 1;\n    in_binds[1].is_unsigned = 1;\n\n    in_binds[2].buffer_type = MYSQL_TYPE_SHORT;\n    in_binds[2].buffer = &s16;\n    in_binds[2].buffer_length = 2;\n    in_binds[2].is_unsigned = 0;\n\n    in_binds[3].buffer_type = MYSQL_TYPE_SHORT;\n    in_binds[3].buffer = &u16;\n    in_binds[3].buffer_length = 2;\n    in_binds[3].is_unsigned = 1;\n\n    in_binds[4].buffer_type = MYSQL_TYPE_LONG;\n    in_binds[4].buffer = &s32;\n    in_binds[4].buffer_length = 4;\n    in_binds[4].is_unsigned = 0;\n\n    in_binds[5].buffer_type = MYSQL_TYPE_LONG;\n    in_binds[5].buffer = &u32;\n    in_binds[5].buffer_length = 4;\n    in_binds[5].is_unsigned = 1;\n\n    in_binds[6].buffer_type = MYSQL_TYPE_LONGLONG;\n    in_binds[6].buffer = &s64;\n    in_binds[6].buffer_length = 8;\n    in_binds[6].is_unsigned = 0;\n\n    in_binds[7].buffer_type = MYSQL_TYPE_LONGLONG;\n    in_binds[7].buffer = &u64;\n    in_binds[7].buffer_length = 8;\n    in_binds[7].is_unsigned = 1;\n\n    in_binds[8].buffer_type = MYSQL_TYPE_STRING;\n    in_binds[8].buffer = s1.data();\n    in_binds[8].buffer_length = s1.size();\n\n    in_binds[9].buffer_type = MYSQL_TYPE_STRING;\n    in_binds[9].buffer = s2.data();\n    in_binds[9].buffer_length = s2.size();\n\n    in_binds[10].buffer_type = MYSQL_TYPE_BLOB;\n    in_binds[10].buffer = b1.data();\n    in_binds[10].buffer_length = b1.size();\n\n    in_binds[11].buffer_type = MYSQL_TYPE_BLOB;\n    in_binds[11].buffer = b2.data();\n    in_binds[11].buffer_length = b2.size();\n\n    in_binds[12].buffer_type = MYSQL_TYPE_FLOAT;\n    in_binds[12].buffer = &flt;\n    in_binds[12].buffer_length = 4;\n\n    in_binds[13].buffer_type = MYSQL_TYPE_DOUBLE;\n    in_binds[13].buffer = &dbl;\n    in_binds[13].buffer_length = 8;\n\n    in_binds[14].buffer_type = MYSQL_TYPE_DATE;\n    in_binds[14].buffer = &dt;\n    in_binds[14].buffer_length = sizeof(dt);\n\n    in_binds[15].buffer_type = MYSQL_TYPE_DATETIME;\n    in_binds[15].buffer = &dtime;\n    in_binds[15].buffer_length = sizeof(dtime);\n\n    in_binds[16].buffer_type = MYSQL_TYPE_TIME;\n    in_binds[16].buffer = &t;\n    in_binds[16].buffer_length = sizeof(t);\n\n    // Prepare the output bind objects (only one parameter)\n    long long int out_id = 0;\n    MYSQL_BIND out_binds[1]{};\n    out_binds[0].buffer_type = MYSQL_TYPE_LONGLONG;\n    out_binds[0].buffer = &out_id;\n    out_binds[0].buffer_length = 8;\n\n    // Ensure that nothing gets optimized away\n    unsigned num_rows = 0;\n\n    // Benchmark starts here\n    auto tbegin = std::chrono::steady_clock::now();\n\n    for (int i = 0; i < 1000; ++i)\n    {\n        // Bind the params\n        if (mysql_stmt_bind_param(stmt, in_binds))\n        {\n            fprintf(stderr, \"Error binding params: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Execute the statement\n        if (mysql_stmt_execute(stmt))\n        {\n            fprintf(stderr, \"Error executing statement: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Bind output\n        if (mysql_stmt_bind_result(stmt, out_binds))\n        {\n            fprintf(stderr, \"Error binding result: %s\\n\", mysql_stmt_error(stmt));\n            exit(1);\n        }\n\n        // Read the rows\n        while (true)\n        {\n            auto status = mysql_stmt_fetch(stmt);\n            if (status == MYSQL_DATA_TRUNCATED)\n            {\n                // No truncation is expected here\n                fprintf(stderr, \"Data truncation error\\n\");\n                exit(1);\n            }\n            else if (status == MYSQL_NO_DATA)\n            {\n                break;\n            }\n            else if (status == 1)\n            {\n                fprintf(stderr, \"Error fetching result: %s\\n\", mysql_stmt_error(stmt));\n                exit(1);\n            }\n            else\n            {\n                ++num_rows;\n            }\n        }\n    }\n\n    // Benchmark ends here\n    auto tend = std::chrono::steady_clock::now();\n    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;\n\n    // Cleanup\n    mysql_stmt_close(stmt);\n    mysql_close(con);\n\n    // We don't expect any rows to be matched\n    return num_rows == 0 ? EXIT_SUCCESS : EXIT_FAILURE;\n}"
  },
  {
    "path": "build.jam",
    "content": "# Copyright René Ferdinand Rivera Morell 2024\n# Distributed under the Boost Software License, Version 1.0.\n# (See accompanying file LICENSE_1_0.txt or copy at\n# http://www.boost.org/LICENSE_1_0.txt)\n\nrequire-b2 5.2 ;\n\nconstant boost_dependencies :\n    /boost/asio//boost_asio\n    /boost/assert//boost_assert\n    /boost/charconv//boost_charconv\n    /boost/compat//boost_compat\n    /boost/config//boost_config\n    /boost/container//boost_container\n    /boost/core//boost_core\n    /boost/describe//boost_describe\n    /boost/endian//boost_endian\n    /boost/intrusive//boost_intrusive\n    /boost/mp11//boost_mp11\n    /boost/optional//boost_optional\n    /boost/pfr//boost_pfr\n    /boost/system//boost_system\n    /boost/throw_exception//boost_throw_exception\n    /boost/variant2//boost_variant2 ;\n\nproject /boost/mysql\n    : common-requirements\n        <include>include\n    ;\n\nexplicit\n    [ alias boost_mysql : : : : <library>$(boost_dependencies) ]\n    [ alias all : boost_mysql example test ]\n    ;\n\ncall-if : boost-library mysql\n    ;\n\n"
  },
  {
    "path": "cmake/utils.cmake",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Include guard\nif (_BOOST_MYSQL_UTILS_INCLUDED)\n    return()\nendif()\nset(_BOOST_MYSQL_UTILS_INCLUDED TRUE)\n\n# Sets _WIN32_WINNT on Windows\nfunction(boost_mysql_set_windows_version TARGET_NAME)\n    if(MSVC)\n        if(WIN32 AND CMAKE_SYSTEM_VERSION)\n            set(WINNT_VERSION ${CMAKE_SYSTEM_VERSION})\n            string(REPLACE \".\" \"\" WINNT_VERSION ${WINNT_VERSION})\n            string(REGEX REPLACE \"([0-9])\" \"0\\\\1\" WINNT_VERSION ${WINNT_VERSION})\n\n            set(WINNT_VERSION \"0x${WINNT_VERSION}\")\n        else()\n            set(WINNT_VERSION \"0x0601\")\n        endif()\n\n        target_compile_definitions(\n            ${TARGET_NAME}\n            PUBLIC\n            _WIN32_WINNT=${WINNT_VERSION} # Silence warnings in Windows\n        )\n    endif()\nendfunction()\n\n# Utility function to set warnings and other compile properties of\n# our test targets\nfunction(boost_mysql_common_target_settings TARGET_NAME)\n    boost_mysql_set_windows_version(${TARGET_NAME})\n\n    if(CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n        target_compile_definitions(\n            ${TARGET_NAME}\n            PUBLIC\n            _SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING # Warnings in C++17 for Asio\n        )\n        target_compile_options(${TARGET_NAME} PUBLIC /bigobj) # Prevent failures on Windows\n    else()\n        # gcc-13 doesn't understand view types\n        if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)\n            target_compile_options(${TARGET_NAME} PUBLIC -Wno-dangling-reference -Wno-array-bounds)\n        endif()\n        target_compile_options(${TARGET_NAME} PUBLIC -Wall -Wextra)\n    endif()\n\n    set_target_properties(${TARGET_NAME} PROPERTIES CXX_EXTENSIONS OFF) # disable extensions\nendfunction()\n\nfunction(boost_mysql_test_target_settings TARGET_NAME)\n    boost_mysql_common_target_settings(${TARGET_NAME})\n\n    # Follow the Boost convention: don't build test targets by default,\n    # and only when explicitly requested by building target tests\n    set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL ON)\n    add_dependencies(tests ${TARGET_NAME})\nendfunction()\n"
  },
  {
    "path": "doc/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n\nproject mysql/doc ;\n\nimport boostbook ;\nimport os ;\nimport path ;\nimport-search /boost/docca ;\nimport docca ;\n\n\n# Note: adding server-specific error codes and collations to the reference\n# increases build times a lot without any benefit\nlocal doxygen_exclussions =\n    detail\n    impl\n    mysql_server_errc.hpp\n    mariadb_server_errc.hpp\n    mysql_collations.hpp\n    mariadb_collations.hpp\n    src.hpp\n;\n\nlocal include-prefix = [ path.root $(__file__:D) [ path.pwd ] ] ;\ninclude-prefix = [ path.native $(include-prefix:D)/include ] ;\n\ndocca.pyreference reference.qbk\n    :\n        [ glob-tree-ex ../include/boost/mysql : *.hpp : $(doxygen_exclussions) ]\n    :\n        <doxygen:param>PROJECT_NAME=MySQL\n        <doxygen:param>PROJECT_BRIEF=\"C++ MySQL Client Library\"\n        <doxygen:param>DISTRIBUTE_GROUP_DOC=YES\n        <doxygen:param>ENABLE_PREPROCESSING=YES\n        <doxygen:param>MACRO_EXPANSION=YES\n        <doxygen:param>EXPAND_ONLY_PREDEF=YES\n        <doxygen:param>SEARCH_INCLUDES=NO\n        <doxygen:param>STRIP_FROM_PATH=$(include-prefix)\n        <doxygen:param>\"PREDEFINED=\\\\\n            BOOST_MYSQL_DOXYGEN \\\\\n            __cpp_char8_t \\\\\n            \\\"BOOST_PFR_ENABLED=1\\\" \\\\\n            \\\"BOOST_PFR_CORE_NAME_ENABLED=1\\\" \\\\\n            \\\"BOOST_DEPRECATED(a)=\\\" \\\\\n            \\\"BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]]\\\" \\\\\n            \\\"BOOST_ASIO_INITFN_RESULT_TYPE(t,a)=auto\\\" \\\\\n            \\\"BOOST_ASIO_COMPLETION_TOKEN_FOR(sig)=class\\\" \\\\\n            \\\"BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct,sig)=auto\\\" \\\\\n            \\\"BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(ex)=\\\" \\\\\n            \\\"BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(ex)=\\\" \\\\\n            \\\"BOOST_MYSQL_RETURN_TYPE(...)=\\\" \\\\\n            \\\"protected=private\\\" \\\\\n            \\\"BOOST_CXX14_CONSTEXPR=constexpr\\\" \\\\\n            \\\"BOOST_INLINE_CONSTEXPR=inline constexpr\\\" \\\\\n            \\\"BOOST_MYSQL_CONSTEVAL=consteval\\\" \\\\\n            \\\"BOOST_MYSQL_CXX14\\\" \\\\\n            \\\"BOOST_MYSQL_WRITABLE_FIELD_TUPLE=class\\\" \\\\\n            \\\"BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR=class\\\" \\\\\n            \\\"BOOST_MYSQL_EXECUTION_REQUEST=class\\\" \\\\\n            \\\"BOOST_MYSQL_RESULTS_TYPE=class\\\" \\\\\n            \\\"BOOST_MYSQL_EXECUTION_STATE_TYPE=class\\\" \\\\\n            \\\"BOOST_MYSQL_OUTPUT_STRING=class\\\" \\\\\n            \\\"BOOST_MYSQL_FORMATTABLE=class\\\" \\\\\n            \\\"BOOST_MYSQL_STATIC_ROW=class\\\" \\\\\n            \\\"BOOST_MYSQL_PIPELINE_REQUEST_TYPE=class\\\" \\\\\n            \\\"BOOST_MYSQL_PIPELINE_STAGE_TYPE=class\\\" \\\\\n            \\\"BOOST_MYSQL_WRITABLE_FIELD=class\\\" \\\\\n            \\\"BOOST_MYSQL_DECL=\\\" \\\\\n            \\\"BOOST_MYSQL_HAS_LOCAL_TIME=\\\" \\\\\n            \\\"BOOST_NO_CXX17_DEDUCTION_GUIDES=\\\" \\\\\n            \"\n        <doxygen:param>SKIP_FUNCTION_MACROS=NO\n        <doxygen:param>OUTPUT_LANGUAGE=English\n        <doxygen:param>ABBREVIATE_BRIEF=\n        <doxygen:param>AUTOLINK_SUPPORT=NO\n        <doxygen:param>EXTRACT_ALL=NO\n        <doxygen:param>EXTRACT_PRIVATE=NO\n        <doxygen:param>EXTRACT_LOCAL_CLASSES=NO\n        <doxygen:param>HIDE_UNDOC_MEMBERS=YES\n        <doxygen:param>HIDE_UNDOC_CLASSES=YES\n        <doxygen:param>HIDE_FRIEND_COMPOUNDS=YES\n        <doxygen:param>CASE_SENSE_NAMES=YES\n        <doxygen:param>SHOW_INCLUDE_FILES=NO\n        <doxygen:param>INLINE_INFO=NO\n        <doxygen:param>SORT_MEMBER_DOCS=NO\n        <doxygen:param>SORT_MEMBERS_CTORS_1ST=YES\n        <doxygen:param>SHOW_USED_FILES=NO\n        <doxygen:param>SHOW_FILES=NO\n        <doxygen:param>SHOW_NAMESPACES=NO\n        <doxygen:param>QUIET=YES\n\n        <docca:config>config.json\n    ;\n\ninstall images\n    :\n        [ glob images/*.png images/*.svg ]\n    :\n        <location>html/mysql/images\n    ;\n\nexplicit images ;\n\nxml mysql_doc\n    :\n        qbk/00_main.qbk\n    :\n        <dependency>reference.qbk\n        <dependency>images\n    ;\n\nexplicit mysql_doc ;\n\n\nboostbook mysql\n    :\n        mysql_doc\n    :\n        <xsl:param>boost.root=../../../..\n        <xsl:param>chapter.autolabel=1\n        <xsl:param>chunk.section.depth=8                # Depth to which sections should be chunked\n        <xsl:param>chunk.first.sections=1               # Chunk the first top-level section?\n        <xsl:param>toc.section.depth=8                  # How deep should recursive sections appear in the TOC?\n        <xsl:param>toc.max.depth=8                      # How many levels should be created for each TOC?\n        <xsl:param>generate.toc=\"chapter toc,title section nop reference nop part toc\"\n        <include>../../../tools/boostbook/dtd\n    :\n        <dependency>images\n    ;\n\n# These are used to inform the build system of the\n# means to build the integrated and stand-alone docs.\n\nalias boostdoc ;\nexplicit boostdoc ;\n\nalias boostrelease : mysql ;\nexplicit boostrelease ;\n"
  },
  {
    "path": "doc/config.json",
    "content": "{\n    \"include_private\": false,\n    \"legacy_behavior\": false,\n    \"external_marker\": \"!EXTERNAL!\",\n    \"link_prefix\": \"mysql.ref.\",\n    \"default_namespace\": \"boost::mysql\",\n    \"convenience_header\": \"boost/mysql.hpp\",\n    \"replace_strings\": {\n        \"__see_below__\": \"``['see-below]``\",\n        \"\\\\bclass CompletionToken\\\\b\": \"class __CompletionToken__\",\n        \"\\\\bclass ExecutionContext\\\\b\": \"class __ExecutionContext__\",\n        \"\\\\bclass ExecutionRequest\\\\b\": \"class __ExecutionRequest__\",\n        \"\\\\bclass ExecutionStateType\\\\b\": \"class __ExecutionStateType__\",\n        \"\\\\bclass Executor\\\\b\": \"class __Executor__\",\n        \"\\\\bclass FieldViewFwdIterator\\\\b\": \"class __FieldViewFwdIterator__\",\n        \"\\\\bclass Formattable\\\\b\": \"class __Formattable__\",\n        \"\\\\bclass OutputString\\\\b\": \"class __OutputString__\",\n        \"\\\\bclass ResultsType\\\\b\": \"class __ResultsType__\",\n        \"\\\\bclass SocketStream\\\\b\": \"class __SocketStream__\",\n        \"\\\\bclass StaticRow\\\\b\": \"class __StaticRow__\",\n        \"\\\\bclass Stream\\\\b\": \"class __Stream__\",\n        \"\\\\bclass WritableField\\\\b\": \"class __WritableField__\",\n        \"\\\\bclass WritableFieldTuple\\\\b\": \"class __WritableFieldTuple__\",\n        \"\\\\bBOOST_MYSQL_FORMATTABLE\\\\b\": \"class\"\n    }\n}"
  },
  {
    "path": "doc/doxygen.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DOC_DOXYGEN_HPP\n#define BOOST_MYSQL_DOC_DOXYGEN_HPP\n\n/**\n * \\brief brief\n * \\details\n * description\n *\n * \\par Preconditions\n * Only for functions, if they have a precondition (i.e. assert(xxx))\n *\n * \\par Exception safety\n * No-throw guarantee.\n * Only for functions. Don't include it in network operations for now.\n * Strong guarantee.\n * Basic guarantee.\n * No-throw guarantee.\n * \\throws {exception} {condition}.\n *\n * \\par Object lifetimes\n * For async stuff or if the function returns views\n *\n * \\par Complexity\n * Include it only for functions in containers or where relevant.\n *      Linear in xxxx.\n *\n * (Include only for async ops)\n * \\par Handler signature\n * The handler signature for this operation is `void(boost::mysql::error_code)`\n *\n * \\par Per-operation cancellation\n * This operation supports per-operation cancellation. <Describe effects>\n * The following `asio::cancellation_type_t` values are supported:\n *\n *   - `asio::cancellation_type_t::terminal`\n *   - `asio::cancellation_type_t::partial`\n *   - `asio::cancellation_type_t::total`\n *\n * Specify this where it adds any value.\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe. \\n\n *\n * Specify this for new async operations. Include the error codes that we may return.\n * \\par Errors\n * \\li \\ref client_errc::X when condition Y\n */\n\n#endif\n"
  },
  {
    "path": "doc/qbk/00_main.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[library Boost.MySQL\n    [quickbook 1.7]\n    [copyright 2019 - 2024 Ruben Perez]\n    [id mysql]\n    [purpose MySQL client library]\n    [license\n        Distributed under the Boost Software License, Version 1.0.\n        (See accompanying file LICENSE_1_0.txt or copy at\n        [@http://www.boost.org/LICENSE_1_0.txt])\n    ]\n    [authors [Perez, Ruben]]\n    [category template]\n    [category generic]\n]\n\n[template nochunk[] [block '''<?dbhtml stop-chunking?>''']]\n[template mdash[] '''&mdash; ''']\n[template link_to_file[path][^'''<ulink url=\"https://github.com/boostorg/mysql/blob/master/'''[path]'''\">'''[path]'''</ulink>''']]\n[template include_file[path][^<'''<ulink url=\"https://github.com/boostorg/mysql/blob/master/include/'''[path]'''\">'''[path]'''</ulink>'''>]]\n[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']\n[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']\n\n[template reflink2[id text][link mysql.ref.boost__mysql__[id] [^[text]]]]\n[template reflink[id][reflink2 [id] [id]]]\n[template refmem[class mem][reflink2 [class].[mem] [class]::[mem]]]\n[template refmemunq[class mem][reflink2 [class].[mem] [mem]]]\n[template asioreflink[id term][@boost:/doc/html/boost_asio/reference/[id].html [^asio::[term]]]]\n[template mysqllink[id text][@https://dev.mysql.com/doc/refman/8.0/en/[id] [text]]]\n\n[def __CompletionToken__ [@boost:/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers ['CompletionToken]]]\n[def __ExecutionContext__ [@boost:/doc/html/boost_asio/reference/ExecutionContext.html ['ExecutionContext]]]\n[def __ExecutionRequest__ [reflink2 ExecutionRequest ['ExecutionRequest]]]\n[def __ExecutionStateType__ [reflink2 ExecutionStateType ['ExecutionStateType]]]\n[def __Executor__ [@boost:/doc/html/boost_asio/reference/Executor1.html ['Executor]]]\n[def __FieldViewFwdIterator__ [reflink2 FieldViewFwdIterator ['FieldViewFwdIterator]]]\n[def __Formattable__ [reflink2 Formattable ['Formattable]]]\n[def __OutputString__ [reflink2 OutputString ['OutputString]]]\n[def __ResultsType__ [reflink2 ResultsType ['ResultsType]]]\n[def __SocketStream__ [reflink2 SocketStream ['SocketStream]]]\n[def __StaticRow__ [reflink2 StaticRow ['StaticRow]]]\n[def __Stream__ [reflink2 Stream ['Stream]]]\n[def __WritableField__ [reflink2 WritableFieldTuple ['WritableField]]]\n[def __WritableFieldTuple__ [reflink2 WritableFieldTuple ['WritableFieldTuple]]]\n\n\n[def __Boost__ [@https://www.boost.org/ Boost]]\n[def __Asio__ [@boost:/libs/asio/index.html Boost.Asio]]\n[def __Beast__ [@boost:/libs/beast/index.html Boost.Beast]]\n[def __Context__ [@boost:/libs/context/index.html Boost.Context]]\n[def __Self__ [@boost:/libs/mysql/index.html Boost.MySQL]]\n[def __boost_optional__ [@boost:/libs/optional/index.html `boost::optional`]]\n[def __Describe__ [@boost:/libs/describe/index.html Boost.Describe]]\n[def __Pfr__ [@boost:/libs/pfr/index.html Boost.Pfr]]\n[def __ssl_context__ [asioreflink ssl__context ssl::context]]\n\n[/ MySQL stuff]\n[def __Mysql__ [@https://www.mysql.com/ MySQL]]\n[def __sql_mode__ [mysqllink sql-mode.html `sql_mode`]]\n[def __allow_invalid_dates__ [mysqllink sql-mode.html#sqlmode_allow_invalid_dates `ALLOW_INVALID_DATES`]]\n[def __strict_sql__ [mysqllink sql-mode.html#sql-mode-strict strict SQL mode]]\n[def __time_zone__ [mysqllink server-system-variables.html#sysvar_time_zone `time_zone`]]\n[def __TINYINT__ [mysqllink integer-types.html `TINYINT`]]\n[def __SMALLINT__ [mysqllink integer-types.html `SMALLINT`]]\n[def __MEDIUMINT__ [mysqllink integer-types.html `MEDIUMINT`]]\n[def __INT__ [mysqllink integer-types.html `INT`]]\n[def __BIGINT__ [mysqllink integer-types.html `BIGINT`]]\n[def __YEAR__ [mysqllink year.html `YEAR`]]\n[def __DATE__ [mysqllink datetime.html `DATE`]]\n[def __DATETIME__ [mysqllink datetime.html `DATETIME`]]\n[def __TIMESTAMP__ [mysqllink datetime.html `TIMESTAMP`]]\n[def __TIME__ [mysqllink time.html `TIME`]]\n[def __FLOAT__ [mysqllink floating-point-types.html `FLOAT`]]\n[def __DOUBLE__ [mysqllink floating-point-types.html `DOUBLE`]]\n[def __DECIMAL__ [mysqllink fixed-point-types.html `DECIMAL`]]\n[def __NUMERIC__ [mysqllink fixed-point-types.html `NUMERIC`]]\n[def __BIT__ [mysqllink bit-type.html `BIT`]]\n[def __CHAR__ [mysqllink char.html `CHAR`]]\n[def __VARCHAR__ [mysqllink char.html `VARCHAR`]]\n[def __BINARY__ [mysqllink binary-varbinary.html `BINARY`]]\n[def __VARBINARY__ [mysqllink binary-varbinary.html `VARBINARY`]]\n[def __TEXT__ [mysqllink blob.html `TEXT`]]\n[def __BLOB__ [mysqllink blob.html `BLOB`]]\n[def __ENUM__ [mysqllink enum.html `ENUM`]]\n[def __SET__ [mysqllink set.html `SET`]]\n[def __JSON__ [mysqllink json.html `JSON`]]\n[def __GEOMETRY__ [mysqllink spatial-type-overview.html `GEOMETRY`]]\n[def __USE__ [mysqllink use.html `USE`]]\n\n[/  Taken db_setup.sql, because import doesn't work for SQL files - keep in sync.\n    Having them in a separate file doesn't work ]\n[def __sp_get_employees__\n```\nCREATE PROCEDURE get_employees(IN pin_company_id CHAR(10))\nBEGIN\n    START TRANSACTION READ ONLY;\n    SELECT id, name, tax_id FROM company WHERE id = pin_company_id;\n    SELECT first_name, last_name, salary FROM employee WHERE company_id = pin_company_id;\n    COMMIT;\nEND\n```]\n\n[def __sp_create_employee__\n```\nCREATE PROCEDURE create_employee(\n    IN  pin_company_id CHAR(10),\n    IN  pin_first_name VARCHAR(100),\n    IN  pin_last_name VARCHAR(100),\n    OUT pout_employee_id INT\n)\nBEGIN\n    START TRANSACTION;\n    INSERT INTO employee (company_id, first_name, last_name)\n        VALUES (pin_company_id, pin_first_name, pin_last_name);\n    SET pout_employee_id = LAST_INSERT_ID();\n    INSERT INTO audit_log (msg) VALUES ('Created new employee...');\n    COMMIT;\nEND\n```]\n\n[/ AUTOGENERATED IMPORTS BEGIN ]\n[import ../../example/1_tutorial/1_sync.cpp]\n[import ../../example/1_tutorial/2_async.cpp]\n[import ../../example/1_tutorial/3_with_params.cpp]\n[import ../../example/1_tutorial/4_static_interface.cpp]\n[import ../../example/1_tutorial/5_updates_transactions.cpp]\n[import ../../example/1_tutorial/6_connection_pool.cpp]\n[import ../../example/1_tutorial/7_error_handling.cpp]\n[import ../../example/2_simple/inserts.cpp]\n[import ../../example/2_simple/deletes.cpp]\n[import ../../example/2_simple/prepared_statements.cpp]\n[import ../../example/2_simple/disable_tls.cpp]\n[import ../../example/2_simple/tls_certificate_verification.cpp]\n[import ../../example/2_simple/metadata.cpp]\n[import ../../example/2_simple/multi_function.cpp]\n[import ../../example/2_simple/callbacks.cpp]\n[import ../../example/2_simple/coroutines_cpp11.cpp]\n[import ../../example/2_simple/unix_socket.cpp]\n[import ../../example/2_simple/batch_inserts.cpp]\n[import ../../example/2_simple/batch_inserts_generic.cpp]\n[import ../../example/2_simple/dynamic_filters.cpp]\n[import ../../example/2_simple/patch_updates.cpp]\n[import ../../example/2_simple/source_script.cpp]\n[import ../../example/2_simple/pipeline.cpp]\n[import ../../example/3_advanced/http_server_cpp20/main.cpp]\n[import ../../example/3_advanced/http_server_cpp20/types.hpp]\n[import ../../example/3_advanced/http_server_cpp20/error.hpp]\n[import ../../example/3_advanced/http_server_cpp20/error.cpp]\n[import ../../example/3_advanced/http_server_cpp20/repository.hpp]\n[import ../../example/3_advanced/http_server_cpp20/repository.cpp]\n[import ../../example/3_advanced/http_server_cpp20/handle_request.hpp]\n[import ../../example/3_advanced/http_server_cpp20/handle_request.cpp]\n[import ../../example/3_advanced/http_server_cpp20/server.hpp]\n[import ../../example/3_advanced/http_server_cpp20/server.cpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/main.cpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/types.hpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/repository.hpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/repository.cpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/handle_request.hpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/handle_request.cpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/server.hpp]\n[import ../../example/3_advanced/http_server_cpp14_coroutines/server.cpp]\n[import ../../test/integration/test/snippets/prepared_statements.cpp]\n[import ../../test/integration/test/snippets/sql_formatting_advanced.cpp]\n[import ../../test/integration/test/snippets/connection_establishment.cpp]\n[import ../../test/integration/test/snippets/charsets.cpp]\n[import ../../test/integration/test/snippets/multi_function.cpp]\n[import ../../test/integration/test/snippets/tutorials.cpp]\n[import ../../test/integration/test/snippets/text_queries.cpp]\n[import ../../test/integration/test/snippets/templated_connection.cpp]\n[import ../../test/integration/test/snippets/metadata.cpp]\n[import ../../test/integration/test/snippets/connection_pool.cpp]\n[import ../../test/integration/test/snippets/time_types.cpp]\n[import ../../test/integration/test/snippets/interfacing_sync_async.cpp]\n[import ../../test/integration/test/snippets/pipeline.cpp]\n[import ../../test/integration/test/snippets/dynamic_interface.cpp]\n[import ../../test/integration/test/snippets/overview.cpp]\n[import ../../test/integration/test/snippets/static_interface.cpp]\n[import ../../test/integration/test/snippets/multi_resultset.cpp]\n[import ../../test/integration/test/snippets/sql_formatting_advanced_2.cpp]\n[/ AUTOGENERATED IMPORTS END ]\n[import ../../test/integration/include/test_integration/snippets/describe.hpp]\n\n[include 01_intro.qbk]\n[include 02_integrating.qbk]\n[include 03_1_tutorial_sync.qbk]\n[include 03_2_tutorial_async.qbk]\n[include 03_3_tutorial_with_params.qbk]\n[include 03_4_tutorial_static_interface.qbk]\n[include 03_5_tutorial_updates_transactions.qbk]\n[include 03_6_tutorial_connection_pool.qbk]\n[include 03_7_tutorial_error_handling.qbk]\n[include 04_overview.qbk]\n[include 05_connection_establishment.qbk]\n[include 06_text_queries.qbk]\n[include 07_prepared_statements.qbk]\n[include 08_dynamic_interface.qbk]\n[include 09_static_interface.qbk]\n[include 10_multi_resultset.qbk]\n[include 11_multi_function.qbk]\n[include 12_connection_pool.qbk]\n[include 13_async.qbk]\n[include 13_1_interfacing_sync_async.qbk]\n[include 14_error_handling.qbk]\n[include 15_sql_formatting_advanced.qbk]\n[include 16_metadata.qbk]\n[include 17_charsets.qbk]\n[include 18_time_types.qbk]\n[include 19_templated_connection.qbk]\n[include 20_pipeline.qbk]\n[include 20_1_benchmarks.qbk]\n[include 21_examples.qbk]\n\n\n\n[section:ref Reference]\n[xinclude helpers/quickref.xml]\n[block'''<part label=\"Two: Reference\">''']\n[include reference.qbk]\n[include helpers/ExecutionRequest.qbk]\n[include helpers/ExecutionStateType.qbk]\n[include helpers/FieldViewFwdIterator.qbk]\n[include helpers/Formattable.qbk]\n[include helpers/OutputString.qbk]\n[include helpers/ResultsType.qbk]\n[include helpers/SocketStream.qbk]\n[include helpers/StaticRow.qbk]\n[include helpers/Stream.qbk]\n[include helpers/WritableFieldTuple.qbk]\n[block'''</part>''']\n[endsect]\n"
  },
  {
    "path": "doc/qbk/01_intro.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:intro Introduction]\n[nochunk]\n\n__Self__ is a C++11 client for the __Mysql__ and [@https://mariadb.com/ MariaDB] database servers, based on __Asio__.\n\n[heading Motivation]\n\nMySQL and MariaDB are widespread SQL database servers. MySQL\nclients connect to the server in order to issue SQL queries. For this\npurpose, MySQL employs a dedicated protocol. __Self__ is an\nimplementation of the client side of this protocol.\n\nThis library is a full implementation of the\n[@https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html MySQL client/server protocol].\nIt aims to expose the protocol primitives in an efficient but easy-to-use way.\nIt is similar in scope to the official [@https://dev.mysql.com/doc/c-api/8.0/en/ libmysqlclient],\nbut interoperable with Asio, safer and more expressive. Note that __Self__\n[*does not use libmysqlclient]: it's a full implementation of the MySQL protocol, which makes\nit natively compatible with Asio.\n\nThis library is relatively low level. It gives you access to text SQL queries and\nprepared statements. Don't expect an ORM. [link mysql.overview This section] presents a quick tour\nover the main library capabilities.\n\nThe design goals of this library are:\n\n* [*Interoperability with Asio]: this library employs the same principles as __Asio__ and __Beast__.\n  Users of any of these libraries will immediately understand Boost.MySQL, and will have it easy\n  to integrate it in their programs.\n* [*Basis for further abstraction]: it allows efficient access to the MySQL client/server protocol\n  so it can be used by higher level components as a building block. Do a single thing and do it well.\n* [*Efficiency].\n* [*Ease of use]: the MySQL protocol is full of pitfalls. We believe in simplicity. While retaining\n  control over the important parts, the library hides as much complexity from the protocol as possible.\n\nNon-goals:\n\n* [*Being an ORM].\n* [*Being a SQL query generator]. The library doesn't focus on utilities to generate queries.\n  Don't expect syntax sugar like `table(\"orders\").select([\"id\", \"quantity\"]).where(\"id\", 42)`.\n* [*Portability to other SQL databases]. This library focuses on MySQL. It won't work with Postgres\n  or SQLite.\n\n[heading When to use]\n\nIf any of the following statements is true, you may consider using __Self__:\n\n* Your application uses __Asio__ and you need to access a MySQL server.\n* You need asynchronous access to a MySQL server from a C++ application.\n* You need efficient access to a MySQL server from a C++ application.\n* You need a BSL-licensed library to access your MySQL server.\n* You are writing a higher-level database access library, like an ORM.\n\nUse cases may include web servers, ETL processes and IoT systems.\n\nIt may not be a good fit for you if:\n\n* You only need synchronous access to a MySQL server and efficiency doesn't matter\n  to your application. The official client libraries may be better suited for you, in this case.\n* You need homogeneous SQL access to different SQL databases (and not only MySQL access).\n  You may find more value in using [@https://github.com/rbock/sqlpp11 sqlpp11] or a similar wrapper\n  library.\n\n\n\n[heading Tested compilers and systems]\n\nBoost.MySQL is tested under the following compilers:\n\n* gcc 5.4 to gcc 15.0 (Linux)\n* clang 4 to clang 20.0 (Linux)\n* Apple clang 14.0 (OSX)\n* MSVC 14.1 - Visual Studio 2017 (Windows)\n* MSVC 14.2 - Visual Studio 2019 (Windows)\n* MSVC 14.3 - Visual Studio 2022 (Windows)\n\nAnd with the following RDBMS systems:\n\n* MySQL v5.7.41.\n* MySQL v8.4.1.\n* MariaDB v11.4.2.\n\n[heading Acknowledgements]\n\nI would like to specially acknowledge [@https://github.com/madmongo1 Richard Hodges] (hodges.r@gmail.com)\nfor his invaluable technical guidance during development. Thanks also to\nChristian Mazakas for his ideas in early stages, and to\n[@https://github.com/klemens-morgenstern Klemens Morgenstern] and\nand [@https://github.com/vinniefalco Vinnie Falco] for his technical advice.\nWithout you, this library would not exist.\n\nFinally, thanks to [@https://github.com/chriskohlhoff Christopher Kohlhoff]\nfor his awesome __Asio__ library, and to [@https://github.com/HowardHinnant\nHoward Hinnant] for his date algorithms, shamelessly copied in this lib.\n\n\n[endsect] [/intro]"
  },
  {
    "path": "doc/qbk/02_integrating.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:integrating Integrating Boost.MySQL into your project]\n[nochunk]\n\n[note\n    [*Breaking change in Boost 1.85]: the compiled library Boost.Charconv is now required.\n    If you're upgrading and getting linker errors, link your executable to the `Boost::charconv`\n    CMake target.\n]\n\n[section:header_only Header-only mode]\n\nThe easiest way to start using the library is header-only mode (the default).\nYou will need the following:\n\n* A C++11 compiler (like gcc >=5.4, clang >=3.6, or Visual Studio 2017 or higher).\n* The Boost headers and Boost.Charconv. You can obtain them following the official installation instructions\nfor [@boost:/more/getting_started/unix-variants.html UNIX-like systems] and for\n[@boost:/more/getting_started/windows.html Windows], or from a package manager.\nNote that Boost.MySQL does not work with the standalone version of __Asio__.\n* The OpenSSL headers and libraries. We recommend using your system package manager to obtain them.\n* CMake.\n\nUse the following `CMakeLists.txt`, replacing `main.cpp` with your project's source files:\n\n[!teletype]\n```\nproject(boost_mysql_example LANGUAGES CXX)\n\nfind_package(Boost REQUIRED COMPONENTS charconv)\nfind_package(Threads REQUIRED)\nfind_package(OpenSSL REQUIRED)\n\nadd_executable(main main.cpp)\ntarget_link_libraries(main PRIVATE Boost::charconv Threads::Threads OpenSSL::Crypto OpenSSL::SSL)\n```\n\n[note\n    `Boost::charconv` is only available in Boost 1.85 and higher. If you're using\n    an older version, use the `Boost::headers` target, instead.\n]\n\nIf you're happy with header-only mode, have a look at [link mysql.tutorial_sync the first tutorial]\nor [link mysql.examples any of the examples] to learn how to use the library.\n\n[endsect]\n\n\n\n[section:separate_compilation Separate compilation mode]\n\nHeader-only mode is simple but can make your project's build times high.\nIf this is the case, we recommend switching to separate compilation mode.\n\nTo use it, you must add the following to exactly one `.cpp` file:\n\n```\n// Contents of boost_mysql.cpp\n\n// This header file contains all Boost.MySQL implementations.\n// It should be included in exactly one .cpp file.\n// All code using Boost.MySQL in separate build mode, including this file,\n// should define BOOST_MYSQL_SEPARATE_COMPILATION.\n#include <boost/mysql/src.hpp>\n```\n\nAll of your code, including this `.cpp` file, should define the \n`BOOST_MYSQL_SEPARATE_COMPILATION` macro. This is what your `CMakeLists.txt`\ncould look like:\n\n[!teletype]\n```\nproject(boost_mysql_example LANGUAGES CXX)\n\nfind_package(Boost REQUIRED COMPONENTS charconv)\nfind_package(Threads REQUIRED)\nfind_package(OpenSSL REQUIRED)\n\nadd_executable(\n    main\n    # Contains Boost.MySQL sources via #include <boost/mysql/src.hpp>\n    boost_mysql.cpp\n    # List any other .cpp your exe has here\n    main.cpp\n)\ntarget_link_libraries(main PRIVATE Boost::charconv Threads::Threads OpenSSL::Crypto OpenSSL::SSL)\n\n# We need to define BOOST_MYSQL_SEPARATE_COMPILATION in any code using Boost.MySQL in separate-build mode\ntarget_compile_definitions(main PRIVATE BOOST_MYSQL_SEPARATE_COMPILATION)\n```\n\nBoost.Asio and Boost.Beast offer a very similar separate compilation mode.\nIf you're using them together with Boost.MySQL, you may consider enabling separate compilation\nfor them, too.\n\n[endsect]\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_1_tutorial_sync.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_sync Tutorial 1: hello world!]\n\nIn this first tutorial, we will write a simple program\nto demonstrate the basic concepts. We will connect to the server\nand issue the query `SELECT \"Hello World!\"`.\n\nTo run this tutorial, you need a running MySQL server listening\nin localhost on port 3306 (the default one). You should have\nthe credentials of a valid MySQL user (username and password).\nNo further setup is needed.\n\nThe full program listing for this tutorial can be found [link mysql.examples.tutorial_sync here].\n\nWe will follow these steps:\n\n# Create a connection object.\n# Establish a session with the server.\n# Issue the query.\n# Use the rows generated by the query.\n# Close the connection.\n\nThis tutorial uses synchronous functions with exceptions,\nas they're easy to use. In subsequent tutorials, we will\nlearn how to use asynchronous functions, which are more versatile.\n\n[heading Namespace conventions]\n\nAll functions and classes reside within the `boost::mysql` namespace.\nTo reduce verbosity, all examples and code samples use the following namespace aliases:\n\n[tutorial_sync_namespaces]\n\n\n\n\n[heading Connection object]\n\nLike most Asio-based applications, we need to create a\n[asioreflink io_context io_context] object before anything else.\nAn `io_context` is an execution context: it contains an event loop,\nfile descriptor states, timers and other items required to perform I/O.\nMost applications should only create a single `io_context`, even when\nmultiple MySQL connections are needed.\n\nWe then create an [reflink any_connection], which represents a single connection\nto a MySQL server:\n\n[tutorial_sync_connection]\n\n\n\n\n[heading Connecting to the server]\n\n[refmem any_connection connect] establishes a client session with the server.\nIt takes a [reflink connect_params] object with the required\ninformation to establish a session:\n\n[tutorial_sync_connect]\n\n\n\n\n[heading Issuing the SQL query]\n\n[refmem any_connection execute] accepts a string containing\nthe SQL query to run and sends it to the server for execution.\nIt returns a [reflink results] object, containing the rows returned by the query:\n\n[tutorial_sync_query]\n\n\n\n\n[heading Obtaining the results]\n\n[reflink results] is a class that holds the result of a query in memory.\nTo obtain the value we selected, we can write:\n\n[tutorial_sync_results]\n\nLet's break this into steps:\n\n* [refmem results rows] returns all the rows that this object contains.\n  It returns a [reflink rows_view], which is a 2D matrix-like structure.\n* `result.rows().at(0)` returns the first row, represented as a [reflink row_view].\n* `result.rows().at(0).at(0)` returns the first field in the first row. This is a\n  [reflink field_view], a variant-like class that can hold any type allowed in MySQL.\n* The obtained `field_view` is streamed to `std::cout`.\n\n\n\n\n[heading Closing the connection]\n\nOnce we are done with the connection, we can close it by calling\n[refmem any_connection close]. Note that\nthis will send a final quit packet to the MySQL server to notify\nwe are closing the connection, and thus may fail.\n\n[tutorial_sync_close]\n\n\n\n\n[heading Next steps]\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_sync here].\n\nYou can now proceed to [link mysql.tutorial_async the next tutorial].\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_2_tutorial_async.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_async Tutorial 2: going async with C++20 coroutines]\n\nIn the [link mysql.tutorial_sync previous tutorial] we used\nsynchronous functions. They are simple, but have a number of limitations:\n\n* They aren't as versatile as async functions. For example, there is no way\n  to set a timeout to a sync operation.\n* They don't scale well. Since sync functions block the calling thread until they complete,\n  you need to create OS threads to achieve parallelism. This doesn't scale well\n  and leads to the inherent complexities of multi-threaded programs.\n* Some classes (like [reflink connection_pool]) only offer an async interface.\n\nFor this reason, we recommend to always use async functions.\nAll Asio-compatible libraries (including this one) allow async\nprogramming using a variety of styles. In this chapter, we will\nexplain how to use C++20 coroutines because they are the simplest to use.\n\n[note\n  Still not using C++20? Don't worry, you can use\n  [link mysql.examples.coroutines_cpp11 stackful coroutines] and\n  [link mysql.examples.callbacks callbacks] even in C++11.\n]\n\n\n\n[heading What is a coroutine?]\n\nRoughly speaking, it's a function that can suspend and resume, keeping local variables\nalive in the process. Suspension happens when reaching a `co_await` expression.\nThese usually appear when the program performs an I/O operation.\nWhen an expression like this is encountered, the following happens:\n\n# The coroutine initiates the I/O operation.\n# The coroutine suspends, passing control back to the `io_context` (that is, the event loop).\n# While the I/O operation is in progress, the `io_context` may run other operations,\n  like other coroutines.\n# When the I/O operation completes, the `io_context` resumes the coroutine\n  immediately after the `co_await` expression.\n\n\n\n\n\n[heading Transforming sync code into coroutines]\n\nRecall the following code from our previous tutorial:\n\n[tutorial_sync_main]\n\nTo transform this code into a coroutine, we need to:\n\n* Extract it to a separate function returning `boost::asio::awaitable<void>`.\n* Replace sync functions (like [refmem any_connection connect]) by async ones\n  (like [refmem any_connection async_connect]).\n* Place a `co_await` operator in front of each I/O operation.\n\nDoing this, we have:\n\n[tutorial_async_coro]\n\nNote that the coroutine doesn't create or return explicitly any\n`boost::asio::awaitable<void>` object - this is handled by the compiler.\nThe return type actually marks the function as being a coroutine.\n`void` here means that the coroutine doesn't return anything.\n\nIf any of the above I/O operations fail, an exception is thrown.\nYou can prevent this by [link mysql.overview.errors using `asio::redirect_error`].\n\n\n\n\n[heading Running our coroutine]\n\nAs in the previous tutorial, we first need to create an `io_context` and a connection:\n\n[tutorial_async_connection]\n\nTo run a coroutine, use [asioreflink co_spawn co_spawn]:\n\n[tutorial_async_co_spawn]\n\nNote that this will only schedule the coroutine. To actually run\nit, we need to call `io_context::run`. This will block the calling\nthread until all the scheduled coroutines and I/O operations complete:\n\n[tutorial_async_run]\n\n\n\n\n\n[heading Next steps]\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_async here].\n\nYou can now proceed to [link mysql.tutorial_with_params the next tutorial].\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_3_tutorial_with_params.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_with_params Tutorial 3: queries with parameters]\n\nUntil now, our SQL queries were hard-coded string literals.\nHowever, most real-world use cases involve \nrunning queries containing user-supplied parameters.\n\nIn this tutorial, we will be using an employee database.\nYou can obtain this sample database by sourcing the `example/db_setup.sql`\nfile in Boost.MySQL source code repository.\n\nThe employee table is defined as:\n\n[!teletype]\n```\n    CREATE TABLE employee(\n        id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n        first_name VARCHAR(100) NOT NULL,\n        last_name VARCHAR(100) NOT NULL,\n        ... -- other fields not relevant for us\n    );\n```\n\nWe will write a program that retrieves an employee by ID\nand prints their full name. The employee ID will be supplied\nby the user as a command line argument. In more realistic\nexamples, you may get it from a file or HTTP request.\n\n\n\n\n[heading Avoiding SQL injection]\n\nWe need to build a query like the following:\n\n[!teletype]\n```\n    SELECT first_name, last_name FROM employee WHERE id = <actual-id>\n```\n\nReplacing `<actual-id>` by the value passed by the user.\n\nSince we don't control the employee ID, we must consider it [*untrusted].\nWe must [*never use raw string concatenation] to build queries.\nOtherwise, malicious values can cause SQL injection vulnerabilities,\nwhich are extremely severe.\n\nBoost.MySQL offers two options to deal with this:\n\n# Compose the query dynamically in the client, using specialized tools\n  to avoid SQL injection. This option is versatile, simple and\n  appropriate for general use.\n# Perform parameter substitution server side using\n  [link mysql.prepared_statements prepared statements]. This is more complex\n  and better suited for cases involving lots of numeric data or\n  executing same query repeatedly.\n\nIn this tutorial, we will use client-side generation\n(termed [link mysql.text_queries client-side SQL formatting] throughout the documentation).\n\n\n\n\n[heading Using with_params]\n\n[refmem any_connection async_execute]\ncan also deal with queries with parameters.\nWe need to replace the string literal by a call\nto [reflink with_params], passing a query template\nand the actual values of the parameters:\n\n[tutorial_with_params_execute]\n\nThe query template uses a syntax similar to `std::format`.\nYou can use numbers, strings,\ndates, times and many other types as parameters.\nMore information about client-side SQL formatting\nis available in [link mysql.text_queries this page].\n\n\n\n[heading Using the retrieved rows]\n\nOur query might return either one row (if an employee is found)\nor none (if no employee with the given ID exists).\nAccounting for this:\n\n[tutorial_with_params_results]\n\n\n\n\n\n[heading Connecting with database]\n\nIf you've run `example/db_setup.sql`, the `employee` table\nexists within the `boost_mysql_examples` database.\nTo use this table without qualification, we need to specify\na database name when connecting. This is achieved by\nsetting [refmem connect_params database]:\n\n[tutorial_with_params_connect_params]\n\n\n\n\n\n[heading Creating the connection inside the coroutine]\n\nSince we're connecting and closing the connection in our coroutine, it\nmakes sense to make it a local variable, instead of passing it as parameter.\nRecall that we need a reference to an execution context (i.e. `io_context`)\nto build a connection. We could pass the `io_context` as a parameter\nto our coroutine, but there's a simpler way: coroutines\nalready hold a reference to where they are executing:\n\n[tutorial_with_params_connection]\n\nThe expression `co_await asio::this_coro::executor` retrieves the [*executor]\nthat our coroutine is using. An executor is a lightweight handle\nto an execution context, and can be used to create our connection.\n\n[note\n  `co_await asio::this_coro::executor` does not perform any I/O.\n  It only retrieves the current coroutine's executor.\n]\n\n\n\n\n\n[heading Wrapping up]\n\nWith all these changes, this is how our coroutine looks like:\n\n[tutorial_with_params_coroutine]\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_with_params here].\n\nYou can now proceed to [link mysql.tutorial_static_interface the next tutorial].\n\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_4_tutorial_static_interface.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_static_interface Tutorial 4: the static interface]\n\nUntil now we've read the rows generated by our queries into\n[reflink results] objects. As we've seen, `results`\nis a 2D structure that contains variant-like values.\nThroughout the documentation, these variant-based APIs\nare called [link mysql.dynamic_interface the dynamic interface].\n\n\n\n[heading Dynamic interface limitations]\n\nWorking with variant-like objects can be cumbersome.\nRecall the following lines from our previous tutorial,\nwhere we used the retrieved rows:\n\n[tutorial_with_params_results]\n\nAn employee is represented here by a [reflink row_view], which is a collection\nof [reflink field_view] objects. `field_view` is a variant-like type\nthat can represent all the types supported by MySQL.\n\nSince `field_view` supports streaming, this code doesn't require\nany casting. However, consider refactoring our code to split\nthe printing logic to a separate function:\n\n[tutorial_static_fn]\n\nLooking at our database schema, we know that both values are\nstrings. We can use [refmem field_view as_string] to perform the casts:\n\n[tutorial_static_casts]\n\nWhile this code works, it can create maintenance problems:\n\n* We retrieve fields by position. That is, we know that `employee.at(0)`\n  holds the employee's `first_name`.\n  However, if we refactor our query, we might forget updating the indices.\n* Following a similar reasoning, the casts are error-prone.\n* Both `at` and `as_string` throw on error. Attempting to avoid exceptions\n  while still performing the required safety checks quickly becomes unmanageable.\n\nIf we know the types returned by our queries at compile time,\nwe can use the static interface, instead. This interface can\nparse the rows returned by a query into instances of\na C++ struct defined by us.\n\n[note\n  The static interface requires C++14 or later.\n]\n\n\n\n\n[heading Using static_results with Boost.Pfr]\n\nIn C++20 and later, we can use __Pfr__ and the [reflink static_results]\nclass to parse the rows. The first step is to define a plain C++\nstruct with the fields we expect in our query:\n\n[tutorial_static_struct]\n\nWe now replace the [reflink results] object by a [reflink static_results].\nThe marker type [reflink pfr_by_name] indicates Boot.MySQL that it should\nuse Boost.Pfr for reflection.\n\n[tutorial_static_execute]\n\nUsing the retrieved data is now much easier, since [refmem static_results rows]\nreturns a `span<const employee>`:\n\n[tutorial_static_results]\n\nWhen using the static interface, `async_execute` will perform a set of\nchecks on the query results to ensure compatibility between the\nC++ types and what MySQL returns. These checks aim to discover\npotential problems as early as possible, and are called\n[link mysql.static_interface.meta_checks metadata checks].\n\n\n\n[heading Using the static interface in C++14]\n\nC++20 makes it possible to use Boost.Pfr as described here,\nwhich is the easiest option. Boost.MySQL also supports __Describe__\nand `std::tuple`'s, which can be used in C++14.\nThe mechanics are quite similar to what's been explained here.\n\n\n\n[heading Wrapping up]\n\n[link mysql.static_interface This section] contains more information about the static interface.\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_static_interface here].\n\nYou can now proceed to [link mysql.tutorial_updates_transactions the next tutorial].\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_5_tutorial_updates_transactions.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_updates_transactions Tutorial 5: UPDATEs, transactions and semicolon-separated queries]\n\nAll the previous tutorials have only used `SELECT` statements, but\nBoost.MySQL is not limited to them. Using [refmemunq any_connection async_execute]\nyou can run any SQL statement supported by MySQL.\n\nIn this tutorial, we will write a program that changes the first name of an\nemployee, given their ID, and prints the updated employee details.\nWe will use an `UPDATE` and transaction management statements.\n`INSERT` and `DELETE` statements have similar mechanics.\n\n\n\n[heading A simple UPDATE]\n\nWe can use the same tools and functions as in previous tutorials:\n\n[tutorial_updates_transactions_update]\n\nBy default, auto-commit is enabled, meaning that when `async_execute`\nreturns, the `UPDATE` is visible to other client connections.\n\n\n\n\n[heading Checking that the UPDATE took effect]\n\nThe above query will succeed even if there was no employee with the given ID.\nWe would like to retrieve the updated employee details on success, and emit\na useful error message if no employee was matched.\n\nWe may be tempted to use [refmem results affected_rows] at first, but\nthis doesn't convey the information we're looking for:\na row may be matched but not affected. For example, if you try to\nset `first_name` to the same value it already has,\nMySQL will count the row as a matched, but not affected.\n\n\nMySQL does not support the `UPDATE ... RETURNING` syntax, so we will\nhave to retrieve the employee manually after updating it.\nWe can add the following after our `UPDATE`:\n\n[tutorial_updates_transactions_select]\n\nHowever, the code above contains a race condition. Imagine the following situation:\n\n* The `UPDATE` is issued. No employee is matched.\n* Before our program sends the `SELECT` query, a different program inserts\n  an employee with the ID that we're trying to update.\n* Our program runs the `SELECT` statement and retrieves the newly inserted row.\n\nTo our program, it looks like we succeeded performing the update, when\nwe really didn't. Depending on the nature of our program, this may\nor may not have serious consequences, but it's something we should avoid.\n\n\n[heading Avoiding the race condition with a transaction block]\n\nWe can fix the race condition using transactions.\nIn MySQL, a transaction block is opened with `START TRANSACTION`.\nSubsequent statements will belong to the transaction block,\nuntil the transaction either commits or is rolled back.\nA `COMMIT` statement commits the transaction.\nA rollback happens if the connection that initiated the transaction\ncloses or an explicit `ROLLBACK` statement is used.\n\nWe will enclose our `UPDATE` and `SELECT` statements in\na transaction block. This will ensure that the `SELECT`\nwill get the updated row, if any:\n\n[tutorial_updates_transactions_txn]\n\n\n\n\n[heading Using multi-queries]\n\nWhile the code we've written is correct, it's not very performant.\nWe're incurring in 4 round-trips to the server, when our queries don't depend\non the result of previous ones. The round-trips occur within a transaction\nblock, which causes certain database rows to be locked, increasing contention.\nWe can improve the situation by running our four statements in a single batch.\n\nMulti-queries are a protocol feature that lets you execute several queries\nat once. Individual queries must be separated by semicolons.\n\nMulti-queries are disabled by default. To enable them, set\n[refmem connect_params multi_queries] to `true` before connecting:\n\n[tutorial_updates_transactions_connect]\n\nMulti-queries can be composed an executed using the same\nfunctions we've been using:\n\n[tutorial_updates_transactions_multi_queries]\n\nAccessing the results is slightly different. MySQL returns 4 resultsets,\none for each query. In Boost.MySQL, this operation is said to be\n[link mysql.multi_resultset multi-resultset].\n[reflink results] can actually store more than one resultset.\n[refmem results rows] actually accesses the rows in the first resultset,\nbecause it's the most common use case.\n\nWe want to get the rows retrieved by the `SELECT` statement,\nwhich corresponds to the third resultset.\n[refmem results at] returns a [reflink resultset_view] containing data\nfor the requested resultset:\n\n[tutorial_updates_transactions_dynamic_results]\n\n\n[heading Using manual indices in with_params]\n\nRepeating `employee_id` in the parameter list passed to `with_params`\nviolates the DRY principle.\nAs with `std::format`, we can refer to a format argument more than once\nby using manual indices:\n\n[tutorial_updates_transactions_manual_indices]\n\n\n\n[heading Using the static interface with multi-resultset]\n\nFinally, we can rewrite our code to use the static interface so it's safer.\nIn multi-resultset scenarios, we can pass as many row types\nto [reflink static_results] as resultsets we expect.\nWe can use the empty tuple (`std::tuple<>`) as a row type\nfor operations that don't return rows, like the `UPDATE`.\nOur code becomes:\n\n[tutorial_updates_transactions_static]\n\n\n[heading Wrapping up]\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_updates_transactions here].\n\nYou can now proceed to [link mysql.tutorial_connection_pool the next tutorial].\n\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_6_tutorial_connection_pool.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_connection_pool Tutorial 6: Connection pools]\n\nAll our programs until now have used one-shot connections.\nThey also didn't feature any fault tolerance:\nif the server is unavailable, our program throws an exception\nand terminates. Most real world scenarios require\nlong-lived, reliable connections, instead.\n\nIn this tutorial, we will implement a server for a simple request-reply\nprotocol. The protocol allows clients to retrieve the full name of\nan employee given their ID.\nWe will use [reflink connection_pool] to maintain a set of healthy connections\nthat we can use when a client connects to our server.\n\n\n\n\n[heading The protocol]\n\nThe protocol is TCP based, and can be described as follows:\n\n* After connecting, the client sends a message containing the employee ID,\n  encoded as an 8-byte, big-endian integer.\n* The server replies with a string containing the employee full name,\n  or \"NOT_FOUND\", if the ID doesn't match any employee.\n* The connection is closed after that.\n\nThis protocol is intentionally overly simplistic, and\nshouldn't be used in production. See our\n[link mysql.examples.http_server_cpp20 HTTP examples]\nfor more advanced use cases.\n\n\n\n\n[heading Creating a connection pool]\n\n[reflink connection_pool] is an I/O object that contains\n[reflink any_connection] objects, and can be\nconstructed from an execution context and a [reflink pool_params]\nconfig struct:\n\n[tutorial_connection_pool_create]\n\nA single connection pool is usually created per application.\n\n[refmem connection_pool async_run] should be called once per pool:\n\n[tutorial_connection_pool_run]\n\n\n\n\n\n\n[heading Using pooled connections]\n\nLet's first write a coroutine that encapsulates database access.\nGiven an employee ID, it should return the string to be sent as response to the client.\nDon't worry about error handling for now - we will take care of it in the next tutorial.\n\nWhen using a pool, we don't need to explicitly create, connect or close connections.\nInstead, we use [refmem connection_pool async_get_connection] to obtain them from the pool:\n\n[tutorial_connection_pool_get_connection]\n\n[reflink pooled_connection] is a wrapper around [reflink any_connection],\nwith some pool-specific additions. We can use it like a regular connection:\n\n[tutorial_connection_pool_use]\n\nWhen a [reflink pooled_connection] is destroyed, the connection is returned\nto the pool. The underlying connection will be cleaned up using a lightweight\nsession reset mechanism and recycled.\nSubsequent [refmemunq connection_pool async_get_connection]\ncalls may retrieve the same connection. This improves efficiency,\nsince session establishment is costly.\n\n[refmemunq connection_pool async_get_connection] waits\nfor a client connection to become available before completing.\nIf the server is unavailable or credentials are invalid,\nit may wait indefinitely. This is a problem for both development and production.\nWe can solve this by using [asioreflink cancel_after cancel_after],\nwhich allows setting timeouts to async operations:\n\n[tutorial_connection_pool_get_connection_timeout]\n\nDon't worry if you don't fully understand how this works.\nWe will go into more detail on [asioreflink cancel_after cancel_after],\ncancellations and completion tokens in the next tutorial.\n\nPutting all pieces together, our coroutine becomes:\n\n[tutorial_connection_pool_db]\n\n\n\n\n[heading Handling a client session]\n\nLet's now build a function that handles a client sessions,\ninvoking the database access logic in the process:\n\n[tutorial_connection_pool_session]\n\n\n\n\n[heading Listening for connections]\n\nWe now need logic to accept incoming TCP connections.\nWe will use an `asio::ip::tcp::acceptor` object\nto accomplish it, listening for connections in a loop\nuntil the server is stopped:\n\n[tutorial_connection_pool_listener]\n\n\n\n\n[heading Waiting for signals]\n\nFinally, we need a way to stop our program. We will use an `asio::signal_set` object\nto catch signals, and call `io_context::stop` when Ctrl-C is pressed:\n\n[tutorial_connection_pool_signals]\n\nPutting all these pieces together, our main program becomes:\n\n[tutorial_connection_pool_main]\n\n\n\n\n[heading Wrapping up]\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_connection_pool here].\n\nFor simplicity, we've left error handling out of this tutorial.\nThis is usually very important in a server like the one we've written,\nand is the topic of our [link mysql.tutorial_error_handling next tutorial].\n\n[endsect]"
  },
  {
    "path": "doc/qbk/03_7_tutorial_error_handling.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:tutorial_error_handling Tutorial 7: Error handling]\n\nThe [link mysql.tutorial_connection_pool previous tutorial]\ndid not include any error handling. When an error is encountered\nwhile talking to the DB or the client, an exception is thrown and\nthe program terminates. This is undesirable in server programs like the one we're writing.\n\nTo add error handling, we can just add try/catch blocks to prevent exception propagation.\nHowever, many code bases discourage the use of exceptions for non-exceptional circumstances,\nlike I/O errors. In this tutorial, we will learn how to manage I/O errors without exceptions\nby using [asioreflink as_tuple as_tuple] and error codes.\n\n\n[heading Error handling strategy]\n\nThere are two kind of I/O errors that our program can encounter:\n\n* Reading and writing to the client may fail. This can happen if\n  the client program is faulty or a network error happens.\n  In this case, we should log the problem and close the connection.\n* Talking to the database may fail. This can happen if [refmemunq connection_pool async_get_connection]\n  is cancelled because of a timeout. In this case, we will return a special string (`\"ERROR\"`)\n  to the client, signalling that we can't fulfill the request, and log the problem.\n\nAdditionally, we will modify how we use `asio::cancel_after` to make the system more reliable.\n\n\n\n\n[heading:completion_token Completion tokens]\n\nBefore proceeding, we need to understand what a completion token is.\nThe concepts in this section are not specific to Boost.MySQL, but apply\nto Asio and all Asio-compatible libraries. Since Asio docs can be terse,\nwe explain them here to facilitate the reader.\n\nAll asynchronous operations accept an optional, last parameter specifying what\nto do when the operation completes.\nThis last parameter is the operation's\n[@boost:/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers completion token].\n\nCallbacks are valid completion tokens. Taking [refmemunq connection_pool async_get_connection]\nas example, the following is valid:\n\n[tutorial_error_handling_callbacks]\n\nWe have already been using this when creating coroutines.\n`asio::co_spawn` is also an async operation, and the callback we pass\nas its last parameter is the completion token.\n\nYou might consider using callbacks if your compiler doesn't support coroutines,\nor just by personal preference. [link mysql.examples.callbacks This example]\ndemonstrates how to use them.\n\nIf you don't specify a completion token, the operation's [*default completion token]\nwill be used. This is usually `asio::deferred` or `mysql::with_diagnostics(asio::deferred)`\n[footnote [reflink with_diagnostics] is an adapter completion token that enhances\nthrown exceptions with a diagnostic string supplied by the server.\n`mysql::with_diagnostics(asio::deferred)` is otherwise equivalent to `asio::deferred`.].\nThese tokens transform asynchronous operations into awaitables,\nso we can use them in C++20 coroutines.\n\nThe default completion token for [refmemunq connection_pool async_get_connection] is\n`mysql::with_diagnostics(asio::deferred)`. This means that the following two are equivalent:\n\n[tutorial_error_handling_default_tokens]\n\nCompletion tokens are generic: once you learn how to use one, you can use it\nwith any Asio-compliant async operation. This includes all functions in Boost.Asio,\nBoost.MySQL, Boost.Beast and Boost.Redis. We say that operations in these libraries\nare compliant with Asio's universal async model. Writing these is hard, but they're easy to use!\n\n\n\n\n\n[heading Adapter completion tokens]\n\nSome tokens don't fully specify what to do when the operation completes,\nbut rather modify some aspect of how the operation executes.\nThey wrap (or adapt) other completion tokens. The underlying token\ndetermines what to do when the operation completes.\n\n[asioreflink cancel_after cancel_after] is an adapter token.\nIt modifies how an operation executes by setting a timeout,\nbut it doesn't specify what to do on completion.\n\nAdapter tokens can be passed an optional completion token\nas the last argument. If the token is omitted, the default\none will be used. Continuing with our example:\n\n[tutorial_error_handling_adapter_tokens]\n\n\n[heading Handler signature and exceptions]\n\nEach async operation has an associated handler signature.\nWe can find these signatures in the documentation for each operation.\nThe handler signature is the prototype that a callback function\npassed as completion token would need to have to be compatible with the operation.\n\nThe handler signature for [refmemunq connection_pool async_get_connection]\nis `void(boost::system::error_code, mysql::pooled_connection)`.\n\nHowever, when we invoke `co_await` on the awaitable returned by `async_get_connection`,\nwe don't get any `error_code`. This is because `co_await` inspects\nthe handler signature at compile-time, looking for an `error_code` as first parameter.\nIf it finds it, `co_await` will remove it from the argument list, returning\nonly the `pooled_connection`. At runtime, the error code is checked.\nIf the code indicates a failure, an exception is thrown.\n\nThis mechanism is important to understand how `as_tuple` works.\n\n\n\n\n[heading asio::as_tuple]\n\n[asioreflink as_tuple as_tuple] is another adapter completion token\nthat can be used to prevent exceptions. It modifies the operation's\nhandler signature, packing all arguments into a `std::tuple`.\nThis inhibits the automatic error code checks explained in the previous section, \nthus preventing exceptions on I/O failure. Continuing with our example:\n\n[tutorial_error_handling_as_tuple]\n\nIn practice, it's usually better to use structured bindings:\n\n[tutorial_error_handling_as_tuple_structured_bindings]\n\nAll the properties of adapter completion tokens apply:\n\n[tutorial_error_handling_as_tuple_default_tokens]\n\nAdapter tokens can be combined. To apply a timeout to the operation\nwhile avoiding exceptions, you can use:\n\n[tutorial_error_handling_as_tuple_cancel_after]\n\n\n\n\n\n[heading Using asio::as_tuple for database code]\n\nLet's apply [asioreflink as_tuple as_tuple] to our database logic.\nWe will remove timeouts for now - we will add them back later.\n\n[tutorial_error_handling_db_nodiag]\n\n\n\n\n\n\n[heading Diagnostics objects]\n\nWhile what we wrote works, it can be improved. When a database operation fails, the server\nmay supply an error string with information about what went wrong. Boost.MySQL may also\ngenerate such strings in certain cases. We get this automatically\nwhen using exceptions. Thanks to [reflink with_diagnostics] and default completion tokens,\nthe library throws [reflink error_with_diagnostics] objects,\nwhich inherit from `boost::system::system_error`\nand have a [refmemunq error_with_diagnostics get_diagnostics] member.\n\nWhen using error codes, we need to handle diagnostics manually.\nAll functions in Boost.MySQL are overloaded to accept a [reflink diagnostics]\noutput parameter. It will be populated with extra information in case of error.\n\nLet's update our code to use diagnostics:\n\n[tutorial_error_handling_db]\n\nWe also need to write the function to log errors:\n\n[tutorial_error_handling_log_error]\n\n[refmem diagnostics client_message] and [refmem diagnostics server_message] differ\nin their origin. Client messages never contain user-supplied input, and can always\nbe used safely. Server messages may contain user input, and should be treated with\nmore caution (logging them is fine).\n\n\n\n\n\n[heading Using asio::as_tuple with client reads and writes]\n\nSince `asio::read` and `asio::write` are compliant async operations,\nwe can use [asioreflink as_tuple as_tuple] with them, too:\n\n[tutorial_error_handling_session_as_tuple]\n\n\n\n\n\n[heading Timeouts]\n\nOur session handler has three logical steps:\n\n* Read a request from the client.\n* Access the database.\n* Write the response to the client.\n\nEach of these steps may take long to complete. We will set a separate timeout\nto each one.\n\nClient reads and writes are the easiest ones to handle -\nwe just need to combine `as_tuple` and `cancel_after`:\n\n[tutorial_error_handling_read_timeout]\n\nThe database logic is more involved. Ideally, we would like\nto set a timeout to the overall database access operation, rather\nthan to individual steps. However, a `co_await` expression\nisn't an async operation, and can't be passed a completion token.\nWe can fix this by replacing plain `co_await` by `asio::co_spawn`,\nwhich accepts a completion token:\n\n[tutorial_error_handling_db_timeout]\n\nWith these modifications, the session handler becomes:\n\n[tutorial_error_handling_session]\n\nWith these modifications, our server is ready!\n\n\n\n[heading Wrapping up]\n\nFull program listing for this tutorial is [link mysql.examples.tutorial_error_handling here].\n\nThis concludes our tutorial series. You can now look at the [link mysql.overview overview section]\nto learn more about the library features, or to the [link mysql.examples example section]\nif you prefer to learn by doing.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/04_overview.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:overview Overview]\n[nochunk]\n\n\nThis section briefly explains the library main classes and functions, and how to use them.\n\nBoost.MySQL exposes sync and async functions implementing functionality involving I/O.\nAs explained [link mysql.tutorial_async in the second tutorial],\nit's advisable to use async functions when possible, because they are more flexible.\n\nBoost.MySQL supports the Boost.Asio universal async model. This means that\na variety of async programming paradigms can be used with the library,\nincluding callbacks, stackful coroutines and C++20 coroutines.\nWe will use C++20 coroutines throughout the document because they're\neasy to use.\n\n[note\n  Still not using C++20? Don't worry, you can use\n  [link mysql.examples.coroutines_cpp11 stackful coroutines] and\n  [link mysql.examples.callbacks callbacks] even in C++11.\n]\n\n\n\n\n\n[section Connection establishment]\n\n[reflink any_connection] is the most primitive I/O object in the library.\nIt can establish and close connections, run queries and manage prepared statements.\nLike most I/O objects, `any_connection` can be constructed from an execution context:\n\n[tutorial_sync_connection]\n\n`any_connection` is named like this for historic reasons:\na templated connection class came before it.\nWe currently recommend using `any_connection` for new\ncode because it's simpler and more powerful.\n\nThe MySQL client/server protocol is session-oriented. Before anything else,\nyou must perform session establishment by calling [refmem any_connection async_connect]:\n\n[overview_connect]\n\n[refmemunq any_connection async_connect] performs the hostname resolution,\nTCP session establishment, TLS handshake and MySQL handshake.\nBy default, TLS is used if the server supports it.\n\nYou can configure a number of parameters here, including\nthe database to use, TLS options and buffer sizes.\nSee [link mysql.connection_establishment this section] for more info.\n\nBoost.MySQL also supports\n[link mysql.connection_establishment.unix using UNIX-domain sockets].\n\nTo cleanly terminate a connection, use [refmemunq any_connection async_close].\nThis sends a packet informing of the imminent close and shuts down TLS.\nThe connection destructor will also close the socket, so no leak occurs.\n\n[endsect]\n\n\n\n\n\n[section Running queries]\n\nThe simplest way to run a SQL query is using [refmem any_connection async_execute].\nYou can execute queries by passing a string as first parameter:\n\n[overview_text_query]\n\nMost queries contain user-supplied input. [*Never use raw string concatenation]\nto build queries, since this is vulnerable to SQL injection.\nBoost.MySQL provides two interfaces to run queries with parameters:\n\n\n[table\n    [\n        [Feature]\n        [Code]\n    ]\n    [\n        [\n            [link mysql.text_queries Client-side SQL formatting]:\n\n            * Securely expands queries client-side.\n            * Text-based protocol.\n            * Adequate for general use.\n        ]\n        [\n            [overview_with_params]\n        ]\n    ]\n    [\n        [\n            [link mysql.prepared_statements Prepared statements]:\n\n            * Parsed and executed in two different operations.\n            * Binary protocol.\n            * Adequate when running a query several times or retrieving\n              lots of numeric data.\n        ]\n        [\n            [overview_statement]\n        ]\n    ]\n]\n\nBy default, we recommend using [reflink with_params] because it's\nsimpler and entails less round-trips to the server.\nSee [link mysql.text_queries.comparison the comparison section] for more info.\n\nClient-side SQL formatting can also be used to\n[link mysql.sql_formatting_advanced.expand expand queries]\nwithout sending them to the server.\n\n[endsect]\n\n\n\n\n\n[section The dynamic and the static interfaces]\n\nIn MySQL, a ['resultset] refers to the results generated by a SQL query.\nA resultset is composed of rows, [link mysql.meta metadata] and\nadditional info, like the last insert ID.\n\nThere are two different interfaces to access resultsets.\nYou can use the [reflink results] class to access rows using a dynamically-typed interface,\nusing variant-like objects to represent values retrieved from the server. On other other hand,\n[reflink static_results] is statically-typed. You specify the shape of your rows at compile-time,\nand the library will parse the retrieved values for you into the types you provide.\n\nYou can use almost every feature in this library (including text queries and prepared statements) with both interfaces.\n\nFor example, given the following table :\n\n[/ (TODO: this code is duplicated.) ]\n\n[!teletype]\n```\n    CREATE TABLE employee(\n        id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n        first_name VARCHAR(100) NOT NULL,\n        last_name VARCHAR(100) NOT NULL,\n        ... -- other fields not relevant for us\n    );\n```\n\nThis is how you would access its contents using either of the interfaces:\n\n[table\n    [\n        [Interface]\n        [Description]\n        [Example]\n    ]\n    [\n        [\n            Dynamic interface: [reflink results]\n        ]\n        [\n            * Variant based\n            * Available in C++11\n            * [link mysql.dynamic_interface Learn more]\n        ]\n        [\n            [overview_ifaces_dynamic]\n        ]\n    ]\n    [\n        [\n            Static interface: [reflink static_results]\n        ]\n        [\n            * Parses rows into your own types\n            * Requires C++20 when using Boost.Pfr, C++14 when using Boost.Describe\n            * [link mysql.static_interface Learn more]\n        ]\n        [\n            [overview_static_struct][br]\n            [overview_ifaces_static]\n        ]\n    ]\n]\n\nPrefer using the static interface when possible.\n\n[endsect]\n\n\n\n\n\n\n\n[section Running INSERT, UPDATE and DELETE statements]\n\nThe same APIs explained above can be used for SQL statements\nthat don't retrieve data:\n\n[overview_update]\n\nWhen performing INSERTs, you might find [refmem results last_insert_id]\nhandy, which retrieves the last AUTO INCREMENT ID generated by the executed statement.\n\nSee [link mysql.tutorial_updates_transactions our tutorial on UPDATEs and transactions]\nfor more info.\n\n[endsect]\n\n\n\n\n\n[section:async Single outstanding async operation per connection]\n\nAt any given point in time, an `any_connection` can only have a single async operation outstanding.\nIn other words, connections implement no asynchronous locking or queueing, which\nkeeps code simple and efficient. If you need to perform several operations in parallel,\nyou can open more connections or use [reflink connection_pool].\n\nTrying to run operations concurrently on a single connection is detected at\nruntime and generates a `client_errc::operation_in_progress` error:\n\n[overview_async_parallel]\n\n[endsect]\n\n\n\n\n\n\n[section:errors Error handling]\n\nAn operation fails if a network error happens,\na protocol violation is encountered, or the server reports an error.\nFor instance, SQL syntax errors make `async_execute` fail.\n\nWhen the server reports an error, it provides a diagnostic string\ndescribing what happened. The [reflink diagnostics] class encapsulates\nthis message. Some library functions generate diagnostics strings, too.\n\nBoth the sync functions in [link mysql.tutorial_sync the first tutorial]\nand the coroutines in this exposition throw exceptions when they fail.\nThe exception type is [reflink error_with_diagnostics], which inherits\nfrom `boost::system::system_error` and adds a [reflink diagnostics] object.\nAsync functions use [reflink with_diagnostics], a completion token adapter,\nto transparently include diagnostics in exceptions.\n\nYou can avoid exceptions when using coroutines with `asio::redirect_error`:\n\n[overview_no_exceptions]\n\n[reflink2 error_code mysql::error_code] is an alias for `boost::system::error_code`.\n\n[endsect]\n\n\n\n\n[section Multi-function operations]\n\nUntil now, we've been using [refmemunq any_connection async_execute], which\nexecutes some SQL and reads all generated data into an in-memory object.\n\nSome use cases may not fit in this simple pattern. For example:\n\n* When reading a very big resultset, it may not be efficient (or even possible) to completely\n  load it in memory. Reading rows in batches may be more adequate.\n* If rows contain very long `TEXT` or `BLOB` fields, it may not be adequate to copy these values\n  from the network buffer into the `results` object. A view-based approach may be better.\n\nFor these cases, we can break the execute operation into several steps,\nusing a ['multi-function operation] (the term is coined by this library). This example reads an entire\ntable in batches, which can be the case in an ETL process:\n\n[overview_multifn]\n\n[note\n    Once you start a multi-function operation with [refmemunq any_connection async_start_execution],\n    the server immediately sends all rows to the client. [*You must read all rows] before engaging in further operations.\n    If you try to initiate an unrelated operation before reading all rows, you will get a\n    `client_errc::engaged_in_multi_function` error.\n]\n\nMulti-function operations are powerful but complex. Only use them when there is a strong reason to do so.\nMulti-function operations also work with the static interface.\nPlease refer to [link mysql.multi_function this section] for more information on these operations.\n\n[endsect]\n\n\n\n[section Connection pools]\n\nConnection pooling is a technique where several long-lived connections\nare re-used for independent logical operations. When compared to\nestablishing individual connections, it has the following benefits:\n\n* It provides better performance. Please consult [link mysql.connection_pool.benchmarks our benchmarks]\n  for more info.\n* It simplifies connection management. The connection pool will establish sessions,\n  perform retries and apply timeouts out of the box.\n\nThis is how you can create a pool of connections:\n\n[connection_pool_create]\n\n[refmem connection_pool async_run] must be called exactly once per pool.\nThis function takes care of actually keeping connections healthy.\n\nTo retrieve a connection, use [refmem connection_pool async_get_connection]:\n\n[connection_pool_get_connection]\n\nFor more info, see [link mysql.connection_pool this section].\n\n[endsect]\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/05_connection_establishment.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:connection_establishment Connection establishment and termination]\n[nochunk]\n\nThis section discusses several aspects regarding the creation,\nestablishment and termination of client connections.\n\n\n\n\n\n[section Authentication]\n\n[refmem connect_params username] and [refmem connect_params password]\ncontain the credentials used during authentication.\nThe password is sent to the server either hashed or over a secure\nchannel such as TLS, as mandated by the protocol.\n\nMySQL implements several authentication plugins that can be used\nto authenticate a user (see the [mysqllink pluggable-authentication.html\npluggable authentication MySQL docs]).\nEach MySQL user is associated to a single authentication\nplugin, specified during using creation.\nAdditionally, servers define a default authentication plugin\n(see [mysqllink server-system-variables.html#sysvar_authentication_policy `authentication_policy`] and\n[mysqllink server-system-variables.html#sysvar_default_authentication_plugin\n`default_authentication_plugin`]). The default plugin will\nbe used for newly created users, and may affect how the handshake works.\n\nThis library implements the two most common authentication plugins:\n\n* [mysqllink native-pluggable-authentication.html `mysql_native_password`].\n  Unless otherwise configured, this is the default plugin for\n  MySQL 5.7 and MariaDB. It can be used over both TLS and plaintext\n  connections. It sends the password hashed, salted by a nonce.\n* [mysqllink caching-sha2-pluggable-authentication.html\n  `caching_sha2_password`]. This is the default plugin for\n  MySQL 8.0+. This plugin used to require using TLS.\n  Since Boost 1.89, this is no longer the case, and it can be used\n  with plaintext connections, too.\n\n\nMulti-factor authentication is not yet supported.\nIf you require support for a plugin not listed above or for MFA,\nplease file a feature request against the GitHub repository.\n\n[note\n    Servers configured with a default authentication plugin\n    not implemented in Boost.MySQL are not supported, regardless\n    of the actual plugin the concrete user employs. This limitation\n    may be lifted in the future.\n]\n\n[endsect]\n\n\n\n[section Connect with database]\n\n[refmem connect_params database] contains the database name\nto connect to. If you specify it, your connection will default to\nuse that database, as if you had issued a __USE__ statement.\nYou can leave it blank to select no database.\nYou can always issue a __USE__ statement using [refmemunq any_connection async_execute]\nto select a different database after establishing the connection.\n\n[endsect]\n\n\n\n\n[section:tls TLS support]\n\nTLS encrypted connections are fully supported by Boost.MySQL.\nTCP connections established using [reflink any_connection] use TLS by default.\n\n[heading TLS handshake and termination]\n\nThe TLS handshake is performed by [refmem any_connection async_connect].\nThis contrasts with libraries like __Beast__, where the TLS handshake\nmust be explicitly invoked by the user.\nWe selected this approach because the TLS handshake is part of the MySQL protocol's handshake:\nthe client and server exchange several unencrypted messages, then perform the TLS handshake\nand continue exchanging encrypted messages, until the connection either succeeds or fails.\nThis scheme enables the TLS negotiation feature (see below for more info).\n\nIf the TLS handshake fails, the entire [refmemunq any_connection async_connect]\noperation will also fail.\n\nTLS shutdown is performed by [refmem any_connection async_close].\nMySQL doesn't always close TLS connections\ngracefully, so errors generated by the TLS shutdown are ignored.\n\n\n[heading:negotiation TLS negotiation]\n\nDuring connection establishment, client and server negotiate whether to use TLS or not.\nBoost.MySQL supports such negotiation using [refmem connect_params ssl]. This is\na [reflink ssl_mode] enum with the following options:\n\n* `ssl_mode::enable` will make the connection use TLS if the server supports it,\n  falling back to a plaintext connection otherwise. [*This is the default]\n  for [reflink any_connection] when using TCP.\n* `ssl_mode::require` ensures that the connection uses TLS.\n  If the server does not support it, [refmemunq any_connection async_connect] fails.\n* `ssl_mode::disable` unconditionally disables TLS.\n\n[*UNIX sockets] are considered secure channels and [*never use TLS].\nWhen connecting using a UNIX socket, [refmem connect_params ssl] is ignored.\n\nAfter a successful connection establishment, you can use\n[refmem any_connection uses_ssl] to query whether the connection is encrypted or not.\n\n\n[heading Disabling TLS]\n\nAs mentioned above, setting [refmem connect_params ssl] to `ssl_mode::disable`\ndisables TLS:\n\n[section_connection_establishment_disable_tls]\n\nSee the [link mysql.examples.disable_tls full example here].\n\n\n\n[heading:options Certificate validation and other TLS options]\n\nYou can pass an optional __ssl_context__ to [reflink any_connection]\nconstructor. You can set many TLS parameters doing this, including\ntrusted CAs, certificate validation callbacks and TLS extensions.\n\n[reflink any_connection_params] contains a [refmemunq any_connection_params ssl_context]\nmember that can be used for this. For example, TLS certificate validation\nis disabled by default. To enable it:\n\n[section_connection_establishment_tls_options]\n\nYou can safely share a single __ssl_context__ among several connections.\n\nIf no `ssl::context` is passed, one will be internally created by the\nconnection when required. The default context doesn't perform certificate validation.\n\nThe full source code for the above example is [link mysql.examples.tls_certificate_verification here].\n\n\n\n[heading TLS in connection_pool]\n\nSince [reflink connection_pool] creates [reflink any_connection] instances,\nthe mechanics for TLS are similar. TLS-related parameters are specified\nduring pool construction, as members of [reflink pool_params]:\n\n* [refmem pool_params ssl] controls TLS negotiation.\n  It's a [reflink ssl_mode] value, with the semantics explained\n  [link mysql.connection_establishment.tls.negotiation above].\n* [refmem pool_params ssl_ctx] is a __ssl_context__\n  that is passed to connections created by the pool.\n  It can be used to configure\n  [link mysql.connection_establishment.tls.options TLS options]\n  like certificate verification. The pool takes ownership\n  of the passed `ssl::context`, as opposed to `any_connection`.\n\n[endsect] [/ TLS ]\n\n\n\n\n\n\n\n\n[section:unix UNIX sockets]\n\n[refmem connect_params server_address] is an [reflink any_address],\na variant-like type that can hold a (hostname, port) pair or a UNIX socket path.\nTo connect to MySQL using a UNIX socket, set `server_address`\nto a UNIX domain path:\n\n[section_connection_establishment_unix_socket]\n\nNote that UNIX sockets never use TLS, regardless of the value of\n[refmem connect_params ssl].\n\n[endsect]\n\n\n\n\n\n[section Changing the network buffer size limit]\n\n[reflink any_connection] owns an internal network buffer\nused to store messages that are to be written or have been read\nfrom the server. Its initial size is given by [refmem any_connection_params initial_buffer_size].\nEvery protocol message needs to fit in memory, so the buffer is expanded as required.\nWhen reading data, every row is sent as an individual message.\n\nThe buffer never resizes past [refmem any_connection_params max_buffer_size].\nIf an operation requires a bigger buffer, it will fail with the\n`client_errc::max_buffer_size_exceeded` error code. The default size\nis 64MB.\n\nIf you need to read or write individual rows bigger than the default limit,\nyou can increase it when constructing the connection:\n\n[section_connection_establishment_max_buffer_size]\n\nNote that reading datasets bigger than 64MB [*does not require increasing the limit]\nas long as individual rows are smaller than the aforementioned limit.\n\nTweaking [refmem any_connection_params initial_buffer_size] may affect\n[refmem any_connection async_read_some_rows] performance, as explained\nin [link mysql.multi_function.read_some_rows this section].\n\n[endsect]\n\n\n\n\n[section Enabling multi-queries]\n\nYou can run several several semicolon-separated queries at once using\n[refmem any_connection async_execute]. This is a protocol feature that\nis disabled by default. You can enable it by setting\n[refmem connect_params multi_queries] to true before connecting:\n\n[section_connection_establishment_multi_queries]\n\nAs explained [link mysql.tutorial_updates_transactions in the tutorial],\nmulti-separated queries are useful in a number of cases,\nlike when using transactions.\n[link mysql.multi_resultset.multi_queries This section] contains more\ninfo on how to use multi-queries.\n\nThis protocol feature is disabled by default as a security hardening\nmeasure. If your application contains a SQL injection vulnerability,\nthis feature can make exploiting it easier. Applications that don't\nneed this feature should leave it off as a best practice.\n\n[note\n  Using multi-queries correctly is secure. Just make sure to use\n  the adequate client-side SQL formatting tools to generate queries securely.\n]\n\n[endsect]\n\n\n\n[section Closing a connection]\n\nYou can cleanly close a connection by calling [refmem any_connection async_close].\nThis sends a ['quit packet] to the server, notifying that we're about to end\nthe connection, performs TLS shutdown, and closes the underlying transport.\nA clean close involves I/O and can thus fail.\n\n[*Destroying the connection] without performing a clean close\nwill just close the underlying transport. [*It won't leak any resource],\nbut you might see warnings in the server log. Try to close connections\ncleanly when possible. \n\n[endsect]\n\n\n\n[section Reconnection and long-lived connections]\n\n[reflink any_connection] doesn't perform any re-connection on its own.\nIf a fatal error (like a network error) is encountered during an operation,\nyou need to re-establish the connection explicitly.\n\nBy design, [refmem any_connection async_connect] can [*always be used]\nto re-establish connections. It works even after the connection encountered\na network error or a cancellation. To achieve this, `async_connect`\nwill wipe any previous connection state before proceeding.\n\nIf you need reliable, long-lived connections, consider\n[link mysql.connection_pool using a connection pool]\ninstead of rolling out your own strategy. `connection_pool`\ntakes care of re-connecting and re-using connections for you. \n\n[endsect]\n\n\n\n\n[endsect] [/ connparams]\n"
  },
  {
    "path": "doc/qbk/06_text_queries.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:text_queries Text queries and client-side SQL formatting]\n[nochunk]\n\n['Text queries] are those that use MySQL text protocol for execution.\nPlain strings and [reflink with_params] use this protocol.\nThis contrasts with [link mysql.prepared_statements prepared statements],\nwhich are first prepared and then executed separately, and use a binary protocol.\n\n[warning\n    [*Never compose SQL queries using raw string concatenation].\n    This is insecure and can lead to [*SQL injection vulnerabilities].\n    Use the client-side SQL formatting facilities explained in this section\n    to avoid vulnerabilities.\n]\n\nUsing text queries you can run\n[link mysql.multi_resultset.multi_queries multiple semicolon-separated queries],\nwhich can improve efficiency.\n\n\n[section Using with_params for simple queries]\n\n[reflink with_params] is the easiest way to use client-side SQL formatting.\nIt can be used as a simpler and more flexible alternative to prepared statements.\nWhile prepared statements expand queries server-side, SQL formatting does it client-side.\nPlease read the [link mysql.text_queries.comparison comparison with prepared statements]\nand the [link mysql.text_queries.comparison.security security considerations] sections for more info.\n\n[reflink with_params] takes a SQL query\nstring with placeholders and a set of parameters. When passed to\n[refmemunq any_connection execute] or [refmemunq any_connection async_execute],\nthe query is expanded in the client with the supplied parameters and\nsent to the server for execution:\n\n[text_queries_with_params_simple]\n\nCurly braces (`{}`) represent placeholders (technically called ['replacement fields]).\nThe notation and semantics are similar to [@https://en.cppreference.com/w/cpp/utility/format/format `std::format`].\n\nAll fundamental types can be used as query parameters. This includes integers, floating point types,\nstrings, blobs, dates and times:\n\n[text_queries_with_params_scalars]\n\n`std::optional<T>` and `boost::optional<T>` can also be used:\n\n[text_queries_with_params_optionals]\n\nCollections and ranges are supported, as long as its elements can be formatted:\n\n[text_queries_with_params_ranges]\n\nSee [link mysql.sql_formatting_advanced.ranges this section] for more on formatting ranges,\nand [link mysql.sql_formatting_advanced.reference this table] for a reference of types\nthat have built-in support for SQL formatting.\n\n[note\n  Like with `std::format`, the query string passed to `with_params` must be known at\n  compile-time. You can skip this check using the [reflink runtime] function.\n]\n\nLike `std::format`, you can use arguments with explicit indices:\n\n[text_queries_with_params_manual_indices]\n\nSee [link mysql.sql_formatting_advanced.format_string_syntax this section]\nfor a reference on the format string syntax.\n\n[endsect]\n\n\n\n\n\n\n[section:errors Common errors and how to fix them]\n\nNot all values can be formatted. If the library finds that formatting a certain\nvalue can cause an ambiguity that could lead to a security problem, an error\nwill be issued and the query won't be sent to the server. Here are the most common errors:\n\n* `client_errc::invalid_encoding`\n    * Cause: one of your string parameters contains invalid code points.\n      With the default character set, this means that it contains [*invalid UTF-8].\n    * Solution: all string values must be encoded according to the connection's character\n      set (usually UTF-8). Sanitize or reject such values. Use the [reflink blob] and [reflink blob_view]\n      types for values that don't represent character strings, but arbitrary binary values.\n* `client_errc::unformattable_value`\n    * Cause: one of your parameters contains an invalid value. For instance, a `double`\n      contains a `NaN` or an `Inf`, unsupported by MySQL.\n    * Solution: reject such values, or replace them by `NULL` before passing them to client-side SQL formatting.\n* `client_errc::unknown_character_set`\n    * Cause: your connection doesn't know the character set you're using. Knowing the character set in use\n      is required to generate queries securely. This situation can happen after calling [refmemunq any_connection reset_connection]\n      or if you used a custom [refmem connect_params connection_collation] when connecting.\n    * Solution: use a [reflink connection_pool] instead of manually resetting connections. If you can't,\n      use the default [refmemunq connect_params connection_collation] when connecting, and use\n      [refmemunq any_connection set_character_set] or [refmemunq any_connection async_set_character_set]\n      after resetting connections.\n    * [link mysql.charsets.tracking Learn more] about how character set tracking works.\n\nFor example:\n\n[text_queries_with_params_invalid_encoding]\n\n[endsect]\n\n\n\n\n[section:comparison Prepared statements vs. client-side SQL formatting]\n\nAlthough both serve a similar purpose, they are fundamentally different. Prepared statements\nare parsed and expanded by the server. Client-side SQL expands the query in the client\nand sends it to the server as a string.\n\nThis means that [*client-side SQL does not understand your queries]. It just knows about how\nto format MySQL types into a string without creating vulnerabilities, but otherwise treats\nyour queries as opaque strings. Client-side SQL yields [*greater flexibility] (you can dynamically\ncompose any query), while statements have more limitations. This also means that\n[*you need to pay more attention to compose valid queries], specially when dealing with complex conditionals.\nLogic errors may lead to exploits. Please read the\n[link mysql.text_queries.comparison.security security considerations section]\nfor more info.\n\nClient-side SQL entails [*less round-trips to the server] than statements, and is usually more efficient\nfor lightweight queries. However, it uses the less compact text protocol, which may be slower for\nqueries retrieving a lot of data. See the\n[link mysql.text_queries.comparison.efficiency efficiency considerations section] for more info.\n\nIn general, [*use client-side SQL] formatting for the following cases:\n\n* Simple queries that don't retrieve a lot of data. Default to `with_params` and\n  only switch to statements if your performance measurements says so.\n* Queries involving dynamic SQL that can't be achieved by statements. Typical cases include:\n    * Dynamic filters ([link mysql.examples.dynamic_filters example]).\n    * Batch inserts. Inserting rows one by one can lead to poor efficiency.\n      You can use client-side SQL formatting to compose a single `INSERT` that\n      inserts several rows at once (see [link mysql.examples.batch_inserts example 1]\n      and [link mysql.examples.batch_inserts_generic example 2]).\n    * PATCH-like updates, where the field list in an `UPDATE` must be dynamic\n      ([link mysql.examples.patch_updates example]).\n    * Queries involving dynamic identifiers, like table and field names.\n    * Conditional sorting.\n    * Pipelines consisting of several semicolon-separated queries with dynamic fields.\n\nOn the other hand, [*prefer prepared statements] if:\n\n* You are executing the same query over and over. You can prepare the statement\n  once and execute it several times.\n* Your query is retrieving a lot of data, and you have performed the relevant performance measurements.\n\n\n\n[heading:efficiency Efficiency considerations]\n\nBoth client-side SQL formatting and prepared statements have pros and cons efficiency-wise:\n\n* Client-formatted SQL entails [*less round-trips to the server]. For prepared statements, you usually need\n  a call to prepare the statement, another one to execute it, and possibly a final one to close it.\n  Client-formatted SQL only requires the execution round-trip. This performance gain increases with network\n  latency and if you are using TLS.\n* Prepared statements always entail a [*mutation of session state], while client-formatted SQL may not.\n  If you're using a [reflink connection_pool] with prepared statements, you can't use\n  [refmem pooled_connection return_without_reset], as this will leak the statement.\n  With client-formatted queries, reset may not be required if your SQL doesn't mutate session state.\n* Client-formatted SQL queries use a usually [*less efficient text-based protocol], while prepared statements\n  use a more compact binary protocol. This is relevant if you're retrieving lots of data that is\n  slow to convert to and from text (like doubles).\n* [*Prepared statements can be re-used]. If you need to execute a query several times,\n  prepared statements will only be parsed once.\n* Client-formatted SQL allows [*more efficient patterns] than prepared statements,\n  like batch inserts and semicolon-separated queries.\n\n\n\n\n[heading:security Security considerations]\n\nBoth client-side SQL formatting and prepared statements [*protect against SQL injection].\nStatements do so by parsing the query with placeholders server-side, before performing parameter\nsubstitution. Client-side SQL quotes and escapes your values to avoid injection, but\n[*does not understand your queries].\n\nThis means that you need to [*ensure that your queries always expand to valid SQL].\nThis is trivial for simple queries, but may be an issue with more complex ones,\ninvolving ranges or dynamic identifiers. For instance, the following query may\nexpand to invalid SQL if the provided range is empty:\n\n[text_queries_with_params_empty_ranges]\n\nThe risk is higher if you're building your query by pieces using [reflink format_sql_to].\n\nTo sum up:\n\n* Client-side SQL protects against SQL injection.\n* Client-side SQL does not protect against logic errors. The risk is only present in complex\n  queries. We suggest the following advice:\n    * Avoid complex query generation logic as much as possible.\n      Use a single format string instead of `format_sql_to`, unless you have no other option.\n    * When using ranges, consider if the empty range would lead to valid SQL or not.\n    * Thoroughly test complex query generation logic.\n* Client-side SQL requires knowing the connection's current character set. This usually happens\n  out of the box, and will lead to a [link mysql.text_queries.errors controlled error]\n  otherwise. Some recommendations:\n    * If in doubt, always use the default character set (`utf8mb4`).\n    * Never issue `SET NAMES` or `SET CHARACTER SET` statements directly -\n      use [refmem any_connection set_character_set] or [refmemunq any_connection async_set_character_set], instead.\n    * If you're using [reflink format_sql] or [reflink format_sql_to], never craft [reflink format_options] values manually.\n      Use [refmem any_connection format_opts], instead.\n\n\n[endsect]\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/07_prepared_statements.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:prepared_statements Prepared statements]\n\nThis section covers using [mysqllink sql-prepared-statements.html\nserver-side prepared statements], an alternative to [reflink with_params].\nIn general, prepared statements are more complex and less flexible than `with_params`,\nbut might provide more efficiency under certain circumstances. Prefer\n`with_params` if you're not sure. See [link mysql.text_queries.comparison this section]\nfor a comparison between `with_params` and prepared statements.\n\nWorking with statements involves three networking operations:\n\n* Preparing a statement: [refmem any_connection async_prepare_statement].\n* Executing a statement: [refmem any_connection async_execute] or [refmem any_connection async_start_execution].\n* Closing a statement (optional): [refmem any_connection async_close_statement].\n\nThe [reflink statement] class holds a server-supplied handle to an open prepared statement.\n\n[heading Preparing a statement]\n\nCalling [refmemunq any_connection async_prepare_statement] yields a [reflink statement] object:\n\n[prepared_statements_prepare]\n\nThe question mark characters (`?`) represent parameters \n(as described [mysqllink prepare.html here]).\nWhen you execute the statement (next section), you\nprovide values for each of the parameters you declared, and the server\nwill use these values to run the statement.\n\n[heading Executing a statement]\n\nBefore executing a statement, you must specify its actual parameters by calling [refmem statement bind].\nBinding happens client-side: the statement handle and the passed parameters are packed into an object\nthat can be passed to [refmemunq any_connection async_execute], without any communication with the server.\nThe object returned by `bind` can be passed to `async_execute`:\n\n[prepared_statements_execute]\n\n\nSome observations:\n\n* You must pass in [*exactly as many parameters\n  as the statement has]. Failing to do so will result in an error.\n* You don't need to sanitize the parameters anyhow. The server takes care of it.\n* Actual parameters are matched to `?` placeholders by order. \n* You can pass types like built-in integers, `float`, [reflink date] or `std::string`,\n  with the expected effects. [link mysql.prepared_statements.writable_field_reference This table]\n  contains a reference with all the allowed types.\n* You can also use [link mysql.static_interface the static interface] to execute statements by replacing [reflink results]\n  by [reflink static_results].\n\n\n[heading Closing a statement]\n\nPrepared statements are created server-side, and thus consume server resources.\nYou can deallocate statements that you don't need anymore by calling [refmemunq any_connection async_close_statement]:\n\n[prepared_statements_close]\n\nPrepared statements are managed by the server on a per-session basis.\nThis is, once you close your connection with the server, any allocated prepared statements\nwill be automatically closed for you. Calling [refmem any_connection async_reset_connection]\nwill also close all the statements prepared by the current session. This is used by\n[reflink connection_pool] to clean up sessions.\n\nIn general, avoid closing statements explicitly if you're using `async_reset_connection` or\n`connection_pool`, or if you're preparing a fixed number of statements at program startup.\nClosing statements involves network traffic that can be avoided.\nOn the other hand, if you are creating and destroying prepared statements\ndynamically without using the aforementioned techniques, consider closing\nstatement explicitly to limit server resource consumption.\n\n[note\n    [reflink statement]'s destructor [*does not deallocate the statement from the server].\n    This is intentional, as closing a statement involves a network\n    operation that may block or fail, and is not required by strategies\n    involving `async_reset_connection`.\n]\n\n\n\n[heading NULLs and optionals]\n\nYou can pass `std::optional` and `boost::optional` for parameters that may be `NULL`:\n\n[prepared_statements_execute_null]\n\n\n\n[heading Parameter server-side type casting]\n\nMySQL is quite permissive with the type of statement parameters. In most cases,\nit will perform the required casts for you. For example, the following will work:\n\n[prepared_statements_casting]\n\n\n\n\n[heading Executing a statement with a variable number of parameters]\n\n[refmem statement bind] has two forms:\n\n* A variadic form, where each statement argument is passed as a C++ argument.\n  This is what we've been using until now. It can only be used if the number\n  of arguments a statement has is known at compile time.\n* A range form, where arguments are passed as a range of variants.\n  This one should only be used if the number of arguments is unknown at compile time.\n\nThe range should contain [reflink field] or [reflink field_view] elements, which\ncan represent any MySQL type. For example:\n\n[prepared_statements_iterator_range]\n\n\n\n\n[heading Type mapping reference for prepared statement parameters]\n\nThe following table contains a reference of the types that can be used when binding a statement.\nIf a type can be used this way, we say to satisfy the `WritableField` concept.\nThe table shows how a parameter `v` in a expression `conn.execute(stmt.bind(v), result)`\nis interpreted by MySQL, depending on `v`'s type.\n\n\n[table:writable_field_reference\n    [\n        [C++ type]\n        [MySQL type]\n        [Compatible with...]\n    ]\n    [\n        [`signed char`, `short`, `int`, `long`, `long long`]\n        [`BIGINT`]\n        [Signed `TINYINT`, `SMALLINT`, `MEDIUMINT`, `INT`, `BIGINT`]\n    ]\n    [\n        [`unsigned char`, `unsigned short`, `unsigned int`, `unsigned long`, `unsigned long long`]\n        [`UNSIGNED BIGINT`]\n        [Unsigned `TINYINT`, `SMALLINT`, `MEDIUMINT`, `INT`, `BIGINT`, `YEAR`, `BIT`]\n    ]\n    [\n        [`bool`]\n        [`BIGINT` (`1` if `true`, `0` if `false`)]\n        [`TINYINT`]\n    ]\n    [\n        [`std::basic_string<char, std::char_traits<char>, Allocator>` (including `std::string`), [reflink string_view], `std::string_view`, `const char*`]\n        [`VARCHAR`]\n        [`CHAR`, `VARCHAR`, `TEXT` (all sizes), `ENUM`, `SET`, `JSON`, `DECIMAL`, `NUMERIC`]\n    ]\n    [\n        [`std::basic_vector<unsigned char, Allocator>` (including [reflink blob]), [reflink blob_view]]\n        [`BLOB`]\n        [`BINARY`, `VARBINARY`, `BLOB` (all sizes), `GEOMETRY`]\n    ]\n    [\n        [`float`]\n        [`FLOAT`]\n        [`FLOAT`]\n    ]\n    [\n        [`double`]\n        [`DOUBLE`]\n        [`DOUBLE`]\n    ]\n    [\n        [[reflink date]]\n        [`DATE`]\n        [`DATE`]\n    ]\n    [\n        [[reflink datetime]]\n        [`DATETIME`]\n        [`DATETIME`, `TIMESTAMP`]\n    ]\n    [\n        [\n            [reflink time][br]\n            Any `std::chrono::duration` convertible to `time`\n        ]\n        [`TIME`]\n        [`TIME`]\n    ]\n    [\n        [`std::nullptr_t`]\n        [`NULL`]\n        [Any of the other types. Used to insert `NULL`s, for example.]\n    ]\n    [\n        [`std::optional<T>`]\n        [\n            Applies `T`'s type mapping if the optional has a value.[br]\n            `NULL` otherwise\n        ]\n        []\n    ]\n    [\n        [`boost::optional<T>`]\n        [\n            Applies `T`'s type mapping if the optional has a value.[br]\n            `NULL` otherwise\n        ]\n        []\n    ]\n    [\n        [[reflink field_view]]\n        [Depends on the actual type stored by the field]\n        []\n    ]\n    [\n        [[reflink field]]\n        [Depends on the actual type stored by the field]\n        []\n    ]\n]\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/08_dynamic_interface.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:dynamic_interface The dynamic interface]\n[nochunk]\n\nTo use the dynamic interface, use the [reflink results] class. `results` is\nan in-memory representation of a resultset. We can depict it like this\n(this is actually a simplified representation, since\n[link mysql.multi_resultset some statements may return more than one resultset]).\n\n[$mysql/images/results.svg [align center] [scale 125]]\n\nWe can see that [refmem results rows] returns a matrix-like object,\ncontaining the retrieved rows. This section is dedicated on diving deeper\non how to use these objects.\n\n[heading Rows and fields]\n\nThis matrix-like structure is composed of variant-like objects called ['fields].\nField objects are capable of representing any value retrieved from MySQL.\n\nThis library defines the following classes to work with rows and fields:\n\n[variablelist\n    [\n        [[reflink field]]\n        [The smallest unit of data. A single \"cell\" in a MySQL table. This is an owning, variant-like type.]\n    ]\n    [\n        [[reflink field_view]]\n        [Like `field`, but non-owning.]\n    ]\n    [\n        [[reflink row]]\n        [An owning, `vector`-like collection of fields.]\n    ]\n    [\n        [[reflink row_view]]\n        [Like `row`, but non-owning.]\n    ]\n    [\n        [[reflink rows]]\n        [An owning, matrix-like collection of fields. Represents several rows of the same size in an optimized way.]\n    ]\n    [\n        [[reflink rows_view]]\n        [Like `rows`, but non-owning.]\n    ]\n]\n\n[refmem results rows] returns a [reflink rows_view] object. The memory for the rows is owned by the\n`results` object. Indexing the returned view also returns view objects:\n\n[dynamic_views]\n\nViews behave similarly to `std::string_view`. You must make sure that you don't use a view after the\nstorage it points to has gone out of scope. In this case, you must not use any of the views after the\n`results` object has gone out of scope.\n\nAs it happens with `std::string_view`, you can take ownership of a view using its owning counterpart:\n\n[dynamic_taking_ownership]\n\n[heading Using fields]\n\n[reflink field] and [reflink field_view] are specialized variant-like types that can hold any type\nyou may find in a MySQL table. Once you obtain a field, you can access its contents using the following functions:\n\n* You can query a field's type by using [refmemunq field_view kind],\n  which returns a [reflink field_kind] enum.\n* You can query whether a field contains a certain type with `field::is_xxx`.\n* You can get the underlying value with `field::as_xxx` and `field::get_xxx`.\n  The `as_xxx` functions are checked (they will throw an exception if the\n  actual type doesn't match), while the `get_xxx` are unchecked (they result\n  in undefined behavior on type mismatch).\n* You can stream fields and compare them for equality.\n\nFor example:\n\n[dynamic_using_fields]\n\n`NULL` values are represented as field objects having `kind() == field_kind::null`.\nYou can check whether a value is `NULL` or not using [refmemunq field_view is_null].\nThis is how `NULL`s are typically handled:\n\n[dynamic_handling_nulls]\n\n[heading MySQL to C++ type mappings]\n\nEvery MySQL type is mapped to a single C++ type. The following table shows these mappings:\n\n[table:accessors\n    [\n        [`field_kind`]\n        [C++ type]\n        [MySQL types]\n        [`is` accessor]\n        [`as` accessor]\n        [`get` accessor]\n    ]\n    [\n        [`int64`]\n        [`std::int64_t`]\n        [__TINYINT__, __SMALLINT__, __MEDIUMINT__, __INT__, __BIGINT__]\n        [[refmemunq field_view is_int64]]\n        [[refmemunq field_view as_int64]]\n        [[refmemunq field_view get_int64]]\n    ]\n    [\n        [`uint64`]\n        [`std::uint64_t`]\n        [Unsigned __TINYINT__, __SMALLINT__, __MEDIUMINT__, __INT__, __BIGINT__, __YEAR__, __BIT__]\n        [[refmemunq field_view is_uint64]]\n        [[refmemunq field_view as_uint64]]\n        [[refmemunq field_view get_uint64]]\n    ]\n    [\n        [`string`]\n        [\n            [reflink string_view] for `field_view`\n            \n            `std::string` for `field`\n        ]\n        [\n            __CHAR__, __VARCHAR__, __TEXT__ (all sizes), __ENUM__, __SET__, __DECIMAL__, __NUMERIC__, __JSON__\n        ]\n        [[refmemunq field_view is_string]]\n        [[refmemunq field_view as_string]]\n        [[refmemunq field_view get_string]]\n    ]\n    [\n        [`blob`]\n        [\n            [reflink blob_view] for `field_view`\n            \n            [reflink blob] for `field`\n        ]\n        [__BINARY__, __VARBINARY__,  __BLOB__  (all sizes), __GEOMETRY__]\n        [[refmemunq field_view is_blob]]\n        [[refmemunq field_view as_blob]]\n        [[refmemunq field_view get_blob]]\n    ]\n    [\n        [`float_`]\n        [`float`]\n        [__FLOAT__]\n        [[refmemunq field_view is_float]]\n        [[refmemunq field_view as_float]]\n        [[refmemunq field_view get_float]]\n    ]\n    [\n        [`double_`]\n        [`double`]\n        [__DOUBLE__]\n        [[refmemunq field_view is_double]]\n        [[refmemunq field_view as_double]]\n        [[refmemunq field_view get_double]]\n    ]\n    [\n        [`date`]\n        [[reflink date]]\n        [__DATE__]\n        [[refmemunq field_view is_date]]\n        [[refmemunq field_view as_date]]\n        [[refmemunq field_view get_date]]\n    ]\n    [\n        [`datetime`]\n        [[reflink datetime]]\n        [__DATETIME__, __TIMESTAMP__]\n        [[refmemunq field_view is_datetime]]\n        [[refmemunq field_view as_datetime]]\n        [[refmemunq field_view get_datetime]]\n    ]\n    [\n        [`time`]\n        [[reflink time]]\n        [__TIME__]\n        [[refmemunq field_view is_time]]\n        [[refmemunq field_view as_time]]\n        [[refmemunq field_view get_time]]\n    ]\n    [\n        [`null`]\n        []\n        [Any of the above, when they're `NULL`]\n        [[refmemunq field_view is_null]]\n        []\n        []\n    ]\n]\n\nNo character set conversion is applied on strings. They are provided\nas the server sends them. If you've run [refmemunq any_connection async_set_character_set],\nstrings will be encoded according to the passed character set. For details, see [link mysql.charsets this section].\n\n[heading The field class]\n\n[reflink field_view] is to [reflink field] what `std::string_view` is to `std::string`.\n\n`field_view`s are cheap to create and to copy, as they are small objects and don't perform\nany memory allocations. They are also immutable. On the other hand, `field`s may be more\nexpensive to create and copy, as they may perform memory allocations. `field`s are mutable.\n\n`field` and `field_view` use the same underlying types for scalars. For strings and blobs,\n`field` uses the owning types `std::string` and [reflink blob], while `field_view` uses the\nreference types [reflink string_view] and [reflink blob_view].\n\n`field` accessors return references, which allow you to mutate the underlying object:\n\n[dynamic_field_accessor_references]\n\nYou can also mutate a `field` using the assignment operator. This allows you to also\nchange the underlying type of a `field`:\n\n[dynamic_field_assignment]\n\n[heading Multi-resultset and multi-function operations]\n\nYou can use both with the dynamic interface. Please refer to the sections\non [link mysql.multi_resultset multi-resultset operations] and\n[link mysql.multi_function multi-function operations] for more information.\n\n[heading MySQL to C++ type mapping reference]\n\nThe following table reflects mapping from database types to C++ types.\nThe range column shows the range of values that MySQL admits for that type. This library\nguarantees that any field retrieved from the database honors that range. The `column_type`\ncolumn shows what [refmem metadata type] would return for a column of that type.\n\n[table:dynamic_field_mappings\n    [\n        [MySQL type]\n        [`field_kind`]\n        [C++ type]\n        [Range]\n        [`column_type`]\n        [Considerations]\n    ]\n    [\n        [__TINYINT__]\n        [`int64`]\n        [`std::int64_t`]\n        [`-0x80` to `0x7f`]\n        [`tinyint`]\n        [1 byte integer]\n    ]\n    [\n        [__TINYINT__ `UNSIGNED`]\n        [`uint64`]\n        [`std::uint64_t`]\n        [`0` to `0xff`]\n        [`tinyint`]\n        [1 byte integer]\n    ]\n    [\n        [__SMALLINT__]\n        [`int64`]\n        [`std::int64_t`]\n        [`-0x8000` to `0x7fff`]\n        [`smallint`]\n        [2 byte integer]\n    ]\n    [\n        [__SMALLINT__ `UNSIGNED`]\n        [`uint64`]\n        [`std::uint64_t`]\n        [`0` to `0xffff`]\n        [`smallint`]\n        [2 byte integer]\n    ]\n    [\n        [__MEDIUMINT__]\n        [`int64`]\n        [`std::int64_t`]\n        [`-0x800000` to `0x7fffff`]\n        [`mediumint`]\n        [3 byte integer]\n    ]\n    [\n        [__MEDIUMINT__ `UNSIGNED`]\n        [`uint64`]\n        [`std::uint64_t`]\n        [`0` to `0xffffff`]\n        [`mediumint`]\n        [3 byte integer]\n    ]\n    [\n        [__INT__]\n        [`int64`]\n        [`std::int64_t`]\n        [`-0x80000000` to `0x7fffffff`]\n        [`int_`]\n        [4 byte integer]\n    ]\n    [\n        [__INT__ `UNSIGNED`]\n        [`uint64`]\n        [`std::uint64_t`]\n        [`0` to `0xffffffff`]\n        [`int_`]\n        [4 byte integer]\n    ]\n    [\n        [__BIGINT__]\n        [`int64`]\n        [`std::int64_t`]\n        [`-0x8000000000000000` to `0x7fffffffffffffff`]\n        [`bigint`]\n        [8 byte integer]\n    ]\n    [\n        [__BIGINT__ `UNSIGNED`]\n        [`uint64`]\n        [`std::uint64_t`]\n        [`0` and `0xffffffffffffffff`]\n        [`bigint`]\n        [8 byte integer]\n    ]\n    [\n        [__YEAR__]\n        [`uint64`]\n        [`std::uint64_t`]\n        [\\[`1901`, `2155`\\], plus zero]\n        [`year`]\n        [\n            1 byte integer type used to represent years\n\n            Zero is often employed to represent invalid year values. We represent zero year as a numeric 0.\n        ]\n    ]\n    [\n        [__BIT__]\n        [`uint64`]\n        [`std::uint64_t`]\n        [Depends on the bitset width. Max `0` to `0xffffffffffffffff`.]\n        [`bit`]\n        [\n            A bitset between 1 and 64 bits wide.\n        ]\n    ]\n    [\n        [__FLOAT__]\n        [`float_`]\n        [`float`]\n        [IEEE 754 `float` range]\n        [`float_`]\n        [\n            4 byte floating point type\n        ]\n    ]\n    [\n        [__DOUBLE__]\n        [`double_`]\n        [`double`]\n        [IEEE 754 `double` range]\n        [`double_`]\n        [\n            8 byte floating point type\n        ]\n    ]\n    [\n        [__DATE__]\n        [`date`]\n        [[reflink date]]\n        [\n            \\[[reflink min_date], [reflink max_date]\\] (some MySQL implementations may allow a narrower range),\n            plus invalid and zero dates (see __allow_invalid_dates__ and  __strict_sql__).\n        ]\n        [`date`]\n        []\n    ]\n    [\n        [__DATETIME__]\n        [`datetime`]\n        [[reflink datetime]]\n        [\n            \\[[reflink min_datetime], [reflink max_datetime]\\] (some MySQL implementations may allow a narrower range),\n            plus invalid and zero datetimes (see __allow_invalid_dates__ and  __strict_sql__).\n        ]\n        [`datetime`]\n        [\n            Time point type without time zone, with a resolution of one microsecond.\n        ]\n    ]\n    [\n        [__TIMESTAMP__]\n        [`datetime`]\n        [[reflink datetime]]\n        [\n            \\[[reflink min_datetime], [reflink max_datetime]\\] (the actual MySQL supported range is usually\n            narrower, but we don't enforce it in the client), plus zero timestamps (see __strict_sql__).\n        ]\n        [`timestamp`]\n        [\n            Time point type with a resolution of one microsecond.\n        ]\n    ]\n    [\n        [__TIME__]\n        [`time`]\n        [[reflink time]]\n        [\n            \\[[reflink min_time], [reflink max_time]\\]\n        ]\n        [`time`]\n        [\n            Signed time duration, with a resolution of one microsecond.\n        ]\n    ]\n    [\n        [__CHAR__]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        []\n        [`char_`]\n        [\n            Fixed-size character string.\n        ]\n    ]\n    [\n        [__VARCHAR__]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        []\n        [`varchar`]\n        [\n            Variable size character string with a maximum size.\n        ]\n    ]\n    [\n        [__TEXT__ (all sizes)]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        []\n        [`text`]\n        [\n            Variable size character string.\n        ]\n    ]\n    [\n        [__ENUM__]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        []\n        [`enum_`]\n        [\n            Character string with a fixed set of possible values (only one possible).\n        ]\n    ]\n    [\n        [__SET__]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        []\n        [`set`]\n        [\n            Character string with a fixed set of possible values (many possible).\n        ]\n    ]\n    [\n        [__JSON__]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        []\n        [`json` (MySQL) or `text` (MariaDB)]\n        [\n            A serialized JSON value of any type.\n            \n            Note that [refmem metadata type] is different depending on the DB system. MySQL has a dedicated `JSON` type, while in MariaDB `JSON` is an alias for `LONGTEXT`. JSON values are represented as strings by this library in both cases.\n        ]\n    ]\n    [\n        [__DECIMAL__/__NUMERIC__]\n        [`string`]\n        [[reflink string_view] or `std::string`]\n        [Depends on the column definition]\n        [`decimal`]\n        [\n            A fixed precision numeric value. In this case, the string will contain\n            the textual representation of the number (e.g. the string `\"20.52\"` for `20.52`).\n\n            This type is mapped to a string to avoid losing precision.\n        ]\n    ]\n    [\n        [__BINARY__]\n        [`blob`]\n        [[reflink blob_view] or [reflink blob]]\n        []\n        [`binary`]\n        [\n            Fixed-size blob.\n        ]\n    ]\n    [\n        [__VARBINARY__]\n        [`blob`]\n        [[reflink blob_view] or [reflink blob]]\n        []\n        [`varbinary`]\n        [\n            Variable size blob with a maximum size.\n        ]\n    ]\n    [\n        [__BLOB__ (all sizes)]\n        [`blob`]\n        [[reflink blob_view] or [reflink blob]]\n        []\n        [`blob`]\n        [\n            Variable size blob.\n        ]\n    ]\n    [\n        [__GEOMETRY__]\n        [`blob`]\n        [[reflink blob_view] or [reflink blob]]\n        []\n        [`geometry`]\n        [\n            Any of the spatial data types. The string contains the binary representation of the geometry type.\n        ]\n    ]\n]\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/09_static_interface.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:static_interface The static interface]\n[nochunk]\n\nWe have already covered the static interface basics in\n[link mysql.tutorial_static_interface the tutorials]. This section expands on this topic.\n\nTo use the static interface, we must first define a data structure that describes the shape of\nour rows. We have several options:\n\n* Use __Describe__ to annotate a plain `struct`\n  with `BOOST_DESCRIBE_STRUCT` to enable reflection on it.\n* Use __Pfr__ and [reflink pfr_by_name] or [reflink pfr_by_position]\n  to use PFR automatic reflection capabilities.\n* Use `std::tuple`.\n\nWe will work with the following table:\n\n[!teletype]\n```\nCREATE TABLE employee(\n    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n    first_name VARCHAR(100) NOT NULL,\n    last_name VARCHAR(100) NOT NULL,\n    salary INT UNSIGNED,\n    company_id CHAR(10) NOT NULL,\n    FOREIGN KEY (company_id) REFERENCES company(id)\n);\n```\n\n[note\n    For simplicity, code snippets use C++20 coroutines. You can use the techniques\n    described here with lower C++ standards by using sync functions, callbacks or\n    `asio::yield_context`. The [link mysql.static_interface.comparison comparison table]\n    shows the C++ standard required by each technique shown here.\n]\n\nLet's start with Boost.Describe. If we want to query the first three fields, we can define our row type like this:\n\n[static_interface_describe_employee_v1]\n\nAnd write the following to query our table:\n\n[static_interface_query]\n\nNote that [refmem static_results rows] returns a `boost::span` object,\nwhich is a C++11 backport of `std::span`. The span points into memory owned by the\n`static_results` object. Care must be taken not to use this view object after the\n`static_results` goes out of scope.\n\n\n\n\n\n[heading Field matching]\n\nColumns in the query are matched to fields in the struct by name.\nIf a struct field cannot be matched to any query column, an error is issued.\nExtra columns in the query are ignored.\n\nIf your query contains columns with names that don't qualify as C++ identifiers,\nyou can use SQL aliases. For example, given this struct:\n\n[static_interface_describe_statistics]\n\nYou can write your query as:\n\n[static_interface_field_order]\n\n\n\n\n[heading:meta_checks Metadata checking]\n\nThe static interface will try to validate as soon as possible that the provided row type \nis compatible with the schema returned by the server. This process is known as [*metadata checking],\nand is performed before reading any data. The following checks are performed:\n\n* [*Type compatibility]: the C++ type must be able to represent any value that the MySQL type can represent.\n  For example, `std::int32_t` is compatible with `TINYINT` (1 byte integer), but not with `BIGINT` (8 byte integer).\n  For a full list of allowable field types, [link mysql.static_interface.readable_field_reference refer to this table].\n* [*Nullability]: if MySQL reports that a column can be `NULL`, your type must account for it. You can use\n  `std::optional<T>` or `boost::optional<T>` for these columns.\n\nLet's add the `salary` field to our employee query. We might try the following:\n\n[static_interface_describe_employee_v2]\n\nHowever, this won't work because of the nullability check.\nIn this case, the correct definition would be:\n\n[static_interface_describe_employee_v3]\n\n\n\n\n[heading Using Boost.PFR]\n\nIf you're using C++20 or above, you can use Boost.PFR to reflect types\nwithout the `BOOST_DESCRIBE_STRUCT` macro:\n\n[static_interface_pfr_employee]\n\nPFR reflection can be enabled in Boost.MySQL by using [reflink pfr_by_name]:\n\n[static_interface_pfr_by_name]\n\n\nNote that [reflink pfr_by_name] is what we call a ['marker type] - an empty type that tells\nclasses like [reflink static_results] how to reflect a type. If no\nmarker type is used, Boost.Describe is used to retrieve reflection data for struct types.\n\n[reflink pfr_by_position] is similar to `pfr_by_name`, but will match\ncolumns in the query to struct fields by position, rather than name.\nIt only requires C++17 to work. For instance:\n\n[static_interface_pfr_by_position]\n\nPlease refer to [link mysql.static_interface.comparison this table] for a comparison\nwith Boost.Describe.\n\n\n\n\n\n\n\n[heading Using tuples]\n\nYou can also use `std::tuple`s as row types. This can be handy for simple queries:\n\n[static_interface_tuples]\n\nFields in tuples are matched to query columns by order. The query must return as many\ncolumns as fields the tuple has, at least. Any extra trailing columns in the query are ignored.\n\n\n\n\n\n\n\n\n\n\n\n[heading Multi-resultset and multi-function operations]\n\nYou can use both with the dynamic interface. Please refer to the sections\non [link mysql.multi_resultset multi-resultset operations] and\n[link mysql.multi_function multi-function operations] for more information.\n\n\n\n\n[heading Reflection techniques comparison]\n\nShould I use Boost.Describe, Boost.PFR or tuples? Each one has its advantages and drawbacks.\nThis table may help you decide:\n\n[table:comparison\n    [\n        [Technique]\n        [Sample code]\n        [Minimum C++ standard]\n        [Comments]\n        [Feature test macro]\n    ]\n    [\n        [Boost.Describe]\n        [\n            [static_interface_comparison_describe_struct][br]\n            [static_interface_comparison_describe]\n        ]\n        [\n            C++14\n        ]\n        [\n            * Requires adding metadata with `BOOST_DESCRIBE_STRUCT`.[br]\n            * Matches fields by name.[br]\n            * No limitations placed on the row type (e.g. works for structs using inheritance).\n        ]\n        [\n            `BOOST_MYSQL_CXX14` is defined\n        ]\n    ]\n    [\n        [Boost.PFR using names]\n        [\n            [static_interface_comparison_pfr_struct][br]\n            [static_interface_comparison_pfr_by_name]\n        ]\n        [\n            C++20\n        ]\n        [\n            * Doesn't require adding metadata to structs.[br]\n            * Matches fields by name.[br]\n            * Works for row types satisfying [@boost:/doc/html/boost_pfr/limitations_and_configuration.html `SimpleAggregate`].\n        ]\n        [\n            `BOOST_PFR_CORE_NAME_ENABLED` is defined and set to `1`\n        ]\n    ]\n    [\n        [Boost.PFR using field position]\n        [\n            [static_interface_comparison_pfr_struct][br]\n            [static_interface_comparison_pfr_by_position]\n        ]\n        [\n            C++17[br]\n            C++14 with limitations\n        ]\n        [\n            * Doesn't require adding metadata to structs.[br]\n            * Matches fields by position.[br]\n            * In C++17 mode, it works for row types satisfying [@boost:/doc/html/boost_pfr/limitations_and_configuration.html `SimpleAggregate`].\n            * In C++14 mode, it may not work for rows containing certain field types, like strings. See\n              [@boost:/doc/html/boost_pfr/limitations_and_configuration.html Boost.PFR documentation] on C++14 limitations.\n        ]\n        [\n            `BOOST_PFR_ENABLED` is defined and set to `1`.\n            `BOOST_PFR_USE_CPP17` is defined and set to `1` for C++17 mode.\n        ]\n    ]\n    [\n        [Standard tuples]\n        [\n            [static_interface_comparison_tuples]\n        ]\n        [\n            C++14\n        ]\n        [\n            * Should only be used for very simple queries.[br]\n            * Matches fields by position.[br]\n        ]\n        [\n            `BOOST_MYSQL_CXX14` is defined\n        ]\n    ]\n]\n\nNote that using the static interface always requires C++14, at least. The `BOOST_MYSQL_CXX14` test macro\nis defined only if the static interface is supported. Including the static interface headers\non an unsupported compiler doesn't cause any error, but classes like [reflink static_results]\nand [reflink static_execution_state] are not defined. The test macro is brought on scope by\nany of the static interface headers.\n\n\n[heading Allowed field types]\n\nAll the types used within your Describe structs or tuples must be within\nthe following table. A Describe struct or tuple composed of valid field\ntypes models the [reflink StaticRow] concept.\n\nThe following table is a reference of the C++ types that can be used in a\n`StaticRow` and their compatibility with MySQL database types:\n\n[table:readable_field_reference\n    [\n        [C++ type]\n        [Compatible with...]\n    ]\n    [\n        [`std::int8_t`]\n        [\n            __TINYINT__\n        ]\n    ]\n    [\n        [`std::uint8_t`]\n        [\n            __TINYINT__ `UNSIGNED`\n        ]\n    ]\n    [\n        [`std::int16_t`]\n        [\n            __TINYINT__[br]\n            __TINYINT__ `UNSIGNED`[br]\n            __SMALLINT__ [br]\n            __YEAR__\n        ]\n    ]\n    [\n        [`std::uint16_t`]\n        [\n            __TINYINT__ `UNSIGNED`[br]\n            __SMALLINT__ `UNSIGNED` [br]\n            __YEAR__\n        ]\n    ]\n    [\n        [`std::int32_t`]\n        [\n            __TINYINT__, __TINYINT__ `UNSIGNED`[br]\n            __SMALLINT__, __SMALLINT__ `UNSIGNED`[br]\n            __MEDIUMINT__, __MEDIUMINT__ `UNSIGNED`[br]\n            __INT__[br]\n            __YEAR__\n        ]\n    ]\n    [\n        [`std::uint32_t`]\n        [\n            __TINYINT__ `UNSIGNED`[br]\n            __SMALLINT__ `UNSIGNED`[br]\n            __MEDIUMINT__ `UNSIGNED`[br]\n            __INT__ `UNSIGNED`[br]\n            __YEAR__\n        ]\n    ]\n    [\n        [`std::int64_t`]\n        [\n            __TINYINT__,  __TINYINT__ `UNSIGNED`[br]\n            __SMALLINT__, __SMALLINT__ `UNSIGNED`[br]\n            __MEDIUMINT__, __MEDIUMINT__ `UNSIGNED`[br]\n            __INT__, __INT__ `UNSIGNED`[br]\n            __BIGINT__[br]\n            __YEAR__\n        ]\n    ]\n    [\n        [`std::uint64_t`]\n        [\n            __TINYINT__ `UNSIGNED`[br]\n            __SMALLINT__ `UNSIGNED`[br]\n            __MEDIUMINT__ `UNSIGNED`[br]\n            __INT__ `UNSIGNED`[br]\n            __BIGINT__ `UNSIGNED`[br]\n            __YEAR__[br]\n            __BIT__\n        ]\n    ]\n    [\n        [`bool`]\n        [\n            `BOOL` or `BOOLEAN` (alias for __TINYINT__).\n        ]\n    ]\n    [\n        [`float`]\n        [\n            __FLOAT__\n        ]\n    ]\n    [\n        [`double`]\n        [\n            __FLOAT__, __DOUBLE__[br]\n        ]\n    ]\n    [\n        [`date`]\n        [\n            __DATE__\n        ]\n    ]\n    [\n        [`datetime`]\n        [\n            __DATETIME__, __TIMESTAMP__\n        ]\n    ]\n    [\n        [`time`]\n        [\n            __TIME__\n        ]\n    ]\n    [\n        [\n            `std::basic_string<char, std::char_traits<char>, Allocator>`[br][br]\n            The object must be default-constructible.\n        ]\n        [\n            __CHAR__, __VARCHAR__, __TEXT__[br]\n            __ENUM__, __SET__[br]\n            __JSON__[br]\n            __DECIMAL__/__NUMERIC__\n        ]\n    ]\n    [\n        [\n            `std::basic_vector<unsigned char, Allocator>`[br][br]\n            The object must be default-constructible.\n        ]\n        [\n            __BINARY__, __VARBINARY__, __BLOB__[br]\n            __GEOMETRY__\n        ]\n    ]\n    [\n        [\n            `std::optional<T>`[br][br]\n            `T` must be any of the types listed in this table.\n        ]\n        [\n            Any type compatible with `T`\n        ]\n    ]\n    [\n        [\n            `boost::optional<T>`[br][br]\n            `T` must be any of the types listed in this table.\n        ]\n        [\n            Any type compatible with `T`\n        ]\n    ]\n]\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/10_multi_resultset.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:multi_resultset Multi-resultset: stored procedures and multi-queries]\n\n[heading Using stored procedures]\n\n[mysqllink create-procedure.html Stored procedures] can be called using the `CALL` SQL statement.\nYou can use `CALL` statements from both text queries and prepared statements, in a similar way\nto other SQL statements. Contrary to other statements, `CALL` may generate more than one resultset.\n\nFor example, given a stored procedure like this:\n\n__sp_get_employees__\n\nA statement like `CALL get_employees('my_company')` will generate three resultsets:\n\n* A first resultset containing the company matched by the first `SELECT`.\n* A second resultset containing the employees matched by the second `SELECT`.\n* A third, empty resultset containing information about the `CALL` statement.\n\nEvery resultset contains its own rows, metadata, last insert ID, affected rows and so on.\n\n\n[heading Calling procedures using the dynamic interface]\n\nThe same [reflink results] class we've been using supports storing more than one resultset.\nYou can execute a `CALL` statement as any other SQL statement:\n\n[multi_resultset_call_dynamic]\n\nIn this context, `results` can be seen as a random-access collection of resultsets. You can access\nresultsets by index using [refmem results at] and [reflink2 results.operator__lb__rb_ results::operator[]].\nThese operations yield a [reflink resultset_view], which is a lightweight object pointing into memory owned by the `results`\nobject. You can take ownserhip of a `resultset_view` using the [reflink resultset] class. For example:\n\n[multi_resultset_results_as_collection]\n\n[heading Calling procedures using the static interface]\n\nThe [reflink static_results] class supports operations that return multiple\nresultsets, too. As with other SQL statements, we need to define the row types\nin our resultsets in advance:\n\n[describe_stored_procedures]\n\nWe can now use `static_results`, passing it as many template arguments as\nresultsets we expect. The library will check that the correct number of\nresultsets are actually returned by the server, and will parse them into\nthe row types that we provided:\n\n[multi_resultset_call_static]\n\n\nUse [refmem static_results rows] with an explicit index to access each resultset's data.\nYou can also use explicit indices with the other accessor functions,\nlike [refmem static_results meta] and [refmem static_results last_insert_id].\n\nFor more information about the static interface, please refer to [link mysql.static_interface this section].\n\n[heading Determining the number of resultsets]\n\nTo know the number of resultsets to expect from a `CALL` statement, use these rules:\n\n* For every statement that retrieves data (e.g. a `SELECT` statement), a resultset is sent.\n  `SELECT ... INTO <variables>` statements don't cause a resultset to be sent.\n* Statements that don't retrieve columns (e.g. `UPDATE`, `DELETE`) don't cause a resultset to be sent.\n* An empty resultset containing information about the `CALL` statement execution is always sent last.\n\nSome examples:\n\n[!teletype]\n```\n    -- Calling proc1 produces only 1 resultset because it only contains statements that\n    -- don't retrieve data\n    CREATE PROCEDURE proc1(IN pin_order_id INT, IN pin_quantity INT)\n    BEGIN\n        START TRANSACTION;\n        UPDATE orders SET quantity = pin_quantity WHERE id = pin_order_id;\n        INSERT INTO audit_log (msg) VALUES (\"Updated order...\");\n        COMMIT;\n    END\n```\n\n[!teletype]\n```\n    -- Calling proc2 produces 3 resultsets: one for the orders SELECT, one for the\n    -- line_items SELECT, and one for the CALL statement\n    CREATE PROCEDURE proc2(IN pin_order_id INT)\n    BEGIN\n        START TRANSACTION READ ONLY;\n        SELECT * FROM orders WHERE id = pin_order_id;\n        SELECT * FROM line_items WHERE order_id = pin_order_id;\n        COMMIT;\n    END\n```\n\n[heading Output parameters]\n\nYou can get the value of `OUT` and `INOUT` parameters in stored procedures by using\nprepared statement placeholders for them. When doing this, you will receive another resultset\nwith a single row containing all output parameter values. This resultset is located after\nall resultsets generated by `SELECT`s, and before the final, empty resultset.\n\nFor example, given this procedure:\n\n__sp_create_employee__\n\nYou can use:\n\n[multi_resultset_out_params]\n\n[refmem results out_params] simplifies the process.\n\n[warning\n    Due to a bug in MySQL, some `OUT` parameters are sent with wrong types.\n    Concretely, string parameters are always sent as blobs, so you will have to\n    use [refmem field_view as_blob] instead of [refmem field_view as_string].\n]\n\n\n[heading:multi_queries Semicolon-separated queries]\n\nIt is possible to run several semicolon-separated text queries in a single [refmem connection execute] call.\nFor security, this capability is disabled by default. Enabling it requires setting [refmem handshake_params multi_queries]\nbefore connecting:\n\n[multi_resultset_multi_queries]\n\nNote that statements like `DELIMITER` [*do not work] using this feature. This is because\n`DELIMITER` is a pseudo-command for the `mysql` command line tool, not actual SQL.\n\nYou can also use the static interface with multi-queries. It works the same as with stored procedures.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/11_multi_function.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:multi_function Multi-function operations]\n[nochunk]\n\nMulti-function operations allow running operations as a set of separate\nsteps, which gives you better control over execution. They work by splitting\nsome of the reads and writes into several function calls.\n\nYou can use multi-function operations to execute text queries and prepared statements,\nand through the dynamic or the static interface.\n\n[heading Protocol primer]\n\nTo make a good use of multi-function operations, you should have a basic understanding\nof the underlying protocol.\n\nThe protocol uses ['messages] to communicate. These are delimited by headers containing the message length.\nAll operations are initiated by the client, by sending a single ['request message], to which\nthe server responds with a set of ['response messages].\n\nThe diagram below shows the message exchange between client and server for text queries and statement\nexecutions. Each arrow represents a message.\n\n[$mysql/images/protocol.svg [align center]]\n\n\nThere are two separate cases:\n\n* If your query retrieved at least one column (even if no rows were generated), we're in ['case 1]. The server sends:\n    * An initial packet informing that the query executed correctly, and that we're in ['case 1].\n    * Some metadata packets describing the columns that the query retrieved. These become available\n      to the user and are necessary to parse the rows.\n    * The actual rows.\n    * An OK packet, which marks the end of the resultset and contains information like `last_insert_id` and\n      `affected_rows`.\n* If your query didn't retrieve any column, we're in ['case 2]. The server will just send an OK packet,\n  with the same information as in ['case 1].\n\n[refmem connection execute] handles the full message exchange. In contrast,\n[refmem connection start_execution] will not read the rows, if any.\n\nSome takeaways:\n\n* The distinction between single-function and multi-function operations exists only\n  in the client. The wire messages exchanged by both are the same.\n* There is no way to tell how many rows a resultset has upfront. You need to read row by row until\n  you find the OK packet marking the end of the resultset.\n* When the server processes the request message, [*it sends all the response messages immediately].\n  These responses will be waiting in the client to be read. If you don't read [*all] of them,\n  subsequent operations will mistakenly read them as their response, causing packet mismatches.\n  Be careful and don't let this happen!\n\n\n\n[heading Using multi-function operations through the dynamic interface]\n\n[reflink execution_state] is the main class for the dynamic interface in multi-function\noperations. An execution state holds information required to progress the execution operation,\nlike metadata (required to parse the rows) and protocol state. Contrary to `results`, it doesn't contain\nthe rows.\n\nGiven the following table definition:\n\n[multi_function_setup]\n\nYou can start a multi-function operation using [refmem connection start_execution]:\n\n[multi_function_dynamic_start]\n\nWe now [*must] read all the generated rows\nby calling [refmem connection read_some_rows], which will return a batch of an unspecified size:\n\n\n[multi_function_dynamic_read]\n\nSome remarks:\n\n* If there are rows to be read, `read_some_rows` will return at least one, but may return more.\n* [refmem execution_state complete] returns `true` after we've read the final OK packet for this operation.\n* The final `row_batch` may or may not be empty, depending on the number of rows and their size.\n* Calling `read_some_rows` after reading the final OK packet returns an empty batch.\n\n`read_some_rows` returns a [reflink rows_view] object pointing into the connection's internal buffer.\nThis view is valid until the connection performs any other operation involving a network transfer. \n\nNote that there is no need to distinguish between ['case 1] and ['case 2] in the diagram above in our code,\nas reading rows for a complete operation is well defined.\n\n\n[heading Using multi-function operations through the static interface]\n\nThe mechanics are similar to what's been exposed above. The static interface uses\n[reflink static_execution_state] to carry state. As with [reflink static_results], we must define and\npass a type describing our rows:\n\n[describe_post]\n\nWe can now start our operation using the same [refmem connection start_execution]:\n\n[multi_function_static_start]\n\nWe now [*must] read all the generated rows by calling [refmem connection read_some_rows]:\n\n[multi_function_static_read]\n\nSome remarks:\n\n* [reflink static_execution_state] doesn't store rows anyhow. It uses the row types passed\n  as template parameters to validate the metadata returned by the server, and ensure it is compatible\n  with the C++ data structures that will be used with `read_some_rows`.\n* We must pass `read_some_rows` a `boost::span` of the appropriate row type.\n  We've used `std::array` to place rows on the stack, but you can use any other contiguous range.\n* `read_some_rows` returns the number of read rows. At maximum, this will be the size\n  of the span, but there may be less, depending on row and network buffer sizes.\n* If there are rows to be read, `read_some_rows` will return at least one, but may return more.\n* [refmem execution_state complete] returns `true` after we've read the final OK packet for this operation.\n* The final read may or may not return rows, depending on the number of rows and their size.\n* Calling `read_some_rows` after reading the final OK packet always reads zero rows.\n\n\n\n[heading Accessing metadata and OK packet data]\n\nYou can access metadata at any point, using [refmem execution_state meta] or [refmem static_execution_state meta].\nThis function returns a collection of [reflink metadata] objects. For more information, please refer to [link mysql.meta this section].\n\nYou can access OK packet data using functions like [refmemunq execution_state last_insert_id]\nand [refmemunq execution_state affected_rows] in both `execution_state` and `static_execution_state`.\nAs this information is contained in the OK packet,\n[*it can only be accessed once the [refmemunq execution_state complete] function returns `true`]. \n\n[heading Using multi-function operations with stored procedures and multi-queries]\n\nWhen using operations that return more than one resultset (e.g. when calling stored procedures),\nthe protocol is slightly more complex:\n\n[$mysql/images/protocol_multi_resultset.svg [align center]]\n\nThe message exchange is as follows:\n\n* A single execution request is sent to the server.\n* The server sends a first resultset, as in the single resultset case.\n  The OK packet contains a flag indicating that another resultset follows.\n* Another resultset is sent, with the same structure as the previous one. The process is\n  repeated until an OK packet indicates that no more resultsets follow.\n\nFor example, given the following stored procedure:\n\n[/ This is an actual procedure. Code imports from SQL don't work. Make sure it doesn't go out of sync ]\n[!teletype]\n```\nCREATE PROCEDURE get_company(IN pin_company_id CHAR(10))\nBEGIN\n    START TRANSACTION READ ONLY;\n    SELECT id, name, tax_id FROM company WHERE id = pin_company_id;\n    SELECT first_name, last_name, salary FROM employee WHERE company_id = pin_company_id;\n    COMMIT;\nEND\n```\n\nWe can write:\n\n[table\n    [\n        [Dynamic interface]\n        [Static interface]\n    ]\n    [\n        [[multi_function_stored_procedure_dynamic]]\n        [[multi_function_stored_procedure_static]]\n    ]\n]\n\nNote that we're using [refmemunq execution_state should_read_rows] instead of [refmemunq execution_state complete]\nas our loop termination condition. `complete()` returns true when all the resultsets have been read,\nwhile `should_read_rows()` will return false once an individual result has been fully read.\n\nWhen using the static interface with multi-function operations, not all schema mismatches can be found\nby the `start_execution` function, since not all the information is available at this point. Errors may\nbe reported by `read_some_rows` and `read_resultset_head`, too. Overall, the same checks are performed as\nwhen using [refmem connection execute], but at different points in time.\n\n[heading Multi-resultset in the general case]\n\n`execution_state` and `static_execution_state` can be seen as state machines with four states. Each state\ndescribes which reading function should be invoked next:\n\n* [refmemunq execution_state should_start_op]: the initial state, after you default-construct an `execution_state`.\n  You should call [refmem connection start_execution] or [refmem connection async_start_execution]  to start the operation.\n* [refmemunq execution_state should_read_rows]: the next operation should be [refmem connection read_some_rows],\n  to read the generated rows.\n* [refmemunq execution_state should_read_head]: the next operation should be [refmem connection read_resultset_head],\n  to read the next resultset metadata. Only operations that generate multiple resultsets go into this state.\n* [refmemunq execution_state complete]: no more operations are required.\n\nFor multi-function operations, you may also access OK packet data ever time a resultset has completely\nbeen read, i.e. when [refmemunq execution_state should_read_head] returns `true`.\n\n[link mysql.examples.source_script This example] shows this general case. It uses\nmulti-queries to run an arbitrary SQL script file.\n\n[heading:read_some_rows More on read_some_rows]\n\nTo properly understand `read_some_rows`, we need to know that every [reflink connection]\nowns an *internal buffer*, where packets sent by the server are stored.\nIt is a single, flat buffer, and you can configure its initial size when creating\na `connection`, passing a [reflink buffer_params] object as the first argument to `connection`'s constructor.\nThe read buffer may be grown under certain circumstances to accommodate large messages.\n\n`read_some_rows` gets the maximum number of rows that fit in the internal buffer (without growing it)\nperforming a single `read_some` operation on the stream (or using cached data).\nIf there are rows to read, `read_some_rows` guarantees to read at least one. This means that,\nif doing what we described yields no rows (e.g. because of a large row that doesn't fit\ninto the buffer), `read_some_rows` will grow the buffer or perform more reads until at least\none row has been read. If you're using the static interface, the number of read rows is limited\nby the size of span you passed, too.\n\nIf you want to get the most of `read_some_rows`, customize the initial buffer size\nto maximize the number of rows that each batch retrieves.\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/12_connection_pool.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:connection_pool Connection pools]\n[nochunk]\n\nConnection pooling is a technique where several long-lived connections\nare re-used for independent logical operations. When compared to\nestablishing individual connections, it has the following benefits:\n\n* It provides better performance. Please consult [link mysql.connection_pool.benchmarks our benchmarks]\n  for more info.\n* It simplifies connection management. The connection pool will establish sessions,\n  perform retries and apply timeouts out of the box.\n\nThis is how you can create a pool of connections:\n\n[connection_pool_create]\n\n[reflink connection_pool] is an I/O object that manages connections.\nIt can be constructed from an executor or execution context (like all I/O objects)\nand a [reflink pool_params] object.\n\n[refmem connection_pool async_run] must be called exactly once per pool.\nThis function takes care of actually keeping connections healthy.\n\nWe're now ready to obtain connections using [refmem connection_pool async_get_connection].\nWe will use C++20 coroutines to make async code simpler:\n\n[connection_pool_get_connection]\n\nBy default, [refmem connection_pool async_run] will run forever. When\nyour application exits, you will want to stop it using [refmem connection_pool cancel].\nThis is typical in signal handlers, to guarantee a clean shutdown.\n\nNote that pooling works only with [reflink any_connection].\n\n[note\n    `connection_pool` exposes async functions only. This has to do\n    with efficiency and oddities in Boost.Asio executor model.\n    If you need to use it from sync code, please visit [link mysql.interfacing_sync_async this section].\n]\n\n\n\n[heading Pool size]\n\nPools start with a fixed initial size, and will be dynamically resized up\nto an upper limit if required. You can configure these sizes using\n[refmem pool_params initial_size] and [refmem pool_params max_size].\n\nThe resizing algorithm works like this:\n\n* When the pool is created, [refmem pool_params initial_size] number of connections are created and\n  connected (by default, `initial_size` is 1).\n* If a connection is requested, but all available connections are in use, a\n  new one is created, until `max_size` is reached. \n* If a connection is requested, and there are `max_size` connections in use,\n  [refmem connection_pool async_get_connection] waits for a connection to become available.\n* Once created, connections never get deallocated.\n\nBy default, [refmem pool_params max_size] is 151, which is\nMySQL's default value for the [mysqllink server-system-variables.html#sysvar_max_connections `max_connections`]\nsystem variable, controlling the maximum number of concurrent connections allowed by the server.\n\n[note\n    Before increasing [refmem pool_params max_size], make sure to also increase\n    the value of `max_connections` in the server. Otherwise, your connections\n    will be rejected by the connection limit.\n]\n\nThis is how you configure pool sizes:\n\n[connection_pool_configure_size]\n\n\n[heading Applying a timeout to async_get_connection]\n\nBy default, [refmem connection_pool async_get_connection] waits until a connection is available.\nThis means that, if the server is unavailable, `async_get_connection` may wait forever.\n\nFor this reason, you may consider setting a timeout to `async_get_connection`.\nYou can do this using [asioreflink cancel_after cancel_after], which uses Asio's\nper-operation cancellation mechanism:\n\n[connection_pool_apply_timeout]\n\nYou might consider setting the timeout at a higher level, instead. For instance,\nif you're handling an HTTP request, you can use `cancel_after` to set a timeout\nto the entire request. The [link mysql.examples.http_server_cpp20 connection pool example]\ntakes this approach.\n\n\n[heading Session state]\n\nMySQL connections hold state. You change session state when you prepare statements,\ncreate temporary tables, start transactions, or set session variables. When using\npooled connections, session state can be problematic: if not reset properly,\nstate from a previous operation may affect subsequent ones.\n\nAfter you return a connection to the pool, the equivalent of\n[refmem any_connection async_reset_connection] and [refmemunq any_connection async_set_character_set]\nare used to wipe session state before\nthe connection can be obtained again. This will deallocate\nprepared statements, rollback uncommitted transactions, clear variables and restore the connection's\ncharacter set to `utf8mb4`.\nIn particular, you don't need to call [refmem any_connection async_close_statement]\nto deallocate statements.\n\nResetting a connection is cheap but entails a cost (a roundtrip to the server).\nIf you've used a connection and you know that you didn't mutate session state,\nyou can use [refmem pooled_connection return_without_reset] to skip resetting.\nFor instance:\n\n[connection_pool_return_without_reset]\n\nConnection reset happens in the background, after the connection has been\nreturned, so it does not affect latency. If you're not sure if an operation\naffects state or not, assume it does.\n\n\n[heading Character set]\n\nPooled connections always use `utf8mb4` as its character set. When connections\nare reset, the equivalent of [refmem any_connection async_set_character_set] is used\nto restore the character set to `utf8mb4` (recall that raw [refmemunq any_connection async_reset_connection]\nwill wipe character set data).\n\nPooled connections always know the character set they're using.\nThis means that [refmem any_connection format_opts] and [refmemunq any_connection current_character_set]\nalways succeed.\n\nWe recommend to always stick to `utf8mb4`. If you really need to use any other character set,\nuse [refmemunq any_connection async_set_character_set] on your connection after it's been retrieved\nfrom the pool.\n\n\n[heading Connection lifecycle]\n\nThe behavior already explained can be summarized using a state model like the following:\n\n[$mysql/images/pooled_connection_lifecycle.svg [align center]]\n\nIn short:\n\n* When a connection is created, it goes into the `pending_connect` state.\n* Connection establishment is attempted. If it succeeds, the connection becomes `idle`.\n  Otherwise, it stays `pending_connect`, and another attempt will be performed\n  after [refmem pool_params retry_interval] has elapsed.\n* `idle` connections can be retrieved by [refmem connection_pool async_get_connection],\n  and they become `in_use`.\n* If a connection is returned by [refmem pooled_connection return_without_reset],\n  it becomes `idle` again.\n* If a connection is returned by [reflink pooled_connection]'s destructor, it becomes\n  `pending_reset`.\n* [refmem any_connection async_reset_connection] is applied to `pending_reset` connections.\n  On success, they become `idle` again. Otherwise, they become `pending_connect` and will\n  be reconnected.\n* If a connection stays `idle` for [refmem pool_params ping_interval], it becomes `pending_ping`.\n  At this point, the connection is probed. If it's alive, it will return to being `idle`.\n  Otherwise, it becomes `pending_connect` to be reconnected. Pings can be disabled by\n  setting [refmem pool_params ping_interval] to zero.\n\n\n[heading:thread_safe Thread-safety]\n\nBy default, [reflink connection_pool] is [*not thread-safe], but it can\nbe easily made thread-safe by setting [refmem pool_params thread_safe]:\n\n[connection_pool_thread_safe_create]\n\nTo correctly understand what is protected by [refmem pool_params thread_safe]\nand what is not, we need a grasp of how pools are implemented.\nBoth [reflink connection_pool] and individual [reflink pooled_connection]'s\nhold pointers to a shared state object containing all data required by the pool:\n\n[$mysql/images/connection_pool_impl.svg [align center]]\n\nThread-safe connection pools internally create an [asioreflink strand strand]\nthat protects the connection pool's state. Operations like\n[refmemunq connection_pool async_get_connection], [refmemunq connection_pool async_run]\nand [reflink pooled_connection]'s destructor will run through the strand,\nand are safe to be run from any thread. Operations that mutate\nstate handles (the internal `std::shared_ptr`), like [*assignment operators,\nare not thread-safe].\n\nData outside the pool's state is not protected. In particular,\n[*`asio::cancel_after` creates an internal timer that can cause\ninadvertent race conditions]. For example:\n\n[connection_pool_thread_safe_use]\n\nThis coroutine must be run within a strand:\n\n[connection_pool_thread_safe_spawn]\n\n\nIf we don't use `asio::make_shared`, we have the following race condition:\n\n* The thread calling `async_get_connection` sets up the timer required by `asio::cancel_after`.\n* In parallel, the thread running the execution context sees that there is a healthy connection\n  and completes the `async_get_connection` operation. As a result, the timer is cancelled.\n  Thus, the timer is accessed concurrently from both threads without protection.\n\n\nIf you're using callbacks, code gets slightly more convoluted. The\nabove coroutine can be rewritten as:\n\n[connection_pool_thread_safe_callbacks]\n\nThread-safety is disabled by default because strands impose a performance\npenalty that is avoidable in single-threaded programs.\n\n\n[heading Transport types and TLS]\n\nYou can use the same set of transports as when working with [reflink any_connection]:\nplaintext TCP, TLS over TCP or UNIX sockets. You can configure them using [refmem pool_params server_address]\nand [refmem pool_params ssl]. By default, TLS over TCP will be used if the server supports it,\nfalling back to plaintext TCP if it does not.\n\nYou can use [refmem pool_params ssl_ctx] to configure TLS options for\nconnections created by the pool. If no context is provided, one will be created for you internally.\n\n\n\n\n[heading:benchmarks Benchmarks]\n\nA throughput benchmark has been conducted to assess the performance gain provided by\n`connection_pool`. Benchmark code is under `bench/connection_pool.cpp`. The test\ngoes as follows:\n\n* The test consists of N = 10000 logically independent sessions. In an application\n  like a webserver, this would map to handling N HTTP requests.\n* Every logical session prepares a `SELECT` statement and executes it.\n  The statement matches a single row by primary key and retrieves a single, short string field\n  (a lightweight query).\n* `num_parallel` = 100 async agents are run in parallel. This means that, at any given\n  point in time, no more than 100 parallel connections to MySQL are made.\n* The test measures the time elapsed between launching the first async agent\n  and receiving the response for the last query (`ellapsed_time`).\n* The test is repeated 10 times for each different configuration, and results are averaged.\n  This time is used to measure the throughput, in \"connections/s\" (as given by `N/ellapsed_time`).\n* Connection pool scenarios use `pooled_connection::~pooled_connection`, which causes a connection\n  reset to be issued. Raw connection scenarios use [refmem any_connection async_connect] and\n  [refmem any_connection async_close] for every session. All tests are single-threaded.\n* The server runs MySQL v8.0.33 in a Docker container, in the same machine as the benchmarks.\n* Benchmarks have been compiled using clang-18 using CMake's Release build type and C++20.\n  They've been run in a Ubuntu 22.04 machine with an 8 core i7-10510U and 32GB of RAM.\n\n[$mysql/images/connection_pool_bench.svg]\n\nWe can see that pooling significantly increases throughput.\nThis is specially true when communication with the server is expensive\n(as is the case when using TLS over TCP). The performance gain is likely\nto increase over high-latency networks, and to decrease for heavyweight queries,\nsince the connection establishment has less overall weight.\n\n[tip\n  When using TLS or running small and frequent queries,\n  pooling can help you.\n]\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/13_1_interfacing_sync_async.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:interfacing_sync_async Interfacing sync and async code: using connection_pool in sync code]\n[nochunk]\n\nAs you may already know, we recommend using asynchronous functions over sync ones because\nthey are more versatile and scalable. Additionally, some classes like [reflink connection_pool]\ndo not offer a sync API.\n\nIf your entire application uses Asio, you can use async functions everywhere\nas explained in the tutorials. However, some legacy applications are inherently synchronous,\nand might need to call asynchronous code and wait for it synchronously.\n\nThis section explains how to handle these cases. We will build a synchronous\nfunction that retrieves an employee object from the database given their ID.\nIt will use [reflink connection_pool] and `asio::cancel_after`, which\ncan only be accessed through asynchronous functions.\n\n\n\n\n[heading The asio::use_future completion token]\n\n[asioreflink use_future use_future] is a [link mysql.tutorial_error_handling.completion_token completion token]\nthat does what we want: it launches an asynchronous operation and returns a `std::future` that\nwill complete when the task finishes.\n\nWith this knowledge, we can write a first version of our function:\n\n[interfacing_sync_async_v1]\n\n\nFor this to work, we need a thread that runs the execution context (event loop).\nThis is, calling `get()` on the future doesn't run the event loop.\nAlso note that our function will be called from a thread different to the\none running the execution context, so we need to make our pool thread-safe:\n\n\n[interfacing_sync_async_v1_init]\n\n\n\n\n[heading Adding timeouts]\n\nAs you might know, [refmemunq connection_pool async_get_connection] may block indefinitely,\nso we should use [asioreflink cancel_after cancel_after] to set a timeout. We might be tempted to do this:\n\n[interfacing_sync_async_v2]\n\nIt might not be obvious, but this is a data race. `asio::cancel_after` creates a timer under the hood.\nThis timer is shared between the thread calling `async_get_connection` and the one running the execution context.\nThe race condition goes like this:\n\n* The thread calling `async_get_connection` sets up the timer required by `asio::cancel_after`.\n* In parallel, the thread running the execution context sees that there is a healthy connection\n  and completes the `async_get_connection` operation. As a result, the timer is cancelled.\n  Thus, the timer is accessed concurrently from both threads without protection.\n\nNote that this happens even if the pool is thread-safe because the timer is not part of the pool.\n\nTo work this around, we can use a [@boost:/doc/html/boost_asio/overview/core/strands.html strand],\nAsio's mechanism to protect against data races. We will create a strand, then enter it and use it\nto run `async_get_connection`. This is a chain of asynchronous operations, so we can use\nan [asioreflink deferred deferred] chain to implement it:\n\n[interfacing_sync_async_v3]\n\nDon't worry if this looks intimidating. Let's break this down into pieces:\n\n* A strand is a compliant Asio executor. This means that we can use `asio::dispatch` and similar functions\n  to submit work to it.\n* [asioreflink dispatch dispatch] submits a piece of work to an executor. We specify the work to execute \n  as a completion token. It uses the executor bound to the passed completion token.\n* [asioreflink bind_executor bind_executor] binds an executor to a completion token. Here, we're binding\n  the strand to a deferred completion chain. This means that `dispatch` will use the strand to run its work.\n* When passing [asioreflink deferred deferred] to an async operation, like `dispatch`, it returns a packaged\n  async operation. We can call the operation with any completion token to initiate it. Here, we use `asio::use_future`\n  to transform the operation into a future. If we were in a C++20 coroutine, we could co_await the returned object, too.\n* The function passed to `deferred` will be executed when the first operation completes, and determines what to do next.\n  This is similar to JavaScript promise chains. Our next operation is `async_get_connection`.\n* We use `bind_executor` with `asio::deferred` to make any intermediate handlers used by `async_get_connection`\n  and `asio::cancel_after` go through the strand, effectively protecting our timer.\n* The future will complete once the entire chain finishes.\n\n\n\n\n[heading Refactoring to use C++20 coroutines]\n\nDeferred compositions can be used even in C++11, but they can get messy pretty fast.\nReasoning about their thread safety is non-trivial, either.\n\nIf you're in C++20 or above, a cleaner approach is to encapsulate all operations\ninvolving networking into a coroutine:\n\n[interfacing_sync_async_v4]\n\nWe're keeping all interactions with the `connection_pool` within coroutines,\nso we don't need to make it thread-safe anymore:\n\n[interfacing_sync_async_v4_init]\n\n\n\n[heading If C++20 is not available]\n\nIf you can't use C++20, you can still use `asio::spawn` or imitate the behavior\nof `asio::use_future` with callbacks. This is what the latter could look like:\n\n[interfacing_sync_async_v5]\n\nIt's not as clean, but the idea remains the same.\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/13_async.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:async Going async]\n[nochunk]\n\nFollowing __Asio__'s convention, all network operations have\nasynchronous versions with the same name prefixed by `async_`.\nThe last parameter to async operations is a __CompletionToken__,\nwhich dictates how the asynchronous operation will be managed\nand the function's return type. These `async_` functions are\ncalled async initiating functions.\n\nEvery async initiating function has an associated\nhandler type, which dictates how the asynchronous operation\ncommunicates its result back to the caller. This handler\ntype always has one of the two following forms:\n\n# `void(error_code)`. Used in operations that do\n   not have a proper result, e.g. [refmem connection async_connect].\n# `void(error_code, T)`. Used in operations that\n   have a result, e.g. [refmem connection async_prepare_statement]\n   (in this case, `T` is `statement`).\n   \nAll asynchronous functions are overloaded\nto accept an optional [reflink diagnostics] output parameter. It is populated\nwith any server-provided error information before calling the completion handler.\n\n[heading Single outstanding operation per connection]\n\nAs mentioned in [link mysql.overview.async this section], only a single async\noperation per connection can be outstanding at a given point in time.\nIf you need to perform queries in parallel, open more connections to the server.\n\n\n[heading Completion tokens]\n\nAny completion token you may use with Boost.Asio can also be used\nwith this library. Here are some of the most common:\n\n* [*C++20 coroutines], using [asioreflink co_spawn co_spawn] and [asioreflink deferred deferred].\n  Passing `deferred` to an initiation function returns an object that can be `co_await`'ed.\n  You can combine deferred with [link mysql.async.with_diagnostics with_diagnostics] to get\n  better error reporting.   \n\n  See [*[link mysql.tutorial_async the async tutorial]] for details.\n\n* [*Stackful coroutines], which you can use to get coroutine-like functionality\n  in C++11. Access this functionality using [asioreflink spawn spawn] and [asioreflink yield_context yield_context],\n  possibly in conjunction with [link mysql.async.with_diagnostics with_diagnostics].\n  You need to link against __Context__ to use these coroutines.\n\n  See [*[link mysql.examples.coroutines_cpp11 this example]] for details.\n\n* [*Callbacks]. You can pass in a callable (function pointer or\n  function object) with the same signature as the handler\n  signature specified for the operation. The callable\n  will be called when the operation completes. The initiating\n  function will return `void`.\n  \n  [link mysql.examples.callbacks This example]\n  demonstrates how to use async functions with callbacks.\n\n* [*Futures]. In this case, you pass in the constant\n  [asioreflink use_future use_future] as completion token.\n  The initiating function will return one of the following:\n    * `std::future<void>`, if the completion handler has the\n      form given by 1).\n    * `std::future<T>`, if the completion handler has the\n      form given by 2).\n  \n  You can wait for the future by calling `future::get`.\n  If an error occurs, `future::get` will throw an exception.\n  Note that the exception is thrown by Asio itself, and will always\n  be of type `boost::system::system_error`, even if diagnostics were\n  available.\n\n* Any other type that satisfies the __CompletionToken__ type requirements.\n  We have listed the most common ones here, but you can craft your own\n  and use it with this library's async operations.\n\n\n[heading:with_diagnostics The with_diagnostics completion token]\n\n[reflink with_diagnostics] is a completion token adapter that you can use\nwith async operations when using exceptions. `with_diagnostics` makes\nyour operations throw [reflink error_with_diagnostics], like sync functions do.\n\n`with_diagnostics(asio::deferred)` is the default completion token for most\noperations in this library. If you're using C++20 coroutines as suggested in the\ntutorials, you're already using it.\n\nWhen using other completion styles that involve exceptions, like\n`asio::yield_context`, you may need to use `with_diagnostics` explicitly.\n[link mysql.examples.coroutines_cpp11 This example] shows how to do it.\n\n`with_diagnostics` only makes sense when using exceptions. When using error codes,\nyou can keep using `asio::as_tuple` and `asio::redirect_error` normally.\n\n\n[heading Cancellations and timeouts]\n\nAll async operations in this library support\n[@boost:/doc/html/boost_asio/overview/core/cancellation.html per-operation cancellation].\nAll operations support only the `terminal` [asioreflink cancellation_type cancellation_type].\nThis means that, if an async operation is cancelled, the [reflink connection] object\nis left in an unspecified state, after which you should close or destroy the connection.\nIn particular, it is [*not] safe to retry the cancelled operation.\n\nSupporting cancellation allows you to implement timeouts without explicit\nsupport from the library. [link mysql.tutorial_error_handling This tutorial]\ncovers the subject in depth.\n\nNote that cancellation happens at the Boost.Asio level, and not at the\nMySQL operation level. This means that, when cancelling an operation, the\ncurrent network read or write will be cancelled. The operation may have\nalready reached the server and be executed. As stated above, after an\noperation is cancelled, the connection is left in an unspecified state, and\nyou should close or destroy it.\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/14_error_handling.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:error_handling Error handling and available overloads]\n\nThis section describes the different error handling strategies\nyou may use with this library, as well as the different overloads\navailable for each function involving network transfers.\n\nThis library uses Boost.System error codes and exceptions,\nlike Asio and Beast. Some server-reported errors may include additional\ndiagnostics information. For example, if you issue a query \nand one of the referenced fields does not exist, the server will return\nan error message indicating which was the offending field. This library\nmakes these diagnostics available through the following classes and\nfunctions:\n\n[variablelist\n    [\n        [[reflink diagnostics]]\n        [\n            An object containing this extra diagnostic information\n            about an error. [refmem diagnostics server_message] contains the server-generated error\n            string, if any.\n        ]\n    ]\n    [\n        [[reflink error_with_diagnostics]]\n        [\n            An exception that inherits from `boost::system::system_error`\n            that contains a `diagnostics` object.\n        ]\n    ]\n    [\n        [[reflink with_diagnostics]]\n        [A completion token that embeds diagnostics in exceptions thrown by async functions.]\n    ]\n    [\n        [[reflink is_fatal_error]]\n        [Checks whether an `error_code` is [link mysql.error_handling.fatal fatal] and thus requires re-establishing the connection.]\n    ]\n]\n\nEvery piece of functionality involving network transfers is offered in four versions:\n\n* [*Synchronous with exceptions]. When they fail, they throw an [reflink error_with_diagnostics] exception.\n* [*Synchronous with [reflink error_code] and [reflink diagnostics]]. These functions output an `error_code` and a `diagnostics`\n  object by lvalue reference to report failures.\n* [*Asynchronous, without `diagnostics`]. When they fail, they call the completion handler with a non-empty `error_code`.\n* [*Asynchronous, with `diagnostics`]. They have a `diagnostics&` parameter before the `CompletionToken`.\n  When they fail, they set the `diagnostics` parameter to any server-provided\n  diagnostic information, if available, and then call the completion handler with a non-empty `error_code`.\n\n[heading Types of errors]\n\nThis library defines the following types of errors:\n\n[table\n    [\n        [Type of error]\n        [Values contained in...]\n        [Error category]\n        [Description]\n    ]\n    [\n        [Client errors]\n        [[reflink client_errc] enum]\n        [[reflink get_client_category]]\n        [Failures detected by Boost.MySQL, like corrupt messages.]\n    ]\n    [\n        [Common server errors]\n        [[reflink common_server_errc] enum]\n        [[reflink get_common_server_category]]\n        [\n            Errors reported by the server, common to both MySQL and MariaDB.\n            No new codes will be added here, since the two DBs are currently developed independently.\n        ]\n    ]\n    [\n        [MySQL-specific server errors]\n        [Integer codes in [br][include_file boost/mysql/mysql_server_errc.hpp]]\n        [[reflink get_mysql_server_category]]\n        [\n            Errors reported by the server, specific to MySQL. New codes will be added in the future.\n        ]\n    ]\n    [\n        [MariaDB-specific server errors]\n        [Integer codes in [br][include_file boost/mysql/mariadb_server_errc.hpp]]\n        [[reflink get_mariadb_server_category]]\n        [\n            Errors reported by the server, specific to MariaDB. New codes will be added in the future.\n        ]\n    ]\n]\n\nNote that new codes are added frequently, so server-specific codes\nare represented as integers, instead of enums.\n\n[heading:fatal Fatal vs. non-fatal errors]\n\nWhen an operation on a established connection (like a query execution)\nresults in an error, two situations may happen:\n\n* The connection object is left in a well-known state. You can safely use the object\n  to run further operations without problems. For instance, if a query fails with\n  `common_server_errc::er_no_such_table` because you misspelled a table name,\n  it is safe to run other queries after the failed one. Such errors are called [*non-fatal].\n* The connection object is left un an unknown state. Further operations will fail with\n  unpredictable results. You should close and re-establish the connection.\n  These are [*fatal] errors, and include protocol and network errors.\n\nYou can use [reflink is_fatal_error] to distinguish between fatal and non-fatal error codes.\n\n[heading Security notes on diagnostics]\n\nThe error message given by [refmem diagnostics server_message] [*may contain user-provided input,\nand should be treated as untrusted]. For certain errors, the MySQL server will include the offending\nfield names and values, which may contain arbitrary input. Please use with caution.\n\nThis message may contain non-ASCII characters. It's encoded using the connection's character set.\n\n[heading:system_result Using boost::system::result]\n\nSome functions, like [refmem basic_format_context get], use\n[@boost:/libs/system/doc/html/system.html#ref_boostsystemresult_hpp `boost::system::result<T>`]\nto communicate errors. `result<T>` contains either a value (an instance of `T`), or an [reflink error_code],\nif the operation failed. `result<T>` is similar to `std::expected`, but only requires C++11.\n\nGiven a `result<T>` object `r`, you can get its contained value calling `r.value()`.\nIf `r` contained an error, a `boost::system::result` exception with the contained\nerror code is thrown. `r.has_value()`, `r.has_error()` and `r.error()` can be\nused to inspect the object.\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/15_sql_formatting_advanced.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:sql_formatting_advanced Advanced client-side SQL query formatting]\n[nochunk]\n\n\n[section:expand Formatting queries without executing them]\n\n`with_params` is handy, but may fall short in some cases involving queries with\ncomplex logic. For these cases, you can use [reflink format_sql] and\n[reflink format_sql_to] to expand a query without executing it.\nThese APIs don't involve communication with the server.\n\n[reflink format_sql] is the simplest, and is akin to `std::format`:\n\n[sql_formatting_format_sql]\n\n`format_sql` requires a [reflink format_options] instance describing\nconnection configuration, like the character set currently in use.\n[refmem any_connection format_opts] provides an easy way to retrieve these.\n[link mysql.sql_formatting_advanced.format_options This section] contains more info about `format_opts`.\n\nSome use cases, usually involving conditionals, may not be\nexpressible in terms of a single format string. In such cases, you can\nuse [reflink format_context] and [reflink format_sql_to] to\nbuild query strings incrementally:\n\n[sql_formatting_incremental_fn]\n[sql_formatting_incremental_use]\n\n[reflink sequence] uses this feature to make formatting ranges easier.\n\nAny type that works with `with_params` also does with `format_sql`\nand `format_sql_to`. These types are said to satisfy the [reflink Formattable] concept.\n[link mysql.sql_formatting_advanced.reference This table] summarizes such types.\n\n[endsect]\n\n\n\n\n\n\n[section:ranges Formatting ranges with sequence]\n\nThe [reflink sequence] function can be used when the default range formatting isn't sufficient.\nIf the elements in your range are not formattable, you can pass a user-defined function to `sequence`\ndescribing how to format each element:\n\n[sql_formatting_sequence_1]\n\nBy default, elements are separated by commas, but this is configurable:\n\n[sql_formatting_sequence_2]\n\nYou can use `sequence` and [reflink with_params] together.\n\nBy default, `sequence` copies the range you pass as parameter,\nmaking it safer for async code. \nYou can use `std::reference_wrapper` or `std::span` to avoid such copies.\n\n[endsect]\n\n\n\n\n[section Format specifiers]\n\nSome types, like strings, can be formatted in multiple ways. As with\n`std::format`, you can select how to format them using format specifiers.\n\nAs we've seen, strings are formatted as single-quoted values by default.\nIf you use the `{:i}` specifier, you can obtain dynamic SQL identifiers, instead:\n\n[sql_formatting_specifiers]\n\nSpecifiers are compatible with explicit indices and named arguments, too.\nThis is equivalent to the previous snippet:\n\n[sql_formatting_specifiers_explicit_indices]\n\n[endsect]\n\n\n\n\n[section Extending format_sql]\n\nYou can specialize [reflink formatter] to add formatting support to your types:\n\n[sql_formatting_formatter_specialization]\n\nThe type can now be used in [reflink format_sql], [reflink format_sql_to] and [reflink with_params]:\n\n[sql_formatting_formatter_use]\n\nYou can add support for format specifiers for your type by modifying\nthe `parse` function in `formatter`. For example, an `employee` can be formatted\ndifferently depending on whether we're using it in an `INSERT` or an `UPDATE`:\n\n[sql_formatting_formatter_specialization_specifiers]\n\nWe can now use it like this:\n\n[sql_formatting_formatter_use_specifiers]\n\nSee the [reflink formatter] reference docs for more info.\n\n[endsect]\n\n\n\n\n[heading:format_string_syntax Format string syntax]\n\nThis section extends on the supported syntax for format strings.\nThe syntax is similar to the one in `fmtlib`.\n\nA format string is composed of regular text and replacement fields.\nRegular text is output verbatim, while replacement fields are substituted\nby formatted arguments. For instance, in `\"SELECT {} FROM employee\"`,\n`\"SELECT \"` and `\" FROM EMPLOYEE\"` is regular text, and `\"{}\"` is a replacement field.\n\nA `{}` is called an [*automatic indexing] replacement field. Arguments are replaced\nin the order they were provided to the format function. For instance:\n\n[sql_formatting_auto_indexing]\n\nA field index can be included within the braces. This is called [*manual indexing].\nIndices can appear in any order, and can be repeated:\n\n[sql_formatting_manual_indices]\n\nFormat strings can use either manual or automatic indexing, but can't mix them:\n\n[sql_formatting_manual_auto_mix]\n\nUnreferenced format arguments are ignored. It's not an error to supply more\nformat arguments than required:\n\n[sql_formatting_unused_args]\n\nYou can output a brace literal by doubling it:\n\n[sql_formatting_brace_literal]\n\nFormat specifiers (e.g. `{:i}`) are supported for some types,\nbut are far less common than in fmtlib, since most types have a\nsingle, canonical representation.\n\nSpecifiers can appear when doing automatic indexing (e.g. `{:i}`) or\nmanual indexing (e.g. `{0:i}`).\n\nTypes specializing formatters can define custom specifiers.\nOnly printable ASCII characters that are not `{` or `}` can be used as specifiers.\n\nFormat strings must be encoded according to [refmem format_options charset].\nOtherwise, an error will be generated. \n\n\n\n\n\n\n[heading:error_handling Error handling model]\n\nSome values can't be securely formatted. For instance, C++\n`double` can be NaN and infinity, which is not supported by MySQL.\nStrings can contain byte sequences that don't represent valid characters,\nwhich makes them impossible to escape securely.\n\nWhen using [reflink with_params] and any of these errors is encountered,\nthe [refmemunq any_connection execute] operation fails, as if a server error\nhad been encountered. This is transparent to the user, so no action is required.\n\n[reflink format_sql] reports these errors by throwing `boost::system::system_error` exceptions,\nwhich contain an error code with details about what happened. For instance:\n\n[sql_formatting_format_double_error]\n\nYou don't have to use exceptions, though. [reflink basic_format_context] and\n[reflink format_sql_to] use [link mysql.error_handling.system_result `boost::system::result`],\ninstead.\n\n[reflink basic_format_context] contains an error code that is set when formatting\na value fails. This is called the ['error state], and can be queried using [refmem format_context_base error_state].\nWhen [refmem basic_format_context get] is called (after all individual values have been formatted),\nthe error state is checked. The `system::result` returned by `get` will contain the error\nstate if it was set, or the generated query if it was not:\n\n[sql_formatting_no_exceptions]\n\nRationale: the error state mechanism makes composing formatters easier,\nas the error state is checked only once.\n\nErrors caused by invalid format strings are also reported using this mechanism.\n\n\n\n\n\n\n[heading:format_options Format options and character set tracking]\n\nMySQL has many configuration options that affect its syntax. There are two options \nthat formatting functions need to know in order to work:\n\n* Whether the backslash character represents an escape sequence or not. By default it does,\n  but this can be disabled dynamically by setting the\n  [@https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_no_backslash_escapes NO_BACKSLASH_ESCAPES] SQL mode.\n  This is tracked by [reflink any_connection] automatically (see [refmem any_connection backslash_escapes]).\n* The connection's [*current character set]. This determines which multi-byte sequences are valid,\n  and is required to iterate and escape the string. The current character set is tracked\n  by connections as far as possible, but deficiencies in the protocol create cases where the character\n  set may not be known to the client. The current character set can be accessed using\n  [refmem any_connection current_character_set].\n\n[refmem any_connection format_opts] is a convenience function that returns a\n[link mysql.error_handling.system_result `boost::system::result`]`<`[reflink format_options]`>`.\nIf the connection could not determine the current character set, the result will contain an error.\nFor a reference on how character set tracking works, please read [link mysql.charsets.tracking this section].\n\n[note\n    Prior to connection establishment, the connection's character set is always unknown.\n    Connect your connection before calling `format_opts`.\n]\n  \n[warning\n    Passing an incorrect `format_options` value to formatting functions may cause\n    escaping to generate incorrect values, which may generate vulnerabilities.\n    Stay safe and always use [refmem any_connection format_opts] instead of\n    hand-crafting `format_options` values. Doing this, if the character set can't be safely\n    determined, you will get a `client_errc::unknown_character_set` error instead of a vulnerability.\n]\n\n\n\n\n\n\n[heading Custom string types]\n\n[reflink format_sql_to] can be used with string types that are not `std::string`,\nas long as they satisfy the [reflink OutputString] concept. This includes\nstrings with custom allocators (like `std::pmr::string`) and `boost::static_string`.\nYou need to use [reflink basic_format_context], specifying the string type:\n\n[sql_formatting_custom_string]\n\n\n\n\n\n[heading Re-using string memory]\n\nYou can pass a string value to the context's constructor, to re-use memory:\n\n[sql_formatting_memory_reuse]\n\n\n\n\n\n[heading Raw string escaping]\n\nIf you're building a SQL framework, or otherwise performing very low-level tasks, you may need\nto just escape a string, without quoting or formatting. You can use [reflink escape_string],\nwhich mimics [@https://dev.mysql.com/doc/c-api/8.0/en/mysql-real-escape-string.html `mysql_real_escape_string`].\n\n[note\n    Don't use this unless you know what you're doing.\n]\n\n\n\n\n[section:reference Types with built-in support for SQL formatting]\n\n[table\n    [\n        [C++ type]\n        [Formatted as...]\n        [Example]\n    ]\n    [\n        [`signed char`, `short`, `int`, `long`, `long long`]\n        [\n            Integral literal[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_signed]\n        ]\n    ]\n    [\n        [`unsigned char`, `unsigned short`, `unsigned int`, `unsigned long`, `unsigned long long`]\n        [\n            Integral literal[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_unsigned]\n        ]\n    ]\n    [\n        [`bool`]\n        [\n            Integral literal `1` if `true`, `0` if `false`[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_bool]\n        ]\n    ]\n    [\n        [\n            String types (convertible to [reflink string_view]), including:[br][br]\n            `std::string`[br][br]\n            [reflink string_view][br][br]\n            `std::string_view`[br][br]\n            `const char*`[br][br]\n        ]\n        [\n            Without format specifiers: single-quoted escaped string literal. Note that `LIKE` special characters (`%` and `_`) are not escaped.[br][br]\n            [*`i`] format specifier: backtick-quoted, escaped SQL identifier.[br][br]\n            [*`r`] format specifier: raw, unescaped SQL. [*Warning]: use this specifier with caution.\n        ]\n        [\n            [sql_formatting_reference_string]\n        ]\n    ]\n    [\n        [\n            Blob types (convertible to `span<const unsigned char>`), including:[br][br]\n            [reflink blob] (`std::vector<unsigned char>`)[br][br]\n            [reflink blob_view] (`span<const unsigned char>`)[br][br]\n            `std::array<unsigned char, N>`\n        ]\n        [\n            Hex string literal[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_blob]\n        ]\n    ]\n    [\n        [`float`, except NaN and inf]\n        [\n            Floating-point literal, after casting to `double.`[br]\n            MySQL does not support NaNs and infinities. Attempting to format\n            these cause a `client_errc::unformattable_value` error.[br]\n            No format specifiers allowed.\n        ]\n        [\n            [sql_formatting_reference_float]\n        ]\n    ]\n    [\n        [`double`, except NaN and inf]\n        [\n            Floating-point literal.[br]\n            MySQL does not support NaNs and infinities. Attempting to format\n            these cause a `client_errc::unformattable_value` error.[br]\n            No format specifiers allowed.\n        ]\n        [\n            [sql_formatting_reference_double]\n        ]\n    ]\n    [\n        [[reflink date]]\n        [\n            Single quoted, `DATE`-compatible string literal[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_date]\n        ]\n    ]\n    [\n        [[reflink datetime]]\n        [\n            Single quoted `DATETIME`-compatible string literal[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_datetime]\n        ]\n    ]\n    [\n        [[reflink time] and `std::chrono::duration` types convertible to [reflink time]]\n        [\n            Single quoted `TIME`-compatible string literal[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_time]\n        ]\n    ]\n    [\n        [`std::nullptr_t`]\n        [\n            `NULL`[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_nullptr]\n        ]\n    ]\n    [\n        [\n            `boost::optional<T>` and `std::optional<T>`, `T` being one of the fundamental types above.[br]\n            Not applicable to custom types or ranges.[br]\n            No format specifiers allowed\n        ]\n        [\n            Formats the underlying value if there is any.[br]\n            `NULL` otherwise.[br]\n        ]\n        [\n            [sql_formatting_reference_optional]\n        ]\n    ]\n    [\n        [[reflink field] and [reflink field_view]]\n        [\n            Formats the underlying value.[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_field]\n        ]\n    ]\n    [\n        [\n            Range of formattable elements. Informally, such ranges support\n            `std::begin()` and `std::end()`, and its iterator `operator*`\n            must yield one of the following:\n\n                * A [reflink2 WritableFieldTuple WritableField] (i.e. one of the fundamental types above).\n                * A type with a custom formatter.\n\n            Ranges of ranges are not supported.\n            Note that `vector<unsigned char>` and similar types are formatted as blobs, not as sequences.\n            \n            See [reflink2 Formattable the Formattable concept reference] for a formal definition.\n        ]\n        [\n            Formats each element in the range, separating elements with commas.[br]\n            Specifiers can be applied to individual elements by prefixing them with a colon (`:`)\n        ]\n        [\n            [sql_formatting_reference_ranges]\n        ]\n    ]\n    [\n        [\n            [reflink format_sequence] (as returned by [reflink sequence])\n        ]\n        [\n            Formats each element in a range by calling a user-supplied function,\n            separating elements by a glue string (a comma by default).[br]\n            No format specifiers allowed\n        ]\n        [\n            [sql_formatting_reference_sequence]\n        ]\n    ]\n    [\n        [Custom type that specializes [reflink formatter]]\n        [\n            Calls `formatter::parse` and `formatter::format`[br]\n            May accept user-defined format specifiers.\n        ]\n        []\n    ]\n    [\n        [[reflink formattable_ref]]\n        [\n            Formats the underlying value. Can represent any of the types above.[br]\n            Accepts the same format specifiers as the underlying type.\n        ]\n        [\n            [sql_formatting_reference_formattable_ref]\n        ]\n    ]\n]\n\n[endsect]\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/16_metadata.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:meta Metadata]\n\nIn the context of this library, metadata refers to information describing\na column retrieved by the execution of a SQL query. The [reflink metadata] class\ncontains information about an individual column.\n\nYou may access metadata using [refmem results meta] or [refmem execution_state meta].\nThere is a `metadata` object per column retrieved by the query. The metadata objects are\npresent even if no row was returned by the query (e.g. a `SELECT` on an empty table).\n\n[reflink connection] objects have an associated [reflink metadata_mode] that describes\nhow to handle metadata when running a query or a statement:\n\n* If [refmem connection meta_mode] is `metadata_mode::minimal` (the default), the library\n  will retain the minimal amount of data required to run the operation. Additional information,\n  like column names, won't be retained. Unless you are using metadata explicitly, you should keep\n  this default, as it consumes slightly less memory.\n* If [refmem connection meta_mode] is `metadata_mode::full`, the library will retain all the information\n  provided by the server, including column names.\n\nOnly the [reflink metadata] members that are strings (database, table and field names)\nare affected by this setting. You may change this setting using [refmem connection set_meta_mode].\n\nFor example:\n\n[metadata]\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/17_charsets.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n\n[section:charsets Character sets and collations]\n[nochunk]\n\nAccording to [mysqllink charset.html MySQL docs], a [*character set] is\n['a set of symbols and their respective encodings].\n`utf8mb4`, `utf16` and `ascii` are character sets supported by MySQL.\nA [*collation] is a set of rules to compare characters, and is associated\nto a single character set. For example, `utf8mb4_spanish_ci` compares\n`utf8mb4` characters in a case-insensitive way.\n\n\n\n\n[heading The connection character set and collation]\n\nEvery client session has an associated character set and collation.\nThe [*connection's character set determines the encoding for character strings\nsent to and retrieved from the server].\nThis includes SQL query strings, string fields and column names in metadata.\nThe connection's collation is used for string literal comparison.\nThe connection's character set and collation can be changed dynamically\nusing SQL.\n\nBy default, Boost.MySQL connections use `utf8mb4_general_ci`,\nthus [*using UTF-8 for all strings]. We recommend using this default,\nas MySQL character sets are easy to get wrong.\n\nThe connection's character set is not linked to the character set\nspecified for databases, tables and columns.\nConsider the following declaration:\n\n```\nCREATE TABLE test_table(\n    col1 TEXT CHARACTER SET utf16 COLLATE utf16_spanish_ci\n);\n```\n\nData stored in `col1` will be encoded using UTF-16 and use\n`utf16_spanish_ci` for comparisons. However, when sent to\nthe client, [*it will be converted to the connection's character set].\n\n[note\n    `utf8mb4` is how MySQL calls regular UTF-8. Confusingly,\n    MySQL has a character set named `utf8` which is not UTF-8 compliant.\n]\n\n\n\n\n\n[heading Connection character set effects]\n\nThe connection's character set is crucial because it affects\nthe encoding of most string fields. The following is a summary\nof what's affected:\n\n* SQL query strings passed to [refmemunq any_connection async_execute] and\n  [refmemunq any_connection async_prepare_statement] must be sent using\n  the connection's character set. Otherwise, server-side parsing errors may happen.\n* SQL templates and string values passed to [reflink with_params]\n  and [reflink format_sql] must be encoded using the connection's character set.\n  Otherwise, values will be rejected by Boost.MySQL when composing the query.\n  Connections [link mysql.charsets.tracking track the character set in use] to detect these errors.\n  If you bypass character set tracking (e.g. by using `SET NAMES` instead of\n  [refmemunq any_connection async_set_character_set]), you may run into vulnerabilities.\n* Statement string parameters passed to [refmem statement bind] should use the connection's character set.\n  Otherwise, MySQL may reject the values.\n* String values in rows and metadata retrieved from the server use the connection's character set.\n* Server-supplied diagnostic messages ([refmem diagnostics server_message]) also\n  use the connection's character set.\n\nTo sum up, to properly use a connection, it's crucial to know\nthe character set it's using.\n\n\n\n\n\n[heading Character set recommendations]\n\nThe following sections provide a deep explanation on how character\nsets work in MySQL. If you don't have the time to read them,\nstick to the following advice:\n\n* [*Always use the default UTF-8]. Character sets in MySQL are complex and full of caveats.\n  If you need to use a different encoding in your application, convert your data to/from UTF-8\n  when interacting with the server. The default [reflink connect_params] ensure that UTF-8 is\n  used, without the need to run any SQL.\n* [*Don't execute SET NAMES] statements or change the `character_set_client` and \n  `character_set_results` session variables using `async_execute`.\n  This breaks character set tracking, which can lead to vulnerabilities.\n* Don't use [refmemunq any_connection async_reset_connection] unless you know what you're doing.\n  If you need to reuse connections, use [reflink connection_pool], instead.\n* Connections obtained from a [reflink connection_pool] always use `utf8mb4`.\n  When connections are returned to the pool, their character set is reset to `utf8mb4`.\n\n\n\n\n[heading:tracking Character set tracking]\n\nThere is a number of actions that can change the connection's character set:\n\n* When connecting with [refmemunq any_connection async_connect],\n  a numeric collation ID is supplied to the server.\n  You can change it using [refmem connect_params connection_collation].\n  The [include_file boost/mysql/mysql_collations.hpp] and \n  [include_file boost/mysql/mariadb_collations.hpp] headers contain\n  available collation IDs.\n  If the server recognizes the passed collation, the connection's character set\n  will be the one associated to the collation. If it doesn't, the connection\n  [*will silently fall back to the server's default character set] (usually `latin1`, which is not Unicode).\n  This can happen when trying to use a newer collation, like `utf8mb4_0900_ai_ci`,\n  with an old MySQL 5.7 server. By default, Boost.MySQL uses\n  `utf8mb4_general_ci`, supported by all servers.\n* Using [refmemunq any_connection async_reset_connection] resets\n  the connection's character set [*to the server's default character set].\n* Using [refmemunq any_connection async_set_character_set] executes\n  a `SET NAMES` statement to set the connection's character set.\n  Executing a pipeline with a set character set stage has the same results.\n* Manually executing a `SET NAMES`, `SET CHARACTER SET` or modifying\n  the `character_set_client` and `character_set_results` change the\n  connection's character set. [*Don't do this], as it will confuse\n  character set tracking.\n\n[reflink any_connection] attempts to track the connection's current character set\nbecause it's required to securely perform client-side SQL formatting.\nThis info is available using [refmem any_connection current_character_set],\nwhich returns a [reflink character_set] object.\nThe current character set is also used by\n`async_execute` when a [reflink with_params_t] object is passed,\nand by [refmem any_connection format_opts].\n\nThe MySQL protocol has limited support for character set tracking, so this task\nrequires some help from the user. Some situations can make the current character set\nto be unknown. If this happens, executing a [reflink with_params_t] fails with\n`client_errc::unknown_character_set`. [refmem any_connection current_character_set]\nand [refmem any_connection format_opts] also return this error.\n\nFollowing the above points, this is how tracking works:\n\n* Before connection establishment, the current character set is always unknown.\n* After [refmemunq any_connection async_connect] succeeds,\n  conservative heuristics are used to determine the current character set.\n  If the passed [refmem connect_params connection_collation] is known to be\n  accepted by all supported servers, its associated character set becomes the\n  current one. If the library is not sure, the current character set is left unknown\n  (this is the safe choice to avoid vulnerabilities).\n  Note that leaving [refmemunq connect_params connection_collation] to its default value\n  always sets the current character set to [reflink utf8mb4_charset].\n* A successful [refmemunq any_connection async_set_character_set]\n  sets the current character set to the passed one.\n  The same applies for a successful set character set pipeline stage.\n* Calling [refmemunq any_connection async_reset_connection]\n  makes the current character set unknown.\n\n[warning\n    [*Do not execute `SET NAMES`], `SET CHARACTER SET` or any other SQL statement\n    that modifies `character_set_client` using `async_execute`. This will make character set\n    information stored in the client invalid.\n]\n\n\n\n\n[heading:custom Adding support for a character set]\n\nBuilt-in support is provided for `utf8mb4` ([reflink utf8mb4_charset])\nand `ascii` ([reflink ascii_charset]). We strongly encourage you to always use `utf8mb4`.\nNote that MySQL doesn't support setting the connection's character set\nto UTF-16 or UTF-32.\n\nIf you really need to use a different character set, you can implement them by\ncreating [reflink character_set] objects. You can then pass them to functions\nlike [refmemunq any_connection set_character_set] like the built-in ones.\n\n[note\n    This is an advanced technique. Don't use it unless you know what you are doing.\n]\n\nThe structure has the following members:\n\n* [refmem character_set name] must match the name you would use in `SET NAMES`.\n* [refmem character_set next_char] is used to iterate the string. It must return\n  the length in bytes of the first code point in the string, or 0 if the code point is invalid.\n\nFor example, this is how you could implement the `utf8mb4` character set. For brevity, only\na small part of the implementation is shown - have a look at the definition of [reflink utf8mb4_charset]\nfor a full implementation.\n\n[charsets_next_char]\n\n\n\n\n\n[heading character_set_results and character_set_client]\n\nSetting the connection's character set during connection establishment\nor using [refmemunq any_connection async_set_character_set] has the ultimate\neffect of changing some session variables. This section lists them as\na reference. We [*strongly encourage you not to modify them manually],\nas this will confuse character set tracking.\n\n* [mysqllink server-system-variables.html#sysvar_character_set_client character_set_client]\n  determines the encoding that SQL statements sent to the server should have. This includes\n  the SQL strings passed to [refmemunq any_connection async_execute] and\n  [refmemunq any_connection async_prepare_statement], and\n  string parameters passed to [refmem statement bind].\n  Not all character sets are permissible in `character_set_client`.\n  For example, UTF-16 and UTF-32 based character sets won't be accepted.\n* [mysqllink server-system-variables.html#sysvar_character_set_results character_set_results]\n  determines the encoding that the server will use to send any kind of result, including\n  string fields retrieved by [refmem connection execute], metadata\n  like [refmem metadata column_name] and error messages.\n  Note that [refmem metadata column_collation] reflects the character set and collation the server\n  has converted the column to before sending it to the client. In the above example, `metadata::column_collation`\n  will be the default collation for UTF16, rather than `latin1_swedish_ci`.\n\n\nThe table below summarizes the encoding used by each piece of functionality in this library:\n\n[table:string_encoding\n    [\n        [Functionality]\n        [Encoding given by...]\n    ]\n    [\n        [\n            SQL query strings passed to [refmemunq any_connection async_execute]\n            and [refmemunq any_connection async_prepare_statement]\n        ]\n        [`character_set_client`]\n    ]\n    [\n        [\n            Strings used with [reflink with_params] and [reflink format_sql]\n        ]\n        [`character_set_client`]\n    ]\n    [\n        [String values passed as parameters to [refmem statement bind]]\n        [`character_set_client`]\n    ]\n    [\n        [\n            String fields in rows retrieved from the server\n        ]\n        [`character_set_results`]\n    ]\n    [\n        [\n            Metadata strings:[br][br]\n            [refmem metadata database][br]\n            [refmem metadata table][br]\n            [refmem metadata original_table][br]\n            [refmem metadata column_name][br]\n            [refmem metadata original_column_name]\n        ]\n        [`character_set_results`]\n    ]\n    [\n        [Server-generated error messages: [refmem diagnostics server_message]]\n        [`character_set_results`]\n    ]\n    [\n        [\n            Informational messages:[br][br]\n            [refmem results info][br]\n            [refmem execution_state info]\n        ]\n        [\n            ASCII. These can only contain ASCII characters and are always ASCII encoded. More info in\n            [@https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html this section].\n        ]\n    ]\n]\n\n\n\n\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/18_time_types.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:time_types Time types: date, datetime and time]\n[nochunk]\n\nThe [reflink date], [reflink datetime] and [reflink time] provide\nsupport for MySQL's native date and time types. This section expands\non how to use them.\n\n[heading The date type]\n\n[reflink date] represents MySQL __DATE__ in C++. `date` holds the year, month and day components of a date,\nwithout any time zone information.\nIt is a type close to the protocol, rather than a vocabulary type. The main reason for using `date` instead\nof a `std::chrono::time_point` type is that, under certain configurations, MySQL allows storing invalid\ndates, such as `2020-00-01`. These are not representable as a `std::chrono::time_point`.\nUnless dealing with these special values, we recommend converting `date`s to a `time_point` before using them.\n\nSince `date` represents a local time point, `std::chrono::local_time` is the most accurate representation for it.\nIf your compiler supports C++20 calendar types (as per `__cpp_lib_chrono >= 201907L`), you can use\n[refmem date as_local_time_point] to perform the cast:\n\n[time_types_date_as_local_time_point]\n\nIf the date is not valid, `as_time_point` will throw an exception.\n\nYou can query whether a `date` contains a valid date or not using [refmem date valid]:\n\n[time_types_date_valid]\n\nYou can combine it with [refmem date get_local_time_point], which performs an unchecked\nconversion:\n\n[time_types_date_get_local_time_point]\n\n[note\n  Using `std::chrono` time zone functionality under MSVC can cause your tooling to report\n  memory leaks. This is [@https://github.com/microsoft/STL/issues/2047 an issue in MSVC's standard library].\n  See [@https://github.com/microsoft/STL/issues/2504 this suggestion] for a possible workaround.\n]\n\nIf your compiler doesn't support local times, you can use [refmem date get_time_point]\nor [refmem date as_time_point], instead. These return [refmem date time_point] objects,\nwhich are `time_points` that use the system clock. These time points should be interpreted\nas local times, rather than UTC:\n\n[time_types_date_as_time_point]\n\n\n\n\n\n[heading The datetime type]\n\n[reflink datetime] represents MySQL __DATETIME__ and __TIMESTAMP__ in C++. `datetime` represents a broken time point,\nhaving year, month, day, hour, minute, second and microsecond.\n\nThe `datetime` object doesn't carry any time zone information with it. The time zone semantics\ndepend on the actual MySQL type:\n\n* __DATETIME__ is a \"naive\" time point object. It represents a time point without any time zone\n  information at all. It is up to the user to interpret which time zone the object is in.\n* When a __TIMESTAMP__ object is inserted, it is interpreted  to be in the connection's local time zone,\n  as given by the __time_zone__ variable, and converted to UTC for storage. When retrieved, it is converted back\n  to the time zone indicated by __time_zone__. The retrieved value of a `TIMESTAMP`\n  field is thus a time point in some local time zone, dictated by the current\n  __time_zone__ variable. As this variable can be changed programmatically from SQL, without\n  the library knowing it, we represent `TIMESTAMP`'s using the `datetime` object, which doesn't include time zone information.\n\nMySQL also accepts invalid datetimes (like `2020-00-10 10:20:59.000000`).\n\nAs with `date`, you can use [refmem datetime as_local_time_point], [refmemunq datetime get_local_time_point]\nand [refmemunq datetime valid] (or [refmemunq datetime as_time_point] and [refmemunq datetime get_time_point],\nif your compiler doesn't support C++20 calendar types):\n\n[time_types_datetime]\n\n\n\n[heading TIMESTAMP considerations]\n\nWhen using `TIMESTAMP`, we recommend setting the __time_zone__ session variable to a known value. To illustrate this,\nconsider an event-logging system with the following table definition:\n\n[time_types_timestamp_setup]\n\nWe will be inserting events with an explicit timestamp. We may also want to retrieve events with\na timestamp filter. This is what our prepared statements would look like:\n\n[time_types_timestamp_stmts]\n\nThese statements may be run from different parts of our code, or even from different applications.\nTo get consistent results, we must make sure that the time zones used during insertion and retrieval are the same.\nBy default, __time_zone__ gets set to `SYSTEM`, which will use the server's time zone settings.\nThis is not what we want here, so let's change it:\n\n[time_types_timestamp_set_time_zone]\n\nWith this, the insertion code can look like:\n\n[time_types_timestamp_insert]\n\nThe querying code would be:\n\n[time_types_timestamp_select]\n    \nIf you don't set __time_zone__, you may apparently get the right results if you run\nboth insertions and queries from clients that don't set `time_zone` and the server doesn't\nchange its configuration. However, relying on this will make your applications brittle, so we\ndon't recommend it.\n\n\n[heading The TIME type]\n\nThe __TIME__ type is a signed duration with a resolution of one microsecond.\nIt is represented using the [reflink time] type, an alias for a\n`std::chrono::duration` specialization with microseconds as period.\n\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/19_templated_connection.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:templated_connection The legacy connection class]\n[nochunk]\n\nYou may encounter code using [reflink connection] or its aliases,\n[reflink tcp_connection], [reflink tcp_ssl_connection],\n[reflink unix_connection]. This was the\nmain way to create client connections until Boost 1.87, when\n[reflink any_connection] became stable.\n\n`connection` is not deprecated, but we don't recommend using it in new code.\n[reflink any_connection] is simpler to use and provides the same\nlevel of efficiency.\n\n\n\n[heading Streams and type aliases]\n\n[reflink connection] is templated on the [reflink Stream] class,\nwhich implements the transport layer to read and write wire bytes.\n\nThe library provides helper type aliases for the most common cases:\n\n[table\n    [\n        [Transport]\n        [Stream type]\n        [Type alias]\n    ]\n    [\n        [SSL over TCP]\n        [`boost::asio::ssl::stream<boost::asio::ip::tcp::socket>`]\n        [\n            [reflink tcp_ssl_connection]\n        ]\n    ]\n    [\n        [Plaintext TCP]\n        [`boost::asio::ip::tcp::socket`]\n        [\n            [reflink tcp_connection]\n        ]\n    ]\n    [\n        [UNIX sockets]\n        [`boost::asio::local::stream_protocol::socket`]\n        [\n            [reflink unix_connection]\n\n            Only available if `BOOST_ASIO_HAS_LOCAL_SOCKETS` is defined.\n        ]\n    ]\n]\n\nIn contrast, [reflink any_connection] is not templated.\nThe same three transports above can be used with `any_connection`.\n\n\n\n\n\n[heading Constructing a connection]\n\n`connection`'s constructor takes the same arguments as the underlying `Stream` constructor.\nFor a [reflink tcp_ssl_connection], we need to pass an execution context and\na __ssl_context__:\n\n[templated_connection_creation]\n\n\n\n\n\n[heading Connection establishment]\n\nUse [refmem connection connect] or [refmem connection async_connect] to perform connection\nestablishment. This function takes two parameters:\n\n* An endpoint to connect to. The endpoint type depends on the stream type.\n  For TCP connections, it's an [asioreflink ip__tcp/endpoint asio::ip::tcp::endpoint],\n  which holds an IP address and a port. For UNIX sockets, it'd be an\n  [asioreflink local__stream_protocol/endpoint asio::local::stream_protocol::endpoint],\n  holding a UNIX path.\n* A [reflink handshake_params] instance, containing all the parameters required\n  to perform the MySQL handshake.\n\nIf you're using TCP, you must perform hostname resolution yourself.\nFor example:\n\n[templated_connection_connect]\n\nAs opposed to `connect_params`, [reflink handshake_params] does not own\nthe strings it contains (like the username and the password). It's your responsibility\nto keep them alive until the connect operation completes.\n\nAll functionality in [reflink handshake_params] has an equivalent in\n[reflink connect_params]. See the [link mysql.templated_connection.reference reference table]\nfor more info.\n\n\n\n\n[heading Using a connection]\n\nOnce connected, [reflink connection] and [reflink any_connection] can\nbe used almost equivalently:\n\n[templated_connection_use]\n\nSome differences:\n\n* Some newer APIs, like [refmemunq any_connection async_set_character_set]\n  and [refmemunq any_connection async_run_pipeline], are not present\n  in [reflink connection].\n* By default, `connection`'s completion token is `asio::deferred`\n  instead of `mysql::with_diagnostics(asio::deferred)`. When using\n  coroutines with exceptions, you need to pass `mysql::with_diagnostics`\n  explicitly if you want exceptions with extra info.\n\n\n\n\n\n[heading Terminating a connection]\n\nAs with `any_connection`, use [refmem connection close] or [refmemunq connection async_close]:\n\n\n\n\n\n[heading TLS support]\n\nTo use TLS, you must use a [reflink connection] with a \n[reflink Stream] that supports TLS.\nA ['TLS-enabled stream] must inherit from\n[asioreflink ssl__stream_base ssl::stream_base].\nThe most common is\n[asioreflink ssl__stream ssl::stream] (used by [reflink tcp_ssl_connection]).\n\nWhen using a stream type that does not support TLS, like [reflink tcp_connection]\nor [reflink unix_connection], [refmem handshake_params ssl] is ignored.\n\n\n\n\n[heading UNIX sockets]\n\n\nTo use UNIX sockets, use [reflink unix_connection]:\n\n[templated_connection_unix]\n\n\n\n\n[heading Handshake and quit]\n\nIn addition to [refmemunq connection connect] and [refmemunq connection close],\n`connection` exposes two additional I/O operations:\n\n* [refmem connection handshake] is like `connect`, but doesn't connect\n  the underlying `Stream`.\n* [refmem connection quit] is like `close`, but doesn't close\n  the underlying `Stream`.\n\nYou can use them like this:\n\n[templated_connection_handshake_quit]\n\nThese functions can be useful in the following cases:\n\n* When you want to perform stream connection establishment yourself.\n  For example, when you want to use the range `asio::connect`\n  overloads, as in the example above.\n* When using an exotic `Stream` type. `connect` and `close`\n  can only be used if the `Stream` type satisfies [reflink SocketStream] - \n  that is, when its lowest layer type is a socket. This holds for\n  all the stream types in the table above, but is not the case\n  for [asioreflink windows__stream_handle windows::stream_handle].\n\n\n\n\n[heading Reconnection]\n\nThe reconnection capabilities of `connection` are more limited than those of `any_connection`.\nConcretely, when using TLS-capable streams, a `connection` can't be re-used after\nit's closed or encounters a fatal error. This is because [asioreflink ssl__stream ssl::stream]\ncan't be re-used. This limitation is not present in [reflink any_connection].\n\nIf you are using [reflink tcp_connection] or [reflink unix_connection],\nor any other stream supporting reconnection, and you want to re-use a connection:\n\n* Call [refmem connection close], or manually close the underlying stream,\n  even if you encountered a fatal error.\n* Call [refmem connection connect] normally, even if the close operation failed.\n* If your [refmem connection connect] operation failed, you can try opening it again\n  by simply calling [refmem connection connect] again.\n\n\nIf your `Stream` type doesn't fulfill the [reflink SocketStream] concept,\nyou need to use [refmemunq connection handshake] and [refmemunq connection quit]\ninstead of `connect` and `close`, and perform transport connection establishment yourself.\n\nAs with `any_connection`, `connection` doesn't perform any built-in retry strategy.\n\n\n\n\n\n[heading Migrating to any_connection]\n\nWe recommend migrating code using templated connections to `any_connection`.\nIn most cases, you only need to change connection establishment code\nto use [reflink connect_params] instead of [reflink handshake_params].\n\nThe following table summarizes all the differences between the\ntwo connection types, and provides migration paths for each feature\nyou may use:\n\n[table:reference\n    [\n        [Feature]\n        [any_connection]\n        [connection]\n    ]\n    [\n        [Hostname resolution]\n        [Performed by [refmem any_connection async_connect]]\n        [Needs to be performed manually]\n    ]\n    [\n        [Credentials]\n        [\n            [refmem connect_params username], [refmem connect_params password]\n        ]\n        [\n            [refmem handshake_params username], [refmem handshake_params password]\n        ]\n    ]\n    [\n        [Database to use]\n        [[refmem connect_params database]]\n        [[refmem handshake_params database]]\n    ]\n    [\n        [Setting TLS options]\n        [\n            [refmem any_connection_params ssl_context]\n        ]\n        [\n            Pass a __ssl_context__ to [reflink tcp_ssl_connection]'s constructor.\n        ]\n    ]\n    [\n        [TLS negotiation]\n        [[refmem connect_params ssl]. Ignored for if using UNIX sockets. Defaults to `mysql::ssl_mode::enable`.]\n        [[refmem handshake_params ssl]. Ignored if `Stream` is not TLS-enabled. Defaults to `mysql::ssl_mode::require`.]\n    ]\n    [\n        [Connection collation]\n        [[refmem connect_params connection_collation]]\n        [[refmem handshake_params connection_collation]]\n    ]\n    [\n        [Enabling multi-queries]\n        [[refmem connect_params multi_queries]]\n        [[refmem handshake_params multi_queries]]\n    ]\n    [\n        [UNIX sockets]\n        [Use a UNIX socket path in [refmem connect_params server_address]]\n        [Use [reflink unix_connection] and pass a UNIX endpoint to [refmem connection connect]]\n    ]\n    [\n        [Windows named pipes]\n        [Not available yet]\n        [Use [asioreflink windows__stream_handle windows::stream_handle] as stream type]\n    ]\n    [\n        [Changing the initial size of the internal network buffer]\n        [[refmem any_connection_params initial_buffer_size]]\n        [Pass a [reflink buffer_params] instance to connection's constructor]\n    ]\n    [\n        [Changing the network buffer size limit]\n        [[refmem any_connection_params max_buffer_size]]\n        [Not available: no limit on the network buffer size]\n    ]\n    [\n        [Access the underlying stream]\n        [Unavailable]\n        [[refmem connection stream]]\n    ]\n    [\n        [Raw handshake and quit]\n        [Unavailable]\n        [[refmem connection handshake], [refmem connection quit]]\n    ]\n    [\n        [Reconnection]\n        [[refmem any_connection async_connect] can always be used]\n        [\n            Requires closing the current connection first.\n            Unavailable for [reflink tcp_ssl_connection].\n        ]\n    ]\n    [\n        [Changing the connection's character set]\n        [[refmem any_connection async_set_character_set]]\n        [Unavailable]\n    ]\n    [\n        [Running pipelines]\n        [[refmem any_connection async_run_pipeline]]\n        [Unavailable]\n    ]\n    [\n        [Including diagnostics in coroutine exceptions]\n        [Enabled by default]\n        [[templated_connection_with_diagnostics]]\n    ]\n    [\n        [Connection pooling]\n        [[reflink connection_pool]]\n        [Unavailable]\n    ]\n]\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/20_1_benchmarks.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:benchmarks Benchmarks against the official connectors]\n[nochunk]\n\nMySQL and MariaDB ship with official C connectors:\n[@https://dev.mysql.com/downloads/c-api/ libmysqlclient] and\n[@https://mariadb.com/kb/en/mariadb-connectorc-api-functions/ libmariadb].\nBoth implement the client/server protocol, as Boost.MySQL does.\nThe question then arises: is Boost.MySQL as fast as the official drivers?\n\n[note\n  TL;DR: Boost.MySQL is as fast as the official C APIs, and may be faster under some circumstances.\n]\n\n\n[heading Design decisions]\n\nThese benchmarks focus on [*the speed of the protocol implementation], in an attempt to\nanswer the question above. This should take into account, at least,\n(de)serialization and buffering. It shouldn't take into account features\nunique to Boost.MySQL, like the static interface or connection pooling.\n\nBoth libmysqlclient and libmariadb offer a connection type, similar to [reflink any_connection],\nwith both sync and async primitives. Sync functions are similar to the ones in Boost.MySQL (although C-flavored).\nAsync functions are much lower-level, and often require either integration into a framework\n(like Asio or libuv) or writing `poll`/`epoll` code by hand. None of these options is trivial.\nAdditionally, sync functions have less overhead, so they're best suited to answer our question.\nFor this reason, [*we only use sync functions] in the benchmarks.\n\nThe benchmarks [*use prepared statements only]. The official drivers handle text\nqueries (issued by `mysql_real_query`) and prepared statements differently.\nRows generated by text queries are returned as strings, and need to be parsed by\nthe user. Boost.MySQL handles this parsing automatically for you.\nFor this reason, comparing text queries doesn't make much sense.\nPrepared statements are handled similarly, and are better suited for\nbig rows and datasets.\n\n[*All tests use a real database]. Neither Boost.MySQL nor the official C clients\nexpose (de)serialization functions. Buffering and optimizing the number of system\ncalls is also critical for efficiency, and can only be measured with real communication.\nThe downside is that database processing introduces delays, and might end up\nbeing the bottleneck.\n\nThe benchmarks try to [*minimize communication overhead by using UNIX sockets].\n\n\n[heading Benchmark procedure]\n\nBenchmark source code can be found in the [@https://github.com/boostorg/mysql/tree/master/bench bench/]\nfolder of the repo. The following benchmarks are performed:\n\n* One small row. Executes a statement yielding a single row with 15 fields,\n  including most of the possible types. Each row weighs around 500 bytes.\n  Execution is repeated 10000 times. The Boost.MySQL version uses [refmem any_connection execute].\n* One big row. Like the above, but rows have 17 fields, and each row weighs between 72 and 108 KB.\n  The Boost.MySQL version uses [refmem any_connection start_execution], which allows zero-copying.\n* Many rows. Executes a statement that yields 5000 of the \"big rows\" described above.\n  The statement is executed only once. The Boost.MySQL version uses [refmem any_connection start_execution]\n  because the resultset size is big.\n* Statement with parameters. Executes a statement with 17 parameters, roughly matching the \"big row\"\n  structure described above. Intended to measure serialization speed.\n  The statement is executed 1000 times.\n\nBenchmark conditions:\n\n* Database: MySQL 8.4.1, running on a Docker container in localhost.\n* OS: Ubuntu 24.04\n* CPU: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz, 8 cores.\n* Compiler: g++-14, using CMake's Release config, C++23.\n* MySQL C API: libmysqlclient24 (as included in the official MySQL 8.4.4 release).\n* MariaDB C API: libmariadb3 1:10.11.11-0ubuntu0.24.04.2 (official Ubuntu package).\n* Boost.MySQL: Boost 1.87.0. The header-only version is used\n  (without defining `BOOST_MYSQL_SEPARATE_COMPILATION`), since it's slightly faster.\n\n\n\n[heading Results]\n\n[$mysql/images/bench-protocol.png [align center]]\n\nThe three libraries exhibit a similar level of performance, which is expected\nfrom a correctly implemented binary protocol. Boost.MySQL outperforms libmysqlclient\nin the single row benchmarks, and is on par with libmariadb. Differences in the\nother benchmarks don't appear to be statistically significant.\n\nDuring these benchmarks, some potential performance improvement areas\nhave been identified. See [https://github.com/boostorg/mysql/issues/458 this issue]\nfor details.\n\nRemember that protocol is just one piece to the whole puzzle.\nCorrectly using features like [reflink connection_pool], [reflink with_params],\nmulti-function operations and multi-queries can make a huge performance difference\nin your application. Never assume anything and always measure!\n\nAcknowledgments: thanks [@https://github.com/LowLevelMahn LowLevelMahn] for proposing the benchmarks.\n\n[endsect]\n"
  },
  {
    "path": "doc/qbk/20_pipeline.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:pipeline (Experimental) Pipelines]\n[nochunk]\n\nFunctions like [refmemunq any_connection execute], [refmemunq any_connection prepare_statement]\nand their async counterparts are half-duplex:\nthey write a single request to the server and wait for its response.\nIn contrast, pipelines can increase efficiency by coalescing several requests into a single message, saving round-trips to the server.\n\n[warning\n    The MySQL client/server protocol doesn't have explicit support for pipelines. [*From the server's point of view,\n    a pipeline is just a sequence of unrelated requests]. The server will try to execute all stages\n    in each pipeline, regardless of the result of previous stages. Pipelines are considered\n    an [*advanced feature]. Please read [link mysql.pipeline.pitfalls the pitfalls section] for more info.\n]\n\n[note\n    This feature is experimental. Its API may change in subsequent releases.\n]\n\n[heading Use cases]\n\nYou should use pipelines for lightweight operations, dominated by round-trip time. Typical examples include:\n\n* Running connection setup code, involving operations like [refmemunq any_connection reset_connection],\n  [refmemunq any_connection set_character_set] or preparing statements. [reflink connection_pool] uses\n  pipelines to clean up connections for re-use.\n* Preparing several statements, in batch.\n* Executing and closing a statement in a single round-trip.\n\n\nYou should [*avoid] pipelines for the following cases:\n\n* When you can achieve the same functionality using semicolon-separated queries\n  (thus using [link mysql.multi_resultset.multi_queries multi-queries] and [link mysql.text_queries client-side SQL formatting]).\n  Multi-queries will stop after the first error, which is usually what you want. See [link mysql.pipeline.pitfalls this section] for more info.\n* When running heavyweight queries, where the gains in round-trip time are not significant.\n* When there are dependencies between stages in the pipeline. Lack of protocol support makes this use case impossible.\n\nIf you're not sure, don't use this feature.\n\n\n\n\n\n\n[heading Pipeline requests and responses]\n\nTo run a pipeline, create a [reflink pipeline_request] object describing what should the pipeline do:\n\n[pipeline_request]\n\nWe're using [refmemunq pipeline_request add_execute] and [refmemunq pipeline_request add_prepare_statement]\nto add stages to our pipeline. You can find all available stage types in the [link mysql.pipeline.reference reference section].\n\nTo actually run the pipeline, create a response object and call\n[refmem any_connection run_pipeline] or [refmemunq any_connection async_run_pipeline]:\n\n[pipeline_run]\n\nFinally, you can access the statements using [refmem stage_response as_statement]:\n\n[pipeline_results]\n\nIf your pipeline contains an execution stage, it will generate a `results` object\nthat can be accessed using [refmem stage_response as_results].\n\n\n\n\n[heading:error Error handling]\n\nIf any of the pipeline stages result in an error, the entire [refmemunq any_connection run_pipeline] operation\nis considered failed. This means that [*if `run_pipipeline` completed successfully, all stages succeeded]. Recall that\n[*all stages are always run, regardless of the outcome of previous stages]. \n\nIf `run_pipipeline` fails, you can check which stages succeeded and failed by inspecting responses.\n[refmem stage_response error] and [refmem stage_response diag] will return error information about failed steps. For instance:\n\n[pipeline_errors]\n\n\n\n\n[heading:pitfalls Potential pitfalls]\n\nAll requests in the pipeline are always run, regardless of the outcome of previous requests. As a result, some pipelines can behave non-intuitively:\n\n[pipeline_pitfalls_bad]\n\nPipelines aren't the best fit here. Instead, you can express the same logic using semicolon-separated queries:\n\n[pipeline_pitfalls_good]\n\nPipeline stages are run sequentially by the server. If any of the stages involves a heavyweight query,\nthe server won't process subsequent stages until the query completes.\n\n\n\n[heading:reference Pipeline stage reference]\n\nIn the table below, the following variables are assumed:\n\n* `req` is a [reflink pipeline_request].\n* `stmt` is a valid [reflink statement].\n* `result` is a [reflink results] object.\n* `conn` is an [reflink any_connection] object.\n\n[table:reference\n    [\n        [Stage type]\n        [Example]\n        [When run, equivalent to...]\n        [Response type]\n    ]\n    [\n        [\n            [*Execute]: behaves like [refmem any_connection execute][br][br]\n            [refmem pipeline_request add_execute][br]\n            [refmem pipeline_request add_execute_range]\n        ]\n        [[pipeline_reference_execute]]\n        [[pipeline_reference_execute_equivalent]]\n        [\n            [reflink results] or an error\n        ]\n    ]\n    [\n        [\n            [*Prepare statement]: behaves like [refmem any_connection prepare_statement][br][br]\n            [refmem pipeline_request add_prepare_statement]\n            \n        ]\n        [[pipeline_reference_prepare_statement]]\n        [[pipeline_reference_prepare_statement_equivalent]]\n        [\n            [reflink statement] or an error\n        ]\n    ]\n    [\n        [\n            [*Close statement]: behaves like [refmem any_connection close_statement][br][br]\n            [refmem pipeline_request add_close_statement]\n        ]\n        [[pipeline_reference_close_statement]]\n        [[pipeline_reference_close_statement_equivalent]]\n        [\n            Possibly empty error\n        ]\n    ]\n    [\n        [\n            [*Reset connection]: behaves like [refmem any_connection reset_connection][br][br]\n            [refmem pipeline_request add_reset_connection]\n        ]\n        [[pipeline_reference_reset_connection]]\n        [[pipeline_reference_reset_connection_equivalent]]\n        [\n            Possibly empty error\n        ]\n    ]\n    [\n        [\n            [*Set character set]: behaves like [refmem any_connection set_character_set][br][br]\n            [refmem pipeline_request add_set_character_set]\n        ]\n        [[pipeline_reference_set_character_set]]\n        [[pipeline_reference_set_character_set_equivalent]]\n        [\n            Possibly empty error\n        ]\n    ]\n]\n\n\n[endsect]"
  },
  {
    "path": "doc/qbk/21_examples.qbk",
    "content": "[/\n    Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[/ This file was auto-generated by examples_qbk.py. Do not edit directly ]\n\n[section:examples Examples]\n\nTo run the examples, please go through the [link mysql.examples.setup setup] first.\n\nHere is a list of available examples:\n\n[heading Tutorials]\n\nSelf-contained programs demonstrating the basic concepts.\n\n* [link mysql.examples.tutorial_sync Tutorial 1 listing: hello world!]\n* [link mysql.examples.tutorial_async Tutorial 2 listing: going async with C++20 coroutines]\n* [link mysql.examples.tutorial_with_params Tutorial 3 listing: queries with parameters]\n* [link mysql.examples.tutorial_static_interface Tutorial 4 listing: the static interface]\n* [link mysql.examples.tutorial_updates_transactions Tutorial 5 listing: UPDATEs, transactions and multi-queries]\n* [link mysql.examples.tutorial_connection_pool Tutorial 6 listing: connection pools]\n* [link mysql.examples.tutorial_error_handling Tutorial 7 listing: error handling]\n\n[heading Simple programs]\n\nSelf-contained programs demonstrating more advanced concepts and techniques.\n\n* [link mysql.examples.inserts INSERTs, last_insert_id() and NULL values]\n* [link mysql.examples.deletes DELETEs and affected_rows()]\n* [link mysql.examples.prepared_statements Prepared statements]\n* [link mysql.examples.disable_tls Disabling TLS for a connection]\n* [link mysql.examples.tls_certificate_verification Setting TLS options: enabling TLS certificate verification]\n* [link mysql.examples.metadata Metadata]\n* [link mysql.examples.multi_function Reading rows in batches with multi-function operations]\n* [link mysql.examples.callbacks Callbacks (async functions in C++11)]\n* [link mysql.examples.coroutines_cpp11 Stackful coroutines (async functions in C++11)]\n* [link mysql.examples.unix_socket UNIX sockets]\n* [link mysql.examples.batch_inserts Batch inserts using client-side query formatting]\n* [link mysql.examples.batch_inserts_generic Generic batch inserts with Boost.Describe]\n* [link mysql.examples.dynamic_filters Queries with dynamic filters]\n* [link mysql.examples.patch_updates Dynamic UPDATE queries with PATCH-like semantics]\n* [link mysql.examples.source_script Sourcing a .sql file using multi-queries]\n* [link mysql.examples.pipeline (Experimental) Pipelines]\n\n[heading Advanced examples]\n\nPrograms implementing real-world functionality.\n\n\n# [@https://github.com/anarthal/servertech-chat The BoostServerTech chat project uses Boost.MySQL and Boost.Redis to implement a chat server]\n\n[heading Setup]\n\nTo run the examples, you need a MySQL server you can connect to.\nExamples make use of a database named `boost_mysql_examples`.\nThe server hostname and credentials (username and password) are passed \nto the examples via the command line.\n\nYou can spin up a server quickly by using Docker:\n\n[!teletype]\n```\n    # Remove the \"-v /var/run/mysqld:/var/run/mysqld\" part if you don't need UNIX sockets\n    > docker run --name some-mysql -p 3306:3306 -v /var/run/mysqld:/var/run/mysqld -d -e MYSQL_ROOT_PASSWORD= -e MYSQL_ALLOW_EMPTY_PASSWORD=1 -d mysql\n\n    # All the required data can be loaded by running example/db_setup.sql.\n    # If you're using the above container, the root user has a blank password\n    > mysql -u root < example/db_setup.sql\n```\n\nPlease note that this container is just for demonstrative purposes,\nand is not suitable for production.\n\nThe root MySQL user for these containers is `root` and has an empty password.\n\n\n[section:tutorial_sync Tutorial 1 listing: hello world!]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_sync]\n\n[endsect]\n\n\n\n\n[section:tutorial_async Tutorial 2 listing: going async with C++20 coroutines]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_async]\n\n[endsect]\n\n\n\n\n[section:tutorial_with_params Tutorial 3 listing: queries with parameters]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_with_params]\n\n[endsect]\n\n\n\n\n[section:tutorial_static_interface Tutorial 4 listing: the static interface]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_static_interface]\n\n[endsect]\n\n\n\n\n[section:tutorial_updates_transactions Tutorial 5 listing: UPDATEs, transactions and multi-queries]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_updates_transactions]\n\n[endsect]\n\n\n\n\n[section:tutorial_connection_pool Tutorial 6 listing: connection pools]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_connection_pool]\n\n[endsect]\n\n\n\n\n[section:tutorial_error_handling Tutorial 7 listing: error handling]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tutorial_error_handling]\n\n[endsect]\n\n\n\n\n[section:inserts INSERTs, last_insert_id() and NULL values]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_inserts]\n\n[endsect]\n\n\n\n\n[section:deletes DELETEs and affected_rows()]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_deletes]\n\n[endsect]\n\n\n\n\n[section:prepared_statements Prepared statements]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_prepared_statements]\n\n[endsect]\n\n\n\n\n[section:disable_tls Disabling TLS for a connection]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_disable_tls]\n\n[endsect]\n\n\n\n\n[section:tls_certificate_verification Setting TLS options: enabling TLS certificate verification]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_tls_certificate_verification]\n\n[endsect]\n\n\n\n\n[section:metadata Metadata]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_metadata]\n\n[endsect]\n\n\n\n\n[section:multi_function Reading rows in batches with multi-function operations]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_multi_function]\n\n[endsect]\n\n\n\n\n[section:callbacks Callbacks (async functions in C++11)]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_callbacks]\n\n[endsect]\n\n\n\n\n[section:coroutines_cpp11 Stackful coroutines (async functions in C++11)]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_coroutines_cpp11]\n\n[endsect]\n\n\n\n\n[section:unix_socket UNIX sockets]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_unix_socket]\n\n[endsect]\n\n\n\n\n[section:batch_inserts Batch inserts using client-side query formatting]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_batch_inserts]\n\n[endsect]\n\n\n\n\n[section:batch_inserts_generic Generic batch inserts with Boost.Describe]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_batch_inserts_generic]\n\n[endsect]\n\n\n\n\n[section:dynamic_filters Queries with dynamic filters]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_dynamic_filters]\n\n[endsect]\n\n\n\n\n[section:patch_updates Dynamic UPDATE queries with PATCH-like semantics]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_patch_updates]\n\n[endsect]\n\n\n\n\n[section:source_script Sourcing a .sql file using multi-queries]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_source_script]\n\n[endsect]\n\n\n\n\n[section:pipeline (Experimental) Pipelines]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_pipeline]\n\n[endsect]\n\n\n\n\n[section:http_server_cpp20 A REST API server that uses C++20 coroutines]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_http_server_cpp20_main_cpp]\n\n[example_http_server_cpp20_types_hpp]\n\n[example_http_server_cpp20_error_hpp]\n\n[example_http_server_cpp20_error_cpp]\n\n[example_http_server_cpp20_repository_hpp]\n\n[example_http_server_cpp20_repository_cpp]\n\n[example_http_server_cpp20_handle_request_hpp]\n\n[example_http_server_cpp20_handle_request_cpp]\n\n[example_http_server_cpp20_server_hpp]\n\n[example_http_server_cpp20_server_cpp]\n\n[endsect]\n\n\n\n\n[section:http_server_cpp14_coroutines A C++14 REST API server that uses asio::yield_context]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n[example_http_server_cpp14_coroutines_main_cpp]\n\n[example_http_server_cpp14_coroutines_types_hpp]\n\n[example_http_server_cpp14_coroutines_repository_hpp]\n\n[example_http_server_cpp14_coroutines_repository_cpp]\n\n[example_http_server_cpp14_coroutines_handle_request_hpp]\n\n[example_http_server_cpp14_coroutines_handle_request_cpp]\n\n[example_http_server_cpp14_coroutines_server_hpp]\n\n[example_http_server_cpp14_coroutines_server_cpp]\n\n[endsect]\n\n\n[endsect]\n\n"
  },
  {
    "path": "doc/qbk/helpers/ExecutionRequest.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__ExecutionRequest ExecutionRequest concept]\n\nAn execution request represents a SQL statement to be executed by the\nserver, plus any required parameters. It may model\na plain text query, a client-side formatted query with parameters,\nor a prepared statement handle with parameters.\n\nFormally, a type `T` is a `ExecutionRequest` if it fulfills any of the following:\n\n* It is convertible to [reflink string_view]. In this case, the execution request\n  contains a text query to be run by the server.\n* An instantiation of the [reflink bound_statement_tuple] class, or a (possibly cv-qualified)\n  reference to it.\n* An instantiation of the [reflink bound_statement_iterator_range] class, or a (possibly cv-qualified)\n  reference to it.\n* An instantiation of the [reflink with_params_t] class, or a (possibly cv-qualified)\n  reference to it.\n\nThis definition may be extended in future versions, but the above types will still satisfy `ExecutionRequest`.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/ExecutionStateType.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__ExecutionStateType ExecutionStateType concept]\n\nA type `T` satisfies `ExecutionStateType` if either:\n\n* It's exactly the [reflink execution_state] class.\n* It's an instantiation of the [reflink static_execution_state] template class.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/FieldViewFwdIterator.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__FieldViewFwdIterator FieldViewFwdIterator concept]\n\nA type `T` fulfills `FieldViewFwdIterator` if it fulfills the\n`LegacyForwardIterator` standard concept, and\n`std::iterator_traits<T>::reference` is convertible to [reflink field_view].\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/Formattable.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__Formattable Formattable concept]\n\nA type `T` is `Formattable` if it can be passed as a format argument to SQL formatting\nfunctions, like [reflink format_sql].\n\nFormally, let `T` be any type, and `U` the result of stripping cv-qualifiers and references from `T`.\n`T` satisfies `Formattable` if any of the following are true:\n\n* `U` satisfies [reflink2 WritableFieldTuple WritableField]. This includes scalar types and optionals.\n* The class [reflink formatter] has been specialized for `U`.\n* `T` is a formattable range, or a reference to one. Formally, given a variable `t` of type `T` (that might be a reference),\n  `T` is a formattable range if:\n    * `std::begin(t)` and `std::end(t)` return an iterator/sentinel pair that can be compared for (in)equality.\n    * The type `std::decay_t<decltype(*std::begin(t))>` is a [reflink2 WritableFieldTuple WritableField]\n      or has a specialized formatter. In other words, the range's element type must be either an elemental\n      type or have a custom formatted defined, but must not be a range.\n    * `U` does not satisfy [reflink2 WritableFieldTuple WritableField] (i.e. `vector<unsigned char>` is\n        formatted as a blob, not as a sequence).\n* `U` is [reflink formattable_ref].\n\nFor a reference table on built-in formattable types, see\n[link mysql.sql_formatting_advanced.reference this section].\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/OutputString.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__OutputString OutputString concept]\n\nAn `OutputString` is a narrow character string type that can be used as output for\noperations that generate a string. Types like `std::string`, `std::basic_string<char, Traits, Allocator>`\nor `boost::static_string<N>` satisfy this concept.\n\nFormally, a type `T` satisfies `OutputString` if all of the following are true:\n\n* It satisfies the `std::movable` concept.\n* Has an `append(const char* data, std::size_t size)` member function that can\n  be used to add a character range to the string.\n* Has a `clear()` function that can be used to remove all characters from the string.\n\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/ResultsType.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__ResultsType ResultsType concept]\n\nA type `T` satisfies `ResultsType` if either:\n\n* It's exactly the [reflink results] class.\n* It's an instantiation of the [reflink static_results] template class.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/SocketStream.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__SocketStream SocketStream concept]\n\n`SocketStream` should meet the [reflink Stream] requirements.\nAdditionally, it should have a `lowest_layer_type` member type,\nand a `lowest_layer` member function, returning a `lowest_layer_type&`,\nfollowing Asio's layered stream model. Additionally,\n`lowest_layer_type` should inherit from an instantiation of \n[asioreflink basic_stream_socket basic_stream_socket].\n\nThe types `boost::asio::basic_stream_socket<Protocol, Executor>` and\n`boost::asio::ssl::stream<boost::asio::basic_stream_socket<Protocol, Executor>>`\nmeet these requirements.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/StaticRow.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__StaticRow StaticRow concept]\n\nA `StaticRow` is a C++ type that can be used to model a row within the\nstatic interface (i.e. can be passed as template parameter to\n[reflink static_results] and [reflink static_execution_state]).\n\nFormally, a type `T` is a `StaticRow` if either of the following is true:\n\n* It is a non-const `struct` annotated with Boost.Describe data (i.e., having\n  `boost::describe::has_describe_members<T>::value == true`), and all the described\n  members fulfill the `ReadableField` exposition-only concept.\n* It is a non-const `std::tuple` instantiation, and all of its types fulfill the\n  `ReadableField` exposition-only concept.\n* It is an instantiation of the [reflink pfr_by_name] or [reflink pfr_by_position]\n  marker types using a type `Underlying` that satisfies the following:\n  * Is reflectable using Boost.PFR. For C++17 and later, this means\n    satisfying [@boost:/doc/html/boost_pfr/limitations_and_configuration.html `SimpleAggregate`].\n    For C++14, stricter requirements apply - see [@boost:/doc/html/boost_pfr/limitations_and_configuration.html the Boost.PFR docs]\n    for more info.\n  * Is a non-const object type (i.e. not a `union` or built-in type).\n  * All of its fields (as given by `pfr::structure_to_tuple`) satisfy `ReadableField`.\n\nNote that row types with no fields (like empty Describe structs and empty tuples) are valid `StaticRow`s.\n\nA `ReadableField` is C++ type that can be used to model a single value in a database row.\nA type `F` is a `ReadableField` if it is any of the types listed\n[link mysql.static_interface.readable_field_reference in this table]. The set of readable field types\nis currently fixed and can't be extended by the user. If this is something you have interest in,\n[@https://github.com/boostorg/mysql/issues/new please file an issue] with your use case to the repo.\n\nThe set of allowable types may be extended in future releases, both for fields and for rows.\n\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/Stream.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__Stream Stream concept]\n\n`Stream` should meet both the `AsyncStream` and `SyncStream` requirements,\n[@boost:/libs/beast/doc/html/beast/concepts/streams.html as defined by Boost.Beast here].\nAdditionally, the type `boost::asio::ssl::stream<Stream>` should be valid and usable\nto both read and write data over SSL.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/WritableFieldTuple.qbk",
    "content": "[/\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[section:boost__mysql__WritableFieldTuple WritableField and WritableFieldTuple concepts]\n\nA type is a `WritableField` if it can be used to represent a statement parameter\nvalue to be sent to the server. A type `T` satisfies `WritableField` if it is\n[link mysql.prepared_statements.writable_field_reference any of the types listed in this table].\nMore types may be added in future releases.\n\nA type `T` is a `WritableFieldTuple` if it's a `std::tuple` specialization,\nor a reference to one, and all element types fulfill\n`WritableField`, or are (possibly cv-qualified) references to `WritableField` types.\nEmpty tuples satisfy `WritableFieldTuple`.\n\n[endsect]"
  },
  {
    "path": "doc/qbk/helpers/quickref.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE library PUBLIC \"-//Boost//DTD BoostBook XML V1.0//EN\" \"../../../../../tools/boostbook/dtd/boostbook.dtd\">\n\n<!--\n    Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n-->\n\n<informaltable frame=\"all\">\n  <tgroup cols=\"3\">\n    <colspec colname=\"a\"/><colspec colname=\"b\"/><colspec colname=\"c\"/><colspec colname=\"d\"/>\n    <tbody><row>\n      <entry valign=\"top\">\n        <bridgehead renderas=\"sect3\">Classes</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.ref.boost__mysql__any_address\">any_address</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__any_connection\">any_connection</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__any_connection_params\">any_connection_params</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__bad_field_access\">bad_field_access</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__basic_format_context\">basic_format_context</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__bound_statement_tuple\">bound_statement_tuple</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__bound_statement_iterator_range\">bound_statement_iterator_range</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__buffer_params\">buffer_params</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__character_set\">character_set</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__connect_params\">connect_params</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__connection\">connection</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__connection_pool\">connection_pool</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__constant_string_view\">constant_string_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__date\">date</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__datetime\">datetime</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__diagnostics\">diagnostics</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__error_with_diagnostics\">error_with_diagnostics</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__execution_state\">execution_state</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__field\">field</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__field_view\">field_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_arg\">format_arg</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_context_base\">format_context_base</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__formattable_ref\">formattable_ref</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__formatter\">formatter</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_options\">format_options</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_sequence\">format_sequence</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__handshake_params\">handshake_params</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__host_and_port\">host_and_port</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__metadata\">metadata</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__pfr_by_name\">pfr_by_name</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__pfr_by_position\">pfr_by_position</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__pipeline_request\">pipeline_request</link> (experimental)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__pool_params\">pool_params</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__pooled_connection\">pooled_connection</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__results\">results</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__resultset_view\">resultset_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__resultset\">resultset</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__row\">row</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__row_view\">row_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__rows\">rows</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__rows_view\">rows_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__stage_response\">stage_response</link> (experimental)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__statement\">statement</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__static_execution_state\">static_execution_state</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__static_results\">static_results</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__unix_path\">unix_path</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__with_diagnostics_t\">with_diagnostics_t</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__with_params_t\">with_params_t</link></member>\n        </simplelist>\n      </entry>\n      <entry valign=\"top\">\n        <bridgehead renderas=\"sect3\">Enumerations</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.ref.boost__mysql__address_type\">address_type</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__client_errc\">client_errc</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__column_type\">column_type</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__common_server_errc\">common_server_errc</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__field_kind\">field_kind</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__metadata_mode\">metadata_mode</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__quoting_context\">quoting_context</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__ssl_mode\">ssl_mode</link></member>\n        </simplelist>\n        <bridgehead renderas=\"sect3\">Constants</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.ref.boost__mysql__ascii_charset\">ascii_charset</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__default_initial_read_buffer_size\">default_initial_read_buffer_size</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__default_port\">default_port</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__default_port_string\">default_port_string</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__max_date\">max_date</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__min_date\">min_date</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__max_datetime\">max_datetime</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__min_datetime\">min_datetime</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__max_time\">max_time</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__min_time\">min_time</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__utf8mb4_charset\">utf8mb4_charset</link></member>\n        </simplelist>\n        <bridgehead renderas=\"sect3\">Functions</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.ref.boost__mysql__escape_string\">escape_string</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_sql\">format_sql</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_sql_to\">format_sql_to</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__get_client_category\">get_client_category</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__get_common_server_category\">get_common_server_category</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__get_mysql_server_category\">get_mysql_server_category</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__get_mariadb_server_category\">get_mariadb_server_category</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__make_error_code\">make_error_code</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__runtime\">runtime</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__sequence\">sequence</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__throw_on_error\">throw_on_error</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__with_diagnostics\">with_diagnostics</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__with_params\">with_params</link></member>\n        </simplelist>\n      </entry>\n      <entry valign=\"top\">\n        <bridgehead renderas=\"sect3\">Type aliases</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.ref.boost__mysql__blob\">blob</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__blob_view\">blob_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__days\">days</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__error_code\">error_code</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__format_context\">format_context</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__make_tuple_element_t\">make_tuple_element_t</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__metadata_collection_view\">metadata_collection_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__sequence_range_t\">sequence_range_t</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__string_view\">string_view</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__tcp_connection\">tcp_connection</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__tcp_ssl_connection\">tcp_ssl_connection</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__time\">time</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__underlying_row_t\">underlying_row_t</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__unix_connection\">unix_connection</link> (legacy)</member>\n          <member><link linkend=\"mysql.ref.boost__mysql__unix_ssl_connection\">unix_ssl_connection</link> (legacy)</member>\n        </simplelist>\n        <bridgehead renderas=\"sect3\">Concepts</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.ref.boost__mysql__ExecutionRequest\">ExecutionRequest</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__ExecutionStateType\">ExecutionStateType</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__FieldViewFwdIterator\">FieldViewFwdIterator</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__Formattable\">Formattable</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__OutputString\">OutputString</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__ResultsType\">ResultsType</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__SocketStream\">SocketStream</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__StaticRow\">StaticRow</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__Stream\">Stream</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__WritableFieldTuple\">WritableField</link></member>\n          <member><link linkend=\"mysql.ref.boost__mysql__WritableFieldTuple\">WritableFieldTuple</link></member>\n        </simplelist>\n        <bridgehead renderas=\"sect3\">Reference tables</bridgehead>\n        <simplelist type=\"vert\" columns=\"1\">\n          <member><link linkend=\"mysql.dynamic_interface.dynamic_field_mappings\">Dynamic interface type mappings</link></member>\n          <member><link linkend=\"mysql.static_interface.readable_field_reference\">ReadableField types</link></member>\n          <member><link linkend=\"mysql.prepared_statements.writable_field_reference\">WritableField types</link></member>\n          <member><link linkend=\"mysql.sql_formatting_advanced.reference\">Formattable types</link></member>\n          <member><link linkend=\"mysql.pipeline.reference\">Pipeline stage reference</link> (experimental)</member>\n        </simplelist>\n      </entry>\n    </row></tbody>\n  </tgroup>\n</informaltable>\n"
  },
  {
    "path": "doc/upgrade_1_82.md",
    "content": "# Upgrade instructions to 1.82\n\nThis document describes how to upgrade from 0.2.x to 1.82 (please remember that 1.82 is the first stable release in this library, and the versioning follows Boost versioning).\n\nThis is a major upgrade, since a lot of changes have been made since the review took place. If you encounter any problems, please file an issue against the repository, and we will be happy to help :)\n\n* The `value` class has been replaced by `field_view`. The generic accessors have been replaced by type-specific functions. Conversions, `get_optional` and `get_std_optional` have been removed, in favor of an interface more similar to `json::value`. The class `field` has been added to be able to take ownership of a `field_view`.\n    * **Action**: replace `value` by `field_view`.\n* Statements are no longer I/O objects. `connection::prepare_statement` works the same, but execution requires going through the connection. \n    * **Action**: replace `stmt.execute(...)` by `conn.execute_statement(stmt, ...)`,\n      `stmt.close()` by `conn.close_statement(stmt)`.\n* Resultsets as I/O objects have been removed, and executing queries and statements is now simpler. There are now two ways to run queries or statements:\n    * `connection::query` and `connection::execute_statement` now read all rows into memory, into a `results` object (which is similar to `resultset`, but is a plain data object and contains all the rows). These functions are equivalent to the old `connection::query`/`statement::execute` plus `resultset::read_all`.\n        * **Action**: if you were using `conn.query(...).read_all()` (or similar), replace it by `conn.query(...)`.\n    * `connection::start_query` and `statement::start_execution` behave similarly to the old `connection::query` and `statement::execute`. They use a data structure called `execution_state`, which is similar to the old `resultset`.\n        * **Action**: if you were reading rows using `read_one` or `read_many`, consider whether your application requires reading row-by-row or not. If it doesn't, apply the point above. If it does, replace `conn.query(...)` by `conn.start_query(...)`, and `result.read_one(...)` by `conn.read_some_rows(...)`. There is no function to read a single row.\n* Statement parameters are now passed as a `std::tuple` to `execute_statement`, rather than a collection.\n    * **Action**:\n        * If you were using `stmt.execute(make_values(a, b), ...)`, replace it by `conn.execute_statement(std::make_tuple(a, b), ...)`\n        * If you were using a collection and can't migrate to a `std::tuple` (because the number of parameters is unknown at compile-time), then have a look at [this solution](https://github.com/boostorg/mysql/issues/110).\n* `error_info` has been renamed to `diagnostics` and `error_info::message()` to `diagnostics::server_message()`. The message is no longer included by default in the thrown exceptions's `what()`. This is because the message may not be UTF-8 compatible.\n    * **Action**: apply the renames. If you're using exceptions, catch the new `error_with_diagnostics` exception type to retrieve the server message.\n* The `date` and `datetime` types are now custom types, instead of aliases for `std::chrono`. This enables them to represent zero and invalid dates.\n    * **Action**: to get a `time_point` from a `date` or `datetime`, use `as_time_point` or `get_time_point` + `valid`.\n* Binary types (`BLOB`, `BINARY`, `VARBINARY`, `GEOMETRY`) are now represented as a special type `blob_view`/`blob`.\n    * **Action**: if you handle these types in your application, use `is_blob`, `get_blob` and `as_blob` functions in `field_view`.\n* The `collation` enum has been removed in favor of plain integers.\n    * **Action**: if you were using collations explicitly, replace the enumerator by the collation ID. You can find them in `<boost/mysql/mysql_collations.hpp>` and `<boost/mysql/mariadb_collations.hpp>`.\n* `connection_params` has been reverted to `handshake_params`.\n    * **Action**: replace occurrences of `connection_params` by `handshake_params`.\n* `row` is no longer streamable. The stream operation on `row` wasn't a universal agreement.\n    * **Action**: if you were streaming rows, switch to using a loop and streaming individual `field_view`s, instead.\n* Metadata strings is no longer retained by default, to save allocations.\n    * **Action**: if your code uses metadata strings (e.g. `metadata::column_name()`, use `conn.set_metadata_mode(metadata_mode::full))` before initiating any query/statement execution.\n* The library now uses `boost::core::string_view` (under the alias `boost::mysql::string_view`) rather than `boost::string_view`.\n    * **Action**: if you were using `boost::string_view` directly, change it to `boost::mysql::string_view`.\n* `errc` has been split into `client_errc`, `server_errc` and server-specific error codes (which don't have an enum).\n    * **Action**: if you were referencing `errc` values directly, replace `errc` by `client_errc` or `server_errc`.\n* `field_type` has been renamed to `column_type`.\n    * **Action**: apply the rename.\n* The following members in `metadata` have been renamed:\n    * `field_name` => `column_name`\n    * `original_field_name` => `original_column_name`\n    * `character_set` => `column_collation`\n    * **Action**: apply the renames.\n* `connection::next_layer()` has been renamed to `connection::stream()`.\n    * **Action**: apply the rename.\n* `no_statement_params` has been removed.\n    * **Action**: replace it by an empty `std::make_tuple()`.\n"
  },
  {
    "path": "example/1_tutorial/1_sync.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n//[example_tutorial_sync\n\n/**\n * Creates a connection, establishes a session and\n * runs a simple \"Hello world!\" query.\n *\n * This example uses synchronous functions and handles errors using exceptions.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include <iostream>\n\n//[tutorial_sync_namespaces\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n//]\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname>\\n\";\n        exit(1);\n    }\n\n    const char* hostname = argv[3];\n    const char* username = argv[1];\n    const char* password = argv[2];\n\n    //[tutorial_sync_connection\n    // The execution context, required to run I/O operations.\n    asio::io_context ctx;\n\n    // Represents a connection to the MySQL server.\n    mysql::any_connection conn(ctx);\n    //]\n\n    //[tutorial_sync_main\n    //[tutorial_sync_connect\n    // The hostname, username and password to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(hostname);\n    params.username = username;\n    params.password = password;\n\n    // Connect to the server\n    conn.connect(params);\n    //]\n\n    //[tutorial_sync_query\n    // Issue the SQL query to the server\n    const char* sql = \"SELECT 'Hello world!'\";\n    mysql::results result;\n    conn.execute(sql, result);\n    //]\n\n    //[tutorial_sync_results\n    // Print the first field in the first row\n    std::cout << result.rows().at(0).at(0) << std::endl;\n    //]\n\n    //[tutorial_sync_close\n    // Close the connection\n    conn.close();\n    //]\n    //]\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n"
  },
  {
    "path": "example/1_tutorial/2_async.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_tutorial_async\n\n/**\n * This example is analogous to the synchronous tutorial, but uses async functions\n * with C++20 coroutines, instead.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/this_coro.hpp>\n\n#include <exception>\n#include <iostream>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n/**\n * The main coroutine.\n * It must have a return type of asio::awaitable<T>.\n * Our coroutine does not communicate any result back, so T=void.\n *\n * The coroutine will suspend every time we call one of the asynchronous functions, saving\n * all information it needs for resuming. When the asynchronous operation completes,\n * the coroutine will resume in the point it was left.\n * We use the same program structure as in the sync world, replacing\n * sync functions by their async equivalents and adding co_await in front of them.\n */\n//[tutorial_async_coro\nasio::awaitable<void> coro_main(\n    mysql::any_connection& conn,\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password\n)\n{\n    // The hostname, username, password and database to use.\n    // TLS is used by default.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Issue the SQL query to the server\n    const char* sql = \"SELECT 'Hello world!'\";\n    mysql::results result;\n    co_await conn.async_execute(sql, result);\n\n    // Print the first field in the first row\n    std::cout << result.rows().at(0).at(0) << std::endl;\n\n    // Close the connection\n    co_await conn.async_close();\n}\n//]\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname>\\n\";\n        exit(1);\n    }\n\n    //[tutorial_async_connection\n    // The execution context, required to run I/O operations.\n    asio::io_context ctx;\n\n    // Represents a connection to the MySQL server.\n    mysql::any_connection conn(ctx);\n    //]\n\n    //[tutorial_async_co_spawn\n    // Enqueue the coroutine for execution.\n    // This does not wait for the coroutine to finish.\n    asio::co_spawn(\n        // The execution context where the coroutine will run\n        ctx,\n\n        // The coroutine to run. This must be a function taking no arguments\n        // and returning an asio::awaitable<T>\n        [&conn, argv] { return coro_main(conn, argv[3], argv[1], argv[2]); },\n\n        // Callback to run when the coroutine completes.\n        // If any exception is thrown in the coroutine body, propagate it to terminate the program.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n    //]\n\n    //[tutorial_async_run\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n    //]\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif"
  },
  {
    "path": "example/1_tutorial/3_with_params.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_tutorial_with_params\n\n/**\n * This example shows how to issue queries with parameters containing\n * untrusted input securely. Given an employee ID, it prints their full name.\n * The example builds on the previous async tutorial.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/this_coro.hpp>\n\n#include <cstdint>\n#include <exception>\n#include <iostream>\n#include <string>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n//[tutorial_with_params_coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::int64_t employee_id\n)\n{\n    //[tutorial_with_params_connection\n    // The connection will use the same executor as the coroutine\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n    //]\n\n    //[tutorial_with_params_connect_params\n    // The hostname, username, password and database to use.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n    //]\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    //[tutorial_with_params_execute\n    // Execute the query with the given parameters. When executed, with_params\n    // expands the given query string template and sends it to the server for execution.\n    // {} are placeholders, as in std::format. Values are escaped as required to prevent\n    // SQL injection.\n    mysql::results result;\n    co_await conn.async_execute(\n        mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n        result\n    );\n    //]\n\n    //[tutorial_with_params_results\n    // Did we find an employee with that ID?\n    if (result.rows().empty())\n    {\n        std::cout << \"Employee not found\" << std::endl;\n    }\n    else\n    {\n        // Print the retrieved details. The first field is the first name,\n        // and the second, the last name.\n        mysql::row_view employee = result.rows().at(0);\n        std::cout << \"Employee's name is: \" << employee.at(0) << ' ' << employee.at(1) << std::endl;\n    }\n    //]\n\n    // Close the connection\n    co_await conn.async_close();\n}\n//]\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <employee-id>\\n\";\n        exit(1);\n    }\n\n    // The execution context, required to run I/O operations.\n    asio::io_context ctx;\n\n    // Enqueue the coroutine for execution.\n    asio::co_spawn(\n        // The execution context where the coroutine will run\n        ctx,\n\n        // The coroutine to run. This must be a function taking no arguments\n        // and returning an asio::awaitable<T>\n        [argv] { return coro_main(argv[3], argv[1], argv[2], std::stoi(argv[4])); },\n\n        // Callback to run when the coroutine completes.\n        // If any exception is thrown in the coroutine body, propagate it to terminate the program.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif"
  },
  {
    "path": "example/1_tutorial/4_static_interface.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pfr.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_tutorial_static_interface\n\n/**\n * This example shows how to use the static interface to parse\n * the results of a query into a C++ struct.\n * Like the previous tutorial, given an employee ID,\n * it prints their full name.\n *\n * It uses Boost.Pfr for reflection, which requires C++20.\n * You can backport it to C++14 if you need by using Boost.Describe.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/this_coro.hpp>\n\n#include <cstdint>\n#include <exception>\n#include <iostream>\n#include <string>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n//[tutorial_static_fn\nvoid print_employee(std::string_view first_name, std::string_view last_name)\n{\n    std::cout << \"Employee's name is: \" << first_name << ' ' << last_name << std::endl;\n}\n//]\n\n//[tutorial_static_struct\n// Should contain a member for each field of interest present in our query.\n// Declaration order doesn't need to match field order in the query.\n// Field names should match the ones in our query\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n};\n//]\n\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::int64_t employee_id\n)\n{\n    // Represents a connection to the MySQL server.\n    // The connection will use the same executor as the coroutine\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    //[tutorial_static_execute\n    // Using static_results will parse the result of our query\n    // into instances of the employee type. Fields will be matched\n    // by name, instead of by position.\n    // pfr_by_name tells the library to use Boost.Pfr for reflection,\n    // and to match fields by name.\n    mysql::static_results<mysql::pfr_by_name<employee>> result;\n\n    // Execute the query with the given parameters, performing the required\n    // escaping to prevent SQL injection.\n    co_await conn.async_execute(\n        mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n        result\n    );\n    //]\n\n    //[tutorial_static_results\n    // Did we find an employee with that ID?\n    if (result.rows().empty())\n    {\n        std::cout << \"Employee not found\" << std::endl;\n    }\n    else\n    {\n        // Print the retrieved details\n        const employee& emp = result.rows()[0];\n        print_employee(emp.first_name, emp.last_name);\n    }\n    //]\n\n    // Close the connection\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <employee-id>\\n\";\n        exit(1);\n    }\n\n    // The execution context, required to run I/O operations.\n    asio::io_context ctx;\n\n    // Enqueue the coroutine for execution.\n    asio::co_spawn(\n        // The execution context where the coroutine will run\n        ctx,\n\n        // The coroutine to run. This must be a function taking no arguments\n        // and returning an asio::awaitable<T>\n        [argv] { return coro_main(argv[3], argv[1], argv[2], std::stoi(argv[4])); },\n\n        // Callback to run when the coroutine completes.\n        // If any exception is thrown in the coroutine body, propagate it to terminate the program.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif"
  },
  {
    "path": "example/1_tutorial/5_updates_transactions.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pfr.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_tutorial_updates_transactions\n\n/**\n * This example demonstrates how to use UPDATE statements,\n * transactions and semicolon-separated queries.\n *\n * The program updates the first name of an employee given their ID\n * and prints their full details.\n *\n * It uses Boost.Pfr for reflection, which requires C++20.\n * You can backport it to C++14 if you need by using Boost.Describe.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/resultset_view.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <cstdint>\n#include <iostream>\n#include <string>\n#include <string_view>\n#include <tuple>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// As in the previous tutorial, this struct models\n// the data returned by our SELECT query. It should contain a member\n// for each field of interest, with a matching name.\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n};\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::int64_t employee_id,\n    std::string_view new_first_name\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    //[section_connection_establishment_multi_queries\n    //[tutorial_updates_transactions_connect\n    // The server host, username, password and database to use.\n    // Setting multi_queries to true makes it possible to run several\n    // semicolon-separated queries with async_execute.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = std::move(username);\n    params.password = std::move(password);\n    params.database = \"boost_mysql_examples\";\n    params.multi_queries = true;\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n    //]\n    //]\n\n    // Perform the update and retrieve the results:\n    //   1. Begin a transaction block. Further updates won't be visible to\n    //      other transactions until this one commits.\n    //   2. Perform the update.\n    //   3. Retrieve the employee we just updated. Since we're in a transaction,\n    //      this will be the employee we just updated (if any),\n    //      without the possibility of other transactions interfering.\n    //   4. Commit the transaction and make everything visible to other transactions.\n    //      If any of the previous steps fail, the commit won't be run, and the\n    //      transaction will be rolled back when the connection is closed.\n    //[tutorial_updates_transactions_static\n    // MySQL returns one resultset for each query, so we pass 4 params to static_results\n    //<-\n    // clang-format off\n    //->\n    mysql::static_results<\n        std::tuple<>,                  // START TRANSACTION doesn't generate rows\n        std::tuple<>,                  // The UPDATE doesn't generate rows\n        mysql::pfr_by_name<employee>,  // The SELECT generates employees\n        std::tuple<>                   // The COMMIT doesn't generate rows\n    > result;\n    //<-\n    // clang-format on\n    //->\n\n    co_await conn.async_execute(\n        mysql::with_params(\n            \"START TRANSACTION;\"\n            \"UPDATE employee SET first_name = {0} WHERE id = {1};\"\n            \"SELECT first_name, last_name FROM employee WHERE id = {1};\"\n            \"COMMIT\",\n            new_first_name,\n            employee_id\n        ),\n        result\n    );\n\n    // We've run 4 SQL queries, so MySQL has returned us 4 resultsets.\n    // The SELECT is the 3rd resultset. Retrieve the generated rows.\n    // employees is a span<const employee>\n    auto employees = result.rows<2>();\n    if (employees.empty())\n    {\n        std::cout << \"No employee with ID = \" << employee_id << std::endl;\n    }\n    else\n    {\n        const employee& emp = employees[0];\n        std::cout << \"Updated: employee is now \" << emp.first_name << \" \" << emp.last_name << std::endl;\n    }\n    //]\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 6)\n    {\n        std::cerr << \"Usage: \" << argv[0]\n                  << \" <username> <password> <server-hostname> <employee-id> <new-first-name>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2], std::stoi(argv[4]), argv[5]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/1_tutorial/6_connection_pool.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pfr.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_tutorial_connection_pool\n\n/**\n * This example demonstrates how to use connection_pool\n * to implement a server for a simple custom TCP-based protocol.\n * It also demonstrates how to set timeouts with asio::cancel_after.\n *\n * The protocol can be used to retrieve the full name of an\n * employee, given their ID. It works as follows:\n *   - The client connects.\n *   - The client sends the employee ID, as a big-endian 64-bit signed int.\n *   - The server responds with a string containing the employee full name.\n *   - The connection is closed.\n *\n * This tutorial doesn't include proper error handling.\n * We will build it in the next one.\n *\n * It uses Boost.Pfr for reflection, which requires C++20.\n * You can backport it to C++14 if you need by using Boost.Describe.\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/buffer.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/read.hpp>\n#include <boost/asio/signal_set.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/asio/write.hpp>\n#include <boost/endian/conversion.hpp>\n#include <boost/system/error_code.hpp>\n\n#include <chrono>\n#include <cstdint>\n#include <exception>\n#include <iostream>\n#include <string>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// Should contain a member for each field of interest present in our query\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n};\n\n//[tutorial_connection_pool_db\n// Encapsulates the database access logic.\n// Given an employee_id, retrieves the employee details to be sent to the client.\nasio::awaitable<std::string> get_employee_details(mysql::connection_pool& pool, std::int64_t employee_id)\n{\n    //[tutorial_connection_pool_get_connection_timeout\n    // Get a connection from the pool.\n    // This will wait until a healthy connection is ready to be used.\n    // pooled_connection grants us exclusive access to the connection until\n    // the object is destroyed.\n    // Fail the operation if no connection becomes available in the next 20 seconds.\n    mysql::pooled_connection conn = co_await pool.async_get_connection(\n        asio::cancel_after(std::chrono::seconds(1))\n    );\n    //]\n\n    //[tutorial_connection_pool_use\n    // Use the connection normally to query the database.\n    // operator-> returns a reference to an any_connection,\n    // so we can apply all what we learnt in previous tutorials\n    mysql::static_results<mysql::pfr_by_name<employee>> result;\n    co_await conn->async_execute(\n        mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n        result\n    );\n    //]\n\n    // Compose the message to be sent back to the client\n    if (result.rows().empty())\n    {\n        co_return \"NOT_FOUND\";\n    }\n    else\n    {\n        const auto& emp = result.rows()[0];\n        co_return emp.first_name + ' ' + emp.last_name;\n    }\n\n    // When the pooled_connection is destroyed, the connection is returned\n    // to the pool, so it can be re-used.\n}\n//]\n\n//[tutorial_connection_pool_session\nasio::awaitable<void> handle_session(mysql::connection_pool& pool, asio::ip::tcp::socket client_socket)\n{\n    // Read the request from the client.\n    // async_read ensures that the 8-byte buffer is filled, handling partial reads.\n    unsigned char message[8]{};\n    co_await asio::async_read(client_socket, asio::buffer(message));\n\n    // Parse the 64-bit big-endian int into a native int64_t\n    std::int64_t employee_id = boost::endian::load_big_s64(message);\n\n    // Invoke the database handling logic\n    std::string response = co_await get_employee_details(pool, employee_id);\n\n    // Write the response back to the client.\n    // async_write ensures that the entire message is written, handling partial writes\n    co_await asio::async_write(client_socket, asio::buffer(response));\n\n    // The socket's destructor will close the client connection\n}\n//]\n\n//[tutorial_connection_pool_listener\nasio::awaitable<void> listener(mysql::connection_pool& pool, unsigned short port)\n{\n    // An object that accepts incoming TCP connections.\n    asio::ip::tcp::acceptor acc(co_await asio::this_coro::executor);\n\n    // The endpoint where the server will listen.\n    asio::ip::tcp::endpoint listening_endpoint(asio::ip::make_address(\"0.0.0.0\"), port);\n\n    // Open the acceptor\n    acc.open(listening_endpoint.protocol());\n\n    // Allow reusing the local address, so we can restart our server\n    // without encountering errors in bind\n    acc.set_option(asio::socket_base::reuse_address(true));\n\n    // Bind to the local address\n    acc.bind(listening_endpoint);\n\n    // Start listening for connections\n    acc.listen();\n    std::cout << \"Server listening at \" << acc.local_endpoint() << std::endl;\n\n    // Start the accept loop\n    while (true)\n    {\n        // Accept a new connection\n        auto sock = co_await acc.async_accept();\n\n        // Function implementing our session logic.\n        // Takes ownership of the socket.\n        // Having this as a named variable workarounds a gcc bug\n        // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107288)\n        auto session_logic = [&pool, s = std::move(sock)]() mutable {\n            return handle_session(pool, std::move(s));\n        };\n\n        // Launch a coroutine that runs our session logic.\n        // We don't co_await this coroutine so we can listen\n        // to new connections while the session is running.\n        asio::co_spawn(\n            // Use the same executor as the current coroutine\n            co_await asio::this_coro::executor,\n\n            // Session logic\n            std::move(session_logic),\n\n            // Propagate exceptions thrown in handle_session\n            [](std::exception_ptr ex) {\n                if (ex)\n                    std::rethrow_exception(ex);\n            }\n        );\n    }\n}\n//]\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <listener-port>\\n\";\n        exit(1);\n    }\n\n    const char* username = argv[1];\n    const char* password = argv[2];\n    const char* server_hostname = argv[3];\n    auto listener_port = static_cast<unsigned short>(std::stoi(argv[4]));\n\n    //[tutorial_connection_pool_main\n    //[tutorial_connection_pool_create\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // pool_params contains configuration for the pool.\n    // You must specify enough information to establish a connection,\n    // including the server address and credentials.\n    // You can configure a lot of other things, like pool limits\n    mysql::pool_params params;\n    params.server_address.emplace_host_and_port(server_hostname);\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Construct the pool.\n    // ctx will be used to create the connections and other I/O objects\n    mysql::connection_pool pool(ctx, std::move(params));\n    //]\n\n    //[tutorial_connection_pool_run\n    // You need to call async_run on the pool before doing anything useful with it.\n    // async_run creates connections and keeps them healthy. It must be called\n    // only once per pool.\n    // The detached completion token means that we don't want to be notified when\n    // the operation ends. It's similar to a no-op callback.\n    pool.async_run(asio::detached);\n    //]\n\n    //[tutorial_connection_pool_signals\n    // signal_set is an I/O object that allows waiting for signals\n    asio::signal_set signals(ctx, SIGINT, SIGTERM);\n\n    // Wait for signals\n    signals.async_wait([&](boost::system::error_code, int) {\n        // Stop the execution context. This will cause io_context::run to return\n        ctx.stop();\n    });\n    //]\n\n    // Launch our listener\n    asio::co_spawn(\n        ctx,\n        [&pool, listener_port] { return listener(pool, listener_port); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n    //]\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/1_tutorial/7_error_handling.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pfr.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_tutorial_error_handling\n\n/**\n * This tutorial adds error handling to the program in the previous tutorial.\n * It shows how to avoid exceptions and use diagnostics objects.\n *\n * It uses Boost.Pfr for reflection, which requires C++20.\n * You can backport it to C++14 if you need by using Boost.Describe.\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/as_tuple.hpp>\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/buffer.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/read.hpp>\n#include <boost/asio/signal_set.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/asio/write.hpp>\n#include <boost/endian/conversion.hpp>\n#include <boost/system/error_code.hpp>\n\n#include <cstdint>\n#include <exception>\n#include <iostream>\n#include <string>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n//[tutorial_error_handling_log_error\n// Log an error to std::cerr\nvoid log_error(const char* header, boost::system::error_code ec, const mysql::diagnostics& diag = {})\n{\n    // Inserting the error code only prints the number and category. Add the message, too.\n    std::cerr << header << \": \" << ec << \" \" << ec.message();\n\n    // client_message() contains client-side generated messages that don't\n    // contain user-input. This is usually embedded in exceptions.\n    // When working with error codes, we need to log it explicitly\n    if (!diag.client_message().empty())\n    {\n        std::cerr << \": \" << diag.client_message();\n    }\n\n    // server_message() contains server-side messages, and thus may\n    // contain user-supplied input. Printing it is safe.\n    if (!diag.server_message().empty())\n    {\n        std::cerr << \": \" << diag.server_message();\n    }\n\n    // Done\n    std::cerr << std::endl;\n}\n//]\n\n// Should contain a member for each field of interest present in our query\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n};\n\n// Encapsulates the database access logic.\n// Given an employee_id, retrieves the employee details to be sent to the client.\n//[tutorial_error_handling_db\nasio::awaitable<std::string> get_employee_details(mysql::connection_pool& pool, std::int64_t employee_id)\n{\n    // Will be populated with error information in case of error\n    mysql::diagnostics diag;\n\n    // Get a connection from the pool.\n    // This will wait until a healthy connection is ready to be used.\n    // ec is an error_code, conn is the mysql::pooled_connection\n    auto [ec, conn] = co_await pool.async_get_connection(diag, asio::as_tuple);\n    if (ec)\n    {\n        // A connection couldn't be obtained.\n        // This may be because a timeout happened.\n        log_error(\"Error in async_get_connection\", ec, diag);\n        co_return \"ERROR\";\n    }\n\n    // Use the connection normally to query the database.\n    mysql::static_results<mysql::pfr_by_name<employee>> result;\n    auto [ec2] = co_await conn->async_execute(\n        mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n        result,\n        diag,\n        asio::as_tuple\n    );\n    if (ec2)\n    {\n        log_error(\"Error running query\", ec2, diag);\n        co_return \"ERROR\";\n    }\n\n    // Compose the message to be sent back to the client\n    if (result.rows().empty())\n    {\n        co_return \"NOT_FOUND\";\n    }\n    else\n    {\n        const auto& emp = result.rows()[0];\n        co_return emp.first_name + ' ' + emp.last_name;\n    }\n\n    // When the pooled_connection is destroyed, the connection is returned\n    // to the pool, so it can be re-used.\n}\n//]\n\n//[tutorial_error_handling_session\nasio::awaitable<void> handle_session(mysql::connection_pool& pool, asio::ip::tcp::socket client_socket)\n{\n    // Enable the use of the \"s\" suffix for std::chrono::seconds\n    using namespace std::chrono_literals;\n\n    //[tutorial_error_handling_read_timeout\n    // Read the request from the client.\n    // async_read ensures that the 8-byte buffer is filled, handling partial reads.\n    // Error the read if it hasn't completed after 30 seconds.\n    unsigned char message[8]{};\n    auto [ec1, bytes_read] = co_await asio::async_read(\n        client_socket,\n        asio::buffer(message),\n        asio::cancel_after(30s, asio::as_tuple)\n    );\n    if (ec1)\n    {\n        // An error or a timeout happened.\n        log_error(\"Error reading from the socket\", ec1);\n        co_return;\n    }\n    //]\n\n    // Parse the 64-bit big-endian int into a native int64_t\n    std::int64_t employee_id = boost::endian::load_big_s64(message);\n\n    //[tutorial_error_handling_db_timeout\n    // Invoke the database handling logic.\n    // Apply an overall timeout of 20 seconds to the entire coroutine.\n    // Using asio::co_spawn allows us to pass a completion token, like asio::cancel_after.\n    // As other async operations, co_spawn's default completion token allows\n    // us to use co_await on its return value.\n    std::string response = co_await asio::co_spawn(\n        // Run the child coroutine using the same executor as this coroutine\n        co_await asio::this_coro::executor,\n\n        // The coroutine should run our database logic\n        [&pool, employee_id] { return get_employee_details(pool, employee_id); },\n\n        // Apply a timeout, and return an object that can be co_awaited.\n        // We don't use as_tuple here because we're already handling I/O errors\n        // inside get_employee_details. If an unexpected exception happens, propagate it.\n        asio::cancel_after(20s)\n    );\n    //]\n\n    // Write the response back to the client.\n    // async_write ensures that the entire message is written, handling partial writes.\n    // Set a timeout to the write operation, too.\n    auto [ec2, bytes_written] = co_await asio::async_write(\n        client_socket,\n        asio::buffer(response),\n        asio::cancel_after(30s, asio::as_tuple)\n    );\n    if (ec2)\n    {\n        log_error(\"Error writing to the socket\", ec2);\n        co_return;\n    }\n\n    // The socket's destructor will close the client connection\n}\n//]\n\nasio::awaitable<void> listener(mysql::connection_pool& pool, unsigned short port)\n{\n    // An object that accepts incoming TCP connections.\n    asio::ip::tcp::acceptor acc(co_await asio::this_coro::executor);\n\n    // The endpoint where the server will listen.\n    asio::ip::tcp::endpoint listening_endpoint(asio::ip::make_address(\"0.0.0.0\"), port);\n\n    // Open the acceptor\n    acc.open(listening_endpoint.protocol());\n\n    // Allow reusing the local address, so we can restart our server\n    // without encountering errors in bind\n    acc.set_option(asio::socket_base::reuse_address(true));\n\n    // Bind to the local address\n    acc.bind(listening_endpoint);\n\n    // Start listening for connections\n    acc.listen();\n    std::cout << \"Server listening at \" << acc.local_endpoint() << std::endl;\n\n    // Start the accept loop\n    while (true)\n    {\n        // Accept a new connection\n        auto [ec, sock] = co_await acc.async_accept(asio::as_tuple);\n        if (ec)\n        {\n            log_error(\"Error accepting connection\", ec);\n            co_return;\n        }\n\n        // Function implementing our session logic.\n        // Take ownership of the socket.\n        // Having this as a named variable workarounds a gcc bug\n        // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107288)\n        auto session_logic = [&pool, s = std::move(sock)]() mutable {\n            return handle_session(pool, std::move(s));\n        };\n\n        // Launch a coroutine that runs our session logic.\n        // We don't co_await this coroutine so we can listen\n        // to new connections while the session is running\n        asio::co_spawn(\n            // Use the same executor as the current coroutine\n            co_await asio::this_coro::executor,\n\n            // Session logic\n            std::move(session_logic),\n\n            // Will be called when the coroutine finishes\n            [](std::exception_ptr ptr) {\n                if (ptr)\n                {\n                    // For extra safety, log the exception but don't propagate it.\n                    // If we failed to anticipate an error condition that ends up raising an exception,\n                    // terminate only the affected session, instead of crashing the server.\n                    try\n                    {\n                        std::rethrow_exception(ptr);\n                    }\n                    catch (const std::exception& exc)\n                    {\n                        std::cerr << \"Uncaught error in a session: \" << exc.what() << std::endl;\n                    }\n                }\n            }\n        );\n    }\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <listener-port>\\n\";\n        exit(1);\n    }\n\n    const char* username = argv[1];\n    const char* password = argv[2];\n    const char* server_hostname = argv[3];\n    auto listener_port = static_cast<unsigned short>(std::stoi(argv[4]));\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // pool_params contains configuration for the pool.\n    // You must specify enough information to establish a connection,\n    // including the server address and credentials.\n    // You can configure a lot of other things, like pool limits\n    mysql::pool_params params;\n    params.server_address.emplace_host_and_port(server_hostname);\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Construct the pool.\n    // ctx will be used to create the connections and other I/O objects\n    mysql::connection_pool pool(ctx, std::move(params));\n\n    // You need to call async_run on the pool before doing anything useful with it.\n    // async_run creates connections and keeps them healthy. It must be called\n    // only once per pool.\n    // The detached completion token means that we don't want to be notified when\n    // the operation ends. It's similar to a no-op callback.\n    pool.async_run(asio::detached);\n\n    // signal_set is an I/O object that allows waiting for signals\n    asio::signal_set signals(ctx, SIGINT, SIGTERM);\n\n    // Wait for signals\n    signals.async_wait([&](boost::system::error_code, int) {\n        // Stop the execution context. This will cause io_context::run to return\n        ctx.stop();\n    });\n\n    // Launch our listener\n    asio::co_spawn(\n        ctx,\n        [&pool, listener_port] { return listener(pool, listener_port); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/batch_inserts.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n\n#include <functional>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_batch_inserts\n\n/**\n * This example demonstrates how to insert several records in a single\n * SQL statement using format_sql.\n *\n * The program reads a JSON file containing a list of employees\n * and inserts it into the employee table. It uses Boost.JSON and\n * Boost.Describe to parse the file.\n *\n * This example uses C++20 coroutines. If you need, you can backport\n * it to C++14 (required by Boost.Describe) by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/json/parse.hpp>\n#include <boost/json/value_to.hpp>\n\n#include <fstream>\n#include <iostream>\n#include <string>\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nnamespace json = boost::json;\n\n/**\n * We will use Boost.Describe to easily parse the JSON file\n * into a std::vector<employee>. The JSON file contain an array\n * of objects like the following:\n * {\n *     \"first_name\": \"Some string\",\n *     \"last_name\": \"Some other string\",\n *     \"company_id\": \"String\",\n *     \"salary\": 20000\n * }\n */\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n    std::string company_id;\n    std::int64_t salary;  // in dollars per year\n};\n\n// Adds reflection capabilities to employee. Required by the JSON parser.\n// Boost.Describe requires C++14\nBOOST_DESCRIBE_STRUCT(employee, (), (first_name, last_name, company_id, salary))\n\n// Reads a file into memory\nstatic std::string read_file(const char* file_name)\n{\n    std::ifstream ifs(file_name);\n    if (!ifs)\n        throw std::runtime_error(\"Cannot open file: \" + std::string(file_name));\n    return std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    const std::vector<employee>& employees\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // A function describing how to format a single employee object. Used with mysql::sequence.\n    auto format_employee_fn = [](const employee& emp, mysql::format_context_base& ctx) {\n        // format_context_base can be used to build query strings incrementally.\n        // Used internally by the sequence() formatter.\n        // format_sql_to expands a format string, replacing {} fields,\n        // and appends the result to the passed context.\n        // When formatted, strings are quoted and escaped as string literals.\n        // ints are formatted as number literals.\n        mysql::format_sql_to(\n            ctx,\n            \"({}, {}, {}, {})\",\n            emp.first_name,\n            emp.last_name,\n            emp.company_id,\n            emp.salary\n        );\n    };\n\n    // Compose and execute the batch INSERT. When passed to execute(), with_params\n    // replaces placeholders ({}) by actual parameter values before sending the query to the server.\n    // When inserting two employees, something like the following may be generated:\n    // INSERT INTO employee (first_name, last_name, company_id, salary)\n    //     VALUES ('John', 'Doe', 'HGS', 20000), ('Rick', 'Smith', 'LLC', 50000)\n    mysql::results result;\n    co_await conn.async_execute(\n        mysql::with_params(\n            \"INSERT INTO employee (first_name, last_name, company_id, salary) VALUES {}\",\n            mysql::sequence(std::ref(employees), format_employee_fn)\n        ),\n        result\n    );\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <input-file>\\n\";\n        exit(1);\n    }\n\n    // Read our JSON file into memory\n    auto contents = read_file(argv[4]);\n\n    // Parse the JSON. json::parse parses the string into a DOM,\n    // and json::value_to validates the JSON schema, parsing values into employee structures\n    auto values = json::value_to<std::vector<employee>>(json::parse(contents));\n\n    // We need one employee, at least\n    if (values.empty())\n    {\n        std::cerr << \"Input file should contain one employee, at least\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [&] { return coro_main(argv[3], argv[1], argv[2], values); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/batch_inserts_generic.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_batch_inserts_generic\n\n/**\n * This example demonstrates how to insert several records in a single\n * SQL statement using format_sql. The implementation is generic,\n * and can be reused to batch-insert any type T with Boost.Describe metadata.\n *\n * The program reads a JSON file containing a list of employees\n * and inserts it into the employee table. It uses Boost.JSON and\n * Boost.Describe to parse the file.\n *\n * This example uses C++20 coroutines. If you need, you can backport\n * it to C++14 (required by Boost.Describe) by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/describe/members.hpp>\n#include <boost/describe/modifiers.hpp>\n#include <boost/json/parse.hpp>\n#include <boost/json/value_to.hpp>\n#include <boost/mp11/list.hpp>\n#include <boost/mp11/tuple.hpp>\n\n#include <array>\n#include <cstddef>\n#include <fstream>\n#include <iostream>\n#include <string>\n#include <string_view>\n\nnamespace describe = boost::describe;\nnamespace mp11 = boost::mp11;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nnamespace json = boost::json;\n\n/**\n * An example Boost.Describe struct. Our code will work with any struct like this,\n * as long as it has metadata as provided by BOOST_DESCRIBE_STRUCT.\n * We will use this type as an example.\n */\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n    std::string company_id;\n    std::int64_t salary;  // in dollars per year\n};\nBOOST_DESCRIBE_STRUCT(employee, (), (first_name, last_name, company_id, salary))\n\n// Retrieves all public data members from a Boost.Describe struct, including inherited ones.\n// This is a Boost.Mp11 compatible type list.\ntemplate <class T>\nusing public_members = describe::describe_members<T, describe::mod_public | describe::mod_inherited>;\n\n// The number of public members of a Boost.Describe struct\ntemplate <class T>\nconstexpr std::size_t num_public_members = mp11::mp_size<public_members<T>>::value;\n\n// Gets the member names of a struct, as an array of strings.\n// For employee, generates\n// {\"first_name\", \"last_name\", \"company_id\", \"salary\"}\ntemplate <class T>\nconstexpr std::array<std::string_view, num_public_members<T>> get_field_names()\n{\n    return mp11::tuple_apply(\n        [](auto... descriptors) {\n            return std::array<std::string_view, num_public_members<T>>{{descriptors.name...}};\n        },\n        mp11::mp_rename<public_members<T>, std::tuple>()\n    );\n}\n\n// A formatting function that generates an insert field list for any struct T with\n// Boost.Describe metadata.\n// For example, employee{\"John\", \"Doe\", \"HGS\", 20000} generates the string\n// \"('John', 'Doe', 'HGS', 20000)\"\nstruct insert_struct_format_fn\n{\n    template <class T>\n    void operator()(const T& value, mysql::format_context_base& ctx) const\n    {\n        // Convert the struct into a std::array of formattable_ref\n        // formattable_ref is a view type that can hold any type that can be formatted\n        auto args = mp11::tuple_apply(\n            [&value](auto... descriptors) {\n                return std::array<mysql::formattable_ref, num_public_members<T>>{\n                    {value.*descriptors.pointer...}\n                };\n            },\n            mp11::mp_rename<public_members<T>, std::tuple>()\n        );\n\n        // Format them as a comma-separated sequence\n        mysql::format_sql_to(ctx, \"({})\", args);\n    }\n};\n\n// Reads a file into memory\nstd::string read_file(const char* file_name)\n{\n    std::ifstream ifs(file_name);\n    if (!ifs)\n        throw std::runtime_error(\"Cannot open file: \" + std::string(file_name));\n    return std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    const std::vector<employee>& employees\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Run the query. Placeholders ({}) will be expanded before the query is sent to the server.\n    // We use sequence() to format C++ ranges as comma-separated sequences.\n    mysql::results result;\n    co_await conn.async_execute(\n        mysql::with_params(\n            \"INSERT INTO employee ({::i}) VALUES {}\",\n            get_field_names<employee>(),\n            mysql::sequence(std::ref(employees), insert_struct_format_fn())\n        ),\n        result\n    );\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <input-file>\\n\";\n        exit(1);\n    }\n\n    // Read our JSON file into memory\n    auto contents = read_file(argv[4]);\n\n    // Parse the JSON. json::parse parses the string into a DOM,\n    // and json::value_to validates the JSON schema, parsing values into employee structures\n    auto values = json::value_to<std::vector<employee>>(json::parse(contents));\n\n    // We need one value to insert, at least\n    if (values.empty())\n    {\n        std::cerr << argv[0] << \": the JSON file should contain at least one employee\" << std::endl;\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [&] { return coro_main(argv[3], argv[1], argv[2], values); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/callbacks.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n//[example_callbacks\n\n/**\n * This example demonstrates how to use callbacks when using async functions.\n * This can be a good choice when targeting a standard lower than C++20.\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/io_context.hpp>\n#include <boost/system/error_code.hpp>\n\n#include <functional>\n#include <iostream>\n#include <memory>\n\n// When using callbacks, we usually employ error codes instead of exceptions.\nusing boost::system::error_code;\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// Prints a database employee to stdout\nvoid print_employee(mysql::row_view employee)\n{\n    std::cout << \"Employee '\" << employee.at(0) << \" \"   // first_name (string)\n              << employee.at(1) << \"' earns \"            // last_name  (string)\n              << employee.at(2) << \" dollars yearly\\n\";  // salary     (double)\n}\n\n// A session object, containing all variables that need to be kept alive for our session.\n// We will use a shared_ptr to ensure that all these variables are kept alive\n// until the last callback is executed\nclass session : public std::enable_shared_from_this<session>\n{\n    mysql::connect_params conn_params;  // MySQL credentials and other connection config\n    mysql::any_connection conn;         // Represents the connection to the MySQL server\n    mysql::results result;              // A result from a query\n    mysql::error_code final_error;      // Will be set in case of error\n    mysql::diagnostics diag;            // Will be populated with info about server errors\n    const char* company_id;             // The ID of the company whose employees we want to list. Untrusted.\npublic:\n    session(\n        asio::io_context& ctx,\n        const char* server_hostname,\n        const char* username,\n        const char* password,\n        const char* company_id\n    )\n        : conn(ctx), company_id(company_id)\n    {\n        conn_params.server_address.emplace_host_and_port(server_hostname);\n        conn_params.username = username;\n        conn_params.password = password;\n        conn_params.database = \"boost_mysql_examples\";\n    }\n\n    // Accessor for error information, so main can access it\n    error_code get_error() const { return final_error; }\n    const boost::mysql::diagnostics& get_diagnostics() const { return diag; }\n\n    // Initiates the callback chain\n    void start()\n    {\n        // Will call on_connect when the connect operation completes.\n        // The session object is kept alive with the shared_ptr that shared_from_this produces\n        conn.async_connect(\n            conn_params,\n            diag,\n            std::bind(&session::on_connect, shared_from_this(), std::placeholders::_1)\n        );\n    }\n\n    void on_connect(error_code ec)\n    {\n        // If there was an error, stop the callback chain\n        if (ec)\n        {\n            final_error = ec;\n            return;\n        }\n\n        // Initiate the query execution. company_id is an untrusted value.\n        // with_params will securely compose a SQL query and send it to the server for execution.\n        // Returned rows will be read into result.\n        // We use the callback chain + shared_ptr technique again\n        conn.async_execute(\n            mysql::with_params(\n                \"SELECT first_name, last_name, salary FROM employee WHERE company_id = {}\",\n                company_id\n            ),\n            result,\n            diag,\n            std::bind(&session::on_execute, shared_from_this(), std::placeholders::_1)\n        );\n    }\n\n    void on_execute(error_code ec)\n    {\n        // If there was an error, stop the callback chain\n        if (ec)\n        {\n            final_error = ec;\n            return;\n        }\n\n        // Print the rows returned by the query\n        for (boost::mysql::row_view employee : result.rows())\n        {\n            print_employee(employee);\n        }\n\n        // Notify the MySQL server we want to quit and then close the socket\n        conn.async_close(diag, std::bind(&session::finish, shared_from_this(), std::placeholders::_1));\n    }\n\n    void finish(error_code err) { final_error = err; }\n};\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4 && argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> [company-id]\\n\";\n        exit(1);\n    }\n\n    // The execution context, required to run I/O operations.\n    boost::asio::io_context ctx;\n\n    // The company_id whose employees we will be listing. This\n    // is user-supplied input, and should be treated as untrusted.\n    const char* company_id = argc == 5 ? argv[4] : \"HGS\";\n\n    // Create the session object and launch it\n    auto sess = std::make_shared<session>(ctx, argv[3], argv[1], argv[2], company_id);\n    sess->start();\n\n    // Run the callback chain until it completes\n    ctx.run();\n\n    // Check for errors\n    if (error_code ec = sess->get_error())\n    {\n        std::cerr << \"Error: \" << ec << \": \" << ec.message() << '\\n'\n                  << \"Server diagnostics: \" << sess->get_diagnostics().server_message() << std::endl;\n        exit(1);\n    }\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n"
  },
  {
    "path": "example/2_simple/coroutines_cpp11.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n//[example_coroutines_cpp11\n\n/**\n * This example demonstrates how to use stackful coroutines when using async functions.\n * This can be a good choice when targeting a standard lower than C++20.\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n * You need to link your program to Boost.Context to use asio::spawn.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/spawn.hpp>\n\n#include <iostream>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\nvoid print_employee(mysql::row_view employee)\n{\n    std::cout << \"Employee '\" << employee.at(0) << \" \"   // first_name (string)\n              << employee.at(1) << \"' earns \"            // last_name  (string)\n              << employee.at(2) << \" dollars yearly\\n\";  // salary     (double)\n}\n\n/**\n * The main coroutine. It will suspend every time we call one of the asynchronous functions, saving\n * all information it needs for resuming. When the asynchronous operation completes,\n * the coroutine will resume in the point it was left.\n * We need to pass the yield object to async functions for this to work.\n */\nvoid coro_main(\n    const char* server_hostname,\n    const char* username,\n    const char* password,\n    const char* company_id,\n    asio::yield_context yield\n)\n{\n    // Represents a connection to the MySQL server.\n    // The connection will use the same executor as the coroutine\n    mysql::any_connection conn(yield.get_executor());\n\n    // The hostname, username, password and database to use\n    mysql::connect_params conn_params;\n    conn_params.server_address.emplace_host_and_port(server_hostname);\n    conn_params.username = username;\n    conn_params.password = password;\n    conn_params.database = \"boost_mysql_examples\";\n\n    // Connect to server. with_diagnostics turns thrown exceptions\n    // into error_with_diagnostics, which contain more info than regular exceptions\n    conn.async_connect(conn_params, mysql::with_diagnostics(yield));\n\n    // Initiate the query execution. company_id is an untrusted value.\n    // with_params will securely compose a SQL query and send it to the server for execution.\n    // Returned rows will be read into result.\n    mysql::results result;\n    conn.async_execute(\n        mysql::with_params(\n            \"SELECT first_name, last_name, salary FROM employee WHERE company_id = {}\",\n            company_id\n        ),\n        result,\n        mysql::with_diagnostics(yield)\n    );\n\n    // Print the employees\n    for (boost::mysql::row_view employee : result.rows())\n    {\n        print_employee(employee);\n    }\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    conn.async_close(mysql::with_diagnostics(yield));\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4 && argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> [company-id]\\n\";\n        exit(1);\n    }\n\n    // The company_id whose employees we will be listing. This\n    // is user-supplied input, and should be treated as untrusted.\n    const char* company_id = argc == 5 ? argv[4] : \"HGS\";\n\n    // The execution context, required to run I/O operations.\n    asio::io_context ctx;\n\n    // Launch the coroutine\n    asio::spawn(\n        ctx,\n        [argv, company_id](asio::yield_context yield) {\n            coro_main(argv[3], argv[1], argv[2], company_id, yield);\n        },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // You will only get this type of exceptions if you use with_diagnostics.\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n"
  },
  {
    "path": "example/2_simple/deletes.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_deletes\n\n/**\n * This example demonstrates how to use DELETE statements\n * and the results::affected_rows() function.\n *\n * The program deletes an employee, given their ID,\n * and prints whether the deletion was successful.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <cstdint>\n#include <iostream>\n#include <string>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::int64_t employee_id\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The server host, username, password and database to use.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = std::move(username);\n    params.password = std::move(password);\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Perform the deletion.\n    mysql::results result;\n    co_await conn.async_execute(\n        mysql::with_params(\"DELETE FROM employee WHERE id = {}\", employee_id),\n        result\n    );\n\n    // affected_rows() returns the number of rows that were affected\n    // by the executed statement. If there was an affected row, the deletion was successful.\n    // Note that this may not work for UPDATEs, as they may match but not affected some rows.\n    if (result.affected_rows() != 0u)\n    {\n        std::cout << \"Deletion successful\\n\";\n    }\n    else\n    {\n        std::cout << \"No employee with such ID\\n\";\n    }\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <employee-id>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2], std::stoi(argv[4])); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/disable_tls.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_disable_tls\n\n/**\n * This example demonstrates how to disable TLS when connecting to MySQL.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <iostream>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    //[section_connection_establishment_disable_tls\n    // The server host, username, password and database to use.\n    // Passing ssl_mode::disable will disable the use of TLS.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = std::move(username);\n    params.password = std::move(password);\n    params.database = \"boost_mysql_examples\";\n    params.ssl = mysql::ssl_mode::disable;\n    //]\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // The connection can now be used normally\n    mysql::results result;\n    co_await conn.async_execute(\"SELECT 'Hello world!'\", result);\n    std::cout << result.rows().at(0).at(0) << std::endl;\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/dynamic_filters.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_dynamic_filters\n\n/**\n * This example implements a dynamic filter using client-side SQL.\n * If you're implementing a filter with many options that can be\n * conditionally enabled, this pattern may be useful for you.\n *\n * This example uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/sequence.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <cassert>\n#include <iomanip>\n#include <iostream>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <vector>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// Prints an employee row to stdout\nvoid print_employee(mysql::row_view employee)\n{\n    std::cout << \"id: \" << employee.at(0)                             // field 0: id\n              << \", first_name: \" << std::setw(16) << employee.at(1)  // field 1: first_name\n              << \", last_name: \" << std::setw(16) << employee.at(2)   // field 2: last_name\n              << \", company_id: \" << employee.at(3)                   // field 3: company_id\n              << \", salary: \" << employee.at(4) << '\\n';              // field 4: salary\n}\n\n// An operator to use in a filter\nenum class op_type\n{\n    lt,   // <\n    lte,  // <=\n    eq,   // =\n    gt,   // >\n    gte,  // >=\n};\n\n// Returns the SQL operator for the given op_type\nstd::string_view op_type_to_sql(op_type value)\n{\n    switch (value)\n    {\n    case op_type::lt: return \"<\";\n    case op_type::lte: return \"<=\";\n    case op_type::eq: return \"=\";\n    case op_type::gte: return \">=\";\n    case op_type::gt: return \">\";\n    default: assert(false); return \"=\";\n    }\n}\n\n// An individual filter to apply.\n// For example, filter{\"salary\", op_type::gt, field_view(20000)} should generate a\n// `salary` > 20000 condition\nstruct filter\n{\n    std::string_view field_name;    // The database column name\n    op_type op;                     // The operator to apply\n    mysql::field_view field_value;  // The value to check. field_view can hold any MySQL type\n};\n\n// Command line arguments\nstruct cmdline_args\n{\n    // MySQL username to use during authentication.\n    std::string_view username;\n\n    // MySQL password to use during authentication.\n    std::string_view password;\n\n    // Hostname where the MySQL server is listening.\n    std::string_view server_hostname;\n\n    // The filters to apply\n    std::vector<filter> filts;\n\n    // If order_by.has_value(), order employees using the given field\n    std::optional<std::string_view> order_by;\n};\n\n// Parses the command line\nstatic cmdline_args parse_cmdline_args(int argc, char** argv)\n{\n    // Available options\n    constexpr std::string_view company_id_prefix = \"--company-id=\";\n    constexpr std::string_view first_name_prefix = \"--first-name=\";\n    constexpr std::string_view last_name_prefix = \"--last-name=\";\n    constexpr std::string_view min_salary_prefix = \"--min-salary=\";\n    constexpr std::string_view order_by_prefix = \"--order-by=\";\n\n    // Helper function to print the usage message and exit\n    auto print_usage_and_exit = [argv]() {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> [filters]\\n\";\n        exit(1);\n    };\n\n    // Check number of arguments\n    if (argc <= 4)\n        print_usage_and_exit();\n\n    // Parse the required arguments\n    cmdline_args res;\n    res.username = argv[1];\n    res.password = argv[2];\n    res.server_hostname = argv[3];\n\n    // Parse the filters\n    for (int i = 4; i < argc; ++i)\n    {\n        std::string_view arg = argv[i];\n\n        // Attempt to match the argument against each prefix\n        if (arg.starts_with(company_id_prefix))\n        {\n            auto value = arg.substr(company_id_prefix.size());\n            res.filts.push_back({\"company_id\", op_type::eq, mysql::field_view(value)});\n        }\n        else if (arg.starts_with(first_name_prefix))\n        {\n            auto value = arg.substr(first_name_prefix.size());\n            res.filts.push_back({\"first_name\", op_type::eq, mysql::field_view(value)});\n        }\n        else if (arg.starts_with(last_name_prefix))\n        {\n            auto value = arg.substr(last_name_prefix.size());\n            res.filts.push_back({\"last_name\", op_type::eq, mysql::field_view(value)});\n        }\n        else if (arg.starts_with(min_salary_prefix))\n        {\n            auto value = std::stod(std::string(arg.substr(min_salary_prefix.size())));\n            res.filts.push_back({\"salary\", op_type::gte, mysql::field_view(value)});\n        }\n        else if (arg.starts_with(order_by_prefix))\n        {\n            auto field_name = arg.substr(order_by_prefix.size());\n\n            // For security, validate the passed field against a set of whitelisted fields\n            if (field_name != \"id\" && field_name != \"first_name\" && field_name != \"last_name\" &&\n                field_name != \"salary\")\n            {\n                std::cerr << \"Order-by: invalid field \" << field_name << std::endl;\n                print_usage_and_exit();\n            }\n            res.order_by = field_name;\n        }\n        else\n        {\n            std::cerr << \"Unrecognized option: \" << arg << std::endl;\n            print_usage_and_exit();\n        }\n    }\n\n    // We should have at least one filter\n    if (res.filts.empty())\n    {\n        std::cerr << \"At least one filter should be specified\" << std::endl;\n        print_usage_and_exit();\n    }\n\n    return res;\n}\n\n// Composes a SELECT query to retrieve employees according to the passed filters.\n// We allow an optional ORDER BY clause that must be added dynamically,\n// so we can't express our query as a single format string.\n// This function uses format_sql_to to build a query string incrementally.\n// format_sql_to requires us to pass a format_options value, containing configuration\n// options like the current character set. Use any_connection::format_opts to obtain it.\n// If your use case allows you to express your query as a single format string, use with_params, instead.\nstd::string compose_get_employees_query(\n    mysql::format_options opts,\n    const std::vector<filter>& filts,\n    std::optional<std::string_view> order_by\n)\n{\n    // A format context allows composing queries incrementally.\n    // This is required because we need to add the ORDER BY clause conditionally\n    mysql::format_context ctx(opts);\n\n    // Adds an individual filter to the context. Used by sequence()\n    auto filter_format_fn = [](filter item, mysql::format_context_base& elm_ctx) {\n        // {:i} formats a string as a SQL identifier. {:r} outputs raw SQL.\n        // filter{\"key\", op_type::eq, field_view(42)} would get formatted as \"`key` = 42\"\n        mysql::format_sql_to(\n            elm_ctx,\n            \"{:i} {:r} {}\",\n            item.field_name,\n            op_type_to_sql(item.op),\n            item.field_value\n        );\n    };\n\n    // Add the query with the filters to ctx.\n    // sequence() will invoke filter_format_fn for each element in filts,\n    // using the string \" AND \" as glue, to separate filters\n    // By default, sequence copies its input range, but we don't need this here,\n    // so we disable the copy by calling ref()\n    mysql::format_sql_to(\n        ctx,\n        \"SELECT id, first_name, last_name, company_id, salary FROM employee WHERE {}\",\n        mysql::sequence(std::ref(filts), filter_format_fn, \" AND \")\n    );\n\n    // Add the order by\n    if (order_by)\n    {\n        // identifier formats a string as a SQL identifier, instead of a string literal.\n        // For instance, this may generate \"ORDER BY `first_name`\"\n        mysql::format_sql_to(ctx, \" ORDER BY {:i}\", *order_by);\n    }\n\n    // Get our generated query. get() returns a system::result<std::string>, which\n    // will contain errors if any of the args couldn't be formatted. This can happen\n    // if you pass string values containing invalid UTF-8.\n    // value() will throw an exception if that's the case.\n    return std::move(ctx).get().value();\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(const cmdline_args& args)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(args.server_hostname));\n    params.username = args.username;\n    params.password = args.password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Compose the query. format_opts() returns a system::result<format_options>,\n    // containing the options required by format_context. format_opts() may return\n    // an error if the connection doesn't know which character set is using -\n    // use async_set_character_set if this happens.\n    std::string query = compose_get_employees_query(conn.format_opts().value(), args.filts, args.order_by);\n\n    // Execute the query as usual. Note that the query was generated\n    // client-side. Appropriately using format_sql_to makes this approach secure.\n    // with_params uses this same technique under the hood.\n    // Casting to string_view saves a copy in async_execute\n    mysql::results result;\n    co_await conn.async_execute(std::string_view(query), result);\n\n    // Print the employees\n    for (mysql::row_view employee : result.rows())\n    {\n        print_employee(employee);\n    }\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    // Parse the command line\n    cmdline_args args = parse_cmdline_args(argc, argv);\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [&] { return coro_main(args); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // You will only get this type of exceptions if you use with_diagnostics.\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's encoding\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/inserts.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_inserts\n\n/**\n * This example demonstrates how to use INSERT statements,\n * the results::last_insert_id() function, and optionals\n * to represent potentially NULL values.\n *\n * The program inserts an employee, given their first name,\n * last name and company ID. It then prints the ID of the newly\n * inserted employee.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <cstdint>\n#include <iostream>\n#include <optional>\n#include <string>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::string_view first_name,\n    std::string_view last_name,\n    std::string_view company_id,\n    std::optional<std::uint32_t> salary  // empty optional means that a NULL value should be inserted\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The server host, username, password and database to use.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = std::move(username);\n    params.password = std::move(password);\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Perform the insertion.\n    // If salary is empty, the last {} will be replaced by NULL.\n    mysql::results result;\n    co_await conn.async_execute(\n        mysql::with_params(\n            \"INSERT INTO employee (first_name, last_name, company_id, salary) VALUES ({}, {}, {}, {})\",\n            first_name,\n            last_name,\n            company_id,\n            salary\n        ),\n        result\n    );\n\n    // results::last_insert_id retrieves the value of the latest\n    // AUTO_INCREMENT field generated by the executed query, if any.\n    // In this case, this is the generated employee_id.\n    // If we needed the entire generated employee, we'd need a transaction\n    // and multi-queries.\n    std::cout << \"Successfully created employee with ID: \" << result.last_insert_id() << std::endl;\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc < 7 || argc > 8)\n    {\n        std::cerr\n            << \"Usage: \" << argv[0]\n            << \" <username> <password> <server-hostname> <first-name> <last-name> <company-id> [<salary>]\\n\";\n        exit(1);\n    }\n\n    // In DB, salary is an UNSIGNED INT (32-bit) representing employee salary in USD\n    // It may be NULL (e.g. for contractors).\n    // Parse the command line argument, if present, and validate it's within a sane range\n    std::optional<std::uint32_t> salary;\n    if (argc == 8)\n    {\n        int parsed_salary = std::stoi(argv[7]);\n        if (parsed_salary < 10000 || parsed_salary >= 1000000)\n        {\n            std::cerr << \"Salary should be between 10000 and 1000000\\n\";\n            exit(1);\n        }\n        salary = static_cast<std::uint32_t>(parsed_salary);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2], argv[4], argv[5], argv[6], salary); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/metadata.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_metadata\n\n/**\n * This example shows how to obtain metadata from SQL queries,\n * including field and table names.\n *\n * This example uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <iostream>\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // By default, string metadata (like column names) won't be retained.\n    // This is for efficiency reasons. You can change this setting by calling\n    // connection::set_meta_mode. It will affect any subsequent queries and statement executions.\n    conn.set_meta_mode(mysql::metadata_mode::full);\n\n    // The socket path, username, password and database to use.\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Issue the query\n    constexpr const char* sql = R\"(\n        SELECT comp.name AS company_name, emp.id AS employee_id\n        FROM employee emp\n        JOIN company comp ON (comp.id = emp.company_id)\n    )\";\n    mysql::results result;\n    co_await conn.async_execute(sql, result);\n\n    /**\n     * results objects allow you to access metadata about the columns in the query\n     * using the meta() function, which returns span-like object containing metadata objects\n     * (one per column in the query, and in the same order as in the query).\n     * You can retrieve the column name, type, number of decimals,\n     * suggested display width, whether the column is part of a key...\n     * These metadata objects are owned by the results object.\n     */\n    assert(result.meta().size() == 2);\n\n    // <-\n    // clang-format off\n    // ->\n    const mysql::metadata& company_name = result.meta()[0];\n    assert(company_name.database() == \"boost_mysql_examples\");  // database name\n    assert(company_name.table() == \"comp\");  // the alias we assigned to the table in the query\n    assert(company_name.original_table() == \"company\");   // the original table name\n    assert(company_name.column_name() == \"company_name\");  // the name of the column in the query\n    assert(company_name.original_column_name() == \"name\");  // the name of the physical column in the table\n    assert(company_name.type() == boost::mysql::column_type::varchar);  // we created the column as a VARCHAR\n    assert(!company_name.is_primary_key());     // column is not a primary key\n    assert(!company_name.is_auto_increment());  // column is not AUTO_INCREMENT\n    assert(company_name.is_not_null());         // column may not be NULL\n\n    const mysql::metadata& employee_id = result.meta()[1];\n    assert(employee_id.database() == \"boost_mysql_examples\");  // database name\n    assert(employee_id.table() == \"emp\");  // the alias we assigned to the table in the query\n    assert(employee_id.original_table() == \"employee\");  // the original table name\n    assert(employee_id.column_name() == \"employee_id\");   // the name of the column in the query\n    assert(employee_id.original_column_name() == \"id\");  // the name of the physical column in the table\n    assert(employee_id.type() == boost::mysql::column_type::int_);  // we created the column as INT\n    assert(employee_id.is_primary_key()); // column is a primary key\n    assert(employee_id.is_auto_increment()); // we declared the column as AUTO_INCREMENT\n    assert(employee_id.is_not_null()); // column cannot be NULL\n    // <-\n    // clang-format on\n    // avoid warnings in release mode\n    static_cast<void>(company_name);\n    static_cast<void>(employee_id);\n    // ->\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/multi_function.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_multi_function\n\n/**\n * This example demonstrates how to run multi-function operations\n * to dump an entire table to stdout, reading rows in batches.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/this_coro.hpp>\n\n#include <iostream>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\nvoid print_employee(mysql::row_view employee)\n{\n    std::cout << \"Employee '\" << employee.at(0) << \" \"   // first_name (string)\n              << employee.at(1) << \"' earns \"            // last_name  (string)\n              << employee.at(2) << \" dollars yearly\\n\";  // salary     (double)\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password\n)\n{\n    // Create a connection. It will use the same executor as our coroutine\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Start our query as a multi-function operation.\n    // This will send the query for execution but won't read the rows.\n    // An execution_state keep tracks of the operation.\n    mysql::execution_state st;\n    co_await conn.async_start_execution(\"SELECT first_name, last_name, salary FROM employee\", st);\n\n    // st.should_read_rows() returns true while there are more rows to read.\n    // Use async_read_some_rows to read a batch of rows.\n    // This function tries to minimize copies. employees is a view\n    // object pointing into the connection's internal buffers,\n    // and is valid until you start the next async operation.\n    while (st.should_read_rows())\n    {\n        mysql::rows_view employees = co_await conn.async_read_some_rows(st);\n        for (auto employee : employees)\n            print_employee(employee);\n    }\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif"
  },
  {
    "path": "example/2_simple/patch_updates.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_patch_updates\n\n/**\n * This example demonstrates how to implement dynamic updates\n * with PATCH-like semantics using client-side SQL formatting.\n *\n * The program updates an employee by ID, modifying fields\n * as provided by command-line arguments, and leaving all other\n * fields unmodified.\n *\n * This example uses C++20 coroutines. If you need, you can backport\n * it to C++14 (required by Boost.Describe) by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <cstdint>\n#include <iostream>\n#include <string>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n/**\n * Represents a single update as a name, value pair.\n * The idea is to use command-line arguments to compose\n * a std::vector<update_field> with the fields to be updated,\n * and use mysql::sequence() to join these with commas\n */\nstruct update_field\n{\n    // The field name to set (i.e. the column name)\n    std::string_view field_name;\n\n    // The value to set the field to. Recall that field_view is\n    // a variant-like type that can hold all types that MySQL supports.\n    mysql::field_view field_value;\n};\n\n// Contains the parsed command-line arguments\nstruct cmdline_args\n{\n    // MySQL username to use during authentication.\n    std::string_view username;\n\n    // MySQL password to use during authentication.\n    std::string_view password;\n\n    // Hostname where the MySQL server is listening.\n    std::string_view server_hostname;\n\n    // The ID of the employee we want to update.\n    std::int64_t employee_id{};\n\n    // A list of name, value pairs containing the employee fields to update.\n    std::vector<update_field> updates;\n};\n\n// Parses the command line arguments, calling exit on failure.\nstatic cmdline_args parse_cmdline_args(int argc, char** argv)\n{\n    // Available options\n    constexpr std::string_view company_id_prefix = \"--company-id=\";\n    constexpr std::string_view first_name_prefix = \"--first-name=\";\n    constexpr std::string_view last_name_prefix = \"--last-name=\";\n    constexpr std::string_view salary_prefix = \"--salary=\";\n\n    // Helper function to print the usage message and exit\n    auto print_usage_and_exit = [argv]() {\n        std::cerr << \"Usage: \" << argv[0]\n                  << \" <username> <password> <server-hostname> employee_id [updates]\\n\";\n        exit(1);\n    };\n\n    // Check number of arguments\n    if (argc <= 5)\n        print_usage_and_exit();\n\n    // Parse the required arguments\n    cmdline_args res;\n    res.username = argv[1];\n    res.password = argv[2];\n    res.server_hostname = argv[3];\n    res.employee_id = std::stoll(argv[4]);\n\n    // Parse the requested updates\n    for (int i = 5; i < argc; ++i)\n    {\n        // Get the argument\n        std::string_view arg = argv[i];\n\n        // Attempt to match it with the options we have\n        if (arg.starts_with(company_id_prefix))\n        {\n            std::string_view new_value = arg.substr(company_id_prefix.size());\n            res.updates.push_back(update_field{\"company_id\", mysql::field_view(new_value)});\n        }\n        else if (arg.starts_with(first_name_prefix))\n        {\n            std::string_view new_value = arg.substr(first_name_prefix.size());\n            res.updates.push_back(update_field{\"first_name\", mysql::field_view(new_value)});\n        }\n        else if (arg.starts_with(last_name_prefix))\n        {\n            std::string_view new_value = arg.substr(last_name_prefix.size());\n            res.updates.push_back(update_field{\"last_name\", mysql::field_view(new_value)});\n        }\n        else if (arg.starts_with(salary_prefix))\n        {\n            double new_value = std::stod(std::string(arg.substr(salary_prefix.size())));\n            res.updates.push_back(update_field{\"salary\", mysql::field_view(new_value)});\n        }\n        else\n        {\n            std::cerr << \"Unrecognized option: \" << arg << std::endl;\n            print_usage_and_exit();\n        }\n    }\n\n    // There should be one update, at least\n    if (res.updates.empty())\n    {\n        std::cerr << \"There should be one update, at least\\n\";\n        print_usage_and_exit();\n    }\n\n    return res;\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(const cmdline_args& args)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(args.server_hostname));\n    params.username = args.username;\n    params.password = std::string(args.password);\n    params.database = \"boost_mysql_examples\";\n    params.multi_queries = true;\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Formats an individual update. Used by sequence().\n    // For update_field{\"first_name\", \"John\"}, it generates the string\n    // \"`first_name` = 'John'\"\n    // Format contexts can build a query string incrementally, and are used by sequence() internally\n    auto update_format_fn = [](update_field upd, mysql::format_context_base& ctx) {\n        mysql::format_sql_to(ctx, \"{:i} = {}\", upd.field_name, upd.field_value);\n    };\n\n    // Compose and execute the query. with_params will expand placeholders\n    // before sending the query to the server.\n    // We use sequence() to output the update list separated by commas.\n    // We want to update the employee and then retrieve it. MySQL doesn't support\n    // the UPDATE ... RETURNING statement to update and retrieve data atomically,\n    // so we will use a transaction to guarantee consistency.\n    // Instead of running every statement separately, we activated params.multi_queries,\n    // which allows semicolon-separated statements.\n    // As in std::format, we can use explicit indices like {0} and {1} to reference arguments.\n    // By default, sequence copies its input range, but we don't need this here,\n    // so we disable the copy by calling ref()\n    mysql::results result;\n    co_await conn.async_execute(\n        mysql::with_params(\n            \"START TRANSACTION; \"\n            \"UPDATE employee SET {0} WHERE id = {1}; \"\n            \"SELECT first_name, last_name, salary, company_id FROM employee WHERE id = {1}; \"\n            \"COMMIT\",\n            mysql::sequence(std::ref(args.updates), update_format_fn),\n            args.employee_id\n        ),\n        result\n    );\n\n    // We ran 4 queries, so the results object will hold 4 resultsets.\n    // Get the rows retrieved by the SELECT (the 3rd one).\n    auto rws = result.at(2).rows();\n\n    // If there are no rows, the given employee does not exist.\n    if (rws.empty())\n    {\n        std::cerr << \"employee_id=\" << args.employee_id << \" not found\" << std::endl;\n        exit(1);\n    }\n\n    // Print the updated employee.\n    const auto employee = rws.at(0);\n    std::cout << \"Updated employee with id=\" << args.employee_id << \":\\n\"\n              << \"  first_name: \" << employee.at(0) << \"\\n  last_name: \" << employee.at(1)\n              << \"\\n  salary: \" << employee.at(2) << \"\\n  company_id: \" << employee.at(3) << std::endl;\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    // Parse the command line\n    cmdline_args args = parse_cmdline_args(argc, argv);\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [&] { return coro_main(args); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's encoding\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/pipeline.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_pipeline\n\n/**\n * (EXPERIMENTAL)\n * This example demonstrates how to use the pipeline API to prepare,\n * execute and close statements in batch.\n * Pipelines are a experimental API.\n *\n * This example uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks or asio::yield_context.\n * Timeouts can't be used with sync functions.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <array>\n#include <iostream>\n#include <span>\n#include <vector>\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\n\n// Prepare several statements in batch.\n// This is faster than preparing them one by one, as it saves round-trips to the server.\nasio::awaitable<std::vector<mysql::statement>> batch_prepare(\n    mysql::any_connection& conn,\n    std::span<const std::string_view> statements\n)\n{\n    // Construct a pipeline request describing the work to be performed.\n    // There must be one prepare_statement_stage per statement to prepare\n    mysql::pipeline_request req;\n    for (auto stmt_sql : statements)\n        req.add_prepare_statement(stmt_sql);\n\n    // Run the pipeline.\n    // stage_response is a variant-like type that can hold the response of any stage type.\n    std::vector<mysql::stage_response> pipe_res;\n    co_await conn.async_run_pipeline(req, pipe_res);\n\n    // If we got here, all statements were prepared successfully.\n    // pipe_res contains as many elements as statements.size(), holding statement objects\n    // Extract them into a vector\n    std::vector<mysql::statement> res;\n    res.reserve(statements.size());\n    for (const auto& stage_res : pipe_res)\n        res.push_back(stage_res.get_statement());\n    co_return res;\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::string_view company_id\n)\n{\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to server\n    co_await conn.async_connect(params);\n\n    // Prepare the statements using the batch prepare function that we previously defined\n    const std::array<std::string_view, 2> stmt_sql{\n        \"INSERT INTO employee (company_id, first_name, last_name) VALUES (?, ?, ?)\",\n        \"INSERT INTO audit_log (msg) VALUES (?)\"\n    };\n    std::vector<mysql::statement> stmts = co_await batch_prepare(conn, stmt_sql);\n\n    // Create a pipeline request to execute them.\n    // Warning: do NOT include the COMMIT statement in this pipeline.\n    // COMMIT must only be executed if all the previous statements succeeded.\n    // In a pipeline, all stages get executed, regardless of the outcome of previous stages.\n    // We say that COMMIT has a dependency on the result of previous stages.\n    mysql::pipeline_request req;\n    req.add_execute(\"START TRANSACTION\")\n        .add_execute(stmts.at(0), company_id, \"Juan\", \"Lopez\")\n        .add_execute(stmts.at(0), company_id, \"Pepito\", \"Rodriguez\")\n        .add_execute(stmts.at(0), company_id, \"Someone\", \"Random\")\n        .add_execute(stmts.at(1), \"Inserted 3 new emplyees\");\n    std::vector<mysql::stage_response> res;\n\n    // Execute the pipeline\n    co_await conn.async_run_pipeline(req, res);\n\n    // If we got here, all stages executed successfully.\n    // Since they were execution stages, the response contains a results object.\n    // Get the IDs of the newly created employees\n    auto id1 = res.at(1).as_results().last_insert_id();\n    auto id2 = res.at(2).as_results().last_insert_id();\n    auto id3 = res.at(3).as_results().last_insert_id();\n\n    // We can now commit our transaction and close the statements.\n    // Clear the request and populate it again\n    req.clear();\n    req.add_execute(\"COMMIT\").add_close_statement(stmts.at(0)).add_close_statement(stmts.at(1));\n\n    // Run it\n    co_await conn.async_run_pipeline(req, res);\n\n    // If we got here, our insertions got committed.\n    std::cout << \"Inserted employees: \" << id1 << \", \" << id2 << \", \" << id3 << std::endl;\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <company-id>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2], argv[4]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/2_simple/prepared_statements.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_prepared_statements\n\n/**\n * This example demonstrates how to prepare, execute\n * and deallocate prepared statements. This program retrieves\n * all employees in a company, given its ID.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/this_coro.hpp>\n\n#include <iostream>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\nvoid print_employee(mysql::row_view employee)\n{\n    std::cout << \"Employee '\" << employee.at(0) << \" \"   // first_name (string)\n              << employee.at(1) << \"' earns \"            // last_name  (string)\n              << employee.at(2) << \" dollars yearly\\n\";  // salary     (double)\n}\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password,\n    std::string_view company_id\n)\n{\n    // Create a connection. It will use the same executor as our coroutine\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n\n    // Prepared statements can be used to execute queries with untrusted\n    // parameters securely. They are an option to mysql::with_params,\n    // but work server-side.\n    // They are more complex but can yield more efficiency when retrieving\n    // lots of numeric data, or when executing the same query several times with the same parameters.\n    // Ask the server to prepare a statement and retrieve its handle\n    mysql::statement stmt = co_await conn.async_prepare_statement(\n        \"SELECT first_name, last_name, salary FROM employee WHERE company_id = ?\"\n    );\n\n    // Execute the statement. bind() must be passed as many parameters (number of ?)\n    // as the statement has. bind() packages the statement handle with the parameters,\n    // and async_execute sends them to the server\n    mysql::results result;\n    co_await conn.async_execute(stmt.bind(company_id), result);\n    for (mysql::row_view employee : result.rows())\n        print_employee(employee);\n\n    // We can execute stmt as many times as we want, potentially with different\n    // parameters, without the need to re-prepare it.\n\n    // Once we're done with a statement, we can close it, to deallocate it from the server.\n    // Closing the connection will also deallocate active statements, so this is not\n    // strictly required here, but it's shown for completeness.\n    // This can be relevant if you're using long-lived sessions.\n    // Note that statement's destructor does NOT close the statement.\n    co_await conn.async_close_statement(stmt);\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <company-id>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2], argv[4]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif"
  },
  {
    "path": "example/2_simple/source_script.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n//[example_source_script\n\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/tcp_ssl.hpp>\n\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/system/system_error.hpp>\n\n#include <fstream>\n#include <iostream>\n#include <stdexcept>\n#include <string>\n\n/**\n * This example runs all command in a .sql file, using multi-queries.\n * Note that special commands that are handled by the mysql command line tool\n * (like DELIMITER) won't work.\n *\n * For this example, we will be using the 'boost_mysql_examples' database.\n * You can get this database by running db_setup.sql.\n * This example assumes you are connecting to a localhost MySQL server.\n *\n * This example uses synchronous functions and handles errors using exceptions.\n */\n\n// Reads a file into memory\nstd::string read_file(const char* file_name)\n{\n    std::ifstream ifs(file_name);\n    if (!ifs)\n        throw std::runtime_error(\"Cannot open file: \" + std::string(file_name));\n    return std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());\n}\n\nvoid print_column_names(boost::mysql::metadata_collection_view meta_collection)\n{\n    if (meta_collection.empty())\n        return;\n\n    bool is_first = true;\n    for (auto meta : meta_collection)\n    {\n        if (!is_first)\n        {\n            std::cout << \" | \";\n        }\n        is_first = false;\n        std::cout << meta.column_name();\n    }\n    std::cout << \"\\n-----------------\\n\";\n}\n\nvoid print_row(boost::mysql::row_view row)\n{\n    bool is_first = true;\n    for (auto field : row)\n    {\n        if (!is_first)\n        {\n            std::cout << \" | \";\n        }\n        is_first = false;\n        std::cout << field;\n    }\n    std::cout << '\\n';\n}\n\nvoid print_ok(const boost::mysql::execution_state& st)\n{\n    std::cout << \"Affected rows: \" << st.affected_rows()\n              << \"\\n\"\n                 \"Last insert ID: \"\n              << st.last_insert_id()\n              << \"\\n\"\n                 \"Warnings: \"\n              << st.warning_count() << \"\\n\\n\"\n              << std::flush;\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname> <path-to-script>\\n\";\n        exit(1);\n    }\n\n    // Read the script file into memory\n    std::string script_contents = read_file(argv[4]);\n\n    // Set up the io_context, SSL context and connection required to\n    // connect to the server.\n    boost::asio::io_context ctx;\n    boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);\n    boost::mysql::tcp_ssl_connection conn(ctx.get_executor(), ssl_ctx);\n\n    // Resolve the server hostname to get a collection of endpoints\n    boost::asio::ip::tcp::resolver resolver(ctx.get_executor());\n    auto endpoints = resolver.resolve(argv[3], boost::mysql::default_port_string);\n\n    // The username, password and database to use\n    boost::mysql::handshake_params params(\n        argv[1],                // username\n        argv[2],                // password\n        \"boost_mysql_examples\"  // database\n    );\n\n    // We're going to use multi-queries, which enables passing the server\n    // a set of semicolon-separated queries. We need to explicitly enable support for it.\n    params.set_multi_queries(true);\n\n    // We'll be using metadata strings to print column names, so we need to enable support for it\n    conn.set_meta_mode(boost::mysql::metadata_mode::full);\n\n    // Connect to the server using the first endpoint returned by the resolver\n    conn.connect(*endpoints.begin(), params);\n\n    // The executed commands may generate a lot of output, so we're going to\n    // use multi-function operations (i.e. start_execution) to read it in batches.\n    boost::mysql::execution_state st;\n    conn.start_execution(script_contents, st);\n\n    // The main read loop. Each executed command will yield a resultset.\n    // st.comoplete() returns true once all resultsets have been read.\n    for (std::size_t resultset_number = 0; !st.complete(); ++resultset_number)\n    {\n        // Advance to next resultset, if required\n        if (st.should_read_head())\n        {\n            conn.read_resultset_head(st);\n        }\n\n        // Print the name of the fields\n        std::cout << \"Resultset number \" << resultset_number << \"\\n\";\n        print_column_names(st.meta());\n\n        // Read the rows and print them\n        while (st.should_read_rows())\n        {\n            boost::mysql::rows_view batch = conn.read_some_rows(st);\n            for (auto row : batch)\n            {\n                print_row(row);\n            }\n        }\n\n        // Print OK packet data\n        print_ok(st);\n    }\n\n    // Close the connection\n    conn.close();\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n"
  },
  {
    "path": "example/2_simple/tls_certificate_verification.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[example_tls_certificate_verification\n\n/**\n * This example demonstrates how to set up TLS certificate verification\n * and, more generally, how to pass custom TLS options to any_connection.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n *\n * This example uses the 'boost_mysql_examples' database, which you\n * can get by running db_setup.sql.\n * Additionally, your server must be configured with a trusted certificate\n * with a common name of \"mysql\".\n */\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/buffer.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/ssl/host_name_verification.hpp>\n#include <boost/asio/this_coro.hpp>\n\n#include <iostream>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// The CA file that signed the server's certificate\nconstexpr const char CA_PEM[] = R\"%(-----BEGIN CERTIFICATE-----\nMIIDZzCCAk+gAwIBAgIUWznm2UoxXw3j7HCcp9PpiayTvFQwDQYJKoZIhvcNAQEL\nBQAwQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAMBgNVBAoM\nBW15c3FsMQ4wDAYDVQQDDAVteXNxbDAgFw0yMDA0MDQxNDMwMjNaGA8zMDE5MDgw\nNjE0MzAyM1owQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAM\nBgNVBAoMBW15c3FsMQ4wDAYDVQQDDAVteXNxbDCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAN0WYdvsDb+a0TxOGPejcwZT0zvTrf921mmDUlrLN1Z0hJ/S\nydgQCSD7Q+6za4lTFZCXcvs52xvvS2gfC0yXyYLCT/jA4RQRxuF+/+w1gDWEbGk0\nKzEpsBuKrEIvEaVdoS78SxInnW/aegshdrRRocp4JQ6KHsZgkLTxSwPfYSUmMUo0\ncRO0Q/ak3VK8NP13A6ZFvZjrBxjS3cSw9HqilgADcyj1D4EokvfI1C9LrgwgLlZC\nXVkjjBqqoMXGGlnXOEK+pm8bU68HM/QvMBkb1Amo8pioNaaYgqJUCP0Ch0iu1nUU\nHtsWt6emXv0jANgIW0oga7xcT4MDGN/M+IRWLTECAwEAAaNTMFEwHQYDVR0OBBYE\nFNxhaGwf5ePPhzK7yOAKD3VF6wm2MB8GA1UdIwQYMBaAFNxhaGwf5ePPhzK7yOAK\nD3VF6wm2MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAoeJCAX\nIDCFoAaZoQ1niI6Ac/cds8G8It0UCcFGSg+HrZ0YujJxWIruRCUG60Q2OAbEvn0+\nuRpTm+4tV1Wt92WFeuRyqkomozx0g4CyfsxGX/x8mLhKPFK/7K9iTXM4/t+xQC4f\nJ+iRmPVsMKQ8YsHYiWVhlOMH9XJQiqERCB2kOKJCH6xkaF2k0GbM2sGgbS7Z6lrd\nfsFTOIVx0VxLVsZnWX3byE9ghnDR5jn18u30Cpb/R/ShxNUGIHqRa4DkM5la6uZX\nW1fpSW11JBSUv4WnOO0C2rlIu7UJWOROqZZ0OsybPRGGwagcyff2qVRuI2XFvAMk\nOzBrmpfHEhF6NDU=\n-----END CERTIFICATE-----\n)%\";\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view server_hostname,\n    std::string_view username,\n    std::string_view password\n)\n{\n    //[section_connection_establishment_tls_options\n    // Create a SSL context, which contains TLS configuration options\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n\n    // Enable certificate verification. If the server's certificate\n    // is not valid or not signed by a trusted CA, async_connect will error.\n    ssl_ctx.set_verify_mode(asio::ssl::verify_peer);\n\n    // Load a trusted CA, which was used to sign the server's certificate.\n    // This will allow the signature verification to succeed in our example.\n    // You will have to run your MySQL server with the test certificates\n    // located under $BOOST_MYSQL_ROOT/tools/ssl/\n    // If you want to use your system's trusted CAs, use\n    // ssl::context::set_default_verify_paths() instead of this function.\n    ssl_ctx.add_certificate_authority(asio::buffer(CA_PEM));\n\n    // We expect the server certificate's common name to be \"mysql\".\n    // If it's not, the certificate will be rejected and handshake or connect will fail.\n    // Replace \"mysql\" by the common name you expect.\n    ssl_ctx.set_verify_callback(asio::ssl::host_name_verification(\"mysql\"));\n\n    // Create a connection.\n    // We pass the context as the second argument to the connection's constructor.\n    // Other TLS options can be also configured using this approach.\n    // We need to keep ssl_ctx alive as long as we use the connection.\n    mysql::any_connection conn(co_await asio::this_coro::executor, mysql::any_connection_params{&ssl_ctx});\n\n    // The hostname, username, password and database to use\n    mysql::connect_params params;\n    params.server_address.emplace_host_and_port(std::string(server_hostname));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server. If certificate verification fails,\n    // async_connect will fail.\n    co_await conn.async_connect(params);\n    //]\n\n    // The connection can now be used normally\n    mysql::results result;\n    co_await conn.async_execute(\"SELECT 'Hello world!'\", result);\n    std::cout << result.rows().at(0).at(0) << std::endl;\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <server-hostname>\\n\";\n        exit(1);\n    }\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(argv[3], argv[1], argv[2]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif"
  },
  {
    "path": "example/2_simple/unix_socket.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/local/stream_protocol.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)\n\n//[example_unix_socket\n\n/**\n * This example demonstrates how to connect to MySQL using a UNIX socket.\n *\n * It uses C++20 coroutines. If you need, you can backport\n * it to C++11 by using callbacks, asio::yield_context\n * or sync functions instead of coroutines.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <iostream>\n#include <string_view>\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// The main coroutine\nasio::awaitable<void> coro_main(\n    std::string_view unix_socket_path,\n    std::string_view username,\n    std::string_view password\n)\n{\n    //[section_connection_establishment_unix_socket\n    // Create a connection.\n    // Will use the same executor as the coroutine.\n    mysql::any_connection conn(co_await asio::this_coro::executor);\n\n    // The socket path, username, password and database to use.\n    // server_address is a variant-like type. Using emplace_unix_path,\n    // we can specify a UNIX socket path, instead of a hostname and a port.\n    // UNIX socket connections never use TLS.\n    mysql::connect_params params;\n    params.server_address.emplace_unix_path(std::string(unix_socket_path));\n    params.username = username;\n    params.password = password;\n    params.database = \"boost_mysql_examples\";\n\n    // Connect to the server\n    co_await conn.async_connect(params);\n    //]\n\n    // The connection can now be used normally\n    mysql::results result;\n    co_await conn.async_execute(\"SELECT 'Hello world!'\", result);\n    std::cout << result.rows().at(0).at(0) << std::endl;\n\n    // Notify the MySQL server we want to quit, then close the underlying connection.\n    co_await conn.async_close();\n}\n\nvoid main_impl(int argc, char** argv)\n{\n    if (argc != 3 && argc != 4)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> [<socket-path>]\\n\";\n        exit(1);\n    }\n\n    // If not provided, use the default UNIX socket path,\n    // compatible with most UNIX systems.\n    const char* socket_path = argc >= 4 ? argv[3] : \"/var/run/mysqld/mysqld.sock\";\n\n    // Create an I/O context, required by all I/O objects\n    asio::io_context ctx;\n\n    // Launch our coroutine\n    asio::co_spawn(\n        ctx,\n        [=] { return coro_main(socket_path, argv[1], argv[2]); },\n        // If any exception is thrown in the coroutine body, rethrow it.\n        [](std::exception_ptr ptr) {\n            if (ptr)\n            {\n                std::rethrow_exception(ptr);\n            }\n        }\n    );\n\n    // Calling run will actually execute the coroutine until completion\n    ctx.run();\n\n    std::cout << \"Done\\n\";\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const boost::mysql::error_with_diagnostics& err)\n    {\n        // Some errors include additional diagnostics, like server-provided error messages.\n        // Security note: diagnostics::server_message may contain user-supplied values (e.g. the\n        // field value that caused the error) and is encoded using to the connection's character set\n        // (UTF-8 by default). Treat is as untrusted input.\n        std::cerr << \"Error: \" << err.what() << \", error code: \" << err.code() << '\\n'\n                  << \"Server diagnostics: \" << err.get_diagnostics().server_message() << std::endl;\n        return 1;\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler/system doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/handle_request.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/static_results.hpp>\n#ifdef BOOST_MYSQL_CXX14\n\n//[example_http_server_cpp14_coroutines_handle_request_cpp\n//\n// File: handle_request.cpp\n//\n// This file contains all the boilerplate code to dispatch HTTP\n// requests to API endpoints. Functions here end up calling\n// note_repository functions.\n\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/spawn.hpp>\n#include <boost/beast/http/message.hpp>\n#include <boost/beast/http/string_body.hpp>\n#include <boost/beast/http/verb.hpp>\n#include <boost/charconv/from_chars.hpp>\n#include <boost/json/parse.hpp>\n#include <boost/json/serialize.hpp>\n#include <boost/json/value_from.hpp>\n#include <boost/json/value_to.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/url/parse.hpp>\n\n#include <cstdint>\n#include <exception>\n#include <iostream>\n#include <string>\n\n#include \"handle_request.hpp\"\n#include \"repository.hpp\"\n#include \"types.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nnamespace http = boost::beast::http;\nusing namespace notes;\n\nnamespace {\n\n// Helper function that logs errors thrown by db_repository\n// when an unexpected database error happens\nvoid log_mysql_error(boost::system::error_code ec, const mysql::diagnostics& diag)\n{\n    // Inserting the error code only prints the number and category. Add the message, too.\n    std::cerr << \"MySQL error: \" << ec << \" \" << ec.message();\n\n    // client_message() contains client-side generated messages that don't\n    // contain user-input. This is usually embedded in exceptions.\n    // When working with error codes, we need to log it explicitly\n    if (!diag.client_message().empty())\n    {\n        std::cerr << \": \" << diag.client_message();\n    }\n\n    // server_message() contains server-side messages, and thus may\n    // contain user-supplied input. Printing it is safe.\n    if (!diag.server_message().empty())\n    {\n        std::cerr << \": \" << diag.server_message();\n    }\n\n    // Done\n    std::cerr << std::endl;\n}\n\n// Attempts to parse a numeric ID from a string.\n// If you're using C++17, you can use std::from_chars, instead\nboost::optional<std::int64_t> parse_id(const std::string& from)\n{\n    std::int64_t id{};\n    auto res = boost::charconv::from_chars(from.data(), from.data() + from.size(), id);\n    if (res.ec != std::errc{} || res.ptr != from.data() + from.size())\n        return {};\n    return id;\n}\n\n// Helpers to create error responses with a single line of code\nhttp::response<http::string_body> error_response(http::status code, const char* msg)\n{\n    http::response<http::string_body> res;\n    res.result(code);\n    res.body() = msg;\n    return res;\n}\n\n// Like error_response, but always uses a 400 status code\nhttp::response<http::string_body> bad_request(const char* body)\n{\n    return error_response(http::status::bad_request, body);\n}\n\n// Like error_response, but always uses a 500 status code and\n// never provides extra information that might help potential attackers.\nhttp::response<http::string_body> internal_server_error()\n{\n    return error_response(http::status::internal_server_error, \"Internal server error\");\n}\n\n// Creates a response with a serialized JSON body.\n// T should be a type with Boost.Describe metadata containing the\n// body data to be serialized\ntemplate <class T>\nhttp::response<http::string_body> json_response(const T& body)\n{\n    http::response<http::string_body> res;\n\n    // Set the content-type header\n    res.set(\"Content-Type\", \"application/json\");\n\n    // Serialize the body data into a string and use it as the response body.\n    // We use Boost.JSON's automatic serialization feature, which uses Boost.Describe\n    // reflection data to generate a serialization function for us.\n    res.body() = boost::json::serialize(boost::json::value_from(body));\n\n    // Done\n    return res;\n}\n\n// Returns true if the request's Content-Type is set to JSON\nbool has_json_content_type(const http::request<http::string_body>& req)\n{\n    auto it = req.find(\"Content-Type\");\n    return it != req.end() && it->value() == \"application/json\";\n}\n\n// Attempts to parse a string as a JSON into an object of type T.\n// T should be a type with Boost.Describe metadata.\n// We use boost::system::result, which may contain a result or an error.\ntemplate <class T>\nboost::system::result<T> parse_json(boost::mysql::string_view json_string)\n{\n    // Attempt to parse the request into a json::value.\n    // This will fail if the provided body isn't valid JSON.\n    boost::system::error_code ec;\n    auto val = boost::json::parse(json_string, ec);\n    if (ec)\n        return ec;\n\n    // Attempt to parse the json::value into a T. This will\n    // fail if the provided JSON doesn't match T's shape.\n    return boost::json::try_value_to<T>(val);\n}\n\n// Contains data associated to an HTTP request.\n// To be passed to individual handler functions\nstruct request_data\n{\n    // The incoming request\n    const http::request<http::string_body>& request;\n\n    // The URL the request is targeting\n    boost::urls::url_view target;\n\n    // Connection pool\n    mysql::connection_pool& pool;\n\n    note_repository repo() const { return note_repository(pool); }\n};\n\n//\n// Endpoint handlers. We have a function per method.\n// All of our endpoints have /notes as the URL path.\n//\n\n// GET /notes: retrieves all the notes.\n// The request doesn't have a body.\n// The response has a JSON body with multi_notes_response format\n//\n// GET /notes?id=<note-id>: retrieves a single note.\n// The request doesn't have a body.\n// The response has a JSON body with single_note_response format\n//\n// Both endpoints share path and method, so they share handler function\nhttp::response<http::string_body> handle_get(const request_data& input, asio::yield_context yield)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n\n    // Did the client specify an ID?\n    if (params_it == input.target.params().end())\n    {\n        auto res = input.repo().get_notes(yield);\n        return json_response(multi_notes_response{std::move(res)});\n    }\n    else\n    {\n        // Parse id\n        auto id = parse_id((*params_it).value);\n        if (!id.has_value())\n            return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n        // Get the note\n        auto res = input.repo().get_note(*id, yield);\n\n        // If we didn't find it, return a 404 error\n        if (!res.has_value())\n            return error_response(http::status::not_found, \"The requested note was not found\");\n\n        // Return it as response\n        return json_response(single_note_response{std::move(*res)});\n    }\n}\n\n// POST /notes: creates a note.\n// The request has a JSON body with note_request_body format.\n// The response has a JSON body with single_note_response format.\nhttp::response<http::string_body> handle_post(const request_data& input, asio::yield_context yield)\n{\n    // Parse the request body\n    if (!has_json_content_type(input.request))\n        return bad_request(\"Invalid Content-Type: expected 'application/json'\");\n    auto args = parse_json<note_request_body>(input.request.body());\n    if (args.has_error())\n        return bad_request(\"Invalid JSON\");\n\n    // Actually create the note\n    auto res = input.repo().create_note(args->title, args->content, yield);\n\n    // Return the newly created note as response\n    return json_response(single_note_response{std::move(res)});\n}\n\n// PUT /notes?id=<note-id>: replaces a note.\n// The request has a JSON body with note_request_body format.\n// The response has a JSON body with single_note_response format.\nhttp::response<http::string_body> handle_put(const request_data& input, asio::yield_context yield)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n    if (params_it == input.target.params().end())\n        return bad_request(\"Mandatory URL parameter 'id' not found\");\n    auto id = parse_id((*params_it).value);\n    if (!id.has_value())\n        return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n    // Parse the request body\n    if (!has_json_content_type(input.request))\n        return bad_request(\"Invalid Content-Type: expected 'application/json'\");\n    auto args = parse_json<note_request_body>(input.request.body());\n    if (args.has_error())\n        return bad_request(\"Invalid JSON\");\n\n    // Perform the update\n    auto res = input.repo().replace_note(*id, args->title, args->content, yield);\n\n    // Check that it took effect. Otherwise, it's because the note wasn't there\n    if (!res.has_value())\n        return bad_request(\"The requested note was not found\");\n\n    // Return the updated note as response\n    return json_response(single_note_response{std::move(*res)});\n}\n\n// DELETE /notes/<note-id>: deletes a note.\n// The request doesn't have a body.\n// The response has a JSON body with delete_note_response format.\nhttp::response<http::string_body> handle_delete(const request_data& input, asio::yield_context yield)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n    if (params_it == input.target.params().end())\n        return bad_request(\"Mandatory URL parameter 'id' not found\");\n    auto id = parse_id((*params_it).value);\n    if (!id.has_value())\n        return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n    // Attempt to delete the note\n    bool deleted = input.repo().delete_note(*id, yield);\n\n    // Return whether the delete was successful in the response.\n    // We don't fail DELETEs for notes that don't exist.\n    return json_response(delete_note_response{deleted});\n}\n\n}  // namespace\n\n// External interface\nhttp::response<http::string_body> notes::handle_request(\n    mysql::connection_pool& pool,\n    const http::request<http::string_body>& request,\n    asio::yield_context yield\n)\n{\n    // Parse the request target\n    auto target = boost::urls::parse_origin_form(request.target());\n    if (!target.has_value())\n        return bad_request(\"Invalid request target\");\n\n    // All our endpoints have /notes as path, with different verbs and parameters.\n    // Verify that the path matches\n    if (target->path() != \"/notes\")\n        return error_response(http::status::not_found, \"Endpoint not found\");\n\n    // Compose the request_data object\n    request_data input{request, *target, pool};\n\n    // Invoke the relevant handler, depending on the method\n    try\n    {\n        switch (input.request.method())\n        {\n        case http::verb::get: return handle_get(input, yield);\n        case http::verb::post: return handle_post(input, yield);\n        case http::verb::put: return handle_put(input, yield);\n        case http::verb::delete_: return handle_delete(input, yield);\n        default: return error_response(http::status::method_not_allowed, \"Method not allowed for /notes\");\n        }\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // A Boost.MySQL error. This will happen if you don't have connectivity\n        // to your database, your schema is incorrect or your credentials are invalid.\n        // Log the error, including diagnostics\n        log_mysql_error(err.code(), err.get_diagnostics());\n\n        // Never disclose error info to a potential attacker\n        return internal_server_error();\n    }\n    catch (const std::exception& err)\n    {\n        // Another kind of error. This indicates a programming error or a severe\n        // server condition (e.g. out of memory). Same procedure as above.\n        std::cerr << \"Uncaught exception: \" << err.what() << std::endl;\n        return internal_server_error();\n    }\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/handle_request.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_HANDLE_REQUEST_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_HANDLE_REQUEST_HPP\n\n//[example_http_server_cpp14_coroutines_handle_request_hpp\n//\n// File: handle_request.hpp\n//\n\n#include <boost/mysql/connection_pool.hpp>\n\n#include <boost/asio/spawn.hpp>\n#include <boost/beast/http/message.hpp>\n#include <boost/beast/http/string_body.hpp>\n\nnamespace notes {\n\n// Handles an individual HTTP request, producing a response.\n// The caller of this function should use response::version,\n// response::keep_alive and response::prepare_payload to adjust the response.\nboost::beast::http::response<boost::beast::http::string_body> handle_request(\n    boost::mysql::connection_pool& pool,\n    const boost::beast::http::request<boost::beast::http::string_body>& request,\n    boost::asio::yield_context yield\n);\n\n}  // namespace notes\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/main.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/static_results.hpp>\n#ifdef BOOST_MYSQL_CXX14\n\n//[example_http_server_cpp14_coroutines_main_cpp\n\n/**\n * Implements a HTTP REST API using Boost.MySQL and Boost.Beast.\n * The server is asynchronous and uses asio::yield_context as its completion\n * style. It only requires C++14 to work.\n *\n * It implements a minimal REST API to manage notes.\n * A note is a simple object containing a user-defined title and content.\n * The REST API offers CRUD operations on such objects:\n *    POST   /notes           Creates a new note.\n *    GET    /notes           Retrieves all notes.\n *    GET    /notes?id=<id>   Retrieves a single note.\n *    PUT    /notes?id=<id>   Replaces a note, changing its title and content.\n *    DELETE /notes?id=<id>   Deletes a note.\n *\n * Notes are stored in MySQL. The note_repository class encapsulates\n * access to MySQL, offering friendly functions to manipulate notes.\n * server.cpp encapsulates all the boilerplate to launch an HTTP server,\n * match URLs to API endpoints, and invoke the relevant note_repository functions.\n *\n * All communication happens asynchronously. We use stackful coroutines to simplify\n * development, using asio::spawn and asio::yield_context.\n * This example requires linking to Boost::context, Boost::json and Boost::url.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/pool_params.hpp>\n\n#include <boost/asio/detached.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/signal_set.hpp>\n#include <boost/asio/spawn.hpp>\n#include <boost/asio/thread_pool.hpp>\n#include <boost/system/error_code.hpp>\n\n#include <cstdlib>\n#include <iostream>\n#include <memory>\n#include <string>\n\n#include \"server.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace notes;\n\nint main(int argc, char* argv[])\n{\n    // Check command line arguments.\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <mysql-hostname> <port>\\n\";\n        return EXIT_FAILURE;\n    }\n\n    // Application config\n    const char* mysql_username = argv[1];\n    const char* mysql_password = argv[2];\n    const char* mysql_hostname = argv[3];\n    auto port = static_cast<unsigned short>(std::stoi(argv[4]));\n\n    // An event loop, where the application will run.\n    asio::io_context ctx;\n\n    // Configuration for the connection pool\n    mysql::pool_params params{\n        // Connect using TCP, to the given hostname and using the default port\n        mysql::host_and_port{mysql_hostname},\n\n        // Authenticate using the given username\n        mysql_username,\n\n        // Password for the above username\n        mysql_password,\n\n        // Database to use when connecting\n        \"boost_mysql_examples\",\n    };\n\n    // Create the connection pool.\n    // shared_state contains all singleton objects that our application may need.\n    // Coroutines created by asio::spawn might survive until the io_context is destroyed\n    // (even after io_context::stop() has been called). This is not the case for callbacks\n    // and C++20 coroutines. Using a shared_ptr here ensures that the pool survives long enough.\n    auto st = std::make_shared<shared_state>(mysql::connection_pool(ctx, std::move(params)));\n\n    // Launch the MySQL pool\n    st->pool.async_run(asio::detached);\n\n    // A signal_set allows us to intercept SIGINT and SIGTERM and exit gracefully\n    asio::signal_set signals{ctx.get_executor(), SIGINT, SIGTERM};\n    signals.async_wait([st, &ctx](boost::system::error_code, int) {\n        // Stop the execution context. This will cause main to exit\n        ctx.stop();\n    });\n\n    // Launch the server. This will run until the context is stopped\n    asio::spawn(\n        // Spawn the coroutine in the io_context\n        ctx,\n\n        // The coroutine to run\n        [st, port](asio::yield_context yield) { run_server(st, port, yield); },\n\n        // If an exception is thrown in the coroutine, propagate it\n        [](std::exception_ptr exc) {\n            if (exc)\n                std::rethrow_exception(exc);\n        }\n    );\n\n    // Run the server until stopped\n    ctx.run();\n\n    std::cout << \"Server exiting\" << std::endl;\n\n    // (If we get here, it means we got a SIGINT or SIGTERM)\n    return EXIT_SUCCESS;\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main() { std::cout << \"Sorry, your compiler doesn't support C++14\\n\"; }\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/repository.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/static_results.hpp>\n#ifdef BOOST_MYSQL_CXX14\n\n//[example_http_server_cpp14_coroutines_repository_cpp\n//\n// File: repository.cpp\n//\n// SQL code to create the notes table is located under $REPO_ROOT/example/db_setup.sql\n// The table looks like this:\n//\n// CREATE TABLE notes(\n//     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n//     title TEXT NOT NULL,\n//     content TEXT NOT NULL\n// );\n\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <iterator>\n#include <tuple>\n#include <utility>\n\n#include \"repository.hpp\"\n#include \"types.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace notes;\nusing mysql::with_diagnostics;\n\nstd::vector<note_t> note_repository::get_notes(asio::yield_context yield)\n{\n    // Get a fresh connection from the pool. This returns a pooled_connection object,\n    // which is a proxy to an any_connection object. Connections are returned to the\n    // pool when the proxy object is destroyed.\n    // with_diagnostics ensures that thrown exceptions include diagnostic information\n    mysql::pooled_connection conn = pool_.async_get_connection(with_diagnostics(yield));\n\n    // Execute the query to retrieve all notes. We use the static interface to\n    // parse results directly into static_results.\n    mysql::static_results<note_t> result;\n    conn->async_execute(\"SELECT id, title, content FROM notes\", result, with_diagnostics(yield));\n\n    // By default, connections are reset after they are returned to the pool\n    // (by using any_connection::async_reset_connection). This will reset any\n    // session state we changed while we were using the connection\n    // (e.g. it will deallocate any statements we prepared).\n    // We did nothing to mutate session state, so we can tell the pool to skip\n    // this step, providing a minor performance gain.\n    // We use pooled_connection::return_without_reset to do this.\n    conn.return_without_reset();\n\n    // Move note_t objects into the result vector to save allocations\n    return std::vector<note_t>(\n        std::make_move_iterator(result.rows().begin()),\n        std::make_move_iterator(result.rows().end())\n    );\n\n    // If an exception is thrown, pooled_connection's destructor will\n    // return the connection automatically to the pool.\n}\n\nboost::optional<note_t> note_repository::get_note(std::int64_t note_id, asio::yield_context yield)\n{\n    // Get a fresh connection from the pool. This returns a pooled_connection object,\n    // which is a proxy to an any_connection object. Connections are returned to the\n    // pool when the proxy object is destroyed.\n    mysql::pooled_connection conn = pool_.async_get_connection(with_diagnostics(yield));\n\n    // When executed, with_params expands a query client-side before sending it to the server.\n    // Placeholders are marked with {}\n    mysql::static_results<note_t> result;\n    conn->async_execute(\n        mysql::with_params(\"SELECT id, title, content FROM notes WHERE id = {}\", note_id),\n        result,\n        with_diagnostics(yield)\n    );\n\n    // We did nothing to mutate session state, so we can skip reset\n    conn.return_without_reset();\n\n    // An empty results object indicates that no note was found\n    if (result.rows().empty())\n        return {};\n    else\n        return std::move(result.rows()[0]);\n}\n\nnote_t note_repository::create_note(\n    mysql::string_view title,\n    mysql::string_view content,\n    asio::yield_context yield\n)\n{\n    // Get a fresh connection from the pool. This returns a pooled_connection object,\n    // which is a proxy to an any_connection object. Connections are returned to the\n    // pool when the proxy object is destroyed.\n    mysql::pooled_connection conn = pool_.async_get_connection(with_diagnostics(yield));\n\n    // We will use statements in this function for the sake of example.\n    // We don't need to deallocate the statement explicitly,\n    // since the pool takes care of it after the connection is returned.\n    // You can also use with_params instead of statements.\n    mysql::statement stmt = conn->async_prepare_statement(\n        \"INSERT INTO notes (title, content) VALUES (?, ?)\",\n        with_diagnostics(yield)\n    );\n\n    // Execute the statement. The statement won't produce any rows,\n    // so we can use static_results<std::tuple<>>\n    mysql::static_results<std::tuple<>> result;\n    conn->async_execute(stmt.bind(title, content), result, with_diagnostics(yield));\n\n    // MySQL reports last_insert_id as a uint64_t regardless of the actual ID type.\n    // Given our table definition, this cast is safe\n    auto new_id = static_cast<std::int64_t>(result.last_insert_id());\n\n    return note_t{new_id, title, content};\n\n    // There's no need to return the connection explicitly to the pool,\n    // pooled_connection's destructor takes care of it.\n}\n\nboost::optional<note_t> note_repository::replace_note(\n    std::int64_t note_id,\n    mysql::string_view title,\n    mysql::string_view content,\n    asio::yield_context yield\n)\n{\n    // Get a fresh connection from the pool. This returns a pooled_connection object,\n    // which is a proxy to an any_connection object. Connections are returned to the\n    // pool when the proxy object is destroyed.\n    mysql::pooled_connection conn = pool_.async_get_connection(with_diagnostics(yield));\n\n    // Expand and execute the query.\n    // It won't produce any rows, so we can use static_results<std::tuple<>>\n    mysql::static_results<std::tuple<>> empty_result;\n    conn->async_execute(\n        mysql::with_params(\n            \"UPDATE notes SET title = {}, content = {} WHERE id = {}\",\n            title,\n            content,\n            note_id\n        ),\n        empty_result,\n        with_diagnostics(yield)\n    );\n\n    // We didn't mutate session state, so we can skip reset\n    conn.return_without_reset();\n\n    // No affected rows means that the note doesn't exist\n    if (empty_result.affected_rows() == 0u)\n        return {};\n\n    return note_t{note_id, title, content};\n}\n\nbool note_repository::delete_note(std::int64_t note_id, asio::yield_context yield)\n{\n    // Get a fresh connection from the pool. This returns a pooled_connection object,\n    // which is a proxy to an any_connection object. Connections are returned to the\n    // pool when the proxy object is destroyed.\n    mysql::pooled_connection conn = pool_.async_get_connection(with_diagnostics(yield));\n\n    // Expand and execute the query.\n    // It won't produce any rows, so we can use static_results<std::tuple<>>\n    mysql::static_results<std::tuple<>> empty_result;\n    conn->async_execute(\n        mysql::with_params(\"DELETE FROM notes WHERE id = {}\", note_id),\n        empty_result,\n        with_diagnostics(yield)\n    );\n\n    // We didn't mutate session state, so we can skip reset\n    conn.return_without_reset();\n\n    // No affected rows means that the note didn't exist\n    return empty_result.affected_rows() != 0u;\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/repository.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_REPOSITORY_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_REPOSITORY_HPP\n\n//[example_http_server_cpp14_coroutines_repository_hpp\n//\n// File: repository.hpp\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/spawn.hpp>\n#include <boost/optional/optional.hpp>\n\n#include <cstdint>\n\n#include \"types.hpp\"\n\nnamespace notes {\n\n// Encapsulates database logic.\n// All operations are async, and use stackful coroutines (asio::yield_context).\n// If the database can't be contacted, or unexpected database errors are found,\n// an exception of type mysql::error_with_diagnostics is thrown.\nclass note_repository\n{\n    boost::mysql::connection_pool& pool_;\n\npublic:\n    // Constructor (this is a cheap-to-construct object)\n    note_repository(boost::mysql::connection_pool& pool) noexcept : pool_(pool) {}\n\n    // Retrieves all notes present in the database\n    std::vector<note_t> get_notes(boost::asio::yield_context yield);\n\n    // Retrieves a single note by ID. Returns an empty optional\n    // if no note with the given ID is present in the database.\n    boost::optional<note_t> get_note(std::int64_t note_id, boost::asio::yield_context yield);\n\n    // Creates a new note in the database with the given components.\n    // Returns the newly created note, including the newly allocated ID.\n    note_t create_note(\n        boost::mysql::string_view title,\n        boost::mysql::string_view content,\n        boost::asio::yield_context yield\n    );\n\n    // Replaces the note identified by note_id, setting its components to the\n    // ones passed. Returns the updated note. If no note with ID matching\n    // note_id can be found, an empty optional is returned.\n    boost::optional<note_t> replace_note(\n        std::int64_t note_id,\n        boost::mysql::string_view title,\n        boost::mysql::string_view content,\n        boost::asio::yield_context yield\n    );\n\n    // Deletes the note identified by note_id. Returns true if\n    // a matching note was deleted, false otherwise.\n    bool delete_note(std::int64_t note_id, boost::asio::yield_context yield);\n};\n\n}  // namespace notes\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/server.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/static_results.hpp>\n#ifdef BOOST_MYSQL_CXX14\n\n//[example_http_server_cpp14_coroutines_server_cpp\n//\n// File: server.cpp\n//\n// This file contains all the boilerplate code to implement a HTTP\n// server. Functions here end up invoking handle_request.\n\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/ip/address.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/spawn.hpp>\n#include <boost/beast/core/flat_buffer.hpp>\n#include <boost/beast/http/error.hpp>\n#include <boost/beast/http/message.hpp>\n#include <boost/beast/http/parser.hpp>\n#include <boost/beast/http/read.hpp>\n#include <boost/beast/http/string_body.hpp>\n#include <boost/beast/http/write.hpp>\n\n#include <cstdlib>\n#include <exception>\n#include <iostream>\n#include <memory>\n\n#include \"handle_request.hpp\"\n#include \"server.hpp\"\n\nnamespace asio = boost::asio;\nnamespace http = boost::beast::http;\nusing namespace notes;\n\nnamespace {\n\n// Runs a single HTTP session until the client closes the connection\nvoid run_http_session(std::shared_ptr<shared_state> st, asio::ip::tcp::socket sock, asio::yield_context yield)\n{\n    using namespace std::chrono_literals;\n\n    boost::system::error_code ec;\n\n    // A buffer to read incoming client requests\n    boost::beast::flat_buffer buff;\n\n    // A timer, to use with asio::cancel_after to implement timeouts.\n    // Re-using the same timer multiple times with cancel_after\n    // is more efficient than using raw cancel_after,\n    // since the timer doesn't need to be re-created for every operation.\n    asio::steady_timer timer(yield.get_executor());\n\n    // A HTTP session might involve more than one message if\n    // keep-alive semantics are used. Loop until the connection closes.\n    while (true)\n    {\n        // Construct a new parser for each message\n        http::request_parser<http::string_body> parser;\n\n        // Apply a reasonable limit to the allowed size\n        // of the body in bytes to prevent abuse.\n        parser.body_limit(10000);\n\n        // Read a request. yield[ec] prevents exceptions from being thrown\n        // on error. We use cancel_after to set a timeout for the overall read operation.\n        http::async_read(sock, buff, parser.get(), asio::cancel_after(60s, yield[ec]));\n\n        if (ec)\n        {\n            if (ec == http::error::end_of_stream)\n            {\n                // This means they closed the connection\n                sock.shutdown(asio::ip::tcp::socket::shutdown_send, ec);\n            }\n            else\n            {\n                // An unknown error happened\n                std::cout << \"Error reading HTTP request: \" << ec.message() << std::endl;\n            }\n            return;\n        }\n\n        const auto& request = parser.get();\n\n        // Process the request to generate a response.\n        // This invokes the business logic, which will need to access MySQL data.\n        // Apply a timeout to the overall request handling process.\n        auto response = asio::spawn(\n            // Use the same executor as this coroutine\n            yield.get_executor(),\n\n            // The logic to invoke\n            [&](asio::yield_context yield2) { return handle_request(st->pool, request, yield2); },\n\n            // Completion token. Passing yield blocks the current coroutine\n            // until handle_request completes.\n            asio::cancel_after(timer, 30s, yield)\n        );\n\n        // Adjust the response, setting fields common to all responses\n        bool keep_alive = response.keep_alive();\n        response.version(request.version());\n        response.keep_alive(keep_alive);\n        response.prepare_payload();\n\n        // Send the response\n        http::async_write(sock, response, asio::cancel_after(60s, yield[ec]));\n        if (ec)\n        {\n            std::cout << \"Error writing HTTP response: \" << ec.message() << std::endl;\n            return;\n        }\n\n        // This means we should close the connection, usually because\n        // the response indicated the \"Connection: close\" semantic.\n        if (!keep_alive)\n        {\n            sock.shutdown(asio::ip::tcp::socket::shutdown_send, ec);\n            return;\n        }\n    }\n}\n\n}  // namespace\n\nvoid notes::run_server(std::shared_ptr<shared_state> st, unsigned short port, asio::yield_context yield)\n{\n    // An object that allows us to accept incoming TCP connections\n    asio::ip::tcp::acceptor acc(yield.get_executor());\n\n    // The endpoint where the server will listen. Edit this if you want to\n    // change the address or port we bind to.\n    asio::ip::tcp::endpoint listening_endpoint(asio::ip::make_address(\"0.0.0.0\"), port);\n\n    // Open the acceptor\n    acc.open(listening_endpoint.protocol());\n\n    // Allow address reuse\n    acc.set_option(asio::socket_base::reuse_address(true));\n\n    // Bind to the server address\n    acc.bind(listening_endpoint);\n\n    // Start listening for connections\n    acc.listen(asio::socket_base::max_listen_connections);\n\n    std::cout << \"Server listening at \" << acc.local_endpoint() << std::endl;\n\n    // Start the acceptor loop\n    while (true)\n    {\n        // Accept a new connection\n        asio::ip::tcp::socket sock = acc.async_accept(yield);\n\n        // Launch a new session for this connection. Each session gets its\n        // own coroutine, so we can get back to listening for new connections.\n        asio::spawn(\n            yield.get_executor(),\n\n            // Function implementing our session logic.\n            // Takes ownership of the socket.\n            [st, sock = std::move(sock)](asio::yield_context yield2) mutable {\n                return run_http_session(std::move(st), std::move(sock), yield2);\n            },\n\n            // Callback to run when the coroutine finishes\n            [](std::exception_ptr ptr) {\n                if (ptr)\n                {\n                    // For extra safety, log the exception but don't propagate it.\n                    // If we failed to anticipate an error condition that ends up raising an exception,\n                    // terminate only the affected session, instead of crashing the server.\n                    try\n                    {\n                        std::rethrow_exception(ptr);\n                    }\n                    catch (const std::exception& exc)\n                    {\n                        std::cerr << \"Uncaught error in a session: \" << exc.what() << std::endl;\n                    }\n                }\n            }\n        );\n    }\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/server.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_SERVER_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_SERVER_HPP\n\n//[example_http_server_cpp14_coroutines_server_hpp\n//\n// File: server.hpp\n//\n\n#include <boost/mysql/connection_pool.hpp>\n\n#include <boost/asio/spawn.hpp>\n\n#include <memory>\n\nnamespace notes {\n\n// State shared by all sessions created by our server.\n// For this application, we only need a connection_pool object.\n// Place here any other singleton objects your application may need.\n// We will use std::shared_ptr<shared_state> to ensure that objects\n// are kept alive until all sessions are terminated.\nstruct shared_state\n{\n    boost::mysql::connection_pool pool;\n\n    shared_state(boost::mysql::connection_pool pool) noexcept : pool(std::move(pool)) {}\n};\n\n// Runs a HTTP server that will listen on 0.0.0.0:port.\n// If the server fails to launch (e.g. because the port is already in use),\n// throws an exception. The server runs until the underlying execution\n// context is stopped.\nvoid run_server(std::shared_ptr<shared_state> st, unsigned short port, boost::asio::yield_context yield);\n\n}  // namespace notes\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp14_coroutines/types.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_TYPES_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP14_COROUTINES_TYPES_HPP\n\n//[example_http_server_cpp14_coroutines_types_hpp\n//\n// File: types.hpp\n//\n// Contains type definitions used in the REST API and database code.\n// We use Boost.Describe (BOOST_DESCRIBE_STRUCT) to add reflection\n// capabilities to our types. This allows using Boost.MySQL\n// static interface (i.e. static_results<T>) to parse query results,\n// and Boost.JSON automatic serialization/deserialization.\n\n#include <boost/describe/class.hpp>\n\n#include <cstdint>\n#include <string>\n#include <vector>\n\nnamespace notes {\n\nstruct note_t\n{\n    // The unique database ID of the object.\n    std::int64_t id;\n\n    // The note's title.\n    std::string title;\n\n    // The note's actual content.\n    std::string content;\n};\nBOOST_DESCRIBE_STRUCT(note_t, (), (id, title, content))\n\n//\n// REST API requests.\n//\n\n// Used for creating and replacing notes\nstruct note_request_body\n{\n    // The title that the new note should have.\n    std::string title;\n\n    // The content that the new note should have.\n    std::string content;\n};\nBOOST_DESCRIBE_STRUCT(note_request_body, (), (title, content))\n\n//\n// REST API responses.\n//\n\n// Used by endpoints returning several notes (like GET /notes).\nstruct multi_notes_response\n{\n    // The retrieved notes.\n    std::vector<note_t> notes;\n};\nBOOST_DESCRIBE_STRUCT(multi_notes_response, (), (notes))\n\n// Used by endpoints returning a single note (like GET /notes/<id>)\nstruct single_note_response\n{\n    // The retrieved note.\n    note_t note;\n};\nBOOST_DESCRIBE_STRUCT(single_note_response, (), (note))\n\n// Used by DELETE /notes/<id>\nstruct delete_note_response\n{\n    // true if the note was found and deleted, false if the note didn't exist.\n    bool deleted;\n};\nBOOST_DESCRIBE_STRUCT(delete_note_response, (), (deleted))\n\n}  // namespace notes\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/db_setup.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\n-- Connection system variables\nSET NAMES utf8;\n\n-- Database\nDROP DATABASE IF EXISTS boost_mysql_orders;\nCREATE DATABASE boost_mysql_orders;\nUSE boost_mysql_orders;\n\n-- User\nDROP USER IF EXISTS 'orders_user'@'%';\nCREATE USER 'orders_user'@'%' IDENTIFIED BY 'orders_password';\nGRANT ALL PRIVILEGES ON boost_mysql_orders.* TO 'orders_user'@'%';\nFLUSH PRIVILEGES;\n\n-- Tables\nCREATE TABLE products (\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    short_name VARCHAR(100) NOT NULL,\n    descr TEXT,\n    price INT NOT NULL,\n    FULLTEXT(short_name, descr)\n);\n\nCREATE TABLE orders(\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    `status` ENUM('draft', 'pending_payment', 'complete') NOT NULL DEFAULT 'draft'\n);\n\nCREATE TABLE order_items(\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    order_id INT NOT NULL,\n    product_id INT NOT NULL,\n    quantity INT NOT NULL,\n    FOREIGN KEY (order_id) REFERENCES orders(id),\n    FOREIGN KEY (product_id) REFERENCES products(id)\n);\n\n-- Contents for the products table\nINSERT INTO products (price, short_name, descr) VALUES\n    (6400, 'A Feast for Odin', 'A Feast for Odin is a points-driven game, with plethora of pathways to victory, with a range of risk balanced against reward. A significant portion of this is your central hall, which has a whopping -86 points of squares and a major part of your game is attempting to cover these up with various tiles. Likewise, long halls and island colonies can also offer large rewards, but they will have penalties of their own.'),\n    (1600, 'Railroad Ink',     'The critically acclaimed roll and write game where you draw routes on your board trying to connect the exits at its edges. The more you connect, the more points you make, but beware: each incomplete route will make you lose points!'),\n    (4000, 'Catan',            'Catan is a board game for two to four players in which you compete to gather resources and build the biggest settlements on the fictional island of Catan. It takes approximately one hour to play.'),\n    (2500, 'Not Alone',        'It is the 25th century. You are a member of an intergalactic expedition shipwrecked on a mysterious planet named Artemia. While waiting for the rescue ship, you begin to explore the planet but an alien entity picks up your scent and begins to hunt you. You are NOT ALONE! Will you survive the dangers of Artemia?'),\n    (4500, 'Dice Hospital',    \"In Dice Hospital, a worker placement board game, players are tasked with running a local hospital. Each round you'll be admitting new patients, hiring specialists, building new departments, and treating as many incoming patients as you can.\")\n;\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/error.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/pfr/config.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_http_server_cpp20_error_cpp\n\n#include <boost/system/error_category.hpp>\n\n#include <iostream>\n#include <mutex>\n\n#include \"error.hpp\"\n\nnamespace {\n\n// Converts an orders::errc to string\nconst char* error_to_string(orders::errc value)\n{\n    switch (value)\n    {\n    case orders::errc::not_found: return \"not_found\";\n    case orders::errc::order_invalid_status: return \"order_invalid_status\";\n    case orders::errc::product_not_found: return \"product_not_found\";\n    default: return \"<unknown orders::errc>\";\n    }\n}\n\n// The category to be returned by get_orders_category\nclass orders_category final : public boost::system::error_category\n{\npublic:\n    // Identifies the error category. Used when converting error_codes to string\n    const char* name() const noexcept final override { return \"orders\"; }\n\n    // Given a numeric error belonging to this category, convert it to a string\n    std::string message(int ev) const final override\n    {\n        return error_to_string(static_cast<orders::errc>(ev));\n    }\n};\n\n// The error category\nstatic const orders_category g_category;\n\n// The std::mutex that guards std::cerr\nstatic std::mutex g_cerr_mutex;\n\n}  // namespace\n\n//\n// External interface\n//\nconst boost::system::error_category& orders::get_orders_category() { return g_category; }\n\nstd::unique_lock<std::mutex> orders::lock_cerr() { return std::unique_lock{g_cerr_mutex}; }\n\nvoid orders::log_error(std::string_view header, boost::system::error_code ec)\n{\n    // Lock the mutex\n    auto guard = lock_cerr();\n\n    // Logging the error code prints the number and category. Add the message, too\n    std::cerr << header << \": \" << ec << \" \" << ec.message() << std::endl;\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/error.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_ERROR_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_ERROR_HPP\n\n//[example_http_server_cpp20_error_hpp\n//\n// File: error.hpp\n//\n// Contains an errc enumeration and the required pieces to\n// use it with boost::system::error_code.\n// We use this indirectly in the DB repository class,\n// when using the error codes in boost::system::result.\n\n#include <boost/system/error_category.hpp>\n\n#include <mutex>\n#include <string_view>\n#include <type_traits>\n\nnamespace orders {\n\n// Error code enum for errors originated within our application\nenum class errc\n{\n    not_found,             // couldn't retrieve or modify a certain resource because it doesn't exist\n    order_invalid_status,  // an operation found an order in a status != the one expected (e.g. not editable)\n    product_not_found,     // a product referenced by a request doesn't exist\n};\n\n// To use errc with boost::system::error_code, we need\n// to define an error category (see the cpp file).\nconst boost::system::error_category& get_orders_category();\n\n// Called when constructing an error_code from an errc value.\ninline boost::system::error_code make_error_code(errc v)\n{\n    // Roughly, an error_code is an int and a category defining what the int means.\n    return boost::system::error_code(static_cast<int>(v), get_orders_category());\n}\n\n// In multi-threaded programs, using std::cerr without any locking\n// can result in interleaved output.\n// Locks a mutex guarding std::cerr to prevent this.\n// All uses of std::cerr should respect this.\nstd::unique_lock<std::mutex> lock_cerr();\n\n// A helper function for the common case where we want to log an error code\nvoid log_error(std::string_view header, boost::system::error_code ec);\n\n}  // namespace orders\n\n// This specialization is required to construct error_code's from errc values\ntemplate <>\nstruct boost::system::is_error_code_enum<orders::errc> : std::true_type\n{\n};\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/handle_request.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/pfr/config.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_http_server_cpp20_handle_request_cpp\n//\n// File: handle_request.cpp\n//\n// This file contains all the boilerplate code to dispatch HTTP\n// requests to API endpoints. Functions here end up calling\n// db_repository fuctions.\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/beast/http/message.hpp>\n#include <boost/beast/http/status.hpp>\n#include <boost/beast/http/string_body.hpp>\n#include <boost/beast/http/verb.hpp>\n#include <boost/json/parse.hpp>\n#include <boost/json/serialize.hpp>\n#include <boost/json/value_from.hpp>\n#include <boost/json/value_to.hpp>\n#include <boost/system/error_code.hpp>\n#include <boost/system/result.hpp>\n#include <boost/url/parse.hpp>\n#include <boost/url/url_view.hpp>\n\n#include <algorithm>\n#include <charconv>\n#include <cstdint>\n#include <exception>\n#include <iostream>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <system_error>\n#include <unordered_map>\n#include <vector>\n\n#include \"error.hpp\"\n#include \"handle_request.hpp\"\n#include \"repository.hpp\"\n#include \"types.hpp\"\n\nnamespace asio = boost::asio;\nnamespace http = boost::beast::http;\nnamespace mysql = boost::mysql;\nusing boost::system::result;\n\nnamespace {\n\n// Helper function that logs errors thrown by db_repository\n// when an unexpected database error happens\nvoid log_mysql_error(boost::system::error_code ec, const mysql::diagnostics& diag)\n{\n    // Lock std::cerr, to avoid race conditions\n    auto guard = orders::lock_cerr();\n\n    // Inserting the error code only prints the number and category. Add the message, too.\n    std::cerr << \"MySQL error: \" << ec << \" \" << ec.message();\n\n    // client_message() contains client-side generated messages that don't\n    // contain user-input. This is usually embedded in exceptions.\n    // When working with error codes, we need to log it explicitly\n    if (!diag.client_message().empty())\n    {\n        std::cerr << \": \" << diag.client_message();\n    }\n\n    // server_message() contains server-side messages, and thus may\n    // contain user-supplied input. Printing it is safe.\n    if (!diag.server_message().empty())\n    {\n        std::cerr << \": \" << diag.server_message();\n    }\n\n    // Done\n    std::cerr << std::endl;\n}\n\n// Attempts to parse a numeric ID from a string\nstd::optional<std::int64_t> parse_id(std::string_view from)\n{\n    std::int64_t id{};\n    auto res = std::from_chars(from.data(), from.data() + from.size(), id);\n    if (res.ec != std::errc{} || res.ptr != from.data() + from.size())\n        return std::nullopt;\n    return id;\n}\n\n// Helpers to create error responses with a single line of code\nhttp::response<http::string_body> error_response(http::status code, std::string_view msg)\n{\n    http::response<http::string_body> res;\n    res.result(code);\n    res.body() = msg;\n    return res;\n}\n\n// Like error_response, but always uses a 400 status code\nhttp::response<http::string_body> bad_request(std::string_view body)\n{\n    return error_response(http::status::bad_request, body);\n}\n\n// Like error_response, but always uses a 500 status code and\n// never provides extra information that might help potential attackers.\nhttp::response<http::string_body> internal_server_error()\n{\n    return error_response(http::status::internal_server_error, \"Internal server error\");\n}\n\n// Creates a response with a serialized JSON body.\n// T should be a type with Boost.Describe metadata containing the\n// body data to be serialized\ntemplate <class T>\nhttp::response<http::string_body> json_response(const T& body)\n{\n    http::response<http::string_body> res;\n\n    // Set the content-type header\n    res.set(\"Content-Type\", \"application/json\");\n\n    // Serialize the body data into a string and use it as the response body.\n    // We use Boost.JSON's automatic serialization feature, which uses Boost.Describe\n    // reflection data to generate a serialization function for us.\n    res.body() = boost::json::serialize(boost::json::value_from(body));\n\n    // Done\n    return res;\n}\n\n// Attempts to parse a string as a JSON into an object of type T.\n// T should be a type with Boost.Describe metadata.\n// We use boost::system::result, which may contain a result or an error.\ntemplate <class T>\nresult<T> parse_json(std::string_view json_string)\n{\n    // Attempt to parse the request into a json::value.\n    // This will fail if the provided body isn't valid JSON.\n    boost::system::error_code ec;\n    auto val = boost::json::parse(json_string, ec);\n    if (ec)\n        return ec;\n\n    // Attempt to parse the json::value into a T. This will\n    // fail if the provided JSON doesn't match T's shape.\n    return boost::json::try_value_to<T>(val);\n}\n\n// Generates an HTTP error response based on an error code\n// returned by db_repository.\nhttp::response<http::string_body> response_from_db_error(boost::system::error_code ec)\n{\n    if (ec.category() == orders::get_orders_category())\n    {\n        switch (static_cast<orders::errc>(ec.value()))\n        {\n        case orders::errc::not_found:\n            return error_response(http::status::not_found, \"The referenced entity does not exist\");\n        case orders::errc::product_not_found:\n            return error_response(\n                http::status::unprocessable_entity,\n                \"The referenced product does not exist\"\n            );\n        case orders::errc::order_invalid_status:\n            return error_response(\n                http::status::unprocessable_entity,\n                \"The referenced order doesn't have the status required by the operation\"\n            );\n        default: return internal_server_error();\n        }\n    }\n    else\n    {\n        return internal_server_error();\n    }\n}\n\n// Contains data associated to an HTTP request.\n// To be passed to individual handler functions\nstruct request_data\n{\n    // The incoming request\n    const http::request<http::string_body>& request;\n\n    // The URL the request is targeting\n    boost::urls::url_view target;\n\n    // Connection pool\n    mysql::connection_pool& pool;\n\n    orders::db_repository repo() const { return orders::db_repository(pool); }\n};\n\n//\n// Endpoint handlers. They should be functions with signature\n// asio::awaitable<http::response<http::string_body>>(const request_data&).\n// Handlers are associated to a single URL path and HTTP method\n//\n\n// GET /products?search={s}: returns a list of products.\n// The 'search' parameter is mandatory.\nasio::awaitable<http::response<http::string_body>> handle_get_products(const request_data& input)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"search\");\n    if (params_it == input.target.params().end())\n        co_return bad_request(\"Missing mandatory query parameter: 'search'\");\n    auto search = (*params_it).value;\n\n    // Invoke the database logic\n    std::vector<orders::product> products = co_await input.repo().get_products(search);\n\n    // Return the response\n    co_return json_response(products);\n}\n\n// GET /orders: returns all orders\n// GET /orders?id={}: returns a single order\n// Both endpoints share handler because they share path and method\nasio::awaitable<http::response<http::string_body>> handle_get_orders(const request_data& input)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n\n    // Which of the two endpoints are we serving?\n    if (params_it == input.target.params().end())\n    {\n        // GET /orders\n        // Invoke the database logic\n        std::vector<orders::order> orders = co_await input.repo().get_orders();\n\n        // Return the response\n        co_return json_response(orders);\n    }\n    else\n    {\n        // GET /orders?id={}\n        // Parse the query parameter\n        auto order_id = parse_id((*params_it).value);\n        if (!order_id.has_value())\n            co_return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n        // Invoke the database logic\n        result<orders::order_with_items> order = co_await input.repo().get_order_by_id(*order_id);\n        if (order.has_error())\n            co_return response_from_db_error(order.error());\n\n        // Return the response\n        co_return json_response(*order);\n    }\n}\n\n// POST /orders: creates a new order.\n// Orders are created empty, so this request has no body.\nasio::awaitable<http::response<http::string_body>> handle_create_order(const request_data& input)\n{\n    // Invoke the database logic\n    orders::order_with_items order = co_await input.repo().create_order();\n\n    // Return the response\n    co_return json_response(order);\n}\n\n// POST /orders/items: adds a new order item to an existing order.\n// The request has a JSON body, described by the add_order_item_request struct.\nasio::awaitable<http::response<http::string_body>> handle_add_order_item(const request_data& input)\n{\n    // Check that the request has the appropriate content type\n    auto it = input.request.find(\"Content-Type\");\n    if (it == input.request.end() || it->value() != \"application/json\")\n        co_return bad_request(\"Invalid Content-Type: expected 'application/json'\");\n\n    // Parse the request body\n    auto req = parse_json<orders::add_order_item_request>(input.request.body());\n    if (req.has_error())\n        co_return bad_request(\"Invalid JSON body\");\n\n    // Invoke the database logic\n    result<orders::order_with_items> res = co_await input.repo()\n                                               .add_order_item(req->order_id, req->product_id, req->quantity);\n    if (res.has_error())\n        co_return response_from_db_error(res.error());\n\n    // Return the response\n    co_return json_response(*res);\n}\n\n// DELETE /orders/items?id={}: deletes an order item.\n// The request has no body.\nasio::awaitable<http::response<http::string_body>> handle_remove_order_item(const request_data& input)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n    if (params_it == input.target.params().end())\n        co_return bad_request(\"Mandatory URL parameter 'id' not found\");\n    auto id = parse_id((*params_it).value);\n    if (!id.has_value())\n        co_return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n    // Invoke the database logic\n    result<orders::order_with_items> res = co_await input.repo().remove_order_item(*id);\n    if (res.has_error())\n        co_return response_from_db_error(res.error());\n\n    // Return the response\n    co_return json_response(*res);\n}\n\n// POST /orders/checkout?id={}: checks out an order.\n// The request has no body.\nasio::awaitable<http::response<http::string_body>> handle_checkout_order(const request_data& input)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n    if (params_it == input.target.params().end())\n        co_return bad_request(\"Mandatory URL parameter 'id' not found\");\n    auto id = parse_id((*params_it).value);\n    if (!id.has_value())\n        co_return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n    // Invoke the database logic\n    result<orders::order_with_items> res = co_await input.repo().checkout_order(*id);\n    if (res.has_error())\n        co_return response_from_db_error(res.error());\n\n    // Return the response\n    co_return json_response(*res);\n}\n\n// POST /orders/complete?id={}: marks an order as completed.\n// The request has no body.\nasio::awaitable<http::response<http::string_body>> handle_complete_order(const request_data& input)\n{\n    // Parse the query parameter\n    auto params_it = input.target.params().find(\"id\");\n    if (params_it == input.target.params().end())\n        co_return bad_request(\"Mandatory URL parameter 'id' not found\");\n    auto id = parse_id((*params_it).value);\n    if (!id.has_value())\n        co_return bad_request(\"URL parameter 'id' should be a valid integer\");\n\n    // Invoke the database logic\n    result<orders::order_with_items> res = co_await input.repo().complete_order(*id);\n    if (res.has_error())\n        co_return response_from_db_error(res.error());\n\n    // Return the response\n    co_return json_response(*res);\n}\n\n// handle_request uses a table to dispatch to each endpoint.\n// This is the table's element type.\nstruct http_endpoint\n{\n    // The HTTP method associated to this endpoint.\n    http::verb method;\n\n    // The endpoint handler.\n    asio::awaitable<http::response<http::string_body>> (*handler)(const request_data&);\n};\n\n// Maps from a URL path to an endpoint handler.\n// A URL path might be present more than once, for different methods.\nconst std::unordered_multimap<std::string_view, http_endpoint> endpoint_table{\n    {\"/products\",        {http::verb::get, &handle_get_products}         },\n    {\"/orders\",          {http::verb::get, &handle_get_orders}           },\n    {\"/orders\",          {http::verb::post, &handle_create_order}        },\n    {\"/orders/items\",    {http::verb::post, &handle_add_order_item}      },\n    {\"/orders/items\",    {http::verb::delete_, &handle_remove_order_item}},\n    {\"/orders/checkout\", {http::verb::post, &handle_checkout_order}      },\n    {\"/orders/complete\", {http::verb::post, &handle_complete_order}      },\n};\n\n}  // namespace\n\n// External interface\nasio::awaitable<http::response<http::string_body>> orders::handle_request(\n    const http::request<http::string_body>& request,\n    mysql::connection_pool& pool\n)\n{\n    // Parse the request target\n    auto target = boost::urls::parse_origin_form(request.target());\n    if (!target.has_value())\n        co_return bad_request(\"Invalid request target\");\n\n    // Try to find an endpoint\n    auto [it1, it2] = endpoint_table.equal_range(target->path());\n    if (it1 == endpoint_table.end())\n        co_return error_response(http::status::not_found, \"The requested endpoint does not exist\");\n\n    // Match the verb. The table structure that we created\n    // allows us to distinguish between an \"endpoint does not exist\" error\n    // and an \"unsupported method\" error.\n    auto it3 = std::find_if(it1, it2, [&request](const std::pair<std::string_view, http_endpoint>& ep) {\n        return ep.second.method == request.method();\n    });\n    if (it3 == it2)\n        co_return error_response(http::status::method_not_allowed, \"Unsupported HTTP method\");\n\n    // Invoke the handler\n    try\n    {\n        // Attempt to handle the request\n        co_return co_await it3->second.handler(request_data{request, *target, pool});\n    }\n    catch (const mysql::error_with_diagnostics& err)\n    {\n        // A Boost.MySQL error. This will happen if you don't have connectivity\n        // to your database, your schema is incorrect or your credentials are invalid.\n        // Log the error, including diagnostics\n        log_mysql_error(err.code(), err.get_diagnostics());\n\n        // Never disclose error info to a potential attacker\n        co_return internal_server_error();\n    }\n    catch (const std::exception& err)\n    {\n        // Another kind of error. This indicates a programming error or a severe\n        // server condition (e.g. out of memory). Same procedure as above.\n        {\n            auto guard = orders::lock_cerr();\n            std::cerr << \"Uncaught exception: \" << err.what() << std::endl;\n        }\n        co_return internal_server_error();\n    }\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/handle_request.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_HANDLE_REQUEST_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_HANDLE_REQUEST_HPP\n\n//[example_http_server_cpp20_handle_request_hpp\n//\n// File: handle_request.hpp\n//\n\n#include <boost/mysql/connection_pool.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/beast/http/message.hpp>\n#include <boost/beast/http/string_body.hpp>\n\nnamespace orders {\n\n// Handles an individual HTTP request, producing a response.\n// The caller of this function should use response::version,\n// response::keep_alive and response::prepare_payload to adjust the response.\nboost::asio::awaitable<boost::beast::http::response<boost::beast::http::string_body>> handle_request(\n    const boost::beast::http::request<boost::beast::http::string_body>& request,\n    boost::mysql::connection_pool& pool\n);\n\n}  // namespace orders\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/main.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/pfr/config.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_http_server_cpp20_main_cpp\n\n/**\n * Implements a HTTP REST API using Boost.MySQL and Boost.Beast.\n * The API models a simplified order management system for an online store.\n * Using the API, users can query the store's product catalog, create and\n * edit orders, and check them out for payment.\n *\n * The API defines the following endpoints:\n *\n *    GET    /products?search={s}       Returns a list of products\n *    GET    /orders                    Returns all orders\n *    GET    /orders?id={}              Returns a single order\n *    POST   /orders                    Creates a new order\n *    POST   /orders/items              Adds a new order item to an existing order\n *    DELETE /orders/items?id={}        Deletes an order item\n *    POST   /orders/checkout?id={}     Checks out an order\n *    POST   /orders/complete?id={}     Completes an order\n *\n * Each order can have any number of order items. An order item\n * represents an individual product that has been added to an order.\n * Orders are created empty, in a 'draft' state. Items can then be\n * added and removed from the order. After adding the desired items,\n * orders can be checked out for payment. A third-party service, like Stripe,\n * would be used to collect the payment. For simplicity, we've left this part\n * out of the example. Once checked out, an order is no longer editable.\n * Finally, after successful payment, order are transitioned to the\n * 'complete' status.\n *\n * The server uses C++20 coroutines and is multi-threaded.\n * It also requires linking to Boost::json and Boost::url.\n * The database schema is defined in db_setup.sql, in the same directory as this file.\n * You need to source this file before running the example.\n */\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/pool_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/signal_set.hpp>\n#include <boost/asio/thread_pool.hpp>\n#include <boost/system/error_code.hpp>\n\n#include <cstddef>\n#include <cstdlib>\n#include <exception>\n#include <iostream>\n#include <string>\n\n#include \"server.hpp\"\n\nusing namespace orders;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\n// The number of threads to use\nstatic constexpr std::size_t num_threads = 5;\n\nint main_impl(int argc, char* argv[])\n{\n    // Check command line arguments.\n    if (argc != 5)\n    {\n        std::cerr << \"Usage: \" << argv[0] << \" <username> <password> <mysql-hostname> <port>\\n\";\n        return EXIT_FAILURE;\n    }\n\n    // Application config\n    const char* mysql_username = argv[1];\n    const char* mysql_password = argv[2];\n    const char* mysql_hostname = argv[3];\n    auto port = static_cast<unsigned short>(std::stoi(argv[4]));\n\n    // An event loop, where the application will run.\n    // We will use the main thread to run the pool, too, so we use\n    // one thread less than configured\n    asio::thread_pool th_pool(num_threads - 1);\n\n    // Create a connection pool\n    mysql::connection_pool pool(\n        // Use the thread pool as execution context\n        th_pool,\n\n        // Pool configuration\n        mysql::pool_params{\n            // Connect using TCP, to the given hostname and using the default port\n            .server_address = mysql::host_and_port{mysql_hostname},\n\n            // Authenticate using the given username\n            .username = mysql_username,\n\n            // Password for the above username\n            .password = mysql_password,\n\n            // Database to use when connecting\n            .database = \"boost_mysql_orders\",\n\n            // We're using multi-queries\n            .multi_queries = true,\n\n            // Using thread_safe will make the pool thread-safe by internally\n            // creating and using a strand.\n            // This allows us to share the pool between sessions, which may run\n            // concurrently, on different threads.\n            .thread_safe = true,\n        }\n    );\n\n    // Launch the MySQL pool\n    pool.async_run(asio::detached);\n\n    // A signal_set allows us to intercept SIGINT and SIGTERM and\n    // exit gracefully\n    asio::signal_set signals{th_pool.get_executor(), SIGINT, SIGTERM};\n\n    // Capture SIGINT and SIGTERM to perform a clean shutdown\n    signals.async_wait([&th_pool](boost::system::error_code, int) {\n        // Stop the execution context. This will cause main to exit\n        th_pool.stop();\n    });\n\n    // Start listening for HTTP connections. This will run until the context is stopped\n    asio::co_spawn(\n        // Use the thread pool to run the listener coroutine\n        th_pool,\n\n        // The coroutine to run\n        [&pool, port] { return run_server(pool, port); },\n\n        // If an exception is thrown in the listener coroutine, propagate it\n        [](std::exception_ptr exc) {\n            if (exc)\n                std::rethrow_exception(exc);\n        }\n    );\n\n    // Attach the current thread to the thread pool. This will block\n    // until stop() is called\n    th_pool.attach();\n\n    // Wait until all threads have exited\n    th_pool.join();\n\n    std::cout << \"Server exiting\" << std::endl;\n\n    // (If we get here, it means we got a SIGINT or SIGTERM)\n    return EXIT_SUCCESS;\n}\n\nint main(int argc, char** argv)\n{\n    try\n    {\n        main_impl(argc, argv);\n    }\n    catch (const std::exception& err)\n    {\n        std::cerr << \"Error: \" << err.what() << std::endl;\n        return 1;\n    }\n}\n\n//]\n\n#else\n\n#include <iostream>\n\nint main()\n{\n    std::cout << \"Sorry, your compiler doesn't have the required capabilities to run this example\"\n              << std::endl;\n}\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/repository.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/pfr/config.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_http_server_cpp20_repository_cpp\n//\n// File: repository.cpp\n//\n// See the db_setup.sql file in this folder for the table definitions\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/system/result.hpp>\n\n#include <string>\n#include <string_view>\n#include <tuple>\n#include <vector>\n\n#include \"error.hpp\"\n#include \"repository.hpp\"\n#include \"types.hpp\"\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace orders;\n\nasio::awaitable<std::vector<product>> db_repository::get_products(std::string_view search)\n{\n    // Get a connection from the pool\n    auto conn = co_await pool_.async_get_connection();\n\n    // Get the products using the MySQL built-in full-text search feature.\n    // Look for the query string in the short_name and descr fields.\n    // Parse the query results into product struct instances\n    mysql::static_results<product> res;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"SELECT id, short_name, descr, price FROM products \"\n            \"WHERE MATCH(short_name, descr) AGAINST({}) \"\n            \"LIMIT 10\",\n            search\n        ),\n        res\n    );\n\n    // By default, connections are reset after they are returned to the pool\n    // (by using any_connection::async_reset_connection). This will reset any\n    // session state we changed while we were using the connection\n    // (e.g. it will deallocate any statements we prepared).\n    // We did nothing to mutate session state, so we can tell the pool to skip\n    // this step, providing a minor performance gain.\n    // We use pooled_connection::return_without_reset to do this.\n    // If an exception was raised, the connection would be reset, for safety.\n    conn.return_without_reset();\n\n    // Return the result\n    co_return std::vector<product>{res.rows().begin(), res.rows().end()};\n}\n\nasio::awaitable<std::vector<order>> db_repository::get_orders()\n{\n    // Get a connection from the pool\n    auto conn = co_await pool_.async_get_connection();\n\n    // Get all the orders.\n    // Parse the result into order structs.\n    mysql::static_results<order> res;\n    co_await conn->async_execute(\"SELECT id, status FROM orders\", res);\n\n    // We didn't mutate session state, so we can skip resetting the connection\n    conn.return_without_reset();\n\n    // Return the result\n    co_return std::vector<order>{res.rows().begin(), res.rows().end()};\n}\n\nasio::awaitable<boost::system::result<order_with_items>> db_repository::get_order_by_id(std::int64_t id)\n{\n    // Get a connection from the pool\n    auto conn = co_await pool_.async_get_connection();\n\n    // Get a single order and all its associated items.\n    // The transaction ensures atomicity between the two SELECTs.\n    // We issued 4 queries, so we get 4 resultsets back.\n    // Ignore the 1st and 4th, and parse the other two into order and order_item structs\n    mysql::static_results<std::tuple<>, order, order_item, std::tuple<>> result;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"START TRANSACTION READ ONLY;\"\n            \"SELECT id, status FROM orders WHERE id = {0};\"\n            \"SELECT id, product_id, quantity FROM order_items WHERE order_id = {0};\"\n            \"COMMIT\",\n            id\n        ),\n        result\n    );\n\n    // We didn't mutate session state\n    conn.return_without_reset();\n\n    // result.rows<N> returns the rows for the N-th resultset, as a span\n    auto orders = result.rows<1>();\n    auto order_items = result.rows<2>();\n\n    // Did we find the order we're looking for?\n    if (orders.empty())\n        co_return orders::errc::not_found;\n    const order& ord = orders[0];\n\n    // If we did, compose the result\n    co_return order_with_items{\n        ord.id,\n        ord.status,\n        {order_items.begin(), order_items.end()}\n    };\n}\n\nasio::awaitable<order_with_items> db_repository::create_order()\n{\n    // Get a connection from the pool\n    auto conn = co_await pool_.async_get_connection();\n\n    // Create the new order.\n    // Orders are created empty, with all fields defaulted.\n    // MySQL does not have an INSERT ... RETURNING statement, so we use\n    // a transaction with an INSERT and a SELECT to create the order\n    // and retrieve it atomically.\n    // This yields 4 resultsets, one per SQL statement.\n    // Ignore all except the SELECT, and parse it into an order struct.\n    mysql::static_results<std::tuple<>, std::tuple<>, order, std::tuple<>> result;\n    co_await conn->async_execute(\n        \"START TRANSACTION;\"\n        \"INSERT INTO orders () VALUES ();\"\n        \"SELECT id, status FROM orders WHERE id = LAST_INSERT_ID();\"\n        \"COMMIT\",\n        result\n    );\n\n    // We didn't mutate session state\n    conn.return_without_reset();\n\n    // This must always yield one row. Return it.\n    const order& ord = result.rows<2>().front();\n    co_return order_with_items{\n        ord.id,\n        ord.status,\n        {}  // A newly created order never has items\n    };\n}\n\nasio::awaitable<boost::system::result<order_with_items>> db_repository::add_order_item(\n    std::int64_t order_id,\n    std::int64_t product_id,\n    std::int64_t quantity\n)\n{\n    // Get a connection from the pool\n    auto conn = co_await pool_.async_get_connection();\n\n    // Retrieve the order and the product.\n    // SELECT ... FOR UPDATE places a lock on the retrieved rows,\n    // so they're not modified by other transactions while we use them.\n    // If you're targeting MySQL 8.0+, you can also use SELECT ... FOR SHARE.\n    // For the product, we only need to check that it does exist,\n    // so we get its ID and parse the returned rows into a std::tuple.\n    mysql::static_results<std::tuple<>, order, std::tuple<std::int64_t>> result1;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"START TRANSACTION;\"\n            \"SELECT id, status FROM orders WHERE id = {} FOR UPDATE;\"\n            \"SELECT id FROM products WHERE id = {} FOR UPDATE\",\n            order_id,\n            product_id\n        ),\n        result1\n    );\n\n    // Check that the order exists\n    if (result1.rows<1>().empty())\n    {\n        // Not found. We did mutate session state by opening a transaction,\n        // so we can't use return_without_reset\n        co_return orders::errc::not_found;\n    }\n    const order& ord = result1.rows<1>().front();\n\n    // Verify that the order is editable.\n    // Using SELECT ... FOR UPDATE prevents race conditions with this check.\n    if (ord.status != status_draft)\n    {\n        co_return orders::errc::order_invalid_status;\n    }\n\n    // Check that the product exists\n    if (result1.rows<2>().empty())\n    {\n        co_return orders::errc::product_not_found;\n    }\n\n    // Insert the new item and retrieve all the items associated to this order\n    mysql::static_results<std::tuple<>, order_item, std::tuple<>> result2;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"INSERT INTO order_items (order_id, product_id, quantity) VALUES ({0}, {1}, {2});\"\n            \"SELECT id, product_id, quantity FROM order_items WHERE order_id = {0};\"\n            \"COMMIT\",\n            order_id,\n            product_id,\n            quantity\n        ),\n        result2\n    );\n\n    // If everything went well, we didn't mutate session state\n    conn.return_without_reset();\n\n    // Compose the return value\n    co_return order_with_items{\n        ord.id,\n        ord.status,\n        {result2.rows<1>().begin(), result2.rows<1>().end()}\n    };\n}\n\nasio::awaitable<boost::system::result<order_with_items>> db_repository::remove_order_item(std::int64_t item_id\n)\n{\n    // Get a connection from the pool\n    auto conn = co_await pool_.async_get_connection();\n\n    // Retrieve the order.\n    // SELECT ... FOR UPDATE places a lock on the order and the item,\n    // so they're not modified by other transactions while we use them.\n    mysql::static_results<std::tuple<>, order> result1;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"START TRANSACTION;\"\n            \"SELECT ord.id AS id, status FROM orders ord\"\n            \"  JOIN order_items it ON (ord.id = it.order_id)\"\n            \"  WHERE it.id = {} FOR UPDATE\",\n            item_id\n        ),\n        result1\n    );\n\n    // Check that the item exists\n    if (result1.rows<1>().empty())\n    {\n        // Not found. We did mutate session state by opening a transaction,\n        // so we can't use return_without_reset\n        co_return orders::errc::not_found;\n    }\n    const order& ord = result1.rows<1>().front();\n\n    // Check that the order is editable\n    if (ord.status != orders::status_draft)\n    {\n        co_return orders::errc::order_invalid_status;\n    }\n\n    // Perform the deletion and retrieve the items\n    mysql::static_results<std::tuple<>, order_item, std::tuple<>> result2;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"DELETE FROM order_items WHERE id = {};\"\n            \"SELECT id, product_id, quantity FROM order_items WHERE order_id = {};\"\n            \"COMMIT\",\n            item_id,\n            ord.id\n        ),\n        result2\n    );\n\n    // If everything went well, we didn't mutate session state\n    conn.return_without_reset();\n\n    // Compose the return value\n    co_return order_with_items{\n        ord.id,\n        ord.status,\n        {result2.rows<1>().begin(), result2.rows<1>().end()}\n    };\n}\n\n// Helper function to implement checkout_order and complete_order\nstatic asio::awaitable<boost::system::result<order_with_items>> change_order_status(\n    mysql::connection_pool& pool,\n    std::int64_t order_id,\n    std::string_view original_status,  // The status that the order should have\n    std::string_view target_status     // The status to transition the order to\n)\n{\n    // Get a connection from the pool\n    auto conn = co_await pool.async_get_connection();\n\n    // Retrieve the order and lock it.\n    // FOR UPDATE places an exclusive lock on the order,\n    // preventing other concurrent transactions (including the ones\n    // related to adding/removing items) from changing the order\n    mysql::static_results<std::tuple<>, std::tuple<std::string>> result1;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"START TRANSACTION;\"\n            \"SELECT status FROM orders WHERE id = {} FOR UPDATE;\",\n            order_id\n        ),\n        result1\n    );\n\n    // Check that the order exists\n    if (result1.rows<1>().empty())\n    {\n        co_return orders::errc::not_found;\n    }\n\n    // Check that the order is in the expected status\n    if (std::get<0>(result1.rows<1>().front()) != original_status)\n    {\n        co_return orders::errc::order_invalid_status;\n    }\n\n    // Update the order and retrieve the order details\n    mysql::static_results<std::tuple<>, order_item, std::tuple<>> result2;\n    co_await conn->async_execute(\n        mysql::with_params(\n            \"UPDATE orders SET status = {1} WHERE id = {0};\"\n            \"SELECT id, product_id, quantity FROM order_items WHERE order_id = {0};\"\n            \"COMMIT\",\n            order_id,\n            target_status\n        ),\n        result2\n    );\n\n    // If everything went well, we didn't mutate session state\n    conn.return_without_reset();\n\n    // Compose the return value\n    co_return order_with_items{\n        order_id,\n        std::string(target_status),\n        {result2.rows<1>().begin(), result2.rows<1>().end()}\n    };\n}\n\nasio::awaitable<boost::system::result<order_with_items>> db_repository::checkout_order(std::int64_t id)\n{\n    return change_order_status(pool_, id, status_draft, status_pending_payment);\n}\n\nasio::awaitable<boost::system::result<order_with_items>> db_repository::complete_order(std::int64_t id)\n{\n    return change_order_status(pool_, id, status_pending_payment, status_complete);\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/repository.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_REPOSITORY_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_REPOSITORY_HPP\n\n//[example_http_server_cpp20_repository_hpp\n//\n// File: repository.hpp\n//\n\n#include <boost/mysql/connection_pool.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/system/result.hpp>\n\n#include <cstdint>\n#include <string_view>\n#include <vector>\n\n#include \"types.hpp\"\n\nnamespace orders {\n\n// Encapsulates database logic.\n// If the database is unavailable, these functions throw.\n// Additionally, functions that may fail depending on the supplied input\n// return boost::system::result<T>, avoiding exceptions in common cases.\nclass db_repository\n{\n    boost::mysql::connection_pool& pool_;\n\npublic:\n    // Constructor (this is a cheap-to-construct object)\n    db_repository(boost::mysql::connection_pool& pool) noexcept : pool_(pool) {}\n\n    // Retrieves products using a full-text search\n    boost::asio::awaitable<std::vector<product>> get_products(std::string_view search);\n\n    // Retrieves all the orders in the database\n    boost::asio::awaitable<std::vector<order>> get_orders();\n\n    // Retrieves an order by ID.\n    // Returns an error if the ID doesn't match any order.\n    boost::asio::awaitable<boost::system::result<order_with_items>> get_order_by_id(std::int64_t id);\n\n    // Creates an empty order. Returns the created order.\n    boost::asio::awaitable<order_with_items> create_order();\n\n    // Adds an item to an order. Retrieves the updated order.\n    // Returns an error if the ID doesn't match any order, the order\n    // is not editable, or the product_id doesn't match any product\n    boost::asio::awaitable<boost::system::result<order_with_items>> add_order_item(\n        std::int64_t order_id,\n        std::int64_t product_id,\n        std::int64_t quantity\n    );\n\n    // Removes an item from an order. Retrieves the updated order.\n    // Returns an error if the ID doesn't match any order item\n    // or the order is not editable.\n    boost::asio::awaitable<boost::system::result<order_with_items>> remove_order_item(std::int64_t item_id);\n\n    // Checks an order out, transitioning it to the pending_payment status.\n    // Returns an error if the ID doesn't match any order\n    // or the order is not editable.\n    boost::asio::awaitable<boost::system::result<order_with_items>> checkout_order(std::int64_t id);\n\n    // Completes an order, transitioning it to the complete status.\n    // Returns an error if the ID doesn't match any order\n    // or the order is not checked out.\n    boost::asio::awaitable<boost::system::result<order_with_items>> complete_order(std::int64_t id);\n};\n\n}  // namespace orders\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/server.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/pfr/config.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n//[example_http_server_cpp20_server_cpp\n//\n// File: server.cpp\n//\n// This file contains all the boilerplate code to implement a HTTP\n// server. Functions here end up invoking handle_request.\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/asio/as_tuple.hpp>\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/ip/address.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/redirect_error.hpp>\n#include <boost/asio/steady_timer.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/beast/core/flat_buffer.hpp>\n#include <boost/beast/http/error.hpp>\n#include <boost/beast/http/message.hpp>\n#include <boost/beast/http/parser.hpp>\n#include <boost/beast/http/read.hpp>\n#include <boost/beast/http/string_body.hpp>\n#include <boost/beast/http/verb.hpp>\n#include <boost/beast/http/write.hpp>\n\n#include <cstdlib>\n#include <exception>\n#include <iostream>\n#include <string_view>\n\n#include \"error.hpp\"\n#include \"handle_request.hpp\"\n#include \"server.hpp\"\n\nnamespace asio = boost::asio;\nnamespace http = boost::beast::http;\nnamespace mysql = boost::mysql;\n\nnamespace {\n\n// Runs a single HTTP session until the client closes the connection.\n// This coroutine will be spawned on a strand, to prevent data races.\nasio::awaitable<void> run_http_session(asio::ip::tcp::socket sock, mysql::connection_pool& pool)\n{\n    using namespace std::chrono_literals;\n\n    boost::system::error_code ec;\n\n    // A buffer to read incoming client requests\n    boost::beast::flat_buffer buff;\n\n    // A timer, to use with asio::cancel_after to implement timeouts.\n    // Re-using the same timer multiple times with cancel_after\n    // is more efficient than using raw cancel_after,\n    // since the timer doesn't need to be re-created for every operation.\n    asio::steady_timer timer(co_await asio::this_coro::executor);\n\n    // A HTTP session might involve more than one message if\n    // keep-alive semantics are used. Loop until the connection closes.\n    while (true)\n    {\n        // Construct a new parser for each message\n        http::request_parser<http::string_body> parser;\n\n        // Apply a reasonable limit to the allowed size\n        // of the body in bytes to prevent abuse.\n        parser.body_limit(10000);\n\n        // Read a request. redirect_error prevents exceptions from being thrown\n        // on error. We use cancel_after to set a timeout for the overall read operation.\n        co_await http::async_read(\n            sock,\n            buff,\n            parser.get(),\n            asio::cancel_after(timer, 60s, asio::redirect_error(ec))\n        );\n\n        if (ec)\n        {\n            if (ec == http::error::end_of_stream)\n            {\n                // This means they closed the connection\n                sock.shutdown(asio::ip::tcp::socket::shutdown_send, ec);\n            }\n            else\n            {\n                // An unknown error happened\n                orders::log_error(\"Error reading HTTP request: \", ec);\n            }\n            co_return;\n        }\n\n        const auto& request = parser.get();\n\n        // Process the request to generate a response.\n        // This invokes the business logic, which will need to access MySQL data.\n        // Apply a timeout to the overall request handling process.\n        auto response = co_await asio::co_spawn(\n            // Use the same executor as this coroutine (it will be a strand)\n            co_await asio::this_coro::executor,\n\n            // The logic to invoke\n            [&] { return orders::handle_request(request, pool); },\n\n            // Completion token. Returns an object that can be co_await'ed\n            asio::cancel_after(timer, 30s)\n        );\n\n        // Adjust the response, setting fields common to all responses\n        bool keep_alive = response.keep_alive();\n        response.version(request.version());\n        response.keep_alive(keep_alive);\n        response.prepare_payload();\n\n        // Send the response\n        co_await http::async_write(sock, response, asio::cancel_after(timer, 60s, asio::redirect_error(ec)));\n        if (ec)\n        {\n            orders::log_error(\"Error writing HTTP response: \", ec);\n            co_return;\n        }\n\n        // This means we should close the connection, usually because\n        // the response indicated the \"Connection: close\" semantic.\n        if (!keep_alive)\n        {\n            sock.shutdown(asio::ip::tcp::socket::shutdown_send, ec);\n            co_return;\n        }\n    }\n}\n\n}  // namespace\n\nasio::awaitable<void> orders::run_server(mysql::connection_pool& pool, unsigned short port)\n{\n    // An object that allows us to accept incoming TCP connections\n    asio::ip::tcp::acceptor acc(co_await asio::this_coro::executor);\n\n    // The endpoint where the server will listen. Edit this if you want to\n    // change the address or port we bind to.\n    asio::ip::tcp::endpoint listening_endpoint(asio::ip::make_address(\"0.0.0.0\"), port);\n\n    // Open the acceptor\n    acc.open(listening_endpoint.protocol());\n\n    // Allow address reuse\n    acc.set_option(asio::socket_base::reuse_address(true));\n\n    // Bind to the server address\n    acc.bind(listening_endpoint);\n\n    // Start listening for connections\n    acc.listen(asio::socket_base::max_listen_connections);\n\n    std::cout << \"Server listening at \" << acc.local_endpoint() << std::endl;\n\n    // Start the acceptor loop\n    while (true)\n    {\n        // Accept a new connection\n        asio::ip::tcp::socket sock = co_await acc.async_accept();\n\n        // Function implementing our session logic.\n        // Takes ownership of the socket.\n        // Having this as a named variable workarounds a gcc bug\n        // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107288)\n        auto session_logic = [&pool, socket = std::move(sock)]() mutable {\n            return run_http_session(std::move(socket), pool);\n        };\n\n        // Launch a new session for this connection. Each session gets its\n        // own coroutine, so we can get back to listening for new connections.\n        asio::co_spawn(\n            // Every session gets its own strand. This prevents data races.\n            asio::make_strand(co_await asio::this_coro::executor),\n\n            // The actual coroutine\n            std::move(session_logic),\n\n            // Callback to run when the coroutine finishes\n            [](std::exception_ptr ptr) {\n                if (ptr)\n                {\n                    // For extra safety, log the exception but don't propagate it.\n                    // If we failed to anticipate an error condition that ends up raising an exception,\n                    // terminate only the affected session, instead of crashing the server.\n                    try\n                    {\n                        std::rethrow_exception(ptr);\n                    }\n                    catch (const std::exception& exc)\n                    {\n                        auto guard = lock_cerr();\n                        std::cerr << \"Uncaught error in a session: \" << exc.what() << std::endl;\n                    }\n                }\n            }\n        );\n    }\n}\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/server.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_SERVER_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_SERVER_HPP\n\n//[example_http_server_cpp20_server_hpp\n//\n// File: server.hpp\n//\n\n#include <boost/mysql/connection_pool.hpp>\n\n#include <boost/asio/awaitable.hpp>\n\nnamespace orders {\n\n// Launches a HTTP server that will listen on 0.0.0.0:port.\n// If the server fails to launch (e.g. because the port is already in use),\n// throws an exception. The server runs until the underlying execution\n// context is stopped.\nboost::asio::awaitable<void> run_server(boost::mysql::connection_pool& pool, unsigned short port);\n\n}  // namespace orders\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/3_advanced/http_server_cpp20/types.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_TYPES_HPP\n#define BOOST_MYSQL_EXAMPLE_3_ADVANCED_HTTP_SERVER_CPP20_TYPES_HPP\n\n//[example_http_server_cpp20_types_hpp\n//\n// File: types.hpp\n//\n// Contains type definitions used in the REST API and database code.\n// We use Boost.Describe (BOOST_DESCRIBE_STRUCT) to add reflection\n// capabilities to our types. This allows using Boost.MySQL\n// static interface (i.e. static_results<T>) to parse query results,\n// and Boost.JSON automatic serialization/deserialization.\n\n#include <boost/describe/class.hpp>\n\n#include <cstdint>\n#include <optional>\n#include <string>\n#include <string_view>\n#include <vector>\n\nnamespace orders {\n\n// A product object, as defined in the database and in the GET /products endpoint\nstruct product\n{\n    // The unique database ID of the object.\n    std::int64_t id;\n\n    // The product's display name\n    std::string short_name;\n\n    // The product's description\n    std::optional<std::string> descr;\n\n    // The product's price, in dollar cents\n    std::int64_t price;\n};\nBOOST_DESCRIBE_STRUCT(product, (), (id, short_name, descr, price))\n\n// An order object, as defined in the database and in some REST endpoints.\n// This object does not include the items associated to the order.\nstruct order\n{\n    // The unique database ID of the object.\n    std::int64_t id;\n\n    // The order status. One of \"draft\", \"pending_payment\" or \"complete\".\n    std::string status;\n};\nBOOST_DESCRIBE_STRUCT(order, (), (id, status))\n\n// Constants for the order::status member\ninline constexpr std::string_view status_draft = \"draft\";\ninline constexpr std::string_view status_pending_payment = \"pending_payment\";\ninline constexpr std::string_view status_complete = \"complete\";\n\n// An order item object, as defined in the database and in some REST endpoints.\n// Does not include the order_id database field.\nstruct order_item\n{\n    // The unique database ID of the object.\n    std::int64_t id;\n\n    // The ID of the product that this order item represents\n    std::int64_t product_id;\n\n    // The number of units of the product that this item represents.\n    // For instance, if product_id=2 and quantity=3,\n    // the user wants to buy 3 units of the product with ID 2.\n    std::int64_t quantity;\n};\nBOOST_DESCRIBE_STRUCT(order_item, (), (id, product_id, quantity))\n\n// An order object, with its associated order items.\n// Used in some REST endpoints.\nstruct order_with_items\n{\n    // The unique database ID of the object.\n    std::int64_t id;\n\n    // The order status. One of \"draft\", \"pending_payment\" or \"complete\".\n    std::string status;\n\n    // The items associated to this order.\n    std::vector<order_item> items;\n};\nBOOST_DESCRIBE_STRUCT(order_with_items, (), (id, status, items))\n\n// REST request for POST /orders/items\nstruct add_order_item_request\n{\n    // Identifies the order to which the item should be added.\n    std::int64_t order_id;\n\n    // Identifies the product that should be added to the order.\n    std::int64_t product_id;\n\n    // The number of units of the above product that should be added to the order.\n    std::int64_t quantity;\n};\nBOOST_DESCRIBE_STRUCT(add_order_item_request, (), (order_id, product_id, quantity))\n\n}  // namespace orders\n\n//]\n\n#endif\n"
  },
  {
    "path": "example/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Note: examples count as integration tests. This is only processed\n# when BOOST_MYSQL_INTEGRATION_TESTS is on\n\n# Get the MySQL hostname to use for examples\nif(DEFINED ENV{BOOST_MYSQL_SERVER_HOST})\n    set(SERVER_HOST $ENV{BOOST_MYSQL_SERVER_HOST})\nelse()\n    set(SERVER_HOST \"127.0.0.1\")\nendif()\n\nadd_library(boost_mysql_examples_common INTERFACE)\ntarget_link_libraries(\n    boost_mysql_examples_common\n    INTERFACE\n    boost_mysql_compiled\n)\n\n\nfunction(add_example EXAMPLE_NAME)\n    # Parse the arguments\n    set(ONE_VALUE_ARGS PYTHON_RUNNER)\n    set(MULTI_VALUE_ARGS SOURCES LIBS ARGS)\n    cmake_parse_arguments(ADD_EXAMPLE \"\" \"${ONE_VALUE_ARGS}\" \"${MULTI_VALUE_ARGS}\" ${ARGN})\n\n    # Create the target\n    set(TARGET_NAME \"boost_mysql_example_${EXAMPLE_NAME}\")\n    add_executable(${TARGET_NAME} ${ADD_EXAMPLE_SOURCES})\n    target_link_libraries(${TARGET_NAME} PRIVATE boost_mysql_examples_common)\n    boost_mysql_test_target_settings(${TARGET_NAME})\n    target_link_libraries(${TARGET_NAME} PRIVATE ${ADD_EXAMPLE_LIBS})\n\n    # Add it as a test\n    if (ADD_EXAMPLE_PYTHON_RUNNER)\n        add_test(\n            NAME ${TARGET_NAME}\n            COMMAND\n            python\n            ${CMAKE_CURRENT_SOURCE_DIR}/private/${ADD_EXAMPLE_PYTHON_RUNNER}\n            $<TARGET_FILE:${TARGET_NAME}>\n            ${ADD_EXAMPLE_ARGS}\n        )\n    else()\n        add_test(\n            NAME ${TARGET_NAME}\n            COMMAND ${TARGET_NAME} ${ADD_EXAMPLE_ARGS}\n        )\n    endif()\nendfunction()\n\nfunction(add_tutorial EXAMPLE_NAME EXAMPLE_PATH)\n    add_example(${EXAMPLE_NAME} SOURCES \"1_tutorial/${EXAMPLE_PATH}\" ${ARGN})\nendfunction()\n\nfunction(add_simple_example EXAMPLE_NAME)\n    add_example(${EXAMPLE_NAME} SOURCES \"2_simple/${EXAMPLE_NAME}.cpp\" ${ARGN})\nendfunction()\n\nset(REGULAR_ARGS example_user example_password ${SERVER_HOST})\n\n# Tutorials\nadd_tutorial(tutorial_sync                 1_sync.cpp                  ARGS ${REGULAR_ARGS})\nadd_tutorial(tutorial_async                2_async.cpp                 ARGS ${REGULAR_ARGS})\nadd_tutorial(tutorial_with_params          3_with_params.cpp           ARGS ${REGULAR_ARGS} 1)\nadd_tutorial(tutorial_static_interface     4_static_interface.cpp      ARGS ${REGULAR_ARGS} 1        LIBS Boost::pfr)\nadd_tutorial(tutorial_updates_transactions 5_updates_transactions.cpp  ARGS ${REGULAR_ARGS} 1 \"John\" LIBS Boost::pfr)\nadd_tutorial(tutorial_connection_pool      6_connection_pool.cpp       ARGS ${SERVER_HOST}           LIBS Boost::pfr\n    PYTHON_RUNNER run_tutorial_connection_pool.py)\nadd_tutorial(tutorial_error_handling       7_error_handling.cpp        ARGS ${SERVER_HOST} --test-errors  LIBS Boost::pfr\n    PYTHON_RUNNER run_tutorial_connection_pool.py)\n\n# Simple\nadd_simple_example(inserts                      ARGS ${REGULAR_ARGS} \"John\" \"Doe\" \"HGS\")\nadd_simple_example(deletes                      ARGS ${REGULAR_ARGS} 20)\nadd_simple_example(callbacks                    ARGS ${REGULAR_ARGS})\nadd_simple_example(coroutines_cpp11             ARGS ${REGULAR_ARGS} LIBS Boost::context)\nadd_simple_example(batch_inserts                ARGS ${SERVER_HOST}  PYTHON_RUNNER run_batch_inserts.py LIBS Boost::json)\nadd_simple_example(batch_inserts_generic        ARGS ${SERVER_HOST}  PYTHON_RUNNER run_batch_inserts.py LIBS Boost::json)\nadd_simple_example(patch_updates                ARGS ${SERVER_HOST}  PYTHON_RUNNER run_patch_updates.py)\nadd_simple_example(dynamic_filters              ARGS ${SERVER_HOST}  PYTHON_RUNNER run_dynamic_filters.py)\nadd_simple_example(disable_tls                  ARGS ${REGULAR_ARGS})\nadd_simple_example(tls_certificate_verification ARGS ${REGULAR_ARGS})\nadd_simple_example(metadata                     ARGS ${REGULAR_ARGS})\nadd_simple_example(prepared_statements          ARGS ${REGULAR_ARGS} \"HGS\")\nadd_simple_example(pipeline                     ARGS ${REGULAR_ARGS} \"HGS\")\nadd_simple_example(multi_function               ARGS ${REGULAR_ARGS})\nadd_simple_example(source_script                ARGS ${REGULAR_ARGS} ${CMAKE_CURRENT_SOURCE_DIR}/private/test_script.sql)\n\n# UNIX sockets. Don't run the example on Windows machines\nif (NOT WIN32)\n    add_simple_example(unix_socket ARGS example_user example_password)\nendif()\n\n# Advanced\nadd_example(\n    http_server_cpp14_coroutines\n    SOURCES\n        3_advanced/http_server_cpp14_coroutines/repository.cpp\n        3_advanced/http_server_cpp14_coroutines/handle_request.cpp\n        3_advanced/http_server_cpp14_coroutines/server.cpp\n        3_advanced/http_server_cpp14_coroutines/main.cpp\n    LIBS\n        Boost::context\n        Boost::json\n        Boost::url\n        Boost::beast\n    PYTHON_RUNNER run_notes.py\n    ARGS ${SERVER_HOST}\n)\n\nadd_example(\n    http_server_cpp20\n    SOURCES\n        3_advanced/http_server_cpp20/error.cpp\n        3_advanced/http_server_cpp20/repository.cpp\n        3_advanced/http_server_cpp20/handle_request.cpp\n        3_advanced/http_server_cpp20/server.cpp\n        3_advanced/http_server_cpp20/main.cpp\n    LIBS\n        Boost::json\n        Boost::url\n        Boost::beast\n        Boost::pfr\n    PYTHON_RUNNER run_orders.py\n    ARGS ${SERVER_HOST}\n)\n"
  },
  {
    "path": "example/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport os ;\nimport sequence ;\n\npath-constant this_dir : . ;\n\n# The hostname to use for examples\nlocal hostname = [ os.environ BOOST_MYSQL_SERVER_HOST ] ;\nif $(hostname) = \"\"\n{\n    hostname = \"127.0.0.1\" ;\n}\n\n# Builds and run an example\nrule run_example (\n    example_name :\n    sources * :\n    args * :\n    python_runner ? :\n    requirements *\n)\n{\n    # If we're using a Python runner, don't use Valgrind\n    local valgrind_target = /boost/mysql/test//launch_with_valgrind ;\n    local launcher = ;\n    if python_runner {\n        valgrind_target = ;\n        launcher = <testing.launcher>\"python $(this_dir)/private/$(python_runner)\" ;\n    }\n\n    # Join the supplied command-line arguments\n    local arg_str = [ sequence.join $(args) : \" \" ] ;\n\n    run\n        /boost/mysql/test//boost_mysql_compiled\n        $(valgrind_target)\n        $(sources)\n    : requirements\n        <testing.arg>$(arg_str)\n        $(launcher)\n        $(requirements)\n    : target-name $(example_name)\n    ;\n}\n\n\nlocal regular_args = example_user example_password $(hostname) ;\n\n# Tutorials\nrun_example tutorial_sync                 : 1_tutorial/1_sync.cpp                 : $(regular_args) ;\nrun_example tutorial_async                : 1_tutorial/2_async.cpp                : $(regular_args) ;\nrun_example tutorial_with_params          : 1_tutorial/3_with_params.cpp          : $(regular_args) 1 ;\nrun_example tutorial_static_interface     : 1_tutorial/4_static_interface.cpp     : $(regular_args) 1 ;\nrun_example tutorial_updates_transactions : 1_tutorial/5_updates_transactions.cpp : $(regular_args) 1 \"John\" ;\nrun_example tutorial_connection_pool      : 1_tutorial/6_connection_pool.cpp      : $(hostname)\n    : run_tutorial_connection_pool.py ;\nrun_example tutorial_error_handling       : 1_tutorial/7_error_handling.cpp       : $(hostname) --test-errors\n    : run_tutorial_connection_pool.py :  ;\n\n# Simple examples\nrun_example inserts : 2_simple/inserts.cpp\n    : $(regular_args) \"John\" \"Doe\" \"HGS\" 50000 ;\nrun_example deletes : 2_simple/deletes.cpp\n    : $(regular_args) 20 ;\nrun_example callbacks : 2_simple/callbacks.cpp\n    : $(regular_args) ;\nrun_example coroutines_cpp11 : 2_simple/coroutines_cpp11.cpp /boost/mysql/test//boost_context_lib\n    : $(regular_args) : :\n    # TODO: remove when https://github.com/boostorg/context/issues/284 is fixed\n    <warnings-as-errors>off\n;\nrun_example batch_inserts : 2_simple/batch_inserts.cpp /boost/mysql/test//boost_json_lib\n    : $(hostname) : run_batch_inserts.py ;\nrun_example batch_inserts_generic : 2_simple/batch_inserts_generic.cpp /boost/mysql/test//boost_json_lib\n    : $(hostname) : run_batch_inserts.py ;\nrun_example patch_updates : 2_simple/patch_updates.cpp\n    : $(hostname) : run_patch_updates.py ;\nrun_example dynamic_filters : 2_simple/dynamic_filters.cpp\n    : $(hostname) : run_dynamic_filters.py ;\nrun_example disable_tls : 2_simple/disable_tls.cpp\n    : $(regular_args) ;\nrun_example tls_certificate_verification : 2_simple/tls_certificate_verification.cpp\n    : $(regular_args) ;\nrun_example metadata : 2_simple/metadata.cpp \n    : $(regular_args) ;\nrun_example prepared_statements : 2_simple/prepared_statements.cpp \n    : $(regular_args) \"HGS\" ;\nrun_example multi_function : 2_simple/multi_function.cpp\n    : $(regular_args) ;\nrun_example pipeline : 2_simple/pipeline.cpp\n    : $(regular_args) \"HGS\" ;\nrun_example source_script : 2_simple/source_script.cpp\n    : $(regular_args) $(this_dir)/private/test_script.sql ;\nrun_example unix_socket : 2_simple/unix_socket.cpp\n    : example_user example_password\n    :\n    :\n        <target-os>windows:<build>no\n    ;\n\n# Advanced\nrun_example http_server_cpp14_coroutines :\n        3_advanced/http_server_cpp14_coroutines/main.cpp\n        3_advanced/http_server_cpp14_coroutines/repository.cpp\n        3_advanced/http_server_cpp14_coroutines/handle_request.cpp\n        3_advanced/http_server_cpp14_coroutines/server.cpp\n        /boost/mysql/test//boost_context_lib\n        /boost/mysql/test//boost_json_lib\n        /boost/url//boost_url\n        /boost/mysql/test//boost_beast_lib\n    : $(hostname)\n    : run_notes.py\n    :\n        # MSVC 14.1 fails with an internal compiler error while building server.cpp for this config\n        <toolset>msvc-14.1,<address-model>32,<cxxstd>17,<variant>release:<build>no\n        # Uses heavily Boost.Context coroutines, which aren't fully supported by asan\n        <address-sanitizer>norecover:<build>no\n        <address-sanitizer>enable:<build>no\n        # TODO: remove when https://github.com/boostorg/context/issues/284 is fixed\n        <warnings-as-errors>off\n    ;\n\nrun_example http_server_cpp20 :\n        3_advanced/http_server_cpp20/main.cpp\n        3_advanced/http_server_cpp20/repository.cpp\n        3_advanced/http_server_cpp20/handle_request.cpp\n        3_advanced/http_server_cpp20/server.cpp\n        3_advanced/http_server_cpp20/error.cpp\n        /boost/mysql/test//boost_json_lib\n        /boost/url//boost_url\n        /boost/mysql/test//boost_beast_lib\n    : $(hostname)\n    : run_orders.py\n    ;\n"
  },
  {
    "path": "example/db_setup.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\n-- Connection system variables\nSET NAMES utf8;\n\n-- Database\nDROP DATABASE IF EXISTS boost_mysql_examples;\nCREATE DATABASE boost_mysql_examples;\nUSE boost_mysql_examples;\n\n-- Tables\nCREATE TABLE company(\n    id CHAR(10) NOT NULL PRIMARY KEY,\n    name VARCHAR(100) NOT NULL,\n    tax_id VARCHAR(50) NOT NULL\n);\nCREATE TABLE employee(\n    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n    first_name VARCHAR(100) NOT NULL,\n    last_name VARCHAR(100) NOT NULL,\n    salary INT UNSIGNED,\n    company_id CHAR(10) NOT NULL,\n    FOREIGN KEY (company_id) REFERENCES company(id)\n);\nCREATE TABLE audit_log(\n    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n    t TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    msg TEXT\n);\nCREATE TABLE notes(\n    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n    title TEXT NOT NULL,\n    content TEXT NOT NULL\n);\n    \nINSERT INTO company (name, id, tax_id) VALUES\n    (\"Award Winning Company, Inc.\", \"AWC\", \"IE1234567V\"),\n    (\"Sector Global Leader Plc\", \"SGL\", \"IE1234568V\"),\n    (\"High Growth Startup, Ltd\", \"HGS\", \"IE1234569V\")\n;\nINSERT INTO employee (first_name, last_name, salary, company_id) VALUES\n    (\"Efficient\", \"Developer\", 30000, \"AWC\"),\n    (\"Lazy\", \"Manager\", 80000, \"AWC\"),\n    (\"Good\", \"Team Player\", 35000, \"HGS\"),\n    (\"Enormous\", \"Slacker\", 45000, \"SGL\"),\n    (\"Coffee\", \"Drinker\", 30000, \"HGS\"),\n    (\"Underpaid\", \"Intern\", 15000, \"AWC\")\n;\n\n-- Stored procedures\nDELIMITER //\n\nCREATE PROCEDURE get_employees(IN pin_company_id CHAR(10))\nBEGIN\n    START TRANSACTION READ ONLY;\n    SELECT id, name, tax_id FROM company WHERE id = pin_company_id;\n    SELECT first_name, last_name, salary FROM employee WHERE company_id = pin_company_id;\n    COMMIT;\nEND//\n\nCREATE PROCEDURE create_employee(\n    IN  pin_company_id CHAR(10),\n    IN  pin_first_name VARCHAR(100),\n    IN  pin_last_name VARCHAR(100),\n    OUT pout_employee_id INT\n)\nBEGIN\n    START TRANSACTION;\n    INSERT INTO employee (company_id, first_name, last_name)\n        VALUES (pin_company_id, pin_first_name, pin_last_name);\n    SET pout_employee_id = LAST_INSERT_ID();\n    INSERT INTO audit_log (msg) VALUES ('Created new employee...');\n    COMMIT;\nEND//\n\nDELIMITER ;\n\n-- User\nDROP USER IF EXISTS 'example_user'@'%';\nCREATE USER 'example_user'@'%' IDENTIFIED BY 'example_password';\nGRANT ALL PRIVILEGES ON boost_mysql_examples.* TO 'example_user'@'%';\nFLUSH PRIVILEGES;\n"
  },
  {
    "path": "example/private/employees_multiple.json",
    "content": "[\n    {\n        \"first_name\": \"Alice\",\n        \"last_name\": \"Davidson\",\n        \"salary\": 40000,\n        \"company_id\": \"HGS\"\n    },\n    {\n        \"first_name\": \"Bob\",\n        \"last_name\": \"Henrik\",\n        \"salary\": 35000,\n        \"company_id\": \"HGS\"\n    },\n    {\n        \"first_name\": \"Darth\",\n        \"last_name\": \"Smith\",\n        \"salary\": 99999,\n        \"company_id\": \"AWC\"\n    }\n]"
  },
  {
    "path": "example/private/employees_single.json",
    "content": "[\n    {\n        \"first_name\": \"Lonely\",\n        \"last_name\": \"Developer\",\n        \"salary\": 90000,\n        \"company_id\": \"AWC\"\n    }\n]"
  },
  {
    "path": "example/private/launch_server.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Utility to run the example TCP and HTTP servers\n\nimport os\nimport re\nfrom subprocess import Popen, PIPE, STDOUT\nfrom contextlib import contextmanager\n\n\n_is_win = os.name == 'nt'\n\n\n# Returns the port the server is listening at\ndef _parse_server_start_line(line: str) -> int:\n    m = re.match(r'Server listening at 0\\.0\\.0\\.0:([0-9]+)', line)\n    if m is None:\n        raise RuntimeError('Unexpected server start line')\n    return int(m.group(1))\n\n\n@contextmanager\ndef launch_server(exe: str, host: str, username: str, password: str):\n    # Launch server and let it choose a free port for us.\n    # This prevents port clashes during b2 parallel test runs\n    server = Popen([exe, username, password, host, '0'], stdout=PIPE, stderr=STDOUT)\n    assert server.stdout is not None\n    with server:\n        try:\n            # Wait until the server is ready\n            ready_line = server.stdout.readline().decode()\n            print(ready_line, end='', flush=True)\n            if ready_line.startswith('Sorry'): # C++ standard unsupported, skip the test\n                exit(0)\n            yield _parse_server_start_line(ready_line)\n        finally:\n            print('Terminating server...', flush=True)\n\n            # In Windows, there is no sane way to cleanly terminate the process.\n            # Sending a Ctrl-C terminates all process attached to the console (including ourselves\n            # and any parent test runner). Running the process in a separate terminal doesn't allow\n            # access to stdout, which is problematic, too.\n            # terminate() sends SIGTERM in Unix, and uses TerminateProcess in Windows\n            server.terminate()\n\n            # Print any output the process generated\n            print('Server stdout: \\n', server.stdout.read().decode(), flush=True)\n\n    # The return code is only relevant in Unix, as in Windows we used TerminateProcess\n    if not _is_win and server.returncode != 0:\n        raise RuntimeError('Server did not exit cleanly. retcode={}'.format(server.returncode))\n"
  },
  {
    "path": "example/private/run_batch_inserts.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom subprocess import run\nimport argparse\nfrom os import path\n\n# Helper to run the batch inserts example\n\n_this_dir = path.abspath(path.dirname(path.realpath(__file__)))\n\nclass _Runner:\n    def __init__(self, exe: str, host: str) -> None:\n        self._exe = exe\n        self._host = host\n    \n    def run(self, fname: str) -> None:\n        json_path = path.join(_this_dir, fname)\n        cmdline = [self._exe, 'example_user', 'example_password', self._host, json_path]\n        print(' + ', ' '.join(cmdline))\n        run(cmdline, check=True)\n\n\ndef main():\n    # Parse command line\n    parser = argparse.ArgumentParser()\n    parser.add_argument('executable')\n    parser.add_argument('host')\n    args = parser.parse_args()\n\n    # Build a runner\n    runner = _Runner(args.executable, args.host)\n\n    # Run the example with several combinations\n    runner.run('employees_single.json')\n    runner.run('employees_multiple.json')\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "example/private/run_dynamic_filters.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom subprocess import run\nimport argparse\nfrom typing import List\n\n# Helper to run the dynamic filters example\n\nclass _Runner:\n    def __init__(self, exe: str, host: str) -> None:\n        self._exe = exe\n        self._host = host\n    \n    def run(self, opts: List[str]) -> None:\n        cmdline = [self._exe, 'example_user', 'example_password', self._host] + opts\n        print(' + ', ' '.join(cmdline))\n        run(cmdline, check=True)\n\n\ndef main():\n    # Parse command line\n    parser = argparse.ArgumentParser()\n    parser.add_argument('executable')\n    parser.add_argument('host')\n    args = parser.parse_args()\n\n    # Build a runner\n    runner = _Runner(args.executable, args.host)\n\n    # Run the example with several combinations\n    runner.run(['--company-id=HGS'])\n    runner.run(['--company-id=AWC', '--last-name=Alice'])\n    runner.run(['--min-salary=25000', '--first-name=Bob', '--order-by=salary'])\n    runner.run(['--company-id=AWC', '--first-name=Underpaid', '--last-name=Intern', '--min-salary=1', '--order-by=salary'])\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "example/private/run_notes.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport requests\nimport random\nimport argparse\nimport sys\nfrom os import path\n\nsys.path.append(path.abspath(path.dirname(path.realpath(__file__))))\nfrom launch_server import launch_server\n\n\ndef _check_response(res: requests.Response):\n    if res.status_code >= 400:\n        print(res.text)\n    res.raise_for_status()\n\n\ndef _random_string() -> str:\n    return bytes(random.getrandbits(8) for _ in range(8)).hex()\n\n\ndef _call_endpoints(port: int):\n    url = 'http://127.0.0.1:{}/notes'.format(port)\n\n    # Create a note\n    note_unique = _random_string()\n    title = 'My note {}'.format(note_unique)\n    content = 'This is a note about {}'.format(note_unique)\n    res = requests.post(\n        url,\n        json={'title': title, 'content': content}\n    )\n    _check_response(res)\n    note = res.json()\n    note_id = int(note['note']['id'])\n    assert note['note']['title'] == title\n    assert note['note']['content'] == content\n\n    # Retrieve all notes\n    res = requests.get(url)\n    _check_response(res)\n    all_notes = res.json()\n    assert len([n for n in all_notes['notes'] if n['id'] == note_id]) == 1\n\n    # Edit the note\n    note_unique = _random_string()\n    title = 'Edited {}'.format(note_unique)\n    content = 'This is a note an edit on {}'.format(note_unique)\n    res = requests.put(\n        url,\n        params={'id': note_id},\n        json={'title': title, 'content': content}\n    )\n    _check_response(res)\n    note = res.json()\n    assert int(note['note']['id']) == note_id\n    assert note['note']['title'] == title\n    assert note['note']['content'] == content\n\n    # Retrieve the note\n    res = requests.get(url, params={'id': note_id})\n    _check_response(res)\n    note = res.json()\n    assert int(note['note']['id']) == note_id\n    assert note['note']['title'] == title\n    assert note['note']['content'] == content\n\n    # Delete the note\n    res = requests.delete(url, params={'id': note_id})\n    _check_response(res)\n    assert res.json()['deleted'] == True\n\n    # The note is not there\n    res = requests.get(url, params={'id': note_id})\n    assert res.status_code == 404\n\n\ndef main():\n    # Parse command line arguments\n    parser = argparse.ArgumentParser()\n    parser.add_argument('executable')\n    parser.add_argument('host')\n    args = parser.parse_args()\n\n    # Launch the server\n    with launch_server(args.executable, args.host, 'example_user', 'example_password') as listening_port:\n    # Run the tests\n        _call_endpoints(listening_port)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "example/private/run_orders.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport requests\nimport argparse\nfrom os import path\nimport unittest\nimport copy\nimport sys\n\nsys.path.append(path.abspath(path.dirname(path.realpath(__file__))))\nfrom launch_server import launch_server\n\n\nclass TestOrders(unittest.TestCase):\n    _port = -1\n\n    @property\n    def _base_url(self) -> str:\n        return 'http://127.0.0.1:{}'.format(self._port)\n    \n    @staticmethod\n    def _json_response(res: requests.Response):\n        if res.status_code >= 400:\n            print(res.text)\n        res.raise_for_status()\n        return res.json()\n\n\n    def _check_error(self, res: requests.Response, expected_status: int) -> None:\n        self.assertEqual(res.status_code, expected_status)\n    \n\n    def _request(self, method: str, url: str, **kwargs) -> requests.Response:\n        return requests.request(method=method, url=self._base_url + url, **kwargs)\n\n\n    def _request_as_json(self, method: str, url: str, **kwargs):\n        return self._json_response(self._request(method, url, **kwargs))\n    \n\n    def _request_error(self, method: str, url: str, expected_status: int, **kwargs):\n        return self._check_error(self._request(method, url, **kwargs), expected_status)\n\n    #\n    # Success cases \n    #\n    def test_search_products(self) -> None:\n        # Issue the request\n        products = self._request_as_json('get', '/products', params={'search': 'odin'})\n\n        # Check\n        self.assertNotEqual(len(products), 0) # At least one product\n        odin = products[0]\n        self.assertIsInstance(odin['id'], int) # We don't know the exact ID\n        self.assertEqual(odin['short_name'], 'A Feast for Odin')\n        self.assertEqual(odin['price'], 6400)\n        self.assertIsInstance(odin['descr'], str)\n    \n\n    def test_order_lifecycle(self) -> None:\n        # Create an order\n        order = self._request_as_json('post', '/orders')\n        order_id = order['id']\n        self.assertIsInstance(order_id, int)\n        self.assertEqual(order['status'], 'draft')\n        self.assertEqual(order['items'], [])\n\n        # Add an item\n        order = self._request_as_json('post', '/orders/items', json={\n            'order_id': order_id,\n            'product_id': 2,\n            'quantity': 20\n        })\n        items = order['items']\n        self.assertEqual(order['id'], order_id)\n        self.assertEqual(order['status'], 'draft')\n        self.assertEqual(len(order['items']), 1)\n        self.assertIsInstance(items[0]['id'], int)\n        self.assertEqual(items[0]['product_id'], 2)\n        self.assertEqual(items[0]['quantity'], 20)\n\n        # Checkout\n        expected_order = copy.deepcopy(order)\n        expected_order['status'] = 'pending_payment'\n        order = self._request_as_json('post', '/orders/checkout', params={'id': order_id})\n        self.assertEqual(order, expected_order)\n\n        # Complete\n        expected_order = copy.deepcopy(order)\n        expected_order['status'] = 'complete'\n        order = self._request_as_json('post', '/orders/complete', params={'id': order_id})\n        self.assertEqual(order, expected_order)\n    \n\n    def test_remove_items(self) -> None:\n        # Create an order\n        order1 = self._request_as_json('post', '/orders')\n        order_id = order1['id']\n\n        # Create two items\n        self._request_as_json('post', '/orders/items', json={\n            'order_id': order_id,\n            'product_id': 2,\n            'quantity': 20\n        })\n        order2 = self._request_as_json('post', '/orders/items', json={\n            'order_id': order_id,\n            'product_id': 1,\n            'quantity': 1\n        })\n        order2_items = order2['items']\n\n        # Sanity check\n        self.assertEqual(order2['id'], order_id)\n        self.assertEqual(order2['status'], 'draft')\n        self.assertEqual(len(order2_items), 2)\n        product_ids = list(set(item['product_id'] for item in order2_items))\n        self.assertEqual(product_ids, [1, 2]) # IDs 1 and 2 in any order\n\n        # Delete one of the items\n        order3 = self._request_as_json('delete', '/orders/items', params={'id': order2_items[0]['id']})\n        self.assertEqual(order3['id'], order_id)\n        self.assertEqual(order3['status'], 'draft')\n        self.assertEqual(order3['items'], [order2_items[1]])\n    \n\n    def test_get_orders(self) -> None:\n        orders = self._request_as_json('get', '/orders')\n        self.assertIsInstance(orders, list)\n    \n\n    def test_get_single_order(self) -> None:\n        # Create an order and add an item\n        order = self._request_as_json('post', '/orders')\n        order = self._request_as_json('post', '/orders/items', json={\n            'order_id': order['id'],\n            'product_id': 2,\n            'quantity': 20\n        })\n\n        # Retrieve the order by id\n        order2 = self._request_as_json('get', '/orders', params={'id': order['id']})\n        self.assertEqual(order2, order)\n    \n\n    #\n    # Search products errors\n    #\n    def test_search_products_missing_param(self) -> None:\n        self._request_error('get', '/products', expected_status=400)\n    \n\n    #\n    # Get order errors\n    #\n    def test_get_order_invalid_id(self) -> None:\n        self._request_error('get', '/orders', params={'id': 'abc'}, expected_status=400)\n    \n\n    def test_get_order_not_found(self) -> None:\n        self._request_error('get', '/orders', params={'id': 0xffffff}, expected_status=404)\n\n\n    #\n    # Add order item errors\n    #\n    def test_add_order_item_invalid_content_type(self) -> None:\n        # Create an order\n        order_id = self._request_as_json('post', '/orders')['id']\n        \n        # Check the error\n        self._request_error('post', '/orders/items', headers={'Content-Type':'text/html'}, json={\n            'order_id': order_id,\n            'product_id': 1,\n            'quantity': 1\n        }, expected_status=400)\n\n\n    def test_add_order_item_invalid_json(self) -> None:\n        self._request_error('post', '/orders/items', headers={'Content-Type':'application/json'},\n                            data='bad', expected_status=400)\n\n\n    def test_add_order_item_invalid_json_keys(self) -> None:\n        self._request_error('post', '/orders/items', json={\n            'order_id': '1',\n            'product_id': 1,\n            'quantity': 1\n        }, expected_status=400)\n    \n\n    def test_add_order_item_order_not_found(self) -> None:\n        self._request_error('post', '/orders/items', json={\n            'order_id': 0xffffffff,\n            'product_id': 1,\n            'quantity': 1\n        }, expected_status=404)\n    \n\n    def test_add_order_item_product_not_found(self) -> None:\n        # Create an order\n        order_id = self._request_as_json('post', '/orders')['id']\n\n        # Check the error\n        self._request_error('post', '/orders/items', json={\n            'order_id': order_id,\n            'product_id': 0xffffffff,\n            'quantity': 1\n        }, expected_status=422)\n    \n\n    def test_add_order_item_order_not_editable(self) -> None:\n        # Create an order and check it out\n        order_id = self._request_as_json('post', '/orders')['id']\n        self._request_as_json('post', '/orders/checkout', params={'id': order_id})\n\n        # Check the error\n        self._request_error('post', '/orders/items', json={\n            'order_id': order_id,\n            'product_id': 1,\n            'quantity': 1\n        }, expected_status=422)\n\n    #\n    # Remove order item errors\n    #\n    def test_remove_order_item_missing_id(self) -> None:\n        self._request_error('delete', '/orders/items', expected_status=400)\n\n\n    def test_remove_order_item_invalid_id(self) -> None:\n        self._request_error('delete', '/orders/items', params={'id': 'abc'}, expected_status=400)\n\n\n    def test_remove_order_item_not_found(self) -> None:\n        self._request_error('delete', '/orders/items', params={'id': 0xffffffff}, expected_status=404)\n\n\n    def test_remove_order_item_order_not_editable(self) -> None:\n        # Create an order with an item and check it out\n        order_id = self._request_as_json('post', '/orders')['id']\n        item_id = self._request_as_json('post', '/orders/items', json={\n            'order_id': order_id,\n            'product_id': 2,\n            'quantity': 20\n        })['items'][0]['id']\n        self._request_as_json('post', '/orders/checkout', params={'id': order_id})\n\n        # Check the error\n        self._request_error('delete', '/orders/items', params={'id': item_id}, expected_status=422)\n    \n\n    #\n    # Checkout order errors\n    #\n    def test_checkout_order_missing_id(self) -> None:\n        self._request_error('post', '/orders/checkout', expected_status=400)\n\n\n    def test_checkout_order_invalid_id(self) -> None:\n        self._request_error('post', '/orders/checkout', params={'id': 'abc'}, expected_status=400)\n\n\n    def test_checkout_order_not_found(self) -> None:\n        self._request_error('post', '/orders/checkout', params={'id': 0xffffffff}, expected_status=404)\n    \n\n    def test_checkout_order_not_editable(self) -> None:\n        # Create an order and check it out\n        order_id = self._request_as_json('post', '/orders')['id']\n        self._request_as_json('post', '/orders/checkout', params={'id': order_id})\n\n        # Check the error\n        self._request_error('post', '/orders/checkout', params={'id': order_id}, expected_status=422)\n\n\n    #\n    # Complete order errors\n    #\n    def test_complete_order_missing_id(self) -> None:\n        self._request_error('post', '/orders/complete', expected_status=400)\n\n\n    def test_complete_order_invalid_id(self) -> None:\n        self._request_error('post', '/orders/complete', params={'id': 'abc'}, expected_status=400)\n\n\n    def test_complete_order_not_found(self) -> None:\n        self._request_error('post', '/orders/complete', params={'id': 0xffffffff}, expected_status=404)\n    \n\n    def test_complete_order_not_editable(self) -> None:\n        # Create an order\n        order_id = self._request_as_json('post', '/orders')['id']\n\n        # Check the error\n        self._request_error('post', '/orders/complete', params={'id': order_id}, expected_status=422)\n    \n\n    #\n    # Generic errors\n    #\n    \n    def test_endpoint_not_found(self) -> None:\n        self._request_error('get', '/orders/other', expected_status=404)\n        self._request_error('get', '/orders_other', expected_status=404)\n    \n\n    def test_method_not_allowed(self) -> None:\n        self._request_error('delete', '/orders', expected_status=405)\n        \n\ndef main():\n    # Parse command line arguments\n    parser = argparse.ArgumentParser()\n    parser.add_argument('executable')\n    parser.add_argument('host')\n    args = parser.parse_args()\n\n    # Launch the server\n    with launch_server(args.executable, args.host, 'orders_user', 'orders_password') as listening_port:\n        TestOrders._port = listening_port\n        unittest.main(argv=[sys.argv[0]])\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "example/private/run_patch_updates.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom subprocess import run\nimport argparse\nfrom typing import List\n\n# Helper to run the batch updates example\n\nclass _Runner:\n    def __init__(self, exe: str, host: str) -> None:\n        self._exe = exe\n        self._host = host\n    \n    def run(self, updates: List[str]) -> None:\n        employee_id = '1' # Guaranteed to exist\n        cmdline = [self._exe, 'example_user', 'example_password', self._host, employee_id] + updates\n        print(' + ', ' '.join(cmdline))\n        run(cmdline, check=True)\n\n\ndef main():\n    # Parse command line\n    parser = argparse.ArgumentParser()\n    parser.add_argument('executable')\n    parser.add_argument('host')\n    args = parser.parse_args()\n\n    # Build a runner\n    runner = _Runner(args.executable, args.host)\n\n    # Run the example with several combinations\n    runner.run(['--salary=40000'])\n    runner.run(['--company-id=HGS', '--last-name=Alice'])\n    runner.run(['--salary=25000', '--company-id=AWC', '--first-name=John', '--last-name=Doe'])\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "example/private/run_tutorial_connection_pool.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport argparse\nimport sys\nfrom os import path\nimport socket\nimport struct\n\nsys.path.append(path.abspath(path.dirname(path.realpath(__file__))))\nfrom launch_server import launch_server\n\n\nclass _Runner:\n    def __init__(self, port: int) -> None:\n        self._port = port\n    \n    def _connect(self) -> socket.socket:\n        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n        sock.connect(('127.0.0.1', self._port))\n        return sock\n\n\n    def _query_employee(self, employee_id: int) -> str:\n        # Open a connection\n        sock = self._connect()\n\n        # Send the request\n        sock.send(struct.pack('>Q', employee_id))\n        \n        # Receive the response. It should always fit in a single TCP segment\n        # for the values we have in CI\n        res = sock.recv(4096).decode()\n        assert len(res) > 0\n        return res\n\n\n    def _generate_error(self) -> None:\n        # Open a connection\n        sock = self._connect()\n\n        # Send an incomplete message\n        sock.send(b'abc')\n        sock.close()\n    \n\n    def run(self, test_errors: bool) -> None:\n        # Generate an error first. The server should not terminate\n        if test_errors:\n            self._generate_error()\n        assert self._query_employee(1) != 'NOT_FOUND'\n        value = self._query_employee(0xffffffff)\n        assert value == 'NOT_FOUND', 'Value is: {}'.format(value)\n\n\ndef main():\n    # Parse command line arguments\n    parser = argparse.ArgumentParser()\n    parser.add_argument('executable')\n    parser.add_argument('host')\n    parser.add_argument('--test-errors', action='store_true')\n    args = parser.parse_args()\n\n    # Launch the server\n    with launch_server(args.executable, args.host, 'example_user', 'example_password') as listening_port:\n    # Run the tests\n        _Runner(listening_port).run(args.test_errors)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "example/private/test_script.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\nUSE boost_mysql_examples;\n\nCREATE TEMPORARY TABLE products (\n    id VARCHAR(50) PRIMARY KEY,\n    description VARCHAR(256)\n);\n\nINSERT INTO products VALUES ('PTT', 'Potatoes'), ('CAR', NULL);\nSELECT * FROM products;\nDROP TABLE products;\n"
  },
  {
    "path": "include/boost/mysql/any_address.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ANY_ADDRESS_HPP\n#define BOOST_MYSQL_ANY_ADDRESS_HPP\n\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <string>\n\nnamespace boost {\nnamespace mysql {\n\n/// The type of an address identifying a MySQL server.\nenum class address_type\n{\n    /// An Internet hostname and a TCP port.\n    host_and_port,\n\n    /// A UNIX domain socket path.\n    unix_path\n};\n\n/**\n * \\brief A host and port identifying how to connect to a MySQL server.\n * \\details\n * This is an owning type with value semantics.\n */\nstruct host_and_port\n{\n    /**\n     * \\brief The hostname where the MySQL server is expected to be listening.\n     * \\details\n     * An empty string is equivalent to `localhost`. This is the default.\n     * This is an owning field\n     */\n    std::string host;\n\n    /// The port where the MySQL server is expected to be listening.\n    unsigned short port{default_port};\n};\n\n/**\n * \\brief Contains a UNIX-socket domain path.\n * \\details\n * This type is defined in all systems, regardless of their UNIX socket support.\n * \\n\n * This is an owning type with value semantics.\n */\nstruct unix_path\n{\n    /**\n     * \\brief The UNIX domain socket path where the MySQL server is listening.\n     * \\details Defaults to the empty string. This is an owning field.\n     */\n    std::string path;\n};\n\n/**\n * \\brief A server address, identifying how to physically connect to a MySQL server.\n * \\details\n * A variant-like type that can represent the network address of a MySQL server,\n * regardless of the transport type being used. It can contain either a host\n * and port (to connect using TCP) or a UNIX path (to connect using UNIX domain sockets).\n * \\n\n * This class may be extended in the future to accommodate Windows named pipes.\n * \\n\n * This type has value semantics: it is owning and regular.\n */\nclass any_address\n{\n#ifndef BOOST_MYSQL_DOXYGEN\n    struct\n    {\n        address_type type;\n        std::string address;\n        unsigned short port;\n    } impl_;\n\n    any_address(address_type t, std::string&& addr, unsigned short port) noexcept\n        : impl_{t, std::move(addr), port}\n    {\n    }\n    friend struct detail::access;\n#endif\n\npublic:\n    /**\n     * \\brief Constructs an empty address.\n     * \\details Results in an address with `this->type() == address_type::host_and_port`,\n     * `this->hostname() == \"\"` and `this->port() == default_port`, which identifies\n     * a server running on `localhost` using the default port.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    any_address() noexcept : any_address(address_type::host_and_port, std::string(), default_port) {}\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Exceptions may be thrown by memory allocations.\n     * \\par Object lifetimes\n     * `*this` and `other` will have independent lifetimes (regular value semantics).\n     */\n    any_address(const any_address& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\details Leaves `other` in a valid but unspecified state.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    any_address(any_address&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Exceptions may be thrown by memory allocations.\n     * \\par Object lifetimes\n     * `*this` and `other` will have independent lifetimes (regular value semantics).\n     */\n    any_address& operator=(const any_address& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\details Leaves `other` in a valid but unspecified state.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    any_address& operator=(any_address&& other) = default;\n\n    /// Destructor.\n    ~any_address() = default;\n\n    /**\n     * \\brief Constructs an address containing a host and a port.\n     * \\details Results in an address with `this->type() == address_type::host_and_port`,\n     * `this->hostname() == value.hostname()` and `this->port() == value.port()`.\n     *\n     * \\par Object lifetimes\n     * `*this` and `value` will have independent lifetimes (regular value semantics).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    any_address(host_and_port value) noexcept\n        : impl_{address_type::host_and_port, std::move(value.host), value.port}\n    {\n    }\n\n    /**\n     * \\brief Constructs an address containing a UNIX socket path.\n     * \\details Results in an address with `this->type() == address_type::unix_path`,\n     * `this->unix_socket_path() == value.path()`.\n     *\n     * \\par Object lifetimes\n     * `*this` and `value` will have independent lifetimes (regular value semantics).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    any_address(unix_path value) noexcept : impl_{address_type::unix_path, std::move(value.path), 0} {}\n\n    /**\n     * \\brief Retrieves the type of address that this object contains.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    address_type type() const noexcept { return impl_.type; }\n\n    /**\n     * \\brief Retrieves the hostname that this object contains.\n     * \\par Preconditions\n     * `this->type() == address_type::host_and_port`\n     *\n     * \\par Object lifetimes\n     * The returned view points into `*this`, and is valid as long as `*this`\n     * is alive and hasn't been assigned to or moved from.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    string_view hostname() const noexcept\n    {\n        BOOST_ASSERT(type() == address_type::host_and_port);\n        return impl_.address;\n    }\n\n    /**\n     * \\brief Retrieves the port that this object contains.\n     * \\par Preconditions\n     * `this->type() == address_type::host_and_port`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    unsigned short port() const noexcept\n    {\n        BOOST_ASSERT(type() == address_type::host_and_port);\n        return impl_.port;\n    }\n\n    /**\n     * \\brief Retrieves the UNIX socket path that this object contains.\n     * \\par Preconditions\n     * `this->type() == address_type::unix_path`\n     *\n     * \\par Object lifetimes\n     * The returned view points into `*this`, and is valid as long as `*this`\n     * is alive and hasn't been assigned to or moved from.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    string_view unix_socket_path() const noexcept\n    {\n        BOOST_ASSERT(type() == address_type::unix_path);\n        return impl_.address;\n    }\n\n    /**\n     * \\brief Replaces the current object with a host and port.\n     * \\details\n     * Destroys the current contained object and constructs a new\n     * host and port from the passed components. This function can\n     * change the underlying type of object held by `*this`.\n     * \\n\n     * The constructed object has `this->type() == address_type::host_and_port`,\n     * `this->hostname() == hostname` and `this->port() == port`.\n     * \\n\n     * An empty hostname is equivalent to `localhost`.\n     * \\n\n     * \\par Exception safety\n     * Basic guarantee. Memory allocations may throw.\n     * \\par Object lifetimes\n     * Invalidates views pointing into `*this`.\n     */\n    void emplace_host_and_port(std::string hostname, unsigned short port = default_port)\n    {\n        impl_.type = address_type::host_and_port;\n        impl_.address = std::move(hostname);\n        impl_.port = port;\n    }\n\n    /**\n     * \\brief Replaces the current object with a UNIX socket path.\n     * \\details\n     * Destroys the current contained object and constructs a new\n     * UNIX socket path from the passed value. This function can\n     * change the underlying type of object held by `*this`.\n     * \\n\n     * The constructed object has `this->type() == address_type::unix_path` and\n     * `this->unix_socket_path() == path`.\n     * \\n\n     * \\par Exception safety\n     * Basic guarantee. Memory allocations may throw.\n     * \\par Object lifetimes\n     * Invalidates views pointing into `*this`.\n     */\n    void emplace_unix_path(std::string path)\n    {\n        impl_.type = address_type::unix_path;\n        impl_.address = std::move(path);\n        impl_.port = 0;\n    }\n\n    /**\n     * \\brief Tests for equality.\n     * \\details Two addresses are equal if they have the same type and individual components.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool operator==(const any_address& rhs) const noexcept\n    {\n        return impl_.type == rhs.impl_.type && impl_.address == rhs.impl_.address &&\n               impl_.port == rhs.impl_.port;\n    }\n\n    /**\n     * \\brief Tests for inequality.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool operator!=(const any_address& rhs) const noexcept { return !(*this == rhs); }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/any_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ANY_CONNECTION_HPP\n#define BOOST_MYSQL_ANY_CONNECTION_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/connect_params_helpers.hpp>\n#include <boost/mysql/detail/connection_impl.hpp>\n#include <boost/mysql/detail/engine.hpp>\n#include <boost/mysql/detail/execution_concepts.hpp>\n#include <boost/mysql/detail/ssl_fwd.hpp>\n#include <boost/mysql/detail/throw_on_error_loc.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/deferred.hpp>\n#include <boost/assert.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/system/result.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n// Forward declarations\ntemplate <class... StaticRow>\nclass static_execution_state;\n\nclass pipeline_request;\nclass stage_response;\n\n/**\n * \\brief Configuration parameters that can be passed to \\ref any_connection's constructor.\n */\nstruct any_connection_params\n{\n    /**\n     * \\brief An external SSL context containing options to configure TLS.\n     * \\details\n     * Relevant only for SSL connections (those that result on \\ref\n     * any_connection::uses_ssl returning `true`).\n     * \\n\n     * If the connection is configured to use TLS, an internal `asio::ssl::stream`\n     * object will be created. If this member is set to a non-null value,\n     * this internal object will be initialized using the passed context.\n     * This is the only way to configure TLS options in `any_connection`.\n     * \\n\n     * If the connection is configured to use TLS and this member is `nullptr`,\n     * an internal `asio::ssl::context` object with suitable default options\n     * will be created.\n     *\n     * \\par Object lifetimes\n     * If set to non-null, the pointee object must be kept alive until\n     * all \\ref any_connection objects constructed from `*this` are destroyed.\n     */\n    asio::ssl::context* ssl_context{};\n\n    /**\n     * \\brief The initial size of the connection's buffer, in bytes.\n     * \\details A bigger read buffer can increase the number of rows\n     * returned by \\ref any_connection::read_some_rows.\n     */\n    std::size_t initial_buffer_size{default_initial_read_buffer_size};\n\n    /**\n     * \\brief The maximum size of the connection's buffer, in bytes (64MB by default).\n     * \\details\n     * Attempting to read or write a protocol packet bigger than this size\n     * will fail with a \\ref client_errc::max_buffer_size_exceeded error.\n     * \\n\n     * This effectively means: \\n\n     *   - Each request sent to the server must be smaller than this value.\n     *   - Each individual row received from the server must be smaller than this value.\n     *     Note that when using `execute` or `async_execute`, results objects may\n     *     allocate memory beyond this limit if the total number of rows is high.\n     * \\n\n     * If you need to send or receive larger packets, you may need to adjust\n     * your server's <a\n     * href=\"https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html#sysvar_max_allowed_packet\">`max_allowed_packet`</a>\n     * system variable, too.\n     */\n    std::size_t max_buffer_size{0x4000000};\n};\n\n/**\n * \\brief A connection to a MySQL server.\n * \\details\n * Represents a connection to a MySQL server.\n * This is the main I/O object that this library implements. It's logically comprised\n * of session state and an internal stream (usually a socket). The stream is not directly\n * accessible. It's constructed using the executor passed to the constructor.\n *\n * This class supports establishing connections\n * with servers using TCP, TCP over TLS and UNIX sockets.\n *\n * The class is named `any_connection` because it's not templated on a `Stream`\n * type, as opposed to \\ref connection. New code should prefer using `any_connection`\n * whenever possible.\n *\n * Compared to \\ref connection, this class:\n *\n * - Is type-erased. The type of the connection doesn't depend on the transport being used.\n * - Is easier to connect, as \\ref connect and \\ref async_connect handle hostname resolution.\n * - Can always be re-connected after being used or encountering an error.\n * - Always uses `asio::any_io_executor`.\n * - Has the same level of performance.\n *\n * This is a move-only type.\n *\n * \\par Single outstanding async operation per connection\n * At any given point in time, only one async operation can be outstanding\n * per connection. If an async operation is initiated while another one is in progress,\n * it will fail with \\ref client_errc::operation_in_progress.\n *\n * \\par Default completion tokens\n * The default completion token for all async operations in this class is\n * `with_diagnostics(asio::deferred)`, which allows you to use `co_await`\n * and have the expected exceptions thrown on error.\n *\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe. \\n\n * This class is <b>not thread-safe</b>: for a single object, if you\n * call its member functions concurrently from separate threads, you will get a race condition.\n */\nclass any_connection\n{\n    detail::connection_impl impl_;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n\n    BOOST_MYSQL_DECL\n    static std::unique_ptr<detail::engine> create_engine(asio::any_io_executor ex, asio::ssl::context* ctx);\n\n    // Used by tests\n    any_connection(std::unique_ptr<detail::engine> eng, any_connection_params params)\n        : impl_(params.initial_buffer_size, params.max_buffer_size, std::move(eng))\n    {\n    }\n\npublic:\n    /**\n     * \\brief Constructs a connection object from an executor and an optional set of parameters.\n     * \\details\n     * The resulting connection has `this->get_executor() == ex`. Any internally required I/O objects\n     * will be constructed using this executor.\n     * \\n\n     * You can configure extra parameters, like the SSL context and buffer sizes, by passing\n     * an \\ref any_connection_params object to this constructor.\n     */\n    any_connection(boost::asio::any_io_executor ex, any_connection_params params = {})\n        : any_connection(create_engine(std::move(ex), params.ssl_context), params)\n    {\n    }\n\n    /**\n     * \\brief Constructs a connection object from an execution context and an optional set of parameters.\n     * \\details\n     * The resulting connection has `this->get_executor() == ctx.get_executor()`.\n     * Any internally required I/O objects will be constructed using this executor.\n     * \\n\n     * You can configure extra parameters, like the SSL context and buffer sizes, by passing\n     * an \\ref any_connection_params object to this constructor.\n     * \\n\n     * This function participates in overload resolution only if `ExecutionContext`\n     * satisfies the `ExecutionContext` requirements imposed by Boost.Asio.\n     */\n    template <\n        class ExecutionContext\n#ifndef BOOST_MYSQL_DOXYGEN\n        ,\n        class = typename std::enable_if<std::is_convertible<\n            decltype(std::declval<ExecutionContext&>().get_executor()),\n            asio::any_io_executor>::value>::type\n#endif\n        >\n    any_connection(ExecutionContext& ctx, any_connection_params params = {})\n        : any_connection(ctx.get_executor(), params)\n    {\n    }\n\n    /**\n     * \\brief Move constructor.\n     */\n    any_connection(any_connection&& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     */\n    any_connection& operator=(any_connection&& rhs) = default;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    any_connection(const any_connection&) = delete;\n    any_connection& operator=(const any_connection&) = delete;\n#endif\n\n    /**\n     * \\brief Destructor.\n     * \\details\n     * Closes the connection at the transport layer (by closing any underlying socket objects).\n     * If you require a clean close, call \\ref close or \\ref async_close before the connection\n     * is destroyed.\n     */\n    ~any_connection() = default;\n\n    /// The executor type associated to this object.\n    using executor_type = asio::any_io_executor;\n\n    /**\n     * \\brief Retrieves the executor associated to this object.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    executor_type get_executor() noexcept { return impl_.get_engine().get_executor(); }\n\n    /**\n     * \\brief Returns whether the connection negotiated the use of SSL or not.\n     * \\details\n     * This function can be used to determine whether you are using a SSL\n     * connection or not when using SSL negotiation.\n     * \\n\n     * This function always returns `false`\n     * for connections that haven't been established yet. If the connection establishment fails,\n     * the return value is undefined.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool uses_ssl() const noexcept { return impl_.ssl_active(); }\n\n    /**\n     * \\brief Returns whether backslashes are being treated as escape sequences.\n     * \\details\n     * By default, the server treats backslashes in string values as escape characters.\n     * This behavior can be disabled by activating the <a\n     *   href=\"https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_no_backslash_escapes\">`NO_BACKSLASH_ESCAPES`</a>\n     * SQL mode.\n     * \\n\n     * Every time an operation involving server communication completes, the server reports whether\n     * this mode was activated or not as part of the response. Connections store this information\n     * and make it available through this function.\n     * \\n\n     * \\li If backslash are treated like escape characters, returns `true`.\n     * \\li If `NO_BACKSLASH_ESCAPES` has been activated, returns `false`.\n     * \\li If connection establishment hasn't happened yet, returns `true`.\n     * \\li Calling this function while an async operation that changes backslash behavior\n     *     is outstanding may return `true` or `false`.\n     * \\n\n     * This function does not involve server communication.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool backslash_escapes() const noexcept { return impl_.backslash_escapes(); }\n\n    /**\n     * \\brief Returns the character set used by this connection.\n     * \\details\n     * Connections attempt to keep track of the current character set.\n     * Deficiencies in the protocol can cause the character set to be unknown, though.\n     * When the character set is known, this function returns\n     * the character set currently in use. Otherwise, returns \\ref client_errc::unknown_character_set.\n     * \\n\n     * The following functions can modify the return value of this function: \\n\n     *   \\li Prior to connection, the character set is always unknown.\n     *   \\li \\ref connect and \\ref async_connect may set the current character set\n     *       to a known value, depending on the requested collation.\n     *   \\li \\ref set_character_set always and \\ref async_set_character_set always\n     *       set the current character set to the passed value.\n     *   \\li \\ref reset_connection and \\ref async_reset_connection always makes the current character\n     *       unknown.\n     *\n     * \\par Avoid changing the character set directly\n     * If you change the connection's character set directly using SQL statements\n     * like `\"SET NAMES utf8mb4\"`, the client has no way to track this change,\n     * and this function will return incorrect results.\n     *\n     * \\par Errors\n     * \\li \\ref client_errc::unknown_character_set if the current character set is unknown.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    system::result<character_set> current_character_set() const noexcept\n    {\n        return impl_.current_character_set();\n    }\n\n    /**\n     * \\brief Returns format options suitable to format SQL according to the current connection configuration.\n     * \\details\n     * If the current character set is known (as given by \\ref current_character_set), returns\n     * a value suitable to be passed to SQL formatting functions. Otherwise, returns an error.\n     *\n     * \\par Errors\n     * \\li \\ref client_errc::unknown_character_set if the current character set is unknown.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    system::result<format_options> format_opts() const noexcept\n    {\n        auto res = current_character_set();\n        if (res.has_error())\n            return res.error();\n        return format_options{res.value(), backslash_escapes()};\n    }\n\n    /**\n     * \\brief Returns the current metadata mode that this connection is using.\n     * \\details\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\returns The metadata mode that will be used for queries and statement executions.\n     */\n    metadata_mode meta_mode() const noexcept { return impl_.meta_mode(); }\n\n    /**\n     * \\brief Sets the metadata mode.\n     * \\details\n     * Will affect any query and statement executions performed after the call.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * No asynchronous operation should be outstanding when this function is called.\n     *\n     * \\param v The new metadata mode.\n     */\n    void set_meta_mode(metadata_mode v) noexcept { impl_.set_meta_mode(v); }\n\n    /**\n     * \\brief Retrieves the connection id associated to the current session.\n     * \\details\n     * If a session has been established, returns its associated connection id.\n     * If no session has been established (i.e. \\ref async_connect hasn't been called yet)\n     * or the session has been terminated (i.e. \\ref async_close has been called), an empty\n     * optional is returned.\n     *\n     * The connection id is a 4 byte value that uniquely identifies a client session\n     * at a given point in time. It can be used with the\n     * <a href=\"https://dev.mysql.com/doc/refman/8.4/en/kill.html\">`KILL`</a> SQL statement\n     * to cancel queries and terminate connections.\n     *\n     * The server sends the connection id assigned to the current session as part of the\n     * handshake process. The value is stored and made available through this function.\n     * The same id can also be obtained by calling the\n     * <a\n     * href=\"https://dev.mysql.com/doc/refman/8.4/en/information-functions.html#function_connection-id\">CONNECTION_ID()</a>\n     * SQL function. However, this function is faster and more reliable, since it does not entail\n     * communication with the server.\n     *\n     * This function is equivalent to the\n     * <a href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-thread-id.html\">`mysql_thread_id`</a> function\n     * in the C connector. This function works properly in 64-bit systems, as opposed to what\n     * the official docs suggest (see\n     * <a href=\"https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-5.html\">this changelog</a>).\n     *\n     * It is safe to call this function while an async operation is outstanding, except for \\ref async_connect\n     * and \\ref async_close.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    boost::optional<std::uint32_t> connection_id() const noexcept { return impl_.connection_id(); }\n\n    /**\n     * \\brief Establishes a connection to a MySQL server.\n     * \\details\n     * This function performs the following:\n     * \\n\n     * \\li If a connection has already been established (by a previous call to \\ref connect\n     *     or \\ref async_connect), closes it at the transport layer (by closing any underlying socket)\n     *     and discards any protocol state associated to it. (If you require\n     *     a clean close, call \\ref close or \\ref async_close before using this function).\n     * \\li If the connection is configured to use TCP (`params.server_address.type() ==\n     *     address_type::host_and_port`), resolves the passed hostname to a set of endpoints. An empty\n     *     hostname is equivalent to `\"localhost\"`.\n     * \\li Establishes the physical connection (performing the\n     *     TCP or UNIX socket connect).\n     * \\li Performs the MySQL handshake to establish a session. If the\n     *     connection is configured to use TLS, the TLS handshake is performed as part of this step.\n     * \\li If any of the above steps fail, the TCP or UNIX socket connection is closed.\n     * \\n\n     * You can configure some options using the \\ref connect_params struct.\n     * \\n\n     * The decision to use TLS or not is performed using the following:\n     * \\n\n     * \\li If the transport is not TCP (`params.server_address.type() != address_type::host_and_port`),\n     *     the connection will never use TLS.\n     * \\li If the transport is TCP, and `params.ssl == ssl_mode::disable`, the connection will not use TLS.\n     * \\li If the transport is TCP, and `params.ssl == ssl_mode::enable`, the connection will use TLS\n     *     only if the server supports it.\n     * \\li If the transport is TCP, and `params.ssl == ssl_mode::require`, the connection will always use TLS.\n     *     If the server doesn't support it, the operation will fail with \\ref\n     *     client_errc::server_doesnt_support_ssl.\n     * \\n\n     * If `params.connection_collation` is within a set of well-known collations, this function\n     * sets the current character set, such that \\ref current_character_set returns a non-null value.\n     * The default collation (`utf8mb4_general_ci`) is the only one guaranteed to be in the set of well-known\n     * collations.\n     */\n    void connect(const connect_params& params, error_code& ec, diagnostics& diag)\n    {\n        impl_.connect_v2(params, ec, diag);\n    }\n\n    /// \\copydoc connect\n    void connect(const connect_params& params)\n    {\n        error_code err;\n        diagnostics diag;\n        connect(params, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc connect\n     *\n     * \\par Object lifetimes\n     * params needs to be kept alive until the operation completes, as no\n     * copies will be made by the library.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_connect(const connect_params& params, diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_connect_v2_t<CompletionToken&&>)\n    {\n        return impl_.async_connect_v2(params, diag, std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_connect\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_connect(const connect_params& params, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_connect_v2_t<CompletionToken&&>)\n    {\n        return async_connect(params, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Executes a text query or prepared statement.\n     * \\details\n     * Sends `req` to the server for execution and reads the response into `result`.\n     * `result` may be either a \\ref results or \\ref static_results object.\n     * `req` should may be either a type convertible to \\ref string_view containing valid SQL\n     * or a bound prepared statement, obtained by calling \\ref statement::bind.\n     * If a string, it must be encoded using the connection's character set.\n     * Any string parameters provided to \\ref statement::bind should also be encoded\n     * using the connection's character set.\n     * \\n\n     * After this operation completes successfully, `result.has_value() == true`.\n     * \\n\n     * Metadata in `result` will be populated according to `this->meta_mode()`.\n     */\n    template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>\n    void execute(ExecutionRequest&& req, ResultsType& result, error_code& err, diagnostics& diag)\n    {\n        impl_.execute(std::forward<ExecutionRequest>(req), result, err, diag);\n    }\n\n    /// \\copydoc execute\n    template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>\n    void execute(ExecutionRequest&& req, ResultsType& result)\n    {\n        error_code err;\n        diagnostics diag;\n        execute(std::forward<ExecutionRequest>(req), result, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc execute\n     * \\par Object lifetimes\n     * If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the caller is\n     * responsible for managing `req`'s validity following these rules:\n     * \\n\n     * \\li If `req` is `string_view`, the string pointed to by `req`\n     *     must be kept alive by the caller until the operation is initiated.\n     * \\li If `req` is a \\ref bound_statement_tuple, and any of the parameters is a reference\n     *     type (like `string_view`), the caller must keep the values pointed by these references alive\n     *     until the operation is initiated.\n     * \\li If `req` is a \\ref bound_statement_iterator_range, the caller must keep objects in\n     *     the iterator range passed to \\ref statement::bind alive until the  operation is initiated.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_RESULTS_TYPE ResultsType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_execute(ExecutionRequest&& req, ResultsType& result, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)\n    {\n        return async_execute(\n            std::forward<ExecutionRequest>(req),\n            result,\n            impl_.shared_diag(),\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc async_execute\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_RESULTS_TYPE ResultsType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_execute(\n        ExecutionRequest&& req,\n        ResultsType& result,\n        diagnostics& diag,\n        CompletionToken&& token = {}\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)\n    {\n        return impl_.async_execute(\n            std::forward<ExecutionRequest>(req),\n            result,\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /**\n     * \\brief Starts a SQL execution as a multi-function operation.\n     * \\details\n     * Writes the execution request and reads the initial server response and the column\n     * metadata, but not the generated rows or subsequent resultsets, if any.\n     * `st` may be either an \\ref execution_state or \\ref static_execution_state object.\n     * \\n\n     * After this operation completes, `st` will have\n     * \\ref execution_state::meta populated.\n     * Metadata will be populated according to `this->meta_mode()`.\n     * \\n\n     * If the operation generated any rows or more than one resultset, these <b>must</b> be read (by using\n     * \\ref read_some_rows and \\ref read_resultset_head) before engaging in any further network operation.\n     * Otherwise, the results are undefined.\n     * \\n\n     * req may be either a type convertible to \\ref string_view containing valid SQL\n     * or a bound prepared statement, obtained by calling \\ref statement::bind.\n     * If a string, it must be encoded using the connection's character set.\n     * Any string parameters provided to \\ref statement::bind should also be encoded\n     * using the connection's character set.\n     * \\n\n     * When using the static interface, this function will detect schema mismatches for the first\n     * resultset. Further errors may be detected by \\ref read_resultset_head and \\ref read_some_rows.\n     * \\n\n     */\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void start_execution(ExecutionRequest&& req, ExecutionStateType& st, error_code& err, diagnostics& diag)\n    {\n        impl_.start_execution(std::forward<ExecutionRequest>(req), st, err, diag);\n    }\n\n    /// \\copydoc start_execution\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void start_execution(ExecutionRequest&& req, ExecutionStateType& st)\n    {\n        error_code err;\n        diagnostics diag;\n        start_execution(std::forward<ExecutionRequest>(req), st, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc start_execution\n     * \\par Object lifetimes\n     * If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the caller is\n     * responsible for managing `req`'s validity following these rules:\n     * \\n\n     * \\li If `req` is `string_view`, the string pointed to by `req`\n     *     must be kept alive by the caller until the operation is initiated.\n     * \\li If `req` is a \\ref bound_statement_tuple, and any of the parameters is a reference\n     *     type (like `string_view`), the caller must keep the values pointed by these references alive\n     *     until the operation is initiated.\n     * \\li If `req` is a \\ref bound_statement_iterator_range, the caller must keep objects in\n     *     the iterator range passed to \\ref statement::bind alive until the  operation is initiated.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_start_execution(ExecutionRequest&& req, ExecutionStateType& st, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<\n                                ExecutionRequest&&,\n                                ExecutionStateType,\n                                CompletionToken&&>)\n    {\n        return async_start_execution(\n            std::forward<ExecutionRequest>(req),\n            st,\n            impl_.shared_diag(),\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc async_start_execution\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_start_execution(\n        ExecutionRequest&& req,\n        ExecutionStateType& st,\n        diagnostics& diag,\n        CompletionToken&& token = {}\n    )\n        BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<\n                                ExecutionRequest&&,\n                                ExecutionStateType,\n                                CompletionToken&&>)\n    {\n        return impl_.async_start_execution(\n            std::forward<ExecutionRequest>(req),\n            st,\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /**\n     * \\brief Prepares a statement server-side.\n     * \\details\n     * `stmt` should be encoded using the connection's character set.\n     * \\n\n     * The returned statement has `valid() == true`.\n     */\n    statement prepare_statement(string_view stmt, error_code& err, diagnostics& diag)\n    {\n        return impl_.run(detail::prepare_statement_algo_params{stmt}, err, diag);\n    }\n\n    /// \\copydoc prepare_statement\n    statement prepare_statement(string_view stmt)\n    {\n        error_code err;\n        diagnostics diag;\n        statement res = prepare_statement(stmt, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n        return res;\n    }\n\n    /**\n     * \\copydoc prepare_statement\n     * \\details\n     * \\par Object lifetimes\n     * If `CompletionToken` is a deferred completion token (e.g. `use_awaitable`), the string\n     * pointed to by `stmt` must be kept alive by the caller until the operation is\n     * initiated.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code, boost::mysql::statement)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_prepare_statement(string_view stmt, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)\n    {\n        return async_prepare_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_prepare_statement\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_prepare_statement(string_view stmt, diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)\n    {\n        return impl_.async_run(\n            detail::prepare_statement_algo_params{stmt},\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /**\n     * \\brief Closes a statement, deallocating it from the server.\n     * \\details\n     * After this operation succeeds, `stmt` must not be used again for execution.\n     * \\n\n     * \\par Preconditions\n     *    `stmt.valid() == true`\n     */\n    void close_statement(const statement& stmt, error_code& err, diagnostics& diag)\n    {\n        impl_.run(impl_.make_params_close_statement(stmt), err, diag);\n    }\n\n    /// \\copydoc close_statement\n    void close_statement(const statement& stmt)\n    {\n        error_code err;\n        diagnostics diag;\n        close_statement(stmt, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc close_statement\n     * \\details\n     * \\par Object lifetimes\n     * It is not required to keep `stmt` alive, as copies are made by the implementation as required.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_close_statement(const statement& stmt, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)\n    {\n        return async_close_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_close_statement\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_close_statement(const statement& stmt, diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_close_statement(stmt), diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * The number of rows that will be read is unspecified. If the operation represented by `st`\n     * has still rows to read, at least one will be read. If there are no more rows, or\n     * `st.should_read_rows() == false`, returns an empty `rows_view`.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in the\n     * constructor. The buffer may be\n     * grown bigger by other read operations, if required.\n     * \\n\n     * The returned view points into memory owned by `*this`. It will be valid until\n     * `*this` performs the next network operation or is destroyed.\n     */\n    rows_view read_some_rows(execution_state& st, error_code& err, diagnostics& diag)\n    {\n        return impl_.run(impl_.make_params_read_some_rows(st), err, diag);\n    }\n\n    /// \\copydoc read_some_rows(execution_state&,error_code&,diagnostics&)\n    rows_view read_some_rows(execution_state& st)\n    {\n        error_code err;\n        diagnostics diag;\n        rows_view res = read_some_rows(st, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n        return res;\n    }\n\n    /**\n     * \\copydoc read_some_rows(execution_state&,error_code&,diagnostics&)\n     * \\details\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code, boost::mysql::rows_view)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_read_some_rows(execution_state& st, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)\n    {\n        return async_read_some_rows(st, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_read_some_rows(execution_state&,CompletionToken&&)\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_read_some_rows(execution_state& st, diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_read_some_rows(st), diag, std::forward<CompletionToken>(token));\n    }\n\n#ifdef BOOST_MYSQL_CXX14\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in the\n     * constructor. The buffer may be grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     */\n    template <class SpanElementType, class... StaticRow>\n    std::size_t read_some_rows(\n        static_execution_state<StaticRow...>& st,\n        span<SpanElementType> output,\n        error_code& err,\n        diagnostics& diag\n    )\n    {\n        return impl_.run(impl_.make_params_read_some_rows_static(st, output), err, diag);\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in the\n     * constructor. The buffer may be grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     */\n    template <class SpanElementType, class... StaticRow>\n    std::size_t read_some_rows(static_execution_state<StaticRow...>& st, span<SpanElementType> output)\n    {\n        error_code err;\n        diagnostics diag;\n        std::size_t res = read_some_rows(st, output, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n        return res;\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in the\n     * constructor. The buffer may be grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code, std::size_t)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     *\n     * \\par Object lifetimes\n     * The storage that `output` references must be kept alive until the operation completes.\n     */\n    template <\n        class SpanElementType,\n        class... StaticRow,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_read_some_rows(\n        static_execution_state<StaticRow...>& st,\n        span<SpanElementType> output,\n        CompletionToken&& token = {}\n    )\n    {\n        return async_read_some_rows(st, output, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in the\n     * constructor. The buffer may be grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code, std::size_t)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     *\n     * \\par Object lifetimes\n     * The storage that `output` references must be kept alive until the operation completes.\n     */\n    template <\n        class SpanElementType,\n        class... StaticRow,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_read_some_rows(\n        static_execution_state<StaticRow...>& st,\n        span<SpanElementType> output,\n        diagnostics& diag,\n        CompletionToken&& token = {}\n    )\n    {\n        return impl_.async_run(\n            impl_.make_params_read_some_rows_static(st, output),\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n#endif\n\n    /**\n     * \\brief Reads metadata for subsequent resultsets in a multi-resultset operation.\n     * \\details\n     * If `st.should_read_head() == true`, this function will read the next resultset's\n     * initial response message and metadata, if any. If the resultset indicates a failure\n     * (e.g. the query associated to this resultset contained an error), this function will fail\n     * with that error.\n     * \\n\n     * If `st.should_read_head() == false`, this function is a no-op.\n     * \\n\n     * `st` may be either an \\ref execution_state or \\ref static_execution_state object.\n     * \\n\n     * This function is only relevant when using multi-function operations with statements\n     * that return more than one resultset.\n     * \\n\n     * When using the static interface, this function will detect schema mismatches for the resultset\n     * currently being read. Further errors may be detected by subsequent invocations of this function\n     * and by \\ref read_some_rows.\n     * \\n\n     */\n    template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void read_resultset_head(ExecutionStateType& st, error_code& err, diagnostics& diag)\n    {\n        return impl_.run(impl_.make_params_read_resultset_head(st), err, diag);\n    }\n\n    /// \\copydoc read_resultset_head\n    template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void read_resultset_head(ExecutionStateType& st)\n    {\n        error_code err;\n        diagnostics diag;\n        read_resultset_head(st, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc read_resultset_head\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_read_resultset_head(ExecutionStateType& st, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)\n    {\n        return async_read_resultset_head(st, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_read_resultset_head\n    template <\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_read_resultset_head(ExecutionStateType& st, diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_read_resultset_head(st), diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Sets the connection's character set, as per SET NAMES.\n     * \\details\n     * Sets the connection's character set by running a\n     * <a href=\"https://dev.mysql.com/doc/refman/8.0/en/set-names.html\">`SET NAMES`</a>\n     * SQL statement, using the passed \\ref character_set::name as the charset name to set.\n     * \\n\n     * This function will also update the value returned by \\ref current_character_set, so\n     * prefer using this function over raw SQL statements.\n     * \\n\n     * If the server was unable to set the character set to the requested value (e.g. because\n     * the server does not support the requested charset), this function will fail,\n     * as opposed to how \\ref connect behaves when an unsupported collation is passed.\n     * This is a limitation of MySQL servers.\n     * \\n\n     * You need to perform connection establishment for this function to succeed, since it\n     * involves communicating with the server.\n     *\n     * \\par Object lifetimes\n     * `charset` will be copied as required, and does not need to be kept alive.\n     */\n    void set_character_set(const character_set& charset, error_code& err, diagnostics& diag)\n    {\n        impl_.run(detail::set_character_set_algo_params{charset}, err, diag);\n    }\n\n    /// \\copydoc set_character_set\n    void set_character_set(const character_set& charset)\n    {\n        error_code err;\n        diagnostics diag;\n        set_character_set(charset, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc set_character_set\n     * \\details\n     * \\n\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_set_character_set(const character_set& charset, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_set_character_set_t<CompletionToken&&>)\n    {\n        return async_set_character_set(charset, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_set_character_set\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_set_character_set(\n        const character_set& charset,\n        diagnostics& diag,\n        CompletionToken&& token = {}\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_set_character_set_t<CompletionToken&&>)\n    {\n        return impl_.async_run(\n            detail::set_character_set_algo_params{charset},\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /**\n     * \\brief Checks whether the server is alive.\n     * \\details\n     * If the server is alive, this function will complete without error.\n     * If it's not, it will fail with the relevant network or protocol error.\n     * \\n\n     * Note that ping requests are treated as any other type of request at the protocol\n     * level, and won't be prioritized anyhow by the server. If the server is stuck\n     * in a long-running query, the ping request won't be answered until the query is\n     * finished.\n     */\n    void ping(error_code& err, diagnostics& diag) { impl_.run(detail::ping_algo_params{}, err, diag); }\n\n    /// \\copydoc ping\n    void ping()\n    {\n        error_code err;\n        diagnostics diag;\n        ping(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc ping\n     * \\details\n     * \\n\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_ping(CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)\n    {\n        return async_ping(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_ping\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_ping(diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)\n    {\n        return impl_.async_run(detail::ping_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Resets server-side session state, like variables and prepared statements.\n     * \\details\n     * Resets all server-side state for the current session:\n     * \\n\n     *   \\li Rolls back any active transactions and resets autocommit mode.\n     *   \\li Releases all table locks.\n     *   \\li Drops all temporary tables.\n     *   \\li Resets all session system variables to their default values (including the ones set by `SET\n     *       NAMES`) and clears all user-defined variables.\n     *   \\li Closes all prepared statements.\n     * \\n\n     * A full reference on the affected session state can be found\n     * <a href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-reset-connection.html\">here</a>.\n     * \\n\n     * \\n\n     * This function will not reset the current physical connection and won't cause re-authentication.\n     * It is faster than closing and re-opening a connection.\n     * \\n\n     * The connection must be connected and authenticated before calling this function.\n     * This function involves communication with the server, and thus may fail.\n     *\n     * \\par Warning on character sets\n     * This function will restore the connection's character set and collation **to the server's default**,\n     * and not to the one specified during connection establishment. Some servers have `latin1` as their\n     * default character set, which is not usually what you want. Since there is no way to know this\n     * character set, \\ref current_character_set will return `nullptr` after the operation succeeds.\n     * We recommend always using \\ref set_character_set or \\ref async_set_character_set after calling this\n     * function.\n     * \\n\n     * You can find the character set that your server will use after the reset by running:\n     * \\code\n     * \"SELECT @@global.character_set_client, @@global.character_set_results;\"\n     * \\endcode\n     */\n    void reset_connection(error_code& err, diagnostics& diag)\n    {\n        impl_.run(detail::reset_connection_algo_params{}, err, diag);\n    }\n\n    /// \\copydoc reset_connection\n    void reset_connection()\n    {\n        error_code err;\n        diagnostics diag;\n        reset_connection(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc reset_connection\n     * \\details\n     * \\n\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_reset_connection(CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)\n    {\n        return async_reset_connection(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_reset_connection\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_reset_connection(diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(detail::reset_connection_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Cleanly closes the connection to the server.\n     * \\details\n     * This function does the following:\n     * \\n\n     * \\li Sends a quit request. This is required by the MySQL protocol, to inform\n     *     the server that we're closing the connection gracefully.\n     * \\li If the connection is using TLS (`this->uses_ssl() == true`), performs\n     *     the TLS shutdown.\n     * \\li Closes the transport-level connection (the TCP or UNIX socket).\n     * \\n\n     * Since this function involves writing a message to the server, it can fail.\n     * Only use this function if you know that the connection is healthy and you want\n     * to cleanly close it.\n     * \\n\n     * If you don't call this function, the destructor or successive connects will\n     * perform a transport-layer close. This doesn't cause any resource leaks, but may\n     * cause warnings to be written to the server logs.\n     */\n    void close(error_code& err, diagnostics& diag)\n    {\n        impl_.run(detail::close_connection_algo_params{}, err, diag);\n    }\n\n    /// \\copydoc close\n    void close()\n    {\n        error_code err;\n        diagnostics diag;\n        close(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc close\n     * \\details\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_close(CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)\n    {\n        return async_close(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_close\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_close(diagnostics& diag, CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)\n    {\n        return this->impl_\n            .async_run(detail::close_connection_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Runs a set of pipelined requests.\n     * \\details\n     * Runs the pipeline described by `req` and stores its response in `res`.\n     * After the operation completes, `res` will have as many elements as stages\n     * were in `req`, even if the operation fails.\n     * \\n\n     * Request stages are seen by the server as a series of unrelated requests.\n     * As a consequence, all stages are always run, even if previous stages fail.\n     * \\n\n     * If all stages succeed, the operation completes successfully. Thus, there is no need to check\n     * the per-stage error code in `res` if this operation completed successfully.\n     * \\n\n     * If any stage fails with a non-fatal error (as per \\ref is_fatal_error), the result of the operation\n     * is the first encountered error. You can check which stages succeeded and which ones didn't by\n     * inspecting each stage in `res`.\n     * \\n\n     * If any stage fails with a fatal error, the result of the operation is the fatal error.\n     * Successive stages will be marked as failed with the fatal error. The server may or may\n     * not have processed such stages.\n     */\n    void run_pipeline(\n        const pipeline_request& req,\n        std::vector<stage_response>& res,\n        error_code& err,\n        diagnostics& diag\n    )\n    {\n        impl_.run(impl_.make_params_pipeline(req, res), err, diag);\n    }\n\n    /// \\copydoc run_pipeline\n    void run_pipeline(const pipeline_request& req, std::vector<stage_response>& res)\n    {\n        error_code err;\n        diagnostics diag;\n        run_pipeline(req, res, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc run_pipeline\n     * \\details\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     *\n     * \\par Object lifetimes\n     * The request and response objects must be kept alive and should not be modified\n     * until the operation completes.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_run_pipeline(\n        const pipeline_request& req,\n        std::vector<stage_response>& res,\n        CompletionToken&& token = {}\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_run_pipeline_t<CompletionToken&&>)\n    {\n        return async_run_pipeline(req, res, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_run_pipeline\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_run_pipeline(\n        const pipeline_request& req,\n        std::vector<stage_response>& res,\n        diagnostics& diag,\n        CompletionToken&& token = {}\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_run_pipeline_t<CompletionToken&&>)\n    {\n        return this->impl_\n            .async_run(impl_.make_params_pipeline(req, res), diag, std::forward<CompletionToken>(token));\n    }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/any_connection.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/bad_field_access.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_BAD_FIELD_ACCESS_HPP\n#define BOOST_MYSQL_BAD_FIELD_ACCESS_HPP\n\n#include <exception>\n\nnamespace boost {\nnamespace mysql {\n\n/// Exception type thrown when trying to access a \\ref field\n/// or \\ref field_view with an incorrect type.\nclass bad_field_access : public std::exception\n{\npublic:\n    /// Returns the error message.\n    const char* what() const noexcept override { return \"bad_value_access\"; }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/blob.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_BLOB_HPP\n#define BOOST_MYSQL_BLOB_HPP\n\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n/// Owning type used to represent binary blobs.\nusing blob = std::vector<unsigned char>;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/blob_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_BLOB_VIEW_HPP\n#define BOOST_MYSQL_BLOB_VIEW_HPP\n\n#include <boost/core/span.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/// Non-owning type used to represent binary blobs.\nusing blob_view = boost::span<const unsigned char>;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/buffer_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_BUFFER_PARAMS_HPP\n#define BOOST_MYSQL_BUFFER_PARAMS_HPP\n\n#include <boost/mysql/defaults.hpp>\n\n#include <boost/config.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief (Legacy) Buffer configuration parameters for a connection.\n *\n * \\par Legacy\n * This class is used with the legacy \\ref connection class.\n * New code should use \\ref any_connection, instead.\n * The equivalent to `buffer_params` is \\ref any_connection_params::initial_buffer_size.\n */\nclass buffer_params\n{\n    std::size_t initial_read_size_;\n\npublic:\n    /// The default value of \\ref initial_read_size.\n    static BOOST_INLINE_CONSTEXPR std::size_t default_initial_read_size = default_initial_read_buffer_size;\n\n    /**\n     * \\brief Initializing constructor.\n     * \\param initial_read_size Initial size of the read buffer. A bigger read buffer\n     * can increase the number of rows returned by \\ref connection::read_some_rows.\n     */\n    constexpr explicit buffer_params(std::size_t initial_read_size = default_initial_read_size) noexcept\n        : initial_read_size_(initial_read_size)\n    {\n    }\n\n    /// Gets the initial size of the read buffer.\n    constexpr std::size_t initial_read_size() const noexcept { return initial_read_size_; }\n\n    /// Sets the initial size of the read buffer.\n    void set_initial_read_size(std::size_t v) noexcept { initial_read_size_ = v; }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/character_set.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_CHARACTER_SET_HPP\n#define BOOST_MYSQL_CHARACTER_SET_HPP\n\n#include <boost/mysql/detail/character_set.hpp>\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Represents a MySQL character set.\n * \\details\n * By default, you should always use \\ref utf8mb4_charset, unless there is\n * a strong reason not to. This struct allows you to extend this library\n * with character sets that are not supported out of the box.\n */\nstruct character_set\n{\n    /**\n     * \\brief The character set name, as a NULL-terminated string.\n     * \\details\n     * This should match the character set name in MySQL. This is the string\n     * you specify when issuing `SET NAMES` statements. You can find available\n     * character sets using the `SHOW CHARACTER SET` statement.\n     */\n    const char* name;\n\n    /**\n     * \\brief Obtains the size of the first character of a string.\n     * \\details\n     * Given a range of bytes, `r`, this function must interpret `r` as a\n     * string encoded using this character set, and return the number of\n     * bytes that the first character in the string spans, or 0 in case of error.\n     * `r` is guaranteed to be non-empty (`r.size() > 0`).\n     * \\n\n     * In some character sets (like UTF-8), not all byte sequences represent\n     * valid characters. If this function finds an invalid byte sequence while\n     * trying to interpret the first character, it should return 0 to signal the error.\n     * \\n\n     * This function must not throw exceptions or have side effects.\n     */\n    std::size_t (*next_char)(span<const unsigned char>);\n};\n\n/// The utf8mb4 character set (the one you should use by default).\nBOOST_INLINE_CONSTEXPR character_set utf8mb4_charset\n#ifndef BOOST_MYSQL_DOXYGEN\n    {\"utf8mb4\", detail::next_char_utf8mb4}\n#endif\n;\n\n/// The ascii character set.\nBOOST_INLINE_CONSTEXPR character_set ascii_charset\n#ifndef BOOST_MYSQL_DOXYGEN\n    {\"ascii\", detail::next_char_ascii};\n#endif\n;\n\n/**\n * \\brief Settings required to format SQL queries client-side.\n * \\details\n * The recommended way to obtain a value of this type is using \\ref any_connection::format_opts.\n */\nstruct format_options\n{\n    /// The connection's current character set.\n    character_set charset;\n\n    /// Whether backslashes represent escape sequences.\n    bool backslash_escapes;\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/character_set.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/client_errc.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_CLIENT_ERRC_HPP\n#define BOOST_MYSQL_CLIENT_ERRC_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/system/error_category.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief MySQL client-defined error codes.\n * \\details These errors are produced by the client itself, rather than the server.\n */\nenum class client_errc : int\n{\n    /**\n     * \\brief An incomplete message was received from the server (indicates a deserialization error or\n     * packet mismatch).\n     */\n    incomplete_message = 1,\n\n    /**\n     * \\brief An unexpected value was found in a server-received message (indicates a deserialization\n     * error or packet mismatch).\n     */\n    protocol_value_error,\n\n    /// The server does not support the minimum required capabilities to establish the connection.\n    server_unsupported,\n\n    /**\n     * \\brief Unexpected extra bytes at the end of a message were received (indicates a deserialization\n     * error or packet mismatch).\n     */\n    extra_bytes,\n\n    /// Mismatched sequence numbers (usually caused by a packet mismatch).\n    sequence_number_mismatch,\n\n    /// The user employs an authentication plugin not known to this library.\n    unknown_auth_plugin,\n\n    /**\n     * \\brief (Legacy) The authentication plugin requires the connection to use SSL.\n     * This code is no longer used, since all supported plugins support plaintext connections.\n     */\n    auth_plugin_requires_ssl,\n\n    /**\n     * \\brief The number of parameters passed to the prepared statement does not match the number of\n     * actual parameters.\n     */\n    wrong_num_params,\n\n    /// The connection mandates SSL, but the server doesn't accept SSL connections.\n    server_doesnt_support_ssl,\n\n    /**\n     * \\brief\n     * The static interface detected a mismatch between your C++ type definitions and what the server\n     * returned in the query.\n     */\n    metadata_check_failed,\n\n    /**\n     * \\brief The static interface detected a mismatch between the number of row types passed to\n     * \\ref static_results or \\ref static_execution_state and the number of resultsets returned by your query.\n     */\n    num_resultsets_mismatch,\n\n    /// The `StaticRow` type passed to read_some_rows does not correspond to the resultset type being read.\n    row_type_mismatch,\n\n    /// The static interface encountered an error when parsing a field into a C++ data structure.\n    static_row_parsing_error,\n\n    /**\n     * \\brief Getting a connection from a connection_pool was cancelled before\n     * the pool was run. Ensure that you're calling connection_pool::async_run.\n     */\n    pool_not_running,\n\n    /**\n     * \\brief Getting a connection from a connection_pool failed because the\n     * pool was cancelled.\n     */\n    pool_cancelled,\n\n    /**\n     * \\brief Getting a connection from a connection_pool was cancelled before\n     * a connection was available.\n     */\n    no_connection_available,\n\n    /// An invalid byte sequence was found while trying to decode a string.\n    invalid_encoding,\n\n    /// A formatting operation could not format one of its arguments.\n    unformattable_value,\n\n    /// A format string containing invalid syntax was provided to a SQL formatting function.\n    format_string_invalid_syntax,\n\n    /**\n     * \\brief A format string with an invalid byte sequence was provided to a SQL formatting\n     * function.\n     */\n    format_string_invalid_encoding,\n\n    /// A format string mixes manual (e.g. {0}) and automatic (e.g. {}) indexing.\n    format_string_manual_auto_mix,\n\n    /// The supplied format specifier (e.g. {:i}) is not supported by the type being formatted.\n    format_string_invalid_specifier,\n\n    /**\n     * \\brief A format argument referenced by a format string was not found. Check the number\n     * of format arguments passed and their names.\n     */\n    format_arg_not_found,\n\n    /**\n     * \\brief The character set used by the connection is not known by the client. Use\n     * \\ref any_connection::set_character_set or \\ref any_connection::async_set_character_set\n     * before invoking operations that require a known charset.\n     */\n    unknown_character_set,\n\n    /**\n     * \\brief An operation attempted to read or write a packet larger than the maximum buffer\n     * size. Try increasing \\ref any_connection_params::max_buffer_size.\n     */\n    max_buffer_size_exceeded,\n\n    /**\n     * \\brief Another operation is currently in progress for this connection. Make sure\n     * that a single connection does not run two asynchronous operations in parallel.\n     */\n    operation_in_progress,\n\n    /**\n     * \\brief The requested operation requires an established session.\n     * Call `async_connect` before invoking other operations.\n     */\n    not_connected,\n\n    /**\n     * \\brief The connection is currently engaged in a multi-function operation.\n     * Finish the current operation by calling `async_read_some_rows` and `async_read_resultset_head`\n     * before starting any other operation.\n     */\n    engaged_in_multi_function,\n\n    /**\n     * \\brief The operation requires the connection to be engaged in a multi-function operation.\n     * Use `async_start_execution` to start one.\n     */\n    not_engaged_in_multi_function,\n\n    /**\n     * \\brief During handshake, the server sent a packet type that is not allowed in the current state\n     * (protocol violation).\n     */\n    bad_handshake_packet_type,\n\n    /// An OpenSSL function failed and did not provide any extra diagnostics.\n    unknown_openssl_error,\n};\n\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_client_category() noexcept;\n\n/// Creates an \\ref error_code from a \\ref client_errc.\ninline error_code make_error_code(client_errc error)\n{\n    return error_code(static_cast<int>(error), get_client_category());\n}\n\n}  // namespace mysql\n\n#ifndef BOOST_MYSQL_DOXYGEN\nnamespace system {\n\ntemplate <>\nstruct is_error_code_enum<::boost::mysql::client_errc>\n{\n    static constexpr bool value = true;\n};\n}  // namespace system\n#endif\n\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/error_categories.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/column_type.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_COLUMN_TYPE_HPP\n#define BOOST_MYSQL_COLUMN_TYPE_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <iosfwd>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Represents the database type of a MySQL column.\n * \\details This represents a database type, as opposed to \\ref field_kind, which represents a\n * C++ type.\n *\\n\n * Unless otherwise noted, the names in this enumeration\n * directly correspond to the names of the types you would use in\n * a `CREATE TABLE` statement to create a column of this type\n * (e.g. `VARCHAR` corresponds to \\ref column_type::varchar).\n */\nenum class column_type\n{\n    tinyint,    ///< `TINYINT` (signed and unsigned).\n    smallint,   ///< `SMALLINT` (signed and unsigned).\n    mediumint,  ///< `MEDIUMINT` (signed and unsigned).\n    int_,       ///< `INT` (signed and unsigned).\n    bigint,     ///< `BIGINT` (signed and unsigned).\n    float_,     ///< `FLOAT` (warning: FLOAT(p) where p >= 24 creates a DOUBLE column).\n    double_,    ///< `DOUBLE`\n    decimal,    ///< `DECIMAL`\n    bit,        ///< `BIT`\n    year,       ///< `YEAR`\n    time,       ///< `TIME`\n    date,       ///< `DATE`\n    datetime,   ///< `DATETIME`\n    timestamp,  ///< `TIMESTAMP`\n    char_,      ///< `CHAR` (any length)\n    varchar,    ///< `VARCHAR` (any length)\n    binary,     ///< `BINARY` (any length)\n    varbinary,  ///< `VARBINARY` (any length)\n    text,       ///< `TEXT` types (`TINYTEXT`, `MEDIUMTEXT`, `TEXT` and `LONGTEXT`)\n    blob,       ///< `BLOB` types (`TINYBLOB`, `MEDIUMBLOB`, `BLOB` and `LONGBLOB`)\n    enum_,      ///< `ENUM`\n    set,        ///< `SET`\n    json,       ///< `JSON`\n    geometry,   ///< `GEOMETRY`\n    unknown,    ///< None of the known types; maybe a new MySQL type we have no knowledge of.\n};\n\n/**\n * \\brief Streams a `column_type`.\n */\nBOOST_MYSQL_DECL\nstd::ostream& operator<<(std::ostream& os, column_type t);\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/column_type.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/common_server_errc.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_COMMON_SERVER_ERRC_HPP\n#define BOOST_MYSQL_COMMON_SERVER_ERRC_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/system/error_category.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Server-defined error codes, shared between MySQL and MariaDB.\n * \\details The numeric value and semantics match the ones described in the MySQL documentation.\n * For more info, consult the error reference for\n * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html\">MySQL 8.0</a>, \n * <a href=\"https://dev.mysql.com/doc/mysql-errors/5.7/en/server-error-reference.html\">MySQL 5.7</a>,\n * <a href=\"https://mariadb.com/kb/en/mariadb-error-codes/\">MariaDB</a>.\n */\nenum class common_server_errc : int\n{\n\n    /**\n     * \\brief Common server error. Error number: 1000, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_hashchk\">ER_HASHCHK</a>.\n     */\n    er_hashchk = 1000,\n\n    /**\n     * \\brief Common server error. Error number: 1001, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_nisamchk\">ER_NISAMCHK</a>.\n     */\n    er_nisamchk = 1001,\n\n    /**\n     * \\brief Common server error. Error number: 1002, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no\">ER_NO</a>.\n     */\n    er_no = 1002,\n\n    /**\n     * \\brief Common server error. Error number: 1003, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_yes\">ER_YES</a>.\n     */\n    er_yes = 1003,\n\n    /**\n     * \\brief Common server error. Error number: 1004, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_file\">ER_CANT_CREATE_FILE</a>.\n     */\n    er_cant_create_file = 1004,\n\n    /**\n     * \\brief Common server error. Error number: 1005, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_table\">ER_CANT_CREATE_TABLE</a>.\n     */\n    er_cant_create_table = 1005,\n\n    /**\n     * \\brief Common server error. Error number: 1006, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_db\">ER_CANT_CREATE_DB</a>.\n     */\n    er_cant_create_db = 1006,\n\n    /**\n     * \\brief Common server error. Error number: 1007, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_db_create_exists\">ER_DB_CREATE_EXISTS</a>.\n     */\n    er_db_create_exists = 1007,\n\n    /**\n     * \\brief Common server error. Error number: 1008, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_db_drop_exists\">ER_DB_DROP_EXISTS</a>.\n     */\n    er_db_drop_exists = 1008,\n\n    /**\n     * \\brief Common server error. Error number: 1009, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_db_drop_delete\">ER_DB_DROP_DELETE</a>.\n     */\n    er_db_drop_delete = 1009,\n\n    /**\n     * \\brief Common server error. Error number: 1010, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_db_drop_rmdir\">ER_DB_DROP_RMDIR</a>.\n     */\n    er_db_drop_rmdir = 1010,\n\n    /**\n     * \\brief Common server error. Error number: 1011, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_delete_file\">ER_CANT_DELETE_FILE</a>.\n     */\n    er_cant_delete_file = 1011,\n\n    /**\n     * \\brief Common server error. Error number: 1012, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_find_system_rec\">ER_CANT_FIND_SYSTEM_REC</a>.\n     */\n    er_cant_find_system_rec = 1012,\n\n    /**\n     * \\brief Common server error. Error number: 1013, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_get_stat\">ER_CANT_GET_STAT</a>.\n     */\n    er_cant_get_stat = 1013,\n\n    /**\n     * \\brief Common server error. Error number: 1014, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_get_wd\">ER_CANT_GET_WD</a>.\n     */\n    er_cant_get_wd = 1014,\n\n    /**\n     * \\brief Common server error. Error number: 1015, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_lock\">ER_CANT_LOCK</a>.\n     */\n    er_cant_lock = 1015,\n\n    /**\n     * \\brief Common server error. Error number: 1016, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_open_file\">ER_CANT_OPEN_FILE</a>.\n     */\n    er_cant_open_file = 1016,\n\n    /**\n     * \\brief Common server error. Error number: 1017, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_file_not_found\">ER_FILE_NOT_FOUND</a>.\n     */\n    er_file_not_found = 1017,\n\n    /**\n     * \\brief Common server error. Error number: 1018, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_read_dir\">ER_CANT_READ_DIR</a>.\n     */\n    er_cant_read_dir = 1018,\n\n    /**\n     * \\brief Common server error. Error number: 1019, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_wd\">ER_CANT_SET_WD</a>.\n     */\n    er_cant_set_wd = 1019,\n\n    /**\n     * \\brief Common server error. Error number: 1020, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_checkread\">ER_CHECKREAD</a>.\n     */\n    er_checkread = 1020,\n\n    /**\n     * \\brief Common server error. Error number: 1021, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_disk_full\">ER_DISK_FULL</a>.\n     */\n    er_disk_full = 1021,\n\n    /**\n     * \\brief Common server error. Error number: 1022, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_key\">ER_DUP_KEY</a>.\n     */\n    er_dup_key = 1022,\n\n    /**\n     * \\brief Common server error. Error number: 1023, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_on_close\">ER_ERROR_ON_CLOSE</a>.\n     */\n    er_error_on_close = 1023,\n\n    /**\n     * \\brief Common server error. Error number: 1024, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_on_read\">ER_ERROR_ON_READ</a>.\n     */\n    er_error_on_read = 1024,\n\n    /**\n     * \\brief Common server error. Error number: 1025, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_on_rename\">ER_ERROR_ON_RENAME</a>.\n     */\n    er_error_on_rename = 1025,\n\n    /**\n     * \\brief Common server error. Error number: 1026, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_on_write\">ER_ERROR_ON_WRITE</a>.\n     */\n    er_error_on_write = 1026,\n\n    /**\n     * \\brief Common server error. Error number: 1027, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_file_used\">ER_FILE_USED</a>.\n     */\n    er_file_used = 1027,\n\n    /**\n     * \\brief Common server error. Error number: 1028, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_filsort_abort\">ER_FILSORT_ABORT</a>.\n     */\n    er_filsort_abort = 1028,\n\n    /**\n     * \\brief Common server error. Error number: 1029, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_form_not_found\">ER_FORM_NOT_FOUND</a>.\n     */\n    er_form_not_found = 1029,\n\n    /**\n     * \\brief Common server error. Error number: 1030, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_get_errno\">ER_GET_ERRNO</a>.\n     */\n    er_get_errno = 1030,\n\n    /**\n     * \\brief Common server error. Error number: 1031, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_illegal_ha\">ER_ILLEGAL_HA</a>.\n     */\n    er_illegal_ha = 1031,\n\n    /**\n     * \\brief Common server error. Error number: 1032, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_key_not_found\">ER_KEY_NOT_FOUND</a>.\n     */\n    er_key_not_found = 1032,\n\n    /**\n     * \\brief Common server error. Error number: 1033, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_form_file\">ER_NOT_FORM_FILE</a>.\n     */\n    er_not_form_file = 1033,\n\n    /**\n     * \\brief Common server error. Error number: 1034, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_keyfile\">ER_NOT_KEYFILE</a>.\n     */\n    er_not_keyfile = 1034,\n\n    /**\n     * \\brief Common server error. Error number: 1035, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_old_keyfile\">ER_OLD_KEYFILE</a>.\n     */\n    er_old_keyfile = 1035,\n\n    /**\n     * \\brief Common server error. Error number: 1036, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_open_as_readonly\">ER_OPEN_AS_READONLY</a>.\n     */\n    er_open_as_readonly = 1036,\n\n    /**\n     * \\brief Common server error. Error number: 1037, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_outofmemory\">ER_OUTOFMEMORY</a>.\n     */\n    er_outofmemory = 1037,\n\n    /**\n     * \\brief Common server error. Error number: 1038, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_out_of_sortmemory\">ER_OUT_OF_SORTMEMORY</a>.\n     */\n    er_out_of_sortmemory = 1038,\n\n    /**\n     * \\brief Common server error. Error number: 1039, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unexpected_eof\">ER_UNEXPECTED_EOF</a>.\n     */\n    er_unexpected_eof = 1039,\n\n    /**\n     * \\brief Common server error. Error number: 1040, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_con_count_error\">ER_CON_COUNT_ERROR</a>.\n     */\n    er_con_count_error = 1040,\n\n    /**\n     * \\brief Common server error. Error number: 1041, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_out_of_resources\">ER_OUT_OF_RESOURCES</a>.\n     */\n    er_out_of_resources = 1041,\n\n    /**\n     * \\brief Common server error. Error number: 1042, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_host_error\">ER_BAD_HOST_ERROR</a>.\n     */\n    er_bad_host_error = 1042,\n\n    /**\n     * \\brief Common server error. Error number: 1043, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_handshake_error\">ER_HANDSHAKE_ERROR</a>.\n     */\n    er_handshake_error = 1043,\n\n    /**\n     * \\brief Common server error. Error number: 1044, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dbaccess_denied_error\">ER_DBACCESS_DENIED_ERROR</a>.\n     */\n    er_dbaccess_denied_error = 1044,\n\n    /**\n     * \\brief Common server error. Error number: 1045, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_access_denied_error\">ER_ACCESS_DENIED_ERROR</a>.\n     */\n    er_access_denied_error = 1045,\n\n    /**\n     * \\brief Common server error. Error number: 1046, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_db_error\">ER_NO_DB_ERROR</a>.\n     */\n    er_no_db_error = 1046,\n\n    /**\n     * \\brief Common server error. Error number: 1047, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_com_error\">ER_UNKNOWN_COM_ERROR</a>.\n     */\n    er_unknown_com_error = 1047,\n\n    /**\n     * \\brief Common server error. Error number: 1048, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_null_error\">ER_BAD_NULL_ERROR</a>.\n     */\n    er_bad_null_error = 1048,\n\n    /**\n     * \\brief Common server error. Error number: 1049, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_db_error\">ER_BAD_DB_ERROR</a>.\n     */\n    er_bad_db_error = 1049,\n\n    /**\n     * \\brief Common server error. Error number: 1050, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_exists_error\">ER_TABLE_EXISTS_ERROR</a>.\n     */\n    er_table_exists_error = 1050,\n\n    /**\n     * \\brief Common server error. Error number: 1051, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_table_error\">ER_BAD_TABLE_ERROR</a>.\n     */\n    er_bad_table_error = 1051,\n\n    /**\n     * \\brief Common server error. Error number: 1052, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_non_uniq_error\">ER_NON_UNIQ_ERROR</a>.\n     */\n    er_non_uniq_error = 1052,\n\n    /**\n     * \\brief Common server error. Error number: 1053, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_server_shutdown\">ER_SERVER_SHUTDOWN</a>.\n     */\n    er_server_shutdown = 1053,\n\n    /**\n     * \\brief Common server error. Error number: 1054, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_field_error\">ER_BAD_FIELD_ERROR</a>.\n     */\n    er_bad_field_error = 1054,\n\n    /**\n     * \\brief Common server error. Error number: 1055, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_field_with_group\">ER_WRONG_FIELD_WITH_GROUP</a>.\n     */\n    er_wrong_field_with_group = 1055,\n\n    /**\n     * \\brief Common server error. Error number: 1056, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_group_field\">ER_WRONG_GROUP_FIELD</a>.\n     */\n    er_wrong_group_field = 1056,\n\n    /**\n     * \\brief Common server error. Error number: 1057, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_sum_select\">ER_WRONG_SUM_SELECT</a>.\n     */\n    er_wrong_sum_select = 1057,\n\n    /**\n     * \\brief Common server error. Error number: 1058, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_value_count\">ER_WRONG_VALUE_COUNT</a>.\n     */\n    er_wrong_value_count = 1058,\n\n    /**\n     * \\brief Common server error. Error number: 1059, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_ident\">ER_TOO_LONG_IDENT</a>.\n     */\n    er_too_long_ident = 1059,\n\n    /**\n     * \\brief Common server error. Error number: 1060, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_fieldname\">ER_DUP_FIELDNAME</a>.\n     */\n    er_dup_fieldname = 1060,\n\n    /**\n     * \\brief Common server error. Error number: 1061, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_keyname\">ER_DUP_KEYNAME</a>.\n     */\n    er_dup_keyname = 1061,\n\n    /**\n     * \\brief Common server error. Error number: 1062, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_entry\">ER_DUP_ENTRY</a>.\n     */\n    er_dup_entry = 1062,\n\n    /**\n     * \\brief Common server error. Error number: 1063, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_field_spec\">ER_WRONG_FIELD_SPEC</a>.\n     */\n    er_wrong_field_spec = 1063,\n\n    /**\n     * \\brief Common server error. Error number: 1064, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_parse_error\">ER_PARSE_ERROR</a>.\n     */\n    er_parse_error = 1064,\n\n    /**\n     * \\brief Common server error. Error number: 1065, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_empty_query\">ER_EMPTY_QUERY</a>.\n     */\n    er_empty_query = 1065,\n\n    /**\n     * \\brief Common server error. Error number: 1066, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_nonuniq_table\">ER_NONUNIQ_TABLE</a>.\n     */\n    er_nonuniq_table = 1066,\n\n    /**\n     * \\brief Common server error. Error number: 1067, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_default\">ER_INVALID_DEFAULT</a>.\n     */\n    er_invalid_default = 1067,\n\n    /**\n     * \\brief Common server error. Error number: 1068, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_multiple_pri_key\">ER_MULTIPLE_PRI_KEY</a>.\n     */\n    er_multiple_pri_key = 1068,\n\n    /**\n     * \\brief Common server error. Error number: 1069, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_keys\">ER_TOO_MANY_KEYS</a>.\n     */\n    er_too_many_keys = 1069,\n\n    /**\n     * \\brief Common server error. Error number: 1070, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_key_parts\">ER_TOO_MANY_KEY_PARTS</a>.\n     */\n    er_too_many_key_parts = 1070,\n\n    /**\n     * \\brief Common server error. Error number: 1071, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_key\">ER_TOO_LONG_KEY</a>.\n     */\n    er_too_long_key = 1071,\n\n    /**\n     * \\brief Common server error. Error number: 1072, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_key_column_does_not_exits\">ER_KEY_COLUMN_DOES_NOT_EXITS</a>.\n     */\n    er_key_column_does_not_exits = 1072,\n\n    /**\n     * \\brief Common server error. Error number: 1073, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_blob_used_as_key\">ER_BLOB_USED_AS_KEY</a>.\n     */\n    er_blob_used_as_key = 1073,\n\n    /**\n     * \\brief Common server error. Error number: 1074, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_fieldlength\">ER_TOO_BIG_FIELDLENGTH</a>.\n     */\n    er_too_big_fieldlength = 1074,\n\n    /**\n     * \\brief Common server error. Error number: 1075, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_auto_key\">ER_WRONG_AUTO_KEY</a>.\n     */\n    er_wrong_auto_key = 1075,\n\n    /**\n     * \\brief Common server error. Error number: 1077, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_normal_shutdown\">ER_NORMAL_SHUTDOWN</a>.\n     */\n    er_normal_shutdown = 1077,\n\n    /**\n     * \\brief Common server error. Error number: 1078, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_got_signal\">ER_GOT_SIGNAL</a>.\n     */\n    er_got_signal = 1078,\n\n    /**\n     * \\brief Common server error. Error number: 1079, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_shutdown_complete\">ER_SHUTDOWN_COMPLETE</a>.\n     */\n    er_shutdown_complete = 1079,\n\n    /**\n     * \\brief Common server error. Error number: 1080, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_forcing_close\">ER_FORCING_CLOSE</a>.\n     */\n    er_forcing_close = 1080,\n\n    /**\n     * \\brief Common server error. Error number: 1081, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ipsock_error\">ER_IPSOCK_ERROR</a>.\n     */\n    er_ipsock_error = 1081,\n\n    /**\n     * \\brief Common server error. Error number: 1082, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_such_index\">ER_NO_SUCH_INDEX</a>.\n     */\n    er_no_such_index = 1082,\n\n    /**\n     * \\brief Common server error. Error number: 1083, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_field_terminators\">ER_WRONG_FIELD_TERMINATORS</a>.\n     */\n    er_wrong_field_terminators = 1083,\n\n    /**\n     * \\brief Common server error. Error number: 1084, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_blobs_and_no_terminated\">ER_BLOBS_AND_NO_TERMINATED</a>.\n     */\n    er_blobs_and_no_terminated = 1084,\n\n    /**\n     * \\brief Common server error. Error number: 1085, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_textfile_not_readable\">ER_TEXTFILE_NOT_READABLE</a>.\n     */\n    er_textfile_not_readable = 1085,\n\n    /**\n     * \\brief Common server error. Error number: 1086, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_file_exists_error\">ER_FILE_EXISTS_ERROR</a>.\n     */\n    er_file_exists_error = 1086,\n\n    /**\n     * \\brief Common server error. Error number: 1087, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_load_info\">ER_LOAD_INFO</a>.\n     */\n    er_load_info = 1087,\n\n    /**\n     * \\brief Common server error. Error number: 1088, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_info\">ER_ALTER_INFO</a>.\n     */\n    er_alter_info = 1088,\n\n    /**\n     * \\brief Common server error. Error number: 1089, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_sub_key\">ER_WRONG_SUB_KEY</a>.\n     */\n    er_wrong_sub_key = 1089,\n\n    /**\n     * \\brief Common server error. Error number: 1090, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_remove_all_fields\">ER_CANT_REMOVE_ALL_FIELDS</a>.\n     */\n    er_cant_remove_all_fields = 1090,\n\n    /**\n     * \\brief Common server error. Error number: 1091, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_drop_field_or_key\">ER_CANT_DROP_FIELD_OR_KEY</a>.\n     */\n    er_cant_drop_field_or_key = 1091,\n\n    /**\n     * \\brief Common server error. Error number: 1092, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_insert_info\">ER_INSERT_INFO</a>.\n     */\n    er_insert_info = 1092,\n\n    /**\n     * \\brief Common server error. Error number: 1093, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_update_table_used\">ER_UPDATE_TABLE_USED</a>.\n     */\n    er_update_table_used = 1093,\n\n    /**\n     * \\brief Common server error. Error number: 1094, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_such_thread\">ER_NO_SUCH_THREAD</a>.\n     */\n    er_no_such_thread = 1094,\n\n    /**\n     * \\brief Common server error. Error number: 1095, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_kill_denied_error\">ER_KILL_DENIED_ERROR</a>.\n     */\n    er_kill_denied_error = 1095,\n\n    /**\n     * \\brief Common server error. Error number: 1096, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_tables_used\">ER_NO_TABLES_USED</a>.\n     */\n    er_no_tables_used = 1096,\n\n    /**\n     * \\brief Common server error. Error number: 1097, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_set\">ER_TOO_BIG_SET</a>.\n     */\n    er_too_big_set = 1097,\n\n    /**\n     * \\brief Common server error. Error number: 1098, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_unique_logfile\">ER_NO_UNIQUE_LOGFILE</a>.\n     */\n    er_no_unique_logfile = 1098,\n\n    /**\n     * \\brief Common server error. Error number: 1099, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_not_locked_for_write\">ER_TABLE_NOT_LOCKED_FOR_WRITE</a>.\n     */\n    er_table_not_locked_for_write = 1099,\n\n    /**\n     * \\brief Common server error. Error number: 1100, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_not_locked\">ER_TABLE_NOT_LOCKED</a>.\n     */\n    er_table_not_locked = 1100,\n\n    /**\n     * \\brief Common server error. Error number: 1102, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_db_name\">ER_WRONG_DB_NAME</a>.\n     */\n    er_wrong_db_name = 1102,\n\n    /**\n     * \\brief Common server error. Error number: 1103, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_table_name\">ER_WRONG_TABLE_NAME</a>.\n     */\n    er_wrong_table_name = 1103,\n\n    /**\n     * \\brief Common server error. Error number: 1104, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_select\">ER_TOO_BIG_SELECT</a>.\n     */\n    er_too_big_select = 1104,\n\n    /**\n     * \\brief Common server error. Error number: 1105, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_error\">ER_UNKNOWN_ERROR</a>.\n     */\n    er_unknown_error = 1105,\n\n    /**\n     * \\brief Common server error. Error number: 1106, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_procedure\">ER_UNKNOWN_PROCEDURE</a>.\n     */\n    er_unknown_procedure = 1106,\n\n    /**\n     * \\brief Common server error. Error number: 1107, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_paramcount_to_procedure\">ER_WRONG_PARAMCOUNT_TO_PROCEDURE</a>.\n     */\n    er_wrong_paramcount_to_procedure = 1107,\n\n    /**\n     * \\brief Common server error. Error number: 1108, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_parameters_to_procedure\">ER_WRONG_PARAMETERS_TO_PROCEDURE</a>.\n     */\n    er_wrong_parameters_to_procedure = 1108,\n\n    /**\n     * \\brief Common server error. Error number: 1109, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_table\">ER_UNKNOWN_TABLE</a>.\n     */\n    er_unknown_table = 1109,\n\n    /**\n     * \\brief Common server error. Error number: 1110, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_field_specified_twice\">ER_FIELD_SPECIFIED_TWICE</a>.\n     */\n    er_field_specified_twice = 1110,\n\n    /**\n     * \\brief Common server error. Error number: 1111, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_group_func_use\">ER_INVALID_GROUP_FUNC_USE</a>.\n     */\n    er_invalid_group_func_use = 1111,\n\n    /**\n     * \\brief Common server error. Error number: 1112, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unsupported_extension\">ER_UNSUPPORTED_EXTENSION</a>.\n     */\n    er_unsupported_extension = 1112,\n\n    /**\n     * \\brief Common server error. Error number: 1113, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_must_have_columns\">ER_TABLE_MUST_HAVE_COLUMNS</a>.\n     */\n    er_table_must_have_columns = 1113,\n\n    /**\n     * \\brief Common server error. Error number: 1114, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_record_file_full\">ER_RECORD_FILE_FULL</a>.\n     */\n    er_record_file_full = 1114,\n\n    /**\n     * \\brief Common server error. Error number: 1115, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_character_set\">ER_UNKNOWN_CHARACTER_SET</a>.\n     */\n    er_unknown_character_set = 1115,\n\n    /**\n     * \\brief Common server error. Error number: 1116, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_tables\">ER_TOO_MANY_TABLES</a>.\n     */\n    er_too_many_tables = 1116,\n\n    /**\n     * \\brief Common server error. Error number: 1117, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_fields\">ER_TOO_MANY_FIELDS</a>.\n     */\n    er_too_many_fields = 1117,\n\n    /**\n     * \\brief Common server error. Error number: 1118, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_rowsize\">ER_TOO_BIG_ROWSIZE</a>.\n     */\n    er_too_big_rowsize = 1118,\n\n    /**\n     * \\brief Common server error. Error number: 1119, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stack_overrun\">ER_STACK_OVERRUN</a>.\n     */\n    er_stack_overrun = 1119,\n\n    /**\n     * \\brief Common server error. Error number: 1121, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_null_column_in_index\">ER_NULL_COLUMN_IN_INDEX</a>.\n     */\n    er_null_column_in_index = 1121,\n\n    /**\n     * \\brief Common server error. Error number: 1122, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_find_udf\">ER_CANT_FIND_UDF</a>.\n     */\n    er_cant_find_udf = 1122,\n\n    /**\n     * \\brief Common server error. Error number: 1123, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_initialize_udf\">ER_CANT_INITIALIZE_UDF</a>.\n     */\n    er_cant_initialize_udf = 1123,\n\n    /**\n     * \\brief Common server error. Error number: 1124, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_udf_no_paths\">ER_UDF_NO_PATHS</a>.\n     */\n    er_udf_no_paths = 1124,\n\n    /**\n     * \\brief Common server error. Error number: 1125, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_udf_exists\">ER_UDF_EXISTS</a>.\n     */\n    er_udf_exists = 1125,\n\n    /**\n     * \\brief Common server error. Error number: 1126, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_open_library\">ER_CANT_OPEN_LIBRARY</a>.\n     */\n    er_cant_open_library = 1126,\n\n    /**\n     * \\brief Common server error. Error number: 1127, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_find_dl_entry\">ER_CANT_FIND_DL_ENTRY</a>.\n     */\n    er_cant_find_dl_entry = 1127,\n\n    /**\n     * \\brief Common server error. Error number: 1128, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_function_not_defined\">ER_FUNCTION_NOT_DEFINED</a>.\n     */\n    er_function_not_defined = 1128,\n\n    /**\n     * \\brief Common server error. Error number: 1129, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_host_is_blocked\">ER_HOST_IS_BLOCKED</a>.\n     */\n    er_host_is_blocked = 1129,\n\n    /**\n     * \\brief Common server error. Error number: 1130, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_host_not_privileged\">ER_HOST_NOT_PRIVILEGED</a>.\n     */\n    er_host_not_privileged = 1130,\n\n    /**\n     * \\brief Common server error. Error number: 1131, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_password_anonymous_user\">ER_PASSWORD_ANONYMOUS_USER</a>.\n     */\n    er_password_anonymous_user = 1131,\n\n    /**\n     * \\brief Common server error. Error number: 1132, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_password_not_allowed\">ER_PASSWORD_NOT_ALLOWED</a>.\n     */\n    er_password_not_allowed = 1132,\n\n    /**\n     * \\brief Common server error. Error number: 1133, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_password_no_match\">ER_PASSWORD_NO_MATCH</a>.\n     */\n    er_password_no_match = 1133,\n\n    /**\n     * \\brief Common server error. Error number: 1134, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_update_info\">ER_UPDATE_INFO</a>.\n     */\n    er_update_info = 1134,\n\n    /**\n     * \\brief Common server error. Error number: 1135, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_thread\">ER_CANT_CREATE_THREAD</a>.\n     */\n    er_cant_create_thread = 1135,\n\n    /**\n     * \\brief Common server error. Error number: 1136, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_value_count_on_row\">ER_WRONG_VALUE_COUNT_ON_ROW</a>.\n     */\n    er_wrong_value_count_on_row = 1136,\n\n    /**\n     * \\brief Common server error. Error number: 1137, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_reopen_table\">ER_CANT_REOPEN_TABLE</a>.\n     */\n    er_cant_reopen_table = 1137,\n\n    /**\n     * \\brief Common server error. Error number: 1138, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_use_of_null\">ER_INVALID_USE_OF_NULL</a>.\n     */\n    er_invalid_use_of_null = 1138,\n\n    /**\n     * \\brief Common server error. Error number: 1139, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_regexp_error\">ER_REGEXP_ERROR</a>.\n     */\n    er_regexp_error = 1139,\n\n    /**\n     * \\brief Common server error. Error number: 1140, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mix_of_group_func_and_fields\">ER_MIX_OF_GROUP_FUNC_AND_FIELDS</a>.\n     */\n    er_mix_of_group_func_and_fields = 1140,\n\n    /**\n     * \\brief Common server error. Error number: 1141, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_nonexisting_grant\">ER_NONEXISTING_GRANT</a>.\n     */\n    er_nonexisting_grant = 1141,\n\n    /**\n     * \\brief Common server error. Error number: 1142, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tableaccess_denied_error\">ER_TABLEACCESS_DENIED_ERROR</a>.\n     */\n    er_tableaccess_denied_error = 1142,\n\n    /**\n     * \\brief Common server error. Error number: 1143, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_columnaccess_denied_error\">ER_COLUMNACCESS_DENIED_ERROR</a>.\n     */\n    er_columnaccess_denied_error = 1143,\n\n    /**\n     * \\brief Common server error. Error number: 1144, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_illegal_grant_for_table\">ER_ILLEGAL_GRANT_FOR_TABLE</a>.\n     */\n    er_illegal_grant_for_table = 1144,\n\n    /**\n     * \\brief Common server error. Error number: 1145, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_grant_wrong_host_or_user\">ER_GRANT_WRONG_HOST_OR_USER</a>.\n     */\n    er_grant_wrong_host_or_user = 1145,\n\n    /**\n     * \\brief Common server error. Error number: 1146, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_such_table\">ER_NO_SUCH_TABLE</a>.\n     */\n    er_no_such_table = 1146,\n\n    /**\n     * \\brief Common server error. Error number: 1147, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_nonexisting_table_grant\">ER_NONEXISTING_TABLE_GRANT</a>.\n     */\n    er_nonexisting_table_grant = 1147,\n\n    /**\n     * \\brief Common server error. Error number: 1148, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_allowed_command\">ER_NOT_ALLOWED_COMMAND</a>.\n     */\n    er_not_allowed_command = 1148,\n\n    /**\n     * \\brief Common server error. Error number: 1149, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_syntax_error\">ER_SYNTAX_ERROR</a>.\n     */\n    er_syntax_error = 1149,\n\n    /**\n     * \\brief Common server error. Error number: 1152, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_aborting_connection\">ER_ABORTING_CONNECTION</a>.\n     */\n    er_aborting_connection = 1152,\n\n    /**\n     * \\brief Common server error. Error number: 1153, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_packet_too_large\">ER_NET_PACKET_TOO_LARGE</a>.\n     */\n    er_net_packet_too_large = 1153,\n\n    /**\n     * \\brief Common server error. Error number: 1154, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_read_error_from_pipe\">ER_NET_READ_ERROR_FROM_PIPE</a>.\n     */\n    er_net_read_error_from_pipe = 1154,\n\n    /**\n     * \\brief Common server error. Error number: 1155, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_fcntl_error\">ER_NET_FCNTL_ERROR</a>.\n     */\n    er_net_fcntl_error = 1155,\n\n    /**\n     * \\brief Common server error. Error number: 1156, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_packets_out_of_order\">ER_NET_PACKETS_OUT_OF_ORDER</a>.\n     */\n    er_net_packets_out_of_order = 1156,\n\n    /**\n     * \\brief Common server error. Error number: 1157, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_uncompress_error\">ER_NET_UNCOMPRESS_ERROR</a>.\n     */\n    er_net_uncompress_error = 1157,\n\n    /**\n     * \\brief Common server error. Error number: 1158, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_read_error\">ER_NET_READ_ERROR</a>.\n     */\n    er_net_read_error = 1158,\n\n    /**\n     * \\brief Common server error. Error number: 1159, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_read_interrupted\">ER_NET_READ_INTERRUPTED</a>.\n     */\n    er_net_read_interrupted = 1159,\n\n    /**\n     * \\brief Common server error. Error number: 1160, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_error_on_write\">ER_NET_ERROR_ON_WRITE</a>.\n     */\n    er_net_error_on_write = 1160,\n\n    /**\n     * \\brief Common server error. Error number: 1161, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_net_write_interrupted\">ER_NET_WRITE_INTERRUPTED</a>.\n     */\n    er_net_write_interrupted = 1161,\n\n    /**\n     * \\brief Common server error. Error number: 1162, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_string\">ER_TOO_LONG_STRING</a>.\n     */\n    er_too_long_string = 1162,\n\n    /**\n     * \\brief Common server error. Error number: 1163, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_cant_handle_blob\">ER_TABLE_CANT_HANDLE_BLOB</a>.\n     */\n    er_table_cant_handle_blob = 1163,\n\n    /**\n     * \\brief Common server error. Error number: 1164, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_cant_handle_auto_increment\">ER_TABLE_CANT_HANDLE_AUTO_INCREMENT</a>.\n     */\n    er_table_cant_handle_auto_increment = 1164,\n\n    /**\n     * \\brief Common server error. Error number: 1166, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_column_name\">ER_WRONG_COLUMN_NAME</a>.\n     */\n    er_wrong_column_name = 1166,\n\n    /**\n     * \\brief Common server error. Error number: 1167, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_key_column\">ER_WRONG_KEY_COLUMN</a>.\n     */\n    er_wrong_key_column = 1167,\n\n    /**\n     * \\brief Common server error. Error number: 1168, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_mrg_table\">ER_WRONG_MRG_TABLE</a>.\n     */\n    er_wrong_mrg_table = 1168,\n\n    /**\n     * \\brief Common server error. Error number: 1169, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_unique\">ER_DUP_UNIQUE</a>.\n     */\n    er_dup_unique = 1169,\n\n    /**\n     * \\brief Common server error. Error number: 1170, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_blob_key_without_length\">ER_BLOB_KEY_WITHOUT_LENGTH</a>.\n     */\n    er_blob_key_without_length = 1170,\n\n    /**\n     * \\brief Common server error. Error number: 1171, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_primary_cant_have_null\">ER_PRIMARY_CANT_HAVE_NULL</a>.\n     */\n    er_primary_cant_have_null = 1171,\n\n    /**\n     * \\brief Common server error. Error number: 1172, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_rows\">ER_TOO_MANY_ROWS</a>.\n     */\n    er_too_many_rows = 1172,\n\n    /**\n     * \\brief Common server error. Error number: 1173, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_requires_primary_key\">ER_REQUIRES_PRIMARY_KEY</a>.\n     */\n    er_requires_primary_key = 1173,\n\n    /**\n     * \\brief Common server error. Error number: 1174, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_raid_compiled\">ER_NO_RAID_COMPILED</a>.\n     */\n    er_no_raid_compiled = 1174,\n\n    /**\n     * \\brief Common server error. Error number: 1175, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_update_without_key_in_safe_mode\">ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE</a>.\n     */\n    er_update_without_key_in_safe_mode = 1175,\n\n    /**\n     * \\brief Common server error. Error number: 1177, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_check_no_such_table\">ER_CHECK_NO_SUCH_TABLE</a>.\n     */\n    er_check_no_such_table = 1177,\n\n    /**\n     * \\brief Common server error. Error number: 1178, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_check_not_implemented\">ER_CHECK_NOT_IMPLEMENTED</a>.\n     */\n    er_check_not_implemented = 1178,\n\n    /**\n     * \\brief Common server error. Error number: 1179, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_do_this_during_an_transaction\">ER_CANT_DO_THIS_DURING_AN_TRANSACTION</a>.\n     */\n    er_cant_do_this_during_an_transaction = 1179,\n\n    /**\n     * \\brief Common server error. Error number: 1180, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_during_commit\">ER_ERROR_DURING_COMMIT</a>.\n     */\n    er_error_during_commit = 1180,\n\n    /**\n     * \\brief Common server error. Error number: 1181, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_during_rollback\">ER_ERROR_DURING_ROLLBACK</a>.\n     */\n    er_error_during_rollback = 1181,\n\n    /**\n     * \\brief Common server error. Error number: 1182, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_during_flush_logs\">ER_ERROR_DURING_FLUSH_LOGS</a>.\n     */\n    er_error_during_flush_logs = 1182,\n\n    /**\n     * \\brief Common server error. Error number: 1183, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_during_checkpoint\">ER_ERROR_DURING_CHECKPOINT</a>.\n     */\n    er_error_during_checkpoint = 1183,\n\n    /**\n     * \\brief Common server error. Error number: 1184, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_new_aborting_connection\">ER_NEW_ABORTING_CONNECTION</a>.\n     */\n    er_new_aborting_connection = 1184,\n\n    /**\n     * \\brief Common server error. Error number: 1186, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_flush_master_binlog_closed\">ER_FLUSH_MASTER_BINLOG_CLOSED</a>.\n     */\n    er_flush_master_binlog_closed = 1186,\n\n    /**\n     * \\brief Common server error. Error number: 1187, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_index_rebuild\">ER_INDEX_REBUILD</a>.\n     */\n    er_index_rebuild = 1187,\n\n    /**\n     * \\brief Common server error. Error number: 1188, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master\">ER_MASTER</a>.\n     */\n    er_master = 1188,\n\n    /**\n     * \\brief Common server error. Error number: 1189, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master_net_read\">ER_MASTER_NET_READ</a>.\n     */\n    er_master_net_read = 1189,\n\n    /**\n     * \\brief Common server error. Error number: 1190, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master_net_write\">ER_MASTER_NET_WRITE</a>.\n     */\n    er_master_net_write = 1190,\n\n    /**\n     * \\brief Common server error. Error number: 1191, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ft_matching_key_not_found\">ER_FT_MATCHING_KEY_NOT_FOUND</a>.\n     */\n    er_ft_matching_key_not_found = 1191,\n\n    /**\n     * \\brief Common server error. Error number: 1192, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_lock_or_active_transaction\">ER_LOCK_OR_ACTIVE_TRANSACTION</a>.\n     */\n    er_lock_or_active_transaction = 1192,\n\n    /**\n     * \\brief Common server error. Error number: 1193, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_system_variable\">ER_UNKNOWN_SYSTEM_VARIABLE</a>.\n     */\n    er_unknown_system_variable = 1193,\n\n    /**\n     * \\brief Common server error. Error number: 1194, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_crashed_on_usage\">ER_CRASHED_ON_USAGE</a>.\n     */\n    er_crashed_on_usage = 1194,\n\n    /**\n     * \\brief Common server error. Error number: 1195, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_crashed_on_repair\">ER_CRASHED_ON_REPAIR</a>.\n     */\n    er_crashed_on_repair = 1195,\n\n    /**\n     * \\brief Common server error. Error number: 1196, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warning_not_complete_rollback\">ER_WARNING_NOT_COMPLETE_ROLLBACK</a>.\n     */\n    er_warning_not_complete_rollback = 1196,\n\n    /**\n     * \\brief Common server error. Error number: 1197, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trans_cache_full\">ER_TRANS_CACHE_FULL</a>.\n     */\n    er_trans_cache_full = 1197,\n\n    /**\n     * \\brief Common server error. Error number: 1198, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_must_stop\">ER_SLAVE_MUST_STOP</a>.\n     */\n    er_slave_must_stop = 1198,\n\n    /**\n     * \\brief Common server error. Error number: 1199, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_not_running\">ER_SLAVE_NOT_RUNNING</a>.\n     */\n    er_slave_not_running = 1199,\n\n    /**\n     * \\brief Common server error. Error number: 1200, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_slave\">ER_BAD_SLAVE</a>.\n     */\n    er_bad_slave = 1200,\n\n    /**\n     * \\brief Common server error. Error number: 1201, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master_info\">ER_MASTER_INFO</a>.\n     */\n    er_master_info = 1201,\n\n    /**\n     * \\brief Common server error. Error number: 1202, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_thread\">ER_SLAVE_THREAD</a>.\n     */\n    er_slave_thread = 1202,\n\n    /**\n     * \\brief Common server error. Error number: 1203, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_user_connections\">ER_TOO_MANY_USER_CONNECTIONS</a>.\n     */\n    er_too_many_user_connections = 1203,\n\n    /**\n     * \\brief Common server error. Error number: 1204, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_set_constants_only\">ER_SET_CONSTANTS_ONLY</a>.\n     */\n    er_set_constants_only = 1204,\n\n    /**\n     * \\brief Common server error. Error number: 1205, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_lock_wait_timeout\">ER_LOCK_WAIT_TIMEOUT</a>.\n     */\n    er_lock_wait_timeout = 1205,\n\n    /**\n     * \\brief Common server error. Error number: 1206, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_lock_table_full\">ER_LOCK_TABLE_FULL</a>.\n     */\n    er_lock_table_full = 1206,\n\n    /**\n     * \\brief Common server error. Error number: 1207, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_read_only_transaction\">ER_READ_ONLY_TRANSACTION</a>.\n     */\n    er_read_only_transaction = 1207,\n\n    /**\n     * \\brief Common server error. Error number: 1208, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_drop_db_with_read_lock\">ER_DROP_DB_WITH_READ_LOCK</a>.\n     */\n    er_drop_db_with_read_lock = 1208,\n\n    /**\n     * \\brief Common server error. Error number: 1209, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_create_db_with_read_lock\">ER_CREATE_DB_WITH_READ_LOCK</a>.\n     */\n    er_create_db_with_read_lock = 1209,\n\n    /**\n     * \\brief Common server error. Error number: 1210, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_arguments\">ER_WRONG_ARGUMENTS</a>.\n     */\n    er_wrong_arguments = 1210,\n\n    /**\n     * \\brief Common server error. Error number: 1211, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_permission_to_create_user\">ER_NO_PERMISSION_TO_CREATE_USER</a>.\n     */\n    er_no_permission_to_create_user = 1211,\n\n    /**\n     * \\brief Common server error. Error number: 1212, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_union_tables_in_different_dir\">ER_UNION_TABLES_IN_DIFFERENT_DIR</a>.\n     */\n    er_union_tables_in_different_dir = 1212,\n\n    /**\n     * \\brief Common server error. Error number: 1213, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_lock_deadlock\">ER_LOCK_DEADLOCK</a>.\n     */\n    er_lock_deadlock = 1213,\n\n    /**\n     * \\brief Common server error. Error number: 1214, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_cant_handle_ft\">ER_TABLE_CANT_HANDLE_FT</a>.\n     */\n    er_table_cant_handle_ft = 1214,\n\n    /**\n     * \\brief Common server error. Error number: 1215, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cannot_add_foreign\">ER_CANNOT_ADD_FOREIGN</a>.\n     */\n    er_cannot_add_foreign = 1215,\n\n    /**\n     * \\brief Common server error. Error number: 1216, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_referenced_row\">ER_NO_REFERENCED_ROW</a>.\n     */\n    er_no_referenced_row = 1216,\n\n    /**\n     * \\brief Common server error. Error number: 1217, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_row_is_referenced\">ER_ROW_IS_REFERENCED</a>.\n     */\n    er_row_is_referenced = 1217,\n\n    /**\n     * \\brief Common server error. Error number: 1218, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_connect_to_master\">ER_CONNECT_TO_MASTER</a>.\n     */\n    er_connect_to_master = 1218,\n\n    /**\n     * \\brief Common server error. Error number: 1219, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_query_on_master\">ER_QUERY_ON_MASTER</a>.\n     */\n    er_query_on_master = 1219,\n\n    /**\n     * \\brief Common server error. Error number: 1220, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_when_executing_command\">ER_ERROR_WHEN_EXECUTING_COMMAND</a>.\n     */\n    er_error_when_executing_command = 1220,\n\n    /**\n     * \\brief Common server error. Error number: 1221, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_usage\">ER_WRONG_USAGE</a>.\n     */\n    er_wrong_usage = 1221,\n\n    /**\n     * \\brief Common server error. Error number: 1222, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_number_of_columns_in_select\">ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT</a>.\n     */\n    er_wrong_number_of_columns_in_select = 1222,\n\n    /**\n     * \\brief Common server error. Error number: 1223, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_update_with_readlock\">ER_CANT_UPDATE_WITH_READLOCK</a>.\n     */\n    er_cant_update_with_readlock = 1223,\n\n    /**\n     * \\brief Common server error. Error number: 1224, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mixing_not_allowed\">ER_MIXING_NOT_ALLOWED</a>.\n     */\n    er_mixing_not_allowed = 1224,\n\n    /**\n     * \\brief Common server error. Error number: 1225, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_argument\">ER_DUP_ARGUMENT</a>.\n     */\n    er_dup_argument = 1225,\n\n    /**\n     * \\brief Common server error. Error number: 1226, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_user_limit_reached\">ER_USER_LIMIT_REACHED</a>.\n     */\n    er_user_limit_reached = 1226,\n\n    /**\n     * \\brief Common server error. Error number: 1227, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_specific_access_denied_error\">ER_SPECIFIC_ACCESS_DENIED_ERROR</a>.\n     */\n    er_specific_access_denied_error = 1227,\n\n    /**\n     * \\brief Common server error. Error number: 1228, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_local_variable\">ER_LOCAL_VARIABLE</a>.\n     */\n    er_local_variable = 1228,\n\n    /**\n     * \\brief Common server error. Error number: 1229, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_global_variable\">ER_GLOBAL_VARIABLE</a>.\n     */\n    er_global_variable = 1229,\n\n    /**\n     * \\brief Common server error. Error number: 1230, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_default\">ER_NO_DEFAULT</a>.\n     */\n    er_no_default = 1230,\n\n    /**\n     * \\brief Common server error. Error number: 1231, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_value_for_var\">ER_WRONG_VALUE_FOR_VAR</a>.\n     */\n    er_wrong_value_for_var = 1231,\n\n    /**\n     * \\brief Common server error. Error number: 1232, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_type_for_var\">ER_WRONG_TYPE_FOR_VAR</a>.\n     */\n    er_wrong_type_for_var = 1232,\n\n    /**\n     * \\brief Common server error. Error number: 1233, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_var_cant_be_read\">ER_VAR_CANT_BE_READ</a>.\n     */\n    er_var_cant_be_read = 1233,\n\n    /**\n     * \\brief Common server error. Error number: 1234, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_use_option_here\">ER_CANT_USE_OPTION_HERE</a>.\n     */\n    er_cant_use_option_here = 1234,\n\n    /**\n     * \\brief Common server error. Error number: 1235, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_supported_yet\">ER_NOT_SUPPORTED_YET</a>.\n     */\n    er_not_supported_yet = 1235,\n\n    /**\n     * \\brief Common server error. Error number: 1236, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master_fatal_error_reading_binlog\">ER_MASTER_FATAL_ERROR_READING_BINLOG</a>.\n     */\n    er_master_fatal_error_reading_binlog = 1236,\n\n    /**\n     * \\brief Common server error. Error number: 1237, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_ignored_table\">ER_SLAVE_IGNORED_TABLE</a>.\n     */\n    er_slave_ignored_table = 1237,\n\n    /**\n     * \\brief Common server error. Error number: 1238, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_incorrect_global_local_var\">ER_INCORRECT_GLOBAL_LOCAL_VAR</a>.\n     */\n    er_incorrect_global_local_var = 1238,\n\n    /**\n     * \\brief Common server error. Error number: 1239, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_fk_def\">ER_WRONG_FK_DEF</a>.\n     */\n    er_wrong_fk_def = 1239,\n\n    /**\n     * \\brief Common server error. Error number: 1240, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_key_ref_do_not_match_table_ref\">ER_KEY_REF_DO_NOT_MATCH_TABLE_REF</a>.\n     */\n    er_key_ref_do_not_match_table_ref = 1240,\n\n    /**\n     * \\brief Common server error. Error number: 1241, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_operand_columns\">ER_OPERAND_COLUMNS</a>.\n     */\n    er_operand_columns = 1241,\n\n    /**\n     * \\brief Common server error. Error number: 1242, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_subquery_no_1_row\">ER_SUBQUERY_NO_1_ROW</a>.\n     */\n    er_subquery_no_1_row = 1242,\n\n    /**\n     * \\brief Common server error. Error number: 1243, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_stmt_handler\">ER_UNKNOWN_STMT_HANDLER</a>.\n     */\n    er_unknown_stmt_handler = 1243,\n\n    /**\n     * \\brief Common server error. Error number: 1244, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_corrupt_help_db\">ER_CORRUPT_HELP_DB</a>.\n     */\n    er_corrupt_help_db = 1244,\n\n    /**\n     * \\brief Common server error. Error number: 1245, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cyclic_reference\">ER_CYCLIC_REFERENCE</a>.\n     */\n    er_cyclic_reference = 1245,\n\n    /**\n     * \\brief Common server error. Error number: 1246, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_auto_convert\">ER_AUTO_CONVERT</a>.\n     */\n    er_auto_convert = 1246,\n\n    /**\n     * \\brief Common server error. Error number: 1247, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_illegal_reference\">ER_ILLEGAL_REFERENCE</a>.\n     */\n    er_illegal_reference = 1247,\n\n    /**\n     * \\brief Common server error. Error number: 1248, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_derived_must_have_alias\">ER_DERIVED_MUST_HAVE_ALIAS</a>.\n     */\n    er_derived_must_have_alias = 1248,\n\n    /**\n     * \\brief Common server error. Error number: 1249, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_select_reduced\">ER_SELECT_REDUCED</a>.\n     */\n    er_select_reduced = 1249,\n\n    /**\n     * \\brief Common server error. Error number: 1250, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tablename_not_allowed_here\">ER_TABLENAME_NOT_ALLOWED_HERE</a>.\n     */\n    er_tablename_not_allowed_here = 1250,\n\n    /**\n     * \\brief Common server error. Error number: 1251, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_supported_auth_mode\">ER_NOT_SUPPORTED_AUTH_MODE</a>.\n     */\n    er_not_supported_auth_mode = 1251,\n\n    /**\n     * \\brief Common server error. Error number: 1252, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_spatial_cant_have_null\">ER_SPATIAL_CANT_HAVE_NULL</a>.\n     */\n    er_spatial_cant_have_null = 1252,\n\n    /**\n     * \\brief Common server error. Error number: 1253, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_collation_charset_mismatch\">ER_COLLATION_CHARSET_MISMATCH</a>.\n     */\n    er_collation_charset_mismatch = 1253,\n\n    /**\n     * \\brief Common server error. Error number: 1254, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_was_running\">ER_SLAVE_WAS_RUNNING</a>.\n     */\n    er_slave_was_running = 1254,\n\n    /**\n     * \\brief Common server error. Error number: 1255, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_was_not_running\">ER_SLAVE_WAS_NOT_RUNNING</a>.\n     */\n    er_slave_was_not_running = 1255,\n\n    /**\n     * \\brief Common server error. Error number: 1256, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_for_uncompress\">ER_TOO_BIG_FOR_UNCOMPRESS</a>.\n     */\n    er_too_big_for_uncompress = 1256,\n\n    /**\n     * \\brief Common server error. Error number: 1257, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_zlib_z_mem_error\">ER_ZLIB_Z_MEM_ERROR</a>.\n     */\n    er_zlib_z_mem_error = 1257,\n\n    /**\n     * \\brief Common server error. Error number: 1258, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_zlib_z_buf_error\">ER_ZLIB_Z_BUF_ERROR</a>.\n     */\n    er_zlib_z_buf_error = 1258,\n\n    /**\n     * \\brief Common server error. Error number: 1259, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_zlib_z_data_error\">ER_ZLIB_Z_DATA_ERROR</a>.\n     */\n    er_zlib_z_data_error = 1259,\n\n    /**\n     * \\brief Common server error. Error number: 1260, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cut_value_group_concat\">ER_CUT_VALUE_GROUP_CONCAT</a>.\n     */\n    er_cut_value_group_concat = 1260,\n\n    /**\n     * \\brief Common server error. Error number: 1261, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_too_few_records\">ER_WARN_TOO_FEW_RECORDS</a>.\n     */\n    er_warn_too_few_records = 1261,\n\n    /**\n     * \\brief Common server error. Error number: 1262, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_too_many_records\">ER_WARN_TOO_MANY_RECORDS</a>.\n     */\n    er_warn_too_many_records = 1262,\n\n    /**\n     * \\brief Common server error. Error number: 1263, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_null_to_notnull\">ER_WARN_NULL_TO_NOTNULL</a>.\n     */\n    er_warn_null_to_notnull = 1263,\n\n    /**\n     * \\brief Common server error. Error number: 1264, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_data_out_of_range\">ER_WARN_DATA_OUT_OF_RANGE</a>.\n     */\n    er_warn_data_out_of_range = 1264,\n\n    /**\n     * \\brief Common server error. Error number: 1265, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_data_truncated\">WARN_DATA_TRUNCATED</a>.\n     */\n    warn_data_truncated = 1265,\n\n    /**\n     * \\brief Common server error. Error number: 1266, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_using_other_handler\">ER_WARN_USING_OTHER_HANDLER</a>.\n     */\n    er_warn_using_other_handler = 1266,\n\n    /**\n     * \\brief Common server error. Error number: 1267, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_aggregate_2collations\">ER_CANT_AGGREGATE_2COLLATIONS</a>.\n     */\n    er_cant_aggregate_2collations = 1267,\n\n    /**\n     * \\brief Common server error. Error number: 1268, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_drop_user\">ER_DROP_USER</a>.\n     */\n    er_drop_user = 1268,\n\n    /**\n     * \\brief Common server error. Error number: 1269, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_revoke_grants\">ER_REVOKE_GRANTS</a>.\n     */\n    er_revoke_grants = 1269,\n\n    /**\n     * \\brief Common server error. Error number: 1270, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_aggregate_3collations\">ER_CANT_AGGREGATE_3COLLATIONS</a>.\n     */\n    er_cant_aggregate_3collations = 1270,\n\n    /**\n     * \\brief Common server error. Error number: 1271, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_aggregate_ncollations\">ER_CANT_AGGREGATE_NCOLLATIONS</a>.\n     */\n    er_cant_aggregate_ncollations = 1271,\n\n    /**\n     * \\brief Common server error. Error number: 1272, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_variable_is_not_struct\">ER_VARIABLE_IS_NOT_STRUCT</a>.\n     */\n    er_variable_is_not_struct = 1272,\n\n    /**\n     * \\brief Common server error. Error number: 1273, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_collation\">ER_UNKNOWN_COLLATION</a>.\n     */\n    er_unknown_collation = 1273,\n\n    /**\n     * \\brief Common server error. Error number: 1274, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_ignored_ssl_params\">ER_SLAVE_IGNORED_SSL_PARAMS</a>.\n     */\n    er_slave_ignored_ssl_params = 1274,\n\n    /**\n     * \\brief Common server error. Error number: 1275, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_server_is_in_secure_auth_mode\">ER_SERVER_IS_IN_SECURE_AUTH_MODE</a>.\n     */\n    er_server_is_in_secure_auth_mode = 1275,\n\n    /**\n     * \\brief Common server error. Error number: 1276, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_field_resolved\">ER_WARN_FIELD_RESOLVED</a>.\n     */\n    er_warn_field_resolved = 1276,\n\n    /**\n     * \\brief Common server error. Error number: 1277, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_slave_until_cond\">ER_BAD_SLAVE_UNTIL_COND</a>.\n     */\n    er_bad_slave_until_cond = 1277,\n\n    /**\n     * \\brief Common server error. Error number: 1278, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_missing_skip_slave\">ER_MISSING_SKIP_SLAVE</a>.\n     */\n    er_missing_skip_slave = 1278,\n\n    /**\n     * \\brief Common server error. Error number: 1279, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_until_cond_ignored\">ER_UNTIL_COND_IGNORED</a>.\n     */\n    er_until_cond_ignored = 1279,\n\n    /**\n     * \\brief Common server error. Error number: 1280, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_name_for_index\">ER_WRONG_NAME_FOR_INDEX</a>.\n     */\n    er_wrong_name_for_index = 1280,\n\n    /**\n     * \\brief Common server error. Error number: 1281, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_name_for_catalog\">ER_WRONG_NAME_FOR_CATALOG</a>.\n     */\n    er_wrong_name_for_catalog = 1281,\n\n    /**\n     * \\brief Common server error. Error number: 1282, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_qc_resize\">ER_WARN_QC_RESIZE</a>.\n     */\n    er_warn_qc_resize = 1282,\n\n    /**\n     * \\brief Common server error. Error number: 1283, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_ft_column\">ER_BAD_FT_COLUMN</a>.\n     */\n    er_bad_ft_column = 1283,\n\n    /**\n     * \\brief Common server error. Error number: 1284, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_key_cache\">ER_UNKNOWN_KEY_CACHE</a>.\n     */\n    er_unknown_key_cache = 1284,\n\n    /**\n     * \\brief Common server error. Error number: 1285, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_hostname_wont_work\">ER_WARN_HOSTNAME_WONT_WORK</a>.\n     */\n    er_warn_hostname_wont_work = 1285,\n\n    /**\n     * \\brief Common server error. Error number: 1286, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_storage_engine\">ER_UNKNOWN_STORAGE_ENGINE</a>.\n     */\n    er_unknown_storage_engine = 1286,\n\n    /**\n     * \\brief Common server error. Error number: 1287, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_deprecated_syntax\">ER_WARN_DEPRECATED_SYNTAX</a>.\n     */\n    er_warn_deprecated_syntax = 1287,\n\n    /**\n     * \\brief Common server error. Error number: 1288, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_non_updatable_table\">ER_NON_UPDATABLE_TABLE</a>.\n     */\n    er_non_updatable_table = 1288,\n\n    /**\n     * \\brief Common server error. Error number: 1289, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_feature_disabled\">ER_FEATURE_DISABLED</a>.\n     */\n    er_feature_disabled = 1289,\n\n    /**\n     * \\brief Common server error. Error number: 1290, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_option_prevents_statement\">ER_OPTION_PREVENTS_STATEMENT</a>.\n     */\n    er_option_prevents_statement = 1290,\n\n    /**\n     * \\brief Common server error. Error number: 1291, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_duplicated_value_in_type\">ER_DUPLICATED_VALUE_IN_TYPE</a>.\n     */\n    er_duplicated_value_in_type = 1291,\n\n    /**\n     * \\brief Common server error. Error number: 1292, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_truncated_wrong_value\">ER_TRUNCATED_WRONG_VALUE</a>.\n     */\n    er_truncated_wrong_value = 1292,\n\n    /**\n     * \\brief Common server error. Error number: 1293, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_much_auto_timestamp_cols\">ER_TOO_MUCH_AUTO_TIMESTAMP_COLS</a>.\n     */\n    er_too_much_auto_timestamp_cols = 1293,\n\n    /**\n     * \\brief Common server error. Error number: 1294, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_on_update\">ER_INVALID_ON_UPDATE</a>.\n     */\n    er_invalid_on_update = 1294,\n\n    /**\n     * \\brief Common server error. Error number: 1295, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unsupported_ps\">ER_UNSUPPORTED_PS</a>.\n     */\n    er_unsupported_ps = 1295,\n\n    /**\n     * \\brief Common server error. Error number: 1296, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_get_errmsg\">ER_GET_ERRMSG</a>.\n     */\n    er_get_errmsg = 1296,\n\n    /**\n     * \\brief Common server error. Error number: 1297, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_get_temporary_errmsg\">ER_GET_TEMPORARY_ERRMSG</a>.\n     */\n    er_get_temporary_errmsg = 1297,\n\n    /**\n     * \\brief Common server error. Error number: 1298, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_time_zone\">ER_UNKNOWN_TIME_ZONE</a>.\n     */\n    er_unknown_time_zone = 1298,\n\n    /**\n     * \\brief Common server error. Error number: 1299, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_invalid_timestamp\">ER_WARN_INVALID_TIMESTAMP</a>.\n     */\n    er_warn_invalid_timestamp = 1299,\n\n    /**\n     * \\brief Common server error. Error number: 1300, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_character_string\">ER_INVALID_CHARACTER_STRING</a>.\n     */\n    er_invalid_character_string = 1300,\n\n    /**\n     * \\brief Common server error. Error number: 1301, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_allowed_packet_overflowed\">ER_WARN_ALLOWED_PACKET_OVERFLOWED</a>.\n     */\n    er_warn_allowed_packet_overflowed = 1301,\n\n    /**\n     * \\brief Common server error. Error number: 1302, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_conflicting_declarations\">ER_CONFLICTING_DECLARATIONS</a>.\n     */\n    er_conflicting_declarations = 1302,\n\n    /**\n     * \\brief Common server error. Error number: 1303, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_no_recursive_create\">ER_SP_NO_RECURSIVE_CREATE</a>.\n     */\n    er_sp_no_recursive_create = 1303,\n\n    /**\n     * \\brief Common server error. Error number: 1304, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_already_exists\">ER_SP_ALREADY_EXISTS</a>.\n     */\n    er_sp_already_exists = 1304,\n\n    /**\n     * \\brief Common server error. Error number: 1305, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_does_not_exist\">ER_SP_DOES_NOT_EXIST</a>.\n     */\n    er_sp_does_not_exist = 1305,\n\n    /**\n     * \\brief Common server error. Error number: 1306, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_drop_failed\">ER_SP_DROP_FAILED</a>.\n     */\n    er_sp_drop_failed = 1306,\n\n    /**\n     * \\brief Common server error. Error number: 1307, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_store_failed\">ER_SP_STORE_FAILED</a>.\n     */\n    er_sp_store_failed = 1307,\n\n    /**\n     * \\brief Common server error. Error number: 1308, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_lilabel_mismatch\">ER_SP_LILABEL_MISMATCH</a>.\n     */\n    er_sp_lilabel_mismatch = 1308,\n\n    /**\n     * \\brief Common server error. Error number: 1309, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_label_redefine\">ER_SP_LABEL_REDEFINE</a>.\n     */\n    er_sp_label_redefine = 1309,\n\n    /**\n     * \\brief Common server error. Error number: 1310, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_label_mismatch\">ER_SP_LABEL_MISMATCH</a>.\n     */\n    er_sp_label_mismatch = 1310,\n\n    /**\n     * \\brief Common server error. Error number: 1311, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_uninit_var\">ER_SP_UNINIT_VAR</a>.\n     */\n    er_sp_uninit_var = 1311,\n\n    /**\n     * \\brief Common server error. Error number: 1312, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_badselect\">ER_SP_BADSELECT</a>.\n     */\n    er_sp_badselect = 1312,\n\n    /**\n     * \\brief Common server error. Error number: 1313, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_badreturn\">ER_SP_BADRETURN</a>.\n     */\n    er_sp_badreturn = 1313,\n\n    /**\n     * \\brief Common server error. Error number: 1314, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_badstatement\">ER_SP_BADSTATEMENT</a>.\n     */\n    er_sp_badstatement = 1314,\n\n    /**\n     * \\brief Common server error. Error number: 1315, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_update_log_deprecated_ignored\">ER_UPDATE_LOG_DEPRECATED_IGNORED</a>.\n     */\n    er_update_log_deprecated_ignored = 1315,\n\n    /**\n     * \\brief Common server error. Error number: 1316, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_update_log_deprecated_translated\">ER_UPDATE_LOG_DEPRECATED_TRANSLATED</a>.\n     */\n    er_update_log_deprecated_translated = 1316,\n\n    /**\n     * \\brief Common server error. Error number: 1317, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_query_interrupted\">ER_QUERY_INTERRUPTED</a>.\n     */\n    er_query_interrupted = 1317,\n\n    /**\n     * \\brief Common server error. Error number: 1318, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_wrong_no_of_args\">ER_SP_WRONG_NO_OF_ARGS</a>.\n     */\n    er_sp_wrong_no_of_args = 1318,\n\n    /**\n     * \\brief Common server error. Error number: 1319, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cond_mismatch\">ER_SP_COND_MISMATCH</a>.\n     */\n    er_sp_cond_mismatch = 1319,\n\n    /**\n     * \\brief Common server error. Error number: 1320, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_noreturn\">ER_SP_NORETURN</a>.\n     */\n    er_sp_noreturn = 1320,\n\n    /**\n     * \\brief Common server error. Error number: 1321, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_noreturnend\">ER_SP_NORETURNEND</a>.\n     */\n    er_sp_noreturnend = 1321,\n\n    /**\n     * \\brief Common server error. Error number: 1322, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_bad_cursor_query\">ER_SP_BAD_CURSOR_QUERY</a>.\n     */\n    er_sp_bad_cursor_query = 1322,\n\n    /**\n     * \\brief Common server error. Error number: 1323, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_bad_cursor_select\">ER_SP_BAD_CURSOR_SELECT</a>.\n     */\n    er_sp_bad_cursor_select = 1323,\n\n    /**\n     * \\brief Common server error. Error number: 1324, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cursor_mismatch\">ER_SP_CURSOR_MISMATCH</a>.\n     */\n    er_sp_cursor_mismatch = 1324,\n\n    /**\n     * \\brief Common server error. Error number: 1325, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cursor_already_open\">ER_SP_CURSOR_ALREADY_OPEN</a>.\n     */\n    er_sp_cursor_already_open = 1325,\n\n    /**\n     * \\brief Common server error. Error number: 1326, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cursor_not_open\">ER_SP_CURSOR_NOT_OPEN</a>.\n     */\n    er_sp_cursor_not_open = 1326,\n\n    /**\n     * \\brief Common server error. Error number: 1327, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_undeclared_var\">ER_SP_UNDECLARED_VAR</a>.\n     */\n    er_sp_undeclared_var = 1327,\n\n    /**\n     * \\brief Common server error. Error number: 1328, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_wrong_no_of_fetch_args\">ER_SP_WRONG_NO_OF_FETCH_ARGS</a>.\n     */\n    er_sp_wrong_no_of_fetch_args = 1328,\n\n    /**\n     * \\brief Common server error. Error number: 1329, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_fetch_no_data\">ER_SP_FETCH_NO_DATA</a>.\n     */\n    er_sp_fetch_no_data = 1329,\n\n    /**\n     * \\brief Common server error. Error number: 1330, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_dup_param\">ER_SP_DUP_PARAM</a>.\n     */\n    er_sp_dup_param = 1330,\n\n    /**\n     * \\brief Common server error. Error number: 1331, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_dup_var\">ER_SP_DUP_VAR</a>.\n     */\n    er_sp_dup_var = 1331,\n\n    /**\n     * \\brief Common server error. Error number: 1332, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_dup_cond\">ER_SP_DUP_COND</a>.\n     */\n    er_sp_dup_cond = 1332,\n\n    /**\n     * \\brief Common server error. Error number: 1333, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_dup_curs\">ER_SP_DUP_CURS</a>.\n     */\n    er_sp_dup_curs = 1333,\n\n    /**\n     * \\brief Common server error. Error number: 1334, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cant_alter\">ER_SP_CANT_ALTER</a>.\n     */\n    er_sp_cant_alter = 1334,\n\n    /**\n     * \\brief Common server error. Error number: 1335, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_subselect_nyi\">ER_SP_SUBSELECT_NYI</a>.\n     */\n    er_sp_subselect_nyi = 1335,\n\n    /**\n     * \\brief Common server error. Error number: 1336, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stmt_not_allowed_in_sf_or_trg\">ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG</a>.\n     */\n    er_stmt_not_allowed_in_sf_or_trg = 1336,\n\n    /**\n     * \\brief Common server error. Error number: 1337, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_varcond_after_curshndlr\">ER_SP_VARCOND_AFTER_CURSHNDLR</a>.\n     */\n    er_sp_varcond_after_curshndlr = 1337,\n\n    /**\n     * \\brief Common server error. Error number: 1338, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cursor_after_handler\">ER_SP_CURSOR_AFTER_HANDLER</a>.\n     */\n    er_sp_cursor_after_handler = 1338,\n\n    /**\n     * \\brief Common server error. Error number: 1339, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_case_not_found\">ER_SP_CASE_NOT_FOUND</a>.\n     */\n    er_sp_case_not_found = 1339,\n\n    /**\n     * \\brief Common server error. Error number: 1340, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fparser_too_big_file\">ER_FPARSER_TOO_BIG_FILE</a>.\n     */\n    er_fparser_too_big_file = 1340,\n\n    /**\n     * \\brief Common server error. Error number: 1341, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fparser_bad_header\">ER_FPARSER_BAD_HEADER</a>.\n     */\n    er_fparser_bad_header = 1341,\n\n    /**\n     * \\brief Common server error. Error number: 1342, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fparser_eof_in_comment\">ER_FPARSER_EOF_IN_COMMENT</a>.\n     */\n    er_fparser_eof_in_comment = 1342,\n\n    /**\n     * \\brief Common server error. Error number: 1343, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fparser_error_in_parameter\">ER_FPARSER_ERROR_IN_PARAMETER</a>.\n     */\n    er_fparser_error_in_parameter = 1343,\n\n    /**\n     * \\brief Common server error. Error number: 1344, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fparser_eof_in_unknown_parameter\">ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER</a>.\n     */\n    er_fparser_eof_in_unknown_parameter = 1344,\n\n    /**\n     * \\brief Common server error. Error number: 1345, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_no_explain\">ER_VIEW_NO_EXPLAIN</a>.\n     */\n    er_view_no_explain = 1345,\n\n    /**\n     * \\brief Common server error. Error number: 1346, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_frm_unknown_type\">ER_FRM_UNKNOWN_TYPE</a>.\n     */\n    er_frm_unknown_type = 1346,\n\n    /**\n     * \\brief Common server error. Error number: 1347, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_object\">ER_WRONG_OBJECT</a>.\n     */\n    er_wrong_object = 1347,\n\n    /**\n     * \\brief Common server error. Error number: 1348, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_nonupdateable_column\">ER_NONUPDATEABLE_COLUMN</a>.\n     */\n    er_nonupdateable_column = 1348,\n\n    /**\n     * \\brief Common server error. Error number: 1350, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_select_clause\">ER_VIEW_SELECT_CLAUSE</a>.\n     */\n    er_view_select_clause = 1350,\n\n    /**\n     * \\brief Common server error. Error number: 1351, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_select_variable\">ER_VIEW_SELECT_VARIABLE</a>.\n     */\n    er_view_select_variable = 1351,\n\n    /**\n     * \\brief Common server error. Error number: 1352, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_select_tmptable\">ER_VIEW_SELECT_TMPTABLE</a>.\n     */\n    er_view_select_tmptable = 1352,\n\n    /**\n     * \\brief Common server error. Error number: 1353, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_wrong_list\">ER_VIEW_WRONG_LIST</a>.\n     */\n    er_view_wrong_list = 1353,\n\n    /**\n     * \\brief Common server error. Error number: 1354, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_view_merge\">ER_WARN_VIEW_MERGE</a>.\n     */\n    er_warn_view_merge = 1354,\n\n    /**\n     * \\brief Common server error. Error number: 1355, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_view_without_key\">ER_WARN_VIEW_WITHOUT_KEY</a>.\n     */\n    er_warn_view_without_key = 1355,\n\n    /**\n     * \\brief Common server error. Error number: 1356, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_invalid\">ER_VIEW_INVALID</a>.\n     */\n    er_view_invalid = 1356,\n\n    /**\n     * \\brief Common server error. Error number: 1357, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_no_drop_sp\">ER_SP_NO_DROP_SP</a>.\n     */\n    er_sp_no_drop_sp = 1357,\n\n    /**\n     * \\brief Common server error. Error number: 1358, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_goto_in_hndlr\">ER_SP_GOTO_IN_HNDLR</a>.\n     */\n    er_sp_goto_in_hndlr = 1358,\n\n    /**\n     * \\brief Common server error. Error number: 1359, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_already_exists\">ER_TRG_ALREADY_EXISTS</a>.\n     */\n    er_trg_already_exists = 1359,\n\n    /**\n     * \\brief Common server error. Error number: 1360, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_does_not_exist\">ER_TRG_DOES_NOT_EXIST</a>.\n     */\n    er_trg_does_not_exist = 1360,\n\n    /**\n     * \\brief Common server error. Error number: 1361, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_on_view_or_temp_table\">ER_TRG_ON_VIEW_OR_TEMP_TABLE</a>.\n     */\n    er_trg_on_view_or_temp_table = 1361,\n\n    /**\n     * \\brief Common server error. Error number: 1362, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_cant_change_row\">ER_TRG_CANT_CHANGE_ROW</a>.\n     */\n    er_trg_cant_change_row = 1362,\n\n    /**\n     * \\brief Common server error. Error number: 1363, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_no_such_row_in_trg\">ER_TRG_NO_SUCH_ROW_IN_TRG</a>.\n     */\n    er_trg_no_such_row_in_trg = 1363,\n\n    /**\n     * \\brief Common server error. Error number: 1364, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_default_for_field\">ER_NO_DEFAULT_FOR_FIELD</a>.\n     */\n    er_no_default_for_field = 1364,\n\n    /**\n     * \\brief Common server error. Error number: 1365, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_division_by_zero\">ER_DIVISION_BY_ZERO</a>.\n     */\n    er_division_by_zero = 1365,\n\n    /**\n     * \\brief Common server error. Error number: 1366, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_truncated_wrong_value_for_field\">ER_TRUNCATED_WRONG_VALUE_FOR_FIELD</a>.\n     */\n    er_truncated_wrong_value_for_field = 1366,\n\n    /**\n     * \\brief Common server error. Error number: 1367, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_illegal_value_for_type\">ER_ILLEGAL_VALUE_FOR_TYPE</a>.\n     */\n    er_illegal_value_for_type = 1367,\n\n    /**\n     * \\brief Common server error. Error number: 1368, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_nonupd_check\">ER_VIEW_NONUPD_CHECK</a>.\n     */\n    er_view_nonupd_check = 1368,\n\n    /**\n     * \\brief Common server error. Error number: 1369, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_check_failed\">ER_VIEW_CHECK_FAILED</a>.\n     */\n    er_view_check_failed = 1369,\n\n    /**\n     * \\brief Common server error. Error number: 1370, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_procaccess_denied_error\">ER_PROCACCESS_DENIED_ERROR</a>.\n     */\n    er_procaccess_denied_error = 1370,\n\n    /**\n     * \\brief Common server error. Error number: 1371, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_relay_log_fail\">ER_RELAY_LOG_FAIL</a>.\n     */\n    er_relay_log_fail = 1371,\n\n    /**\n     * \\brief Common server error. Error number: 1372, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_passwd_length\">ER_PASSWD_LENGTH</a>.\n     */\n    er_passwd_length = 1372,\n\n    /**\n     * \\brief Common server error. Error number: 1373, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_target_binlog\">ER_UNKNOWN_TARGET_BINLOG</a>.\n     */\n    er_unknown_target_binlog = 1373,\n\n    /**\n     * \\brief Common server error. Error number: 1374, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_io_err_log_index_read\">ER_IO_ERR_LOG_INDEX_READ</a>.\n     */\n    er_io_err_log_index_read = 1374,\n\n    /**\n     * \\brief Common server error. Error number: 1375, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_purge_prohibited\">ER_BINLOG_PURGE_PROHIBITED</a>.\n     */\n    er_binlog_purge_prohibited = 1375,\n\n    /**\n     * \\brief Common server error. Error number: 1376, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fseek_fail\">ER_FSEEK_FAIL</a>.\n     */\n    er_fseek_fail = 1376,\n\n    /**\n     * \\brief Common server error. Error number: 1377, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_purge_fatal_err\">ER_BINLOG_PURGE_FATAL_ERR</a>.\n     */\n    er_binlog_purge_fatal_err = 1377,\n\n    /**\n     * \\brief Common server error. Error number: 1378, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_log_in_use\">ER_LOG_IN_USE</a>.\n     */\n    er_log_in_use = 1378,\n\n    /**\n     * \\brief Common server error. Error number: 1379, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_log_purge_unknown_err\">ER_LOG_PURGE_UNKNOWN_ERR</a>.\n     */\n    er_log_purge_unknown_err = 1379,\n\n    /**\n     * \\brief Common server error. Error number: 1380, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_relay_log_init\">ER_RELAY_LOG_INIT</a>.\n     */\n    er_relay_log_init = 1380,\n\n    /**\n     * \\brief Common server error. Error number: 1381, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_binary_logging\">ER_NO_BINARY_LOGGING</a>.\n     */\n    er_no_binary_logging = 1381,\n\n    /**\n     * \\brief Common server error. Error number: 1382, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_reserved_syntax\">ER_RESERVED_SYNTAX</a>.\n     */\n    er_reserved_syntax = 1382,\n\n    /**\n     * \\brief Common server error. Error number: 1383, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wsas_failed\">ER_WSAS_FAILED</a>.\n     */\n    er_wsas_failed = 1383,\n\n    /**\n     * \\brief Common server error. Error number: 1384, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_diff_groups_proc\">ER_DIFF_GROUPS_PROC</a>.\n     */\n    er_diff_groups_proc = 1384,\n\n    /**\n     * \\brief Common server error. Error number: 1385, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_group_for_proc\">ER_NO_GROUP_FOR_PROC</a>.\n     */\n    er_no_group_for_proc = 1385,\n\n    /**\n     * \\brief Common server error. Error number: 1386, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_order_with_proc\">ER_ORDER_WITH_PROC</a>.\n     */\n    er_order_with_proc = 1386,\n\n    /**\n     * \\brief Common server error. Error number: 1387, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_logging_prohibit_changing_of\">ER_LOGGING_PROHIBIT_CHANGING_OF</a>.\n     */\n    er_logging_prohibit_changing_of = 1387,\n\n    /**\n     * \\brief Common server error. Error number: 1388, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_file_mapping\">ER_NO_FILE_MAPPING</a>.\n     */\n    er_no_file_mapping = 1388,\n\n    /**\n     * \\brief Common server error. Error number: 1389, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_magic\">ER_WRONG_MAGIC</a>.\n     */\n    er_wrong_magic = 1389,\n\n    /**\n     * \\brief Common server error. Error number: 1390, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ps_many_param\">ER_PS_MANY_PARAM</a>.\n     */\n    er_ps_many_param = 1390,\n\n    /**\n     * \\brief Common server error. Error number: 1391, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_key_part_0\">ER_KEY_PART_0</a>.\n     */\n    er_key_part_0 = 1391,\n\n    /**\n     * \\brief Common server error. Error number: 1392, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_checksum\">ER_VIEW_CHECKSUM</a>.\n     */\n    er_view_checksum = 1392,\n\n    /**\n     * \\brief Common server error. Error number: 1393, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_multiupdate\">ER_VIEW_MULTIUPDATE</a>.\n     */\n    er_view_multiupdate = 1393,\n\n    /**\n     * \\brief Common server error. Error number: 1394, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_no_insert_field_list\">ER_VIEW_NO_INSERT_FIELD_LIST</a>.\n     */\n    er_view_no_insert_field_list = 1394,\n\n    /**\n     * \\brief Common server error. Error number: 1395, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_delete_merge_view\">ER_VIEW_DELETE_MERGE_VIEW</a>.\n     */\n    er_view_delete_merge_view = 1395,\n\n    /**\n     * \\brief Common server error. Error number: 1396, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cannot_user\">ER_CANNOT_USER</a>.\n     */\n    er_cannot_user = 1396,\n\n    /**\n     * \\brief Common server error. Error number: 1397, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xaer_nota\">ER_XAER_NOTA</a>.\n     */\n    er_xaer_nota = 1397,\n\n    /**\n     * \\brief Common server error. Error number: 1398, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xaer_inval\">ER_XAER_INVAL</a>.\n     */\n    er_xaer_inval = 1398,\n\n    /**\n     * \\brief Common server error. Error number: 1399, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xaer_rmfail\">ER_XAER_RMFAIL</a>.\n     */\n    er_xaer_rmfail = 1399,\n\n    /**\n     * \\brief Common server error. Error number: 1400, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xaer_outside\">ER_XAER_OUTSIDE</a>.\n     */\n    er_xaer_outside = 1400,\n\n    /**\n     * \\brief Common server error. Error number: 1401, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xaer_rmerr\">ER_XAER_RMERR</a>.\n     */\n    er_xaer_rmerr = 1401,\n\n    /**\n     * \\brief Common server error. Error number: 1402, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xa_rbrollback\">ER_XA_RBROLLBACK</a>.\n     */\n    er_xa_rbrollback = 1402,\n\n    /**\n     * \\brief Common server error. Error number: 1403, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_nonexisting_proc_grant\">ER_NONEXISTING_PROC_GRANT</a>.\n     */\n    er_nonexisting_proc_grant = 1403,\n\n    /**\n     * \\brief Common server error. Error number: 1404, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_proc_auto_grant_fail\">ER_PROC_AUTO_GRANT_FAIL</a>.\n     */\n    er_proc_auto_grant_fail = 1404,\n\n    /**\n     * \\brief Common server error. Error number: 1405, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_proc_auto_revoke_fail\">ER_PROC_AUTO_REVOKE_FAIL</a>.\n     */\n    er_proc_auto_revoke_fail = 1405,\n\n    /**\n     * \\brief Common server error. Error number: 1406, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_data_too_long\">ER_DATA_TOO_LONG</a>.\n     */\n    er_data_too_long = 1406,\n\n    /**\n     * \\brief Common server error. Error number: 1407, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_bad_sqlstate\">ER_SP_BAD_SQLSTATE</a>.\n     */\n    er_sp_bad_sqlstate = 1407,\n\n    /**\n     * \\brief Common server error. Error number: 1408, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_startup\">ER_STARTUP</a>.\n     */\n    er_startup = 1408,\n\n    /**\n     * \\brief Common server error. Error number: 1409, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_load_from_fixed_size_rows_to_var\">ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR</a>.\n     */\n    er_load_from_fixed_size_rows_to_var = 1409,\n\n    /**\n     * \\brief Common server error. Error number: 1410, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_user_with_grant\">ER_CANT_CREATE_USER_WITH_GRANT</a>.\n     */\n    er_cant_create_user_with_grant = 1410,\n\n    /**\n     * \\brief Common server error. Error number: 1411, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_value_for_type\">ER_WRONG_VALUE_FOR_TYPE</a>.\n     */\n    er_wrong_value_for_type = 1411,\n\n    /**\n     * \\brief Common server error. Error number: 1412, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_def_changed\">ER_TABLE_DEF_CHANGED</a>.\n     */\n    er_table_def_changed = 1412,\n\n    /**\n     * \\brief Common server error. Error number: 1413, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_dup_handler\">ER_SP_DUP_HANDLER</a>.\n     */\n    er_sp_dup_handler = 1413,\n\n    /**\n     * \\brief Common server error. Error number: 1414, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_not_var_arg\">ER_SP_NOT_VAR_ARG</a>.\n     */\n    er_sp_not_var_arg = 1414,\n\n    /**\n     * \\brief Common server error. Error number: 1415, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_no_retset\">ER_SP_NO_RETSET</a>.\n     */\n    er_sp_no_retset = 1415,\n\n    /**\n     * \\brief Common server error. Error number: 1416, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_geometry_object\">ER_CANT_CREATE_GEOMETRY_OBJECT</a>.\n     */\n    er_cant_create_geometry_object = 1416,\n\n    /**\n     * \\brief Common server error. Error number: 1417, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_failed_routine_break_binlog\">ER_FAILED_ROUTINE_BREAK_BINLOG</a>.\n     */\n    er_failed_routine_break_binlog = 1417,\n\n    /**\n     * \\brief Common server error. Error number: 1418, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_routine\">ER_BINLOG_UNSAFE_ROUTINE</a>.\n     */\n    er_binlog_unsafe_routine = 1418,\n\n    /**\n     * \\brief Common server error. Error number: 1419, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_create_routine_need_super\">ER_BINLOG_CREATE_ROUTINE_NEED_SUPER</a>.\n     */\n    er_binlog_create_routine_need_super = 1419,\n\n    /**\n     * \\brief Common server error. Error number: 1420, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_exec_stmt_with_open_cursor\">ER_EXEC_STMT_WITH_OPEN_CURSOR</a>.\n     */\n    er_exec_stmt_with_open_cursor = 1420,\n\n    /**\n     * \\brief Common server error. Error number: 1421, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stmt_has_no_open_cursor\">ER_STMT_HAS_NO_OPEN_CURSOR</a>.\n     */\n    er_stmt_has_no_open_cursor = 1421,\n\n    /**\n     * \\brief Common server error. Error number: 1422, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_commit_not_allowed_in_sf_or_trg\">ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG</a>.\n     */\n    er_commit_not_allowed_in_sf_or_trg = 1422,\n\n    /**\n     * \\brief Common server error. Error number: 1423, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_default_for_view_field\">ER_NO_DEFAULT_FOR_VIEW_FIELD</a>.\n     */\n    er_no_default_for_view_field = 1423,\n\n    /**\n     * \\brief Common server error. Error number: 1424, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_no_recursion\">ER_SP_NO_RECURSION</a>.\n     */\n    er_sp_no_recursion = 1424,\n\n    /**\n     * \\brief Common server error. Error number: 1425, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_scale\">ER_TOO_BIG_SCALE</a>.\n     */\n    er_too_big_scale = 1425,\n\n    /**\n     * \\brief Common server error. Error number: 1426, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_precision\">ER_TOO_BIG_PRECISION</a>.\n     */\n    er_too_big_precision = 1426,\n\n    /**\n     * \\brief Common server error. Error number: 1427, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_m_bigger_than_d\">ER_M_BIGGER_THAN_D</a>.\n     */\n    er_m_bigger_than_d = 1427,\n\n    /**\n     * \\brief Common server error. Error number: 1428, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_lock_of_system_table\">ER_WRONG_LOCK_OF_SYSTEM_TABLE</a>.\n     */\n    er_wrong_lock_of_system_table = 1428,\n\n    /**\n     * \\brief Common server error. Error number: 1429, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_connect_to_foreign_data_source\">ER_CONNECT_TO_FOREIGN_DATA_SOURCE</a>.\n     */\n    er_connect_to_foreign_data_source = 1429,\n\n    /**\n     * \\brief Common server error. Error number: 1430, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_query_on_foreign_data_source\">ER_QUERY_ON_FOREIGN_DATA_SOURCE</a>.\n     */\n    er_query_on_foreign_data_source = 1430,\n\n    /**\n     * \\brief Common server error. Error number: 1431, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_data_source_doesnt_exist\">ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST</a>.\n     */\n    er_foreign_data_source_doesnt_exist = 1431,\n\n    /**\n     * \\brief Common server error. Error number: 1432, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_data_string_invalid_cant_create\">ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE</a>.\n     */\n    er_foreign_data_string_invalid_cant_create = 1432,\n\n    /**\n     * \\brief Common server error. Error number: 1433, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_data_string_invalid\">ER_FOREIGN_DATA_STRING_INVALID</a>.\n     */\n    er_foreign_data_string_invalid = 1433,\n\n    /**\n     * \\brief Common server error. Error number: 1434, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_federated_table\">ER_CANT_CREATE_FEDERATED_TABLE</a>.\n     */\n    er_cant_create_federated_table = 1434,\n\n    /**\n     * \\brief Common server error. Error number: 1435, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_in_wrong_schema\">ER_TRG_IN_WRONG_SCHEMA</a>.\n     */\n    er_trg_in_wrong_schema = 1435,\n\n    /**\n     * \\brief Common server error. Error number: 1436, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stack_overrun_need_more\">ER_STACK_OVERRUN_NEED_MORE</a>.\n     */\n    er_stack_overrun_need_more = 1436,\n\n    /**\n     * \\brief Common server error. Error number: 1437, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_body\">ER_TOO_LONG_BODY</a>.\n     */\n    er_too_long_body = 1437,\n\n    /**\n     * \\brief Common server error. Error number: 1438, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_cant_drop_default_keycache\">ER_WARN_CANT_DROP_DEFAULT_KEYCACHE</a>.\n     */\n    er_warn_cant_drop_default_keycache = 1438,\n\n    /**\n     * \\brief Common server error. Error number: 1439, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_big_displaywidth\">ER_TOO_BIG_DISPLAYWIDTH</a>.\n     */\n    er_too_big_displaywidth = 1439,\n\n    /**\n     * \\brief Common server error. Error number: 1440, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xaer_dupid\">ER_XAER_DUPID</a>.\n     */\n    er_xaer_dupid = 1440,\n\n    /**\n     * \\brief Common server error. Error number: 1441, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_datetime_function_overflow\">ER_DATETIME_FUNCTION_OVERFLOW</a>.\n     */\n    er_datetime_function_overflow = 1441,\n\n    /**\n     * \\brief Common server error. Error number: 1442, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_update_used_table_in_sf_or_trg\">ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG</a>.\n     */\n    er_cant_update_used_table_in_sf_or_trg = 1442,\n\n    /**\n     * \\brief Common server error. Error number: 1443, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_prevent_update\">ER_VIEW_PREVENT_UPDATE</a>.\n     */\n    er_view_prevent_update = 1443,\n\n    /**\n     * \\brief Common server error. Error number: 1444, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ps_no_recursion\">ER_PS_NO_RECURSION</a>.\n     */\n    er_ps_no_recursion = 1444,\n\n    /**\n     * \\brief Common server error. Error number: 1445, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_cant_set_autocommit\">ER_SP_CANT_SET_AUTOCOMMIT</a>.\n     */\n    er_sp_cant_set_autocommit = 1445,\n\n    /**\n     * \\brief Common server error. Error number: 1446, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_malformed_definer\">ER_MALFORMED_DEFINER</a>.\n     */\n    er_malformed_definer = 1446,\n\n    /**\n     * \\brief Common server error. Error number: 1447, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_frm_no_user\">ER_VIEW_FRM_NO_USER</a>.\n     */\n    er_view_frm_no_user = 1447,\n\n    /**\n     * \\brief Common server error. Error number: 1448, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_other_user\">ER_VIEW_OTHER_USER</a>.\n     */\n    er_view_other_user = 1448,\n\n    /**\n     * \\brief Common server error. Error number: 1449, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_such_user\">ER_NO_SUCH_USER</a>.\n     */\n    er_no_such_user = 1449,\n\n    /**\n     * \\brief Common server error. Error number: 1450, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_forbid_schema_change\">ER_FORBID_SCHEMA_CHANGE</a>.\n     */\n    er_forbid_schema_change = 1450,\n\n    /**\n     * \\brief Common server error. Error number: 1451, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_row_is_referenced_2\">ER_ROW_IS_REFERENCED_2</a>.\n     */\n    er_row_is_referenced_2 = 1451,\n\n    /**\n     * \\brief Common server error. Error number: 1452, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_referenced_row_2\">ER_NO_REFERENCED_ROW_2</a>.\n     */\n    er_no_referenced_row_2 = 1452,\n\n    /**\n     * \\brief Common server error. Error number: 1453, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_bad_var_shadow\">ER_SP_BAD_VAR_SHADOW</a>.\n     */\n    er_sp_bad_var_shadow = 1453,\n\n    /**\n     * \\brief Common server error. Error number: 1454, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_no_definer\">ER_TRG_NO_DEFINER</a>.\n     */\n    er_trg_no_definer = 1454,\n\n    /**\n     * \\brief Common server error. Error number: 1455, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_old_file_format\">ER_OLD_FILE_FORMAT</a>.\n     */\n    er_old_file_format = 1455,\n\n    /**\n     * \\brief Common server error. Error number: 1456, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_recursion_limit\">ER_SP_RECURSION_LIMIT</a>.\n     */\n    er_sp_recursion_limit = 1456,\n\n    /**\n     * \\brief Common server error. Error number: 1457, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_proc_table_corrupt\">ER_SP_PROC_TABLE_CORRUPT</a>.\n     */\n    er_sp_proc_table_corrupt = 1457,\n\n    /**\n     * \\brief Common server error. Error number: 1458, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_wrong_name\">ER_SP_WRONG_NAME</a>.\n     */\n    er_sp_wrong_name = 1458,\n\n    /**\n     * \\brief Common server error. Error number: 1459, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_needs_upgrade\">ER_TABLE_NEEDS_UPGRADE</a>.\n     */\n    er_table_needs_upgrade = 1459,\n\n    /**\n     * \\brief Common server error. Error number: 1460, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sp_no_aggregate\">ER_SP_NO_AGGREGATE</a>.\n     */\n    er_sp_no_aggregate = 1460,\n\n    /**\n     * \\brief Common server error. Error number: 1461, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_max_prepared_stmt_count_reached\">ER_MAX_PREPARED_STMT_COUNT_REACHED</a>.\n     */\n    er_max_prepared_stmt_count_reached = 1461,\n\n    /**\n     * \\brief Common server error. Error number: 1462, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_recursive\">ER_VIEW_RECURSIVE</a>.\n     */\n    er_view_recursive = 1462,\n\n    /**\n     * \\brief Common server error. Error number: 1463, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_non_grouping_field_used\">ER_NON_GROUPING_FIELD_USED</a>.\n     */\n    er_non_grouping_field_used = 1463,\n\n    /**\n     * \\brief Common server error. Error number: 1464, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_cant_handle_spkeys\">ER_TABLE_CANT_HANDLE_SPKEYS</a>.\n     */\n    er_table_cant_handle_spkeys = 1464,\n\n    /**\n     * \\brief Common server error. Error number: 1465, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_triggers_on_system_schema\">ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA</a>.\n     */\n    er_no_triggers_on_system_schema = 1465,\n\n    /**\n     * \\brief Common server error. Error number: 1466, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_removed_spaces\">ER_REMOVED_SPACES</a>.\n     */\n    er_removed_spaces = 1466,\n\n    /**\n     * \\brief Common server error. Error number: 1467, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_autoinc_read_failed\">ER_AUTOINC_READ_FAILED</a>.\n     */\n    er_autoinc_read_failed = 1467,\n\n    /**\n     * \\brief Common server error. Error number: 1468, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_username\">ER_USERNAME</a>.\n     */\n    er_username = 1468,\n\n    /**\n     * \\brief Common server error. Error number: 1469, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_hostname\">ER_HOSTNAME</a>.\n     */\n    er_hostname = 1469,\n\n    /**\n     * \\brief Common server error. Error number: 1470, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_string_length\">ER_WRONG_STRING_LENGTH</a>.\n     */\n    er_wrong_string_length = 1470,\n\n    /**\n     * \\brief Common server error. Error number: 1471, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_non_insertable_table\">ER_NON_INSERTABLE_TABLE</a>.\n     */\n    er_non_insertable_table = 1471,\n\n    /**\n     * \\brief Common server error. Error number: 1472, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_admin_wrong_mrg_table\">ER_ADMIN_WRONG_MRG_TABLE</a>.\n     */\n    er_admin_wrong_mrg_table = 1472,\n\n    /**\n     * \\brief Common server error. Error number: 1473, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_high_level_of_nesting_for_select\">ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT</a>.\n     */\n    er_too_high_level_of_nesting_for_select = 1473,\n\n    /**\n     * \\brief Common server error. Error number: 1474, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_name_becomes_empty\">ER_NAME_BECOMES_EMPTY</a>.\n     */\n    er_name_becomes_empty = 1474,\n\n    /**\n     * \\brief Common server error. Error number: 1475, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ambiguous_field_term\">ER_AMBIGUOUS_FIELD_TERM</a>.\n     */\n    er_ambiguous_field_term = 1475,\n\n    /**\n     * \\brief Common server error. Error number: 1476, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_server_exists\">ER_FOREIGN_SERVER_EXISTS</a>.\n     */\n    er_foreign_server_exists = 1476,\n\n    /**\n     * \\brief Common server error. Error number: 1477, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_server_doesnt_exist\">ER_FOREIGN_SERVER_DOESNT_EXIST</a>.\n     */\n    er_foreign_server_doesnt_exist = 1477,\n\n    /**\n     * \\brief Common server error. Error number: 1478, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_illegal_ha_create_option\">ER_ILLEGAL_HA_CREATE_OPTION</a>.\n     */\n    er_illegal_ha_create_option = 1478,\n\n    /**\n     * \\brief Common server error. Error number: 1479, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_requires_values_error\">ER_PARTITION_REQUIRES_VALUES_ERROR</a>.\n     */\n    er_partition_requires_values_error = 1479,\n\n    /**\n     * \\brief Common server error. Error number: 1480, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_wrong_values_error\">ER_PARTITION_WRONG_VALUES_ERROR</a>.\n     */\n    er_partition_wrong_values_error = 1480,\n\n    /**\n     * \\brief Common server error. Error number: 1481, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_maxvalue_error\">ER_PARTITION_MAXVALUE_ERROR</a>.\n     */\n    er_partition_maxvalue_error = 1481,\n\n    /**\n     * \\brief Common server error. Error number: 1482, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_subpartition_error\">ER_PARTITION_SUBPARTITION_ERROR</a>.\n     */\n    er_partition_subpartition_error = 1482,\n\n    /**\n     * \\brief Common server error. Error number: 1483, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_subpart_mix_error\">ER_PARTITION_SUBPART_MIX_ERROR</a>.\n     */\n    er_partition_subpart_mix_error = 1483,\n\n    /**\n     * \\brief Common server error. Error number: 1484, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_wrong_no_part_error\">ER_PARTITION_WRONG_NO_PART_ERROR</a>.\n     */\n    er_partition_wrong_no_part_error = 1484,\n\n    /**\n     * \\brief Common server error. Error number: 1485, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_wrong_no_subpart_error\">ER_PARTITION_WRONG_NO_SUBPART_ERROR</a>.\n     */\n    er_partition_wrong_no_subpart_error = 1485,\n\n    /**\n     * \\brief Common server error. Error number: 1486, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_expr_in_partition_func_error\">ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR</a>.\n     */\n    er_wrong_expr_in_partition_func_error = 1486,\n\n    /**\n     * \\brief Common server error. Error number: 1488, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_field_not_found_part_error\">ER_FIELD_NOT_FOUND_PART_ERROR</a>.\n     */\n    er_field_not_found_part_error = 1488,\n\n    /**\n     * \\brief Common server error. Error number: 1489, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_list_of_fields_only_in_hash_error\">ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR</a>.\n     */\n    er_list_of_fields_only_in_hash_error = 1489,\n\n    /**\n     * \\brief Common server error. Error number: 1490, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_inconsistent_partition_info_error\">ER_INCONSISTENT_PARTITION_INFO_ERROR</a>.\n     */\n    er_inconsistent_partition_info_error = 1490,\n\n    /**\n     * \\brief Common server error. Error number: 1491, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_func_not_allowed_error\">ER_PARTITION_FUNC_NOT_ALLOWED_ERROR</a>.\n     */\n    er_partition_func_not_allowed_error = 1491,\n\n    /**\n     * \\brief Common server error. Error number: 1492, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partitions_must_be_defined_error\">ER_PARTITIONS_MUST_BE_DEFINED_ERROR</a>.\n     */\n    er_partitions_must_be_defined_error = 1492,\n\n    /**\n     * \\brief Common server error. Error number: 1493, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_range_not_increasing_error\">ER_RANGE_NOT_INCREASING_ERROR</a>.\n     */\n    er_range_not_increasing_error = 1493,\n\n    /**\n     * \\brief Common server error. Error number: 1494, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_inconsistent_type_of_functions_error\">ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR</a>.\n     */\n    er_inconsistent_type_of_functions_error = 1494,\n\n    /**\n     * \\brief Common server error. Error number: 1495, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_multiple_def_const_in_list_part_error\">ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR</a>.\n     */\n    er_multiple_def_const_in_list_part_error = 1495,\n\n    /**\n     * \\brief Common server error. Error number: 1496, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_entry_error\">ER_PARTITION_ENTRY_ERROR</a>.\n     */\n    er_partition_entry_error = 1496,\n\n    /**\n     * \\brief Common server error. Error number: 1497, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mix_handler_error\">ER_MIX_HANDLER_ERROR</a>.\n     */\n    er_mix_handler_error = 1497,\n\n    /**\n     * \\brief Common server error. Error number: 1498, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_not_defined_error\">ER_PARTITION_NOT_DEFINED_ERROR</a>.\n     */\n    er_partition_not_defined_error = 1498,\n\n    /**\n     * \\brief Common server error. Error number: 1499, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_partitions_error\">ER_TOO_MANY_PARTITIONS_ERROR</a>.\n     */\n    er_too_many_partitions_error = 1499,\n\n    /**\n     * \\brief Common server error. Error number: 1500, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_subpartition_error\">ER_SUBPARTITION_ERROR</a>.\n     */\n    er_subpartition_error = 1500,\n\n    /**\n     * \\brief Common server error. Error number: 1501, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_handler_file\">ER_CANT_CREATE_HANDLER_FILE</a>.\n     */\n    er_cant_create_handler_file = 1501,\n\n    /**\n     * \\brief Common server error. Error number: 1502, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_blob_field_in_part_func_error\">ER_BLOB_FIELD_IN_PART_FUNC_ERROR</a>.\n     */\n    er_blob_field_in_part_func_error = 1502,\n\n    /**\n     * \\brief Common server error. Error number: 1503, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unique_key_need_all_fields_in_pf\">ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF</a>.\n     */\n    er_unique_key_need_all_fields_in_pf = 1503,\n\n    /**\n     * \\brief Common server error. Error number: 1504, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_parts_error\">ER_NO_PARTS_ERROR</a>.\n     */\n    er_no_parts_error = 1504,\n\n    /**\n     * \\brief Common server error. Error number: 1505, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_mgmt_on_nonpartitioned\">ER_PARTITION_MGMT_ON_NONPARTITIONED</a>.\n     */\n    er_partition_mgmt_on_nonpartitioned = 1505,\n\n    /**\n     * \\brief Common server error. Error number: 1507, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_drop_partition_non_existent\">ER_DROP_PARTITION_NON_EXISTENT</a>.\n     */\n    er_drop_partition_non_existent = 1507,\n\n    /**\n     * \\brief Common server error. Error number: 1508, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_drop_last_partition\">ER_DROP_LAST_PARTITION</a>.\n     */\n    er_drop_last_partition = 1508,\n\n    /**\n     * \\brief Common server error. Error number: 1509, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_coalesce_only_on_hash_partition\">ER_COALESCE_ONLY_ON_HASH_PARTITION</a>.\n     */\n    er_coalesce_only_on_hash_partition = 1509,\n\n    /**\n     * \\brief Common server error. Error number: 1510, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_reorg_hash_only_on_same_no\">ER_REORG_HASH_ONLY_ON_SAME_NO</a>.\n     */\n    er_reorg_hash_only_on_same_no = 1510,\n\n    /**\n     * \\brief Common server error. Error number: 1511, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_reorg_no_param_error\">ER_REORG_NO_PARAM_ERROR</a>.\n     */\n    er_reorg_no_param_error = 1511,\n\n    /**\n     * \\brief Common server error. Error number: 1512, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_only_on_range_list_partition\">ER_ONLY_ON_RANGE_LIST_PARTITION</a>.\n     */\n    er_only_on_range_list_partition = 1512,\n\n    /**\n     * \\brief Common server error. Error number: 1513, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_add_partition_subpart_error\">ER_ADD_PARTITION_SUBPART_ERROR</a>.\n     */\n    er_add_partition_subpart_error = 1513,\n\n    /**\n     * \\brief Common server error. Error number: 1514, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_add_partition_no_new_partition\">ER_ADD_PARTITION_NO_NEW_PARTITION</a>.\n     */\n    er_add_partition_no_new_partition = 1514,\n\n    /**\n     * \\brief Common server error. Error number: 1515, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_coalesce_partition_no_partition\">ER_COALESCE_PARTITION_NO_PARTITION</a>.\n     */\n    er_coalesce_partition_no_partition = 1515,\n\n    /**\n     * \\brief Common server error. Error number: 1516, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_reorg_partition_not_exist\">ER_REORG_PARTITION_NOT_EXIST</a>.\n     */\n    er_reorg_partition_not_exist = 1516,\n\n    /**\n     * \\brief Common server error. Error number: 1517, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_same_name_partition\">ER_SAME_NAME_PARTITION</a>.\n     */\n    er_same_name_partition = 1517,\n\n    /**\n     * \\brief Common server error. Error number: 1518, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_binlog_error\">ER_NO_BINLOG_ERROR</a>.\n     */\n    er_no_binlog_error = 1518,\n\n    /**\n     * \\brief Common server error. Error number: 1519, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_consecutive_reorg_partitions\">ER_CONSECUTIVE_REORG_PARTITIONS</a>.\n     */\n    er_consecutive_reorg_partitions = 1519,\n\n    /**\n     * \\brief Common server error. Error number: 1520, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_reorg_outside_range\">ER_REORG_OUTSIDE_RANGE</a>.\n     */\n    er_reorg_outside_range = 1520,\n\n    /**\n     * \\brief Common server error. Error number: 1521, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_function_failure\">ER_PARTITION_FUNCTION_FAILURE</a>.\n     */\n    er_partition_function_failure = 1521,\n\n    /**\n     * \\brief Common server error. Error number: 1522, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_part_state_error\">ER_PART_STATE_ERROR</a>.\n     */\n    er_part_state_error = 1522,\n\n    /**\n     * \\brief Common server error. Error number: 1523, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_limited_part_range\">ER_LIMITED_PART_RANGE</a>.\n     */\n    er_limited_part_range = 1523,\n\n    /**\n     * \\brief Common server error. Error number: 1524, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_plugin_is_not_loaded\">ER_PLUGIN_IS_NOT_LOADED</a>.\n     */\n    er_plugin_is_not_loaded = 1524,\n\n    /**\n     * \\brief Common server error. Error number: 1525, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_value\">ER_WRONG_VALUE</a>.\n     */\n    er_wrong_value = 1525,\n\n    /**\n     * \\brief Common server error. Error number: 1526, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_partition_for_given_value\">ER_NO_PARTITION_FOR_GIVEN_VALUE</a>.\n     */\n    er_no_partition_for_given_value = 1526,\n\n    /**\n     * \\brief Common server error. Error number: 1527, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_filegroup_option_only_once\">ER_FILEGROUP_OPTION_ONLY_ONCE</a>.\n     */\n    er_filegroup_option_only_once = 1527,\n\n    /**\n     * \\brief Common server error. Error number: 1528, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_create_filegroup_failed\">ER_CREATE_FILEGROUP_FAILED</a>.\n     */\n    er_create_filegroup_failed = 1528,\n\n    /**\n     * \\brief Common server error. Error number: 1529, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_drop_filegroup_failed\">ER_DROP_FILEGROUP_FAILED</a>.\n     */\n    er_drop_filegroup_failed = 1529,\n\n    /**\n     * \\brief Common server error. Error number: 1530, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tablespace_auto_extend_error\">ER_TABLESPACE_AUTO_EXTEND_ERROR</a>.\n     */\n    er_tablespace_auto_extend_error = 1530,\n\n    /**\n     * \\brief Common server error. Error number: 1531, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_size_number\">ER_WRONG_SIZE_NUMBER</a>.\n     */\n    er_wrong_size_number = 1531,\n\n    /**\n     * \\brief Common server error. Error number: 1532, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_size_overflow_error\">ER_SIZE_OVERFLOW_ERROR</a>.\n     */\n    er_size_overflow_error = 1532,\n\n    /**\n     * \\brief Common server error. Error number: 1533, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_filegroup_failed\">ER_ALTER_FILEGROUP_FAILED</a>.\n     */\n    er_alter_filegroup_failed = 1533,\n\n    /**\n     * \\brief Common server error. Error number: 1534, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_logging_failed\">ER_BINLOG_ROW_LOGGING_FAILED</a>.\n     */\n    er_binlog_row_logging_failed = 1534,\n\n    /**\n     * \\brief Common server error. Error number: 1535, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_wrong_table_def\">ER_BINLOG_ROW_WRONG_TABLE_DEF</a>.\n     */\n    er_binlog_row_wrong_table_def = 1535,\n\n    /**\n     * \\brief Common server error. Error number: 1536, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_rbr_to_sbr\">ER_BINLOG_ROW_RBR_TO_SBR</a>.\n     */\n    er_binlog_row_rbr_to_sbr = 1536,\n\n    /**\n     * \\brief Common server error. Error number: 1537, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_already_exists\">ER_EVENT_ALREADY_EXISTS</a>.\n     */\n    er_event_already_exists = 1537,\n\n    /**\n     * \\brief Common server error. Error number: 1538, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_store_failed\">ER_EVENT_STORE_FAILED</a>.\n     */\n    er_event_store_failed = 1538,\n\n    /**\n     * \\brief Common server error. Error number: 1539, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_does_not_exist\">ER_EVENT_DOES_NOT_EXIST</a>.\n     */\n    er_event_does_not_exist = 1539,\n\n    /**\n     * \\brief Common server error. Error number: 1540, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_cant_alter\">ER_EVENT_CANT_ALTER</a>.\n     */\n    er_event_cant_alter = 1540,\n\n    /**\n     * \\brief Common server error. Error number: 1541, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_drop_failed\">ER_EVENT_DROP_FAILED</a>.\n     */\n    er_event_drop_failed = 1541,\n\n    /**\n     * \\brief Common server error. Error number: 1542, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_interval_not_positive_or_too_big\">ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG</a>.\n     */\n    er_event_interval_not_positive_or_too_big = 1542,\n\n    /**\n     * \\brief Common server error. Error number: 1543, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_ends_before_starts\">ER_EVENT_ENDS_BEFORE_STARTS</a>.\n     */\n    er_event_ends_before_starts = 1543,\n\n    /**\n     * \\brief Common server error. Error number: 1544, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_exec_time_in_the_past\">ER_EVENT_EXEC_TIME_IN_THE_PAST</a>.\n     */\n    er_event_exec_time_in_the_past = 1544,\n\n    /**\n     * \\brief Common server error. Error number: 1545, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_open_table_failed\">ER_EVENT_OPEN_TABLE_FAILED</a>.\n     */\n    er_event_open_table_failed = 1545,\n\n    /**\n     * \\brief Common server error. Error number: 1546, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_neither_m_expr_nor_m_at\">ER_EVENT_NEITHER_M_EXPR_NOR_M_AT</a>.\n     */\n    er_event_neither_m_expr_nor_m_at = 1546,\n\n    /**\n     * \\brief Common server error. Error number: 1549, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_cannot_delete\">ER_EVENT_CANNOT_DELETE</a>.\n     */\n    er_event_cannot_delete = 1549,\n\n    /**\n     * \\brief Common server error. Error number: 1550, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_compile_error\">ER_EVENT_COMPILE_ERROR</a>.\n     */\n    er_event_compile_error = 1550,\n\n    /**\n     * \\brief Common server error. Error number: 1551, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_same_name\">ER_EVENT_SAME_NAME</a>.\n     */\n    er_event_same_name = 1551,\n\n    /**\n     * \\brief Common server error. Error number: 1552, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_data_too_long\">ER_EVENT_DATA_TOO_LONG</a>.\n     */\n    er_event_data_too_long = 1552,\n\n    /**\n     * \\brief Common server error. Error number: 1553, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_drop_index_fk\">ER_DROP_INDEX_FK</a>.\n     */\n    er_drop_index_fk = 1553,\n\n    /**\n     * \\brief Common server error. Error number: 1554, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_deprecated_syntax_with_ver\">ER_WARN_DEPRECATED_SYNTAX_WITH_VER</a>.\n     */\n    er_warn_deprecated_syntax_with_ver = 1554,\n\n    /**\n     * \\brief Common server error. Error number: 1555, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_write_lock_log_table\">ER_CANT_WRITE_LOCK_LOG_TABLE</a>.\n     */\n    er_cant_write_lock_log_table = 1555,\n\n    /**\n     * \\brief Common server error. Error number: 1556, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_lock_log_table\">ER_CANT_LOCK_LOG_TABLE</a>.\n     */\n    er_cant_lock_log_table = 1556,\n\n    /**\n     * \\brief Common server error. Error number: 1558, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_col_count_doesnt_match_please_update\">ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE</a>.\n     */\n    er_col_count_doesnt_match_please_update = 1558,\n\n    /**\n     * \\brief Common server error. Error number: 1559, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_temp_table_prevents_switch_out_of_rbr\">ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR</a>.\n     */\n    er_temp_table_prevents_switch_out_of_rbr = 1559,\n\n    /**\n     * \\brief Common server error. Error number: 1560, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stored_function_prevents_switch_binlog_format\">ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT</a>.\n     */\n    er_stored_function_prevents_switch_binlog_format = 1560,\n\n    /**\n     * \\brief Common server error. Error number: 1562, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_no_temporary\">ER_PARTITION_NO_TEMPORARY</a>.\n     */\n    er_partition_no_temporary = 1562,\n\n    /**\n     * \\brief Common server error. Error number: 1563, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_const_domain_error\">ER_PARTITION_CONST_DOMAIN_ERROR</a>.\n     */\n    er_partition_const_domain_error = 1563,\n\n    /**\n     * \\brief Common server error. Error number: 1564, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_function_is_not_allowed\">ER_PARTITION_FUNCTION_IS_NOT_ALLOWED</a>.\n     */\n    er_partition_function_is_not_allowed = 1564,\n\n    /**\n     * \\brief Common server error. Error number: 1565, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ddl_log_error\">ER_DDL_LOG_ERROR</a>.\n     */\n    er_ddl_log_error = 1565,\n\n    /**\n     * \\brief Common server error. Error number: 1566, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_null_in_values_less_than\">ER_NULL_IN_VALUES_LESS_THAN</a>.\n     */\n    er_null_in_values_less_than = 1566,\n\n    /**\n     * \\brief Common server error. Error number: 1567, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_partition_name\">ER_WRONG_PARTITION_NAME</a>.\n     */\n    er_wrong_partition_name = 1567,\n\n    /**\n     * \\brief Common server error. Error number: 1568, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_change_tx_characteristics\">ER_CANT_CHANGE_TX_CHARACTERISTICS</a>.\n     */\n    er_cant_change_tx_characteristics = 1568,\n\n    /**\n     * \\brief Common server error. Error number: 1569, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_entry_autoincrement_case\">ER_DUP_ENTRY_AUTOINCREMENT_CASE</a>.\n     */\n    er_dup_entry_autoincrement_case = 1569,\n\n    /**\n     * \\brief Common server error. Error number: 1570, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_modify_queue_error\">ER_EVENT_MODIFY_QUEUE_ERROR</a>.\n     */\n    er_event_modify_queue_error = 1570,\n\n    /**\n     * \\brief Common server error. Error number: 1571, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_set_var_error\">ER_EVENT_SET_VAR_ERROR</a>.\n     */\n    er_event_set_var_error = 1571,\n\n    /**\n     * \\brief Common server error. Error number: 1572, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_merge_error\">ER_PARTITION_MERGE_ERROR</a>.\n     */\n    er_partition_merge_error = 1572,\n\n    /**\n     * \\brief Common server error. Error number: 1573, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_activate_log\">ER_CANT_ACTIVATE_LOG</a>.\n     */\n    er_cant_activate_log = 1573,\n\n    /**\n     * \\brief Common server error. Error number: 1574, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_rbr_not_available\">ER_RBR_NOT_AVAILABLE</a>.\n     */\n    er_rbr_not_available = 1574,\n\n    /**\n     * \\brief Common server error. Error number: 1575, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_base64_decode_error\">ER_BASE64_DECODE_ERROR</a>.\n     */\n    er_base64_decode_error = 1575,\n\n    /**\n     * \\brief Common server error. Error number: 1576, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_recursion_forbidden\">ER_EVENT_RECURSION_FORBIDDEN</a>.\n     */\n    er_event_recursion_forbidden = 1576,\n\n    /**\n     * \\brief Common server error. Error number: 1577, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_events_db_error\">ER_EVENTS_DB_ERROR</a>.\n     */\n    er_events_db_error = 1577,\n\n    /**\n     * \\brief Common server error. Error number: 1578, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_only_integers_allowed\">ER_ONLY_INTEGERS_ALLOWED</a>.\n     */\n    er_only_integers_allowed = 1578,\n\n    /**\n     * \\brief Common server error. Error number: 1579, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unsuported_log_engine\">ER_UNSUPORTED_LOG_ENGINE</a>.\n     */\n    er_unsuported_log_engine = 1579,\n\n    /**\n     * \\brief Common server error. Error number: 1580, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_log_statement\">ER_BAD_LOG_STATEMENT</a>.\n     */\n    er_bad_log_statement = 1580,\n\n    /**\n     * \\brief Common server error. Error number: 1581, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_rename_log_table\">ER_CANT_RENAME_LOG_TABLE</a>.\n     */\n    er_cant_rename_log_table = 1581,\n\n    /**\n     * \\brief Common server error. Error number: 1582, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_paramcount_to_native_fct\">ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT</a>.\n     */\n    er_wrong_paramcount_to_native_fct = 1582,\n\n    /**\n     * \\brief Common server error. Error number: 1583, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_parameters_to_native_fct\">ER_WRONG_PARAMETERS_TO_NATIVE_FCT</a>.\n     */\n    er_wrong_parameters_to_native_fct = 1583,\n\n    /**\n     * \\brief Common server error. Error number: 1584, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_parameters_to_stored_fct\">ER_WRONG_PARAMETERS_TO_STORED_FCT</a>.\n     */\n    er_wrong_parameters_to_stored_fct = 1584,\n\n    /**\n     * \\brief Common server error. Error number: 1585, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_native_fct_name_collision\">ER_NATIVE_FCT_NAME_COLLISION</a>.\n     */\n    er_native_fct_name_collision = 1585,\n\n    /**\n     * \\brief Common server error. Error number: 1586, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_entry_with_key_name\">ER_DUP_ENTRY_WITH_KEY_NAME</a>.\n     */\n    er_dup_entry_with_key_name = 1586,\n\n    /**\n     * \\brief Common server error. Error number: 1587, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_purge_emfile\">ER_BINLOG_PURGE_EMFILE</a>.\n     */\n    er_binlog_purge_emfile = 1587,\n\n    /**\n     * \\brief Common server error. Error number: 1588, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_cannot_create_in_the_past\">ER_EVENT_CANNOT_CREATE_IN_THE_PAST</a>.\n     */\n    er_event_cannot_create_in_the_past = 1588,\n\n    /**\n     * \\brief Common server error. Error number: 1589, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_cannot_alter_in_the_past\">ER_EVENT_CANNOT_ALTER_IN_THE_PAST</a>.\n     */\n    er_event_cannot_alter_in_the_past = 1589,\n\n    /**\n     * \\brief Common server error. Error number: 1590, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_incident\">ER_SLAVE_INCIDENT</a>.\n     */\n    er_slave_incident = 1590,\n\n    /**\n     * \\brief Common server error. Error number: 1591, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_partition_for_given_value_silent\">ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT</a>.\n     */\n    er_no_partition_for_given_value_silent = 1591,\n\n    /**\n     * \\brief Common server error. Error number: 1592, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_statement\">ER_BINLOG_UNSAFE_STATEMENT</a>.\n     */\n    er_binlog_unsafe_statement = 1592,\n\n    /**\n     * \\brief Common server error. Error number: 1594, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_relay_log_read_failure\">ER_SLAVE_RELAY_LOG_READ_FAILURE</a>.\n     */\n    er_slave_relay_log_read_failure = 1594,\n\n    /**\n     * \\brief Common server error. Error number: 1595, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_relay_log_write_failure\">ER_SLAVE_RELAY_LOG_WRITE_FAILURE</a>.\n     */\n    er_slave_relay_log_write_failure = 1595,\n\n    /**\n     * \\brief Common server error. Error number: 1596, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_create_event_failure\">ER_SLAVE_CREATE_EVENT_FAILURE</a>.\n     */\n    er_slave_create_event_failure = 1596,\n\n    /**\n     * \\brief Common server error. Error number: 1597, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_master_com_failure\">ER_SLAVE_MASTER_COM_FAILURE</a>.\n     */\n    er_slave_master_com_failure = 1597,\n\n    /**\n     * \\brief Common server error. Error number: 1598, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_logging_impossible\">ER_BINLOG_LOGGING_IMPOSSIBLE</a>.\n     */\n    er_binlog_logging_impossible = 1598,\n\n    /**\n     * \\brief Common server error. Error number: 1599, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_no_creation_ctx\">ER_VIEW_NO_CREATION_CTX</a>.\n     */\n    er_view_no_creation_ctx = 1599,\n\n    /**\n     * \\brief Common server error. Error number: 1600, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_view_invalid_creation_ctx\">ER_VIEW_INVALID_CREATION_CTX</a>.\n     */\n    er_view_invalid_creation_ctx = 1600,\n\n    /**\n     * \\brief Common server error. Error number: 1601, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sr_invalid_creation_ctx\">ER_SR_INVALID_CREATION_CTX</a>.\n     */\n    er_sr_invalid_creation_ctx = 1601,\n\n    /**\n     * \\brief Common server error. Error number: 1602, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_corrupted_file\">ER_TRG_CORRUPTED_FILE</a>.\n     */\n    er_trg_corrupted_file = 1602,\n\n    /**\n     * \\brief Common server error. Error number: 1603, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_no_creation_ctx\">ER_TRG_NO_CREATION_CTX</a>.\n     */\n    er_trg_no_creation_ctx = 1603,\n\n    /**\n     * \\brief Common server error. Error number: 1604, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_invalid_creation_ctx\">ER_TRG_INVALID_CREATION_CTX</a>.\n     */\n    er_trg_invalid_creation_ctx = 1604,\n\n    /**\n     * \\brief Common server error. Error number: 1605, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_event_invalid_creation_ctx\">ER_EVENT_INVALID_CREATION_CTX</a>.\n     */\n    er_event_invalid_creation_ctx = 1605,\n\n    /**\n     * \\brief Common server error. Error number: 1606, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_trg_cant_open_table\">ER_TRG_CANT_OPEN_TABLE</a>.\n     */\n    er_trg_cant_open_table = 1606,\n\n    /**\n     * \\brief Common server error. Error number: 1607, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_create_sroutine\">ER_CANT_CREATE_SROUTINE</a>.\n     */\n    er_cant_create_sroutine = 1607,\n\n    /**\n     * \\brief Common server error. Error number: 1609, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_format_description_event_before_binlog_statement\">ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT</a>.\n     */\n    er_no_format_description_event_before_binlog_statement = 1609,\n\n    /**\n     * \\brief Common server error. Error number: 1610, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_corrupt_event\">ER_SLAVE_CORRUPT_EVENT</a>.\n     */\n    er_slave_corrupt_event = 1610,\n\n    /**\n     * \\brief Common server error. Error number: 1612, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_log_purge_no_file\">ER_LOG_PURGE_NO_FILE</a>.\n     */\n    er_log_purge_no_file = 1612,\n\n    /**\n     * \\brief Common server error. Error number: 1613, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xa_rbtimeout\">ER_XA_RBTIMEOUT</a>.\n     */\n    er_xa_rbtimeout = 1613,\n\n    /**\n     * \\brief Common server error. Error number: 1614, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_xa_rbdeadlock\">ER_XA_RBDEADLOCK</a>.\n     */\n    er_xa_rbdeadlock = 1614,\n\n    /**\n     * \\brief Common server error. Error number: 1615, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_need_reprepare\">ER_NEED_REPREPARE</a>.\n     */\n    er_need_reprepare = 1615,\n\n    /**\n     * \\brief Common server error. Error number: 1616, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_delayed_not_supported\">ER_DELAYED_NOT_SUPPORTED</a>.\n     */\n    er_delayed_not_supported = 1616,\n\n    /**\n     * \\brief Common server error. Error number: 1617, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_no_master_info\">WARN_NO_MASTER_INFO</a>.\n     */\n    warn_no_master_info = 1617,\n\n    /**\n     * \\brief Common server error. Error number: 1618, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_option_ignored\">WARN_OPTION_IGNORED</a>.\n     */\n    warn_option_ignored = 1618,\n\n    /**\n     * \\brief Common server error. Error number: 1619, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_plugin_delete_builtin\">ER_PLUGIN_DELETE_BUILTIN</a>.\n     */\n    er_plugin_delete_builtin = 1619,\n\n    /**\n     * \\brief Common server error. Error number: 1620, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_plugin_busy\">WARN_PLUGIN_BUSY</a>.\n     */\n    warn_plugin_busy = 1620,\n\n    /**\n     * \\brief Common server error. Error number: 1621, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_variable_is_readonly\">ER_VARIABLE_IS_READONLY</a>.\n     */\n    er_variable_is_readonly = 1621,\n\n    /**\n     * \\brief Common server error. Error number: 1622, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_engine_transaction_rollback\">ER_WARN_ENGINE_TRANSACTION_ROLLBACK</a>.\n     */\n    er_warn_engine_transaction_rollback = 1622,\n\n    /**\n     * \\brief Common server error. Error number: 1623, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_heartbeat_failure\">ER_SLAVE_HEARTBEAT_FAILURE</a>.\n     */\n    er_slave_heartbeat_failure = 1623,\n\n    /**\n     * \\brief Common server error. Error number: 1624, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_heartbeat_value_out_of_range\">ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE</a>.\n     */\n    er_slave_heartbeat_value_out_of_range = 1624,\n\n    /**\n     * \\brief Common server error. Error number: 1626, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_conflict_fn_parse_error\">ER_CONFLICT_FN_PARSE_ERROR</a>.\n     */\n    er_conflict_fn_parse_error = 1626,\n\n    /**\n     * \\brief Common server error. Error number: 1627, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_exceptions_write_error\">ER_EXCEPTIONS_WRITE_ERROR</a>.\n     */\n    er_exceptions_write_error = 1627,\n\n    /**\n     * \\brief Common server error. Error number: 1628, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_table_comment\">ER_TOO_LONG_TABLE_COMMENT</a>.\n     */\n    er_too_long_table_comment = 1628,\n\n    /**\n     * \\brief Common server error. Error number: 1629, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_field_comment\">ER_TOO_LONG_FIELD_COMMENT</a>.\n     */\n    er_too_long_field_comment = 1629,\n\n    /**\n     * \\brief Common server error. Error number: 1630, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_func_inexistent_name_collision\">ER_FUNC_INEXISTENT_NAME_COLLISION</a>.\n     */\n    er_func_inexistent_name_collision = 1630,\n\n    /**\n     * \\brief Common server error. Error number: 1631, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_database_name\">ER_DATABASE_NAME</a>.\n     */\n    er_database_name = 1631,\n\n    /**\n     * \\brief Common server error. Error number: 1632, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_name\">ER_TABLE_NAME</a>.\n     */\n    er_table_name = 1632,\n\n    /**\n     * \\brief Common server error. Error number: 1633, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_name\">ER_PARTITION_NAME</a>.\n     */\n    er_partition_name = 1633,\n\n    /**\n     * \\brief Common server error. Error number: 1634, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_subpartition_name\">ER_SUBPARTITION_NAME</a>.\n     */\n    er_subpartition_name = 1634,\n\n    /**\n     * \\brief Common server error. Error number: 1635, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_temporary_name\">ER_TEMPORARY_NAME</a>.\n     */\n    er_temporary_name = 1635,\n\n    /**\n     * \\brief Common server error. Error number: 1636, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_renamed_name\">ER_RENAMED_NAME</a>.\n     */\n    er_renamed_name = 1636,\n\n    /**\n     * \\brief Common server error. Error number: 1637, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_concurrent_trxs\">ER_TOO_MANY_CONCURRENT_TRXS</a>.\n     */\n    er_too_many_concurrent_trxs = 1637,\n\n    /**\n     * \\brief Common server error. Error number: 1638, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_non_ascii_separator_not_implemented\">WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED</a>.\n     */\n    warn_non_ascii_separator_not_implemented = 1638,\n\n    /**\n     * \\brief Common server error. Error number: 1639, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_debug_sync_timeout\">ER_DEBUG_SYNC_TIMEOUT</a>.\n     */\n    er_debug_sync_timeout = 1639,\n\n    /**\n     * \\brief Common server error. Error number: 1640, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_debug_sync_hit_limit\">ER_DEBUG_SYNC_HIT_LIMIT</a>.\n     */\n    er_debug_sync_hit_limit = 1640,\n\n    /**\n     * \\brief Common server error. Error number: 1641, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_signal_set\">ER_DUP_SIGNAL_SET</a>.\n     */\n    er_dup_signal_set = 1641,\n\n    /**\n     * \\brief Common server error. Error number: 1642, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_signal_warn\">ER_SIGNAL_WARN</a>.\n     */\n    er_signal_warn = 1642,\n\n    /**\n     * \\brief Common server error. Error number: 1643, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_signal_not_found\">ER_SIGNAL_NOT_FOUND</a>.\n     */\n    er_signal_not_found = 1643,\n\n    /**\n     * \\brief Common server error. Error number: 1644, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_signal_exception\">ER_SIGNAL_EXCEPTION</a>.\n     */\n    er_signal_exception = 1644,\n\n    /**\n     * \\brief Common server error. Error number: 1645, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_resignal_without_active_handler\">ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER</a>.\n     */\n    er_resignal_without_active_handler = 1645,\n\n    /**\n     * \\brief Common server error. Error number: 1646, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_signal_bad_condition_type\">ER_SIGNAL_BAD_CONDITION_TYPE</a>.\n     */\n    er_signal_bad_condition_type = 1646,\n\n    /**\n     * \\brief Common server error. Error number: 1647, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_cond_item_truncated\">WARN_COND_ITEM_TRUNCATED</a>.\n     */\n    warn_cond_item_truncated = 1647,\n\n    /**\n     * \\brief Common server error. Error number: 1648, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cond_item_too_long\">ER_COND_ITEM_TOO_LONG</a>.\n     */\n    er_cond_item_too_long = 1648,\n\n    /**\n     * \\brief Common server error. Error number: 1649, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_locale\">ER_UNKNOWN_LOCALE</a>.\n     */\n    er_unknown_locale = 1649,\n\n    /**\n     * \\brief Common server error. Error number: 1650, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_ignore_server_ids\">ER_SLAVE_IGNORE_SERVER_IDS</a>.\n     */\n    er_slave_ignore_server_ids = 1650,\n\n    /**\n     * \\brief Common server error. Error number: 1651, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_query_cache_disabled\">ER_QUERY_CACHE_DISABLED</a>.\n     */\n    er_query_cache_disabled = 1651,\n\n    /**\n     * \\brief Common server error. Error number: 1652, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_same_name_partition_field\">ER_SAME_NAME_PARTITION_FIELD</a>.\n     */\n    er_same_name_partition_field = 1652,\n\n    /**\n     * \\brief Common server error. Error number: 1653, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_column_list_error\">ER_PARTITION_COLUMN_LIST_ERROR</a>.\n     */\n    er_partition_column_list_error = 1653,\n\n    /**\n     * \\brief Common server error. Error number: 1654, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_type_column_value_error\">ER_WRONG_TYPE_COLUMN_VALUE_ERROR</a>.\n     */\n    er_wrong_type_column_value_error = 1654,\n\n    /**\n     * \\brief Common server error. Error number: 1655, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_partition_func_fields_error\">ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR</a>.\n     */\n    er_too_many_partition_func_fields_error = 1655,\n\n    /**\n     * \\brief Common server error. Error number: 1656, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_maxvalue_in_values_in\">ER_MAXVALUE_IN_VALUES_IN</a>.\n     */\n    er_maxvalue_in_values_in = 1656,\n\n    /**\n     * \\brief Common server error. Error number: 1657, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_many_values_error\">ER_TOO_MANY_VALUES_ERROR</a>.\n     */\n    er_too_many_values_error = 1657,\n\n    /**\n     * \\brief Common server error. Error number: 1658, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_row_single_partition_field_error\">ER_ROW_SINGLE_PARTITION_FIELD_ERROR</a>.\n     */\n    er_row_single_partition_field_error = 1658,\n\n    /**\n     * \\brief Common server error. Error number: 1659, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_field_type_not_allowed_as_partition_field\">ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD</a>.\n     */\n    er_field_type_not_allowed_as_partition_field = 1659,\n\n    /**\n     * \\brief Common server error. Error number: 1660, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_fields_too_long\">ER_PARTITION_FIELDS_TOO_LONG</a>.\n     */\n    er_partition_fields_too_long = 1660,\n\n    /**\n     * \\brief Common server error. Error number: 1661, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_engine_and_stmt_engine\">ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE</a>.\n     */\n    er_binlog_row_engine_and_stmt_engine = 1661,\n\n    /**\n     * \\brief Common server error. Error number: 1662, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_mode_and_stmt_engine\">ER_BINLOG_ROW_MODE_AND_STMT_ENGINE</a>.\n     */\n    er_binlog_row_mode_and_stmt_engine = 1662,\n\n    /**\n     * \\brief Common server error. Error number: 1663, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_and_stmt_engine\">ER_BINLOG_UNSAFE_AND_STMT_ENGINE</a>.\n     */\n    er_binlog_unsafe_and_stmt_engine = 1663,\n\n    /**\n     * \\brief Common server error. Error number: 1664, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_injection_and_stmt_engine\">ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE</a>.\n     */\n    er_binlog_row_injection_and_stmt_engine = 1664,\n\n    /**\n     * \\brief Common server error. Error number: 1665, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_stmt_mode_and_row_engine\">ER_BINLOG_STMT_MODE_AND_ROW_ENGINE</a>.\n     */\n    er_binlog_stmt_mode_and_row_engine = 1665,\n\n    /**\n     * \\brief Common server error. Error number: 1666, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_row_injection_and_stmt_mode\">ER_BINLOG_ROW_INJECTION_AND_STMT_MODE</a>.\n     */\n    er_binlog_row_injection_and_stmt_mode = 1666,\n\n    /**\n     * \\brief Common server error. Error number: 1667, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_multiple_engines_and_self_logging_engine\">ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE</a>.\n     */\n    er_binlog_multiple_engines_and_self_logging_engine = 1667,\n\n    /**\n     * \\brief Common server error. Error number: 1668, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_limit\">ER_BINLOG_UNSAFE_LIMIT</a>.\n     */\n    er_binlog_unsafe_limit = 1668,\n\n    /**\n     * \\brief Common server error. Error number: 1670, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_system_table\">ER_BINLOG_UNSAFE_SYSTEM_TABLE</a>.\n     */\n    er_binlog_unsafe_system_table = 1670,\n\n    /**\n     * \\brief Common server error. Error number: 1671, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_autoinc_columns\">ER_BINLOG_UNSAFE_AUTOINC_COLUMNS</a>.\n     */\n    er_binlog_unsafe_autoinc_columns = 1671,\n\n    /**\n     * \\brief Common server error. Error number: 1672, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_udf\">ER_BINLOG_UNSAFE_UDF</a>.\n     */\n    er_binlog_unsafe_udf = 1672,\n\n    /**\n     * \\brief Common server error. Error number: 1673, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_system_variable\">ER_BINLOG_UNSAFE_SYSTEM_VARIABLE</a>.\n     */\n    er_binlog_unsafe_system_variable = 1673,\n\n    /**\n     * \\brief Common server error. Error number: 1674, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_system_function\">ER_BINLOG_UNSAFE_SYSTEM_FUNCTION</a>.\n     */\n    er_binlog_unsafe_system_function = 1674,\n\n    /**\n     * \\brief Common server error. Error number: 1675, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_nontrans_after_trans\">ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS</a>.\n     */\n    er_binlog_unsafe_nontrans_after_trans = 1675,\n\n    /**\n     * \\brief Common server error. Error number: 1676, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_message_and_statement\">ER_MESSAGE_AND_STATEMENT</a>.\n     */\n    er_message_and_statement = 1676,\n\n    /**\n     * \\brief Common server error. Error number: 1677, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_conversion_failed\">ER_SLAVE_CONVERSION_FAILED</a>.\n     */\n    er_slave_conversion_failed = 1677,\n\n    /**\n     * \\brief Common server error. Error number: 1678, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_cant_create_conversion\">ER_SLAVE_CANT_CREATE_CONVERSION</a>.\n     */\n    er_slave_cant_create_conversion = 1678,\n\n    /**\n     * \\brief Common server error. Error number: 1679, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_inside_transaction_prevents_switch_binlog_format\">ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT</a>.\n     */\n    er_inside_transaction_prevents_switch_binlog_format = 1679,\n\n    /**\n     * \\brief Common server error. Error number: 1680, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_path_length\">ER_PATH_LENGTH</a>.\n     */\n    er_path_length = 1680,\n\n    /**\n     * \\brief Common server error. Error number: 1681, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_deprecated_syntax_no_replacement\">ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT</a>.\n     */\n    er_warn_deprecated_syntax_no_replacement = 1681,\n\n    /**\n     * \\brief Common server error. Error number: 1682, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_native_table_structure\">ER_WRONG_NATIVE_TABLE_STRUCTURE</a>.\n     */\n    er_wrong_native_table_structure = 1682,\n\n    /**\n     * \\brief Common server error. Error number: 1683, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_perfschema_usage\">ER_WRONG_PERFSCHEMA_USAGE</a>.\n     */\n    er_wrong_perfschema_usage = 1683,\n\n    /**\n     * \\brief Common server error. Error number: 1684, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_i_s_skipped_table\">ER_WARN_I_S_SKIPPED_TABLE</a>.\n     */\n    er_warn_i_s_skipped_table = 1684,\n\n    /**\n     * \\brief Common server error. Error number: 1685, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_inside_transaction_prevents_switch_binlog_direct\">ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT</a>.\n     */\n    er_inside_transaction_prevents_switch_binlog_direct = 1685,\n\n    /**\n     * \\brief Common server error. Error number: 1686, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stored_function_prevents_switch_binlog_direct\">ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT</a>.\n     */\n    er_stored_function_prevents_switch_binlog_direct = 1686,\n\n    /**\n     * \\brief Common server error. Error number: 1687, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_spatial_must_have_geom_col\">ER_SPATIAL_MUST_HAVE_GEOM_COL</a>.\n     */\n    er_spatial_must_have_geom_col = 1687,\n\n    /**\n     * \\brief Common server error. Error number: 1688, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_index_comment\">ER_TOO_LONG_INDEX_COMMENT</a>.\n     */\n    er_too_long_index_comment = 1688,\n\n    /**\n     * \\brief Common server error. Error number: 1689, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_lock_aborted\">ER_LOCK_ABORTED</a>.\n     */\n    er_lock_aborted = 1689,\n\n    /**\n     * \\brief Common server error. Error number: 1690, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_data_out_of_range\">ER_DATA_OUT_OF_RANGE</a>.\n     */\n    er_data_out_of_range = 1690,\n\n    /**\n     * \\brief Common server error. Error number: 1691, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_wrong_spvar_type_in_limit\">ER_WRONG_SPVAR_TYPE_IN_LIMIT</a>.\n     */\n    er_wrong_spvar_type_in_limit = 1691,\n\n    /**\n     * \\brief Common server error. Error number: 1692, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_multiple_engines_and_self_logging_engine\">ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE</a>.\n     */\n    er_binlog_unsafe_multiple_engines_and_self_logging_engine = 1692,\n\n    /**\n     * \\brief Common server error. Error number: 1693, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_mixed_statement\">ER_BINLOG_UNSAFE_MIXED_STATEMENT</a>.\n     */\n    er_binlog_unsafe_mixed_statement = 1693,\n\n    /**\n     * \\brief Common server error. Error number: 1694, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_inside_transaction_prevents_switch_sql_log_bin\">ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN</a>.\n     */\n    er_inside_transaction_prevents_switch_sql_log_bin = 1694,\n\n    /**\n     * \\brief Common server error. Error number: 1695, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stored_function_prevents_switch_sql_log_bin\">ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN</a>.\n     */\n    er_stored_function_prevents_switch_sql_log_bin = 1695,\n\n    /**\n     * \\brief Common server error. Error number: 1696, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_failed_read_from_par_file\">ER_FAILED_READ_FROM_PAR_FILE</a>.\n     */\n    er_failed_read_from_par_file = 1696,\n\n    /**\n     * \\brief Common server error. Error number: 1697, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_values_is_not_int_type_error\">ER_VALUES_IS_NOT_INT_TYPE_ERROR</a>.\n     */\n    er_values_is_not_int_type_error = 1697,\n\n    /**\n     * \\brief Common server error. Error number: 1698, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_access_denied_no_password_error\">ER_ACCESS_DENIED_NO_PASSWORD_ERROR</a>.\n     */\n    er_access_denied_no_password_error = 1698,\n\n    /**\n     * \\brief Common server error. Error number: 1699, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_set_password_auth_plugin\">ER_SET_PASSWORD_AUTH_PLUGIN</a>.\n     */\n    er_set_password_auth_plugin = 1699,\n\n    /**\n     * \\brief Common server error. Error number: 1700, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_grant_plugin_user_exists\">ER_GRANT_PLUGIN_USER_EXISTS</a>.\n     */\n    er_grant_plugin_user_exists = 1700,\n\n    /**\n     * \\brief Common server error. Error number: 1701, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_truncate_illegal_fk\">ER_TRUNCATE_ILLEGAL_FK</a>.\n     */\n    er_truncate_illegal_fk = 1701,\n\n    /**\n     * \\brief Common server error. Error number: 1702, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_plugin_is_permanent\">ER_PLUGIN_IS_PERMANENT</a>.\n     */\n    er_plugin_is_permanent = 1702,\n\n    /**\n     * \\brief Common server error. Error number: 1703, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_heartbeat_value_out_of_range_min\">ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN</a>.\n     */\n    er_slave_heartbeat_value_out_of_range_min = 1703,\n\n    /**\n     * \\brief Common server error. Error number: 1704, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_heartbeat_value_out_of_range_max\">ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX</a>.\n     */\n    er_slave_heartbeat_value_out_of_range_max = 1704,\n\n    /**\n     * \\brief Common server error. Error number: 1705, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stmt_cache_full\">ER_STMT_CACHE_FULL</a>.\n     */\n    er_stmt_cache_full = 1705,\n\n    /**\n     * \\brief Common server error. Error number: 1706, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_multi_update_key_conflict\">ER_MULTI_UPDATE_KEY_CONFLICT</a>.\n     */\n    er_multi_update_key_conflict = 1706,\n\n    /**\n     * \\brief Common server error. Error number: 1707, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_needs_rebuild\">ER_TABLE_NEEDS_REBUILD</a>.\n     */\n    er_table_needs_rebuild = 1707,\n\n    /**\n     * \\brief Common server error. Error number: 1708, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_option_below_limit\">WARN_OPTION_BELOW_LIMIT</a>.\n     */\n    warn_option_below_limit = 1708,\n\n    /**\n     * \\brief Common server error. Error number: 1709, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_index_column_too_long\">ER_INDEX_COLUMN_TOO_LONG</a>.\n     */\n    er_index_column_too_long = 1709,\n\n    /**\n     * \\brief Common server error. Error number: 1710, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_in_trigger_body\">ER_ERROR_IN_TRIGGER_BODY</a>.\n     */\n    er_error_in_trigger_body = 1710,\n\n    /**\n     * \\brief Common server error. Error number: 1711, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_error_in_unknown_trigger_body\">ER_ERROR_IN_UNKNOWN_TRIGGER_BODY</a>.\n     */\n    er_error_in_unknown_trigger_body = 1711,\n\n    /**\n     * \\brief Common server error. Error number: 1712, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_index_corrupt\">ER_INDEX_CORRUPT</a>.\n     */\n    er_index_corrupt = 1712,\n\n    /**\n     * \\brief Common server error. Error number: 1713, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_undo_record_too_big\">ER_UNDO_RECORD_TOO_BIG</a>.\n     */\n    er_undo_record_too_big = 1713,\n\n    /**\n     * \\brief Common server error. Error number: 1714, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_insert_ignore_select\">ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT</a>.\n     */\n    er_binlog_unsafe_insert_ignore_select = 1714,\n\n    /**\n     * \\brief Common server error. Error number: 1715, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_insert_select_update\">ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE</a>.\n     */\n    er_binlog_unsafe_insert_select_update = 1715,\n\n    /**\n     * \\brief Common server error. Error number: 1716, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_replace_select\">ER_BINLOG_UNSAFE_REPLACE_SELECT</a>.\n     */\n    er_binlog_unsafe_replace_select = 1716,\n\n    /**\n     * \\brief Common server error. Error number: 1717, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_create_ignore_select\">ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT</a>.\n     */\n    er_binlog_unsafe_create_ignore_select = 1717,\n\n    /**\n     * \\brief Common server error. Error number: 1718, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_create_replace_select\">ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT</a>.\n     */\n    er_binlog_unsafe_create_replace_select = 1718,\n\n    /**\n     * \\brief Common server error. Error number: 1719, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_update_ignore\">ER_BINLOG_UNSAFE_UPDATE_IGNORE</a>.\n     */\n    er_binlog_unsafe_update_ignore = 1719,\n\n    /**\n     * \\brief Common server error. Error number: 1722, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_write_autoinc_select\">ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT</a>.\n     */\n    er_binlog_unsafe_write_autoinc_select = 1722,\n\n    /**\n     * \\brief Common server error. Error number: 1723, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_create_select_autoinc\">ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC</a>.\n     */\n    er_binlog_unsafe_create_select_autoinc = 1723,\n\n    /**\n     * \\brief Common server error. Error number: 1724, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_insert_two_keys\">ER_BINLOG_UNSAFE_INSERT_TWO_KEYS</a>.\n     */\n    er_binlog_unsafe_insert_two_keys = 1724,\n\n    /**\n     * \\brief Common server error. Error number: 1727, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_unsafe_autoinc_not_first\">ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST</a>.\n     */\n    er_binlog_unsafe_autoinc_not_first = 1727,\n\n    /**\n     * \\brief Common server error. Error number: 1728, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cannot_load_from_table_v2\">ER_CANNOT_LOAD_FROM_TABLE_V2</a>.\n     */\n    er_cannot_load_from_table_v2 = 1728,\n\n    /**\n     * \\brief Common server error. Error number: 1729, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master_delay_value_out_of_range\">ER_MASTER_DELAY_VALUE_OUT_OF_RANGE</a>.\n     */\n    er_master_delay_value_out_of_range = 1729,\n\n    /**\n     * \\brief Common server error. Error number: 1730, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_only_fd_and_rbr_events_allowed_in_binlog_statement\">ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT</a>.\n     */\n    er_only_fd_and_rbr_events_allowed_in_binlog_statement = 1730,\n\n    /**\n     * \\brief Common server error. Error number: 1731, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_exchange_different_option\">ER_PARTITION_EXCHANGE_DIFFERENT_OPTION</a>.\n     */\n    er_partition_exchange_different_option = 1731,\n\n    /**\n     * \\brief Common server error. Error number: 1732, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_exchange_part_table\">ER_PARTITION_EXCHANGE_PART_TABLE</a>.\n     */\n    er_partition_exchange_part_table = 1732,\n\n    /**\n     * \\brief Common server error. Error number: 1733, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_exchange_temp_table\">ER_PARTITION_EXCHANGE_TEMP_TABLE</a>.\n     */\n    er_partition_exchange_temp_table = 1733,\n\n    /**\n     * \\brief Common server error. Error number: 1734, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_instead_of_subpartition\">ER_PARTITION_INSTEAD_OF_SUBPARTITION</a>.\n     */\n    er_partition_instead_of_subpartition = 1734,\n\n    /**\n     * \\brief Common server error. Error number: 1735, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_partition\">ER_UNKNOWN_PARTITION</a>.\n     */\n    er_unknown_partition = 1735,\n\n    /**\n     * \\brief Common server error. Error number: 1736, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tables_different_metadata\">ER_TABLES_DIFFERENT_METADATA</a>.\n     */\n    er_tables_different_metadata = 1736,\n\n    /**\n     * \\brief Common server error. Error number: 1737, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_row_does_not_match_partition\">ER_ROW_DOES_NOT_MATCH_PARTITION</a>.\n     */\n    er_row_does_not_match_partition = 1737,\n\n    /**\n     * \\brief Common server error. Error number: 1738, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_cache_size_greater_than_max\">ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX</a>.\n     */\n    er_binlog_cache_size_greater_than_max = 1738,\n\n    /**\n     * \\brief Common server error. Error number: 1739, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_index_not_applicable\">ER_WARN_INDEX_NOT_APPLICABLE</a>.\n     */\n    er_warn_index_not_applicable = 1739,\n\n    /**\n     * \\brief Common server error. Error number: 1740, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_exchange_foreign_key\">ER_PARTITION_EXCHANGE_FOREIGN_KEY</a>.\n     */\n    er_partition_exchange_foreign_key = 1740,\n\n    /**\n     * \\brief Common server error. Error number: 1741, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_such_key_value\">ER_NO_SUCH_KEY_VALUE</a>.\n     */\n    er_no_such_key_value = 1741,\n\n    /**\n     * \\brief Common server error. Error number: 1743, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_network_read_event_checksum_failure\">ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE</a>.\n     */\n    er_network_read_event_checksum_failure = 1743,\n\n    /**\n     * \\brief Common server error. Error number: 1744, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_read_event_checksum_failure\">ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE</a>.\n     */\n    er_binlog_read_event_checksum_failure = 1744,\n\n    /**\n     * \\brief Common server error. Error number: 1745, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_stmt_cache_size_greater_than_max\">ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX</a>.\n     */\n    er_binlog_stmt_cache_size_greater_than_max = 1745,\n\n    /**\n     * \\brief Common server error. Error number: 1746, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_update_table_in_create_table_select\">ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT</a>.\n     */\n    er_cant_update_table_in_create_table_select = 1746,\n\n    /**\n     * \\brief Common server error. Error number: 1747, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_partition_clause_on_nonpartitioned\">ER_PARTITION_CLAUSE_ON_NONPARTITIONED</a>.\n     */\n    er_partition_clause_on_nonpartitioned = 1747,\n\n    /**\n     * \\brief Common server error. Error number: 1748, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_row_does_not_match_given_partition_set\">ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET</a>.\n     */\n    er_row_does_not_match_given_partition_set = 1748,\n\n    /**\n     * \\brief Common server error. Error number: 1750, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_change_rpl_info_repository_failure\">ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE</a>.\n     */\n    er_change_rpl_info_repository_failure = 1750,\n\n    /**\n     * \\brief Common server error. Error number: 1751, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warning_not_complete_rollback_with_created_temp_table\">ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE</a>.\n     */\n    er_warning_not_complete_rollback_with_created_temp_table = 1751,\n\n    /**\n     * \\brief Common server error. Error number: 1752, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warning_not_complete_rollback_with_dropped_temp_table\">ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE</a>.\n     */\n    er_warning_not_complete_rollback_with_dropped_temp_table = 1752,\n\n    /**\n     * \\brief Common server error. Error number: 1753, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_feature_is_not_supported\">ER_MTS_FEATURE_IS_NOT_SUPPORTED</a>.\n     */\n    er_mts_feature_is_not_supported = 1753,\n\n    /**\n     * \\brief Common server error. Error number: 1754, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_updated_dbs_greater_max\">ER_MTS_UPDATED_DBS_GREATER_MAX</a>.\n     */\n    er_mts_updated_dbs_greater_max = 1754,\n\n    /**\n     * \\brief Common server error. Error number: 1755, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_cant_parallel\">ER_MTS_CANT_PARALLEL</a>.\n     */\n    er_mts_cant_parallel = 1755,\n\n    /**\n     * \\brief Common server error. Error number: 1756, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_inconsistent_data\">ER_MTS_INCONSISTENT_DATA</a>.\n     */\n    er_mts_inconsistent_data = 1756,\n\n    /**\n     * \\brief Common server error. Error number: 1757, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fulltext_not_supported_with_partitioning\">ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING</a>.\n     */\n    er_fulltext_not_supported_with_partitioning = 1757,\n\n    /**\n     * \\brief Common server error. Error number: 1758, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_da_invalid_condition_number\">ER_DA_INVALID_CONDITION_NUMBER</a>.\n     */\n    er_da_invalid_condition_number = 1758,\n\n    /**\n     * \\brief Common server error. Error number: 1759, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_insecure_plain_text\">ER_INSECURE_PLAIN_TEXT</a>.\n     */\n    er_insecure_plain_text = 1759,\n\n    /**\n     * \\brief Common server error. Error number: 1760, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_insecure_change_master\">ER_INSECURE_CHANGE_MASTER</a>.\n     */\n    er_insecure_change_master = 1760,\n\n    /**\n     * \\brief Common server error. Error number: 1761, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_duplicate_key_with_child_info\">ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO</a>.\n     */\n    er_foreign_duplicate_key_with_child_info = 1761,\n\n    /**\n     * \\brief Common server error. Error number: 1762, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_foreign_duplicate_key_without_child_info\">ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO</a>.\n     */\n    er_foreign_duplicate_key_without_child_info = 1762,\n\n    /**\n     * \\brief Common server error. Error number: 1763, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sqlthread_with_secure_slave\">ER_SQLTHREAD_WITH_SECURE_SLAVE</a>.\n     */\n    er_sqlthread_with_secure_slave = 1763,\n\n    /**\n     * \\brief Common server error. Error number: 1764, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_has_no_ft\">ER_TABLE_HAS_NO_FT</a>.\n     */\n    er_table_has_no_ft = 1764,\n\n    /**\n     * \\brief Common server error. Error number: 1765, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_variable_not_settable_in_sf_or_trigger\">ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER</a>.\n     */\n    er_variable_not_settable_in_sf_or_trigger = 1765,\n\n    /**\n     * \\brief Common server error. Error number: 1766, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_variable_not_settable_in_transaction\">ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION</a>.\n     */\n    er_variable_not_settable_in_transaction = 1766,\n\n    /**\n     * \\brief Common server error. Error number: 1767, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_next_is_not_in_gtid_next_list\">ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST</a>.\n     */\n    er_gtid_next_is_not_in_gtid_next_list = 1767,\n\n    /**\n     * \\brief Common server error. Error number: 1769, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_set_statement_cannot_invoke_function\">ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION</a>.\n     */\n    er_set_statement_cannot_invoke_function = 1769,\n\n    /**\n     * \\brief Common server error. Error number: 1770, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_next_cant_be_automatic_if_gtid_next_list_is_non_null\">ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL</a>.\n     */\n    er_gtid_next_cant_be_automatic_if_gtid_next_list_is_non_null = 1770,\n\n    /**\n     * \\brief Common server error. Error number: 1771, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_skipping_logged_transaction\">ER_SKIPPING_LOGGED_TRANSACTION</a>.\n     */\n    er_skipping_logged_transaction = 1771,\n\n    /**\n     * \\brief Common server error. Error number: 1772, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_malformed_gtid_set_specification\">ER_MALFORMED_GTID_SET_SPECIFICATION</a>.\n     */\n    er_malformed_gtid_set_specification = 1772,\n\n    /**\n     * \\brief Common server error. Error number: 1773, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_malformed_gtid_set_encoding\">ER_MALFORMED_GTID_SET_ENCODING</a>.\n     */\n    er_malformed_gtid_set_encoding = 1773,\n\n    /**\n     * \\brief Common server error. Error number: 1774, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_malformed_gtid_specification\">ER_MALFORMED_GTID_SPECIFICATION</a>.\n     */\n    er_malformed_gtid_specification = 1774,\n\n    /**\n     * \\brief Common server error. Error number: 1775, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gno_exhausted\">ER_GNO_EXHAUSTED</a>.\n     */\n    er_gno_exhausted = 1775,\n\n    /**\n     * \\brief Common server error. Error number: 1776, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_slave_auto_position\">ER_BAD_SLAVE_AUTO_POSITION</a>.\n     */\n    er_bad_slave_auto_position = 1776,\n\n    /**\n     * \\brief Common server error. Error number: 1778, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_do_implicit_commit_in_trx_when_gtid_next_is_set\">ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET</a>.\n     */\n    er_cant_do_implicit_commit_in_trx_when_gtid_next_is_set = 1778,\n\n    /**\n     * \\brief Common server error. Error number: 1780, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_mode_requires_binlog\">ER_GTID_MODE_REQUIRES_BINLOG</a>.\n     */\n    er_gtid_mode_requires_binlog = 1780,\n\n    /**\n     * \\brief Common server error. Error number: 1781, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_next_to_gtid_when_gtid_mode_is_off\">ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF</a>.\n     */\n    er_cant_set_gtid_next_to_gtid_when_gtid_mode_is_off = 1781,\n\n    /**\n     * \\brief Common server error. Error number: 1782, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_next_to_anonymous_when_gtid_mode_is_on\">ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON</a>.\n     */\n    er_cant_set_gtid_next_to_anonymous_when_gtid_mode_is_on = 1782,\n\n    /**\n     * \\brief Common server error. Error number: 1783, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_next_list_to_non_null_when_gtid_mode_is_off\">ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF</a>.\n     */\n    er_cant_set_gtid_next_list_to_non_null_when_gtid_mode_is_off = 1783,\n\n    /**\n     * \\brief Common server error. Error number: 1785, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_unsafe_non_transactional_table\">ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE</a>.\n     */\n    er_gtid_unsafe_non_transactional_table = 1785,\n\n    /**\n     * \\brief Common server error. Error number: 1786, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_unsafe_create_select\">ER_GTID_UNSAFE_CREATE_SELECT</a>.\n     */\n    er_gtid_unsafe_create_select = 1786,\n\n    /**\n     * \\brief Common server error. Error number: 1787, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_unsafe_create_drop_temporary_table_in_transaction\">ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION</a>.\n     */\n    er_gtid_unsafe_create_drop_temporary_table_in_transaction = 1787,\n\n    /**\n     * \\brief Common server error. Error number: 1788, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_mode_can_only_change_one_step_at_a_time\">ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME</a>.\n     */\n    er_gtid_mode_can_only_change_one_step_at_a_time = 1788,\n\n    /**\n     * \\brief Common server error. Error number: 1789, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_master_has_purged_required_gtids\">ER_MASTER_HAS_PURGED_REQUIRED_GTIDS</a>.\n     */\n    er_master_has_purged_required_gtids = 1789,\n\n    /**\n     * \\brief Common server error. Error number: 1790, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_next_when_owning_gtid\">ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID</a>.\n     */\n    er_cant_set_gtid_next_when_owning_gtid = 1790,\n\n    /**\n     * \\brief Common server error. Error number: 1791, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_explain_format\">ER_UNKNOWN_EXPLAIN_FORMAT</a>.\n     */\n    er_unknown_explain_format = 1791,\n\n    /**\n     * \\brief Common server error. Error number: 1792, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_execute_in_read_only_transaction\">ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION</a>.\n     */\n    er_cant_execute_in_read_only_transaction = 1792,\n\n    /**\n     * \\brief Common server error. Error number: 1793, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_too_long_table_partition_comment\">ER_TOO_LONG_TABLE_PARTITION_COMMENT</a>.\n     */\n    er_too_long_table_partition_comment = 1793,\n\n    /**\n     * \\brief Common server error. Error number: 1794, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_configuration\">ER_SLAVE_CONFIGURATION</a>.\n     */\n    er_slave_configuration = 1794,\n\n    /**\n     * \\brief Common server error. Error number: 1795, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_ft_limit\">ER_INNODB_FT_LIMIT</a>.\n     */\n    er_innodb_ft_limit = 1795,\n\n    /**\n     * \\brief Common server error. Error number: 1796, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_no_ft_temp_table\">ER_INNODB_NO_FT_TEMP_TABLE</a>.\n     */\n    er_innodb_no_ft_temp_table = 1796,\n\n    /**\n     * \\brief Common server error. Error number: 1797, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_ft_wrong_docid_column\">ER_INNODB_FT_WRONG_DOCID_COLUMN</a>.\n     */\n    er_innodb_ft_wrong_docid_column = 1797,\n\n    /**\n     * \\brief Common server error. Error number: 1798, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_ft_wrong_docid_index\">ER_INNODB_FT_WRONG_DOCID_INDEX</a>.\n     */\n    er_innodb_ft_wrong_docid_index = 1798,\n\n    /**\n     * \\brief Common server error. Error number: 1799, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_online_log_too_big\">ER_INNODB_ONLINE_LOG_TOO_BIG</a>.\n     */\n    er_innodb_online_log_too_big = 1799,\n\n    /**\n     * \\brief Common server error. Error number: 1800, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_alter_algorithm\">ER_UNKNOWN_ALTER_ALGORITHM</a>.\n     */\n    er_unknown_alter_algorithm = 1800,\n\n    /**\n     * \\brief Common server error. Error number: 1801, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_unknown_alter_lock\">ER_UNKNOWN_ALTER_LOCK</a>.\n     */\n    er_unknown_alter_lock = 1801,\n\n    /**\n     * \\brief Common server error. Error number: 1802, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_change_master_cant_run_with_gaps\">ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS</a>.\n     */\n    er_mts_change_master_cant_run_with_gaps = 1802,\n\n    /**\n     * \\brief Common server error. Error number: 1803, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_recovery_failure\">ER_MTS_RECOVERY_FAILURE</a>.\n     */\n    er_mts_recovery_failure = 1803,\n\n    /**\n     * \\brief Common server error. Error number: 1804, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_reset_workers\">ER_MTS_RESET_WORKERS</a>.\n     */\n    er_mts_reset_workers = 1804,\n\n    /**\n     * \\brief Common server error. Error number: 1805, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_col_count_doesnt_match_corrupted_v2\">ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2</a>.\n     */\n    er_col_count_doesnt_match_corrupted_v2 = 1805,\n\n    /**\n     * \\brief Common server error. Error number: 1806, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_silent_retry_transaction\">ER_SLAVE_SILENT_RETRY_TRANSACTION</a>.\n     */\n    er_slave_silent_retry_transaction = 1806,\n\n    /**\n     * \\brief Common server error. Error number: 1808, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_schema_mismatch\">ER_TABLE_SCHEMA_MISMATCH</a>.\n     */\n    er_table_schema_mismatch = 1808,\n\n    /**\n     * \\brief Common server error. Error number: 1809, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_in_system_tablespace\">ER_TABLE_IN_SYSTEM_TABLESPACE</a>.\n     */\n    er_table_in_system_tablespace = 1809,\n\n    /**\n     * \\brief Common server error. Error number: 1810, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_io_read_error\">ER_IO_READ_ERROR</a>.\n     */\n    er_io_read_error = 1810,\n\n    /**\n     * \\brief Common server error. Error number: 1811, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_io_write_error\">ER_IO_WRITE_ERROR</a>.\n     */\n    er_io_write_error = 1811,\n\n    /**\n     * \\brief Common server error. Error number: 1812, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tablespace_missing\">ER_TABLESPACE_MISSING</a>.\n     */\n    er_tablespace_missing = 1812,\n\n    /**\n     * \\brief Common server error. Error number: 1813, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tablespace_exists\">ER_TABLESPACE_EXISTS</a>.\n     */\n    er_tablespace_exists = 1813,\n\n    /**\n     * \\brief Common server error. Error number: 1814, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_tablespace_discarded\">ER_TABLESPACE_DISCARDED</a>.\n     */\n    er_tablespace_discarded = 1814,\n\n    /**\n     * \\brief Common server error. Error number: 1815, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_internal_error\">ER_INTERNAL_ERROR</a>.\n     */\n    er_internal_error = 1815,\n\n    /**\n     * \\brief Common server error. Error number: 1816, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_import_error\">ER_INNODB_IMPORT_ERROR</a>.\n     */\n    er_innodb_import_error = 1816,\n\n    /**\n     * \\brief Common server error. Error number: 1817, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_index_corrupt\">ER_INNODB_INDEX_CORRUPT</a>.\n     */\n    er_innodb_index_corrupt = 1817,\n\n    /**\n     * \\brief Common server error. Error number: 1818, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_invalid_year_column_length\">ER_INVALID_YEAR_COLUMN_LENGTH</a>.\n     */\n    er_invalid_year_column_length = 1818,\n\n    /**\n     * \\brief Common server error. Error number: 1819, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_not_valid_password\">ER_NOT_VALID_PASSWORD</a>.\n     */\n    er_not_valid_password = 1819,\n\n    /**\n     * \\brief Common server error. Error number: 1820, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_must_change_password\">ER_MUST_CHANGE_PASSWORD</a>.\n     */\n    er_must_change_password = 1820,\n\n    /**\n     * \\brief Common server error. Error number: 1821, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_no_index_child\">ER_FK_NO_INDEX_CHILD</a>.\n     */\n    er_fk_no_index_child = 1821,\n\n    /**\n     * \\brief Common server error. Error number: 1822, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_no_index_parent\">ER_FK_NO_INDEX_PARENT</a>.\n     */\n    er_fk_no_index_parent = 1822,\n\n    /**\n     * \\brief Common server error. Error number: 1823, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_fail_add_system\">ER_FK_FAIL_ADD_SYSTEM</a>.\n     */\n    er_fk_fail_add_system = 1823,\n\n    /**\n     * \\brief Common server error. Error number: 1824, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_cannot_open_parent\">ER_FK_CANNOT_OPEN_PARENT</a>.\n     */\n    er_fk_cannot_open_parent = 1824,\n\n    /**\n     * \\brief Common server error. Error number: 1825, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_incorrect_option\">ER_FK_INCORRECT_OPTION</a>.\n     */\n    er_fk_incorrect_option = 1825,\n\n    /**\n     * \\brief Common server error. Error number: 1827, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_password_format\">ER_PASSWORD_FORMAT</a>.\n     */\n    er_password_format = 1827,\n\n    /**\n     * \\brief Common server error. Error number: 1828, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_column_cannot_drop\">ER_FK_COLUMN_CANNOT_DROP</a>.\n     */\n    er_fk_column_cannot_drop = 1828,\n\n    /**\n     * \\brief Common server error. Error number: 1829, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_column_cannot_drop_child\">ER_FK_COLUMN_CANNOT_DROP_CHILD</a>.\n     */\n    er_fk_column_cannot_drop_child = 1829,\n\n    /**\n     * \\brief Common server error. Error number: 1830, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_column_not_null\">ER_FK_COLUMN_NOT_NULL</a>.\n     */\n    er_fk_column_not_null = 1830,\n\n    /**\n     * \\brief Common server error. Error number: 1831, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_index\">ER_DUP_INDEX</a>.\n     */\n    er_dup_index = 1831,\n\n    /**\n     * \\brief Common server error. Error number: 1832, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_column_cannot_change\">ER_FK_COLUMN_CANNOT_CHANGE</a>.\n     */\n    er_fk_column_cannot_change = 1832,\n\n    /**\n     * \\brief Common server error. Error number: 1833, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_fk_column_cannot_change_child\">ER_FK_COLUMN_CANNOT_CHANGE_CHILD</a>.\n     */\n    er_fk_column_cannot_change_child = 1833,\n\n    /**\n     * \\brief Common server error. Error number: 1835, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_malformed_packet\">ER_MALFORMED_PACKET</a>.\n     */\n    er_malformed_packet = 1835,\n\n    /**\n     * \\brief Common server error. Error number: 1836, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_read_only_mode\">ER_READ_ONLY_MODE</a>.\n     */\n    er_read_only_mode = 1836,\n\n    /**\n     * \\brief Common server error. Error number: 1838, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_variable_not_settable_in_sp\">ER_VARIABLE_NOT_SETTABLE_IN_SP</a>.\n     */\n    er_variable_not_settable_in_sp = 1838,\n\n    /**\n     * \\brief Common server error. Error number: 1839, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_purged_when_gtid_mode_is_off\">ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF</a>.\n     */\n    er_cant_set_gtid_purged_when_gtid_mode_is_off = 1839,\n\n    /**\n     * \\brief Common server error. Error number: 1840, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_purged_when_gtid_executed_is_not_empty\">ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY</a>.\n     */\n    er_cant_set_gtid_purged_when_gtid_executed_is_not_empty = 1840,\n\n    /**\n     * \\brief Common server error. Error number: 1841, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_cant_set_gtid_purged_when_owned_gtids_is_not_empty\">ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY</a>.\n     */\n    er_cant_set_gtid_purged_when_owned_gtids_is_not_empty = 1841,\n\n    /**\n     * \\brief Common server error. Error number: 1842, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_purged_was_changed\">ER_GTID_PURGED_WAS_CHANGED</a>.\n     */\n    er_gtid_purged_was_changed = 1842,\n\n    /**\n     * \\brief Common server error. Error number: 1843, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_gtid_executed_was_changed\">ER_GTID_EXECUTED_WAS_CHANGED</a>.\n     */\n    er_gtid_executed_was_changed = 1843,\n\n    /**\n     * \\brief Common server error. Error number: 1844, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_stmt_mode_and_no_repl_tables\">ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES</a>.\n     */\n    er_binlog_stmt_mode_and_no_repl_tables = 1844,\n\n    /**\n     * \\brief Common server error. Error number: 1845, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported\">ER_ALTER_OPERATION_NOT_SUPPORTED</a>.\n     */\n    er_alter_operation_not_supported = 1845,\n\n    /**\n     * \\brief Common server error. Error number: 1846, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON</a>.\n     */\n    er_alter_operation_not_supported_reason = 1846,\n\n    /**\n     * \\brief Common server error. Error number: 1847, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_copy\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY</a>.\n     */\n    er_alter_operation_not_supported_reason_copy = 1847,\n\n    /**\n     * \\brief Common server error. Error number: 1848, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_partition\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION</a>.\n     */\n    er_alter_operation_not_supported_reason_partition = 1848,\n\n    /**\n     * \\brief Common server error. Error number: 1849, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_fk_rename\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME</a>.\n     */\n    er_alter_operation_not_supported_reason_fk_rename = 1849,\n\n    /**\n     * \\brief Common server error. Error number: 1850, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_column_type\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE</a>.\n     */\n    er_alter_operation_not_supported_reason_column_type = 1850,\n\n    /**\n     * \\brief Common server error. Error number: 1851, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_fk_check\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK</a>.\n     */\n    er_alter_operation_not_supported_reason_fk_check = 1851,\n\n    /**\n     * \\brief Common server error. Error number: 1853, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_nopk\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK</a>.\n     */\n    er_alter_operation_not_supported_reason_nopk = 1853,\n\n    /**\n     * \\brief Common server error. Error number: 1854, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_autoinc\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC</a>.\n     */\n    er_alter_operation_not_supported_reason_autoinc = 1854,\n\n    /**\n     * \\brief Common server error. Error number: 1855, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_hidden_fts\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS</a>.\n     */\n    er_alter_operation_not_supported_reason_hidden_fts = 1855,\n\n    /**\n     * \\brief Common server error. Error number: 1856, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_change_fts\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS</a>.\n     */\n    er_alter_operation_not_supported_reason_change_fts = 1856,\n\n    /**\n     * \\brief Common server error. Error number: 1857, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_fts\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS</a>.\n     */\n    er_alter_operation_not_supported_reason_fts = 1857,\n\n    /**\n     * \\brief Common server error. Error number: 1858, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_sql_slave_skip_counter_not_settable_in_gtid_mode\">ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE</a>.\n     */\n    er_sql_slave_skip_counter_not_settable_in_gtid_mode = 1858,\n\n    /**\n     * \\brief Common server error. Error number: 1859, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_unknown_in_index\">ER_DUP_UNKNOWN_IN_INDEX</a>.\n     */\n    er_dup_unknown_in_index = 1859,\n\n    /**\n     * \\brief Common server error. Error number: 1860, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_ident_causes_too_long_path\">ER_IDENT_CAUSES_TOO_LONG_PATH</a>.\n     */\n    er_ident_causes_too_long_path = 1860,\n\n    /**\n     * \\brief Common server error. Error number: 1861, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_alter_operation_not_supported_reason_not_null\">ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL</a>.\n     */\n    er_alter_operation_not_supported_reason_not_null = 1861,\n\n    /**\n     * \\brief Common server error. Error number: 1862, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_must_change_password_login\">ER_MUST_CHANGE_PASSWORD_LOGIN</a>.\n     */\n    er_must_change_password_login = 1862,\n\n    /**\n     * \\brief Common server error. Error number: 1863, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_row_in_wrong_partition\">ER_ROW_IN_WRONG_PARTITION</a>.\n     */\n    er_row_in_wrong_partition = 1863,\n\n    /**\n     * \\brief Common server error. Error number: 1864, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_mts_event_bigger_pending_jobs_size_max\">ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX</a>.\n     */\n    er_mts_event_bigger_pending_jobs_size_max = 1864,\n\n    /**\n     * \\brief Common server error. Error number: 1865, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_no_ft_uses_parser\">ER_INNODB_NO_FT_USES_PARSER</a>.\n     */\n    er_innodb_no_ft_uses_parser = 1865,\n\n    /**\n     * \\brief Common server error. Error number: 1866, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_binlog_logical_corruption\">ER_BINLOG_LOGICAL_CORRUPTION</a>.\n     */\n    er_binlog_logical_corruption = 1866,\n\n    /**\n     * \\brief Common server error. Error number: 1867, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_purge_log_in_use\">ER_WARN_PURGE_LOG_IN_USE</a>.\n     */\n    er_warn_purge_log_in_use = 1867,\n\n    /**\n     * \\brief Common server error. Error number: 1868, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_warn_purge_log_is_active\">ER_WARN_PURGE_LOG_IS_ACTIVE</a>.\n     */\n    er_warn_purge_log_is_active = 1868,\n\n    /**\n     * \\brief Common server error. Error number: 1869, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_auto_increment_conflict\">ER_AUTO_INCREMENT_CONFLICT</a>.\n     */\n    er_auto_increment_conflict = 1869,\n\n    /**\n     * \\brief Common server error. Error number: 1870, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_warn_on_blockhole_in_rbr\">WARN_ON_BLOCKHOLE_IN_RBR</a>.\n     */\n    warn_on_blockhole_in_rbr = 1870,\n\n    /**\n     * \\brief Common server error. Error number: 1871, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_mi_init_repository\">ER_SLAVE_MI_INIT_REPOSITORY</a>.\n     */\n    er_slave_mi_init_repository = 1871,\n\n    /**\n     * \\brief Common server error. Error number: 1872, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_slave_rli_init_repository\">ER_SLAVE_RLI_INIT_REPOSITORY</a>.\n     */\n    er_slave_rli_init_repository = 1872,\n\n    /**\n     * \\brief Common server error. Error number: 1873, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_access_denied_change_user_error\">ER_ACCESS_DENIED_CHANGE_USER_ERROR</a>.\n     */\n    er_access_denied_change_user_error = 1873,\n\n    /**\n     * \\brief Common server error. Error number: 1874, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_read_only\">ER_INNODB_READ_ONLY</a>.\n     */\n    er_innodb_read_only = 1874,\n\n    /**\n     * \\brief Common server error. Error number: 1875, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stop_slave_sql_thread_timeout\">ER_STOP_SLAVE_SQL_THREAD_TIMEOUT</a>.\n     */\n    er_stop_slave_sql_thread_timeout = 1875,\n\n    /**\n     * \\brief Common server error. Error number: 1876, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_stop_slave_io_thread_timeout\">ER_STOP_SLAVE_IO_THREAD_TIMEOUT</a>.\n     */\n    er_stop_slave_io_thread_timeout = 1876,\n\n    /**\n     * \\brief Common server error. Error number: 1877, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_table_corrupt\">ER_TABLE_CORRUPT</a>.\n     */\n    er_table_corrupt = 1877,\n\n    /**\n     * \\brief Common server error. Error number: 1878, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_temp_file_write_failure\">ER_TEMP_FILE_WRITE_FAILURE</a>.\n     */\n    er_temp_file_write_failure = 1878,\n\n    /**\n     * \\brief Common server error. Error number: 1879, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_innodb_ft_aux_not_hex_id\">ER_INNODB_FT_AUX_NOT_HEX_ID</a>.\n     */\n    er_innodb_ft_aux_not_hex_id = 1879,\n\n};\n\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_common_server_category() noexcept;\n\n/// Creates an \\ref error_code from a \\ref common_server_errc.\ninline error_code make_error_code(common_server_errc error)\n{\n    return error_code(static_cast<int>(error), get_common_server_category());\n}\n\n}  // namespace mysql\n\n#ifndef BOOST_MYSQL_DOXYGEN\nnamespace system {\n\ntemplate <>\nstruct is_error_code_enum<::boost::mysql::common_server_errc>\n{\n    static constexpr bool value = true;\n};\n\n}  // namespace system\n#endif\n\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/error_categories.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/connect_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_CONNECT_PARAMS_HPP\n#define BOOST_MYSQL_CONNECT_PARAMS_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <cstdint>\n#include <string>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Parameters to be used with \\ref any_connection connect functions.\n * \\details\n * To be passed to \\ref any_connection::connect and \\ref any_connection::async_connect.\n * Includes the server address and MySQL handshake parameters. This is an owning type.\n */\nstruct connect_params\n{\n    /**\n     * \\brief Determines how to establish a physical connection to the MySQL server.\n     * \\details\n     * This can be either a host and port or a UNIX socket path.\n     * Defaults to (localhost, 3306).\n     */\n    any_address server_address;\n\n    /// User name to authenticate as.\n    std::string username;\n\n    /// Password for that username, possibly empty.\n    std::string password;\n\n    /// Database name to use, or empty string for no database (this is the default).\n    std::string database;\n\n    /**\n     * \\brief The ID of the collation to use for the connection.\n     * \\details Impacts how text queries and prepared statements are interpreted. Defaults to\n     * `utf8mb4_general_ci`, which is compatible with MySQL 5.x, 8.x and MariaDB.\n     */\n    std::uint16_t connection_collation{45};\n\n    /**\n     * \\brief Controls whether to use TLS or not.\n     * \\details\n     * See \\ref ssl_mode for more information about the possible modes.\n     * This option is only relevant when `server_address.type() == address_type::host_and_port`.\n     * UNIX socket connections will never use TLS, regardless of this value.\n     */\n    ssl_mode ssl{ssl_mode::enable};\n\n    /**\n     * \\brief Whether to enable support for executing semicolon-separated text queries.\n     * \\details Disabled by default.\n     */\n    bool multi_queries{false};\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_CONNECTION_HPP\n#define BOOST_MYSQL_CONNECTION_HPP\n\n#include <boost/mysql/buffer_params.hpp>\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/connection_impl.hpp>\n#include <boost/mysql/detail/engine_stream_adaptor.hpp>\n#include <boost/mysql/detail/execution_concepts.hpp>\n#include <boost/mysql/detail/rebind_executor.hpp>\n#include <boost/mysql/detail/socket_stream.hpp>\n#include <boost/mysql/detail/throw_on_error_loc.hpp>\n#include <boost/mysql/detail/writable_field_traits.hpp>\n\n#include <boost/assert.hpp>\n\n#include <cstddef>\n#include <type_traits>\n#include <utility>\n\n/// The Boost libraries namespace.\nnamespace boost {\n/// Boost.MySQL library namespace.\nnamespace mysql {\n\n// Forward declarations\ntemplate <class... StaticRow>\nclass static_execution_state;\n\n/**\n * \\brief (Legacy) A connection to a MySQL server.\n * \\details\n * Represents a templated connection to a MySQL server.\n *\n * `connection` owns a `Stream` object that\n * is accessed by functions involving network operations, as well as session state. You can access\n * the stream using \\ref connection::stream, and its executor via \\ref connection::get_executor. The\n * executor used by this object is always the same as the underlying stream.\n *\n * \\par Single outstanding async operation per connection\n * At any given point in time, only one async operation can be outstanding\n * per connection. If an async operation is initiated while another one is in progress,\n * it will fail with \\ref client_errc::operation_in_progress.\n *\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe. \\n\n * This class is <b>not thread-safe</b>: for a single object, if you\n * call its member functions concurrently from separate threads, you will get a race condition.\n *\n * \\par Legacy\n * New code should use \\ref any_connection instead of this class, as it's simpler to use\n * and provides the same level of performance.\n */\ntemplate <class Stream>\nclass connection\n{\n    detail::connection_impl impl_;\n\npublic:\n    /**\n     * \\brief Initializing constructor.\n     * \\details\n     * As part of the initialization, an internal `Stream` object is created.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Throws if the `Stream` constructor throws\n     * or if memory allocation for internal state fails.\n     *\n     * \\param args Arguments to be forwarded to the `Stream` constructor.\n     */\n    template <\n        class... Args,\n        class EnableIf = typename std::enable_if<std::is_constructible<Stream, Args...>::value>::type>\n    connection(Args&&... args) : connection(buffer_params(), std::forward<Args>(args)...)\n    {\n    }\n\n    /**\n     * \\brief Initializing constructor with buffer params.\n     * \\details\n     * As part of the initialization, an internal `Stream` object is created.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Throws if the `Stream` constructor throws\n     * or if memory allocation for internal state fails.\n     *\n     * \\param buff_params Specifies initial sizes for internal buffers.\n     * \\param args Arguments to be forwarded to the `Stream` constructor.\n     */\n    template <\n        class... Args,\n        class EnableIf = typename std::enable_if<std::is_constructible<Stream, Args...>::value>::type>\n    connection(const buffer_params& buff_params, Args&&... args)\n        : impl_(\n              buff_params.initial_read_size(),\n              static_cast<std::size_t>(-1),\n              detail::make_engine<Stream>(std::forward<Args>(args)...)\n          )\n    {\n    }\n\n    /**\n     * \\brief Move constructor.\n     */\n    connection(connection&& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     */\n    connection& operator=(connection&& rhs) = default;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    connection(const connection&) = delete;\n    connection& operator=(const connection&) = delete;\n#endif\n\n    /// The executor type associated to this object.\n    using executor_type = typename Stream::executor_type;\n\n    /// Retrieves the executor associated to this object.\n    executor_type get_executor() { return stream().get_executor(); }\n\n    /// The `Stream` type this connection is using.\n    using stream_type = Stream;\n\n    /**\n     * \\brief Retrieves the underlying Stream object.\n     * \\details\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    Stream& stream() noexcept { return detail::stream_from_engine<Stream>(impl_.get_engine()); }\n\n    /**\n     * \\brief Retrieves the underlying Stream object.\n     * \\details\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    const Stream& stream() const noexcept { return detail::stream_from_engine<Stream>(impl_.get_engine()); }\n\n    /**\n     * \\brief Returns whether the connection negotiated the use of SSL or not.\n     * \\details\n     * This function can be used to determine whether you are using a SSL\n     * connection or not when using SSL negotiation.\n     * \\n\n     * This function always returns `false` if the underlying\n     * stream does not support SSL. This function always returns `false`\n     * for connections that haven't been\n     * established yet (handshake not run yet). If the handshake fails,\n     * the return value is undefined.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\returns Whether the connection is using SSL.\n     */\n    bool uses_ssl() const noexcept { return impl_.ssl_active(); }\n\n    /// \\copydoc any_connection::meta_mode\n    metadata_mode meta_mode() const noexcept { return impl_.meta_mode(); }\n\n    /// \\copydoc any_connection::set_meta_mode\n    void set_meta_mode(metadata_mode v) noexcept { impl_.set_meta_mode(v); }\n\n    /**\n     * \\brief Establishes a connection to a MySQL server.\n     * \\details\n     * This function is only available if `Stream` satisfies the\n     * `SocketStream` concept.\n     * \\n\n     * Connects the underlying stream and performs the handshake\n     * with the server. The underlying stream is closed in case of error. Prefer\n     * this function to \\ref connection::handshake.\n     * \\n\n     * If using a SSL-capable stream, the SSL handshake will be performed by this function.\n     * \\n\n     * `endpoint` should be convertible to `Stream::lowest_layer_type::endpoint_type`.\n     */\n    template <typename EndpointType>\n    void connect(\n        const EndpointType& endpoint,\n        const handshake_params& params,\n        error_code& ec,\n        diagnostics& diag\n    )\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"connect can only be used if Stream satisfies the SocketStream concept\"\n        );\n        impl_.connect<typename Stream::lowest_layer_type::endpoint_type>(endpoint, params, ec, diag);\n    }\n\n    /// \\copydoc connect\n    template <typename EndpointType>\n    void connect(const EndpointType& endpoint, const handshake_params& params)\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"connect can only be used if Stream satisfies the SocketStream concept\"\n        );\n        error_code err;\n        diagnostics diag;\n        connect(endpoint, params, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc connect\n     * \\par Object lifetimes\n     * The strings pointed to by `params` should be kept alive by the caller\n     * until the operation completes, as no copy is made by the library.\n     * `endpoint` is copied as required and doesn't need to be kept alive.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <\n        typename EndpointType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))\n    async_connect(\n        const EndpointType& endpoint,\n        const handshake_params& params,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    )\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"async_connect can only be used if Stream satisfies the SocketStream concept\"\n        );\n        return async_connect(endpoint, params, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_connect\n    template <\n        typename EndpointType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))\n    async_connect(\n        const EndpointType& endpoint,\n        const handshake_params& params,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    )\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"async_connect can only be used if Stream satisfies the SocketStream concept\"\n        );\n        return impl_.async_connect<typename Stream::lowest_layer_type::endpoint_type>(\n            endpoint,\n            params,\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /**\n     * \\brief Performs the MySQL-level handshake.\n     * \\details\n     * Does not connect the underlying stream.\n     * If the `Stream` template parameter fulfills the `SocketConnection`\n     * requirements, use \\ref connection::connect instead of this function.\n     * \\n\n     * If using a SSL-capable stream, the SSL handshake will be performed by this function.\n     */\n    void handshake(const handshake_params& params, error_code& ec, diagnostics& diag)\n    {\n        impl_.run(impl_.make_params_handshake(params), ec, diag);\n    }\n\n    /// \\copydoc handshake\n    void handshake(const handshake_params& params)\n    {\n        error_code err;\n        diagnostics diag;\n        handshake(params, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc handshake\n     * \\par Object lifetimes\n     * The strings pointed to by `params` should be kept alive by the caller\n     * until the operation completes, as no copy is made by the library.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_handshake(\n        const handshake_params& params,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_handshake_t<CompletionToken&&>)\n    {\n        return async_handshake(params, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_handshake\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_handshake(\n        const handshake_params& params,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_handshake_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_handshake(params), diag, std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc any_connection::execute\n    template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>\n    void execute(ExecutionRequest&& req, ResultsType& result, error_code& err, diagnostics& diag)\n    {\n        impl_.execute(std::forward<ExecutionRequest>(req), result, err, diag);\n    }\n\n    /// \\copydoc execute\n    template <BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest, BOOST_MYSQL_RESULTS_TYPE ResultsType>\n    void execute(ExecutionRequest&& req, ResultsType& result)\n    {\n        error_code err;\n        diagnostics diag;\n        execute(std::forward<ExecutionRequest>(req), result, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /// \\copydoc any_connection::async_execute\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_RESULTS_TYPE ResultsType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_execute(\n        ExecutionRequest&& req,\n        ResultsType& result,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)\n    {\n        return async_execute(\n            std::forward<ExecutionRequest>(req),\n            result,\n            impl_.shared_diag(),\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc async_execute\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_RESULTS_TYPE ResultsType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_execute(\n        ExecutionRequest&& req,\n        ResultsType& result,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_execute_t<ExecutionRequest&&, ResultsType, CompletionToken&&>)\n    {\n        return impl_.async_execute(\n            std::forward<ExecutionRequest>(req),\n            result,\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc any_connection::start_execution\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void start_execution(ExecutionRequest&& req, ExecutionStateType& st, error_code& err, diagnostics& diag)\n    {\n        impl_.start_execution(std::forward<ExecutionRequest>(req), st, err, diag);\n    }\n\n    /// \\copydoc start_execution\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void start_execution(ExecutionRequest&& req, ExecutionStateType& st)\n    {\n        error_code err;\n        diagnostics diag;\n        start_execution(std::forward<ExecutionRequest>(req), st, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /// \\copydoc any_connection::async_start_execution\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_start_execution(\n        ExecutionRequest&& req,\n        ExecutionStateType& st,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    )\n        BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<\n                                ExecutionRequest&&,\n                                ExecutionStateType,\n                                CompletionToken&&>)\n    {\n        return async_start_execution(\n            std::forward<ExecutionRequest>(req),\n            st,\n            impl_.shared_diag(),\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc async_start_execution\n    template <\n        BOOST_MYSQL_EXECUTION_REQUEST ExecutionRequest,\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_start_execution(\n        ExecutionRequest&& req,\n        ExecutionStateType& st,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    )\n        BOOST_MYSQL_RETURN_TYPE(detail::async_start_execution_t<\n                                ExecutionRequest&&,\n                                ExecutionStateType,\n                                CompletionToken&&>)\n    {\n        return impl_.async_start_execution(\n            std::forward<ExecutionRequest>(req),\n            st,\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc any_connection::prepare_statement\n    statement prepare_statement(string_view stmt, error_code& err, diagnostics& diag)\n    {\n        return impl_.run(detail::prepare_statement_algo_params{stmt}, err, diag);\n    }\n\n    /// \\copydoc prepare_statement\n    statement prepare_statement(string_view stmt)\n    {\n        error_code err;\n        diagnostics diag;\n        statement res = prepare_statement(stmt, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n        return res;\n    }\n\n    /// \\copydoc any_connection::async_prepare_statement\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_prepare_statement(\n        string_view stmt,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)\n    {\n        return async_prepare_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_prepare_statement\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::statement))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_prepare_statement(\n        string_view stmt,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_prepare_statement_t<CompletionToken&&>)\n    {\n        return impl_.async_run(\n            detail::prepare_statement_algo_params{stmt},\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n\n    /// \\copydoc any_connection::close_statement\n    void close_statement(const statement& stmt, error_code& err, diagnostics& diag)\n    {\n        impl_.run(impl_.make_params_close_statement(stmt), err, diag);\n    }\n\n    /// \\copydoc close_statement\n    void close_statement(const statement& stmt)\n    {\n        error_code err;\n        diagnostics diag;\n        close_statement(stmt, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /// \\copydoc any_connection::async_close_statement\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_close_statement(\n        const statement& stmt,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)\n    {\n        return async_close_statement(stmt, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_close_statement\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_close_statement(\n        const statement& stmt,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_close_statement_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_close_statement(stmt), diag, std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc any_connection::read_some_rows\n    rows_view read_some_rows(execution_state& st, error_code& err, diagnostics& diag)\n    {\n        return impl_.run(impl_.make_params_read_some_rows(st), err, diag);\n    }\n\n    /// \\copydoc read_some_rows(execution_state&,error_code&,diagnostics&)\n    rows_view read_some_rows(execution_state& st)\n    {\n        error_code err;\n        diagnostics diag;\n        rows_view res = read_some_rows(st, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n        return res;\n    }\n\n    /// \\copydoc any_connection::async_read_some_rows(execution_state&,CompletionToken&&)\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_read_some_rows(\n        execution_state& st,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)\n    {\n        return async_read_some_rows(st, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_read_some_rows(execution_state&,CompletionToken&&)\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::rows_view))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_read_some_rows(\n        execution_state& st,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_some_rows_dynamic_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_read_some_rows(st), diag, std::forward<CompletionToken>(token));\n    }\n\n#ifdef BOOST_MYSQL_CXX14\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s\n     * constructor, using \\ref buffer_params::initial_read_size. The buffer may be\n     * grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     */\n    template <class SpanElementType, class... StaticRow>\n    std::size_t read_some_rows(\n        static_execution_state<StaticRow...>& st,\n        span<SpanElementType> output,\n        error_code& err,\n        diagnostics& diag\n    )\n    {\n        return impl_.run(impl_.make_params_read_some_rows_static(st, output), err, diag);\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s\n     * constructor, using \\ref buffer_params::initial_read_size. The buffer may be\n     * grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     */\n    template <class SpanElementType, class... StaticRow>\n    std::size_t read_some_rows(static_execution_state<StaticRow...>& st, span<SpanElementType> output)\n    {\n        error_code err;\n        diagnostics diag;\n        std::size_t res = read_some_rows(st, output, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n        return res;\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s\n     * constructor, using \\ref buffer_params::initial_read_size. The buffer may be\n     * grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code, std::size_t)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     *\n     * \\par Object lifetimes\n     * The storage that `output` references must be kept alive until the operation completes.\n     */\n    template <\n        class SpanElementType,\n        class... StaticRow,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::size_t))\n    async_read_some_rows(\n        static_execution_state<StaticRow...>& st,\n        span<SpanElementType> output,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    )\n    {\n        return async_read_some_rows(st, output, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Reads a batch of rows.\n     * \\details\n     * Reads a batch of rows of unspecified size into the storage given by `output`.\n     * At most `output.size()` rows will be read. If the operation represented by `st`\n     * has still rows to read, and `output.size() > 0`, at least one row will be read.\n     * \\n\n     * Returns the number of read rows.\n     * \\n\n     * If there are no more rows, or `st.should_read_rows() == false`, this function is a no-op and returns\n     * zero.\n     * \\n\n     * The number of rows that will be read depends on the connection's buffer size. The bigger the buffer,\n     * the greater the batch size (up to a maximum). You can set the initial buffer size in `connection`'s\n     * constructor, using \\ref buffer_params::initial_read_size. The buffer may be\n     * grown bigger by other read operations, if required.\n     * \\n\n     * Rows read by this function are owning objects, and don't hold any reference to\n     * the connection's internal buffers (contrary what happens with the dynamic interface's counterpart).\n     * \\n\n     * The type `SpanElementType` must be the underlying row type for one of the types in the\n     * `StaticRow` parameter pack (i.e., one of the types in `underlying_row_t<StaticRow>...`).\n     * The type must match the resultset that is currently being processed by `st`. For instance,\n     * given `static_execution_state<T1, T2>`, when reading rows for the second resultset, `SpanElementType`\n     * must exactly be `underlying_row_t<T2>`. If this is not the case, a runtime error will be issued.\n     * \\n\n     * This function can report schema mismatches.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code, std::size_t)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     *\n     * \\par Object lifetimes\n     * The storage that `output` references must be kept alive until the operation completes.\n     */\n    template <\n        class SpanElementType,\n        class... StaticRow,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, std::size_t))\n    async_read_some_rows(\n        static_execution_state<StaticRow...>& st,\n        span<SpanElementType> output,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    )\n    {\n        return impl_.async_run(\n            impl_.make_params_read_some_rows_static(st, output),\n            diag,\n            std::forward<CompletionToken>(token)\n        );\n    }\n#endif\n\n    /// \\copydoc any_connection::read_resultset_head\n    template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void read_resultset_head(ExecutionStateType& st, error_code& err, diagnostics& diag)\n    {\n        return impl_.run(impl_.make_params_read_resultset_head(st), err, diag);\n    }\n\n    /// \\copydoc read_resultset_head\n    template <BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType>\n    void read_resultset_head(ExecutionStateType& st)\n    {\n        error_code err;\n        diagnostics diag;\n        read_resultset_head(st, err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /// \\copydoc any_connection::async_read_resultset_head\n    template <\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_read_resultset_head(\n        ExecutionStateType& st,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)\n    {\n        return async_read_resultset_head(st, impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_read_resultset_head\n    template <\n        BOOST_MYSQL_EXECUTION_STATE_TYPE ExecutionStateType,\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_read_resultset_head(\n        ExecutionStateType& st,\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_read_resultset_head_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(impl_.make_params_read_resultset_head(st), diag, std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc any_connection::ping\n    void ping(error_code& err, diagnostics& diag) { impl_.run(detail::ping_algo_params{}, err, diag); }\n\n    /// \\copydoc ping\n    void ping()\n    {\n        error_code err;\n        diagnostics diag;\n        ping(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /// \\copydoc any_connection::async_ping\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_ping(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))\n        BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)\n    {\n        return async_ping(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_ping\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_ping(\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_ping_t<CompletionToken&&>)\n    {\n        return impl_.async_run(detail::ping_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Resets server-side session state, like variables and prepared statements.\n     * \\details\n     * Resets all server-side state for the current session:\n     * \\n\n     *   \\li Rolls back any active transactions and resets autocommit mode.\n     *   \\li Releases all table locks.\n     *   \\li Drops all temporary tables.\n     *   \\li Resets all session system variables to their default values (including the ones set by `SET\n     *       NAMES`) and clears all user-defined variables.\n     *   \\li Closes all prepared statements.\n     * \\n\n     * A full reference on the affected session state can be found\n     * <a href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-reset-connection.html\">here</a>.\n     * \\n\n     * This function will not reset the current physical connection and won't cause re-authentication.\n     * It is faster than closing and re-opening a connection.\n     * \\n\n     * The connection must be connected and authenticated before calling this function.\n     * This function involves communication with the server, and thus may fail.\n     *\n     * \\par Warning on character sets\n     * This function will restore the connection's character set and collation **to the server's default**,\n     * and not to the one specified during connection establishment. Some servers have `latin1` as their\n     * default character set, which is not usually what you want. Use a `SET NAMES` statement after using\n     * this function to be sure.\n     * \\n\n     * You can find the character set that your server will use after reset by running:\n     * \\code\n     * \"SELECT @@global.character_set_client, @@global.character_set_results;\"\n     * \\endcode\n     */\n    void reset_connection(error_code& err, diagnostics& diag)\n    {\n        impl_.run(detail::reset_connection_algo_params{}, err, diag);\n    }\n\n    /// \\copydoc reset_connection\n    void reset_connection()\n    {\n        error_code err;\n        diagnostics diag;\n        reset_connection(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc reset_connection\n     * \\details\n     * \\n\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_reset_connection(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))\n        BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)\n    {\n        return async_reset_connection(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_reset_connection\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_reset_connection(\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_reset_connection_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(detail::reset_connection_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Closes the connection to the server.\n     * \\details\n     * This function is only available if `Stream` satisfies the `SocketStream` concept.\n     * \\n\n     * Sends a quit request, performs the TLS shutdown (if required)\n     * and closes the underlying stream. Prefer this function to \\ref connection::quit.\n     * \\n\n     */\n    void close(error_code& err, diagnostics& diag)\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"close can only be used if Stream satisfies the SocketStream concept\"\n        );\n        impl_.run(detail::close_connection_algo_params{}, err, diag);\n    }\n\n    /// \\copydoc close\n    void close()\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"close can only be used if Stream satisfies the SocketStream concept\"\n        );\n        error_code err;\n        diagnostics diag;\n        close(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc close\n     * \\details\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_close(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))\n        BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"async_close can only be used if Stream satisfies the SocketStream concept\"\n        );\n        return async_close(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_close\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_close(\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_close_connection_t<CompletionToken&&>)\n    {\n        static_assert(\n            detail::is_socket_stream<Stream>::value,\n            \"async_close can only be used if Stream satisfies the SocketStream concept\"\n        );\n        return impl_\n            .async_run(detail::close_connection_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Notifies the MySQL server that the client wants to end the session and shutdowns SSL.\n     * \\details Sends a quit request to the MySQL server. If the connection is using SSL,\n     * this function will also perform the SSL shutdown. You should\n     * close the underlying physical connection after calling this function.\n     * \\n\n     * If the `Stream` template parameter fulfills the `SocketConnection`\n     * requirements, use \\ref connection::close instead of this function,\n     * as it also takes care of closing the underlying stream.\n     */\n    void quit(error_code& err, diagnostics& diag)\n    {\n        impl_.run(detail::quit_connection_algo_params{}, err, diag);\n    }\n\n    /// \\copydoc quit\n    void quit()\n    {\n        error_code err;\n        diagnostics diag;\n        quit(err, diag);\n        detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);\n    }\n\n    /**\n     * \\copydoc quit\n     * \\details\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`.\n     *\n     * \\par Executor\n     * Intermediate completion handlers, as well as the final handler, are executed using\n     * `token`'s associated executor, or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     */\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_quit(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))\n        BOOST_MYSQL_RETURN_TYPE(detail::async_quit_connection_t<CompletionToken&&>)\n    {\n        return async_quit(impl_.shared_diag(), std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_quit\n    template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n                  CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>\n    auto async_quit(\n        diagnostics& diag,\n        CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)\n    ) BOOST_MYSQL_RETURN_TYPE(detail::async_quit_connection_t<CompletionToken&&>)\n    {\n        return impl_\n            .async_run(detail::quit_connection_algo_params{}, diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Rebinds the connection type to another executor.\n     * \\details\n     * The `Stream` type must either provide a `rebind_executor`\n     * member with the same semantics, or be an instantiation of `boost::asio::ssl::stream` with\n     * a `Stream` type providing a `rebind_executor` member.\n     */\n    template <typename Executor1>\n    struct rebind_executor\n    {\n        /// The connection type when rebound to the specified executor.\n        using other = connection<typename detail::rebind_executor<Stream, Executor1>::type>;\n    };\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/connection_pool.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_CONNECTION_POOL_HPP\n#define BOOST_MYSQL_CONNECTION_POOL_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/connection_pool_fwd.hpp>\n#include <boost/mysql/detail/initiation_base.hpp>\n\n#include <boost/asio/any_completion_handler.hpp>\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/async_result.hpp>\n\n#include <chrono>\n#include <memory>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A proxy to a connection owned by a pool that returns it to the pool when destroyed.\n * \\details\n * A `pooled_connection` behaves like to a `std::unique_ptr`: it has exclusive ownership of an\n * \\ref any_connection created by the pool. When destroyed, it returns the connection to the pool.\n * A `pooled_connection` may own nothing. We say such a connection is invalid (`this->valid() == false`).\n *\n * This class is movable but not copyable.\n *\n * \\par Object lifetimes\n * While `*this` is alive, the \\ref connection_pool internal data will be kept alive\n * automatically. It's safe to destroy the `connection_pool` object before `*this`.\n *\n * \\par Thread safety\n * This object and the \\ref any_connection object it may point to are **not thread safe**,\n * even if the connection pool used to obtain them was constructed with\n * \\ref pool_params::thread_safe set to true.\n *\n * Functions that return the underlying connection to the pool\n * cause a mutation on the pool state object. Calling such functions\n * on objects obtained from the same pool\n * is thread-safe only if the pool was constructed with \\ref pool_params::thread_safe set to true.\n *\n * In other words, individual connections can't be shared between threads. Pools can\n * be shared only if they're constructed with \\ref pool_params::thread_safe set to true.\n *\n * - Distinct objects: safe if the \\ref connection_pool that was used to obtain the objects\n *   was created with \\ref pool_params::thread_safe set to true. Otherwise, unsafe.\n * - Shared objects: always unsafe.\n */\nclass pooled_connection\n{\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n    friend class detail::basic_pool_impl<any_connection, std::chrono::steady_clock, pooled_connection>;\n#endif\n\n    struct impl_t\n    {\n        detail::connection_node* node;\n        std::shared_ptr<detail::pool_impl> pool;\n    } impl_{};\n\n    pooled_connection(detail::connection_node& node, std::shared_ptr<detail::pool_impl> pool_impl) noexcept\n        : impl_{&node, std::move(pool_impl)}\n    {\n        BOOST_ASSERT(impl_.pool);\n    }\n\npublic:\n    /**\n     * \\brief Constructs an invalid pooled connection.\n     * \\details\n     * The resulting object is invalid (`this->valid() == false`).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    pooled_connection() noexcept = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\details\n     * Transfers connection ownership from `other` to `*this`.\n     *\n     * After this function returns, if `other.valid() == true`, `this->valid() == true`.\n     * In any case, `other` will become invalid (`other.valid() == false`).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    pooled_connection(pooled_connection&& other) noexcept : impl_(std::move(other.impl_)) {}\n\n    /**\n     * \\brief Move assignment.\n     * \\details\n     * If `this->valid()`, returns the connection owned by `*this` to the pool and marks\n     * it as pending reset (as if the destructor was called).\n     * It then transfers connection ownership from `other` to `*this`.\n     *\n     * After this function returns, if `other.valid() == true`, `this->valid() == true`.\n     * In any case, `other` will become invalid (`other.valid() == false`).\n     *\n     * \\par Thread-safety\n     * May cause a mutation on the connection pool that `this` points to.\n     * Thread-safe for a shared pool only if it was constructed with\n     * \\ref pool_params::thread_safe set to true.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    pooled_connection& operator=(pooled_connection&& other) noexcept\n    {\n        if (valid())\n        {\n            detail::return_connection(*impl_.pool, *impl_.node, true);\n        }\n        impl_ = std::move(other.impl_);\n        return *this;\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    pooled_connection(const pooled_connection&) = delete;\n    pooled_connection& operator=(const pooled_connection&) = delete;\n#endif\n\n    /**\n     * \\brief Destructor.\n     * \\details\n     * If `this->valid() == true`, returns the owned connection to the pool\n     * and marks it as pending reset. If your connection doesn't need to be reset\n     * (e.g. because you didn't mutate session state), use \\ref return_without_reset.\n     *\n     * \\par Thread-safety\n     * May cause a mutation on the connection pool that `this` points to.\n     * Thread-safe for a shared pool only if it was constructed with\n     * \\ref pool_params::thread_safe set to true.\n     */\n    ~pooled_connection()\n    {\n        if (valid())\n            detail::return_connection(*impl_.pool, *impl_.node, true);\n    }\n\n    /**\n     * \\brief Returns whether the object owns a connection or not.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool valid() const noexcept { return impl_.pool.get() != nullptr; }\n\n    /**\n     * \\brief Retrieves the connection owned by this object.\n     * \\par Preconditions\n     * The object should own a connection (`this->valid() == true`).\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` or an object\n     * move-constructed or move-assigned from `*this` is alive.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    any_connection& get() noexcept { return detail::get_connection(*impl_.node); }\n\n    /// \\copydoc get\n    const any_connection& get() const noexcept { return detail::get_connection(*impl_.node); }\n\n    /// \\copydoc get\n    any_connection* operator->() noexcept { return &get(); }\n\n    /// \\copydoc get\n    const any_connection* operator->() const noexcept { return &get(); }\n\n    /**\n     * \\brief Returns the owned connection to the pool and marks it as not requiring reset.\n     * \\details\n     * Returns a connection to the pool and marks it as idle. This will\n     * skip the \\ref any_connection::async_reset_connection call to wipe session state.\n     * \\n\n     * This can provide a performance gain, but must be used with care. Failing to wipe\n     * session state can lead to resource leaks (prepared statements not being released),\n     * incorrect results and vulnerabilities (different logical operations interacting due\n     * to leftover state).\n     * \\n\n     * Please read the documentation on \\ref any_connection::async_reset_connection before\n     * calling this function. If in doubt, don't use it, and leave the destructor return\n     * the connection to the pool for you.\n     * \\n\n     * When this function returns, `*this` will own nothing (`this->valid() == false`).\n     *\n     * \\par Preconditions\n     * `this->valid() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Thread-safety\n     * Causes a mutation on the connection pool that `this` points to.\n     * Thread-safe for a shared pool only if it was constructed with\n     * \\ref pool_params::thread_safe set to true.\n     */\n    void return_without_reset() noexcept\n    {\n        BOOST_ASSERT(valid());\n        detail::return_connection(*impl_.pool, *impl_.node, false);\n        impl_ = impl_t{};\n    }\n};\n\n/**\n * \\brief A pool of connections of variable size.\n * \\details\n * A connection pool creates and manages \\ref any_connection objects.\n * Using a pool allows to reuse sessions, avoiding part of the overhead associated\n * to session establishment. It also features built-in error handling and reconnection.\n * See the discussion and examples for more details on when to use this class.\n *\n * Connections are retrieved by \\ref async_get_connection, which yields a\n * \\ref pooled_connection object. They are returned to the pool when the\n * `pooled_connection` is destroyed, or by calling \\ref pooled_connection::return_without_reset.\n *\n * A pool needs to be run before it can return any connection. Use \\ref async_run for this.\n * Pools can only be run once.\n *\n * Connections are created, connected and managed internally by the pool, following\n * a well-defined state model. Please refer to the discussion for details.\n *\n * Due to oddities in Boost.Asio's universal async model, this class only\n * exposes async functions. You can use `asio::use_future` to transform them\n * into sync functions (please read the discussion for details).\n *\n * This is a move-only type.\n *\n * \\par Default completion tokens\n * The default completion token for all async operations in this class is\n * `with_diagnostics(asio::deferred)`, which allows you to use `co_await`\n * and have the expected exceptions thrown on error.\n *\n * \\par Thread-safety\n * Pools are composed of an internal state object, plus a handle to such state.\n * Each component has different thread-safety rules.\n *\n * Regarding **internal state**, connection pools are **not thread-safe by default**,\n * but can be made safe by constructing them with\n * \\ref pool_params::thread_safe set to `true`.\n * Internal state is also mutated by some functions outside `connection_pool`, like\n * returning connections.\n *\n * The following actions imply a pool state mutation, and are protected by a strand\n * when thread-safety is enabled:\n *\n * - Calling \\ref connection_pool::async_run.\n * - Calling \\ref connection_pool::async_get_connection.\n * - Cancelling \\ref async_get_connection by emitting a cancellation signal.\n * - Returning a connection by destroying a \\ref pooled_connection or\n *   calling \\ref pooled_connection::return_without_reset.\n * - Cancelling the pool by calling \\ref connection_pool::cancel,\n *   emitting a cancellation signal for \\ref async_run, or destroying the\n *   `connection_pool` object.\n *\n * The **handle to the pool state** is **never thread-safe**, even for\n * pools with thread-safety enabled. Functions like assignments\n * modify the handle, and cause race conditions if called\n * concurrently with other functions. Other objects,\n * like \\ref pooled_connection, have their own state handle,\n * and thus interact only with the pool state.\n *\n * If configured to be thread-safe, the protection applies only to the pool's state.\n * In particular, be careful when using `asio::cancel_after` and similar tokens.\n * Please read\n * <a href=\"../connection_pool.html#mysql.connection_pool.thread_safe\">this page</a> for more info.\n *\n * In summary:\n *\n * - Distinct objects: safe. \\n\n * - Shared objects: unsafe. Setting \\ref pool_params::thread_safe\n *   to `true` makes some functions safe.\n *\n * \\par Object lifetimes\n * Connection pool objects create an internal state object that is referenced\n * by other objects and operations (like \\ref pooled_connection). This object\n * will be kept alive using shared ownership semantics even after the `connection_pool`\n * object is destroyed. This results in intuitive lifetime rules.\n */\nclass connection_pool\n{\n    std::shared_ptr<detail::pool_impl> impl_;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n\n    struct initiate_run : detail::initiation_base\n    {\n        using detail::initiation_base::initiation_base;\n\n        // Having diagnostics* here makes async_run compatible with with_diagnostics\n        template <class Handler>\n        void operator()(Handler&& h, diagnostics*, std::shared_ptr<detail::pool_impl> self)\n        {\n            async_run_erased(std::move(self), std::forward<Handler>(h));\n        }\n    };\n\n    BOOST_MYSQL_DECL\n    static void async_run_erased(\n        std::shared_ptr<detail::pool_impl> pool,\n        asio::any_completion_handler<void(error_code)> handler\n    );\n\n    struct initiate_get_connection : detail::initiation_base\n    {\n        using detail::initiation_base::initiation_base;\n\n        template <class Handler>\n        void operator()(Handler&& h, diagnostics* diag, std::shared_ptr<detail::pool_impl> self)\n        {\n            async_get_connection_erased(std::move(self), diag, std::forward<Handler>(h));\n        }\n    };\n\n    BOOST_MYSQL_DECL\n    static void async_get_connection_erased(\n        std::shared_ptr<detail::pool_impl> pool,\n        diagnostics* diag,\n        asio::any_completion_handler<void(error_code, pooled_connection)> handler\n    );\n\n    template <class CompletionToken>\n    auto async_get_connection_impl(diagnostics* diag, CompletionToken&& token)\n        -> decltype(asio::async_initiate<CompletionToken, void(error_code, pooled_connection)>(\n            std::declval<initiate_get_connection>(),\n            token,\n            diag,\n            impl_\n        ))\n    {\n        BOOST_ASSERT(valid());\n        return asio::async_initiate<CompletionToken, void(error_code, pooled_connection)>(\n            initiate_get_connection{get_executor()},\n            token,\n            diag,\n            impl_\n        );\n    }\n\n    BOOST_MYSQL_DECL\n    connection_pool(asio::any_io_executor ex, pool_params&& params, int);\n\npublic:\n    /**\n     * \\brief Constructs a connection pool.\n     * \\details\n     *\n     * The pool is created in a \"not-running\" state. Call \\ref async_run to transition to the\n     * \"running\" state.\n     *\n     * The constructed pool is always valid (`this->valid() == true`).\n     *\n     * \\par Executor\n     * The passed executor becomes the pool executor, available through \\ref get_executor.\n     * `ex` is used as follows:\n     *\n     *   - If `params.thread_safe == true`, `ex` is used to build a strand. The strand is used\n     *     to build internal I/O objects, like timers.\n     *   - If `params.thread_safe == false`, `ex` is used directly to build internal I/O objects.\n     *   - If `params.connection_executor` is empty, `ex` is used to build individual connections,\n     *     regardless of the chosen thread-safety mode. Otherwise, `params.connection_executor`\n     *     is used.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Exceptions may be thrown by memory allocations.\n     * \\throws std::invalid_argument If `params` contains values that violate the rules described in \\ref\n     *         pool_params.\n     */\n    connection_pool(asio::any_io_executor ex, pool_params params)\n        : connection_pool(std::move(ex), std::move(params), 0)\n    {\n    }\n\n    /**\n     * \\brief Constructs a connection pool.\n     * \\details\n     * Equivalent to `connection_pool(ctx.get_executor(), params)`.\n     *\n     * This function participates in overload resolution only if `ExecutionContext`\n     * satisfies the `ExecutionContext` requirements imposed by Boost.Asio.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Exceptions may be thrown by memory allocations.\n     * \\throws std::invalid_argument If `params` contains values that violate the rules described in \\ref\n     *         pool_params.\n     */\n    template <\n        class ExecutionContext\n#ifndef BOOST_MYSQL_DOXYGEN\n        ,\n        class = typename std::enable_if<std::is_convertible<\n            decltype(std::declval<ExecutionContext&>().get_executor()),\n            asio::any_io_executor>::value>::type\n#endif\n        >\n    connection_pool(ExecutionContext& ctx, pool_params params)\n        : connection_pool(ctx.get_executor(), std::move(params), 0)\n    {\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    connection_pool(const connection_pool&) = delete;\n    connection_pool& operator=(const connection_pool&) = delete;\n#endif\n\n    /**\n     * \\brief Move-constructor.\n     * \\details\n     * Constructs a connection pool by taking ownership of `other`.\n     *\n     * After this function returns, if `other.valid() == true`, `this->valid() == true`.\n     * In any case, `other` will become invalid (`other.valid() == false`).\n     *\n     * Moving a connection pool with outstanding async operations\n     * is safe.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Thread-safety\n     * Mutates `other`'s internal state handle. Does not access the pool state.\n     * This function **can never be called concurrently with other functions\n     * that read the internal state handle**, even for pools created\n     * with \\ref pool_params::thread_safe set to true.\n     *\n     * The internal pool state is not accessed, so this function can be called\n     * concurrently with functions that only access the pool's internal state,\n     * like returning connections.\n     */\n    connection_pool(connection_pool&& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\details\n     * Assigns `other` to `*this`, transferring ownership.\n     *\n     * After this function returns, if `other.valid() == true`, `this->valid() == true`.\n     * In any case, `other` will become invalid (`other.valid() == false`).\n     *\n     * Moving a connection pool with outstanding async operations\n     * is safe.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Thread-safety\n     * Mutates `*this` and `other`'s internal state handle. Does not access the pool state.\n     * This function **can never be called concurrently with other functions\n     * that read the internal state handle**, even for pools created\n     * with \\ref pool_params::thread_safe set to true.\n     *\n     * The internal pool state is not accessed, so this function can be called\n     * concurrently with functions that only access the pool's internal state,\n     * like returning connections.\n     */\n    connection_pool& operator=(connection_pool&& other) = default;\n\n    /**\n     * \\brief Destructor.\n     * \\details\n     * Cancels all outstanding async operations on `*this`, as per \\ref cancel.\n     *\n     * \\par Thread-safety\n     * Mutates the internal state handle. Mutates the pool state.\n     * This function **can never be called concurrently with other functions\n     * that read the internal state handle**, even for pools created\n     * with \\ref pool_params::thread_safe set to true.\n     *\n     * The internal pool state is modified as per \\ref cancel.\n     * If thread-safety is enabled, it's safe to call the destructor concurrently\n     * with functions that only access the pool's internal state,\n     * like returning connections.\n     */\n    ~connection_pool()\n    {\n        if (valid())\n            cancel();\n    }\n\n    /**\n     * \\brief Returns whether the object is in a moved-from state.\n     * \\details\n     * This function returns always `true` except for pools that have been\n     * moved-from. Moved-from objects don't represent valid pools. They can only\n     * be assigned to or destroyed.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Thread-safety\n     * Reads the internal state handle. Does not access the pool state.\n     * Can be called concurrently with any other function that reads the state handle,\n     * like \\ref async_run or \\ref async_get_connection.\n     * It can't be called concurrently with functions modifying the handle, like assignments,\n     * even if \\ref pool_params::thread_safe is set to true.\n     */\n    bool valid() const noexcept { return impl_.get() != nullptr; }\n\n    /// The executor type associated to this object.\n    using executor_type = asio::any_io_executor;\n\n    /**\n     * \\brief Retrieves the executor associated to this object.\n     * \\details\n     * Returns the executor used to construct the pool as first argument.\n     * This is the case even when using \\ref pool_params::thread_safe -\n     * the internal strand created in this case is never exposed.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Thread-safety\n     * Reads the internal state handle. Reads the pool state.\n     * If the pool was built with thread-safety enabled, it can be called\n     * concurrently with other functions that don't modify the state handle.\n     */\n    BOOST_MYSQL_DECL\n    executor_type get_executor() noexcept;\n\n    /**\n     * \\brief Runs the pool task in charge of managing connections.\n     * \\details\n     * This function creates and connects new connections, and resets and pings\n     * already created ones. You need to call this function for \\ref async_get_connection\n     * to succeed.\n     *\n     * The async operation will run indefinitely, until the pool is cancelled\n     * (by calling \\ref cancel or using per-operation cancellation on the `async_run` operation).\n     * The operation completes once all internal connection operations\n     * (including connects, pings and resets) complete.\n     *\n     * It is safe to call this function after calling \\ref cancel.\n     *\n     * \\par Preconditions\n     * This function can be called at most once for a single pool.\n     * Formally, `async_run` hasn't been called before on `*this` or any object\n     * used to move-construct or move-assign `*this`.\n     *\n     * Additionally, `this->valid() == true`.\n     *\n     * \\par Object lifetimes\n     * While the operation is outstanding, the pool's internal data will be kept alive.\n     * It is safe to destroy `*this` while the operation is outstanding.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is `void(boost::mysql::error_code)`\n     *\n     * \\par Executor\n     *\n     * The final handler is executed using `token`'s associated executor,\n     * or `this->get_executor()` if the token doesn't have an associated\n     * executor. The final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     *\n     * If the pool was constructed with thread-safety enabled, intermediate\n     * completion handlers are executed using an internal strand that wraps `this->get_executor()`.\n     * Otherwise, intermediate handlers are executed using `this->get_executor()`.\n     * In any case, the token's associated executor is only used for the final handler.\n     *\n     * \\par Per-operation cancellation\n     * This operation supports per-operation cancellation. Cancelling `async_run`\n     * is equivalent to calling \\ref connection_pool::cancel.\n     * The following `asio::cancellation_type_t` values are supported:\n     *\n     *   - `asio::cancellation_type_t::terminal`\n     *   - `asio::cancellation_type_t::partial`\n     *\n     * Note that `asio::cancellation_type_t::total` is not supported because invoking\n     * `async_run` always has observable side effects.\n     *\n     * \\par Errors\n     * This function always complete successfully. The handler signature ensures\n     * maximum compatibility with Boost.Asio infrastructure.\n     *\n     * \\par Thread-safety\n     * Reads the internal state handle. Mutates the pool state.\n     * If the pool was built with thread-safety enabled, it can be called\n     * concurrently with other functions that don't modify the state handle.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_run(CompletionToken&& token = {})\n        BOOST_MYSQL_RETURN_TYPE(decltype(asio::async_initiate<CompletionToken, void(error_code)>(\n            std::declval<initiate_run>(),\n            token,\n            static_cast<diagnostics*>(nullptr),\n            impl_\n        )))\n    {\n        BOOST_ASSERT(valid());\n        return asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_run{get_executor()},\n            token,\n            static_cast<diagnostics*>(nullptr),\n            impl_\n        );\n    }\n\n    /**\n     * \\brief Retrieves a connection from the pool.\n     * \\details\n     * Retrieves an idle connection from the pool to be used.\n     *\n     * If this function completes successfully (empty error code), the return \\ref pooled_connection\n     * will have `valid() == true` and will be usable. If it completes with a non-empty error code,\n     * it will have `valid() == false`.\n     *\n     * If a connection is idle when the operation is started, it will complete immediately\n     * with that connection. Otherwise, it will wait for a connection to become idle\n     * (possibly creating one in the process, if pool configuration allows it), until\n     * the operation is cancelled (by emitting a cancellation signal) or the pool\n     * is cancelled (by calling \\ref connection_pool::cancel).\n     * If the pool is not running, the operation fails immediately.\n     *\n     * If the operation is cancelled, and the overload with \\ref diagnostics was used,\n     * the output diagnostics will contain the most recent error generated by\n     * the connections attempting to connect (via \\ref any_connection::async_connect), if any.\n     * In cases where \\ref async_get_connection doesn't complete because connections are unable\n     * to connect, this feature can help figuring out where the problem is.\n     *\n     * \\par Preconditions\n     * `this->valid() == true` \\n\n     *\n     * \\par Object lifetimes\n     * While the operation is outstanding, the pool's internal data will be kept alive.\n     * It is safe to destroy `*this` while the operation is outstanding.\n     *\n     * \\par Handler signature\n     * The handler signature for this operation is\n     * `void(boost::mysql::error_code, boost::mysql::pooled_connection)`\n     *\n     * \\par Executor\n     *\n     * If the final handler has an associated immediate executor, and the operation\n     * completes immediately, the final handler is dispatched to it.\n     * Otherwise, the final handler is called as if it was submitted using `asio::post`,\n     * and is never be called inline from within this function.\n     * Immediate completions can only happen when thread-safety is not enabled.\n     *\n     * The final handler is executed using `token`'s associated executor,\n     * or `this->get_executor()` if the token doesn't have an associated\n     * executor.\n     *\n     * If the pool was constructed with thread-safety enabled, intermediate\n     * completion handlers are executed using an internal strand that wraps `this->get_executor()`.\n     * Otherwise, intermediate handlers are executed using\n     * `token`'s associated executor if it has one, or `this->get_executor()` if it hasn't.\n     *\n     * **Caution**: be careful when using thread-safety and `asio::cancel_after`, as it\n     * can result in inadvertent race conditions. Please refer to\n     * <a href=\"../../../connection_pool.html#mysql.connection_pool.thread_safe\">this\n     * page</a> for more info.\n     *\n     * \\par Per-operation cancellation\n     * This operation supports per-operation cancellation.\n     * Cancelling `async_get_connection` has no observable side effects.\n     * The following `asio::cancellation_type_t` values are supported:\n     *\n     *   - `asio::cancellation_type_t::terminal`\n     *   - `asio::cancellation_type_t::partial`\n     *   - `asio::cancellation_type_t::total`\n     *\n     * \\par Errors\n     *   - \\ref client_errc::no_connection_available, if the `async_get_connection`\n     *     operation is cancelled before a connection becomes available.\n     *   - \\ref client_errc::pool_not_running, if the `async_get_connection`\n     *     operation is cancelled before async_run is called.\n     *   - \\ref client_errc::pool_cancelled, if the pool is cancelled before\n     *     the operation completes, or `async_get_connection` is called\n     *     on a pool that has been cancelled.\n     *\n     * \\par Thread-safety\n     * Reads the internal state handle. Mutates the pool state.\n     * If the pool was built with thread-safety enabled, it can be called\n     * concurrently with other functions that don't modify the state handle.\n     */\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::pooled_connection))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_get_connection(CompletionToken&& token = {}) BOOST_MYSQL_RETURN_TYPE(\n        decltype(async_get_connection_impl(nullptr, std::forward<CompletionToken>(token)))\n    )\n    {\n        return async_get_connection_impl(nullptr, std::forward<CompletionToken>(token));\n    }\n\n    /// \\copydoc async_get_connection\n    template <\n        BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::pooled_connection))\n            CompletionToken = with_diagnostics_t<asio::deferred_t>>\n    auto async_get_connection(diagnostics& diag, CompletionToken&& token = {}) BOOST_MYSQL_RETURN_TYPE(\n        decltype(async_get_connection_impl(nullptr, std::forward<CompletionToken>(token)))\n    )\n    {\n        return async_get_connection_impl(&diag, std::forward<CompletionToken>(token));\n    }\n\n    /**\n     * \\brief Stops any current outstanding operation and marks the pool as cancelled.\n     * \\details\n     * This function has the following effects:\n     *\n     * \\li Stops the currently outstanding \\ref async_run operation, if any, which will complete\n     *     with a success error code.\n     * \\li Cancels any outstanding \\ref async_get_connection operations.\n     * \\li Marks the pool as cancelled. Successive `async_get_connection` calls will\n     *     fail immediately.\n     *\n     * This function will return immediately, without waiting for the cancelled operations to complete.\n     *\n     * You may call this function any number of times. Successive calls will have no effect.\n     *\n     * \\par Preconditions\n     * `this->valid() == true`\n     *\n     * \\par Exception safety\n     * Basic guarantee. Memory allocations and acquiring mutexes may throw.\n     *\n     * \\par Thread-safety\n     * Reads the internal state handle. Mutates the pool state.\n     * If the pool was built with thread-safety enabled, it can be called\n     * concurrently with other functions that don't modify the state handle.\n     */\n    BOOST_MYSQL_DECL\n    void cancel();\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/connection_pool.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/constant_string_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_CONSTANT_STRING_VIEW_HPP\n#define BOOST_MYSQL_CONSTANT_STRING_VIEW_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/config.hpp>\n\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A string view that should be known at compile-time.\n * \\details\n * This type is used when a string function argument must always be known at compile-time\n * except in rare cases. See \\ref format_sql format strings for an example.\n *\n * \\par Object lifetimes\n * This type holds internally a \\ref string_view, and follows the same lifetime rules as `string_view`.\n * We recommend to only use this type as a function argument, to provide compile-time checks.\n */\nclass constant_string_view\n{\n    string_view impl_;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    constexpr constant_string_view(string_view value, int) noexcept : impl_(value) {}\n    friend constexpr constant_string_view runtime(string_view) noexcept;\n#endif\n\npublic:\n    /**\n     * \\brief Consteval constructor.\n     * \\details\n     * Constructs a \\ref string_view from the passed argument.\n     * \\n\n     * This function is `consteval`: it results in a compile-time error\n     * if the passed value is not known at compile-time. You can bypass\n     * this check using the \\ref runtime function. This check works only\n     * for C++20 and above. No check is performed for lower C++ standard versions.\n     * \\n\n     * This constructor is only considered if a \\ref string_view can be constructed\n     * from the passed value.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Ownership is not transferred to the constructed object. As with `string_view`,\n     * the user is responsible for keeping the original character buffer alive.\n     */\n    template <\n        class T\n#ifndef BOOST_MYSQL_DOXYGEN\n        ,\n        class = typename std::enable_if<std::is_convertible<const T&, string_view>::value>::type\n#endif\n        >\n    BOOST_MYSQL_CONSTEVAL constant_string_view(const T& value) noexcept : impl_(value)\n    {\n    }\n\n    /**\n     * \\brief Retrieves the underlying string view.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view has the same lifetime rules as `*this`.\n     */\n    constexpr string_view get() const noexcept { return impl_; }\n};\n\n/**\n * \\brief Creates a \\ref constant_string_view from a runtime value.\n * \\details\n * You can use this function to bypass the `consteval` check performed by \\ref constant_string_view\n * constructor.\n * \\n\n * Don't use this function unless you know what you are doing. `consteval` checks exist\n * for the sake of security. Make sure to only pass trusted values to the relevant API.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Object lifetimes\n * The returned value has the same lifetime semantics as the passed view.\n */\nconstexpr constant_string_view runtime(string_view value) noexcept { return constant_string_view(value, 0); }\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/date.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DATE_HPP\n#define BOOST_MYSQL_DATE_HPP\n\n#include <boost/mysql/days.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/datetime.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <chrono>\n#include <cstdint>\n#include <iosfwd>\n#include <stdexcept>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Type representing MySQL `DATE` data type.\n * \\details\n * Represents a Gregorian date broken by its year, month and day components, without a time zone.\n * \\n\n * This type is close to the protocol and should not be used as a vocabulary type.\n * Instead, cast it to a `std::chrono::time_point` by calling \\ref as_time_point,\n * \\ref get_time_point, \\ref as_local_time_point or \\ref get_local_time_point.\n * \\n\n * Dates retrieved from MySQL don't include any time zone information. Determining the time zone\n * is left to the application. Thus, any time point obtained from this class should be\n * interpreted as a local time in an unspecified time zone, like `std::chrono::local_time`.\n * For compatibility with older compilers, \\ref as_time_point and \\ref get_time_point return\n * `system_clock` time points. These should be interpreted as local times rather\n * than UTC. Prefer using \\ref as_local_time_point or \\ref get_local_time_point\n * if your compiler supports them, as they provide more accurate semantics.\n * \\n\n * As opposed to `time_point`, this type allows representing MySQL invalid and zero dates.\n * These values are allowed by MySQL but don't represent real dates.\n * \\n\n * Note: using `std::chrono` time zone functionality under MSVC may cause memory leaks to be reported.\n * See <a href=\"https://github.com/microsoft/STL/issues/2047\">this issue</a> for an explanation and\n * <a href=\"https://github.com/microsoft/STL/issues/2504\">this other issue</a> for a workaround.\n */\nclass date\n{\npublic:\n    /**\n     * \\brief A `std::chrono::time_point` that can represent any valid `date`.\n     * \\details\n     * Time points used by this class are always local times, even if defined\n     * to use the system clock.\n     */\n    using time_point = std::chrono::time_point<std::chrono::system_clock, days>;\n\n    /**\n     * \\brief Constructs a zero date.\n     * \\details\n     * Results in a date with all of its components set to zero.\n     * The resulting object has `this->valid() == false`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr date() noexcept = default;\n\n    /**\n     * \\brief Constructs a date from its year, month and date components.\n     * \\details\n     * Component values that yield invalid dates (like zero or out-of-range\n     * values) are allowed, resulting in an object with `this->valid() == false`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr date(std::uint16_t year, std::uint8_t month, std::uint8_t day) noexcept\n        : year_(year), month_(month), day_(day)\n    {\n    }\n\n    /**\n     * \\brief Constructs a date from a `time_point`.\n     * \\details\n     * The time point is interpreted as a local time. No time zone conversion is performed.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws on invalid input.\n     * \\throws std::out_of_range If the resulting `date` would be\n     * out of the [\\ref min_date, \\ref max_date] range.\n     */\n    BOOST_CXX14_CONSTEXPR explicit date(time_point tp)\n    {\n        bool ok = detail::days_to_ymd(tp.time_since_epoch().count(), year_, month_, day_);\n        if (!ok)\n            BOOST_THROW_EXCEPTION(std::out_of_range(\"date::date: time_point was out of range\"));\n    }\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n    /**\n     * \\brief Constructs a date from a local time point.\n     * \\details\n     * Equivalent to constructing a `date` from a `time_point` with the same\n     * `time_since_epoch()` as `tp`.\n     * \\n\n     * Requires C++20 calendar types.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws on invalid input.\n     * \\throws std::out_of_range If the resulting `date` would be\n     * out of the [\\ref min_date, \\ref max_date] range.\n     */\n    constexpr explicit date(std::chrono::local_days tp) : date(time_point(tp.time_since_epoch())) {}\n#endif\n\n    /**\n     * \\brief Retrieves the year component.\n     * \\details\n     * Represents the year number in the Gregorian calendar.\n     * If `this->valid() == true`, this value is within the `[0, 9999]` range.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint16_t year() const noexcept { return year_; }\n\n    /**\n     * \\brief Retrieves the month component (1-based).\n     * \\details\n     * A value of 1 represents January.\n     * If `this->valid() == true`, this value is within the `[1, 12]` range.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t month() const noexcept { return month_; }\n\n    /**\n     * \\brief Retrieves the day component (1-based).\n     * \\details\n     * A value of 1 represents the first day of the month.\n     * If `this->valid() == true`, this value is within the `[1, last_month_day]` range\n     * (where `last_month_day` is the last day of the month).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t day() const noexcept { return day_; }\n\n    /**\n     * \\brief Returns `true` if `*this` represents a valid `time_point`.\n     * \\details If any of the individual components is out of range, the date\n     * doesn't represent an actual `time_point` (e.g. `date(2020, 2, 30)`) or\n     * the date is not in the [\\ref min_date, \\ref max_date] validity range,\n     * returns `false`. Otherwise, returns `true`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr bool valid() const noexcept { return detail::is_valid(year_, month_, day_); }\n\n    /**\n     * \\brief Converts `*this` into a `time_point` (unchecked access).\n     * \\details\n     * If your compiler supports it, prefer using \\ref get_local_time_point,\n     * as it provides more accurate semantics.\n     *\n     * \\par Preconditions\n     * `this->valid() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR time_point get_time_point() const noexcept\n    {\n        BOOST_ASSERT(valid());\n        return time_point(unch_get_days());\n    }\n\n    /**\n     * \\brief Converts `*this` into a `time_point` (checked access).\n     * \\details\n     * If your compiler supports it, prefer using \\ref as_local_time_point,\n     * as it provides more accurate semantics.\n     *\n     * \\par Exception safety\n     * Strong guarantee.\n     * \\throws std::invalid_argument If `!this->valid()`.\n     */\n    BOOST_CXX14_CONSTEXPR time_point as_time_point() const\n    {\n        if (!valid())\n            BOOST_THROW_EXCEPTION(std::invalid_argument(\"date::as_time_point: invalid date\"));\n        return time_point(unch_get_days());\n    }\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n    /**\n     * \\brief Converts `*this` into a local time point (unchecked access).\n     * \\details\n     * The returned object has the same `time_since_epoch()` as `this->get_time_point()`,\n     * but uses the `std::chrono::local_t` pseudo-clock to better represent\n     * the absence of time zone information.\n     * \\n\n     * Requires C++20 calendar types.\n     *\n     * \\par Preconditions\n     * `this->valid() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::chrono::local_days get_local_time_point() const noexcept\n    {\n        BOOST_ASSERT(valid());\n        return std::chrono::local_days(unch_get_days());\n    }\n\n    /**\n     * \\brief Converts `*this` into a local time point (checked access).\n     * \\details\n     * The returned object has the same `time_since_epoch()` as `this->as_time_point()`,\n     * but uses the `std::chrono::local_t` pseudo-clock to better represent\n     * the absence of time zone information.\n     * \\n\n     * Requires C++20 calendar types.\n     *\n     * \\par Exception safety\n     * Strong guarantee.\n     * \\throws std::invalid_argument If `!this->valid()`.\n     */\n    constexpr std::chrono::local_days as_local_time_point() const\n    {\n        if (!valid())\n            BOOST_THROW_EXCEPTION(std::invalid_argument(\"date::as_local_time_point: invalid date\"));\n        return std::chrono::local_days(unch_get_days());\n    }\n#endif\n\n    /**\n     * \\brief Tests for equality.\n     * \\details Two dates are considered equal if all of its individual components\n     * are equal. This function works for invalid dates, too.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr bool operator==(const date& rhs) const noexcept\n    {\n        return year_ == rhs.year_ && month_ == rhs.month_ && day_ == rhs.day_;\n    }\n\n    /**\n     * \\brief Tests for inequality.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr bool operator!=(const date& rhs) const noexcept { return !(rhs == *this); }\n\n    /**\n     * \\brief Returns the current system time as a date object.\n     * \\par Exception safety\n     * Strong guarantee. Only throws if obtaining the current time throws.\n     */\n    static date now()\n    {\n        auto now = time_point::clock::now();\n        return date(std::chrono::time_point_cast<time_point::duration>(now));\n    }\n\nprivate:\n    std::uint16_t year_{};\n    std::uint8_t month_{};\n    std::uint8_t day_{};\n\n    BOOST_CXX14_CONSTEXPR days unch_get_days() const\n    {\n        return days(detail::ymd_to_days(year_, month_, day_));\n    }\n};\n\n/**\n * \\relates date\n * \\brief Streams a date.\n * \\details This function works for invalid dates, too.\n */\nBOOST_MYSQL_DECL\nstd::ostream& operator<<(std::ostream& os, const date& v);\n\n/// The minimum allowed value for \\ref date.\nBOOST_INLINE_CONSTEXPR date min_date{0u, 1u, 1u};\n\n/// The maximum allowed value for \\ref date.\nBOOST_INLINE_CONSTEXPR date max_date{9999u, 12u, 31u};\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/date.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/datetime.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DATETIME_HPP\n#define BOOST_MYSQL_DATETIME_HPP\n\n#include <boost/mysql/days.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/datetime.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <chrono>\n#include <cstdint>\n#include <iosfwd>\n#include <ratio>\n#include <stdexcept>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Type representing MySQL `DATETIME` and `TIMESTAMP` data types.\n * \\details Represents a Gregorian date and time broken by its year, month, day, hour, minute, second and\n * microsecond components, without a time zone.\n * \\n\n * This type is close to the protocol and should not be used as a vocabulary type.\n * Instead, cast it to a `std::chrono::time_point` by calling \\ref as_time_point,\n * \\ref get_time_point, \\ref as_local_time_point or \\ref get_local_time_point.\n * \\n\n * Datetimes retrieved from MySQL don't include any time zone information. Determining the time zone\n * is left to the application. Thus, any time point obtained from this class should be\n * interpreted as a local time in an unspecified time zone, like `std::chrono::local_time`.\n * For compatibility with older compilers, \\ref as_time_point and \\ref get_time_point return\n * `system_clock` time points. These should be interpreted as local times rather\n * than UTC. Prefer using \\ref as_local_time_point or \\ref get_local_time_point\n * if your compiler supports them, as they provide more accurate semantics.\n * \\n\n * As opposed to `time_point`, this type allows representing MySQL invalid and zero datetimes.\n * These values are allowed by MySQL but don't represent real time points.\n * \\n\n * Note: using `std::chrono` time zone functionality under MSVC may cause memory leaks to be reported.\n * See <a href=\"https://github.com/microsoft/STL/issues/2047\">this issue</a> for an explanation and\n * <a href=\"https://github.com/microsoft/STL/issues/2504\">this other issue</a> for a workaround.\n */\nclass datetime\n{\npublic:\n    /**\n     * \\brief A `std::chrono::time_point` that can represent any valid datetime, with microsecond resolution.\n     * \\details\n     * Time points used by this class are always local times, even if defined\n     * to use the system clock. Prefer using \\ref local_time_point, if your compiler\n     * supports it.\n     */\n    using time_point = std::chrono::\n        time_point<std::chrono::system_clock, std::chrono::duration<std::int64_t, std::micro>>;\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n\n    /**\n     * \\brief A `std::chrono::local_time` that can represent any valid datetime, with microsecond resolution.\n     * \\details Requires C++20 calendar types.\n     */\n    using local_time_point = std::chrono::local_time<std::chrono::duration<std::int64_t, std::micro>>;\n#endif\n\n    /**\n     * \\brief Constructs a zero datetime.\n     * \\details Results in a datetime with all of its components set to zero.\n     * The resulting object has `this->valid() == false`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr datetime() noexcept = default;\n\n    /**\n     * \\brief Constructs a datetime from its individual components.\n     * \\details\n     * Component values that yield invalid datetimes (like zero or out-of-range\n     * values) are allowed, resulting in an object with `this->valid() == false`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr datetime(\n        std::uint16_t year,\n        std::uint8_t month,\n        std::uint8_t day,\n        std::uint8_t hour = 0,\n        std::uint8_t minute = 0,\n        std::uint8_t second = 0,\n        std::uint32_t microsecond = 0\n    ) noexcept\n        : year_(year),\n          month_(month),\n          day_(day),\n          hour_(hour),\n          minute_(minute),\n          second_(second),\n          microsecond_(microsecond)\n    {\n    }\n\n    /**\n     * \\brief Constructs a datetime from a `time_point`.\n     * \\par Exception safety\n     * Strong guarantee. Throws on invalid input.\n     * \\throws std::out_of_range If the resulting `datetime` object would be\n     * out of the [\\ref min_datetime, \\ref max_datetime] range.\n     */\n    BOOST_CXX14_CONSTEXPR inline explicit datetime(time_point tp);\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n    /**\n     * \\brief Constructs a datetime from a `local_time_point`.\n     * \\details\n     * Equivalent to constructing a `date` from a `time_point` with the same\n     * `time_since_epoch()` as `tp`.\n     * \\n\n     * Requires C++20 calendar types.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws on invalid input.\n     * \\throws std::out_of_range If the resulting `datetime` object would be\n     * out of the [\\ref min_datetime, \\ref max_datetime] range.\n     */\n    constexpr explicit datetime(local_time_point tp) : datetime(time_point(tp.time_since_epoch())) {}\n#endif\n\n    /**\n     * \\brief Retrieves the year component.\n     * \\details\n     * Represents the year number in the Gregorian calendar.\n     * If `this->valid() == true`, this value is within the `[0, 9999]` range.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint16_t year() const noexcept { return year_; }\n\n    /**\n     * \\brief Retrieves the month component (1-based).\n     * \\details\n     * A value of 1 represents January.\n     * If `this->valid() == true`, this value is within the `[1, 12]` range.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t month() const noexcept { return month_; }\n\n    /**\n     * \\brief Retrieves the day component (1-based).\n     * \\details\n     * A value of 1 represents the first day of the month.\n     * If `this->valid() == true`, this value is within the `[1, last_month_day]` range\n     * (where `last_month_day` is the last day of the month).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t day() const noexcept { return day_; }\n\n    /**\n     * \\brief Retrieves the hour component.\n     * \\details If `this->valid() == true`, this value is within the `[0, 23]` range.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t hour() const noexcept { return hour_; }\n\n    /**\n     * \\brief Retrieves the minute component.\n     * \\details If `this->valid() == true`, this value is within the `[0, 59]` range.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t minute() const noexcept { return minute_; }\n\n    /**\n     * \\brief Retrieves the second component.\n     * \\details If `this->valid() == true`, this value is within the `[0, 59]` range.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint8_t second() const noexcept { return second_; }\n\n    /**\n     * \\brief Retrieves the microsecond component.\n     * \\details If `this->valid() == true`, this value is within the `[0, 999999]` range.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr std::uint32_t microsecond() const noexcept { return microsecond_; }\n\n    /**\n     * \\brief Returns `true` if `*this` represents a valid `time_point`.\n     * \\details If any of the individual components is out of range, the datetime\n     * doesn't represent an actual `time_point` (e.g. `datetime(2020, 2, 30)`) or\n     * the datetime is not in the [\\ref min_date, \\ref max_date] validity range,\n     * returns `false`. Otherwise, returns `true`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr bool valid() const noexcept\n    {\n        return detail::is_valid(year_, month_, day_) && hour_ <= detail::max_hour &&\n               minute_ <= detail::max_min && second_ <= detail::max_sec && microsecond_ <= detail::max_micro;\n    }\n\n    /**\n     * \\brief Converts `*this` into a `time_point` (unchecked access).\n     * \\details\n     * If your compiler supports it, prefer using \\ref get_local_time_point,\n     * as it provides more accurate semantics.\n     *\n     * \\par Preconditions\n     * `this->valid() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR time_point get_time_point() const noexcept\n    {\n        BOOST_ASSERT(valid());\n        return time_point(unch_get_micros());\n    }\n\n    /**\n     * \\brief Converts `*this` into a `time_point` (checked access).\n     * \\details\n     * If your compiler supports it, prefer using \\ref as_local_time_point,\n     * as it provides more accurate semantics.\n     *\n     * \\par Exception safety\n     * Strong guarantee.\n     * \\throws std::invalid_argument If `!this->valid()`.\n     */\n    BOOST_CXX14_CONSTEXPR inline time_point as_time_point() const\n    {\n        if (!valid())\n            BOOST_THROW_EXCEPTION(std::invalid_argument(\"datetime::as_time_point: invalid datetime\"));\n        return time_point(unch_get_micros());\n    }\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n    /**\n     * \\brief Converts `*this` into a `local_time_point` (unchecked access).\n     * \\details\n     * The returned object has the same `time_since_epoch()` as `this->get_time_point()`,\n     * but uses the `std::chrono::local_t` pseudo-clock to better represent\n     * the absence of time zone information.\n     * \\n\n     * Requires C++20 calendar types.\n     *\n     * \\par Preconditions\n     * `this->valid() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr local_time_point get_local_time_point() const noexcept\n    {\n        BOOST_ASSERT(valid());\n        return local_time_point(unch_get_micros());\n    }\n\n    /**\n     * \\brief Converts `*this` into a local time point (checked access).\n     * \\details\n     * The returned object has the same `time_since_epoch()` as `this->as_time_point()`,\n     * but uses the `std::chrono::local_t` pseudo-clock to better represent\n     * the absence of time zone information.\n     * \\n\n     * Requires C++20 calendar types.\n     *\n     * \\par Exception safety\n     * Strong guarantee.\n     * \\throws std::invalid_argument If `!this->valid()`.\n     */\n    constexpr local_time_point as_local_time_point() const\n    {\n        if (!valid())\n            BOOST_THROW_EXCEPTION(std::invalid_argument(\"date::as_local_time_point: invalid date\"));\n        return local_time_point(unch_get_micros());\n    }\n#endif\n\n    /**\n     * \\brief Tests for equality.\n     * \\details Two datetimes are considered equal if all of its individual components\n     * are equal. This function works for invalid datetimes, too.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr bool operator==(const datetime& rhs) const noexcept\n    {\n        return year_ == rhs.year_ && month_ == rhs.month_ && day_ == rhs.day_ && hour_ == rhs.hour_ &&\n               minute_ == rhs.minute_ && second_ == rhs.second_ && microsecond_ == rhs.microsecond_;\n    }\n\n    /**\n     * \\brief Tests for inequality.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    constexpr bool operator!=(const datetime& rhs) const noexcept { return !(*this == rhs); }\n\n    /**\n     * \\brief Returns the current system time as a datetime object.\n     * \\par Exception safety\n     * Strong guarantee. Only throws if obtaining the current time throws.\n     */\n    static datetime now()\n    {\n        auto now = time_point::clock::now();\n        return datetime(std::chrono::time_point_cast<time_point::duration>(now));\n    }\n\nprivate:\n    std::uint16_t year_{};\n    std::uint8_t month_{};\n    std::uint8_t day_{};\n    std::uint8_t hour_{};\n    std::uint8_t minute_{};\n    std::uint8_t second_{};\n    std::uint32_t microsecond_{};\n\n    BOOST_CXX14_CONSTEXPR inline time_point::duration unch_get_micros() const\n    {\n        // Doing time of day independently to prevent overflow\n        days d(detail::ymd_to_days(year_, month_, day_));\n        auto time_of_day = std::chrono::hours(hour_) + std::chrono::minutes(minute_) +\n                           std::chrono::seconds(second_) + std::chrono::microseconds(microsecond_);\n        return time_point::duration(d) + time_of_day;\n    }\n};\n\n/**\n * \\relates datetime\n * \\brief Streams a datetime.\n * \\details This function works for invalid datetimes, too.\n */\nBOOST_MYSQL_DECL\nstd::ostream& operator<<(std::ostream& os, const datetime& v);\n\n/// The minimum allowed value for \\ref datetime.\nBOOST_INLINE_CONSTEXPR datetime min_datetime(0u, 1u, 1u);\n\n/// The maximum allowed value for \\ref datetime.\nBOOST_INLINE_CONSTEXPR datetime max_datetime(9999u, 12u, 31u, 23u, 59u, 59u, 999999u);\n\n}  // namespace mysql\n}  // namespace boost\n\n// Implementations\nBOOST_CXX14_CONSTEXPR boost::mysql::datetime::datetime(time_point tp)\n{\n    using std::chrono::duration_cast;\n    using std::chrono::hours;\n    using std::chrono::microseconds;\n    using std::chrono::minutes;\n    using std::chrono::seconds;\n\n    // Avoiding using -= for durations as it's not constexpr until C++17\n    auto input_dur = tp.time_since_epoch();\n    auto rem = input_dur % days(1);\n    auto num_days = duration_cast<days>(input_dur);\n    if (rem.count() < 0)\n    {\n        rem = rem + days(1);\n        num_days = num_days - days(1);\n    }\n    auto num_hours = duration_cast<hours>(rem);\n    rem = rem - num_hours;\n    auto num_minutes = duration_cast<minutes>(rem);\n    rem = rem - num_minutes;\n    auto num_seconds = duration_cast<seconds>(rem);\n    rem = rem - num_seconds;\n    auto num_microseconds = duration_cast<microseconds>(rem);\n\n    BOOST_ASSERT(num_hours.count() >= 0 && num_hours.count() <= detail::max_hour);\n    BOOST_ASSERT(num_minutes.count() >= 0 && num_minutes.count() <= detail::max_min);\n    BOOST_ASSERT(num_seconds.count() >= 0 && num_seconds.count() <= detail::max_sec);\n    BOOST_ASSERT(num_microseconds.count() >= 0 && num_microseconds.count() <= detail::max_micro);\n\n    bool ok = detail::days_to_ymd(num_days.count(), year_, month_, day_);\n    if (!ok)\n        BOOST_THROW_EXCEPTION(std::out_of_range(\"datetime::datetime: time_point was out of range\"));\n\n    microsecond_ = static_cast<std::uint32_t>(num_microseconds.count());\n    second_ = static_cast<std::uint8_t>(num_seconds.count());\n    minute_ = static_cast<std::uint8_t>(num_minutes.count());\n    hour_ = static_cast<std::uint8_t>(num_hours.count());\n}\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/datetime.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/days.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DAYS_HPP\n#define BOOST_MYSQL_DAYS_HPP\n\n#include <chrono>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Duration representing a day (24 hours).\n * \\details Suitable to represent the range of dates MySQL offers.\n * May differ in representation from `std::chrono::days` in C++20.\n */\nusing days = std::chrono::duration<int, std::ratio<3600 * 24>>;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/defaults.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DEFAULTS_HPP\n#define BOOST_MYSQL_DEFAULTS_HPP\n\n#include <boost/config.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\n\n/// The default TCP port for the MySQL protocol.\nBOOST_INLINE_CONSTEXPR unsigned short default_port = 3306;\n\n/// The default TCP port for the MySQL protocol, as a string. Useful for hostname resolution.\nBOOST_INLINE_CONSTEXPR const char* default_port_string = \"3306\";\n\n/// The default initial size of the connection's internal buffer, in bytes.\nBOOST_INLINE_CONSTEXPR std::size_t default_initial_read_buffer_size = 1024;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/access.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ACCESS_HPP\n#define BOOST_MYSQL_DETAIL_ACCESS_HPP\n\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Exposes access to the implementation of public access, which is sometimes\n// required by library internals.\nstruct access\n{\n    template <class T>\n    static decltype(std::declval<T>().impl_)& get_impl(T& obj) noexcept\n    {\n        return obj.impl_;\n    }\n\n    template <class T>\n    static const decltype(std::declval<T>().impl_)& get_impl(const T& obj) noexcept\n    {\n        return obj.impl_;\n    }\n\n    template <class T, class... Args>\n    static T construct(Args&&... args)\n    {\n        return T(std::forward<Args>(args)...);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/algo_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ALGO_PARAMS_HPP\n#define BOOST_MYSQL_DETAIL_ALGO_PARAMS_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\nclass rows_view;\nclass statement;\nclass stage_response;\n\nnamespace detail {\n\nclass execution_processor;\nclass execution_state_impl;\nstruct pipeline_request_stage;\n\nstruct connect_algo_params\n{\n    const void* server_address;  // Points to an any_address or an endpoint for the corresponding stream. For\n                                 // the templated connection, only valid until the first yield!\n    handshake_params hparams;\n    bool secure_channel;  // Are we using UNIX sockets or any other secure channel?\n\n    using result_type = void;\n};\n\nstruct handshake_algo_params\n{\n    handshake_params hparams;\n    bool secure_channel;  // Are we using UNIX sockets or any other secure channel?\n\n    using result_type = void;\n};\n\nstruct execute_algo_params\n{\n    any_execution_request req;\n    execution_processor* proc;\n\n    using result_type = void;\n};\n\nstruct start_execution_algo_params\n{\n    any_execution_request req;\n    execution_processor* proc;\n\n    using result_type = void;\n};\n\nstruct read_resultset_head_algo_params\n{\n    execution_processor* proc;\n\n    using result_type = void;\n};\n\nstruct read_some_rows_algo_params\n{\n    execution_processor* proc;\n    output_ref output;\n\n    using result_type = std::size_t;\n};\n\nstruct read_some_rows_dynamic_algo_params\n{\n    execution_state_impl* exec_st;\n\n    using result_type = rows_view;\n};\n\nstruct prepare_statement_algo_params\n{\n    string_view stmt_sql;\n\n    using result_type = statement;\n};\n\nstruct close_statement_algo_params\n{\n    std::uint32_t stmt_id;\n\n    using result_type = void;\n};\n\nstruct ping_algo_params\n{\n    using result_type = void;\n};\n\nstruct reset_connection_algo_params\n{\n    using result_type = void;\n};\n\nstruct set_character_set_algo_params\n{\n    character_set charset;\n\n    using result_type = void;\n};\n\nstruct quit_connection_algo_params\n{\n    using result_type = void;\n};\n\nstruct close_connection_algo_params\n{\n    using result_type = void;\n};\n\nstruct run_pipeline_algo_params\n{\n    span<const std::uint8_t> request_buffer;\n    span<const pipeline_request_stage> request_stages;\n    std::vector<stage_response>* response;\n\n    using result_type = void;\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/any_execution_request.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ANY_EXECUTION_REQUEST_HPP\n#define BOOST_MYSQL_DETAIL_ANY_EXECUTION_REQUEST_HPP\n\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstdint>\n#include <type_traits>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\nclass field_view;\nclass format_arg;\n\nnamespace detail {\n\nstruct any_execution_request\n{\n    enum class type_t\n    {\n        query,\n        query_with_params,\n        stmt\n    };\n\n    union data_t\n    {\n        string_view query;\n        struct query_with_params_t\n        {\n            constant_string_view query;\n            span<const format_arg> args;\n        } query_with_params;\n        struct stmt_t\n        {\n            std::uint32_t stmt_id;\n            std::uint16_t num_params;\n            span<const field_view> params;\n        } stmt;\n\n        data_t(string_view q) noexcept : query(q) {}\n        data_t(query_with_params_t v) noexcept : query_with_params(v) {}\n        data_t(stmt_t v) noexcept : stmt(v) {}\n    };\n\n    type_t type;\n    data_t data;\n\n    any_execution_request(string_view q) noexcept : type(type_t::query), data(q) {}\n    any_execution_request(data_t::query_with_params_t v) noexcept : type(type_t::query_with_params), data(v)\n    {\n    }\n    any_execution_request(data_t::stmt_t v) noexcept : type(type_t::stmt), data(v) {}\n};\n\nstruct no_execution_request_traits\n{\n};\n\ntemplate <class T, class = void>\nstruct execution_request_traits : no_execution_request_traits\n{\n};\n\ntemplate <class T>\nstruct execution_request_traits<T, typename std::enable_if<std::is_convertible<T, string_view>::value>::type>\n{\n    static any_execution_request make_request(string_view input, std::vector<field_view>&) { return input; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/any_resumable_ref.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ANY_RESUMABLE_REF_HPP\n#define BOOST_MYSQL_DETAIL_ANY_RESUMABLE_REF_HPP\n\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <cstddef>\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass any_resumable_ref\n{\npublic:\n    using fn_t = next_action (*)(void*, error_code, std::size_t);\n\n    template <class T, class = typename std::enable_if<!std::is_same<T, any_resumable_ref>::value>::type>\n    explicit any_resumable_ref(T& op) noexcept : algo_(&op), fn_(&do_resume<T>)\n    {\n    }\n\n    // Allow using standalone functions\n    any_resumable_ref(void* algo, fn_t fn) noexcept : algo_(algo), fn_(fn) {}\n\n    next_action resume(error_code ec, std::size_t bytes_transferred)\n    {\n        return fn_(algo_, ec, bytes_transferred);\n    }\n\nprivate:\n    template <class T>\n    static next_action do_resume(void* self, error_code ec, std::size_t bytes_transferred)\n    {\n        return static_cast<T*>(self)->resume(ec, bytes_transferred);\n    }\n\n    void* algo_{};\n    fn_t fn_{};\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/character_set.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_CHARACTER_SET_HPP\n#define BOOST_MYSQL_DETAIL_CHARACTER_SET_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline std::size_t next_char_ascii(span<const unsigned char> input) { return input[0] <= 0x7f ? 1 : 0; }\nBOOST_MYSQL_DECL std::size_t next_char_utf8mb4(span<const unsigned char> input);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/coldef_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_COLDEF_VIEW_HPP\n#define BOOST_MYSQL_DETAIL_COLDEF_VIEW_HPP\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstruct coldef_view\n{\n    string_view database;\n    string_view table;\n    string_view org_table;\n    string_view name;\n    string_view org_name;\n    std::uint16_t collation_id;\n    std::uint32_t column_length;  // maximum length of the field\n    column_type type;\n    std::uint16_t flags;\n    std::uint8_t decimals;  // max shown decimal digits. 0x00 for int/static strings; 0x1f for\n                            // dynamic strings, double, float\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/config.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_CONFIG_HPP\n#define BOOST_MYSQL_DETAIL_CONFIG_HPP\n\n#include <boost/config.hpp>\n\n// clang-format off\n\n// Concepts\n#if defined(__cpp_concepts) && defined(__cpp_lib_concepts)\n    #define BOOST_MYSQL_HAS_CONCEPTS\n#endif\n\n// C++14 conformance\n#if BOOST_CXX_VERSION >= 201402L\n    #define BOOST_MYSQL_CXX14\n#endif\n\n// Consteval\n#ifdef __cpp_consteval\n    #define BOOST_MYSQL_CONSTEVAL consteval\n#else\n    #define BOOST_MYSQL_CONSTEVAL constexpr\n#endif\n\n// Separate build\n#if defined(BOOST_MYSQL_SEPARATE_COMPILATION)\n    #define BOOST_MYSQL_DECL\n#else\n    #define BOOST_MYSQL_HEADER_ONLY\n    #define BOOST_MYSQL_DECL inline\n#endif\n\n// Auto return type. Having this as a macro helps the documentation tool.\n#ifdef BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION\n#define BOOST_MYSQL_RETURN_TYPE(...) -> __VA_ARGS__\n#else\n#define BOOST_MYSQL_RETURN_TYPE(...)\n#endif\n\n// Chrono calendar types and functions\n#if __cpp_lib_chrono >= 201907L\n#define BOOST_MYSQL_HAS_LOCAL_TIME\n#endif\n\n// clang-format on\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/connect_params_helpers.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_CONNECT_PARAMS_HELPERS_HPP\n#define BOOST_MYSQL_DETAIL_CONNECT_PARAMS_HELPERS_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline ssl_mode adjust_ssl_mode(ssl_mode input, address_type addr_type)\n{\n    return addr_type == address_type::host_and_port ? input : ssl_mode::disable;\n}\n\ninline handshake_params make_hparams(const connect_params& input)\n{\n    return handshake_params(\n        input.username,\n        input.password,\n        input.database,\n        input.connection_collation,\n        adjust_ssl_mode(input.ssl, input.server_address.type()),\n        input.multi_queries\n    );\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/connection_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_CONNECTION_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_CONNECTION_IMPL_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/connect_params_helpers.hpp>\n#include <boost/mysql/detail/engine.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/initiation_base.hpp>\n#include <boost/mysql/detail/intermediate_handler.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/system/result.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <memory>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n// Forward decl\ntemplate <class... StaticRow>\nclass static_execution_state;\n\nstruct character_set;\nclass pipeline_request;\n\nnamespace detail {\n\n//\n// Helpers to interact with connection_state, without including its definition\n//\nclass connection_state;\n\nstruct connection_state_deleter\n{\n    BOOST_MYSQL_DECL void operator()(connection_state*) const;\n};\n\nBOOST_MYSQL_DECL std::vector<field_view>& get_shared_fields(connection_state&);\n\ntemplate <class AlgoParams>\nany_resumable_ref setup(connection_state&, diagnostics&, const AlgoParams&);\n\n// Note: AlgoParams should have !is_void_result\ntemplate <class AlgoParams>\ntypename AlgoParams::result_type get_result(const connection_state&);\n\n//\n// helpers to run algos\n//\ntemplate <class AlgoParams>\nusing has_void_result = std::is_same<typename AlgoParams::result_type, void>;\n\ntemplate <class AlgoParams, bool is_void>\nstruct completion_signature_impl;\n\ntemplate <class AlgoParams>\nstruct completion_signature_impl<AlgoParams, true>\n{\n    // Using typedef to workaround a msvc 14.1 bug\n    typedef void(type)(error_code);\n};\n\ntemplate <class AlgoParams>\nstruct completion_signature_impl<AlgoParams, false>\n{\n    // Using typedef to workaround a msvc 14.1 bug\n    typedef void(type)(error_code, typename AlgoParams::result_type);\n};\n\ntemplate <class AlgoParams>\nusing completion_signature_t = typename completion_signature_impl<\n    AlgoParams,\n    has_void_result<AlgoParams>::value>::type;\n\n// Intermediate handler\ntemplate <class AlgoParams>\nstruct generic_algo_fn\n{\n    static_assert(!has_void_result<AlgoParams>::value, \"Internal error: result_type should be non-void\");\n\n    using result_t = typename AlgoParams::result_type;\n\n    template <class Handler>\n    void operator()(Handler&& handler, error_code ec)\n    {\n        std::move(handler)(ec, ec ? result_t{} : get_result<AlgoParams>(*st));\n    }\n\n    connection_state* st;\n};\n\n// Note: the 1st async_initiate arg should be a diagnostics*,\n// so completion tokens knowing how Boost.MySQL work can operate\nclass connection_impl\n{\n    std::unique_ptr<engine> engine_;\n    std::unique_ptr<connection_state, connection_state_deleter> st_;\n\n    asio::any_io_executor get_executor() const { return engine_->get_executor(); }\n\n    // Helper for execution requests\n    template <class T>\n    static auto make_request(T&& input, connection_state& st)\n        -> decltype(execution_request_traits<typename std::decay<T>::type>::make_request(\n            std::forward<T>(input),\n            get_shared_fields(st)\n        ))\n    {\n        return execution_request_traits<typename std::decay<T>::type>::make_request(\n            std::forward<T>(input),\n            get_shared_fields(st)\n        );\n    }\n\n    // Generic algorithm\n    template <class AlgoParams>\n    typename AlgoParams::result_type run_impl(\n        AlgoParams params,\n        error_code& ec,\n        diagnostics& diag,\n        std::true_type /* has_void_result */\n    )\n    {\n        engine_->run(setup(*st_, diag, params), ec);\n    }\n\n    template <class AlgoParams>\n    typename AlgoParams::result_type run_impl(\n        AlgoParams params,\n        error_code& ec,\n        diagnostics& diag,\n        std::false_type /* has_void_result */\n    )\n    {\n        engine_->run(setup(*st_, diag, params), ec);\n        return get_result<AlgoParams>(*st_);\n    }\n\n    template <class AlgoParams, class Handler>\n    static void async_run_impl(\n        engine& eng,\n        connection_state& st,\n        AlgoParams params,\n        diagnostics& diag,\n        Handler&& handler,\n        std::true_type /* has_void_result */\n    )\n    {\n        eng.async_run(setup(st, diag, params), std::forward<Handler>(handler));\n    }\n\n    template <class AlgoParams, class Handler>\n    static void async_run_impl(\n        engine& eng,\n        connection_state& st,\n        AlgoParams params,\n        diagnostics& diag,\n        Handler&& handler,\n        std::false_type /* has_void_result */\n    )\n    {\n        eng.async_run(\n            setup(st, diag, params),\n            make_intermediate_handler(generic_algo_fn<AlgoParams>{&st}, std::forward<Handler>(handler))\n        );\n    }\n\n    template <class AlgoParams, class Handler>\n    static void async_run_impl(\n        engine& eng,\n        connection_state& st,\n        AlgoParams params,\n        diagnostics& diag,\n        Handler&& handler\n    )\n    {\n        async_run_impl(eng, st, params, diag, std::forward<Handler>(handler), has_void_result<AlgoParams>{});\n    }\n\n    struct run_algo_initiation : initiation_base\n    {\n        using initiation_base::initiation_base;\n\n        template <class Handler, class AlgoParams>\n        void operator()(\n            Handler&& handler,\n            diagnostics* diag,\n            engine* eng,\n            connection_state* st,\n            AlgoParams params\n        )\n        {\n            async_run_impl(*eng, *st, params, *diag, std::forward<Handler>(handler));\n        }\n    };\n\n    // Connect\n    static connect_algo_params make_params_connect(const void* server_address, const handshake_params& params)\n    {\n        return connect_algo_params{server_address, params, false};\n    }\n\n    static connect_algo_params make_params_connect_v2(const connect_params& params)\n    {\n        return connect_algo_params{\n            &params.server_address,\n            make_hparams(params),\n            params.server_address.type() == address_type::unix_path\n        };\n    }\n\n    template <class EndpointType>\n    struct initiate_connect : initiation_base\n    {\n        using initiation_base::initiation_base;\n\n        template <class Handler>\n        void operator()(\n            Handler&& handler,\n            diagnostics* diag,\n            engine* eng,\n            connection_state* st,\n            const EndpointType& endpoint,\n            handshake_params params\n        )\n        {\n            async_run_impl(\n                *eng,\n                *st,\n                make_params_connect(&endpoint, params),\n                *diag,\n                std::forward<Handler>(handler)\n            );\n        }\n    };\n\n    struct initiate_connect_v2 : initiation_base\n    {\n        using initiation_base::initiation_base;\n\n        template <class Handler>\n        void operator()(\n            Handler&& handler,\n            diagnostics* diag,\n            engine* eng,\n            connection_state* st,\n            const connect_params* params\n        )\n        {\n            async_run_impl(*eng, *st, make_params_connect_v2(*params), *diag, std::forward<Handler>(handler));\n        }\n    };\n\n    // execute\n    struct initiate_execute : initiation_base\n    {\n        using initiation_base::initiation_base;\n\n        template <class Handler, class ExecutionRequest>\n        void operator()(\n            Handler&& handler,\n            diagnostics* diag,\n            engine* eng,\n            connection_state* st,\n            ExecutionRequest&& req,\n            execution_processor* proc\n        )\n        {\n            async_run_impl(\n                *eng,\n                *st,\n                execute_algo_params{make_request(std::forward<ExecutionRequest>(req), *st), proc},\n                *diag,\n                std::forward<Handler>(handler)\n            );\n        }\n    };\n\n    // start execution\n    struct initiate_start_execution : initiation_base\n    {\n        using initiation_base::initiation_base;\n\n        template <class Handler, class ExecutionRequest>\n        void operator()(\n            Handler&& handler,\n            diagnostics* diag,\n            engine* eng,\n            connection_state* st,\n            ExecutionRequest&& req,\n            execution_processor* proc\n        )\n        {\n            async_run_impl(\n                *eng,\n                *st,\n                start_execution_algo_params{make_request(std::forward<ExecutionRequest>(req), *st), proc},\n                *diag,\n                std::forward<Handler>(handler)\n            );\n        }\n    };\n\npublic:\n    BOOST_MYSQL_DECL connection_impl(\n        std::size_t read_buff_size,\n        std::size_t max_buffer_size,\n        std::unique_ptr<engine> eng\n    );\n\n    BOOST_MYSQL_DECL metadata_mode meta_mode() const;\n    BOOST_MYSQL_DECL void set_meta_mode(metadata_mode m);\n    BOOST_MYSQL_DECL bool ssl_active() const;\n    BOOST_MYSQL_DECL bool backslash_escapes() const;\n    BOOST_MYSQL_DECL system::result<character_set> current_character_set() const;\n    BOOST_MYSQL_DECL boost::optional<std::uint32_t> connection_id() const;\n    BOOST_MYSQL_DECL diagnostics& shared_diag();\n\n    engine& get_engine()\n    {\n        BOOST_ASSERT(engine_);\n        return *engine_;\n    }\n\n    const engine& get_engine() const\n    {\n        BOOST_ASSERT(engine_);\n        return *engine_;\n    }\n\n    // Generic algorithm\n    template <class AlgoParams>\n    typename AlgoParams::result_type run(AlgoParams params, error_code& ec, diagnostics& diag)\n    {\n        return run_impl(params, ec, diag, has_void_result<AlgoParams>{});\n    }\n\n    template <class AlgoParams, class CompletionToken>\n    auto async_run(AlgoParams params, diagnostics& diag, CompletionToken&& token)\n        -> decltype(asio::async_initiate<CompletionToken, completion_signature_t<AlgoParams>>(\n            run_algo_initiation(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            params\n        ))\n    {\n        return asio::async_initiate<CompletionToken, completion_signature_t<AlgoParams>>(\n            run_algo_initiation(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            params\n        );\n    }\n\n    // Connect\n    template <class EndpointType>\n    void connect(\n        const EndpointType& endpoint,\n        const handshake_params& params,\n        error_code& err,\n        diagnostics& diag\n    )\n    {\n        run(make_params_connect(&endpoint, params), err, diag);\n    }\n\n    void connect_v2(const connect_params& params, error_code& err, diagnostics& diag)\n    {\n        run(make_params_connect_v2(params), err, diag);\n    }\n\n    template <class EndpointType, class CompletionToken>\n    auto async_connect(\n        const EndpointType& endpoint,\n        const handshake_params& params,\n        diagnostics& diag,\n        CompletionToken&& token\n    )\n        -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_connect<EndpointType>(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            endpoint,\n            params\n        ))\n    {\n        return asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_connect<EndpointType>(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            endpoint,\n            params\n        );\n    }\n\n    template <class CompletionToken>\n    auto async_connect_v2(const connect_params& params, diagnostics& diag, CompletionToken&& token)\n        -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_connect_v2(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            &params\n        ))\n    {\n        return asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_connect_v2(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            &params\n        );\n    }\n\n    // Handshake\n    handshake_algo_params make_params_handshake(const handshake_params& params) const\n    {\n        return {params, false};\n    }\n\n    // Execute\n    template <class ExecutionRequest, class ResultsType>\n    void execute(ExecutionRequest&& req, ResultsType& result, error_code& err, diagnostics& diag)\n    {\n        run(\n            execute_algo_params{\n                make_request(std::forward<ExecutionRequest>(req), *st_),\n                &access::get_impl(result).get_interface()\n            },\n            err,\n            diag\n        );\n    }\n\n    template <class ExecutionRequest, class ResultsType, class CompletionToken>\n    auto async_execute(\n        ExecutionRequest&& req,\n        ResultsType& result,\n        diagnostics& diag,\n        CompletionToken&& token\n    )\n        -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_execute(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            std::forward<ExecutionRequest>(req),\n            &access::get_impl(result).get_interface()\n        ))\n    {\n        return asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_execute(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            std::forward<ExecutionRequest>(req),\n            &access::get_impl(result).get_interface()\n        );\n    }\n\n    // Start execution\n    template <class ExecutionRequest, class ExecutionStateType>\n    void start_execution(\n        ExecutionRequest&& req,\n        ExecutionStateType& exec_st,\n        error_code& err,\n        diagnostics& diag\n    )\n    {\n        run(\n            start_execution_algo_params{\n                make_request(std::forward<ExecutionRequest>(req), *st_),\n                &access::get_impl(exec_st).get_interface()\n            },\n            err,\n            diag\n        );\n    }\n\n    template <class ExecutionRequest, class ExecutionStateType, class CompletionToken>\n    auto async_start_execution(\n        ExecutionRequest&& req,\n        ExecutionStateType& exec_st,\n        diagnostics& diag,\n        CompletionToken&& token\n    )\n        -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_start_execution(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            std::forward<ExecutionRequest>(req),\n            &access::get_impl(exec_st).get_interface()\n        ))\n    {\n        return asio::async_initiate<CompletionToken, void(error_code)>(\n            initiate_start_execution(get_executor()),\n            token,\n            &diag,\n            engine_.get(),\n            st_.get(),\n            std::forward<ExecutionRequest>(req),\n            &access::get_impl(exec_st).get_interface()\n        );\n    }\n\n    // Read some rows (dynamic)\n    read_some_rows_dynamic_algo_params make_params_read_some_rows(execution_state& st) const\n    {\n        return {&access::get_impl(st).get_interface()};\n    }\n\n    // Read some rows (static)\n    template <class SpanElementType, class ExecutionState>\n    read_some_rows_algo_params make_params_read_some_rows_static(\n        ExecutionState& exec_st,\n        span<SpanElementType> output\n    ) const\n    {\n        return {\n            &access::get_impl(exec_st).get_interface(),\n            access::get_impl(exec_st).make_output_ref(output)\n        };\n    }\n\n    // Read resultset head\n    template <class ExecutionStateType>\n    read_resultset_head_algo_params make_params_read_resultset_head(ExecutionStateType& st) const\n    {\n        return {&detail::access::get_impl(st).get_interface()};\n    }\n\n    // Close statement\n    close_statement_algo_params make_params_close_statement(statement stmt) const { return {stmt.id()}; }\n\n    // Run pipeline. Separately compiled to avoid including the pipeline header here\n    BOOST_MYSQL_DECL\n    static run_pipeline_algo_params make_params_pipeline(\n        const pipeline_request& req,\n        std::vector<stage_response>& response\n    );\n\n    // Exposed for testing\n    connection_state& get_state() { return *st_; }\n};\n\n// To use some completion tokens, like deferred, in C++11, the old macros\n// BOOST_ASIO_INITFN_AUTO_RESULT_TYPE are no longer enough.\n// Helper typedefs to reduce duplication\ntemplate <class AlgoParams, class CompletionToken>\nusing async_run_t = decltype(std::declval<connection_impl&>().async_run(\n    std::declval<AlgoParams>(),\n    std::declval<diagnostics&>(),\n    std::declval<CompletionToken>()\n));\n\ntemplate <class EndpointType, class CompletionToken>\nusing async_connect_t = decltype(std::declval<connection_impl&>().async_connect(\n    std::declval<const EndpointType&>(),\n    std::declval<const handshake_params&>(),\n    std::declval<diagnostics&>(),\n    std::declval<CompletionToken>()\n));\n\ntemplate <class CompletionToken>\nusing async_connect_v2_t = decltype(std::declval<connection_impl&>().async_connect_v2(\n    std::declval<const connect_params&>(),\n    std::declval<diagnostics&>(),\n    std::declval<CompletionToken>()\n));\n\ntemplate <class ExecutionRequest, class ResultsType, class CompletionToken>\nusing async_execute_t = decltype(std::declval<connection_impl&>().async_execute(\n    std::declval<ExecutionRequest>(),\n    std::declval<ResultsType&>(),\n    std::declval<diagnostics&>(),\n    std::declval<CompletionToken>()\n));\n\ntemplate <class ExecutionRequest, class ExecutionStateType, class CompletionToken>\nusing async_start_execution_t = decltype(std::declval<connection_impl&>().async_start_execution(\n    std::declval<ExecutionRequest>(),\n    std::declval<ExecutionStateType&>(),\n    std::declval<diagnostics&>(),\n    std::declval<CompletionToken>()\n));\n\ntemplate <class CompletionToken>\nusing async_handshake_t = async_run_t<handshake_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_read_resultset_head_t = async_run_t<read_resultset_head_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_read_some_rows_dynamic_t = async_run_t<read_some_rows_dynamic_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_prepare_statement_t = async_run_t<prepare_statement_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_close_statement_t = async_run_t<close_statement_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_set_character_set_t = async_run_t<set_character_set_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_ping_t = async_run_t<ping_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_reset_connection_t = async_run_t<reset_connection_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_quit_connection_t = async_run_t<quit_connection_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_close_connection_t = async_run_t<close_connection_algo_params, CompletionToken>;\n\ntemplate <class CompletionToken>\nusing async_run_pipeline_t = async_run_t<run_pipeline_algo_params, CompletionToken>;\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/connection_impl.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/connection_pool_fwd.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_CONNECTION_POOL_FWD_HPP\n#define BOOST_MYSQL_DETAIL_CONNECTION_POOL_FWD_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <chrono>\n\nnamespace boost {\nnamespace mysql {\n\nclass pooled_connection;\nclass any_connection;\n\nnamespace detail {\n\ntemplate <class ConnectionType, class ClockType>\nclass basic_connection_node;\n\ntemplate <class ConnectionType, class ClockType, class ConnectionWrapper>\nclass basic_pool_impl;\n\nusing connection_node = basic_connection_node<any_connection, std::chrono::steady_clock>;\nusing pool_impl = basic_pool_impl<any_connection, std::chrono::steady_clock, pooled_connection>;\n\nBOOST_MYSQL_DECL void return_connection(pool_impl& pool, connection_node& node, bool should_reset) noexcept;\nBOOST_MYSQL_DECL any_connection& get_connection(connection_node& node) noexcept;\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/datetime.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_DATETIME_HPP\n#define BOOST_MYSQL_DETAIL_DATETIME_HPP\n\n// All these algorithms have been taken from:\n// http://howardhinnant.github.io/date_algorithms.html\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n\n#include <cstdint>\n#include <limits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Helpers\nBOOST_INLINE_CONSTEXPR unsigned char last_month_day_arr[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\n\nconstexpr bool is_leap(std::uint16_t y) noexcept { return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); }\n\nconstexpr inline std::uint8_t last_month_day(std::uint16_t y, std::uint8_t m) noexcept\n{\n    return m != 2 || !is_leap(y) ? last_month_day_arr[m - 1] : 29u;\n}\n\n// Interface\nBOOST_INLINE_CONSTEXPR std::uint16_t max_year = 9999;\nBOOST_INLINE_CONSTEXPR std::uint8_t max_month = 12;\nBOOST_INLINE_CONSTEXPR std::uint8_t max_day = 31;\nBOOST_INLINE_CONSTEXPR std::uint8_t max_hour = 23;\nBOOST_INLINE_CONSTEXPR std::uint8_t max_min = 59;\nBOOST_INLINE_CONSTEXPR std::uint8_t max_sec = 59;\nBOOST_INLINE_CONSTEXPR std::uint32_t max_micro = 999999;\n\nconstexpr inline bool is_valid(std::uint16_t years, std::uint8_t month, std::uint8_t day) noexcept\n{\n    return years <= max_year && month > 0 && month <= max_month && day > 0 &&\n           day <= last_month_day(years, month);\n}\n\nBOOST_CXX14_CONSTEXPR inline int ymd_to_days(\n    std::uint16_t years,\n    std::uint8_t month,\n    std::uint8_t day\n) noexcept\n{\n    BOOST_ASSERT(is_valid(years, month, day));\n    int y = years;\n    const int m = month;\n    const int d = day;\n    y -= m <= 2;\n    const int era = (y >= 0 ? y : y - 399) / 400;\n    const unsigned yoe = static_cast<unsigned>(y - era * 400);            // [0, 399]\n    const unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  // [0, 365]\n    const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           // [0, 146096]\n    return era * 146097 + static_cast<int>(doe) - 719468;\n}\n\nBOOST_CXX14_CONSTEXPR inline bool days_to_ymd(\n    int num_days,\n    std::uint16_t& years,\n    std::uint8_t& month,\n    std::uint8_t& day\n) noexcept\n{\n    // Prevent overflow\n    constexpr int days_magic = 719468;\n    if (num_days > (std::numeric_limits<int>::max)() - days_magic)\n        return false;\n\n    num_days += days_magic;\n    const int era = (num_days >= 0 ? num_days : num_days - 146096) / 146097;\n    const unsigned doe = static_cast<unsigned>(num_days - era * 146097);         // [0, 146096]\n    const unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;  // [0, 399]\n    const int y = static_cast<int>(yoe) + era * 400;\n    const unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100);  // [0, 365]\n    const unsigned mp = (5 * doy + 2) / 153;                       // [0, 11]\n    const unsigned d = doy - (153 * mp + 2) / 5 + 1;               // [1, 31]\n    const unsigned m = mp + (mp < 10 ? 3 : -9);                    // [1, 12]\n    const int final_year = y + (m <= 2);\n    if (final_year < 0 || final_year > static_cast<int>(max_year))\n        return false;\n    else\n    {\n        years = static_cast<std::uint16_t>(final_year);\n        month = static_cast<std::uint8_t>(m);\n        day = static_cast<std::uint8_t>(d);\n        return true;\n    }\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/engine.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ENGINE_HPP\n#define BOOST_MYSQL_DETAIL_ENGINE_HPP\n\n#include <boost/mysql/detail/any_resumable_ref.hpp>\n\n#include <boost/asio/any_completion_handler.hpp>\n#include <boost/asio/any_io_executor.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass engine\n{\npublic:\n    using executor_type = asio::any_io_executor;\n\n    virtual ~engine() {}\n    virtual executor_type get_executor() = 0;\n    virtual bool supports_ssl() const = 0;\n    virtual void run(any_resumable_ref resumable, error_code& err) = 0;\n    virtual void async_run(any_resumable_ref resumable, asio::any_completion_handler<void(error_code)>) = 0;\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/engine_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ENGINE_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_ENGINE_IMPL_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/any_resumable_ref.hpp>\n#include <boost/mysql/detail/engine.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/buffer.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/compose.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/immediate.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/assert.hpp>\n\n#include <cstddef>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline asio::mutable_buffer to_buffer(span<std::uint8_t> buff) noexcept\n{\n    return asio::mutable_buffer(buff.data(), buff.size());\n}\n\ninline bool has_terminal_cancellation(asio::cancellation_type_t cancel_type)\n{\n    return static_cast<bool>(cancel_type & asio::cancellation_type_t::terminal);\n}\n\ntemplate <class EngineStream>\nstruct run_algo_op\n{\n    int resume_point_{0};\n    EngineStream& stream_;\n    any_resumable_ref resumable_;\n    bool has_done_io_{false};\n    error_code stored_ec_;\n\n    run_algo_op(EngineStream& stream, any_resumable_ref algo) noexcept : stream_(stream), resumable_(algo) {}\n\n    template <class Self>\n    void operator()(Self& self, error_code io_ec = {}, std::size_t bytes_transferred = 0)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            while (true)\n            {\n                // If we were cancelled, but the last operation completed successfully,\n                // set a cancelled error code so the algorithm exits. This might happen\n                // if a cancellation signal is emitted after an intermediate operation succeeded\n                // but before the handler was called.\n                if (!io_ec && has_terminal_cancellation(self.cancelled()))\n                    io_ec = asio::error::operation_aborted;\n\n                // Run the op\n                act = resumable_.resume(io_ec, bytes_transferred);\n                if (act.is_done())\n                {\n                    stored_ec_ = act.error();\n                    if (!has_done_io_)\n                    {\n                        BOOST_MYSQL_YIELD(\n                            resume_point_,\n                            1,\n                            asio::async_immediate(stream_.get_executor(), std::move(self))\n                        )\n                    }\n                    self.complete(stored_ec_);\n                    return;\n                }\n                else if (act.type() == next_action_type::read)\n                {\n                    BOOST_MYSQL_YIELD(\n                        resume_point_,\n                        2,\n                        stream_.async_read_some(\n                            to_buffer(act.read_args().buffer),\n                            act.read_args().use_ssl,\n                            std::move(self)\n                        )\n                    )\n                    has_done_io_ = true;\n                }\n                else if (act.type() == next_action_type::write)\n                {\n                    BOOST_MYSQL_YIELD(\n                        resume_point_,\n                        3,\n                        stream_.async_write_some(\n                            asio::buffer(act.write_args().buffer),\n                            act.write_args().use_ssl,\n                            std::move(self)\n                        )\n                    )\n                    has_done_io_ = true;\n                }\n                else if (act.type() == next_action_type::ssl_handshake)\n                {\n                    BOOST_MYSQL_YIELD(resume_point_, 4, stream_.async_ssl_handshake(std::move(self)))\n                    has_done_io_ = true;\n                }\n                else if (act.type() == next_action_type::ssl_shutdown)\n                {\n                    BOOST_MYSQL_YIELD(resume_point_, 5, stream_.async_ssl_shutdown(std::move(self)))\n                    has_done_io_ = true;\n                }\n                else if (act.type() == next_action_type::connect)\n                {\n                    BOOST_MYSQL_YIELD(\n                        resume_point_,\n                        6,\n                        stream_.async_connect(act.connect_endpoint(), std::move(self))\n                    )\n                    has_done_io_ = true;\n                }\n                else\n                {\n                    BOOST_ASSERT(act.type() == next_action_type::close);\n                    stream_.close(io_ec);\n                }\n            }\n        }\n    }\n};\n\n// EngineStream is an \"extended\" stream concept, with the following operations:\n//    using executor_type = asio::any_io_executor;\n//    executor_type get_executor();\n//    bool supports_ssl() const;\n//    std::size_t read_some(asio::mutable_buffer, bool use_ssl, error_code&);\n//    void async_read_some(asio::mutable_buffer, bool use_ssl, CompletinToken&&);\n//    std::size_t write_some(asio::const_buffer, bool use_ssl, error_code&);\n//    void async_write_some(asio::const_buffer, bool use_ssl, CompletinToken&&);\n//    void ssl_handshake(error_code&);\n//    void async_ssl_handshake(CompletionToken&&);\n//    void ssl_shutdown(error_code&);\n//    void async_ssl_shutdown(CompletionToken&&);\n//    void connect(const void* server_address, error_code&);\n//    void async_connect(const void* server_address, CompletionToken&&);\n//    void close(error_code&);\n// Async operations are only required to support callback types\n// See stream_adaptor for an implementation\ntemplate <class EngineStream>\nclass engine_impl final : public engine\n{\n    EngineStream stream_;\n\npublic:\n    template <class... Args>\n    engine_impl(Args&&... args) : stream_(std::forward<Args>(args)...)\n    {\n    }\n\n    EngineStream& stream() { return stream_; }\n    const EngineStream& stream() const { return stream_; }\n\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() override final { return stream_.get_executor(); }\n\n    bool supports_ssl() const override final { return stream_.supports_ssl(); }\n\n    void run(any_resumable_ref resumable, error_code& ec) override final\n    {\n        ec.clear();\n        error_code io_ec;\n        std::size_t bytes_transferred = 0;\n\n        while (true)\n        {\n            // Run the op\n            auto act = resumable.resume(io_ec, bytes_transferred);\n\n            // Apply the next action\n            bytes_transferred = 0;\n            if (act.is_done())\n            {\n                ec = act.error();\n                return;\n            }\n            else if (act.type() == next_action_type::read)\n            {\n                bytes_transferred = stream_.read_some(\n                    to_buffer(act.read_args().buffer),\n                    act.read_args().use_ssl,\n                    io_ec\n                );\n            }\n            else if (act.type() == next_action_type::write)\n            {\n                bytes_transferred = stream_.write_some(\n                    asio::buffer(act.write_args().buffer),\n                    act.write_args().use_ssl,\n                    io_ec\n                );\n            }\n            else if (act.type() == next_action_type::ssl_handshake)\n            {\n                stream_.ssl_handshake(io_ec);\n            }\n            else if (act.type() == next_action_type::ssl_shutdown)\n            {\n                stream_.ssl_shutdown(io_ec);\n            }\n            else if (act.type() == next_action_type::connect)\n            {\n                stream_.connect(act.connect_endpoint(), io_ec);\n            }\n            else\n            {\n                BOOST_ASSERT(act.type() == next_action_type::close);\n                stream_.close(io_ec);\n            }\n        }\n    }\n\n    void async_run(any_resumable_ref resumable, asio::any_completion_handler<void(error_code)> h)\n        override final\n    {\n        return asio::async_compose<asio::any_completion_handler<void(error_code)>, void(error_code)>(\n            run_algo_op<EngineStream>(stream_, resumable),\n            h,\n            stream_\n        );\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/engine_stream_adaptor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ENGINE_STREAM_ADAPTOR_HPP\n#define BOOST_MYSQL_DETAIL_ENGINE_STREAM_ADAPTOR_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/engine_impl.hpp>\n#include <boost/mysql/detail/socket_stream.hpp>\n#include <boost/mysql/detail/void_t.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/ssl/stream.hpp>\n#include <boost/config.hpp>\n#include <boost/core/ignore_unused.hpp>\n\n#include <type_traits>\n\n// Adapts a regular Asio Stream to meet the EngineStream requirements\n// We only use callbacks with the async functions in this file, so no need to support arbitrary return types\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Connect and close helpers\n// LCOV_EXCL_START\ntemplate <class Stream>\nvoid do_connect_impl(Stream&, const void*, error_code&, std::false_type)\n{\n    BOOST_ASSERT(false);\n}\n// LCOV_EXCL_STOP\n\ntemplate <class Stream>\nvoid do_connect_impl(Stream& stream, const void* ep, error_code& ec, std::true_type)\n{\n    stream.lowest_layer().connect(\n        *static_cast<const typename Stream::lowest_layer_type::endpoint_type*>(ep),\n        ec\n    );\n}\n\ntemplate <class Stream>\nvoid do_connect(Stream& stream, const void* ep, error_code& ec)\n{\n    do_connect_impl(stream, ep, ec, is_socket_stream<Stream>{});\n}\n\n// LCOV_EXCL_START\ntemplate <class Stream, class CompletionToken>\nvoid do_async_connect_impl(Stream&, const void*, CompletionToken&&, std::false_type)\n{\n    BOOST_ASSERT(false);\n}\n// LCOV_EXCL_STOP\n\ntemplate <class Stream, class CompletionToken>\nvoid do_async_connect_impl(Stream& stream, const void* ep, CompletionToken&& token, std::true_type)\n{\n    stream.lowest_layer().async_connect(\n        *static_cast<const typename Stream::lowest_layer_type::endpoint_type*>(ep),\n        std::forward<CompletionToken>(token)\n    );\n}\n\ntemplate <class Stream, class CompletionToken>\nvoid do_async_connect(Stream& stream, const void* ep, CompletionToken&& token)\n{\n    do_async_connect_impl(stream, ep, std::forward<CompletionToken>(token), is_socket_stream<Stream>{});\n}\n\n// LCOV_EXCL_START\ntemplate <class Stream>\nvoid do_close_impl(Stream&, error_code&, std::false_type)\n{\n    BOOST_ASSERT(false);\n}\n// LCOV_EXCL_STOP\n\ntemplate <class Stream>\nvoid do_close_impl(Stream& stream, error_code& ec, std::true_type)\n{\n    stream.lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);\n    stream.lowest_layer().close(ec);\n}\n\ntemplate <class Stream>\nvoid do_close(Stream& stream, error_code& ec)\n{\n    do_close_impl(stream, ec, is_socket_stream<Stream>{});\n}\n\ntemplate <class Stream>\nclass engine_stream_adaptor\n{\n    Stream stream_;\n\npublic:\n    template <class... Args>\n    engine_stream_adaptor(Args&&... args) : stream_(std::forward<Args>(args)...)\n    {\n    }\n\n    Stream& stream() { return stream_; }\n    const Stream& stream() const { return stream_; }\n\n    bool supports_ssl() const { return false; }\n\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return stream_.get_executor(); }\n\n    // SSL\n    // LCOV_EXCL_START\n    void ssl_handshake(error_code&) { BOOST_ASSERT(false); }\n\n    template <class CompletinToken>\n    void async_ssl_handshake(CompletinToken&&)\n    {\n        BOOST_ASSERT(false);\n    }\n\n    void ssl_shutdown(error_code&) { BOOST_ASSERT(false); }\n\n    template <class CompletionToken>\n    void async_ssl_shutdown(CompletionToken&&)\n    {\n        BOOST_ASSERT(false);\n    }\n    // LCOV_EXCL_STOP\n\n    // Reading\n    std::size_t read_some(boost::asio::mutable_buffer buff, bool use_ssl, error_code& ec)\n    {\n        BOOST_ASSERT(!use_ssl);\n        boost::ignore_unused(use_ssl);\n        return stream_.read_some(buff, ec);\n    }\n\n    template <class CompletionToken>\n    void async_read_some(boost::asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        BOOST_ASSERT(!use_ssl);\n        boost::ignore_unused(use_ssl);\n        stream_.async_read_some(buff, std::forward<CompletionToken>(token));\n    }\n\n    // Writing\n    std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)\n    {\n        BOOST_ASSERT(!use_ssl);\n        boost::ignore_unused(use_ssl);\n        return stream_.write_some(buff, ec);\n    }\n\n    template <class CompletionToken>\n    void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        BOOST_ASSERT(!use_ssl);\n        boost::ignore_unused(use_ssl);\n        stream_.async_write_some(buff, std::forward<CompletionToken>(token));\n    }\n\n    // Connect and close\n    void connect(const void* endpoint, error_code& ec) { do_connect(stream_, endpoint, ec); }\n\n    template <class CompletionToken>\n    void async_connect(const void* endpoint, CompletionToken&& token)\n    {\n        do_async_connect(stream_, endpoint, std::forward<CompletionToken>(token));\n    }\n\n    void close(error_code& ec) { do_close(stream_, ec); }\n};\n\ntemplate <class Stream>\nclass engine_stream_adaptor<asio::ssl::stream<Stream>>\n{\n    asio::ssl::stream<Stream> stream_;\n\npublic:\n    template <class... Args>\n    engine_stream_adaptor(Args&&... args) : stream_(std::forward<Args>(args)...)\n    {\n    }\n\n    asio::ssl::stream<Stream>& stream() { return stream_; }\n    const asio::ssl::stream<Stream>& stream() const { return stream_; }\n\n    bool supports_ssl() const { return true; }\n\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return stream_.get_executor(); }\n\n    // SSL\n    void ssl_handshake(error_code& ec) { stream_.handshake(asio::ssl::stream_base::client, ec); }\n\n    template <class CompletionToken>\n    void async_ssl_handshake(CompletionToken&& token)\n    {\n        stream_.async_handshake(asio::ssl::stream_base::client, std::forward<CompletionToken>(token));\n    }\n\n    void ssl_shutdown(error_code& ec) { stream_.shutdown(ec); }\n\n    template <class CompletionToken>\n    void async_ssl_shutdown(CompletionToken&& token)\n    {\n        stream_.async_shutdown(std::forward<CompletionToken>(token));\n    }\n\n    // Reading\n    std::size_t read_some(boost::asio::mutable_buffer buff, bool use_ssl, error_code& ec)\n    {\n        if (use_ssl)\n        {\n            return stream_.read_some(buff, ec);\n        }\n        else\n        {\n            return stream_.next_layer().read_some(buff, ec);\n        }\n    }\n\n    template <class CompletionToken>\n    void async_read_some(boost::asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        if (use_ssl)\n        {\n            stream_.async_read_some(buff, std::forward<CompletionToken>(token));\n        }\n        else\n        {\n            stream_.next_layer().async_read_some(buff, std::forward<CompletionToken>(token));\n        }\n    }\n\n    // Writing\n    std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)\n    {\n        if (use_ssl)\n        {\n            return stream_.write_some(buff, ec);\n        }\n        else\n        {\n            return stream_.next_layer().write_some(buff, ec);\n        }\n    }\n\n    template <class CompletionToken>\n    void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        if (use_ssl)\n        {\n            stream_.async_write_some(buff, std::forward<CompletionToken>(token));\n        }\n        else\n        {\n            stream_.next_layer().async_write_some(buff, std::forward<CompletionToken>(token));\n        }\n    }\n\n    // Connect and close\n    void connect(const void* endpoint, error_code& ec) { do_connect(stream_, endpoint, ec); }\n\n    template <class CompletionToken>\n    void async_connect(const void* endpoint, CompletionToken&& token)\n    {\n        do_async_connect(stream_, endpoint, std::forward<CompletionToken>(token));\n    }\n\n    void close(error_code& ec) { do_close(stream_, ec); }\n};\n\n#ifdef BOOST_MYSQL_SEPARATE_COMPILATION\nextern template class engine_impl<engine_stream_adaptor<asio::ssl::stream<asio::ip::tcp::socket>>>;\nextern template class engine_impl<engine_stream_adaptor<asio::ip::tcp::socket>>;\n#endif\n\ntemplate <class Stream, class... Args>\nstd::unique_ptr<engine> make_engine(Args&&... args)\n{\n    return std::unique_ptr<engine>(new engine_impl<engine_stream_adaptor<Stream>>(std::forward<Args>(args)...)\n    );\n}\n\n// Use these only for engines created using make_engine\ntemplate <class Stream>\nStream& stream_from_engine(engine& eng)\n{\n    using derived_t = engine_impl<engine_stream_adaptor<Stream>>;\n    return static_cast<derived_t&>(eng).stream().stream();\n}\n\ntemplate <class Stream>\nconst Stream& stream_from_engine(const engine& eng)\n{\n    using derived_t = engine_impl<engine_stream_adaptor<Stream>>;\n    return static_cast<const derived_t&>(eng).stream().stream();\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/escape_string.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ESCAPE_STRING_HPP\n#define BOOST_MYSQL_DETAIL_ESCAPE_STRING_HPP\n\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/output_string.hpp>\n\n#include <boost/config.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n// Forward decls\nstruct format_options;\n\nnamespace detail {\n\nBOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code\nescape_string(string_view input, const format_options& opts, char quote_char, output_string_ref output);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/escape_string.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/execution_concepts.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_EXECUTION_CONCEPTS_HPP\n#define BOOST_MYSQL_DETAIL_EXECUTION_CONCEPTS_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/config.hpp>\n\n#include <type_traits>\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\nnamespace boost {\nnamespace mysql {\n\n// Forward decls\ntemplate <class... StaticRow>\nclass static_execution_state;\n\ntemplate <class... StaticRow>\nclass static_results;\n\nclass execution_state;\nclass results;\n\nnamespace detail {\n\n// Execution state\ntemplate <class T>\nstruct is_static_execution_state : std::false_type\n{\n};\n\ntemplate <class... T>\nstruct is_static_execution_state<static_execution_state<T...>> : std::true_type\n{\n};\n\ntemplate <class T>\nconcept execution_state_type = std::is_same_v<T, execution_state> || is_static_execution_state<T>::value;\n\n// Results\ntemplate <class T>\nstruct is_static_results : std::false_type\n{\n};\n\ntemplate <class... T>\nstruct is_static_results<static_results<T...>> : std::true_type\n{\n};\n\ntemplate <class T>\nconcept results_type = std::is_same_v<T, results> || is_static_results<T>::value;\n\n// Execution request\ntemplate <class T>\nstruct is_execution_request\n{\n    static constexpr bool value = !std::is_base_of<\n        no_execution_request_traits,\n        execution_request_traits<typename std::decay<T>::type>>::value;\n};\n\ntemplate <class T>\nconcept execution_request = is_execution_request<T>::value;\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#define BOOST_MYSQL_EXECUTION_STATE_TYPE ::boost::mysql::detail::execution_state_type\n#define BOOST_MYSQL_RESULTS_TYPE ::boost::mysql::detail::results_type\n#define BOOST_MYSQL_EXECUTION_REQUEST ::boost::mysql::detail::execution_request\n\n#else\n\n#define BOOST_MYSQL_EXECUTION_STATE_TYPE class\n#define BOOST_MYSQL_RESULTS_TYPE class\n#define BOOST_MYSQL_EXECUTION_REQUEST class\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/execution_processor/execution_processor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HPP\n#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/ok_view.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <limits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// A type-erased reference to be used as the output range for static_execution_state\nclass output_ref\n{\n    // Pointer to the first element of the span\n    void* data_{};\n\n    // Number of elements in the span\n    std::size_t max_size_{(std::numeric_limits<std::size_t>::max)()};\n\n    // Identifier for the type of elements. Index in the resultset type list\n    std::size_t type_index_{};\n\n    // Offset into the span's data (static_execution_state). Otherwise unused\n    std::size_t offset_{};\n\npublic:\n    constexpr output_ref() noexcept = default;\n\n    template <class T>\n    constexpr output_ref(boost::span<T> span, std::size_t type_index, std::size_t offset = 0) noexcept\n        : data_(span.data()), max_size_(span.size()), type_index_(type_index), offset_(offset)\n    {\n    }\n\n    std::size_t max_size() const noexcept { return max_size_; }\n    std::size_t type_index() const noexcept { return type_index_; }\n    std::size_t offset() const noexcept { return offset_; }\n    void set_offset(std::size_t v) noexcept { offset_ = v; }\n\n    template <class T>\n    T& span_element() const noexcept\n    {\n        BOOST_ASSERT(data_);\n        return static_cast<T*>(data_)[offset_];\n    }\n};\n\nclass execution_processor\n{\npublic:\n    virtual ~execution_processor() {}\n\n    void reset(resultset_encoding enc, metadata_mode mode) noexcept\n    {\n        state_ = state_t::reading_first;\n        encoding_ = enc;\n        mode_ = mode;\n        seqnum_ = 0;\n        remaining_meta_ = 0;\n        reset_impl();\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    error_code on_head_ok_packet(const ok_view& pack, diagnostics& diag)\n    {\n        BOOST_ASSERT(is_reading_head());\n        auto err = on_head_ok_packet_impl(pack, diag);\n        set_state_for_ok(pack);\n        return err;\n    }\n\n    void on_num_meta(std::size_t num_columns)\n    {\n        BOOST_ASSERT(is_reading_head());\n        on_num_meta_impl(num_columns);\n        remaining_meta_ = num_columns;\n        set_state(state_t::reading_metadata);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    error_code on_meta(const coldef_view& pack, diagnostics& diag)\n    {\n        BOOST_ASSERT(is_reading_meta());\n        bool is_last = --remaining_meta_ == 0;\n        auto err = on_meta_impl(pack, is_last, diag);\n        if (is_last)\n            set_state(state_t::reading_rows);\n        return err;\n    }\n\n    void on_row_batch_start()\n    {\n        BOOST_ASSERT(is_reading_rows());\n        on_row_batch_start_impl();\n    }\n\n    void on_row_batch_finish() { on_row_batch_finish_impl(); }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    error_code on_row(span<const std::uint8_t> msg, const output_ref& ref, std::vector<field_view>& storage)\n    {\n        BOOST_ASSERT(is_reading_rows());\n        return on_row_impl(msg, ref, storage);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    error_code on_row_ok_packet(const ok_view& pack)\n    {\n        BOOST_ASSERT(is_reading_rows());\n        auto err = on_row_ok_packet_impl(pack);\n        set_state_for_ok(pack);\n        return err;\n    }\n\n    bool is_reading_first() const noexcept { return state_ == state_t::reading_first; }\n    bool is_reading_first_subseq() const noexcept { return state_ == state_t::reading_first_subseq; }\n    bool is_reading_head() const noexcept\n    {\n        return state_ == state_t::reading_first || state_ == state_t::reading_first_subseq;\n    }\n    bool is_reading_meta() const noexcept { return state_ == state_t::reading_metadata; }\n    bool is_reading_rows() const noexcept { return state_ == state_t::reading_rows; }\n    bool is_complete() const noexcept { return state_ == state_t::complete; }\n\n    resultset_encoding encoding() const noexcept { return encoding_; }\n    std::uint8_t& sequence_number() noexcept { return seqnum_; }\n    metadata_mode meta_mode() const noexcept { return mode_; }\n\nprotected:\n    virtual void reset_impl() noexcept = 0;\n    virtual error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) = 0;\n    virtual void on_num_meta_impl(std::size_t num_columns) = 0;\n    virtual error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) = 0;\n    virtual error_code on_row_ok_packet_impl(const ok_view& pack) = 0;\n    virtual error_code on_row_impl(\n        span<const std::uint8_t> msg,\n        const output_ref& ref,\n        std::vector<field_view>& storage\n    ) = 0;\n    virtual void on_row_batch_start_impl() = 0;\n    virtual void on_row_batch_finish_impl() = 0;\n\n    metadata create_meta(const coldef_view& coldef) const\n    {\n        return access::construct<metadata>(coldef, mode_ == metadata_mode::full);\n    }\n\nprivate:\n    enum class state_t\n    {\n        // waiting for 1st packet, for the 1st resultset\n        reading_first,\n\n        // same, but for subsequent resultsets (distiguised to provide a cleaner xp to\n        // the user in (static_)execution_state)\n        reading_first_subseq,\n\n        // waiting for metadata packets\n        reading_metadata,\n\n        // waiting for rows\n        reading_rows,\n\n        // done\n        complete\n    };\n\n    state_t state_{state_t::reading_first};\n    resultset_encoding encoding_{resultset_encoding::text};\n    std::uint8_t seqnum_{};\n    metadata_mode mode_{metadata_mode::minimal};\n    std::size_t remaining_meta_{};\n\n    void set_state(state_t v) noexcept { state_ = v; }\n\n    void set_state_for_ok(const ok_view& pack) noexcept\n    {\n        if (pack.more_results())\n        {\n            set_state(state_t::reading_first_subseq);\n        }\n        else\n        {\n            set_state(state_t::complete);\n        }\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/execution_processor/execution_state_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_STATE_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_STATE_IMPL_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n\n#include <boost/assert.hpp>\n\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass execution_state_impl final : public execution_processor\n{\n    struct ok_data\n    {\n        bool has_value{false};           // The OK packet information is default constructed, or actual data?\n        std::uint64_t affected_rows{};   // OK packet data\n        std::uint64_t last_insert_id{};  // OK packet data\n        std::uint16_t warnings{};        // OK packet data\n        bool is_out_params{false};       // Does this resultset contain OUT param information?\n    };\n\n    std::vector<metadata> meta_;\n    ok_data eof_data_;\n    std::vector<char> info_;\n\n    void on_new_resultset() noexcept\n    {\n        meta_.clear();\n        eof_data_ = ok_data{};\n        info_.clear();\n    }\n\n    BOOST_MYSQL_DECL\n    void on_ok_packet_impl(const ok_view& pack);\n\n    BOOST_MYSQL_DECL\n    void reset_impl() noexcept override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics&) override final;\n\n    BOOST_MYSQL_DECL\n    void on_num_meta_impl(std::size_t num_columns) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_meta_impl(const coldef_view&, bool, diagnostics&) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>& fields)\n        override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_ok_packet_impl(const ok_view& pack) override final;\n\n    void on_row_batch_start_impl() noexcept override final {}\n\n    void on_row_batch_finish_impl() noexcept override final {}\n\npublic:\n    execution_state_impl() = default;\n\n    metadata_collection_view meta() const noexcept { return meta_; }\n\n    std::uint64_t get_affected_rows() const noexcept\n    {\n        BOOST_ASSERT(eof_data_.has_value);\n        return eof_data_.affected_rows;\n    }\n\n    std::uint64_t get_last_insert_id() const noexcept\n    {\n        BOOST_ASSERT(eof_data_.has_value);\n        return eof_data_.last_insert_id;\n    }\n\n    unsigned get_warning_count() const noexcept\n    {\n        BOOST_ASSERT(eof_data_.has_value);\n        return eof_data_.warnings;\n    }\n\n    string_view get_info() const noexcept\n    {\n        BOOST_ASSERT(eof_data_.has_value);\n        return string_view(info_.data(), info_.size());\n    }\n\n    bool get_is_out_params() const noexcept\n    {\n        BOOST_ASSERT(eof_data_.has_value);\n        return eof_data_.is_out_params;\n    }\n\n    execution_state_impl& get_interface() noexcept { return *this; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/execution_state_impl.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/execution_processor/results_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_RESULTS_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_RESULTS_IMPL_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/row_impl.hpp>\n\n#include <boost/assert.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstruct per_resultset_data\n{\n    std::size_t num_columns{};       // Number of columns this resultset has\n    std::size_t meta_offset{};       // Offset into the vector of metadata\n    std::size_t field_offset;        // Offset into the vector of fields (append mode only)\n    std::size_t num_rows{};          // Number of rows this resultset has (append mode only)\n    std::uint64_t affected_rows{};   // OK packet data\n    std::uint64_t last_insert_id{};  // OK packet data\n    std::uint16_t warnings{};        // OK packet data\n    std::size_t info_offset{};       // Offset into the vector of info characters\n    std::size_t info_size{};         // Number of characters that this resultset's info string has\n    bool has_ok_packet_data{false};  // The OK packet information is default constructed, or actual data?\n    bool is_out_params{false};       // Does this resultset contain OUT param information?\n};\n\n// A container similar to a vector with SBO. To avoid depending on Boost.Container\nclass resultset_container\n{\n    bool first_has_data_{false};\n    per_resultset_data first_;\n    std::vector<per_resultset_data> rest_;\n\npublic:\n    resultset_container() = default;\n    std::size_t size() const noexcept { return !first_has_data_ ? 0 : rest_.size() + 1; }\n    bool empty() const noexcept { return !first_has_data_; }\n    void clear() noexcept\n    {\n        first_has_data_ = false;\n        rest_.clear();\n    }\n    per_resultset_data& operator[](std::size_t i) noexcept\n    {\n        return const_cast<per_resultset_data&>(const_cast<const resultset_container&>(*this)[i]);\n    }\n    const per_resultset_data& operator[](std::size_t i) const noexcept\n    {\n        BOOST_ASSERT(i < size());\n        return i == 0 ? first_ : rest_[i - 1];\n    }\n    per_resultset_data& back() noexcept\n    {\n        return const_cast<per_resultset_data&>(const_cast<const resultset_container&>(*this).back());\n    }\n    const per_resultset_data& back() const noexcept\n    {\n        BOOST_ASSERT(first_has_data_);\n        return rest_.empty() ? first_ : rest_.back();\n    }\n    BOOST_MYSQL_DECL per_resultset_data& emplace_back();\n};\n\n// Rows for all resultsets are stored in a single rows_impl object.\n// - When a row batch is started, we record how many fields we had before the batch.\n// - When rows are read, fields are allocated in the rows_impl object, then deserialized against\n//   the allocated storage. At this point, strings/blobs point into the connection read buffer.\n// - When a row batch is finished, we copy strings/blobs into the rows_impl, then transform them\n//   into offsets to allow rows_impl to grow.\n// - When the final OK packet is received, offsets are transformed back into views.\nclass results_impl final : public execution_processor\n{\npublic:\n    results_impl() = default;\n\n    BOOST_MYSQL_DECL\n    row_view get_out_params() const noexcept;\n\n    std::size_t num_resultsets() const noexcept { return per_result_.size(); }\n\n    rows_view get_rows(std::size_t index) const noexcept\n    {\n        const auto& resultset_data = per_result_[index];\n        return access::construct<rows_view>(\n            rows_.fields().data() + resultset_data.field_offset,\n            resultset_data.num_rows * resultset_data.num_columns,\n            resultset_data.num_columns\n        );\n    }\n\n    metadata_collection_view get_meta(std::size_t index) const noexcept\n    {\n        const auto& resultset_data = get_resultset(index);\n        return metadata_collection_view(\n            meta_.data() + resultset_data.meta_offset,\n            resultset_data.num_columns\n        );\n    }\n\n    std::uint64_t get_affected_rows(std::size_t index) const noexcept\n    {\n        return get_resultset(index).affected_rows;\n    }\n\n    std::uint64_t get_last_insert_id(std::size_t index) const noexcept\n    {\n        return get_resultset(index).last_insert_id;\n    }\n\n    unsigned get_warning_count(std::size_t index) const noexcept { return get_resultset(index).warnings; }\n\n    string_view get_info(std::size_t index) const noexcept\n    {\n        const auto& resultset_data = get_resultset(index);\n        return string_view(info_.data() + resultset_data.info_offset, resultset_data.info_size);\n    }\n\n    bool get_is_out_params(std::size_t index) const noexcept { return get_resultset(index).is_out_params; }\n\n    results_impl& get_interface() noexcept { return *this; }\n\nprivate:\n    // Virtual impls\n    BOOST_MYSQL_DECL\n    void reset_impl() noexcept override final;\n\n    BOOST_MYSQL_DECL\n    void on_num_meta_impl(std::size_t num_columns) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics&) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_meta_impl(const coldef_view&, bool, diagnostics&) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>&)\n        override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_ok_packet_impl(const ok_view& pack) override final;\n\n    BOOST_MYSQL_DECL\n    void on_row_batch_start_impl() override final;\n\n    BOOST_MYSQL_DECL\n    void on_row_batch_finish_impl() override final;\n\n    // Data\n    std::vector<metadata> meta_;\n    resultset_container per_result_;\n    std::vector<char> info_;\n    row_impl rows_;\n    std::size_t num_fields_at_batch_start_{no_batch};\n\n    // Auxiliar\n    static BOOST_INLINE_CONSTEXPR std::size_t no_batch = std::size_t(-1);\n\n    bool has_active_batch() const noexcept { return num_fields_at_batch_start_ != no_batch; }\n\n    BOOST_MYSQL_DECL\n    void finish_batch();\n\n    per_resultset_data& current_resultset() noexcept\n    {\n        BOOST_ASSERT(!per_result_.empty());\n        return per_result_.back();\n    }\n\n    const per_resultset_data& current_resultset() const noexcept\n    {\n        BOOST_ASSERT(!per_result_.empty());\n        return per_result_.back();\n    }\n\n    BOOST_MYSQL_DECL\n    per_resultset_data& add_resultset();\n\n    BOOST_MYSQL_DECL\n    void on_ok_packet_impl(const ok_view& pack);\n\n    const per_resultset_data& get_resultset(std::size_t index) const noexcept\n    {\n        BOOST_ASSERT(index < per_result_.size());\n        return per_result_[index];\n    }\n\n    metadata_collection_view current_resultset_meta() const noexcept\n    {\n        return get_meta(per_result_.size() - 1);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/results_impl.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/execution_processor/static_execution_state_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_EXECUTION_STATE_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_EXECUTION_STATE_IMPL_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#include <boost/assert.hpp>\n\n#include <array>\n#include <cstddef>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nusing execst_parse_fn_t =\n    error_code (*)(span<const std::size_t> pos_map, span<const field_view> from, const output_ref& ref);\n\nstruct execst_resultset_descriptor\n{\n    std::size_t num_columns;\n    name_table_t name_table;\n    meta_check_fn_t meta_check;\n    execst_parse_fn_t parse_fn;\n    std::size_t type_index;\n};\n\nclass execst_external_data\n{\npublic:\n    struct ptr_data\n    {\n        std::size_t* pos_map;\n    };\n\n    execst_external_data(span<const execst_resultset_descriptor> desc, ptr_data ptr) noexcept\n        : desc_(desc), ptr_(ptr)\n    {\n    }\n\n    std::size_t num_resultsets() const noexcept { return desc_.size(); }\n    std::size_t num_columns(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].num_columns;\n    }\n    name_table_t name_table(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].name_table;\n    }\n    meta_check_fn_t meta_check_fn(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].meta_check;\n    }\n    execst_parse_fn_t parse_fn(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].parse_fn;\n    }\n    std::size_t type_index(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].type_index;\n    }\n    span<std::size_t> pos_map(std::size_t idx) const noexcept\n    {\n        return span<std::size_t>(ptr_.pos_map, num_columns(idx));\n    }\n\n    void set_pointers(ptr_data ptr) noexcept { ptr_ = ptr; }\n\nprivate:\n    span<const execst_resultset_descriptor> desc_;\n    ptr_data ptr_;\n};\n\nclass static_execution_state_erased_impl final : public execution_processor\n{\npublic:\n    static_execution_state_erased_impl(execst_external_data ext) noexcept : ext_(ext) {}\n\n    execst_external_data& ext_data() noexcept { return ext_; }\n\n    metadata_collection_view meta() const noexcept { return meta_; }\n\n    std::uint64_t get_affected_rows() const noexcept\n    {\n        BOOST_ASSERT(ok_data_.has_value);\n        return ok_data_.affected_rows;\n    }\n\n    std::uint64_t get_last_insert_id() const noexcept\n    {\n        BOOST_ASSERT(ok_data_.has_value);\n        return ok_data_.last_insert_id;\n    }\n\n    unsigned get_warning_count() const noexcept\n    {\n        BOOST_ASSERT(ok_data_.has_value);\n        return ok_data_.warnings;\n    }\n\n    string_view get_info() const noexcept\n    {\n        BOOST_ASSERT(ok_data_.has_value);\n        return string_view(info_.data(), info_.size());\n    }\n\n    bool get_is_out_params() const noexcept\n    {\n        BOOST_ASSERT(ok_data_.has_value);\n        return ok_data_.is_out_params;\n    }\n\nprivate:\n    // Data\n    struct ok_packet_data\n    {\n        bool has_value{false};           // The OK packet information is default constructed, or actual data?\n        std::uint64_t affected_rows{};   // OK packet data\n        std::uint64_t last_insert_id{};  // OK packet data\n        std::uint16_t warnings{};        // OK packet data\n        bool is_out_params{false};       // Does this resultset contain OUT param information?\n    };\n\n    execst_external_data ext_;\n    std::size_t resultset_index_{};\n    ok_packet_data ok_data_;\n    std::vector<char> info_;\n    std::vector<metadata> meta_;\n\n    // Virtual impls\n    BOOST_MYSQL_DECL\n    void reset_impl() noexcept override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) override final;\n\n    BOOST_MYSQL_DECL\n    void on_num_meta_impl(std::size_t num_columns) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_impl(\n        span<const std::uint8_t> msg,\n        const output_ref& ref,\n        std::vector<field_view>& fields\n    ) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_ok_packet_impl(const ok_view& pack) override final;\n\n    void on_row_batch_start_impl() noexcept override final {}\n\n    void on_row_batch_finish_impl() noexcept override final {}\n\n    // Auxiliar\n    name_table_t current_name_table() const noexcept { return ext_.name_table(resultset_index_ - 1); }\n    span<std::size_t> current_pos_map() noexcept { return ext_.pos_map(resultset_index_ - 1); }\n    span<const std::size_t> current_pos_map() const noexcept { return ext_.pos_map(resultset_index_ - 1); }\n\n    error_code meta_check(diagnostics& diag) const\n    {\n        return ext_.meta_check_fn(resultset_index_ - 1)(current_pos_map(), meta_, diag);\n    }\n\n    BOOST_MYSQL_DECL\n    void on_new_resultset() noexcept;\n\n    BOOST_MYSQL_DECL\n    error_code on_ok_packet_impl(const ok_view& pack);\n};\n\ntemplate <class StaticRow>\nstatic error_code execst_parse_fn(\n    span<const std::size_t> pos_map,\n    span<const field_view> from,\n    const output_ref& ref\n)\n{\n    return parse<StaticRow>(pos_map, from, ref.span_element<underlying_row_t<StaticRow>>());\n}\n\ntemplate <class... StaticRow>\nconstexpr std::array<execst_resultset_descriptor, sizeof...(StaticRow)> create_execst_resultset_descriptors()\n{\n    return {{{\n        get_row_size<StaticRow>(),\n        get_row_name_table<StaticRow>(),\n        &meta_check<StaticRow>,\n        &execst_parse_fn<StaticRow>,\n        get_type_index<underlying_row_t<StaticRow>, StaticRow...>(),\n    }...}};\n}\n\ntemplate <class... StaticRow>\nBOOST_INLINE_CONSTEXPR std::array<execst_resultset_descriptor, sizeof...(StaticRow)>\n    execst_resultset_descriptor_table = create_execst_resultset_descriptors<StaticRow...>();\n\ntemplate <BOOST_MYSQL_STATIC_ROW... StaticRow>\nclass static_execution_state_impl\n{\n    // Storage for our data, which requires knowing the template args\n    struct\n    {\n        std::array<std::size_t, max_num_columns<StaticRow...>> pos_map{};\n    } data_;\n\n    // The type-erased impl, that will use pointers to the above storage\n    static_execution_state_erased_impl impl_;\n\n    execst_external_data::ptr_data ptr_data() noexcept\n    {\n        return {\n            data_.pos_map.data(),\n        };\n    }\n\n    void set_pointers() noexcept { impl_.ext_data().set_pointers(ptr_data()); }\n\npublic:\n    static_execution_state_impl() noexcept\n        : impl_({execst_resultset_descriptor_table<StaticRow...>, ptr_data()})\n    {\n    }\n\n    static_execution_state_impl(const static_execution_state_impl& rhs) : data_(rhs.data_), impl_(rhs.impl_)\n    {\n        set_pointers();\n    }\n\n    static_execution_state_impl(static_execution_state_impl&& rhs) noexcept\n        : data_(std::move(rhs.data_)), impl_(std::move(rhs.impl_))\n    {\n        set_pointers();\n    }\n\n    static_execution_state_impl& operator=(const static_execution_state_impl& rhs)\n    {\n        data_ = rhs.data_;\n        impl_ = rhs.impl_;\n        set_pointers();\n        return *this;\n    }\n\n    static_execution_state_impl& operator=(static_execution_state_impl&& rhs)\n    {\n        data_ = std::move(rhs.data_);\n        impl_ = std::move(rhs.impl_);\n        set_pointers();\n        return *this;\n    }\n\n    ~static_execution_state_impl() = default;\n\n    template <class SpanElementType>\n    output_ref make_output_ref(span<SpanElementType> output, std::size_t offset = 0) const noexcept\n    {\n        constexpr std::size_t index = get_type_index<SpanElementType, StaticRow...>();\n        static_assert(\n            index != index_not_found,\n            \"SpanElementType must be one of the types returned by the query\"\n        );\n        return output_ref(output, index, offset);\n    }\n\n    const static_execution_state_erased_impl& get_interface() const noexcept { return impl_; }\n    static_execution_state_erased_impl& get_interface() noexcept { return impl_; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/static_execution_state_impl.ipp>\n#endif\n\n#endif  // BOOST_MYSQL_CXX14\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/execution_processor/static_results_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_RESULTS_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_RESULTS_IMPL_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/typing/readable_field_traits.hpp>\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/mp11/algorithm.hpp>\n#include <boost/mp11/integer_sequence.hpp>\n\n#include <array>\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nusing results_reset_fn_t = void (*)(void*);\nusing results_parse_fn_t =\n    error_code (*)(span<const std::size_t> pos_map, span<const field_view> from, void* to);\n\nstruct results_resultset_descriptor\n{\n    std::size_t num_columns;\n    name_table_t name_table;\n    meta_check_fn_t meta_check;\n    results_parse_fn_t parse_fn;\n};\n\nstruct static_per_resultset_data\n{\n    std::size_t meta_offset{};\n    std::size_t meta_size{};\n    std::size_t info_offset{};\n    std::size_t info_size{};\n    bool has_ok_packet_data{false};  // The OK packet information is default constructed, or actual data?\n    std::uint64_t affected_rows{};   // OK packet data\n    std::uint64_t last_insert_id{};  // OK packet data\n    std::uint16_t warnings{};        // OK packet data\n    bool is_out_params{false};       // Does this resultset contain OUT param information?\n};\n\nclass results_external_data\n{\npublic:\n    struct ptr_data\n    {\n        void* rows;\n        std::size_t* pos_map;\n        static_per_resultset_data* per_resultset;\n    };\n\n    results_external_data(\n        span<const results_resultset_descriptor> desc,\n        results_reset_fn_t reset,\n        ptr_data ptr\n    ) noexcept\n        : desc_(desc), reset_(reset), ptr_(ptr)\n    {\n    }\n\n    void set_pointers(ptr_data ptr) noexcept { ptr_ = ptr; }\n\n    std::size_t num_resultsets() const noexcept { return desc_.size(); }\n    std::size_t num_columns(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].num_columns;\n    }\n    name_table_t name_table(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].name_table;\n    }\n    meta_check_fn_t meta_check_fn(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].meta_check;\n    }\n    results_parse_fn_t parse_fn(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return desc_[idx].parse_fn;\n    }\n    results_reset_fn_t reset_fn() const noexcept { return reset_; }\n    void* rows() const noexcept { return ptr_.rows; }\n    span<std::size_t> pos_map(std::size_t idx) const noexcept\n    {\n        return span<std::size_t>(ptr_.pos_map, num_columns(idx));\n    }\n    static_per_resultset_data& per_result(std::size_t idx) const noexcept\n    {\n        BOOST_ASSERT(idx < num_resultsets());\n        return ptr_.per_resultset[idx];\n    }\n\nprivate:\n    span<const results_resultset_descriptor> desc_;\n    results_reset_fn_t reset_;\n    ptr_data ptr_;\n};\n\nclass static_results_erased_impl final : public execution_processor\n{\npublic:\n    static_results_erased_impl(results_external_data ext) noexcept : ext_(ext) {}\n\n    results_external_data& ext_data() noexcept { return ext_; }\n\n    metadata_collection_view get_meta(std::size_t index) const noexcept\n    {\n        const auto& resultset_data = ext_.per_result(index);\n        return metadata_collection_view(meta_.data() + resultset_data.meta_offset, resultset_data.meta_size);\n    }\n\n    std::uint64_t get_affected_rows(std::size_t index) const noexcept\n    {\n        return ext_.per_result(index).affected_rows;\n    }\n\n    std::uint64_t get_last_insert_id(std::size_t index) const noexcept\n    {\n        return ext_.per_result(index).last_insert_id;\n    }\n\n    unsigned get_warning_count(std::size_t index) const noexcept { return ext_.per_result(index).warnings; }\n\n    string_view get_info(std::size_t index) const noexcept\n    {\n        const auto& resultset_data = ext_.per_result(index);\n        return string_view(info_.data() + resultset_data.info_offset, resultset_data.info_size);\n    }\n\n    bool get_is_out_params(std::size_t index) const noexcept { return ext_.per_result(index).is_out_params; }\n\nprivate:\n    // Virtual implementations\n    BOOST_MYSQL_DECL\n    void reset_impl() noexcept override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) override final;\n\n    BOOST_MYSQL_DECL\n    void on_num_meta_impl(std::size_t num_columns) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>& fields)\n        override final;\n\n    BOOST_MYSQL_DECL\n    error_code on_row_ok_packet_impl(const ok_view& pack) override final;\n\n    void on_row_batch_start_impl() override final {}\n    void on_row_batch_finish_impl() override final {}\n\n    // Data\n    results_external_data ext_;\n    std::vector<metadata> meta_;\n    std::vector<char> info_;\n    std::size_t resultset_index_{0};\n\n    // Helpers\n    span<std::size_t> current_pos_map() noexcept { return ext_.pos_map(resultset_index_ - 1); }\n    span<const std::size_t> current_pos_map() const noexcept { return ext_.pos_map(resultset_index_ - 1); }\n    name_table_t current_name_table() const noexcept { return ext_.name_table(resultset_index_ - 1); }\n    static_per_resultset_data& current_resultset() noexcept { return ext_.per_result(resultset_index_ - 1); }\n    metadata_collection_view current_resultset_meta() const noexcept\n    {\n        return get_meta(resultset_index_ - 1);\n    }\n\n    BOOST_MYSQL_DECL\n    static_per_resultset_data& add_resultset();\n\n    BOOST_MYSQL_DECL\n    error_code on_ok_packet_impl(const ok_view& pack);\n\n    error_code meta_check(diagnostics& diag) const\n    {\n        return ext_.meta_check_fn(resultset_index_ - 1)(current_pos_map(), current_resultset_meta(), diag);\n    }\n};\n\ntemplate <class... StaticRow>\nusing results_rows_t = std::tuple<std::vector<underlying_row_t<StaticRow>>...>;\n\ntemplate <class... StaticRow>\nstruct results_fns\n{\n    using rows_t = results_rows_t<StaticRow...>;\n\n    struct reset_fn\n    {\n        rows_t& obj;\n\n        template <std::size_t I>\n        void operator()(boost::mp11::mp_size_t<I>) const noexcept\n        {\n            std::get<I>(obj).clear();\n        }\n    };\n\n    static void reset(void* rows_ptr) noexcept\n    {\n        auto& rows = *static_cast<rows_t*>(rows_ptr);\n        boost::mp11::mp_for_each<boost::mp11::mp_iota_c<sizeof...(StaticRow)>>(reset_fn{rows});\n    }\n\n    template <std::size_t I>\n    static error_code do_parse(span<const std::size_t> pos_map, span<const field_view> from, void* to)\n    {\n        using StaticRowT = mp11::mp_at_c<mp11::mp_list<StaticRow...>, I>;\n        auto& v = std::get<I>(*static_cast<rows_t*>(to));\n        v.emplace_back();\n        return parse<StaticRowT>(pos_map, from, v.back());\n    }\n\n    template <std::size_t I>\n    static constexpr results_resultset_descriptor create_descriptor()\n    {\n        using StaticRowT = mp11::mp_at_c<mp11::mp_list<StaticRow...>, I>;\n        return {\n            get_row_size<StaticRowT>(),\n            get_row_name_table<StaticRowT>(),\n            &meta_check<StaticRowT>,\n            &do_parse<I>,\n        };\n    }\n\n    template <std::size_t... I>\n    static constexpr std::array<results_resultset_descriptor, sizeof...(StaticRow)> create_descriptors(mp11::index_sequence<\n                                                                                                       I...>)\n    {\n        return {{create_descriptor<I>()...}};\n    }\n};\n\ntemplate <class... StaticRow>\nBOOST_INLINE_CONSTEXPR std::array<results_resultset_descriptor, sizeof...(StaticRow)>\n    results_resultset_descriptor_table = results_fns<StaticRow...>::create_descriptors(\n        mp11::make_index_sequence<sizeof...(StaticRow)>()\n    );\n\ntemplate <std::size_t I, class... StaticRow>\nusing rows_span_t = boost::span<\n    const typename std::tuple_element<I, std::tuple<underlying_row_t<StaticRow>...>>::type>;\n\ntemplate <BOOST_MYSQL_STATIC_ROW... StaticRow>\nclass static_results_impl\n{\n    // Data that requires knowing template params\n    struct\n    {\n        results_rows_t<StaticRow...> rows;\n        std::array<std::size_t, max_num_columns<StaticRow...>> pos_map{};\n        std::array<static_per_resultset_data, sizeof...(StaticRow)> per_resultset{};\n    } data_;\n\n    // The type-erased impl, that will use pointers to the above storage\n    static_results_erased_impl impl_;\n\n    results_external_data::ptr_data ptr_data() noexcept\n    {\n        return {\n            &data_.rows,\n            data_.pos_map.data(),\n            data_.per_resultset.data(),\n        };\n    }\n\n    void set_pointers() noexcept { impl_.ext_data().set_pointers(ptr_data()); }\n\npublic:\n    static_results_impl() noexcept\n        : impl_(results_external_data(\n              results_resultset_descriptor_table<StaticRow...>,\n              &results_fns<StaticRow...>::reset,\n              ptr_data()\n          ))\n    {\n    }\n\n    static_results_impl(const static_results_impl& rhs) : data_(rhs.data_), impl_(rhs.impl_)\n    {\n        set_pointers();\n    }\n\n    static_results_impl(static_results_impl&& rhs) noexcept\n        : data_(std::move(rhs.data_)), impl_(std::move(rhs.impl_))\n    {\n        set_pointers();\n    }\n\n    static_results_impl& operator=(const static_results_impl& rhs)\n    {\n        data_ = rhs.data_;\n        impl_ = rhs.impl_;\n        set_pointers();\n        return *this;\n    }\n\n    static_results_impl& operator=(static_results_impl&& rhs)\n    {\n        data_ = std::move(rhs.data_);\n        impl_ = std::move(rhs.impl_);\n        set_pointers();\n        return *this;\n    }\n\n    // User facing\n    template <std::size_t I>\n    rows_span_t<I, StaticRow...> get_rows() const noexcept\n    {\n        return std::get<I>(data_.rows);\n    }\n\n    const static_results_erased_impl& get_interface() const noexcept { return impl_; }\n    static_results_erased_impl& get_interface() noexcept { return impl_; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/static_results_impl.ipp>\n#endif\n\n#endif  // BOOST_MYSQL_CXX14\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/field_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_FIELD_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_FIELD_IMPL_HPP\n\n#include <boost/mysql/bad_field_access.hpp>\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/mp11/algorithm.hpp>\n#include <boost/throw_exception.hpp>\n#include <boost/variant2/variant.hpp>\n\n#include <string>\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Breaks a circular dependency between field_view and field\nstruct field_impl\n{\n    using null_t = boost::variant2::monostate;\n\n    using variant_type = boost::variant2::variant<\n        null_t,         // Any of the below when the value is NULL\n        std::int64_t,   // signed TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT\n        std::uint64_t,  // unsigned TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, YEAR, BIT\n        std::string,    // CHAR, VARCHAR,  TEXT (all sizes), , ENUM,\n                        // SET, DECIMAL\n        blob,           // BINARY, VARBINARY, BLOB (all sizes), GEOMETRY\n        float,          // FLOAT\n        double,         // DOUBLE\n        date,           // DATE\n        datetime,       // DATETIME, TIMESTAMP\n        time            // TIME\n        >;\n\n    variant_type data;\n\n    field_impl() = default;\n\n    template <typename... Args>\n    field_impl(Args&&... args) noexcept(std::is_nothrow_constructible<variant_type, Args...>::value)\n        : data(std::forward<Args>(args)...)\n    {\n    }\n\n    field_kind kind() const noexcept { return static_cast<field_kind>(data.index()); }\n\n    template <typename T>\n    const T& as() const\n    {\n        const T* res = boost::variant2::get_if<T>(&data);\n        if (!res)\n            BOOST_THROW_EXCEPTION(bad_field_access());\n        return *res;\n    }\n\n    template <typename T>\n    T& as()\n    {\n        T* res = boost::variant2::get_if<T>(&data);\n        if (!res)\n            BOOST_THROW_EXCEPTION(bad_field_access());\n        return *res;\n    }\n\n    template <typename T>\n    const T& get() const noexcept\n    {\n        constexpr auto I = mp11::mp_find<variant_type, T>::value;\n        return boost::variant2::unsafe_get<I>(data);\n    }\n\n    template <typename T>\n    T& get() noexcept\n    {\n        constexpr auto I = mp11::mp_find<variant_type, T>::value;\n        return boost::variant2::unsafe_get<I>(data);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/flags.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_FLAGS_HPP\n#define BOOST_MYSQL_DETAIL_FLAGS_HPP\n\n#include <boost/config.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nnamespace column_flags {\n\nBOOST_INLINE_CONSTEXPR std::uint16_t not_null = 1;             // Field can't be NULL.\nBOOST_INLINE_CONSTEXPR std::uint16_t pri_key = 2;              // Field is part of a primary key.\nBOOST_INLINE_CONSTEXPR std::uint16_t unique_key = 4;           // Field is part of a unique key.\nBOOST_INLINE_CONSTEXPR std::uint16_t multiple_key = 8;         // Field is part of a key.\nBOOST_INLINE_CONSTEXPR std::uint16_t blob = 16;                // Field is a blob.\nBOOST_INLINE_CONSTEXPR std::uint16_t unsigned_ = 32;           // Field is unsigned.\nBOOST_INLINE_CONSTEXPR std::uint16_t zerofill = 64;            // Field is zerofill.\nBOOST_INLINE_CONSTEXPR std::uint16_t binary = 128;             // Field is binary.\nBOOST_INLINE_CONSTEXPR std::uint16_t enum_ = 256;              // field is an enum\nBOOST_INLINE_CONSTEXPR std::uint16_t auto_increment = 512;     // field is a autoincrement field\nBOOST_INLINE_CONSTEXPR std::uint16_t timestamp = 1024;         // Field is a timestamp.\nBOOST_INLINE_CONSTEXPR std::uint16_t set = 2048;               // field is a set\nBOOST_INLINE_CONSTEXPR std::uint16_t no_default_value = 4096;  // Field doesn't have default value.\nBOOST_INLINE_CONSTEXPR std::uint16_t on_update_now = 8192;     // Field is set to NOW on UPDATE.\nBOOST_INLINE_CONSTEXPR std::uint16_t part_key = 16384;         // Intern; Part of some key.\nBOOST_INLINE_CONSTEXPR std::uint16_t num = 32768;              // Field is num (for clients)\n\n}  // namespace column_flags\n\nnamespace status_flags {\n\nBOOST_INLINE_CONSTEXPR std::uint32_t more_results = 8;\nBOOST_INLINE_CONSTEXPR std::uint32_t no_backslash_escapes = 512;\nBOOST_INLINE_CONSTEXPR std::uint32_t out_params = 4096;\n\n}  // namespace status_flags\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/format_sql.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_FORMAT_SQL_HPP\n#define BOOST_MYSQL_DETAIL_FORMAT_SQL_HPP\n\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/writable_field_traits.hpp>\n\n#include <iterator>\n#include <type_traits>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\n\n// Forward decls\ntemplate <class T>\nstruct formatter;\n\nclass format_context_base;\nclass formattable_ref;\nclass format_arg;\n\nnamespace detail {\n\nclass format_state;\n\nstruct formatter_is_unspecialized\n{\n};\n\ntemplate <class T>\nconstexpr bool has_specialized_formatter()\n{\n    return !std::is_base_of<formatter_is_unspecialized, formatter<typename std::decay<T>::type>>::value;\n}\n\ntemplate <class T>\nstruct is_writable_field_ref : is_writable_field<typename std::decay<T>::type>\n{\n};\n\ntemplate <class T>\nstruct is_formattable_ref : std::is_same<typename std::decay<T>::type, formattable_ref>\n{\n};\n\n// Is T suitable for being the element type of a formattable range?\ntemplate <class T>\nconstexpr bool is_formattable_range_elm_type()\n{\n    return is_writable_field_ref<T>::value || has_specialized_formatter<T>() || is_formattable_ref<T>::value;\n}\n\ntemplate <class T, class = void>\nstruct is_formattable_range : std::false_type\n{\n};\n\n// Note: T might be a reference.\n// Using T& + reference collapsing gets the right semantics for non-const ranges\ntemplate <class T>\nstruct is_formattable_range<\n    T,\n    typename std::enable_if<\n        // std::begin and std::end can be called on it, and we can compare values\n        std::is_convertible<decltype(std::begin(std::declval<T&>()) != std::end(std::declval<T&>())), bool>::\n            value &&\n\n        // value_type is either a writable field or a type with a specialized formatter.\n        // We don't support sequences of sequences out of the box (no known use case)\n        is_formattable_range_elm_type<decltype(*std::begin(std::declval<T&>()))>()\n\n        // end of conditions\n        >::type> : std::true_type\n{\n};\n\ntemplate <class T>\nconstexpr bool is_formattable_type()\n{\n    return is_formattable_range_elm_type<T>() || is_formattable_range<T>::value;\n}\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\n// If you're getting an error referencing this concept,\n// it means that you are attempting to format a type that doesn't support it.\ntemplate <class T>\nconcept formattable =\n    // This covers basic types and optionals\n    is_writable_field_ref<T>::value ||\n    // This covers custom types that specialized boost::mysql::formatter\n    has_specialized_formatter<T>() ||\n    // This covers ranges of formattable types\n    is_formattable_range<T>::value ||\n    // This covers passing formattable_ref as a format argument\n    is_formattable_ref<T>::value;\n\n#define BOOST_MYSQL_FORMATTABLE ::boost::mysql::detail::formattable\n\n#else\n\n#define BOOST_MYSQL_FORMATTABLE class\n\n#endif\n\n// A type-erased argument passed to format. Built-in types are passed\n// directly in the struct (as a field_view), instead of by pointer,\n// to reduce the number of do_format instantiations\nstruct formattable_ref_impl\n{\n    enum class type_t\n    {\n        field,\n        field_with_specs,\n        fn_and_ptr\n    };\n\n    struct fn_and_ptr\n    {\n        const void* obj;\n        bool (*format_fn)(const void*, const char*, const char*, format_context_base&);\n    };\n\n    union data_t\n    {\n        field_view fv;\n        fn_and_ptr custom;\n\n        data_t(field_view fv) noexcept : fv(fv) {}\n        data_t(fn_and_ptr v) noexcept : custom(v) {}\n    };\n\n    type_t type;\n    data_t data;\n};\n\n// Create a type-erased formattable_ref_impl from a formattable value\ntemplate <class T>\nformattable_ref_impl make_formattable_ref(T&& v);\n\nBOOST_MYSQL_DECL\nvoid vformat_sql_to(format_context_base& ctx, constant_string_view format_str, span<const format_arg> args);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/initiation_base.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_INITIATION_BASE_HPP\n#define BOOST_MYSQL_DETAIL_INITIATION_BASE_HPP\n\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/associator.hpp>\n#include <boost/asio/deferred.hpp>\n\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstruct executor_with_default : asio::any_io_executor\n{\n    using default_completion_token_type = with_diagnostics_t<asio::deferred_t>;\n\n    template <\n        typename InnerExecutor1,\n        class = typename std::enable_if<!std::is_same<InnerExecutor1, executor_with_default>::value>::type>\n    executor_with_default(const InnerExecutor1& ex) noexcept : asio::any_io_executor(ex)\n    {\n    }\n};\n\n// Base class for initiation objects. Includes a bound executor, so they're compatible\n// with asio::cancel_after and similar. The bound executor has our default completion token.\n// Use only in the ops that should use this token.\nstruct initiation_base\n{\n    executor_with_default ex;\n\n    initiation_base(asio::any_io_executor ex) noexcept : ex(std::move(ex)) {}\n\n    using executor_type = executor_with_default;\n    const executor_type& get_executor() const noexcept { return ex; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/intermediate_handler.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_INTERMEDIATE_HANDLER_HPP\n#define BOOST_MYSQL_DETAIL_INTERMEDIATE_HANDLER_HPP\n\n#include <boost/asio/associator.hpp>\n\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// An intermediate handler that propagates associated characteristics.\n// HandlerFn must be a function void(Handler&&, args...) that calls the handler\ntemplate <class HandlerFn, class FinalHandler>\nstruct intermediate_handler\n{\n    HandlerFn fn;\n    FinalHandler handler;\n\n    template <class... Args>\n    void operator()(Args&&... args)\n    {\n        fn(std::move(handler), std::forward<Args>(args)...);\n    }\n};\n\ntemplate <class HandlerFn, class FinalHandler>\nintermediate_handler<typename std::decay<HandlerFn>::type, typename std::decay<FinalHandler>::type> make_intermediate_handler(\n    HandlerFn&& fn,\n    FinalHandler&& handler\n)\n{\n    return {std::forward<HandlerFn>(fn), std::forward<FinalHandler>(handler)};\n}\n\n}  // namespace detail\n}  // namespace mysql\n\nnamespace asio {\n\ntemplate <\n    template <typename, typename>\n    class Associator,\n    class HandlerFn,\n    class FinalHandler,\n    typename DefaultCandidate>\nstruct associator<Associator, mysql::detail::intermediate_handler<HandlerFn, FinalHandler>, DefaultCandidate>\n    : Associator<FinalHandler, DefaultCandidate>\n{\n    static typename Associator<FinalHandler, DefaultCandidate>::type get(\n        const mysql::detail::intermediate_handler<HandlerFn, FinalHandler>& h\n    ) noexcept\n    {\n        return Associator<FinalHandler, DefaultCandidate>::get(h.handler);\n    }\n\n    static auto get(\n        const mysql::detail::intermediate_handler<HandlerFn, FinalHandler>& h,\n        const DefaultCandidate& c\n    ) noexcept -> decltype(Associator<FinalHandler, DefaultCandidate>::get(h.handler, c))\n    {\n        return Associator<FinalHandler, DefaultCandidate>::get(h.handler, c);\n    }\n};\n\n}  // namespace asio\n\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/next_action.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_NEXT_ACTION_HPP\n#define BOOST_MYSQL_DETAIL_NEXT_ACTION_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nenum class next_action_type\n{\n    none,\n    write,\n    read,\n    ssl_handshake,\n    ssl_shutdown,\n    connect,\n    close,\n};\n\nclass next_action\n{\npublic:\n    struct read_args_t\n    {\n        span<std::uint8_t> buffer;\n        bool use_ssl;\n    };\n\n    struct write_args_t\n    {\n        span<const std::uint8_t> buffer;\n        bool use_ssl;\n    };\n\n    next_action(error_code ec = {}) noexcept : type_(next_action_type::none), data_(ec) {}\n\n    // Type\n    next_action_type type() const noexcept { return type_; }\n    bool is_done() const noexcept { return type_ == next_action_type::none; }\n    bool success() const noexcept { return is_done() && !data_.ec; }\n\n    // Arguments\n    error_code error() const noexcept\n    {\n        BOOST_ASSERT(is_done());\n        return data_.ec;\n    }\n    const void* connect_endpoint() const noexcept { return data_.connect_endpoint; }\n    read_args_t read_args() const noexcept\n    {\n        BOOST_ASSERT(type_ == next_action_type::read);\n        return data_.read_args;\n    }\n    write_args_t write_args() const noexcept\n    {\n        BOOST_ASSERT(type_ == next_action_type::write);\n        return data_.write_args;\n    }\n\n    static next_action connect(const void* endpoint) noexcept\n    {\n        return next_action(next_action_type::connect, endpoint);\n    }\n    static next_action read(read_args_t args) noexcept { return next_action(next_action_type::read, args); }\n    static next_action write(write_args_t args) noexcept\n    {\n        return next_action(next_action_type::write, args);\n    }\n    static next_action ssl_handshake() noexcept\n    {\n        return next_action(next_action_type::ssl_handshake, data_t());\n    }\n    static next_action ssl_shutdown() noexcept\n    {\n        return next_action(next_action_type::ssl_shutdown, data_t());\n    }\n    static next_action close() noexcept { return next_action(next_action_type::close, data_t()); }\n\nprivate:\n    next_action_type type_{next_action_type::none};\n    union data_t\n    {\n        error_code ec;\n        const void* connect_endpoint;\n        read_args_t read_args;\n        write_args_t write_args;\n\n        data_t() noexcept : ec(error_code()) {}\n        data_t(const void* endpoint) noexcept : connect_endpoint(endpoint) {}\n        data_t(error_code ec) noexcept : ec(ec) {}\n        data_t(read_args_t args) noexcept : read_args(args) {}\n        data_t(write_args_t args) noexcept : write_args(args) {}\n    } data_;\n\n    next_action(next_action_type t, data_t data) noexcept : type_(t), data_(data) {}\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/ok_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_OK_VIEW_HPP\n#define BOOST_MYSQL_DETAIL_OK_VIEW_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/flags.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstruct ok_view\n{\n    std::uint64_t affected_rows;\n    std::uint64_t last_insert_id;\n    std::uint16_t status_flags;\n    std::uint16_t warnings;\n    string_view info;\n\n    bool more_results() const noexcept { return status_flags & status_flags::more_results; }\n    bool backslash_escapes() const noexcept { return !(status_flags & status_flags::no_backslash_escapes); }\n    bool is_out_params() const noexcept { return status_flags & status_flags::out_params; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/output_string.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_OUTPUT_STRING_HPP\n#define BOOST_MYSQL_DETAIL_OUTPUT_STRING_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <cstddef>\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n#include <concepts>\n#endif\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\ntemplate <class T>\nconcept output_string = std::movable<T> && requires(T& t, const char* data, std::size_t sz) {\n    t.append(data, sz);\n    t.clear();\n};\n\n#define BOOST_MYSQL_OUTPUT_STRING ::boost::mysql::detail::output_string\n\n#else\n\n#define BOOST_MYSQL_OUTPUT_STRING class\n\n#endif\n\nclass output_string_ref\n{\n    using append_fn_t = void (*)(void*, const char*, std::size_t);\n\n    append_fn_t append_fn_;\n    void* container_;\n\n    template <class T>\n    static void do_append(void* container, const char* data, std::size_t size)\n    {\n        static_cast<T*>(container)->append(data, size);\n    }\n\npublic:\n    output_string_ref(append_fn_t append_fn, void* container) noexcept\n        : append_fn_(append_fn), container_(container)\n    {\n    }\n\n    template <class T>\n    static output_string_ref create(T& obj) noexcept\n    {\n        return output_string_ref(&do_append<T>, &obj);\n    }\n\n    void append(string_view data)\n    {\n        if (data.size() > 0u)\n            append_fn_(container_, data.data(), data.size());\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/pipeline.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_PIPELINE_HPP\n#define BOOST_MYSQL_DETAIL_PIPELINE_HPP\n\n#include <boost/mysql/character_set.hpp>\n\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass execution_processor;\n\nenum class pipeline_stage_kind\n{\n    execute,\n    prepare_statement,\n    close_statement,\n    reset_connection,\n    set_character_set,\n    ping,\n};\n\nstruct pipeline_request_stage\n{\n    pipeline_stage_kind kind;\n    std::uint8_t seqnum;\n    union stage_specific_t\n    {\n        std::nullptr_t nothing;\n        resultset_encoding enc;\n        character_set charset;\n\n        stage_specific_t() noexcept : nothing() {}\n        stage_specific_t(resultset_encoding v) noexcept : enc(v) {}\n        stage_specific_t(character_set v) noexcept : charset(v) {}\n    } stage_specific;\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/rebind_executor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_REBIND_EXECUTOR_HPP\n#define BOOST_MYSQL_DETAIL_REBIND_EXECUTOR_HPP\n\n#include <boost/asio/ssl/stream.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// This is required because ssl::stream doesn't have a rebind_executor member type\ntemplate <class Stream, class Executor>\nstruct rebind_executor\n{\n    using type = typename Stream::template rebind_executor<Executor>::other;\n};\n\ntemplate <class Stream, class Executor>\nstruct rebind_executor<boost::asio::ssl::stream<Stream>, Executor>\n{\n    using type = boost::asio::ssl::stream<typename rebind_executor<Stream, Executor>::type>;\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/results_iterator.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_RESULTS_ITERATOR_HPP\n#define BOOST_MYSQL_DETAIL_RESULTS_ITERATOR_HPP\n\n#include <boost/mysql/resultset.hpp>\n#include <boost/mysql/resultset_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/results_impl.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass results_iterator\n{\n    const results_impl* self_{};\n    std::size_t index_{};\n\npublic:\n    using value_type = resultset;\n    using reference = resultset_view;\n    using pointer = resultset_view;\n    using difference_type = std::ptrdiff_t;\n    using iterator_category = std::random_access_iterator_tag;\n\n    results_iterator() = default;\n    results_iterator(const results_impl* self, std::size_t index) noexcept : self_(self), index_(index) {}\n\n    results_iterator& operator++() noexcept\n    {\n        ++index_;\n        return *this;\n    }\n    results_iterator operator++(int) noexcept\n    {\n        auto res = *this;\n        ++(*this);\n        return res;\n    }\n    results_iterator& operator--() noexcept\n    {\n        --index_;\n        return *this;\n    }\n    results_iterator operator--(int) noexcept\n    {\n        auto res = *this;\n        --(*this);\n        return res;\n    }\n    results_iterator& operator+=(std::ptrdiff_t n) noexcept\n    {\n        index_ += n;\n        return *this;\n    }\n    results_iterator& operator-=(std::ptrdiff_t n) noexcept\n    {\n        index_ -= n;\n        return *this;\n    }\n    results_iterator operator+(std::ptrdiff_t n) const noexcept\n    {\n        return results_iterator(self_, index_ + n);\n    }\n    results_iterator operator-(std::ptrdiff_t n) const noexcept { return *this + (-n); }\n    std::ptrdiff_t operator-(results_iterator rhs) const noexcept { return index_ - rhs.index_; }\n\n    pointer operator->() const noexcept { return **this; }\n    reference operator*() const noexcept { return (*this)[0]; }\n    reference operator[](std::ptrdiff_t i) const noexcept\n    {\n        return access::construct<resultset_view>(*self_, index_ + i);\n    }\n\n    bool operator==(results_iterator rhs) const noexcept { return index_ == rhs.index_; }\n    bool operator!=(results_iterator rhs) const noexcept { return !(*this == rhs); }\n    bool operator<(results_iterator rhs) const noexcept { return index_ < rhs.index_; }\n    bool operator<=(results_iterator rhs) const noexcept { return index_ <= rhs.index_; }\n    bool operator>(results_iterator rhs) const noexcept { return index_ > rhs.index_; }\n    bool operator>=(results_iterator rhs) const noexcept { return index_ >= rhs.index_; }\n\n    std::size_t index() const noexcept { return index_; }\n    const results_impl* obj() const noexcept { return self_; }\n};\n\ninline results_iterator operator+(std::ptrdiff_t n, results_iterator it) noexcept { return it + n; }\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/resultset_encoding.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_RESULTSET_ENCODING_HPP\n#define BOOST_MYSQL_DETAIL_RESULTSET_ENCODING_HPP\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nenum class resultset_encoding\n{\n    text,\n    binary\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* INCLUDE_BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_COMMON_HPP_ */\n"
  },
  {
    "path": "include/boost/mysql/detail/row_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ROW_IMPL_HPP\n#define BOOST_MYSQL_DETAIL_ROW_IMPL_HPP\n\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Adds num_fields default-constructed fields to the vector, return pointer to the first\n// allocated value. Used to allocate fields before deserialization\ninline span<field_view> add_fields(std::vector<field_view>& storage, std::size_t num_fields)\n{\n    std::size_t old_size = storage.size();\n    storage.resize(old_size + num_fields);\n    return span<field_view>(storage.data() + old_size, num_fields);\n}\n\n// A field_view vector with strings pointing into a\n// single character buffer. Used to implement owning row types\nclass row_impl\n{\npublic:\n    row_impl() = default;\n\n    BOOST_MYSQL_DECL\n    row_impl(const row_impl&);\n\n    row_impl(row_impl&&) = default;\n\n    BOOST_MYSQL_DECL\n    row_impl& operator=(const row_impl&);\n\n    row_impl& operator=(row_impl&&) = default;\n\n    ~row_impl() = default;\n\n    // Copies the given span into *this\n    BOOST_MYSQL_DECL\n    row_impl(const field_view* fields, std::size_t size);\n\n    // Copies the given span into *this, used by row/rows in assignment from view\n    BOOST_MYSQL_DECL\n    void assign(const field_view* fields, std::size_t size);\n\n    // Adds new default constructed fields to provide storage to deserialization\n    span<field_view> add_fields(std::size_t num_fields)\n    {\n        return ::boost::mysql::detail::add_fields(fields_, num_fields);\n    }\n\n    // Saves strings in the [first, first+num_fields) range into the string buffer, used by execute\n    BOOST_MYSQL_DECL\n    void copy_strings_as_offsets(std::size_t first, std::size_t num_fields);\n\n    // Restores any offsets into string views, used by execute\n    BOOST_MYSQL_DECL\n    void offsets_to_string_views();\n\n    const std::vector<field_view>& fields() const noexcept { return fields_; }\n\n    void clear() noexcept\n    {\n        fields_.clear();\n        string_buffer_.clear();\n    }\n\nprivate:\n    std::vector<field_view> fields_;\n    std::vector<unsigned char> string_buffer_;\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/row_impl.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/rows_iterator.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_ROWS_ITERATOR_HPP\n#define BOOST_MYSQL_DETAIL_ROWS_ITERATOR_HPP\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <iterator>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline row_view row_slice(const field_view* fields, std::size_t num_columns, std::size_t offset) noexcept\n{\n    return access::construct<row_view>(fields + num_columns * offset, num_columns);\n}\n\nclass rows_iterator\n{\n    const field_view* fields_{nullptr};\n    std::size_t num_columns_{0};\n    std::size_t row_num_{0};\n\npublic:\n    using value_type = row;\n    using reference = row_view;\n    using pointer = row_view;\n    using difference_type = std::ptrdiff_t;\n    using iterator_category = std::random_access_iterator_tag;\n\n    rows_iterator() = default;\n    rows_iterator(const field_view* fields, std::size_t num_columns, std::size_t rownum) noexcept\n        : fields_(fields), num_columns_(num_columns), row_num_(rownum)\n    {\n    }\n\n    rows_iterator& operator++() noexcept\n    {\n        ++row_num_;\n        return *this;\n    }\n    rows_iterator operator++(int) noexcept\n    {\n        auto res = *this;\n        ++(*this);\n        return res;\n    }\n    rows_iterator& operator--() noexcept\n    {\n        --row_num_;\n        return *this;\n    }\n    rows_iterator operator--(int) noexcept\n    {\n        auto res = *this;\n        --(*this);\n        return res;\n    }\n    rows_iterator& operator+=(std::ptrdiff_t n) noexcept\n    {\n        row_num_ += n;\n        return *this;\n    }\n    rows_iterator& operator-=(std::ptrdiff_t n) noexcept\n    {\n        row_num_ -= n;\n        return *this;\n    }\n    rows_iterator operator+(std::ptrdiff_t n) const noexcept\n    {\n        return rows_iterator(fields_, num_columns_, row_num_ + n);\n    }\n    rows_iterator operator-(std::ptrdiff_t n) const noexcept\n    {\n        return rows_iterator(fields_, num_columns_, row_num_ - n);\n    }\n    std::ptrdiff_t operator-(rows_iterator rhs) const noexcept { return row_num_ - rhs.row_num_; }\n\n    pointer operator->() const noexcept { return **this; }\n    reference operator*() const noexcept { return (*this)[0]; }\n    reference operator[](std::ptrdiff_t i) const noexcept\n    {\n        return row_slice(fields_, num_columns_, row_num_ + i);\n    }\n\n    bool operator==(rows_iterator rhs) const noexcept { return row_num_ == rhs.row_num_; }\n    bool operator!=(rows_iterator rhs) const noexcept { return !(*this == rhs); }\n    bool operator<(rows_iterator rhs) const noexcept { return row_num_ < rhs.row_num_; }\n    bool operator<=(rows_iterator rhs) const noexcept { return row_num_ <= rhs.row_num_; }\n    bool operator>(rows_iterator rhs) const noexcept { return row_num_ > rhs.row_num_; }\n    bool operator>=(rows_iterator rhs) const noexcept { return row_num_ >= rhs.row_num_; }\n};\n\ninline rows_iterator operator+(std::ptrdiff_t n, rows_iterator it) noexcept { return it + n; }\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/sequence.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_SEQUENCE_HPP\n#define BOOST_MYSQL_DETAIL_SEQUENCE_HPP\n\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/compat/to_array.hpp>\n#include <boost/compat/type_traits.hpp>\n\n#include <array>\n#include <cstddef>\n#include <functional>\n#include <iterator>\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n#include <concepts>\n#endif\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate <class T>\nstruct sequence_range_impl\n{\n    using type = T;\n};\n\ntemplate <class T>\nstruct sequence_range_impl<std::reference_wrapper<T>>\n{\n    using type = T&;\n};\n\ntemplate <class T, std::size_t N>\nstruct sequence_range_impl<T[N]>\n{\n    using type = std::array<T, N>;\n};\n\ntemplate <class T>\nusing sequence_range_type = sequence_range_impl<compat::remove_cvref_t<T>>;\n\ntemplate <class Range>\nRange&& cast_range(Range&& range)\n{\n    return std::forward<Range>(range);\n}\n\ntemplate <class T, std::size_t N>\nstd::array<compat::remove_cv_t<T>, N> cast_range(T (&a)[N])\n{\n    return compat::to_array(a);\n}\n\ntemplate <class T, std::size_t N>\nstd::array<compat::remove_cv_t<T>, N> cast_range(T (&&a)[N])\n{\n    return compat::to_array(std::move(a));\n}\n\n// TODO: should this be Range&&?\ntemplate <class Range, class FormatFn>\nvoid do_format_sequence(Range& range, const FormatFn& fn, constant_string_view glue, format_context_base& ctx)\n{\n    bool is_first = true;\n    for (auto it = std::begin(range); it != std::end(range); ++it)\n    {\n        if (!is_first)\n            ctx.append_raw(glue);\n        is_first = false;\n        fn(*it, ctx);\n    }\n}\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\ntemplate <class FormatFn, class Range>\nconcept format_fn_for_range = requires(const FormatFn& format_fn, Range&& range, format_context_base& ctx) {\n    { std::begin(range) != std::end(range) } -> std::convertible_to<bool>;\n    format_fn(*std::begin(range), ctx);\n    std::end(range);\n};\n#endif\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/socket_stream.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_SOCKET_STREAM_HPP\n#define BOOST_MYSQL_DETAIL_SOCKET_STREAM_HPP\n\n#include <boost/asio/basic_socket.hpp>\n#include <boost/asio/basic_stream_socket.hpp>\n\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate <class T>\nstruct is_socket : std::false_type\n{\n};\n\n// typename basic_stream_socket::lowest_layer_type is basic_socket, so we accept basic_socket and\n// basic_stream_socket here\ntemplate <class Protocol, class Executor>\nstruct is_socket<asio::basic_socket<Protocol, Executor>> : std::true_type\n{\n};\n\ntemplate <class Protocol, class Executor>\nstruct is_socket<asio::basic_stream_socket<Protocol, Executor>> : std::true_type\n{\n};\n\ntemplate <class T, class = void>\nstruct is_socket_stream : std::false_type\n{\n};\n\ntemplate <class T>\nstruct is_socket_stream<T, typename std::enable_if<is_socket<typename T::lowest_layer_type>::value>::type>\n    : std::true_type\n{\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/ssl_fwd.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_SSL_FWD_HPP\n#define BOOST_MYSQL_DETAIL_SSL_FWD_HPP\n\n// SSL headers are heavyweight\nnamespace boost {\nnamespace asio {\nnamespace ssl {\n\nclass context;\n\n}  // namespace ssl\n}  // namespace asio\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/string_view_offset.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_STRING_VIEW_OFFSET_HPP\n#define BOOST_MYSQL_DETAIL_STRING_VIEW_OFFSET_HPP\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Represents a string_view using offsets into a buffer.\n// Useful during deserialization, for buffers that may reallocate.\nstruct string_view_offset\n{\n    std::size_t offset;\n    std::size_t size;\n\n    constexpr bool operator==(string_view_offset rhs) const noexcept\n    {\n        return offset == rhs.offset && size == rhs.size;\n    }\n    constexpr bool operator!=(string_view_offset rhs) const noexcept { return !(*this == rhs); }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/throw_on_error_loc.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_THROW_ON_ERROR_LOC_HPP\n#define BOOST_MYSQL_DETAIL_THROW_ON_ERROR_LOC_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n\n#include <boost/assert/source_location.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline void throw_on_error_loc(error_code err, const diagnostics& diag, const source_location& loc)\n{\n    if (err)\n    {\n        ::boost::throw_exception(error_with_diagnostics(err, diag), loc);\n    }\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/typing/meta_check_context.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_TYPING_META_CHECK_CONTEXT_HPP\n#define BOOST_MYSQL_DETAIL_TYPING_META_CHECK_CONTEXT_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/typing/pos_map.hpp>\n\n#include <memory>\n#include <sstream>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline const char* column_type_to_str(const metadata& meta) noexcept\n{\n    switch (meta.type())\n    {\n    case column_type::tinyint: return meta.is_unsigned() ? \"TINYINT UNSIGNED\" : \"TINYINT\";\n    case column_type::smallint: return meta.is_unsigned() ? \"SMALLINT UNSIGNED\" : \"SMALLINT\";\n    case column_type::mediumint: return meta.is_unsigned() ? \"MEDIUMINT UNSIGNED\" : \"MEDIUMINT\";\n    case column_type::int_: return meta.is_unsigned() ? \"INT UNSIGNED\" : \"INT\";\n    case column_type::bigint: return meta.is_unsigned() ? \"BIGINT UNSIGNED\" : \"BIGINT\";\n    case column_type::float_: return \"FLOAT\";\n    case column_type::double_: return \"DOUBLE\";\n    case column_type::decimal: return \"DECIMAL\";\n    case column_type::bit: return \"BIT\";\n    case column_type::year: return \"YEAR\";\n    case column_type::time: return \"TIME\";\n    case column_type::date: return \"DATE\";\n    case column_type::datetime: return \"DATETIME\";\n    case column_type::timestamp: return \"TIMESTAMP\";\n    case column_type::char_: return \"CHAR\";\n    case column_type::varchar: return \"VARCHAR\";\n    case column_type::binary: return \"BINARY\";\n    case column_type::varbinary: return \"VARBINARY\";\n    case column_type::text: return \"TEXT\";\n    case column_type::blob: return \"BLOB\";\n    case column_type::enum_: return \"ENUM\";\n    case column_type::set: return \"SET\";\n    case column_type::json: return \"JSON\";\n    case column_type::geometry: return \"GEOMETRY\";\n    default: return \"<unknown column type>\";\n    }\n}\n\nclass meta_check_context\n{\n    std::unique_ptr<std::ostringstream> errors_;\n    std::size_t current_index_{};\n    span<const std::size_t> pos_map_;\n    name_table_t name_table_;\n    metadata_collection_view meta_{};\n    bool nullability_checked_{};\n\n    std::ostringstream& add_error()\n    {\n        if (!errors_)\n            errors_.reset(new std::ostringstream);\n        else\n            *errors_ << '\\n';\n        return *errors_;\n    }\n\n    void insert_field_name(std::ostringstream& os)\n    {\n        if (has_field_names(name_table_))\n            os << \"'\" << name_table_[current_index_] << \"'\";\n        else\n            os << \"in position \" << current_index_;\n    }\n\npublic:\n    meta_check_context(\n        span<const std::size_t> pos_map,\n        name_table_t name_table,\n        metadata_collection_view meta\n    ) noexcept\n        : pos_map_(pos_map), name_table_(name_table), meta_(meta)\n    {\n    }\n\n    // Accessors\n    const metadata& current_meta() const noexcept { return map_metadata(pos_map_, current_index_, meta_); }\n    bool is_current_field_absent() const noexcept { return pos_map_[current_index_] == pos_absent; }\n\n    // Iteration\n    void advance() noexcept\n    {\n        nullability_checked_ = false;\n        ++current_index_;\n    }\n\n    // Nullability\n    void set_nullability_checked() noexcept { nullability_checked_ = true; }\n    bool nullability_checked() const noexcept { return nullability_checked_; }\n\n    // Error reporting\n    BOOST_MYSQL_DECL\n    void add_field_absent_error();\n\n    BOOST_MYSQL_DECL\n    void add_type_mismatch_error(const char* cpp_type_name);\n\n    BOOST_MYSQL_DECL\n    void add_nullability_error();\n\n    BOOST_MYSQL_DECL\n    error_code check_errors(diagnostics& diag) const;\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/meta_check_context.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/typing/pos_map.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_TYPING_POS_MAP_HPP\n#define BOOST_MYSQL_DETAIL_TYPING_POS_MAP_HPP\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// These functions map C++ type positions to positions to positions in the DB query\n\nBOOST_INLINE_CONSTEXPR std::size_t pos_absent = static_cast<std::size_t>(-1);\nusing name_table_t = boost::span<const string_view>;\n\ninline bool has_field_names(name_table_t name_table) noexcept { return !name_table.empty(); }\n\ninline void pos_map_reset(span<std::size_t> self) noexcept\n{\n    for (std::size_t i = 0; i < self.size(); ++i)\n        self.data()[i] = pos_absent;\n}\n\ninline void pos_map_add_field(\n    span<std::size_t> self,\n    name_table_t name_table,\n    std::size_t db_index,\n    string_view field_name\n) noexcept\n{\n    if (has_field_names(name_table))\n    {\n        BOOST_ASSERT(self.size() == name_table.size());\n\n        // We're mapping fields by name. Try to find where in our target struct\n        // is the current field located\n        auto it = std::find(name_table.begin(), name_table.end(), field_name);\n        if (it != name_table.end())\n        {\n            std::size_t cpp_index = it - name_table.begin();\n            self[cpp_index] = db_index;\n        }\n    }\n    else\n    {\n        // We're mapping by position. Any extra trailing fields are discarded\n        if (db_index < self.size())\n        {\n            self[db_index] = db_index;\n        }\n    }\n}\n\ninline field_view map_field_view(\n    span<const std::size_t> self,\n    std::size_t cpp_index,\n    span<const field_view> array\n) noexcept\n{\n    BOOST_ASSERT(cpp_index < self.size());\n    return array[self[cpp_index]];\n}\n\ninline const metadata& map_metadata(\n    span<const std::size_t> self,\n    std::size_t cpp_index,\n    metadata_collection_view meta\n) noexcept\n{\n    BOOST_ASSERT(cpp_index < self.size());\n    return meta[self[cpp_index]];\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/typing/readable_field_traits.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP\n#define BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/typing/meta_check_context.hpp>\n#include <boost/mysql/detail/typing/pos_map.hpp>\n#include <boost/mysql/detail/void_t.hpp>\n\n#include <boost/mp11/algorithm.hpp>\n#include <boost/mp11/utility.hpp>\n\n#include <cstdint>\n#include <limits>\n#include <string>\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Helpers for integers\ntemplate <class SignedInt>\nerror_code parse_signed_int(field_view input, SignedInt& output)\n{\n    using unsigned_t = typename std::make_unsigned<SignedInt>::type;\n    using limits_t = std::numeric_limits<SignedInt>;\n\n    auto kind = input.kind();\n    if (kind == field_kind::int64)\n    {\n        auto v = input.get_int64();\n        if (v < (limits_t::min)() || v > (limits_t::max)())\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = static_cast<SignedInt>(v);\n        return error_code();\n    }\n    else if (kind == field_kind::uint64)\n    {\n        auto v = input.get_uint64();\n        if (v > static_cast<unsigned_t>((limits_t::max)()))\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = static_cast<SignedInt>(v);\n        return error_code();\n    }\n    else\n    {\n        return client_errc::static_row_parsing_error;\n    }\n}\n\ntemplate <class UnsignedInt>\nerror_code parse_unsigned_int(field_view input, UnsignedInt& output)\n{\n    if (input.kind() != field_kind::uint64)\n    {\n        return client_errc::static_row_parsing_error;\n    }\n    auto v = input.get_uint64();\n    if (v > (std::numeric_limits<UnsignedInt>::max)())\n    {\n        return client_errc::static_row_parsing_error;\n    }\n    output = static_cast<UnsignedInt>(v);\n    return error_code();\n}\n\n// We want all integer types to be allowed as fields. Some integers\n// may have the same width as others, but different type (e.g. long and long long\n// may both be 64-bit, but different types). Auxiliar int_traits to allow this to work\ntemplate <class T, bool is_signed = std::is_signed<T>::value, std::size_t width = sizeof(T)>\nstruct int_traits\n{\n    static constexpr bool is_supported = false;\n};\n\ntemplate <class T>\nstruct int_traits<T, true, 1>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"int8_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint: return !ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, false, 1>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"uint8_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint: return ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, true, 2>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"int16_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint: return true;\n        case column_type::smallint:\n        case column_type::year: return !ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, false, 2>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"uint16_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint:\n        case column_type::smallint:\n        case column_type::year: return ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, true, 4>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"int32_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint:\n        case column_type::smallint:\n        case column_type::year:\n        case column_type::mediumint: return true;\n        case column_type::int_: return !ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, false, 4>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"uint32_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint:\n        case column_type::smallint:\n        case column_type::year:\n        case column_type::mediumint:\n        case column_type::int_: return ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, true, 8>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"int64_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint:\n        case column_type::smallint:\n        case column_type::year:\n        case column_type::mediumint:\n        case column_type::int_: return true;\n        case column_type::bigint: return !ctx.current_meta().is_unsigned();\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }\n};\n\ntemplate <class T>\nstruct int_traits<T, false, 8>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"uint64_t\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::tinyint:\n        case column_type::smallint:\n        case column_type::year:\n        case column_type::mediumint:\n        case column_type::int_:\n        case column_type::bigint: return ctx.current_meta().is_unsigned();\n        case column_type::bit: return true;\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, std::uint64_t& output)\n    {\n        return parse_unsigned_int(input, output);\n    }\n};\n\n// Traits\ntemplate <typename T, class EnableIf = void>\nstruct readable_field_traits\n{\n    static constexpr bool is_supported = false;\n};\n\ntemplate <>\nstruct readable_field_traits<char, void> : int_traits<char>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<signed char, void> : int_traits<signed char>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<unsigned char, void> : int_traits<unsigned char>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<short, void> : int_traits<short>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<unsigned short, void> : int_traits<unsigned short>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<int, void> : int_traits<int>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<unsigned int, void> : int_traits<unsigned int>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<long, void> : int_traits<long>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<unsigned long, void> : int_traits<unsigned long>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<long long, void> : int_traits<long long>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<unsigned long long, void> : int_traits<unsigned long long>\n{\n};\n\ntemplate <>\nstruct readable_field_traits<bool, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"bool\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        return ctx.current_meta().type() == column_type::tinyint && !ctx.current_meta().is_unsigned();\n    }\n    static error_code parse(field_view input, bool& output)\n    {\n        if (input.kind() != field_kind::int64)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = input.get_int64() != 0;\n        return error_code();\n    }\n};\n\ntemplate <>\nstruct readable_field_traits<float, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"float\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        return ctx.current_meta().type() == column_type::float_;\n    }\n    static error_code parse(field_view input, float& output)\n    {\n        if (input.kind() != field_kind::float_)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = input.get_float();\n        return error_code();\n    }\n};\n\ntemplate <>\nstruct readable_field_traits<double, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"double\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::float_:\n        case column_type::double_: return true;\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, double& output)\n    {\n        auto kind = input.kind();\n        if (kind == field_kind::float_)\n        {\n            output = input.get_float();\n            return error_code();\n        }\n        else if (kind == field_kind::double_)\n        {\n            output = input.get_double();\n            return error_code();\n        }\n        else\n        {\n            return client_errc::static_row_parsing_error;\n        }\n    }\n};\n\ntemplate <class Allocator>\nstruct readable_field_traits<std::basic_string<char, std::char_traits<char>, Allocator>, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"string\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::decimal:\n        case column_type::char_:\n        case column_type::varchar:\n        case column_type::text:\n        case column_type::enum_:\n        case column_type::set:\n        case column_type::json: return true;\n        default: return false;\n        }\n    }\n    static error_code parse(\n        field_view input,\n        std::basic_string<char, std::char_traits<char>, Allocator>& output\n    )\n    {\n        if (input.kind() != field_kind::string)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = input.get_string();\n        return error_code();\n    }\n};\n\ntemplate <class Allocator>\nstruct readable_field_traits<std::vector<unsigned char, Allocator>, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"blob\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::binary:\n        case column_type::varbinary:\n        case column_type::blob:\n        case column_type::geometry:\n        case column_type::unknown: return true;\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, std::vector<unsigned char, Allocator>& output)\n    {\n        if (input.kind() != field_kind::blob)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        auto view = input.get_blob();\n        output.assign(view.begin(), view.end());\n        return error_code();\n    }\n};\n\ntemplate <>\nstruct readable_field_traits<date, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"date\";\n    static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::date; }\n    static error_code parse(field_view input, date& output)\n    {\n        if (input.kind() != field_kind::date)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = input.get_date();\n        return error_code();\n    }\n};\n\ntemplate <>\nstruct readable_field_traits<datetime, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"datetime\";\n    static bool meta_check(meta_check_context& ctx)\n    {\n        switch (ctx.current_meta().type())\n        {\n        case column_type::datetime:\n        case column_type::timestamp: return true;\n        default: return false;\n        }\n    }\n    static error_code parse(field_view input, datetime& output)\n    {\n        if (input.kind() != field_kind::datetime)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = input.get_datetime();\n        return error_code();\n    }\n};\n\ntemplate <>\nstruct readable_field_traits<time, void>\n{\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = \"time\";\n    static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::time; }\n    static error_code parse(field_view input, time& output)\n    {\n        if (input.kind() != field_kind::time)\n        {\n            return client_errc::static_row_parsing_error;\n        }\n        output = input.get_time();\n        return error_code();\n    }\n};\n\n// std::optional<T> and boost::optional<T>. To avoid dependencies,\n// this is achieved through a \"concept\"\ntemplate <class T, class = void>\nstruct is_readable_optional : std::false_type\n{\n};\n\ntemplate <class T>\nstruct is_readable_optional<\n    T,\n    void_t<\n        typename std::enable_if<\n            std::is_same<decltype(std::declval<T&>().value()), typename T::value_type&>::value>::type,\n        decltype(std::declval<T&>().emplace()),  // T should be default constructible\n        decltype(std::declval<T&>().reset())>> : std::true_type\n{\n};\n\ntemplate <class T>\nstruct readable_field_traits<\n    T,\n    typename std::enable_if<\n        is_readable_optional<T>::value && readable_field_traits<typename T::value_type>::is_supported>::type>\n{\n    using value_type = typename T::value_type;\n    static constexpr bool is_supported = true;\n    static BOOST_INLINE_CONSTEXPR const char* type_name = readable_field_traits<value_type>::type_name;\n    static bool meta_check(meta_check_context& ctx)\n    {\n        ctx.set_nullability_checked();\n        return readable_field_traits<value_type>::meta_check(ctx);\n    }\n    static error_code parse(field_view input, T& output)\n    {\n        if (input.is_null())\n        {\n            output.reset();\n            return error_code();\n        }\n        else\n        {\n            output.emplace();\n            return readable_field_traits<value_type>::parse(input, output.value());\n        }\n    }\n};\n\ntemplate <class T>\nstruct is_readable_field\n{\n    static constexpr bool value = readable_field_traits<T>::is_supported;\n};\n\ntemplate <typename ReadableField>\nvoid meta_check_field_impl(meta_check_context& ctx)\n{\n    using traits_t = readable_field_traits<ReadableField>;\n\n    // Verify that the field is present\n    if (ctx.is_current_field_absent())\n    {\n        ctx.add_field_absent_error();\n        return;\n    }\n\n    // Perform the check\n    bool ok = traits_t::meta_check(ctx);\n    if (!ok)\n    {\n        ctx.add_type_mismatch_error(traits_t::type_name);\n    }\n\n    // Check nullability\n    if (!ctx.nullability_checked() && !ctx.current_meta().is_not_null())\n    {\n        ctx.add_nullability_error();\n    }\n}\n\ntemplate <typename ReadableField>\nvoid meta_check_field(meta_check_context& ctx)\n{\n    static_assert(is_readable_field<ReadableField>::value, \"Should be a ReadableField\");\n    meta_check_field_impl<ReadableField>(ctx);\n    ctx.advance();\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/typing/row_traits.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_TYPING_ROW_TRAITS_HPP\n#define BOOST_MYSQL_DETAIL_TYPING_ROW_TRAITS_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/typing/meta_check_context.hpp>\n#include <boost/mysql/detail/typing/pos_map.hpp>\n#include <boost/mysql/detail/typing/readable_field_traits.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/describe/members.hpp>\n#include <boost/mp11/algorithm.hpp>\n#include <boost/mp11/list.hpp>\n#include <boost/mp11/utility.hpp>\n\n#include <cstddef>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n//\n// Base templates. Every StaticRow type must specialize the row_traits class,\n// providing the following members:\n//\n//    // type of the actual row to be parsed. This supports marker types, like pfr_by_name\n//    using underlying_row_type = /* */;\n//\n//    // MP11 type list with the row's member types\n//    using field_types = /* */;\n//\n//    static constexpr name_table_t name_table() noexcept; // field names\n//\n//    template <class F> /* Apply F to each member */\n//    static void for_each_member(underlying_row_t<StaticRow>& to, F&& function);\n//\n\n//\nstruct row_traits_is_unspecialized\n{\n};\n\ntemplate <class T, bool is_describe_struct = describe::has_describe_members<T>::value>\nclass row_traits : public row_traits_is_unspecialized\n{\n};\n\n//\n// Describe structs\n//\n// Workaround std::array::data not being constexpr in C++14\ntemplate <class T, std::size_t N>\nstruct array_wrapper\n{\n    T data_[N];\n\n    constexpr boost::span<const T> span() const noexcept { return boost::span<const T>(data_); }\n};\n\ntemplate <class T>\nstruct array_wrapper<T, 0>\n{\n    struct\n    {\n    } data_;  // allow empty brace initialization\n\n    constexpr boost::span<const T> span() const noexcept { return boost::span<const T>(); }\n};\n\n// Workaround for char_traits::length not being constexpr in C++14\n// Only used to retrieve Describe member name lengths\nconstexpr std::size_t get_length(const char* s) noexcept\n{\n    const char* p = s;\n    while (*p)\n        ++p;\n    return p - s;\n}\n\ntemplate <class DescribeStruct>\nusing row_members = describe::\n    describe_members<DescribeStruct, describe::mod_public | describe::mod_inherited>;\n\ntemplate <template <class...> class ListType, class... MemberDescriptor>\nconstexpr array_wrapper<string_view, sizeof...(MemberDescriptor)> get_describe_names(ListType<\n                                                                                     MemberDescriptor...>)\n{\n    return {{string_view(MemberDescriptor::name, get_length(MemberDescriptor::name))...}};\n}\n\ntemplate <class DescribeStruct>\nBOOST_INLINE_CONSTEXPR auto describe_names_storage = get_describe_names(row_members<DescribeStruct>{});\n\ntemplate <class DescribeStruct>\nclass row_traits<DescribeStruct, true>\n{\n    // clang-format off\n    template <class D>\n    using descriptor_to_type = typename\n        std::remove_reference<decltype(std::declval<DescribeStruct>().*std::declval<D>().pointer)>::type;\n    // clang-format on\n\npublic:\n    using underlying_row_type = DescribeStruct;\n    using field_types = mp11::mp_transform<descriptor_to_type, row_members<DescribeStruct>>;\n\n    static constexpr name_table_t name_table() noexcept\n    {\n        return describe_names_storage<DescribeStruct>.span();\n    }\n\n    template <class F>\n    static void for_each_member(DescribeStruct& to, F&& function)\n    {\n        mp11::mp_for_each<row_members<DescribeStruct>>([function, &to](auto D) { function(to.*D.pointer); });\n    }\n};\n\n//\n// Tuples\n//\ntemplate <class... ReadableField>\nclass row_traits<std::tuple<ReadableField...>, false>\n{\npublic:\n    using underlying_row_type = std::tuple<ReadableField...>;\n    using field_types = std::tuple<ReadableField...>;\n    static constexpr name_table_t name_table() noexcept { return name_table_t(); }\n\n    template <class F>\n    static void for_each_member(underlying_row_type& to, F&& function)\n    {\n        mp11::tuple_for_each(to, std::forward<F>(function));\n    }\n};\n\n//\n// Helpers to implement the external interface section\n//\n\n// Helpers to check that all the fields satisfy ReadableField\n// and produce meaningful error messages, with the offending field type, at least\n// Workaround clang 3.6 not liking generic lambdas in the below constexpr function\nstruct readable_field_checker\n{\n    template <class TypeIdentity>\n    constexpr void operator()(TypeIdentity) const noexcept\n    {\n        using T = typename TypeIdentity::type;\n        static_assert(\n            is_readable_field<T>::value,\n            \"You're trying to use an unsupported field type in a row type. Review your row type definitions.\"\n        );\n    }\n};\n\ntemplate <class TypeList>\nstatic constexpr bool check_readable_field() noexcept\n{\n    mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, TypeList>>(readable_field_checker{});\n    return true;\n}\n\n// Centralize where check_readable_field happens\ntemplate <class StaticRow>\nstruct row_traits_with_check : row_traits<StaticRow>\n{\n    static_assert(check_readable_field<typename row_traits<StaticRow>::field_types>(), \"\");\n};\n\n// Meta checking\nstruct meta_check_field_fn\n{\n    meta_check_context& ctx;\n\n    template <class TypeIdentity>\n    void operator()(TypeIdentity)\n    {\n        meta_check_field<typename TypeIdentity::type>(ctx);\n    }\n};\n\n// Useful for testing\ntemplate <class ReadableFieldList>\nerror_code meta_check_impl(\n    name_table_t name_table,\n    span<const std::size_t> pos_map,\n    metadata_collection_view meta,\n    diagnostics& diag\n)\n{\n    BOOST_ASSERT(pos_map.size() == mp11::mp_size<ReadableFieldList>::value);\n    meta_check_context ctx(pos_map, name_table, meta);\n    mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, ReadableFieldList>>(meta_check_field_fn{ctx});\n    return ctx.check_errors(diag);\n}\n\n// Parsing\nclass parse_context\n{\n    span<const std::size_t> pos_map_;\n    span<const field_view> fields_;\n    std::size_t index_{};\n    error_code ec_;\n\npublic:\n    parse_context(span<const std::size_t> pos_map, span<const field_view> fields) noexcept\n        : pos_map_(pos_map), fields_(fields)\n    {\n    }\n\n    template <class ReadableField>\n    void parse(ReadableField& output)\n    {\n        auto ec = readable_field_traits<ReadableField>::parse(\n            map_field_view(pos_map_, index_++, fields_),\n            output\n        );\n        if (!ec_)\n            ec_ = ec;\n    }\n\n    error_code error() const noexcept { return ec_; }\n};\n\n// Using this instead of a lambda reduces the number of generated instantiations\nstruct parse_functor\n{\n    parse_context& ctx;\n\n    template <class ReadableField>\n    void operator()(ReadableField& output) const\n    {\n        ctx.parse(output);\n    }\n};\n\n//\n// External interface. Other Boost.MySQL components should never use row_traits\n// directly, but the functions below, instead.\n//\ntemplate <class T>\nBOOST_INLINE_CONSTEXPR bool\n    is_static_row = !std::is_base_of<row_traits_is_unspecialized, row_traits<T>>::value;\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\n// Note that static_row only inspects the shape of the row only (i.e. it's a tuple vs. it's nothing we know),\n// and not individual fields. These are static_assert-ed in individual row_traits. This gives us an error\n// message that contains the offending types, at least.\ntemplate <class T>\nconcept static_row = is_static_row<T>;\n\n#define BOOST_MYSQL_STATIC_ROW ::boost::mysql::detail::static_row\n\n#else\n#define BOOST_MYSQL_STATIC_ROW class\n#endif\n\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nusing underlying_row_t = typename row_traits_with_check<StaticRow>::underlying_row_type;\n\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nconstexpr std::size_t get_row_size() noexcept\n{\n    return mp11::mp_size<typename row_traits_with_check<StaticRow>::field_types>::value;\n}\n\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nconstexpr name_table_t get_row_name_table() noexcept\n{\n    return row_traits_with_check<StaticRow>::name_table();\n}\n\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nerror_code meta_check(span<const std::size_t> pos_map, metadata_collection_view meta, diagnostics& diag)\n{\n    using field_types = typename row_traits_with_check<StaticRow>::field_types;\n    BOOST_ASSERT(pos_map.size() == get_row_size<StaticRow>());\n    return meta_check_impl<field_types>(get_row_name_table<StaticRow>(), pos_map, meta, diag);\n}\n\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nerror_code parse(\n    span<const std::size_t> pos_map,\n    span<const field_view> from,\n    underlying_row_t<StaticRow>& to\n)\n{\n    BOOST_ASSERT(pos_map.size() == get_row_size<StaticRow>());\n    BOOST_ASSERT(from.size() >= get_row_size<StaticRow>());\n    parse_context ctx(pos_map, from);\n    row_traits_with_check<StaticRow>::for_each_member(to, parse_functor{ctx});\n    return ctx.error();\n}\n\nusing meta_check_fn_t =\n    error_code (*)(span<const std::size_t> field_map, metadata_collection_view meta, diagnostics& diag);\n\n// For multi-resultset\ntemplate <class... StaticRow>\nBOOST_INLINE_CONSTEXPR std::size_t max_num_columns = (std::max)({get_row_size<StaticRow>()...});\n\nBOOST_INLINE_CONSTEXPR std::size_t index_not_found = static_cast<std::size_t>(-1);\n\ntemplate <class UnderlyingRowType, class... RowType>\nconstexpr std::size_t get_type_index() noexcept\n{\n    using lunique = mp11::mp_unique<mp11::mp_list<underlying_row_t<RowType>...>>;\n    using index_t = mp11::mp_find<lunique, UnderlyingRowType>;\n    return index_t::value < mp11::mp_size<lunique>::value ? index_t::value : index_not_found;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif  // BOOST_MYSQL_CXX14\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/detail/void_t.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_VOID_T_HPP\n#define BOOST_MYSQL_DETAIL_VOID_T_HPP\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate <typename...>\nusing void_t = void;\n\n}\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP_ */\n"
  },
  {
    "path": "include/boost/mysql/detail/writable_field_traits.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DETAIL_WRITABLE_FIELD_TRAITS_HPP\n#define BOOST_MYSQL_DETAIL_WRITABLE_FIELD_TRAITS_HPP\n\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate <class T, class En1 = void, class En2 = void>\nstruct writable_field_traits\n{\n    static constexpr bool is_supported = false;\n};\n\ntemplate <>\nstruct writable_field_traits<bool>\n{\n    static constexpr bool is_supported = true;\n    static field_view to_field(bool value) noexcept { return field_view(value ? 1 : 0); }\n};\n\ntemplate <class T>\nstruct writable_field_traits<\n    T,\n    typename std::enable_if<\n        std::is_constructible<field_view, const T&>::value && std::is_object<T>::value>::type,\n    void>\n{\n    static constexpr bool is_supported = true;\n    static field_view to_field(const T& value) noexcept { return field_view(value); }\n};\n\n// Optionals. To avoid dependencies, we use a \"concept\".\n// We consider a type an optional if has a `bool has_value() const` and\n// `const value_type& value() const`\ntemplate <class T>\nstruct writable_field_traits<\n    T,\n    void,\n    typename std::enable_if<\n        std::is_same<decltype(std::declval<const T&>().has_value()), bool>::value &&\n        std::is_same<decltype(std::declval<const T&>().value()), const typename T::value_type&>::value>::type>\n{\n    using value_traits = writable_field_traits<typename T::value_type>;\n    static constexpr bool is_supported = value_traits::is_supported;\n    static field_view to_field(const T& value) noexcept\n    {\n        return value.has_value() ? value_traits::to_field(value.value()) : field_view();\n    }\n};\n\ntemplate <class T>\nfield_view to_field(const T& value) noexcept\n{\n    return writable_field_traits<T>::to_field(value);\n}\n\ntemplate <class T>\nstruct is_writable_field : std::integral_constant<bool, writable_field_traits<T>::is_supported>\n{\n};\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\ntemplate <class T>\nconcept writable_field = is_writable_field<T>::value;\n\n#define BOOST_MYSQL_WRITABLE_FIELD ::boost::mysql::detail::writable_field\n\n#else\n\n#define BOOST_MYSQL_WRITABLE_FIELD class\n\n#endif\n\n// field_view_forward_iterator\ntemplate <typename T, typename = void>\nstruct is_field_view_forward_iterator : std::false_type\n{\n};\n\n// clang-format off\ntemplate <typename T>\nstruct is_field_view_forward_iterator<\n    T,\n    typename std::enable_if<\n        std::is_convertible<\n            typename std::iterator_traits<T>::reference,\n            field_view\n        >::value\n        &&\n        std::is_base_of<\n            std::forward_iterator_tag, \n            typename std::iterator_traits<T>::iterator_category\n        >::value\n    >::type\n> : std::true_type { };\n// clang-format on\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\ntemplate <class T>\nconcept field_view_forward_iterator = is_field_view_forward_iterator<T>::value;\n\n#define BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR ::boost::mysql::detail::field_view_forward_iterator\n\n#else  // BOOST_MYSQL_HAS_CONCEPTS\n\n#define BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR class\n\n#endif  // BOOST_MYSQL_HAS_CONCEPTS\n\n// writable_field_tuple\ntemplate <class... T>\nstruct is_writable_field_tuple_impl : std::false_type\n{\n};\n\ntemplate <class... T>\nstruct is_writable_field_tuple_impl<std::tuple<T...>>\n    : mp11::mp_all_of<mp11::mp_list<typename std::remove_reference<T>::type...>, is_writable_field>\n{\n};\n\ntemplate <class Tuple>\nstruct is_writable_field_tuple : is_writable_field_tuple_impl<typename std::decay<Tuple>::type>\n{\n};\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\ntemplate <class T>\nconcept writable_field_tuple = is_writable_field_tuple<T>::value;\n\n#define BOOST_MYSQL_WRITABLE_FIELD_TUPLE ::boost::mysql::detail::writable_field_tuple\n\n#else  // BOOST_MYSQL_HAS_CONCEPTS\n\n#define BOOST_MYSQL_WRITABLE_FIELD_TUPLE class\n\n#endif  // BOOST_MYSQL_HAS_CONCEPTS\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/diagnostics.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_DIAGNOSTICS_HPP\n#define BOOST_MYSQL_DIAGNOSTICS_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <string>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Contains additional information about errors.\n * \\details\n * This class is a container for additional diagnostics about an operation that\n * failed. It can contain server-generated messages (\\ref server_message) or client-side messages\n * (\\ref client_message). More members may be added in the future.\n */\nclass diagnostics\n{\npublic:\n    /**\n     * \\brief Constructs a diagnostics object with empty error messages.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    diagnostics() = default;\n\n    /**\n     * \\brief Gets the client-generated error message.\n     * \\details\n     * Contrary to \\ref server_message, the client message never contains any string data\n     * returned by the server, and is always ASCII-encoded. If you're using the static interface,\n     * it may contain C++ type identifiers, too.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view is valid as long as `*this` is alive, hasn't been assigned-to\n     * or moved-from, and \\ref clear hasn't been called. Moving `*this` invalidates the view.\n     */\n    string_view client_message() const noexcept\n    {\n        return impl_.is_server ? string_view() : string_view(impl_.msg);\n    }\n\n    /**\n     * \\brief Gets the server-generated error message.\n     * \\details\n     * It's encoded according to `character_set_results` character set, which\n     * usually matches the connection's character set. It may potentially contain user input.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view is valid as long as `*this` is alive, hasn't been assigned-to\n     * or moved-from, and \\ref clear hasn't been called. Moving `*this` invalidates the view.\n     */\n    string_view server_message() const noexcept\n    {\n        return impl_.is_server ? string_view(impl_.msg) : string_view();\n    }\n\n    /**\n     * \\brief Clears the error messages.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void clear() noexcept\n    {\n        impl_.is_server = false;\n        impl_.msg.clear();\n    }\n\nprivate:\n#ifndef BOOST_MYSQL_DOXYGEN\n    struct\n    {\n        bool is_server{};\n        std::string msg;\n\n        void assign_client(std::string from)\n        {\n            msg = std::move(from);\n            is_server = false;\n        }\n\n        void assign_server(std::string from)\n        {\n            msg = std::move(from);\n            is_server = true;\n        }\n\n    } impl_;\n\n    friend bool operator==(const diagnostics& lhs, const diagnostics& rhs) noexcept;\n    friend struct detail::access;\n#endif\n};\n\n/**\n * \\relates diagnostics\n * \\brief Compares two diagnostics objects.\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator==(const diagnostics& lhs, const diagnostics& rhs) noexcept\n{\n    return lhs.impl_.is_server == rhs.impl_.is_server && lhs.impl_.msg == rhs.impl_.msg;\n}\n\n/**\n * \\relates diagnostics\n * \\brief Compares two diagnostics objects.\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator!=(const diagnostics& lhs, const diagnostics& rhs) noexcept { return !(lhs == rhs); }\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/error_categories.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ERROR_CATEGORIES_HPP\n#define BOOST_MYSQL_ERROR_CATEGORIES_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/system/error_category.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Returns the error_category associated to \\ref client_errc.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Object lifetimes\n * The returned reference is always valid (points to a singleton).\n *\n * \\par Thread safety\n * This function is thread-safe.\n */\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_client_category() noexcept;\n\n/**\n * \\brief Returns the error_category associated to \\ref common_server_errc.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Object lifetimes\n * The returned reference is always valid (points to a singleton).\n *\n * \\par Thread safety\n * This function is thread-safe.\n */\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_common_server_category() noexcept;\n\n/**\n * \\brief Returns the error_category associated to errors specific to MySQL.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Object lifetimes\n * The returned reference is always valid (points to a singleton).\n *\n * \\par Thread safety\n * This function is thread-safe.\n */\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_mysql_server_category() noexcept;\n\n/**\n * \\brief Returns the error_category associated to errors specific to MariaDB.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Object lifetimes\n * The returned reference is always valid (points to a singleton).\n *\n * \\par Thread safety\n * This function is thread-safe.\n */\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_mariadb_server_category() noexcept;\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/error_categories.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/error_code.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ERROR_CODE_HPP\n#define BOOST_MYSQL_ERROR_CODE_HPP\n\n#include <boost/system/error_code.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/// An alias for boost::system error codes.\nusing error_code = boost::system::error_code;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/error_with_diagnostics.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ERROR_WITH_DIAGNOSTICS_HPP\n#define BOOST_MYSQL_ERROR_WITH_DIAGNOSTICS_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/system/system_error.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A system_error with an embedded diagnostics object.\n * \\details\n * Like `boost::system::system_error`, but adds a \\ref diagnostics member\n * containing additional information.\n */\nclass error_with_diagnostics : public system::system_error\n{\n    diagnostics diag_;\n\n    static system::system_error create_base(const error_code& err, const diagnostics& diag)\n    {\n        return diag.client_message().empty() ? system::system_error(err)\n                                             : system::system_error(err, diag.client_message());\n    }\n\npublic:\n    /// Initializing constructor.\n    error_with_diagnostics(const error_code& err, const diagnostics& diag)\n        : system::system_error(create_base(err, diag)), diag_(diag)\n    {\n    }\n\n    /**\n     * \\brief Retrieves the server diagnostics embedded in this object.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive.\n     */\n    const diagnostics& get_diagnostics() const noexcept { return diag_; }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/escape_string.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ESCAPE_STRING_HPP\n#define BOOST_MYSQL_ESCAPE_STRING_HPP\n\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/escape_string.hpp>\n#include <boost/mysql/detail/output_string.hpp>\n\n#include <boost/config.hpp>\n\nnamespace boost {\nnamespace mysql {\n\nstruct format_options;\n\n/**\n * \\brief Identifies the context which a string is being escaped for.\n */\nenum class quoting_context : char\n{\n    /// The string is surrounded by double quotes.\n    double_quote = '\"',\n\n    /// The string is surrounded by single quotes.\n    single_quote = '\\'',\n\n    /// The string is surrounded by backticks.\n    backtick = '`',\n};\n\n/**\n * \\brief Escapes a string, making it safe for query composition.\n * \\details\n * Given a string `input`, computes a string with special characters\n * escaped, and places it in `output`. This function is a low-level building\n * block for composing client-side queries with runtime string values without\n * incurring in SQL injection vulnerabilities.\n * If you can, prefer using higher-level functions like \\ref format_sql.\n * \\n\n * Escaping rules are different depending on the context a string is\n * being used in. `quot_ctx` identifies where the string will appear in\n * a query. Possible values are: \\n\n * \\li \\ref quoting_context::double_quote : the string is surrounded by\n *     double quotes.\n * \\li \\ref quoting_context::single_quote : the string is surrounded by\n *     single quotes.\n * \\li \\ref quoting_context::backtick : the string is surrounded by\n *     backticks, as happens when escaping identifiers.\n * \\n\n * By default, MySQL treats backslash characters as escapes in string values\n * (for instance, the string `\"\\n\"` is treated as a newline). This behavior is\n * enabled by default, but can be disabled by enabling the\n * <a\n *    href=\"https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_no_backslash_escapes\">`NO_BACKSLASH_ESCAPES`</a>\n * SQL mode. When enabled, backslashes no longer have a special meaning, which changes\n * the escaping rules. `opts.backslash_escapes` should be set to `true` if backslashes represent\n * escapes (i.e. `NO_BACKSLASH_ESCAPES` is not enabled), and `false` otherwise.\n * \\n\n * MySQL can be configured to treat double-quoted strings as identifiers instead of values.\n * This is enabled by activating the\n * <a href=\"https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_ansi_quotes\">`ANSI_QUOTES`</a> or\n * <a href=\"https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_ansi\">`ANSI`</a> SQL modes.\n * Servers don't report whether this mode is enabled to clients.\n * This SQL mode is not directly supported by this function.\n * \\n\n * `opts.charset` should identify the connection's character set (as given by the\n * `character_set_client` session variable). The character set is used to iterate\n * over the input string. It must be an ASCII-compatible character set (like \\ref utf8mb4_charset).\n * All character sets allowed by `character_set_client` satisfy this requirement.\n * \\n\n * You can use \\ref any_connection::format_opts to retrieve an `opts` value suitable for your connection.\n * \\n\n * \\par Exception safety\n * Basic guarantee. Memory allocations may throw.\n *\n * \\par Complexity\n * Linear in `input.size()`.\n *\n * \\par Errors\n * \\ref client_errc::invalid_encoding if `input` contains a string\n *      that is not valid according to `opts.charset`.\n */\ntemplate <BOOST_MYSQL_OUTPUT_STRING OutputString>\nBOOST_ATTRIBUTE_NODISCARD error_code\nescape_string(string_view input, const format_options& opts, quoting_context quot_ctx, OutputString& output)\n{\n    output.clear();\n    return detail::escape_string(\n        input,\n        opts,\n        static_cast<char>(quot_ctx),\n        detail::output_string_ref::create(output)\n    );\n}\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/execution_state.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_EXECUTION_STATE_HPP\n#define BOOST_MYSQL_EXECUTION_STATE_HPP\n\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/execution_state_impl.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Holds state for multi-function SQL execution operations (dynamic interface).\n * \\details\n * This class behaves like a state machine. The current state can be accessed using\n * \\ref should_start_op, \\ref should_read_rows, \\ref should_read_head\n * and \\ref complete. They are mutually exclusive.\n * More states may be added in the future as more protocol features are implemented.\n *\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe.\n */\nclass execution_state\n{\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details The constructed object is guaranteed to have\n     * `should_start_op() == true`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    execution_state() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s.\n     */\n    execution_state(const execution_state& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Views obtained from `other` remain valid.\n     */\n    execution_state(execution_state&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s. Views obtained from `*this`\n     * are invalidated.\n     */\n    execution_state& operator=(const execution_state& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Views obtained from `*this` are invalidated. Views obtained from `other` remain valid.\n     */\n    execution_state& operator=(execution_state&& other) = default;\n\n    /**\n     * \\brief Returns whether `*this` is in the initial state.\n     * \\details\n     * Call \\ref connection::start_execution or \\ref connection::async_start_execution to move\n     * forward. No data is available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool should_start_op() const noexcept { return impl_.is_reading_first(); }\n\n    /**\n     * \\brief Returns whether the next operation should be read resultset head.\n     * \\details\n     * Call \\ref connection::read_resultset_head or its async counterpart to move forward.\n     * Metadata and OK data for the previous resultset is available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool should_read_head() const noexcept { return impl_.is_reading_first_subseq(); }\n\n    /**\n     * \\brief Returns whether the next operation should be read some rows.\n     * \\details\n     * Call \\ref connection::read_some_rows or its async counterpart to move forward.\n     * Metadata for the current resultset is available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool should_read_rows() const noexcept { return impl_.is_reading_rows(); }\n\n    /**\n     * \\brief Returns whether all the messages generated by this operation have been read.\n     * \\details\n     * No further network calls are required to move forward. Metadata and OK data for the last\n     * resultset are available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool complete() const noexcept { return impl_.is_complete(); }\n\n    /**\n     * \\brief Returns metadata about the columns in the query.\n     * \\details\n     * The returned collection will have as many \\ref metadata objects as columns retrieved by\n     * the SQL query, and in the same order.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     */\n    metadata_collection_view meta() const noexcept { return impl_.meta(); }\n\n    /**\n     * \\brief Returns the number of rows affected by the SQL statement associated to this resultset.\n     * Note that this is NOT the number of matched rows. If a row\n     * is matched but not affected, it won't be accounted for here.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     */\n    std::uint64_t affected_rows() const noexcept { return impl_.get_affected_rows(); }\n\n    /**\n     * \\brief Returns the last insert ID produced by the SQL statement associated to this resultset.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     */\n    std::uint64_t last_insert_id() const noexcept { return impl_.get_last_insert_id(); }\n\n    /**\n     * \\brief Returns the number of warnings produced by the SQL statement associated to this resultset.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     */\n    unsigned warning_count() const noexcept { return impl_.get_warning_count(); }\n\n    /**\n     * \\brief Returns additional text information about this resultset.\n     * \\details\n     * The format of this information is documented by MySQL <a\n     * href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html\">here</a>.\n     * \\n\n     * The returned string always uses ASCII encoding, regardless of the connection's character set.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     */\n    string_view info() const noexcept { return impl_.get_info(); }\n\n    /**\n     * \\brief Returns whether the current resultset represents a procedure OUT params.\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_out_params() const noexcept { return impl_.get_is_out_params(); }\n\nprivate:\n    detail::execution_state_impl impl_;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/field.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_FIELD_HPP\n#define BOOST_MYSQL_FIELD_HPP\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/field_impl.hpp>\n\n#include <boost/config.hpp>\n#include <boost/variant2/variant.hpp>\n\n#include <cstddef>\n#include <iosfwd>\n#include <string>\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n#include <string_view>\n#endif\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Variant-like class that can represent of any of the allowed database types.\n * \\details\n * This is a regular variant-like class that can represent any of the types that MySQL allows. It\n * has value semantics (as opposed to \\ref field_view). Instances of this class are not created\n * by the library. They should be created by the user, when the reference semantics of\n * \\ref field_view are not appropriate.\n * \\n\n * Like a variant, at any point, a `field` always contains a value of\n * certain type. You can query the type using \\ref kind and the `is_xxx` functions\n * like \\ref is_int64. Use `as_xxx` and `get_xxx` for checked and unchecked value\n * access, respectively. You can mutate a `field` by calling the assignment operator,\n * or using the lvalue references returned by `as_xxx` and `get_xxx`.\n */\nclass field\n{\npublic:\n    /**\n     * \\brief Constructs a `field` holding NULL.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    field() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     */\n    field(const field&) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * All references into `other` are invalidated, including the ones obtained by calling\n     * get_xxx, as_xxx and \\ref field::operator field_view().\n     */\n    field(field&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(const field&) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references to `*this` obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view(). All references into `other`\n     * are invalidated, including the ones obtained by calling get_xxx, as_xxx and\n     * \\ref field::operator field_view().\n     */\n    field& operator=(field&& other) = default;\n\n    /// Destructor.\n    ~field() = default;\n\n    /**\n     * \\brief Constructs a `field` holding NULL.\n     * \\details\n     * Caution: `field(NULL)` will __NOT__ match this overload. It will try to construct\n     * a `string_view` from a NULL C string, causing undefined behavior.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(std::nullptr_t) noexcept {}\n\n    /**\n     * \\brief Constructs a `field` holding an `int64`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(signed char v) noexcept : repr_(std::int64_t(v)) {}\n\n    /// \\copydoc field(signed char)\n    explicit field(short v) noexcept : repr_(std::int64_t(v)) {}\n\n    /// \\copydoc field(signed char)\n    explicit field(int v) noexcept : repr_(std::int64_t(v)) {}\n\n    /// \\copydoc field(signed char)\n    explicit field(long v) noexcept : repr_(std::int64_t(v)) {}\n\n    /// \\copydoc field(signed char)\n    explicit field(long long v) noexcept : repr_(std::int64_t(v)) {}\n\n    /**\n     * \\brief Constructs a `field` holding an `uint64`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(unsigned char v) noexcept : repr_(std::uint64_t(v)) {}\n\n    /// \\copydoc field(unsigned char)\n    explicit field(unsigned short v) noexcept : repr_(std::uint64_t(v)) {}\n\n    /// \\copydoc field(unsigned char)\n    explicit field(unsigned int v) noexcept : repr_(std::uint64_t(v)) {}\n\n    /// \\copydoc field(unsigned char)\n    explicit field(unsigned long v) noexcept : repr_(std::uint64_t(v)) {}\n\n    /// \\copydoc field(unsigned char)\n    explicit field(unsigned long long v) noexcept : repr_(std::uint64_t(v)) {}\n\n    /**\n     * \\brief Constructors from character types would incorrectly construct a `field` holding an integer,\n     * so they are not allowed.\n     */\n    explicit field(char) = delete;\n\n    /// \\copydoc field(char)\n    explicit field(wchar_t) = delete;\n\n    /// \\copydoc field(char)\n    explicit field(char16_t) = delete;\n\n    /// \\copydoc field(char)\n    explicit field(char32_t) = delete;\n\n#ifdef __cpp_char8_t\n    /// \\copydoc field(char)\n    explicit field(char8_t) = delete;\n#endif\n\n    /**\n     * \\brief Constructs a `field` holding a string.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     */\n    explicit field(const std::string& v) : repr_(v) {}\n\n    /**\n     * \\brief Constructs a `field` holding a string.\n     * \\details v is moved into an internal `std::string` object.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(std::string&& v) noexcept : repr_(std::move(v)) {}\n\n    /// \\copydoc field(const std::string&)\n    explicit field(const char* v) : repr_(boost::variant2::in_place_type_t<std::string>(), v) {}\n\n    /// \\copydoc field(const std::string&)\n    explicit field(string_view v) : repr_(boost::variant2::in_place_type_t<std::string>(), v) {}\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n    /// \\copydoc field(const std::string&)\n    explicit field(std::string_view v) : repr_(boost::variant2::in_place_type_t<std::string>(), v) {}\n#endif\n\n    /**\n     * \\brief Constructs a `field` holding a `blob`.\n     * \\details v is moved into an internal `blob` object.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(blob v) noexcept : repr_(std::move(v)) {}\n\n    /**\n     * \\brief Constructs a `field` holding a `float`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(float v) noexcept : repr_(v) {}\n\n    /**\n     * \\brief Constructs a `field` holding a `double`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(double v) noexcept : repr_(v) {}\n\n    /**\n     * \\brief Constructs a `field` holding a `date`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(const date& v) noexcept : repr_(v) {}\n\n    /**\n     * \\brief Constructs a `field` holding a `datetime`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(const datetime& v) noexcept : repr_(v) {}\n\n    /**\n     * \\brief Constructs a `field` holding a `time`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    explicit field(const time& v) noexcept : repr_(v) {}\n\n    /**\n     * \\brief Constructs a `field` from a \\ref field_view.\n     * \\details The resulting `field` has the same kind and value as the original `field_view`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * The resulting `field` is guaranteed to be valid even after `v` becomes invalid.\n     */\n    field(const field_view& v) { from_view(v); }\n\n    /**\n     * \\brief Replaces `*this` with a `NULL`, changing the kind to `null` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(std::nullptr_t) noexcept\n    {\n        repr_.data.emplace<detail::field_impl::null_t>();\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `int64` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(signed char v) noexcept\n    {\n        repr_.data.emplace<std::int64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(signed char)\n    field& operator=(short v) noexcept\n    {\n        repr_.data.emplace<std::int64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(signed char)\n    field& operator=(int v) noexcept\n    {\n        repr_.data.emplace<std::int64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(signed char)\n    field& operator=(long v) noexcept\n    {\n        repr_.data.emplace<std::int64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(signed char)\n    field& operator=(long long v) noexcept\n    {\n        repr_.data.emplace<std::int64_t>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `uint64` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(unsigned char v) noexcept\n    {\n        repr_.data.emplace<std::uint64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(unsigned char)\n    field& operator=(unsigned short v) noexcept\n    {\n        repr_.data.emplace<std::uint64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(unsigned char)\n    field& operator=(unsigned int v) noexcept\n    {\n        repr_.data.emplace<std::uint64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(unsigned char)\n    field& operator=(unsigned long v) noexcept\n    {\n        repr_.data.emplace<std::uint64_t>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(unsigned char)\n    field& operator=(unsigned long long v) noexcept\n    {\n        repr_.data.emplace<std::uint64_t>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Assignments from character types would incorrectly assign an integer,\n     * so they are not allowed.\n     */\n    field& operator=(char) = delete;\n\n    /// \\copydoc operator=(char)\n    field& operator=(wchar_t) = delete;\n\n    /// \\copydoc operator=(char)\n    field& operator=(char16_t) = delete;\n\n    /// \\copydoc operator=(char)\n    field& operator=(char32_t) = delete;\n\n#ifdef __cpp_char8_t\n    /// \\copydoc operator=(char)\n    field& operator=(char8_t) = delete;\n#endif\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `string` and destroying any previous\n     * contents.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(const std::string& v)\n    {\n        repr_.data.emplace<std::string>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(const std::string&)\n    field& operator=(std::string&& v)\n    {\n        repr_.data.emplace<std::string>(std::move(v));\n        return *this;\n    }\n\n    /// \\copydoc operator=(const std::string&)\n    field& operator=(const char* v)\n    {\n        repr_.data.emplace<std::string>(v);\n        return *this;\n    }\n\n    /// \\copydoc operator=(const std::string&)\n    field& operator=(string_view v)\n    {\n        repr_.data.emplace<std::string>(v);\n        return *this;\n    }\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n    /// \\copydoc operator=(const std::string&)\n    field& operator=(std::string_view v)\n    {\n        repr_.data.emplace<std::string>(v);\n        return *this;\n    }\n#endif\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `blob` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(blob v)\n    {\n        repr_.data.emplace<blob>(std::move(v));\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `float_` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(float v) noexcept\n    {\n        repr_.data.emplace<float>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `double` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(double v) noexcept\n    {\n        repr_.data.emplace<double>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `date` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(const date& v) noexcept\n    {\n        repr_.data.emplace<date>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `datetime` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions,\n     * but not the ones obtained by \\ref field::operator field_view().\n     */\n    field& operator=(const datetime& v) noexcept\n    {\n        repr_.data.emplace<datetime>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `time` and destroying any\n     * previous contents.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Invalidates references obtained by as_xxx and get_xxx functions, but not\n     */\n    field& operator=(const time& v) noexcept\n    {\n        repr_.data.emplace<time>(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Replaces `*this` with `v`, changing the kind to `v.kind()` and destroying any previous\n     * contents.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * Invalidates references to `*this` obtained by as_xxx and get_xxx functions, but not\n     * the ones obtained by \\ref field::operator field_view().\n     *\\n\n     * `*this` is guaranteed to be valid even after `v` becomes invalid.\n     */\n    field& operator=(const field_view& v)\n    {\n        from_view(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Returns the type of the value this `field` is holding.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    field_kind kind() const noexcept { return repr_.kind(); }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `NULL` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_null() const noexcept { return kind() == field_kind::null; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `int64` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_int64() const noexcept { return kind() == field_kind::int64; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `uint64` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_uint64() const noexcept { return kind() == field_kind::uint64; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a string value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_string() const noexcept { return kind() == field_kind::string; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a blob value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_blob() const noexcept { return kind() == field_kind::blob; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `float` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_float() const noexcept { return kind() == field_kind::float_; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `double` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_double() const noexcept { return kind() == field_kind::double_; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `date` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_date() const noexcept { return kind() == field_kind::date; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `datetime` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_datetime() const noexcept { return kind() == field_kind::datetime; }\n\n    /**\n     * \\brief Returns whether this `field` is holding a `time` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_time() const noexcept { return kind() == field_kind::time; }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `std::int64_t` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_int64()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const std::int64_t& as_int64() const { return repr_.as<std::int64_t>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `std::uint64_t` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_uint64()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const std::uint64_t& as_uint64() const { return repr_.as<std::uint64_t>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `std::string` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_string()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const std::string& as_string() const { return repr_.as<std::string>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `blob` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_blob()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const blob& as_blob() const { return repr_.as<blob>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `float` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_float()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const float& as_float() const { return repr_.as<float>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `double` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_double()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const double& as_double() const { return repr_.as<double>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `date` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_date()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const date& as_date() const { return repr_.as<date>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `datetime` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_datetime()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const datetime& as_datetime() const { return repr_.as<datetime>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `time` value or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_time()`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const time& as_time() const { return repr_.as<time>(); }\n\n    /// \\copydoc as_int64\n    std::int64_t& as_int64() { return repr_.as<std::int64_t>(); }\n\n    /// \\copydoc as_uint64\n    std::uint64_t& as_uint64() { return repr_.as<std::uint64_t>(); }\n\n    /// \\copydoc as_string\n    std::string& as_string() { return repr_.as<std::string>(); }\n\n    /// \\copydoc as_blob\n    blob& as_blob() { return repr_.as<blob>(); }\n\n    /// \\copydoc as_float\n    float& as_float() { return repr_.as<float>(); }\n\n    /// \\copydoc as_double\n    double& as_double() { return repr_.as<double>(); }\n\n    /// \\copydoc as_date\n    date& as_date() { return repr_.as<date>(); }\n\n    /// \\copydoc as_datetime\n    datetime& as_datetime() { return repr_.as<datetime>(); }\n\n    /// \\copydoc as_time\n    time& as_time() { return repr_.as<time>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `std::int64_t` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_int64() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const std::int64_t& get_int64() const noexcept { return repr_.get<std::int64_t>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `std::uint64_t` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_uint64() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const std::uint64_t& get_uint64() const noexcept { return repr_.get<std::uint64_t>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `std::string` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_string() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const std::string& get_string() const noexcept { return repr_.get<std::string>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `blob` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_blob() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const blob& get_blob() const noexcept { return repr_.get<blob>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `float` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_float() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const float& get_float() const noexcept { return repr_.get<float>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `double` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_double() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const double& get_double() const noexcept { return repr_.get<double>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `date` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_date() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const date& get_date() const noexcept { return repr_.get<date>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `datetime` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_datetime() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const datetime& get_datetime() const noexcept { return repr_.get<datetime>(); }\n\n    /**\n     * \\brief Retrieves a reference to the underlying `time` value (unchecked access).\n     * \\par Preconditions\n     * `this->is_time() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and no function that invalidates\n     * references is called on `*this`.\n     */\n    const time& get_time() const noexcept { return repr_.get<time>(); }\n\n    /// \\copydoc get_int64\n    std::int64_t& get_int64() noexcept { return repr_.get<std::int64_t>(); }\n\n    /// \\copydoc get_uint64\n    std::uint64_t& get_uint64() noexcept { return repr_.get<std::uint64_t>(); }\n\n    /// \\copydoc get_string\n    std::string& get_string() noexcept { return repr_.get<std::string>(); }\n\n    /// \\copydoc get_blob\n    blob& get_blob() noexcept { return repr_.get<blob>(); }\n\n    /// \\copydoc get_float\n    float& get_float() noexcept { return repr_.get<float>(); }\n\n    /// \\copydoc get_double\n    double& get_double() noexcept { return repr_.get<double>(); }\n\n    /// \\copydoc get_date\n    date& get_date() noexcept { return repr_.get<date>(); }\n\n    /// \\copydoc get_datetime\n    datetime& get_datetime() noexcept { return repr_.get<datetime>(); }\n\n    /// \\copydoc get_time\n    time& get_time() noexcept { return repr_.get<time>(); }\n\n    /**\n     * \\brief Constructs a \\ref field_view pointing to `*this`.\n     * \\details The resulting `field_view` has the same kind and value as `*this`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned object acts as a\n     * reference to `*this`, and will be valid as long as `*this` is alive.\n     */\n    inline operator field_view() const noexcept { return field_view(&repr_); }\n\nprivate:\n    detail::field_impl repr_;\n\n    BOOST_MYSQL_DECL\n    void from_view(const field_view& v);\n};\n\n/**\n * \\relates field\n * \\brief Tests for equality.\n * \\details The same considerations as \\ref field_view::operator== apply.\n *\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator==(const field& lhs, const field& rhs) noexcept\n{\n    return field_view(lhs) == field_view(rhs);\n}\n\n/**\n * \\relates field\n * \\brief Tests for inequality.\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator!=(const field& lhs, const field& rhs) noexcept { return !(lhs == rhs); }\n\n/**\n * \\relates field\n * \\brief Tests for equality.\n * \\details The same considerations as \\ref field_view::operator== apply.\n *\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator==(const field_view& lhs, const field& rhs) noexcept { return lhs == field_view(rhs); }\n\n/**\n * \\relates field\n * \\brief Tests for inequality.\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator!=(const field_view& lhs, const field& rhs) noexcept { return !(lhs == rhs); }\n\n/**\n * \\relates field\n * \\brief Tests for equality.\n * \\details The same considerations as \\ref field_view::operator== apply.\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator==(const field& lhs, const field_view& rhs) noexcept { return field_view(lhs) == rhs; }\n\n/**\n * \\relates field\n * \\brief Tests for inequality.\n * \\par Exception safety\n * No-throw guarantee.\n */\ninline bool operator!=(const field& lhs, const field_view& rhs) noexcept { return !(lhs == rhs); }\n\n/**\n * \\relates field\n * \\brief Streams a `field`.\n */\nBOOST_MYSQL_DECL\nstd::ostream& operator<<(std::ostream& os, const field& v);\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/field.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/field_kind.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_FIELD_KIND_HPP\n#define BOOST_MYSQL_FIELD_KIND_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <iosfwd>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Represents the possible C++ types a `field` or `field_view` may have.\n */\nenum class field_kind\n{\n    // Order here is important\n\n    /// Any of the below when the value is NULL\n    null = 0,\n\n    /// The field contains a `std::int64_t`.\n    int64,\n\n    /// The field contains a `std::uint64_t`.\n    uint64,\n\n    /**\n     * \\brief The field contains a string (`std::string` for `field` and \\ref string_view for\n     * `field_view`).\n     */\n    string,\n\n    /**\n     * \\brief The field contains a binary string (\\ref blob for `field` and \\ref blob_view for\n     * `field_view`).\n     */\n    blob,\n\n    /// The field contains a `float`.\n    float_,\n\n    /// The field contains a `double`.\n    double_,\n\n    /// The field contains a \\ref date.\n    date,\n\n    /// The field contains a \\ref datetime.\n    datetime,\n\n    /// The field contains a \\ref time.\n    time\n};\n\n/**\n * \\brief Streams a field_kind.\n */\nBOOST_MYSQL_DECL\nstd::ostream& operator<<(std::ostream& os, field_kind v);\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/field_kind.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/field_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_FIELD_VIEW_HPP\n#define BOOST_MYSQL_FIELD_VIEW_HPP\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/field_impl.hpp>\n#include <boost/mysql/detail/string_view_offset.hpp>\n\n#include <boost/config.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <iosfwd>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Non-owning variant-like class that can represent of any of the allowed database types.\n * \\details\n * This is a variant-like class, similar to \\ref field, but semi-owning and read-only. Values\n * of this type are usually created by the library, not directly by the user. It's cheap to\n * construct and copy, and it's the main library interface when reading values from MySQL.\n * \\n\n * Like a variant, at any point, a `field_view` always points to a value of\n * certain type. You can query the type using \\ref field_view::kind and the `is_xxx` functions\n * like \\ref field_view::is_int64. Use `as_xxx` and `get_xxx` for checked and unchecked value\n * access, respectively. As opposed to \\ref field, these functions return values instead of\n * references.\n *\n * \\par Object lifetimes\n * Depending on how it was constructed, `field_view` can have value or reference semantics:\n * \\n\n * \\li If it was created by the library, the `field_view` will have an associated \\ref row,\n *     \\ref rows or \\ref results object holding memory to which the `field_view` points. It will be valid as\n *     long as the memory allocated by that object is valid.\n * \\li If it was created from a \\ref field (by calling `operator field_view`), the\n *     `field_view` acts as a reference to that `field` object, and will be valid as long as the\n *     `field` is.\n * \\li If it was created from a scalar (null, integral, floating point, date, datetime or time), the\n *     `field_view` has value semnatics and will always be valid.\n * \\li If it was created from a string or blob type, the `field_view` acts as a `string_view` or `blob_view`,\n *     and will be valid as long as the original string/blob is.\n * \\n\n * Calling any member function on a `field_view` that has been invalidated results in undefined\n * behavior.\n */\nclass field_view\n{\npublic:\n    /**\n     * \\brief Constructs a `field_view` holding NULL.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR field_view() = default;\n\n    /**\n     * \\brief Constructs a `field_view` holding NULL.\n     * \\details\n     * Caution: `field_view(NULL)` will <b>not</b> match this overload. It will try to construct\n     * a `string_view` from a NULL C string, causing undefined behavior.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(std::nullptr_t) noexcept {}\n\n    /**\n     * \\brief Constructs a `field_view` holding an `int64`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(signed char v) noexcept : impl_{std::int64_t(v)} {}\n\n    /// \\copydoc field_view(signed char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(short v) noexcept : impl_{std::int64_t(v)} {}\n\n    /// \\copydoc field_view(signed char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(int v) noexcept : impl_{std::int64_t(v)} {}\n\n    /// \\copydoc field_view(signed char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(long v) noexcept : impl_{std::int64_t(v)} {}\n\n    /// \\copydoc field_view(signed char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(long long v) noexcept : impl_{std::int64_t(v)} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a `uint64`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(unsigned char v) noexcept : impl_{std::uint64_t(v)} {}\n\n    /// \\copydoc field_view(unsigned char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(unsigned short v) noexcept : impl_{std::uint64_t(v)} {}\n\n    /// \\copydoc field_view(unsigned char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(unsigned int v) noexcept : impl_{std::uint64_t(v)} {}\n\n    /// \\copydoc field_view(unsigned char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(unsigned long v) noexcept : impl_{std::uint64_t(v)} {}\n\n    /// \\copydoc field_view(unsigned char)\n    BOOST_CXX14_CONSTEXPR explicit field_view(unsigned long long v) noexcept : impl_{std::uint64_t(v)} {}\n\n    /**\n     * \\brief Constructors from character types would incorrectly construct a `field_view` holding an integer,\n     * so they are not allowed.\n     */\n    explicit field_view(char) = delete;\n\n    /// \\copydoc field_view(char)\n    explicit field_view(wchar_t) = delete;\n\n    /// \\copydoc field_view(char)\n    explicit field_view(char16_t) = delete;\n\n    /// \\copydoc field_view(char)\n    explicit field_view(char32_t) = delete;\n\n#ifdef __cpp_char8_t\n    /// \\copydoc field_view(char)\n    explicit field_view(char8_t) = delete;\n#endif\n\n    /**\n     * \\brief Constructs a `field_view` holding a string.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with reference semantics. It will\n     * be valid as long as the character buffer the `string_view` points to is valid.\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(string_view v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a blob.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with reference semantics. It will\n     * be valid as long as the character buffer the `blob_view` points to is valid.\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(blob_view v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a `float`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(float v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a `double`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(double v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a `date`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(const date& v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a `datetime`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(const datetime& v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Constructs a `field_view` holding a `time`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Results in a `field_view` with value semantics (always valid).\n     */\n    BOOST_CXX14_CONSTEXPR explicit field_view(const time& v) noexcept : impl_{v} {}\n\n    /**\n     * \\brief Returns the type of the value this `field_view` is pointing to.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline field_kind kind() const noexcept;\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `NULL` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_null() const noexcept { return kind() == field_kind::null; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `int64` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_int64() const noexcept { return kind() == field_kind::int64; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `uint64` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_uint64() const noexcept { return kind() == field_kind::uint64; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a string value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_string() const noexcept { return kind() == field_kind::string; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a binary blob.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_blob() const noexcept { return kind() == field_kind::blob; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `float` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_float() const noexcept { return kind() == field_kind::float_; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `double` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_double() const noexcept { return kind() == field_kind::double_; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `date` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_date() const noexcept { return kind() == field_kind::date; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `datetime` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_datetime() const noexcept { return kind() == field_kind::datetime; }\n\n    /**\n     * \\brief Returns whether this `field_view` points to a `time` value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool is_time() const noexcept { return kind() == field_kind::time; }\n\n    /**\n     * \\brief Retrieves the underlying value as an `int64` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_int64()`\n     */\n    BOOST_CXX14_CONSTEXPR inline std::int64_t as_int64() const;\n\n    /**\n     * \\brief Retrieves the underlying value as an `uint64` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_uint64()`\n     */\n    BOOST_CXX14_CONSTEXPR inline std::uint64_t as_uint64() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a string or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_string()`\n     * \\par Object lifetimes\n     * The returned view has the same lifetime rules as `*this` (it's valid as long as `*this` is valid).\n     */\n    BOOST_CXX14_CONSTEXPR inline string_view as_string() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a blob or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_blob()`\n     * \\par Object lifetimes\n     * The returned view has the same lifetime rules as `*this` (it's valid as long as `*this` is valid).\n     */\n    BOOST_CXX14_CONSTEXPR inline blob_view as_blob() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a `float` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_float()`\n     */\n    BOOST_CXX14_CONSTEXPR inline float as_float() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a `double` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_double()`\n     */\n    BOOST_CXX14_CONSTEXPR inline double as_double() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a `date` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_date()`\n     */\n    BOOST_CXX14_CONSTEXPR inline date as_date() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a `datetime` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_datetime()`\n     */\n    BOOST_CXX14_CONSTEXPR inline datetime as_datetime() const;\n\n    /**\n     * \\brief Retrieves the underlying value as a `time` or throws an exception.\n     * \\par Exception safety\n     * Strong guarantee. Throws on type mismatch.\n     * \\throws bad_field_access If `!this->is_time()`\n     */\n    BOOST_CXX14_CONSTEXPR inline time as_time() const;\n\n    /**\n     * \\brief Retrieves the underlying value as an `int64` (unchecked access).\n     * \\par Preconditions\n     * `this->is_int64() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline std::int64_t get_int64() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<std::int64_t>() : impl_.repr.int64;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as an `uint64` (unchecked access).\n     * \\par Preconditions\n     * `this->is_uint64() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline std::uint64_t get_uint64() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<std::uint64_t>() : impl_.repr.uint64;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a string (unchecked access).\n     * \\par Preconditions\n     * `this->is_string() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view has the same lifetime rules as `*this` (it's valid as long as `*this` is valid).\n     */\n    BOOST_CXX14_CONSTEXPR inline string_view get_string() const noexcept\n    {\n        return is_field_ptr() ? string_view(impl_.repr.field_ptr->get<std::string>()) : impl_.repr.string;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a blob (unchecked access).\n     * \\par Preconditions\n     * `this->is_blob() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view has the same lifetime rules as `*this` (it's valid as long as `*this` is valid).\n     */\n    BOOST_CXX14_CONSTEXPR inline blob_view get_blob() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<blob>() : impl_.repr.blob;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a `float` (unchecked access).\n     * \\par Preconditions\n     * `this->is_float() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline float get_float() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<float>() : impl_.repr.float_;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a `double` (unchecked access).\n     * \\par Preconditions\n     * `this->is_double() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline double get_double() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<double>() : impl_.repr.double_;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a `date` (unchecked access).\n     * \\par Preconditions\n     * `this->is_date() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline date get_date() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<date>() : impl_.repr.date_;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a `datetime` (unchecked access).\n     * \\par Preconditions\n     * `this->is_datetime() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline datetime get_datetime() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<datetime>() : impl_.repr.datetime_;\n    }\n\n    /**\n     * \\brief Retrieves the underlying value as a `time` (unchecked access).\n     * \\par Preconditions\n     * `this->is_time() == true` (if violated, results in undefined behavior).\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline time get_time() const noexcept\n    {\n        return is_field_ptr() ? impl_.repr.field_ptr->get<time>() : impl_.repr.time_;\n    }\n\n    /**\n     * \\brief Tests for equality.\n     * \\details\n     * If one of the operands is a `uint64` and the other a\n     * `int64`, and the values are equal, returns `true`. Otherwise, if the types are\n     * different, returns always `false` (`float` and `double` values are considered to be\n     * different between them). `NULL` values are equal to other `NULL` values.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR inline bool operator==(const field_view& rhs) const noexcept;\n\n    /**\n     * \\brief Tests for inequality.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    BOOST_CXX14_CONSTEXPR bool operator!=(const field_view& rhs) const noexcept { return !(*this == rhs); }\n\nprivate:\n    BOOST_CXX14_CONSTEXPR explicit field_view(detail::string_view_offset v, bool is_blob) noexcept\n        : impl_{v, is_blob}\n    {\n    }\n\n    BOOST_CXX14_CONSTEXPR explicit field_view(const detail::field_impl* v) noexcept : impl_{v} {}\n\n    enum class internal_kind\n    {\n        null = 0,\n        int64,\n        uint64,\n        string,\n        blob,\n        float_,\n        double_,\n        date,\n        datetime,\n        time,\n        sv_offset_string,\n        sv_offset_blob,\n        field_ptr\n    };\n\n    union repr_t\n    {\n        std::int64_t int64;\n        std::uint64_t uint64;\n        string_view string;\n        blob_view blob;\n        float float_;\n        double double_;\n        date date_;\n        datetime datetime_;\n        time time_;\n        detail::string_view_offset sv_offset_;\n        const detail::field_impl* field_ptr;\n\n        BOOST_CXX14_CONSTEXPR repr_t() noexcept : int64{} {}\n        BOOST_CXX14_CONSTEXPR repr_t(std::int64_t v) noexcept : int64(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(std::uint64_t v) noexcept : uint64(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(string_view v) noexcept : string{v} {}\n        BOOST_CXX14_CONSTEXPR repr_t(blob_view v) noexcept : blob{v} {}\n        BOOST_CXX14_CONSTEXPR repr_t(float v) noexcept : float_(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(double v) noexcept : double_(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(date v) noexcept : date_(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(datetime v) noexcept : datetime_(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(time v) noexcept : time_(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(detail::string_view_offset v) noexcept : sv_offset_(v) {}\n        BOOST_CXX14_CONSTEXPR repr_t(const detail::field_impl* v) noexcept : field_ptr(v) {}\n    };\n\n    struct impl_t\n    {\n        internal_kind ikind{internal_kind::null};\n        repr_t repr{};\n\n        // Required by lib internal functions\n        bool is_string_offset() const noexcept { return ikind == internal_kind::sv_offset_string; }\n        bool is_blob_offset() const noexcept { return ikind == internal_kind::sv_offset_blob; }\n\n        BOOST_CXX14_CONSTEXPR impl_t() = default;\n        BOOST_CXX14_CONSTEXPR impl_t(std::int64_t v) noexcept : ikind(internal_kind::int64), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(std::uint64_t v) noexcept : ikind(internal_kind::uint64), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(string_view v) noexcept : ikind(internal_kind::string), repr{v} {}\n        BOOST_CXX14_CONSTEXPR impl_t(blob_view v) noexcept : ikind(internal_kind::blob), repr{v} {}\n        BOOST_CXX14_CONSTEXPR impl_t(float v) noexcept : ikind(internal_kind::float_), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(double v) noexcept : ikind(internal_kind::double_), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(date v) noexcept : ikind(internal_kind::date), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(datetime v) noexcept : ikind(internal_kind::datetime), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(time v) noexcept : ikind(internal_kind::time), repr(v) {}\n        BOOST_CXX14_CONSTEXPR impl_t(detail::string_view_offset v, bool is_blob) noexcept\n            : ikind(is_blob ? internal_kind::sv_offset_blob : internal_kind::sv_offset_string), repr{v}\n        {\n        }\n        BOOST_CXX14_CONSTEXPR impl_t(const detail::field_impl* v) noexcept\n            : ikind(internal_kind::field_ptr), repr(v)\n        {\n        }\n    } impl_;\n\n    BOOST_CXX14_CONSTEXPR bool is_field_ptr() const noexcept\n    {\n        return impl_.ikind == internal_kind::field_ptr;\n    }\n    BOOST_CXX14_CONSTEXPR inline void check_kind(internal_kind expected) const;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend class field;\n    friend struct detail::access;\n    BOOST_MYSQL_DECL\n    friend std::ostream& operator<<(std::ostream& os, const field_view& v);\n#endif\n};\n\n/**\n * \\relates field_view\n * \\brief Streams a `field_view`.\n */\nBOOST_MYSQL_DECL\nstd::ostream& operator<<(std::ostream& os, const field_view& v);\n\n}  // namespace mysql\n}  // namespace boost\n\n#include <boost/mysql/impl/field_view.hpp>\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/field_view.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/format_sql.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_FORMAT_SQL_HPP\n#define BOOST_MYSQL_FORMAT_SQL_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/format_sql.hpp>\n#include <boost/mysql/detail/output_string.hpp>\n\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n#include <boost/system/result.hpp>\n\n#include <initializer_list>\n#include <string>\n#include <type_traits>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief An extension point to customize SQL formatting.\n * \\details\n * This type can be specialized for custom types to make them formattable.\n * This makes them satisfy the `Formattable` concept, and thus usable in\n * \\ref format_sql and similar functions.\n * \\n\n * A `formatter` specialization for a type `T` should have the following form:\n * ```\n * template <>\n * struct formatter<T>\n * {\n *     const char* parse(const char* begin, const char* end); // parse format specs\n *     void format(const T& value, format_context_base& ctx) const; // perform the actual formatting\n * };\n * ```\n * \\n\n * When a value with a custom formatter is formatted (using \\ref format_sql or a similar\n * function), the library performs the following actions: \\n\n *   - An instance of `formatter<T>` is default-constructed, where `T` is the type of the\n *     value being formatted after removing const and references.\n *   - The `parse` function is invoked on the constructed instance,\n *     with `[begin, end)` pointing to the format specifier\n *     that the current replacement field has. If `parse` finds specifiers it understands, it should\n *     remember them, usually setting some flag in the `formatter` instance.\n *     `parse` must return an iterator to the first\n *     unparsed character in the range (or the `end` iterator, if everything was parsed).\n *     Some examples of what would get passed to `parse`:\n *       - In `\"SELECT {}\"`, the range would be empty.\n *       - In `\"SELECT {:abc}\"`, the range would be `\"abc\"`.\n *       - In `\"SELECT {0:i}\"`, the range would be `\"i\"`.\n *   - If `parse` didn't manage to parse all the passed specifiers (i.e. if it returned an iterator\n *     different to the passed's end), a \\ref client_errc::format_string_invalid_specifier\n *     is emitted and the format operation finishes.\n *   - Otherwise, `format` is invoked on the formatter instance, passing the value to be formatted\n *     and the \\ref format_context_base where format operation is running.\n *     This function should perform the actual formatting, usually calling\n *     \\ref format_sql_to on the passed context.\n *\n * \\n\n * Don't specialize `formatter` for built-in types, like `int`, `std::string` or\n * optionals (formally, any type satisfying `WritableField`), as the specializations will be ignored.\n */\ntemplate <class T>\nstruct formatter\n#ifndef BOOST_MYSQL_DOXYGEN\n    : detail::formatter_is_unspecialized\n{\n}\n#endif\n;\n\n/**\n * \\brief A type-erased reference to a `Formattable` value.\n * \\details\n * This type can hold references to any value that satisfies the `Formattable`\n * concept. The `formattable_ref` type itself satisfies `Formattable`,\n * and can thus be used as an argument to format functions.\n *\n * \\par Object lifetimes\n * This is a non-owning type. It should be only used as a function argument,\n * to avoid lifetime issues.\n */\nclass formattable_ref\n{\n    detail::formattable_ref_impl impl_;\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\npublic:\n    /**\n     * \\brief Constructor.\n     * \\details\n     * Constructs a type-erased formattable reference from a concrete\n     * `Formattable` type.\n     * \\n\n     * This constructor participates in overload resolution only if\n     * the passed value meets the `Formattable` concept and\n     * is not a `formattable_ref` or a reference to one.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * value is potentially stored as a view, although some cheap-to-copy\n     * types may be stored as values.\n     */\n    template <\n        BOOST_MYSQL_FORMATTABLE Formattable\n#ifndef BOOST_MYSQL_DOXYGEN\n        ,\n        class = typename std::enable_if<\n            detail::is_formattable_type<Formattable>() &&\n            !detail::is_formattable_ref<Formattable>::value>::type\n#endif\n        >\n    formattable_ref(Formattable&& value) noexcept\n        : impl_(detail::make_formattable_ref(std::forward<Formattable>(value)))\n    {\n    }\n};\n\n/**\n * \\brief A named format argument, to be used in initializer lists.\n * \\details\n * Represents a name, value pair to be passed to a formatting function.\n * This type should only be used in initializer lists, as a function argument.\n *\n * \\par Object lifetimes\n * This is a non-owning type. Both the argument name and value are stored\n * as views.\n */\nclass format_arg\n{\n#ifndef BOOST_MYSQL_DOXYGEN\n    struct\n    {\n        string_view name;\n        detail::formattable_ref_impl value;\n    } impl_;\n\n    friend struct detail::access;\n#endif\n\npublic:\n    /**\n     * \\brief Constructor.\n     * \\details\n     * Constructs an argument from a name and a value.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Both `name` and `value` are stored as views.\n     */\n    format_arg(string_view name, formattable_ref value) noexcept\n        : impl_{name, detail::access::get_impl(value)}\n    {\n    }\n};\n\n/**\n * \\brief Base class for concrete format contexts.\n * \\details\n * Conceptually, a format context contains: \\n\n *   \\li The result string. Output operations append characters to this output string.\n *       `format_context_base` is agnostic to the output string type.\n *   \\li \\ref format_options required to format values.\n *   \\li An error state (\\ref error_state) that is set by output operations when they fail.\n *       The error state is propagated to \\ref basic_format_context::get.\n * \\n\n * References to this class are useful when you need to manipulate\n * a format context without knowing the type of the actual context that will be used,\n * like when specializing \\ref formatter.\n * \\n\n * This class can't be\n * instantiated directly - use \\ref basic_format_context, instead.\n * Do not subclass it, either.\n */\nclass format_context_base\n{\n#ifndef BOOST_MYSQL_DOXYGEN\n    struct\n    {\n        detail::output_string_ref output;\n        format_options opts;\n        error_code ec;\n    } impl_;\n\n    friend struct detail::access;\n    friend class detail::format_state;\n#endif\n\n    BOOST_MYSQL_DECL void format_arg(detail::formattable_ref_impl arg, string_view format_spec);\n\nprotected:\n    format_context_base(detail::output_string_ref out, format_options opts, error_code ec = {}) noexcept\n        : impl_{out, opts, ec}\n    {\n    }\n\n    format_context_base(detail::output_string_ref out, const format_context_base& rhs) noexcept\n        : impl_{out, rhs.impl_.opts, rhs.impl_.ec}\n    {\n    }\n\n    void assign(const format_context_base& rhs) noexcept\n    {\n        // output never changes, it always points to the derived object's storage\n        impl_.opts = rhs.impl_.opts;\n        impl_.ec = rhs.impl_.ec;\n    }\n\npublic:\n    /**\n     * \\brief Adds raw SQL to the output string (low level).\n     * \\details\n     * Adds raw, unescaped SQL to the output string. Doesn't alter the error state.\n     * \\n\n     * By default, the passed SQL should be available at compile-time.\n     * Use \\ref runtime if you need to use runtime values.\n     * \\n\n     * This is a low level function. In general, prefer \\ref format_sql_to, instead.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Memory allocations may throw.\n     *\n     * \\par Object lifetimes\n     * The passed string is copied as required and doesn't need to be kept alive.\n     */\n    format_context_base& append_raw(constant_string_view sql)\n    {\n        impl_.output.append(sql.get());\n        return *this;\n    }\n\n    /**\n     * \\brief Formats a value and adds it to the output string (low level).\n     * \\details\n     * value is formatted according to its type, applying the passed format specifiers.\n     * If formatting generates an error (for instance, a string with invalid encoding is passed),\n     * the error state may be set.\n     * \\n\n     * This is a low level function. In general, prefer \\ref format_sql_to, instead.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Memory allocations may throw.\n     *\n     * \\par Errors\n     * The error state may be updated with the following errors: \\n\n     * \\li \\ref client_errc::invalid_encoding if a string with byte sequences that can't be decoded\n     *          with the current character set is passed.\n     * \\li \\ref client_errc::unformattable_value if a NaN or infinity `float` or `double` is passed.\n     * \\li \\ref client_errc::format_string_invalid_specifier if `format_specifiers` includes\n     *          specifiers not supported by the type being formatted.\n     * \\li Any other error code that user-supplied formatter specializations may add using \\ref add_error.\n     */\n    format_context_base& append_value(\n        formattable_ref value,\n        constant_string_view format_specifiers = string_view()\n    )\n    {\n        format_arg(detail::access::get_impl(value), format_specifiers.get());\n        return *this;\n    }\n\n    /**\n     * \\brief Adds an error to the current error state.\n     * \\details\n     * This function can be used by custom formatters to report that they\n     * received a value that can't be formatted. For instance, it's used by\n     * the built-in string formatter when a string with an invalid encoding is supplied.\n     * \\n\n     * If the error state is not set before calling this function, the error\n     * state is updated to `ec`. Otherwise, the error is ignored.\n     * This implies that once the error state is set, it can't be reset.\n     * \\n\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void add_error(error_code ec) noexcept\n    {\n        if (!impl_.ec)\n            impl_.ec = ec;\n    }\n\n    /**\n     * \\brief Retrieves the current error state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    error_code error_state() const noexcept { return impl_.ec; }\n\n    /**\n     * \\brief Retrieves the format options.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    format_options format_opts() const noexcept { return impl_.opts; }\n};\n\n/**\n * \\brief Format context for incremental SQL formatting.\n * \\details\n * The primary interface for incremental SQL formatting. Contrary to \\ref format_context_base,\n * this type is aware of the output string's actual type. `basic_format_context` owns\n * an instance of `OutputString`. Format operations will append characters to such string.\n * \\n\n * Objects of this type are single-use: once the result has been retrieved using \\ref get,\n * they cannot be re-used. This is a move-only type.\n */\ntemplate <BOOST_MYSQL_OUTPUT_STRING OutputString>\nclass basic_format_context : public format_context_base\n{\n    OutputString output_{};\n\n    detail::output_string_ref ref() noexcept { return detail::output_string_ref::create(output_); }\n\npublic:\n    /**\n     * \\brief Constructor.\n     * \\details\n     * Uses a default-constructed `OutputString` as output string, and an empty\n     * error code as error state. This constructor can only be called if `OutputString`\n     * is default-constructible.\n     *\n     * \\par Exception safety\n     * Strong guarantee: exceptions thrown by default-constructing `OutputString` are propagated.\n     */\n    explicit basic_format_context(format_options opts)\n#ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done\n        noexcept(std::is_nothrow_default_constructible<OutputString>::value)\n#endif\n        : format_context_base(ref(), opts)\n    {\n    }\n\n    /**\n     * \\brief Constructor.\n     * \\details\n     * Move constructs an `OutputString` using `storage`. After construction,\n     * the output string is cleared. Uses an empty\n     * error code as error state. This constructor allows re-using existing\n     * memory for the output string.\n     * \\n\n     *\n     * \\par Exception safety\n     * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.\n     */\n    basic_format_context(format_options opts, OutputString&& storage)\n#ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done\n        noexcept(std::is_nothrow_move_constructible<OutputString>::value)\n#endif\n        : format_context_base(ref(), opts), output_(std::move(storage))\n    {\n        output_.clear();\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    basic_format_context(const basic_format_context&) = delete;\n    basic_format_context& operator=(const basic_format_context&) = delete;\n#endif\n\n    /**\n     * \\brief Move constructor.\n     * \\details\n     * Move constructs an `OutputString` using `rhs`'s output string.\n     * `*this` will have the same format options and error state than `rhs`.\n     * `rhs` is left in a valid but unspecified state.\n     *\n     * \\par Exception safety\n     * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.\n     */\n    basic_format_context(basic_format_context&& rhs)\n#ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done\n        noexcept(std::is_nothrow_move_constructible<OutputString>::value)\n#endif\n        : format_context_base(ref(), rhs), output_(std::move(rhs.output_))\n    {\n    }\n\n    /**\n     * \\brief Move assignment.\n     * \\details\n     * Move assigns `rhs`'s output string to `*this` output string.\n     * `*this` will have the same format options and error state than `rhs`.\n     * `rhs` is left in a valid but unspecified state.\n     *\n     * \\par Exception safety\n     * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.\n     */\n    basic_format_context& operator=(basic_format_context&& rhs)\n#ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done\n        noexcept(std::is_nothrow_move_assignable<OutputString>::value)\n#endif\n    {\n        output_ = std::move(rhs.output_);\n        assign(rhs);\n        return *this;\n    }\n\n    /**\n     * \\brief Retrieves the result of the formatting operation.\n     * \\details\n     * After running the relevant formatting operations (using \\ref append_raw,\n     * \\ref append_value or \\ref format_sql_to), call this function to retrieve the\n     * overall result of the operation.\n     * \\n\n     * If \\ref error_state is a non-empty error code, returns it as an error.\n     * Otherwise, returns the output string, move-constructing it into the `system::result` object.\n     * \\n\n     * This function is move-only: once called, `*this` is left in a valid but unspecified state.\n     *\n     * \\par Exception safety\n     * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.\n     */\n    system::result<OutputString> get() &&\n#ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done\n        noexcept(std::is_nothrow_move_constructible<OutputString>::value)\n#endif\n    {\n        auto ec = error_state();\n        if (ec)\n            return ec;\n        return std::move(output_);\n    }\n};\n\n/**\n * \\brief Format context for incremental SQL formatting.\n * \\details\n * Convenience type alias for `basic_format_context`'s most common case.\n */\nusing format_context = basic_format_context<std::string>;\n\n/**\n * \\brief Composes a SQL query client-side appending it to a format context.\n * \\details\n * Parses `format_str` as a format string, substituting replacement fields (like `{}`, `{1}` or `{name}`)\n * by formatted arguments, extracted from `args`.\n * \\n\n * Formatting is performed as if \\ref format_context_base::append_raw and\n * \\ref format_context_base::append_value were called on `ctx`, effectively appending\n * characters to its output string.\n * \\n\n * Compared to \\ref format_sql, this function is more flexible, allowing the following use cases: \\n\n *   \\li Appending characters to an existing context. Can be used to concatenate the output of successive\n *       format operations efficiently.\n *   \\li Using string types different to `std::string` (works with any \\ref basic_format_context).\n *   \\li Avoiding exceptions (see \\ref basic_format_context::get).\n *\n *\n * \\par Exception safety\n * Basic guarantee. Memory allocations may throw.\n *\n * \\par Errors\n * \\li \\ref client_errc::invalid_encoding if `args` contains a string with byte sequences\n *     that can't be decoded with the current character set.\n * \\li \\ref client_errc::unformattable_value if `args` contains a floating-point value\n *     that is NaN or infinity.\n * \\li \\ref client_errc::format_string_invalid_specifier if a replacement field includes\n *          a specifier not supported by the type being formatted.\n * \\li Any other error generated by user-defined \\ref formatter specializations.\n * \\li \\ref client_errc::format_string_invalid_syntax if `format_str` can't be parsed as\n *     a format string.\n * \\li \\ref client_errc::format_string_invalid_encoding if `format_str` contains byte byte sequences\n *     that can't be decoded with the current character set.\n * \\li \\ref client_errc::format_string_manual_auto_mix if `format_str` contains a mix of automatic\n *     (`{}`) and manual indexed (`{1}`) replacement fields.\n * \\li \\ref client_errc::format_arg_not_found if an argument referenced by `format_str` isn't present\n *     in `args` (there aren't enough arguments or a named argument is not found).\n */\ntemplate <BOOST_MYSQL_FORMATTABLE... Formattable>\nvoid format_sql_to(format_context_base& ctx, constant_string_view format_str, Formattable&&... args)\n{\n    std::initializer_list<format_arg> args_il{\n        {string_view(), std::forward<Formattable>(args)}\n        ...\n    };\n    detail::vformat_sql_to(ctx, format_str, args_il);\n}\n\n/**\n * \\copydoc format_sql_to\n * \\details\n * \\n\n * This overload allows using named arguments.\n */\ninline void format_sql_to(\n    format_context_base& ctx,\n    constant_string_view format_str,\n    std::initializer_list<format_arg> args\n)\n{\n    detail::vformat_sql_to(ctx, format_str, args);\n}\n\n/**\n * \\brief Composes a SQL query client-side.\n * \\details\n * Parses `format_str` as a format string, substituting replacement fields (like `{}`, `{1}` or `{name}`)\n * by formatted arguments, extracted from `args`. `opts` is using to parse the string and format string\n * arguments.\n * \\n\n * Formatting is performed as if \\ref format_context::append_raw and \\ref format_context::append_value\n * were called on a context created by this function.\n * \\n\n *\n * \\par Exception safety\n * Strong guarantee. Memory allocations may throw. `boost::system::system_error` is thrown if an error\n * is found while formatting. See below for more info.\n *\n * \\par Errors\n * \\li \\ref client_errc::invalid_encoding if `args` contains a string with byte sequences\n *     that can't be decoded with the current character set.\n * \\li \\ref client_errc::unformattable_value if `args` contains a floating-point value\n *     that is NaN or infinity.\n * \\li \\ref client_errc::format_string_invalid_specifier if a replacement field includes\n *          a specifier not supported by the type being formatted.\n * \\li Any other error generated by user-defined \\ref formatter specializations.\n * \\li \\ref client_errc::format_string_invalid_syntax if `format_str` can't be parsed as\n *     a format string.\n * \\li \\ref client_errc::format_string_invalid_encoding if `format_str` contains byte byte sequences\n *     that can't be decoded with the current character set.\n * \\li \\ref client_errc::format_string_manual_auto_mix if `format_str` contains a mix of automatic\n *     (`{}`) and manual indexed (`{1}`) replacement fields.\n * \\li \\ref client_errc::format_arg_not_found if an argument referenced by `format_str` isn't present\n *     in `args` (there aren't enough arguments or a named argument is not found).\n */\ntemplate <BOOST_MYSQL_FORMATTABLE... Formattable>\nstd::string format_sql(format_options opts, constant_string_view format_str, Formattable&&... args);\n\n/**\n * \\copydoc format_sql\n * \\details\n * \\n\n * This overload allows using named arguments.\n */\nBOOST_MYSQL_DECL\nstd::string format_sql(\n    format_options opts,\n    constant_string_view format_str,\n    std::initializer_list<format_arg> args\n);\n\n}  // namespace mysql\n}  // namespace boost\n\n#include <boost/mysql/impl/format_sql.hpp>\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/format_sql.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/handshake_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_HANDSHAKE_PARAMS_HPP\n#define BOOST_MYSQL_HANDSHAKE_PARAMS_HPP\n\n#include <boost/mysql/buffer_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief (Legacy) Parameters defining how to perform the handshake with a MySQL server.\n *\n * \\par Object lifetimes\n * This object stores references to strings (like username and password), performing\n * no copy of these values. Users are responsible for keeping them alive until required.\n *\n * \\par Legacy\n * This class is used with the legacy \\ref connection class.\n * New code should use \\ref any_connection, instead.\n * The equivalent to `handshake_params` is \\ref connect_params.\n */\nclass handshake_params\n{\n    string_view username_;\n    string_view password_;\n    string_view database_;\n    std::uint16_t connection_collation_;\n    ssl_mode ssl_;\n    bool multi_queries_;\n\npublic:\n    /// The default collation to use with the connection (`utf8mb4_general_ci` on both MySQL and MariaDB).\n    static BOOST_INLINE_CONSTEXPR std::uint16_t default_collation = 45;\n\n    /**\n     * \\brief Initializing constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\param username User name to authenticate as.\n     * \\param password Password for that username, possibly empty.\n     * \\param db Database name to use, or empty string for no database (this is the default).\n     * \\param connection_col The ID of the collation to use for the connection.\n     * Impacts how text queries and prepared statements are interpreted. Defaults to\n     * `utf8mb4_general_ci` (see \\ref default_collation), which is compatible with MySQL 5.x, 8.x and MariaDB.\n     * \\param mode The \\ref ssl_mode to use with this connection; ignored if\n     * the connection's `Stream` does not support SSL.\n     * \\param multi_queries Whether to enable support for executing semicolon-separated\n     * queries using \\ref connection::execute and \\ref connection::start_execution. Disabled by default.\n     */\n    handshake_params(\n        string_view username,\n        string_view password,\n        string_view db = \"\",\n        std::uint16_t connection_col = default_collation,\n        ssl_mode mode = ssl_mode::require,\n        bool multi_queries = false\n    )\n        : username_(username),\n          password_(password),\n          database_(db),\n          connection_collation_(connection_col),\n          ssl_(mode),\n          multi_queries_(multi_queries)\n    {\n    }\n\n    /**\n     * \\brief Retrieves the username.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    string_view username() const noexcept { return username_; }\n\n    /**\n     * \\brief Sets the username.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void set_username(string_view value) noexcept { username_ = value; }\n\n    /**\n     * \\brief Retrieves the password.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    string_view password() const noexcept { return password_; }\n\n    /**\n     * \\brief Sets the password.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void set_password(string_view value) noexcept { password_ = value; }\n\n    /**\n     * \\brief Retrieves the database name to use when connecting.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    string_view database() const noexcept { return database_; }\n\n    /**\n     * \\brief Sets the database name to use when connecting.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void set_database(string_view value) noexcept { database_ = value; }\n\n    /**\n     * \\brief Retrieves the connection collation.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    std::uint16_t connection_collation() const noexcept { return connection_collation_; }\n\n    /**\n     * \\brief Sets the connection collation.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void set_connection_collation(std::uint16_t value) noexcept { connection_collation_ = value; }\n\n    /**\n     * \\brief Retrieves the SSL mode.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    ssl_mode ssl() const noexcept { return ssl_; }\n\n    /**\n     * \\brief Sets the SSL mode.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void set_ssl(ssl_mode value) noexcept { ssl_ = value; }\n\n    /**\n     * \\brief Retrieves whether multi-query support is enabled.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool multi_queries() const noexcept { return multi_queries_; }\n\n    /**\n     * \\brief Enables or disables support for the multi-query feature.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void set_multi_queries(bool v) noexcept { multi_queries_ = v; }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/any_connection.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_ANY_CONNECTION_IPP\n#define BOOST_MYSQL_IMPL_ANY_CONNECTION_IPP\n\n#pragma once\n\n#include <boost/mysql/any_connection.hpp>\n\n#include <boost/mysql/detail/engine.hpp>\n#include <boost/mysql/detail/engine_impl.hpp>\n\n#include <boost/mysql/impl/internal/variant_stream.hpp>\n\nstd::unique_ptr<boost::mysql::detail::engine> boost::mysql::any_connection::create_engine(\n    asio::any_io_executor ex,\n    asio::ssl::context* ctx\n)\n{\n    return std::unique_ptr<detail::engine>(new detail::engine_impl<detail::variant_stream>(std::move(ex), ctx)\n    );\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/character_set.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_CHARACTER_SET_IPP\n#define BOOST_MYSQL_IMPL_CHARACTER_SET_IPP\n\n#pragma once\n\n#include <boost/mysql/character_set.hpp>\n\n#include <boost/assert.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline bool in_range(unsigned char byte, unsigned char lower, unsigned char upper)\n{\n    return byte >= lower && byte <= upper;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nstd::size_t boost::mysql::detail::next_char_utf8mb4(span<const unsigned char> input)\n{\n    // s[0]    s[1]    s[2]    s[3]    comment\n    // 00-7F                           ascii\n    // 80-c1                           invalid\n    // c2-df   80-bf                   2byte\n    // e0      a0-bf   80-bf           3byte, case 1\n    // e1-ec   80-bf   80-bf           3byte, case 2\n    // ed      80-9f   80-bf           3byte, case 3 (surrogates)\n    // ee-ef   80-bf   80-bf           3byte, case 2\n    // f0      90-bf   80-bf   80-bf   4byte, case 1\n    // f1-f3   80-bf   80-bf   80-bf   4byte, case 2\n    // f4      80-8f   80-bf   80-bf   4byte, case 3\n\n    BOOST_ASSERT(!input.empty());\n\n    auto first_char = input.front();\n    BOOST_ASSERT(first_char >= 0x80);  // ascii range covered by call_next_char\n\n    if (first_char < 0xc2)\n    {\n        return 0;\n    }\n    else if (first_char < 0xe0)\n    {\n        return (input.size() < 2u || !in_range(input[1], 0x80, 0xbf)) ? 0 : 2;\n    }\n    else if (first_char == 0xe0)\n    {\n        return (input.size() < 3u || !in_range(input[1], 0xa0, 0xbf) || !in_range(input[2], 0x80, 0xbf)) ? 0\n                                                                                                         : 3;\n    }\n    else if (first_char == 0xed)\n    {\n        return (input.size() < 3u || !in_range(input[1], 0x80, 0x9f) || !in_range(input[2], 0x80, 0xbf)) ? 0\n                                                                                                         : 3;\n    }\n    else if (first_char <= 0xef)\n    {\n        // Includes e1-ec and ee-ef\n        return (input.size() < 3u || !in_range(input[1], 0x80, 0xbf) || !in_range(input[2], 0x80, 0xbf)) ? 0\n                                                                                                         : 3;\n    }\n    else if (first_char == 0xf0)\n    {\n        return (input.size() < 4u || !in_range(input[1], 0x90, 0xbf) || !in_range(input[2], 0x80, 0xbf) ||\n                !in_range(input[3], 0x80, 0xbf))\n                   ? 0\n                   : 4;\n    }\n    else if (first_char <= 0xf3)\n    {\n        return (input.size() < 4u || !in_range(input[1], 0x80, 0xbf) || !in_range(input[2], 0x80, 0xbf) ||\n                !in_range(input[3], 0x80, 0xbf))\n                   ? 0\n                   : 4;\n    }\n    else if (first_char == 0xf4)\n    {\n        return (input.size() < 4u || !in_range(input[1], 0x80, 0x8f) || !in_range(input[2], 0x80, 0xbf) ||\n                !in_range(input[3], 0x80, 0xbf))\n                   ? 0\n                   : 4;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/column_type.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_COLUMN_TYPE_IPP\n#define BOOST_MYSQL_IMPL_COLUMN_TYPE_IPP\n\n#pragma once\n\n#include <boost/mysql/column_type.hpp>\n\n#include <ostream>\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, column_type t)\n{\n    switch (t)\n    {\n    case column_type::tinyint: return os << \"tinyint\";\n    case column_type::smallint: return os << \"smallint\";\n    case column_type::mediumint: return os << \"mediumint\";\n    case column_type::int_: return os << \"int_\";\n    case column_type::bigint: return os << \"bigint\";\n    case column_type::float_: return os << \"float_\";\n    case column_type::double_: return os << \"double_\";\n    case column_type::decimal: return os << \"decimal\";\n    case column_type::bit: return os << \"bit\";\n    case column_type::year: return os << \"year\";\n    case column_type::time: return os << \"time\";\n    case column_type::date: return os << \"date\";\n    case column_type::datetime: return os << \"datetime\";\n    case column_type::timestamp: return os << \"timestamp\";\n    case column_type::char_: return os << \"char_\";\n    case column_type::varchar: return os << \"varchar\";\n    case column_type::binary: return os << \"binary\";\n    case column_type::varbinary: return os << \"varbinary\";\n    case column_type::text: return os << \"text\";\n    case column_type::blob: return os << \"blob\";\n    case column_type::enum_: return os << \"enum_\";\n    case column_type::set: return os << \"set\";\n    case column_type::json: return os << \"json\";\n    case column_type::geometry: return os << \"geometry\";\n    default: return os << \"<unknown column type>\";\n    }\n}\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/connection_impl.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_CONNECTION_IMPL_IPP\n#define BOOST_MYSQL_IMPL_CONNECTION_IMPL_IPP\n\n#pragma once\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/pipeline.hpp>\n\n#include <boost/mysql/detail/connection_impl.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <boost/throw_exception.hpp>\n\n#include <cstddef>\n#include <stdexcept>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline connection_state* new_connection_state(\n    std::size_t initial_buffer_size,\n    std::size_t max_buffer_size,\n    bool engine_supports_ssl\n)\n{\n    if (initial_buffer_size > max_buffer_size)\n    {\n        BOOST_THROW_EXCEPTION(std::invalid_argument(\n            \"any_connection::any_connection: initial_buffer_size should be <= max_buffer_size\"\n        ));\n    }\n    return new connection_state(initial_buffer_size, max_buffer_size, engine_supports_ssl);\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nvoid boost::mysql::detail::connection_state_deleter::operator()(connection_state* st) const { delete st; }\n\nstd::vector<boost::mysql::field_view>& boost::mysql::detail::get_shared_fields(connection_state& st)\n{\n    return st.data().shared_fields;\n}\n\nboost::mysql::detail::connection_impl::connection_impl(\n    std::size_t read_buff_size,\n    std::size_t max_buffer_size,\n    std::unique_ptr<engine> eng\n)\n    : engine_(std::move(eng)),\n      st_(new_connection_state(read_buff_size, max_buffer_size, engine_->supports_ssl()))\n{\n}\n\nboost::mysql::metadata_mode boost::mysql::detail::connection_impl::meta_mode() const\n{\n    return st_->data().meta_mode;\n}\n\nvoid boost::mysql::detail::connection_impl::set_meta_mode(metadata_mode v) { st_->data().meta_mode = v; }\n\nbool boost::mysql::detail::connection_impl::ssl_active() const { return st_->data().tls_active; }\n\nbool boost::mysql::detail::connection_impl::backslash_escapes() const\n{\n    return st_->data().backslash_escapes;\n}\n\nboost::mysql::diagnostics& boost::mysql::detail::connection_impl::shared_diag()\n{\n    return st_->data().shared_diag;\n}\n\nboost::system::result<boost::mysql::character_set> boost::mysql::detail::connection_impl::\n    current_character_set() const\n{\n    character_set charset = st_->data().current_charset;\n    if (charset.name == nullptr)\n        return client_errc::unknown_character_set;\n    return charset;\n}\n\nboost::optional<std::uint32_t> boost::mysql::detail::connection_impl::connection_id() const\n{\n    const auto& data = st_->data();\n    if (data.status == connection_status::not_connected)\n        return {};\n    else\n        return data.connection_id;\n}\n\nboost::mysql::detail::run_pipeline_algo_params boost::mysql::detail::connection_impl::make_params_pipeline(\n    const pipeline_request& req,\n    std::vector<stage_response>& response\n)\n{\n    const auto& req_impl = access::get_impl(req);\n    return {req_impl.buffer_, req_impl.stages_, &response};\n}\n\ntemplate <class AlgoParams>\nboost::mysql::detail::any_resumable_ref boost::mysql::detail::setup(\n    connection_state& st,\n    diagnostics& diag,\n    const AlgoParams& params\n)\n{\n    return st.setup(diag, params);\n}\n\ntemplate <class AlgoParams>\ntypename AlgoParams::result_type boost::mysql::detail::get_result(const connection_state& st)\n{\n    return st.result<AlgoParams>();\n}\n\n#ifdef BOOST_MYSQL_SEPARATE_COMPILATION\n\n#define BOOST_MYSQL_INSTANTIATE_SETUP(op_params_type) \\\n    template any_resumable_ref setup<op_params_type>(connection_state&, diagnostics&, const op_params_type&);\n\n#define BOOST_MYSQL_INSTANTIATE_GET_RESULT(op_params_type) \\\n    template op_params_type::result_type get_result<op_params_type>(const connection_state&);\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nBOOST_MYSQL_INSTANTIATE_SETUP(connect_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(handshake_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(execute_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(start_execution_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(read_resultset_head_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(read_some_rows_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(read_some_rows_dynamic_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(prepare_statement_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(close_statement_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(set_character_set_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(ping_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(reset_connection_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(quit_connection_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(close_connection_algo_params)\nBOOST_MYSQL_INSTANTIATE_SETUP(run_pipeline_algo_params)\n\nBOOST_MYSQL_INSTANTIATE_GET_RESULT(read_some_rows_algo_params)\nBOOST_MYSQL_INSTANTIATE_GET_RESULT(read_some_rows_dynamic_algo_params)\nBOOST_MYSQL_INSTANTIATE_GET_RESULT(prepare_statement_algo_params)\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/connection_pool.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_CONNECTION_POOL_IPP\n#define BOOST_MYSQL_IMPL_CONNECTION_POOL_IPP\n\n#pragma once\n\n#include <boost/mysql/connection_pool.hpp>\n\n#include <boost/mysql/detail/connection_pool_fwd.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/connection_pool_impl.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n\n#include <memory>\n\nvoid boost::mysql::detail::return_connection(\n    pool_impl& pool,\n    connection_node& node,\n    bool should_reset\n) noexcept\n{\n    pool.return_connection(node, should_reset);\n}\n\nboost::mysql::any_connection& boost::mysql::detail::get_connection(boost::mysql::detail::connection_node& node\n) noexcept\n{\n    return node.connection();\n}\n\nboost::mysql::connection_pool::connection_pool(asio::any_io_executor ex, pool_params&& params, int)\n    : impl_(std::make_shared<detail::pool_impl>(std::move(ex), std::move(params)))\n{\n}\n\nboost::mysql::connection_pool::executor_type boost::mysql::connection_pool::get_executor() noexcept\n{\n    return impl_->get_executor();\n}\n\nvoid boost::mysql::connection_pool::async_run_erased(\n    std::shared_ptr<detail::pool_impl> pool,\n    asio::any_completion_handler<void(error_code)> handler\n)\n{\n    pool->async_run(std::move(handler));\n}\n\nvoid boost::mysql::connection_pool::async_get_connection_erased(\n    std::shared_ptr<detail::pool_impl> pool,\n    diagnostics* diag,\n    asio::any_completion_handler<void(error_code, pooled_connection)> handler\n)\n{\n    pool->async_get_connection(diag, std::move(handler));\n}\n\nvoid boost::mysql::connection_pool::cancel()\n{\n    BOOST_ASSERT(valid());\n    impl_->cancel();\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/date.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_DATE_IPP\n#define BOOST_MYSQL_IMPL_DATE_IPP\n\n#pragma once\n\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/dt_to_string.hpp>\n\n#include <cstddef>\n#include <ostream>\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const date& value)\n{\n    char buffer[32]{};\n    std::size_t sz = detail::date_to_string(value.year(), value.month(), value.day(), buffer);\n    return os << string_view(buffer, sz);\n}\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/datetime.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_DATETIME_IPP\n#define BOOST_MYSQL_IMPL_DATETIME_IPP\n\n#pragma once\n\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/dt_to_string.hpp>\n\n#include <cstddef>\n#include <ostream>\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const datetime& value)\n{\n    char buffer[64]{};\n    std::size_t sz = detail::datetime_to_string(\n        value.year(),\n        value.month(),\n        value.day(),\n        value.hour(),\n        value.minute(),\n        value.second(),\n        value.microsecond(),\n        buffer\n    );\n    os << string_view(buffer, sz);\n    return os;\n}\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/engine_impl_instantiations.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_ENGINE_IMPL_INSTANTIATIONS_IPP\n#define BOOST_MYSQL_IMPL_ENGINE_IMPL_INSTANTIATIONS_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/engine_stream_adaptor.hpp>\n\n// To be included only in src.hpp\n\n#ifdef BOOST_MYSQL_SEPARATE_COMPILATION\ntemplate class boost::mysql::detail::engine_impl<\n    boost::mysql::detail::engine_stream_adaptor<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>>;\ntemplate class boost::mysql::detail::engine_impl<\n    boost::mysql::detail::engine_stream_adaptor<boost::asio::ip::tcp::socket>>;\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/error_categories.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_ERROR_CATEGORIES_IPP\n#define BOOST_MYSQL_IMPL_ERROR_CATEGORIES_IPP\n\n#pragma once\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/error_categories.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/mysql/impl/internal/error/server_error_to_string.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline const char* error_to_string(client_errc error)\n{\n    switch (error)\n    {\n    case client_errc::incomplete_message: return \"An incomplete message was received from the server\";\n    case client_errc::extra_bytes: return \"Unexpected extra bytes at the end of a message were received\";\n    case client_errc::sequence_number_mismatch: return \"Mismatched sequence numbers\";\n    case client_errc::server_unsupported:\n        return \"The server does not support the minimum required capabilities to establish the \"\n               \"connection\";\n    case client_errc::protocol_value_error:\n        return \"An unexpected value was found in a server-received message\";\n    case client_errc::unknown_auth_plugin:\n        return \"The user employs an authentication plugin not known to this library\";\n    case client_errc::auth_plugin_requires_ssl:\n        return \"The authentication plugin requires the connection to use SSL\";\n    case client_errc::wrong_num_params:\n        return \"The number of parameters passed to the prepared statement does not match the \"\n               \"number of actual parameters\";\n    case client_errc::server_doesnt_support_ssl:\n        return \"The connection is configured to require SSL, but the server doesn't allow SSL connections. \"\n               \"Configure SSL on your server or change your connection to not require SSL\";\n    case client_errc::metadata_check_failed:\n        return \"The static interface detected a type mismatch between your declared row type and what the \"\n               \"server returned. Verify your type definitions.\";\n    case client_errc::num_resultsets_mismatch:\n        return \"The static interface detected a mismatch between the number of resultsets passed as template \"\n               \"arguments to static_results<T1, T2...>/static_execution_state<T1, T2...> and the number of \"\n               \"results returned by server\";\n    case client_errc::static_row_parsing_error:\n        return \"The static interface encountered an error when parsing a field into a C++ data structure.\";\n    case client_errc::row_type_mismatch:\n        return \"The StaticRow type passed to read_some_rows does not correspond to the resultset type being \"\n               \"read\";\n    case client_errc::pool_not_running:\n        return \"Getting a connection from a connection_pool was cancelled before the pool was run. Ensure \"\n               \"that you're calling connection_pool::async_run.\";\n    case client_errc::pool_cancelled:\n        return \"Getting a connection from a connection_pool failed because the pool was cancelled.\";\n    case client_errc::no_connection_available:\n        return \"Getting a connection from a connection_pool was cancelled before \"\n               \"a connection was available.\";\n    case client_errc::invalid_encoding:\n        return \"A string passed to a formatting function contains a byte sequence that can't be decoded with \"\n               \"the current character set.\";\n    case client_errc::unformattable_value:\n        return \"A formatting operation could not format one of its arguments.\";\n    case client_errc::format_string_invalid_syntax:\n        return \"A format string with invalid syntax was provided to a SQL formatting function.\";\n    case client_errc::format_string_invalid_encoding:\n        return \"A format string with an invalid byte sequence was provided to a SQL formatting function.\";\n    case client_errc::format_string_manual_auto_mix:\n        return \"A format string mixes manual (e.g. {0}) and automatic (e.g. {}) indexing.\";\n    case client_errc::format_string_invalid_specifier:\n        return \"The supplied format specifier is not supported by the type being formatted.\";\n    case client_errc::format_arg_not_found:\n        return \"A format argument referenced by a format string was not found. Check the number of format \"\n               \"arguments passed and their names.\";\n    case client_errc::unknown_character_set:\n        return \"The character set used by the connection is not known by the client. Use set_character_set \"\n               \"or async_set_character_set before invoking operations that require a known charset.\";\n    case client_errc::max_buffer_size_exceeded:\n        return \"An operation attempted to read or write a packet larger than the maximum buffer size. \"\n               \"Try increasing any_connection_params::max_buffer_size.\";\n    case client_errc::operation_in_progress:\n        return \"Another operation is currently in progress for this connection. Make sure that a single \"\n               \"connection does not run two asynchronous operations in parallel.\";\n    case client_errc::not_connected:\n        return \"The requested operation requires an established session. Call async_connect before invoking \"\n               \"other operations.\";\n    case client_errc::engaged_in_multi_function:\n        return \"The connection is currently engaged in a multi-function operation.\"\n               \"Finish the current operation by calling async_read_some_rows and async_read_resultset_head \"\n               \"before \"\n               \"starting any other operation.\";\n    case client_errc::not_engaged_in_multi_function:\n        return \"The operation requires the connection to be engaged in a multi-function operation. \"\n               \"Use async_start_execution to start one.\";\n    case client_errc::bad_handshake_packet_type:\n        return \"During handshake, the server sent a packet type that is not allowed in the current state \"\n               \"(protocol violation).\";\n    case client_errc::unknown_openssl_error:\n        return \"An OpenSSL function failed and did not provide any extra diagnostics.\";\n    default: return \"<unknown MySQL client error>\";\n    }\n}\n\ninline const char* error_to_string(common_server_errc v)\n{\n    const char* res = detail::common_error_to_string(static_cast<int>(v));\n    return res ? res : \"<unknown server error>\";\n}\n\nclass client_category final : public boost::system::error_category\n{\npublic:\n    const char* name() const noexcept final override { return \"mysql.client\"; }\n    std::string message(int ev) const final override { return error_to_string(static_cast<client_errc>(ev)); }\n};\n\nclass common_server_category final : public boost::system::error_category\n{\npublic:\n    const char* name() const noexcept final override { return \"mysql.common-server\"; }\n    std::string message(int ev) const final override\n    {\n        return error_to_string(static_cast<common_server_errc>(ev));\n    }\n};\n\nclass mysql_server_category final : public boost::system::error_category\n{\npublic:\n    const char* name() const noexcept final override { return \"mysql.mysql-server\"; }\n    std::string message(int ev) const final override { return detail::mysql_error_to_string(ev); }\n};\n\nclass mariadb_server_category final : public boost::system::error_category\n{\npublic:\n    const char* name() const noexcept final override { return \"mysql.mariadb-server\"; }\n    std::string message(int ev) const final override { return detail::mariadb_error_to_string(ev); }\n};\n\n// Optimization, so that static initialization happens only once (reduces C++11 thread-safe initialization\n// overhead)\nstruct all_categories\n{\n    client_category client;\n    common_server_category common_server;\n    mysql_server_category mysql_server;\n    mariadb_server_category mariadb_server;\n\n    static const all_categories& get() noexcept\n    {\n        static all_categories res;\n        return res;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nconst boost::system::error_category& boost::mysql::get_client_category() noexcept\n{\n    return detail::all_categories::get().client;\n}\n\nconst boost::system::error_category& boost::mysql::get_common_server_category() noexcept\n{\n    return detail::all_categories::get().common_server;\n}\n\nconst boost::system::error_category& boost::mysql::get_mysql_server_category() noexcept\n{\n    return detail::all_categories::get().mysql_server;\n}\n\nconst boost::system::error_category& boost::mysql::get_mariadb_server_category() noexcept\n{\n    return detail::all_categories::get().mariadb_server;\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/escape_string.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_ESCAPE_STRING_IPP\n#define BOOST_MYSQL_IMPL_ESCAPE_STRING_IPP\n\n#pragma once\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/escape_string.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/output_string.hpp>\n\n#include <boost/mysql/impl/internal/call_next_char.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// A (possibly null) escape sequence of two characters. Used as the return value for escapers\nclass escape_sequence\n{\n    char data_[2]{};\n\npublic:\n    escape_sequence() = default;\n    escape_sequence(char ch1, char ch2) noexcept : data_{ch1, ch2} {}\n\n    bool is_escape() const noexcept { return data_[0] != '\\0'; }\n    string_view data() const noexcept { return string_view(data_, 2); }\n};\n\n// Escaper is a function object that takes a char and returns a\n// escape_sequence determining whether we should escape the char or not\ntemplate <class Escaper>\nBOOST_ATTRIBUTE_NODISCARD error_code\nescape_impl(string_view input, character_set charset, Escaper escaper, output_string_ref output)\n{\n    const char* it = input.data();\n    const char* end = it + input.size();\n\n    // The raw range is a range of contiguous characters that don't need escaping.\n    // We only append the raw range once we find a character that needs escaping\n    const char* raw_begin = it;\n    while (it != end)\n    {\n        escape_sequence seq = escaper(*it);\n        if (seq.is_escape())\n        {\n            // Dump what we already had\n            output.append({raw_begin, it});\n\n            // Output the escape sequence\n            output.append(seq.data());\n\n            // Advance\n            ++it;\n\n            // Update the start of the range that doesn't need escaping\n            raw_begin = it;\n        }\n        else\n        {\n            // Advance with the charset function\n            std::size_t char_size = detail::call_next_char(charset, it, end);\n            if (char_size == 0u)\n                return client_errc::invalid_encoding;\n            it += char_size;\n        }\n    }\n\n    // Dump the remaining of the string, if any\n    output.append({raw_begin, end});\n\n    // Done\n    return error_code();\n}\n\nstruct backslash_escaper\n{\n    escape_sequence operator()(char input) const noexcept\n    {\n        switch (input)\n        {\n        case '\\0': return {'\\\\', '0'};\n        case '\\n': return {'\\\\', 'n'};\n        case '\\r': return {'\\\\', 'r'};\n        case '\\\\': return {'\\\\', '\\\\'};\n        case '\\'': return {'\\\\', '\\''};\n        case '\"': return {'\\\\', '\"'};\n        case '\\x1a': return {'\\\\', 'Z'};    // Ctrl+Z\n        default: return escape_sequence();  // No escape\n        }\n    };\n};\n\nstruct quote_escaper\n{\n    char quot;\n\n    quote_escaper(char q) noexcept : quot(q) {}\n\n    escape_sequence operator()(char input) const noexcept\n    {\n        return input == quot ? escape_sequence(quot, quot) : escape_sequence();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::error_code boost::mysql::detail::escape_string(\n    string_view input,\n    const format_options& opts,\n    char escape_char,\n    output_string_ref output\n)\n{\n    return (escape_char == '`' || !opts.backslash_escapes)\n               ? detail::escape_impl(input, opts.charset, quote_escaper(escape_char), output)\n               : detail::escape_impl(input, opts.charset, backslash_escaper(), output);\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/execution_state_impl.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_EXECUTION_STATE_IMPL_IPP\n#define BOOST_MYSQL_IMPL_EXECUTION_STATE_IMPL_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/execution_processor/execution_state_impl.hpp>\n#include <boost/mysql/detail/row_impl.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nvoid boost::mysql::detail::execution_state_impl::on_ok_packet_impl(const ok_view& pack)\n{\n    eof_data_.has_value = true;\n    eof_data_.affected_rows = pack.affected_rows;\n    eof_data_.last_insert_id = pack.last_insert_id;\n    eof_data_.warnings = pack.warnings;\n    eof_data_.is_out_params = pack.is_out_params();\n    info_.assign(pack.info.begin(), pack.info.end());\n}\n\nvoid boost::mysql::detail::execution_state_impl::reset_impl() noexcept\n{\n    meta_.clear();\n    eof_data_ = ok_data();\n    info_.clear();\n}\n\nboost::mysql::error_code boost::mysql::detail::execution_state_impl::\n    on_head_ok_packet_impl(const ok_view& pack, diagnostics&)\n{\n    on_new_resultset();\n    on_ok_packet_impl(pack);\n    return error_code();\n}\n\nvoid boost::mysql::detail::execution_state_impl::on_num_meta_impl(std::size_t num_columns)\n{\n    on_new_resultset();\n    meta_.reserve(num_columns);\n}\n\nboost::mysql::error_code boost::mysql::detail::execution_state_impl::\n    on_meta_impl(const coldef_view& coldef, bool, diagnostics&)\n{\n    meta_.push_back(create_meta(coldef));\n    return error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::execution_state_impl::on_row_impl(\n    span<const std::uint8_t> msg,\n    const output_ref&,\n    std::vector<field_view>& fields\n)\n\n{\n    // add row storage\n    span<field_view> storage = add_fields(fields, meta_.size());\n\n    // deserialize the row\n    return deserialize_row(encoding(), msg, meta_, storage);\n}\n\nboost::mysql::error_code boost::mysql::detail::execution_state_impl::on_row_ok_packet_impl(const ok_view& pack\n)\n{\n    on_ok_packet_impl(pack);\n    return error_code();\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/field.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_FIELD_IPP\n#define BOOST_MYSQL_IMPL_FIELD_IPP\n\n#pragma once\n\n#include <boost/mysql/field.hpp>\n\n#include <ostream>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline blob to_blob(blob_view v) { return blob(v.data(), v.data() + v.size()); }\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nvoid boost::mysql::field::from_view(const field_view& fv)\n{\n    switch (fv.kind())\n    {\n    case field_kind::null: repr_.data.emplace<detail::field_impl::null_t>(); break;\n    case field_kind::int64: repr_.data.emplace<std::int64_t>(fv.get_int64()); break;\n    case field_kind::uint64: repr_.data.emplace<std::uint64_t>(fv.get_uint64()); break;\n    case field_kind::string: repr_.data.emplace<std::string>(fv.get_string()); break;\n    case field_kind::blob: repr_.data.emplace<blob>(detail::to_blob(fv.get_blob())); break;\n    case field_kind::float_: repr_.data.emplace<float>(fv.get_float()); break;\n    case field_kind::double_: repr_.data.emplace<double>(fv.get_double()); break;\n    case field_kind::date: repr_.data.emplace<date>(fv.get_date()); break;\n    case field_kind::datetime: repr_.data.emplace<datetime>(fv.get_datetime()); break;\n    case field_kind::time: repr_.data.emplace<time>(fv.get_time()); break;\n    }\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const field& value)\n{\n    return os << field_view(value);\n}\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/field_kind.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_FIELD_KIND_IPP\n#define BOOST_MYSQL_IMPL_FIELD_KIND_IPP\n\n#pragma once\n\n#include <boost/mysql/field_kind.hpp>\n\n#include <ostream>\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, boost::mysql::field_kind v)\n{\n    switch (v)\n    {\n    case field_kind::null: return os << \"null\";\n    case field_kind::int64: return os << \"int64\";\n    case field_kind::uint64: return os << \"uint64\";\n    case field_kind::string: return os << \"string\";\n    case field_kind::float_: return os << \"float_\";\n    case field_kind::double_: return os << \"double_\";\n    case field_kind::date: return os << \"date\";\n    case field_kind::datetime: return os << \"datetime\";\n    case field_kind::time: return os << \"time\";\n    default: return os << \"<invalid>\";\n    }\n}\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/field_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_FIELD_VIEW_HPP\n#define BOOST_MYSQL_IMPL_FIELD_VIEW_HPP\n\n#pragma once\n\n#include <boost/mysql/bad_field_access.hpp>\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <cstring>\n#include <limits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline bool blobs_equal(blob_view b1, blob_view b2)\n{\n    if (b1.size() != b2.size())\n        return false;\n    return b1.empty() || std::memcmp(b1.data(), b2.data(), b2.size()) == 0;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nBOOST_CXX14_CONSTEXPR inline boost::mysql::field_kind boost::mysql::field_view::kind() const noexcept\n{\n    switch (impl_.ikind)\n    {\n    case internal_kind::null: return field_kind::null;\n    case internal_kind::int64: return field_kind::int64;\n    case internal_kind::uint64: return field_kind::uint64;\n    case internal_kind::string: return field_kind::string;\n    case internal_kind::blob: return field_kind::blob;\n    case internal_kind::float_: return field_kind::float_;\n    case internal_kind::double_: return field_kind::double_;\n    case internal_kind::date: return field_kind::date;\n    case internal_kind::datetime: return field_kind::datetime;\n    case internal_kind::time: return field_kind::time;\n    case internal_kind::field_ptr: return impl_.repr.field_ptr->kind();\n    // sv_offset values must be converted via offset_to_string_view before calling any other fn\n    default: return field_kind::null;\n    }\n}\n\nBOOST_CXX14_CONSTEXPR std::int64_t boost::mysql::field_view::as_int64() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<std::int64_t>();\n    check_kind(internal_kind::int64);\n    return impl_.repr.int64;\n}\n\nBOOST_CXX14_CONSTEXPR std::uint64_t boost::mysql::field_view::as_uint64() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<std::uint64_t>();\n    check_kind(internal_kind::uint64);\n    return impl_.repr.uint64;\n}\n\nBOOST_CXX14_CONSTEXPR boost::mysql::string_view boost::mysql::field_view::as_string() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<std::string>();\n    check_kind(internal_kind::string);\n    return impl_.repr.string;\n}\n\nBOOST_CXX14_CONSTEXPR boost::mysql::blob_view boost::mysql::field_view::as_blob() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<blob>();\n    check_kind(internal_kind::blob);\n    return impl_.repr.blob;\n}\n\nBOOST_CXX14_CONSTEXPR float boost::mysql::field_view::as_float() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<float>();\n    check_kind(internal_kind::float_);\n    return impl_.repr.float_;\n}\n\nBOOST_CXX14_CONSTEXPR double boost::mysql::field_view::as_double() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<double>();\n    check_kind(internal_kind::double_);\n    return impl_.repr.double_;\n}\n\nBOOST_CXX14_CONSTEXPR boost::mysql::date boost::mysql::field_view::as_date() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<date>();\n    check_kind(internal_kind::date);\n    return impl_.repr.date_;\n}\n\nBOOST_CXX14_CONSTEXPR boost::mysql::datetime boost::mysql::field_view::as_datetime() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<datetime>();\n    check_kind(internal_kind::datetime);\n    return impl_.repr.datetime_;\n}\n\nBOOST_CXX14_CONSTEXPR boost::mysql::time boost::mysql::field_view::as_time() const\n{\n    if (is_field_ptr())\n        return impl_.repr.field_ptr->as<time>();\n    check_kind(internal_kind::time);\n    return impl_.repr.time_;\n}\n\nBOOST_CXX14_CONSTEXPR void boost::mysql::field_view::check_kind(internal_kind expected) const\n{\n    if (impl_.ikind != expected)\n        BOOST_THROW_EXCEPTION(bad_field_access());\n}\n\nBOOST_CXX14_CONSTEXPR bool boost::mysql::field_view::operator==(const field_view& rhs) const noexcept\n{\n    // Make operator== work for types not representable by field_kind\n    if (impl_.ikind == internal_kind::sv_offset_string || impl_.ikind == internal_kind::sv_offset_blob)\n    {\n        return rhs.impl_.ikind == impl_.ikind && impl_.repr.sv_offset_ == rhs.impl_.repr.sv_offset_;\n    }\n\n    auto k = kind(), rhs_k = rhs.kind();\n    switch (k)\n    {\n    case field_kind::null: return rhs_k == field_kind::null;\n    case field_kind::int64:\n        if (rhs_k == field_kind::int64)\n            return get_int64() == rhs.get_int64();\n        else if (rhs_k == field_kind::uint64)\n        {\n            std::int64_t this_val = get_int64();\n            if (this_val < 0)\n                return false;\n            else\n                return static_cast<std::uint64_t>(this_val) == rhs.get_uint64();\n        }\n        else\n            return false;\n    case field_kind::uint64:\n        if (rhs_k == field_kind::uint64)\n            return get_uint64() == rhs.get_uint64();\n        else if (rhs_k == field_kind::int64)\n        {\n            std::int64_t rhs_val = rhs.get_int64();\n            if (rhs_val < 0)\n                return false;\n            else\n                return static_cast<std::uint64_t>(rhs_val) == get_uint64();\n        }\n        else\n            return false;\n    case field_kind::string: return rhs_k == field_kind::string && get_string() == rhs.get_string();\n    case field_kind::blob:\n        return rhs_k == field_kind::blob && detail::blobs_equal(get_blob(), rhs.get_blob());\n    case field_kind::float_: return rhs_k == field_kind::float_ && get_float() == rhs.get_float();\n    case field_kind::double_: return rhs_k == field_kind::double_ && get_double() == rhs.get_double();\n    case field_kind::date: return rhs_k == field_kind::date && get_date() == rhs.get_date();\n    case field_kind::datetime: return rhs_k == field_kind::datetime && get_datetime() == rhs.get_datetime();\n    case field_kind::time: return rhs_k == field_kind::time && get_time() == rhs.get_time();\n    default: BOOST_ASSERT(false); return false;  // LCOV_EXCL_LINE\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/field_view.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_FIELD_VIEW_IPP\n#define BOOST_MYSQL_IMPL_FIELD_VIEW_IPP\n\n#pragma once\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/byte_to_hex.hpp>\n#include <boost/mysql/impl/internal/dt_to_string.hpp>\n\n#include <boost/assert.hpp>\n\n#include <cstddef>\n#include <ostream>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline std::ostream& print_blob(std::ostream& os, blob_view value)\n{\n    if (value.empty())\n        return os << \"{}\";\n\n    char buffer[16]{'0', 'x'};\n\n    os << \"{ \";\n    for (std::size_t i = 0; i < value.size(); ++i)\n    {\n        // Separating comma\n        if (i != 0)\n            os << \", \";\n\n        // Convert to hex\n        byte_to_hex(value[i], buffer + 2);\n\n        // Insert\n        os << string_view(buffer, 4);\n    }\n    os << \" }\";\n    return os;\n}\n\ninline std::ostream& print_time(std::ostream& os, const boost::mysql::time& value)\n{\n    char buffer[64]{};\n    std::size_t sz = detail::time_to_string(value, buffer);\n    os << string_view(buffer, sz);\n    return os;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const field_view& value)\n{\n    // Make operator<< work for detail::string_view_offset types\n    if (value.impl_.is_string_offset() || value.impl_.is_blob_offset())\n    {\n        return os << \"<sv_offset>\";\n    }\n\n    switch (value.kind())\n    {\n    case field_kind::null: return os << \"<NULL>\";\n    case field_kind::int64: return os << value.get_int64();\n    case field_kind::uint64: return os << value.get_uint64();\n    case field_kind::string: return os << value.get_string();\n    case field_kind::blob: return detail::print_blob(os, value.get_blob());\n    case field_kind::float_: return os << value.get_float();\n    case field_kind::double_: return os << value.get_double();\n    case field_kind::date: return os << value.get_date();\n    case field_kind::datetime: return os << value.get_datetime();\n    case field_kind::time: return detail::print_time(os, value.get_time());\n    default: BOOST_ASSERT(false); return os;  // LCOV_EXCL_LINE\n    }\n}\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/format_sql.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_FORMAT_SQL_HPP\n#define BOOST_MYSQL_IMPL_FORMAT_SQL_HPP\n\n#pragma once\n\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/mysql/detail/format_sql.hpp>\n\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nBOOST_MYSQL_DECL\nstd::pair<bool, string_view> parse_range_specifiers(const char* spec_begin, const char* spec_end);\n\n// To use with arguments with a custom formatter\ntemplate <class T>\nbool do_format_custom_formatter(\n    const void* obj,\n    const char* spec_begin,\n    const char* spec_end,\n    format_context_base& ctx\n)\n{\n    // T here may be the actual type U or const U\n    using U = typename std::remove_const<T>::type;\n\n    formatter<U> fmt;\n\n    // Parse the spec\n    const char* it = fmt.parse(spec_begin, spec_end);\n    if (it != spec_end)\n    {\n        return false;\n    }\n\n    // Retrieve the object\n    auto& value = *const_cast<T*>(static_cast<const T*>(obj));\n\n    // Format\n    fmt.format(value, ctx);\n\n    // Done\n    return true;\n}\n\n// To use with ranges\ntemplate <class T>\nbool do_format_range(const void* obj, const char* spec_begin, const char* spec_end, format_context_base& ctx)\n{\n    // Parse specifiers\n    auto res = detail::parse_range_specifiers(spec_begin, spec_end);\n    if (!res.first)\n        return false;\n    auto spec = runtime(res.second);\n\n    // Retrieve the object. T here may be the actual type U or const U\n    auto& value = *const_cast<T*>(static_cast<const T*>(obj));\n\n    // Output the sequence\n    bool is_first = true;\n    for (auto it = std::begin(value); it != std::end(value); ++it)\n    {\n        if (!is_first)\n            ctx.append_raw(\", \");\n        is_first = false;\n        ctx.append_value(*it, spec);\n    }\n    return true;\n}\n\n// Make formattable_ref formattable\ninline formattable_ref_impl make_formattable_ref_custom(\n    formattable_ref v,\n    std::true_type  // is format ref\n)\n{\n    return access::get_impl(v);\n}\n\n// Make types with custom formatters formattable\ntemplate <class T>\nformattable_ref_impl make_formattable_ref_custom(\n    T&& v,\n    std::false_type  // is format ref\n)\n{\n    // If you're getting an error here, it means that you're passing a type\n    // that is not formattable to a SQL formatting function.\n    static_assert(\n        has_specialized_formatter<T>(),\n        \"T is not formattable. Please use a formattable type or specialize formatter<T> to make it \"\n        \"formattable\"\n    );\n\n    // Although everything is passed as const void*, do_format_custom_formatter\n    // can bypass const-ness for non-const values. This helps with non-const ranges (e.g. filter_view)\n    return {\n        formattable_ref_impl::type_t::fn_and_ptr,\n        formattable_ref_impl::\n            fn_and_ptr{&v, &do_format_custom_formatter<typename std::remove_reference<T>::type>}\n    };\n}\n\n// Make ranges formattable\ntemplate <class T>\nformattable_ref_impl make_formattable_ref_range(\n    T&& v,\n    std::true_type  // formattable range\n)\n{\n    // Although everything is passed as const void*, do_format_range\n    // can bypass const-ness for non-const ranges (e.g. filter_view)\n    return {\n        formattable_ref_impl::type_t::fn_and_ptr,\n        formattable_ref_impl::fn_and_ptr{&v, &do_format_range<typename std::remove_reference<T>::type>}\n    };\n}\n\ntemplate <class T>\nformattable_ref_impl make_formattable_ref_range(\n    T&& v,\n    std::false_type  // formattable range\n)\n{\n    return make_formattable_ref_custom(std::forward<T>(v), is_formattable_ref<T>());\n}\n\n// Used for types having is_writable_field<T>\ntemplate <class T>\nformattable_ref_impl make_formattable_ref_writable(\n    const T& v,\n    std::true_type  // is_writable_field\n)\n{\n    // Only string types (and not field_views or optionals) support the string specifiers\n    return {\n        std::is_convertible<T, string_view>::value ? formattable_ref_impl::type_t::field_with_specs\n                                                   : formattable_ref_impl::type_t::field,\n        to_field(v)\n    };\n}\n\ntemplate <class T>\nformattable_ref_impl make_formattable_ref_writable(\n    T&& v,\n    std::false_type  // is_writable_field\n)\n{\n    return make_formattable_ref_range(std::forward<T>(v), is_formattable_range<T>());\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\ntemplate <class T>\nboost::mysql::detail::formattable_ref_impl boost::mysql::detail::make_formattable_ref(T&& v)\n{\n    // Hierarchy:\n    //    1. writable field?\n    //    2. formattable range?\n    //    3. custom formatter or formattable_ref?\n    return make_formattable_ref_writable(std::forward<T>(v), is_writable_field_ref<T>());\n}\n\ntemplate <BOOST_MYSQL_FORMATTABLE... Formattable>\nstd::string boost::mysql::format_sql(\n    format_options opts,\n    constant_string_view format_str,\n    Formattable&&... args\n)\n{\n    std::initializer_list<format_arg> args_il{\n        {string_view(), std::forward<Formattable>(args)}\n        ...\n    };\n    return format_sql(opts, format_str, args_il);\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/format_sql.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_FORMAT_SQL_IPP\n#define BOOST_MYSQL_IMPL_FORMAT_SQL_IPP\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/escape_string.hpp>\n#include <boost/mysql/detail/format_sql.hpp>\n#include <boost/mysql/detail/output_string.hpp>\n\n#include <boost/mysql/impl/internal/byte_to_hex.hpp>\n#include <boost/mysql/impl/internal/call_next_char.hpp>\n#include <boost/mysql/impl/internal/dt_to_string.hpp>\n\n#include <boost/charconv/from_chars.hpp>\n#include <boost/charconv/to_chars.hpp>\n#include <boost/core/detail/string_view.hpp>\n#include <boost/system/result.hpp>\n#include <boost/system/system_error.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <cmath>\n#include <cstddef>\n#include <limits>\n#include <string>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Helpers to format fundamental types\ninline void append_quoted_identifier(string_view name, format_context_base& ctx)\n{\n    ctx.append_raw(\"`\");\n    auto& impl = access::get_impl(ctx);\n    auto ec = detail::escape_string(name, impl.opts, '`', impl.output);\n    if (ec)\n        ctx.add_error(ec);\n    ctx.append_raw(\"`\");\n}\n\ntemplate <class T>\nvoid append_int(T integer, format_context_base& ctx)\n{\n    // Make sure our buffer is big enough. 2: sign + digits10 is only 1 below max\n    constexpr std::size_t buffsize = 32;\n    static_assert(2 + std::numeric_limits<double>::digits10 < buffsize, \"\");\n\n    char buff[buffsize];\n\n    auto res = charconv::to_chars(buff, buff + buffsize, integer);\n\n    // Can only fail because of buffer being too small\n    BOOST_ASSERT(res.ec == std::errc());\n\n    // Copy\n    access::get_impl(ctx).output.append(string_view(buff, res.ptr - buff));\n}\n\ninline void append_double(double number, format_context_base& ctx)\n{\n    // Make sure our buffer is big enough. 4: sign, radix point, e+\n    // 3: max exponent digits\n    constexpr std::size_t buffsize = 32;\n    static_assert(4 + std::numeric_limits<double>::max_digits10 + 3 < buffsize, \"\");\n\n    // inf and nan are not supported by MySQL\n    if (std::isinf(number) || std::isnan(number))\n    {\n        ctx.add_error(client_errc::unformattable_value);\n        return;\n    }\n\n    char buff[buffsize];\n\n    // We format as scientific to make MySQL understand the number as a double.\n    // Otherwise, it takes it as a DECIMAL.\n    auto res = charconv::to_chars(buff, buff + buffsize, number, charconv::chars_format::scientific);\n\n    // Can only fail because of buffer being too small\n    BOOST_ASSERT(res.ec == std::errc());\n\n    // Copy\n    access::get_impl(ctx).output.append(string_view(buff, res.ptr - buff));\n}\n\ninline void append_quoted_string(string_view str, format_context_base& ctx)\n{\n    auto& impl = access::get_impl(ctx);\n    impl.output.append(\"'\");\n    auto ec = detail::escape_string(str, impl.opts, '\\'', impl.output);\n    if (ec)\n        ctx.add_error(ec);\n    impl.output.append(\"'\");\n}\n\ninline void append_string(string_view str, string_view format_spec, format_context_base& ctx)\n{\n    // Parse format spec\n    if (format_spec.size() > 1u)\n    {\n        ctx.add_error(client_errc::format_string_invalid_specifier);\n        return;\n    }\n\n    // No specifier: quoted string\n    if (format_spec.empty())\n        return append_quoted_string(str, ctx);\n\n    // We got a specifier\n    switch (format_spec[0])\n    {\n    case 'i':\n        // format as identifier\n        return append_quoted_identifier(str, ctx);\n    case 'r':\n        // append raw SQL\n        ctx.append_raw(runtime(str));\n        break;\n    default: ctx.add_error(client_errc::format_string_invalid_specifier);\n    }\n}\n\ninline void append_blob(blob_view b, format_context_base& ctx)\n{\n    // Blobs have a binary character set, which may include characters\n    // that are not valid in the current character set. However, escaping\n    // is always performed using the character_set_connection.\n    // mysql_real_escape_string escapes multibyte characters with a backslash,\n    // but this behavior is not documented, so we don't want to rely on it.\n    // The most reliable way to encode blobs is using hex strings.\n\n    // Output string\n    auto output = access::get_impl(ctx).output;\n\n    // We output characters to a temporary buffer, batching append calls\n    constexpr std::size_t buffer_size = 64;\n    char buffer[buffer_size]{};\n    char* it = buffer;\n    char* const end = buffer + buffer_size;\n\n    // Binary string introducer\n    output.append(\"x'\");\n\n    // Serialize contents\n    for (unsigned char byte : b)\n    {\n        // Serialize the byte\n        it = byte_to_hex(byte, it);\n\n        // If we filled the buffer, dump it\n        if (it == end)\n        {\n            output.append({buffer, buffer_size});\n            it = buffer;\n        }\n    }\n\n    // Dump anything that didn't fill the buffer\n    output.append({buffer, static_cast<std::size_t>(it - buffer)});\n\n    // Closing quote\n    ctx.append_raw(\"'\");\n}\n\ninline void append_quoted_date(date d, format_context_base& ctx)\n{\n    char buffer[34];\n    buffer[0] = '\\'';\n    std::size_t sz = detail::date_to_string(d.year(), d.month(), d.day(), span<char, 32>(buffer + 1, 32));\n    buffer[sz + 1] = '\\'';\n    access::get_impl(ctx).output.append(string_view(buffer, sz + 2));\n}\n\ninline void append_quoted_datetime(datetime d, format_context_base& ctx)\n{\n    char buffer[66];\n    buffer[0] = '\\'';\n    std::size_t sz = detail::datetime_to_string(\n        d.year(),\n        d.month(),\n        d.day(),\n        d.hour(),\n        d.minute(),\n        d.second(),\n        d.microsecond(),\n        span<char, 64>(buffer + 1, 64)\n    );\n    buffer[sz + 1] = '\\'';\n    access::get_impl(ctx).output.append(string_view(buffer, sz + 2));\n}\n\ninline void append_quoted_time(time t, format_context_base& ctx)\n{\n    char buffer[66];\n    buffer[0] = '\\'';\n    std::size_t sz = time_to_string(t, span<char, 64>(buffer + 1, 64));\n    buffer[sz + 1] = '\\'';\n    access::get_impl(ctx).output.append(string_view(buffer, sz + 2));\n}\n\ninline void append_field_view(\n    field_view fv,\n    string_view format_spec,\n    bool allow_specs,\n    format_context_base& ctx\n)\n{\n    auto kind = fv.kind();\n\n    // String types may allow specs\n    if (allow_specs && kind == field_kind::string)\n    {\n        append_string(fv.get_string(), format_spec, ctx);\n        return;\n    }\n\n    // Reject specifiers if !allow_specs or for other types\n    if (!format_spec.empty())\n    {\n        ctx.add_error(client_errc::format_string_invalid_specifier);\n        return;\n    }\n\n    // Perform the formatting operation\n    switch (fv.kind())\n    {\n    case field_kind::null: ctx.append_raw(\"NULL\"); return;\n    case field_kind::int64: return append_int(fv.get_int64(), ctx);\n    case field_kind::uint64: return append_int(fv.get_uint64(), ctx);\n    case field_kind::float_:\n        // float is formatted as double because it's parsed as such\n        return append_double(fv.get_float(), ctx);\n    case field_kind::double_: return append_double(fv.get_double(), ctx);\n    case field_kind::string: return append_quoted_string(fv.get_string(), ctx);\n    case field_kind::blob: return append_blob(fv.get_blob(), ctx);\n    case field_kind::date: return append_quoted_date(fv.get_date(), ctx);\n    case field_kind::datetime: return append_quoted_datetime(fv.get_datetime(), ctx);\n    case field_kind::time: return append_quoted_time(fv.get_time(), ctx);\n    default: BOOST_ASSERT(false); return;  // LCOV_EXCL_LINE\n    }\n}\n\n// Helpers for parsing format strings\ninline bool is_number(char c) { return c >= '0' && c <= '9'; }\n\ninline bool is_name_start(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; }\n\ninline bool is_format_spec_char(char c)\n{\n    return c != '{' && c != '}' && static_cast<unsigned char>(c) >= 0x20 &&\n           static_cast<unsigned char>(c) <= 0x7e;\n}\n\nclass format_state\n{\n    format_context_base& ctx_;\n    span<const format_arg> args_;\n\n    // Borrowed from fmt\n    // 0: we haven't used any args yet\n    // -1: we're doing explicit indexing\n    // >0: we're doing auto indexing\n    int next_arg_id_{0};\n\n    BOOST_ATTRIBUTE_NODISCARD\n    bool advance(const char*& it, const char* end)\n    {\n        std::size_t size = detail::call_next_char(ctx_.impl_.opts.charset, it, end);\n        if (size == 0)\n        {\n            ctx_.add_error(client_errc::format_string_invalid_encoding);\n            return false;\n        }\n        it += size;\n        return true;\n    }\n\n    bool uses_auto_ids() const noexcept { return next_arg_id_ > 0; }\n    bool uses_explicit_ids() const noexcept { return next_arg_id_ == -1; }\n\n    void do_field(format_arg arg, string_view format_spec)\n    {\n        ctx_.format_arg(access::get_impl(arg).value, format_spec);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    bool do_indexed_field(int arg_id, string_view format_spec)\n    {\n        BOOST_ASSERT(arg_id >= 0);\n        if (static_cast<std::size_t>(arg_id) >= args_.size())\n        {\n            ctx_.add_error(client_errc::format_arg_not_found);\n            return false;\n        }\n        do_field(args_[arg_id], format_spec);\n        return true;\n    }\n\n    struct arg_id_t\n    {\n        enum class type_t\n        {\n            none,\n            integral,\n            identifier\n        };\n        union data_t\n        {\n            unsigned short integral;\n            string_view identifier;\n\n            data_t() noexcept : integral{} {}\n        };\n\n        type_t type;\n        data_t data;\n\n        arg_id_t() noexcept : type(type_t::none), data() {}\n        arg_id_t(unsigned short v) noexcept : type(type_t::integral) { data.integral = v; }\n        arg_id_t(string_view v) noexcept : type(type_t::identifier) { data.identifier = v; }\n    };\n\n    BOOST_ATTRIBUTE_NODISCARD\n    static arg_id_t parse_arg_id(const char*& it, const char* format_end)\n    {\n        if (is_number(*it))\n        {\n            unsigned short field_index = 0;\n            auto res = charconv::from_chars(it, format_end, field_index);\n            if (res.ec != std::errc{})\n                return arg_id_t();\n            it = res.ptr;\n            return field_index;\n        }\n        else if (is_name_start(*it))\n        {\n            const char* name_begin = it;\n            while (it != format_end && (is_name_start(*it) || is_number(*it)))\n                ++it;\n            string_view field_name(name_begin, it);\n            return field_name;\n        }\n        else\n        {\n            return arg_id_t();\n        }\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    static string_view parse_format_spec(const char*& it, const char* format_end)\n    {\n        if (it != format_end && *it == ':')\n        {\n            ++it;\n            const char* first = it;\n            while (it != format_end && is_format_spec_char(*it))\n                ++it;\n            return {first, it};\n        }\n        else\n        {\n            return string_view();\n        }\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    bool parse_field(const char*& it, const char* format_end)\n    {\n        // Taken from fmtlib and adapted to our requirements\n        // it points to the character next to the opening '{'\n        // replacement_field ::=  \"{\" [arg_id] [\":\" (format_spec)] \"}\"\n        // arg_id            ::=  integer | identifier\n        // integer           ::=  <decimal, unsigned short, parsed by from_chars>\n        // identifier        ::=  id_start id_continue*\n        // id_start          ::=  \"a\"...\"z\" | \"A\"...\"Z\" | \"_\"\n        // id_continue       ::=  id_start | digit\n        // digit             ::=  \"0\"...\"9\"\n        // format_spec       ::=  <any character >= 0x20 && <= 0x7e && != \"{\", \"}\">\n\n        // Parse the ID and spec components\n        auto arg_id = parse_arg_id(it, format_end);\n        auto spec = parse_format_spec(it, format_end);\n\n        // If we're not at the end on the string, it's a syntax error\n        if (it == format_end || *it != '}')\n        {\n            ctx_.add_error(client_errc::format_string_invalid_syntax);\n            return false;\n        }\n        ++it;\n\n        // Process what was parsed\n        switch (arg_id.type)\n        {\n        case arg_id_t::type_t::none: return append_auto_field(spec);\n        case arg_id_t::type_t::integral: return append_indexed_field(arg_id.data.integral, spec);\n        case arg_id_t::type_t::identifier: return append_named_field(arg_id.data.identifier, spec);\n        default: BOOST_ASSERT(false); return false;  // LCOV_EXCL_LINE\n        }\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    bool append_named_field(string_view field_name, string_view format_spec)\n    {\n        // Find the argument\n        for (const auto& arg : args_)\n        {\n            if (access::get_impl(arg).name == field_name)\n            {\n                do_field(arg, format_spec);\n                return true;\n            }\n        }\n\n        // Not found\n        ctx_.add_error(client_errc::format_arg_not_found);\n        return false;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    bool append_indexed_field(int index, string_view format_spec)\n    {\n        if (uses_auto_ids())\n        {\n            ctx_.add_error(client_errc::format_string_manual_auto_mix);\n            return false;\n        }\n        next_arg_id_ = -1;\n        return do_indexed_field(index, format_spec);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    bool append_auto_field(string_view format_spec)\n    {\n        if (uses_explicit_ids())\n        {\n            ctx_.add_error(client_errc::format_string_manual_auto_mix);\n            return false;\n        }\n        return do_indexed_field(next_arg_id_++, format_spec);\n    }\n\npublic:\n    format_state(format_context_base& ctx, span<const format_arg> args) noexcept : ctx_(ctx), args_(args) {}\n\n    void format(string_view format_str)\n    {\n        // We can use operator++ when we know a character is ASCII. Some charsets\n        // allow ASCII continuation bytes, so we need to skip the entire character otherwise\n        auto cur_begin = format_str.data();\n        auto it = format_str.data();\n        auto end = format_str.data() + format_str.size();\n        while (it != end)\n        {\n            if (*it == '{')\n            {\n                // May be a replacement field or a literal brace. In any case, dump accumulated output\n                ctx_.impl_.output.append({cur_begin, it});\n                ++it;\n\n                if (it == end)\n                {\n                    // If the string ends here, it's en error\n                    ctx_.add_error(client_errc::format_string_invalid_syntax);\n                    return;\n                }\n                else if (*it == '{')\n                {\n                    // A double brace is the escaped form of '{'\n                    ctx_.append_raw(\"{\");\n                    ++it;\n                }\n                else\n                {\n                    // It's a replacement field. Process it\n                    if (!parse_field(it, end))\n                        return;\n                }\n                cur_begin = it;\n            }\n            else if (*it == '}')\n            {\n                // A lonely } is only legal as a escape curly brace (i.e. }})\n                ctx_.impl_.output.append({cur_begin, it});\n                ++it;\n                if (it == end || *it != '}')\n                {\n                    ctx_.add_error(client_errc::format_string_invalid_syntax);\n                    return;\n                }\n                ctx_.impl_.output.append(\"}\");\n                ++it;\n                cur_begin = it;\n            }\n            else\n            {\n                if (!advance(it, end))\n                    return;\n            }\n        }\n\n        // Dump any remaining SQL\n        ctx_.impl_.output.append({cur_begin, end});\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nvoid boost::mysql::format_context_base::format_arg(detail::formattable_ref_impl arg, string_view format_spec)\n{\n    switch (arg.type)\n    {\n    case detail::formattable_ref_impl::type_t::field:\n        detail::append_field_view(arg.data.fv, format_spec, false, *this);\n        break;\n    case detail::formattable_ref_impl::type_t::field_with_specs:\n        detail::append_field_view(arg.data.fv, format_spec, true, *this);\n        break;\n    case detail::formattable_ref_impl::type_t::fn_and_ptr:\n        if (!arg.data.custom.format_fn(arg.data.custom.obj, format_spec.begin(), format_spec.end(), *this))\n        {\n            add_error(client_errc::format_string_invalid_specifier);\n        }\n        break;\n    default: BOOST_ASSERT(false);  // LCOV_EXCL_LINE\n    }\n}\n\nvoid boost::mysql::detail::vformat_sql_to(\n    format_context_base& ctx,\n    constant_string_view format_str,\n    span<const format_arg> args\n)\n{\n    detail::format_state(ctx, args).format(format_str.get());\n}\n\nstd::string boost::mysql::format_sql(\n    format_options opts,\n    constant_string_view format_str,\n    std::initializer_list<format_arg> args\n)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, format_str, args);\n    return std::move(ctx).get().value();\n}\n\nstd::pair<bool, boost::mysql::string_view> boost::mysql::detail::parse_range_specifiers(\n    const char* spec_begin,\n    const char* spec_end\n)\n{\n    // range_format_spec ::=  [\":\" [underlying_spec]]\n    // Example: {::i} => format an array of strings as identifiers\n\n    // Empty: no specifiers\n    if (spec_begin == spec_end)\n        return {true, {}};\n\n    // If the first character is not a ':', the spec is invalid.\n    if (*spec_begin != ':')\n        return {false, {}};\n    ++spec_begin;\n\n    // Return the rest of the range\n    return {\n        true,\n        {spec_begin, spec_end}\n    };\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/byte_to_hex.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_BYTE_TO_HEX_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_BYTE_TO_HEX_HPP\n\n#include <boost/config.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// We implement the translation to hex ourselves, since it's easy enough.\n// We use a table to look up characters\nBOOST_INLINE_CONSTEXPR char byte_to_hex_table[16] =\n    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\n\n// it should point to a buffer of size 2, at least\ninline char* byte_to_hex(unsigned char byte, char* it)\n{\n    *it++ = byte_to_hex_table[(byte & ~15) >> 4];\n    *it++ = byte_to_hex_table[byte & 15];\n    return it;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/call_next_char.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_CALL_NEXT_CHAR_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_CALL_NEXT_CHAR_HPP\n\n#include <boost/mysql/character_set.hpp>\n\n#include <boost/assert.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline std::size_t call_next_char(const character_set& charset, const char* first, const char* last) noexcept\n{\n    // Range must be non-empty\n    BOOST_ASSERT(last > first);\n\n    // ASCII characters are always 1 byte (UTF-16 and friends are not supported)\n    auto* data = reinterpret_cast<const unsigned char*>(first);\n    if (*data < 0x80)\n        return 1u;\n\n    // May be a multi-byte character. Call the relevant function\n    return charset.next_char({data, static_cast<std::size_t>(last - first)});\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/connection_pool/connection_node.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_CONNECTION_NODE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_CONNECTION_NODE_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pipeline.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/connection_pool_fwd.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/internal_pool_params.hpp>\n#include <boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/basic_waitable_timer.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/compose.hpp>\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/intrusive/list.hpp>\n#include <boost/intrusive/list_hook.hpp>\n\n#include <chrono>\n#include <utility>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// State shared between connection tasks\ntemplate <class ConnectionType, class ClockType>\nstruct conn_shared_state\n{\n    // The list of connections that are currently idle. Non-owning.\n    intrusive::list<basic_connection_node<ConnectionType, ClockType>> idle_list;\n\n    // Timer acting as a condition variable to wait for idle connections\n    asio::basic_waitable_timer<ClockType> idle_connections_cv;\n\n    // The number of pending connections (currently getting ready).\n    // Required to compute how many connections we should create at any given point in time.\n    std::size_t num_pending_connections{0};\n\n    // The number of async_get_connection ops that are waiting for a connection to become available.\n    // Required to compute how many connections we should create at any given point in time.\n    std::size_t num_pending_requests{0};\n\n    // Info about the last connection attempt. Already processed, suitable to be used\n    // as the result of an async_get_connection op\n    diagnostics last_connect_diag;\n\n    // The number of running connections, to track when they exit\n    std::size_t num_running_connections{0};\n\n    // Timer acting as a condition variable to wait for all connections to exit\n    asio::basic_waitable_timer<ClockType> conns_finished_cv;\n\n    conn_shared_state(asio::any_io_executor ex)\n        : idle_connections_cv(ex, (ClockType::time_point::max)()),\n          conns_finished_cv(std::move(ex), (ClockType::time_point::max)())\n    {\n    }\n\n    void on_connection_start() { ++num_running_connections; }\n\n    void on_connection_finish()\n    {\n        if (--num_running_connections == 0u)\n            conns_finished_cv.expires_at((ClockType::time_point::min)());\n    }\n};\n\n// The templated type is never exposed to the user. We template\n// so tests can inject mocks.\ntemplate <class ConnectionType, class ClockType>\nclass basic_connection_node : public intrusive::list_base_hook<>,\n                              public sansio_connection_node<basic_connection_node<ConnectionType, ClockType>>\n{\n    using this_type = basic_connection_node<ConnectionType, ClockType>;\n    using timer_type = asio::basic_waitable_timer<ClockType>;\n\n    // Not thread-safe\n    const internal_pool_params* params_;\n    conn_shared_state<ConnectionType, ClockType>* shared_st_;\n    ConnectionType conn_;\n    timer_type timer_;\n    diagnostics connect_diag_;\n    timer_type collection_timer_;  // Notifications about collections. A separate timer makes potential race\n                                   // conditions not harmful\n    const pipeline_request* reset_pipeline_req_;\n    std::vector<stage_response> reset_pipeline_res_;\n\n    // Thread-safe\n    std::atomic<collection_state> collection_state_{collection_state::none};\n\n    // Hooks for sansio_connection_node\n    friend class sansio_connection_node<this_type>;\n    void entering_idle()\n    {\n        shared_st_->idle_list.push_back(*this);\n        shared_st_->idle_connections_cv.cancel_one();\n    }\n    void exiting_idle() { shared_st_->idle_list.erase(shared_st_->idle_list.iterator_to(*this)); }\n    void entering_pending() { ++shared_st_->num_pending_connections; }\n    void exiting_pending() { --shared_st_->num_pending_connections; }\n\n    // Helpers\n    void propagate_connect_diag(error_code ec)\n    {\n        shared_st_->last_connect_diag = create_connect_diagnostics(ec, connect_diag_);\n    }\n\n    template <class Op, class Self>\n    void run_with_timeout(Op&& op, std::chrono::steady_clock::duration timeout, Self& self)\n    {\n        if (timeout.count() > 0)\n        {\n            std::forward<Op>(op)(asio::cancel_after(timer_, timeout, std::move(self)));\n        }\n        else\n        {\n            std::forward<Op>(op)(std::move(self));\n        }\n    }\n\n    struct connection_task_op\n    {\n        this_type& node_;\n        next_connection_action last_act_{next_connection_action::none};\n\n        connection_task_op(this_type& node) noexcept : node_(node) {}\n\n        template <class Self>\n        void operator()(Self& self)\n        {\n            // Called when the op starts\n            node_.shared_st_->on_connection_start();\n            (*this)(self, error_code());\n        }\n\n        template <class Self>\n        void operator()(Self& self, error_code ec)\n        {\n            // A collection status may be generated by idle_wait actions\n            auto col_st = last_act_ == next_connection_action::idle_wait\n                              ? node_.collection_state_.exchange(collection_state::none)\n                              : collection_state::none;\n\n            // Connect actions should set the shared diagnostics, so these\n            // get reported to the user\n            if (last_act_ == next_connection_action::connect)\n                node_.propagate_connect_diag(ec);\n\n            // Invoke the sans-io algorithm\n            last_act_ = node_.resume(ec, col_st);\n\n            // Apply the next action\n            switch (last_act_)\n            {\n            case next_connection_action::connect:\n                node_.run_with_timeout(\n                    node_.conn_\n                        .async_connect(node_.params_->connect_config, node_.connect_diag_, asio::deferred),\n                    node_.params_->connect_timeout,\n                    self\n                );\n                break;\n            case next_connection_action::sleep_connect_failed:\n                node_.timer_.expires_after(node_.params_->retry_interval);\n                node_.timer_.async_wait(std::move(self));\n                break;\n            case next_connection_action::ping:\n                node_.run_with_timeout(\n                    node_.conn_.async_ping(asio::deferred),\n                    node_.params_->ping_timeout,\n                    self\n                );\n                break;\n            case next_connection_action::reset:\n                node_.run_with_timeout(\n                    node_.conn_.async_run_pipeline(\n                        *node_.reset_pipeline_req_,\n                        node_.reset_pipeline_res_,\n                        asio::deferred\n                    ),\n                    node_.params_->ping_timeout,\n                    self\n                );\n                break;\n            case next_connection_action::idle_wait:\n                node_.run_with_timeout(\n                    node_.collection_timer_.async_wait(asio::deferred),\n                    node_.params_->ping_interval,\n                    self\n                );\n                break;\n            case next_connection_action::none:\n                node_.shared_st_->on_connection_finish();\n                self.complete(error_code());\n                break;\n            default: BOOST_ASSERT(false);  // LCOV_EXCL_LINE\n            }\n        }\n    };\n\npublic:\n    basic_connection_node(\n        internal_pool_params& params,\n        boost::asio::any_io_executor pool_ex,\n        boost::asio::any_io_executor conn_ex,\n        conn_shared_state<ConnectionType, ClockType>& shared_st,\n        const pipeline_request* reset_pipeline_req\n    )\n        : params_(&params),\n          shared_st_(&shared_st),\n          conn_(std::move(conn_ex), params.make_ctor_params()),\n          timer_(pool_ex),\n          collection_timer_(pool_ex, (std::chrono::steady_clock::time_point::max)()),\n          reset_pipeline_req_(reset_pipeline_req)\n    {\n    }\n\n    // Not thread-safe\n    void cancel()\n    {\n        sansio_connection_node<this_type>::cancel();\n        timer_.cancel();\n        collection_timer_.cancel();\n    }\n\n    // Not thread-safe\n    template <class CompletionToken>\n    auto async_run(CompletionToken&& token)\n        -> decltype(asio::async_compose<CompletionToken, void(error_code)>(connection_task_op{*this}, token))\n    {\n        return asio::async_compose<CompletionToken, void(error_code)>(connection_task_op{*this}, token);\n    }\n\n    // Not thread-safe\n    void notify_collectable() { collection_timer_.cancel(); }\n\n    // Thread-safe\n    void mark_as_collectable(bool should_reset) noexcept\n    {\n        collection_state_.store(\n            should_reset ? collection_state::needs_collect_with_reset : collection_state::needs_collect\n        );\n    }\n\n    // Getter, used by pooled_connection\n    ConnectionType& connection() noexcept { return conn_; }\n\n    // Exposed for testing\n    collection_state get_collection_state() const noexcept { return collection_state_; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/connection_pool/connection_pool_impl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_CONNECTION_POOL_IMPL_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_CONNECTION_POOL_IMPL_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/connection_node.hpp>\n#include <boost/mysql/impl/internal/connection_pool/internal_pool_params.hpp>\n#include <boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp>\n#include <boost/mysql/impl/internal/coroutine.hpp>\n\n#include <boost/asio/any_completion_handler.hpp>\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/associated_cancellation_slot.hpp>\n#include <boost/asio/basic_waitable_timer.hpp>\n#include <boost/asio/bind_cancellation_slot.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/compose.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/immediate.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/asio/strand.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <list>\n#include <memory>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline pipeline_request make_reset_pipeline()\n{\n    pipeline_request req;\n    req.add_reset_connection().add_set_character_set(utf8mb4_charset);\n    return req;\n}\n\n// Templating on ConnectionWrapper is useful for mocking in tests.\n// Production code always uses ConnectionWrapper = pooled_connection.\ntemplate <class ConnectionType, class ClockType, class ConnectionWrapper>\nclass basic_pool_impl\n    : public std::enable_shared_from_this<basic_pool_impl<ConnectionType, ClockType, ConnectionWrapper>>\n{\n    using this_type = basic_pool_impl<ConnectionType, ClockType, ConnectionWrapper>;\n    using node_type = basic_connection_node<ConnectionType, ClockType>;\n    using timer_type = asio::basic_waitable_timer<ClockType>;\n    using shared_state_type = conn_shared_state<ConnectionType, ClockType>;\n\n    enum class state_t\n    {\n        initial,\n        running,\n        cancelled,\n    };\n\n    // The passed pool executor, as is\n    asio::any_io_executor original_pool_ex_;\n\n    // If thread_safe, a strand wrapping inner_pool_ex_, otherwise inner_pool_ex_\n    asio::any_io_executor pool_ex_;\n\n    // executor to be used by connections\n    asio::any_io_executor conn_ex_;\n\n    // Rest of the parameters\n    internal_pool_params params_;\n\n    // State\n    state_t state_{state_t::initial};\n    std::list<node_type> all_conns_;\n    shared_state_type shared_st_;\n    timer_type cancel_timer_;\n    const pipeline_request reset_pipeline_req_{make_reset_pipeline()};\n\n    std::shared_ptr<this_type> shared_from_this_wrapper()\n    {\n        // Some compilers get confused without this explicit cast\n        return static_cast<std::enable_shared_from_this<this_type>*>(this)->shared_from_this();\n    }\n\n    // Create and run one connection\n    void create_connection()\n    {\n        // Connection tasks always run in the pool's executor\n        all_conns_.emplace_back(params_, pool_ex_, conn_ex_, shared_st_, &reset_pipeline_req_);\n        all_conns_.back().async_run(asio::bind_executor(pool_ex_, asio::detached));\n    }\n\n    // Create and run connections as required by the current config and state\n    void create_connections()\n    {\n        // Calculate how many we should create\n        std::size_t n = num_connections_to_create(\n            params_.initial_size,\n            params_.max_size,\n            all_conns_.size(),\n            shared_st_.num_pending_connections,\n            shared_st_.num_pending_requests\n        );\n\n        // Create them\n        BOOST_ASSERT((all_conns_.size() + n) <= params_.max_size);\n        for (std::size_t i = 0; i < n; ++i)\n            create_connection();\n    }\n\n    // An async_get_connection request is about to wait for an available connection\n    void enter_request_pending()\n    {\n        // Record that we're pending\n        ++shared_st_.num_pending_requests;\n\n        // Create new connections, if required.\n        // Don't create any connections if we're not yet running,\n        // since this would leave connections running after run exits\n        if (state_ == state_t::running)\n            create_connections();\n    }\n\n    // An async_get_connection request finished waiting\n    void exit_request_pending()\n    {\n        // Record that we're no longer pending\n        BOOST_ASSERT(shared_st_.num_pending_requests > 0u);\n        --shared_st_.num_pending_requests;\n    }\n\n    node_type* try_get_connection()\n    {\n        if (!shared_st_.idle_list.empty())\n        {\n            node_type& res = shared_st_.idle_list.front();\n            res.mark_as_in_use();\n            return &res;\n        }\n        else\n        {\n            return nullptr;\n        }\n    }\n\n    template <class OpSelf>\n    void enter_strand(OpSelf& self)\n    {\n        asio::dispatch(asio::bind_executor(pool_ex_, std::move(self)));\n    }\n\n    template <class OpSelf>\n    void exit_strand(OpSelf& self)\n    {\n        asio::post(get_executor(), std::move(self));\n    }\n\n    template <class OpSelf>\n    void wait_for_connections(OpSelf& self)\n    {\n        // Having this encapsulated helps prevent subtle use-after-move errors\n        if (params_.thread_safe)\n        {\n            shared_st_.idle_connections_cv.async_wait(asio::bind_executor(pool_ex_, std::move(self)));\n        }\n        else\n        {\n            shared_st_.idle_connections_cv.async_wait(std::move(self));\n        }\n    }\n\n    struct run_op\n    {\n        int resume_point_{0};\n        std::shared_ptr<this_type> obj_;\n        asio::cancellation_slot cancel_slot_;\n\n        run_op(std::shared_ptr<this_type> obj, asio::cancellation_slot slot) noexcept\n            : obj_(std::move(obj)), cancel_slot_(slot)\n        {\n        }\n\n        struct cancel_handler\n        {\n            this_type* self;\n\n            void operator()(asio::cancellation_type_t type) const\n            {\n                if (run_supports_cancel_type(type))\n                    self->cancel();\n            }\n        };\n\n        template <class Self>\n        void operator()(Self& self, error_code = {})\n        {\n            switch (resume_point_)\n            {\n            case 0:\n                // Emplace a cancellation handler, if required\n                if (cancel_slot_.is_connected())\n                {\n                    cancel_slot_.template emplace<cancel_handler>(cancel_handler{obj_.get()});\n                }\n\n                // Ensure we run within the strand\n                if (obj_->params_.thread_safe)\n                {\n                    BOOST_MYSQL_YIELD(resume_point_, 1, obj_->enter_strand(self))\n                }\n\n                // Check that we're not running and set the state adequately\n                BOOST_ASSERT(obj_->state_ == state_t::initial);\n                obj_->state_ = state_t::running;\n\n                // Create the initial connections\n                obj_->create_connections();\n\n                // Wait for the cancel notification to arrive.\n                BOOST_MYSQL_YIELD(resume_point_, 2, obj_->cancel_timer_.async_wait(std::move(self)))\n\n                // Ensure we run within the strand\n                if (obj_->params_.thread_safe)\n                {\n                    BOOST_MYSQL_YIELD(resume_point_, 3, obj_->enter_strand(self))\n                }\n\n                // Deliver the cancel notification to all other tasks\n                obj_->state_ = state_t::cancelled;\n                for (auto& conn : obj_->all_conns_)\n                    conn.cancel();\n                obj_->shared_st_.idle_connections_cv.expires_at((ClockType::time_point::min)());\n\n                // Wait for all connection tasks to exit\n                BOOST_MYSQL_YIELD(\n                    resume_point_,\n                    4,\n                    obj_->shared_st_.conns_finished_cv.async_wait(std::move(self))\n                )\n\n                // Done\n                cancel_slot_.clear();\n                obj_.reset();\n                self.complete(error_code());\n            }\n        }\n    };\n\n    struct get_connection_op\n    {\n        // Operation arguments\n        std::shared_ptr<this_type> obj;\n        diagnostics* diag;\n\n        // The proxy signal. Used in thread-safe mode. Present here only for\n        // lifetime management\n        std::shared_ptr<asio::cancellation_signal> sig;\n\n        // The original cancellation slot. Needed for proper cleanup after we proxy\n        // the signal in thread-safe mode\n        asio::cancellation_slot parent_slot;\n\n        // State\n        int resume_point{0};\n        error_code result_ec;\n        node_type* result_conn{};\n        bool has_waited{false};\n\n        get_connection_op(\n            std::shared_ptr<this_type> obj,\n            diagnostics* diag,\n            std::shared_ptr<asio::cancellation_signal> sig,\n            asio::cancellation_slot parent_slot\n        ) noexcept\n            : obj(std::move(obj)), diag(diag), sig(std::move(sig)), parent_slot(parent_slot)\n        {\n        }\n\n        bool thread_safe() const { return obj->params_.thread_safe; }\n\n        template <class Self>\n        void do_complete(Self& self)\n        {\n            auto wr = result_ec ? ConnectionWrapper() : ConnectionWrapper(*result_conn, std::move(obj));\n            parent_slot.clear();\n            sig.reset();\n            self.complete(result_ec, std::move(wr));\n        }\n\n        template <class Self>\n        void operator()(Self& self, error_code = {})\n        {\n            switch (resume_point)\n            {\n            case 0:\n                // This op supports total cancellation. Must be explicitly enabled,\n                // as composed ops only support terminal cancellation by default.\n                self.reset_cancellation_state(asio::enable_total_cancellation());\n\n                // Clear diagnostics\n                if (diag)\n                    diag->clear();\n\n                // Enter the strand\n                if (thread_safe())\n                {\n                    BOOST_MYSQL_YIELD(resume_point, 1, obj->enter_strand(self))\n                }\n\n                // This loop guards us against possible race conditions\n                // between waiting on the pending request timer and getting the\n                // connection\n                while (true)\n                {\n                    if (obj->state_ == state_t::cancelled)\n                    {\n                        // The pool was cancelled\n                        result_ec = client_errc::pool_cancelled;\n                        break;\n                    }\n                    else if (get_connection_supports_cancel_type(self.cancelled()))\n                    {\n                        // The operation was cancelled. Try to provide diagnostics\n                        if (obj->state_ == state_t::initial)\n                        {\n                            // The operation failed because the pool is not running\n                            result_ec = client_errc::pool_not_running;\n                        }\n                        else\n                        {\n                            result_ec = client_errc::no_connection_available;\n                            if (diag)\n                                *diag = obj->shared_st_.last_connect_diag;\n                        }\n                        break;\n                    }\n\n                    // Try to get a connection\n                    if ((result_conn = obj->try_get_connection()) != nullptr)\n                    {\n                        // There was a connection\n                        break;\n                    }\n\n                    // No luck. Record that we're waiting for a connection.\n                    obj->enter_request_pending();\n\n                    // Wait to be notified, or until a cancellation happens\n                    BOOST_MYSQL_YIELD(resume_point, 2, obj->wait_for_connections(self))\n\n                    // Record that we're no longer pending\n                    obj->exit_request_pending();\n\n                    // Remember that we have waited, so completions are dispatched\n                    // correctly\n                    has_waited = true;\n                }\n\n                // Perform any required dispatching before completing\n                if (thread_safe())\n                {\n                    // Exit the strand\n                    BOOST_MYSQL_YIELD(resume_point, 3, obj->exit_strand(self))\n                }\n                else if (!has_waited)\n                {\n                    // This is an immediate completion\n                    BOOST_MYSQL_YIELD(\n                        resume_point,\n                        4,\n                        asio::async_immediate(self.get_io_executor(), std::move(self))\n                    )\n                }\n\n                // Done\n                do_complete(self);\n            }\n        }\n    };\n\n    // Cancel handler to use for get_connection in thread-safe mode.\n    // This imitates what Asio does for composed ops\n    struct get_connection_cancel_handler\n    {\n        // Pointer to the proxy cancellation signal\n        // Lifetime managed by the get_connection composed op\n        std::weak_ptr<asio::cancellation_signal> sig;\n\n        // Pointer to the pool object\n        std::weak_ptr<this_type> obj;\n\n        get_connection_cancel_handler(\n            std::weak_ptr<asio::cancellation_signal> sig,\n            std::weak_ptr<this_type> obj\n        ) noexcept\n            : sig(std::move(sig)), obj(std::move(obj))\n        {\n        }\n\n        void operator()(asio::cancellation_type_t type)\n        {\n            if (get_connection_supports_cancel_type(type))\n            {\n                // Try to get the pool object back\n                std::shared_ptr<this_type> obj_shared = obj.lock();\n                if (obj_shared)\n                {\n                    // Dispatch to the strand. We don't need to keep a reference to the\n                    // pool because even if it was destroyed before running the handler,\n                    // the strand would be alive.\n                    auto sig_copy = sig;\n                    asio::dispatch(asio::bind_executor(obj_shared->strand(), [sig_copy, type]() {\n                        // If the operation has already completed, the weak ptr will be\n                        // invalid\n                        auto sig_shared = sig_copy.lock();\n                        if (sig_shared)\n                        {\n                            sig_shared->emit(type);\n                        }\n                    }));\n                }\n            }\n        }\n    };\n\n    // Not thread-safe\n    void cancel_unsafe() { cancel_timer_.expires_at((std::chrono::steady_clock::time_point::min)()); }\n\npublic:\n    basic_pool_impl(asio::any_io_executor ex, pool_params&& params)\n        : original_pool_ex_(std::move(ex)),\n          pool_ex_(params.thread_safe ? asio::make_strand(original_pool_ex_) : original_pool_ex_),\n          conn_ex_(params.connection_executor ? std::move(params.connection_executor) : original_pool_ex_),\n          params_(make_internal_pool_params(std::move(params))),\n          shared_st_(pool_ex_),\n          cancel_timer_(pool_ex_, (std::chrono::steady_clock::time_point::max)())\n    {\n    }\n\n    asio::strand<asio::any_io_executor> strand()\n    {\n        BOOST_ASSERT(params_.thread_safe);\n        return *pool_ex_.template target<asio::strand<asio::any_io_executor>>();\n    }\n\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return original_pool_ex_; }\n\n    void async_run(asio::any_completion_handler<void(error_code)> handler)\n    {\n        // Completely disable composed cancellation handling, as it's not what we\n        // want\n        auto slot = asio::get_associated_cancellation_slot(handler);\n        auto token_without_slot = asio::bind_cancellation_slot(asio::cancellation_slot(), std::move(handler));\n\n        // Initiate passing the original token's slot manually\n        asio::async_compose<decltype(token_without_slot), void(error_code)>(\n            run_op(shared_from_this_wrapper(), slot),\n            token_without_slot,\n            pool_ex_\n        );\n    }\n\n    void async_get_connection(\n        diagnostics* diag,\n        asio::any_completion_handler<void(error_code, ConnectionWrapper)> handler\n    )\n    {\n        // The slot to pass for cleanup\n        asio::cancellation_slot parent_slot;\n\n        // The signal pointer. Will only be created if required\n        std::shared_ptr<asio::cancellation_signal> sig;\n\n        // In thread-safe mode, and if we have a connected slot, create a proxy\n        // signal that dispatches to the strand\n        if (params_.thread_safe)\n        {\n            parent_slot = asio::get_associated_cancellation_slot(handler);\n            if (parent_slot.is_connected())\n            {\n                // Create a signal. In rare cases, the memory acquired here may outlive\n                // the async operation (e.g. the completion handler runs after the\n                // signal is emitted and before the strand dispatch runs). This means we\n                // can't use the handler's allocator.\n                sig = std::make_shared<asio::cancellation_signal>();\n\n                // Emplace the handler\n                parent_slot.template emplace<get_connection_cancel_handler>(sig, shared_from_this_wrapper());\n\n                // Bind the handler to the slot\n                handler = asio::bind_cancellation_slot(sig->slot(), std::move(handler));\n            }\n        }\n\n        // Start\n        using handler_type = asio::any_completion_handler<void(error_code, ConnectionWrapper)>;\n        asio::async_compose<handler_type, void(error_code, ConnectionWrapper)>(\n            get_connection_op(shared_from_this_wrapper(), diag, std::move(sig), parent_slot),\n            handler,\n            pool_ex_\n        );\n    }\n\n    void cancel()\n    {\n        if (params_.thread_safe)\n        {\n            // A handler to be passed to dispatch. Binds the executor\n            // and keeps the pool alive\n            struct dispatch_handler\n            {\n                std::shared_ptr<this_type> pool_ptr;\n\n                using executor_type = asio::any_io_executor;\n                executor_type get_executor() const noexcept { return pool_ptr->strand(); }\n\n                void operator()() const { pool_ptr->cancel_unsafe(); }\n            };\n\n            asio::dispatch(dispatch_handler{shared_from_this_wrapper()});\n        }\n        else\n        {\n            cancel_unsafe();\n        }\n    }\n\n    void return_connection(node_type& node, bool should_reset) noexcept\n    {\n        // This is safe to be called from any thread\n        node.mark_as_collectable(should_reset);\n\n        // The notification isn't thread-safe\n        if (params_.thread_safe)\n        {\n            // A handler to be passed to dispatch. Binds the executor\n            // and keeps the pool alive\n            struct dispatch_handler\n            {\n                std::shared_ptr<this_type> pool_ptr;\n                node_type* node_ptr;\n\n                using executor_type = asio::any_io_executor;\n                executor_type get_executor() const noexcept { return pool_ptr->strand(); }\n\n                void operator()() const { node_ptr->notify_collectable(); }\n            };\n\n            // If, for any reason, this notification fails, the connection will\n            // be collected when the next ping is due.\n            try\n            {\n                asio::dispatch(dispatch_handler{shared_from_this_wrapper(), &node});\n            }\n            catch (...)\n            {\n            }\n        }\n        else\n        {\n            node.notify_collectable();\n        }\n    }\n\n    // Exposed for testing\n    static bool run_supports_cancel_type(asio::cancellation_type_t v)\n    {\n        // run doesn't support total, as the pool state is always modified\n        return !!(v & (asio::cancellation_type_t::partial | asio::cancellation_type_t::terminal));\n    }\n\n    static bool get_connection_supports_cancel_type(asio::cancellation_type_t v)\n    {\n        // get_connection supports all cancel types\n        return !!(\n            v & (asio::cancellation_type_t::partial | asio::cancellation_type_t::total |\n                 asio::cancellation_type_t::terminal)\n        );\n    }\n\n    std::list<node_type>& nodes() noexcept { return all_conns_; }\n    shared_state_type& shared_state() noexcept { return shared_st_; }\n    internal_pool_params& params() noexcept { return params_; }\n    asio::any_io_executor connection_ex() noexcept { return conn_ex_; }\n    const pipeline_request& reset_pipeline_request() const { return reset_pipeline_req_; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/connection_pool/internal_pool_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_INTERNAL_POOL_PARAMS_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_INTERNAL_POOL_PARAMS_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/ssl/context.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <stdexcept>\n#include <string>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Same as pool_params, but structured in a way that is more helpful for the impl\nstruct internal_pool_params\n{\n    connect_params connect_config;\n    optional<asio::ssl::context> ssl_ctx;\n    std::size_t initial_buffer_size;\n    std::size_t initial_size;\n    std::size_t max_size;\n    std::chrono::steady_clock::duration connect_timeout;\n    std::chrono::steady_clock::duration ping_timeout;\n    std::chrono::steady_clock::duration retry_interval;\n    std::chrono::steady_clock::duration ping_interval;\n    bool thread_safe;\n\n    any_connection_params make_ctor_params() noexcept\n    {\n        any_connection_params res;\n        res.ssl_context = ssl_ctx.get_ptr();\n        res.initial_buffer_size = initial_buffer_size;\n        return res;\n    }\n};\n\ninline void check_validity(const pool_params& params)\n{\n    const char* msg = nullptr;\n    if (params.max_size == 0)\n        msg = \"pool_params::max_size must be greater than zero\";\n    else if (params.max_size < params.initial_size)\n        msg = \"pool_params::max_size must be greater than pool_params::initial_size\";\n    else if (params.connect_timeout.count() < 0)\n        msg = \"pool_params::connect_timeout must not be negative\";\n    else if (params.retry_interval.count() <= 0)\n        msg = \"pool_params::retry_interval must be greater than zero\";\n    else if (params.ping_interval.count() < 0)\n        msg = \"pool_params::ping_interval must not be negative\";\n    else if (params.ping_timeout.count() < 0)\n        msg = \"pool_params::ping_timeout must not be negative\";\n\n    if (msg != nullptr)\n    {\n        BOOST_THROW_EXCEPTION(std::invalid_argument(msg));\n    }\n}\n\ninline internal_pool_params make_internal_pool_params(pool_params&& params)\n{\n    check_validity(params);\n\n    connect_params connect_prms;\n    connect_prms.server_address = std::move(params.server_address);\n    connect_prms.username = std::move(params.username);\n    connect_prms.password = std::move(params.password);\n    connect_prms.database = std::move(params.database);\n    connect_prms.ssl = params.ssl;\n    connect_prms.multi_queries = params.multi_queries;\n\n    return {\n        std::move(connect_prms),\n        std::move(params.ssl_ctx),\n        params.initial_buffer_size,\n        params.initial_size,\n        params.max_size,\n        params.connect_timeout,\n        params.ping_timeout,\n        params.retry_interval,\n        params.ping_interval,\n        params.thread_safe,\n    };\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_SANSIO_CONNECTION_NODE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_SANSIO_CONNECTION_NODE_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/assert.hpp>\n\n#include <algorithm>\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// The status the connection is in\nenum class node_status\n{\n    // Connection task hasn't initiated yet.\n    // This status doesn't count as pending. This facilitates tracking pending connections.\n    initial,\n\n    // Connection is trying to connect\n    connect_in_progress,\n\n    // Connect failed and we're sleeping\n    sleep_connect_failed_in_progress,\n\n    // Connection is trying to reset\n    reset_in_progress,\n\n    // Connection is trying to ping\n    ping_in_progress,\n\n    // Connection can be handed to the user\n    idle,\n\n    // Connection has been handed to the user\n    in_use,\n\n    // After cancel\n    terminated,\n};\n\n// The next I/O action the connection should take. There's\n// no 1-1 mapping to node_status\nenum class next_connection_action\n{\n    // Do nothing, exit the loop\n    none,\n\n    // Issue a connect\n    connect,\n\n    // Connect failed, issue a sleep\n    sleep_connect_failed,\n\n    // Wait until a collection request is issued or the ping interval elapses\n    idle_wait,\n\n    // Issue a reset\n    reset,\n\n    // Issue a ping\n    ping,\n};\n\n// A collection_state represents the possibility that a connection\n// that was in_use was returned by the user\nenum class collection_state\n{\n    // Connection wasn't returned\n    none,\n\n    // Connection was returned and needs reset\n    needs_collect,\n\n    // Connection was returned and doesn't need reset\n    needs_collect_with_reset\n};\n\n// CRTP. Derived should implement the entering_xxx and exiting_xxx hook functions.\n// Derived must derive from this class\ntemplate <class Derived>\nclass sansio_connection_node\n{\n    node_status status_;\n\n    inline bool is_pending(node_status status) noexcept\n    {\n        return status != node_status::initial && status != node_status::idle &&\n               status != node_status::in_use && status != node_status::terminated;\n    }\n\n    inline static next_connection_action status_to_action(node_status status) noexcept\n    {\n        switch (status)\n        {\n        case node_status::connect_in_progress: return next_connection_action::connect;\n        case node_status::sleep_connect_failed_in_progress:\n            return next_connection_action::sleep_connect_failed;\n        case node_status::ping_in_progress: return next_connection_action::ping;\n        case node_status::reset_in_progress: return next_connection_action::reset;\n        case node_status::idle:\n        case node_status::in_use: return next_connection_action::idle_wait;\n        default: return next_connection_action::none;\n        }\n    }\n\n    next_connection_action set_status(node_status new_status)\n    {\n        auto& derived = static_cast<Derived&>(*this);\n\n        // Notify we're entering/leaving the idle status\n        if (new_status == node_status::idle && status_ != node_status::idle)\n            derived.entering_idle();\n        else if (new_status != node_status::idle && status_ == node_status::idle)\n            derived.exiting_idle();\n\n        // Notify we're entering/leaving a pending status\n        if (!is_pending(status_) && is_pending(new_status))\n            derived.entering_pending();\n        else if (is_pending(status_) && !is_pending(new_status))\n            derived.exiting_pending();\n\n        // Actually update status\n        status_ = new_status;\n\n        return status_to_action(new_status);\n    }\n\npublic:\n    sansio_connection_node(node_status initial_status = node_status::initial) noexcept\n        : status_(initial_status)\n    {\n    }\n\n    void mark_as_in_use() noexcept\n    {\n        BOOST_ASSERT(status_ == node_status::idle);\n        set_status(node_status::in_use);\n    }\n\n    void cancel() { set_status(node_status::terminated); }\n\n    next_connection_action resume(error_code ec, collection_state col_st)\n    {\n        switch (status_)\n        {\n        case node_status::initial: return set_status(node_status::connect_in_progress);\n        case node_status::connect_in_progress:\n            return ec ? set_status(node_status::sleep_connect_failed_in_progress)\n                      : set_status(node_status::idle);\n        case node_status::sleep_connect_failed_in_progress:\n            return set_status(node_status::connect_in_progress);\n        case node_status::idle:\n            // The wait finished with no interruptions, and the connection\n            // is still idle. Time to ping.\n            return set_status(node_status::ping_in_progress);\n        case node_status::in_use:\n            // If col_st != none, the user has notified us to collect the connection.\n            // This happens after they return the connection to the pool.\n            // Update status and continue\n            if (col_st == collection_state::needs_collect)\n            {\n                // No reset needed, we're idle\n                return set_status(node_status::idle);\n            }\n            else if (col_st == collection_state::needs_collect_with_reset)\n            {\n                return set_status(node_status::reset_in_progress);\n            }\n            else\n            {\n                // The user is still using the connection (it's taking long, but can happen).\n                // Idle wait again until they return the connection.\n                return next_connection_action::idle_wait;\n            }\n        case node_status::ping_in_progress:\n        case node_status::reset_in_progress:\n            // Reconnect if there was an error. Otherwise, we're idle\n            return ec ? set_status(node_status::connect_in_progress) : set_status(node_status::idle);\n        case node_status::terminated:\n        default: return next_connection_action::none;\n        }\n    }\n\n    // Exposed for testing\n    node_status status() const noexcept { return status_; }\n};\n\n// Composes a diagnostics object containing info about the last connect error.\n// Suitable for the diagnostics output of async_get_connection\ninline diagnostics create_connect_diagnostics(error_code connect_ec, const diagnostics& connect_diag)\n{\n    diagnostics res;\n    if (connect_ec)\n    {\n        // Manipulating the internal representations is more efficient here,\n        // and better than using stringstream\n        auto& res_impl = access::get_impl(res);\n        const auto& connect_diag_impl = access::get_impl(connect_diag);\n\n        if (connect_ec == asio::error::operation_aborted)\n        {\n            // operation_aborted in this context means timeout\n            res_impl.msg = \"Last connection attempt timed out\";\n            res_impl.is_server = false;\n        }\n        else\n        {\n            // Add the error code information\n            res_impl.msg = \"Last connection attempt failed with: \";\n            res_impl.msg += connect_ec.message();\n            res_impl.msg += \" [\";\n            res_impl.msg += connect_ec.to_string();\n            res_impl.msg += \"]\";\n\n            // Add any diagnostics\n            if (connect_diag_impl.msg.empty())\n            {\n                // The resulting object doesn't contain server-supplied info\n                res_impl.is_server = false;\n            }\n            else\n            {\n                // The resulting object may contain server-supplied info\n                res_impl.msg += \": \";\n                res_impl.msg += connect_diag_impl.msg;\n                res_impl.is_server = connect_diag_impl.is_server;\n            }\n        }\n    }\n    return res;\n}\n\n// Given config params and the current state, computes the number\n// of connections that the pool should create at any given point in time\ninline std::size_t num_connections_to_create(\n    std::size_t initial_size,         // config\n    std::size_t max_size,             // config\n    std::size_t current_connections,  // the number of connections in the pool, in any state\n    std::size_t pending_connections,  // the number of connections in the pool in pending state\n    std::size_t pending_requests      // the current number of async_get_connection requests that are waiting\n)\n{\n    BOOST_ASSERT(initial_size <= max_size);\n    BOOST_ASSERT(current_connections <= max_size);\n    BOOST_ASSERT(pending_connections <= current_connections);\n\n    // We aim to have one pending connection per pending request.\n    // When these connections successfully connect, they will fulfill the pending requests.\n    std::size_t required_by_requests = pending_requests > pending_connections\n                                           ? static_cast<std::size_t>(pending_requests - pending_connections)\n                                           : 0u;\n\n    // We should always have at least min_connections.\n    // This might not be the case if the pool is just starting.\n    std::size_t required_by_min = current_connections < initial_size\n                                      ? static_cast<std::size_t>(initial_size - current_connections)\n                                      : 0u;\n\n    // We can't excess max_connections. This is the room for new connections that we have\n    std::size_t room = static_cast<std::size_t>(max_size - current_connections);\n\n    return (std::min)((std::max)(required_by_requests, required_by_min), room);\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/coroutine.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_COROUTINE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_COROUTINE_HPP\n\n// asio::coroutine uses __COUNTER__ internally, which can trigger\n// ODR violations if we use them in header-only code. These manifest as\n// extremely hard-to-debug bugs only present in release builds\n\n// Coroutine state is represented as an integer (resume_point_var).\n// Every yield gets assigned a unique value (resume_point_id).\n// Yielding sets the next resume point, returns, and sets a case label for re-entering.\n// Coroutines need to switch on resume_point_var to re-enter.\n\n// Enclosing this in a scope allows placing the macro inside a brace-less for/while loop\n// The empty scope after the case label is required because labels can't be at the end of a compound statement\n#define BOOST_MYSQL_YIELD(resume_point_var, resume_point_id, ...) \\\n    {                                                             \\\n        resume_point_var = resume_point_id;                       \\\n        return __VA_ARGS__;                                       \\\n    case resume_point_id:                                         \\\n    {                                                             \\\n    }                                                             \\\n    }\n\n#define BOOST_MYSQL_YIELD_VOID(resume_point_var, resume_point_id) \\\n    BOOST_MYSQL_YIELD(resume_point_var, resume_point_id, static_cast<void>(0))\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/dt_to_string.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_DT_TO_STRING_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_DT_TO_STRING_HPP\n\n#include <boost/mysql/time.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/charconv/to_chars.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <cstdlib>\n#include <system_error>\n#include <type_traits>\n\n// gcc-11+ issues spurious warnings about to_chars\n#if BOOST_GCC >= 70000\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wstringop-overflow\"\n#endif\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Helpers\ntemplate <class IntType>\ninline char* call_to_chars(char* begin, char* end, IntType value) noexcept\n{\n    auto r = charconv::to_chars(begin, end, value);\n    BOOST_ASSERT(r.ec == std::errc());\n    return r.ptr;\n}\n\ntemplate <class UnsignedInt>\ninline char* write_pad2(char* begin, char* end, UnsignedInt value) noexcept\n{\n    static_assert(std::is_unsigned<UnsignedInt>::value, \"\");\n    if (value < 10u)\n        *begin++ = '0';\n    return call_to_chars(begin, end, value);\n}\n\ninline char* write_pad4(char* begin, char* end, unsigned long value) noexcept\n{\n    for (auto l : {1000u, 100u, 10u})\n    {\n        if (value < l)\n            *begin++ = '0';\n    }\n    return call_to_chars(begin, end, value);\n}\n\ninline char* write_pad6(char* begin, char* end, unsigned long value) noexcept\n{\n    for (auto l : {100000u, 10000u, 1000u, 100u, 10u})\n    {\n        if (value < l)\n            *begin++ = '0';\n    }\n    return call_to_chars(begin, end, value);\n}\n\ninline std::size_t date_to_string(\n    std::uint16_t year,\n    std::uint8_t month,\n    std::uint8_t day,\n    span<char, 32> output\n) noexcept\n{\n    // Worst-case output is 14 chars, extra space just in case\n\n    // Iterators\n    char* it = output.data();\n    char* end = it + output.size();\n\n    // Year\n    it = write_pad4(it, end, year);\n\n    // Month\n    *it++ = '-';\n    it = write_pad2(it, end, static_cast<unsigned long>(month));\n\n    // Day\n    *it++ = '-';\n    it = write_pad2(it, end, static_cast<unsigned long>(day));\n\n    // Done\n    return it - output.data();\n}\n\ninline std::size_t datetime_to_string(\n    std::uint16_t year,\n    std::uint8_t month,\n    std::uint8_t day,\n    std::uint8_t hour,\n    std::uint8_t minute,\n    std::uint8_t second,\n    std::uint32_t microsecond,\n    span<char, 64> output\n) noexcept\n{\n    // Worst-case output is 37 chars, extra space just in case\n\n    // Iterators\n    char* it = output.data();\n    char* end = it + output.size();\n\n    // Date\n    it += date_to_string(year, month, day, span<char, 32>(it, 32));\n\n    // Hour\n    *it++ = ' ';\n    it = write_pad2(it, end, static_cast<unsigned long>(hour));\n\n    // Minutes\n    *it++ = ':';\n    it = write_pad2(it, end, static_cast<unsigned long>(minute));\n\n    // Seconds\n    *it++ = ':';\n    it = write_pad2(it, end, static_cast<unsigned long>(second));\n\n    // Microseconds\n    *it++ = '.';\n    it = write_pad6(it, end, microsecond);\n\n    // Done\n    return it - output.data();\n}\n\ninline std::size_t time_to_string(::boost::mysql::time value, span<char, 64> output) noexcept\n{\n    // Worst-case output is 34 chars, extra space just in case\n\n    // Values. Note that std::abs(time::min()) invokes UB because of\n    // signed integer overflow\n    constexpr auto min_val = (::boost::mysql::time::min)();\n    using unsigned_t = typename std::make_unsigned<typename ::boost::mysql::time::rep>::type;\n    auto total_count = value == min_val ? static_cast<unsigned_t>(min_val.count())\n                                        : static_cast<unsigned_t>(std::abs(value.count()));\n\n    auto num_micros = total_count % 1000000u;\n    total_count /= 1000000u;\n\n    auto num_secs = total_count % 60u;\n    total_count /= 60u;\n\n    auto num_mins = total_count % 60u;\n    total_count /= 60u;\n\n    auto num_hours = total_count;\n\n    // Iterators\n    char* it = output.data();\n    char* end = it + output.size();\n\n    // Sign\n    if (value.count() < 0)\n        *it++ = '-';\n\n    // Hours\n    it = write_pad2(it, end, num_hours);  // type is unspecified\n\n    // Minutes\n    *it++ = ':';\n    it = write_pad2(it, end, static_cast<unsigned long>(num_mins));\n\n    // Seconds\n    *it++ = ':';\n    it = write_pad2(it, end, static_cast<unsigned long>(num_secs));\n\n    // Microseconds\n    *it++ = '.';\n    it = write_pad6(it, end, static_cast<unsigned long>(num_micros));\n\n    // Done\n    return it - output.data();\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#if BOOST_GCC >= 110000\n#pragma GCC diagnostic pop\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/error/server_error_to_string.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_ERROR_SERVER_ERROR_TO_STRING_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_ERROR_SERVER_ERROR_TO_STRING_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Returns NULL if this is not a common error (not a member of common_server_errc)\nBOOST_MYSQL_DECL\nconst char* common_error_to_string(int v);\n\n// These return a default string if the error is not known\nBOOST_MYSQL_DECL\nconst char* mysql_error_to_string(int v);\n\nBOOST_MYSQL_DECL\nconst char* mariadb_error_to_string(int v);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/internal/error/server_error_to_string.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/error/server_error_to_string.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_ERROR_SERVER_ERROR_TO_STRING_IPP\n#define BOOST_MYSQL_IMPL_INTERNAL_ERROR_SERVER_ERROR_TO_STRING_IPP\n\n// This file was generated by server_errors.py - do not edit directly.\n\n#include <boost/config.hpp>\n#include <boost/mysql/impl/internal/error/server_error_to_string.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nBOOST_INLINE_CONSTEXPR const char* common_error_messages[] = {\n    \"er_hashchk\",\n    \"er_nisamchk\",\n    \"er_no\",\n    \"er_yes\",\n    \"er_cant_create_file\",\n    \"er_cant_create_table\",\n    \"er_cant_create_db\",\n    \"er_db_create_exists\",\n    \"er_db_drop_exists\",\n    \"er_db_drop_delete\",\n    \"er_db_drop_rmdir\",\n    \"er_cant_delete_file\",\n    \"er_cant_find_system_rec\",\n    \"er_cant_get_stat\",\n    \"er_cant_get_wd\",\n    \"er_cant_lock\",\n    \"er_cant_open_file\",\n    \"er_file_not_found\",\n    \"er_cant_read_dir\",\n    \"er_cant_set_wd\",\n    \"er_checkread\",\n    \"er_disk_full\",\n    \"er_dup_key\",\n    \"er_error_on_close\",\n    \"er_error_on_read\",\n    \"er_error_on_rename\",\n    \"er_error_on_write\",\n    \"er_file_used\",\n    \"er_filsort_abort\",\n    \"er_form_not_found\",\n    \"er_get_errno\",\n    \"er_illegal_ha\",\n    \"er_key_not_found\",\n    \"er_not_form_file\",\n    \"er_not_keyfile\",\n    \"er_old_keyfile\",\n    \"er_open_as_readonly\",\n    \"er_outofmemory\",\n    \"er_out_of_sortmemory\",\n    \"er_unexpected_eof\",\n    \"er_con_count_error\",\n    \"er_out_of_resources\",\n    \"er_bad_host_error\",\n    \"er_handshake_error\",\n    \"er_dbaccess_denied_error\",\n    \"er_access_denied_error\",\n    \"er_no_db_error\",\n    \"er_unknown_com_error\",\n    \"er_bad_null_error\",\n    \"er_bad_db_error\",\n    \"er_table_exists_error\",\n    \"er_bad_table_error\",\n    \"er_non_uniq_error\",\n    \"er_server_shutdown\",\n    \"er_bad_field_error\",\n    \"er_wrong_field_with_group\",\n    \"er_wrong_group_field\",\n    \"er_wrong_sum_select\",\n    \"er_wrong_value_count\",\n    \"er_too_long_ident\",\n    \"er_dup_fieldname\",\n    \"er_dup_keyname\",\n    \"er_dup_entry\",\n    \"er_wrong_field_spec\",\n    \"er_parse_error\",\n    \"er_empty_query\",\n    \"er_nonuniq_table\",\n    \"er_invalid_default\",\n    \"er_multiple_pri_key\",\n    \"er_too_many_keys\",\n    \"er_too_many_key_parts\",\n    \"er_too_long_key\",\n    \"er_key_column_does_not_exits\",\n    \"er_blob_used_as_key\",\n    \"er_too_big_fieldlength\",\n    \"er_wrong_auto_key\",\n    nullptr,\n    \"er_normal_shutdown\",\n    \"er_got_signal\",\n    \"er_shutdown_complete\",\n    \"er_forcing_close\",\n    \"er_ipsock_error\",\n    \"er_no_such_index\",\n    \"er_wrong_field_terminators\",\n    \"er_blobs_and_no_terminated\",\n    \"er_textfile_not_readable\",\n    \"er_file_exists_error\",\n    \"er_load_info\",\n    \"er_alter_info\",\n    \"er_wrong_sub_key\",\n    \"er_cant_remove_all_fields\",\n    \"er_cant_drop_field_or_key\",\n    \"er_insert_info\",\n    \"er_update_table_used\",\n    \"er_no_such_thread\",\n    \"er_kill_denied_error\",\n    \"er_no_tables_used\",\n    \"er_too_big_set\",\n    \"er_no_unique_logfile\",\n    \"er_table_not_locked_for_write\",\n    \"er_table_not_locked\",\n    nullptr,\n    \"er_wrong_db_name\",\n    \"er_wrong_table_name\",\n    \"er_too_big_select\",\n    \"er_unknown_error\",\n    \"er_unknown_procedure\",\n    \"er_wrong_paramcount_to_procedure\",\n    \"er_wrong_parameters_to_procedure\",\n    \"er_unknown_table\",\n    \"er_field_specified_twice\",\n    \"er_invalid_group_func_use\",\n    \"er_unsupported_extension\",\n    \"er_table_must_have_columns\",\n    \"er_record_file_full\",\n    \"er_unknown_character_set\",\n    \"er_too_many_tables\",\n    \"er_too_many_fields\",\n    \"er_too_big_rowsize\",\n    \"er_stack_overrun\",\n    nullptr,\n    \"er_null_column_in_index\",\n    \"er_cant_find_udf\",\n    \"er_cant_initialize_udf\",\n    \"er_udf_no_paths\",\n    \"er_udf_exists\",\n    \"er_cant_open_library\",\n    \"er_cant_find_dl_entry\",\n    \"er_function_not_defined\",\n    \"er_host_is_blocked\",\n    \"er_host_not_privileged\",\n    \"er_password_anonymous_user\",\n    \"er_password_not_allowed\",\n    \"er_password_no_match\",\n    \"er_update_info\",\n    \"er_cant_create_thread\",\n    \"er_wrong_value_count_on_row\",\n    \"er_cant_reopen_table\",\n    \"er_invalid_use_of_null\",\n    \"er_regexp_error\",\n    \"er_mix_of_group_func_and_fields\",\n    \"er_nonexisting_grant\",\n    \"er_tableaccess_denied_error\",\n    \"er_columnaccess_denied_error\",\n    \"er_illegal_grant_for_table\",\n    \"er_grant_wrong_host_or_user\",\n    \"er_no_such_table\",\n    \"er_nonexisting_table_grant\",\n    \"er_not_allowed_command\",\n    \"er_syntax_error\",\n    nullptr,\n    nullptr,\n    \"er_aborting_connection\",\n    \"er_net_packet_too_large\",\n    \"er_net_read_error_from_pipe\",\n    \"er_net_fcntl_error\",\n    \"er_net_packets_out_of_order\",\n    \"er_net_uncompress_error\",\n    \"er_net_read_error\",\n    \"er_net_read_interrupted\",\n    \"er_net_error_on_write\",\n    \"er_net_write_interrupted\",\n    \"er_too_long_string\",\n    \"er_table_cant_handle_blob\",\n    \"er_table_cant_handle_auto_increment\",\n    nullptr,\n    \"er_wrong_column_name\",\n    \"er_wrong_key_column\",\n    \"er_wrong_mrg_table\",\n    \"er_dup_unique\",\n    \"er_blob_key_without_length\",\n    \"er_primary_cant_have_null\",\n    \"er_too_many_rows\",\n    \"er_requires_primary_key\",\n    \"er_no_raid_compiled\",\n    \"er_update_without_key_in_safe_mode\",\n    nullptr,\n    \"er_check_no_such_table\",\n    \"er_check_not_implemented\",\n    \"er_cant_do_this_during_an_transaction\",\n    \"er_error_during_commit\",\n    \"er_error_during_rollback\",\n    \"er_error_during_flush_logs\",\n    \"er_error_during_checkpoint\",\n    \"er_new_aborting_connection\",\n    nullptr,\n    \"er_flush_master_binlog_closed\",\n    \"er_index_rebuild\",\n    \"er_master\",\n    \"er_master_net_read\",\n    \"er_master_net_write\",\n    \"er_ft_matching_key_not_found\",\n    \"er_lock_or_active_transaction\",\n    \"er_unknown_system_variable\",\n    \"er_crashed_on_usage\",\n    \"er_crashed_on_repair\",\n    \"er_warning_not_complete_rollback\",\n    \"er_trans_cache_full\",\n    \"er_slave_must_stop\",\n    \"er_slave_not_running\",\n    \"er_bad_slave\",\n    \"er_master_info\",\n    \"er_slave_thread\",\n    \"er_too_many_user_connections\",\n    \"er_set_constants_only\",\n    \"er_lock_wait_timeout\",\n    \"er_lock_table_full\",\n    \"er_read_only_transaction\",\n    \"er_drop_db_with_read_lock\",\n    \"er_create_db_with_read_lock\",\n    \"er_wrong_arguments\",\n    \"er_no_permission_to_create_user\",\n    \"er_union_tables_in_different_dir\",\n    \"er_lock_deadlock\",\n    \"er_table_cant_handle_ft\",\n    \"er_cannot_add_foreign\",\n    \"er_no_referenced_row\",\n    \"er_row_is_referenced\",\n    \"er_connect_to_master\",\n    \"er_query_on_master\",\n    \"er_error_when_executing_command\",\n    \"er_wrong_usage\",\n    \"er_wrong_number_of_columns_in_select\",\n    \"er_cant_update_with_readlock\",\n    \"er_mixing_not_allowed\",\n    \"er_dup_argument\",\n    \"er_user_limit_reached\",\n    \"er_specific_access_denied_error\",\n    \"er_local_variable\",\n    \"er_global_variable\",\n    \"er_no_default\",\n    \"er_wrong_value_for_var\",\n    \"er_wrong_type_for_var\",\n    \"er_var_cant_be_read\",\n    \"er_cant_use_option_here\",\n    \"er_not_supported_yet\",\n    \"er_master_fatal_error_reading_binlog\",\n    \"er_slave_ignored_table\",\n    \"er_incorrect_global_local_var\",\n    \"er_wrong_fk_def\",\n    \"er_key_ref_do_not_match_table_ref\",\n    \"er_operand_columns\",\n    \"er_subquery_no_1_row\",\n    \"er_unknown_stmt_handler\",\n    \"er_corrupt_help_db\",\n    \"er_cyclic_reference\",\n    \"er_auto_convert\",\n    \"er_illegal_reference\",\n    \"er_derived_must_have_alias\",\n    \"er_select_reduced\",\n    \"er_tablename_not_allowed_here\",\n    \"er_not_supported_auth_mode\",\n    \"er_spatial_cant_have_null\",\n    \"er_collation_charset_mismatch\",\n    \"er_slave_was_running\",\n    \"er_slave_was_not_running\",\n    \"er_too_big_for_uncompress\",\n    \"er_zlib_z_mem_error\",\n    \"er_zlib_z_buf_error\",\n    \"er_zlib_z_data_error\",\n    \"er_cut_value_group_concat\",\n    \"er_warn_too_few_records\",\n    \"er_warn_too_many_records\",\n    \"er_warn_null_to_notnull\",\n    \"er_warn_data_out_of_range\",\n    \"warn_data_truncated\",\n    \"er_warn_using_other_handler\",\n    \"er_cant_aggregate_2collations\",\n    \"er_drop_user\",\n    \"er_revoke_grants\",\n    \"er_cant_aggregate_3collations\",\n    \"er_cant_aggregate_ncollations\",\n    \"er_variable_is_not_struct\",\n    \"er_unknown_collation\",\n    \"er_slave_ignored_ssl_params\",\n    \"er_server_is_in_secure_auth_mode\",\n    \"er_warn_field_resolved\",\n    \"er_bad_slave_until_cond\",\n    \"er_missing_skip_slave\",\n    \"er_until_cond_ignored\",\n    \"er_wrong_name_for_index\",\n    \"er_wrong_name_for_catalog\",\n    \"er_warn_qc_resize\",\n    \"er_bad_ft_column\",\n    \"er_unknown_key_cache\",\n    \"er_warn_hostname_wont_work\",\n    \"er_unknown_storage_engine\",\n    \"er_warn_deprecated_syntax\",\n    \"er_non_updatable_table\",\n    \"er_feature_disabled\",\n    \"er_option_prevents_statement\",\n    \"er_duplicated_value_in_type\",\n    \"er_truncated_wrong_value\",\n    \"er_too_much_auto_timestamp_cols\",\n    \"er_invalid_on_update\",\n    \"er_unsupported_ps\",\n    \"er_get_errmsg\",\n    \"er_get_temporary_errmsg\",\n    \"er_unknown_time_zone\",\n    \"er_warn_invalid_timestamp\",\n    \"er_invalid_character_string\",\n    \"er_warn_allowed_packet_overflowed\",\n    \"er_conflicting_declarations\",\n    \"er_sp_no_recursive_create\",\n    \"er_sp_already_exists\",\n    \"er_sp_does_not_exist\",\n    \"er_sp_drop_failed\",\n    \"er_sp_store_failed\",\n    \"er_sp_lilabel_mismatch\",\n    \"er_sp_label_redefine\",\n    \"er_sp_label_mismatch\",\n    \"er_sp_uninit_var\",\n    \"er_sp_badselect\",\n    \"er_sp_badreturn\",\n    \"er_sp_badstatement\",\n    \"er_update_log_deprecated_ignored\",\n    \"er_update_log_deprecated_translated\",\n    \"er_query_interrupted\",\n    \"er_sp_wrong_no_of_args\",\n    \"er_sp_cond_mismatch\",\n    \"er_sp_noreturn\",\n    \"er_sp_noreturnend\",\n    \"er_sp_bad_cursor_query\",\n    \"er_sp_bad_cursor_select\",\n    \"er_sp_cursor_mismatch\",\n    \"er_sp_cursor_already_open\",\n    \"er_sp_cursor_not_open\",\n    \"er_sp_undeclared_var\",\n    \"er_sp_wrong_no_of_fetch_args\",\n    \"er_sp_fetch_no_data\",\n    \"er_sp_dup_param\",\n    \"er_sp_dup_var\",\n    \"er_sp_dup_cond\",\n    \"er_sp_dup_curs\",\n    \"er_sp_cant_alter\",\n    \"er_sp_subselect_nyi\",\n    \"er_stmt_not_allowed_in_sf_or_trg\",\n    \"er_sp_varcond_after_curshndlr\",\n    \"er_sp_cursor_after_handler\",\n    \"er_sp_case_not_found\",\n    \"er_fparser_too_big_file\",\n    \"er_fparser_bad_header\",\n    \"er_fparser_eof_in_comment\",\n    \"er_fparser_error_in_parameter\",\n    \"er_fparser_eof_in_unknown_parameter\",\n    \"er_view_no_explain\",\n    \"er_frm_unknown_type\",\n    \"er_wrong_object\",\n    \"er_nonupdateable_column\",\n    nullptr,\n    \"er_view_select_clause\",\n    \"er_view_select_variable\",\n    \"er_view_select_tmptable\",\n    \"er_view_wrong_list\",\n    \"er_warn_view_merge\",\n    \"er_warn_view_without_key\",\n    \"er_view_invalid\",\n    \"er_sp_no_drop_sp\",\n    \"er_sp_goto_in_hndlr\",\n    \"er_trg_already_exists\",\n    \"er_trg_does_not_exist\",\n    \"er_trg_on_view_or_temp_table\",\n    \"er_trg_cant_change_row\",\n    \"er_trg_no_such_row_in_trg\",\n    \"er_no_default_for_field\",\n    \"er_division_by_zero\",\n    \"er_truncated_wrong_value_for_field\",\n    \"er_illegal_value_for_type\",\n    \"er_view_nonupd_check\",\n    \"er_view_check_failed\",\n    \"er_procaccess_denied_error\",\n    \"er_relay_log_fail\",\n    \"er_passwd_length\",\n    \"er_unknown_target_binlog\",\n    \"er_io_err_log_index_read\",\n    \"er_binlog_purge_prohibited\",\n    \"er_fseek_fail\",\n    \"er_binlog_purge_fatal_err\",\n    \"er_log_in_use\",\n    \"er_log_purge_unknown_err\",\n    \"er_relay_log_init\",\n    \"er_no_binary_logging\",\n    \"er_reserved_syntax\",\n    \"er_wsas_failed\",\n    \"er_diff_groups_proc\",\n    \"er_no_group_for_proc\",\n    \"er_order_with_proc\",\n    \"er_logging_prohibit_changing_of\",\n    \"er_no_file_mapping\",\n    \"er_wrong_magic\",\n    \"er_ps_many_param\",\n    \"er_key_part_0\",\n    \"er_view_checksum\",\n    \"er_view_multiupdate\",\n    \"er_view_no_insert_field_list\",\n    \"er_view_delete_merge_view\",\n    \"er_cannot_user\",\n    \"er_xaer_nota\",\n    \"er_xaer_inval\",\n    \"er_xaer_rmfail\",\n    \"er_xaer_outside\",\n    \"er_xaer_rmerr\",\n    \"er_xa_rbrollback\",\n    \"er_nonexisting_proc_grant\",\n    \"er_proc_auto_grant_fail\",\n    \"er_proc_auto_revoke_fail\",\n    \"er_data_too_long\",\n    \"er_sp_bad_sqlstate\",\n    \"er_startup\",\n    \"er_load_from_fixed_size_rows_to_var\",\n    \"er_cant_create_user_with_grant\",\n    \"er_wrong_value_for_type\",\n    \"er_table_def_changed\",\n    \"er_sp_dup_handler\",\n    \"er_sp_not_var_arg\",\n    \"er_sp_no_retset\",\n    \"er_cant_create_geometry_object\",\n    \"er_failed_routine_break_binlog\",\n    \"er_binlog_unsafe_routine\",\n    \"er_binlog_create_routine_need_super\",\n    \"er_exec_stmt_with_open_cursor\",\n    \"er_stmt_has_no_open_cursor\",\n    \"er_commit_not_allowed_in_sf_or_trg\",\n    \"er_no_default_for_view_field\",\n    \"er_sp_no_recursion\",\n    \"er_too_big_scale\",\n    \"er_too_big_precision\",\n    \"er_m_bigger_than_d\",\n    \"er_wrong_lock_of_system_table\",\n    \"er_connect_to_foreign_data_source\",\n    \"er_query_on_foreign_data_source\",\n    \"er_foreign_data_source_doesnt_exist\",\n    \"er_foreign_data_string_invalid_cant_create\",\n    \"er_foreign_data_string_invalid\",\n    \"er_cant_create_federated_table\",\n    \"er_trg_in_wrong_schema\",\n    \"er_stack_overrun_need_more\",\n    \"er_too_long_body\",\n    \"er_warn_cant_drop_default_keycache\",\n    \"er_too_big_displaywidth\",\n    \"er_xaer_dupid\",\n    \"er_datetime_function_overflow\",\n    \"er_cant_update_used_table_in_sf_or_trg\",\n    \"er_view_prevent_update\",\n    \"er_ps_no_recursion\",\n    \"er_sp_cant_set_autocommit\",\n    \"er_malformed_definer\",\n    \"er_view_frm_no_user\",\n    \"er_view_other_user\",\n    \"er_no_such_user\",\n    \"er_forbid_schema_change\",\n    \"er_row_is_referenced_2\",\n    \"er_no_referenced_row_2\",\n    \"er_sp_bad_var_shadow\",\n    \"er_trg_no_definer\",\n    \"er_old_file_format\",\n    \"er_sp_recursion_limit\",\n    \"er_sp_proc_table_corrupt\",\n    \"er_sp_wrong_name\",\n    \"er_table_needs_upgrade\",\n    \"er_sp_no_aggregate\",\n    \"er_max_prepared_stmt_count_reached\",\n    \"er_view_recursive\",\n    \"er_non_grouping_field_used\",\n    \"er_table_cant_handle_spkeys\",\n    \"er_no_triggers_on_system_schema\",\n    \"er_removed_spaces\",\n    \"er_autoinc_read_failed\",\n    \"er_username\",\n    \"er_hostname\",\n    \"er_wrong_string_length\",\n    \"er_non_insertable_table\",\n    \"er_admin_wrong_mrg_table\",\n    \"er_too_high_level_of_nesting_for_select\",\n    \"er_name_becomes_empty\",\n    \"er_ambiguous_field_term\",\n    \"er_foreign_server_exists\",\n    \"er_foreign_server_doesnt_exist\",\n    \"er_illegal_ha_create_option\",\n    \"er_partition_requires_values_error\",\n    \"er_partition_wrong_values_error\",\n    \"er_partition_maxvalue_error\",\n    \"er_partition_subpartition_error\",\n    \"er_partition_subpart_mix_error\",\n    \"er_partition_wrong_no_part_error\",\n    \"er_partition_wrong_no_subpart_error\",\n    \"er_wrong_expr_in_partition_func_error\",\n    nullptr,\n    \"er_field_not_found_part_error\",\n    \"er_list_of_fields_only_in_hash_error\",\n    \"er_inconsistent_partition_info_error\",\n    \"er_partition_func_not_allowed_error\",\n    \"er_partitions_must_be_defined_error\",\n    \"er_range_not_increasing_error\",\n    \"er_inconsistent_type_of_functions_error\",\n    \"er_multiple_def_const_in_list_part_error\",\n    \"er_partition_entry_error\",\n    \"er_mix_handler_error\",\n    \"er_partition_not_defined_error\",\n    \"er_too_many_partitions_error\",\n    \"er_subpartition_error\",\n    \"er_cant_create_handler_file\",\n    \"er_blob_field_in_part_func_error\",\n    \"er_unique_key_need_all_fields_in_pf\",\n    \"er_no_parts_error\",\n    \"er_partition_mgmt_on_nonpartitioned\",\n    nullptr,\n    \"er_drop_partition_non_existent\",\n    \"er_drop_last_partition\",\n    \"er_coalesce_only_on_hash_partition\",\n    \"er_reorg_hash_only_on_same_no\",\n    \"er_reorg_no_param_error\",\n    \"er_only_on_range_list_partition\",\n    \"er_add_partition_subpart_error\",\n    \"er_add_partition_no_new_partition\",\n    \"er_coalesce_partition_no_partition\",\n    \"er_reorg_partition_not_exist\",\n    \"er_same_name_partition\",\n    \"er_no_binlog_error\",\n    \"er_consecutive_reorg_partitions\",\n    \"er_reorg_outside_range\",\n    \"er_partition_function_failure\",\n    \"er_part_state_error\",\n    \"er_limited_part_range\",\n    \"er_plugin_is_not_loaded\",\n    \"er_wrong_value\",\n    \"er_no_partition_for_given_value\",\n    \"er_filegroup_option_only_once\",\n    \"er_create_filegroup_failed\",\n    \"er_drop_filegroup_failed\",\n    \"er_tablespace_auto_extend_error\",\n    \"er_wrong_size_number\",\n    \"er_size_overflow_error\",\n    \"er_alter_filegroup_failed\",\n    \"er_binlog_row_logging_failed\",\n    \"er_binlog_row_wrong_table_def\",\n    \"er_binlog_row_rbr_to_sbr\",\n    \"er_event_already_exists\",\n    \"er_event_store_failed\",\n    \"er_event_does_not_exist\",\n    \"er_event_cant_alter\",\n    \"er_event_drop_failed\",\n    \"er_event_interval_not_positive_or_too_big\",\n    \"er_event_ends_before_starts\",\n    \"er_event_exec_time_in_the_past\",\n    \"er_event_open_table_failed\",\n    \"er_event_neither_m_expr_nor_m_at\",\n    nullptr,\n    nullptr,\n    \"er_event_cannot_delete\",\n    \"er_event_compile_error\",\n    \"er_event_same_name\",\n    \"er_event_data_too_long\",\n    \"er_drop_index_fk\",\n    \"er_warn_deprecated_syntax_with_ver\",\n    \"er_cant_write_lock_log_table\",\n    \"er_cant_lock_log_table\",\n    nullptr,\n    \"er_col_count_doesnt_match_please_update\",\n    \"er_temp_table_prevents_switch_out_of_rbr\",\n    \"er_stored_function_prevents_switch_binlog_format\",\n    nullptr,\n    \"er_partition_no_temporary\",\n    \"er_partition_const_domain_error\",\n    \"er_partition_function_is_not_allowed\",\n    \"er_ddl_log_error\",\n    \"er_null_in_values_less_than\",\n    \"er_wrong_partition_name\",\n    \"er_cant_change_tx_characteristics\",\n    \"er_dup_entry_autoincrement_case\",\n    \"er_event_modify_queue_error\",\n    \"er_event_set_var_error\",\n    \"er_partition_merge_error\",\n    \"er_cant_activate_log\",\n    \"er_rbr_not_available\",\n    \"er_base64_decode_error\",\n    \"er_event_recursion_forbidden\",\n    \"er_events_db_error\",\n    \"er_only_integers_allowed\",\n    \"er_unsuported_log_engine\",\n    \"er_bad_log_statement\",\n    \"er_cant_rename_log_table\",\n    \"er_wrong_paramcount_to_native_fct\",\n    \"er_wrong_parameters_to_native_fct\",\n    \"er_wrong_parameters_to_stored_fct\",\n    \"er_native_fct_name_collision\",\n    \"er_dup_entry_with_key_name\",\n    \"er_binlog_purge_emfile\",\n    \"er_event_cannot_create_in_the_past\",\n    \"er_event_cannot_alter_in_the_past\",\n    \"er_slave_incident\",\n    \"er_no_partition_for_given_value_silent\",\n    \"er_binlog_unsafe_statement\",\n    nullptr,\n    \"er_slave_relay_log_read_failure\",\n    \"er_slave_relay_log_write_failure\",\n    \"er_slave_create_event_failure\",\n    \"er_slave_master_com_failure\",\n    \"er_binlog_logging_impossible\",\n    \"er_view_no_creation_ctx\",\n    \"er_view_invalid_creation_ctx\",\n    \"er_sr_invalid_creation_ctx\",\n    \"er_trg_corrupted_file\",\n    \"er_trg_no_creation_ctx\",\n    \"er_trg_invalid_creation_ctx\",\n    \"er_event_invalid_creation_ctx\",\n    \"er_trg_cant_open_table\",\n    \"er_cant_create_sroutine\",\n    nullptr,\n    \"er_no_format_description_event_before_binlog_statement\",\n    \"er_slave_corrupt_event\",\n    nullptr,\n    \"er_log_purge_no_file\",\n    \"er_xa_rbtimeout\",\n    \"er_xa_rbdeadlock\",\n    \"er_need_reprepare\",\n    \"er_delayed_not_supported\",\n    \"warn_no_master_info\",\n    \"warn_option_ignored\",\n    \"er_plugin_delete_builtin\",\n    \"warn_plugin_busy\",\n    \"er_variable_is_readonly\",\n    \"er_warn_engine_transaction_rollback\",\n    \"er_slave_heartbeat_failure\",\n    \"er_slave_heartbeat_value_out_of_range\",\n    nullptr,\n    \"er_conflict_fn_parse_error\",\n    \"er_exceptions_write_error\",\n    \"er_too_long_table_comment\",\n    \"er_too_long_field_comment\",\n    \"er_func_inexistent_name_collision\",\n    \"er_database_name\",\n    \"er_table_name\",\n    \"er_partition_name\",\n    \"er_subpartition_name\",\n    \"er_temporary_name\",\n    \"er_renamed_name\",\n    \"er_too_many_concurrent_trxs\",\n    \"warn_non_ascii_separator_not_implemented\",\n    \"er_debug_sync_timeout\",\n    \"er_debug_sync_hit_limit\",\n    \"er_dup_signal_set\",\n    \"er_signal_warn\",\n    \"er_signal_not_found\",\n    \"er_signal_exception\",\n    \"er_resignal_without_active_handler\",\n    \"er_signal_bad_condition_type\",\n    \"warn_cond_item_truncated\",\n    \"er_cond_item_too_long\",\n    \"er_unknown_locale\",\n    \"er_slave_ignore_server_ids\",\n    \"er_query_cache_disabled\",\n    \"er_same_name_partition_field\",\n    \"er_partition_column_list_error\",\n    \"er_wrong_type_column_value_error\",\n    \"er_too_many_partition_func_fields_error\",\n    \"er_maxvalue_in_values_in\",\n    \"er_too_many_values_error\",\n    \"er_row_single_partition_field_error\",\n    \"er_field_type_not_allowed_as_partition_field\",\n    \"er_partition_fields_too_long\",\n    \"er_binlog_row_engine_and_stmt_engine\",\n    \"er_binlog_row_mode_and_stmt_engine\",\n    \"er_binlog_unsafe_and_stmt_engine\",\n    \"er_binlog_row_injection_and_stmt_engine\",\n    \"er_binlog_stmt_mode_and_row_engine\",\n    \"er_binlog_row_injection_and_stmt_mode\",\n    \"er_binlog_multiple_engines_and_self_logging_engine\",\n    \"er_binlog_unsafe_limit\",\n    nullptr,\n    \"er_binlog_unsafe_system_table\",\n    \"er_binlog_unsafe_autoinc_columns\",\n    \"er_binlog_unsafe_udf\",\n    \"er_binlog_unsafe_system_variable\",\n    \"er_binlog_unsafe_system_function\",\n    \"er_binlog_unsafe_nontrans_after_trans\",\n    \"er_message_and_statement\",\n    \"er_slave_conversion_failed\",\n    \"er_slave_cant_create_conversion\",\n    \"er_inside_transaction_prevents_switch_binlog_format\",\n    \"er_path_length\",\n    \"er_warn_deprecated_syntax_no_replacement\",\n    \"er_wrong_native_table_structure\",\n    \"er_wrong_perfschema_usage\",\n    \"er_warn_i_s_skipped_table\",\n    \"er_inside_transaction_prevents_switch_binlog_direct\",\n    \"er_stored_function_prevents_switch_binlog_direct\",\n    \"er_spatial_must_have_geom_col\",\n    \"er_too_long_index_comment\",\n    \"er_lock_aborted\",\n    \"er_data_out_of_range\",\n    \"er_wrong_spvar_type_in_limit\",\n    \"er_binlog_unsafe_multiple_engines_and_self_logging_engine\",\n    \"er_binlog_unsafe_mixed_statement\",\n    \"er_inside_transaction_prevents_switch_sql_log_bin\",\n    \"er_stored_function_prevents_switch_sql_log_bin\",\n    \"er_failed_read_from_par_file\",\n    \"er_values_is_not_int_type_error\",\n    \"er_access_denied_no_password_error\",\n    \"er_set_password_auth_plugin\",\n    \"er_grant_plugin_user_exists\",\n    \"er_truncate_illegal_fk\",\n    \"er_plugin_is_permanent\",\n    \"er_slave_heartbeat_value_out_of_range_min\",\n    \"er_slave_heartbeat_value_out_of_range_max\",\n    \"er_stmt_cache_full\",\n    \"er_multi_update_key_conflict\",\n    \"er_table_needs_rebuild\",\n    \"warn_option_below_limit\",\n    \"er_index_column_too_long\",\n    \"er_error_in_trigger_body\",\n    \"er_error_in_unknown_trigger_body\",\n    \"er_index_corrupt\",\n    \"er_undo_record_too_big\",\n    \"er_binlog_unsafe_insert_ignore_select\",\n    \"er_binlog_unsafe_insert_select_update\",\n    \"er_binlog_unsafe_replace_select\",\n    \"er_binlog_unsafe_create_ignore_select\",\n    \"er_binlog_unsafe_create_replace_select\",\n    \"er_binlog_unsafe_update_ignore\",\n    nullptr,\n    nullptr,\n    \"er_binlog_unsafe_write_autoinc_select\",\n    \"er_binlog_unsafe_create_select_autoinc\",\n    \"er_binlog_unsafe_insert_two_keys\",\n    nullptr,\n    nullptr,\n    \"er_binlog_unsafe_autoinc_not_first\",\n    \"er_cannot_load_from_table_v2\",\n    \"er_master_delay_value_out_of_range\",\n    \"er_only_fd_and_rbr_events_allowed_in_binlog_statement\",\n    \"er_partition_exchange_different_option\",\n    \"er_partition_exchange_part_table\",\n    \"er_partition_exchange_temp_table\",\n    \"er_partition_instead_of_subpartition\",\n    \"er_unknown_partition\",\n    \"er_tables_different_metadata\",\n    \"er_row_does_not_match_partition\",\n    \"er_binlog_cache_size_greater_than_max\",\n    \"er_warn_index_not_applicable\",\n    \"er_partition_exchange_foreign_key\",\n    \"er_no_such_key_value\",\n    nullptr,\n    \"er_network_read_event_checksum_failure\",\n    \"er_binlog_read_event_checksum_failure\",\n    \"er_binlog_stmt_cache_size_greater_than_max\",\n    \"er_cant_update_table_in_create_table_select\",\n    \"er_partition_clause_on_nonpartitioned\",\n    \"er_row_does_not_match_given_partition_set\",\n    nullptr,\n    \"er_change_rpl_info_repository_failure\",\n    \"er_warning_not_complete_rollback_with_created_temp_table\",\n    \"er_warning_not_complete_rollback_with_dropped_temp_table\",\n    \"er_mts_feature_is_not_supported\",\n    \"er_mts_updated_dbs_greater_max\",\n    \"er_mts_cant_parallel\",\n    \"er_mts_inconsistent_data\",\n    \"er_fulltext_not_supported_with_partitioning\",\n    \"er_da_invalid_condition_number\",\n    \"er_insecure_plain_text\",\n    \"er_insecure_change_master\",\n    \"er_foreign_duplicate_key_with_child_info\",\n    \"er_foreign_duplicate_key_without_child_info\",\n    \"er_sqlthread_with_secure_slave\",\n    \"er_table_has_no_ft\",\n    \"er_variable_not_settable_in_sf_or_trigger\",\n    \"er_variable_not_settable_in_transaction\",\n    \"er_gtid_next_is_not_in_gtid_next_list\",\n    nullptr,\n    \"er_set_statement_cannot_invoke_function\",\n    \"er_gtid_next_cant_be_automatic_if_gtid_next_list_is_non_null\",\n    \"er_skipping_logged_transaction\",\n    \"er_malformed_gtid_set_specification\",\n    \"er_malformed_gtid_set_encoding\",\n    \"er_malformed_gtid_specification\",\n    \"er_gno_exhausted\",\n    \"er_bad_slave_auto_position\",\n    nullptr,\n    \"er_cant_do_implicit_commit_in_trx_when_gtid_next_is_set\",\n    nullptr,\n    \"er_gtid_mode_requires_binlog\",\n    \"er_cant_set_gtid_next_to_gtid_when_gtid_mode_is_off\",\n    \"er_cant_set_gtid_next_to_anonymous_when_gtid_mode_is_on\",\n    \"er_cant_set_gtid_next_list_to_non_null_when_gtid_mode_is_off\",\n    nullptr,\n    \"er_gtid_unsafe_non_transactional_table\",\n    \"er_gtid_unsafe_create_select\",\n    \"er_gtid_unsafe_create_drop_temporary_table_in_transaction\",\n    \"er_gtid_mode_can_only_change_one_step_at_a_time\",\n    \"er_master_has_purged_required_gtids\",\n    \"er_cant_set_gtid_next_when_owning_gtid\",\n    \"er_unknown_explain_format\",\n    \"er_cant_execute_in_read_only_transaction\",\n    \"er_too_long_table_partition_comment\",\n    \"er_slave_configuration\",\n    \"er_innodb_ft_limit\",\n    \"er_innodb_no_ft_temp_table\",\n    \"er_innodb_ft_wrong_docid_column\",\n    \"er_innodb_ft_wrong_docid_index\",\n    \"er_innodb_online_log_too_big\",\n    \"er_unknown_alter_algorithm\",\n    \"er_unknown_alter_lock\",\n    \"er_mts_change_master_cant_run_with_gaps\",\n    \"er_mts_recovery_failure\",\n    \"er_mts_reset_workers\",\n    \"er_col_count_doesnt_match_corrupted_v2\",\n    \"er_slave_silent_retry_transaction\",\n    nullptr,\n    \"er_table_schema_mismatch\",\n    \"er_table_in_system_tablespace\",\n    \"er_io_read_error\",\n    \"er_io_write_error\",\n    \"er_tablespace_missing\",\n    \"er_tablespace_exists\",\n    \"er_tablespace_discarded\",\n    \"er_internal_error\",\n    \"er_innodb_import_error\",\n    \"er_innodb_index_corrupt\",\n    \"er_invalid_year_column_length\",\n    \"er_not_valid_password\",\n    \"er_must_change_password\",\n    \"er_fk_no_index_child\",\n    \"er_fk_no_index_parent\",\n    \"er_fk_fail_add_system\",\n    \"er_fk_cannot_open_parent\",\n    \"er_fk_incorrect_option\",\n    nullptr,\n    \"er_password_format\",\n    \"er_fk_column_cannot_drop\",\n    \"er_fk_column_cannot_drop_child\",\n    \"er_fk_column_not_null\",\n    \"er_dup_index\",\n    \"er_fk_column_cannot_change\",\n    \"er_fk_column_cannot_change_child\",\n    nullptr,\n    \"er_malformed_packet\",\n    \"er_read_only_mode\",\n    nullptr,\n    \"er_variable_not_settable_in_sp\",\n    \"er_cant_set_gtid_purged_when_gtid_mode_is_off\",\n    \"er_cant_set_gtid_purged_when_gtid_executed_is_not_empty\",\n    \"er_cant_set_gtid_purged_when_owned_gtids_is_not_empty\",\n    \"er_gtid_purged_was_changed\",\n    \"er_gtid_executed_was_changed\",\n    \"er_binlog_stmt_mode_and_no_repl_tables\",\n    \"er_alter_operation_not_supported\",\n    \"er_alter_operation_not_supported_reason\",\n    \"er_alter_operation_not_supported_reason_copy\",\n    \"er_alter_operation_not_supported_reason_partition\",\n    \"er_alter_operation_not_supported_reason_fk_rename\",\n    \"er_alter_operation_not_supported_reason_column_type\",\n    \"er_alter_operation_not_supported_reason_fk_check\",\n    nullptr,\n    \"er_alter_operation_not_supported_reason_nopk\",\n    \"er_alter_operation_not_supported_reason_autoinc\",\n    \"er_alter_operation_not_supported_reason_hidden_fts\",\n    \"er_alter_operation_not_supported_reason_change_fts\",\n    \"er_alter_operation_not_supported_reason_fts\",\n    \"er_sql_slave_skip_counter_not_settable_in_gtid_mode\",\n    \"er_dup_unknown_in_index\",\n    \"er_ident_causes_too_long_path\",\n    \"er_alter_operation_not_supported_reason_not_null\",\n    \"er_must_change_password_login\",\n    \"er_row_in_wrong_partition\",\n    \"er_mts_event_bigger_pending_jobs_size_max\",\n    \"er_innodb_no_ft_uses_parser\",\n    \"er_binlog_logical_corruption\",\n    \"er_warn_purge_log_in_use\",\n    \"er_warn_purge_log_is_active\",\n    \"er_auto_increment_conflict\",\n    \"warn_on_blockhole_in_rbr\",\n    \"er_slave_mi_init_repository\",\n    \"er_slave_rli_init_repository\",\n    \"er_access_denied_change_user_error\",\n    \"er_innodb_read_only\",\n    \"er_stop_slave_sql_thread_timeout\",\n    \"er_stop_slave_io_thread_timeout\",\n    \"er_table_corrupt\",\n    \"er_temp_file_write_failure\",\n    \"er_innodb_ft_aux_not_hex_id\",\n\n};\n\n} // namespace detail\n} // namespace mysql\n} // namespace boost\n\nconst char* boost::mysql::detail::common_error_to_string(int v)\n{\n    constexpr int first = 1000;\n    constexpr int last = first + sizeof(common_error_messages) / sizeof(const char*);\n    return (v >= first && v < last) ? common_error_messages[v - first] : nullptr;\n}\n\nconst char* boost::mysql::detail::mysql_error_to_string(int v)\n{\n    switch (v)\n    {\n    case 1076: return \"er_ready\";\n    case 1101: return \"er_blob_cant_have_default\";\n    case 1120: return \"er_wrong_outer_join_unused\";\n    case 1176: return \"er_key_does_not_exits\";\n    case 1185: return \"er_dump_not_implemented\";\n    case 1349: return \"er_view_select_derived_unused\";\n    case 1487: return \"er_no_const_expr_in_range_or_list_error\";\n    case 1506: return \"er_foreign_key_on_partitioned\";\n    case 1547: return \"er_obsolete_col_count_doesnt_match_corrupted\";\n    case 1548: return \"er_obsolete_cannot_load_from_table\";\n    case 1557: return \"er_foreign_duplicate_key_old_unused\";\n    case 1561: return \"er_ndb_cant_switch_binlog_format\";\n    case 1593: return \"er_binlog_fatal_error\";\n    case 1608: return \"er_never_used\";\n    case 1611: return \"er_load_data_invalid_column_unused\";\n    case 1625: return \"er_ndb_replication_schema_error\";\n    case 1720: return \"er_plugin_no_uninstall\";\n    case 1721: return \"er_plugin_no_install\";\n    case 1725: return \"er_table_in_fk_check\";\n    case 1726: return \"er_unsupported_engine\";\n    case 1742: return \"er_rpl_info_data_too_long\";\n    case 1768: return \"er_cant_change_gtid_next_in_transaction\";\n    case 1777: return \"er_auto_position_requires_gtid_mode_not_off\";\n    case 1779: return \"er_gtid_mode_on_requires_enforce_gtid_consistency_on\";\n    case 1807: return \"er_discard_fk_checks_running\";\n    case 1826: return \"er_fk_dup_name\";\n    case 1837: return \"er_gtid_next_type_undefined_gtid\";\n    case 1880: return \"er_old_temporals_upgraded\";\n    case 1881: return \"er_innodb_forced_recovery\";\n    case 1882: return \"er_aes_invalid_iv\";\n    case 1883: return \"er_plugin_cannot_be_uninstalled\";\n    case 1884: return \"er_gtid_unsafe_binlog_splittable_statement_and_assigned_gtid\";\n    case 1885: return \"er_slave_has_more_gtids_than_master\";\n    case 1886: return \"er_missing_key\";\n    case 1887: return \"warn_named_pipe_access_everyone\";\n    case 1888: return \"er_found_missing_gtids\";\n    case 3000: return \"er_file_corrupt\";\n    case 3001: return \"er_error_on_master\";\n    case 3002: return \"er_inconsistent_error\";\n    case 3003: return \"er_storage_engine_not_loaded\";\n    case 3004: return \"er_get_stacked_da_without_active_handler\";\n    case 3005: return \"er_warn_legacy_syntax_converted\";\n    case 3006: return \"er_binlog_unsafe_fulltext_plugin\";\n    case 3007: return \"er_cannot_discard_temporary_table\";\n    case 3008: return \"er_fk_depth_exceeded\";\n    case 3009: return \"er_col_count_doesnt_match_please_update_v2\";\n    case 3010: return \"er_warn_trigger_doesnt_have_created\";\n    case 3011: return \"er_referenced_trg_does_not_exist\";\n    case 3012: return \"er_explain_not_supported\";\n    case 3013: return \"er_invalid_field_size\";\n    case 3014: return \"er_missing_ha_create_option\";\n    case 3015: return \"er_engine_out_of_memory\";\n    case 3016: return \"er_password_expire_anonymous_user\";\n    case 3017: return \"er_slave_sql_thread_must_stop\";\n    case 3018: return \"er_no_ft_materialized_subquery\";\n    case 3019: return \"er_innodb_undo_log_full\";\n    case 3020: return \"er_invalid_argument_for_logarithm\";\n    case 3021: return \"er_slave_channel_io_thread_must_stop\";\n    case 3022: return \"er_warn_open_temp_tables_must_be_zero\";\n    case 3023: return \"er_warn_only_master_log_file_no_pos\";\n    case 3024: return \"er_query_timeout\";\n    case 3025: return \"er_non_ro_select_disable_timer\";\n    case 3026: return \"er_dup_list_entry\";\n    case 3027: return \"er_sql_mode_no_effect\";\n    case 3028: return \"er_aggregate_order_for_union\";\n    case 3029: return \"er_aggregate_order_non_agg_query\";\n    case 3030: return \"er_slave_worker_stopped_previous_thd_error\";\n    case 3031: return \"er_dont_support_slave_preserve_commit_order\";\n    case 3032: return \"er_server_offline_mode\";\n    case 3033: return \"er_gis_different_srids\";\n    case 3034: return \"er_gis_unsupported_argument\";\n    case 3035: return \"er_gis_unknown_error\";\n    case 3036: return \"er_gis_unknown_exception\";\n    case 3037: return \"er_gis_invalid_data\";\n    case 3038: return \"er_boost_geometry_empty_input_exception\";\n    case 3039: return \"er_boost_geometry_centroid_exception\";\n    case 3040: return \"er_boost_geometry_overlay_invalid_input_exception\";\n    case 3041: return \"er_boost_geometry_turn_info_exception\";\n    case 3042: return \"er_boost_geometry_self_intersection_point_exception\";\n    case 3043: return \"er_boost_geometry_unknown_exception\";\n    case 3044: return \"er_std_bad_alloc_error\";\n    case 3045: return \"er_std_domain_error\";\n    case 3046: return \"er_std_length_error\";\n    case 3047: return \"er_std_invalid_argument\";\n    case 3048: return \"er_std_out_of_range_error\";\n    case 3049: return \"er_std_overflow_error\";\n    case 3050: return \"er_std_range_error\";\n    case 3051: return \"er_std_underflow_error\";\n    case 3052: return \"er_std_logic_error\";\n    case 3053: return \"er_std_runtime_error\";\n    case 3054: return \"er_std_unknown_exception\";\n    case 3055: return \"er_gis_data_wrong_endianess\";\n    case 3056: return \"er_change_master_password_length\";\n    case 3057: return \"er_user_lock_wrong_name\";\n    case 3058: return \"er_user_lock_deadlock\";\n    case 3059: return \"er_replace_inaccessible_rows\";\n    case 3060: return \"er_alter_operation_not_supported_reason_gis\";\n    case 3061: return \"er_illegal_user_var\";\n    case 3062: return \"er_gtid_mode_off\";\n    case 3063: return \"er_unsupported_by_replication_thread\";\n    case 3064: return \"er_incorrect_type\";\n    case 3065: return \"er_field_in_order_not_select\";\n    case 3066: return \"er_aggregate_in_order_not_select\";\n    case 3067: return \"er_invalid_rpl_wild_table_filter_pattern\";\n    case 3068: return \"er_net_ok_packet_too_large\";\n    case 3069: return \"er_invalid_json_data\";\n    case 3070: return \"er_invalid_geojson_missing_member\";\n    case 3071: return \"er_invalid_geojson_wrong_type\";\n    case 3072: return \"er_invalid_geojson_unspecified\";\n    case 3073: return \"er_dimension_unsupported\";\n    case 3074: return \"er_slave_channel_does_not_exist\";\n    case 3075: return \"er_slave_multiple_channels_host_port\";\n    case 3076: return \"er_slave_channel_name_invalid_or_too_long\";\n    case 3077: return \"er_slave_new_channel_wrong_repository\";\n    case 3078: return \"er_slave_channel_delete\";\n    case 3079: return \"er_slave_multiple_channels_cmd\";\n    case 3080: return \"er_slave_max_channels_exceeded\";\n    case 3081: return \"er_slave_channel_must_stop\";\n    case 3082: return \"er_slave_channel_not_running\";\n    case 3083: return \"er_slave_channel_was_running\";\n    case 3084: return \"er_slave_channel_was_not_running\";\n    case 3085: return \"er_slave_channel_sql_thread_must_stop\";\n    case 3086: return \"er_slave_channel_sql_skip_counter\";\n    case 3087: return \"er_wrong_field_with_group_v2\";\n    case 3088: return \"er_mix_of_group_func_and_fields_v2\";\n    case 3089: return \"er_warn_deprecated_sysvar_update\";\n    case 3090: return \"er_warn_deprecated_sqlmode\";\n    case 3091: return \"er_cannot_log_partial_drop_database_with_gtid\";\n    case 3092: return \"er_group_replication_configuration\";\n    case 3093: return \"er_group_replication_running\";\n    case 3094: return \"er_group_replication_applier_init_error\";\n    case 3095: return \"er_group_replication_stop_applier_thread_timeout\";\n    case 3096: return \"er_group_replication_communication_layer_session_error\";\n    case 3097: return \"er_group_replication_communication_layer_join_error\";\n    case 3098: return \"er_before_dml_validation_error\";\n    case 3099: return \"er_prevents_variable_without_rbr\";\n    case 3100: return \"er_run_hook_error\";\n    case 3101: return \"er_transaction_rollback_during_commit\";\n    case 3102: return \"er_generated_column_function_is_not_allowed\";\n    case 3103: return \"er_unsupported_alter_inplace_on_virtual_column\";\n    case 3104: return \"er_wrong_fk_option_for_generated_column\";\n    case 3105: return \"er_non_default_value_for_generated_column\";\n    case 3106: return \"er_unsupported_action_on_generated_column\";\n    case 3107: return \"er_generated_column_non_prior\";\n    case 3108: return \"er_dependent_by_generated_column\";\n    case 3109: return \"er_generated_column_ref_auto_inc\";\n    case 3110: return \"er_feature_not_available\";\n    case 3111: return \"er_cant_set_gtid_mode\";\n    case 3112: return \"er_cant_use_auto_position_with_gtid_mode_off\";\n    case 3113: return \"er_cant_replicate_anonymous_with_auto_position\";\n    case 3114: return \"er_cant_replicate_anonymous_with_gtid_mode_on\";\n    case 3115: return \"er_cant_replicate_gtid_with_gtid_mode_off\";\n    case 3116: return \"er_cant_enforce_gtid_consistency_with_ongoing_gtid_violating_tx\";\n    case 3117: return \"er_enforce_gtid_consistency_warn_with_ongoing_gtid_violating_tx\";\n    case 3118: return \"er_account_has_been_locked\";\n    case 3119: return \"er_wrong_tablespace_name\";\n    case 3120: return \"er_tablespace_is_not_empty\";\n    case 3121: return \"er_wrong_file_name\";\n    case 3122: return \"er_boost_geometry_inconsistent_turns_exception\";\n    case 3123: return \"er_warn_optimizer_hint_syntax_error\";\n    case 3124: return \"er_warn_bad_max_execution_time\";\n    case 3125: return \"er_warn_unsupported_max_execution_time\";\n    case 3126: return \"er_warn_conflicting_hint\";\n    case 3127: return \"er_warn_unknown_qb_name\";\n    case 3128: return \"er_unresolved_hint_name\";\n    case 3129: return \"er_warn_on_modifying_gtid_executed_table\";\n    case 3130: return \"er_pluggable_protocol_command_not_supported\";\n    case 3131: return \"er_locking_service_wrong_name\";\n    case 3132: return \"er_locking_service_deadlock\";\n    case 3133: return \"er_locking_service_timeout\";\n    case 3134: return \"er_gis_max_points_in_geometry_overflowed\";\n    case 3135: return \"er_sql_mode_merged\";\n    case 3136: return \"er_vtoken_plugin_token_mismatch\";\n    case 3137: return \"er_vtoken_plugin_token_not_found\";\n    case 3138: return \"er_cant_set_variable_when_owning_gtid\";\n    case 3139: return \"er_slave_channel_operation_not_allowed\";\n    case 3140: return \"er_invalid_json_text\";\n    case 3141: return \"er_invalid_json_text_in_param\";\n    case 3142: return \"er_invalid_json_binary_data\";\n    case 3143: return \"er_invalid_json_path\";\n    case 3144: return \"er_invalid_json_charset\";\n    case 3145: return \"er_invalid_json_charset_in_function\";\n    case 3146: return \"er_invalid_type_for_json\";\n    case 3147: return \"er_invalid_cast_to_json\";\n    case 3148: return \"er_invalid_json_path_charset\";\n    case 3149: return \"er_invalid_json_path_wildcard\";\n    case 3150: return \"er_json_value_too_big\";\n    case 3151: return \"er_json_key_too_big\";\n    case 3152: return \"er_json_used_as_key\";\n    case 3153: return \"er_json_vacuous_path\";\n    case 3154: return \"er_json_bad_one_or_all_arg\";\n    case 3155: return \"er_numeric_json_value_out_of_range\";\n    case 3156: return \"er_invalid_json_value_for_cast\";\n    case 3157: return \"er_json_document_too_deep\";\n    case 3158: return \"er_json_document_null_key\";\n    case 3159: return \"er_secure_transport_required\";\n    case 3160: return \"er_no_secure_transports_configured\";\n    case 3161: return \"er_disabled_storage_engine\";\n    case 3162: return \"er_user_does_not_exist\";\n    case 3163: return \"er_user_already_exists\";\n    case 3164: return \"er_audit_api_abort\";\n    case 3165: return \"er_invalid_json_path_array_cell\";\n    case 3166: return \"er_bufpool_resize_inprogress\";\n    case 3167: return \"er_feature_disabled_see_doc\";\n    case 3168: return \"er_server_isnt_available\";\n    case 3169: return \"er_session_was_killed\";\n    case 3170: return \"er_capacity_exceeded\";\n    case 3171: return \"er_capacity_exceeded_in_range_optimizer\";\n    case 3172: return \"er_table_needs_upg_part\";\n    case 3173: return \"er_cant_wait_for_executed_gtid_set_while_owning_a_gtid\";\n    case 3174: return \"er_cannot_add_foreign_base_col_virtual\";\n    case 3175: return \"er_cannot_create_virtual_index_constraint\";\n    case 3176: return \"er_error_on_modifying_gtid_executed_table\";\n    case 3177: return \"er_lock_refused_by_engine\";\n    case 3178: return \"er_unsupported_alter_online_on_virtual_column\";\n    case 3179: return \"er_master_key_rotation_not_supported_by_se\";\n    case 3180: return \"er_master_key_rotation_error_by_se\";\n    case 3181: return \"er_master_key_rotation_binlog_failed\";\n    case 3182: return \"er_master_key_rotation_se_unavailable\";\n    case 3183: return \"er_tablespace_cannot_encrypt\";\n    case 3184: return \"er_invalid_encryption_option\";\n    case 3185: return \"er_cannot_find_key_in_keyring\";\n    case 3186: return \"er_capacity_exceeded_in_parser\";\n    case 3187: return \"er_unsupported_alter_encryption_inplace\";\n    case 3188: return \"er_keyring_udf_keyring_service_error\";\n    case 3189: return \"er_user_column_old_length\";\n    case 3190: return \"er_cant_reset_master\";\n    case 3191: return \"er_group_replication_max_group_size\";\n    case 3192: return \"er_cannot_add_foreign_base_col_stored\";\n    case 3193: return \"er_table_referenced\";\n    case 3194: return \"er_partition_engine_deprecated_for_table\";\n    case 3195: return \"er_warn_using_geomfromwkb_to_set_srid_zero\";\n    case 3196: return \"er_warn_using_geomfromwkb_to_set_srid\";\n    case 3197: return \"er_xa_retry\";\n    case 3198: return \"er_keyring_aws_udf_aws_kms_error\";\n    case 3199: return \"er_binlog_unsafe_xa\";\n    case 3200: return \"er_udf_error\";\n    case 3201: return \"er_keyring_migration_failure\";\n    case 3202: return \"er_keyring_access_denied_error\";\n    case 3203: return \"er_keyring_migration_status\";\n    case 3204: return \"er_plugin_failed_to_open_tables\";\n    case 3205: return \"er_plugin_failed_to_open_table\";\n    case 3206: return \"er_audit_log_no_keyring_plugin_installed\";\n    case 3207: return \"er_audit_log_encryption_password_has_not_been_set\";\n    case 3208: return \"er_audit_log_could_not_create_aes_key\";\n    case 3209: return \"er_audit_log_encryption_password_cannot_be_fetched\";\n    case 3210: return \"er_audit_log_json_filtering_not_enabled\";\n    case 3211: return \"er_audit_log_udf_insufficient_privilege\";\n    case 3212: return \"er_audit_log_super_privilege_required\";\n    case 3213: return \"er_could_not_reinitialize_audit_log_filters\";\n    case 3214: return \"er_audit_log_udf_invalid_argument_type\";\n    case 3215: return \"er_audit_log_udf_invalid_argument_count\";\n    case 3216: return \"er_audit_log_has_not_been_installed\";\n    case 3217: return \"er_audit_log_udf_read_invalid_max_array_length_arg_type\";\n    case 3218: return \"er_audit_log_udf_read_invalid_max_array_length_arg_value\";\n    case 3219: return \"er_audit_log_json_filter_parsing_error\";\n    case 3220: return \"er_audit_log_json_filter_name_cannot_be_empty\";\n    case 3221: return \"er_audit_log_json_user_name_cannot_be_empty\";\n    case 3222: return \"er_audit_log_json_filter_does_not_exists\";\n    case 3223: return \"er_audit_log_user_first_character_must_be_alphanumeric\";\n    case 3224: return \"er_audit_log_user_name_invalid_character\";\n    case 3225: return \"er_audit_log_host_name_invalid_character\";\n    case 3226: return \"obsolete_warn_deprecated_maxdb_sql_mode_for_timestamp\";\n    case 3228: return \"er_cant_open_error_log\";\n    case 3230: return \"er_cant_start_server_named_pipe\";\n    case 3231: return \"er_write_set_exceeds_limit\";\n    case 3232: return \"er_deprecated_tls_version_session\";\n    case 3233: return \"er_warn_deprecated_tls_version\";\n    case 3234: return \"er_warn_wrong_native_table_structure\";\n    case 3235: return \"er_aes_invalid_kdf_name\";\n    case 3236: return \"er_aes_invalid_kdf_iterations\";\n    case 3237: return \"warn_aes_key_size\";\n    case 3238: return \"er_aes_invalid_kdf_option_size\";\n    case 3500: return \"er_unsupport_compressed_temporary_table\";\n    case 3501: return \"er_acl_operation_failed\";\n    case 3502: return \"er_unsupported_index_algorithm\";\n    case 3503: return \"er_no_such_db\";\n    case 3504: return \"er_too_big_enum\";\n    case 3505: return \"er_too_long_set_enum_value\";\n    case 3506: return \"er_invalid_dd_object\";\n    case 3507: return \"er_updating_dd_table\";\n    case 3508: return \"er_invalid_dd_object_id\";\n    case 3509: return \"er_invalid_dd_object_name\";\n    case 3510: return \"er_tablespace_missing_with_name\";\n    case 3511: return \"er_too_long_routine_comment\";\n    case 3512: return \"er_sp_load_failed\";\n    case 3513: return \"er_invalid_bitwise_operands_size\";\n    case 3514: return \"er_invalid_bitwise_aggregate_operands_size\";\n    case 3515: return \"er_warn_unsupported_hint\";\n    case 3516: return \"er_unexpected_geometry_type\";\n    case 3517: return \"er_srs_parse_error\";\n    case 3518: return \"er_srs_proj_parameter_missing\";\n    case 3519: return \"er_warn_srs_not_found\";\n    case 3520: return \"er_srs_not_cartesian\";\n    case 3521: return \"er_srs_not_cartesian_undefined\";\n    case 3522: return \"er_pk_index_cant_be_invisible\";\n    case 3523: return \"er_unknown_authid\";\n    case 3524: return \"er_failed_role_grant\";\n    case 3525: return \"er_open_role_tables\";\n    case 3526: return \"er_failed_default_roles\";\n    case 3527: return \"er_components_no_scheme\";\n    case 3528: return \"er_components_no_scheme_service\";\n    case 3529: return \"er_components_cant_load\";\n    case 3530: return \"er_role_not_granted\";\n    case 3531: return \"er_failed_revoke_role\";\n    case 3532: return \"er_rename_role\";\n    case 3533: return \"er_components_cant_acquire_service_implementation\";\n    case 3534: return \"er_components_cant_satisfy_dependency\";\n    case 3535: return \"er_components_load_cant_register_service_implementation\";\n    case 3536: return \"er_components_load_cant_initialize\";\n    case 3537: return \"er_components_unload_not_loaded\";\n    case 3538: return \"er_components_unload_cant_deinitialize\";\n    case 3539: return \"er_components_cant_release_service\";\n    case 3540: return \"er_components_unload_cant_unregister_service\";\n    case 3541: return \"er_components_cant_unload\";\n    case 3542: return \"er_warn_unload_the_not_persisted\";\n    case 3543: return \"er_component_table_incorrect\";\n    case 3544: return \"er_component_manipulate_row_failed\";\n    case 3545: return \"er_components_unload_duplicate_in_group\";\n    case 3546: return \"er_cant_set_gtid_purged_due_sets_constraints\";\n    case 3547: return \"er_cannot_lock_user_management_caches\";\n    case 3548: return \"er_srs_not_found\";\n    case 3549: return \"er_variable_not_persisted\";\n    case 3550: return \"er_is_query_invalid_clause\";\n    case 3551: return \"er_unable_to_store_statistics\";\n    case 3552: return \"er_no_system_schema_access\";\n    case 3553: return \"er_no_system_tablespace_access\";\n    case 3554: return \"er_no_system_table_access\";\n    case 3555: return \"er_no_system_table_access_for_dictionary_table\";\n    case 3556: return \"er_no_system_table_access_for_system_table\";\n    case 3557: return \"er_no_system_table_access_for_table\";\n    case 3558: return \"er_invalid_option_key\";\n    case 3559: return \"er_invalid_option_value\";\n    case 3560: return \"er_invalid_option_key_value_pair\";\n    case 3561: return \"er_invalid_option_start_character\";\n    case 3562: return \"er_invalid_option_end_character\";\n    case 3563: return \"er_invalid_option_characters\";\n    case 3564: return \"er_duplicate_option_key\";\n    case 3565: return \"er_warn_srs_not_found_axis_order\";\n    case 3566: return \"er_no_access_to_native_fct\";\n    case 3567: return \"er_reset_master_to_value_out_of_range\";\n    case 3568: return \"er_unresolved_table_lock\";\n    case 3569: return \"er_duplicate_table_lock\";\n    case 3570: return \"er_binlog_unsafe_skip_locked\";\n    case 3571: return \"er_binlog_unsafe_nowait\";\n    case 3572: return \"er_lock_nowait\";\n    case 3573: return \"er_cte_recursive_requires_union\";\n    case 3574: return \"er_cte_recursive_requires_nonrecursive_first\";\n    case 3575: return \"er_cte_recursive_forbids_aggregation\";\n    case 3576: return \"er_cte_recursive_forbidden_join_order\";\n    case 3577: return \"er_cte_recursive_requires_single_reference\";\n    case 3578: return \"er_switch_tmp_engine\";\n    case 3579: return \"er_window_no_such_window\";\n    case 3580: return \"er_window_circularity_in_window_graph\";\n    case 3581: return \"er_window_no_child_partitioning\";\n    case 3582: return \"er_window_no_inherit_frame\";\n    case 3583: return \"er_window_no_redefine_order_by\";\n    case 3584: return \"er_window_frame_start_illegal\";\n    case 3585: return \"er_window_frame_end_illegal\";\n    case 3586: return \"er_window_frame_illegal\";\n    case 3587: return \"er_window_range_frame_order_type\";\n    case 3588: return \"er_window_range_frame_temporal_type\";\n    case 3589: return \"er_window_range_frame_numeric_type\";\n    case 3590: return \"er_window_range_bound_not_constant\";\n    case 3591: return \"er_window_duplicate_name\";\n    case 3592: return \"er_window_illegal_order_by\";\n    case 3593: return \"er_window_invalid_window_func_use\";\n    case 3594: return \"er_window_invalid_window_func_alias_use\";\n    case 3595: return \"er_window_nested_window_func_use_in_window_spec\";\n    case 3596: return \"er_window_rows_interval_use\";\n    case 3597: return \"er_window_no_group_order_unused\";\n    case 3598: return \"er_window_explain_json\";\n    case 3599: return \"er_window_function_ignores_frame\";\n    case 3600: return \"er_wl9236_now_unused\";\n    case 3601: return \"er_invalid_no_of_args\";\n    case 3602: return \"er_field_in_grouping_not_group_by\";\n    case 3603: return \"er_too_long_tablespace_comment\";\n    case 3604: return \"er_engine_cant_drop_table\";\n    case 3605: return \"er_engine_cant_drop_missing_table\";\n    case 3606: return \"er_tablespace_dup_filename\";\n    case 3607: return \"er_db_drop_rmdir2\";\n    case 3608: return \"er_imp_no_files_matched\";\n    case 3609: return \"er_imp_schema_does_not_exist\";\n    case 3610: return \"er_imp_table_already_exists\";\n    case 3611: return \"er_imp_incompatible_mysqld_version\";\n    case 3612: return \"er_imp_incompatible_dd_version\";\n    case 3613: return \"er_imp_incompatible_sdi_version\";\n    case 3614: return \"er_warn_invalid_hint\";\n    case 3615: return \"er_var_does_not_exist\";\n    case 3616: return \"er_longitude_out_of_range\";\n    case 3617: return \"er_latitude_out_of_range\";\n    case 3618: return \"er_not_implemented_for_geographic_srs\";\n    case 3619: return \"er_illegal_privilege_level\";\n    case 3620: return \"er_no_system_view_access\";\n    case 3621: return \"er_component_filter_flabbergasted\";\n    case 3622: return \"er_part_expr_too_long\";\n    case 3623: return \"er_udf_drop_dynamically_registered\";\n    case 3624: return \"er_unable_to_store_column_statistics\";\n    case 3625: return \"er_unable_to_update_column_statistics\";\n    case 3626: return \"er_unable_to_drop_column_statistics\";\n    case 3627: return \"er_unable_to_build_histogram\";\n    case 3628: return \"er_mandatory_role\";\n    case 3629: return \"er_missing_tablespace_file\";\n    case 3630: return \"er_persist_only_access_denied_error\";\n    case 3631: return \"er_cmd_need_super\";\n    case 3632: return \"er_path_in_datadir\";\n    case 3633: return \"er_clone_ddl_in_progress\";\n    case 3634: return \"er_clone_too_many_concurrent_clones\";\n    case 3635: return \"er_applier_log_event_validation_error\";\n    case 3636: return \"er_cte_max_recursion_depth\";\n    case 3637: return \"er_not_hint_updatable_variable\";\n    case 3638: return \"er_credentials_contradict_to_history\";\n    case 3639: return \"er_warning_password_history_clauses_void\";\n    case 3640: return \"er_client_does_not_support\";\n    case 3641: return \"er_i_s_skipped_tablespace\";\n    case 3642: return \"er_tablespace_engine_mismatch\";\n    case 3643: return \"er_wrong_srid_for_column\";\n    case 3644: return \"er_cannot_alter_srid_due_to_index\";\n    case 3645: return \"er_warn_binlog_partial_updates_disabled\";\n    case 3646: return \"er_warn_binlog_v1_row_events_disabled\";\n    case 3647: return \"er_warn_binlog_partial_updates_suggests_partial_images\";\n    case 3648: return \"er_could_not_apply_json_diff\";\n    case 3649: return \"er_corrupted_json_diff\";\n    case 3650: return \"er_resource_group_exists\";\n    case 3651: return \"er_resource_group_not_exists\";\n    case 3652: return \"er_invalid_vcpu_id\";\n    case 3653: return \"er_invalid_vcpu_range\";\n    case 3654: return \"er_invalid_thread_priority\";\n    case 3655: return \"er_disallowed_operation\";\n    case 3656: return \"er_resource_group_busy\";\n    case 3657: return \"er_resource_group_disabled\";\n    case 3658: return \"er_feature_unsupported\";\n    case 3659: return \"er_attribute_ignored\";\n    case 3660: return \"er_invalid_thread_id\";\n    case 3661: return \"er_resource_group_bind_failed\";\n    case 3662: return \"er_invalid_use_of_force_option\";\n    case 3663: return \"er_group_replication_command_failure\";\n    case 3664: return \"er_sdi_operation_failed\";\n    case 3665: return \"er_missing_json_table_value\";\n    case 3666: return \"er_wrong_json_table_value\";\n    case 3667: return \"er_tf_must_have_alias\";\n    case 3668: return \"er_tf_forbidden_join_type\";\n    case 3669: return \"er_jt_value_out_of_range\";\n    case 3670: return \"er_jt_max_nested_path\";\n    case 3671: return \"er_password_expiration_not_supported_by_auth_method\";\n    case 3672: return \"er_invalid_geojson_crs_not_top_level\";\n    case 3673: return \"er_bad_null_error_not_ignored\";\n    case 3674: return \"warn_useless_spatial_index\";\n    case 3675: return \"er_disk_full_nowait\";\n    case 3676: return \"er_parse_error_in_digest_fn\";\n    case 3677: return \"er_undisclosed_parse_error_in_digest_fn\";\n    case 3678: return \"er_schema_dir_exists\";\n    case 3679: return \"er_schema_dir_missing\";\n    case 3680: return \"er_schema_dir_create_failed\";\n    case 3681: return \"er_schema_dir_unknown\";\n    case 3682: return \"er_only_implemented_for_srid_0_and_4326\";\n    case 3683: return \"er_binlog_expire_log_days_and_secs_used_together\";\n    case 3684: return \"er_regexp_buffer_overflow\";\n    case 3685: return \"er_regexp_illegal_argument\";\n    case 3686: return \"er_regexp_index_outofbounds_error\";\n    case 3687: return \"er_regexp_internal_error\";\n    case 3688: return \"er_regexp_rule_syntax\";\n    case 3689: return \"er_regexp_bad_escape_sequence\";\n    case 3690: return \"er_regexp_unimplemented\";\n    case 3691: return \"er_regexp_mismatched_paren\";\n    case 3692: return \"er_regexp_bad_interval\";\n    case 3693: return \"er_regexp_max_lt_min\";\n    case 3694: return \"er_regexp_invalid_back_ref\";\n    case 3695: return \"er_regexp_look_behind_limit\";\n    case 3696: return \"er_regexp_missing_close_bracket\";\n    case 3697: return \"er_regexp_invalid_range\";\n    case 3698: return \"er_regexp_stack_overflow\";\n    case 3699: return \"er_regexp_time_out\";\n    case 3700: return \"er_regexp_pattern_too_big\";\n    case 3701: return \"er_cant_set_error_log_service\";\n    case 3702: return \"er_empty_pipeline_for_error_log_service\";\n    case 3703: return \"er_component_filter_diagnostics\";\n    case 3704: return \"er_not_implemented_for_cartesian_srs\";\n    case 3705: return \"er_not_implemented_for_projected_srs\";\n    case 3706: return \"er_nonpositive_radius\";\n    case 3707: return \"er_restart_server_failed\";\n    case 3708: return \"er_srs_missing_mandatory_attribute\";\n    case 3709: return \"er_srs_multiple_attribute_definitions\";\n    case 3710: return \"er_srs_name_cant_be_empty_or_whitespace\";\n    case 3711: return \"er_srs_organization_cant_be_empty_or_whitespace\";\n    case 3712: return \"er_srs_id_already_exists\";\n    case 3713: return \"er_warn_srs_id_already_exists\";\n    case 3714: return \"er_cant_modify_srid_0\";\n    case 3715: return \"er_warn_reserved_srid_range\";\n    case 3716: return \"er_cant_modify_srs_used_by_column\";\n    case 3717: return \"er_srs_invalid_character_in_attribute\";\n    case 3718: return \"er_srs_attribute_string_too_long\";\n    case 3719: return \"er_deprecated_utf8_alias\";\n    case 3720: return \"er_deprecated_national\";\n    case 3721: return \"er_invalid_default_utf8mb4_collation\";\n    case 3722: return \"er_unable_to_collect_log_status\";\n    case 3723: return \"er_reserved_tablespace_name\";\n    case 3724: return \"er_unable_to_set_option\";\n    case 3725: return \"er_slave_possibly_diverged_after_ddl\";\n    case 3726: return \"er_srs_not_geographic\";\n    case 3727: return \"er_polygon_too_large\";\n    case 3728: return \"er_spatial_unique_index\";\n    case 3729: return \"er_index_type_not_supported_for_spatial_index\";\n    case 3730: return \"er_fk_cannot_drop_parent\";\n    case 3731: return \"er_geometry_param_longitude_out_of_range\";\n    case 3732: return \"er_geometry_param_latitude_out_of_range\";\n    case 3733: return \"er_fk_cannot_use_virtual_column\";\n    case 3734: return \"er_fk_no_column_parent\";\n    case 3735: return \"er_cant_set_error_suppression_list\";\n    case 3736: return \"er_srs_geogcs_invalid_axes\";\n    case 3737: return \"er_srs_invalid_semi_major_axis\";\n    case 3738: return \"er_srs_invalid_inverse_flattening\";\n    case 3739: return \"er_srs_invalid_angular_unit\";\n    case 3740: return \"er_srs_invalid_prime_meridian\";\n    case 3741: return \"er_transform_source_srs_not_supported\";\n    case 3742: return \"er_transform_target_srs_not_supported\";\n    case 3743: return \"er_transform_source_srs_missing_towgs84\";\n    case 3744: return \"er_transform_target_srs_missing_towgs84\";\n    case 3745: return \"er_temp_table_prevents_switch_session_binlog_format\";\n    case 3746: return \"er_temp_table_prevents_switch_global_binlog_format\";\n    case 3747: return \"er_running_applier_prevents_switch_global_binlog_format\";\n    case 3748: return \"er_client_gtid_unsafe_create_drop_temp_table_in_trx_in_sbr\";\n    case 3750: return \"er_table_without_pk\";\n    case 3751: return \"er_warn_data_truncated_functional_index\";\n    case 3752: return \"er_warn_data_out_of_range_functional_index\";\n    case 3753: return \"er_functional_index_on_json_or_geometry_function\";\n    case 3754: return \"er_functional_index_ref_auto_increment\";\n    case 3755: return \"er_cannot_drop_column_functional_index\";\n    case 3756: return \"er_functional_index_primary_key\";\n    case 3757: return \"er_functional_index_on_lob\";\n    case 3758: return \"er_functional_index_function_is_not_allowed\";\n    case 3759: return \"er_fulltext_functional_index\";\n    case 3760: return \"er_spatial_functional_index\";\n    case 3761: return \"er_wrong_key_column_functional_index\";\n    case 3762: return \"er_functional_index_on_field\";\n    case 3763: return \"er_generated_column_named_function_is_not_allowed\";\n    case 3764: return \"er_generated_column_row_value\";\n    case 3765: return \"er_generated_column_variables\";\n    case 3766: return \"er_dependent_by_default_generated_value\";\n    case 3767: return \"er_default_val_generated_non_prior\";\n    case 3768: return \"er_default_val_generated_ref_auto_inc\";\n    case 3769: return \"er_default_val_generated_function_is_not_allowed\";\n    case 3770: return \"er_default_val_generated_named_function_is_not_allowed\";\n    case 3771: return \"er_default_val_generated_row_value\";\n    case 3772: return \"er_default_val_generated_variables\";\n    case 3773: return \"er_default_as_val_generated\";\n    case 3774: return \"er_unsupported_action_on_default_val_generated\";\n    case 3775: return \"er_gtid_unsafe_alter_add_col_with_default_expression\";\n    case 3776: return \"er_fk_cannot_change_engine\";\n    case 3777: return \"er_warn_deprecated_user_set_expr\";\n    case 3778: return \"er_warn_deprecated_utf8mb3_collation\";\n    case 3779: return \"er_warn_deprecated_nested_comment_syntax\";\n    case 3780: return \"er_fk_incompatible_columns\";\n    case 3781: return \"er_gr_hold_wait_timeout\";\n    case 3782: return \"er_gr_hold_killed\";\n    case 3783: return \"er_gr_hold_member_status_error\";\n    case 3784: return \"er_rpl_encryption_failed_to_fetch_key\";\n    case 3785: return \"er_rpl_encryption_key_not_found\";\n    case 3786: return \"er_rpl_encryption_keyring_invalid_key\";\n    case 3787: return \"er_rpl_encryption_header_error\";\n    case 3788: return \"er_rpl_encryption_failed_to_rotate_logs\";\n    case 3789: return \"er_rpl_encryption_key_exists_unexpected\";\n    case 3790: return \"er_rpl_encryption_failed_to_generate_key\";\n    case 3791: return \"er_rpl_encryption_failed_to_store_key\";\n    case 3792: return \"er_rpl_encryption_failed_to_remove_key\";\n    case 3793: return \"er_rpl_encryption_unable_to_change_option\";\n    case 3794: return \"er_rpl_encryption_master_key_recovery_failed\";\n    case 3795: return \"er_slow_log_mode_ignored_when_not_logging_to_file\";\n    case 3796: return \"er_grp_trx_consistency_not_allowed\";\n    case 3797: return \"er_grp_trx_consistency_before\";\n    case 3798: return \"er_grp_trx_consistency_after_on_trx_begin\";\n    case 3799: return \"er_grp_trx_consistency_begin_not_allowed\";\n    case 3800: return \"er_functional_index_row_value_is_not_allowed\";\n    case 3801: return \"er_rpl_encryption_failed_to_encrypt\";\n    case 3802: return \"er_page_tracking_not_started\";\n    case 3803: return \"er_page_tracking_range_not_tracked\";\n    case 3804: return \"er_page_tracking_cannot_purge\";\n    case 3805: return \"er_rpl_encryption_cannot_rotate_binlog_master_key\";\n    case 3806: return \"er_binlog_master_key_recovery_out_of_combination\";\n    case 3807: return \"er_binlog_master_key_rotation_fail_to_operate_key\";\n    case 3808: return \"er_binlog_master_key_rotation_fail_to_rotate_logs\";\n    case 3809: return \"er_binlog_master_key_rotation_fail_to_reencrypt_log\";\n    case 3810: return \"er_binlog_master_key_rotation_fail_to_cleanup_unused_keys\";\n    case 3811: return \"er_binlog_master_key_rotation_fail_to_cleanup_aux_key\";\n    case 3812: return \"er_non_boolean_expr_for_check_constraint\";\n    case 3813: return \"er_column_check_constraint_references_other_column\";\n    case 3814: return \"er_check_constraint_named_function_is_not_allowed\";\n    case 3815: return \"er_check_constraint_function_is_not_allowed\";\n    case 3816: return \"er_check_constraint_variables\";\n    case 3817: return \"er_check_constraint_row_value\";\n    case 3818: return \"er_check_constraint_refers_auto_increment_column\";\n    case 3819: return \"er_check_constraint_violated\";\n    case 3820: return \"er_check_constraint_refers_unknown_column\";\n    case 3821: return \"er_check_constraint_not_found\";\n    case 3822: return \"er_check_constraint_dup_name\";\n    case 3823: return \"er_check_constraint_clause_using_fk_refer_action_column\";\n    case 3824: return \"warn_unencrypted_table_in_encrypted_db\";\n    case 3825: return \"er_invalid_encryption_request\";\n    case 3826: return \"er_cannot_set_table_encryption\";\n    case 3827: return \"er_cannot_set_database_encryption\";\n    case 3828: return \"er_cannot_set_tablespace_encryption\";\n    case 3829: return \"er_tablespace_cannot_be_encrypted\";\n    case 3830: return \"er_tablespace_cannot_be_decrypted\";\n    case 3831: return \"er_tablespace_type_unknown\";\n    case 3832: return \"er_target_tablespace_unencrypted\";\n    case 3833: return \"er_cannot_use_encryption_clause\";\n    case 3834: return \"er_invalid_multiple_clauses\";\n    case 3835: return \"er_unsupported_use_of_grant_as\";\n    case 3836: return \"er_uknown_auth_id_or_access_denied_for_grant_as\";\n    case 3837: return \"er_dependent_by_functional_index\";\n    case 3838: return \"er_plugin_not_early\";\n    case 3839: return \"er_innodb_redo_log_archive_start_subdir_path\";\n    case 3840: return \"er_innodb_redo_log_archive_start_timeout\";\n    case 3841: return \"er_innodb_redo_log_archive_dirs_invalid\";\n    case 3842: return \"er_innodb_redo_log_archive_label_not_found\";\n    case 3843: return \"er_innodb_redo_log_archive_dir_empty\";\n    case 3844: return \"er_innodb_redo_log_archive_no_such_dir\";\n    case 3845: return \"er_innodb_redo_log_archive_dir_clash\";\n    case 3846: return \"er_innodb_redo_log_archive_dir_permissions\";\n    case 3847: return \"er_innodb_redo_log_archive_file_create\";\n    case 3848: return \"er_innodb_redo_log_archive_active\";\n    case 3849: return \"er_innodb_redo_log_archive_inactive\";\n    case 3850: return \"er_innodb_redo_log_archive_failed\";\n    case 3851: return \"er_innodb_redo_log_archive_session\";\n    case 3852: return \"er_std_regex_error\";\n    case 3853: return \"er_invalid_json_type\";\n    case 3854: return \"er_cannot_convert_string\";\n    case 3855: return \"er_dependent_by_partition_func\";\n    case 3856: return \"er_warn_deprecated_float_auto_increment\";\n    case 3857: return \"er_rpl_cant_stop_slave_while_locked_backup\";\n    case 3858: return \"er_warn_deprecated_float_digits\";\n    case 3859: return \"er_warn_deprecated_float_unsigned\";\n    case 3860: return \"er_warn_deprecated_integer_display_width\";\n    case 3861: return \"er_warn_deprecated_zerofill\";\n    case 3862: return \"er_clone_donor\";\n    case 3863: return \"er_clone_protocol\";\n    case 3864: return \"er_clone_donor_version\";\n    case 3865: return \"er_clone_os\";\n    case 3866: return \"er_clone_platform\";\n    case 3867: return \"er_clone_charset\";\n    case 3868: return \"er_clone_config\";\n    case 3869: return \"er_clone_sys_config\";\n    case 3870: return \"er_clone_plugin_match\";\n    case 3871: return \"er_clone_loopback\";\n    case 3872: return \"er_clone_encryption\";\n    case 3873: return \"er_clone_disk_space\";\n    case 3874: return \"er_clone_in_progress\";\n    case 3875: return \"er_clone_disallowed\";\n    case 3876: return \"er_cannot_grant_roles_to_anonymous_user\";\n    case 3877: return \"er_secondary_engine_plugin\";\n    case 3878: return \"er_second_password_cannot_be_empty\";\n    case 3879: return \"er_db_access_denied\";\n    case 3880: return \"er_da_auth_id_with_system_user_priv_in_mandatory_roles\";\n    case 3881: return \"er_da_rpl_gtid_table_cannot_open\";\n    case 3882: return \"er_geometry_in_unknown_length_unit\";\n    case 3883: return \"er_da_plugin_install_error\";\n    case 3884: return \"er_no_session_temp\";\n    case 3885: return \"er_da_unknown_error_number\";\n    case 3886: return \"er_column_change_size\";\n    case 3887: return \"er_regexp_invalid_capture_group_name\";\n    case 3888: return \"er_da_ssl_library_error\";\n    case 3889: return \"er_secondary_engine\";\n    case 3890: return \"er_secondary_engine_ddl\";\n    case 3891: return \"er_incorrect_current_password\";\n    case 3892: return \"er_missing_current_password\";\n    case 3893: return \"er_current_password_not_required\";\n    case 3894: return \"er_password_cannot_be_retained_on_plugin_change\";\n    case 3895: return \"er_current_password_cannot_be_retained\";\n    case 3896: return \"er_partial_revokes_exist\";\n    case 3897: return \"er_cannot_grant_system_priv_to_mandatory_role\";\n    case 3898: return \"er_xa_replication_filters\";\n    case 3899: return \"er_unsupported_sql_mode\";\n    case 3900: return \"er_regexp_invalid_flag\";\n    case 3901: return \"er_partial_revoke_and_db_grant_both_exists\";\n    case 3902: return \"er_unit_not_found\";\n    case 3903: return \"er_invalid_json_value_for_func_index\";\n    case 3904: return \"er_json_value_out_of_range_for_func_index\";\n    case 3905: return \"er_exceeded_mv_keys_num\";\n    case 3906: return \"er_exceeded_mv_keys_space\";\n    case 3907: return \"er_functional_index_data_is_too_long\";\n    case 3908: return \"er_wrong_mvi_value\";\n    case 3909: return \"er_warn_func_index_not_applicable\";\n    case 3910: return \"er_grp_rpl_udf_error\";\n    case 3911: return \"er_update_gtid_purged_with_gr\";\n    case 3912: return \"er_grouping_on_timestamp_in_dst\";\n    case 3913: return \"er_table_name_causes_too_long_path\";\n    case 3914: return \"er_audit_log_insufficient_privilege\";\n    case 3916: return \"er_da_grp_rpl_started_auto_rejoin\";\n    case 3917: return \"er_sysvar_change_during_query\";\n    case 3918: return \"er_globstat_change_during_query\";\n    case 3919: return \"er_grp_rpl_message_service_init_failure\";\n    case 3920: return \"er_change_master_wrong_compression_algorithm_client\";\n    case 3921: return \"er_change_master_wrong_compression_level_client\";\n    case 3922: return \"er_wrong_compression_algorithm_client\";\n    case 3923: return \"er_wrong_compression_level_client\";\n    case 3924: return \"er_change_master_wrong_compression_algorithm_list_client\";\n    case 3925: return \"er_client_privilege_checks_user_cannot_be_anonymous\";\n    case 3926: return \"er_client_privilege_checks_user_does_not_exist\";\n    case 3927: return \"er_client_privilege_checks_user_corrupt\";\n    case 3928: return \"er_client_privilege_checks_user_needs_rpl_applier_priv\";\n    case 3929: return \"er_warn_da_privilege_not_registered\";\n    case 3930: return \"er_client_keyring_udf_key_invalid\";\n    case 3931: return \"er_client_keyring_udf_key_type_invalid\";\n    case 3932: return \"er_client_keyring_udf_key_too_long\";\n    case 3933: return \"er_client_keyring_udf_key_type_too_long\";\n    case 3934: return \"er_json_schema_validation_error_with_detailed_report\";\n    case 3935: return \"er_da_udf_invalid_charset_specified\";\n    case 3936: return \"er_da_udf_invalid_charset\";\n    case 3937: return \"er_da_udf_invalid_collation\";\n    case 3938: return \"er_da_udf_invalid_extension_argument_type\";\n    case 3939: return \"er_multiple_constraints_with_same_name\";\n    case 3940: return \"er_constraint_not_found\";\n    case 3941: return \"er_alter_constraint_enforcement_not_supported\";\n    case 3942: return \"er_table_value_constructor_must_have_columns\";\n    case 3943: return \"er_table_value_constructor_cannot_have_default\";\n    case 3944: return \"er_client_query_failure_invalid_non_row_format\";\n    case 3945: return \"er_require_row_format_invalid_value\";\n    case 3946: return \"er_failed_to_determine_if_role_is_mandatory\";\n    case 3947: return \"er_failed_to_fetch_mandatory_role_list\";\n    case 3948: return \"er_client_local_files_disabled\";\n    case 3949: return \"er_imp_incompatible_cfg_version\";\n    case 3950: return \"er_da_oom\";\n    case 3951: return \"er_da_udf_invalid_argument_to_set_charset\";\n    case 3952: return \"er_da_udf_invalid_return_type_to_set_charset\";\n    case 3953: return \"er_multiple_into_clauses\";\n    case 3954: return \"er_misplaced_into\";\n    case 3955: return \"er_user_access_denied_for_user_account_blocked_by_password_lock\";\n    case 3956: return \"er_warn_deprecated_year_unsigned\";\n    case 3957: return \"er_clone_network_packet\";\n    case 3958: return \"er_sdi_operation_failed_missing_record\";\n    case 3959: return \"er_dependent_by_check_constraint\";\n    case 3960: return \"er_grp_operation_not_allowed_gr_must_stop\";\n    case 3961: return \"er_warn_deprecated_json_table_on_error_on_empty\";\n    case 3962: return \"er_warn_deprecated_inner_into\";\n    case 3963: return \"er_warn_deprecated_values_function_always_null\";\n    case 3964: return \"er_warn_deprecated_sql_calc_found_rows\";\n    case 3965: return \"er_warn_deprecated_found_rows\";\n    case 3966: return \"er_missing_json_value\";\n    case 3967: return \"er_multiple_json_values\";\n    case 3968: return \"er_hostname_too_long\";\n    case 3969: return \"er_warn_client_deprecated_partition_prefix_key\";\n    case 3970: return \"er_group_replication_user_empty_msg\";\n    case 3971: return \"er_group_replication_user_mandatory_msg\";\n    case 3972: return \"er_group_replication_password_length\";\n    case 3973: return \"er_subquery_transform_rejected\";\n    case 3974: return \"er_da_grp_rpl_recovery_endpoint_format\";\n    case 3975: return \"er_da_grp_rpl_recovery_endpoint_invalid\";\n    case 3976: return \"er_wrong_value_for_var_plus_actionable_part\";\n    case 3977: return \"er_statement_not_allowed_after_start_transaction\";\n    case 3978: return \"er_foreign_key_with_atomic_create_select\";\n    case 3979: return \"er_not_allowed_with_start_transaction\";\n    case 3980: return \"er_invalid_json_attribute\";\n    case 3981: return \"er_engine_attribute_not_supported\";\n    case 3982: return \"er_invalid_user_attribute_json\";\n    case 3983: return \"er_innodb_redo_disabled\";\n    case 3984: return \"er_innodb_redo_archiving_enabled\";\n    case 3985: return \"er_mdl_out_of_resources\";\n    case 3986: return \"er_implicit_comparison_for_json\";\n    case 3987: return \"er_function_does_not_support_character_set\";\n    case 3988: return \"er_impossible_string_conversion\";\n    case 3989: return \"er_schema_read_only\";\n    case 3990: return \"er_rpl_async_reconnect_gtid_mode_off\";\n    case 3991: return \"er_rpl_async_reconnect_auto_position_off\";\n    case 3992: return \"er_disable_gtid_mode_requires_async_reconnect_off\";\n    case 3993: return \"er_disable_auto_position_requires_async_reconnect_off\";\n    case 3994: return \"er_invalid_parameter_use\";\n    case 3995: return \"er_character_set_mismatch\";\n    case 3996: return \"er_warn_var_value_change_not_supported\";\n    case 3997: return \"er_invalid_time_zone_interval\";\n    case 3998: return \"er_invalid_cast\";\n    case 3999: return \"er_hypergraph_not_supported_yet\";\n    case 4000: return \"er_warn_hypergraph_experimental\";\n    case 4001: return \"er_da_no_error_log_parser_configured\";\n    case 4002: return \"er_da_error_log_table_disabled\";\n    case 4003: return \"er_da_error_log_multiple_filters\";\n    case 4004: return \"er_da_cant_open_error_log\";\n    case 4005: return \"er_user_referenced_as_definer\";\n    case 4006: return \"er_cannot_user_referenced_as_definer\";\n    case 4007: return \"er_regex_number_too_big\";\n    case 4008: return \"er_spvar_noninteger_type\";\n    case 4009: return \"warn_unsupported_acl_tables_read\";\n    case 4010: return \"er_binlog_unsafe_acl_table_read_in_dml_ddl\";\n    case 4011: return \"er_stop_replica_monitor_io_thread_timeout\";\n    case 4012: return \"er_starting_replica_monitor_io_thread\";\n    case 4013: return \"er_cant_use_anonymous_to_gtid_with_gtid_mode_not_on\";\n    case 4014: return \"er_cant_combine_anonymous_to_gtid_and_autoposition\";\n    case 4015: return \"er_assign_gtids_to_anonymous_transactions_requires_gtid_mode_on\";\n    case 4016: return \"er_sql_slave_skip_counter_used_with_gtid_mode_on\";\n    case 4017: return \"er_using_assign_gtids_to_anonymous_transactions_as_local_or_uuid\";\n    case 4018: return \"er_cant_set_anonymous_to_gtid_and_wait_until_sql_thd_after_gtids\";\n    case 4019: return \"er_cant_set_sql_after_or_before_gtids_with_anonymous_to_gtid\";\n    case 4020: return \"er_anonymous_to_gtid_uuid_same_as_group_name\";\n    case 4021: return \"er_cant_use_same_uuid_as_group_name\";\n    case 4022: return \"er_grp_rpl_recovery_channel_still_running\";\n    case 4023: return \"er_innodb_invalid_autoextend_size_value\";\n    case 4024: return \"er_innodb_incompatible_with_tablespace\";\n    case 4025: return \"er_innodb_autoextend_size_out_of_range\";\n    case 4026: return \"er_cannot_use_autoextend_size_clause\";\n    case 4027: return \"er_role_granted_to_itself\";\n    case 4028: return \"er_table_must_have_a_visible_column\";\n    case 4029: return \"er_innodb_compression_failure\";\n    case 4030: return \"er_warn_async_conn_failover_network_namespace\";\n    case 4031: return \"er_client_interaction_timeout\";\n    case 4032: return \"er_invalid_cast_to_geometry\";\n    case 4033: return \"er_invalid_cast_polygon_ring_direction\";\n    case 4034: return \"er_gis_different_srids_aggregation\";\n    case 4035: return \"er_reload_keyring_failure\";\n    case 4036: return \"er_sdi_get_keys_invalid_tablespace\";\n    case 4037: return \"er_change_rpl_src_wrong_compression_algorithm_size\";\n    case 4039: return \"er_cant_use_same_uuid_as_view_change_uuid\";\n    case 4040: return \"er_anonymous_to_gtid_uuid_same_as_view_change_uuid\";\n    case 4041: return \"er_grp_rpl_view_change_uuid_fail_get_variable\";\n    case 4042: return \"er_warn_aduit_log_max_size_and_prune_seconds\";\n    case 4043: return \"er_warn_aduit_log_max_size_close_to_rotate_on_size\";\n    case 4044: return \"er_kerberos_create_user\";\n    case 4045: return \"er_install_plugin_conflict_client\";\n    case 4046: return \"er_da_error_log_component_flush_failed\";\n    case 4047: return \"er_warn_sql_after_mts_gaps_gap_not_calculated\";\n    case 4048: return \"er_invalid_assignment_target\";\n    case 4049: return \"er_operation_not_allowed_on_gr_secondary\";\n    case 4050: return \"er_grp_rpl_failover_channel_status_propagation\";\n    case 4051: return \"er_warn_audit_log_format_unix_timestamp_only_when_json\";\n    case 4052: return \"er_invalid_mfa_plugin_specified\";\n    case 4053: return \"er_identified_by_unsupported\";\n    case 4054: return \"er_invalid_plugin_for_registration\";\n    case 4055: return \"er_plugin_requires_registration\";\n    case 4056: return \"er_mfa_method_exists\";\n    case 4057: return \"er_mfa_method_not_exists\";\n    case 4058: return \"er_authentication_policy_mismatch\";\n    case 4059: return \"er_plugin_registration_done\";\n    case 4060: return \"er_invalid_user_for_registration\";\n    case 4061: return \"er_user_registration_failed\";\n    case 4062: return \"er_mfa_methods_invalid_order\";\n    case 4063: return \"er_mfa_methods_identical\";\n    case 4064: return \"er_invalid_mfa_operations_for_passwordless_user\";\n    case 4065: return \"er_change_replication_source_no_options_for_gtid_only\";\n    case 4066: return \"er_change_rep_source_cant_disable_req_row_format_with_gtid_only\";\n    case 4067: return \"er_change_rep_source_cant_disable_auto_position_with_gtid_only\";\n    case 4068: return \"er_change_rep_source_cant_disable_gtid_only_without_positions\";\n    case 4069: return \"er_change_rep_source_cant_disable_auto_pos_without_positions\";\n    case 4070: return \"er_change_rep_source_gr_channel_with_gtid_mode_not_on\";\n    case 4071: return \"er_cant_use_gtid_only_with_gtid_mode_not_on\";\n    case 4072: return \"er_warn_c_disable_gtid_only_with_source_auto_pos_invalid_pos\";\n    case 4073: return \"er_da_ssl_fips_mode_error\";\n    case 4074: return \"er_value_out_of_range\";\n    case 4075: return \"er_fulltext_with_rollup\";\n    case 4076: return \"er_regexp_missing_resource\";\n    case 4077: return \"er_warn_regexp_using_default\";\n    case 4078: return \"er_regexp_missing_file\";\n    case 4079: return \"er_warn_deprecated_collation\";\n    case 4080: return \"er_concurrent_procedure_usage\";\n    case 4081: return \"er_da_global_conn_limit\";\n    case 4082: return \"er_da_conn_limit\";\n    case 4083: return \"er_alter_operation_not_supported_reason_column_type_instant\";\n    case 4084: return \"er_warn_sf_udf_name_collision\";\n    case 4085: return \"er_cannot_purge_binlog_with_backup_lock\";\n    case 4086: return \"er_too_many_windows\";\n    case 4087: return \"er_mysqlbackup_client_msg\";\n    case 4088: return \"er_comment_contains_invalid_string\";\n    case 4089: return \"er_definition_contains_invalid_string\";\n    case 4090: return \"er_cant_execute_command_with_assigned_gtid_next\";\n    case 4091: return \"er_xa_temp_table\";\n    case 4092: return \"er_innodb_max_row_version\";\n    case 4094: return \"er_operation_not_allowed_while_primary_change_is_running\";\n    case 4095: return \"er_warn_deprecated_datetime_delimiter\";\n    case 4096: return \"er_warn_deprecated_superfluous_delimiter\";\n    case 4097: return \"er_cannot_persist_sensitive_variables\";\n    case 4098: return \"er_warn_cannot_securely_persist_sensitive_variables\";\n    case 4099: return \"er_warn_trg_already_exists\";\n    case 4100: return \"er_if_not_exists_unsupported_trg_exists_on_different_table\";\n    case 4101: return \"er_if_not_exists_unsupported_udf_native_fct_name_collision\";\n    case 4102: return \"er_set_password_auth_plugin_error\";\n    case 4105: return \"er_srs_invalid_latitude_of_origin\";\n    case 4106: return \"er_srs_invalid_longitude_of_origin\";\n    case 4107: return \"er_srs_unused_proj_parameter_present\";\n    case 4108: return \"er_gipk_column_exists\";\n    case 4109: return \"er_gipk_failed_autoinc_column_exists\";\n    case 4110: return \"er_gipk_column_alter_not_allowed\";\n    case 4111: return \"er_drop_pk_column_to_drop_gipk\";\n    case 4112: return \"er_create_select_with_gipk_disallowed_in_sbr\";\n    case 4113: return \"er_da_expire_logs_days_ignored\";\n    case 4114: return \"er_cte_recursive_not_union\";\n    case 4115: return \"er_command_backend_failed_to_fetch_security_ctx\";\n    case 4116: return \"er_command_service_backend_failed\";\n    case 4117: return \"er_client_file_privilege_for_replication_checks\";\n    case 4118: return \"er_group_replication_force_members_command_failure\";\n    case 4119: return \"er_warn_deprecated_ident\";\n    case 4120: return \"er_intersect_all_max_duplicates_exceeded\";\n    case 4121: return \"er_tp_query_thrs_per_grp_exceeds_txn_thr_limit\";\n    case 4122: return \"er_bad_timestamp_format\";\n    case 4123: return \"er_shape_pridiction_udf\";\n    case 4124: return \"er_srs_invalid_height\";\n    case 4125: return \"er_srs_invalid_scaling\";\n    case 4126: return \"er_srs_invalid_zone_width\";\n    case 4127: return \"er_srs_invalid_latitude_polar_stere_var_a\";\n    case 4128: return \"er_warn_deprecated_client_no_schema_option\";\n    case 4129: return \"er_table_not_empty\";\n    case 4130: return \"er_table_no_primary_key\";\n    case 4131: return \"er_table_in_shared_tablespace\";\n    case 4132: return \"er_index_other_than_pk\";\n    case 4133: return \"er_load_bulk_data_unsorted\";\n    case 4134: return \"er_bulk_executor_error\";\n    case 4135: return \"er_bulk_reader_libcurl_init_failed\";\n    case 4136: return \"er_bulk_reader_libcurl_error\";\n    case 4137: return \"er_bulk_reader_server_error\";\n    case 4138: return \"er_bulk_reader_communication_error\";\n    case 4139: return \"er_bulk_load_data_failed\";\n    case 4140: return \"er_bulk_loader_column_too_big_for_leftover_buffer\";\n    case 4141: return \"er_bulk_loader_component_error\";\n    case 4142: return \"er_bulk_loader_file_contains_less_lines_than_ignore_clause\";\n    case 4143: return \"er_bulk_parser_missing_enclosed_by\";\n    case 4144: return \"er_bulk_parser_row_buffer_max_total_cols_exceeded\";\n    case 4145: return \"er_bulk_parser_copy_buffer_size_exceeded\";\n    case 4146: return \"er_bulk_parser_unexpected_end_of_input\";\n    case 4147: return \"er_bulk_parser_unexpected_row_terminator\";\n    case 4148: return \"er_bulk_parser_unexpected_char_after_ending_enclosed_by\";\n    case 4149: return \"er_bulk_parser_unexpected_char_after_null_escape\";\n    case 4150: return \"er_bulk_parser_unexpected_char_after_column_terminator\";\n    case 4151: return \"er_bulk_parser_incomplete_escape_sequence\";\n    case 4152: return \"er_load_bulk_data_failed\";\n    case 4153: return \"er_load_bulk_data_wrong_value_for_field\";\n    case 4154: return \"er_load_bulk_data_warn_null_to_notnull\";\n    case 4155: return \"er_require_table_primary_key_check_generate_with_gr\";\n    case 4156: return \"er_cant_change_sys_var_in_read_only_mode\";\n    case 4157: return \"er_innodb_instant_add_drop_not_supported_max_size\";\n    case 4158: return \"er_innodb_instant_add_not_supported_max_fields\";\n    case 4159: return \"er_cant_set_persisted\";\n    case 4160: return \"er_install_component_set_null_value\";\n    case 4161: return \"er_install_component_set_unused_value\";\n    case 4162: return \"er_warn_deprecated_user_defined_collations\";\n    case 4163: return \"er_user_lock_overlong_name\";\n    case 4164: return \"er_warn_no_space_version_comment\";\n    case 4165: return \"er_validate_password_insufficient_changed_characters\";\n    case 4166: return \"er_warn_deprecated_with_note\";\n\n    default: return \"<unknown MySQL-specific server error>\";\n    }\n}\n\nconst char* boost::mysql::detail::mariadb_error_to_string(int v)\n{\n    switch (v)\n    {\n    case 1076: return \"er_binlog_cant_delete_gtid_domain\";\n    case 1120: return \"er_wrong_outer_join\";\n    case 1150: return \"er_delayed_cant_change_lock\";\n    case 1151: return \"er_too_many_delayed_threads\";\n    case 1165: return \"er_delayed_insert_table_locked\";\n    case 1176: return \"er_key_does_not_exists\";\n    case 1349: return \"er_view_select_derived\";\n    case 1487: return \"er_not_constant_expression\";\n    case 1506: return \"er_feature_not_supported_with_partitioning\";\n    case 1593: return \"er_slave_fatal_error\";\n    case 1611: return \"er_load_data_invalid_column\";\n    case 1669: return \"er_binlog_unsafe_insert_delayed\";\n    case 1726: return \"er_vers_not_allowed\";\n    case 1742: return \"er_value_too_long\";\n    case 1768: return \"er_cant_change_gtid_next_in_transaction_when_gtid_next_list_is_null\";\n    case 1777: return \"er_auto_position_requires_gtid_mode_on\";\n    case 1779: return \"er_gtid_mode_2_or_3_requires_enforce_gtid_consistency_on\";\n    case 1784: return \"er_found_gtid_event_when_gtid_mode_is_off\";\n    case 1826: return \"er_dup_constraint_name\";\n    case 1834: return \"er_fk_cannot_delete_parent\";\n    case 1837: return \"er_gtid_next_type_undefined_group\";\n    case 1852: return \"er_alter_operation_not_supported_reason_ignore\";\n    case 1901: return \"er_generated_column_function_is_not_allowed\";\n    case 1903: return \"er_primary_key_based_on_generated_column\";\n    case 1904: return \"er_key_based_on_generated_virtual_column\";\n    case 1905: return \"er_wrong_fk_option_for_generated_column\";\n    case 1906: return \"er_warning_non_default_value_for_generated_column\";\n    case 1907: return \"er_unsupported_action_on_generated_column\";\n    case 1910: return \"er_unsupported_engine_for_generated_columns\";\n    case 1911: return \"er_unknown_option\";\n    case 1912: return \"er_bad_option_value\";\n    case 1916: return \"er_data_overflow\";\n    case 1917: return \"er_data_truncated\";\n    case 1918: return \"er_bad_data\";\n    case 1919: return \"er_dyn_col_wrong_format\";\n    case 1920: return \"er_dyn_col_implementation_limit\";\n    case 1921: return \"er_dyn_col_data\";\n    case 1922: return \"er_dyn_col_wrong_charset\";\n    case 1923: return \"er_illegal_subquery_optimizer_switches\";\n    case 1924: return \"er_query_cache_is_disabled\";\n    case 1925: return \"er_query_cache_is_globaly_disabled\";\n    case 1926: return \"er_view_orderby_ignored\";\n    case 1927: return \"er_connection_killed\";\n    case 1929: return \"er_inside_transaction_prevents_switch_skip_replication\";\n    case 1930: return \"er_stored_function_prevents_switch_skip_replication\";\n    case 1931: return \"er_query_exceeded_rows_examined_limit\";\n    case 1932: return \"er_no_such_table_in_engine\";\n    case 1933: return \"er_target_not_explainable\";\n    case 1934: return \"er_connection_already_exists\";\n    case 1935: return \"er_master_log_prefix\";\n    case 1936: return \"er_cant_start_stop_slave\";\n    case 1937: return \"er_slave_started\";\n    case 1938: return \"er_slave_stopped\";\n    case 1939: return \"er_sql_discover_error\";\n    case 1940: return \"er_failed_gtid_state_init\";\n    case 1941: return \"er_incorrect_gtid_state\";\n    case 1942: return \"er_cannot_update_gtid_state\";\n    case 1943: return \"er_duplicate_gtid_domain\";\n    case 1944: return \"er_gtid_open_table_failed\";\n    case 1945: return \"er_gtid_position_not_found_in_binlog\";\n    case 1946: return \"er_cannot_load_slave_gtid_state\";\n    case 1947: return \"er_master_gtid_pos_conflicts_with_binlog\";\n    case 1948: return \"er_master_gtid_pos_missing_domain\";\n    case 1949: return \"er_until_requires_using_gtid\";\n    case 1950: return \"er_gtid_strict_out_of_order\";\n    case 1951: return \"er_gtid_start_from_binlog_hole\";\n    case 1952: return \"er_slave_unexpected_master_switch\";\n    case 1953: return \"er_inside_transaction_prevents_switch_gtid_domain_id_seq_no\";\n    case 1954: return \"er_stored_function_prevents_switch_gtid_domain_id_seq_no\";\n    case 1955: return \"er_gtid_position_not_found_in_binlog2\";\n    case 1956: return \"er_binlog_must_be_empty\";\n    case 1957: return \"er_no_such_query\";\n    case 1958: return \"er_bad_base64_data\";\n    case 1959: return \"er_invalid_role\";\n    case 1960: return \"er_invalid_current_user\";\n    case 1961: return \"er_cannot_grant_role\";\n    case 1962: return \"er_cannot_revoke_role\";\n    case 1963: return \"er_change_slave_parallel_threads_active\";\n    case 1964: return \"er_prior_commit_failed\";\n    case 1965: return \"er_it_is_a_view\";\n    case 1966: return \"er_slave_skip_not_in_gtid\";\n    case 1967: return \"er_table_definition_too_big\";\n    case 1968: return \"er_plugin_installed\";\n    case 1969: return \"er_statement_timeout\";\n    case 1970: return \"er_subqueries_not_supported\";\n    case 1971: return \"er_set_statement_not_supported\";\n    case 1973: return \"er_user_create_exists\";\n    case 1974: return \"er_user_drop_exists\";\n    case 1975: return \"er_role_create_exists\";\n    case 1976: return \"er_role_drop_exists\";\n    case 1977: return \"er_cannot_convert_character\";\n    case 1978: return \"er_invalid_default_value_for_field\";\n    case 1979: return \"er_kill_query_denied_error\";\n    case 1980: return \"er_no_eis_for_field\";\n    case 1981: return \"er_warn_aggfunc_dependence\";\n    case 1982: return \"warn_innodb_partition_option_ignored\";\n    case 3000: return \"er_file_corrupt\";\n    case 3001: return \"er_error_on_master\";\n    case 3002: return \"er_inconsistent_error\";\n    case 3003: return \"er_storage_engine_not_loaded\";\n    case 3004: return \"er_get_stacked_da_without_active_handler\";\n    case 3005: return \"er_warn_legacy_syntax_converted\";\n    case 3006: return \"er_binlog_unsafe_fulltext_plugin\";\n    case 3007: return \"er_cannot_discard_temporary_table\";\n    case 3008: return \"er_fk_depth_exceeded\";\n    case 3009: return \"er_col_count_doesnt_match_please_update_v2\";\n    case 3010: return \"er_warn_trigger_doesnt_have_created\";\n    case 3011: return \"er_referenced_trg_does_not_exist_mysql\";\n    case 3012: return \"er_explain_not_supported\";\n    case 3013: return \"er_invalid_field_size\";\n    case 3014: return \"er_missing_ha_create_option\";\n    case 3015: return \"er_engine_out_of_memory\";\n    case 3016: return \"er_password_expire_anonymous_user\";\n    case 3017: return \"er_slave_sql_thread_must_stop\";\n    case 3018: return \"er_no_ft_materialized_subquery\";\n    case 3019: return \"er_innodb_undo_log_full\";\n    case 3020: return \"er_invalid_argument_for_logarithm\";\n    case 3021: return \"er_slave_channel_io_thread_must_stop\";\n    case 3022: return \"er_warn_open_temp_tables_must_be_zero\";\n    case 3023: return \"er_warn_only_master_log_file_no_pos\";\n    case 3024: return \"er_query_timeout\";\n    case 3025: return \"er_non_ro_select_disable_timer\";\n    case 3026: return \"er_dup_list_entry\";\n    case 3027: return \"er_sql_mode_no_effect\";\n    case 3028: return \"er_aggregate_order_for_union\";\n    case 3029: return \"er_aggregate_order_non_agg_query\";\n    case 3030: return \"er_slave_worker_stopped_previous_thd_error\";\n    case 3031: return \"er_dont_support_slave_preserve_commit_order\";\n    case 3032: return \"er_server_offline_mode\";\n    case 3033: return \"er_gis_different_srids\";\n    case 3034: return \"er_gis_unsupported_argument\";\n    case 3035: return \"er_gis_unknown_error\";\n    case 3036: return \"er_gis_unknown_exception\";\n    case 3037: return \"er_gis_invalid_data\";\n    case 3038: return \"er_boost_geometry_empty_input_exception\";\n    case 3039: return \"er_boost_geometry_centroid_exception\";\n    case 3040: return \"er_boost_geometry_overlay_invalid_input_exception\";\n    case 3041: return \"er_boost_geometry_turn_info_exception\";\n    case 3042: return \"er_boost_geometry_self_intersection_point_exception\";\n    case 3043: return \"er_boost_geometry_unknown_exception\";\n    case 3044: return \"er_std_bad_alloc_error\";\n    case 3045: return \"er_std_domain_error\";\n    case 3046: return \"er_std_length_error\";\n    case 3047: return \"er_std_invalid_argument\";\n    case 3048: return \"er_std_out_of_range_error\";\n    case 3049: return \"er_std_overflow_error\";\n    case 3050: return \"er_std_range_error\";\n    case 3051: return \"er_std_underflow_error\";\n    case 3052: return \"er_std_logic_error\";\n    case 3053: return \"er_std_runtime_error\";\n    case 3054: return \"er_std_unknown_exception\";\n    case 3055: return \"er_gis_data_wrong_endianess\";\n    case 3056: return \"er_change_master_password_length\";\n    case 3057: return \"er_user_lock_wrong_name\";\n    case 3058: return \"er_user_lock_deadlock\";\n    case 3059: return \"er_replace_inaccessible_rows\";\n    case 3060: return \"er_alter_operation_not_supported_reason_gis\";\n    case 4002: return \"er_with_col_wrong_list\";\n    case 4003: return \"er_too_many_definitions_in_with_clause\";\n    case 4004: return \"er_dup_query_name\";\n    case 4005: return \"er_recursive_without_anchors\";\n    case 4006: return \"er_unacceptable_mutual_recursion\";\n    case 4007: return \"er_ref_to_recursive_with_table_in_derived\";\n    case 4008: return \"er_not_standard_compliant_recursive\";\n    case 4009: return \"er_wrong_window_spec_name\";\n    case 4010: return \"er_dup_window_name\";\n    case 4011: return \"er_partition_list_in_referencing_window_spec\";\n    case 4012: return \"er_order_list_in_referencing_window_spec\";\n    case 4013: return \"er_window_frame_in_referenced_window_spec\";\n    case 4014: return \"er_bad_combination_of_window_frame_bound_specs\";\n    case 4015: return \"er_wrong_placement_of_window_function\";\n    case 4016: return \"er_window_function_in_window_spec\";\n    case 4017: return \"er_not_allowed_window_frame\";\n    case 4018: return \"er_no_order_list_in_window_spec\";\n    case 4019: return \"er_range_frame_needs_simple_orderby\";\n    case 4020: return \"er_wrong_type_for_rows_frame\";\n    case 4021: return \"er_wrong_type_for_range_frame\";\n    case 4022: return \"er_frame_exclusion_not_supported\";\n    case 4023: return \"er_window_function_dont_have_frame\";\n    case 4024: return \"er_invalid_ntile_argument\";\n    case 4025: return \"er_constraint_failed\";\n    case 4026: return \"er_expression_is_too_big\";\n    case 4027: return \"er_error_evaluating_expression\";\n    case 4028: return \"er_calculating_default_value\";\n    case 4029: return \"er_expression_refers_to_uninit_field\";\n    case 4030: return \"er_partition_default_error\";\n    case 4031: return \"er_referenced_trg_does_not_exist\";\n    case 4032: return \"er_invalid_default_param\";\n    case 4033: return \"er_binlog_non_supported_bulk\";\n    case 4034: return \"er_binlog_uncompress_error\";\n    case 4035: return \"er_json_bad_chr\";\n    case 4036: return \"er_json_not_json_chr\";\n    case 4037: return \"er_json_eos\";\n    case 4038: return \"er_json_syntax\";\n    case 4039: return \"er_json_escaping\";\n    case 4040: return \"er_json_depth\";\n    case 4041: return \"er_json_path_eos\";\n    case 4042: return \"er_json_path_syntax\";\n    case 4043: return \"er_json_path_depth\";\n    case 4044: return \"er_json_path_no_wildcard\";\n    case 4045: return \"er_json_path_array\";\n    case 4046: return \"er_json_one_or_all\";\n    case 4047: return \"er_unsupported_compressed_table\";\n    case 4048: return \"er_geojson_incorrect\";\n    case 4049: return \"er_geojson_too_few_points\";\n    case 4050: return \"er_geojson_not_closed\";\n    case 4051: return \"er_json_path_empty\";\n    case 4052: return \"er_slave_same_id\";\n    case 4053: return \"er_flashback_not_supported\";\n    case 4054: return \"er_keys_out_of_order\";\n    case 4055: return \"er_overlapping_keys\";\n    case 4056: return \"er_require_row_binlog_format\";\n    case 4057: return \"er_isolation_mode_not_supported\";\n    case 4058: return \"er_on_duplicate_disabled\";\n    case 4059: return \"er_updates_with_consistent_snapshot\";\n    case 4060: return \"er_rollback_only\";\n    case 4061: return \"er_rollback_to_savepoint\";\n    case 4062: return \"er_isolation_level_with_consistent_snapshot\";\n    case 4063: return \"er_unsupported_collation\";\n    case 4064: return \"er_metadata_inconsistency\";\n    case 4065: return \"er_cf_different\";\n    case 4066: return \"er_rdb_ttl_duration_format\";\n    case 4067: return \"er_rdb_status_general\";\n    case 4068: return \"er_rdb_status_msg\";\n    case 4069: return \"er_rdb_ttl_unsupported\";\n    case 4070: return \"er_rdb_ttl_col_format\";\n    case 4071: return \"er_per_index_cf_deprecated\";\n    case 4072: return \"er_key_create_during_alter\";\n    case 4073: return \"er_sk_populate_during_alter\";\n    case 4074: return \"er_sum_func_with_window_func_as_arg\";\n    case 4075: return \"er_net_ok_packet_too_large\";\n    case 4076: return \"er_geojson_empty_coordinates\";\n    case 4077: return \"er_myrocks_cant_nopad_collation\";\n    case 4078: return \"er_illegal_parameter_data_types2_for_operation\";\n    case 4079: return \"er_illegal_parameter_data_type_for_operation\";\n    case 4080: return \"er_wrong_paramcount_to_cursor\";\n    case 4081: return \"er_unknown_structured_variable\";\n    case 4082: return \"er_row_variable_does_not_have_field\";\n    case 4083: return \"er_end_identifier_does_not_match\";\n    case 4084: return \"er_sequence_run_out\";\n    case 4085: return \"er_sequence_invalid_data\";\n    case 4086: return \"er_sequence_invalid_table_structure\";\n    case 4087: return \"er_sequence_access_error\";\n    case 4088: return \"er_sequence_binlog_format\";\n    case 4089: return \"er_not_sequence\";\n    case 4090: return \"er_not_sequence2\";\n    case 4091: return \"er_unknown_sequences\";\n    case 4092: return \"er_unknown_view\";\n    case 4093: return \"er_wrong_insert_into_sequence\";\n    case 4094: return \"er_sp_stack_trace\";\n    case 4095: return \"er_package_routine_in_spec_not_defined_in_body\";\n    case 4096: return \"er_package_routine_forward_declaration_not_defined\";\n    case 4097: return \"er_compressed_column_used_as_key\";\n    case 4098: return \"er_unknown_compression_method\";\n    case 4099: return \"er_wrong_number_of_values_in_tvc\";\n    case 4100: return \"er_field_reference_in_tvc\";\n    case 4101: return \"er_wrong_type_for_percentile_func\";\n    case 4102: return \"er_argument_not_constant\";\n    case 4103: return \"er_argument_out_of_range\";\n    case 4104: return \"er_wrong_type_of_argument\";\n    case 4105: return \"er_not_aggregate_function\";\n    case 4106: return \"er_invalid_aggregate_function\";\n    case 4107: return \"er_invalid_value_to_limit\";\n    case 4108: return \"er_invisible_not_null_without_default\";\n    case 4109: return \"er_update_info_with_system_versioning\";\n    case 4110: return \"er_vers_field_wrong_type\";\n    case 4111: return \"er_vers_engine_unsupported\";\n    case 4113: return \"er_partition_wrong_type\";\n    case 4114: return \"warn_vers_part_full\";\n    case 4115: return \"warn_vers_parameters\";\n    case 4116: return \"er_vers_drop_partition_interval\";\n    case 4118: return \"warn_vers_part_non_historical\";\n    case 4119: return \"er_vers_alter_not_allowed\";\n    case 4120: return \"er_vers_alter_engine_prohibited\";\n    case 4121: return \"er_vers_range_prohibited\";\n    case 4122: return \"er_conflicting_for_system_time\";\n    case 4123: return \"er_vers_table_must_have_columns\";\n    case 4124: return \"er_vers_not_versioned\";\n    case 4125: return \"er_missing\";\n    case 4126: return \"er_vers_period_columns\";\n    case 4127: return \"er_part_wrong_value\";\n    case 4128: return \"er_vers_wrong_parts\";\n    case 4129: return \"er_vers_no_trx_id\";\n    case 4130: return \"er_vers_alter_system_field\";\n    case 4131: return \"er_drop_versioning_system_time_partition\";\n    case 4132: return \"er_vers_db_not_supported\";\n    case 4133: return \"er_vers_trt_is_disabled\";\n    case 4134: return \"er_vers_duplicate_row_start_end\";\n    case 4135: return \"er_vers_already_versioned\";\n    case 4137: return \"er_vers_not_supported\";\n    case 4138: return \"er_vers_trx_part_historic_row_not_supported\";\n    case 4139: return \"er_index_file_full\";\n    case 4140: return \"er_updated_column_only_once\";\n    case 4141: return \"er_empty_row_in_tvc\";\n    case 4142: return \"er_vers_query_in_partition\";\n    case 4143: return \"er_key_doesnt_support\";\n    case 4144: return \"er_alter_operation_table_options_need_rebuild\";\n    case 4145: return \"er_backup_lock_is_active\";\n    case 4146: return \"er_backup_not_running\";\n    case 4147: return \"er_backup_wrong_stage\";\n    case 4148: return \"er_backup_stage_failed\";\n    case 4149: return \"er_backup_unknown_stage\";\n    case 4150: return \"er_user_is_blocked\";\n    case 4151: return \"er_account_has_been_locked\";\n    case 4152: return \"er_period_temporary_not_allowed\";\n    case 4153: return \"er_period_types_mismatch\";\n    case 4154: return \"er_more_than_one_period\";\n    case 4155: return \"er_period_field_wrong_attributes\";\n    case 4156: return \"er_period_not_found\";\n    case 4157: return \"er_period_columns_updated\";\n    case 4158: return \"er_period_constraint_drop\";\n    case 4159: return \"er_too_long_keypart\";\n    case 4160: return \"er_too_long_database_comment\";\n    case 4161: return \"er_unknown_data_type\";\n    case 4162: return \"er_unknown_operator\";\n    case 4163: return \"er_warn_history_row_start_time\";\n    case 4164: return \"er_part_starts_beyond_interval\";\n    case 4165: return \"er_galera_replication_not_supported\";\n    case 4166: return \"er_load_infile_capability_disabled\";\n    case 4167: return \"er_no_secure_transports_configured\";\n    case 4168: return \"er_slave_ignored_shared_table\";\n    case 4169: return \"er_no_autoincrement_with_unique\";\n    case 4170: return \"er_key_contains_period_fields\";\n    case 4171: return \"er_key_cant_have_without_overlaps\";\n    case 4172: return \"er_not_allowed_in_this_context\";\n    case 4173: return \"er_data_was_commited_under_rollback\";\n    case 4174: return \"er_pk_index_cant_be_ignored\";\n    case 4175: return \"er_binlog_unsafe_skip_locked\";\n    case 4176: return \"er_json_table_error_on_field\";\n    case 4177: return \"er_json_table_alias_required\";\n    case 4178: return \"er_json_table_scalar_expected\";\n    case 4179: return \"er_json_table_multiple_matches\";\n    case 4180: return \"er_with_ties_needs_order\";\n    case 4181: return \"er_removed_orphan_trigger\";\n    case 4182: return \"er_storage_engine_disabled\";\n    case 4183: return \"warn_sformat_error\";\n    case 4184: return \"er_partition_convert_subpartitioned\";\n    case 4185: return \"er_provider_not_loaded\";\n    case 4186: return \"er_json_histogram_parse_failed\";\n    case 4187: return \"er_sf_out_inout_arg_not_allowed\";\n    case 4188: return \"er_inconsistent_slave_temp_table\";\n    case 4189: return \"er_vers_hist_part_failed\";\n    case 4190: return \"warn_option_changing\";\n    case 4191: return \"er_cm_option_missing_requirement\";\n    case 4192: return \"er_slave_statement_timeout\";\n    case 4193: return \"er_json_invalid_value_for_keyword\";\n    case 4194: return \"er_json_schema_keyword_unsupported\";\n\n    default: return \"<unknown MariaDB-specific server error>\";\n    }\n}\n\n#endif\n\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/next_power_of_two.hpp",
    "content": "//\n// Copyright (c) 2026 Vladislav Soulgard (vsoulgard at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_NEXT_POWER_OF_TWO_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_NEXT_POWER_OF_TWO_HPP\n\n#include <boost/assert.hpp>\n\n#include <type_traits>\n#include <limits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate<int Shift, class UnsignedInt, bool Continue>\nstruct recursive_shift_or;\n\n// Apply shift and continue to the next power of 2\ntemplate<int Shift, class UnsignedInt>\nstruct recursive_shift_or<Shift, UnsignedInt, true>\n{\n    static void apply(UnsignedInt& n)\n    {\n        n |= n >> Shift;\n        recursive_shift_or<Shift * 2, UnsignedInt, (Shift * 2 < sizeof(UnsignedInt) * 8)>::apply(n);\n    }\n};\n\n// Stop recursion when shift exceeds type width\ntemplate<int Shift, class UnsignedInt>\nstruct recursive_shift_or<Shift, UnsignedInt, false>\n{\n    static void apply(UnsignedInt&) {}\n};\n\n// Returns the smallest power of two greater than or equal to n.\n// Precondition: n must not exceed the largest power of two that fits\n// in UnsignedInt. For example:\n//   - uint8_t:  n <= 128 (2^7)\n//   - uint16_t: n <= 32768 (2^15)\n//   - uint32_t: n <= 2147483648 (2^31)\n//   - uint64_t: n <= 9223372036854775808 (2^63)\n//\n// Passing a larger value results in undefined behavior (overflow).\n// In debug builds, this is caught by BOOST_ASSERT.\ntemplate<class UnsignedInt>\nUnsignedInt next_power_of_two(UnsignedInt n) noexcept\n{\n    static_assert(std::is_unsigned<UnsignedInt>::value, \"\");\n    // Assert overflow (if value is bigger than maximum power)\n    BOOST_ASSERT(!(n > (std::numeric_limits<UnsignedInt>::max() >> 1) + 1));\n    if (n == 0) return 1;\n    n--;\n    // Fill all lower bits\n    recursive_shift_or<1, UnsignedInt, (1 < sizeof(UnsignedInt) * 8)>::apply(n);\n    return n + 1;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/capabilities.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_CAPABILITIES_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_CAPABILITIES_HPP\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nenum class capabilities : std::uint32_t\n{\n    // CLIENT_LONG_PASSWORD: Use the improved version of Old Password Authentication\n    long_password = 1,\n\n    // CLIENT_FOUND_ROWS: Send found rows instead of affected rows in EOF_Packet\n    found_rows = 2,\n\n    // CLIENT_LONG_FLAG: Get all column flags\n    long_flag = 4,\n\n    // CLIENT_CONNECT_WITH_DB: Database (schema) name can be specified on connect in Handshake Response Packet\n    connect_with_db = 8,\n\n    // CLIENT_NO_SCHEMA: Don't allow database.table.column\n    no_schema = 16,\n\n    // CLIENT_COMPRESS: Compression protocol supported\n    compress = 32,\n\n    // CLIENT_ODBC: Special handling of ODBC behavior\n    odbc = 64,\n\n    // CLIENT_LOCAL_FILES: Can use LOAD DATA LOCAL\n    local_files = 128,\n\n    // CLIENT_IGNORE_SPACE: Ignore spaces before '('\n    ignore_space = 256,\n\n    // CLIENT_PROTOCOL_41: New 4.1 protocol\n    protocol_41 = 512,\n\n    // CLIENT_INTERACTIVE: This is an interactive client\n    interactive = 1024,\n\n    // CLIENT_SSL: Use SSL encryption for the session\n    ssl = 2048,\n\n    // CLIENT_IGNORE_SIGPIPE: Client only flag\n    ignore_sigpipe = 4096,\n\n    // CLIENT_TRANSACTIONS: Client knows about transactions\n    transactions = 8192,\n\n    // CLIENT_RESERVED: DEPRECATED: Old flag for 4.1 protocol\n    reserved = 16384,\n\n    // CLIENT_SECURE_CONNECTION: DEPRECATED: Old flag for 4.1 authentication, required by MariaDB\n    secure_connection = 32768,\n\n    // CLIENT_MULTI_STATEMENTS: Enable/disable multi-stmt support\n    multi_statements = (1UL << 16),\n\n    // CLIENT_MULTI_RESULTS: Enable/disable multi-results\n    multi_results = (1UL << 17),\n\n    // CLIENT_PS_MULTI_RESULTS: Multi-results and OUT parameters in PS-protocol\n    ps_multi_results = (1UL << 18),\n\n    // CLIENT_PLUGIN_AUTH: Client supports plugin authentication\n    plugin_auth = (1UL << 19),\n\n    // CLIENT_CONNECT_ATTRS: Client supports connection attributes\n    connect_attrs = (1UL << 20),\n\n    // CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: Enable authentication response packet to be larger than 255\n    // bytes\n    plugin_auth_lenenc_data = (1UL << 21),\n\n    // CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: Don't close the connection for a user account with expired\n    // password\n    can_handle_expired_passwords = (1UL << 22),\n\n    // CLIENT_SESSION_TRACK: Capable of handling server state change information\n    session_track = (1UL << 23),\n\n    // CLIENT_DEPRECATE_EOF: Client no longer needs EOF_Packet and will use OK_Packet instead\n    deprecate_eof = (1UL << 24),\n\n    // CLIENT_SSL_VERIFY_SERVER_CERT: Verify server certificate\n    ssl_verify_server_cert = (1UL << 30),\n\n    // CLIENT_OPTIONAL_RESULTSET_METADATA: The client can handle optional metadata information in the\n    // resultset\n    optional_resultset_metadata = (1UL << 25),\n\n    // CLIENT_REMEMBER_OPTIONS: Don't reset the options after an unsuccessful connect\n    remember_options = (1UL << 31),\n};\n\nconstexpr capabilities operator&(capabilities lhs, capabilities rhs)\n{\n    return static_cast<capabilities>(static_cast<std::uint32_t>(lhs) & static_cast<std::uint32_t>(rhs));\n}\n\nconstexpr capabilities operator|(capabilities lhs, capabilities rhs)\n{\n    return static_cast<capabilities>(static_cast<std::uint32_t>(lhs) | static_cast<std::uint32_t>(rhs));\n}\n\n// Are all capabilities in subset in caps?\nconstexpr bool has_capabilities(capabilities caps, capabilities subset) { return (caps & subset) == subset; }\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/db_flavor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DB_FLAVOR_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DB_FLAVOR_HPP\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nenum class db_flavor\n{\n    mysql,\n    mariadb\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/deserialization.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZATION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZATION_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/ok_view.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/error/server_error_to_string.hpp>\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/text_protocol.hpp>\n#include <boost/mysql/impl/internal/protocol/static_buffer.hpp>\n\n#include <boost/config.hpp>\n#include <boost/core/ignore_unused.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// OK packets (views because strings are non-owning)\ninline error_code deserialize_ok_packet(span<const std::uint8_t> msg, ok_view& output);  // for testing\n\n// Error packets (exposed for testing)\nstruct err_view\n{\n    std::uint16_t error_code;\n    string_view error_message;\n};\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_error_packet(\n    span<const std::uint8_t> message,\n    err_view& pack,\n    bool has_sql_state = true\n);\nBOOST_ATTRIBUTE_NODISCARD inline error_code process_error_packet(\n    span<const std::uint8_t> message,\n    db_flavor flavor,\n    diagnostics& diag,\n    bool has_sql_state = true\n);\n\n// Deserializes a response that may be an OK or an error packet.\n// Applicable for commands like ping and reset connection.\n// If the response is an OK packet, sets backslash_escapes according to the\n// OK packet's server status flags\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_ok_response(\n    span<const std::uint8_t> message,\n    db_flavor flavor,\n    diagnostics& diag,\n    bool& backslash_escapes\n);\n\n// Column definition\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_column_definition(\n    span<const std::uint8_t> input,\n    coldef_view& output\n);\n\n// Prepare statement response\nstruct prepare_stmt_response\n{\n    std::uint32_t id;\n    std::uint16_t num_columns;\n    std::uint16_t num_params;\n};\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_prepare_stmt_response_impl(\n    span<const std::uint8_t> message,\n    prepare_stmt_response& output\n);  // exposed for testing, doesn't take header into account\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_prepare_stmt_response(\n    span<const std::uint8_t> message,\n    db_flavor flavor,\n    prepare_stmt_response& output,\n    diagnostics& diag\n);\n\n// Execution messages\nstruct execute_response\n{\n    enum class type_t\n    {\n        num_fields,\n        ok_packet,\n        error\n    } type;\n    union data_t\n    {\n        std::size_t num_fields;\n        ok_view ok_pack;\n        error_code err;\n\n        data_t(size_t v) noexcept : num_fields(v) {}\n        data_t(const ok_view& v) noexcept : ok_pack(v) {}\n        data_t(error_code v) noexcept : err(v) {}\n    } data;\n\n    execute_response(std::size_t v) noexcept : type(type_t::num_fields), data(v) {}\n    execute_response(const ok_view& v) noexcept : type(type_t::ok_packet), data(v) {}\n    execute_response(error_code v) noexcept : type(type_t::error), data(v) {}\n};\ninline execute_response deserialize_execute_response(\n    span<const std::uint8_t> msg,\n    db_flavor flavor,\n    diagnostics& diag\n);\n\nstruct row_message\n{\n    enum class type_t\n    {\n        row,\n        ok_packet,\n        error\n    } type;\n    union data_t\n    {\n        span<const std::uint8_t> row;\n        ok_view ok_pack;\n        error_code err;\n\n        data_t(span<const std::uint8_t> row) noexcept : row(row) {}\n        data_t(const ok_view& ok_pack) noexcept : ok_pack(ok_pack) {}\n        data_t(error_code err) noexcept : err(err) {}\n    } data;\n\n    row_message(span<const std::uint8_t> row) noexcept : type(type_t::row), data(row) {}\n    row_message(const ok_view& ok_pack) noexcept : type(type_t::ok_packet), data(ok_pack) {}\n    row_message(error_code v) noexcept : type(type_t::error), data(v) {}\n};\ninline row_message deserialize_row_message(span<const std::uint8_t> msg, db_flavor flavor, diagnostics& diag);\n\ninline error_code deserialize_row(\n    resultset_encoding encoding,\n    span<const std::uint8_t> message,\n    metadata_collection_view meta,\n    span<field_view> output  // Should point to meta.size() field_view objects\n);\n\n// Server hello\nstruct server_hello\n{\n    using auth_buffer_type = static_buffer<8 + 0xff>;\n    db_flavor server;\n    std::uint32_t connection_id{};\n    auth_buffer_type auth_plugin_data;\n    capabilities server_capabilities{};\n    string_view auth_plugin_name;\n};\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_server_hello_impl(\n    span<const std::uint8_t> msg,\n    server_hello& output\n);  // exposed for testing, doesn't take message header into account\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_server_hello(\n    span<const std::uint8_t> msg,\n    server_hello& output,\n    diagnostics& diag\n);\n\n// Auth switch\nstruct auth_switch\n{\n    string_view plugin_name;\n    span<const std::uint8_t> auth_data;\n};\nBOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_auth_switch(\n    span<const std::uint8_t> msg,\n    auth_switch& output\n);  // exposed for testing\n\n// Handshake server response\nstruct handshake_server_response\n{\n    enum class type_t\n    {\n        ok,\n        error,\n        auth_switch,\n        auth_more_data\n    } type;\n\n    union data_t\n    {\n        ok_view ok;\n        error_code err;\n        auth_switch auth_sw;\n        span<const std::uint8_t> more_data;\n\n        data_t(const ok_view& ok) noexcept : ok(ok) {}\n        data_t(error_code err) noexcept : err(err) {}\n        data_t(auth_switch msg) noexcept : auth_sw(msg) {}\n        data_t(span<const std::uint8_t> more_data) noexcept : more_data(more_data) {}\n    } data;\n\n    handshake_server_response(const ok_view& ok) noexcept : type(type_t::ok), data(ok) {}\n    handshake_server_response(error_code err) noexcept : type(type_t::error), data(err) {}\n    handshake_server_response(auth_switch auth_switch) noexcept : type(type_t::auth_switch), data(auth_switch)\n    {\n    }\n    handshake_server_response(span<const std::uint8_t> more_data) noexcept\n        : type(type_t::auth_more_data), data(more_data)\n    {\n    }\n};\ninline handshake_server_response deserialize_handshake_server_response(\n    span<const std::uint8_t> buff,\n    db_flavor flavor,\n    diagnostics& diag\n);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n//\n// Implementations\n//\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Constants\nBOOST_INLINE_CONSTEXPR std::uint8_t error_packet_header = 0xff;\nBOOST_INLINE_CONSTEXPR std::uint8_t ok_packet_header = 0x00;\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n//\n// Deserialization\n//\n\n// OK packets\nboost::mysql::error_code boost::mysql::detail::deserialize_ok_packet(\n    span<const std::uint8_t> msg,\n    ok_view& output\n)\n{\n    struct ok_packet\n    {\n        // header: int<1>     header     0x00 or 0xFE the OK packet header\n        int_lenenc affected_rows;\n        int_lenenc last_insert_id;\n        int2 status_flags;  // server_status_flags\n        int2 warnings;\n        // CLIENT_SESSION_TRACK: not implemented\n        string_lenenc info;\n    } pack{};\n\n    deserialization_context ctx(msg);\n    auto err = ctx.deserialize(pack.affected_rows, pack.last_insert_id, pack.status_flags, pack.warnings);\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    if (ctx.enough_size(1))  // message is optional, may be omitted\n    {\n        err = pack.info.deserialize(ctx);\n        if (err != deserialize_errc::ok)\n            return to_error_code(err);\n    }\n\n    output = {\n        pack.affected_rows.value,\n        pack.last_insert_id.value,\n        pack.status_flags.value,\n        pack.warnings.value,\n        pack.info.value,\n    };\n\n    return ctx.check_extra_bytes();\n}\n\n// Error packets\nboost::mysql::error_code boost::mysql::detail::deserialize_error_packet(\n    span<const std::uint8_t> msg,\n    err_view& output,\n    bool has_sql_state\n)\n{\n    struct err_packet\n    {\n        // int1     header     0xFF ERR packet header\n        int2 error_code;\n        // if capabilities & CLIENT_PROTOCOL_41 {  (modeled here as has_sql_state)\n        string_fixed<1> sql_state_marker;\n        string_fixed<5> sql_state;\n        // }\n        string_eof error_message;\n    } pack{};\n\n    deserialization_context ctx(msg);\n    auto err = has_sql_state ? ctx.deserialize(\n                                   pack.error_code,\n                                   pack.sql_state_marker,\n                                   pack.sql_state,\n                                   pack.error_message\n                               )\n                             : ctx.deserialize(pack.error_code, pack.error_message);\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    output = err_view{\n        pack.error_code.value,\n        pack.error_message.value,\n    };\n\n    return ctx.check_extra_bytes();\n}\n\nboost::mysql::error_code boost::mysql::detail::process_error_packet(\n    span<const std::uint8_t> msg,\n    db_flavor flavor,\n    diagnostics& diag,\n    bool has_sql_state\n)\n{\n    err_view error_packet{};\n    auto err = deserialize_error_packet(msg, error_packet, has_sql_state);\n    if (err)\n        return err;\n\n    // Error message\n    access::get_impl(diag).assign_server(error_packet.error_message);\n\n    // Error code\n    if (common_error_to_string(error_packet.error_code))\n    {\n        // This is an error shared between MySQL and MariaDB, represented as a common_server_errc.\n        // get_common_error_message will check that the code has a common_server_errc representation\n        // (the common error range has \"holes\" because of removed error codes)\n        return static_cast<common_server_errc>(error_packet.error_code);\n    }\n    else\n    {\n        // This is a MySQL or MariaDB specific code. There is no fixed list of error codes,\n        // as they both keep adding more codes, so no validation happens.\n        const auto& cat = flavor == db_flavor::mysql ? get_mysql_server_category()\n                                                     : get_mariadb_server_category();\n        return error_code(error_packet.error_code, cat);\n    }\n}\n\n// Column definition\nboost::mysql::error_code boost::mysql::detail::deserialize_column_definition(\n    span<const std::uint8_t> input,\n    coldef_view& output\n)\n{\n    deserialization_context ctx(input);\n\n    struct column_definition_packet\n    {\n        string_lenenc catalog;    // always \"def\"\n        string_lenenc schema;     // database\n        string_lenenc table;      // virtual table\n        string_lenenc org_table;  // physical table\n        string_lenenc name;       // virtual column name\n        string_lenenc org_name;   // physical column name\n        string_lenenc fixed_fields;\n    } pack{};\n\n    // pack.fixed_fields itself is a structure like this.\n    // The proto allows for extensibility here - adding fields just increasing fixed_fields.length\n    struct fixed_fields_pack\n    {\n        int2 character_set;  // collation id, somehow named character_set in the protocol docs\n        int4 column_length;  // maximum length of the field\n        int1 type;      // type of the column as defined in enum_field_types - this is a protocol_field_type\n        int2 flags;     // Flags as defined in Column Definition Flags\n        int1 decimals;  // max shown decimal digits. 0x00 for int/static strings; 0x1f for\n                        // dynamic strings, double, float\n    } fixed_fields{};\n\n    // Deserialize the main structure\n    auto err = ctx.deserialize(\n        pack.catalog,\n        pack.schema,\n        pack.table,\n        pack.org_table,\n        pack.name,\n        pack.org_name,\n        pack.fixed_fields\n    );\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    // Deserialize the fixed_fields structure.\n    // Intentionally not checking for extra bytes here, since there may be unknown fields that should just get\n    // ignored\n    deserialization_context subctx(to_span(pack.fixed_fields.value));\n    err = subctx.deserialize(\n        fixed_fields.character_set,\n        fixed_fields.column_length,\n        fixed_fields.type,\n        fixed_fields.flags,\n        fixed_fields.decimals\n    );\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    // Compose output\n    output = coldef_view{\n        pack.schema.value,\n        pack.table.value,\n        pack.org_table.value,\n        pack.name.value,\n        pack.org_name.value,\n        fixed_fields.character_set.value,\n        fixed_fields.column_length.value,\n        compute_column_type(\n            static_cast<protocol_field_type>(fixed_fields.type.value),\n            fixed_fields.flags.value,\n            fixed_fields.character_set.value\n        ),\n        fixed_fields.flags.value,\n        fixed_fields.decimals.value,\n    };\n\n    return ctx.check_extra_bytes();\n}\n\nboost::mysql::error_code boost::mysql::detail::deserialize_ok_response(\n    span<const std::uint8_t> message,\n    db_flavor flavor,\n    diagnostics& diag,\n    bool& backslash_escapes\n)\n{\n    // Header\n    int1 header{};\n    deserialization_context ctx(message);\n    auto err = to_error_code(header.deserialize(ctx));\n    if (err)\n        return err;\n\n    if (header.value == ok_packet_header)\n    {\n        // Verify that the ok_packet is correct\n        ok_view ok{};\n        err = deserialize_ok_packet(ctx.to_span(), ok);\n        if (err)\n            return err;\n        backslash_escapes = ok.backslash_escapes();\n        return error_code();\n    }\n    else if (header.value == error_packet_header)\n    {\n        // Theoretically, the server can answer with an error packet, too\n        return process_error_packet(ctx.to_span(), flavor, diag);\n    }\n    else\n    {\n        // Invalid message\n        return client_errc::protocol_value_error;\n    }\n}\n\nboost::mysql::error_code boost::mysql::detail::deserialize_prepare_stmt_response_impl(\n    span<const std::uint8_t> message,\n    prepare_stmt_response& output\n)\n{\n    struct com_stmt_prepare_ok_packet\n    {\n        // std::uint8_t status: must be 0\n        int4 statement_id;\n        int2 num_columns;\n        int2 num_params;\n        int1 reserved_1;  // must be 0\n        int2 warning_count;\n        // int1 metadata_follows when CLIENT_OPTIONAL_RESULTSET_METADATA: not implemented\n    } pack{};\n\n    deserialization_context ctx(message);\n\n    auto err = ctx.deserialize(\n        pack.statement_id,\n        pack.num_columns,\n        pack.num_params,\n        pack.reserved_1,\n        pack.warning_count\n    );\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    output = prepare_stmt_response{\n        pack.statement_id.value,\n        pack.num_columns.value,\n        pack.num_params.value,\n    };\n\n    return ctx.check_extra_bytes();\n}\n\nboost::mysql::error_code boost::mysql::detail::deserialize_prepare_stmt_response(\n    span<const std::uint8_t> message,\n    db_flavor flavor,\n    prepare_stmt_response& output,\n    diagnostics& diag\n)\n{\n    deserialization_context ctx(message);\n    int1 msg_type{};\n    auto err = to_error_code(msg_type.deserialize(ctx));\n    if (err)\n        return err;\n\n    if (msg_type.value == error_packet_header)\n    {\n        return process_error_packet(ctx.to_span(), flavor, diag);\n    }\n    else if (msg_type.value != 0)\n    {\n        return client_errc::protocol_value_error;\n    }\n    else\n    {\n        return deserialize_prepare_stmt_response_impl(ctx.to_span(), output);\n    }\n}\n\n// execute response\nboost::mysql::detail::execute_response boost::mysql::detail::deserialize_execute_response(\n    span<const std::uint8_t> msg,\n    db_flavor flavor,\n    diagnostics& diag\n)\n{\n    // Response may be: ok_packet, err_packet, local infile request (not implemented)\n    // If it is none of this, then the message type itself is the beginning of\n    // a length-encoded int containing the field count\n    deserialization_context ctx(msg);\n    int1 msg_type{};\n    auto err = to_error_code(msg_type.deserialize(ctx));\n    if (err)\n        return err;\n\n    if (msg_type.value == ok_packet_header)\n    {\n        ok_view ok{};\n        err = deserialize_ok_packet(ctx.to_span(), ok);\n        if (err)\n            return err;\n        return ok;\n    }\n    else if (msg_type.value == error_packet_header)\n    {\n        return process_error_packet(ctx.to_span(), flavor, diag);\n    }\n    else\n    {\n        // Resultset with metadata. First packet is an int_lenenc with\n        // the number of field definitions to expect. Message type is part\n        // of this packet, so we must rewind the context\n        ctx.rewind(1);\n        int_lenenc num_fields{};\n        err = to_error_code(num_fields.deserialize(ctx));\n        if (err)\n            return err;\n        err = ctx.check_extra_bytes();\n        if (err)\n            return err;\n\n        // We should have at least one field.\n        // The max number of fields is some value around 1024. For simplicity/extensibility,\n        // we accept anything less than 0xffff\n        if (num_fields.value == 0 || num_fields.value > 0xffffu)\n        {\n            return make_error_code(client_errc::protocol_value_error);\n        }\n\n        return static_cast<std::size_t>(num_fields.value);\n    }\n}\n\nboost::mysql::detail::row_message boost::mysql::detail::deserialize_row_message(\n    span<const std::uint8_t> msg,\n    db_flavor flavor,\n    diagnostics& diag\n)\n{\n    constexpr std::uint8_t eof_packet_header = 0xfe;\n\n    // Message type: row, error or eof?\n    int1 msg_type{};\n    deserialization_context ctx(msg);\n    auto deser_errc = msg_type.deserialize(ctx);\n    if (deser_errc != deserialize_errc::ok)\n    {\n        return to_error_code(deser_errc);\n    }\n\n    if (msg_type.value == eof_packet_header)\n    {\n        // end of resultset => this is a ok_packet, not a row\n        ok_view ok{};\n        auto err = deserialize_ok_packet(ctx.to_span(), ok);\n        if (err)\n            return err;\n        return ok;\n    }\n    else if (msg_type.value == error_packet_header)\n    {\n        // An error occurred during the generation of the rows\n        return process_error_packet(ctx.to_span(), flavor, diag);\n    }\n    else\n    {\n        // An actual row\n        ctx.rewind(1);  // keep the 'message type' byte, as it is part of the actual message\n        return span<const std::uint8_t>(ctx.first(), ctx.size());\n    }\n}\n\n// Deserialize row\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline bool is_next_field_null(const deserialization_context& ctx)\n{\n    if (!ctx.enough_size(1))\n        return false;\n    return *ctx.first() == 0xfb;\n}\n\ninline error_code deserialize_text_row(\n    deserialization_context& ctx,\n    metadata_collection_view meta,\n    field_view* output\n)\n{\n    for (std::vector<field_view>::size_type i = 0; i < meta.size(); ++i)\n    {\n        if (is_next_field_null(ctx))\n        {\n            ctx.advance(1);\n            output[i] = field_view(nullptr);\n        }\n        else\n        {\n            string_lenenc value_str;\n            auto err = value_str.deserialize(ctx);\n            if (err != deserialize_errc::ok)\n                return to_error_code(err);\n            err = deserialize_text_field(value_str.value, meta[i], output[i]);\n            if (err != deserialize_errc::ok)\n                return to_error_code(err);\n        }\n    }\n    return ctx.check_extra_bytes();\n}\n\ninline error_code deserialize_binary_row(\n    deserialization_context& ctx,\n    metadata_collection_view meta,\n    field_view* output\n)\n{\n    // Skip packet header (it is not part of the message in the binary\n    // protocol but it is in the text protocol, so we include it for homogeneity)\n    if (!ctx.enough_size(1))\n        return client_errc::incomplete_message;\n    ctx.advance(1);\n\n    // Number of fields\n    std::size_t num_fields = meta.size();\n\n    // Null bitmap\n    null_bitmap_parser null_bitmap(num_fields);\n    const std::uint8_t* null_bitmap_first = ctx.first();\n    std::size_t null_bitmap_size = null_bitmap.byte_count();\n    if (!ctx.enough_size(null_bitmap_size))\n        return client_errc::incomplete_message;\n    ctx.advance(null_bitmap_size);\n\n    // Actual values\n    for (std::vector<field_view>::size_type i = 0; i < num_fields; ++i)\n    {\n        if (null_bitmap.is_null(null_bitmap_first, i))\n        {\n            output[i] = field_view(nullptr);\n        }\n        else\n        {\n            auto err = deserialize_binary_field(ctx, meta[i], output[i]);\n            if (err != deserialize_errc::ok)\n                return to_error_code(err);\n        }\n    }\n\n    // Check for remaining bytes\n    return ctx.check_extra_bytes();\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::error_code boost::mysql::detail::deserialize_row(\n    resultset_encoding encoding,\n    span<const std::uint8_t> buff,\n    metadata_collection_view meta,\n    span<field_view> output\n)\n{\n    BOOST_ASSERT(meta.size() == output.size());\n    deserialization_context ctx(buff);\n    return encoding == detail::resultset_encoding::text ? deserialize_text_row(ctx, meta, output.data())\n                                                        : deserialize_binary_row(ctx, meta, output.data());\n}\n\n// Server hello\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline capabilities compose_capabilities(string_fixed<2> low, string_fixed<2> high)\n{\n    std::uint32_t res = 0;\n    auto capabilities_begin = reinterpret_cast<std::uint8_t*>(&res);\n    memcpy(capabilities_begin, low.value.data(), 2);\n    memcpy(capabilities_begin + 2, high.value.data(), 2);\n    return static_cast<capabilities>(boost::endian::little_to_native(res));\n}\n\ninline db_flavor parse_db_version(string_view version_string)\n{\n    return version_string.find(\"MariaDB\") != string_view::npos ? db_flavor::mariadb : db_flavor::mysql;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::error_code boost::mysql::detail::deserialize_server_hello_impl(\n    span<const std::uint8_t> msg,\n    server_hello& output\n)\n{\n    struct server_hello_packet\n    {\n        // int<1>     protocol version     Always 10\n        string_null server_version;\n        int4 connection_id;\n        string_fixed<8> auth_plugin_data_part_1;\n        int1 filler;  // should be 0\n        string_fixed<2> capability_flags_low;\n        int1 character_set;  // default server a_protocol_character_set, only the lower 8-bits\n        int2 status_flags;   // server_status_flags\n        string_fixed<2> capability_flags_high;\n        int1 auth_plugin_data_len;\n        string_fixed<10> reserved;\n        // auth plugin data, 2nd part. This has a weird representation that doesn't fit any defined type\n        string_null auth_plugin_name;\n    } pack{};\n\n    deserialization_context ctx(msg);\n\n    auto err = ctx.deserialize(\n        pack.server_version,\n        pack.connection_id,\n        pack.auth_plugin_data_part_1,\n        pack.filler,\n        pack.capability_flags_low,\n        pack.character_set,\n        pack.status_flags,\n        pack.capability_flags_high\n    );\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    // Compose capabilities\n    auto cap = compose_capabilities(pack.capability_flags_low, pack.capability_flags_high);\n\n    // Check minimum server capabilities to deserialize this frame\n    if (!has_capabilities(cap, capabilities::plugin_auth))\n        return client_errc::server_unsupported;\n\n    // Deserialize next fields\n    err = ctx.deserialize(pack.auth_plugin_data_len, pack.reserved);\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    // Auth plugin data, second part\n    auto auth2_length = static_cast<std::uint8_t>((std::max)(\n        static_cast<std::size_t>(13u),\n        static_cast<std::size_t>(pack.auth_plugin_data_len.value - pack.auth_plugin_data_part_1.value.size())\n    ));\n    const std::uint8_t* auth2_data = ctx.first();\n    if (!ctx.enough_size(auth2_length))\n        return client_errc::incomplete_message;\n    ctx.advance(auth2_length);\n\n    // Auth plugin name\n    err = pack.auth_plugin_name.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    // Compose output\n    output.connection_id = pack.connection_id.value;\n    output.server = parse_db_version(pack.server_version.value);\n    output.server_capabilities = cap;\n    output.auth_plugin_name = pack.auth_plugin_name.value;\n\n    // Compose auth_plugin_data\n    output.auth_plugin_data.clear();\n    output.auth_plugin_data.append(span<const std::uint8_t>(\n        reinterpret_cast<const std::uint8_t*>(pack.auth_plugin_data_part_1.value.data()),\n        pack.auth_plugin_data_part_1.value.size()\n    ));\n\n    // discard an extra trailing NULL byte\n    output.auth_plugin_data.append(span<const std::uint8_t>(auth2_data, auth2_length - 1));\n\n    return ctx.check_extra_bytes();\n}\n\nboost::mysql::error_code boost::mysql::detail::deserialize_server_hello(\n    span<const std::uint8_t> msg,\n    server_hello& output,\n    diagnostics& diag\n)\n{\n    constexpr std::uint8_t handshake_protocol_version_9 = 9;\n    constexpr std::uint8_t handshake_protocol_version_10 = 10;\n\n    deserialization_context ctx(msg);\n\n    // Message type\n    int1 msg_type{};\n    auto err = to_error_code(msg_type.deserialize(ctx));\n    if (err)\n        return err;\n    if (msg_type.value == handshake_protocol_version_9)\n    {\n        return make_error_code(client_errc::server_unsupported);\n    }\n    else if (msg_type.value == error_packet_header)\n    {\n        // We don't know which DB is yet. The server has no knowledge of our capabilities\n        // yet, so it will assume we don't support the 4.1 protocol and send an error\n        // packet without SQL state\n        return process_error_packet(ctx.to_span(), db_flavor::mysql, diag, false);\n    }\n    else if (msg_type.value != handshake_protocol_version_10)\n    {\n        return make_error_code(client_errc::protocol_value_error);\n    }\n    else\n    {\n        return deserialize_server_hello_impl(ctx.to_span(), output);\n    }\n}\n\n// auth_switch\nBOOST_ATTRIBUTE_NODISCARD\nboost::mysql::error_code boost::mysql::detail::deserialize_auth_switch(\n    span<const std::uint8_t> msg,\n    auth_switch& output\n)\n{\n    struct auth_switch_request_packet\n    {\n        string_null plugin_name;\n        string_eof auth_plugin_data;\n    } pack{};\n\n    deserialization_context ctx(msg);\n\n    auto err = ctx.deserialize(pack.plugin_name, pack.auth_plugin_data);\n    if (err != deserialize_errc::ok)\n        return to_error_code(err);\n\n    // Discard an additional NULL at the end of auth data\n    string_view auth_data = pack.auth_plugin_data.value;\n    if (!auth_data.empty() && auth_data.back() == 0)\n    {\n        auth_data = auth_data.substr(0, auth_data.size() - 1);\n    }\n\n    output = {\n        pack.plugin_name.value,\n        to_span(auth_data),\n    };\n\n    return ctx.check_extra_bytes();\n}\n\nboost::mysql::detail::handshake_server_response boost::mysql::detail::deserialize_handshake_server_response(\n    span<const std::uint8_t> buff,\n    db_flavor flavor,\n    diagnostics& diag\n)\n{\n    constexpr std::uint8_t auth_switch_request_header = 0xfe;\n    constexpr std::uint8_t auth_more_data_header = 0x01;\n\n    deserialization_context ctx(buff);\n    int1 msg_type{};\n    auto err = to_error_code(msg_type.deserialize(ctx));\n    if (err)\n        return err;\n\n    if (msg_type.value == ok_packet_header)\n    {\n        ok_view ok{};\n        err = deserialize_ok_packet(ctx.to_span(), ok);\n        if (err)\n            return err;\n        return ok;\n    }\n    else if (msg_type.value == error_packet_header)\n    {\n        return process_error_packet(ctx.to_span(), flavor, diag);\n    }\n    else if (msg_type.value == auth_switch_request_header)\n    {\n        // We have received an auth switch request. Deserialize it\n        auth_switch auth_sw{};\n        err = deserialize_auth_switch(ctx.to_span(), auth_sw);\n        if (err)\n            return err;\n        return auth_sw;\n    }\n    else if (msg_type.value == auth_more_data_header)\n    {\n        // We have received an auth more data request. Deserialize it.\n        // Note that string_eof never fails deserialization (by definition)\n        string_eof auth_more_data;\n        auto ec = auth_more_data.deserialize(ctx);\n        BOOST_ASSERT(ec == deserialize_errc::ok);\n        boost::ignore_unused(ec);\n        return handshake_server_response(to_span(auth_more_data.value));\n    }\n    else\n    {\n        // Unknown message type\n        return make_error_code(client_errc::protocol_value_error);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/frame_header.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_FRAME_HEADER_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_FRAME_HEADER_HPP\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n#include <boost/endian/conversion.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nBOOST_INLINE_CONSTEXPR std::size_t max_packet_size = 0xffffff;\nBOOST_INLINE_CONSTEXPR std::size_t frame_header_size = 4;\n\nstruct frame_header\n{\n    std::uint32_t size;\n    std::uint8_t sequence_number;\n};\n\ninline void serialize_frame_header(span<std::uint8_t, frame_header_size> to, frame_header header)\n{\n    BOOST_ASSERT(header.size <= 0xffffff);\n    endian::store_little_u24(to.data(), header.size);\n    to[3] = header.sequence_number;\n}\n\ninline frame_header deserialize_frame_header(span<const std::uint8_t, frame_header_size> buffer)\n{\n    return {endian::load_little_u24(buffer.data()), buffer[3]};\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_BINARY_PROTOCOL_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_BINARY_PROTOCOL_HPP\n\n#include <boost/mysql/days.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n\n#include <boost/mysql/detail/datetime.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/bit_deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n\n#include <array>\n#include <chrono>\n#include <cmath>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline deserialize_errc deserialize_binary_field(\n    deserialization_context& ctx,\n    const metadata& meta,\n    field_view& output\n);\n\ninline void serialize_binary_field(serialization_context& ctx, field_view input);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n//\n// Implementation\n//\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// constants\nnamespace binc {\n\nBOOST_INLINE_CONSTEXPR std::size_t year_sz = 2;\nBOOST_INLINE_CONSTEXPR std::size_t month_sz = 1;\nBOOST_INLINE_CONSTEXPR std::size_t date_day_sz = 1;\nBOOST_INLINE_CONSTEXPR std::size_t time_days_sz = 4;\nBOOST_INLINE_CONSTEXPR std::size_t hours_sz = 1;\nBOOST_INLINE_CONSTEXPR std::size_t mins_sz = 1;\nBOOST_INLINE_CONSTEXPR std::size_t secs_sz = 1;\nBOOST_INLINE_CONSTEXPR std::size_t micros_sz = 4;\nBOOST_INLINE_CONSTEXPR std::size_t time_sign_sz = 1;\n\nBOOST_INLINE_CONSTEXPR std::size_t date_sz = year_sz + month_sz + date_day_sz;  // does not include length\n\nBOOST_INLINE_CONSTEXPR std::size_t datetime_d_sz = date_sz;\nBOOST_INLINE_CONSTEXPR std::size_t datetime_dhms_sz = datetime_d_sz + hours_sz + mins_sz + secs_sz;\nBOOST_INLINE_CONSTEXPR std::size_t datetime_dhmsu_sz = datetime_dhms_sz + micros_sz;\n\nBOOST_INLINE_CONSTEXPR std::size_t time_dhms_sz = time_sign_sz + time_days_sz + hours_sz + mins_sz + secs_sz;\nBOOST_INLINE_CONSTEXPR std::size_t time_dhmsu_sz = time_dhms_sz + micros_sz;\n\n}  // namespace binc\n\n//\n// Deserialization\n//\n\n// strings\ninline deserialize_errc deserialize_binary_field_string(\n    deserialization_context& ctx,\n    field_view& output,\n    bool is_blob\n)\n{\n    string_lenenc deser;\n    auto err = deser.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return err;\n    if (is_blob)\n    {\n        output = field_view(to_span(deser.value));\n    }\n    else\n    {\n        output = field_view(deser.value);\n    }\n    return deserialize_errc::ok;\n}\n\n// ints\ntemplate <class TargetType, class DeserializableType>\ninline deserialize_errc deserialize_binary_field_int_impl(deserialization_context& ctx, field_view& output)\n{\n    int_holder<DeserializableType> deser;\n    auto err = deser.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return err;\n    output = field_view(static_cast<TargetType>(deser.value));\n    return deserialize_errc::ok;\n}\n\ntemplate <class DeserializableTypeUnsigned, class DeserializableTypeSigned>\ninline deserialize_errc deserialize_binary_field_int(\n    const metadata& meta,\n    deserialization_context& ctx,\n    field_view& output\n)\n{\n    return meta.is_unsigned()\n               ? deserialize_binary_field_int_impl<std::uint64_t, DeserializableTypeUnsigned>(ctx, output)\n               : deserialize_binary_field_int_impl<std::int64_t, DeserializableTypeSigned>(ctx, output);\n}\n\n// Bits. These come as a binary value between 1 and 8 bytes,\n// packed in a string\ninline deserialize_errc deserialize_binary_field_bit(deserialization_context& ctx, field_view& output)\n{\n    string_lenenc buffer;\n    auto err = buffer.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return err;\n    return deserialize_bit(buffer.value, output);\n}\n\n// Floats\ntemplate <class T>\ninline deserialize_errc deserialize_binary_field_float(deserialization_context& ctx, field_view& output)\n{\n    // Size check\n    if (!ctx.enough_size(sizeof(T)))\n        return deserialize_errc::incomplete_message;\n\n    // Endianness conversion\n    T v = endian::endian_load<T, sizeof(T), endian::order::little>(ctx.first());\n\n    // Nans and infs not allowed in SQL\n    if (std::isnan(v) || std::isinf(v))\n        return deserialize_errc::protocol_value_error;\n\n    // Done\n    ctx.advance(sizeof(T));\n    output = field_view(v);\n    return deserialize_errc::ok;\n}\n\n// Time types\ninline deserialize_errc deserialize_binary_ymd(deserialization_context& ctx, date& output)\n{\n    using namespace boost::mysql::detail;\n\n    int2 year{};\n    int1 month{};\n    int1 day{};\n\n    // Deserialize\n    auto err = ctx.deserialize(year, month, day);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Range check\n    if (year.value > max_year || month.value > max_month || day.value > max_day)\n    {\n        return deserialize_errc::protocol_value_error;\n    }\n\n    output = date(year.value, month.value, day.value);\n\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_binary_field_date(deserialization_context& ctx, field_view& output)\n{\n    using namespace boost::mysql::detail::binc;\n\n    // Deserialize length\n    int1 length;\n    auto err = length.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Check for zero dates\n    if (length.value < date_sz)\n    {\n        output = field_view(date());\n        return deserialize_errc::ok;\n    }\n\n    // Deserialize rest of fields\n    date d;\n    err = deserialize_binary_ymd(ctx, d);\n    if (err != deserialize_errc::ok)\n        return err;\n    output = field_view(d);\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_binary_field_datetime(deserialization_context& ctx, field_view& output)\n{\n    using namespace binc;\n\n    // Deserialize length\n    int1 length{};\n    auto err = length.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // If the DATETIME does not contain some of the values below,\n    // they are supposed to be zero\n    date d{};\n    int1 hours{};\n    int1 minutes{};\n    int1 seconds{};\n    int4 micros{};\n\n    // Date part\n    if (length.value >= datetime_d_sz)\n    {\n        err = deserialize_binary_ymd(ctx, d);\n        if (err != deserialize_errc::ok)\n            return err;\n    }\n\n    // Hours, minutes, seconds\n    if (length.value >= datetime_dhms_sz)\n    {\n        err = ctx.deserialize(hours, minutes, seconds);\n        if (err != deserialize_errc::ok)\n            return err;\n    }\n\n    // Microseconds\n    if (length.value >= datetime_dhmsu_sz)\n    {\n        err = micros.deserialize(ctx);\n        if (err != deserialize_errc::ok)\n            return err;\n    }\n\n    // Validity check. deserialize_binary_ymd already does it for date\n    if (hours.value > max_hour || minutes.value > max_min || seconds.value > max_sec ||\n        micros.value > max_micro)\n    {\n        return deserialize_errc::protocol_value_error;\n    }\n\n    // Compose the final datetime\n    datetime dt(d.year(), d.month(), d.day(), hours.value, minutes.value, seconds.value, micros.value);\n    output = field_view(dt);\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_binary_field_time(deserialization_context& ctx, field_view& output)\n{\n    using namespace boost::mysql::detail;\n    using namespace boost::mysql::detail::binc;\n\n    // Deserialize length\n    int1 length{};\n    auto err = length.deserialize(ctx);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // If the TIME contains no value for these fields, they are zero\n    int1 is_negative{};\n    int4 num_days{};\n    int1 hours{};\n    int1 minutes{};\n    int1 seconds{};\n    int4 microseconds{};\n\n    // Sign, days, hours, minutes, seconds\n    if (length.value >= time_dhms_sz)\n    {\n        err = ctx.deserialize(is_negative, num_days, hours, minutes, seconds);\n        if (err != deserialize_errc::ok)\n            return err;\n    }\n\n    // Microseconds\n    if (length.value >= time_dhmsu_sz)\n    {\n        err = microseconds.deserialize(ctx);\n        if (err != deserialize_errc::ok)\n            return err;\n    }\n\n    // Range check\n    constexpr std::size_t time_max_days = 34;  // equivalent to the 839 hours, in the broken format\n    if (num_days.value > time_max_days || hours.value > max_hour || minutes.value > max_min ||\n        seconds.value > max_sec || microseconds.value > max_micro)\n    {\n        return deserialize_errc::protocol_value_error;\n    }\n\n    // Compose the final time\n    output = field_view(boost::mysql::time(\n        (is_negative.value ? -1 : 1) *\n        (days(num_days.value) + std::chrono::hours(hours.value) + std::chrono::minutes(minutes.value) +\n         std::chrono::seconds(seconds.value) + std::chrono::microseconds(microseconds.value))\n    ));\n    return deserialize_errc::ok;\n}\n\n//\n// Serialization\n//\ntemplate <class T>\ninline void serialize_binary_float(serialization_context& ctx, T input)\n{\n    std::array<std::uint8_t, sizeof(T)> buffer{};\n    boost::endian::endian_store<T, sizeof(T), boost::endian::order::little>(buffer.data(), input);\n    ctx.add(buffer);\n}\n\ninline void serialize_binary_date(serialization_context& ctx, const date& input)\n{\n    ctx.serialize_fixed(\n        int1{static_cast<std::uint8_t>(binc::date_sz)},\n        int2{input.year()},\n        int1{input.month()},\n        int1{input.day()}\n    );\n}\n\ninline void serialize_binary_datetime(serialization_context& ctx, const datetime& input)\n{\n    ctx.serialize_fixed(\n        int1{static_cast<std::uint8_t>(binc::datetime_dhmsu_sz)},\n        int2{input.year()},\n        int1{input.month()},\n        int1{input.day()},\n        int1{input.hour()},\n        int1{input.minute()},\n        int1{input.second()},\n        int4{input.microsecond()}\n    );\n}\n\ninline void serialize_binary_time(serialization_context& ctx, const boost::mysql::time& input)\n{\n    using namespace binc;\n    using boost::mysql::days;\n    using std::chrono::duration_cast;\n    using std::chrono::hours;\n    using std::chrono::microseconds;\n    using std::chrono::minutes;\n    using std::chrono::seconds;\n\n    // Break time\n    auto num_micros = duration_cast<microseconds>(input % seconds(1));\n    auto num_secs = duration_cast<seconds>(input % minutes(1) - num_micros);\n    auto num_mins = duration_cast<minutes>(input % hours(1) - num_secs);\n    auto num_hours = duration_cast<hours>(input % days(1) - num_mins);\n    auto num_days = duration_cast<days>(input - num_hours);\n    auto is_negative = (input.count() < 0) ? 1 : 0;\n\n    // Serialize\n    ctx.serialize_fixed(\n        int1{static_cast<std::uint8_t>(time_dhmsu_sz)},\n        int1{static_cast<std::uint8_t>(is_negative)},\n        int4{static_cast<std::uint32_t>(std::abs(num_days.count()))},\n        int1{static_cast<std::uint8_t>(std::abs(num_hours.count()))},\n        int1{static_cast<std::uint8_t>(std::abs(num_mins.count()))},\n        int1{static_cast<std::uint8_t>(std::abs(num_secs.count()))},\n        int4{static_cast<std::uint32_t>(std::abs(num_micros.count()))}\n    );\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::detail::deserialize_errc boost::mysql::detail::deserialize_binary_field(\n    deserialization_context& ctx,\n    const metadata& meta,\n    field_view& output\n)\n{\n    switch (meta.type())\n    {\n    case column_type::tinyint:\n        return deserialize_binary_field_int<std::uint8_t, std::int8_t>(meta, ctx, output);\n    case column_type::smallint:\n    case column_type::year:\n        return deserialize_binary_field_int<std::uint16_t, std::int16_t>(meta, ctx, output);\n    case column_type::mediumint:\n    case column_type::int_:\n        return deserialize_binary_field_int<std::uint32_t, std::int32_t>(meta, ctx, output);\n    case column_type::bigint:\n        return deserialize_binary_field_int<std::uint64_t, std::int64_t>(meta, ctx, output);\n    case column_type::bit: return deserialize_binary_field_bit(ctx, output);\n    case column_type::float_: return deserialize_binary_field_float<float>(ctx, output);\n    case column_type::double_: return deserialize_binary_field_float<double>(ctx, output);\n    case column_type::timestamp:\n    case column_type::datetime: return deserialize_binary_field_datetime(ctx, output);\n    case column_type::date: return deserialize_binary_field_date(ctx, output);\n    case column_type::time: return deserialize_binary_field_time(ctx, output);\n    // True string types\n    case column_type::char_:\n    case column_type::varchar:\n    case column_type::text:\n    case column_type::enum_:\n    case column_type::set:\n    case column_type::decimal:\n    case column_type::json: return deserialize_binary_field_string(ctx, output, false);\n    // Blobs and anything else\n    case column_type::binary:\n    case column_type::varbinary:\n    case column_type::blob:\n    case column_type::geometry:\n    default: return deserialize_binary_field_string(ctx, output, true);\n    }\n}\n\nvoid boost::mysql::detail::serialize_binary_field(serialization_context& ctx, field_view input)\n{\n    switch (input.kind())\n    {\n    case field_kind::null: break;\n    case field_kind::int64: sint8{input.get_int64()}.serialize(ctx); break;\n    case field_kind::uint64: int8{input.get_uint64()}.serialize(ctx); break;\n    case field_kind::string: string_lenenc{input.get_string()}.serialize(ctx); break;\n    case field_kind::blob: string_lenenc{to_string(input.get_blob())}.serialize(ctx); break;\n    case field_kind::float_: serialize_binary_float(ctx, input.get_float()); break;\n    case field_kind::double_: serialize_binary_float(ctx, input.get_double()); break;\n    case field_kind::date: serialize_binary_date(ctx, input.get_date()); break;\n    case field_kind::datetime: serialize_binary_datetime(ctx, input.get_datetime()); break;\n    case field_kind::time: serialize_binary_time(ctx, input.get_time()); break;\n    default: BOOST_ASSERT(false); break;  // LCOV_EXCL_LINE\n    }\n}\n\n#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP_ */\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/bit_deserialization.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_BIT_DESERIALIZATION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_BIT_DESERIALIZATION_HPP\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n\n#include <boost/endian/conversion.hpp>\n\n#include <cstring>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// All BIT values come as binary values between 1 and 8 bytes length packed in string_lenenc's,\n// for both the text and the binary protocols. As the text protocol already unpacks the\n// string_lenenc layer, this function is in charge of just parsing the binary payload. The length of\n// the BIT value depends on how the type was defined in the table (e.g. BIT(14) will send a 2 byte\n// value; BIT(54) will send a 7 byte one). Values are sent as big-endian.\ninline deserialize_errc deserialize_bit(string_view from, field_view& to)\n{\n    std::size_t num_bytes = from.size();\n    if (num_bytes < 1 || num_bytes > 8)\n    {\n        return deserialize_errc::protocol_value_error;\n    }\n    unsigned char temp[8]{};\n    unsigned char* dest = temp + sizeof(temp) - num_bytes;\n    std::memcpy(dest, from.data(), num_bytes);\n    to = field_view(endian::load_big_u64(temp));\n    return deserialize_errc::ok;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_DESERIALIZATION_CONTEXT_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_DESERIALIZATION_CONTEXT_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// We operate with this enum directly in the deserialization routines for efficiency, then transform it to an\n// actual error code\nenum class deserialize_errc\n{\n    ok = 0,\n    incomplete_message = 1,\n    protocol_value_error,\n    server_unsupported\n};\n\ninline error_code to_error_code(deserialize_errc v)\n{\n    switch (v)\n    {\n    case deserialize_errc::ok: return error_code();\n    case deserialize_errc::incomplete_message: return error_code(client_errc::incomplete_message);\n    case deserialize_errc::protocol_value_error: return error_code(client_errc::protocol_value_error);\n    case deserialize_errc::server_unsupported: return error_code(client_errc::server_unsupported);\n    default: BOOST_ASSERT(false); return error_code();  // LCOV_EXCL_LINE\n    }\n}\n\nclass deserialization_context\n{\n    const std::uint8_t* first_;\n    const std::uint8_t* last_;\n\npublic:\n    explicit deserialization_context(span<const std::uint8_t> data) noexcept\n        : first_(data.data()), last_(first_ + data.size())\n    {\n    }\n    const std::uint8_t* first() const { return first_; }\n    const std::uint8_t* last() const { return last_; }\n    std::size_t size() const { return last_ - first_; }\n    void advance(std::size_t sz)\n    {\n        first_ += sz;\n        BOOST_ASSERT(last_ >= first_);\n    }\n    void rewind(std::size_t sz) { first_ -= sz; }\n    bool enough_size(std::size_t required_size) const { return size() >= required_size; }\n    string_view get_string(std::size_t sz) const\n    {\n        return string_view(reinterpret_cast<const char*>(first_), sz);\n    }\n    error_code check_extra_bytes() const\n    {\n        return last_ == first_ ? error_code() : error_code(client_errc::extra_bytes);\n    }\n\n    span<const std::uint8_t> to_span() const { return span<const std::uint8_t>(first_, last_); }\n\n    deserialize_errc deserialize() { return deserialize_errc::ok; }\n\n    template <class Deserializable1, class... Deserializable2>\n    deserialize_errc deserialize(Deserializable1& value1, Deserializable2&... args)\n    {\n        deserialize_errc err = value1.deserialize(*this);\n        if (err == deserialize_errc::ok)\n        {\n            err = deserialize(args...);\n        }\n        return err;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_NULL_BITMAP_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_NULL_BITMAP_HPP\n\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n\n#include <algorithm>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// When parsing binary rows, we need to add this offset to\n// field positions to get the actual field index to use -\n// the first two positions are reserved\nBOOST_INLINE_CONSTEXPR std::size_t binary_row_null_bitmap_offset = 2;\n\n// Helper to parse the null bitmap contained in binary rows\nclass null_bitmap_parser\n{\n    std::size_t num_fields_;\n\npublic:\n    constexpr null_bitmap_parser(std::size_t num_fields) noexcept : num_fields_{num_fields} {};\n    constexpr std::size_t byte_count() const { return (num_fields_ + 7 + binary_row_null_bitmap_offset) / 8; }\n    bool is_null(const std::uint8_t* first, std::size_t field_pos) const\n    {\n        BOOST_ASSERT(field_pos < num_fields_);\n\n        std::size_t byte_pos = (field_pos + binary_row_null_bitmap_offset) / 8;\n        std::size_t bit_pos = (field_pos + binary_row_null_bitmap_offset) % 8;\n        return first[byte_pos] & (1 << bit_pos);\n    }\n};\n\nclass null_bitmap_generator\n{\n    span<const field_view> fields_;\n    std::size_t current_{0};\n\npublic:\n    null_bitmap_generator(span<const field_view> fields) noexcept : fields_(fields) {}\n    bool done() const { return current_ == fields_.size(); }\n    std::uint8_t next()\n    {\n        BOOST_ASSERT(current_ < fields_.size());\n\n        std::uint8_t res = 0;\n\n        // Generate\n        const std::size_t max_i = (std::min)(fields_.size(), current_ + 8u);\n        for (std::size_t i = current_; i < max_i; ++i)\n        {\n            if (fields_[i].is_null())\n            {\n                const auto bit_pos = i % 8;\n                res |= (1 << bit_pos);\n            }\n        }\n\n        // Update state\n        current_ = max_i;\n\n        // Return\n        return res;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* INCLUDE_NULL_BITMAP_HPP_ */\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_PROTOCOL_FIELD_TYPE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_PROTOCOL_FIELD_TYPE_HPP\n\n#include <boost/mysql/column_type.hpp>\n\n#include <boost/mysql/detail/flags.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nenum class protocol_field_type : std::uint8_t\n{\n    decimal = 0x00,      // Apparently not sent\n    tiny = 0x01,         // TINYINT\n    short_ = 0x02,       // SMALLINT\n    long_ = 0x03,        // INT\n    float_ = 0x04,       // FLOAT\n    double_ = 0x05,      // DOUBLE\n    null = 0x06,         // Apparently not sent\n    timestamp = 0x07,    // TIMESTAMP\n    longlong = 0x08,     // BIGINT\n    int24 = 0x09,        // MEDIUMINT\n    date = 0x0a,         // DATE\n    time = 0x0b,         // TIME\n    datetime = 0x0c,     // DATETIME\n    year = 0x0d,         // YEAR\n    varchar = 0x0f,      // Apparently not sent\n    bit = 0x10,          // BIT\n    json = 0xf5,         // JSON\n    newdecimal = 0xf6,   // DECIMAL\n    enum_ = 0xf7,        // Apparently not sent\n    set = 0xf8,          // Apparently not sent\n    tiny_blob = 0xf9,    // Apparently not sent\n    medium_blob = 0xfa,  // Apparently not sent\n    long_blob = 0xfb,    // Apparently not sent\n    blob = 0xfc,         // Used for all TEXT and BLOB types\n    var_string = 0xfd,   // Used for VARCHAR and VARBINARY\n    string = 0xfe,       // Used for CHAR and BINARY, ENUM (enum flag set), SET (set flag set)\n    geometry = 0xff      // GEOMETRY\n};\n\ninline column_type compute_column_type(\n    protocol_field_type protocol_type,\n    std::uint16_t flags,\n    std::uint16_t collation\n);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n//\n// Implementations\n//\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nBOOST_INLINE_CONSTEXPR std::uint16_t binary_collation = 63;  // used to distinguish blobs from strings\n\ninline column_type compute_field_type_string(std::uint16_t flags, std::uint16_t collation)\n{\n    if (flags & column_flags::set)\n        return column_type::set;\n    else if (flags & column_flags::enum_)\n        return column_type::enum_;\n    else if (collation == binary_collation)\n        return column_type::binary;\n    else\n        return column_type::char_;\n}\n\ninline column_type compute_field_type_var_string(std::uint16_t collation)\n{\n    return collation == binary_collation ? column_type::varbinary : column_type::varchar;\n}\n\ninline column_type compute_field_type_blob(std::uint16_t collation)\n{\n    return collation == binary_collation ? column_type::blob : column_type::text;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::column_type boost::mysql::detail::compute_column_type(\n    protocol_field_type protocol_type,\n    std::uint16_t flags,\n    std::uint16_t collation\n)\n{\n    // Some protocol_field_types seem to not be sent by the server. We've found instances\n    // where some servers, with certain SQL statements, send some of the \"apparently not sent\"\n    // types (e.g. MariaDB was sending medium_blob only if you SELECT TEXT variables - but not with TEXT\n    // columns). So we've taken a defensive approach here\n    switch (protocol_type)\n    {\n    case protocol_field_type::decimal:\n    case protocol_field_type::newdecimal: return column_type::decimal;\n    case protocol_field_type::geometry: return column_type::geometry;\n    case protocol_field_type::tiny: return column_type::tinyint;\n    case protocol_field_type::short_: return column_type::smallint;\n    case protocol_field_type::int24: return column_type::mediumint;\n    case protocol_field_type::long_: return column_type::int_;\n    case protocol_field_type::longlong: return column_type::bigint;\n    case protocol_field_type::float_: return column_type::float_;\n    case protocol_field_type::double_: return column_type::double_;\n    case protocol_field_type::bit: return column_type::bit;\n    case protocol_field_type::date: return column_type::date;\n    case protocol_field_type::datetime: return column_type::datetime;\n    case protocol_field_type::timestamp: return column_type::timestamp;\n    case protocol_field_type::time: return column_type::time;\n    case protocol_field_type::year: return column_type::year;\n    case protocol_field_type::json: return column_type::json;\n    case protocol_field_type::enum_: return column_type::enum_;  // in theory not set\n    case protocol_field_type::set: return column_type::set;      // in theory not set\n    case protocol_field_type::string: return compute_field_type_string(flags, collation);\n    case protocol_field_type::varchar:  // in theory not sent\n    case protocol_field_type::var_string: return compute_field_type_var_string(collation);\n    case protocol_field_type::tiny_blob:    // in theory not sent\n    case protocol_field_type::medium_blob:  // in theory not sent\n    case protocol_field_type::long_blob:    // in theory not sent\n    case protocol_field_type::blob: return compute_field_type_blob(collation);\n    default: return column_type::unknown;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/protocol_types.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_PROTOCOL_TYPES_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_PROTOCOL_TYPES_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/span_string.hpp>\n\n#include <boost/endian/conversion.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Integers\ntemplate <class IntType>\nstruct int_holder\n{\n    IntType value;\n\n    // This is a fixed-size type\n    static constexpr std::size_t size = sizeof(IntType);\n\n    void serialize_fixed(std::uint8_t* to) const\n    {\n        endian::endian_store<IntType, sizeof(IntType), endian::order::little>(to, value);\n    }\n\n    void serialize(serialization_context& ctx) const { ctx.serialize_fixed(*this); }\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        constexpr std::size_t sz = sizeof(IntType);\n        if (!ctx.enough_size(sz))\n        {\n            return deserialize_errc::incomplete_message;\n        }\n        value = endian::endian_load<IntType, sz, boost::endian::order::little>(ctx.first());\n        ctx.advance(sz);\n        return deserialize_errc::ok;\n    }\n};\n\nusing int1 = int_holder<std::uint8_t>;\nusing int2 = int_holder<std::uint16_t>;\nusing int4 = int_holder<std::uint32_t>;\nusing int8 = int_holder<std::uint64_t>;\nusing sint8 = int_holder<std::int64_t>;\n\nstruct int3\n{\n    std::uint32_t value;\n\n    // This is a fixed-size type\n    static constexpr std::size_t size = 3u;\n\n    void serialize_fixed(std::uint8_t* to) const { endian::store_little_u24(to, value); }\n\n    void serialize(serialization_context& ctx) const { ctx.serialize_fixed(*this); }\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        if (!ctx.enough_size(3))\n            return deserialize_errc::incomplete_message;\n        value = endian::load_little_u24(ctx.first());\n        ctx.advance(3);\n        return deserialize_errc::ok;\n    }\n};\n\nstruct int_lenenc\n{\n    std::uint64_t value;\n\n    void serialize(serialization_context& ctx) const\n    {\n        if (value < 251)\n        {\n            ctx.add(static_cast<std::uint8_t>(value));\n        }\n        else if (value < 0x10000)\n        {\n            ctx.serialize_fixed(\n                int1{static_cast<std::uint8_t>(0xfc)},\n                int2{static_cast<std::uint16_t>(value)}\n            );\n        }\n        else if (value < 0x1000000)\n        {\n            ctx.serialize_fixed(\n                int1{static_cast<std::uint8_t>(0xfd)},\n                int3{static_cast<std::uint32_t>(value)}\n            );\n        }\n        else\n        {\n            ctx.serialize_fixed(int1{static_cast<std::uint8_t>(0xfe)}, int8{value});\n        }\n    }\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        int1 first_byte{};\n        auto err = first_byte.deserialize(ctx);\n        if (err != deserialize_errc::ok)\n        {\n            return err;\n        }\n\n        if (first_byte.value == 0xfc)\n        {\n            int2 int2_value{};\n            err = int2_value.deserialize(ctx);\n            value = int2_value.value;\n        }\n        else if (first_byte.value == 0xfd)\n        {\n            int3 int3_value{};\n            err = int3_value.deserialize(ctx);\n            value = int3_value.value;\n        }\n        else if (first_byte.value == 0xfe)\n        {\n            int8 int8_value{};\n            err = int8_value.deserialize(ctx);\n            value = int8_value.value;\n        }\n        else\n        {\n            err = deserialize_errc::ok;\n            value = first_byte.value;\n        }\n        return err;\n    }\n};\n\nstruct string_null\n{\n    string_view value;\n\n    void serialize(serialization_context& ctx) const\n    {\n        ctx.add(to_span(value));\n        ctx.add(static_cast<std::uint8_t>(0));  // null terminator\n    }\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        auto string_end = std::find(ctx.first(), ctx.last(), 0);\n        if (string_end == ctx.last())\n        {\n            return deserialize_errc::incomplete_message;\n        }\n        std::size_t length = string_end - ctx.first();\n        value = ctx.get_string(length);\n        ctx.advance(length + 1);  // skip the null terminator\n        return deserialize_errc::ok;\n    }\n};\n\nstruct string_eof\n{\n    string_view value;\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        std::size_t size = ctx.size();\n        value = ctx.get_string(size);\n        ctx.advance(size);\n        return deserialize_errc::ok;\n    }\n\n    void serialize(serialization_context& ctx) const { ctx.add(to_span(value)); }\n};\n\nstruct string_lenenc\n{\n    string_view value;\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        int_lenenc length;\n        auto err = length.deserialize(ctx);\n        if (err != deserialize_errc::ok)\n        {\n            return err;\n        }\n        if (length.value > (std::numeric_limits<std::size_t>::max)())\n        {\n            return deserialize_errc::protocol_value_error;\n        }\n        auto len = static_cast<std::size_t>(length.value);\n        if (!ctx.enough_size(len))\n        {\n            return deserialize_errc::incomplete_message;\n        }\n\n        value = ctx.get_string(len);\n        ctx.advance(len);\n        return deserialize_errc::ok;\n    }\n\n    void serialize(serialization_context& ctx) const\n    {\n        ctx.serialize(int_lenenc{value.size()});\n        ctx.add(to_span(value));\n    }\n};\n\ntemplate <std::size_t N>\nstruct string_fixed\n{\n    std::array<char, N> value;\n\n    // This is a fixed size type\n    static constexpr std::size_t size = N;\n\n    void serialize_fixed(std::uint8_t* to) const { std::memcpy(to, value.data(), N); }\n\n    void serialize(serialization_context& ctx) const { ctx.serialize_fixed(*this); }\n\n    deserialize_errc deserialize(deserialization_context& ctx)\n    {\n        if (!ctx.enough_size(N))\n            return deserialize_errc::incomplete_message;\n        std::memcpy(value.data(), ctx.first(), N);\n        ctx.advance(N);\n        return deserialize_errc::ok;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/serialization_context.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_SERIALIZATION_CONTEXT_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_SERIALIZATION_CONTEXT_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/protocol/frame_header.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/core/ignore_unused.hpp>\n#include <boost/core/span.hpp>\n#include <boost/endian/conversion.hpp>\n\n#include <algorithm>\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Disables framing in serialization_context\nBOOST_INLINE_CONSTEXPR std::size_t disable_framing = static_cast<std::size_t>(-1);\n\n// Helper to compose a packet with any required frame headers. Embedding knowledge\n// of frame headers in serialization functions creates messages ready to send.\n// We require the entire message to be created before it's sent, so we don't lose any functionality.\n//\n// This class knows the offset of the next frame header. Adding data will correctly\n// insert space for headers as required while copying the data.\n//\n// Like format_context_base, contains an error that can be set if a serialization\n// function helps (e.g. because it would overrun the buffer size limit).\n// Once set, serializing is a no-op. This pattern allows us to check for errors just once.\nclass serialization_context\n{\n    std::vector<std::uint8_t>& buffer_;\n    std::size_t max_buffer_size_;\n    std::size_t max_frame_size_;\n    std::size_t next_header_offset_;\n    error_code err_;\n\n    // max_frame_size_ == -1 can be used to disable framing. Used for testing\n    bool framing_enabled() const { return max_frame_size_ != disable_framing; }\n\n    void append_to_buffer(span<const std::uint8_t> contents)\n    {\n        // Check if the buffer has space for the given contents\n        if (buffer_.size() + contents.size() > max_buffer_size_)\n            add_error(client_errc::max_buffer_size_exceeded);\n\n        // Copy if there was no error\n        if (!err_)\n            buffer_.insert(buffer_.end(), contents.begin(), contents.end());\n    }\n\n    void append_header() { append_to_buffer(std::array<std::uint8_t, frame_header_size>{}); }\n\n    void add_impl(span<const std::uint8_t> content)\n    {\n        // Add the content in chunks, inserting space for headers where required\n        std::size_t content_offset = 0;\n        while (content_offset < content.size())\n        {\n            // Serialize what we've got space for\n            BOOST_ASSERT(next_header_offset_ > buffer_.size());\n            auto remaining_content = static_cast<std::size_t>(content.size() - content_offset);\n            auto remaining_frame = static_cast<std::size_t>(next_header_offset_ - buffer_.size());\n            auto size_to_write = (std::min)(remaining_content, remaining_frame);\n            append_to_buffer(content.subspan(content_offset, size_to_write));\n            content_offset += size_to_write;\n\n            // Insert space for a frame header if required\n            if (buffer_.size() == next_header_offset_)\n            {\n                append_header();\n                next_header_offset_ += (max_frame_size_ + frame_header_size);\n            }\n        }\n    }\n\n    template <class Serializable, class... Rest>\n    static constexpr std::size_t fixed_total_size(Serializable, Rest... rest)\n    {\n        return Serializable::size + fixed_total_size(rest...);\n    }\n\n    static constexpr std::size_t fixed_total_size() { return 0u; }\n\n    template <class Serializable, class... Rest>\n    static void serialize_fixed_impl(std::uint8_t* it, Serializable serializable, Rest... rest)\n    {\n        serializable.serialize_fixed(it);\n        serialize_fixed_impl(it + Serializable::size, rest...);\n    }\n\n    static void serialize_fixed_impl(std::uint8_t*) {}\n\npublic:\n    serialization_context(\n        std::vector<std::uint8_t>& buff,\n        std::size_t max_buffer_size = static_cast<std::size_t>(-1),\n        std::size_t max_frame_size = max_packet_size\n    )\n        : buffer_(buff),\n          max_buffer_size_(max_buffer_size),\n          max_frame_size_(max_frame_size),\n          next_header_offset_(\n              framing_enabled() ? buffer_.size() + max_frame_size_ + frame_header_size\n                                : static_cast<std::size_t>(-1)\n          )\n    {\n        // Add space for the initial header\n        if (framing_enabled())\n            append_header();\n    }\n\n    // Exposed for testing\n    std::size_t next_header_offset() const { return next_header_offset_; }\n\n    void add(std::uint8_t value) { add_impl({&value, 1}); }\n\n    // To be called by serialize() functions. Appends bytes to the buffer.\n    void add(span<const std::uint8_t> content) { add_impl(content); }\n\n    // Make serialization_context compatible with output_string\n    void append(const char* content, std::size_t size)\n    {\n        add({reinterpret_cast<const std::uint8_t*>(content), size});\n    }\n\n    // Sets the error state\n    void add_error(error_code ec)\n    {\n        if (!err_)\n            err_ = ec;\n    }\n\n    error_code error() const { return err_; }\n\n    // Write frame headers to an already serialized message with space for them\n    std::uint8_t write_frame_headers(std::uint8_t seqnum, std::size_t initial_offset)\n    {\n        BOOST_ASSERT(framing_enabled());\n        BOOST_ASSERT(!err_);\n        BOOST_ASSERT(initial_offset < buffer_.size());\n\n        // Actually write the headers\n        std::size_t offset = initial_offset;\n        while (offset < buffer_.size())\n        {\n            // Calculate the current frame size\n            std::size_t frame_first = offset + frame_header_size;\n            std::size_t frame_last = (std::min)(frame_first + max_frame_size_, buffer_.size());\n            auto frame_size = static_cast<std::uint32_t>(frame_last - frame_first);\n\n            // Write the frame header\n            BOOST_ASSERT(frame_first <= buffer_.size());\n            serialize_frame_header(\n                span<std::uint8_t, frame_header_size>(buffer_.data() + offset, frame_header_size),\n                frame_header{frame_size, seqnum++}\n            );\n\n            // Skip to the next frame\n            offset = frame_last;\n        }\n\n        // We should have finished just at the buffer end\n        BOOST_ASSERT(offset == buffer_.size());\n\n        return seqnum;\n    }\n\n    // Optimization for fixed size types. We serialize them to an\n    // intermediate, stack-based buffer, then copy them to the actual buffer.\n    // This saves reallocations and space checks\n    template <class... Serializable>\n    void serialize_fixed(Serializable... s)\n    {\n        std::array<std::uint8_t, fixed_total_size(Serializable{}...)> buff;\n        serialize_fixed_impl(buff.data(), s...);\n        add(buff);\n    }\n\n    // Allow chaining\n    template <class... Serializable>\n    void serialize(Serializable... s)\n    {\n        int dummy[] = {(s.serialize(*this), 0)...};\n        ignore_unused(dummy);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/span_string.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_SPAN_STRING_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_SPAN_STRING_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline string_view to_string(span<const std::uint8_t> v)\n{\n    return string_view(reinterpret_cast<const char*>(v.data()), v.size());\n}\ninline span<const std::uint8_t> to_span(string_view v)\n{\n    return span<const std::uint8_t>(reinterpret_cast<const std::uint8_t*>(v.data()), v.size());\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/impl/text_protocol.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_TEXT_PROTOCOL_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_IMPL_TEXT_PROTOCOL_HPP\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/datetime.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/bit_deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/span_string.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/charconv/from_chars.hpp>\n\n#include <cmath>\n#include <cstddef>\n#include <cstdlib>\n#include <cstring>\n#include <system_error>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline deserialize_errc deserialize_text_field(string_view from, const metadata& meta, field_view& output);\n\n}\n}  // namespace mysql\n}  // namespace boost\n\n//\n// Implementation\n//\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Constants\nBOOST_INLINE_CONSTEXPR unsigned max_decimals = 6u;\nBOOST_INLINE_CONSTEXPR unsigned time_max_hour = 838;\n\n// Integers\ntemplate <class T>\ninline deserialize_errc deserialize_text_value_int_impl(string_view from, field_view& to)\n{\n    // Iterators\n    const char* begin = from.data();\n    const char* end = begin + from.size();\n\n    // Convert\n    T v;\n    auto res = charconv::from_chars(from.data(), from.data() + from.size(), v);\n\n    // Check\n    if (res.ec != std::errc() || res.ptr != end)\n        return deserialize_errc::protocol_value_error;\n\n    // Done\n    to = field_view(v);\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_text_value_int(string_view from, field_view& to, const metadata& meta)\n{\n    return meta.is_unsigned() ? deserialize_text_value_int_impl<std::uint64_t>(from, to)\n                              : deserialize_text_value_int_impl<std::int64_t>(from, to);\n}\n\n// Floating points\ntemplate <class T>\ninline deserialize_errc deserialize_text_value_float(string_view from, field_view& to)\n{\n    // Iterators\n    const char* begin = from.data();\n    const char* end = begin + from.size();\n\n    // Convert\n    T val;\n    auto res = charconv::from_chars(begin, end, val);\n\n    // Check. SQL std forbids nan and inf\n    if (res.ec != std::errc() || res.ptr != end || std::isnan(val) || std::isinf(val))\n        return deserialize_errc::protocol_value_error;\n\n    // Done\n    to = field_view(val);\n    return deserialize_errc::ok;\n}\n\n// Strings\ninline deserialize_errc deserialize_text_value_string(string_view from, field_view& to)\n{\n    to = field_view(from);\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_text_value_blob(string_view from, field_view& to) noexcept\n{\n    to = field_view(to_span(from));\n    return deserialize_errc::ok;\n}\n\n// Date/time types\ntemplate <class IntType>\ninline deserialize_errc deserialize_fixed_width_number(\n    const char*& it,\n    const char* end,\n    IntType& to,\n    std::size_t size\n)\n{\n    auto res = charconv::from_chars(it, end, to);\n    if (res.ec != std::errc() || res.ptr != it + size)\n        return deserialize_errc::protocol_value_error;\n    it = res.ptr;\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc check_separator(const char*& it, const char* end, char sep)\n{\n    if (it == end || *it++ != sep)\n        return deserialize_errc::protocol_value_error;\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_text_ymd(const char*& it, const char* end, date& to)\n{\n    // Year\n    std::uint16_t year = 0;\n    auto err = deserialize_fixed_width_number(it, end, year, 4);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Separator\n    err = check_separator(it, end, '-');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Month\n    std::uint8_t month = 0;\n    err = deserialize_fixed_width_number(it, end, month, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Separator\n    err = check_separator(it, end, '-');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Day\n    std::uint8_t day = 0;\n    err = deserialize_fixed_width_number(it, end, day, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Range check for individual components. MySQL doesn't allow invidiual components\n    // to be out of range, although they may be zero or representing an invalid date\n    if (year > max_year || month > max_month || day > max_day)\n        return deserialize_errc::protocol_value_error;\n\n    to = date(year, month, day);\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_microsecond(\n    const char*& it,\n    const char* end,\n    std::uint32_t& output,\n    unsigned decimals\n)\n{\n    // Sanitize decimals\n    decimals = (std::min)(decimals, max_decimals);\n\n    if (decimals)\n    {\n        // Microsecond separator\n        auto err = check_separator(it, end, '.');\n        if (err != deserialize_errc::ok)\n            return err;\n\n        // Microseconds. Depending on decimals, this has a variable width.\n        // For instance, with decimals = 2, a value could be '.92', meaning 920000 microseconds.\n        // Max decimals is 6 (guaranteed by sanitize_decimals).\n        // Right pad the input string with zeros and convert\n\n        // Size check\n        if (it + decimals > end)\n            return deserialize_errc::protocol_value_error;\n\n        // Right pad with zeros\n        char micros_buff[6] = {'0', '0', '0', '0', '0', '0'};\n        std::memcpy(micros_buff, it, decimals);\n\n        // Parse\n        const char* buff_begin = micros_buff;\n        const char* buff_end = micros_buff + sizeof(micros_buff);\n        err = deserialize_fixed_width_number(buff_begin, buff_end, output, 6);\n        if (err != deserialize_errc::ok)\n            return err;\n\n        // Update iterator\n        it += decimals;\n    }\n\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_text_value_date(string_view from, field_view& to)\n{\n    // Iterators\n    const char* it = from.data();\n    const char* end = it + from.size();\n\n    // Deserialize\n    date d;\n    auto err = deserialize_text_ymd(it, end, d);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Size check\n    if (it != end)\n        return deserialize_errc::protocol_value_error;\n\n    // Done\n    to = field_view(d);\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_text_value_datetime(\n    string_view from,\n    field_view& to,\n    const metadata& meta\n)\n{\n    // Iterators\n    const char* it = from.data();\n    const char* end = it + from.size();\n\n    // Deserialize date part\n    date d;\n    auto err = deserialize_text_ymd(it, end, d);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Separator\n    err = check_separator(it, end, ' ');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Hour\n    std::uint8_t hour = 0;\n    err = deserialize_fixed_width_number(it, end, hour, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Separator\n    err = check_separator(it, end, ':');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Minute\n    std::uint8_t minute = 0;\n    err = deserialize_fixed_width_number(it, end, minute, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Separator\n    err = check_separator(it, end, ':');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Second\n    std::uint8_t second = 0;\n    err = deserialize_fixed_width_number(it, end, second, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Microsecond\n    std::uint32_t microsecond = 0;\n    err = deserialize_microsecond(it, end, microsecond, meta.decimals());\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Size check\n    if (it != end)\n        return deserialize_errc::protocol_value_error;\n\n    // Validity check. Although MySQL allows invalid and zero datetimes, it doesn't allow\n    // individual components to be out of range.\n    if (hour > max_hour || minute > max_min || second > max_sec || microsecond > max_micro)\n    {\n        return deserialize_errc::protocol_value_error;\n    }\n\n    to = field_view(datetime(d.year(), d.month(), d.day(), hour, minute, second, microsecond));\n    return deserialize_errc::ok;\n}\n\ninline deserialize_errc deserialize_text_value_time(string_view from, field_view& to, const metadata& meta)\n{\n    // Iterators\n    const char* it = from.data();\n    const char* end = it + from.size();\n\n    // Sign\n    if (it == end)\n        return deserialize_errc::protocol_value_error;\n    bool is_negative = *it == '-';\n    if (is_negative)\n        ++it;\n\n    // Hours\n    std::uint16_t hours = 0;\n    auto res = charconv::from_chars(it, end, hours);\n    if (res.ec != std::errc())\n        return deserialize_errc::protocol_value_error;\n    auto hour_num_chars = res.ptr - it;\n    if (hour_num_chars != 2 && hour_num_chars != 3)  // may take between 2 and 3 chars\n        return deserialize_errc::protocol_value_error;\n    it = res.ptr;\n\n    // Separator\n    auto err = check_separator(it, end, ':');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Minute\n    std::uint8_t minute = 0;\n    err = deserialize_fixed_width_number(it, end, minute, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Separator\n    err = check_separator(it, end, ':');\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Second\n    std::uint8_t second = 0;\n    err = deserialize_fixed_width_number(it, end, second, 2);\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Microsecond\n    std::uint32_t microsecond = 0;\n    err = deserialize_microsecond(it, end, microsecond, meta.decimals());\n    if (err != deserialize_errc::ok)\n        return err;\n\n    // Size check\n    if (it != end)\n        return deserialize_errc::protocol_value_error;\n\n    // Range check\n    if (hours > time_max_hour || minute > max_min || second > max_sec || microsecond > max_micro)\n        return deserialize_errc::protocol_value_error;\n\n    // Sum it\n    auto t = std::chrono::hours(hours) + std::chrono::minutes(minute) + std::chrono::seconds(second) +\n             std::chrono::microseconds(microsecond);\n    if (is_negative)\n    {\n        t = -t;\n    }\n\n    // Done\n    to = field_view(t);\n    return deserialize_errc::ok;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::detail::deserialize_errc boost::mysql::detail::deserialize_text_field(\n    string_view from,\n    const metadata& meta,\n    field_view& output\n)\n{\n    switch (meta.type())\n    {\n    case column_type::tinyint:\n    case column_type::smallint:\n    case column_type::mediumint:\n    case column_type::int_:\n    case column_type::bigint:\n    case column_type::year: return deserialize_text_value_int(from, output, meta);\n    case column_type::bit: return deserialize_bit(from, output);\n    case column_type::float_: return deserialize_text_value_float<float>(from, output);\n    case column_type::double_: return deserialize_text_value_float<double>(from, output);\n    case column_type::timestamp:\n    case column_type::datetime: return deserialize_text_value_datetime(from, output, meta);\n    case column_type::date: return deserialize_text_value_date(from, output);\n    case column_type::time: return deserialize_text_value_time(from, output, meta);\n    // True string types\n    case column_type::char_:\n    case column_type::varchar:\n    case column_type::text:\n    case column_type::enum_:\n    case column_type::set:\n    case column_type::decimal:\n    case column_type::json: return deserialize_text_value_string(from, output);\n    // Blobs and anything else\n    case column_type::binary:\n    case column_type::varbinary:\n    case column_type::blob:\n    case column_type::geometry:\n    default: return deserialize_text_value_blob(from, output);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/serialization.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP\n\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/frame_header.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n\n#include <boost/assert.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// quit\nstruct quit_command\n{\n    void serialize(serialization_context& ctx) const { ctx.add(0x01); }\n};\n\n// ping\nstruct ping_command\n{\n    void serialize(serialization_context& ctx) const { ctx.add(0x0e); }\n};\n\n// reset_connection\nstruct reset_connection_command\n{\n    void serialize(serialization_context& ctx) const { ctx.add(0x1f); }\n};\n\n// query\nstruct query_command\n{\n    string_view query;\n\n    void serialize(serialization_context& ctx) const\n    {\n        ctx.add(0x03);\n        string_eof{query}.serialize(ctx);\n    }\n};\n\n// prepare_statement\nstruct prepare_stmt_command\n{\n    string_view stmt;\n\n    void serialize(serialization_context& ctx) const\n    {\n        ctx.add(0x16);\n        string_eof{stmt}.serialize(ctx);\n    }\n};\n\n// execute statement\nstruct execute_stmt_command\n{\n    std::uint32_t statement_id;\n    span<const field_view> params;\n\n    inline void serialize(serialization_context& ctx) const;\n};\n\n// close statement\nstruct close_stmt_command\n{\n    std::uint32_t statement_id;\n    void serialize(serialization_context& ctx) const { ctx.serialize_fixed(int1{0x19}, int4{statement_id}); }\n};\n\n// Login request\nstruct login_request\n{\n    capabilities negotiated_capabilities;  // capabilities\n    std::uint32_t max_packet_size;\n    std::uint32_t collation_id;\n    string_view username;\n    span<const std::uint8_t> auth_response;\n    string_view database;\n    string_view auth_plugin_name;\n\n    inline void serialize(serialization_context& ctx) const;\n};\n\n// SSL request\nstruct ssl_request\n{\n    capabilities negotiated_capabilities;\n    std::uint32_t max_packet_size;\n    std::uint32_t collation_id;\n\n    inline void serialize(serialization_context& ctx) const;\n};\n\n// Auth switch response\nstruct auth_switch_response\n{\n    span<const std::uint8_t> auth_plugin_data;\n\n    void serialize(serialization_context& ctx) const { ctx.add(auth_plugin_data); }\n};\n\n// The result of serialize_top_level (similar to system::result,\n// doesn't track source locations)\nstruct serialize_top_level_result\n{\n    error_code err;\n    std::uint8_t seqnum{};\n\n    constexpr serialize_top_level_result(error_code ec) noexcept : err(ec) {}\n    constexpr serialize_top_level_result(std::uint8_t seqnum) noexcept : seqnum(seqnum) {}\n};\n\n// Serialize a complete message. May fail\ntemplate <class Serializable>\ninline serialize_top_level_result serialize_top_level(\n    const Serializable& input,\n    std::vector<std::uint8_t>& to,\n    std::uint8_t seqnum = 0,\n    std::size_t max_buffer_size = static_cast<std::size_t>(-1),\n    std::size_t max_frame_size = max_packet_size\n)\n{\n    std::size_t initial_offset = to.size();\n    serialization_context ctx(to, max_buffer_size, max_frame_size);\n    input.serialize(ctx);\n    auto err = ctx.error();\n    if (err)\n        return err;\n    return ctx.write_frame_headers(seqnum, initial_offset);\n}\n\n// Same, but for cases that can't fail. Does not enforce any limit on buffer size\ntemplate <class Serializable>\ninline std::uint8_t serialize_top_level_checked(\n    const Serializable& input,\n    std::vector<std::uint8_t>& to,\n    std::uint8_t seqnum = 0,\n    std::size_t max_frame_size = max_packet_size\n)\n{\n    auto res = serialize_top_level(input, to, seqnum, static_cast<std::size_t>(-1), max_frame_size);\n    BOOST_ASSERT(res.err == error_code());\n    return res.seqnum;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n//\n// Implementations\n//\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Maps from an actual value to a protocol_field_type (for execute statement)\ninline protocol_field_type to_protocol_field_type(field_kind kind)\n{\n    switch (kind)\n    {\n    case field_kind::null: return protocol_field_type::null;\n    case field_kind::int64: return protocol_field_type::longlong;\n    case field_kind::uint64: return protocol_field_type::longlong;\n    case field_kind::string: return protocol_field_type::string;\n    case field_kind::blob: return protocol_field_type::blob;\n    case field_kind::float_: return protocol_field_type::float_;\n    case field_kind::double_: return protocol_field_type::double_;\n    case field_kind::date: return protocol_field_type::date;\n    case field_kind::datetime: return protocol_field_type::datetime;\n    case field_kind::time: return protocol_field_type::time;\n    default: BOOST_ASSERT(false); return protocol_field_type::null;  // LCOV_EXCL_LINE\n    }\n}\n\n// Returns the collation ID's first byte (for login packets)\ninline std::uint8_t get_collation_first_byte(std::uint32_t collation_id)\n{\n    return static_cast<std::uint8_t>(collation_id % 0xff);\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nvoid boost::mysql::detail::execute_stmt_command::serialize(serialization_context& ctx) const\n{\n    // The wire layout is as follows:\n    //  command ID\n    //  std::uint32_t statement_id;\n    //  std::uint8_t flags;\n    //  std::uint32_t iteration_count;\n    //  if num_params > 0:\n    //      NULL bitmap\n    //      std::uint8_t new_params_bind_flag;\n    //      array<meta_packet, num_params> meta;\n    //          protocol_field_type type;\n    //          std::uint8_t unsigned_flag;\n    //      array<field_view, num_params> params;\n\n    constexpr int1 command_id{0x17};\n    constexpr int1 flags{0};\n    constexpr int4 iteration_count{1};\n    constexpr int1 new_params_bind_flag{1};\n\n    // header\n    ctx.serialize_fixed(command_id, int4{statement_id}, flags, iteration_count);\n\n    // Number of parameters\n    auto num_params = params.size();\n\n    if (num_params > 0)\n    {\n        // NULL bitmap\n        null_bitmap_generator null_gen(params);\n        while (!null_gen.done())\n            ctx.add(null_gen.next());\n\n        // new parameters bind flag\n        new_params_bind_flag.serialize(ctx);\n\n        // value metadata\n        for (field_view param : params)\n        {\n            field_kind kind = param.kind();\n            protocol_field_type type = to_protocol_field_type(kind);\n            std::uint8_t unsigned_flag = kind == field_kind::uint64 ? std::uint8_t(0x80) : std::uint8_t(0);\n            ctx.serialize_fixed(int1{static_cast<std::uint8_t>(type)}, int1{unsigned_flag});\n        }\n\n        // actual values\n        for (field_view param : params)\n        {\n            serialize_binary_field(ctx, param);\n        }\n    }\n}\n\nvoid boost::mysql::detail::login_request::serialize(serialization_context& ctx) const\n{\n    ctx.serialize_fixed(\n        int4{static_cast<std::uint32_t>(negotiated_capabilities)},  // client_flag\n        int4{max_packet_size},                                      // max_packet_size\n        int1{get_collation_first_byte(collation_id)},               //  character_set\n        string_fixed<23>{}                                          // filler (all zeros)\n    );\n    ctx.serialize(\n        string_null{username},\n        string_lenenc{to_string(auth_response)}  // we require CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA\n    );\n    if (has_capabilities(negotiated_capabilities, capabilities::connect_with_db))\n    {\n        string_null{database}.serialize(ctx);  // database\n    }\n    string_null{auth_plugin_name}.serialize(ctx);  //  client_plugin_name\n}\n\nvoid boost::mysql::detail::ssl_request::serialize(serialization_context& ctx) const\n{\n    ctx.serialize_fixed(\n        int4{static_cast<std::uint32_t>(negotiated_capabilities)},  // client_flag\n        int4{max_packet_size},                                      // max_packet_size\n        int1{get_collation_first_byte(collation_id)},               // character_set,\n        string_fixed<23>{}                                          // filler, all zeros\n    );\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/protocol/static_buffer.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_STATIC_BUFFER_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_STATIC_BUFFER_HPP\n\n// A very simplified variable-length buffer with fixed max-size\n\n#include <boost/assert.hpp>\n#include <boost/core/span.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate <std::size_t N>\nclass static_buffer\n{\n    std::array<std::uint8_t, N> buffer_{};\n    std::size_t size_{};\n\npublic:\n    // Allow inspecting the supplied template argument\n    static constexpr std::size_t max_size = N;\n\n    // Constructors\n    static_buffer() = default;\n    static_buffer(std::size_t sz) noexcept : size_(sz) { BOOST_ASSERT(sz <= size_); }\n\n    // Size and data\n    std::size_t size() const noexcept { return size_; }\n    const std::uint8_t* data() const noexcept { return buffer_.data(); }\n    std::uint8_t* data() noexcept { return buffer_.data(); }\n\n    // Modifiers\n    void append(span<const std::uint8_t> data) noexcept\n    {\n        if (!data.empty())\n        {\n            std::size_t new_size = size_ + data.size();\n            BOOST_ASSERT(new_size <= N);\n            std::memcpy(buffer_.data() + size_, data.data(), data.size());\n            size_ = new_size;\n        }\n    }\n\n    void clear() noexcept { size_ = 0; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/auth_plugin_common.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_AUTH_PLUGIN_COMMON_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_AUTH_PLUGIN_COMMON_HPP\n\n#include <boost/config.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// All scrambles in all the plugins we know have this size\nBOOST_INLINE_CONSTEXPR std::size_t scramble_size = 20u;\n\n// Hashed passwords vary in size, but they all fit in a buffer like this\nBOOST_INLINE_CONSTEXPR std::size_t max_hash_size = 32u;\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/caching_sha2_password.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CACHING_SHA2_PASSWORD_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CACHING_SHA2_PASSWORD_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/static_buffer.hpp>\n#include <boost/mysql/impl/internal/sansio/auth_plugin_common.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/csha2p_encrypt_password.hpp>\n\n#include <boost/asio/ssl/error.hpp>\n#include <boost/container/small_vector.hpp>\n#include <boost/core/span.hpp>\n#include <boost/system/result.hpp>\n#include <boost/system/system_category.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <openssl/sha.h>\n\n// Reference:\n// https://dev.mysql.com/doc/dev/mysql-server/latest/page_caching_sha2_authentication_exchanges.html\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Constants\nBOOST_INLINE_CONSTEXPR std::size_t csha2p_hash_size = 32;\nBOOST_INLINE_CONSTEXPR const char* csha2p_plugin_name = \"caching_sha2_password\";\nstatic_assert(csha2p_hash_size <= max_hash_size, \"\");\nstatic_assert(csha2p_hash_size == SHA256_DIGEST_LENGTH, \"Buffer size mismatch\");\n\ninline void csha2p_hash_password_impl(\n    string_view password,\n    span<const std::uint8_t, scramble_size> scramble,\n    span<std::uint8_t, csha2p_hash_size> output\n)\n{\n    // SHA(SHA(password_sha) concat scramble) XOR password_sha\n    // hash1 = SHA(pass)\n    std::array<std::uint8_t, csha2p_hash_size> password_sha;\n    SHA256(reinterpret_cast<const unsigned char*>(password.data()), password.size(), password_sha.data());\n\n    // SHA(password_sha) concat scramble = buffer\n    std::array<std::uint8_t, csha2p_hash_size + scramble_size> buffer;\n    SHA256(password_sha.data(), password_sha.size(), buffer.data());\n    std::memcpy(buffer.data() + csha2p_hash_size, scramble.data(), scramble.size());\n\n    // SHA(SHA(password_sha) concat scramble) = SHA(buffer) = salted_password\n    std::array<std::uint8_t, csha2p_hash_size> salted_password;\n    SHA256(buffer.data(), buffer.size(), salted_password.data());\n\n    // salted_password XOR password_sha\n    for (unsigned i = 0; i < csha2p_hash_size; ++i)\n    {\n        output[i] = salted_password[i] ^ password_sha[i];\n    }\n}\n\ninline static_buffer<max_hash_size> csha2p_hash_password(\n    string_view password,\n    span<const std::uint8_t, scramble_size> scramble\n)\n{\n    // Empty passwords are not hashed\n    if (password.empty())\n        return {};\n\n    // Run the algorithm\n    static_buffer<max_hash_size> res(csha2p_hash_size);\n    csha2p_hash_password_impl(\n        password,\n        scramble,\n        span<std::uint8_t, csha2p_hash_size>(res.data(), csha2p_hash_size)\n    );\n    return res;\n}\n\nclass csha2p_algo\n{\n    int resume_point_{0};\n\n    static bool is_perform_full_auth(span<const std::uint8_t> server_data)\n    {\n        return server_data.size() == 1u && server_data[0] == 4;\n    }\n\n    static bool is_fast_auth_ok(span<const std::uint8_t> server_data)\n    {\n        return server_data.size() == 1u && server_data[0] == 3;\n    }\n\n    static next_action encrypt_password(\n        connection_state_data& st,\n        std::uint8_t& seqnum,\n        string_view password,\n        span<const std::uint8_t, scramble_size> scramble,\n        span<const std::uint8_t> server_key\n    )\n    {\n        container::small_vector<std::uint8_t, 512> buff;\n        auto ec = csha2p_encrypt_password(password, scramble, server_key, buff, asio::error::ssl_category);\n        if (ec)\n            return ec;\n        return st.write(\n            string_eof{string_view(reinterpret_cast<const char*>(buff.data()), buff.size())},\n            seqnum\n        );\n    }\n\npublic:\n    csha2p_algo() = default;\n\n    next_action resume(\n        connection_state_data& st,\n        span<const std::uint8_t> server_data,\n        string_view password,\n        span<const std::uint8_t, scramble_size> scramble,\n        bool secure_channel,\n        std::uint8_t& seqnum\n    )\n    {\n        switch (resume_point_)\n        {\n        case 0:\n            // If we got a more data packet, the server either required us to perform full auth,\n            // or told us to read again because an OK packet or error packet is coming.\n            if (is_perform_full_auth(server_data))\n            {\n                if (secure_channel)\n                {\n                    // We should send a packet with just the password, as a NULL-terminated string\n                    BOOST_MYSQL_YIELD(resume_point_, 1, st.write(string_null{password}, seqnum))\n\n                    // The server shouldn't send us any more packets\n                    return error_code(client_errc::bad_handshake_packet_type);\n                }\n                else\n                {\n                    // Request the server's public key\n                    BOOST_MYSQL_YIELD(resume_point_, 2, st.write(int1{2}, seqnum))\n\n                    // Encrypt the password with the key we were given\n                    BOOST_MYSQL_YIELD(\n                        resume_point_,\n                        3,\n                        encrypt_password(st, seqnum, password, scramble, server_data)\n                    )\n\n                    // The server shouldn't send us any more packets\n                    return error_code(client_errc::bad_handshake_packet_type);\n                }\n            }\n            else if (is_fast_auth_ok(server_data))\n            {\n                // We should wait for the server to send an OK or an error\n                BOOST_MYSQL_YIELD(resume_point_, 4, st.read(seqnum))\n            }\n            else\n            {\n                // The server sent a data packet and we don't know what it means.\n                // Treat it as a protocol violation error and exit\n                return error_code(client_errc::bad_handshake_packet_type);\n            }\n        }\n\n        // If we got here, the server sent us more data, which is a protocol violation\n        return error_code(client_errc::bad_handshake_packet_type);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/close_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CLOSE_CONNECTION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CLOSE_CONNECTION_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/quit_connection.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass close_connection_algo\n{\n    int resume_point_{0};\n    quit_connection_algo quit_{{}};\n    error_code stored_ec_;\n\npublic:\n    close_connection_algo(close_connection_algo_params) noexcept {}\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            // If we're not connected, we're done.\n            // If we're in a multi-function operation, it's safe to proceed.\n            if (st.status == connection_status::not_connected)\n                return next_action();\n\n            // Attempt quit\n            while (!(act = quit_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 1, act)\n            stored_ec_ = act.error();\n\n            // Close the transport\n            BOOST_MYSQL_YIELD(resume_point_, 2, next_action::close())\n\n            // If quit resulted in an error, keep that error.\n            // Otherwise, return any error derived from close\n            if (stored_ec_)\n                ec = stored_ec_;\n        }\n\n        return ec;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/close_statement.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CLOSE_STATEMENT_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CLOSE_STATEMENT_HPP\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline run_pipeline_algo_params setup_close_statement_pipeline(\n    connection_state_data& st,\n    close_statement_algo_params params\n)\n{\n    // Pipeline a ping with the close statement, to avoid delays on old connections\n    // that don't set tcp_nodelay. Both requests are small and fixed size, so\n    // we don't enforce any buffer limits here.\n    st.write_buffer.clear();\n    auto seqnum1 = serialize_top_level_checked(close_stmt_command{params.stmt_id}, st.write_buffer);\n    auto seqnum2 = serialize_top_level_checked(ping_command{}, st.write_buffer);\n    st.shared_pipeline_stages = {\n        {\n         {pipeline_stage_kind::close_statement, seqnum1, {}},\n         {pipeline_stage_kind::ping, seqnum2, {}},\n         }\n    };\n    return {st.write_buffer, st.shared_pipeline_stages, nullptr};\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/connect.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CONNECT_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CONNECT_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/handshake.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass connect_algo\n{\n    int resume_point_{0};\n    const void* server_address_;\n    handshake_algo handshake_;\n    error_code stored_ec_;\n\npublic:\n    connect_algo(connect_algo_params params) noexcept\n        : server_address_(params.server_address), handshake_({params.hparams, params.secure_channel})\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n            // Handshake and connect wipe out state, so no state checks are performed.\n\n            // Physical connect\n            BOOST_MYSQL_YIELD(resume_point_, 1, next_action::connect(server_address_))\n            if (ec)\n                return ec;\n\n            // Handshake\n            while (!(act = handshake_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 2, act)\n\n            // If handshake failed, close the stream ignoring the result\n            // and return handshake's error code\n            if (act.error())\n            {\n                stored_ec_ = act.error();\n                BOOST_MYSQL_YIELD(resume_point_, 3, next_action::close())\n                return stored_ec_;\n            }\n\n            // Done\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/connection_state.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CONNECTION_STATE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CONNECTION_STATE_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/any_resumable_ref.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/sansio/close_connection.hpp>\n#include <boost/mysql/impl/internal/sansio/close_statement.hpp>\n#include <boost/mysql/impl/internal/sansio/connect.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/execute.hpp>\n#include <boost/mysql/impl/internal/sansio/handshake.hpp>\n#include <boost/mysql/impl/internal/sansio/ping.hpp>\n#include <boost/mysql/impl/internal/sansio/prepare_statement.hpp>\n#include <boost/mysql/impl/internal/sansio/quit_connection.hpp>\n#include <boost/mysql/impl/internal/sansio/read_resultset_head.hpp>\n#include <boost/mysql/impl/internal/sansio/read_some_rows.hpp>\n#include <boost/mysql/impl/internal/sansio/read_some_rows_dynamic.hpp>\n#include <boost/mysql/impl/internal/sansio/reset_connection.hpp>\n#include <boost/mysql/impl/internal/sansio/run_pipeline.hpp>\n#include <boost/mysql/impl/internal/sansio/set_character_set.hpp>\n#include <boost/mysql/impl/internal/sansio/start_execution.hpp>\n#include <boost/mysql/impl/internal/sansio/top_level_algo.hpp>\n\n#include <boost/variant2/variant.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// clang-format off\ntemplate <class AlgoParams> struct get_algo;\ntemplate <> struct get_algo<connect_algo_params> { using type = connect_algo; };\ntemplate <> struct get_algo<handshake_algo_params> { using type = handshake_algo; };\ntemplate <> struct get_algo<execute_algo_params> { using type = execute_algo; };\ntemplate <> struct get_algo<start_execution_algo_params> { using type = start_execution_algo; };\ntemplate <> struct get_algo<read_resultset_head_algo_params> { using type = read_resultset_head_algo; };\ntemplate <> struct get_algo<read_some_rows_algo_params> { using type = read_some_rows_algo; };\ntemplate <> struct get_algo<read_some_rows_dynamic_algo_params> { using type = read_some_rows_dynamic_algo; };\ntemplate <> struct get_algo<prepare_statement_algo_params> { using type = prepare_statement_algo; };\ntemplate <> struct get_algo<set_character_set_algo_params> { using type = set_character_set_algo; };\ntemplate <> struct get_algo<quit_connection_algo_params> { using type = quit_connection_algo; };\ntemplate <> struct get_algo<close_connection_algo_params> { using type = close_connection_algo; };\ntemplate <> struct get_algo<run_pipeline_algo_params> { using type = run_pipeline_algo; };\ntemplate <class AlgoParams> using get_algo_t = typename get_algo<AlgoParams>::type;\n// clang-format on\n\nclass connection_state\n{\n    // Helper\n    template <class... Algos>\n    using make_any_algo_type = variant2::variant<top_level_algo<Algos>...>;\n\n    using any_algo = make_any_algo_type<\n        connect_algo,\n        handshake_algo,\n        execute_algo,\n        start_execution_algo,\n        read_resultset_head_algo,\n        read_some_rows_algo,\n        read_some_rows_dynamic_algo,\n        prepare_statement_algo,\n        set_character_set_algo,\n        quit_connection_algo,\n        close_connection_algo,\n        run_pipeline_algo>;\n\n    connection_state_data st_data_;\n    any_algo algo_;\n\n    // A function compatible with any_resumable_ref that always fails immediately\n    // with operation_in_progress. We can't change algo_ while an algorithm is running,\n    // so we need an any_resumable_ref that doesn't point into algo_\n    static next_action fail_op_in_progress(void*, error_code, std::size_t)\n    {\n        return error_code(client_errc::operation_in_progress);\n    }\n\npublic:\n    // We initialize the algo state with a dummy value. This will be overwritten\n    // by setup() before the first algorithm starts running. Doing this avoids\n    // the need for a special null algo\n    connection_state(std::size_t read_buffer_size, std::size_t max_buffer_size, bool transport_supports_ssl)\n        : st_data_(read_buffer_size, max_buffer_size, transport_supports_ssl),\n          algo_(top_level_algo<quit_connection_algo>(\n              st_data_,\n              st_data_.shared_diag,\n              quit_connection_algo_params{}\n          ))\n    {\n    }\n\n    const connection_state_data& data() const { return st_data_; }\n    connection_state_data& data() { return st_data_; }\n\n    template <class AlgoParams>\n    any_resumable_ref setup(diagnostics& diag, AlgoParams params)\n    {\n        // Clear diagnostics\n        diag.clear();\n\n        // If there is an operation in progress, don't change anything, just fail\n        if (st_data_.op_in_progress)\n            return any_resumable_ref(nullptr, &fail_op_in_progress);\n\n        // Emplace the algorithm\n        using algo_type = top_level_algo<get_algo_t<AlgoParams>>;\n        return any_resumable_ref(algo_.emplace<algo_type>(st_data_, diag, params));\n    }\n\n    any_resumable_ref setup(diagnostics& diag, close_statement_algo_params params)\n    {\n        return setup(diag, setup_close_statement_pipeline(st_data_, params));\n    }\n\n    any_resumable_ref setup(diagnostics& diag, reset_connection_algo_params)\n    {\n        return setup(diag, setup_reset_connection_pipeline(st_data_));\n    }\n\n    any_resumable_ref setup(diagnostics& diag, ping_algo_params)\n    {\n        return setup(diag, setup_ping_pipeline(st_data_));\n    }\n\n    template <typename AlgoParams>\n    typename AlgoParams::result_type result() const\n    {\n        return variant2::get<top_level_algo<get_algo_t<AlgoParams>>>(algo_).inner_algo().result(st_data_);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/connection_state_data.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CONNECTION_STATE_DATA_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CONNECTION_STATE_DATA_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n\n#include <boost/mysql/detail/next_action.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/message_reader.hpp>\n\n#include <boost/assert.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nenum class connection_status\n{\n    // Never connected or closed\n    not_connected,\n\n    // Connected and ready for a command\n    ready,\n\n    // In the middle of a multi-function operation\n    engaged_in_multi_function,\n};\n\nstruct connection_state_data\n{\n    // Are we connected? In the middle of a multi-function operation?\n    connection_status status{connection_status::not_connected};\n\n    // Are we currently executing an operation?\n    // Prevent the user from running concurrent operations\n    bool op_in_progress{false};\n\n    // Are we talking to MySQL or MariaDB?\n    db_flavor flavor{db_flavor::mysql};\n\n    // What are the connection's capabilities?\n    capabilities current_capabilities{};\n\n    // The current connection ID. Supplied by handshake, can be used in KILL statements\n    std::uint32_t connection_id{};\n\n    // Used by async ops without output diagnostics params, to avoid allocations\n    diagnostics shared_diag;\n\n    // Temporary field storage, re-used by several ops\n    std::vector<field_view> shared_fields;\n\n    // Temporary pipeline stage storage, re-used by several ops\n    std::array<pipeline_request_stage, 2> shared_pipeline_stages;\n\n    // Do we want to retain metadata strings or not? Used to save allocations\n    metadata_mode meta_mode{metadata_mode::minimal};\n\n    // Is TLS supported for the current connection?\n    bool tls_supported;\n\n    // Is TLS enabled for the current connection?\n    bool tls_active{false};\n\n    // Do backslashes represent escape sequences? By default they do, but they can\n    // be disabled using a variable. OK packets include a flag with this info.\n    bool backslash_escapes{true};\n\n    // The current character set, or a default-constructed character set (will all nullptrs) if unknown\n    character_set current_charset{};\n\n    // The write buffer\n    std::vector<std::uint8_t> write_buffer;\n\n    // Reader\n    message_reader reader;\n\n    std::size_t max_buffer_size() const { return reader.max_buffer_size(); }\n\n    connection_state_data(\n        std::size_t read_buffer_size,\n        std::size_t max_buff_size = static_cast<std::size_t>(-1),\n        bool transport_supports_ssl = false\n    )\n        : tls_supported(transport_supports_ssl), reader(read_buffer_size, max_buff_size)\n    {\n    }\n\n    void reset()\n    {\n        status = connection_status::not_connected;\n        flavor = db_flavor::mysql;\n        current_capabilities = capabilities{};\n        connection_id = 0u;\n        // Metadata mode does not get reset on handshake\n        reader.reset();\n        // Writer does not need reset, since every write clears previous state\n        tls_active = false;\n        backslash_escapes = true;\n        current_charset = character_set{};\n    }\n\n    // Reads an OK packet from the reader. This operation is repeated in several places.\n    error_code deserialize_ok(diagnostics& diag)\n    {\n        return deserialize_ok_response(reader.message(), flavor, diag, backslash_escapes);\n    }\n\n    // Helpers for sans-io algorithms\n    next_action read(std::uint8_t& seqnum, bool keep_parsing_state = false)\n    {\n        // buffer is attached by top_level_algo\n        reader.prepare_read(seqnum, keep_parsing_state);\n        return next_action::read({});\n    }\n\n    template <class Serializable>\n    next_action write(const Serializable& msg, std::uint8_t& seqnum)\n    {\n        // use_ssl is attached by top_level_algo\n        write_buffer.clear();\n        auto res = serialize_top_level(msg, write_buffer, seqnum, max_buffer_size());\n        if (res.err)\n            return res.err;\n        seqnum = res.seqnum;\n        return next_action::write({write_buffer, false});\n    }\n\n    // Helpers to implement connection status in algorithms\n    error_code check_status_ready() const\n    {\n        switch (status)\n        {\n        case connection_status::not_connected: return client_errc::not_connected;\n        case connection_status::engaged_in_multi_function: return client_errc::engaged_in_multi_function;\n        default: BOOST_ASSERT(status == connection_status::ready); return error_code();\n        }\n    }\n\n    error_code check_status_multi_function() const\n    {\n        switch (status)\n        {\n        case connection_status::not_connected: return client_errc::not_connected;\n        case connection_status::ready: return client_errc::not_engaged_in_multi_function;\n        default: BOOST_ASSERT(status == connection_status::engaged_in_multi_function); return error_code();\n        }\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/csha2p_encrypt_password.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CSHA2P_ENCRYPT_PASSWORD_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_CSHA2P_ENCRYPT_PASSWORD_HPP\n\n// Having this in a separate file allows us to mock the OpenSSL API in the tests\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/sansio/auth_plugin_common.hpp>\n\n#include <boost/assert/source_location.hpp>\n#include <boost/container/small_vector.hpp>\n#include <boost/core/span.hpp>\n#include <boost/system/error_category.hpp>\n#include <boost/system/system_category.hpp>\n\n#include <cstdint>\n#include <memory>\n#include <openssl/bio.h>\n#include <openssl/err.h>\n#include <openssl/evp.h>\n#include <openssl/pem.h>\n#include <openssl/rsa.h>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// The OpenSSL category is passed as parameter to avoid including asio/ssl headers here.\n// Doing so would make mocking OpenSSL more difficult (more functions used)\ninline error_code translate_openssl_error(\n    unsigned long code,\n    const source_location* loc,\n    const system::error_category& openssl_category\n)\n{\n    // If ERR_SYSTEM_ERROR is true, the error code is a system error.\n    // This function only exists since OpenSSL 3\n#if OPENSSL_VERSION_NUMBER >= 0x30000000L\n    if (ERR_SYSTEM_ERROR(code))\n    {\n        return error_code(ERR_GET_REASON(code), system::system_category(), loc);\n    }\n#endif\n\n    // In OpenSSL < 3, error codes > 0x80000000 are reserved for the user,\n    // so it's unlikely that we will encounter these here. Overflow here\n    // is implementation-defined behavior (and not UB), so we're fine.\n    // This is what Asio does, anyway.\n    int int_code = static_cast<int>(code);\n\n    // An error code of zero would mean success, while this function is always\n    // called because an OpenSSL primitive failed. It might indicate that OpenSSL\n    // did not provide any extra error information. But it should still be an error\n    if (int_code == 0)\n        return error_code(client_errc::unknown_openssl_error, loc);\n    else\n        return error_code(int_code, openssl_category, loc);\n}\n\ninline container::small_vector<std::uint8_t, 512> csha2p_salt_password(\n    string_view password,\n    span<const std::uint8_t, scramble_size> scramble\n)\n{\n    // Salt the password, as a NULL-terminated string\n    container::small_vector<std::uint8_t, 512> res(password.size() + 1u, 0);\n    for (std::size_t i = 0; i < password.size(); ++i)\n        res[i] = password[i] ^ scramble[i % scramble.size()];\n\n    // Add the NULL terminator. It should be salted, too. Since 0 ^ U = U,\n    // the byte should be the scramble at the position we're in\n    res[password.size()] = scramble[password.size() % scramble.size()];\n\n    return res;\n}\n\ninline error_code csha2p_encrypt_password(\n    string_view password,\n    span<const std::uint8_t, scramble_size> scramble,\n    span<const std::uint8_t> server_key,\n    container::small_vector<std::uint8_t, 512>& output,\n    const system::error_category& openssl_category\n)\n{\n    // RAII helpers\n    struct bio_deleter\n    {\n        void operator()(BIO* bio) const noexcept { BIO_free(bio); }\n    };\n    using unique_bio = std::unique_ptr<BIO, bio_deleter>;\n\n    struct evp_pkey_deleter\n    {\n        void operator()(EVP_PKEY* pkey) const noexcept { EVP_PKEY_free(pkey); }\n    };\n    using unique_evp_pkey = std::unique_ptr<EVP_PKEY, evp_pkey_deleter>;\n\n    struct evp_pkey_ctx_deleter\n    {\n        void operator()(EVP_PKEY_CTX* ctx) const noexcept { EVP_PKEY_CTX_free(ctx); }\n    };\n    using unique_evp_pkey_ctx = std::unique_ptr<EVP_PKEY_CTX, evp_pkey_ctx_deleter>;\n\n    // Apply a sanity check to the key buffer size\n    constexpr std::size_t max_key_buffer_size = 1024u * 1024u;  // 1MB\n    if (server_key.size() > max_key_buffer_size)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return error_code(client_errc::protocol_value_error, &loc);\n    }\n\n    // Try to parse the private key\n    unique_bio bio{BIO_new_mem_buf(server_key.data(), static_cast<int>(server_key.size()))};\n    if (!bio)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n    unique_evp_pkey key(PEM_read_bio_PUBKEY(bio.get(), nullptr, nullptr, nullptr));\n    if (!key)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n\n    // Salt the password\n    auto salted_password = csha2p_salt_password(password, scramble);\n\n    // Set up the encryption context\n    unique_evp_pkey_ctx ctx(EVP_PKEY_CTX_new(key.get(), nullptr));\n    if (!ctx)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n    if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n    int rsa_pad_res = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING);\n    if (rsa_pad_res <= 0)\n    {\n        // If the server passed us a key type that does not support encryption,\n        // OpenSSL returns -2 and does not add an error to the stack (ERR_get_error returns 0).\n        // This shouldn't happen with real servers, so we re-use an existing error code and set\n        // the source location to allow diagnosis\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        if (rsa_pad_res == -2)\n            return error_code(client_errc::protocol_value_error, &loc);\n        else\n            return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n\n    // Allocate a buffer for encryption\n    int max_size = EVP_PKEY_size(key.get());\n    if (max_size <= 0)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n    output.resize(max_size);\n\n    // Encrypt\n    std::size_t actual_size = static_cast<std::size_t>(max_size);\n    if (EVP_PKEY_encrypt(\n            ctx.get(),\n            output.data(),\n            &actual_size,\n            salted_password.data(),\n            salted_password.size()\n        ) <= 0)\n    {\n        static constexpr auto loc = BOOST_CURRENT_LOCATION;\n        return translate_openssl_error(ERR_get_error(), &loc, openssl_category);\n    }\n\n    // Adjust size\n    BOOST_ASSERT(actual_size <= output.size());\n    output.resize(actual_size);\n\n    // Done\n    return error_code();\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/execute.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_EXECUTE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_EXECUTE_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/read_resultset_head.hpp>\n#include <boost/mysql/impl/internal/sansio/read_some_rows.hpp>\n#include <boost/mysql/impl/internal/sansio/start_execution.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass read_execute_response_algo\n{\n    int resume_point_{0};\n    read_resultset_head_algo read_head_st_;\n    read_some_rows_algo read_some_rows_st_;\n\npublic:\n    // We pass false because they are subordinate algos. This suppresses state checks.\n    // This is always a subordinate algo, so it never performs state checks.\n    read_execute_response_algo(execution_processor* proc) noexcept\n        : read_head_st_({proc}, false), read_some_rows_st_({proc, output_ref()}, false)\n    {\n    }\n\n    execution_processor& processor() { return read_head_st_.processor(); }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            while (!processor().is_complete())\n            {\n                if (processor().is_reading_head())\n                {\n                    read_head_st_.reset();\n                    while (!(act = read_head_st_.resume(st, diag, ec)).is_done())\n                        BOOST_MYSQL_YIELD(resume_point_, 1, act)\n                    if (act.error())\n                        return act;\n                }\n                else if (processor().is_reading_rows())\n                {\n                    read_some_rows_st_.reset();\n                    while (!(act = read_some_rows_st_.resume(st, diag, ec)).is_done())\n                        BOOST_MYSQL_YIELD(resume_point_, 2, act)\n                    if (act.error())\n                        return act;\n                }\n            }\n        }\n\n        return next_action();\n    }\n};\n\nclass execute_algo\n{\n    int resume_point_{0};\n    start_execution_algo start_execution_st_;\n    read_execute_response_algo read_response_st_;\n\n    execution_processor& processor() { return read_response_st_.processor(); }\n\npublic:\n    // We pass false to the start execution algo's constructor because it's a subordinate algo.\n    // This disables state checks.\n    execute_algo(execute_algo_params params) noexcept\n        : start_execution_st_({params.req, params.proc}, false), read_response_st_(params.proc)\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Check status\n            ec = st.check_status_ready();\n            if (ec)\n                return ec;\n\n            // Send request and read the first response\n            while (!(act = start_execution_st_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 1, act)\n            if (act.error())\n                return act;\n\n            // Read anything else\n            while (!(act = read_response_st_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 2, act)\n            return act;\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/handshake.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_HANDSHAKE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_HANDSHAKE_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n#include <boost/mysql/detail/ok_view.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/protocol/static_buffer.hpp>\n#include <boost/mysql/impl/internal/sansio/auth_plugin_common.hpp>\n#include <boost/mysql/impl/internal/sansio/caching_sha2_password.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/mysql_native_password.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/system/result.hpp>\n#include <boost/variant2/variant.hpp>\n\n#include <array>\n#include <cstdint>\n#include <cstring>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Stores which authentication plugin we're using, plus any required state. Variant-like\nclass any_authentication_plugin\n{\n    enum class type_t\n    {\n        mnp,\n        csha2p\n    };\n\n    // Which authentication plugin are we using?\n    type_t type_{type_t::mnp};\n\n    // State for algorithms that require stateful exchanges.\n    // mysql_native_password is stateless, so only caching_sha2_password has an entry here\n    csha2p_algo csha2p_;\n\npublic:\n    any_authentication_plugin() = default;\n\n    // Emplaces a plugin of the type given by plugin_name. Errors on unknown plugin\n    error_code emplace_by_name(string_view plugin_name)\n    {\n        if (plugin_name == mnp_plugin_name)\n        {\n            type_ = type_t::mnp;\n            return error_code();\n        }\n        else if (plugin_name == csha2p_plugin_name)\n        {\n            type_ = type_t::csha2p;\n            csha2p_ = csha2p_algo();  // Reset any leftover state, just in case\n            return error_code();\n        }\n        else\n        {\n            return client_errc::unknown_auth_plugin;\n        }\n    }\n\n    // Hashes the password with the selected plugin\n    static_buffer<max_hash_size> hash_password(\n        string_view password,\n        span<const std::uint8_t, scramble_size> scramble\n    ) const\n    {\n        switch (type_)\n        {\n        case type_t::mnp: return mnp_hash_password(password, scramble);\n        case type_t::csha2p: return csha2p_hash_password(password, scramble);\n        default: BOOST_ASSERT(false); return {};  // LCOV_EXCL_LINE\n        }\n    }\n\n    // Invokes the plugin action. Use when a more_data packet is received.\n    next_action resume(\n        connection_state_data& st,\n        span<const std::uint8_t> server_data,\n        string_view password,\n        span<const std::uint8_t, scramble_size> scramble,\n        bool secure_channel,\n        std::uint8_t& seqnum\n    )\n    {\n        switch (type_)\n        {\n        case type_t::mnp:\n            // This algorithm doesn't allow more data frames\n            return error_code(client_errc::bad_handshake_packet_type);\n        case type_t::csha2p:\n            return csha2p_.resume(st, server_data, password, scramble, secure_channel, seqnum);\n        default:\n            BOOST_ASSERT(false);\n            return next_action(client_errc::bad_handshake_packet_type);  // LCOV_EXCL_LINE\n        }\n    }\n\n    string_view name() const\n    {\n        switch (type_)\n        {\n        case type_t::mnp: return mnp_plugin_name;\n        case type_t::csha2p: return csha2p_plugin_name;\n        default: BOOST_ASSERT(false); return {};  // LCOV_EXCL_LINE\n        }\n    }\n};\n\nclass handshake_algo\n{\n    int resume_point_{0};\n    handshake_params hparams_;\n    any_authentication_plugin plugin_;\n    std::array<std::uint8_t, scramble_size> scramble_;\n    std::uint8_t sequence_number_{0};\n    bool secure_channel_{false};\n\n    static capabilities conditional_capability(bool condition, capabilities cap)\n    {\n        return condition ? cap : capabilities{};\n    }\n\n    // Given our params and the capabilities that the server sent us,\n    // performs capability negotiation, returning either the capabilities to\n    // send to the server or an error\n    static system::result<capabilities> negotiate_capabilities(\n        const handshake_params& params,\n        capabilities server_caps,\n        bool transport_supports_ssl\n    )\n    {\n        // The capabilities that we absolutely require. These are always set except in extremely old servers\n        constexpr capabilities mandatory_capabilities =\n            // We don't speak the older protocol\n            capabilities::protocol_41 |\n\n            // We only know how to deserialize the hello frame if this is set\n            capabilities::plugin_auth |\n\n            // Same as above\n            capabilities::plugin_auth_lenenc_data |\n\n            // This makes processing execute responses easier\n            capabilities::deprecate_eof |\n\n            // Used in MariaDB to signal 4.1 protocol. Always set in MySQL, too\n            capabilities::secure_connection;\n\n        // The capabilities that we support but don't require\n        constexpr capabilities optional_capabilities = capabilities::multi_results |\n                                                       capabilities::ps_multi_results;\n\n        auto ssl = transport_supports_ssl ? params.ssl() : ssl_mode::disable;\n        capabilities required_caps = mandatory_capabilities |\n                                     conditional_capability(\n                                         !params.database().empty(),\n                                         capabilities::connect_with_db\n                                     ) |\n                                     conditional_capability(\n                                         params.multi_queries(),\n                                         capabilities::multi_statements\n                                     ) |\n                                     conditional_capability(ssl == ssl_mode::require, capabilities::ssl);\n        if (has_capabilities(required_caps, capabilities::ssl) &&\n            !has_capabilities(server_caps, capabilities::ssl))\n        {\n            // This happens if the server doesn't have SSL configured. This special\n            // error code helps users diagnosing their problem a lot (server_unsupported doesn't).\n            return make_error_code(client_errc::server_doesnt_support_ssl);\n        }\n        else if (!has_capabilities(server_caps, required_caps))\n        {\n            return make_error_code(client_errc::server_unsupported);\n        }\n        return server_caps & (required_caps | optional_capabilities |\n                              conditional_capability(ssl == ssl_mode::enable, capabilities::ssl));\n    }\n\n    // Attempts to map the collection_id to a character set. We try to be conservative\n    // here, since servers will happily accept unknown collation IDs, silently defaulting\n    // to the server's default character set (often latin1, which is not Unicode).\n    static character_set collation_id_to_charset(std::uint16_t collation_id)\n    {\n        switch (collation_id)\n        {\n        case mysql_collations::utf8mb4_bin:\n        case mysql_collations::utf8mb4_general_ci: return utf8mb4_charset;\n        case mysql_collations::ascii_general_ci:\n        case mysql_collations::ascii_bin: return ascii_charset;\n        default: return character_set{};\n        }\n    }\n\n    // Saves the scramble, checking that it has the right size\n    error_code save_scramble(span<const std::uint8_t> value)\n    {\n        // All scrambles must have exactly this size. Otherwise, it's a protocol violation error\n        if (value.size() != scramble_size)\n            return client_errc::protocol_value_error;\n\n        // Store the scramble\n        std::memcpy(scramble_.data(), value.data(), scramble_size);\n\n        // Done\n        return error_code();\n    }\n\n    error_code process_hello(connection_state_data& st, diagnostics& diag, span<const std::uint8_t> buffer)\n    {\n        // Deserialize server hello\n        server_hello hello{};\n        auto err = deserialize_server_hello(buffer, hello, diag);\n        if (err)\n            return err;\n\n        // Check capabilities\n        auto negotiated_caps = negotiate_capabilities(hparams_, hello.server_capabilities, st.tls_supported);\n        if (negotiated_caps.has_error())\n            return negotiated_caps.error();\n\n        // Set capabilities, db flavor and connection ID\n        st.current_capabilities = *negotiated_caps;\n        st.flavor = hello.server;\n        st.connection_id = hello.connection_id;\n\n        // If we're using SSL, mark the channel as secure\n        secure_channel_ = secure_channel_ || has_capabilities(*negotiated_caps, capabilities::ssl);\n\n        // Save which authentication plugin we're using. Do this before saving the scramble,\n        // as an unknown plugin might have a scramble size different to what we know\n        err = plugin_.emplace_by_name(hello.auth_plugin_name);\n        if (err)\n            return err;\n\n        // Save the scramble for later\n        return save_scramble(hello.auth_plugin_data);\n    }\n\n    // Response to that initial greeting\n    ssl_request compose_ssl_request(const connection_state_data& st)\n    {\n        return ssl_request{\n            st.current_capabilities,\n            static_cast<std::uint32_t>(max_packet_size),\n            hparams_.connection_collation(),\n        };\n    }\n\n    next_action serialize_login_request(connection_state_data& st)\n    {\n        auto hashed_password = plugin_.hash_password(hparams_.password(), scramble_);\n        return st.write(\n            login_request{\n                st.current_capabilities,\n                static_cast<std::uint32_t>(max_packet_size),\n                hparams_.connection_collation(),\n                hparams_.username(),\n                hashed_password,\n                hparams_.database(),\n                plugin_.name(),\n            },\n            sequence_number_\n        );\n    }\n\n    // Processes auth_switch and auth_more_data messages, and leaves the result in auth_resp_\n    next_action process_auth_switch(connection_state_data& st, auth_switch msg)\n    {\n        // Emplace the new authentication plugin\n        auto ec = plugin_.emplace_by_name(msg.plugin_name);\n        if (ec)\n            return ec;\n\n        // Store the scramble for later (required by caching_sha2_password, for instance)\n        ec = save_scramble(msg.auth_data);\n        if (ec)\n            return ec;\n\n        // Hash the password\n        auto hashed_password = plugin_.hash_password(hparams_.password(), scramble_);\n\n        // Serialize the response\n        return st.write(auth_switch_response{hashed_password}, sequence_number_);\n    }\n\n    void on_success(connection_state_data& st, const ok_view& ok)\n    {\n        st.status = connection_status::ready;\n        st.backslash_escapes = ok.backslash_escapes();\n        st.current_charset = collation_id_to_charset(hparams_.connection_collation());\n    }\n\n    next_action resume_impl(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        if (ec)\n            return ec;\n\n        handshake_server_response resp(error_code{});\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n            // Handshake wipes out state, so no state checks are performed.\n            // Setup\n            st.reset();\n\n            // Read server greeting\n            BOOST_MYSQL_YIELD(resume_point_, 1, st.read(sequence_number_))\n\n            // Process server greeting\n            ec = process_hello(st, diag, st.reader.message());\n            if (ec)\n                return ec;\n\n            // SSL\n            if (has_capabilities(st.current_capabilities, capabilities::ssl))\n            {\n                // Send SSL request\n                BOOST_MYSQL_YIELD(resume_point_, 2, st.write(compose_ssl_request(st), sequence_number_))\n\n                // SSL handshake\n                BOOST_MYSQL_YIELD(resume_point_, 3, next_action::ssl_handshake())\n\n                // Mark the connection as using ssl\n                st.tls_active = true;\n            }\n\n            // Compose and send handshake response\n            BOOST_MYSQL_YIELD(resume_point_, 4, serialize_login_request(st))\n\n            // Receive the response\n            BOOST_MYSQL_YIELD(resume_point_, 5, st.read(sequence_number_))\n\n            // Process it\n            resp = deserialize_handshake_server_response(st.reader.message(), st.flavor, diag);\n\n            // Auth switches are only legal at this point. Handle the case here\n            if (resp.type == handshake_server_response::type_t::auth_switch)\n            {\n                // Write our packet\n                BOOST_MYSQL_YIELD(resume_point_, 6, process_auth_switch(st, resp.data.auth_sw))\n\n                // Read another packet\n                BOOST_MYSQL_YIELD(resume_point_, 7, st.read(sequence_number_))\n\n                // Deserialize it\n                resp = deserialize_handshake_server_response(st.reader.message(), st.flavor, diag);\n            }\n\n            // Now we will send/receive raw data packets from the server until an OK or error happens.\n            // Packets requiring responses are auth_more_data packets\n            while (resp.type == handshake_server_response::type_t::auth_more_data)\n            {\n                // Invoke the authentication plugin algorithm\n                act = plugin_.resume(\n                    st,\n                    resp.data.more_data,\n                    hparams_.password(),\n                    scramble_,\n                    secure_channel_,\n                    sequence_number_\n                );\n\n                // Do what the plugin says\n                if (act.type() == next_action_type::none)\n                {\n                    // The plugin signalled an error. Exit\n                    BOOST_ASSERT(act.error());\n                    return act;\n                }\n                else if (act.type() == next_action_type::write)\n                {\n                    // The plugin wants us to first write the message in the write buffer, then read\n                    BOOST_MYSQL_YIELD(resume_point_, 8, act)\n                    BOOST_MYSQL_YIELD(resume_point_, 9, st.read(sequence_number_))\n                }\n                else\n                {\n                    // The plugin wants us to read another packet\n                    BOOST_ASSERT(act.type() == next_action_type::read);\n                    BOOST_MYSQL_YIELD(resume_point_, 10, act)\n                }\n\n                // If we got here, we've successfully read a packet. Deserialize it\n                resp = deserialize_handshake_server_response(st.reader.message(), st.flavor, diag);\n            }\n\n            // If we got here, we've received a packet that terminates the algorithm\n            if (resp.type == handshake_server_response::type_t::ok)\n            {\n                // Auth success, quit\n                on_success(st, resp.data.ok);\n                return next_action();\n            }\n            else if (resp.type == handshake_server_response::type_t::error)\n            {\n                // Error, quit\n                return resp.data.err;\n            }\n            else\n            {\n                // Auth switches are no longer allowed at this point\n                BOOST_ASSERT(resp.type == handshake_server_response::type_t::auth_switch);\n                return error_code(client_errc::bad_handshake_packet_type);\n            }\n        }\n\n        // We should never get here\n        BOOST_ASSERT(false);\n        return next_action();  // LCOV_EXCL_LINE\n    }\n\npublic:\n    handshake_algo(handshake_algo_params params) noexcept\n        : hparams_(params.hparams), secure_channel_(params.secure_channel)\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        // On error, reset the connection's state to well-known values\n        auto act = resume_impl(st, diag, ec);\n        if (act.is_done() && act.error())\n            st.reset();\n        return act;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/message_reader.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_MESSAGE_READER_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_MESSAGE_READER_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/frame_header.hpp>\n#include <boost/mysql/impl/internal/sansio/read_buffer.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Flow:\n//   Prepare a read operation with prepare_read()\n//   In a loop, until done():\n//      prepare_buffer() to resize the buffer to an appropriate size\n//      Read bytes against buffer()\n//      Call resume with the number of bytes read\n// Or call prepare_read() and check done() to attempt to get a cached message\n//    (further prepare_read calls should use keep_state=true)\nclass message_reader\n{\npublic:\n    message_reader(\n        std::size_t initial_buffer_size,\n        std::size_t max_buffer_size = static_cast<std::size_t>(-1),\n        std::size_t max_frame_size = max_packet_size\n    )\n        : buffer_(initial_buffer_size, max_buffer_size), max_frame_size_(max_frame_size)\n    {\n    }\n\n    void reset()\n    {\n        buffer_.reset();\n        state_ = parse_state();\n    }\n\n    std::size_t max_buffer_size() const { return buffer_.max_size(); }\n\n    // Prepares a read operation. sequence_number should be kept alive until\n    // the next read is prepared or no more calls to resume() are expected.\n    // If keep_state=true, and the op is not complete, parsing state is preserved\n    void prepare_read(std::uint8_t& sequence_number, bool keep_state = false)\n    {\n        if (!keep_state || done())\n            state_ = parse_state(sequence_number);\n        else\n            state_.sequence_number = &sequence_number;\n        resume(0);\n    }\n\n    // Is parsing the current message done?\n    bool done() const { return state_.resume_point == -1; }\n\n    // Returns any errors generated during parsing. Requires this->done()\n    error_code error() const\n    {\n        BOOST_ASSERT(done());\n        return state_.ec;\n    }\n\n    // Returns the last parsed message. Valid until prepare_buffer()\n    // is next called. Requires done() && !error()\n    span<const std::uint8_t> message() const\n    {\n        BOOST_ASSERT(done());\n        BOOST_ASSERT(!error());\n        return buffer_.current_message();\n    }\n\n    // Returns buffer space suitable to read bytes to\n    span<std::uint8_t> buffer() { return buffer_.free_area(); }\n\n    // Removes old messages stored in the buffer, and resizes it, if required, to accommodate\n    // the message currently being parsed.\n    BOOST_ATTRIBUTE_NODISCARD\n    error_code prepare_buffer()\n    {\n        constexpr std::size_t small_move_threshold = 1024;\n        const std::size_t occupied_space = buffer_.pending_size() + buffer_.current_message_size();\n        // Compact the buffer (remove reserved area) if one of the following holds:\n        // 1. The cost of memmove is low: active data (current_message + pending)\n        // is small enough to make the copy cheap.\n        // 2. Compaction could prevent a reallocation.\n        if (occupied_space <= small_move_threshold ||\n            (state_.required_size > buffer_.free_size()))\n        {\n            buffer_.remove_reserved();\n        }\n        auto ec = buffer_.grow_to_fit(state_.required_size);\n        if (ec)\n            return ec;\n        state_.required_size = 0;\n        return error_code();\n    }\n\n    // The main operation. Call it after reading bytes against buffer(),\n    // with the number of bytes read\n    void resume(std::size_t bytes_read)\n    {\n        frame_header header{};\n        buffer_.move_to_pending(bytes_read);\n\n        switch (state_.resume_point)\n        {\n        case 0:\n\n            // Move the previously parsed message to the reserved area, if any\n            buffer_.move_to_reserved(buffer_.current_message_size());\n\n            while (true)\n            {\n                // Read the header\n                set_required_size(frame_header_size);\n                while (buffer_.pending_size() < frame_header_size)\n                    BOOST_MYSQL_YIELD_VOID(state_.resume_point, 1)\n\n                // Mark the header as belonging to the current message\n                buffer_.move_to_current_message(frame_header_size);\n\n                // Deserialize the header\n                header = deserialize_frame_header(span<const std::uint8_t, frame_header_size>(\n                    buffer_.pending_first() - frame_header_size,\n                    frame_header_size\n                ));\n\n                // Process the sequence number\n                if (*state_.sequence_number != header.sequence_number)\n                {\n                    state_.ec = client_errc::sequence_number_mismatch;\n                    state_.resume_point = -1;\n                    return;\n                }\n                ++*state_.sequence_number;\n\n                // Process the packet size\n                state_.body_bytes = header.size;\n                state_.more_frames_follow = (state_.body_bytes == max_frame_size_);\n\n                // We are done with the header\n                if (state_.is_first_frame)\n                {\n                    // If it's the 1st frame, we can just move the header bytes to the reserved\n                    // area, avoiding a big memmove\n                    buffer_.move_to_reserved(frame_header_size);\n                }\n                else\n                {\n                    buffer_.remove_current_message_last(frame_header_size);\n                }\n                state_.is_first_frame = false;\n\n                // Read the body\n                set_required_size(state_.body_bytes);\n                while (buffer_.pending_size() < state_.body_bytes)\n                    BOOST_MYSQL_YIELD_VOID(state_.resume_point, 2)\n\n                buffer_.move_to_current_message(state_.body_bytes);\n\n                // Check if we're done\n                if (!state_.more_frames_follow)\n                {\n                    state_.resume_point = -1;\n                    return;\n                }\n            }\n        }\n    }\n\n    // Exposed for testing\n    const read_buffer& internal_buffer() const { return buffer_; }\n\nprivate:\n    read_buffer buffer_;\n    std::size_t max_frame_size_;\n\n    struct parse_state\n    {\n        int resume_point{0};\n        std::uint8_t* sequence_number{};\n        bool is_first_frame{true};\n        std::size_t body_bytes{0};\n        bool more_frames_follow{false};\n        std::size_t required_size{0};\n        error_code ec;\n\n        parse_state() = default;\n        parse_state(std::uint8_t& seqnum) noexcept : sequence_number(&seqnum) {}\n    } state_;\n\n    void set_required_size(std::size_t required_bytes)\n    {\n        if (required_bytes > buffer_.pending_size())\n            state_.required_size = required_bytes - buffer_.pending_size();\n        else\n            state_.required_size = 0;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/mysql_native_password.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_MYSQL_NATIVE_PASSWORD_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_MYSQL_NATIVE_PASSWORD_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/static_buffer.hpp>\n#include <boost/mysql/impl/internal/sansio/auth_plugin_common.hpp>\n\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n#include <boost/system/result.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <openssl/sha.h>\n\n// Reference:\n// https://dev.mysql.com/doc/dev/mysql-server/8.4.4/page_protocol_connection_phase_authentication_methods_native_password_authentication.html\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Constants\nBOOST_INLINE_CONSTEXPR std::size_t mnp_hash_size = 20;\nBOOST_INLINE_CONSTEXPR const char* mnp_plugin_name = \"mysql_native_password\";\nstatic_assert(mnp_hash_size <= max_hash_size, \"\");\nstatic_assert(mnp_hash_size == SHA_DIGEST_LENGTH, \"Buffer size mismatch\");\n\n// SHA1( password ) XOR SHA1( \"20-bytes random data from server\" <concat> SHA1( SHA1( password ) ) )\ninline void mnp_hash_password_impl(\n    string_view password,\n    span<const std::uint8_t, scramble_size> scramble,\n    span<std::uint8_t, mnp_hash_size> output\n)\n{\n    // SHA1 (password)\n    std::array<std::uint8_t, mnp_hash_size> password_sha1;\n    SHA1(reinterpret_cast<const unsigned char*>(password.data()), password.size(), password_sha1.data());\n\n    // Add server scramble (salt)\n    std::array<std::uint8_t, scramble_size + mnp_hash_size> salted_buffer;\n    std::memcpy(salted_buffer.data(), scramble.data(), scramble.size());\n    SHA1(password_sha1.data(), password_sha1.size(), salted_buffer.data() + mnp_hash_size);\n    std::array<std::uint8_t, mnp_hash_size> salted_sha1;\n    SHA1(salted_buffer.data(), salted_buffer.size(), salted_sha1.data());\n\n    // XOR\n    for (std::size_t i = 0; i < mnp_hash_size; ++i)\n    {\n        output[i] = password_sha1[i] ^ salted_sha1[i];\n    }\n}\n\n// The static buffer size is chosen so that every plugin uses the same size\ninline static_buffer<max_hash_size> mnp_hash_password(\n    string_view password,\n    span<const std::uint8_t, scramble_size> scramble\n)\n{\n    // Empty passwords are not hashed\n    if (password.empty())\n        return {};\n\n    // Run the algorithm\n    static_buffer<max_hash_size> res(mnp_hash_size);\n    mnp_hash_password_impl(password, scramble, span<std::uint8_t, mnp_hash_size>(res.data(), mnp_hash_size));\n    return res;\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/ping.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_PING_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_PING_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass read_ping_response_algo\n{\n    int resume_point_{0};\n    std::uint8_t seqnum_{0};\n\npublic:\n    read_ping_response_algo(std::uint8_t seqnum) noexcept : seqnum_(seqnum) {}\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Issue a read\n            BOOST_MYSQL_YIELD(resume_point_, 1, st.read(seqnum_))\n            if (ec)\n                return ec;\n\n            // Process the OK packet and done\n            ec = st.deserialize_ok(diag);\n        }\n\n        return ec;\n    }\n};\n\ninline run_pipeline_algo_params setup_ping_pipeline(connection_state_data& st)\n{\n    // The ping request is fixed size and small. No buffer limit is enforced on it.\n    st.write_buffer.clear();\n    st.shared_pipeline_stages[0] = {\n        pipeline_stage_kind::ping,\n        serialize_top_level_checked(ping_command{}, st.write_buffer),\n        {}\n    };\n    return {\n        st.write_buffer,\n        {st.shared_pipeline_stages.data(), 1},\n        nullptr\n    };\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/prepare_statement.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_PREPARE_STATEMENT_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_PREPARE_STATEMENT_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass read_prepare_statement_response_algo\n{\n    int resume_point_{0};\n    std::uint8_t sequence_number_{0};\n    unsigned remaining_meta_{0};\n    statement res_;\n\n    error_code process_response(connection_state_data& st, diagnostics& diag)\n    {\n        prepare_stmt_response response{};\n        auto err = deserialize_prepare_stmt_response(st.reader.message(), st.flavor, response, diag);\n        if (err)\n            return err;\n        res_ = access::construct<statement>(response.id, response.num_params);\n        remaining_meta_ = response.num_columns + response.num_params;\n        return error_code();\n    }\n\npublic:\n    read_prepare_statement_response_algo(std::uint8_t seqnum) noexcept : sequence_number_(seqnum) {}\n\n    std::uint8_t& sequence_number() { return sequence_number_; }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        if (ec)\n            return ec;\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Read response\n            BOOST_MYSQL_YIELD(resume_point_, 1, st.read(sequence_number_))\n\n            // Process response\n            ec = process_response(st, diag);\n            if (ec)\n                return ec;\n\n            // Server sends now one packet per parameter and field.\n            // We ignore these for now.\n            for (; remaining_meta_ > 0u; --remaining_meta_)\n                BOOST_MYSQL_YIELD(resume_point_, 2, st.read(sequence_number_))\n        }\n\n        return next_action();\n    }\n\n    statement result(const connection_state_data&) const { return res_; }\n};\n\nclass prepare_statement_algo\n{\n    int resume_point_{0};\n    read_prepare_statement_response_algo read_response_st_;\n    string_view stmt_sql_;\n\npublic:\n    prepare_statement_algo(prepare_statement_algo_params params) noexcept\n        : read_response_st_(0u), stmt_sql_(params.stmt_sql)\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n            // Check status\n            ec = st.check_status_ready();\n            if (ec)\n                return ec;\n\n            // Send request\n            BOOST_MYSQL_YIELD(\n                resume_point_,\n                1,\n                st.write(prepare_stmt_command{stmt_sql_}, read_response_st_.sequence_number())\n            )\n            if (ec)\n                return ec;\n\n            // Read response\n            while (!(act = read_response_st_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 2, act)\n            return act;\n        }\n\n        return next_action();\n    }\n\n    statement result(const connection_state_data& st) const { return read_response_st_.result(st); }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/quit_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_QUIT_CONNECTION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_QUIT_CONNECTION_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass quit_connection_algo\n{\n    int resume_point_{0};\n    std::uint8_t sequence_number_{0};\n    bool should_perform_shutdown_{};\n\npublic:\n    quit_connection_algo(quit_connection_algo_params) noexcept {}\n\n    next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n    {\n        switch (resume_point_)\n        {\n        case 0:\n            // This can only be top-level in connection, and never in any_connection.\n            // State checks are not worthy here - already handled by close.\n\n            // Mark the session as finished\n            should_perform_shutdown_ = st.tls_active;\n            st.status = connection_status::not_connected;\n            st.tls_active = false;\n\n            // Send quit message\n            BOOST_MYSQL_YIELD(resume_point_, 1, st.write(quit_command(), sequence_number_))\n            if (ec)\n                return ec;\n\n            // If there was no error and TLS is active, attempt TLS shutdown.\n            // MySQL usually just closes the socket, instead of\n            // sending the close_notify message required by the shutdown, so we ignore this error.\n            if (should_perform_shutdown_)\n            {\n                BOOST_MYSQL_YIELD(resume_point_, 2, next_action::ssl_shutdown())\n            }\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* INCLUDE_BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_QUIT_CONNECTION_HPP_ */\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/read_buffer.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_BUFFER_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_BUFFER_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/next_power_of_two.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Custom buffer type optimized for read operations performed in the MySQL protocol.\n// The buffer is a single, resizable chunk of memory with four areas:\n//   - Reserved area: messages that have already been read but are kept alive,\n//     either because we need them or because we haven't cleaned them yet.\n//   - Current message area: delimits the message we are currently parsing.\n//   - Pending bytes area: bytes we've read but haven't been parsed into a message yet.\n//   - Free area: free space for more bytes to be read.\nclass read_buffer\n{\n    std::vector<std::uint8_t> buffer_;\n    std::size_t current_message_offset_{0};\n    std::size_t pending_offset_{0};\n    std::size_t free_offset_{0};\n    std::size_t max_size_;\n\npublic:\n    read_buffer(std::size_t size, std::size_t max_size = static_cast<std::size_t>(-1))\n        : buffer_(size), max_size_(max_size)\n    {\n        BOOST_ASSERT(size <= max_size_);\n    }\n\n    void reset() noexcept\n    {\n        current_message_offset_ = 0;\n        pending_offset_ = 0;\n        free_offset_ = 0;\n    }\n\n    // Whole buffer accessors\n    const std::uint8_t* first() const noexcept { return buffer_.data(); }\n    std::size_t size() const noexcept { return buffer_.size(); }\n    std::size_t max_size() const { return max_size_; }\n\n    // Area accessors\n    std::uint8_t* reserved_first() noexcept { return buffer_.data(); }\n    const std::uint8_t* reserved_first() const noexcept { return buffer_.data(); }\n    std::uint8_t* current_message_first() noexcept { return buffer_.data() + current_message_offset_; }\n    const std::uint8_t* current_message_first() const noexcept\n    {\n        return buffer_.data() + current_message_offset_;\n    }\n    std::uint8_t* pending_first() noexcept { return buffer_.data() + pending_offset_; }\n    const std::uint8_t* pending_first() const noexcept { return buffer_.data() + pending_offset_; }\n    std::uint8_t* free_first() noexcept { return buffer_.data() + free_offset_; }\n    const std::uint8_t* free_first() const noexcept { return buffer_.data() + free_offset_; }\n\n    std::size_t reserved_size() const noexcept { return current_message_offset_; }\n    std::size_t current_message_size() const noexcept { return pending_offset_ - current_message_offset_; }\n    std::size_t pending_size() const noexcept { return free_offset_ - pending_offset_; }\n    std::size_t free_size() const noexcept { return buffer_.size() - free_offset_; }\n\n    span<const std::uint8_t> reserved_area() const noexcept { return {reserved_first(), reserved_size()}; }\n    span<const std::uint8_t> current_message() const noexcept\n    {\n        return {current_message_first(), current_message_size()};\n    }\n    span<const std::uint8_t> pending_area() const noexcept { return {pending_first(), pending_size()}; }\n    span<std::uint8_t> free_area() noexcept { return {free_first(), free_size()}; }\n\n    // Moves n bytes from the free to the processing area (e.g. they've been read)\n    void move_to_pending(std::size_t length) noexcept\n    {\n        BOOST_ASSERT(length <= free_size());\n        free_offset_ += length;\n    }\n\n    // Moves n bytes from the processing to the current message area\n    void move_to_current_message(std::size_t length) noexcept\n    {\n        BOOST_ASSERT(length <= pending_size());\n        pending_offset_ += length;\n    }\n\n    // Removes the last length bytes from the current message area,\n    // effectively memmove'ing all subsequent bytes backwards.\n    // Used to remove intermediate headers. length must be > 0\n    void remove_current_message_last(std::size_t length) noexcept\n    {\n        BOOST_ASSERT(length <= current_message_size());\n        BOOST_ASSERT(length > 0);\n        std::memmove(pending_first() - length, pending_first(), pending_size());\n        pending_offset_ -= length;\n        free_offset_ -= length;\n    }\n\n    // Moves length bytes from the current message area to the reserved area\n    // Used to move entire parsed messages or message headers\n    void move_to_reserved(std::size_t length) noexcept\n    {\n        BOOST_ASSERT(length <= current_message_size());\n        current_message_offset_ += length;\n    }\n\n    // Removes the reserved area, effectively memmove'ing evth backwards\n    void remove_reserved() noexcept\n    {\n        if (reserved_size() > 0)\n        {\n            // If reserved_size() > 0, these ptrs should never be NULL\n            void* to = buffer_.data();\n            const void* from = current_message_first();\n            BOOST_ASSERT(to != nullptr);\n            BOOST_ASSERT(from != nullptr);\n            std::size_t currmsg_size = current_message_size();\n            std::size_t pend_size = pending_size();\n            std::memmove(to, from, currmsg_size + pend_size);\n            current_message_offset_ = 0;\n            pending_offset_ = currmsg_size;\n            free_offset_ = currmsg_size + pend_size;\n        }\n    }\n\n    // Makes sure the free size is at least n bytes long; resizes the buffer if required\n    // Buffer grows to power of two, unless limited by max_size\n    BOOST_ATTRIBUTE_NODISCARD\n    error_code grow_to_fit(std::size_t n)\n    {\n        if (free_size() < n)\n        {\n            std::size_t required_size = buffer_.size() + n - free_size();\n            std::size_t new_size = next_power_of_two<std::size_t>(required_size);\n            if (new_size > max_size_)\n            {\n                new_size = required_size;\n                if (new_size > max_size_)\n                    return client_errc::max_buffer_size_exceeded;\n            }\n            buffer_.resize(new_size);\n        }\n        return error_code();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/read_resultset_head.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_RESULTSET_HEAD_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_RESULTSET_HEAD_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline error_code process_execution_response(\n    connection_state_data& st,\n    execution_processor& proc,\n    span<const std::uint8_t> msg,\n    diagnostics& diag\n)\n{\n    auto response = deserialize_execute_response(msg, st.flavor, diag);\n    error_code err;\n    switch (response.type)\n    {\n    case execute_response::type_t::error: err = response.data.err; break;\n    case execute_response::type_t::ok_packet:\n        st.backslash_escapes = response.data.ok_pack.backslash_escapes();\n        err = proc.on_head_ok_packet(response.data.ok_pack, diag);\n        break;\n    case execute_response::type_t::num_fields: proc.on_num_meta(response.data.num_fields); break;\n    }\n    return err;\n}\n\ninline error_code process_field_definition(\n    execution_processor& proc,\n    span<const std::uint8_t> msg,\n    diagnostics& diag\n)\n{\n    // Deserialize the message\n    coldef_view coldef{};\n    auto err = deserialize_column_definition(msg, coldef);\n    if (err)\n        return err;\n\n    // Notify the processor\n    return proc.on_meta(coldef, diag);\n}\n\nclass read_resultset_head_algo\n{\n    execution_processor* proc_;\n    bool is_top_level_;\n\n    struct state_t\n    {\n        int resume_point{0};\n    } state_;\n\n    // Status changes are only performed if we're the top-level algorithm.\n    // After an error, multi-function operations are considered finished\n    void maybe_set_status_ready(connection_state_data& st) const\n    {\n        if (is_top_level_)\n            st.status = connection_status::ready;\n    }\n\npublic:\n    read_resultset_head_algo(read_resultset_head_algo_params params, bool is_top_level = true) noexcept\n        : proc_(params.proc), is_top_level_(is_top_level)\n    {\n    }\n\n    void reset() { state_ = state_t{}; }\n\n    execution_processor& processor() { return *proc_; }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        switch (state_.resume_point)\n        {\n        case 0:\n\n            // If we're not reading head, return (for compatibility, we don't error here).\n            if (!proc_->is_reading_head())\n                return next_action();\n\n            // Check connection status. The check is only correct if we're the top-level algorithm\n            if (is_top_level_)\n            {\n                ec = st.check_status_multi_function();\n                if (ec)\n                    return ec;\n            }\n\n            // Read the response\n            BOOST_MYSQL_YIELD(state_.resume_point, 1, st.read(proc_->sequence_number()))\n            if (ec)\n            {\n                maybe_set_status_ready(st);\n                return ec;\n            }\n\n            // Response may be: ok_packet, err_packet, local infile request\n            // (not implemented), or response with fields\n            ec = process_execution_response(st, *proc_, st.reader.message(), diag);\n            if (ec)\n            {\n                maybe_set_status_ready(st);\n                return ec;\n            }\n\n            // Read all of the field definitions\n            while (proc_->is_reading_meta())\n            {\n                // Read a message\n                BOOST_MYSQL_YIELD(state_.resume_point, 2, st.read(proc_->sequence_number()))\n                if (ec)\n                {\n                    maybe_set_status_ready(st);\n                    return ec;\n                }\n\n                // Process the metadata packet\n                ec = process_field_definition(*proc_, st.reader.message(), diag);\n                if (ec)\n                {\n                    maybe_set_status_ready(st);\n                    return ec;\n                }\n            }\n\n            // No EOF packet is expected here, as we require deprecate EOF capabilities\n\n            // If the received the final OK packet, we're no longer running a multi-function op\n            if (proc_->is_complete() && is_top_level_)\n                st.status = connection_status::ready;\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/read_some_rows.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_SOME_ROWS_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_SOME_ROWS_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass read_some_rows_algo\n{\n    execution_processor* proc_;\n    output_ref output_;\n    bool is_top_level_;\n\n    struct state_t\n    {\n        int resume_point{0};\n        std::size_t rows_read{0};\n    } state_;\n\n    BOOST_ATTRIBUTE_NODISCARD static std::pair<error_code, std::size_t> process_some_rows(\n        connection_state_data& st,\n        execution_processor& proc,\n        output_ref output,\n        diagnostics& diag\n    )\n    {\n        // Process all read messages until they run out, an error happens\n        // or an EOF is received\n        std::size_t read_rows = 0;\n        error_code err;\n        proc.on_row_batch_start();\n        while (true)\n        {\n            // Check for errors (like seqnum mismatches)\n            if (st.reader.error())\n                return {st.reader.error(), read_rows};\n\n            // Get the row message\n            auto buff = st.reader.message();\n\n            // Deserialize it\n            auto res = deserialize_row_message(buff, st.flavor, diag);\n            if (res.type == row_message::type_t::error)\n            {\n                err = res.data.err;\n            }\n            else if (res.type == row_message::type_t::row)\n            {\n                output.set_offset(read_rows);\n                err = proc.on_row(res.data.row, output, st.shared_fields);\n                if (!err)\n                    ++read_rows;\n            }\n            else\n            {\n                st.backslash_escapes = res.data.ok_pack.backslash_escapes();\n                err = proc.on_row_ok_packet(res.data.ok_pack);\n            }\n\n            if (err)\n                return {err, read_rows};\n\n            // TODO: can we make this better?\n            if (!proc.is_reading_rows() || read_rows >= output.max_size())\n                break;\n\n            // Attempt to parse the next message\n            st.reader.prepare_read(proc.sequence_number());\n            if (!st.reader.done())\n                break;\n        }\n        proc.on_row_batch_finish();\n        return {error_code(), read_rows};\n    }\n\n    // Status changes are only performed if we're the top-level algorithm.\n    // After an error, multi-function operations are considered finished\n    void maybe_set_status_ready(connection_state_data& st) const\n    {\n        if (is_top_level_)\n            st.status = connection_status::ready;\n    }\n\npublic:\n    read_some_rows_algo(read_some_rows_algo_params params, bool is_top_level = true) noexcept\n        : proc_(params.proc), output_(params.output), is_top_level_(is_top_level)\n    {\n    }\n\n    void reset() { state_ = state_t{}; }\n\n    const execution_processor& processor() const { return *proc_; }\n    execution_processor& processor() { return *proc_; }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        switch (state_.resume_point)\n        {\n        case 0:\n\n            // Clear any previous use of shared fields.\n            // Required for the dynamic version to work.\n            st.shared_fields.clear();\n\n            // If we are not reading rows, return (for compatibility, we don't error here)\n            if (!processor().is_reading_rows())\n                return next_action();\n\n            // Check connection status. The check is only correct if we're the top-level algorithm\n            if (is_top_level_)\n            {\n                ec = st.check_status_multi_function();\n                if (ec)\n                    return ec;\n            }\n\n            // Read at least one message. Keep parsing state, in case a previous message\n            // was parsed partially\n            BOOST_MYSQL_YIELD(state_.resume_point, 1, st.read(proc_->sequence_number(), true))\n            if (ec)\n            {\n                // If there was an error reading the message, we're no longer in a multi-function operation\n                maybe_set_status_ready(st);\n                return ec;\n            }\n\n            // Process messages\n            std::tie(ec, state_.rows_read) = process_some_rows(st, *proc_, output_, diag);\n            if (ec)\n            {\n                // If there was an error parsing the message, we're no longer in a multi-function operation\n                maybe_set_status_ready(st);\n                return ec;\n            }\n\n            // If we received the final OK packet, we're no longer in a multi-function operation\n            if (proc_->is_complete() && is_top_level_)\n                st.status = connection_status::ready;\n        }\n\n        return next_action();\n    }\n\n    std::size_t result(const connection_state_data&) const { return state_.rows_read; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/read_some_rows_dynamic.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_SOME_ROWS_DYNAMIC_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_READ_SOME_ROWS_DYNAMIC_HPP\n\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/execution_processor/execution_state_impl.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/read_some_rows.hpp>\n\n#include <cstddef>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass read_some_rows_dynamic_algo : public read_some_rows_algo\n{\npublic:\n    // This algorithm is always top-level\n    read_some_rows_dynamic_algo(read_some_rows_dynamic_algo_params params) noexcept\n        : read_some_rows_algo(read_some_rows_algo_params{params.exec_st, output_ref()})\n    {\n    }\n\n    rows_view result(const connection_state_data& st) const\n    {\n        std::size_t num_rows = read_some_rows_algo::result(st);\n        std::size_t num_cols = static_cast<const execution_state_impl&>(processor()).meta().size();\n        return access::construct<rows_view>(st.shared_fields.data(), num_rows * num_cols, num_cols);\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/reset_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_RESET_CONNECTION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_RESET_CONNECTION_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass read_reset_connection_response_algo\n{\n    int resume_point_{0};\n    std::uint8_t seqnum_{0};\n\npublic:\n    read_reset_connection_response_algo(std::uint8_t seqnum) noexcept : seqnum_(seqnum) {}\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Read the reset response\n            BOOST_MYSQL_YIELD(resume_point_, 1, st.read(seqnum_))\n            if (ec)\n                return ec;\n\n            // Verify it's what we expected\n            ec = st.deserialize_ok(diag);\n            if (!ec)\n            {\n                // Reset was successful. Resetting changes the connection's character set\n                // to the server's default, which is an unknown value that doesn't have to match\n                // what was specified in handshake. As a safety measure, clear the current charset\n                st.current_charset = character_set{};\n            }\n\n            // Done\n        }\n\n        return ec;\n    }\n};\n\ninline run_pipeline_algo_params setup_reset_connection_pipeline(connection_state_data& st)\n{\n    // reset_connection request is fixed size and small, so we don't enforce any buffer limit\n    st.write_buffer.clear();\n    st.shared_pipeline_stages[0] = {\n        pipeline_stage_kind::reset_connection,\n        serialize_top_level_checked(reset_connection_command{}, st.write_buffer),\n        {}\n    };\n    return {\n        st.write_buffer,\n        {st.shared_pipeline_stages.data(), 1},\n        nullptr\n    };\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* INCLUDE_BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_CLOSE_STATEMENT_HPP_ */\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/run_pipeline.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_RUN_PIPELINE_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_RUN_PIPELINE_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/is_fatal_error.hpp>\n#include <boost/mysql/pipeline.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/execute.hpp>\n#include <boost/mysql/impl/internal/sansio/ping.hpp>\n#include <boost/mysql/impl/internal/sansio/prepare_statement.hpp>\n#include <boost/mysql/impl/internal/sansio/reset_connection.hpp>\n#include <boost/mysql/impl/internal/sansio/set_character_set.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nclass run_pipeline_algo\n{\n    union any_read_algo\n    {\n        std::nullptr_t nothing;\n        read_execute_response_algo execute;\n        read_prepare_statement_response_algo prepare_statement;\n        read_reset_connection_response_algo reset_connection;\n        read_ping_response_algo ping;\n        read_set_character_set_response_algo set_character_set;\n\n        any_read_algo() noexcept : nothing{} {}\n    };\n\n    span<const std::uint8_t> request_buffer_;\n    span<const pipeline_request_stage> stages_;\n    std::vector<stage_response>* response_;\n\n    int resume_point_{0};\n    std::size_t current_stage_index_{0};\n    error_code pipeline_ec_;  // Result of the entire operation\n    bool has_hatal_error_{};  // If true, fail further stages with pipeline_ec_\n    any_read_algo read_response_algo_;\n    diagnostics temp_diag_;\n\n    void setup_response()\n    {\n        if (response_)\n        {\n            // Create as many response items as request stages\n            response_->resize(stages_.size());\n\n            // Setup them\n            for (std::size_t i = 0u; i < stages_.size(); ++i)\n            {\n                // Execution stages need to be initialized to results objects.\n                // Otherwise, clear any previous content\n                auto& impl = access::get_impl((*response_)[i]);\n                if (stages_[i].kind == pipeline_stage_kind::execute)\n                    impl.emplace_results();\n                else\n                    impl.emplace_error();\n            }\n        }\n    }\n\n    void setup_current_stage(const connection_state_data& st)\n    {\n        // Reset previous data\n        temp_diag_.clear();\n\n        // Setup read algo\n        auto stage = stages_[current_stage_index_];\n        switch (stage.kind)\n        {\n        case pipeline_stage_kind::execute:\n        {\n            BOOST_ASSERT(response_ != nullptr);  // we don't support execution ignoring the response\n            auto& processor = access::get_impl((*response_)[current_stage_index_]).get_processor();\n            processor.reset(stage.stage_specific.enc, st.meta_mode);\n            processor.sequence_number() = stage.seqnum;\n            read_response_algo_.execute = {&processor};\n            break;\n        }\n        case pipeline_stage_kind::prepare_statement:\n            read_response_algo_.prepare_statement = {stage.seqnum};\n            break;\n        case pipeline_stage_kind::close_statement:\n            // Close statement doesn't have a response\n            read_response_algo_.nothing = nullptr;\n            break;\n        case pipeline_stage_kind::set_character_set:\n            read_response_algo_.set_character_set = {stage.stage_specific.charset, stage.seqnum};\n            break;\n        case pipeline_stage_kind::reset_connection:\n            read_response_algo_.reset_connection = {stage.seqnum};\n            break;\n        case pipeline_stage_kind::ping: read_response_algo_.ping = {stage.seqnum}; break;\n        default: BOOST_ASSERT(false);  // LCOV_EXCL_LINE\n        }\n    }\n\n    void set_stage_error(error_code ec, diagnostics&& diag)\n    {\n        if (response_)\n        {\n            access::get_impl((*response_)[current_stage_index_]).set_error(ec, std::move(diag));\n        }\n    }\n\n    void on_stage_finished(const connection_state_data& st, diagnostics& output_diag, error_code stage_ec)\n    {\n        if (stage_ec)\n        {\n            // If the error was fatal, fail successive stages.\n            // This error is the result of the operation\n            if (is_fatal_error(stage_ec))\n            {\n                pipeline_ec_ = stage_ec;\n                output_diag = temp_diag_;\n                has_hatal_error_ = true;\n            }\n            else if (!pipeline_ec_)\n            {\n                // In the absence of fatal errors, the first error we encounter is the result of the operation\n                pipeline_ec_ = stage_ec;\n                output_diag = temp_diag_;\n            }\n\n            // Propagate the error\n            if (response_ != nullptr)\n            {\n                set_stage_error(stage_ec, std::move(temp_diag_));\n            }\n        }\n        else\n        {\n            if (stages_[current_stage_index_].kind == pipeline_stage_kind::prepare_statement)\n            {\n                // Propagate results. We don't support prepare statements ignoring the response\n                BOOST_ASSERT(response_ != nullptr);\n                access::get_impl((*response_)[current_stage_index_])\n                    .set_result(read_response_algo_.prepare_statement.result(st));\n            }\n        }\n    }\n\n    next_action resume_read_algo(connection_state_data& st, error_code ec)\n    {\n        switch (stages_[current_stage_index_].kind)\n        {\n        case pipeline_stage_kind::execute: return read_response_algo_.execute.resume(st, temp_diag_, ec);\n        case pipeline_stage_kind::prepare_statement:\n            return read_response_algo_.prepare_statement.resume(st, temp_diag_, ec);\n        case pipeline_stage_kind::reset_connection:\n            return read_response_algo_.reset_connection.resume(st, temp_diag_, ec);\n        case pipeline_stage_kind::set_character_set:\n            return read_response_algo_.set_character_set.resume(st, temp_diag_, ec);\n        case pipeline_stage_kind::ping: return read_response_algo_.ping.resume(st, temp_diag_, ec);\n        case pipeline_stage_kind::close_statement: return next_action();  // has no response\n        default: BOOST_ASSERT(false); return next_action();               // LCOV_EXCL_LINE\n        }\n    }\n\npublic:\n    run_pipeline_algo(run_pipeline_algo_params params) noexcept\n        : request_buffer_(params.request_buffer), stages_(params.request_stages), response_(params.response)\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Clear previous state\n            setup_response();\n\n            // If the request is empty, don't do anything\n            if (stages_.empty())\n                break;\n\n            // Check status\n            ec = st.check_status_ready();\n            if (ec)\n                return ec;\n\n            // Write the request. use_ssl is attached by top_level_algo\n            BOOST_MYSQL_YIELD(resume_point_, 1, next_action::write({request_buffer_, false}))\n\n            // If writing the request failed, fail all the stages with the given error code\n            if (ec)\n            {\n                pipeline_ec_ = ec;\n                has_hatal_error_ = true;\n            }\n\n            // For each stage\n            for (; current_stage_index_ < stages_.size(); ++current_stage_index_)\n            {\n                // If there was a fatal error, just set the error and move forward\n                if (has_hatal_error_)\n                {\n                    set_stage_error(pipeline_ec_, diagnostics(diag));\n                    continue;\n                }\n\n                // Setup the stage\n                setup_current_stage(st);\n\n                // Run it until completion\n                ec.clear();\n                while (!(act = resume_read_algo(st, ec)).is_done())\n                    BOOST_MYSQL_YIELD(resume_point_, 2, act)\n\n                // Process the stage's result\n                on_stage_finished(st, diag, act.error());\n            }\n        }\n\n        return pipeline_ec_;\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/set_character_set.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_SET_CHARACTER_SET_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_SET_CHARACTER_SET_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <boost/system/result.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Securely compose a SET NAMES statement\ninline system::result<std::string> compose_set_names(character_set charset)\n{\n    // The character set should not be default-constructed\n    BOOST_ASSERT(charset.name != nullptr);\n\n    // For security, if the character set has non-ascii characters in it name, reject it.\n    format_context ctx(format_options{ascii_charset, true});\n    ctx.append_raw(\"SET NAMES \").append_value(charset.name);\n    return std::move(ctx).get();\n}\n\nclass read_set_character_set_response_algo\n{\n    int resume_point_{0};\n    character_set charset_;\n    std::uint8_t seqnum_{0};\n\npublic:\n    read_set_character_set_response_algo(character_set charset, std::uint8_t seqnum)\n        : charset_(charset), seqnum_(seqnum)\n    {\n    }\n    character_set charset() const { return charset_; }\n    std::uint8_t& sequence_number() { return seqnum_; }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        // SET NAMES never returns rows. Using execute requires us to allocate\n        // a results object, which we can avoid by simply sending the query and reading the OK response.\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Read the response\n            BOOST_MYSQL_YIELD(resume_point_, 1, st.read(seqnum_))\n            if (ec)\n                return ec;\n\n            // Verify it's what we expected\n            ec = st.deserialize_ok(diag);\n            if (ec)\n                return ec;\n\n            // If we were successful, update the character set\n            st.current_charset = charset_;\n        }\n\n        return next_action();\n    }\n};\n\nclass set_character_set_algo\n{\n    int resume_point_{0};\n    read_set_character_set_response_algo read_response_st_;\n\n    next_action compose_request(connection_state_data& st)\n    {\n        auto q = compose_set_names(read_response_st_.charset());\n        if (q.has_error())\n            return q.error();\n        return st.write(query_command{q.value()}, read_response_st_.sequence_number());\n    }\n\npublic:\n    set_character_set_algo(set_character_set_algo_params params) noexcept\n        : read_response_st_(params.charset, 0u)\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        // SET NAMES never returns rows. Using execute requires us to allocate\n        // a results object, which we can avoid by simply sending the query and reading the OK response.\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Check status\n            ec = st.check_status_ready();\n            if (ec)\n                return ec;\n\n            // Send the execution request\n            BOOST_MYSQL_YIELD(resume_point_, 1, compose_request(st))\n            if (ec)\n                return ec;\n\n            // Read the response\n            while (!(act = read_response_st_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 2, act)\n            return act;\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/start_execution.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_START_EXECUTION_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_START_EXECUTION_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n#include <boost/mysql/detail/output_string.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/read_resultset_head.hpp>\n\n#include <boost/core/span.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// A serializable to generate the query in the write buffer without copies\nstruct query_with_params\n{\n    constant_string_view query;\n    span<const format_arg> args;\n    format_options opts;\n\n    void serialize(serialization_context& ctx) const\n    {\n        // Create a format context\n        auto fmt_ctx = access::construct<format_context_base>(output_string_ref::create(ctx), opts);\n\n        // Serialize the query header\n        ctx.add(0x03);\n\n        // Serialize the actual query\n        vformat_sql_to(fmt_ctx, query, args);\n\n        // Check for errors\n        ctx.add_error(fmt_ctx.error_state());\n    }\n};\n\nclass start_execution_algo\n{\n    int resume_point_{0};\n    read_resultset_head_algo read_head_st_;\n    any_execution_request req_;\n    bool is_top_level_;\n\n    std::uint8_t& seqnum() { return processor().sequence_number(); }\n    execution_processor& processor() { return read_head_st_.processor(); }\n\n    static resultset_encoding get_encoding(any_execution_request::type_t type)\n    {\n        switch (type)\n        {\n        case any_execution_request::type_t::query:\n        case any_execution_request::type_t::query_with_params: return resultset_encoding::text;\n        case any_execution_request::type_t::stmt: return resultset_encoding::binary;\n        default: BOOST_ASSERT(false); return resultset_encoding::text;  // LCOV_EXCL_LINE\n        }\n    }\n\n    next_action write_query_with_params(\n        connection_state_data& st,\n        any_execution_request::data_t::query_with_params_t data\n    )\n    {\n        // Determine format options\n        if (st.current_charset.name == nullptr)\n        {\n            return error_code(client_errc::unknown_character_set);\n        }\n        format_options opts{st.current_charset, st.backslash_escapes};\n\n        // Write the request\n        return st.write(query_with_params{data.query, data.args, opts}, seqnum());\n    }\n\n    next_action write_stmt(connection_state_data& st, any_execution_request::data_t::stmt_t data)\n    {\n        if (data.num_params != data.params.size())\n            return error_code(client_errc::wrong_num_params);\n        return st.write(execute_stmt_command{data.stmt_id, data.params}, seqnum());\n    }\n\n    next_action compose_request(connection_state_data& st)\n    {\n        switch (req_.type)\n        {\n        case any_execution_request::type_t::query: return st.write(query_command{req_.data.query}, seqnum());\n        case any_execution_request::type_t::query_with_params:\n            return write_query_with_params(st, req_.data.query_with_params);\n        case any_execution_request::type_t::stmt: return write_stmt(st, req_.data.stmt);\n        default: BOOST_ASSERT(false); return next_action();  // LCOV_EXCL_LINE\n        }\n    }\n\npublic:\n    // We pass false to the read head algo's constructor because it's a subordinate algos.\n    // This suppresses state checks.\n    start_execution_algo(start_execution_algo_params params, bool is_top_level = true) noexcept\n        : read_head_st_({params.proc}, false), req_(params.req), is_top_level_(is_top_level)\n    {\n    }\n\n    next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n            // Check connection status. The check is only correct if we're the top-level algorithm\n            if (is_top_level_)\n            {\n                ec = st.check_status_ready();\n                if (ec)\n                    return ec;\n            }\n\n            // Reset the processor\n            processor().reset(get_encoding(req_.type), st.meta_mode);\n\n            // Send the execution request\n            BOOST_MYSQL_YIELD(resume_point_, 1, compose_request(st))\n            if (ec)\n                return ec;\n\n            // If the request was sent successfully, and we're the top-level algorithm,\n            // we're now running a multi-function operation. The status flag is cleared\n            // by the other algorithms on error or when an OK packet is received\n            if (is_top_level_)\n                st.status = connection_status::engaged_in_multi_function;\n\n            // Read the first resultset's head and return its result\n            while (!(act = read_head_st_.resume(st, diag, ec)).is_done())\n                BOOST_MYSQL_YIELD(resume_point_, 2, act)\n\n            // If there was an error, we're no longer running a multi-function operation\n            if (act.error())\n            {\n                if (is_top_level_)\n                    st.status = connection_status::ready;\n                return act;\n            }\n\n            // If we received the final OK packet, we're no longer running a multi-function operation\n            if (processor().is_complete() && is_top_level_)\n                st.status = connection_status::ready;\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/sansio/top_level_algo.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_TOP_LEVEL_ALGO_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_TOP_LEVEL_ALGO_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/run_pipeline.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\n#ifdef BOOST_USE_VALGRIND\n#include <valgrind/memcheck.h>\n#endif\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Valgrind\n#ifdef BOOST_USE_VALGRIND\ninline void valgrind_make_mem_defined(const void* data, std::size_t size)\n{\n    VALGRIND_MAKE_MEM_DEFINED(data, size);\n}\n#else\ninline void valgrind_make_mem_defined(const void*, std::size_t) noexcept {}\n#endif\n\n// InnerAlgo should have\n//   Constructible from the args forwarded by the ctor.\n//   next_action resume(connection_state_data&, error_code);\n//   AlgoParams::result_type result(const connection_state_data&) const; // if AlgoParams::result_type != void\ntemplate <class InnerAlgo>\nclass top_level_algo\n{\n    int resume_point_{0};\n    connection_state_data* st_;\n    diagnostics* diag_;\n    InnerAlgo algo_;\n    span<const std::uint8_t> bytes_to_write_;\n\npublic:\n    template <class... Args>\n    top_level_algo(connection_state_data& st, diagnostics& diag, Args&&... args)\n        : st_(&st), diag_(&diag), algo_(std::forward<Args>(args)...)\n    {\n    }\n\n    const InnerAlgo& inner_algo() const { return algo_; }\n\n    next_action resume(error_code ec, std::size_t bytes_transferred)\n    {\n        next_action act;\n\n        switch (resume_point_)\n        {\n        case 0:\n            // We shouldn't be running another operation if we get here\n            // (caught by setup).\n            // Record that we're running an operation\n            BOOST_ASSERT(!st_->op_in_progress);\n            st_->op_in_progress = true;\n\n            // Run until completion\n            while (true)\n            {\n                // Run the op\n                act = algo_.resume(*st_, *diag_, ec);\n\n                // Check next action\n                if (act.is_done())\n                {\n                    // Record that we're no longer running an operation\n                    st_->op_in_progress = false;\n\n                    // Done\n                    return act;\n                }\n                else if (act.type() == next_action_type::read)\n                {\n                    // Read until a complete message is received\n                    // (may be zero times if cached)\n                    while (!st_->reader.done() && !ec)\n                    {\n                        ec = st_->reader.prepare_buffer();\n                        if (ec)\n                            break;\n                        BOOST_MYSQL_YIELD(\n                            resume_point_,\n                            1,\n                            next_action::read({st_->reader.buffer(), st_->tls_active})\n                        )\n                        valgrind_make_mem_defined(st_->reader.buffer().data(), bytes_transferred);\n                        st_->reader.resume(bytes_transferred);\n                    }\n\n                    // Check for errors\n                    if (!ec)\n                        ec = st_->reader.error();\n\n                    // We've got a message, continue\n                }\n                else if (act.type() == next_action_type::write)\n                {\n                    // Write until a complete message was written\n                    bytes_to_write_ = act.write_args().buffer;\n\n                    while (!bytes_to_write_.empty() && !ec)\n                    {\n                        BOOST_MYSQL_YIELD(\n                            resume_point_,\n                            2,\n                            next_action::write({bytes_to_write_, st_->tls_active})\n                        )\n                        bytes_to_write_ = bytes_to_write_.subspan(bytes_transferred);\n                    }\n\n                    // We fully wrote a message, continue\n                }\n                else\n                {\n                    // Other ops always require I/O\n                    BOOST_MYSQL_YIELD(resume_point_, 3, act)\n                }\n            }\n        }\n\n        return next_action();\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/ssl_context_with_default.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_SSL_CONTEXT_WITH_DEFAULT_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_SSL_CONTEXT_WITH_DEFAULT_HPP\n\n#include <boost/asio/ssl/context.hpp>\n#include <boost/variant2/variant.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline asio::ssl::context& default_ssl_context()\n{\n    // As of MySQL 5.7.35, support for previous TLS versions is deprecated,\n    // so this is a secure default. User can override it if they want\n    static asio::ssl::context ctx(asio::ssl::context::tlsv12_client);\n    return ctx;\n}\n\nclass ssl_context_with_default\n{\n    asio::ssl::context* impl_;\n\npublic:\n    ssl_context_with_default(asio::ssl::context* ctx) noexcept : impl_(ctx) {}\n\n    asio::ssl::context& get()\n    {\n        if (impl_ == nullptr)\n            impl_ = &default_ssl_context();\n        return *impl_;\n    }\n\n    // Exposed for the sake of testing\n    const asio::ssl::context* get_ptr() const noexcept { return impl_; }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/internal/variant_stream.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_VARIANT_STREAM_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_VARIANT_STREAM_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <boost/mysql/impl/internal/coroutine.hpp>\n#include <boost/mysql/impl/internal/ssl_context_with_default.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/associated_immediate_executor.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/compose.hpp>\n#include <boost/asio/connect.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/generic/stream_protocol.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/local/stream_protocol.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/ssl/stream.hpp>\n#include <boost/core/span.hpp>\n#include <boost/optional/optional.hpp>\n\n#include <memory>\n#include <string>\n#include <utility>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstruct variant_stream_state\n{\n    asio::generic::stream_protocol::socket sock;\n    ssl_context_with_default ssl_ctx;\n    boost::optional<asio::ssl::stream<asio::generic::stream_protocol::socket&>> ssl;\n\n    variant_stream_state(asio::any_io_executor ex, asio::ssl::context* ctx) : sock(ex), ssl_ctx(ctx) {}\n\n    asio::ssl::stream<asio::generic::stream_protocol::socket&>& create_ssl_stream()\n    {\n        // The stream object must be re-created even if it already exists, since\n        // once used for a connection (anytime after ssl::stream::handshake is called),\n        // it can't be re-used for any subsequent connections\n        ssl.emplace(sock, ssl_ctx.get());\n        return *ssl;\n    }\n};\n\nenum class vsconnect_action_type\n{\n    none,\n    resolve,\n    connect,\n    immediate,  // we'll be performing an immediate completion\n};\n\nstruct vsconnect_action\n{\n    vsconnect_action_type type;\n\n    union data_t\n    {\n        error_code err;\n        struct resolve_t\n        {\n            const std::string* hostname;\n            const std::string* service;\n        } resolve;\n        span<const asio::generic::stream_protocol::endpoint> connect;\n\n        data_t(error_code v) noexcept : err(v) {}\n        data_t(resolve_t v) noexcept : resolve(v) {}\n        data_t(span<const asio::generic::stream_protocol::endpoint> v) noexcept : connect(v) {}\n    } data;\n\n    struct immediate_tag\n    {\n    };\n\n    vsconnect_action(immediate_tag) noexcept : type(vsconnect_action_type::immediate), data(error_code()) {}\n    vsconnect_action(error_code v = {}) noexcept : type(vsconnect_action_type::none), data(v) {}\n    vsconnect_action(data_t::resolve_t v) noexcept : type(vsconnect_action_type::resolve), data(v) {}\n    vsconnect_action(span<const asio::generic::stream_protocol::endpoint> v) noexcept\n        : type(vsconnect_action_type::connect), data(v)\n    {\n    }\n};\n\nclass variant_stream_connect_algo\n{\n    variant_stream_state* st_;\n    const any_address* addr_;\n    boost::optional<asio::ip::tcp::resolver> resolv_;\n    std::vector<asio::generic::stream_protocol::endpoint> endpoints_;\n    std::string service_;\n    int resume_point_{0};\n\n    const std::string& address() const { return access::get_impl(*addr_).address; }\n    asio::any_io_executor get_executor() const { return st_->sock.get_executor(); }\n\npublic:\n    variant_stream_connect_algo(variant_stream_state& st, const any_address& addr) : st_(&st), addr_(&addr) {}\n\n    asio::ip::tcp::resolver& resolver() { return *resolv_; }\n    asio::generic::stream_protocol::socket& socket() { return st_->sock; }\n\n    vsconnect_action resume(\n        error_code ec,\n        const asio::ip::tcp::resolver::results_type* resolver_results,\n        asio::cancellation_type_t cancel_state\n    )\n    {\n        // All errors are considered fatal\n        if (ec)\n            return ec;\n\n        // If we received a terminal cancellation signal, exit with the appropriate error code.\n        // In composed async operations, if the cancellation arrives after an intermediate operation\n        // has completed, but before the handler is called, the operation finishes successfully,\n        // but the cancellation state is set. This check covers this case.\n        if (!!(cancel_state & asio::cancellation_type_t::terminal))\n            return error_code(asio::error::operation_aborted);\n\n        switch (resume_point_)\n        {\n        case 0:\n\n            // Clean up any previous state\n            st_->sock = asio::generic::stream_protocol::socket(get_executor());\n\n            // Set up the endpoints vector\n            if (addr_->type() == address_type::host_and_port)\n            {\n                // Emplace the resolver\n                resolv_.emplace(get_executor());\n\n                // Resolve the endpoints\n                service_ = std::to_string(addr_->port());\n                BOOST_MYSQL_YIELD(resume_point_, 1, vsconnect_action({&address(), &service_}));\n\n                // Convert them to a vector of type-erased endpoints.\n                // This workarounds https://github.com/chriskohlhoff/asio/issues/1502\n                // and makes connect() uniform for TCP and UNIX\n                endpoints_.reserve(resolver_results->size());\n                for (const auto& entry : *resolver_results)\n                {\n                    endpoints_.push_back(entry.endpoint());\n                }\n            }\n            else\n            {\n                BOOST_ASSERT(addr_->type() == address_type::unix_path);\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\n                endpoints_.push_back(asio::local::stream_protocol::endpoint(address()));\n#else\n                BOOST_MYSQL_YIELD(resume_point_, 3, vsconnect_action::immediate_tag{});\n                return vsconnect_action(asio::error::operation_not_supported);\n#endif\n            }\n\n            // Actually connect\n            BOOST_MYSQL_YIELD(resume_point_, 2, vsconnect_action{endpoints_});\n\n            // If we're doing TCP, disable Naggle's algorithm\n            if (addr_->type() == address_type::host_and_port)\n            {\n                st_->sock.set_option(asio::ip::tcp::no_delay(true));\n            }\n\n            // Done\n        }\n\n        return {};\n    }\n};\n\n// Implements the EngineStream concept (see stream_adaptor)\nclass variant_stream\n{\npublic:\n    variant_stream(asio::any_io_executor ex, asio::ssl::context* ctx) : st_(std::move(ex), ctx) {}\n\n    bool supports_ssl() const { return true; }\n\n    // Executor\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return st_.sock.get_executor(); }\n\n    // SSL\n    void ssl_handshake(error_code& ec)\n    {\n        st_.create_ssl_stream().handshake(asio::ssl::stream_base::client, ec);\n    }\n\n    template <class CompletionToken>\n    void async_ssl_handshake(CompletionToken&& token)\n    {\n        st_.create_ssl_stream();\n        st_.ssl->async_handshake(asio::ssl::stream_base::client, std::forward<CompletionToken>(token));\n    }\n\n    void ssl_shutdown(error_code& ec)\n    {\n        BOOST_ASSERT(st_.ssl.has_value());\n        st_.ssl->shutdown(ec);\n    }\n\n    template <class CompletionToken>\n    void async_ssl_shutdown(CompletionToken&& token)\n    {\n        BOOST_ASSERT(st_.ssl.has_value());\n        st_.ssl->async_shutdown(std::forward<CompletionToken>(token));\n    }\n\n    // Reading\n    std::size_t read_some(asio::mutable_buffer buff, bool use_ssl, error_code& ec)\n    {\n        if (use_ssl)\n        {\n            BOOST_ASSERT(st_.ssl.has_value());\n            return st_.ssl->read_some(buff, ec);\n        }\n        else\n        {\n            return st_.sock.read_some(buff, ec);\n        }\n    }\n\n    template <class CompletionToken>\n    void async_read_some(asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        if (use_ssl)\n        {\n            BOOST_ASSERT(st_.ssl.has_value());\n            st_.ssl->async_read_some(buff, std::forward<CompletionToken>(token));\n        }\n        else\n        {\n            st_.sock.async_read_some(buff, std::forward<CompletionToken>(token));\n        }\n    }\n\n    // Writing\n    std::size_t write_some(boost::asio::const_buffer buff, bool use_ssl, error_code& ec)\n    {\n        if (use_ssl)\n        {\n            BOOST_ASSERT(st_.ssl.has_value());\n            return st_.ssl->write_some(buff, ec);\n        }\n        else\n        {\n            return st_.sock.write_some(buff, ec);\n        }\n    }\n\n    template <class CompletionToken>\n    void async_write_some(boost::asio::const_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        if (use_ssl)\n        {\n            BOOST_ASSERT(st_.ssl.has_value());\n            return st_.ssl->async_write_some(buff, std::forward<CompletionToken>(token));\n        }\n        else\n        {\n            return st_.sock.async_write_some(buff, std::forward<CompletionToken>(token));\n        }\n    }\n\n    // Connect and close\n    void connect(const void* server_address, error_code& output_ec)\n    {\n        // Setup\n        variant_stream_connect_algo algo(st_, *static_cast<const any_address*>(server_address));\n        error_code ec;\n        asio::ip::tcp::resolver::results_type resolver_results;\n\n        // Run until complete\n        while (true)\n        {\n            // The sync algorithm doesn't support cancellation\n            auto act = algo.resume(ec, &resolver_results, asio::cancellation_type_t::none);\n            switch (act.type)\n            {\n            case vsconnect_action_type::connect: asio::connect(st_.sock, act.data.connect, ec); break;\n            case vsconnect_action_type::resolve:\n                resolver_results = algo.resolver()\n                                       .resolve(*act.data.resolve.hostname, *act.data.resolve.service, ec);\n                break;\n            case vsconnect_action_type::immediate: break;  // has effect only for async\n            case vsconnect_action_type::none: output_ec = act.data.err; return;\n            default: BOOST_ASSERT(false);  // LCOV_EXCL_LINE\n            }\n        }\n    }\n\n    template <class CompletionToken>\n    void async_connect(const void* server_address, CompletionToken&& token)\n    {\n        asio::async_compose<CompletionToken, void(error_code)>(\n            connect_op(*this, *static_cast<const any_address*>(server_address)),\n            token,\n            get_executor()\n        );\n    }\n\n    void close(error_code& ec)\n    {\n        st_.sock.shutdown(asio::generic::stream_protocol::socket::shutdown_both, ec);\n        st_.sock.close(ec);\n    }\n\n    // Exposed for testing\n    const asio::generic::stream_protocol::socket& socket() const { return st_.sock; }\n\nprivate:\n    variant_stream_state st_;\n\n    struct connect_op\n    {\n        std::unique_ptr<variant_stream_connect_algo> algo_;\n\n        connect_op(variant_stream& this_obj, const any_address& server_address)\n            : algo_(new variant_stream_connect_algo(this_obj.st_, server_address))\n        {\n        }\n\n        template <class Self>\n        void operator()(\n            Self& self,\n            error_code ec = {},\n            const asio::ip::tcp::resolver::results_type& resolver_results = {}\n        )\n        {\n            auto act = algo_->resume(ec, &resolver_results, self.cancelled());\n            switch (act.type)\n            {\n            case vsconnect_action_type::connect:\n                asio::async_connect(algo_->socket(), act.data.connect, std::move(self));\n                break;\n            case vsconnect_action_type::resolve:\n                algo_->resolver()\n                    .async_resolve(*act.data.resolve.hostname, *act.data.resolve.service, std::move(self));\n                break;\n            case vsconnect_action_type::immediate:\n                asio::dispatch(\n                    asio::get_associated_immediate_executor(self, self.get_io_executor()),\n                    std::move(self)\n                );\n                break;\n            case vsconnect_action_type::none:\n                algo_.reset();\n                self.complete(act.data.err);\n                break;\n            default: BOOST_ASSERT(false);  // LCOV_EXCL_LINE\n            }\n        }\n\n        // Signature for range connect\n        template <class Self>\n        void operator()(Self& self, error_code ec, asio::generic::stream_protocol::endpoint)\n        {\n            (*this)(self, ec, asio::ip::tcp::resolver::results_type{});\n        }\n    };\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/is_fatal_error.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_IS_FATAL_ERROR_IPP\n#define BOOST_MYSQL_IMPL_IS_FATAL_ERROR_IPP\n\n#pragma once\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/is_fatal_error.hpp>\n\nbool boost::mysql::is_fatal_error(error_code ec) noexcept\n{\n    // If there is no failure, it's not fatal\n    if (!ec)\n        return false;\n\n    // Retrieve the error category\n    const auto& cat = ec.category();\n\n    if (cat == get_common_server_category())\n    {\n        // Server errors may or may not be fatal. MySQL defines a ton of different errors.\n        // After some research, these are the ones I'd recommend to consider fatal\n        auto code = static_cast<common_server_errc>(ec.value());\n        switch (code)\n        {\n        // Different flavors of communication errors. These usually indicate that the connection\n        // has been left in an unspecified state, and the safest is to reconnect it.\n        case common_server_errc::er_unknown_com_error:\n        case common_server_errc::er_aborting_connection:\n        case common_server_errc::er_net_packet_too_large:\n        case common_server_errc::er_net_read_error_from_pipe:\n        case common_server_errc::er_net_fcntl_error:\n        case common_server_errc::er_net_packets_out_of_order:\n        case common_server_errc::er_net_uncompress_error:\n        case common_server_errc::er_net_read_error:\n        case common_server_errc::er_net_read_interrupted:\n        case common_server_errc::er_net_error_on_write:\n        case common_server_errc::er_net_write_interrupted:\n        case common_server_errc::er_malformed_packet:\n        case common_server_errc::er_zlib_z_buf_error:\n        case common_server_errc::er_zlib_z_data_error:\n        case common_server_errc::er_zlib_z_mem_error: return true;\n        default: return false;\n        }\n    }\n    else if (cat == get_mysql_server_category() || cat == get_mariadb_server_category())\n    {\n        // DB-specific codes are all non fatal\n        return false;\n    }\n    else if (cat == get_client_category())\n    {\n        auto code = static_cast<client_errc>(ec.value());\n        switch (code)\n        {\n        // These indicate malformed frames or packet mismatches\n        case client_errc::incomplete_message:\n        case client_errc::protocol_value_error:\n        case client_errc::extra_bytes:\n        case client_errc::sequence_number_mismatch:\n\n        // Exceeding the max buffer size is not recoverable\n        case client_errc::max_buffer_size_exceeded:\n\n        // These are produced by the static interface, and currently cause parsing\n        // to stop, leaving unread packets in the network buffer.\n        // See https://github.com/boostorg/mysql/issues/212\n        case client_errc::metadata_check_failed:\n        case client_errc::num_resultsets_mismatch:\n        case client_errc::row_type_mismatch:\n        case client_errc::static_row_parsing_error:\n\n        // These are only produced by handshake. We categorize them as fatal because they need reconnection,\n        // although anything affecting handshake effectively does.\n        case client_errc::server_doesnt_support_ssl:\n        case client_errc::unknown_auth_plugin:\n        case client_errc::server_unsupported:\n        case client_errc::auth_plugin_requires_ssl:\n        case client_errc::bad_handshake_packet_type:\n        case client_errc::unknown_openssl_error: return true;\n\n        default: return false;\n        }\n    }\n    else\n    {\n        // Other categories are fatal - these include network and SSL errors\n        return true;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/meta_check_context.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_META_CHECK_CONTEXT_IPP\n#define BOOST_MYSQL_IMPL_META_CHECK_CONTEXT_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/typing/meta_check_context.hpp>\n\nvoid boost::mysql::detail::meta_check_context::add_field_absent_error()\n{\n    auto& stream = add_error();\n    stream << \"Field \";\n    insert_field_name(stream);\n    if (has_field_names(name_table_))\n    {\n        stream << \" is not present in the data returned by the server\";\n    }\n    else\n    {\n        stream << \" can't be mapped: there are more fields in your C++ data type than in your query\";\n    }\n}\n\nvoid boost::mysql::detail::meta_check_context::add_type_mismatch_error(const char* cpp_type_name)\n{\n    auto& stream = add_error();\n    stream << \"Incompatible types for field \";\n    insert_field_name(stream);\n    stream << \": C++ type '\" << cpp_type_name << \"' is not compatible with DB type '\"\n           << column_type_to_str(current_meta()) << \"'\";\n}\n\nvoid boost::mysql::detail::meta_check_context::add_nullability_error()\n{\n    auto& stream = add_error();\n    stream << \"NULL checks failed for field \";\n    insert_field_name(stream);\n    stream << \": the database type may be NULL, but the C++ type cannot. Use std::optional<T> or \"\n              \"boost::optional<T>\";\n}\n\nboost::mysql::error_code boost::mysql::detail::meta_check_context::check_errors(diagnostics& diag) const\n{\n    if (errors_ != nullptr)\n    {\n        access::get_impl(diag).assign_client(errors_->str());\n        return client_errc::metadata_check_failed;\n    }\n    return error_code();\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/pfr.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_PFR_HPP\n#define BOOST_MYSQL_IMPL_PFR_HPP\n\n#pragma once\n\n#include <boost/config.hpp>\n\n// Silence MSVC 14.1 warnings caused by https://github.com/boostorg/pfr/issues/167\n#if defined(BOOST_MSVC) && BOOST_MSVC < 1920\n#pragma warning(push)\n#pragma warning(disable : 4100)\n#endif\n\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#include <boost/pfr/core.hpp>\n#include <boost/pfr/core_name.hpp>\n#include <boost/pfr/traits.hpp>\n\n#include <type_traits>\n#include <utility>\n\n#if BOOST_PFR_CORE_NAME_ENABLED\n#include <array>\n#include <cstddef>\n#include <string_view>\n#endif\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Not all types reflected by PFR are acceptable for us - this function performs this checking\ntemplate <class T>\nconstexpr bool is_pfr_reflectable() noexcept\n{\n    return std::is_class<T>::value && !std::is_const<T>::value\n    // is_implicitly_reflectable_v returns always false when implicit reflection\n    // (which requires structured bindings and C++17) is not available\n#if BOOST_PFR_ENABLE_IMPLICIT_REFLECTION\n           && pfr::is_implicitly_reflectable_v<T, struct mysql_tag>\n#endif\n        ;\n}\n\ntemplate <class T>\nusing pfr_fields_t = decltype(pfr::structure_to_tuple(std::declval<const T&>()));\n\n#if BOOST_PFR_CORE_NAME_ENABLED\n\n// PFR field names use std::string_view\ntemplate <std::size_t N>\nconstexpr std::array<string_view, N> to_name_table_storage(std::array<std::string_view, N> input) noexcept\n{\n    std::array<string_view, N> res{};\n    for (std::size_t i = 0; i < N; ++i)\n        res[i] = input[i];\n    return res;\n}\n\ntemplate <class T>\nconstexpr inline std::size_t pfr_row_size_v = mp11::mp_size<pfr_fields_t<T>>::value;\n\ntemplate <class T>\nconstexpr std::array<string_view, pfr_row_size_v<T>> create_pfr_name_table() noexcept\n{\n    // Some MSVC compilers have trouble with pfr::names_as_array<T>() when\n    // the row type is empty\n    if constexpr (pfr_row_size_v<T> == 0u)\n    {\n        return {};\n    }\n    else\n    {\n        return to_name_table_storage(pfr::names_as_array<T>());\n    }\n}\n\ntemplate <class T>\nconstexpr inline auto pfr_names_storage = create_pfr_name_table<T>();\n\ntemplate <class T>\nclass row_traits<pfr_by_name<T>, false>\n{\n    static_assert(\n        is_pfr_reflectable<T>(),\n        \"T needs to be a non-const object type that supports PFR reflection\"\n    );\n\npublic:\n    using underlying_row_type = T;\n    using field_types = pfr_fields_t<T>;\n\n    static constexpr name_table_t name_table() noexcept { return pfr_names_storage<T>; }\n\n    template <class F>\n    static void for_each_member(T& to, F&& function)\n    {\n        pfr::for_each_field(to, std::forward<F>(function));\n    }\n};\n\n#endif\n\ntemplate <class T>\nclass row_traits<pfr_by_position<T>, false>\n{\n    static_assert(\n        is_pfr_reflectable<T>(),\n        \"T needs to be a non-const object type that supports PFR reflection\"\n    );\n\npublic:\n    using underlying_row_type = T;\n    using field_types = pfr_fields_t<T>;\n\n    static constexpr name_table_t name_table() noexcept { return {}; }\n\n    template <class F>\n    static void for_each_member(T& to, F&& function)\n    {\n        pfr::for_each_field(to, std::forward<F>(function));\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#if defined(BOOST_MSVC) && BOOST_MSVC < 1920\n#pragma warning(pop)\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/pipeline.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_PIPELINE_IPP\n#define BOOST_MYSQL_IMPL_PIPELINE_IPP\n\n#pragma once\n\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/pipeline.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n#include <boost/mysql/impl/internal/sansio/set_character_set.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <stdexcept>\n\nboost::mysql::pipeline_request& boost::mysql::pipeline_request::add_execute(string_view query)\n{\n    impl_.stages_.reserve(impl_.stages_.size() + 1);  // strong guarantee\n    impl_.stages_.push_back({\n        detail::pipeline_stage_kind::execute,\n        detail::serialize_top_level_checked(detail::query_command{query}, impl_.buffer_),\n        detail::resultset_encoding::text,\n    });\n    return *this;\n}\n\nboost::mysql::pipeline_request& boost::mysql::pipeline_request::add_execute_range(\n    statement stmt,\n    span<const field_view> params\n)\n{\n    if (params.size() != stmt.num_params())\n    {\n        BOOST_THROW_EXCEPTION(\n            std::invalid_argument(\"Wrong number of actual parameters supplied to a prepared statement\")\n        );\n    }\n    impl_.stages_.reserve(impl_.stages_.size() + 1);  // strong guarantee\n    impl_.stages_.push_back({\n        detail::pipeline_stage_kind::execute,\n        detail::serialize_top_level_checked(detail::execute_stmt_command{stmt.id(), params}, impl_.buffer_),\n        detail::resultset_encoding::binary,\n    });\n    return *this;\n}\n\nboost::mysql::pipeline_request& boost::mysql::pipeline_request::add_prepare_statement(string_view stmt_sql)\n{\n    impl_.stages_.reserve(impl_.stages_.size() + 1);  // strong guarantee\n    impl_.stages_.push_back({\n        detail::pipeline_stage_kind::prepare_statement,\n        detail::serialize_top_level_checked(detail::prepare_stmt_command{stmt_sql}, impl_.buffer_),\n        {},\n    });\n    return *this;\n}\n\nboost::mysql::pipeline_request& boost::mysql::pipeline_request::add_close_statement(statement stmt)\n{\n    impl_.stages_.reserve(impl_.stages_.size() + 1);  // strong guarantee\n    impl_.stages_.push_back({\n        detail::pipeline_stage_kind::close_statement,\n        detail::serialize_top_level_checked(detail::close_stmt_command{stmt.id()}, impl_.buffer_),\n        {},\n    });\n    return *this;\n}\n\nboost::mysql::pipeline_request& boost::mysql::pipeline_request::add_reset_connection()\n{\n    impl_.stages_.reserve(impl_.stages_.size() + 1);  // strong guarantee\n    impl_.stages_.push_back({\n        detail::pipeline_stage_kind::reset_connection,\n        detail::serialize_top_level_checked(detail::reset_connection_command{}, impl_.buffer_),\n        {},\n    });\n    return *this;\n}\n\nboost::mysql::pipeline_request& boost::mysql::pipeline_request::add_set_character_set(character_set charset)\n{\n    auto q = detail::compose_set_names(charset);\n    if (q.has_error())\n    {\n        BOOST_THROW_EXCEPTION(std::invalid_argument(\"Invalid character set name\"));\n    }\n    impl_.stages_.reserve(impl_.stages_.size() + 1);  // strong guarantee\n    impl_.stages_.push_back({\n        detail::pipeline_stage_kind::set_character_set,\n        detail::serialize_top_level_checked(detail::query_command{*q}, impl_.buffer_),\n        charset,\n    });\n    return *this;\n}\n\nvoid boost::mysql::stage_response::check_has_results() const\n{\n    if (!has_results())\n    {\n        BOOST_THROW_EXCEPTION(\n            std::invalid_argument(\"stage_response::as_results: object doesn't contain results\")\n        );\n    }\n}\n\nboost::mysql::statement boost::mysql::stage_response::as_statement() const\n{\n    if (!has_statement())\n    {\n        BOOST_THROW_EXCEPTION(\n            std::invalid_argument(\"stage_response::as_statement: object doesn't contain a statement\")\n        );\n    }\n    return variant2::unsafe_get<1>(impl_.value);\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/results_impl.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_RESULTS_IMPL_IPP\n#define BOOST_MYSQL_IMPL_RESULTS_IMPL_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/execution_processor/results_impl.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nboost::mysql::detail::per_resultset_data& boost::mysql::detail::resultset_container::emplace_back()\n{\n    if (!first_has_data_)\n    {\n        first_ = per_resultset_data();\n        first_has_data_ = true;\n        return first_;\n    }\n    else\n    {\n        rest_.emplace_back();\n        return rest_.back();\n    }\n}\n\nboost::mysql::row_view boost::mysql::detail::results_impl::get_out_params() const noexcept\n{\n    BOOST_ASSERT(is_complete());\n    for (std::size_t i = 0; i < per_result_.size(); ++i)\n    {\n        if (per_result_[i].is_out_params)\n        {\n            auto res = get_rows(i);\n            return res.empty() ? row_view() : res[0];\n        }\n    }\n    return row_view();\n}\n\nvoid boost::mysql::detail::results_impl::reset_impl() noexcept\n{\n    meta_.clear();\n    per_result_.clear();\n    info_.clear();\n    rows_.clear();\n    num_fields_at_batch_start_ = no_batch;\n}\n\nvoid boost::mysql::detail::results_impl::on_num_meta_impl(std::size_t num_columns)\n{\n    auto& resultset_data = add_resultset();\n    meta_.reserve(meta_.size() + num_columns);\n    resultset_data.num_columns = num_columns;\n}\n\nboost::mysql::error_code boost::mysql::detail::results_impl::\n    on_head_ok_packet_impl(const ok_view& pack, diagnostics&)\n{\n    add_resultset();\n    on_ok_packet_impl(pack);\n    return error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::results_impl::\n    on_meta_impl(const coldef_view& coldef, bool, diagnostics&)\n{\n    meta_.push_back(create_meta(coldef));\n    return error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::results_impl::\n    on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>&)\n{\n    BOOST_ASSERT(has_active_batch());\n\n    // add row storage\n    std::size_t num_fields = current_resultset().num_columns;\n    span<field_view> storage = rows_.add_fields(num_fields);\n    ++current_resultset().num_rows;\n\n    // deserialize the row\n    auto err = deserialize_row(encoding(), msg, current_resultset_meta(), storage);\n    if (err)\n        return err;\n\n    return error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::results_impl::on_row_ok_packet_impl(const ok_view& pack)\n{\n    on_ok_packet_impl(pack);\n    return error_code();\n}\n\nvoid boost::mysql::detail::results_impl::on_row_batch_start_impl()\n{\n    BOOST_ASSERT(!has_active_batch());\n    num_fields_at_batch_start_ = rows_.fields().size();\n}\n\nvoid boost::mysql::detail::results_impl::on_row_batch_finish_impl() { finish_batch(); }\n\nvoid boost::mysql::detail::results_impl::finish_batch()\n{\n    if (has_active_batch())\n    {\n        rows_.copy_strings_as_offsets(\n            num_fields_at_batch_start_,\n            rows_.fields().size() - num_fields_at_batch_start_\n        );\n        num_fields_at_batch_start_ = no_batch;\n    }\n}\n\nboost::mysql::detail::per_resultset_data& boost::mysql::detail::results_impl::add_resultset()\n{\n    // Allocate a new per-resultset object\n    auto& resultset_data = per_result_.emplace_back();\n    resultset_data.meta_offset = meta_.size();\n    resultset_data.field_offset = rows_.fields().size();\n    resultset_data.info_offset = info_.size();\n    return resultset_data;\n}\n\nvoid boost::mysql::detail::results_impl::on_ok_packet_impl(const ok_view& pack)\n{\n    auto& resultset_data = current_resultset();\n    resultset_data.affected_rows = pack.affected_rows;\n    resultset_data.last_insert_id = pack.last_insert_id;\n    resultset_data.warnings = pack.warnings;\n    resultset_data.info_size = pack.info.size();\n    resultset_data.has_ok_packet_data = true;\n    resultset_data.is_out_params = pack.is_out_params();\n    info_.insert(info_.end(), pack.info.begin(), pack.info.end());\n    if (!pack.more_results())\n    {\n        finish_batch();\n        rows_.offsets_to_string_views();\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/resultset.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_RESULTSET_IPP\n#define BOOST_MYSQL_IMPL_RESULTSET_IPP\n\n#pragma once\n\n#include <boost/mysql/resultset.hpp>\n\nvoid boost::mysql::resultset::assign(resultset_view v)\n{\n    has_value_ = v.has_value();\n    if (has_value_)\n    {\n        meta_.assign(v.meta().begin(), v.meta().end());\n        rws_ = v.rows();\n        affected_rows_ = v.affected_rows();\n        last_insert_id_ = v.last_insert_id();\n        warnings_ = static_cast<std::uint16_t>(v.warning_count());\n        info_.assign(v.info().begin(), v.info().end());\n        is_out_params_ = v.is_out_params();\n    }\n    else\n    {\n        meta_.clear();\n        rws_ = ::boost::mysql::rows();\n        affected_rows_ = 0;\n        last_insert_id_ = 0;\n        warnings_ = 0;\n        info_.clear();\n        is_out_params_ = false;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/row_impl.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_ROW_IMPL_IPP\n#define BOOST_MYSQL_IMPL_ROW_IMPL_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/row_impl.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ninline std::size_t get_string_size(field_view f)\n{\n    switch (f.kind())\n    {\n    case field_kind::string: return f.get_string().size();\n    case field_kind::blob: return f.get_blob().size();\n    default: return 0;\n    }\n}\n\ninline unsigned char* copy_string(unsigned char* buffer_it, field_view& f)\n{\n    auto str = f.get_string();\n    if (!str.empty())\n    {\n        std::memcpy(buffer_it, str.data(), str.size());\n        f = field_view(string_view(reinterpret_cast<const char*>(buffer_it), str.size()));\n        buffer_it += str.size();\n    }\n    return buffer_it;\n}\n\ninline unsigned char* copy_blob(unsigned char* buffer_it, field_view& f)\n{\n    auto b = f.get_blob();\n    if (!b.empty())\n    {\n        std::memcpy(buffer_it, b.data(), b.size());\n        f = field_view(blob_view(buffer_it, b.size()));\n        buffer_it += b.size();\n    }\n    return buffer_it;\n}\n\ninline std::size_t copy_string_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f)\n{\n    auto str = f.get_string();\n    if (!str.empty())\n    {\n        std::memcpy(buffer_first + offset, str.data(), str.size());\n        f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, false);\n        return str.size();\n    }\n    return 0;\n}\n\ninline std::size_t copy_blob_as_offset(unsigned char* buffer_first, std::size_t offset, field_view& f)\n{\n    auto str = f.get_blob();\n    if (!str.empty())\n    {\n        std::memcpy(buffer_first + offset, str.data(), str.size());\n        f = detail::access::construct<field_view>(detail::string_view_offset{offset, str.size()}, true);\n        return str.size();\n    }\n    return 0;\n}\n\ninline void copy_strings(std::vector<field_view>& fields, std::vector<unsigned char>& string_buffer)\n{\n    // Calculate the required size for the new strings\n    std::size_t size = 0;\n    for (auto f : fields)\n    {\n        size += get_string_size(f);\n    }\n\n    // Make space. The previous fields should be in offset form\n    string_buffer.resize(string_buffer.size() + size);\n\n    // Copy strings and blobs\n    unsigned char* buffer_it = string_buffer.data();\n    for (auto& f : fields)\n    {\n        switch (f.kind())\n        {\n        case field_kind::string: buffer_it = copy_string(buffer_it, f); break;\n        case field_kind::blob: buffer_it = copy_blob(buffer_it, f); break;\n        default: break;\n        }\n    }\n    BOOST_ASSERT(buffer_it == string_buffer.data() + size);\n}\n\ninline field_view offset_to_string_view(field_view fv, const std::uint8_t* buffer_first)\n{\n    auto& impl = detail::access::get_impl(fv);\n    if (impl.is_string_offset())\n    {\n        return field_view(string_view(\n            reinterpret_cast<const char*>(buffer_first) + impl.repr.sv_offset_.offset,\n            impl.repr.sv_offset_.size\n        ));\n    }\n    else if (impl.is_blob_offset())\n    {\n        return field_view(blob_view(buffer_first + impl.repr.sv_offset_.offset, impl.repr.sv_offset_.size));\n    }\n    else\n    {\n        return fv;\n    }\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nboost::mysql::detail::row_impl::row_impl(const field_view* fields, std::size_t size)\n    : fields_(fields, fields + size)\n{\n    copy_strings(fields_, string_buffer_);\n}\n\nboost::mysql::detail::row_impl::row_impl(const row_impl& rhs) : fields_(rhs.fields_)\n{\n    copy_strings(fields_, string_buffer_);\n}\n\nboost::mysql::detail::row_impl& boost::mysql::detail::row_impl::operator=(const row_impl& rhs)\n{\n    assign(rhs.fields_.data(), rhs.fields_.size());\n    return *this;\n}\n\nvoid boost::mysql::detail::row_impl::assign(const field_view* fields, std::size_t size)\n{\n    // Protect against self-assignment. This is valid as long as we\n    // don't implement sub-range operators (e.g. row_view[2:4])\n    if (fields_.data() == fields)\n    {\n        BOOST_ASSERT(fields_.size() == size);\n    }\n    else\n    {\n        fields_.assign(fields, fields + size);\n        string_buffer_.clear();\n        copy_strings(fields_, string_buffer_);\n    }\n}\n\nvoid boost::mysql::detail::row_impl::copy_strings_as_offsets(std::size_t first, std::size_t num_fields)\n{\n    // Preconditions\n    BOOST_ASSERT(first <= fields_.size());\n    BOOST_ASSERT(first + num_fields <= fields_.size());\n\n    // Calculate the required size for the new strings\n    std::size_t size = 0;\n    for (std::size_t i = first; i < first + num_fields; ++i)\n    {\n        size += get_string_size(fields_[i]);\n    }\n\n    // Make space. The previous fields should be in offset form\n    std::size_t old_string_buffer_size = string_buffer_.size();\n    string_buffer_.resize(old_string_buffer_size + size);\n\n    // Copy strings and blobs\n    std::size_t offset = old_string_buffer_size;\n    for (std::size_t i = first; i < first + num_fields; ++i)\n    {\n        auto& f = fields_[i];\n        switch (f.kind())\n        {\n        case field_kind::string: offset += copy_string_as_offset(string_buffer_.data(), offset, f); break;\n        case field_kind::blob: offset += copy_blob_as_offset(string_buffer_.data(), offset, f); break;\n        default: break;\n        }\n    }\n    BOOST_ASSERT(offset == string_buffer_.size());\n}\n\nvoid boost::mysql::detail::row_impl::offsets_to_string_views()\n{\n    for (auto& f : fields_)\n        f = offset_to_string_view(f, string_buffer_.data());\n}\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/statement.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_STATEMENT_HPP\n#define BOOST_MYSQL_IMPL_STATEMENT_HPP\n\n#pragma once\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/writable_field_traits.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/core/ignore_unused.hpp>\n\n#include <tuple>\n#include <vector>\n\ntemplate <BOOST_MYSQL_WRITABLE_FIELD_TUPLE WritableFieldTuple>\nclass boost::mysql::bound_statement_tuple\n{\n    friend class statement;\n    friend struct detail::access;\n\n    struct impl\n    {\n        statement stmt;\n        WritableFieldTuple params;\n    } impl_;\n\n    template <typename TupleType>\n    bound_statement_tuple(const statement& stmt, TupleType&& t) : impl_{stmt, std::forward<TupleType>(t)}\n    {\n    }\n};\n\ntemplate <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>\nclass boost::mysql::bound_statement_iterator_range\n{\n    friend class statement;\n    friend struct detail::access;\n\n    struct impl\n    {\n        statement stmt;\n        FieldViewFwdIterator first;\n        FieldViewFwdIterator last;\n    } impl_;\n\n    bound_statement_iterator_range(\n        const statement& stmt,\n        FieldViewFwdIterator first,\n        FieldViewFwdIterator last\n    )\n        : impl_{stmt, first, last}\n    {\n    }\n};\n\ntemplate <BOOST_MYSQL_WRITABLE_FIELD_TUPLE WritableFieldTuple, typename EnableIf>\nboost::mysql::bound_statement_tuple<typename std::decay<WritableFieldTuple>::type> boost::mysql::statement::\n    bind(WritableFieldTuple&& args) const\n\n{\n    BOOST_ASSERT(valid());\n    return bound_statement_tuple<typename std::decay<WritableFieldTuple>::type>(\n        *this,\n        std::forward<WritableFieldTuple>(args)\n    );\n}\n\ntemplate <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator, typename EnableIf>\nboost::mysql::bound_statement_iterator_range<FieldViewFwdIterator> boost::mysql::statement::bind(\n    FieldViewFwdIterator first,\n    FieldViewFwdIterator last\n) const\n{\n    BOOST_ASSERT(valid());\n    return bound_statement_iterator_range<FieldViewFwdIterator>(*this, first, last);\n}\n\n// Execution request traits\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// Tuple\ntemplate <std::size_t N>\nstruct stmt_tuple_request_proxy\n{\n    statement stmt;\n    std::array<field_view, N> params;\n\n    operator any_execution_request() const\n    {\n        return any_execution_request({stmt.id(), static_cast<std::uint16_t>(stmt.num_params()), params});\n    }\n};\n\ntemplate <class... T>\nstruct execution_request_traits<bound_statement_tuple<std::tuple<T...>>>\n{\n    template <std::size_t... I>\n    static std::array<field_view, sizeof...(T)> tuple_to_array(const std::tuple<T...>& t, mp11::index_sequence<I...>)\n    {\n        boost::ignore_unused(t);  // MSVC gets confused if sizeof...(T) == 0\n        return {{to_field(std::get<I>(t))...}};\n    }\n\n    static stmt_tuple_request_proxy<sizeof...(T)> make_request(const bound_statement_tuple<std::tuple<T...>>& input, std::vector<field_view>&)\n    {\n        auto& impl = access::get_impl(input);\n        return {impl.stmt, tuple_to_array(impl.params, mp11::make_index_sequence<sizeof...(T)>())};\n    }\n};\n\n// Iterator range\ntemplate <class FieldViewFwdIterator>\nstruct execution_request_traits<bound_statement_iterator_range<FieldViewFwdIterator>>\n{\n    static any_execution_request make_request(\n        const bound_statement_iterator_range<FieldViewFwdIterator>& input,\n        std::vector<field_view>& shared_fields\n    )\n    {\n        auto& impl = access::get_impl(input);\n        shared_fields.assign(impl.first, impl.last);\n        return any_execution_request(\n            {impl.stmt.id(), static_cast<std::uint16_t>(impl.stmt.num_params()), shared_fields}\n        );\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/static_execution_state_impl.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_STATIC_EXECUTION_STATE_IMPL_IPP\n#define BOOST_MYSQL_IMPL_STATIC_EXECUTION_STATE_IMPL_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/execution_processor/static_execution_state_impl.hpp>\n#include <boost/mysql/detail/row_impl.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\nvoid boost::mysql::detail::static_execution_state_erased_impl::reset_impl() noexcept\n{\n    resultset_index_ = 0;\n    ok_data_ = ok_packet_data();\n    info_.clear();\n    meta_.clear();\n}\n\nboost::mysql::error_code boost::mysql::detail::static_execution_state_erased_impl::on_head_ok_packet_impl(\n    const ok_view& pack,\n    diagnostics& diag\n)\n{\n    on_new_resultset();\n    auto err = on_ok_packet_impl(pack);\n    if (err)\n        return err;\n    return meta_check(diag);\n}\n\nvoid boost::mysql::detail::static_execution_state_erased_impl::on_num_meta_impl(std::size_t num_columns)\n{\n    on_new_resultset();\n    meta_.reserve(num_columns);\n}\n\nboost::mysql::error_code boost::mysql::detail::static_execution_state_erased_impl::on_meta_impl(\n    const coldef_view& coldef,\n    bool is_last,\n    diagnostics& diag\n)\n\n{\n    std::size_t meta_index = meta_.size();\n\n    // Store the object\n    meta_.push_back(create_meta(coldef));\n\n    // Record its position\n    pos_map_add_field(current_pos_map(), current_name_table(), meta_index, coldef.name);\n\n    return is_last ? meta_check(diag) : error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::static_execution_state_erased_impl::on_row_impl(\n    span<const std::uint8_t> msg,\n    const output_ref& ref,\n    std::vector<field_view>& fields\n)\n\n{\n    // check output\n    if (ref.type_index() != ext_.type_index(resultset_index_ - 1))\n        return client_errc::row_type_mismatch;\n\n    // Allocate temporary space\n    fields.clear();\n    span<field_view> storage = add_fields(fields, meta_.size());\n\n    // deserialize the row\n    auto err = deserialize_row(encoding(), msg, meta_, storage);\n    if (err)\n        return err;\n\n    // parse it into the output ref\n    err = ext_.parse_fn(resultset_index_ - 1)(current_pos_map(), storage, ref);\n    if (err)\n        return err;\n\n    return error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::static_execution_state_erased_impl::on_row_ok_packet_impl(\n    const ok_view& pack\n)\n{\n    return on_ok_packet_impl(pack);\n}\n\nvoid boost::mysql::detail::static_execution_state_erased_impl::on_new_resultset() noexcept\n{\n    ++resultset_index_;\n    ok_data_ = ok_packet_data{};\n    info_.clear();\n    meta_.clear();\n    pos_map_reset(current_pos_map());\n}\n\nboost::mysql::error_code boost::mysql::detail::static_execution_state_erased_impl::on_ok_packet_impl(\n    const ok_view& pack\n)\n{\n    ok_data_.has_value = true;\n    ok_data_.affected_rows = pack.affected_rows;\n    ok_data_.last_insert_id = pack.last_insert_id;\n    ok_data_.warnings = pack.warnings;\n    ok_data_.is_out_params = pack.is_out_params();\n    info_.assign(pack.info.begin(), pack.info.end());\n    bool should_be_last = resultset_index_ == ext_.num_resultsets();\n    bool is_last = !pack.more_results();\n    return should_be_last == is_last ? error_code() : client_errc::num_resultsets_mismatch;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/static_results_impl.ipp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_STATIC_RESULTS_IMPL_IPP\n#define BOOST_MYSQL_IMPL_STATIC_RESULTS_IMPL_IPP\n\n#pragma once\n\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/execution_processor/static_results_impl.hpp>\n#include <boost/mysql/detail/row_impl.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\nvoid boost::mysql::detail::static_results_erased_impl::reset_impl() noexcept\n{\n    ext_.reset_fn()(ext_.rows());\n    info_.clear();\n    meta_.clear();\n    resultset_index_ = 0;\n}\n\nboost::mysql::error_code boost::mysql::detail::static_results_erased_impl::on_head_ok_packet_impl(\n    const ok_view& pack,\n    diagnostics& diag\n)\n{\n    add_resultset();\n    auto err = on_ok_packet_impl(pack);\n    if (err)\n        return err;\n    return meta_check(diag);\n}\n\nvoid boost::mysql::detail::static_results_erased_impl::on_num_meta_impl(std::size_t num_columns)\n{\n    auto& resultset_data = add_resultset();\n    meta_.reserve(meta_.size() + num_columns);\n    resultset_data.meta_size = num_columns;\n}\n\nboost::mysql::error_code boost::mysql::detail::static_results_erased_impl::on_meta_impl(\n    const coldef_view& coldef,\n    bool is_last,\n    diagnostics& diag\n)\n\n{\n    std::size_t meta_index = meta_.size() - current_resultset().meta_offset;\n\n    // Store the new object\n    meta_.push_back(create_meta(coldef));\n\n    // Fill the pos map entry for this field, if any\n    pos_map_add_field(current_pos_map(), current_name_table(), meta_index, coldef.name);\n\n    return is_last ? meta_check(diag) : error_code();\n}\n\nboost::mysql::error_code boost::mysql::detail::static_results_erased_impl::on_row_impl(\n    span<const std::uint8_t> msg,\n    const output_ref&,\n    std::vector<field_view>& fields\n)\n\n{\n    auto meta = current_resultset_meta();\n\n    // Allocate temporary storage\n    fields.clear();\n    span<field_view> storage = add_fields(fields, meta.size());\n\n    // deserialize the row\n    auto err = deserialize_row(encoding(), msg, meta, storage);\n    if (err)\n        return err;\n\n    // parse it against the appropriate tuple element\n    return ext_.parse_fn(resultset_index_ - 1)(current_pos_map(), storage, ext_.rows());\n}\n\nboost::mysql::error_code boost::mysql::detail::static_results_erased_impl::on_row_ok_packet_impl(\n    const ok_view& pack\n)\n{\n    return on_ok_packet_impl(pack);\n}\n\nboost::mysql::detail::static_per_resultset_data& boost::mysql::detail::static_results_erased_impl::\n    add_resultset()\n{\n    ++resultset_index_;\n    auto& resultset_data = current_resultset();\n    resultset_data = static_per_resultset_data();\n    resultset_data.meta_offset = meta_.size();\n    resultset_data.info_offset = info_.size();\n    pos_map_reset(current_pos_map());\n    return resultset_data;\n}\n\nboost::mysql::error_code boost::mysql::detail::static_results_erased_impl::on_ok_packet_impl(\n    const ok_view& pack\n)\n{\n    auto& resultset_data = current_resultset();\n    resultset_data.affected_rows = pack.affected_rows;\n    resultset_data.last_insert_id = pack.last_insert_id;\n    resultset_data.warnings = pack.warnings;\n    resultset_data.info_size = pack.info.size();\n    resultset_data.has_ok_packet_data = true;\n    resultset_data.is_out_params = pack.is_out_params();\n    info_.insert(info_.end(), pack.info.begin(), pack.info.end());\n    bool should_be_last = resultset_index_ == ext_.num_resultsets();\n    bool is_last = !pack.more_results();\n    return should_be_last == is_last ? error_code() : client_errc::num_resultsets_mismatch;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/with_diagnostics.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_WITH_DIAGNOSTICS_HPP\n#define BOOST_MYSQL_IMPL_WITH_DIAGNOSTICS_HPP\n\n#pragma once\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/mysql/detail/intermediate_handler.hpp>\n\n#include <boost/asio/associated_allocator.hpp>\n#include <boost/asio/async_result.hpp>\n#include <boost/mp11/algorithm.hpp>\n#include <boost/mp11/list.hpp>\n\n#include <cstddef>\n#include <exception>\n#include <memory>\n#include <tuple>\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstruct with_diag_handler_fn\n{\n    template <class Handler, class... Args>\n    void operator()(Handler&& handler, error_code ec, Args&&... args)\n    {\n        std::exception_ptr exc = ec ? std::make_exception_ptr(error_with_diagnostics(ec, diag))\n                                    : std::exception_ptr();\n        owning_diag.reset();\n        std::move(handler)(std::move(exc), std::forward<Args>(args)...);\n    }\n\n    // The diagnostics to use, taken from initiation\n    const diagnostics& diag;\n\n    // Keep alive any allocated diagnostics\n    std::shared_ptr<diagnostics> owning_diag;\n};\n\n// By default, don't modify the signature.\n// This makes asio::as_tuple(with_diagnostics(X)) equivalent\n// to asio::as_tuple(X).\ntemplate <typename Signature>\nstruct with_diag_signature\n{\n    using type = Signature;\n};\n\ntemplate <typename R, typename... Args>\nstruct with_diag_signature<R(error_code, Args...)>\n{\n    using type = R(std::exception_ptr, Args...);\n};\n\ntemplate <typename R, typename... Args>\nstruct with_diag_signature<R(error_code, Args...)&>\n{\n    using type = R(std::exception_ptr, Args...) &;\n};\n\ntemplate <typename R, typename... Args>\nstruct with_diag_signature<R(error_code, Args...) &&>\n{\n    using type = R(std::exception_ptr, Args...) &&;\n};\n\n#if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)\n\ntemplate <typename R, typename... Args>\nstruct with_diag_signature<R(error_code, Args...) noexcept>\n{\n    using type = R(std::exception_ptr, Args...) noexcept;\n};\n\ntemplate <typename R, typename... Args>\nstruct with_diag_signature<R(error_code, Args...) & noexcept>\n{\n    using type = R(std::exception_ptr, Args...) & noexcept;\n};\n\ntemplate <typename R, typename... Args>\nstruct with_diag_signature<R(error_code, Args...) && noexcept>\n{\n    using type = R(std::exception_ptr, Args...) && noexcept;\n};\n\n#endif  // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)\n\n// Inheriting from Initiation propagates its executor type,\n// if any. Required by tokens like asio::cancel_after\ntemplate <class Initiation>\nstruct with_diag_init : public Initiation\n{\n    template <class I>\n    with_diag_init(I&& i) : Initiation(std::forward<I>(i))\n    {\n    }\n\n    // We pass the inner token's initiation as 1st arg\n    template <class Handler, class... Args>\n    void operator()(Handler&& handler, Args&&... args) &&\n    {\n        // Find the diagnostics object in the list of arguments\n        using types = mp11::mp_list<typename std::decay<Args>::type...>;\n        constexpr std::size_t pos = mp11::mp_find<types, diagnostics*>::value;\n\n        // If you're getting an error here, it's because you're trying to use\n        // with_diagnostics with an async function unrelated to Boost.MySQL.\n        static_assert(\n            pos < mp11::mp_size<types>::value,\n            \"with_diagnostics only works with Boost.MySQL async functions\"\n        );\n\n        // Actually get the object\n        diagnostics*& diag = std::get<pos>(std::tuple<Args&...>{args...});\n\n        // Some functions (e.g. connection_pool) may pass nullptr as diag.\n        // When using this token, allocate a diagnostics instance and overwrite the passed value\n        std::shared_ptr<diagnostics> owning_diag;\n        if (!diag)\n        {\n            // The allocator to use\n            auto base_alloc = asio::get_associated_allocator(handler);\n            using alloc_type = typename std::allocator_traits<decltype(base_alloc\n            )>::template rebind_alloc<diagnostics>;\n\n            owning_diag = std::allocate_shared<diagnostics>(alloc_type{std::move(base_alloc)});\n            diag = owning_diag.get();\n        }\n\n        // Actually initiate\n        static_cast<Initiation&&>(*this)(\n            make_intermediate_handler(\n                with_diag_handler_fn{*diag, std::move(owning_diag)},\n                std::forward<Handler>(handler)\n            ),\n            std::forward<Args>(args)...\n        );\n    }\n};\n\n// Did with_diagnostics modify any of the signatures?\n// We really support only modifying all or none, and that's enough.\ntemplate <class Signature>\nusing with_diag_has_original_signature = std::\n    is_same<Signature, typename with_diag_signature<Signature>::type>;\n\ntemplate <class... Signatures>\nusing with_diag_has_original_signatures = mp11::\n    mp_all_of<mp11::mp_list<Signatures...>, with_diag_has_original_signature>;\n\ntemplate <typename CompletionToken, bool has_original_signatures, typename... Signatures>\nstruct with_diagnostics_async_result;\n\n// async_result when the signature was modified\ntemplate <typename CompletionToken, typename... Signatures>\nstruct with_diagnostics_async_result<CompletionToken, false, Signatures...>\n    : asio::async_result<CompletionToken, typename with_diag_signature<Signatures>::type...>\n{\n    template <class RawCompletionToken>\n    using maybe_const_token_t = typename std::conditional<\n        std::is_const<typename std::remove_reference<RawCompletionToken>::type>::value,\n        const CompletionToken,\n        CompletionToken>::type;\n\n    template <typename Initiation, typename RawCompletionToken, typename... Args>\n    static auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)\n        -> decltype(asio::async_initiate<\n                    maybe_const_token_t<RawCompletionToken>,\n                    typename with_diag_signature<Signatures>::type...>(\n            with_diag_init<typename std::decay<Initiation>::type>{std::forward<Initiation>(initiation)},\n            access::get_impl(token),\n            std::forward<Args>(args)...\n        ))\n    {\n        return asio::async_initiate<\n            maybe_const_token_t<RawCompletionToken>,\n            typename with_diag_signature<Signatures>::type...>(\n            with_diag_init<typename std::decay<Initiation>::type>{std::forward<Initiation>(initiation)},\n            access::get_impl(token),\n            std::forward<Args>(args)...\n        );\n    }\n};\n\n// async_result when the signature wasn't modified (pass-through)\ntemplate <typename CompletionToken, typename... Signatures>\nstruct with_diagnostics_async_result<CompletionToken, true, Signatures...>\n    : asio::async_result<CompletionToken, Signatures...>\n{\n    template <class RawCompletionToken>\n    using maybe_const_token_t = typename std::conditional<\n        std::is_const<typename std::remove_reference<RawCompletionToken>::type>::value,\n        const CompletionToken,\n        CompletionToken>::type;\n\n    template <typename Initiation, typename RawCompletionToken, typename... Args>\n    static auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args)\n        -> decltype(asio::async_initiate<maybe_const_token_t<RawCompletionToken>, Signatures...>(\n            std::forward<Initiation>(initiation),\n            access::get_impl(token),\n            std::forward<Args>(args)...\n        ))\n    {\n        return asio::async_initiate<maybe_const_token_t<RawCompletionToken>, Signatures...>(\n            std::forward<Initiation>(initiation),\n            access::get_impl(token),\n            std::forward<Args>(args)...\n        );\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n\nnamespace asio {\n\ntemplate <typename CompletionToken, typename... Signatures>\nstruct async_result<mysql::with_diagnostics_t<CompletionToken>, Signatures...>\n    : mysql::detail::with_diagnostics_async_result<\n          CompletionToken,\n          mysql::detail::with_diag_has_original_signatures<Signatures...>::value,\n          Signatures...>\n{\n};\n\n}  // namespace asio\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/impl/with_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IMPL_WITH_PARAMS_HPP\n#define BOOST_MYSQL_IMPL_WITH_PARAMS_HPP\n\n#pragma once\n\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/mysql/detail/any_execution_request.hpp>\n\n#include <boost/core/ignore_unused.hpp>\n#include <boost/core/span.hpp>\n#include <boost/mp11/integer_sequence.hpp>\n\n// Execution request traits\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\ntemplate <std::size_t N>\nstruct with_params_proxy\n{\n    constant_string_view query;\n    std::array<format_arg, N> args;\n\n    operator detail::any_execution_request() const { return any_execution_request({query, args}); }\n};\n\ntemplate <class... T>\nstruct execution_request_traits<with_params_t<T...>>\n{\n    template <class WithParamsType, std::size_t... I>\n    static with_params_proxy<sizeof...(T)> make_request_impl(WithParamsType&& input, mp11::index_sequence<I...>)\n    {\n        boost::ignore_unused(input);  // MSVC gets confused for tuples of size 0\n        // clang-format off\n        return {\n            input.query,\n            {{\n                {\n                    string_view(),\n                    formattable_ref(std::get<I>(std::forward<WithParamsType>(input).args))\n                }...\n            }}\n        };\n        // clang-format on\n    }\n\n    // Allow the value category of the object to be deduced\n    template <class WithParamsType>\n    static with_params_proxy<sizeof...(T)> make_request(WithParamsType&& input, std::vector<field_view>&)\n    {\n        return make_request_impl(\n            std::forward<WithParamsType>(input),\n            mp11::make_index_sequence<sizeof...(T)>()\n        );\n    }\n};\n\n// Old MSVCs fail to process the above when sizeof...(T) is zero\ntemplate <>\nstruct execution_request_traits<with_params_t<>>\n{\n    static any_execution_request make_request(with_params_t<> input, std::vector<field_view>&)\n    {\n        return any_execution_request({input.query, span<format_arg>{}});\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/is_fatal_error.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_IS_FATAL_ERROR_HPP\n#define BOOST_MYSQL_IS_FATAL_ERROR_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Checks whether an error requires re-connection.\n * \\details\n * After an operation on an established connection (like executing a query) fails,\n * the connection may be usable for further operations (if the error was non-fatal)\n * or not (if the error was fatal). This function determines whether an error\n * code returned by a connection operation is fatal or not.\n * \\n\n * To recover from a fatal error code, close and re-establish the connection.\n *\n * \\par Exception safety\n * No-throw guarantee.\n */\nBOOST_MYSQL_DECL\nbool is_fatal_error(error_code ec) noexcept;\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/is_fatal_error.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/mariadb_collations.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_MARIADB_COLLATIONS_HPP\n#define BOOST_MYSQL_MARIADB_COLLATIONS_HPP\n\n// This header was generated by collations.py - do not edit directly\n\n#include <boost/config.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace mariadb_collations {\n\n// Identifies the big5_chinese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t big5_chinese_ci = 1;\n\n// Identifies the latin2_czech_cs collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_czech_cs = 2;\n\n// Identifies the dec8_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t dec8_swedish_ci = 3;\n\n// Identifies the cp850_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp850_general_ci = 4;\n\n// Identifies the latin1_german1_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_german1_ci = 5;\n\n// Identifies the hp8_english_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hp8_english_ci = 6;\n\n// Identifies the koi8r_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8r_general_ci = 7;\n\n// Identifies the latin1_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_swedish_ci = 8;\n\n// Identifies the latin2_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_general_ci = 9;\n\n// Identifies the swe7_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t swe7_swedish_ci = 10;\n\n// Identifies the ascii_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ascii_general_ci = 11;\n\n// Identifies the ujis_japanese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ujis_japanese_ci = 12;\n\n// Identifies the sjis_japanese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t sjis_japanese_ci = 13;\n\n// Identifies the cp1251_bulgarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_bulgarian_ci = 14;\n\n// Identifies the latin1_danish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_danish_ci = 15;\n\n// Identifies the hebrew_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hebrew_general_ci = 16;\n\n// Identifies the tis620_thai_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t tis620_thai_ci = 18;\n\n// Identifies the euckr_korean_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t euckr_korean_ci = 19;\n\n// Identifies the latin7_estonian_cs collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_estonian_cs = 20;\n\n// Identifies the latin2_hungarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_hungarian_ci = 21;\n\n// Identifies the koi8u_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8u_general_ci = 22;\n\n// Identifies the cp1251_ukrainian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_ukrainian_ci = 23;\n\n// Identifies the gb2312_chinese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb2312_chinese_ci = 24;\n\n// Identifies the greek_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t greek_general_ci = 25;\n\n// Identifies the cp1250_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_general_ci = 26;\n\n// Identifies the latin2_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_croatian_ci = 27;\n\n// Identifies the gbk_chinese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gbk_chinese_ci = 28;\n\n// Identifies the cp1257_lithuanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_lithuanian_ci = 29;\n\n// Identifies the latin5_turkish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin5_turkish_ci = 30;\n\n// Identifies the latin1_german2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_german2_ci = 31;\n\n// Identifies the armscii8_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t armscii8_general_ci = 32;\n\n// Identifies the utf8_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_general_ci = 33;\n\n// Identifies the cp1250_czech_cs collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_czech_cs = 34;\n\n// Identifies the ucs2_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_general_ci = 35;\n\n// Identifies the cp866_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp866_general_ci = 36;\n\n// Identifies the keybcs2_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t keybcs2_general_ci = 37;\n\n// Identifies the macce_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macce_general_ci = 38;\n\n// Identifies the macroman_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macroman_general_ci = 39;\n\n// Identifies the cp852_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp852_general_ci = 40;\n\n// Identifies the latin7_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_general_ci = 41;\n\n// Identifies the latin7_general_cs collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_general_cs = 42;\n\n// Identifies the macce_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macce_bin = 43;\n\n// Identifies the cp1250_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_croatian_ci = 44;\n\n// Identifies the utf8mb4_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_general_ci = 45;\n\n// Identifies the utf8mb4_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_bin = 46;\n\n// Identifies the latin1_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_bin = 47;\n\n// Identifies the latin1_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_general_ci = 48;\n\n// Identifies the latin1_general_cs collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_general_cs = 49;\n\n// Identifies the cp1251_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_bin = 50;\n\n// Identifies the cp1251_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_general_ci = 51;\n\n// Identifies the cp1251_general_cs collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_general_cs = 52;\n\n// Identifies the macroman_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macroman_bin = 53;\n\n// Identifies the utf16_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_general_ci = 54;\n\n// Identifies the utf16_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_bin = 55;\n\n// Identifies the utf16le_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16le_general_ci = 56;\n\n// Identifies the cp1256_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1256_general_ci = 57;\n\n// Identifies the cp1257_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_bin = 58;\n\n// Identifies the cp1257_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_general_ci = 59;\n\n// Identifies the utf32_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_general_ci = 60;\n\n// Identifies the utf32_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_bin = 61;\n\n// Identifies the utf16le_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16le_bin = 62;\n\n// Identifies the binary collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t binary = 63;\n\n// Identifies the armscii8_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t armscii8_bin = 64;\n\n// Identifies the ascii_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ascii_bin = 65;\n\n// Identifies the cp1250_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_bin = 66;\n\n// Identifies the cp1256_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1256_bin = 67;\n\n// Identifies the cp866_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp866_bin = 68;\n\n// Identifies the dec8_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t dec8_bin = 69;\n\n// Identifies the greek_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t greek_bin = 70;\n\n// Identifies the hebrew_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hebrew_bin = 71;\n\n// Identifies the hp8_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hp8_bin = 72;\n\n// Identifies the keybcs2_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t keybcs2_bin = 73;\n\n// Identifies the koi8r_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8r_bin = 74;\n\n// Identifies the koi8u_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8u_bin = 75;\n\n// Identifies the latin2_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_bin = 77;\n\n// Identifies the latin5_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin5_bin = 78;\n\n// Identifies the latin7_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_bin = 79;\n\n// Identifies the cp850_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp850_bin = 80;\n\n// Identifies the cp852_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp852_bin = 81;\n\n// Identifies the swe7_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t swe7_bin = 82;\n\n// Identifies the utf8_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_bin = 83;\n\n// Identifies the big5_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t big5_bin = 84;\n\n// Identifies the euckr_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t euckr_bin = 85;\n\n// Identifies the gb2312_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb2312_bin = 86;\n\n// Identifies the gbk_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gbk_bin = 87;\n\n// Identifies the sjis_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t sjis_bin = 88;\n\n// Identifies the tis620_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t tis620_bin = 89;\n\n// Identifies the ucs2_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_bin = 90;\n\n// Identifies the ujis_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ujis_bin = 91;\n\n// Identifies the geostd8_general_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t geostd8_general_ci = 92;\n\n// Identifies the geostd8_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t geostd8_bin = 93;\n\n// Identifies the latin1_spanish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_spanish_ci = 94;\n\n// Identifies the cp932_japanese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp932_japanese_ci = 95;\n\n// Identifies the cp932_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp932_bin = 96;\n\n// Identifies the eucjpms_japanese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t eucjpms_japanese_ci = 97;\n\n// Identifies the eucjpms_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t eucjpms_bin = 98;\n\n// Identifies the cp1250_polish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_polish_ci = 99;\n\n// Identifies the utf16_unicode_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_unicode_ci = 101;\n\n// Identifies the utf16_icelandic_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_icelandic_ci = 102;\n\n// Identifies the utf16_latvian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_latvian_ci = 103;\n\n// Identifies the utf16_romanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_romanian_ci = 104;\n\n// Identifies the utf16_slovenian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_slovenian_ci = 105;\n\n// Identifies the utf16_polish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_polish_ci = 106;\n\n// Identifies the utf16_estonian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_estonian_ci = 107;\n\n// Identifies the utf16_spanish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_spanish_ci = 108;\n\n// Identifies the utf16_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_swedish_ci = 109;\n\n// Identifies the utf16_turkish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_turkish_ci = 110;\n\n// Identifies the utf16_czech_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_czech_ci = 111;\n\n// Identifies the utf16_danish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_danish_ci = 112;\n\n// Identifies the utf16_lithuanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_lithuanian_ci = 113;\n\n// Identifies the utf16_slovak_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_slovak_ci = 114;\n\n// Identifies the utf16_spanish2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_spanish2_ci = 115;\n\n// Identifies the utf16_roman_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_roman_ci = 116;\n\n// Identifies the utf16_persian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_persian_ci = 117;\n\n// Identifies the utf16_esperanto_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_esperanto_ci = 118;\n\n// Identifies the utf16_hungarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_hungarian_ci = 119;\n\n// Identifies the utf16_sinhala_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_sinhala_ci = 120;\n\n// Identifies the utf16_german2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_german2_ci = 121;\n\n// Identifies the utf16_croatian_mysql561_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_croatian_mysql561_ci = 122;\n\n// Identifies the utf16_unicode_520_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_unicode_520_ci = 123;\n\n// Identifies the utf16_vietnamese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_vietnamese_ci = 124;\n\n// Identifies the ucs2_unicode_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_unicode_ci = 128;\n\n// Identifies the ucs2_icelandic_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_icelandic_ci = 129;\n\n// Identifies the ucs2_latvian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_latvian_ci = 130;\n\n// Identifies the ucs2_romanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_romanian_ci = 131;\n\n// Identifies the ucs2_slovenian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_slovenian_ci = 132;\n\n// Identifies the ucs2_polish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_polish_ci = 133;\n\n// Identifies the ucs2_estonian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_estonian_ci = 134;\n\n// Identifies the ucs2_spanish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_spanish_ci = 135;\n\n// Identifies the ucs2_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_swedish_ci = 136;\n\n// Identifies the ucs2_turkish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_turkish_ci = 137;\n\n// Identifies the ucs2_czech_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_czech_ci = 138;\n\n// Identifies the ucs2_danish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_danish_ci = 139;\n\n// Identifies the ucs2_lithuanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_lithuanian_ci = 140;\n\n// Identifies the ucs2_slovak_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_slovak_ci = 141;\n\n// Identifies the ucs2_spanish2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_spanish2_ci = 142;\n\n// Identifies the ucs2_roman_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_roman_ci = 143;\n\n// Identifies the ucs2_persian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_persian_ci = 144;\n\n// Identifies the ucs2_esperanto_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_esperanto_ci = 145;\n\n// Identifies the ucs2_hungarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_hungarian_ci = 146;\n\n// Identifies the ucs2_sinhala_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_sinhala_ci = 147;\n\n// Identifies the ucs2_german2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_german2_ci = 148;\n\n// Identifies the ucs2_croatian_mysql561_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_croatian_mysql561_ci = 149;\n\n// Identifies the ucs2_unicode_520_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_unicode_520_ci = 150;\n\n// Identifies the ucs2_vietnamese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_vietnamese_ci = 151;\n\n// Identifies the ucs2_general_mysql500_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_general_mysql500_ci = 159;\n\n// Identifies the utf32_unicode_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_unicode_ci = 160;\n\n// Identifies the utf32_icelandic_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_icelandic_ci = 161;\n\n// Identifies the utf32_latvian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_latvian_ci = 162;\n\n// Identifies the utf32_romanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_romanian_ci = 163;\n\n// Identifies the utf32_slovenian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_slovenian_ci = 164;\n\n// Identifies the utf32_polish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_polish_ci = 165;\n\n// Identifies the utf32_estonian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_estonian_ci = 166;\n\n// Identifies the utf32_spanish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_spanish_ci = 167;\n\n// Identifies the utf32_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_swedish_ci = 168;\n\n// Identifies the utf32_turkish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_turkish_ci = 169;\n\n// Identifies the utf32_czech_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_czech_ci = 170;\n\n// Identifies the utf32_danish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_danish_ci = 171;\n\n// Identifies the utf32_lithuanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_lithuanian_ci = 172;\n\n// Identifies the utf32_slovak_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_slovak_ci = 173;\n\n// Identifies the utf32_spanish2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_spanish2_ci = 174;\n\n// Identifies the utf32_roman_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_roman_ci = 175;\n\n// Identifies the utf32_persian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_persian_ci = 176;\n\n// Identifies the utf32_esperanto_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_esperanto_ci = 177;\n\n// Identifies the utf32_hungarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_hungarian_ci = 178;\n\n// Identifies the utf32_sinhala_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_sinhala_ci = 179;\n\n// Identifies the utf32_german2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_german2_ci = 180;\n\n// Identifies the utf32_croatian_mysql561_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_croatian_mysql561_ci = 181;\n\n// Identifies the utf32_unicode_520_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_unicode_520_ci = 182;\n\n// Identifies the utf32_vietnamese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_vietnamese_ci = 183;\n\n// Identifies the utf8_unicode_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_unicode_ci = 192;\n\n// Identifies the utf8_icelandic_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_icelandic_ci = 193;\n\n// Identifies the utf8_latvian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_latvian_ci = 194;\n\n// Identifies the utf8_romanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_romanian_ci = 195;\n\n// Identifies the utf8_slovenian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_slovenian_ci = 196;\n\n// Identifies the utf8_polish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_polish_ci = 197;\n\n// Identifies the utf8_estonian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_estonian_ci = 198;\n\n// Identifies the utf8_spanish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_spanish_ci = 199;\n\n// Identifies the utf8_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_swedish_ci = 200;\n\n// Identifies the utf8_turkish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_turkish_ci = 201;\n\n// Identifies the utf8_czech_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_czech_ci = 202;\n\n// Identifies the utf8_danish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_danish_ci = 203;\n\n// Identifies the utf8_lithuanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_lithuanian_ci = 204;\n\n// Identifies the utf8_slovak_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_slovak_ci = 205;\n\n// Identifies the utf8_spanish2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_spanish2_ci = 206;\n\n// Identifies the utf8_roman_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_roman_ci = 207;\n\n// Identifies the utf8_persian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_persian_ci = 208;\n\n// Identifies the utf8_esperanto_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_esperanto_ci = 209;\n\n// Identifies the utf8_hungarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_hungarian_ci = 210;\n\n// Identifies the utf8_sinhala_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_sinhala_ci = 211;\n\n// Identifies the utf8_german2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_german2_ci = 212;\n\n// Identifies the utf8_croatian_mysql561_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_croatian_mysql561_ci = 213;\n\n// Identifies the utf8_unicode_520_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_unicode_520_ci = 214;\n\n// Identifies the utf8_vietnamese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_vietnamese_ci = 215;\n\n// Identifies the utf8_general_mysql500_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_general_mysql500_ci = 223;\n\n// Identifies the utf8mb4_unicode_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_unicode_ci = 224;\n\n// Identifies the utf8mb4_icelandic_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_icelandic_ci = 225;\n\n// Identifies the utf8mb4_latvian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_latvian_ci = 226;\n\n// Identifies the utf8mb4_romanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_romanian_ci = 227;\n\n// Identifies the utf8mb4_slovenian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_slovenian_ci = 228;\n\n// Identifies the utf8mb4_polish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_polish_ci = 229;\n\n// Identifies the utf8mb4_estonian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_estonian_ci = 230;\n\n// Identifies the utf8mb4_spanish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_spanish_ci = 231;\n\n// Identifies the utf8mb4_swedish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_swedish_ci = 232;\n\n// Identifies the utf8mb4_turkish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_turkish_ci = 233;\n\n// Identifies the utf8mb4_czech_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_czech_ci = 234;\n\n// Identifies the utf8mb4_danish_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_danish_ci = 235;\n\n// Identifies the utf8mb4_lithuanian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_lithuanian_ci = 236;\n\n// Identifies the utf8mb4_slovak_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_slovak_ci = 237;\n\n// Identifies the utf8mb4_spanish2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_spanish2_ci = 238;\n\n// Identifies the utf8mb4_roman_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_roman_ci = 239;\n\n// Identifies the utf8mb4_persian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_persian_ci = 240;\n\n// Identifies the utf8mb4_esperanto_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_esperanto_ci = 241;\n\n// Identifies the utf8mb4_hungarian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_hungarian_ci = 242;\n\n// Identifies the utf8mb4_sinhala_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sinhala_ci = 243;\n\n// Identifies the utf8mb4_german2_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_german2_ci = 244;\n\n// Identifies the utf8mb4_croatian_mysql561_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_croatian_mysql561_ci = 245;\n\n// Identifies the utf8mb4_unicode_520_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_unicode_520_ci = 246;\n\n// Identifies the utf8mb4_vietnamese_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_vietnamese_ci = 247;\n\n// Identifies the utf8_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_croatian_ci = 576;\n\n// Identifies the utf8_myanmar_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_myanmar_ci = 577;\n\n// Identifies the utf8_thai_520_w2 collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_thai_520_w2 = 578;\n\n// Identifies the utf8mb4_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_croatian_ci = 608;\n\n// Identifies the utf8mb4_myanmar_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_myanmar_ci = 609;\n\n// Identifies the utf8mb4_thai_520_w2 collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_thai_520_w2 = 610;\n\n// Identifies the ucs2_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_croatian_ci = 640;\n\n// Identifies the ucs2_myanmar_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_myanmar_ci = 641;\n\n// Identifies the ucs2_thai_520_w2 collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_thai_520_w2 = 642;\n\n// Identifies the utf16_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_croatian_ci = 672;\n\n// Identifies the utf16_myanmar_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_myanmar_ci = 673;\n\n// Identifies the utf16_thai_520_w2 collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_thai_520_w2 = 674;\n\n// Identifies the utf32_croatian_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_croatian_ci = 736;\n\n// Identifies the utf32_myanmar_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_myanmar_ci = 737;\n\n// Identifies the utf32_thai_520_w2 collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_thai_520_w2 = 738;\n\n// Identifies the big5_chinese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t big5_chinese_nopad_ci = 1025;\n\n// Identifies the dec8_swedish_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t dec8_swedish_nopad_ci = 1027;\n\n// Identifies the cp850_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp850_general_nopad_ci = 1028;\n\n// Identifies the hp8_english_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hp8_english_nopad_ci = 1030;\n\n// Identifies the koi8r_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8r_general_nopad_ci = 1031;\n\n// Identifies the latin1_swedish_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_swedish_nopad_ci = 1032;\n\n// Identifies the latin2_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_general_nopad_ci = 1033;\n\n// Identifies the swe7_swedish_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t swe7_swedish_nopad_ci = 1034;\n\n// Identifies the ascii_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ascii_general_nopad_ci = 1035;\n\n// Identifies the ujis_japanese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ujis_japanese_nopad_ci = 1036;\n\n// Identifies the sjis_japanese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t sjis_japanese_nopad_ci = 1037;\n\n// Identifies the hebrew_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hebrew_general_nopad_ci = 1040;\n\n// Identifies the tis620_thai_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t tis620_thai_nopad_ci = 1042;\n\n// Identifies the euckr_korean_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t euckr_korean_nopad_ci = 1043;\n\n// Identifies the koi8u_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8u_general_nopad_ci = 1046;\n\n// Identifies the gb2312_chinese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb2312_chinese_nopad_ci = 1048;\n\n// Identifies the greek_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t greek_general_nopad_ci = 1049;\n\n// Identifies the cp1250_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_general_nopad_ci = 1050;\n\n// Identifies the gbk_chinese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gbk_chinese_nopad_ci = 1052;\n\n// Identifies the latin5_turkish_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin5_turkish_nopad_ci = 1054;\n\n// Identifies the armscii8_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t armscii8_general_nopad_ci = 1056;\n\n// Identifies the utf8_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_general_nopad_ci = 1057;\n\n// Identifies the ucs2_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_general_nopad_ci = 1059;\n\n// Identifies the cp866_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp866_general_nopad_ci = 1060;\n\n// Identifies the keybcs2_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t keybcs2_general_nopad_ci = 1061;\n\n// Identifies the macce_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macce_general_nopad_ci = 1062;\n\n// Identifies the macroman_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macroman_general_nopad_ci = 1063;\n\n// Identifies the cp852_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp852_general_nopad_ci = 1064;\n\n// Identifies the latin7_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_general_nopad_ci = 1065;\n\n// Identifies the macce_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macce_nopad_bin = 1067;\n\n// Identifies the utf8mb4_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_general_nopad_ci = 1069;\n\n// Identifies the utf8mb4_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_nopad_bin = 1070;\n\n// Identifies the latin1_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_nopad_bin = 1071;\n\n// Identifies the cp1251_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_nopad_bin = 1074;\n\n// Identifies the cp1251_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_general_nopad_ci = 1075;\n\n// Identifies the macroman_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macroman_nopad_bin = 1077;\n\n// Identifies the utf16_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_general_nopad_ci = 1078;\n\n// Identifies the utf16_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_nopad_bin = 1079;\n\n// Identifies the utf16le_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16le_general_nopad_ci = 1080;\n\n// Identifies the cp1256_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1256_general_nopad_ci = 1081;\n\n// Identifies the cp1257_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_nopad_bin = 1082;\n\n// Identifies the cp1257_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_general_nopad_ci = 1083;\n\n// Identifies the utf32_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_general_nopad_ci = 1084;\n\n// Identifies the utf32_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_nopad_bin = 1085;\n\n// Identifies the utf16le_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16le_nopad_bin = 1086;\n\n// Identifies the armscii8_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t armscii8_nopad_bin = 1088;\n\n// Identifies the ascii_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ascii_nopad_bin = 1089;\n\n// Identifies the cp1250_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_nopad_bin = 1090;\n\n// Identifies the cp1256_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1256_nopad_bin = 1091;\n\n// Identifies the cp866_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp866_nopad_bin = 1092;\n\n// Identifies the dec8_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t dec8_nopad_bin = 1093;\n\n// Identifies the greek_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t greek_nopad_bin = 1094;\n\n// Identifies the hebrew_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hebrew_nopad_bin = 1095;\n\n// Identifies the hp8_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hp8_nopad_bin = 1096;\n\n// Identifies the keybcs2_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t keybcs2_nopad_bin = 1097;\n\n// Identifies the koi8r_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8r_nopad_bin = 1098;\n\n// Identifies the koi8u_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8u_nopad_bin = 1099;\n\n// Identifies the latin2_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_nopad_bin = 1101;\n\n// Identifies the latin5_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin5_nopad_bin = 1102;\n\n// Identifies the latin7_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_nopad_bin = 1103;\n\n// Identifies the cp850_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp850_nopad_bin = 1104;\n\n// Identifies the cp852_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp852_nopad_bin = 1105;\n\n// Identifies the swe7_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t swe7_nopad_bin = 1106;\n\n// Identifies the utf8_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_nopad_bin = 1107;\n\n// Identifies the big5_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t big5_nopad_bin = 1108;\n\n// Identifies the euckr_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t euckr_nopad_bin = 1109;\n\n// Identifies the gb2312_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb2312_nopad_bin = 1110;\n\n// Identifies the gbk_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gbk_nopad_bin = 1111;\n\n// Identifies the sjis_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t sjis_nopad_bin = 1112;\n\n// Identifies the tis620_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t tis620_nopad_bin = 1113;\n\n// Identifies the ucs2_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_nopad_bin = 1114;\n\n// Identifies the ujis_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ujis_nopad_bin = 1115;\n\n// Identifies the geostd8_general_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t geostd8_general_nopad_ci = 1116;\n\n// Identifies the geostd8_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t geostd8_nopad_bin = 1117;\n\n// Identifies the cp932_japanese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp932_japanese_nopad_ci = 1119;\n\n// Identifies the cp932_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp932_nopad_bin = 1120;\n\n// Identifies the eucjpms_japanese_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t eucjpms_japanese_nopad_ci = 1121;\n\n// Identifies the eucjpms_nopad_bin collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t eucjpms_nopad_bin = 1122;\n\n// Identifies the utf16_unicode_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_unicode_nopad_ci = 1125;\n\n// Identifies the utf16_unicode_520_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_unicode_520_nopad_ci = 1147;\n\n// Identifies the ucs2_unicode_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_unicode_nopad_ci = 1152;\n\n// Identifies the ucs2_unicode_520_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_unicode_520_nopad_ci = 1174;\n\n// Identifies the utf32_unicode_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_unicode_nopad_ci = 1184;\n\n// Identifies the utf32_unicode_520_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_unicode_520_nopad_ci = 1206;\n\n// Identifies the utf8_unicode_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_unicode_nopad_ci = 1216;\n\n// Identifies the utf8_unicode_520_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_unicode_520_nopad_ci = 1238;\n\n// Identifies the utf8mb4_unicode_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_unicode_nopad_ci = 1248;\n\n// Identifies the utf8mb4_unicode_520_nopad_ci collation in mariadb servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_unicode_520_nopad_ci = 1270;\n\n}  // namespace mariadb_collations\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/mariadb_server_errc.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_MARIADB_SERVER_ERRC_HPP\n#define BOOST_MYSQL_MARIADB_SERVER_ERRC_HPP\n\n#include <boost/config.hpp>\n\nnamespace boost {\nnamespace mysql {\n\nnamespace mariadb_server_errc {\n\n/// Server error specific to mariadb. Error number: 1076, symbol: ER_BINLOG_CANT_DELETE_GTID_DOMAIN.\nBOOST_INLINE_CONSTEXPR int er_binlog_cant_delete_gtid_domain = 1076;\n\n/// Server error specific to mariadb. Error number: 1120, symbol: ER_WRONG_OUTER_JOIN.\nBOOST_INLINE_CONSTEXPR int er_wrong_outer_join = 1120;\n\n/// Server error specific to mariadb. Error number: 1150, symbol: ER_DELAYED_CANT_CHANGE_LOCK.\nBOOST_INLINE_CONSTEXPR int er_delayed_cant_change_lock = 1150;\n\n/// Server error specific to mariadb. Error number: 1151, symbol: ER_TOO_MANY_DELAYED_THREADS.\nBOOST_INLINE_CONSTEXPR int er_too_many_delayed_threads = 1151;\n\n/// Server error specific to mariadb. Error number: 1165, symbol: ER_DELAYED_INSERT_TABLE_LOCKED.\nBOOST_INLINE_CONSTEXPR int er_delayed_insert_table_locked = 1165;\n\n/// Server error specific to mariadb. Error number: 1176, symbol: ER_KEY_DOES_NOT_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_key_does_not_exists = 1176;\n\n/// Server error specific to mariadb. Error number: 1349, symbol: ER_VIEW_SELECT_DERIVED.\nBOOST_INLINE_CONSTEXPR int er_view_select_derived = 1349;\n\n/// Server error specific to mariadb. Error number: 1487, symbol: ER_NOT_CONSTANT_EXPRESSION.\nBOOST_INLINE_CONSTEXPR int er_not_constant_expression = 1487;\n\n/// Server error specific to mariadb. Error number: 1506, symbol: ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING.\nBOOST_INLINE_CONSTEXPR int er_feature_not_supported_with_partitioning = 1506;\n\n/// Server error specific to mariadb. Error number: 1593, symbol: ER_SLAVE_FATAL_ERROR.\nBOOST_INLINE_CONSTEXPR int er_slave_fatal_error = 1593;\n\n/// Server error specific to mariadb. Error number: 1611, symbol: ER_LOAD_DATA_INVALID_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_load_data_invalid_column = 1611;\n\n/// Server error specific to mariadb. Error number: 1669, symbol: ER_BINLOG_UNSAFE_INSERT_DELAYED.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_insert_delayed = 1669;\n\n/// Server error specific to mariadb. Error number: 1726, symbol: ER_VERS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_vers_not_allowed = 1726;\n\n/// Server error specific to mariadb. Error number: 1742, symbol: ER_VALUE_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_value_too_long = 1742;\n\n/// Server error specific to mariadb. Error number: 1768, symbol: ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL.\nBOOST_INLINE_CONSTEXPR int er_cant_change_gtid_next_in_transaction_when_gtid_next_list_is_null = 1768;\n\n/// Server error specific to mariadb. Error number: 1777, symbol: ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON.\nBOOST_INLINE_CONSTEXPR int er_auto_position_requires_gtid_mode_on = 1777;\n\n/// Server error specific to mariadb. Error number: 1779, symbol: ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON.\nBOOST_INLINE_CONSTEXPR int er_gtid_mode_2_or_3_requires_enforce_gtid_consistency_on = 1779;\n\n/// Server error specific to mariadb. Error number: 1784, symbol: ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF.\nBOOST_INLINE_CONSTEXPR int er_found_gtid_event_when_gtid_mode_is_off = 1784;\n\n/// Server error specific to mariadb. Error number: 1826, symbol: ER_DUP_CONSTRAINT_NAME.\nBOOST_INLINE_CONSTEXPR int er_dup_constraint_name = 1826;\n\n/// Server error specific to mariadb. Error number: 1834, symbol: ER_FK_CANNOT_DELETE_PARENT.\nBOOST_INLINE_CONSTEXPR int er_fk_cannot_delete_parent = 1834;\n\n/// Server error specific to mariadb. Error number: 1837, symbol: ER_GTID_NEXT_TYPE_UNDEFINED_GROUP.\nBOOST_INLINE_CONSTEXPR int er_gtid_next_type_undefined_group = 1837;\n\n/// Server error specific to mariadb. Error number: 1852, symbol: ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE.\nBOOST_INLINE_CONSTEXPR int er_alter_operation_not_supported_reason_ignore = 1852;\n\n/// Server error specific to mariadb. Error number: 1901, symbol: ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_generated_column_function_is_not_allowed = 1901;\n\n/// Server error specific to mariadb. Error number: 1903, symbol: ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_primary_key_based_on_generated_column = 1903;\n\n/// Server error specific to mariadb. Error number: 1904, symbol: ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_key_based_on_generated_virtual_column = 1904;\n\n/// Server error specific to mariadb. Error number: 1905, symbol: ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_wrong_fk_option_for_generated_column = 1905;\n\n/// Server error specific to mariadb. Error number: 1906, symbol: ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_warning_non_default_value_for_generated_column = 1906;\n\n/// Server error specific to mariadb. Error number: 1907, symbol: ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_unsupported_action_on_generated_column = 1907;\n\n/// Server error specific to mariadb. Error number: 1910, symbol: ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS.\nBOOST_INLINE_CONSTEXPR int er_unsupported_engine_for_generated_columns = 1910;\n\n/// Server error specific to mariadb. Error number: 1911, symbol: ER_UNKNOWN_OPTION.\nBOOST_INLINE_CONSTEXPR int er_unknown_option = 1911;\n\n/// Server error specific to mariadb. Error number: 1912, symbol: ER_BAD_OPTION_VALUE.\nBOOST_INLINE_CONSTEXPR int er_bad_option_value = 1912;\n\n/// Server error specific to mariadb. Error number: 1916, symbol: ER_DATA_OVERFLOW.\nBOOST_INLINE_CONSTEXPR int er_data_overflow = 1916;\n\n/// Server error specific to mariadb. Error number: 1917, symbol: ER_DATA_TRUNCATED.\nBOOST_INLINE_CONSTEXPR int er_data_truncated = 1917;\n\n/// Server error specific to mariadb. Error number: 1918, symbol: ER_BAD_DATA.\nBOOST_INLINE_CONSTEXPR int er_bad_data = 1918;\n\n/// Server error specific to mariadb. Error number: 1919, symbol: ER_DYN_COL_WRONG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_dyn_col_wrong_format = 1919;\n\n/// Server error specific to mariadb. Error number: 1920, symbol: ER_DYN_COL_IMPLEMENTATION_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_dyn_col_implementation_limit = 1920;\n\n/// Server error specific to mariadb. Error number: 1921, symbol: ER_DYN_COL_DATA.\nBOOST_INLINE_CONSTEXPR int er_dyn_col_data = 1921;\n\n/// Server error specific to mariadb. Error number: 1922, symbol: ER_DYN_COL_WRONG_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_dyn_col_wrong_charset = 1922;\n\n/// Server error specific to mariadb. Error number: 1923, symbol: ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES.\nBOOST_INLINE_CONSTEXPR int er_illegal_subquery_optimizer_switches = 1923;\n\n/// Server error specific to mariadb. Error number: 1924, symbol: ER_QUERY_CACHE_IS_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_query_cache_is_disabled = 1924;\n\n/// Server error specific to mariadb. Error number: 1925, symbol: ER_QUERY_CACHE_IS_GLOBALY_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_query_cache_is_globaly_disabled = 1925;\n\n/// Server error specific to mariadb. Error number: 1926, symbol: ER_VIEW_ORDERBY_IGNORED.\nBOOST_INLINE_CONSTEXPR int er_view_orderby_ignored = 1926;\n\n/// Server error specific to mariadb. Error number: 1927, symbol: ER_CONNECTION_KILLED.\nBOOST_INLINE_CONSTEXPR int er_connection_killed = 1927;\n\n/// Server error specific to mariadb. Error number: 1929, symbol: ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION.\nBOOST_INLINE_CONSTEXPR int er_inside_transaction_prevents_switch_skip_replication = 1929;\n\n/// Server error specific to mariadb. Error number: 1930, symbol: ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION.\nBOOST_INLINE_CONSTEXPR int er_stored_function_prevents_switch_skip_replication = 1930;\n\n/// Server error specific to mariadb. Error number: 1931, symbol: ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_query_exceeded_rows_examined_limit = 1931;\n\n/// Server error specific to mariadb. Error number: 1932, symbol: ER_NO_SUCH_TABLE_IN_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_no_such_table_in_engine = 1932;\n\n/// Server error specific to mariadb. Error number: 1933, symbol: ER_TARGET_NOT_EXPLAINABLE.\nBOOST_INLINE_CONSTEXPR int er_target_not_explainable = 1933;\n\n/// Server error specific to mariadb. Error number: 1934, symbol: ER_CONNECTION_ALREADY_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_connection_already_exists = 1934;\n\n/// Server error specific to mariadb. Error number: 1935, symbol: ER_MASTER_LOG_PREFIX.\nBOOST_INLINE_CONSTEXPR int er_master_log_prefix = 1935;\n\n/// Server error specific to mariadb. Error number: 1936, symbol: ER_CANT_START_STOP_SLAVE.\nBOOST_INLINE_CONSTEXPR int er_cant_start_stop_slave = 1936;\n\n/// Server error specific to mariadb. Error number: 1937, symbol: ER_SLAVE_STARTED.\nBOOST_INLINE_CONSTEXPR int er_slave_started = 1937;\n\n/// Server error specific to mariadb. Error number: 1938, symbol: ER_SLAVE_STOPPED.\nBOOST_INLINE_CONSTEXPR int er_slave_stopped = 1938;\n\n/// Server error specific to mariadb. Error number: 1939, symbol: ER_SQL_DISCOVER_ERROR.\nBOOST_INLINE_CONSTEXPR int er_sql_discover_error = 1939;\n\n/// Server error specific to mariadb. Error number: 1940, symbol: ER_FAILED_GTID_STATE_INIT.\nBOOST_INLINE_CONSTEXPR int er_failed_gtid_state_init = 1940;\n\n/// Server error specific to mariadb. Error number: 1941, symbol: ER_INCORRECT_GTID_STATE.\nBOOST_INLINE_CONSTEXPR int er_incorrect_gtid_state = 1941;\n\n/// Server error specific to mariadb. Error number: 1942, symbol: ER_CANNOT_UPDATE_GTID_STATE.\nBOOST_INLINE_CONSTEXPR int er_cannot_update_gtid_state = 1942;\n\n/// Server error specific to mariadb. Error number: 1943, symbol: ER_DUPLICATE_GTID_DOMAIN.\nBOOST_INLINE_CONSTEXPR int er_duplicate_gtid_domain = 1943;\n\n/// Server error specific to mariadb. Error number: 1944, symbol: ER_GTID_OPEN_TABLE_FAILED.\nBOOST_INLINE_CONSTEXPR int er_gtid_open_table_failed = 1944;\n\n/// Server error specific to mariadb. Error number: 1945, symbol: ER_GTID_POSITION_NOT_FOUND_IN_BINLOG.\nBOOST_INLINE_CONSTEXPR int er_gtid_position_not_found_in_binlog = 1945;\n\n/// Server error specific to mariadb. Error number: 1946, symbol: ER_CANNOT_LOAD_SLAVE_GTID_STATE.\nBOOST_INLINE_CONSTEXPR int er_cannot_load_slave_gtid_state = 1946;\n\n/// Server error specific to mariadb. Error number: 1947, symbol: ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG.\nBOOST_INLINE_CONSTEXPR int er_master_gtid_pos_conflicts_with_binlog = 1947;\n\n/// Server error specific to mariadb. Error number: 1948, symbol: ER_MASTER_GTID_POS_MISSING_DOMAIN.\nBOOST_INLINE_CONSTEXPR int er_master_gtid_pos_missing_domain = 1948;\n\n/// Server error specific to mariadb. Error number: 1949, symbol: ER_UNTIL_REQUIRES_USING_GTID.\nBOOST_INLINE_CONSTEXPR int er_until_requires_using_gtid = 1949;\n\n/// Server error specific to mariadb. Error number: 1950, symbol: ER_GTID_STRICT_OUT_OF_ORDER.\nBOOST_INLINE_CONSTEXPR int er_gtid_strict_out_of_order = 1950;\n\n/// Server error specific to mariadb. Error number: 1951, symbol: ER_GTID_START_FROM_BINLOG_HOLE.\nBOOST_INLINE_CONSTEXPR int er_gtid_start_from_binlog_hole = 1951;\n\n/// Server error specific to mariadb. Error number: 1952, symbol: ER_SLAVE_UNEXPECTED_MASTER_SWITCH.\nBOOST_INLINE_CONSTEXPR int er_slave_unexpected_master_switch = 1952;\n\n/// Server error specific to mariadb. Error number: 1953, symbol: ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO.\nBOOST_INLINE_CONSTEXPR int er_inside_transaction_prevents_switch_gtid_domain_id_seq_no = 1953;\n\n/// Server error specific to mariadb. Error number: 1954, symbol: ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO.\nBOOST_INLINE_CONSTEXPR int er_stored_function_prevents_switch_gtid_domain_id_seq_no = 1954;\n\n/// Server error specific to mariadb. Error number: 1955, symbol: ER_GTID_POSITION_NOT_FOUND_IN_BINLOG2.\nBOOST_INLINE_CONSTEXPR int er_gtid_position_not_found_in_binlog2 = 1955;\n\n/// Server error specific to mariadb. Error number: 1956, symbol: ER_BINLOG_MUST_BE_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_binlog_must_be_empty = 1956;\n\n/// Server error specific to mariadb. Error number: 1957, symbol: ER_NO_SUCH_QUERY.\nBOOST_INLINE_CONSTEXPR int er_no_such_query = 1957;\n\n/// Server error specific to mariadb. Error number: 1958, symbol: ER_BAD_BASE64_DATA.\nBOOST_INLINE_CONSTEXPR int er_bad_base64_data = 1958;\n\n/// Server error specific to mariadb. Error number: 1959, symbol: ER_INVALID_ROLE.\nBOOST_INLINE_CONSTEXPR int er_invalid_role = 1959;\n\n/// Server error specific to mariadb. Error number: 1960, symbol: ER_INVALID_CURRENT_USER.\nBOOST_INLINE_CONSTEXPR int er_invalid_current_user = 1960;\n\n/// Server error specific to mariadb. Error number: 1961, symbol: ER_CANNOT_GRANT_ROLE.\nBOOST_INLINE_CONSTEXPR int er_cannot_grant_role = 1961;\n\n/// Server error specific to mariadb. Error number: 1962, symbol: ER_CANNOT_REVOKE_ROLE.\nBOOST_INLINE_CONSTEXPR int er_cannot_revoke_role = 1962;\n\n/// Server error specific to mariadb. Error number: 1963, symbol: ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE.\nBOOST_INLINE_CONSTEXPR int er_change_slave_parallel_threads_active = 1963;\n\n/// Server error specific to mariadb. Error number: 1964, symbol: ER_PRIOR_COMMIT_FAILED.\nBOOST_INLINE_CONSTEXPR int er_prior_commit_failed = 1964;\n\n/// Server error specific to mariadb. Error number: 1965, symbol: ER_IT_IS_A_VIEW.\nBOOST_INLINE_CONSTEXPR int er_it_is_a_view = 1965;\n\n/// Server error specific to mariadb. Error number: 1966, symbol: ER_SLAVE_SKIP_NOT_IN_GTID.\nBOOST_INLINE_CONSTEXPR int er_slave_skip_not_in_gtid = 1966;\n\n/// Server error specific to mariadb. Error number: 1967, symbol: ER_TABLE_DEFINITION_TOO_BIG.\nBOOST_INLINE_CONSTEXPR int er_table_definition_too_big = 1967;\n\n/// Server error specific to mariadb. Error number: 1968, symbol: ER_PLUGIN_INSTALLED.\nBOOST_INLINE_CONSTEXPR int er_plugin_installed = 1968;\n\n/// Server error specific to mariadb. Error number: 1969, symbol: ER_STATEMENT_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_statement_timeout = 1969;\n\n/// Server error specific to mariadb. Error number: 1970, symbol: ER_SUBQUERIES_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_subqueries_not_supported = 1970;\n\n/// Server error specific to mariadb. Error number: 1971, symbol: ER_SET_STATEMENT_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_set_statement_not_supported = 1971;\n\n/// Server error specific to mariadb. Error number: 1973, symbol: ER_USER_CREATE_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_user_create_exists = 1973;\n\n/// Server error specific to mariadb. Error number: 1974, symbol: ER_USER_DROP_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_user_drop_exists = 1974;\n\n/// Server error specific to mariadb. Error number: 1975, symbol: ER_ROLE_CREATE_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_role_create_exists = 1975;\n\n/// Server error specific to mariadb. Error number: 1976, symbol: ER_ROLE_DROP_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_role_drop_exists = 1976;\n\n/// Server error specific to mariadb. Error number: 1977, symbol: ER_CANNOT_CONVERT_CHARACTER.\nBOOST_INLINE_CONSTEXPR int er_cannot_convert_character = 1977;\n\n/// Server error specific to mariadb. Error number: 1978, symbol: ER_INVALID_DEFAULT_VALUE_FOR_FIELD.\nBOOST_INLINE_CONSTEXPR int er_invalid_default_value_for_field = 1978;\n\n/// Server error specific to mariadb. Error number: 1979, symbol: ER_KILL_QUERY_DENIED_ERROR.\nBOOST_INLINE_CONSTEXPR int er_kill_query_denied_error = 1979;\n\n/// Server error specific to mariadb. Error number: 1980, symbol: ER_NO_EIS_FOR_FIELD.\nBOOST_INLINE_CONSTEXPR int er_no_eis_for_field = 1980;\n\n/// Server error specific to mariadb. Error number: 1981, symbol: ER_WARN_AGGFUNC_DEPENDENCE.\nBOOST_INLINE_CONSTEXPR int er_warn_aggfunc_dependence = 1981;\n\n/// Server error specific to mariadb. Error number: 1982, symbol: WARN_INNODB_PARTITION_OPTION_IGNORED.\nBOOST_INLINE_CONSTEXPR int warn_innodb_partition_option_ignored = 1982;\n\n/// Server error specific to mariadb. Error number: 3000, symbol: ER_FILE_CORRUPT.\nBOOST_INLINE_CONSTEXPR int er_file_corrupt = 3000;\n\n/// Server error specific to mariadb. Error number: 3001, symbol: ER_ERROR_ON_MASTER.\nBOOST_INLINE_CONSTEXPR int er_error_on_master = 3001;\n\n/// Server error specific to mariadb. Error number: 3002, symbol: ER_INCONSISTENT_ERROR.\nBOOST_INLINE_CONSTEXPR int er_inconsistent_error = 3002;\n\n/// Server error specific to mariadb. Error number: 3003, symbol: ER_STORAGE_ENGINE_NOT_LOADED.\nBOOST_INLINE_CONSTEXPR int er_storage_engine_not_loaded = 3003;\n\n/// Server error specific to mariadb. Error number: 3004, symbol: ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER.\nBOOST_INLINE_CONSTEXPR int er_get_stacked_da_without_active_handler = 3004;\n\n/// Server error specific to mariadb. Error number: 3005, symbol: ER_WARN_LEGACY_SYNTAX_CONVERTED.\nBOOST_INLINE_CONSTEXPR int er_warn_legacy_syntax_converted = 3005;\n\n/// Server error specific to mariadb. Error number: 3006, symbol: ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_fulltext_plugin = 3006;\n\n/// Server error specific to mariadb. Error number: 3007, symbol: ER_CANNOT_DISCARD_TEMPORARY_TABLE.\nBOOST_INLINE_CONSTEXPR int er_cannot_discard_temporary_table = 3007;\n\n/// Server error specific to mariadb. Error number: 3008, symbol: ER_FK_DEPTH_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_fk_depth_exceeded = 3008;\n\n/// Server error specific to mariadb. Error number: 3009, symbol: ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2.\nBOOST_INLINE_CONSTEXPR int er_col_count_doesnt_match_please_update_v2 = 3009;\n\n/// Server error specific to mariadb. Error number: 3010, symbol: ER_WARN_TRIGGER_DOESNT_HAVE_CREATED.\nBOOST_INLINE_CONSTEXPR int er_warn_trigger_doesnt_have_created = 3010;\n\n/// Server error specific to mariadb. Error number: 3011, symbol: ER_REFERENCED_TRG_DOES_NOT_EXIST_MYSQL.\nBOOST_INLINE_CONSTEXPR int er_referenced_trg_does_not_exist_mysql = 3011;\n\n/// Server error specific to mariadb. Error number: 3012, symbol: ER_EXPLAIN_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_explain_not_supported = 3012;\n\n/// Server error specific to mariadb. Error number: 3013, symbol: ER_INVALID_FIELD_SIZE.\nBOOST_INLINE_CONSTEXPR int er_invalid_field_size = 3013;\n\n/// Server error specific to mariadb. Error number: 3014, symbol: ER_MISSING_HA_CREATE_OPTION.\nBOOST_INLINE_CONSTEXPR int er_missing_ha_create_option = 3014;\n\n/// Server error specific to mariadb. Error number: 3015, symbol: ER_ENGINE_OUT_OF_MEMORY.\nBOOST_INLINE_CONSTEXPR int er_engine_out_of_memory = 3015;\n\n/// Server error specific to mariadb. Error number: 3016, symbol: ER_PASSWORD_EXPIRE_ANONYMOUS_USER.\nBOOST_INLINE_CONSTEXPR int er_password_expire_anonymous_user = 3016;\n\n/// Server error specific to mariadb. Error number: 3017, symbol: ER_SLAVE_SQL_THREAD_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_slave_sql_thread_must_stop = 3017;\n\n/// Server error specific to mariadb. Error number: 3018, symbol: ER_NO_FT_MATERIALIZED_SUBQUERY.\nBOOST_INLINE_CONSTEXPR int er_no_ft_materialized_subquery = 3018;\n\n/// Server error specific to mariadb. Error number: 3019, symbol: ER_INNODB_UNDO_LOG_FULL.\nBOOST_INLINE_CONSTEXPR int er_innodb_undo_log_full = 3019;\n\n/// Server error specific to mariadb. Error number: 3020, symbol: ER_INVALID_ARGUMENT_FOR_LOGARITHM.\nBOOST_INLINE_CONSTEXPR int er_invalid_argument_for_logarithm = 3020;\n\n/// Server error specific to mariadb. Error number: 3021, symbol: ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_io_thread_must_stop = 3021;\n\n/// Server error specific to mariadb. Error number: 3022, symbol: ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO.\nBOOST_INLINE_CONSTEXPR int er_warn_open_temp_tables_must_be_zero = 3022;\n\n/// Server error specific to mariadb. Error number: 3023, symbol: ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS.\nBOOST_INLINE_CONSTEXPR int er_warn_only_master_log_file_no_pos = 3023;\n\n/// Server error specific to mariadb. Error number: 3024, symbol: ER_QUERY_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_query_timeout = 3024;\n\n/// Server error specific to mariadb. Error number: 3025, symbol: ER_NON_RO_SELECT_DISABLE_TIMER.\nBOOST_INLINE_CONSTEXPR int er_non_ro_select_disable_timer = 3025;\n\n/// Server error specific to mariadb. Error number: 3026, symbol: ER_DUP_LIST_ENTRY.\nBOOST_INLINE_CONSTEXPR int er_dup_list_entry = 3026;\n\n/// Server error specific to mariadb. Error number: 3027, symbol: ER_SQL_MODE_NO_EFFECT.\nBOOST_INLINE_CONSTEXPR int er_sql_mode_no_effect = 3027;\n\n/// Server error specific to mariadb. Error number: 3028, symbol: ER_AGGREGATE_ORDER_FOR_UNION.\nBOOST_INLINE_CONSTEXPR int er_aggregate_order_for_union = 3028;\n\n/// Server error specific to mariadb. Error number: 3029, symbol: ER_AGGREGATE_ORDER_NON_AGG_QUERY.\nBOOST_INLINE_CONSTEXPR int er_aggregate_order_non_agg_query = 3029;\n\n/// Server error specific to mariadb. Error number: 3030, symbol: ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR.\nBOOST_INLINE_CONSTEXPR int er_slave_worker_stopped_previous_thd_error = 3030;\n\n/// Server error specific to mariadb. Error number: 3031, symbol: ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER.\nBOOST_INLINE_CONSTEXPR int er_dont_support_slave_preserve_commit_order = 3031;\n\n/// Server error specific to mariadb. Error number: 3032, symbol: ER_SERVER_OFFLINE_MODE.\nBOOST_INLINE_CONSTEXPR int er_server_offline_mode = 3032;\n\n/// Server error specific to mariadb. Error number: 3033, symbol: ER_GIS_DIFFERENT_SRIDS.\nBOOST_INLINE_CONSTEXPR int er_gis_different_srids = 3033;\n\n/// Server error specific to mariadb. Error number: 3034, symbol: ER_GIS_UNSUPPORTED_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_gis_unsupported_argument = 3034;\n\n/// Server error specific to mariadb. Error number: 3035, symbol: ER_GIS_UNKNOWN_ERROR.\nBOOST_INLINE_CONSTEXPR int er_gis_unknown_error = 3035;\n\n/// Server error specific to mariadb. Error number: 3036, symbol: ER_GIS_UNKNOWN_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_gis_unknown_exception = 3036;\n\n/// Server error specific to mariadb. Error number: 3037, symbol: ER_GIS_INVALID_DATA.\nBOOST_INLINE_CONSTEXPR int er_gis_invalid_data = 3037;\n\n/// Server error specific to mariadb. Error number: 3038, symbol: ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_empty_input_exception = 3038;\n\n/// Server error specific to mariadb. Error number: 3039, symbol: ER_BOOST_GEOMETRY_CENTROID_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_centroid_exception = 3039;\n\n/// Server error specific to mariadb. Error number: 3040, symbol: ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_overlay_invalid_input_exception = 3040;\n\n/// Server error specific to mariadb. Error number: 3041, symbol: ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_turn_info_exception = 3041;\n\n/// Server error specific to mariadb. Error number: 3042, symbol: ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_self_intersection_point_exception = 3042;\n\n/// Server error specific to mariadb. Error number: 3043, symbol: ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_unknown_exception = 3043;\n\n/// Server error specific to mariadb. Error number: 3044, symbol: ER_STD_BAD_ALLOC_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_bad_alloc_error = 3044;\n\n/// Server error specific to mariadb. Error number: 3045, symbol: ER_STD_DOMAIN_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_domain_error = 3045;\n\n/// Server error specific to mariadb. Error number: 3046, symbol: ER_STD_LENGTH_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_length_error = 3046;\n\n/// Server error specific to mariadb. Error number: 3047, symbol: ER_STD_INVALID_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_std_invalid_argument = 3047;\n\n/// Server error specific to mariadb. Error number: 3048, symbol: ER_STD_OUT_OF_RANGE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_out_of_range_error = 3048;\n\n/// Server error specific to mariadb. Error number: 3049, symbol: ER_STD_OVERFLOW_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_overflow_error = 3049;\n\n/// Server error specific to mariadb. Error number: 3050, symbol: ER_STD_RANGE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_range_error = 3050;\n\n/// Server error specific to mariadb. Error number: 3051, symbol: ER_STD_UNDERFLOW_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_underflow_error = 3051;\n\n/// Server error specific to mariadb. Error number: 3052, symbol: ER_STD_LOGIC_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_logic_error = 3052;\n\n/// Server error specific to mariadb. Error number: 3053, symbol: ER_STD_RUNTIME_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_runtime_error = 3053;\n\n/// Server error specific to mariadb. Error number: 3054, symbol: ER_STD_UNKNOWN_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_std_unknown_exception = 3054;\n\n/// Server error specific to mariadb. Error number: 3055, symbol: ER_GIS_DATA_WRONG_ENDIANESS.\nBOOST_INLINE_CONSTEXPR int er_gis_data_wrong_endianess = 3055;\n\n/// Server error specific to mariadb. Error number: 3056, symbol: ER_CHANGE_MASTER_PASSWORD_LENGTH.\nBOOST_INLINE_CONSTEXPR int er_change_master_password_length = 3056;\n\n/// Server error specific to mariadb. Error number: 3057, symbol: ER_USER_LOCK_WRONG_NAME.\nBOOST_INLINE_CONSTEXPR int er_user_lock_wrong_name = 3057;\n\n/// Server error specific to mariadb. Error number: 3058, symbol: ER_USER_LOCK_DEADLOCK.\nBOOST_INLINE_CONSTEXPR int er_user_lock_deadlock = 3058;\n\n/// Server error specific to mariadb. Error number: 3059, symbol: ER_REPLACE_INACCESSIBLE_ROWS.\nBOOST_INLINE_CONSTEXPR int er_replace_inaccessible_rows = 3059;\n\n/// Server error specific to mariadb. Error number: 3060, symbol: ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS.\nBOOST_INLINE_CONSTEXPR int er_alter_operation_not_supported_reason_gis = 3060;\n\n/// Server error specific to mariadb. Error number: 4002, symbol: ER_WITH_COL_WRONG_LIST.\nBOOST_INLINE_CONSTEXPR int er_with_col_wrong_list = 4002;\n\n/// Server error specific to mariadb. Error number: 4003, symbol: ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE.\nBOOST_INLINE_CONSTEXPR int er_too_many_definitions_in_with_clause = 4003;\n\n/// Server error specific to mariadb. Error number: 4004, symbol: ER_DUP_QUERY_NAME.\nBOOST_INLINE_CONSTEXPR int er_dup_query_name = 4004;\n\n/// Server error specific to mariadb. Error number: 4005, symbol: ER_RECURSIVE_WITHOUT_ANCHORS.\nBOOST_INLINE_CONSTEXPR int er_recursive_without_anchors = 4005;\n\n/// Server error specific to mariadb. Error number: 4006, symbol: ER_UNACCEPTABLE_MUTUAL_RECURSION.\nBOOST_INLINE_CONSTEXPR int er_unacceptable_mutual_recursion = 4006;\n\n/// Server error specific to mariadb. Error number: 4007, symbol: ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED.\nBOOST_INLINE_CONSTEXPR int er_ref_to_recursive_with_table_in_derived = 4007;\n\n/// Server error specific to mariadb. Error number: 4008, symbol: ER_NOT_STANDARD_COMPLIANT_RECURSIVE.\nBOOST_INLINE_CONSTEXPR int er_not_standard_compliant_recursive = 4008;\n\n/// Server error specific to mariadb. Error number: 4009, symbol: ER_WRONG_WINDOW_SPEC_NAME.\nBOOST_INLINE_CONSTEXPR int er_wrong_window_spec_name = 4009;\n\n/// Server error specific to mariadb. Error number: 4010, symbol: ER_DUP_WINDOW_NAME.\nBOOST_INLINE_CONSTEXPR int er_dup_window_name = 4010;\n\n/// Server error specific to mariadb. Error number: 4011, symbol: ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC.\nBOOST_INLINE_CONSTEXPR int er_partition_list_in_referencing_window_spec = 4011;\n\n/// Server error specific to mariadb. Error number: 4012, symbol: ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC.\nBOOST_INLINE_CONSTEXPR int er_order_list_in_referencing_window_spec = 4012;\n\n/// Server error specific to mariadb. Error number: 4013, symbol: ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC.\nBOOST_INLINE_CONSTEXPR int er_window_frame_in_referenced_window_spec = 4013;\n\n/// Server error specific to mariadb. Error number: 4014, symbol: ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS.\nBOOST_INLINE_CONSTEXPR int er_bad_combination_of_window_frame_bound_specs = 4014;\n\n/// Server error specific to mariadb. Error number: 4015, symbol: ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION.\nBOOST_INLINE_CONSTEXPR int er_wrong_placement_of_window_function = 4015;\n\n/// Server error specific to mariadb. Error number: 4016, symbol: ER_WINDOW_FUNCTION_IN_WINDOW_SPEC.\nBOOST_INLINE_CONSTEXPR int er_window_function_in_window_spec = 4016;\n\n/// Server error specific to mariadb. Error number: 4017, symbol: ER_NOT_ALLOWED_WINDOW_FRAME.\nBOOST_INLINE_CONSTEXPR int er_not_allowed_window_frame = 4017;\n\n/// Server error specific to mariadb. Error number: 4018, symbol: ER_NO_ORDER_LIST_IN_WINDOW_SPEC.\nBOOST_INLINE_CONSTEXPR int er_no_order_list_in_window_spec = 4018;\n\n/// Server error specific to mariadb. Error number: 4019, symbol: ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY.\nBOOST_INLINE_CONSTEXPR int er_range_frame_needs_simple_orderby = 4019;\n\n/// Server error specific to mariadb. Error number: 4020, symbol: ER_WRONG_TYPE_FOR_ROWS_FRAME.\nBOOST_INLINE_CONSTEXPR int er_wrong_type_for_rows_frame = 4020;\n\n/// Server error specific to mariadb. Error number: 4021, symbol: ER_WRONG_TYPE_FOR_RANGE_FRAME.\nBOOST_INLINE_CONSTEXPR int er_wrong_type_for_range_frame = 4021;\n\n/// Server error specific to mariadb. Error number: 4022, symbol: ER_FRAME_EXCLUSION_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_frame_exclusion_not_supported = 4022;\n\n/// Server error specific to mariadb. Error number: 4023, symbol: ER_WINDOW_FUNCTION_DONT_HAVE_FRAME.\nBOOST_INLINE_CONSTEXPR int er_window_function_dont_have_frame = 4023;\n\n/// Server error specific to mariadb. Error number: 4024, symbol: ER_INVALID_NTILE_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_invalid_ntile_argument = 4024;\n\n/// Server error specific to mariadb. Error number: 4025, symbol: ER_CONSTRAINT_FAILED.\nBOOST_INLINE_CONSTEXPR int er_constraint_failed = 4025;\n\n/// Server error specific to mariadb. Error number: 4026, symbol: ER_EXPRESSION_IS_TOO_BIG.\nBOOST_INLINE_CONSTEXPR int er_expression_is_too_big = 4026;\n\n/// Server error specific to mariadb. Error number: 4027, symbol: ER_ERROR_EVALUATING_EXPRESSION.\nBOOST_INLINE_CONSTEXPR int er_error_evaluating_expression = 4027;\n\n/// Server error specific to mariadb. Error number: 4028, symbol: ER_CALCULATING_DEFAULT_VALUE.\nBOOST_INLINE_CONSTEXPR int er_calculating_default_value = 4028;\n\n/// Server error specific to mariadb. Error number: 4029, symbol: ER_EXPRESSION_REFERS_TO_UNINIT_FIELD.\nBOOST_INLINE_CONSTEXPR int er_expression_refers_to_uninit_field = 4029;\n\n/// Server error specific to mariadb. Error number: 4030, symbol: ER_PARTITION_DEFAULT_ERROR.\nBOOST_INLINE_CONSTEXPR int er_partition_default_error = 4030;\n\n/// Server error specific to mariadb. Error number: 4031, symbol: ER_REFERENCED_TRG_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_referenced_trg_does_not_exist = 4031;\n\n/// Server error specific to mariadb. Error number: 4032, symbol: ER_INVALID_DEFAULT_PARAM.\nBOOST_INLINE_CONSTEXPR int er_invalid_default_param = 4032;\n\n/// Server error specific to mariadb. Error number: 4033, symbol: ER_BINLOG_NON_SUPPORTED_BULK.\nBOOST_INLINE_CONSTEXPR int er_binlog_non_supported_bulk = 4033;\n\n/// Server error specific to mariadb. Error number: 4034, symbol: ER_BINLOG_UNCOMPRESS_ERROR.\nBOOST_INLINE_CONSTEXPR int er_binlog_uncompress_error = 4034;\n\n/// Server error specific to mariadb. Error number: 4035, symbol: ER_JSON_BAD_CHR.\nBOOST_INLINE_CONSTEXPR int er_json_bad_chr = 4035;\n\n/// Server error specific to mariadb. Error number: 4036, symbol: ER_JSON_NOT_JSON_CHR.\nBOOST_INLINE_CONSTEXPR int er_json_not_json_chr = 4036;\n\n/// Server error specific to mariadb. Error number: 4037, symbol: ER_JSON_EOS.\nBOOST_INLINE_CONSTEXPR int er_json_eos = 4037;\n\n/// Server error specific to mariadb. Error number: 4038, symbol: ER_JSON_SYNTAX.\nBOOST_INLINE_CONSTEXPR int er_json_syntax = 4038;\n\n/// Server error specific to mariadb. Error number: 4039, symbol: ER_JSON_ESCAPING.\nBOOST_INLINE_CONSTEXPR int er_json_escaping = 4039;\n\n/// Server error specific to mariadb. Error number: 4040, symbol: ER_JSON_DEPTH.\nBOOST_INLINE_CONSTEXPR int er_json_depth = 4040;\n\n/// Server error specific to mariadb. Error number: 4041, symbol: ER_JSON_PATH_EOS.\nBOOST_INLINE_CONSTEXPR int er_json_path_eos = 4041;\n\n/// Server error specific to mariadb. Error number: 4042, symbol: ER_JSON_PATH_SYNTAX.\nBOOST_INLINE_CONSTEXPR int er_json_path_syntax = 4042;\n\n/// Server error specific to mariadb. Error number: 4043, symbol: ER_JSON_PATH_DEPTH.\nBOOST_INLINE_CONSTEXPR int er_json_path_depth = 4043;\n\n/// Server error specific to mariadb. Error number: 4044, symbol: ER_JSON_PATH_NO_WILDCARD.\nBOOST_INLINE_CONSTEXPR int er_json_path_no_wildcard = 4044;\n\n/// Server error specific to mariadb. Error number: 4045, symbol: ER_JSON_PATH_ARRAY.\nBOOST_INLINE_CONSTEXPR int er_json_path_array = 4045;\n\n/// Server error specific to mariadb. Error number: 4046, symbol: ER_JSON_ONE_OR_ALL.\nBOOST_INLINE_CONSTEXPR int er_json_one_or_all = 4046;\n\n/// Server error specific to mariadb. Error number: 4047, symbol: ER_UNSUPPORTED_COMPRESSED_TABLE.\nBOOST_INLINE_CONSTEXPR int er_unsupported_compressed_table = 4047;\n\n/// Server error specific to mariadb. Error number: 4048, symbol: ER_GEOJSON_INCORRECT.\nBOOST_INLINE_CONSTEXPR int er_geojson_incorrect = 4048;\n\n/// Server error specific to mariadb. Error number: 4049, symbol: ER_GEOJSON_TOO_FEW_POINTS.\nBOOST_INLINE_CONSTEXPR int er_geojson_too_few_points = 4049;\n\n/// Server error specific to mariadb. Error number: 4050, symbol: ER_GEOJSON_NOT_CLOSED.\nBOOST_INLINE_CONSTEXPR int er_geojson_not_closed = 4050;\n\n/// Server error specific to mariadb. Error number: 4051, symbol: ER_JSON_PATH_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_json_path_empty = 4051;\n\n/// Server error specific to mariadb. Error number: 4052, symbol: ER_SLAVE_SAME_ID.\nBOOST_INLINE_CONSTEXPR int er_slave_same_id = 4052;\n\n/// Server error specific to mariadb. Error number: 4053, symbol: ER_FLASHBACK_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_flashback_not_supported = 4053;\n\n/// Server error specific to mariadb. Error number: 4054, symbol: ER_KEYS_OUT_OF_ORDER.\nBOOST_INLINE_CONSTEXPR int er_keys_out_of_order = 4054;\n\n/// Server error specific to mariadb. Error number: 4055, symbol: ER_OVERLAPPING_KEYS.\nBOOST_INLINE_CONSTEXPR int er_overlapping_keys = 4055;\n\n/// Server error specific to mariadb. Error number: 4056, symbol: ER_REQUIRE_ROW_BINLOG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_require_row_binlog_format = 4056;\n\n/// Server error specific to mariadb. Error number: 4057, symbol: ER_ISOLATION_MODE_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_isolation_mode_not_supported = 4057;\n\n/// Server error specific to mariadb. Error number: 4058, symbol: ER_ON_DUPLICATE_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_on_duplicate_disabled = 4058;\n\n/// Server error specific to mariadb. Error number: 4059, symbol: ER_UPDATES_WITH_CONSISTENT_SNAPSHOT.\nBOOST_INLINE_CONSTEXPR int er_updates_with_consistent_snapshot = 4059;\n\n/// Server error specific to mariadb. Error number: 4060, symbol: ER_ROLLBACK_ONLY.\nBOOST_INLINE_CONSTEXPR int er_rollback_only = 4060;\n\n/// Server error specific to mariadb. Error number: 4061, symbol: ER_ROLLBACK_TO_SAVEPOINT.\nBOOST_INLINE_CONSTEXPR int er_rollback_to_savepoint = 4061;\n\n/// Server error specific to mariadb. Error number: 4062, symbol: ER_ISOLATION_LEVEL_WITH_CONSISTENT_SNAPSHOT.\nBOOST_INLINE_CONSTEXPR int er_isolation_level_with_consistent_snapshot = 4062;\n\n/// Server error specific to mariadb. Error number: 4063, symbol: ER_UNSUPPORTED_COLLATION.\nBOOST_INLINE_CONSTEXPR int er_unsupported_collation = 4063;\n\n/// Server error specific to mariadb. Error number: 4064, symbol: ER_METADATA_INCONSISTENCY.\nBOOST_INLINE_CONSTEXPR int er_metadata_inconsistency = 4064;\n\n/// Server error specific to mariadb. Error number: 4065, symbol: ER_CF_DIFFERENT.\nBOOST_INLINE_CONSTEXPR int er_cf_different = 4065;\n\n/// Server error specific to mariadb. Error number: 4066, symbol: ER_RDB_TTL_DURATION_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_rdb_ttl_duration_format = 4066;\n\n/// Server error specific to mariadb. Error number: 4067, symbol: ER_RDB_STATUS_GENERAL.\nBOOST_INLINE_CONSTEXPR int er_rdb_status_general = 4067;\n\n/// Server error specific to mariadb. Error number: 4068, symbol: ER_RDB_STATUS_MSG.\nBOOST_INLINE_CONSTEXPR int er_rdb_status_msg = 4068;\n\n/// Server error specific to mariadb. Error number: 4069, symbol: ER_RDB_TTL_UNSUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_rdb_ttl_unsupported = 4069;\n\n/// Server error specific to mariadb. Error number: 4070, symbol: ER_RDB_TTL_COL_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_rdb_ttl_col_format = 4070;\n\n/// Server error specific to mariadb. Error number: 4071, symbol: ER_PER_INDEX_CF_DEPRECATED.\nBOOST_INLINE_CONSTEXPR int er_per_index_cf_deprecated = 4071;\n\n/// Server error specific to mariadb. Error number: 4072, symbol: ER_KEY_CREATE_DURING_ALTER.\nBOOST_INLINE_CONSTEXPR int er_key_create_during_alter = 4072;\n\n/// Server error specific to mariadb. Error number: 4073, symbol: ER_SK_POPULATE_DURING_ALTER.\nBOOST_INLINE_CONSTEXPR int er_sk_populate_during_alter = 4073;\n\n/// Server error specific to mariadb. Error number: 4074, symbol: ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG.\nBOOST_INLINE_CONSTEXPR int er_sum_func_with_window_func_as_arg = 4074;\n\n/// Server error specific to mariadb. Error number: 4075, symbol: ER_NET_OK_PACKET_TOO_LARGE.\nBOOST_INLINE_CONSTEXPR int er_net_ok_packet_too_large = 4075;\n\n/// Server error specific to mariadb. Error number: 4076, symbol: ER_GEOJSON_EMPTY_COORDINATES.\nBOOST_INLINE_CONSTEXPR int er_geojson_empty_coordinates = 4076;\n\n/// Server error specific to mariadb. Error number: 4077, symbol: ER_MYROCKS_CANT_NOPAD_COLLATION.\nBOOST_INLINE_CONSTEXPR int er_myrocks_cant_nopad_collation = 4077;\n\n/// Server error specific to mariadb. Error number: 4078, symbol: ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION.\nBOOST_INLINE_CONSTEXPR int er_illegal_parameter_data_types2_for_operation = 4078;\n\n/// Server error specific to mariadb. Error number: 4079, symbol: ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION.\nBOOST_INLINE_CONSTEXPR int er_illegal_parameter_data_type_for_operation = 4079;\n\n/// Server error specific to mariadb. Error number: 4080, symbol: ER_WRONG_PARAMCOUNT_TO_CURSOR.\nBOOST_INLINE_CONSTEXPR int er_wrong_paramcount_to_cursor = 4080;\n\n/// Server error specific to mariadb. Error number: 4081, symbol: ER_UNKNOWN_STRUCTURED_VARIABLE.\nBOOST_INLINE_CONSTEXPR int er_unknown_structured_variable = 4081;\n\n/// Server error specific to mariadb. Error number: 4082, symbol: ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD.\nBOOST_INLINE_CONSTEXPR int er_row_variable_does_not_have_field = 4082;\n\n/// Server error specific to mariadb. Error number: 4083, symbol: ER_END_IDENTIFIER_DOES_NOT_MATCH.\nBOOST_INLINE_CONSTEXPR int er_end_identifier_does_not_match = 4083;\n\n/// Server error specific to mariadb. Error number: 4084, symbol: ER_SEQUENCE_RUN_OUT.\nBOOST_INLINE_CONSTEXPR int er_sequence_run_out = 4084;\n\n/// Server error specific to mariadb. Error number: 4085, symbol: ER_SEQUENCE_INVALID_DATA.\nBOOST_INLINE_CONSTEXPR int er_sequence_invalid_data = 4085;\n\n/// Server error specific to mariadb. Error number: 4086, symbol: ER_SEQUENCE_INVALID_TABLE_STRUCTURE.\nBOOST_INLINE_CONSTEXPR int er_sequence_invalid_table_structure = 4086;\n\n/// Server error specific to mariadb. Error number: 4087, symbol: ER_SEQUENCE_ACCESS_ERROR.\nBOOST_INLINE_CONSTEXPR int er_sequence_access_error = 4087;\n\n/// Server error specific to mariadb. Error number: 4088, symbol: ER_SEQUENCE_BINLOG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_sequence_binlog_format = 4088;\n\n/// Server error specific to mariadb. Error number: 4089, symbol: ER_NOT_SEQUENCE.\nBOOST_INLINE_CONSTEXPR int er_not_sequence = 4089;\n\n/// Server error specific to mariadb. Error number: 4090, symbol: ER_NOT_SEQUENCE2.\nBOOST_INLINE_CONSTEXPR int er_not_sequence2 = 4090;\n\n/// Server error specific to mariadb. Error number: 4091, symbol: ER_UNKNOWN_SEQUENCES.\nBOOST_INLINE_CONSTEXPR int er_unknown_sequences = 4091;\n\n/// Server error specific to mariadb. Error number: 4092, symbol: ER_UNKNOWN_VIEW.\nBOOST_INLINE_CONSTEXPR int er_unknown_view = 4092;\n\n/// Server error specific to mariadb. Error number: 4093, symbol: ER_WRONG_INSERT_INTO_SEQUENCE.\nBOOST_INLINE_CONSTEXPR int er_wrong_insert_into_sequence = 4093;\n\n/// Server error specific to mariadb. Error number: 4094, symbol: ER_SP_STACK_TRACE.\nBOOST_INLINE_CONSTEXPR int er_sp_stack_trace = 4094;\n\n/// Server error specific to mariadb. Error number: 4095, symbol: ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY.\nBOOST_INLINE_CONSTEXPR int er_package_routine_in_spec_not_defined_in_body = 4095;\n\n/// Server error specific to mariadb. Error number: 4096, symbol: ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED.\nBOOST_INLINE_CONSTEXPR int er_package_routine_forward_declaration_not_defined = 4096;\n\n/// Server error specific to mariadb. Error number: 4097, symbol: ER_COMPRESSED_COLUMN_USED_AS_KEY.\nBOOST_INLINE_CONSTEXPR int er_compressed_column_used_as_key = 4097;\n\n/// Server error specific to mariadb. Error number: 4098, symbol: ER_UNKNOWN_COMPRESSION_METHOD.\nBOOST_INLINE_CONSTEXPR int er_unknown_compression_method = 4098;\n\n/// Server error specific to mariadb. Error number: 4099, symbol: ER_WRONG_NUMBER_OF_VALUES_IN_TVC.\nBOOST_INLINE_CONSTEXPR int er_wrong_number_of_values_in_tvc = 4099;\n\n/// Server error specific to mariadb. Error number: 4100, symbol: ER_FIELD_REFERENCE_IN_TVC.\nBOOST_INLINE_CONSTEXPR int er_field_reference_in_tvc = 4100;\n\n/// Server error specific to mariadb. Error number: 4101, symbol: ER_WRONG_TYPE_FOR_PERCENTILE_FUNC.\nBOOST_INLINE_CONSTEXPR int er_wrong_type_for_percentile_func = 4101;\n\n/// Server error specific to mariadb. Error number: 4102, symbol: ER_ARGUMENT_NOT_CONSTANT.\nBOOST_INLINE_CONSTEXPR int er_argument_not_constant = 4102;\n\n/// Server error specific to mariadb. Error number: 4103, symbol: ER_ARGUMENT_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_argument_out_of_range = 4103;\n\n/// Server error specific to mariadb. Error number: 4104, symbol: ER_WRONG_TYPE_OF_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_wrong_type_of_argument = 4104;\n\n/// Server error specific to mariadb. Error number: 4105, symbol: ER_NOT_AGGREGATE_FUNCTION.\nBOOST_INLINE_CONSTEXPR int er_not_aggregate_function = 4105;\n\n/// Server error specific to mariadb. Error number: 4106, symbol: ER_INVALID_AGGREGATE_FUNCTION.\nBOOST_INLINE_CONSTEXPR int er_invalid_aggregate_function = 4106;\n\n/// Server error specific to mariadb. Error number: 4107, symbol: ER_INVALID_VALUE_TO_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_invalid_value_to_limit = 4107;\n\n/// Server error specific to mariadb. Error number: 4108, symbol: ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT.\nBOOST_INLINE_CONSTEXPR int er_invisible_not_null_without_default = 4108;\n\n/// Server error specific to mariadb. Error number: 4109, symbol: ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING.\nBOOST_INLINE_CONSTEXPR int er_update_info_with_system_versioning = 4109;\n\n/// Server error specific to mariadb. Error number: 4110, symbol: ER_VERS_FIELD_WRONG_TYPE.\nBOOST_INLINE_CONSTEXPR int er_vers_field_wrong_type = 4110;\n\n/// Server error specific to mariadb. Error number: 4111, symbol: ER_VERS_ENGINE_UNSUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_vers_engine_unsupported = 4111;\n\n/// Server error specific to mariadb. Error number: 4113, symbol: ER_PARTITION_WRONG_TYPE.\nBOOST_INLINE_CONSTEXPR int er_partition_wrong_type = 4113;\n\n/// Server error specific to mariadb. Error number: 4114, symbol: WARN_VERS_PART_FULL.\nBOOST_INLINE_CONSTEXPR int warn_vers_part_full = 4114;\n\n/// Server error specific to mariadb. Error number: 4115, symbol: WARN_VERS_PARAMETERS.\nBOOST_INLINE_CONSTEXPR int warn_vers_parameters = 4115;\n\n/// Server error specific to mariadb. Error number: 4116, symbol: ER_VERS_DROP_PARTITION_INTERVAL.\nBOOST_INLINE_CONSTEXPR int er_vers_drop_partition_interval = 4116;\n\n/// Server error specific to mariadb. Error number: 4118, symbol: WARN_VERS_PART_NON_HISTORICAL.\nBOOST_INLINE_CONSTEXPR int warn_vers_part_non_historical = 4118;\n\n/// Server error specific to mariadb. Error number: 4119, symbol: ER_VERS_ALTER_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_vers_alter_not_allowed = 4119;\n\n/// Server error specific to mariadb. Error number: 4120, symbol: ER_VERS_ALTER_ENGINE_PROHIBITED.\nBOOST_INLINE_CONSTEXPR int er_vers_alter_engine_prohibited = 4120;\n\n/// Server error specific to mariadb. Error number: 4121, symbol: ER_VERS_RANGE_PROHIBITED.\nBOOST_INLINE_CONSTEXPR int er_vers_range_prohibited = 4121;\n\n/// Server error specific to mariadb. Error number: 4122, symbol: ER_CONFLICTING_FOR_SYSTEM_TIME.\nBOOST_INLINE_CONSTEXPR int er_conflicting_for_system_time = 4122;\n\n/// Server error specific to mariadb. Error number: 4123, symbol: ER_VERS_TABLE_MUST_HAVE_COLUMNS.\nBOOST_INLINE_CONSTEXPR int er_vers_table_must_have_columns = 4123;\n\n/// Server error specific to mariadb. Error number: 4124, symbol: ER_VERS_NOT_VERSIONED.\nBOOST_INLINE_CONSTEXPR int er_vers_not_versioned = 4124;\n\n/// Server error specific to mariadb. Error number: 4125, symbol: ER_MISSING.\nBOOST_INLINE_CONSTEXPR int er_missing = 4125;\n\n/// Server error specific to mariadb. Error number: 4126, symbol: ER_VERS_PERIOD_COLUMNS.\nBOOST_INLINE_CONSTEXPR int er_vers_period_columns = 4126;\n\n/// Server error specific to mariadb. Error number: 4127, symbol: ER_PART_WRONG_VALUE.\nBOOST_INLINE_CONSTEXPR int er_part_wrong_value = 4127;\n\n/// Server error specific to mariadb. Error number: 4128, symbol: ER_VERS_WRONG_PARTS.\nBOOST_INLINE_CONSTEXPR int er_vers_wrong_parts = 4128;\n\n/// Server error specific to mariadb. Error number: 4129, symbol: ER_VERS_NO_TRX_ID.\nBOOST_INLINE_CONSTEXPR int er_vers_no_trx_id = 4129;\n\n/// Server error specific to mariadb. Error number: 4130, symbol: ER_VERS_ALTER_SYSTEM_FIELD.\nBOOST_INLINE_CONSTEXPR int er_vers_alter_system_field = 4130;\n\n/// Server error specific to mariadb. Error number: 4131, symbol: ER_DROP_VERSIONING_SYSTEM_TIME_PARTITION.\nBOOST_INLINE_CONSTEXPR int er_drop_versioning_system_time_partition = 4131;\n\n/// Server error specific to mariadb. Error number: 4132, symbol: ER_VERS_DB_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_vers_db_not_supported = 4132;\n\n/// Server error specific to mariadb. Error number: 4133, symbol: ER_VERS_TRT_IS_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_vers_trt_is_disabled = 4133;\n\n/// Server error specific to mariadb. Error number: 4134, symbol: ER_VERS_DUPLICATE_ROW_START_END.\nBOOST_INLINE_CONSTEXPR int er_vers_duplicate_row_start_end = 4134;\n\n/// Server error specific to mariadb. Error number: 4135, symbol: ER_VERS_ALREADY_VERSIONED.\nBOOST_INLINE_CONSTEXPR int er_vers_already_versioned = 4135;\n\n/// Server error specific to mariadb. Error number: 4137, symbol: ER_VERS_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_vers_not_supported = 4137;\n\n/// Server error specific to mariadb. Error number: 4138, symbol: ER_VERS_TRX_PART_HISTORIC_ROW_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_vers_trx_part_historic_row_not_supported = 4138;\n\n/// Server error specific to mariadb. Error number: 4139, symbol: ER_INDEX_FILE_FULL.\nBOOST_INLINE_CONSTEXPR int er_index_file_full = 4139;\n\n/// Server error specific to mariadb. Error number: 4140, symbol: ER_UPDATED_COLUMN_ONLY_ONCE.\nBOOST_INLINE_CONSTEXPR int er_updated_column_only_once = 4140;\n\n/// Server error specific to mariadb. Error number: 4141, symbol: ER_EMPTY_ROW_IN_TVC.\nBOOST_INLINE_CONSTEXPR int er_empty_row_in_tvc = 4141;\n\n/// Server error specific to mariadb. Error number: 4142, symbol: ER_VERS_QUERY_IN_PARTITION.\nBOOST_INLINE_CONSTEXPR int er_vers_query_in_partition = 4142;\n\n/// Server error specific to mariadb. Error number: 4143, symbol: ER_KEY_DOESNT_SUPPORT.\nBOOST_INLINE_CONSTEXPR int er_key_doesnt_support = 4143;\n\n/// Server error specific to mariadb. Error number: 4144, symbol: ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD.\nBOOST_INLINE_CONSTEXPR int er_alter_operation_table_options_need_rebuild = 4144;\n\n/// Server error specific to mariadb. Error number: 4145, symbol: ER_BACKUP_LOCK_IS_ACTIVE.\nBOOST_INLINE_CONSTEXPR int er_backup_lock_is_active = 4145;\n\n/// Server error specific to mariadb. Error number: 4146, symbol: ER_BACKUP_NOT_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_backup_not_running = 4146;\n\n/// Server error specific to mariadb. Error number: 4147, symbol: ER_BACKUP_WRONG_STAGE.\nBOOST_INLINE_CONSTEXPR int er_backup_wrong_stage = 4147;\n\n/// Server error specific to mariadb. Error number: 4148, symbol: ER_BACKUP_STAGE_FAILED.\nBOOST_INLINE_CONSTEXPR int er_backup_stage_failed = 4148;\n\n/// Server error specific to mariadb. Error number: 4149, symbol: ER_BACKUP_UNKNOWN_STAGE.\nBOOST_INLINE_CONSTEXPR int er_backup_unknown_stage = 4149;\n\n/// Server error specific to mariadb. Error number: 4150, symbol: ER_USER_IS_BLOCKED.\nBOOST_INLINE_CONSTEXPR int er_user_is_blocked = 4150;\n\n/// Server error specific to mariadb. Error number: 4151, symbol: ER_ACCOUNT_HAS_BEEN_LOCKED.\nBOOST_INLINE_CONSTEXPR int er_account_has_been_locked = 4151;\n\n/// Server error specific to mariadb. Error number: 4152, symbol: ER_PERIOD_TEMPORARY_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_period_temporary_not_allowed = 4152;\n\n/// Server error specific to mariadb. Error number: 4153, symbol: ER_PERIOD_TYPES_MISMATCH.\nBOOST_INLINE_CONSTEXPR int er_period_types_mismatch = 4153;\n\n/// Server error specific to mariadb. Error number: 4154, symbol: ER_MORE_THAN_ONE_PERIOD.\nBOOST_INLINE_CONSTEXPR int er_more_than_one_period = 4154;\n\n/// Server error specific to mariadb. Error number: 4155, symbol: ER_PERIOD_FIELD_WRONG_ATTRIBUTES.\nBOOST_INLINE_CONSTEXPR int er_period_field_wrong_attributes = 4155;\n\n/// Server error specific to mariadb. Error number: 4156, symbol: ER_PERIOD_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_period_not_found = 4156;\n\n/// Server error specific to mariadb. Error number: 4157, symbol: ER_PERIOD_COLUMNS_UPDATED.\nBOOST_INLINE_CONSTEXPR int er_period_columns_updated = 4157;\n\n/// Server error specific to mariadb. Error number: 4158, symbol: ER_PERIOD_CONSTRAINT_DROP.\nBOOST_INLINE_CONSTEXPR int er_period_constraint_drop = 4158;\n\n/// Server error specific to mariadb. Error number: 4159, symbol: ER_TOO_LONG_KEYPART.\nBOOST_INLINE_CONSTEXPR int er_too_long_keypart = 4159;\n\n/// Server error specific to mariadb. Error number: 4160, symbol: ER_TOO_LONG_DATABASE_COMMENT.\nBOOST_INLINE_CONSTEXPR int er_too_long_database_comment = 4160;\n\n/// Server error specific to mariadb. Error number: 4161, symbol: ER_UNKNOWN_DATA_TYPE.\nBOOST_INLINE_CONSTEXPR int er_unknown_data_type = 4161;\n\n/// Server error specific to mariadb. Error number: 4162, symbol: ER_UNKNOWN_OPERATOR.\nBOOST_INLINE_CONSTEXPR int er_unknown_operator = 4162;\n\n/// Server error specific to mariadb. Error number: 4163, symbol: ER_WARN_HISTORY_ROW_START_TIME.\nBOOST_INLINE_CONSTEXPR int er_warn_history_row_start_time = 4163;\n\n/// Server error specific to mariadb. Error number: 4164, symbol: ER_PART_STARTS_BEYOND_INTERVAL.\nBOOST_INLINE_CONSTEXPR int er_part_starts_beyond_interval = 4164;\n\n/// Server error specific to mariadb. Error number: 4165, symbol: ER_GALERA_REPLICATION_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_galera_replication_not_supported = 4165;\n\n/// Server error specific to mariadb. Error number: 4166, symbol: ER_LOAD_INFILE_CAPABILITY_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_load_infile_capability_disabled = 4166;\n\n/// Server error specific to mariadb. Error number: 4167, symbol: ER_NO_SECURE_TRANSPORTS_CONFIGURED.\nBOOST_INLINE_CONSTEXPR int er_no_secure_transports_configured = 4167;\n\n/// Server error specific to mariadb. Error number: 4168, symbol: ER_SLAVE_IGNORED_SHARED_TABLE.\nBOOST_INLINE_CONSTEXPR int er_slave_ignored_shared_table = 4168;\n\n/// Server error specific to mariadb. Error number: 4169, symbol: ER_NO_AUTOINCREMENT_WITH_UNIQUE.\nBOOST_INLINE_CONSTEXPR int er_no_autoincrement_with_unique = 4169;\n\n/// Server error specific to mariadb. Error number: 4170, symbol: ER_KEY_CONTAINS_PERIOD_FIELDS.\nBOOST_INLINE_CONSTEXPR int er_key_contains_period_fields = 4170;\n\n/// Server error specific to mariadb. Error number: 4171, symbol: ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS.\nBOOST_INLINE_CONSTEXPR int er_key_cant_have_without_overlaps = 4171;\n\n/// Server error specific to mariadb. Error number: 4172, symbol: ER_NOT_ALLOWED_IN_THIS_CONTEXT.\nBOOST_INLINE_CONSTEXPR int er_not_allowed_in_this_context = 4172;\n\n/// Server error specific to mariadb. Error number: 4173, symbol: ER_DATA_WAS_COMMITED_UNDER_ROLLBACK.\nBOOST_INLINE_CONSTEXPR int er_data_was_commited_under_rollback = 4173;\n\n/// Server error specific to mariadb. Error number: 4174, symbol: ER_PK_INDEX_CANT_BE_IGNORED.\nBOOST_INLINE_CONSTEXPR int er_pk_index_cant_be_ignored = 4174;\n\n/// Server error specific to mariadb. Error number: 4175, symbol: ER_BINLOG_UNSAFE_SKIP_LOCKED.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_skip_locked = 4175;\n\n/// Server error specific to mariadb. Error number: 4176, symbol: ER_JSON_TABLE_ERROR_ON_FIELD.\nBOOST_INLINE_CONSTEXPR int er_json_table_error_on_field = 4176;\n\n/// Server error specific to mariadb. Error number: 4177, symbol: ER_JSON_TABLE_ALIAS_REQUIRED.\nBOOST_INLINE_CONSTEXPR int er_json_table_alias_required = 4177;\n\n/// Server error specific to mariadb. Error number: 4178, symbol: ER_JSON_TABLE_SCALAR_EXPECTED.\nBOOST_INLINE_CONSTEXPR int er_json_table_scalar_expected = 4178;\n\n/// Server error specific to mariadb. Error number: 4179, symbol: ER_JSON_TABLE_MULTIPLE_MATCHES.\nBOOST_INLINE_CONSTEXPR int er_json_table_multiple_matches = 4179;\n\n/// Server error specific to mariadb. Error number: 4180, symbol: ER_WITH_TIES_NEEDS_ORDER.\nBOOST_INLINE_CONSTEXPR int er_with_ties_needs_order = 4180;\n\n/// Server error specific to mariadb. Error number: 4181, symbol: ER_REMOVED_ORPHAN_TRIGGER.\nBOOST_INLINE_CONSTEXPR int er_removed_orphan_trigger = 4181;\n\n/// Server error specific to mariadb. Error number: 4182, symbol: ER_STORAGE_ENGINE_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_storage_engine_disabled = 4182;\n\n/// Server error specific to mariadb. Error number: 4183, symbol: WARN_SFORMAT_ERROR.\nBOOST_INLINE_CONSTEXPR int warn_sformat_error = 4183;\n\n/// Server error specific to mariadb. Error number: 4184, symbol: ER_PARTITION_CONVERT_SUBPARTITIONED.\nBOOST_INLINE_CONSTEXPR int er_partition_convert_subpartitioned = 4184;\n\n/// Server error specific to mariadb. Error number: 4185, symbol: ER_PROVIDER_NOT_LOADED.\nBOOST_INLINE_CONSTEXPR int er_provider_not_loaded = 4185;\n\n/// Server error specific to mariadb. Error number: 4186, symbol: ER_JSON_HISTOGRAM_PARSE_FAILED.\nBOOST_INLINE_CONSTEXPR int er_json_histogram_parse_failed = 4186;\n\n/// Server error specific to mariadb. Error number: 4187, symbol: ER_SF_OUT_INOUT_ARG_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_sf_out_inout_arg_not_allowed = 4187;\n\n/// Server error specific to mariadb. Error number: 4188, symbol: ER_INCONSISTENT_SLAVE_TEMP_TABLE.\nBOOST_INLINE_CONSTEXPR int er_inconsistent_slave_temp_table = 4188;\n\n/// Server error specific to mariadb. Error number: 4189, symbol: ER_VERS_HIST_PART_FAILED.\nBOOST_INLINE_CONSTEXPR int er_vers_hist_part_failed = 4189;\n\n/// Server error specific to mariadb. Error number: 4190, symbol: WARN_OPTION_CHANGING.\nBOOST_INLINE_CONSTEXPR int warn_option_changing = 4190;\n\n/// Server error specific to mariadb. Error number: 4191, symbol: ER_CM_OPTION_MISSING_REQUIREMENT.\nBOOST_INLINE_CONSTEXPR int er_cm_option_missing_requirement = 4191;\n\n/// Server error specific to mariadb. Error number: 4192, symbol: ER_SLAVE_STATEMENT_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_slave_statement_timeout = 4192;\n\n/// Server error specific to mariadb. Error number: 4193, symbol: ER_JSON_INVALID_VALUE_FOR_KEYWORD.\nBOOST_INLINE_CONSTEXPR int er_json_invalid_value_for_keyword = 4193;\n\n/// Server error specific to mariadb. Error number: 4194, symbol: ER_JSON_SCHEMA_KEYWORD_UNSUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_json_schema_keyword_unsupported = 4194;\n\n}  // namespace mariadb_server_errc\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/metadata.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_METADATA_HPP\n#define BOOST_MYSQL_METADATA_HPP\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/flags.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Metadata about a column in a SQL query.\n * \\details This is a regular, value type. Instances of this class are not created by the user\n * directly, but by the library.\n */\nclass metadata\n{\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details The constructed metadata object has undefined\n     * values for all of its members.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    metadata() = default;\n\n    /**\n     * \\brief Move constructor.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * `string_view`s obtained by calling accessor functions on `other` are invalidated.\n     */\n    metadata(metadata&& other) = default;\n\n    /**\n     * \\brief Copy constructor.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     */\n    metadata(const metadata& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * `string_view`s obtained by calling accessor functions on both `*this` and `other`\n     * are invalidated.\n     */\n    metadata& operator=(metadata&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `string_view`s obtained by calling accessor functions on `*this`\n     * are invalidated.\n     */\n    metadata& operator=(const metadata& other) = default;\n\n    /// Destructor.\n    ~metadata() = default;\n\n    /**\n     * \\brief Returns the name of the database (schema) the column belongs to.\n     * \\details\n     * This is optional information - it won't be populated unless\n     * the connection executing the query has `meta_mode() == metadata_mode::full`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and hasn't been\n     * assigned to or moved from.\n     */\n    string_view database() const noexcept { return substring(0, table_offset_); }\n\n    /**\n     * \\brief Returns the name of the virtual table the column belongs to.\n     * \\details If the table was aliased, this will be the name of the alias\n     * (e.g. in `\"SELECT * FROM employees emp\"`, `table()` will be `\"emp\"`).\n     *\\n\n     * This is optional information - it won't be populated unless\n     * the connection executing the query has `meta_mode() == metadata_mode::full`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and hasn't been\n     * assigned to or moved from.\n     */\n    string_view table() const noexcept { return substring(table_offset_, org_table_offset_); }\n\n    /**\n     * \\brief Returns the name of the physical table the column belongs to.\n     * \\details E.g. in `\"SELECT * FROM employees emp\"`,\n     * `original_table()` will be `\"employees\"`.\n     * \\n\n     * This is optional information - it won't be populated unless\n     * the connection executing the query has `meta_mode() == metadata_mode::full`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and hasn't been\n     * assigned to or moved from.\n     */\n    string_view original_table() const noexcept { return substring(org_table_offset_, name_offset_); }\n\n    /**\n     * \\brief Returns the actual name of the column.\n     * \\details If the column was aliased, this will be the name of the alias\n     * (e.g. in `\"SELECT id AS employee_id FROM employees\"`,\n     * `column_name()` will be `\"employee_id\"`).\n     *\\n\n     * This is optional information - it won't be populated unless\n     * the connection executing the query has `meta_mode() == metadata_mode::full`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and hasn't been\n     * assigned to or moved from.\n     */\n    string_view column_name() const noexcept { return substring(name_offset_, org_name_offset_); }\n\n    /**\n     * \\brief Returns the original (physical) name of the column.\n     * \\details E.g. in `\"SELECT id AS employee_id FROM employees\"`,\n     * `original_column_name()` will be `\"id\"`.\n     * \\n\n     * This is optional information - it won't be populated unless\n     * the connection executing the query has `meta_mode() == metadata_mode::full`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive and hasn't been\n     * assigned to or moved from.\n     */\n    string_view original_column_name() const noexcept { return substring(org_name_offset_, strings_.size()); }\n\n    /**\n     * \\brief Returns the ID of the collation that fields belonging to this column use.\n     * \\details This is <b>not</b> the collation used when defining the column\n     * in a `CREATE TABLE` statement, but the collation that fields that belong to\n     * this column and are sent to the client have. It usually matches the connection's collation.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    std::uint16_t column_collation() const noexcept { return character_set_; }\n\n    /**\n     * \\brief Returns the maximum length of the column.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    unsigned column_length() const noexcept { return column_length_; }\n\n    /**\n     * \\brief  Returns the type of the column (see \\ref column_type for more info).\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    column_type type() const noexcept { return type_; }\n\n    /**\n     * \\brief  Returns the number of decimals of the column.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    unsigned decimals() const noexcept { return decimals_; }\n\n    /**\n     * \\brief Returns `true` if the column is not allowed to be NULL, `false` if it is nullable.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_not_null() const noexcept { return flag_set(detail::column_flags::not_null); }\n\n    /**\n     * \\brief Returns `true` if the column is part of a `PRIMARY KEY`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_primary_key() const noexcept { return flag_set(detail::column_flags::pri_key); }\n\n    /**\n     * \\brief Returns `true` if the column is part of a `UNIQUE KEY` (but not a `PRIMARY KEY`).\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_unique_key() const noexcept { return flag_set(detail::column_flags::unique_key); }\n\n    /**\n     * \\brief Returns `true` if the column is part of a `KEY` (but not a `UNIQUE KEY` or `PRIMARY KEY`).\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_multiple_key() const noexcept { return flag_set(detail::column_flags::multiple_key); }\n\n    /**\n     * \\brief Returns `true` if the column has no sign (is `UNSIGNED`).\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_unsigned() const noexcept { return flag_set(detail::column_flags::unsigned_); }\n\n    /**\n     * \\brief Returns `true` if the column is defined as `ZEROFILL` (padded to its maximum length by\n     *        zeros).\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_zerofill() const noexcept { return flag_set(detail::column_flags::zerofill); }\n\n    /**\n     * \\brief Returns `true` if the column is defined as `AUTO_INCREMENT`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_auto_increment() const noexcept { return flag_set(detail::column_flags::auto_increment); }\n\n    /**\n     * \\brief Returns `true` if the column does not have a default value.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool has_no_default_value() const noexcept { return flag_set(detail::column_flags::no_default_value); }\n\n    /**\n     * \\brief Returns `true` if the column is defined as `ON UPDATE CURRENT_TIMESTAMP`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_set_to_now_on_update() const noexcept { return flag_set(detail::column_flags::on_update_now); }\n\nprivate:\n    // All strings together: schema, table, org table, name, org name\n    std::vector<char> strings_;\n    std::size_t table_offset_{};      // virtual table\n    std::size_t org_table_offset_{};  // physical table\n    std::size_t name_offset_{};       // virtual column name\n    std::size_t org_name_offset_{};   // physical column name\n    std::uint16_t character_set_{};\n    std::uint32_t column_length_{};  // maximum length of the field\n    column_type type_{};             // type of the column\n    std::uint16_t flags_{};          // Flags as defined in Column Definition Flags\n    std::uint8_t decimals_{};        // max shown decimal digits. 0x00 for int/static strings; 0x1f for\n                                     // dynamic strings, double, float\n\n    static std::size_t total_string_size(const detail::coldef_view& coldef)\n    {\n        return coldef.database.size() + coldef.table.size() + coldef.org_table.size() + coldef.name.size() +\n               coldef.org_name.size();\n    }\n\n    static char* copy_string(string_view from, char* to)\n    {\n        if (!from.empty())\n            std::memcpy(to, from.data(), from.size());\n        return to + from.size();\n    }\n\n    metadata(const detail::coldef_view& coldef, bool copy_strings)\n        : strings_(copy_strings ? total_string_size(coldef) : 0u, '\\0'),\n          character_set_(coldef.collation_id),\n          column_length_(coldef.column_length),\n          type_(coldef.type),\n          flags_(coldef.flags),\n          decimals_(coldef.decimals)\n    {\n        if (copy_strings)\n        {\n            // Offsets\n            table_offset_ = coldef.database.size();\n            org_table_offset_ = table_offset_ + coldef.table.size();\n            name_offset_ = org_table_offset_ + coldef.org_table.size();\n            org_name_offset_ = name_offset_ + coldef.name.size();\n\n            // Values. The packet points into a network packet, so it's guaranteed to\n            // not overlap with\n            char* it = strings_.data();\n            it = copy_string(coldef.database, it);\n            it = copy_string(coldef.table, it);\n            it = copy_string(coldef.org_table, it);\n            it = copy_string(coldef.name, it);\n            it = copy_string(coldef.org_name, it);\n            BOOST_ASSERT(it == strings_.data() + strings_.size());\n        }\n    }\n\n    bool flag_set(std::uint16_t flag) const noexcept { return flags_ & flag; }\n\n    string_view substring(std::size_t first, std::size_t last) const\n    {\n        return {strings_.data() + first, static_cast<std::size_t>(last - first)};\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/metadata_collection_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_METADATA_COLLECTION_VIEW_HPP\n#define BOOST_MYSQL_METADATA_COLLECTION_VIEW_HPP\n\n#include <boost/mysql/metadata.hpp>\n\n#include <boost/core/span.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A read-only view of a collection of \\ref metadata objects.\n * \\par Object lifetimes\n * The object doesn't own the storage for the \\ref metadata objects. These are typically\n * owned by a \\ref results or \\ref execution_state object. This view is valid as long\n * as the memory allocated for the \\ref metadata objects remain valid.\n */\nusing metadata_collection_view = boost::span<const metadata>;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/metadata_mode.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_METADATA_MODE_HPP\n#define BOOST_MYSQL_METADATA_MODE_HPP\n\nnamespace boost {\nnamespace mysql {\n\n/// Describes how to handle metadata when running a query or statement.\nenum class metadata_mode\n{\n    /**\n     * \\brief Retain the minimum metadata possible to be able to execute the operation.\n     * This is the most efficient mode, but will leave some fields in the \\ref metadata\n     * class empty.\n     */\n    minimal,\n\n    /**\n     * \\brief Retain as much metadata as possible. All the fields in \\ref metadata are usable,\n     * but causes more allocations.\n     */\n    full\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/mysql_collations.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_MYSQL_COLLATIONS_HPP\n#define BOOST_MYSQL_MYSQL_COLLATIONS_HPP\n\n// This header was generated by collations.py - do not edit directly\n\n#include <boost/config.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace mysql_collations {\n\n// Identifies the big5_chinese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t big5_chinese_ci = 1;\n\n// Identifies the latin2_czech_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_czech_cs = 2;\n\n// Identifies the dec8_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t dec8_swedish_ci = 3;\n\n// Identifies the cp850_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp850_general_ci = 4;\n\n// Identifies the latin1_german1_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_german1_ci = 5;\n\n// Identifies the hp8_english_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hp8_english_ci = 6;\n\n// Identifies the koi8r_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8r_general_ci = 7;\n\n// Identifies the latin1_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_swedish_ci = 8;\n\n// Identifies the latin2_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_general_ci = 9;\n\n// Identifies the swe7_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t swe7_swedish_ci = 10;\n\n// Identifies the ascii_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ascii_general_ci = 11;\n\n// Identifies the ujis_japanese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ujis_japanese_ci = 12;\n\n// Identifies the sjis_japanese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t sjis_japanese_ci = 13;\n\n// Identifies the cp1251_bulgarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_bulgarian_ci = 14;\n\n// Identifies the latin1_danish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_danish_ci = 15;\n\n// Identifies the hebrew_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hebrew_general_ci = 16;\n\n// Identifies the tis620_thai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t tis620_thai_ci = 18;\n\n// Identifies the euckr_korean_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t euckr_korean_ci = 19;\n\n// Identifies the latin7_estonian_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_estonian_cs = 20;\n\n// Identifies the latin2_hungarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_hungarian_ci = 21;\n\n// Identifies the koi8u_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8u_general_ci = 22;\n\n// Identifies the cp1251_ukrainian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_ukrainian_ci = 23;\n\n// Identifies the gb2312_chinese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb2312_chinese_ci = 24;\n\n// Identifies the greek_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t greek_general_ci = 25;\n\n// Identifies the cp1250_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_general_ci = 26;\n\n// Identifies the latin2_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_croatian_ci = 27;\n\n// Identifies the gbk_chinese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gbk_chinese_ci = 28;\n\n// Identifies the cp1257_lithuanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_lithuanian_ci = 29;\n\n// Identifies the latin5_turkish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin5_turkish_ci = 30;\n\n// Identifies the latin1_german2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_german2_ci = 31;\n\n// Identifies the armscii8_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t armscii8_general_ci = 32;\n\n// Identifies the utf8_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_general_ci = 33;\n\n// Identifies the cp1250_czech_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_czech_cs = 34;\n\n// Identifies the ucs2_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_general_ci = 35;\n\n// Identifies the cp866_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp866_general_ci = 36;\n\n// Identifies the keybcs2_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t keybcs2_general_ci = 37;\n\n// Identifies the macce_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macce_general_ci = 38;\n\n// Identifies the macroman_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macroman_general_ci = 39;\n\n// Identifies the cp852_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp852_general_ci = 40;\n\n// Identifies the latin7_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_general_ci = 41;\n\n// Identifies the latin7_general_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_general_cs = 42;\n\n// Identifies the macce_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macce_bin = 43;\n\n// Identifies the cp1250_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_croatian_ci = 44;\n\n// Identifies the utf8mb4_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_general_ci = 45;\n\n// Identifies the utf8mb4_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_bin = 46;\n\n// Identifies the latin1_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_bin = 47;\n\n// Identifies the latin1_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_general_ci = 48;\n\n// Identifies the latin1_general_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_general_cs = 49;\n\n// Identifies the cp1251_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_bin = 50;\n\n// Identifies the cp1251_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_general_ci = 51;\n\n// Identifies the cp1251_general_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1251_general_cs = 52;\n\n// Identifies the macroman_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t macroman_bin = 53;\n\n// Identifies the utf16_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_general_ci = 54;\n\n// Identifies the utf16_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_bin = 55;\n\n// Identifies the utf16le_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16le_general_ci = 56;\n\n// Identifies the cp1256_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1256_general_ci = 57;\n\n// Identifies the cp1257_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_bin = 58;\n\n// Identifies the cp1257_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1257_general_ci = 59;\n\n// Identifies the utf32_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_general_ci = 60;\n\n// Identifies the utf32_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_bin = 61;\n\n// Identifies the utf16le_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16le_bin = 62;\n\n// Identifies the binary collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t binary = 63;\n\n// Identifies the armscii8_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t armscii8_bin = 64;\n\n// Identifies the ascii_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ascii_bin = 65;\n\n// Identifies the cp1250_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_bin = 66;\n\n// Identifies the cp1256_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1256_bin = 67;\n\n// Identifies the cp866_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp866_bin = 68;\n\n// Identifies the dec8_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t dec8_bin = 69;\n\n// Identifies the greek_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t greek_bin = 70;\n\n// Identifies the hebrew_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hebrew_bin = 71;\n\n// Identifies the hp8_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t hp8_bin = 72;\n\n// Identifies the keybcs2_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t keybcs2_bin = 73;\n\n// Identifies the koi8r_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8r_bin = 74;\n\n// Identifies the koi8u_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t koi8u_bin = 75;\n\n// Identifies the utf8_tolower_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_tolower_ci = 76;\n\n// Identifies the latin2_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin2_bin = 77;\n\n// Identifies the latin5_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin5_bin = 78;\n\n// Identifies the latin7_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin7_bin = 79;\n\n// Identifies the cp850_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp850_bin = 80;\n\n// Identifies the cp852_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp852_bin = 81;\n\n// Identifies the swe7_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t swe7_bin = 82;\n\n// Identifies the utf8_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_bin = 83;\n\n// Identifies the big5_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t big5_bin = 84;\n\n// Identifies the euckr_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t euckr_bin = 85;\n\n// Identifies the gb2312_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb2312_bin = 86;\n\n// Identifies the gbk_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gbk_bin = 87;\n\n// Identifies the sjis_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t sjis_bin = 88;\n\n// Identifies the tis620_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t tis620_bin = 89;\n\n// Identifies the ucs2_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_bin = 90;\n\n// Identifies the ujis_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ujis_bin = 91;\n\n// Identifies the geostd8_general_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t geostd8_general_ci = 92;\n\n// Identifies the geostd8_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t geostd8_bin = 93;\n\n// Identifies the latin1_spanish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t latin1_spanish_ci = 94;\n\n// Identifies the cp932_japanese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp932_japanese_ci = 95;\n\n// Identifies the cp932_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp932_bin = 96;\n\n// Identifies the eucjpms_japanese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t eucjpms_japanese_ci = 97;\n\n// Identifies the eucjpms_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t eucjpms_bin = 98;\n\n// Identifies the cp1250_polish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t cp1250_polish_ci = 99;\n\n// Identifies the utf16_unicode_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_unicode_ci = 101;\n\n// Identifies the utf16_icelandic_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_icelandic_ci = 102;\n\n// Identifies the utf16_latvian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_latvian_ci = 103;\n\n// Identifies the utf16_romanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_romanian_ci = 104;\n\n// Identifies the utf16_slovenian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_slovenian_ci = 105;\n\n// Identifies the utf16_polish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_polish_ci = 106;\n\n// Identifies the utf16_estonian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_estonian_ci = 107;\n\n// Identifies the utf16_spanish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_spanish_ci = 108;\n\n// Identifies the utf16_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_swedish_ci = 109;\n\n// Identifies the utf16_turkish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_turkish_ci = 110;\n\n// Identifies the utf16_czech_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_czech_ci = 111;\n\n// Identifies the utf16_danish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_danish_ci = 112;\n\n// Identifies the utf16_lithuanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_lithuanian_ci = 113;\n\n// Identifies the utf16_slovak_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_slovak_ci = 114;\n\n// Identifies the utf16_spanish2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_spanish2_ci = 115;\n\n// Identifies the utf16_roman_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_roman_ci = 116;\n\n// Identifies the utf16_persian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_persian_ci = 117;\n\n// Identifies the utf16_esperanto_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_esperanto_ci = 118;\n\n// Identifies the utf16_hungarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_hungarian_ci = 119;\n\n// Identifies the utf16_sinhala_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_sinhala_ci = 120;\n\n// Identifies the utf16_german2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_german2_ci = 121;\n\n// Identifies the utf16_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_croatian_ci = 122;\n\n// Identifies the utf16_unicode_520_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_unicode_520_ci = 123;\n\n// Identifies the utf16_vietnamese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf16_vietnamese_ci = 124;\n\n// Identifies the ucs2_unicode_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_unicode_ci = 128;\n\n// Identifies the ucs2_icelandic_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_icelandic_ci = 129;\n\n// Identifies the ucs2_latvian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_latvian_ci = 130;\n\n// Identifies the ucs2_romanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_romanian_ci = 131;\n\n// Identifies the ucs2_slovenian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_slovenian_ci = 132;\n\n// Identifies the ucs2_polish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_polish_ci = 133;\n\n// Identifies the ucs2_estonian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_estonian_ci = 134;\n\n// Identifies the ucs2_spanish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_spanish_ci = 135;\n\n// Identifies the ucs2_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_swedish_ci = 136;\n\n// Identifies the ucs2_turkish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_turkish_ci = 137;\n\n// Identifies the ucs2_czech_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_czech_ci = 138;\n\n// Identifies the ucs2_danish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_danish_ci = 139;\n\n// Identifies the ucs2_lithuanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_lithuanian_ci = 140;\n\n// Identifies the ucs2_slovak_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_slovak_ci = 141;\n\n// Identifies the ucs2_spanish2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_spanish2_ci = 142;\n\n// Identifies the ucs2_roman_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_roman_ci = 143;\n\n// Identifies the ucs2_persian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_persian_ci = 144;\n\n// Identifies the ucs2_esperanto_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_esperanto_ci = 145;\n\n// Identifies the ucs2_hungarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_hungarian_ci = 146;\n\n// Identifies the ucs2_sinhala_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_sinhala_ci = 147;\n\n// Identifies the ucs2_german2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_german2_ci = 148;\n\n// Identifies the ucs2_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_croatian_ci = 149;\n\n// Identifies the ucs2_unicode_520_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_unicode_520_ci = 150;\n\n// Identifies the ucs2_vietnamese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_vietnamese_ci = 151;\n\n// Identifies the ucs2_general_mysql500_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t ucs2_general_mysql500_ci = 159;\n\n// Identifies the utf32_unicode_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_unicode_ci = 160;\n\n// Identifies the utf32_icelandic_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_icelandic_ci = 161;\n\n// Identifies the utf32_latvian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_latvian_ci = 162;\n\n// Identifies the utf32_romanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_romanian_ci = 163;\n\n// Identifies the utf32_slovenian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_slovenian_ci = 164;\n\n// Identifies the utf32_polish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_polish_ci = 165;\n\n// Identifies the utf32_estonian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_estonian_ci = 166;\n\n// Identifies the utf32_spanish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_spanish_ci = 167;\n\n// Identifies the utf32_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_swedish_ci = 168;\n\n// Identifies the utf32_turkish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_turkish_ci = 169;\n\n// Identifies the utf32_czech_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_czech_ci = 170;\n\n// Identifies the utf32_danish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_danish_ci = 171;\n\n// Identifies the utf32_lithuanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_lithuanian_ci = 172;\n\n// Identifies the utf32_slovak_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_slovak_ci = 173;\n\n// Identifies the utf32_spanish2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_spanish2_ci = 174;\n\n// Identifies the utf32_roman_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_roman_ci = 175;\n\n// Identifies the utf32_persian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_persian_ci = 176;\n\n// Identifies the utf32_esperanto_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_esperanto_ci = 177;\n\n// Identifies the utf32_hungarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_hungarian_ci = 178;\n\n// Identifies the utf32_sinhala_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_sinhala_ci = 179;\n\n// Identifies the utf32_german2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_german2_ci = 180;\n\n// Identifies the utf32_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_croatian_ci = 181;\n\n// Identifies the utf32_unicode_520_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_unicode_520_ci = 182;\n\n// Identifies the utf32_vietnamese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf32_vietnamese_ci = 183;\n\n// Identifies the utf8_unicode_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_unicode_ci = 192;\n\n// Identifies the utf8_icelandic_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_icelandic_ci = 193;\n\n// Identifies the utf8_latvian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_latvian_ci = 194;\n\n// Identifies the utf8_romanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_romanian_ci = 195;\n\n// Identifies the utf8_slovenian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_slovenian_ci = 196;\n\n// Identifies the utf8_polish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_polish_ci = 197;\n\n// Identifies the utf8_estonian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_estonian_ci = 198;\n\n// Identifies the utf8_spanish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_spanish_ci = 199;\n\n// Identifies the utf8_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_swedish_ci = 200;\n\n// Identifies the utf8_turkish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_turkish_ci = 201;\n\n// Identifies the utf8_czech_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_czech_ci = 202;\n\n// Identifies the utf8_danish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_danish_ci = 203;\n\n// Identifies the utf8_lithuanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_lithuanian_ci = 204;\n\n// Identifies the utf8_slovak_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_slovak_ci = 205;\n\n// Identifies the utf8_spanish2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_spanish2_ci = 206;\n\n// Identifies the utf8_roman_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_roman_ci = 207;\n\n// Identifies the utf8_persian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_persian_ci = 208;\n\n// Identifies the utf8_esperanto_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_esperanto_ci = 209;\n\n// Identifies the utf8_hungarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_hungarian_ci = 210;\n\n// Identifies the utf8_sinhala_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_sinhala_ci = 211;\n\n// Identifies the utf8_german2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_german2_ci = 212;\n\n// Identifies the utf8_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_croatian_ci = 213;\n\n// Identifies the utf8_unicode_520_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_unicode_520_ci = 214;\n\n// Identifies the utf8_vietnamese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_vietnamese_ci = 215;\n\n// Identifies the utf8_general_mysql500_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8_general_mysql500_ci = 223;\n\n// Identifies the utf8mb4_unicode_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_unicode_ci = 224;\n\n// Identifies the utf8mb4_icelandic_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_icelandic_ci = 225;\n\n// Identifies the utf8mb4_latvian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_latvian_ci = 226;\n\n// Identifies the utf8mb4_romanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_romanian_ci = 227;\n\n// Identifies the utf8mb4_slovenian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_slovenian_ci = 228;\n\n// Identifies the utf8mb4_polish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_polish_ci = 229;\n\n// Identifies the utf8mb4_estonian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_estonian_ci = 230;\n\n// Identifies the utf8mb4_spanish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_spanish_ci = 231;\n\n// Identifies the utf8mb4_swedish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_swedish_ci = 232;\n\n// Identifies the utf8mb4_turkish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_turkish_ci = 233;\n\n// Identifies the utf8mb4_czech_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_czech_ci = 234;\n\n// Identifies the utf8mb4_danish_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_danish_ci = 235;\n\n// Identifies the utf8mb4_lithuanian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_lithuanian_ci = 236;\n\n// Identifies the utf8mb4_slovak_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_slovak_ci = 237;\n\n// Identifies the utf8mb4_spanish2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_spanish2_ci = 238;\n\n// Identifies the utf8mb4_roman_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_roman_ci = 239;\n\n// Identifies the utf8mb4_persian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_persian_ci = 240;\n\n// Identifies the utf8mb4_esperanto_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_esperanto_ci = 241;\n\n// Identifies the utf8mb4_hungarian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_hungarian_ci = 242;\n\n// Identifies the utf8mb4_sinhala_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sinhala_ci = 243;\n\n// Identifies the utf8mb4_german2_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_german2_ci = 244;\n\n// Identifies the utf8mb4_croatian_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_croatian_ci = 245;\n\n// Identifies the utf8mb4_unicode_520_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_unicode_520_ci = 246;\n\n// Identifies the utf8mb4_vietnamese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_vietnamese_ci = 247;\n\n// Identifies the gb18030_chinese_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb18030_chinese_ci = 248;\n\n// Identifies the gb18030_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb18030_bin = 249;\n\n// Identifies the gb18030_unicode_520_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t gb18030_unicode_520_ci = 250;\n\n// Identifies the utf8mb4_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_0900_ai_ci = 255;\n\n// Identifies the utf8mb4_de_pb_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_de_pb_0900_ai_ci = 256;\n\n// Identifies the utf8mb4_is_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_is_0900_ai_ci = 257;\n\n// Identifies the utf8mb4_lv_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_lv_0900_ai_ci = 258;\n\n// Identifies the utf8mb4_ro_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_ro_0900_ai_ci = 259;\n\n// Identifies the utf8mb4_sl_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sl_0900_ai_ci = 260;\n\n// Identifies the utf8mb4_pl_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_pl_0900_ai_ci = 261;\n\n// Identifies the utf8mb4_et_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_et_0900_ai_ci = 262;\n\n// Identifies the utf8mb4_es_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_es_0900_ai_ci = 263;\n\n// Identifies the utf8mb4_sv_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sv_0900_ai_ci = 264;\n\n// Identifies the utf8mb4_tr_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_tr_0900_ai_ci = 265;\n\n// Identifies the utf8mb4_cs_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_cs_0900_ai_ci = 266;\n\n// Identifies the utf8mb4_da_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_da_0900_ai_ci = 267;\n\n// Identifies the utf8mb4_lt_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_lt_0900_ai_ci = 268;\n\n// Identifies the utf8mb4_sk_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sk_0900_ai_ci = 269;\n\n// Identifies the utf8mb4_es_trad_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_es_trad_0900_ai_ci = 270;\n\n// Identifies the utf8mb4_la_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_la_0900_ai_ci = 271;\n\n// Identifies the utf8mb4_eo_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_eo_0900_ai_ci = 273;\n\n// Identifies the utf8mb4_hu_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_hu_0900_ai_ci = 274;\n\n// Identifies the utf8mb4_hr_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_hr_0900_ai_ci = 275;\n\n// Identifies the utf8mb4_vi_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_vi_0900_ai_ci = 277;\n\n// Identifies the utf8mb4_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_0900_as_cs = 278;\n\n// Identifies the utf8mb4_de_pb_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_de_pb_0900_as_cs = 279;\n\n// Identifies the utf8mb4_is_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_is_0900_as_cs = 280;\n\n// Identifies the utf8mb4_lv_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_lv_0900_as_cs = 281;\n\n// Identifies the utf8mb4_ro_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_ro_0900_as_cs = 282;\n\n// Identifies the utf8mb4_sl_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sl_0900_as_cs = 283;\n\n// Identifies the utf8mb4_pl_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_pl_0900_as_cs = 284;\n\n// Identifies the utf8mb4_et_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_et_0900_as_cs = 285;\n\n// Identifies the utf8mb4_es_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_es_0900_as_cs = 286;\n\n// Identifies the utf8mb4_sv_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sv_0900_as_cs = 287;\n\n// Identifies the utf8mb4_tr_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_tr_0900_as_cs = 288;\n\n// Identifies the utf8mb4_cs_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_cs_0900_as_cs = 289;\n\n// Identifies the utf8mb4_da_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_da_0900_as_cs = 290;\n\n// Identifies the utf8mb4_lt_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_lt_0900_as_cs = 291;\n\n// Identifies the utf8mb4_sk_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_sk_0900_as_cs = 292;\n\n// Identifies the utf8mb4_es_trad_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_es_trad_0900_as_cs = 293;\n\n// Identifies the utf8mb4_la_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_la_0900_as_cs = 294;\n\n// Identifies the utf8mb4_eo_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_eo_0900_as_cs = 296;\n\n// Identifies the utf8mb4_hu_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_hu_0900_as_cs = 297;\n\n// Identifies the utf8mb4_hr_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_hr_0900_as_cs = 298;\n\n// Identifies the utf8mb4_vi_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_vi_0900_as_cs = 300;\n\n// Identifies the utf8mb4_ja_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_ja_0900_as_cs = 303;\n\n// Identifies the utf8mb4_ja_0900_as_cs_ks collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_ja_0900_as_cs_ks = 304;\n\n// Identifies the utf8mb4_0900_as_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_0900_as_ci = 305;\n\n// Identifies the utf8mb4_ru_0900_ai_ci collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_ru_0900_ai_ci = 306;\n\n// Identifies the utf8mb4_ru_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_ru_0900_as_cs = 307;\n\n// Identifies the utf8mb4_zh_0900_as_cs collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_zh_0900_as_cs = 308;\n\n// Identifies the utf8mb4_0900_bin collation in mysql servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t utf8mb4_0900_bin = 309;\n\n}  // namespace mysql_collations\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/mysql_server_errc.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_MYSQL_SERVER_ERRC_HPP\n#define BOOST_MYSQL_MYSQL_SERVER_ERRC_HPP\n\n#include <boost/config.hpp>\n\nnamespace boost {\nnamespace mysql {\n\nnamespace mysql_server_errc {\n\n/// Server error specific to mysql. Error number: 1076, symbol: ER_READY.\nBOOST_INLINE_CONSTEXPR int er_ready = 1076;\n\n/// Server error specific to mysql. Error number: 1101, symbol: ER_BLOB_CANT_HAVE_DEFAULT.\nBOOST_INLINE_CONSTEXPR int er_blob_cant_have_default = 1101;\n\n/// Server error specific to mysql. Error number: 1120, symbol: ER_WRONG_OUTER_JOIN_UNUSED.\nBOOST_INLINE_CONSTEXPR int er_wrong_outer_join_unused = 1120;\n\n/// Server error specific to mysql. Error number: 1176, symbol: ER_KEY_DOES_NOT_EXITS.\nBOOST_INLINE_CONSTEXPR int er_key_does_not_exits = 1176;\n\n/// Server error specific to mysql. Error number: 1185, symbol: ER_DUMP_NOT_IMPLEMENTED.\nBOOST_INLINE_CONSTEXPR int er_dump_not_implemented = 1185;\n\n/// Server error specific to mysql. Error number: 1349, symbol: ER_VIEW_SELECT_DERIVED_UNUSED.\nBOOST_INLINE_CONSTEXPR int er_view_select_derived_unused = 1349;\n\n/// Server error specific to mysql. Error number: 1487, symbol: ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR.\nBOOST_INLINE_CONSTEXPR int er_no_const_expr_in_range_or_list_error = 1487;\n\n/// Server error specific to mysql. Error number: 1506, symbol: ER_FOREIGN_KEY_ON_PARTITIONED.\nBOOST_INLINE_CONSTEXPR int er_foreign_key_on_partitioned = 1506;\n\n/// Server error specific to mysql. Error number: 1547, symbol: ER_OBSOLETE_COL_COUNT_DOESNT_MATCH_CORRUPTED.\nBOOST_INLINE_CONSTEXPR int er_obsolete_col_count_doesnt_match_corrupted = 1547;\n\n/// Server error specific to mysql. Error number: 1548, symbol: ER_OBSOLETE_CANNOT_LOAD_FROM_TABLE.\nBOOST_INLINE_CONSTEXPR int er_obsolete_cannot_load_from_table = 1548;\n\n/// Server error specific to mysql. Error number: 1557, symbol: ER_FOREIGN_DUPLICATE_KEY_OLD_UNUSED.\nBOOST_INLINE_CONSTEXPR int er_foreign_duplicate_key_old_unused = 1557;\n\n/// Server error specific to mysql. Error number: 1561, symbol: ER_NDB_CANT_SWITCH_BINLOG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_ndb_cant_switch_binlog_format = 1561;\n\n/// Server error specific to mysql. Error number: 1593, symbol: ER_BINLOG_FATAL_ERROR.\nBOOST_INLINE_CONSTEXPR int er_binlog_fatal_error = 1593;\n\n/// Server error specific to mysql. Error number: 1608, symbol: ER_NEVER_USED.\nBOOST_INLINE_CONSTEXPR int er_never_used = 1608;\n\n/// Server error specific to mysql. Error number: 1611, symbol: ER_LOAD_DATA_INVALID_COLUMN_UNUSED.\nBOOST_INLINE_CONSTEXPR int er_load_data_invalid_column_unused = 1611;\n\n/// Server error specific to mysql. Error number: 1625, symbol: ER_NDB_REPLICATION_SCHEMA_ERROR.\nBOOST_INLINE_CONSTEXPR int er_ndb_replication_schema_error = 1625;\n\n/// Server error specific to mysql. Error number: 1720, symbol: ER_PLUGIN_NO_UNINSTALL.\nBOOST_INLINE_CONSTEXPR int er_plugin_no_uninstall = 1720;\n\n/// Server error specific to mysql. Error number: 1721, symbol: ER_PLUGIN_NO_INSTALL.\nBOOST_INLINE_CONSTEXPR int er_plugin_no_install = 1721;\n\n/// Server error specific to mysql. Error number: 1725, symbol: ER_TABLE_IN_FK_CHECK.\nBOOST_INLINE_CONSTEXPR int er_table_in_fk_check = 1725;\n\n/// Server error specific to mysql. Error number: 1726, symbol: ER_UNSUPPORTED_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_unsupported_engine = 1726;\n\n/// Server error specific to mysql. Error number: 1742, symbol: ER_RPL_INFO_DATA_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_rpl_info_data_too_long = 1742;\n\n/// Server error specific to mysql. Error number: 1768, symbol: ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION.\nBOOST_INLINE_CONSTEXPR int er_cant_change_gtid_next_in_transaction = 1768;\n\n/// Server error specific to mysql. Error number: 1777, symbol: ER_AUTO_POSITION_REQUIRES_GTID_MODE_NOT_OFF.\nBOOST_INLINE_CONSTEXPR int er_auto_position_requires_gtid_mode_not_off = 1777;\n\n/// Server error specific to mysql. Error number: 1779, symbol: ER_GTID_MODE_ON_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON.\nBOOST_INLINE_CONSTEXPR int er_gtid_mode_on_requires_enforce_gtid_consistency_on = 1779;\n\n/// Server error specific to mysql. Error number: 1807, symbol: ER_DISCARD_FK_CHECKS_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_discard_fk_checks_running = 1807;\n\n/// Server error specific to mysql. Error number: 1826, symbol: ER_FK_DUP_NAME.\nBOOST_INLINE_CONSTEXPR int er_fk_dup_name = 1826;\n\n/// Server error specific to mysql. Error number: 1837, symbol: ER_GTID_NEXT_TYPE_UNDEFINED_GTID.\nBOOST_INLINE_CONSTEXPR int er_gtid_next_type_undefined_gtid = 1837;\n\n/// Server error specific to mysql. Error number: 1880, symbol: ER_OLD_TEMPORALS_UPGRADED.\nBOOST_INLINE_CONSTEXPR int er_old_temporals_upgraded = 1880;\n\n/// Server error specific to mysql. Error number: 1881, symbol: ER_INNODB_FORCED_RECOVERY.\nBOOST_INLINE_CONSTEXPR int er_innodb_forced_recovery = 1881;\n\n/// Server error specific to mysql. Error number: 1882, symbol: ER_AES_INVALID_IV.\nBOOST_INLINE_CONSTEXPR int er_aes_invalid_iv = 1882;\n\n/// Server error specific to mysql. Error number: 1883, symbol: ER_PLUGIN_CANNOT_BE_UNINSTALLED.\nBOOST_INLINE_CONSTEXPR int er_plugin_cannot_be_uninstalled = 1883;\n\n/// Server error specific to mysql. Error number: 1884, symbol: ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_ASSIGNED_GTID.\nBOOST_INLINE_CONSTEXPR int er_gtid_unsafe_binlog_splittable_statement_and_assigned_gtid = 1884;\n\n/// Server error specific to mysql. Error number: 1885, symbol: ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER.\nBOOST_INLINE_CONSTEXPR int er_slave_has_more_gtids_than_master = 1885;\n\n/// Server error specific to mysql. Error number: 1886, symbol: ER_MISSING_KEY.\nBOOST_INLINE_CONSTEXPR int er_missing_key = 1886;\n\n/// Server error specific to mysql. Error number: 1887, symbol: WARN_NAMED_PIPE_ACCESS_EVERYONE.\nBOOST_INLINE_CONSTEXPR int warn_named_pipe_access_everyone = 1887;\n\n/// Server error specific to mysql. Error number: 1888, symbol: ER_FOUND_MISSING_GTIDS.\nBOOST_INLINE_CONSTEXPR int er_found_missing_gtids = 1888;\n\n/// Server error specific to mysql. Error number: 3000, symbol: ER_FILE_CORRUPT.\nBOOST_INLINE_CONSTEXPR int er_file_corrupt = 3000;\n\n/// Server error specific to mysql. Error number: 3001, symbol: ER_ERROR_ON_MASTER.\nBOOST_INLINE_CONSTEXPR int er_error_on_master = 3001;\n\n/// Server error specific to mysql. Error number: 3002, symbol: ER_INCONSISTENT_ERROR.\nBOOST_INLINE_CONSTEXPR int er_inconsistent_error = 3002;\n\n/// Server error specific to mysql. Error number: 3003, symbol: ER_STORAGE_ENGINE_NOT_LOADED.\nBOOST_INLINE_CONSTEXPR int er_storage_engine_not_loaded = 3003;\n\n/// Server error specific to mysql. Error number: 3004, symbol: ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER.\nBOOST_INLINE_CONSTEXPR int er_get_stacked_da_without_active_handler = 3004;\n\n/// Server error specific to mysql. Error number: 3005, symbol: ER_WARN_LEGACY_SYNTAX_CONVERTED.\nBOOST_INLINE_CONSTEXPR int er_warn_legacy_syntax_converted = 3005;\n\n/// Server error specific to mysql. Error number: 3006, symbol: ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_fulltext_plugin = 3006;\n\n/// Server error specific to mysql. Error number: 3007, symbol: ER_CANNOT_DISCARD_TEMPORARY_TABLE.\nBOOST_INLINE_CONSTEXPR int er_cannot_discard_temporary_table = 3007;\n\n/// Server error specific to mysql. Error number: 3008, symbol: ER_FK_DEPTH_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_fk_depth_exceeded = 3008;\n\n/// Server error specific to mysql. Error number: 3009, symbol: ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2.\nBOOST_INLINE_CONSTEXPR int er_col_count_doesnt_match_please_update_v2 = 3009;\n\n/// Server error specific to mysql. Error number: 3010, symbol: ER_WARN_TRIGGER_DOESNT_HAVE_CREATED.\nBOOST_INLINE_CONSTEXPR int er_warn_trigger_doesnt_have_created = 3010;\n\n/// Server error specific to mysql. Error number: 3011, symbol: ER_REFERENCED_TRG_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_referenced_trg_does_not_exist = 3011;\n\n/// Server error specific to mysql. Error number: 3012, symbol: ER_EXPLAIN_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_explain_not_supported = 3012;\n\n/// Server error specific to mysql. Error number: 3013, symbol: ER_INVALID_FIELD_SIZE.\nBOOST_INLINE_CONSTEXPR int er_invalid_field_size = 3013;\n\n/// Server error specific to mysql. Error number: 3014, symbol: ER_MISSING_HA_CREATE_OPTION.\nBOOST_INLINE_CONSTEXPR int er_missing_ha_create_option = 3014;\n\n/// Server error specific to mysql. Error number: 3015, symbol: ER_ENGINE_OUT_OF_MEMORY.\nBOOST_INLINE_CONSTEXPR int er_engine_out_of_memory = 3015;\n\n/// Server error specific to mysql. Error number: 3016, symbol: ER_PASSWORD_EXPIRE_ANONYMOUS_USER.\nBOOST_INLINE_CONSTEXPR int er_password_expire_anonymous_user = 3016;\n\n/// Server error specific to mysql. Error number: 3017, symbol: ER_SLAVE_SQL_THREAD_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_slave_sql_thread_must_stop = 3017;\n\n/// Server error specific to mysql. Error number: 3018, symbol: ER_NO_FT_MATERIALIZED_SUBQUERY.\nBOOST_INLINE_CONSTEXPR int er_no_ft_materialized_subquery = 3018;\n\n/// Server error specific to mysql. Error number: 3019, symbol: ER_INNODB_UNDO_LOG_FULL.\nBOOST_INLINE_CONSTEXPR int er_innodb_undo_log_full = 3019;\n\n/// Server error specific to mysql. Error number: 3020, symbol: ER_INVALID_ARGUMENT_FOR_LOGARITHM.\nBOOST_INLINE_CONSTEXPR int er_invalid_argument_for_logarithm = 3020;\n\n/// Server error specific to mysql. Error number: 3021, symbol: ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_io_thread_must_stop = 3021;\n\n/// Server error specific to mysql. Error number: 3022, symbol: ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO.\nBOOST_INLINE_CONSTEXPR int er_warn_open_temp_tables_must_be_zero = 3022;\n\n/// Server error specific to mysql. Error number: 3023, symbol: ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS.\nBOOST_INLINE_CONSTEXPR int er_warn_only_master_log_file_no_pos = 3023;\n\n/// Server error specific to mysql. Error number: 3024, symbol: ER_QUERY_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_query_timeout = 3024;\n\n/// Server error specific to mysql. Error number: 3025, symbol: ER_NON_RO_SELECT_DISABLE_TIMER.\nBOOST_INLINE_CONSTEXPR int er_non_ro_select_disable_timer = 3025;\n\n/// Server error specific to mysql. Error number: 3026, symbol: ER_DUP_LIST_ENTRY.\nBOOST_INLINE_CONSTEXPR int er_dup_list_entry = 3026;\n\n/// Server error specific to mysql. Error number: 3027, symbol: ER_SQL_MODE_NO_EFFECT.\nBOOST_INLINE_CONSTEXPR int er_sql_mode_no_effect = 3027;\n\n/// Server error specific to mysql. Error number: 3028, symbol: ER_AGGREGATE_ORDER_FOR_UNION.\nBOOST_INLINE_CONSTEXPR int er_aggregate_order_for_union = 3028;\n\n/// Server error specific to mysql. Error number: 3029, symbol: ER_AGGREGATE_ORDER_NON_AGG_QUERY.\nBOOST_INLINE_CONSTEXPR int er_aggregate_order_non_agg_query = 3029;\n\n/// Server error specific to mysql. Error number: 3030, symbol: ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR.\nBOOST_INLINE_CONSTEXPR int er_slave_worker_stopped_previous_thd_error = 3030;\n\n/// Server error specific to mysql. Error number: 3031, symbol: ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER.\nBOOST_INLINE_CONSTEXPR int er_dont_support_slave_preserve_commit_order = 3031;\n\n/// Server error specific to mysql. Error number: 3032, symbol: ER_SERVER_OFFLINE_MODE.\nBOOST_INLINE_CONSTEXPR int er_server_offline_mode = 3032;\n\n/// Server error specific to mysql. Error number: 3033, symbol: ER_GIS_DIFFERENT_SRIDS.\nBOOST_INLINE_CONSTEXPR int er_gis_different_srids = 3033;\n\n/// Server error specific to mysql. Error number: 3034, symbol: ER_GIS_UNSUPPORTED_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_gis_unsupported_argument = 3034;\n\n/// Server error specific to mysql. Error number: 3035, symbol: ER_GIS_UNKNOWN_ERROR.\nBOOST_INLINE_CONSTEXPR int er_gis_unknown_error = 3035;\n\n/// Server error specific to mysql. Error number: 3036, symbol: ER_GIS_UNKNOWN_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_gis_unknown_exception = 3036;\n\n/// Server error specific to mysql. Error number: 3037, symbol: ER_GIS_INVALID_DATA.\nBOOST_INLINE_CONSTEXPR int er_gis_invalid_data = 3037;\n\n/// Server error specific to mysql. Error number: 3038, symbol: ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_empty_input_exception = 3038;\n\n/// Server error specific to mysql. Error number: 3039, symbol: ER_BOOST_GEOMETRY_CENTROID_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_centroid_exception = 3039;\n\n/// Server error specific to mysql. Error number: 3040, symbol: ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_overlay_invalid_input_exception = 3040;\n\n/// Server error specific to mysql. Error number: 3041, symbol: ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_turn_info_exception = 3041;\n\n/// Server error specific to mysql. Error number: 3042, symbol: ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_self_intersection_point_exception = 3042;\n\n/// Server error specific to mysql. Error number: 3043, symbol: ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_unknown_exception = 3043;\n\n/// Server error specific to mysql. Error number: 3044, symbol: ER_STD_BAD_ALLOC_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_bad_alloc_error = 3044;\n\n/// Server error specific to mysql. Error number: 3045, symbol: ER_STD_DOMAIN_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_domain_error = 3045;\n\n/// Server error specific to mysql. Error number: 3046, symbol: ER_STD_LENGTH_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_length_error = 3046;\n\n/// Server error specific to mysql. Error number: 3047, symbol: ER_STD_INVALID_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_std_invalid_argument = 3047;\n\n/// Server error specific to mysql. Error number: 3048, symbol: ER_STD_OUT_OF_RANGE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_out_of_range_error = 3048;\n\n/// Server error specific to mysql. Error number: 3049, symbol: ER_STD_OVERFLOW_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_overflow_error = 3049;\n\n/// Server error specific to mysql. Error number: 3050, symbol: ER_STD_RANGE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_range_error = 3050;\n\n/// Server error specific to mysql. Error number: 3051, symbol: ER_STD_UNDERFLOW_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_underflow_error = 3051;\n\n/// Server error specific to mysql. Error number: 3052, symbol: ER_STD_LOGIC_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_logic_error = 3052;\n\n/// Server error specific to mysql. Error number: 3053, symbol: ER_STD_RUNTIME_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_runtime_error = 3053;\n\n/// Server error specific to mysql. Error number: 3054, symbol: ER_STD_UNKNOWN_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_std_unknown_exception = 3054;\n\n/// Server error specific to mysql. Error number: 3055, symbol: ER_GIS_DATA_WRONG_ENDIANESS.\nBOOST_INLINE_CONSTEXPR int er_gis_data_wrong_endianess = 3055;\n\n/// Server error specific to mysql. Error number: 3056, symbol: ER_CHANGE_MASTER_PASSWORD_LENGTH.\nBOOST_INLINE_CONSTEXPR int er_change_master_password_length = 3056;\n\n/// Server error specific to mysql. Error number: 3057, symbol: ER_USER_LOCK_WRONG_NAME.\nBOOST_INLINE_CONSTEXPR int er_user_lock_wrong_name = 3057;\n\n/// Server error specific to mysql. Error number: 3058, symbol: ER_USER_LOCK_DEADLOCK.\nBOOST_INLINE_CONSTEXPR int er_user_lock_deadlock = 3058;\n\n/// Server error specific to mysql. Error number: 3059, symbol: ER_REPLACE_INACCESSIBLE_ROWS.\nBOOST_INLINE_CONSTEXPR int er_replace_inaccessible_rows = 3059;\n\n/// Server error specific to mysql. Error number: 3060, symbol: ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS.\nBOOST_INLINE_CONSTEXPR int er_alter_operation_not_supported_reason_gis = 3060;\n\n/// Server error specific to mysql. Error number: 3061, symbol: ER_ILLEGAL_USER_VAR.\nBOOST_INLINE_CONSTEXPR int er_illegal_user_var = 3061;\n\n/// Server error specific to mysql. Error number: 3062, symbol: ER_GTID_MODE_OFF.\nBOOST_INLINE_CONSTEXPR int er_gtid_mode_off = 3062;\n\n/// Server error specific to mysql. Error number: 3063, symbol: ER_UNSUPPORTED_BY_REPLICATION_THREAD.\nBOOST_INLINE_CONSTEXPR int er_unsupported_by_replication_thread = 3063;\n\n/// Server error specific to mysql. Error number: 3064, symbol: ER_INCORRECT_TYPE.\nBOOST_INLINE_CONSTEXPR int er_incorrect_type = 3064;\n\n/// Server error specific to mysql. Error number: 3065, symbol: ER_FIELD_IN_ORDER_NOT_SELECT.\nBOOST_INLINE_CONSTEXPR int er_field_in_order_not_select = 3065;\n\n/// Server error specific to mysql. Error number: 3066, symbol: ER_AGGREGATE_IN_ORDER_NOT_SELECT.\nBOOST_INLINE_CONSTEXPR int er_aggregate_in_order_not_select = 3066;\n\n/// Server error specific to mysql. Error number: 3067, symbol: ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN.\nBOOST_INLINE_CONSTEXPR int er_invalid_rpl_wild_table_filter_pattern = 3067;\n\n/// Server error specific to mysql. Error number: 3068, symbol: ER_NET_OK_PACKET_TOO_LARGE.\nBOOST_INLINE_CONSTEXPR int er_net_ok_packet_too_large = 3068;\n\n/// Server error specific to mysql. Error number: 3069, symbol: ER_INVALID_JSON_DATA.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_data = 3069;\n\n/// Server error specific to mysql. Error number: 3070, symbol: ER_INVALID_GEOJSON_MISSING_MEMBER.\nBOOST_INLINE_CONSTEXPR int er_invalid_geojson_missing_member = 3070;\n\n/// Server error specific to mysql. Error number: 3071, symbol: ER_INVALID_GEOJSON_WRONG_TYPE.\nBOOST_INLINE_CONSTEXPR int er_invalid_geojson_wrong_type = 3071;\n\n/// Server error specific to mysql. Error number: 3072, symbol: ER_INVALID_GEOJSON_UNSPECIFIED.\nBOOST_INLINE_CONSTEXPR int er_invalid_geojson_unspecified = 3072;\n\n/// Server error specific to mysql. Error number: 3073, symbol: ER_DIMENSION_UNSUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_dimension_unsupported = 3073;\n\n/// Server error specific to mysql. Error number: 3074, symbol: ER_SLAVE_CHANNEL_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_does_not_exist = 3074;\n\n/// Server error specific to mysql. Error number: 3075, symbol: ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT.\nBOOST_INLINE_CONSTEXPR int er_slave_multiple_channels_host_port = 3075;\n\n/// Server error specific to mysql. Error number: 3076, symbol: ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_name_invalid_or_too_long = 3076;\n\n/// Server error specific to mysql. Error number: 3077, symbol: ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY.\nBOOST_INLINE_CONSTEXPR int er_slave_new_channel_wrong_repository = 3077;\n\n/// Server error specific to mysql. Error number: 3078, symbol: ER_SLAVE_CHANNEL_DELETE.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_delete = 3078;\n\n/// Server error specific to mysql. Error number: 3079, symbol: ER_SLAVE_MULTIPLE_CHANNELS_CMD.\nBOOST_INLINE_CONSTEXPR int er_slave_multiple_channels_cmd = 3079;\n\n/// Server error specific to mysql. Error number: 3080, symbol: ER_SLAVE_MAX_CHANNELS_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_slave_max_channels_exceeded = 3080;\n\n/// Server error specific to mysql. Error number: 3081, symbol: ER_SLAVE_CHANNEL_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_must_stop = 3081;\n\n/// Server error specific to mysql. Error number: 3082, symbol: ER_SLAVE_CHANNEL_NOT_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_not_running = 3082;\n\n/// Server error specific to mysql. Error number: 3083, symbol: ER_SLAVE_CHANNEL_WAS_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_was_running = 3083;\n\n/// Server error specific to mysql. Error number: 3084, symbol: ER_SLAVE_CHANNEL_WAS_NOT_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_was_not_running = 3084;\n\n/// Server error specific to mysql. Error number: 3085, symbol: ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_sql_thread_must_stop = 3085;\n\n/// Server error specific to mysql. Error number: 3086, symbol: ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_sql_skip_counter = 3086;\n\n/// Server error specific to mysql. Error number: 3087, symbol: ER_WRONG_FIELD_WITH_GROUP_V2.\nBOOST_INLINE_CONSTEXPR int er_wrong_field_with_group_v2 = 3087;\n\n/// Server error specific to mysql. Error number: 3088, symbol: ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2.\nBOOST_INLINE_CONSTEXPR int er_mix_of_group_func_and_fields_v2 = 3088;\n\n/// Server error specific to mysql. Error number: 3089, symbol: ER_WARN_DEPRECATED_SYSVAR_UPDATE.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_sysvar_update = 3089;\n\n/// Server error specific to mysql. Error number: 3090, symbol: ER_WARN_DEPRECATED_SQLMODE.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_sqlmode = 3090;\n\n/// Server error specific to mysql. Error number: 3091, symbol: ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID.\nBOOST_INLINE_CONSTEXPR int er_cannot_log_partial_drop_database_with_gtid = 3091;\n\n/// Server error specific to mysql. Error number: 3092, symbol: ER_GROUP_REPLICATION_CONFIGURATION.\nBOOST_INLINE_CONSTEXPR int er_group_replication_configuration = 3092;\n\n/// Server error specific to mysql. Error number: 3093, symbol: ER_GROUP_REPLICATION_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_group_replication_running = 3093;\n\n/// Server error specific to mysql. Error number: 3094, symbol: ER_GROUP_REPLICATION_APPLIER_INIT_ERROR.\nBOOST_INLINE_CONSTEXPR int er_group_replication_applier_init_error = 3094;\n\n/// Server error specific to mysql. Error number: 3095, symbol: ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_group_replication_stop_applier_thread_timeout = 3095;\n\n/// Server error specific to mysql. Error number: 3096, symbol: ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR.\nBOOST_INLINE_CONSTEXPR int er_group_replication_communication_layer_session_error = 3096;\n\n/// Server error specific to mysql. Error number: 3097, symbol: ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR.\nBOOST_INLINE_CONSTEXPR int er_group_replication_communication_layer_join_error = 3097;\n\n/// Server error specific to mysql. Error number: 3098, symbol: ER_BEFORE_DML_VALIDATION_ERROR.\nBOOST_INLINE_CONSTEXPR int er_before_dml_validation_error = 3098;\n\n/// Server error specific to mysql. Error number: 3099, symbol: ER_PREVENTS_VARIABLE_WITHOUT_RBR.\nBOOST_INLINE_CONSTEXPR int er_prevents_variable_without_rbr = 3099;\n\n/// Server error specific to mysql. Error number: 3100, symbol: ER_RUN_HOOK_ERROR.\nBOOST_INLINE_CONSTEXPR int er_run_hook_error = 3100;\n\n/// Server error specific to mysql. Error number: 3101, symbol: ER_TRANSACTION_ROLLBACK_DURING_COMMIT.\nBOOST_INLINE_CONSTEXPR int er_transaction_rollback_during_commit = 3101;\n\n/// Server error specific to mysql. Error number: 3102, symbol: ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_generated_column_function_is_not_allowed = 3102;\n\n/// Server error specific to mysql. Error number: 3103, symbol: ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_unsupported_alter_inplace_on_virtual_column = 3103;\n\n/// Server error specific to mysql. Error number: 3104, symbol: ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_wrong_fk_option_for_generated_column = 3104;\n\n/// Server error specific to mysql. Error number: 3105, symbol: ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_non_default_value_for_generated_column = 3105;\n\n/// Server error specific to mysql. Error number: 3106, symbol: ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_unsupported_action_on_generated_column = 3106;\n\n/// Server error specific to mysql. Error number: 3107, symbol: ER_GENERATED_COLUMN_NON_PRIOR.\nBOOST_INLINE_CONSTEXPR int er_generated_column_non_prior = 3107;\n\n/// Server error specific to mysql. Error number: 3108, symbol: ER_DEPENDENT_BY_GENERATED_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_dependent_by_generated_column = 3108;\n\n/// Server error specific to mysql. Error number: 3109, symbol: ER_GENERATED_COLUMN_REF_AUTO_INC.\nBOOST_INLINE_CONSTEXPR int er_generated_column_ref_auto_inc = 3109;\n\n/// Server error specific to mysql. Error number: 3110, symbol: ER_FEATURE_NOT_AVAILABLE.\nBOOST_INLINE_CONSTEXPR int er_feature_not_available = 3110;\n\n/// Server error specific to mysql. Error number: 3111, symbol: ER_CANT_SET_GTID_MODE.\nBOOST_INLINE_CONSTEXPR int er_cant_set_gtid_mode = 3111;\n\n/// Server error specific to mysql. Error number: 3112, symbol: ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF.\nBOOST_INLINE_CONSTEXPR int er_cant_use_auto_position_with_gtid_mode_off = 3112;\n\n/// Server error specific to mysql. Error number: 3113, symbol: ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION.\nBOOST_INLINE_CONSTEXPR int er_cant_replicate_anonymous_with_auto_position = 3113;\n\n/// Server error specific to mysql. Error number: 3114, symbol: ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON.\nBOOST_INLINE_CONSTEXPR int er_cant_replicate_anonymous_with_gtid_mode_on = 3114;\n\n/// Server error specific to mysql. Error number: 3115, symbol: ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF.\nBOOST_INLINE_CONSTEXPR int er_cant_replicate_gtid_with_gtid_mode_off = 3115;\n\n/// Server error specific to mysql. Error number: 3116, symbol: ER_CANT_ENFORCE_GTID_CONSISTENCY_WITH_ONGOING_GTID_VIOLATING_TX.\nBOOST_INLINE_CONSTEXPR int er_cant_enforce_gtid_consistency_with_ongoing_gtid_violating_tx = 3116;\n\n/// Server error specific to mysql. Error number: 3117, symbol: ER_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TX.\nBOOST_INLINE_CONSTEXPR int er_enforce_gtid_consistency_warn_with_ongoing_gtid_violating_tx = 3117;\n\n/// Server error specific to mysql. Error number: 3118, symbol: ER_ACCOUNT_HAS_BEEN_LOCKED.\nBOOST_INLINE_CONSTEXPR int er_account_has_been_locked = 3118;\n\n/// Server error specific to mysql. Error number: 3119, symbol: ER_WRONG_TABLESPACE_NAME.\nBOOST_INLINE_CONSTEXPR int er_wrong_tablespace_name = 3119;\n\n/// Server error specific to mysql. Error number: 3120, symbol: ER_TABLESPACE_IS_NOT_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_tablespace_is_not_empty = 3120;\n\n/// Server error specific to mysql. Error number: 3121, symbol: ER_WRONG_FILE_NAME.\nBOOST_INLINE_CONSTEXPR int er_wrong_file_name = 3121;\n\n/// Server error specific to mysql. Error number: 3122, symbol: ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION.\nBOOST_INLINE_CONSTEXPR int er_boost_geometry_inconsistent_turns_exception = 3122;\n\n/// Server error specific to mysql. Error number: 3123, symbol: ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR.\nBOOST_INLINE_CONSTEXPR int er_warn_optimizer_hint_syntax_error = 3123;\n\n/// Server error specific to mysql. Error number: 3124, symbol: ER_WARN_BAD_MAX_EXECUTION_TIME.\nBOOST_INLINE_CONSTEXPR int er_warn_bad_max_execution_time = 3124;\n\n/// Server error specific to mysql. Error number: 3125, symbol: ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME.\nBOOST_INLINE_CONSTEXPR int er_warn_unsupported_max_execution_time = 3125;\n\n/// Server error specific to mysql. Error number: 3126, symbol: ER_WARN_CONFLICTING_HINT.\nBOOST_INLINE_CONSTEXPR int er_warn_conflicting_hint = 3126;\n\n/// Server error specific to mysql. Error number: 3127, symbol: ER_WARN_UNKNOWN_QB_NAME.\nBOOST_INLINE_CONSTEXPR int er_warn_unknown_qb_name = 3127;\n\n/// Server error specific to mysql. Error number: 3128, symbol: ER_UNRESOLVED_HINT_NAME.\nBOOST_INLINE_CONSTEXPR int er_unresolved_hint_name = 3128;\n\n/// Server error specific to mysql. Error number: 3129, symbol: ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE.\nBOOST_INLINE_CONSTEXPR int er_warn_on_modifying_gtid_executed_table = 3129;\n\n/// Server error specific to mysql. Error number: 3130, symbol: ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_pluggable_protocol_command_not_supported = 3130;\n\n/// Server error specific to mysql. Error number: 3131, symbol: ER_LOCKING_SERVICE_WRONG_NAME.\nBOOST_INLINE_CONSTEXPR int er_locking_service_wrong_name = 3131;\n\n/// Server error specific to mysql. Error number: 3132, symbol: ER_LOCKING_SERVICE_DEADLOCK.\nBOOST_INLINE_CONSTEXPR int er_locking_service_deadlock = 3132;\n\n/// Server error specific to mysql. Error number: 3133, symbol: ER_LOCKING_SERVICE_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_locking_service_timeout = 3133;\n\n/// Server error specific to mysql. Error number: 3134, symbol: ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED.\nBOOST_INLINE_CONSTEXPR int er_gis_max_points_in_geometry_overflowed = 3134;\n\n/// Server error specific to mysql. Error number: 3135, symbol: ER_SQL_MODE_MERGED.\nBOOST_INLINE_CONSTEXPR int er_sql_mode_merged = 3135;\n\n/// Server error specific to mysql. Error number: 3136, symbol: ER_VTOKEN_PLUGIN_TOKEN_MISMATCH.\nBOOST_INLINE_CONSTEXPR int er_vtoken_plugin_token_mismatch = 3136;\n\n/// Server error specific to mysql. Error number: 3137, symbol: ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_vtoken_plugin_token_not_found = 3137;\n\n/// Server error specific to mysql. Error number: 3138, symbol: ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID.\nBOOST_INLINE_CONSTEXPR int er_cant_set_variable_when_owning_gtid = 3138;\n\n/// Server error specific to mysql. Error number: 3139, symbol: ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_slave_channel_operation_not_allowed = 3139;\n\n/// Server error specific to mysql. Error number: 3140, symbol: ER_INVALID_JSON_TEXT.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_text = 3140;\n\n/// Server error specific to mysql. Error number: 3141, symbol: ER_INVALID_JSON_TEXT_IN_PARAM.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_text_in_param = 3141;\n\n/// Server error specific to mysql. Error number: 3142, symbol: ER_INVALID_JSON_BINARY_DATA.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_binary_data = 3142;\n\n/// Server error specific to mysql. Error number: 3143, symbol: ER_INVALID_JSON_PATH.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_path = 3143;\n\n/// Server error specific to mysql. Error number: 3144, symbol: ER_INVALID_JSON_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_charset = 3144;\n\n/// Server error specific to mysql. Error number: 3145, symbol: ER_INVALID_JSON_CHARSET_IN_FUNCTION.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_charset_in_function = 3145;\n\n/// Server error specific to mysql. Error number: 3146, symbol: ER_INVALID_TYPE_FOR_JSON.\nBOOST_INLINE_CONSTEXPR int er_invalid_type_for_json = 3146;\n\n/// Server error specific to mysql. Error number: 3147, symbol: ER_INVALID_CAST_TO_JSON.\nBOOST_INLINE_CONSTEXPR int er_invalid_cast_to_json = 3147;\n\n/// Server error specific to mysql. Error number: 3148, symbol: ER_INVALID_JSON_PATH_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_path_charset = 3148;\n\n/// Server error specific to mysql. Error number: 3149, symbol: ER_INVALID_JSON_PATH_WILDCARD.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_path_wildcard = 3149;\n\n/// Server error specific to mysql. Error number: 3150, symbol: ER_JSON_VALUE_TOO_BIG.\nBOOST_INLINE_CONSTEXPR int er_json_value_too_big = 3150;\n\n/// Server error specific to mysql. Error number: 3151, symbol: ER_JSON_KEY_TOO_BIG.\nBOOST_INLINE_CONSTEXPR int er_json_key_too_big = 3151;\n\n/// Server error specific to mysql. Error number: 3152, symbol: ER_JSON_USED_AS_KEY.\nBOOST_INLINE_CONSTEXPR int er_json_used_as_key = 3152;\n\n/// Server error specific to mysql. Error number: 3153, symbol: ER_JSON_VACUOUS_PATH.\nBOOST_INLINE_CONSTEXPR int er_json_vacuous_path = 3153;\n\n/// Server error specific to mysql. Error number: 3154, symbol: ER_JSON_BAD_ONE_OR_ALL_ARG.\nBOOST_INLINE_CONSTEXPR int er_json_bad_one_or_all_arg = 3154;\n\n/// Server error specific to mysql. Error number: 3155, symbol: ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_numeric_json_value_out_of_range = 3155;\n\n/// Server error specific to mysql. Error number: 3156, symbol: ER_INVALID_JSON_VALUE_FOR_CAST.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_value_for_cast = 3156;\n\n/// Server error specific to mysql. Error number: 3157, symbol: ER_JSON_DOCUMENT_TOO_DEEP.\nBOOST_INLINE_CONSTEXPR int er_json_document_too_deep = 3157;\n\n/// Server error specific to mysql. Error number: 3158, symbol: ER_JSON_DOCUMENT_NULL_KEY.\nBOOST_INLINE_CONSTEXPR int er_json_document_null_key = 3158;\n\n/// Server error specific to mysql. Error number: 3159, symbol: ER_SECURE_TRANSPORT_REQUIRED.\nBOOST_INLINE_CONSTEXPR int er_secure_transport_required = 3159;\n\n/// Server error specific to mysql. Error number: 3160, symbol: ER_NO_SECURE_TRANSPORTS_CONFIGURED.\nBOOST_INLINE_CONSTEXPR int er_no_secure_transports_configured = 3160;\n\n/// Server error specific to mysql. Error number: 3161, symbol: ER_DISABLED_STORAGE_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_disabled_storage_engine = 3161;\n\n/// Server error specific to mysql. Error number: 3162, symbol: ER_USER_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_user_does_not_exist = 3162;\n\n/// Server error specific to mysql. Error number: 3163, symbol: ER_USER_ALREADY_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_user_already_exists = 3163;\n\n/// Server error specific to mysql. Error number: 3164, symbol: ER_AUDIT_API_ABORT.\nBOOST_INLINE_CONSTEXPR int er_audit_api_abort = 3164;\n\n/// Server error specific to mysql. Error number: 3165, symbol: ER_INVALID_JSON_PATH_ARRAY_CELL.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_path_array_cell = 3165;\n\n/// Server error specific to mysql. Error number: 3166, symbol: ER_BUFPOOL_RESIZE_INPROGRESS.\nBOOST_INLINE_CONSTEXPR int er_bufpool_resize_inprogress = 3166;\n\n/// Server error specific to mysql. Error number: 3167, symbol: ER_FEATURE_DISABLED_SEE_DOC.\nBOOST_INLINE_CONSTEXPR int er_feature_disabled_see_doc = 3167;\n\n/// Server error specific to mysql. Error number: 3168, symbol: ER_SERVER_ISNT_AVAILABLE.\nBOOST_INLINE_CONSTEXPR int er_server_isnt_available = 3168;\n\n/// Server error specific to mysql. Error number: 3169, symbol: ER_SESSION_WAS_KILLED.\nBOOST_INLINE_CONSTEXPR int er_session_was_killed = 3169;\n\n/// Server error specific to mysql. Error number: 3170, symbol: ER_CAPACITY_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_capacity_exceeded = 3170;\n\n/// Server error specific to mysql. Error number: 3171, symbol: ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER.\nBOOST_INLINE_CONSTEXPR int er_capacity_exceeded_in_range_optimizer = 3171;\n\n/// Server error specific to mysql. Error number: 3172, symbol: ER_TABLE_NEEDS_UPG_PART.\nBOOST_INLINE_CONSTEXPR int er_table_needs_upg_part = 3172;\n\n/// Server error specific to mysql. Error number: 3173, symbol: ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID.\nBOOST_INLINE_CONSTEXPR int er_cant_wait_for_executed_gtid_set_while_owning_a_gtid = 3173;\n\n/// Server error specific to mysql. Error number: 3174, symbol: ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL.\nBOOST_INLINE_CONSTEXPR int er_cannot_add_foreign_base_col_virtual = 3174;\n\n/// Server error specific to mysql. Error number: 3175, symbol: ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT.\nBOOST_INLINE_CONSTEXPR int er_cannot_create_virtual_index_constraint = 3175;\n\n/// Server error specific to mysql. Error number: 3176, symbol: ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE.\nBOOST_INLINE_CONSTEXPR int er_error_on_modifying_gtid_executed_table = 3176;\n\n/// Server error specific to mysql. Error number: 3177, symbol: ER_LOCK_REFUSED_BY_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_lock_refused_by_engine = 3177;\n\n/// Server error specific to mysql. Error number: 3178, symbol: ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_unsupported_alter_online_on_virtual_column = 3178;\n\n/// Server error specific to mysql. Error number: 3179, symbol: ER_MASTER_KEY_ROTATION_NOT_SUPPORTED_BY_SE.\nBOOST_INLINE_CONSTEXPR int er_master_key_rotation_not_supported_by_se = 3179;\n\n/// Server error specific to mysql. Error number: 3180, symbol: ER_MASTER_KEY_ROTATION_ERROR_BY_SE.\nBOOST_INLINE_CONSTEXPR int er_master_key_rotation_error_by_se = 3180;\n\n/// Server error specific to mysql. Error number: 3181, symbol: ER_MASTER_KEY_ROTATION_BINLOG_FAILED.\nBOOST_INLINE_CONSTEXPR int er_master_key_rotation_binlog_failed = 3181;\n\n/// Server error specific to mysql. Error number: 3182, symbol: ER_MASTER_KEY_ROTATION_SE_UNAVAILABLE.\nBOOST_INLINE_CONSTEXPR int er_master_key_rotation_se_unavailable = 3182;\n\n/// Server error specific to mysql. Error number: 3183, symbol: ER_TABLESPACE_CANNOT_ENCRYPT.\nBOOST_INLINE_CONSTEXPR int er_tablespace_cannot_encrypt = 3183;\n\n/// Server error specific to mysql. Error number: 3184, symbol: ER_INVALID_ENCRYPTION_OPTION.\nBOOST_INLINE_CONSTEXPR int er_invalid_encryption_option = 3184;\n\n/// Server error specific to mysql. Error number: 3185, symbol: ER_CANNOT_FIND_KEY_IN_KEYRING.\nBOOST_INLINE_CONSTEXPR int er_cannot_find_key_in_keyring = 3185;\n\n/// Server error specific to mysql. Error number: 3186, symbol: ER_CAPACITY_EXCEEDED_IN_PARSER.\nBOOST_INLINE_CONSTEXPR int er_capacity_exceeded_in_parser = 3186;\n\n/// Server error specific to mysql. Error number: 3187, symbol: ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE.\nBOOST_INLINE_CONSTEXPR int er_unsupported_alter_encryption_inplace = 3187;\n\n/// Server error specific to mysql. Error number: 3188, symbol: ER_KEYRING_UDF_KEYRING_SERVICE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_keyring_udf_keyring_service_error = 3188;\n\n/// Server error specific to mysql. Error number: 3189, symbol: ER_USER_COLUMN_OLD_LENGTH.\nBOOST_INLINE_CONSTEXPR int er_user_column_old_length = 3189;\n\n/// Server error specific to mysql. Error number: 3190, symbol: ER_CANT_RESET_MASTER.\nBOOST_INLINE_CONSTEXPR int er_cant_reset_master = 3190;\n\n/// Server error specific to mysql. Error number: 3191, symbol: ER_GROUP_REPLICATION_MAX_GROUP_SIZE.\nBOOST_INLINE_CONSTEXPR int er_group_replication_max_group_size = 3191;\n\n/// Server error specific to mysql. Error number: 3192, symbol: ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED.\nBOOST_INLINE_CONSTEXPR int er_cannot_add_foreign_base_col_stored = 3192;\n\n/// Server error specific to mysql. Error number: 3193, symbol: ER_TABLE_REFERENCED.\nBOOST_INLINE_CONSTEXPR int er_table_referenced = 3193;\n\n/// Server error specific to mysql. Error number: 3194, symbol: ER_PARTITION_ENGINE_DEPRECATED_FOR_TABLE.\nBOOST_INLINE_CONSTEXPR int er_partition_engine_deprecated_for_table = 3194;\n\n/// Server error specific to mysql. Error number: 3195, symbol: ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID_ZERO.\nBOOST_INLINE_CONSTEXPR int er_warn_using_geomfromwkb_to_set_srid_zero = 3195;\n\n/// Server error specific to mysql. Error number: 3196, symbol: ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID.\nBOOST_INLINE_CONSTEXPR int er_warn_using_geomfromwkb_to_set_srid = 3196;\n\n/// Server error specific to mysql. Error number: 3197, symbol: ER_XA_RETRY.\nBOOST_INLINE_CONSTEXPR int er_xa_retry = 3197;\n\n/// Server error specific to mysql. Error number: 3198, symbol: ER_KEYRING_AWS_UDF_AWS_KMS_ERROR.\nBOOST_INLINE_CONSTEXPR int er_keyring_aws_udf_aws_kms_error = 3198;\n\n/// Server error specific to mysql. Error number: 3199, symbol: ER_BINLOG_UNSAFE_XA.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_xa = 3199;\n\n/// Server error specific to mysql. Error number: 3200, symbol: ER_UDF_ERROR.\nBOOST_INLINE_CONSTEXPR int er_udf_error = 3200;\n\n/// Server error specific to mysql. Error number: 3201, symbol: ER_KEYRING_MIGRATION_FAILURE.\nBOOST_INLINE_CONSTEXPR int er_keyring_migration_failure = 3201;\n\n/// Server error specific to mysql. Error number: 3202, symbol: ER_KEYRING_ACCESS_DENIED_ERROR.\nBOOST_INLINE_CONSTEXPR int er_keyring_access_denied_error = 3202;\n\n/// Server error specific to mysql. Error number: 3203, symbol: ER_KEYRING_MIGRATION_STATUS.\nBOOST_INLINE_CONSTEXPR int er_keyring_migration_status = 3203;\n\n/// Server error specific to mysql. Error number: 3204, symbol: ER_PLUGIN_FAILED_TO_OPEN_TABLES.\nBOOST_INLINE_CONSTEXPR int er_plugin_failed_to_open_tables = 3204;\n\n/// Server error specific to mysql. Error number: 3205, symbol: ER_PLUGIN_FAILED_TO_OPEN_TABLE.\nBOOST_INLINE_CONSTEXPR int er_plugin_failed_to_open_table = 3205;\n\n/// Server error specific to mysql. Error number: 3206, symbol: ER_AUDIT_LOG_NO_KEYRING_PLUGIN_INSTALLED.\nBOOST_INLINE_CONSTEXPR int er_audit_log_no_keyring_plugin_installed = 3206;\n\n/// Server error specific to mysql. Error number: 3207, symbol: ER_AUDIT_LOG_ENCRYPTION_PASSWORD_HAS_NOT_BEEN_SET.\nBOOST_INLINE_CONSTEXPR int er_audit_log_encryption_password_has_not_been_set = 3207;\n\n/// Server error specific to mysql. Error number: 3208, symbol: ER_AUDIT_LOG_COULD_NOT_CREATE_AES_KEY.\nBOOST_INLINE_CONSTEXPR int er_audit_log_could_not_create_aes_key = 3208;\n\n/// Server error specific to mysql. Error number: 3209, symbol: ER_AUDIT_LOG_ENCRYPTION_PASSWORD_CANNOT_BE_FETCHED.\nBOOST_INLINE_CONSTEXPR int er_audit_log_encryption_password_cannot_be_fetched = 3209;\n\n/// Server error specific to mysql. Error number: 3210, symbol: ER_AUDIT_LOG_JSON_FILTERING_NOT_ENABLED.\nBOOST_INLINE_CONSTEXPR int er_audit_log_json_filtering_not_enabled = 3210;\n\n/// Server error specific to mysql. Error number: 3211, symbol: ER_AUDIT_LOG_UDF_INSUFFICIENT_PRIVILEGE.\nBOOST_INLINE_CONSTEXPR int er_audit_log_udf_insufficient_privilege = 3211;\n\n/// Server error specific to mysql. Error number: 3212, symbol: ER_AUDIT_LOG_SUPER_PRIVILEGE_REQUIRED.\nBOOST_INLINE_CONSTEXPR int er_audit_log_super_privilege_required = 3212;\n\n/// Server error specific to mysql. Error number: 3213, symbol: ER_COULD_NOT_REINITIALIZE_AUDIT_LOG_FILTERS.\nBOOST_INLINE_CONSTEXPR int er_could_not_reinitialize_audit_log_filters = 3213;\n\n/// Server error specific to mysql. Error number: 3214, symbol: ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_TYPE.\nBOOST_INLINE_CONSTEXPR int er_audit_log_udf_invalid_argument_type = 3214;\n\n/// Server error specific to mysql. Error number: 3215, symbol: ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_COUNT.\nBOOST_INLINE_CONSTEXPR int er_audit_log_udf_invalid_argument_count = 3215;\n\n/// Server error specific to mysql. Error number: 3216, symbol: ER_AUDIT_LOG_HAS_NOT_BEEN_INSTALLED.\nBOOST_INLINE_CONSTEXPR int er_audit_log_has_not_been_installed = 3216;\n\n/// Server error specific to mysql. Error number: 3217, symbol: ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_TYPE.\nBOOST_INLINE_CONSTEXPR int er_audit_log_udf_read_invalid_max_array_length_arg_type = 3217;\n\n/// Server error specific to mysql. Error number: 3218, symbol: ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_VALUE.\nBOOST_INLINE_CONSTEXPR int er_audit_log_udf_read_invalid_max_array_length_arg_value = 3218;\n\n/// Server error specific to mysql. Error number: 3219, symbol: ER_AUDIT_LOG_JSON_FILTER_PARSING_ERROR.\nBOOST_INLINE_CONSTEXPR int er_audit_log_json_filter_parsing_error = 3219;\n\n/// Server error specific to mysql. Error number: 3220, symbol: ER_AUDIT_LOG_JSON_FILTER_NAME_CANNOT_BE_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_audit_log_json_filter_name_cannot_be_empty = 3220;\n\n/// Server error specific to mysql. Error number: 3221, symbol: ER_AUDIT_LOG_JSON_USER_NAME_CANNOT_BE_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_audit_log_json_user_name_cannot_be_empty = 3221;\n\n/// Server error specific to mysql. Error number: 3222, symbol: ER_AUDIT_LOG_JSON_FILTER_DOES_NOT_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_audit_log_json_filter_does_not_exists = 3222;\n\n/// Server error specific to mysql. Error number: 3223, symbol: ER_AUDIT_LOG_USER_FIRST_CHARACTER_MUST_BE_ALPHANUMERIC.\nBOOST_INLINE_CONSTEXPR int er_audit_log_user_first_character_must_be_alphanumeric = 3223;\n\n/// Server error specific to mysql. Error number: 3224, symbol: ER_AUDIT_LOG_USER_NAME_INVALID_CHARACTER.\nBOOST_INLINE_CONSTEXPR int er_audit_log_user_name_invalid_character = 3224;\n\n/// Server error specific to mysql. Error number: 3225, symbol: ER_AUDIT_LOG_HOST_NAME_INVALID_CHARACTER.\nBOOST_INLINE_CONSTEXPR int er_audit_log_host_name_invalid_character = 3225;\n\n/// Server error specific to mysql. Error number: 3226, symbol: OBSOLETE_WARN_DEPRECATED_MAXDB_SQL_MODE_FOR_TIMESTAMP.\nBOOST_INLINE_CONSTEXPR int obsolete_warn_deprecated_maxdb_sql_mode_for_timestamp = 3226;\n\n/// Server error specific to mysql. Error number: 3228, symbol: ER_CANT_OPEN_ERROR_LOG.\nBOOST_INLINE_CONSTEXPR int er_cant_open_error_log = 3228;\n\n/// Server error specific to mysql. Error number: 3230, symbol: ER_CANT_START_SERVER_NAMED_PIPE.\nBOOST_INLINE_CONSTEXPR int er_cant_start_server_named_pipe = 3230;\n\n/// Server error specific to mysql. Error number: 3231, symbol: ER_WRITE_SET_EXCEEDS_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_write_set_exceeds_limit = 3231;\n\n/// Server error specific to mysql. Error number: 3232, symbol: ER_DEPRECATED_TLS_VERSION_SESSION.\nBOOST_INLINE_CONSTEXPR int er_deprecated_tls_version_session = 3232;\n\n/// Server error specific to mysql. Error number: 3233, symbol: ER_WARN_DEPRECATED_TLS_VERSION.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_tls_version = 3233;\n\n/// Server error specific to mysql. Error number: 3234, symbol: ER_WARN_WRONG_NATIVE_TABLE_STRUCTURE.\nBOOST_INLINE_CONSTEXPR int er_warn_wrong_native_table_structure = 3234;\n\n/// Server error specific to mysql. Error number: 3235, symbol: ER_AES_INVALID_KDF_NAME.\nBOOST_INLINE_CONSTEXPR int er_aes_invalid_kdf_name = 3235;\n\n/// Server error specific to mysql. Error number: 3236, symbol: ER_AES_INVALID_KDF_ITERATIONS.\nBOOST_INLINE_CONSTEXPR int er_aes_invalid_kdf_iterations = 3236;\n\n/// Server error specific to mysql. Error number: 3237, symbol: WARN_AES_KEY_SIZE.\nBOOST_INLINE_CONSTEXPR int warn_aes_key_size = 3237;\n\n/// Server error specific to mysql. Error number: 3238, symbol: ER_AES_INVALID_KDF_OPTION_SIZE.\nBOOST_INLINE_CONSTEXPR int er_aes_invalid_kdf_option_size = 3238;\n\n/// Server error specific to mysql. Error number: 3500, symbol: ER_UNSUPPORT_COMPRESSED_TEMPORARY_TABLE.\nBOOST_INLINE_CONSTEXPR int er_unsupport_compressed_temporary_table = 3500;\n\n/// Server error specific to mysql. Error number: 3501, symbol: ER_ACL_OPERATION_FAILED.\nBOOST_INLINE_CONSTEXPR int er_acl_operation_failed = 3501;\n\n/// Server error specific to mysql. Error number: 3502, symbol: ER_UNSUPPORTED_INDEX_ALGORITHM.\nBOOST_INLINE_CONSTEXPR int er_unsupported_index_algorithm = 3502;\n\n/// Server error specific to mysql. Error number: 3503, symbol: ER_NO_SUCH_DB.\nBOOST_INLINE_CONSTEXPR int er_no_such_db = 3503;\n\n/// Server error specific to mysql. Error number: 3504, symbol: ER_TOO_BIG_ENUM.\nBOOST_INLINE_CONSTEXPR int er_too_big_enum = 3504;\n\n/// Server error specific to mysql. Error number: 3505, symbol: ER_TOO_LONG_SET_ENUM_VALUE.\nBOOST_INLINE_CONSTEXPR int er_too_long_set_enum_value = 3505;\n\n/// Server error specific to mysql. Error number: 3506, symbol: ER_INVALID_DD_OBJECT.\nBOOST_INLINE_CONSTEXPR int er_invalid_dd_object = 3506;\n\n/// Server error specific to mysql. Error number: 3507, symbol: ER_UPDATING_DD_TABLE.\nBOOST_INLINE_CONSTEXPR int er_updating_dd_table = 3507;\n\n/// Server error specific to mysql. Error number: 3508, symbol: ER_INVALID_DD_OBJECT_ID.\nBOOST_INLINE_CONSTEXPR int er_invalid_dd_object_id = 3508;\n\n/// Server error specific to mysql. Error number: 3509, symbol: ER_INVALID_DD_OBJECT_NAME.\nBOOST_INLINE_CONSTEXPR int er_invalid_dd_object_name = 3509;\n\n/// Server error specific to mysql. Error number: 3510, symbol: ER_TABLESPACE_MISSING_WITH_NAME.\nBOOST_INLINE_CONSTEXPR int er_tablespace_missing_with_name = 3510;\n\n/// Server error specific to mysql. Error number: 3511, symbol: ER_TOO_LONG_ROUTINE_COMMENT.\nBOOST_INLINE_CONSTEXPR int er_too_long_routine_comment = 3511;\n\n/// Server error specific to mysql. Error number: 3512, symbol: ER_SP_LOAD_FAILED.\nBOOST_INLINE_CONSTEXPR int er_sp_load_failed = 3512;\n\n/// Server error specific to mysql. Error number: 3513, symbol: ER_INVALID_BITWISE_OPERANDS_SIZE.\nBOOST_INLINE_CONSTEXPR int er_invalid_bitwise_operands_size = 3513;\n\n/// Server error specific to mysql. Error number: 3514, symbol: ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE.\nBOOST_INLINE_CONSTEXPR int er_invalid_bitwise_aggregate_operands_size = 3514;\n\n/// Server error specific to mysql. Error number: 3515, symbol: ER_WARN_UNSUPPORTED_HINT.\nBOOST_INLINE_CONSTEXPR int er_warn_unsupported_hint = 3515;\n\n/// Server error specific to mysql. Error number: 3516, symbol: ER_UNEXPECTED_GEOMETRY_TYPE.\nBOOST_INLINE_CONSTEXPR int er_unexpected_geometry_type = 3516;\n\n/// Server error specific to mysql. Error number: 3517, symbol: ER_SRS_PARSE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_srs_parse_error = 3517;\n\n/// Server error specific to mysql. Error number: 3518, symbol: ER_SRS_PROJ_PARAMETER_MISSING.\nBOOST_INLINE_CONSTEXPR int er_srs_proj_parameter_missing = 3518;\n\n/// Server error specific to mysql. Error number: 3519, symbol: ER_WARN_SRS_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_warn_srs_not_found = 3519;\n\n/// Server error specific to mysql. Error number: 3520, symbol: ER_SRS_NOT_CARTESIAN.\nBOOST_INLINE_CONSTEXPR int er_srs_not_cartesian = 3520;\n\n/// Server error specific to mysql. Error number: 3521, symbol: ER_SRS_NOT_CARTESIAN_UNDEFINED.\nBOOST_INLINE_CONSTEXPR int er_srs_not_cartesian_undefined = 3521;\n\n/// Server error specific to mysql. Error number: 3522, symbol: ER_PK_INDEX_CANT_BE_INVISIBLE.\nBOOST_INLINE_CONSTEXPR int er_pk_index_cant_be_invisible = 3522;\n\n/// Server error specific to mysql. Error number: 3523, symbol: ER_UNKNOWN_AUTHID.\nBOOST_INLINE_CONSTEXPR int er_unknown_authid = 3523;\n\n/// Server error specific to mysql. Error number: 3524, symbol: ER_FAILED_ROLE_GRANT.\nBOOST_INLINE_CONSTEXPR int er_failed_role_grant = 3524;\n\n/// Server error specific to mysql. Error number: 3525, symbol: ER_OPEN_ROLE_TABLES.\nBOOST_INLINE_CONSTEXPR int er_open_role_tables = 3525;\n\n/// Server error specific to mysql. Error number: 3526, symbol: ER_FAILED_DEFAULT_ROLES.\nBOOST_INLINE_CONSTEXPR int er_failed_default_roles = 3526;\n\n/// Server error specific to mysql. Error number: 3527, symbol: ER_COMPONENTS_NO_SCHEME.\nBOOST_INLINE_CONSTEXPR int er_components_no_scheme = 3527;\n\n/// Server error specific to mysql. Error number: 3528, symbol: ER_COMPONENTS_NO_SCHEME_SERVICE.\nBOOST_INLINE_CONSTEXPR int er_components_no_scheme_service = 3528;\n\n/// Server error specific to mysql. Error number: 3529, symbol: ER_COMPONENTS_CANT_LOAD.\nBOOST_INLINE_CONSTEXPR int er_components_cant_load = 3529;\n\n/// Server error specific to mysql. Error number: 3530, symbol: ER_ROLE_NOT_GRANTED.\nBOOST_INLINE_CONSTEXPR int er_role_not_granted = 3530;\n\n/// Server error specific to mysql. Error number: 3531, symbol: ER_FAILED_REVOKE_ROLE.\nBOOST_INLINE_CONSTEXPR int er_failed_revoke_role = 3531;\n\n/// Server error specific to mysql. Error number: 3532, symbol: ER_RENAME_ROLE.\nBOOST_INLINE_CONSTEXPR int er_rename_role = 3532;\n\n/// Server error specific to mysql. Error number: 3533, symbol: ER_COMPONENTS_CANT_ACQUIRE_SERVICE_IMPLEMENTATION.\nBOOST_INLINE_CONSTEXPR int er_components_cant_acquire_service_implementation = 3533;\n\n/// Server error specific to mysql. Error number: 3534, symbol: ER_COMPONENTS_CANT_SATISFY_DEPENDENCY.\nBOOST_INLINE_CONSTEXPR int er_components_cant_satisfy_dependency = 3534;\n\n/// Server error specific to mysql. Error number: 3535, symbol: ER_COMPONENTS_LOAD_CANT_REGISTER_SERVICE_IMPLEMENTATION.\nBOOST_INLINE_CONSTEXPR int er_components_load_cant_register_service_implementation = 3535;\n\n/// Server error specific to mysql. Error number: 3536, symbol: ER_COMPONENTS_LOAD_CANT_INITIALIZE.\nBOOST_INLINE_CONSTEXPR int er_components_load_cant_initialize = 3536;\n\n/// Server error specific to mysql. Error number: 3537, symbol: ER_COMPONENTS_UNLOAD_NOT_LOADED.\nBOOST_INLINE_CONSTEXPR int er_components_unload_not_loaded = 3537;\n\n/// Server error specific to mysql. Error number: 3538, symbol: ER_COMPONENTS_UNLOAD_CANT_DEINITIALIZE.\nBOOST_INLINE_CONSTEXPR int er_components_unload_cant_deinitialize = 3538;\n\n/// Server error specific to mysql. Error number: 3539, symbol: ER_COMPONENTS_CANT_RELEASE_SERVICE.\nBOOST_INLINE_CONSTEXPR int er_components_cant_release_service = 3539;\n\n/// Server error specific to mysql. Error number: 3540, symbol: ER_COMPONENTS_UNLOAD_CANT_UNREGISTER_SERVICE.\nBOOST_INLINE_CONSTEXPR int er_components_unload_cant_unregister_service = 3540;\n\n/// Server error specific to mysql. Error number: 3541, symbol: ER_COMPONENTS_CANT_UNLOAD.\nBOOST_INLINE_CONSTEXPR int er_components_cant_unload = 3541;\n\n/// Server error specific to mysql. Error number: 3542, symbol: ER_WARN_UNLOAD_THE_NOT_PERSISTED.\nBOOST_INLINE_CONSTEXPR int er_warn_unload_the_not_persisted = 3542;\n\n/// Server error specific to mysql. Error number: 3543, symbol: ER_COMPONENT_TABLE_INCORRECT.\nBOOST_INLINE_CONSTEXPR int er_component_table_incorrect = 3543;\n\n/// Server error specific to mysql. Error number: 3544, symbol: ER_COMPONENT_MANIPULATE_ROW_FAILED.\nBOOST_INLINE_CONSTEXPR int er_component_manipulate_row_failed = 3544;\n\n/// Server error specific to mysql. Error number: 3545, symbol: ER_COMPONENTS_UNLOAD_DUPLICATE_IN_GROUP.\nBOOST_INLINE_CONSTEXPR int er_components_unload_duplicate_in_group = 3545;\n\n/// Server error specific to mysql. Error number: 3546, symbol: ER_CANT_SET_GTID_PURGED_DUE_SETS_CONSTRAINTS.\nBOOST_INLINE_CONSTEXPR int er_cant_set_gtid_purged_due_sets_constraints = 3546;\n\n/// Server error specific to mysql. Error number: 3547, symbol: ER_CANNOT_LOCK_USER_MANAGEMENT_CACHES.\nBOOST_INLINE_CONSTEXPR int er_cannot_lock_user_management_caches = 3547;\n\n/// Server error specific to mysql. Error number: 3548, symbol: ER_SRS_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_srs_not_found = 3548;\n\n/// Server error specific to mysql. Error number: 3549, symbol: ER_VARIABLE_NOT_PERSISTED.\nBOOST_INLINE_CONSTEXPR int er_variable_not_persisted = 3549;\n\n/// Server error specific to mysql. Error number: 3550, symbol: ER_IS_QUERY_INVALID_CLAUSE.\nBOOST_INLINE_CONSTEXPR int er_is_query_invalid_clause = 3550;\n\n/// Server error specific to mysql. Error number: 3551, symbol: ER_UNABLE_TO_STORE_STATISTICS.\nBOOST_INLINE_CONSTEXPR int er_unable_to_store_statistics = 3551;\n\n/// Server error specific to mysql. Error number: 3552, symbol: ER_NO_SYSTEM_SCHEMA_ACCESS.\nBOOST_INLINE_CONSTEXPR int er_no_system_schema_access = 3552;\n\n/// Server error specific to mysql. Error number: 3553, symbol: ER_NO_SYSTEM_TABLESPACE_ACCESS.\nBOOST_INLINE_CONSTEXPR int er_no_system_tablespace_access = 3553;\n\n/// Server error specific to mysql. Error number: 3554, symbol: ER_NO_SYSTEM_TABLE_ACCESS.\nBOOST_INLINE_CONSTEXPR int er_no_system_table_access = 3554;\n\n/// Server error specific to mysql. Error number: 3555, symbol: ER_NO_SYSTEM_TABLE_ACCESS_FOR_DICTIONARY_TABLE.\nBOOST_INLINE_CONSTEXPR int er_no_system_table_access_for_dictionary_table = 3555;\n\n/// Server error specific to mysql. Error number: 3556, symbol: ER_NO_SYSTEM_TABLE_ACCESS_FOR_SYSTEM_TABLE.\nBOOST_INLINE_CONSTEXPR int er_no_system_table_access_for_system_table = 3556;\n\n/// Server error specific to mysql. Error number: 3557, symbol: ER_NO_SYSTEM_TABLE_ACCESS_FOR_TABLE.\nBOOST_INLINE_CONSTEXPR int er_no_system_table_access_for_table = 3557;\n\n/// Server error specific to mysql. Error number: 3558, symbol: ER_INVALID_OPTION_KEY.\nBOOST_INLINE_CONSTEXPR int er_invalid_option_key = 3558;\n\n/// Server error specific to mysql. Error number: 3559, symbol: ER_INVALID_OPTION_VALUE.\nBOOST_INLINE_CONSTEXPR int er_invalid_option_value = 3559;\n\n/// Server error specific to mysql. Error number: 3560, symbol: ER_INVALID_OPTION_KEY_VALUE_PAIR.\nBOOST_INLINE_CONSTEXPR int er_invalid_option_key_value_pair = 3560;\n\n/// Server error specific to mysql. Error number: 3561, symbol: ER_INVALID_OPTION_START_CHARACTER.\nBOOST_INLINE_CONSTEXPR int er_invalid_option_start_character = 3561;\n\n/// Server error specific to mysql. Error number: 3562, symbol: ER_INVALID_OPTION_END_CHARACTER.\nBOOST_INLINE_CONSTEXPR int er_invalid_option_end_character = 3562;\n\n/// Server error specific to mysql. Error number: 3563, symbol: ER_INVALID_OPTION_CHARACTERS.\nBOOST_INLINE_CONSTEXPR int er_invalid_option_characters = 3563;\n\n/// Server error specific to mysql. Error number: 3564, symbol: ER_DUPLICATE_OPTION_KEY.\nBOOST_INLINE_CONSTEXPR int er_duplicate_option_key = 3564;\n\n/// Server error specific to mysql. Error number: 3565, symbol: ER_WARN_SRS_NOT_FOUND_AXIS_ORDER.\nBOOST_INLINE_CONSTEXPR int er_warn_srs_not_found_axis_order = 3565;\n\n/// Server error specific to mysql. Error number: 3566, symbol: ER_NO_ACCESS_TO_NATIVE_FCT.\nBOOST_INLINE_CONSTEXPR int er_no_access_to_native_fct = 3566;\n\n/// Server error specific to mysql. Error number: 3567, symbol: ER_RESET_MASTER_TO_VALUE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_reset_master_to_value_out_of_range = 3567;\n\n/// Server error specific to mysql. Error number: 3568, symbol: ER_UNRESOLVED_TABLE_LOCK.\nBOOST_INLINE_CONSTEXPR int er_unresolved_table_lock = 3568;\n\n/// Server error specific to mysql. Error number: 3569, symbol: ER_DUPLICATE_TABLE_LOCK.\nBOOST_INLINE_CONSTEXPR int er_duplicate_table_lock = 3569;\n\n/// Server error specific to mysql. Error number: 3570, symbol: ER_BINLOG_UNSAFE_SKIP_LOCKED.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_skip_locked = 3570;\n\n/// Server error specific to mysql. Error number: 3571, symbol: ER_BINLOG_UNSAFE_NOWAIT.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_nowait = 3571;\n\n/// Server error specific to mysql. Error number: 3572, symbol: ER_LOCK_NOWAIT.\nBOOST_INLINE_CONSTEXPR int er_lock_nowait = 3572;\n\n/// Server error specific to mysql. Error number: 3573, symbol: ER_CTE_RECURSIVE_REQUIRES_UNION.\nBOOST_INLINE_CONSTEXPR int er_cte_recursive_requires_union = 3573;\n\n/// Server error specific to mysql. Error number: 3574, symbol: ER_CTE_RECURSIVE_REQUIRES_NONRECURSIVE_FIRST.\nBOOST_INLINE_CONSTEXPR int er_cte_recursive_requires_nonrecursive_first = 3574;\n\n/// Server error specific to mysql. Error number: 3575, symbol: ER_CTE_RECURSIVE_FORBIDS_AGGREGATION.\nBOOST_INLINE_CONSTEXPR int er_cte_recursive_forbids_aggregation = 3575;\n\n/// Server error specific to mysql. Error number: 3576, symbol: ER_CTE_RECURSIVE_FORBIDDEN_JOIN_ORDER.\nBOOST_INLINE_CONSTEXPR int er_cte_recursive_forbidden_join_order = 3576;\n\n/// Server error specific to mysql. Error number: 3577, symbol: ER_CTE_RECURSIVE_REQUIRES_SINGLE_REFERENCE.\nBOOST_INLINE_CONSTEXPR int er_cte_recursive_requires_single_reference = 3577;\n\n/// Server error specific to mysql. Error number: 3578, symbol: ER_SWITCH_TMP_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_switch_tmp_engine = 3578;\n\n/// Server error specific to mysql. Error number: 3579, symbol: ER_WINDOW_NO_SUCH_WINDOW.\nBOOST_INLINE_CONSTEXPR int er_window_no_such_window = 3579;\n\n/// Server error specific to mysql. Error number: 3580, symbol: ER_WINDOW_CIRCULARITY_IN_WINDOW_GRAPH.\nBOOST_INLINE_CONSTEXPR int er_window_circularity_in_window_graph = 3580;\n\n/// Server error specific to mysql. Error number: 3581, symbol: ER_WINDOW_NO_CHILD_PARTITIONING.\nBOOST_INLINE_CONSTEXPR int er_window_no_child_partitioning = 3581;\n\n/// Server error specific to mysql. Error number: 3582, symbol: ER_WINDOW_NO_INHERIT_FRAME.\nBOOST_INLINE_CONSTEXPR int er_window_no_inherit_frame = 3582;\n\n/// Server error specific to mysql. Error number: 3583, symbol: ER_WINDOW_NO_REDEFINE_ORDER_BY.\nBOOST_INLINE_CONSTEXPR int er_window_no_redefine_order_by = 3583;\n\n/// Server error specific to mysql. Error number: 3584, symbol: ER_WINDOW_FRAME_START_ILLEGAL.\nBOOST_INLINE_CONSTEXPR int er_window_frame_start_illegal = 3584;\n\n/// Server error specific to mysql. Error number: 3585, symbol: ER_WINDOW_FRAME_END_ILLEGAL.\nBOOST_INLINE_CONSTEXPR int er_window_frame_end_illegal = 3585;\n\n/// Server error specific to mysql. Error number: 3586, symbol: ER_WINDOW_FRAME_ILLEGAL.\nBOOST_INLINE_CONSTEXPR int er_window_frame_illegal = 3586;\n\n/// Server error specific to mysql. Error number: 3587, symbol: ER_WINDOW_RANGE_FRAME_ORDER_TYPE.\nBOOST_INLINE_CONSTEXPR int er_window_range_frame_order_type = 3587;\n\n/// Server error specific to mysql. Error number: 3588, symbol: ER_WINDOW_RANGE_FRAME_TEMPORAL_TYPE.\nBOOST_INLINE_CONSTEXPR int er_window_range_frame_temporal_type = 3588;\n\n/// Server error specific to mysql. Error number: 3589, symbol: ER_WINDOW_RANGE_FRAME_NUMERIC_TYPE.\nBOOST_INLINE_CONSTEXPR int er_window_range_frame_numeric_type = 3589;\n\n/// Server error specific to mysql. Error number: 3590, symbol: ER_WINDOW_RANGE_BOUND_NOT_CONSTANT.\nBOOST_INLINE_CONSTEXPR int er_window_range_bound_not_constant = 3590;\n\n/// Server error specific to mysql. Error number: 3591, symbol: ER_WINDOW_DUPLICATE_NAME.\nBOOST_INLINE_CONSTEXPR int er_window_duplicate_name = 3591;\n\n/// Server error specific to mysql. Error number: 3592, symbol: ER_WINDOW_ILLEGAL_ORDER_BY.\nBOOST_INLINE_CONSTEXPR int er_window_illegal_order_by = 3592;\n\n/// Server error specific to mysql. Error number: 3593, symbol: ER_WINDOW_INVALID_WINDOW_FUNC_USE.\nBOOST_INLINE_CONSTEXPR int er_window_invalid_window_func_use = 3593;\n\n/// Server error specific to mysql. Error number: 3594, symbol: ER_WINDOW_INVALID_WINDOW_FUNC_ALIAS_USE.\nBOOST_INLINE_CONSTEXPR int er_window_invalid_window_func_alias_use = 3594;\n\n/// Server error specific to mysql. Error number: 3595, symbol: ER_WINDOW_NESTED_WINDOW_FUNC_USE_IN_WINDOW_SPEC.\nBOOST_INLINE_CONSTEXPR int er_window_nested_window_func_use_in_window_spec = 3595;\n\n/// Server error specific to mysql. Error number: 3596, symbol: ER_WINDOW_ROWS_INTERVAL_USE.\nBOOST_INLINE_CONSTEXPR int er_window_rows_interval_use = 3596;\n\n/// Server error specific to mysql. Error number: 3597, symbol: ER_WINDOW_NO_GROUP_ORDER_UNUSED.\nBOOST_INLINE_CONSTEXPR int er_window_no_group_order_unused = 3597;\n\n/// Server error specific to mysql. Error number: 3598, symbol: ER_WINDOW_EXPLAIN_JSON.\nBOOST_INLINE_CONSTEXPR int er_window_explain_json = 3598;\n\n/// Server error specific to mysql. Error number: 3599, symbol: ER_WINDOW_FUNCTION_IGNORES_FRAME.\nBOOST_INLINE_CONSTEXPR int er_window_function_ignores_frame = 3599;\n\n/// Server error specific to mysql. Error number: 3600, symbol: ER_WL9236_NOW_UNUSED.\nBOOST_INLINE_CONSTEXPR int er_wl9236_now_unused = 3600;\n\n/// Server error specific to mysql. Error number: 3601, symbol: ER_INVALID_NO_OF_ARGS.\nBOOST_INLINE_CONSTEXPR int er_invalid_no_of_args = 3601;\n\n/// Server error specific to mysql. Error number: 3602, symbol: ER_FIELD_IN_GROUPING_NOT_GROUP_BY.\nBOOST_INLINE_CONSTEXPR int er_field_in_grouping_not_group_by = 3602;\n\n/// Server error specific to mysql. Error number: 3603, symbol: ER_TOO_LONG_TABLESPACE_COMMENT.\nBOOST_INLINE_CONSTEXPR int er_too_long_tablespace_comment = 3603;\n\n/// Server error specific to mysql. Error number: 3604, symbol: ER_ENGINE_CANT_DROP_TABLE.\nBOOST_INLINE_CONSTEXPR int er_engine_cant_drop_table = 3604;\n\n/// Server error specific to mysql. Error number: 3605, symbol: ER_ENGINE_CANT_DROP_MISSING_TABLE.\nBOOST_INLINE_CONSTEXPR int er_engine_cant_drop_missing_table = 3605;\n\n/// Server error specific to mysql. Error number: 3606, symbol: ER_TABLESPACE_DUP_FILENAME.\nBOOST_INLINE_CONSTEXPR int er_tablespace_dup_filename = 3606;\n\n/// Server error specific to mysql. Error number: 3607, symbol: ER_DB_DROP_RMDIR2.\nBOOST_INLINE_CONSTEXPR int er_db_drop_rmdir2 = 3607;\n\n/// Server error specific to mysql. Error number: 3608, symbol: ER_IMP_NO_FILES_MATCHED.\nBOOST_INLINE_CONSTEXPR int er_imp_no_files_matched = 3608;\n\n/// Server error specific to mysql. Error number: 3609, symbol: ER_IMP_SCHEMA_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_imp_schema_does_not_exist = 3609;\n\n/// Server error specific to mysql. Error number: 3610, symbol: ER_IMP_TABLE_ALREADY_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_imp_table_already_exists = 3610;\n\n/// Server error specific to mysql. Error number: 3611, symbol: ER_IMP_INCOMPATIBLE_MYSQLD_VERSION.\nBOOST_INLINE_CONSTEXPR int er_imp_incompatible_mysqld_version = 3611;\n\n/// Server error specific to mysql. Error number: 3612, symbol: ER_IMP_INCOMPATIBLE_DD_VERSION.\nBOOST_INLINE_CONSTEXPR int er_imp_incompatible_dd_version = 3612;\n\n/// Server error specific to mysql. Error number: 3613, symbol: ER_IMP_INCOMPATIBLE_SDI_VERSION.\nBOOST_INLINE_CONSTEXPR int er_imp_incompatible_sdi_version = 3613;\n\n/// Server error specific to mysql. Error number: 3614, symbol: ER_WARN_INVALID_HINT.\nBOOST_INLINE_CONSTEXPR int er_warn_invalid_hint = 3614;\n\n/// Server error specific to mysql. Error number: 3615, symbol: ER_VAR_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_var_does_not_exist = 3615;\n\n/// Server error specific to mysql. Error number: 3616, symbol: ER_LONGITUDE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_longitude_out_of_range = 3616;\n\n/// Server error specific to mysql. Error number: 3617, symbol: ER_LATITUDE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_latitude_out_of_range = 3617;\n\n/// Server error specific to mysql. Error number: 3618, symbol: ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS.\nBOOST_INLINE_CONSTEXPR int er_not_implemented_for_geographic_srs = 3618;\n\n/// Server error specific to mysql. Error number: 3619, symbol: ER_ILLEGAL_PRIVILEGE_LEVEL.\nBOOST_INLINE_CONSTEXPR int er_illegal_privilege_level = 3619;\n\n/// Server error specific to mysql. Error number: 3620, symbol: ER_NO_SYSTEM_VIEW_ACCESS.\nBOOST_INLINE_CONSTEXPR int er_no_system_view_access = 3620;\n\n/// Server error specific to mysql. Error number: 3621, symbol: ER_COMPONENT_FILTER_FLABBERGASTED.\nBOOST_INLINE_CONSTEXPR int er_component_filter_flabbergasted = 3621;\n\n/// Server error specific to mysql. Error number: 3622, symbol: ER_PART_EXPR_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_part_expr_too_long = 3622;\n\n/// Server error specific to mysql. Error number: 3623, symbol: ER_UDF_DROP_DYNAMICALLY_REGISTERED.\nBOOST_INLINE_CONSTEXPR int er_udf_drop_dynamically_registered = 3623;\n\n/// Server error specific to mysql. Error number: 3624, symbol: ER_UNABLE_TO_STORE_COLUMN_STATISTICS.\nBOOST_INLINE_CONSTEXPR int er_unable_to_store_column_statistics = 3624;\n\n/// Server error specific to mysql. Error number: 3625, symbol: ER_UNABLE_TO_UPDATE_COLUMN_STATISTICS.\nBOOST_INLINE_CONSTEXPR int er_unable_to_update_column_statistics = 3625;\n\n/// Server error specific to mysql. Error number: 3626, symbol: ER_UNABLE_TO_DROP_COLUMN_STATISTICS.\nBOOST_INLINE_CONSTEXPR int er_unable_to_drop_column_statistics = 3626;\n\n/// Server error specific to mysql. Error number: 3627, symbol: ER_UNABLE_TO_BUILD_HISTOGRAM.\nBOOST_INLINE_CONSTEXPR int er_unable_to_build_histogram = 3627;\n\n/// Server error specific to mysql. Error number: 3628, symbol: ER_MANDATORY_ROLE.\nBOOST_INLINE_CONSTEXPR int er_mandatory_role = 3628;\n\n/// Server error specific to mysql. Error number: 3629, symbol: ER_MISSING_TABLESPACE_FILE.\nBOOST_INLINE_CONSTEXPR int er_missing_tablespace_file = 3629;\n\n/// Server error specific to mysql. Error number: 3630, symbol: ER_PERSIST_ONLY_ACCESS_DENIED_ERROR.\nBOOST_INLINE_CONSTEXPR int er_persist_only_access_denied_error = 3630;\n\n/// Server error specific to mysql. Error number: 3631, symbol: ER_CMD_NEED_SUPER.\nBOOST_INLINE_CONSTEXPR int er_cmd_need_super = 3631;\n\n/// Server error specific to mysql. Error number: 3632, symbol: ER_PATH_IN_DATADIR.\nBOOST_INLINE_CONSTEXPR int er_path_in_datadir = 3632;\n\n/// Server error specific to mysql. Error number: 3633, symbol: ER_CLONE_DDL_IN_PROGRESS.\nBOOST_INLINE_CONSTEXPR int er_clone_ddl_in_progress = 3633;\n\n/// Server error specific to mysql. Error number: 3634, symbol: ER_CLONE_TOO_MANY_CONCURRENT_CLONES.\nBOOST_INLINE_CONSTEXPR int er_clone_too_many_concurrent_clones = 3634;\n\n/// Server error specific to mysql. Error number: 3635, symbol: ER_APPLIER_LOG_EVENT_VALIDATION_ERROR.\nBOOST_INLINE_CONSTEXPR int er_applier_log_event_validation_error = 3635;\n\n/// Server error specific to mysql. Error number: 3636, symbol: ER_CTE_MAX_RECURSION_DEPTH.\nBOOST_INLINE_CONSTEXPR int er_cte_max_recursion_depth = 3636;\n\n/// Server error specific to mysql. Error number: 3637, symbol: ER_NOT_HINT_UPDATABLE_VARIABLE.\nBOOST_INLINE_CONSTEXPR int er_not_hint_updatable_variable = 3637;\n\n/// Server error specific to mysql. Error number: 3638, symbol: ER_CREDENTIALS_CONTRADICT_TO_HISTORY.\nBOOST_INLINE_CONSTEXPR int er_credentials_contradict_to_history = 3638;\n\n/// Server error specific to mysql. Error number: 3639, symbol: ER_WARNING_PASSWORD_HISTORY_CLAUSES_VOID.\nBOOST_INLINE_CONSTEXPR int er_warning_password_history_clauses_void = 3639;\n\n/// Server error specific to mysql. Error number: 3640, symbol: ER_CLIENT_DOES_NOT_SUPPORT.\nBOOST_INLINE_CONSTEXPR int er_client_does_not_support = 3640;\n\n/// Server error specific to mysql. Error number: 3641, symbol: ER_I_S_SKIPPED_TABLESPACE.\nBOOST_INLINE_CONSTEXPR int er_i_s_skipped_tablespace = 3641;\n\n/// Server error specific to mysql. Error number: 3642, symbol: ER_TABLESPACE_ENGINE_MISMATCH.\nBOOST_INLINE_CONSTEXPR int er_tablespace_engine_mismatch = 3642;\n\n/// Server error specific to mysql. Error number: 3643, symbol: ER_WRONG_SRID_FOR_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_wrong_srid_for_column = 3643;\n\n/// Server error specific to mysql. Error number: 3644, symbol: ER_CANNOT_ALTER_SRID_DUE_TO_INDEX.\nBOOST_INLINE_CONSTEXPR int er_cannot_alter_srid_due_to_index = 3644;\n\n/// Server error specific to mysql. Error number: 3645, symbol: ER_WARN_BINLOG_PARTIAL_UPDATES_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_warn_binlog_partial_updates_disabled = 3645;\n\n/// Server error specific to mysql. Error number: 3646, symbol: ER_WARN_BINLOG_V1_ROW_EVENTS_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_warn_binlog_v1_row_events_disabled = 3646;\n\n/// Server error specific to mysql. Error number: 3647, symbol: ER_WARN_BINLOG_PARTIAL_UPDATES_SUGGESTS_PARTIAL_IMAGES.\nBOOST_INLINE_CONSTEXPR int er_warn_binlog_partial_updates_suggests_partial_images = 3647;\n\n/// Server error specific to mysql. Error number: 3648, symbol: ER_COULD_NOT_APPLY_JSON_DIFF.\nBOOST_INLINE_CONSTEXPR int er_could_not_apply_json_diff = 3648;\n\n/// Server error specific to mysql. Error number: 3649, symbol: ER_CORRUPTED_JSON_DIFF.\nBOOST_INLINE_CONSTEXPR int er_corrupted_json_diff = 3649;\n\n/// Server error specific to mysql. Error number: 3650, symbol: ER_RESOURCE_GROUP_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_resource_group_exists = 3650;\n\n/// Server error specific to mysql. Error number: 3651, symbol: ER_RESOURCE_GROUP_NOT_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_resource_group_not_exists = 3651;\n\n/// Server error specific to mysql. Error number: 3652, symbol: ER_INVALID_VCPU_ID.\nBOOST_INLINE_CONSTEXPR int er_invalid_vcpu_id = 3652;\n\n/// Server error specific to mysql. Error number: 3653, symbol: ER_INVALID_VCPU_RANGE.\nBOOST_INLINE_CONSTEXPR int er_invalid_vcpu_range = 3653;\n\n/// Server error specific to mysql. Error number: 3654, symbol: ER_INVALID_THREAD_PRIORITY.\nBOOST_INLINE_CONSTEXPR int er_invalid_thread_priority = 3654;\n\n/// Server error specific to mysql. Error number: 3655, symbol: ER_DISALLOWED_OPERATION.\nBOOST_INLINE_CONSTEXPR int er_disallowed_operation = 3655;\n\n/// Server error specific to mysql. Error number: 3656, symbol: ER_RESOURCE_GROUP_BUSY.\nBOOST_INLINE_CONSTEXPR int er_resource_group_busy = 3656;\n\n/// Server error specific to mysql. Error number: 3657, symbol: ER_RESOURCE_GROUP_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_resource_group_disabled = 3657;\n\n/// Server error specific to mysql. Error number: 3658, symbol: ER_FEATURE_UNSUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_feature_unsupported = 3658;\n\n/// Server error specific to mysql. Error number: 3659, symbol: ER_ATTRIBUTE_IGNORED.\nBOOST_INLINE_CONSTEXPR int er_attribute_ignored = 3659;\n\n/// Server error specific to mysql. Error number: 3660, symbol: ER_INVALID_THREAD_ID.\nBOOST_INLINE_CONSTEXPR int er_invalid_thread_id = 3660;\n\n/// Server error specific to mysql. Error number: 3661, symbol: ER_RESOURCE_GROUP_BIND_FAILED.\nBOOST_INLINE_CONSTEXPR int er_resource_group_bind_failed = 3661;\n\n/// Server error specific to mysql. Error number: 3662, symbol: ER_INVALID_USE_OF_FORCE_OPTION.\nBOOST_INLINE_CONSTEXPR int er_invalid_use_of_force_option = 3662;\n\n/// Server error specific to mysql. Error number: 3663, symbol: ER_GROUP_REPLICATION_COMMAND_FAILURE.\nBOOST_INLINE_CONSTEXPR int er_group_replication_command_failure = 3663;\n\n/// Server error specific to mysql. Error number: 3664, symbol: ER_SDI_OPERATION_FAILED.\nBOOST_INLINE_CONSTEXPR int er_sdi_operation_failed = 3664;\n\n/// Server error specific to mysql. Error number: 3665, symbol: ER_MISSING_JSON_TABLE_VALUE.\nBOOST_INLINE_CONSTEXPR int er_missing_json_table_value = 3665;\n\n/// Server error specific to mysql. Error number: 3666, symbol: ER_WRONG_JSON_TABLE_VALUE.\nBOOST_INLINE_CONSTEXPR int er_wrong_json_table_value = 3666;\n\n/// Server error specific to mysql. Error number: 3667, symbol: ER_TF_MUST_HAVE_ALIAS.\nBOOST_INLINE_CONSTEXPR int er_tf_must_have_alias = 3667;\n\n/// Server error specific to mysql. Error number: 3668, symbol: ER_TF_FORBIDDEN_JOIN_TYPE.\nBOOST_INLINE_CONSTEXPR int er_tf_forbidden_join_type = 3668;\n\n/// Server error specific to mysql. Error number: 3669, symbol: ER_JT_VALUE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_jt_value_out_of_range = 3669;\n\n/// Server error specific to mysql. Error number: 3670, symbol: ER_JT_MAX_NESTED_PATH.\nBOOST_INLINE_CONSTEXPR int er_jt_max_nested_path = 3670;\n\n/// Server error specific to mysql. Error number: 3671, symbol: ER_PASSWORD_EXPIRATION_NOT_SUPPORTED_BY_AUTH_METHOD.\nBOOST_INLINE_CONSTEXPR int er_password_expiration_not_supported_by_auth_method = 3671;\n\n/// Server error specific to mysql. Error number: 3672, symbol: ER_INVALID_GEOJSON_CRS_NOT_TOP_LEVEL.\nBOOST_INLINE_CONSTEXPR int er_invalid_geojson_crs_not_top_level = 3672;\n\n/// Server error specific to mysql. Error number: 3673, symbol: ER_BAD_NULL_ERROR_NOT_IGNORED.\nBOOST_INLINE_CONSTEXPR int er_bad_null_error_not_ignored = 3673;\n\n/// Server error specific to mysql. Error number: 3674, symbol: WARN_USELESS_SPATIAL_INDEX.\nBOOST_INLINE_CONSTEXPR int warn_useless_spatial_index = 3674;\n\n/// Server error specific to mysql. Error number: 3675, symbol: ER_DISK_FULL_NOWAIT.\nBOOST_INLINE_CONSTEXPR int er_disk_full_nowait = 3675;\n\n/// Server error specific to mysql. Error number: 3676, symbol: ER_PARSE_ERROR_IN_DIGEST_FN.\nBOOST_INLINE_CONSTEXPR int er_parse_error_in_digest_fn = 3676;\n\n/// Server error specific to mysql. Error number: 3677, symbol: ER_UNDISCLOSED_PARSE_ERROR_IN_DIGEST_FN.\nBOOST_INLINE_CONSTEXPR int er_undisclosed_parse_error_in_digest_fn = 3677;\n\n/// Server error specific to mysql. Error number: 3678, symbol: ER_SCHEMA_DIR_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_schema_dir_exists = 3678;\n\n/// Server error specific to mysql. Error number: 3679, symbol: ER_SCHEMA_DIR_MISSING.\nBOOST_INLINE_CONSTEXPR int er_schema_dir_missing = 3679;\n\n/// Server error specific to mysql. Error number: 3680, symbol: ER_SCHEMA_DIR_CREATE_FAILED.\nBOOST_INLINE_CONSTEXPR int er_schema_dir_create_failed = 3680;\n\n/// Server error specific to mysql. Error number: 3681, symbol: ER_SCHEMA_DIR_UNKNOWN.\nBOOST_INLINE_CONSTEXPR int er_schema_dir_unknown = 3681;\n\n/// Server error specific to mysql. Error number: 3682, symbol: ER_ONLY_IMPLEMENTED_FOR_SRID_0_AND_4326.\nBOOST_INLINE_CONSTEXPR int er_only_implemented_for_srid_0_and_4326 = 3682;\n\n/// Server error specific to mysql. Error number: 3683, symbol: ER_BINLOG_EXPIRE_LOG_DAYS_AND_SECS_USED_TOGETHER.\nBOOST_INLINE_CONSTEXPR int er_binlog_expire_log_days_and_secs_used_together = 3683;\n\n/// Server error specific to mysql. Error number: 3684, symbol: ER_REGEXP_BUFFER_OVERFLOW.\nBOOST_INLINE_CONSTEXPR int er_regexp_buffer_overflow = 3684;\n\n/// Server error specific to mysql. Error number: 3685, symbol: ER_REGEXP_ILLEGAL_ARGUMENT.\nBOOST_INLINE_CONSTEXPR int er_regexp_illegal_argument = 3685;\n\n/// Server error specific to mysql. Error number: 3686, symbol: ER_REGEXP_INDEX_OUTOFBOUNDS_ERROR.\nBOOST_INLINE_CONSTEXPR int er_regexp_index_outofbounds_error = 3686;\n\n/// Server error specific to mysql. Error number: 3687, symbol: ER_REGEXP_INTERNAL_ERROR.\nBOOST_INLINE_CONSTEXPR int er_regexp_internal_error = 3687;\n\n/// Server error specific to mysql. Error number: 3688, symbol: ER_REGEXP_RULE_SYNTAX.\nBOOST_INLINE_CONSTEXPR int er_regexp_rule_syntax = 3688;\n\n/// Server error specific to mysql. Error number: 3689, symbol: ER_REGEXP_BAD_ESCAPE_SEQUENCE.\nBOOST_INLINE_CONSTEXPR int er_regexp_bad_escape_sequence = 3689;\n\n/// Server error specific to mysql. Error number: 3690, symbol: ER_REGEXP_UNIMPLEMENTED.\nBOOST_INLINE_CONSTEXPR int er_regexp_unimplemented = 3690;\n\n/// Server error specific to mysql. Error number: 3691, symbol: ER_REGEXP_MISMATCHED_PAREN.\nBOOST_INLINE_CONSTEXPR int er_regexp_mismatched_paren = 3691;\n\n/// Server error specific to mysql. Error number: 3692, symbol: ER_REGEXP_BAD_INTERVAL.\nBOOST_INLINE_CONSTEXPR int er_regexp_bad_interval = 3692;\n\n/// Server error specific to mysql. Error number: 3693, symbol: ER_REGEXP_MAX_LT_MIN.\nBOOST_INLINE_CONSTEXPR int er_regexp_max_lt_min = 3693;\n\n/// Server error specific to mysql. Error number: 3694, symbol: ER_REGEXP_INVALID_BACK_REF.\nBOOST_INLINE_CONSTEXPR int er_regexp_invalid_back_ref = 3694;\n\n/// Server error specific to mysql. Error number: 3695, symbol: ER_REGEXP_LOOK_BEHIND_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_regexp_look_behind_limit = 3695;\n\n/// Server error specific to mysql. Error number: 3696, symbol: ER_REGEXP_MISSING_CLOSE_BRACKET.\nBOOST_INLINE_CONSTEXPR int er_regexp_missing_close_bracket = 3696;\n\n/// Server error specific to mysql. Error number: 3697, symbol: ER_REGEXP_INVALID_RANGE.\nBOOST_INLINE_CONSTEXPR int er_regexp_invalid_range = 3697;\n\n/// Server error specific to mysql. Error number: 3698, symbol: ER_REGEXP_STACK_OVERFLOW.\nBOOST_INLINE_CONSTEXPR int er_regexp_stack_overflow = 3698;\n\n/// Server error specific to mysql. Error number: 3699, symbol: ER_REGEXP_TIME_OUT.\nBOOST_INLINE_CONSTEXPR int er_regexp_time_out = 3699;\n\n/// Server error specific to mysql. Error number: 3700, symbol: ER_REGEXP_PATTERN_TOO_BIG.\nBOOST_INLINE_CONSTEXPR int er_regexp_pattern_too_big = 3700;\n\n/// Server error specific to mysql. Error number: 3701, symbol: ER_CANT_SET_ERROR_LOG_SERVICE.\nBOOST_INLINE_CONSTEXPR int er_cant_set_error_log_service = 3701;\n\n/// Server error specific to mysql. Error number: 3702, symbol: ER_EMPTY_PIPELINE_FOR_ERROR_LOG_SERVICE.\nBOOST_INLINE_CONSTEXPR int er_empty_pipeline_for_error_log_service = 3702;\n\n/// Server error specific to mysql. Error number: 3703, symbol: ER_COMPONENT_FILTER_DIAGNOSTICS.\nBOOST_INLINE_CONSTEXPR int er_component_filter_diagnostics = 3703;\n\n/// Server error specific to mysql. Error number: 3704, symbol: ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS.\nBOOST_INLINE_CONSTEXPR int er_not_implemented_for_cartesian_srs = 3704;\n\n/// Server error specific to mysql. Error number: 3705, symbol: ER_NOT_IMPLEMENTED_FOR_PROJECTED_SRS.\nBOOST_INLINE_CONSTEXPR int er_not_implemented_for_projected_srs = 3705;\n\n/// Server error specific to mysql. Error number: 3706, symbol: ER_NONPOSITIVE_RADIUS.\nBOOST_INLINE_CONSTEXPR int er_nonpositive_radius = 3706;\n\n/// Server error specific to mysql. Error number: 3707, symbol: ER_RESTART_SERVER_FAILED.\nBOOST_INLINE_CONSTEXPR int er_restart_server_failed = 3707;\n\n/// Server error specific to mysql. Error number: 3708, symbol: ER_SRS_MISSING_MANDATORY_ATTRIBUTE.\nBOOST_INLINE_CONSTEXPR int er_srs_missing_mandatory_attribute = 3708;\n\n/// Server error specific to mysql. Error number: 3709, symbol: ER_SRS_MULTIPLE_ATTRIBUTE_DEFINITIONS.\nBOOST_INLINE_CONSTEXPR int er_srs_multiple_attribute_definitions = 3709;\n\n/// Server error specific to mysql. Error number: 3710, symbol: ER_SRS_NAME_CANT_BE_EMPTY_OR_WHITESPACE.\nBOOST_INLINE_CONSTEXPR int er_srs_name_cant_be_empty_or_whitespace = 3710;\n\n/// Server error specific to mysql. Error number: 3711, symbol: ER_SRS_ORGANIZATION_CANT_BE_EMPTY_OR_WHITESPACE.\nBOOST_INLINE_CONSTEXPR int er_srs_organization_cant_be_empty_or_whitespace = 3711;\n\n/// Server error specific to mysql. Error number: 3712, symbol: ER_SRS_ID_ALREADY_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_srs_id_already_exists = 3712;\n\n/// Server error specific to mysql. Error number: 3713, symbol: ER_WARN_SRS_ID_ALREADY_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_warn_srs_id_already_exists = 3713;\n\n/// Server error specific to mysql. Error number: 3714, symbol: ER_CANT_MODIFY_SRID_0.\nBOOST_INLINE_CONSTEXPR int er_cant_modify_srid_0 = 3714;\n\n/// Server error specific to mysql. Error number: 3715, symbol: ER_WARN_RESERVED_SRID_RANGE.\nBOOST_INLINE_CONSTEXPR int er_warn_reserved_srid_range = 3715;\n\n/// Server error specific to mysql. Error number: 3716, symbol: ER_CANT_MODIFY_SRS_USED_BY_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_cant_modify_srs_used_by_column = 3716;\n\n/// Server error specific to mysql. Error number: 3717, symbol: ER_SRS_INVALID_CHARACTER_IN_ATTRIBUTE.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_character_in_attribute = 3717;\n\n/// Server error specific to mysql. Error number: 3718, symbol: ER_SRS_ATTRIBUTE_STRING_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_srs_attribute_string_too_long = 3718;\n\n/// Server error specific to mysql. Error number: 3719, symbol: ER_DEPRECATED_UTF8_ALIAS.\nBOOST_INLINE_CONSTEXPR int er_deprecated_utf8_alias = 3719;\n\n/// Server error specific to mysql. Error number: 3720, symbol: ER_DEPRECATED_NATIONAL.\nBOOST_INLINE_CONSTEXPR int er_deprecated_national = 3720;\n\n/// Server error specific to mysql. Error number: 3721, symbol: ER_INVALID_DEFAULT_UTF8MB4_COLLATION.\nBOOST_INLINE_CONSTEXPR int er_invalid_default_utf8mb4_collation = 3721;\n\n/// Server error specific to mysql. Error number: 3722, symbol: ER_UNABLE_TO_COLLECT_LOG_STATUS.\nBOOST_INLINE_CONSTEXPR int er_unable_to_collect_log_status = 3722;\n\n/// Server error specific to mysql. Error number: 3723, symbol: ER_RESERVED_TABLESPACE_NAME.\nBOOST_INLINE_CONSTEXPR int er_reserved_tablespace_name = 3723;\n\n/// Server error specific to mysql. Error number: 3724, symbol: ER_UNABLE_TO_SET_OPTION.\nBOOST_INLINE_CONSTEXPR int er_unable_to_set_option = 3724;\n\n/// Server error specific to mysql. Error number: 3725, symbol: ER_SLAVE_POSSIBLY_DIVERGED_AFTER_DDL.\nBOOST_INLINE_CONSTEXPR int er_slave_possibly_diverged_after_ddl = 3725;\n\n/// Server error specific to mysql. Error number: 3726, symbol: ER_SRS_NOT_GEOGRAPHIC.\nBOOST_INLINE_CONSTEXPR int er_srs_not_geographic = 3726;\n\n/// Server error specific to mysql. Error number: 3727, symbol: ER_POLYGON_TOO_LARGE.\nBOOST_INLINE_CONSTEXPR int er_polygon_too_large = 3727;\n\n/// Server error specific to mysql. Error number: 3728, symbol: ER_SPATIAL_UNIQUE_INDEX.\nBOOST_INLINE_CONSTEXPR int er_spatial_unique_index = 3728;\n\n/// Server error specific to mysql. Error number: 3729, symbol: ER_INDEX_TYPE_NOT_SUPPORTED_FOR_SPATIAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_index_type_not_supported_for_spatial_index = 3729;\n\n/// Server error specific to mysql. Error number: 3730, symbol: ER_FK_CANNOT_DROP_PARENT.\nBOOST_INLINE_CONSTEXPR int er_fk_cannot_drop_parent = 3730;\n\n/// Server error specific to mysql. Error number: 3731, symbol: ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_geometry_param_longitude_out_of_range = 3731;\n\n/// Server error specific to mysql. Error number: 3732, symbol: ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_geometry_param_latitude_out_of_range = 3732;\n\n/// Server error specific to mysql. Error number: 3733, symbol: ER_FK_CANNOT_USE_VIRTUAL_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_fk_cannot_use_virtual_column = 3733;\n\n/// Server error specific to mysql. Error number: 3734, symbol: ER_FK_NO_COLUMN_PARENT.\nBOOST_INLINE_CONSTEXPR int er_fk_no_column_parent = 3734;\n\n/// Server error specific to mysql. Error number: 3735, symbol: ER_CANT_SET_ERROR_SUPPRESSION_LIST.\nBOOST_INLINE_CONSTEXPR int er_cant_set_error_suppression_list = 3735;\n\n/// Server error specific to mysql. Error number: 3736, symbol: ER_SRS_GEOGCS_INVALID_AXES.\nBOOST_INLINE_CONSTEXPR int er_srs_geogcs_invalid_axes = 3736;\n\n/// Server error specific to mysql. Error number: 3737, symbol: ER_SRS_INVALID_SEMI_MAJOR_AXIS.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_semi_major_axis = 3737;\n\n/// Server error specific to mysql. Error number: 3738, symbol: ER_SRS_INVALID_INVERSE_FLATTENING.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_inverse_flattening = 3738;\n\n/// Server error specific to mysql. Error number: 3739, symbol: ER_SRS_INVALID_ANGULAR_UNIT.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_angular_unit = 3739;\n\n/// Server error specific to mysql. Error number: 3740, symbol: ER_SRS_INVALID_PRIME_MERIDIAN.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_prime_meridian = 3740;\n\n/// Server error specific to mysql. Error number: 3741, symbol: ER_TRANSFORM_SOURCE_SRS_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_transform_source_srs_not_supported = 3741;\n\n/// Server error specific to mysql. Error number: 3742, symbol: ER_TRANSFORM_TARGET_SRS_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_transform_target_srs_not_supported = 3742;\n\n/// Server error specific to mysql. Error number: 3743, symbol: ER_TRANSFORM_SOURCE_SRS_MISSING_TOWGS84.\nBOOST_INLINE_CONSTEXPR int er_transform_source_srs_missing_towgs84 = 3743;\n\n/// Server error specific to mysql. Error number: 3744, symbol: ER_TRANSFORM_TARGET_SRS_MISSING_TOWGS84.\nBOOST_INLINE_CONSTEXPR int er_transform_target_srs_missing_towgs84 = 3744;\n\n/// Server error specific to mysql. Error number: 3745, symbol: ER_TEMP_TABLE_PREVENTS_SWITCH_SESSION_BINLOG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_temp_table_prevents_switch_session_binlog_format = 3745;\n\n/// Server error specific to mysql. Error number: 3746, symbol: ER_TEMP_TABLE_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_temp_table_prevents_switch_global_binlog_format = 3746;\n\n/// Server error specific to mysql. Error number: 3747, symbol: ER_RUNNING_APPLIER_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_running_applier_prevents_switch_global_binlog_format = 3747;\n\n/// Server error specific to mysql. Error number: 3748, symbol: ER_CLIENT_GTID_UNSAFE_CREATE_DROP_TEMP_TABLE_IN_TRX_IN_SBR.\nBOOST_INLINE_CONSTEXPR int er_client_gtid_unsafe_create_drop_temp_table_in_trx_in_sbr = 3748;\n\n/// Server error specific to mysql. Error number: 3750, symbol: ER_TABLE_WITHOUT_PK.\nBOOST_INLINE_CONSTEXPR int er_table_without_pk = 3750;\n\n/// Server error specific to mysql. Error number: 3751, symbol: ER_WARN_DATA_TRUNCATED_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_warn_data_truncated_functional_index = 3751;\n\n/// Server error specific to mysql. Error number: 3752, symbol: ER_WARN_DATA_OUT_OF_RANGE_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_warn_data_out_of_range_functional_index = 3752;\n\n/// Server error specific to mysql. Error number: 3753, symbol: ER_FUNCTIONAL_INDEX_ON_JSON_OR_GEOMETRY_FUNCTION.\nBOOST_INLINE_CONSTEXPR int er_functional_index_on_json_or_geometry_function = 3753;\n\n/// Server error specific to mysql. Error number: 3754, symbol: ER_FUNCTIONAL_INDEX_REF_AUTO_INCREMENT.\nBOOST_INLINE_CONSTEXPR int er_functional_index_ref_auto_increment = 3754;\n\n/// Server error specific to mysql. Error number: 3755, symbol: ER_CANNOT_DROP_COLUMN_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_cannot_drop_column_functional_index = 3755;\n\n/// Server error specific to mysql. Error number: 3756, symbol: ER_FUNCTIONAL_INDEX_PRIMARY_KEY.\nBOOST_INLINE_CONSTEXPR int er_functional_index_primary_key = 3756;\n\n/// Server error specific to mysql. Error number: 3757, symbol: ER_FUNCTIONAL_INDEX_ON_LOB.\nBOOST_INLINE_CONSTEXPR int er_functional_index_on_lob = 3757;\n\n/// Server error specific to mysql. Error number: 3758, symbol: ER_FUNCTIONAL_INDEX_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_functional_index_function_is_not_allowed = 3758;\n\n/// Server error specific to mysql. Error number: 3759, symbol: ER_FULLTEXT_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_fulltext_functional_index = 3759;\n\n/// Server error specific to mysql. Error number: 3760, symbol: ER_SPATIAL_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_spatial_functional_index = 3760;\n\n/// Server error specific to mysql. Error number: 3761, symbol: ER_WRONG_KEY_COLUMN_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_wrong_key_column_functional_index = 3761;\n\n/// Server error specific to mysql. Error number: 3762, symbol: ER_FUNCTIONAL_INDEX_ON_FIELD.\nBOOST_INLINE_CONSTEXPR int er_functional_index_on_field = 3762;\n\n/// Server error specific to mysql. Error number: 3763, symbol: ER_GENERATED_COLUMN_NAMED_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_generated_column_named_function_is_not_allowed = 3763;\n\n/// Server error specific to mysql. Error number: 3764, symbol: ER_GENERATED_COLUMN_ROW_VALUE.\nBOOST_INLINE_CONSTEXPR int er_generated_column_row_value = 3764;\n\n/// Server error specific to mysql. Error number: 3765, symbol: ER_GENERATED_COLUMN_VARIABLES.\nBOOST_INLINE_CONSTEXPR int er_generated_column_variables = 3765;\n\n/// Server error specific to mysql. Error number: 3766, symbol: ER_DEPENDENT_BY_DEFAULT_GENERATED_VALUE.\nBOOST_INLINE_CONSTEXPR int er_dependent_by_default_generated_value = 3766;\n\n/// Server error specific to mysql. Error number: 3767, symbol: ER_DEFAULT_VAL_GENERATED_NON_PRIOR.\nBOOST_INLINE_CONSTEXPR int er_default_val_generated_non_prior = 3767;\n\n/// Server error specific to mysql. Error number: 3768, symbol: ER_DEFAULT_VAL_GENERATED_REF_AUTO_INC.\nBOOST_INLINE_CONSTEXPR int er_default_val_generated_ref_auto_inc = 3768;\n\n/// Server error specific to mysql. Error number: 3769, symbol: ER_DEFAULT_VAL_GENERATED_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_default_val_generated_function_is_not_allowed = 3769;\n\n/// Server error specific to mysql. Error number: 3770, symbol: ER_DEFAULT_VAL_GENERATED_NAMED_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_default_val_generated_named_function_is_not_allowed = 3770;\n\n/// Server error specific to mysql. Error number: 3771, symbol: ER_DEFAULT_VAL_GENERATED_ROW_VALUE.\nBOOST_INLINE_CONSTEXPR int er_default_val_generated_row_value = 3771;\n\n/// Server error specific to mysql. Error number: 3772, symbol: ER_DEFAULT_VAL_GENERATED_VARIABLES.\nBOOST_INLINE_CONSTEXPR int er_default_val_generated_variables = 3772;\n\n/// Server error specific to mysql. Error number: 3773, symbol: ER_DEFAULT_AS_VAL_GENERATED.\nBOOST_INLINE_CONSTEXPR int er_default_as_val_generated = 3773;\n\n/// Server error specific to mysql. Error number: 3774, symbol: ER_UNSUPPORTED_ACTION_ON_DEFAULT_VAL_GENERATED.\nBOOST_INLINE_CONSTEXPR int er_unsupported_action_on_default_val_generated = 3774;\n\n/// Server error specific to mysql. Error number: 3775, symbol: ER_GTID_UNSAFE_ALTER_ADD_COL_WITH_DEFAULT_EXPRESSION.\nBOOST_INLINE_CONSTEXPR int er_gtid_unsafe_alter_add_col_with_default_expression = 3775;\n\n/// Server error specific to mysql. Error number: 3776, symbol: ER_FK_CANNOT_CHANGE_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_fk_cannot_change_engine = 3776;\n\n/// Server error specific to mysql. Error number: 3777, symbol: ER_WARN_DEPRECATED_USER_SET_EXPR.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_user_set_expr = 3777;\n\n/// Server error specific to mysql. Error number: 3778, symbol: ER_WARN_DEPRECATED_UTF8MB3_COLLATION.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_utf8mb3_collation = 3778;\n\n/// Server error specific to mysql. Error number: 3779, symbol: ER_WARN_DEPRECATED_NESTED_COMMENT_SYNTAX.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_nested_comment_syntax = 3779;\n\n/// Server error specific to mysql. Error number: 3780, symbol: ER_FK_INCOMPATIBLE_COLUMNS.\nBOOST_INLINE_CONSTEXPR int er_fk_incompatible_columns = 3780;\n\n/// Server error specific to mysql. Error number: 3781, symbol: ER_GR_HOLD_WAIT_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_gr_hold_wait_timeout = 3781;\n\n/// Server error specific to mysql. Error number: 3782, symbol: ER_GR_HOLD_KILLED.\nBOOST_INLINE_CONSTEXPR int er_gr_hold_killed = 3782;\n\n/// Server error specific to mysql. Error number: 3783, symbol: ER_GR_HOLD_MEMBER_STATUS_ERROR.\nBOOST_INLINE_CONSTEXPR int er_gr_hold_member_status_error = 3783;\n\n/// Server error specific to mysql. Error number: 3784, symbol: ER_RPL_ENCRYPTION_FAILED_TO_FETCH_KEY.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_failed_to_fetch_key = 3784;\n\n/// Server error specific to mysql. Error number: 3785, symbol: ER_RPL_ENCRYPTION_KEY_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_key_not_found = 3785;\n\n/// Server error specific to mysql. Error number: 3786, symbol: ER_RPL_ENCRYPTION_KEYRING_INVALID_KEY.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_keyring_invalid_key = 3786;\n\n/// Server error specific to mysql. Error number: 3787, symbol: ER_RPL_ENCRYPTION_HEADER_ERROR.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_header_error = 3787;\n\n/// Server error specific to mysql. Error number: 3788, symbol: ER_RPL_ENCRYPTION_FAILED_TO_ROTATE_LOGS.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_failed_to_rotate_logs = 3788;\n\n/// Server error specific to mysql. Error number: 3789, symbol: ER_RPL_ENCRYPTION_KEY_EXISTS_UNEXPECTED.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_key_exists_unexpected = 3789;\n\n/// Server error specific to mysql. Error number: 3790, symbol: ER_RPL_ENCRYPTION_FAILED_TO_GENERATE_KEY.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_failed_to_generate_key = 3790;\n\n/// Server error specific to mysql. Error number: 3791, symbol: ER_RPL_ENCRYPTION_FAILED_TO_STORE_KEY.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_failed_to_store_key = 3791;\n\n/// Server error specific to mysql. Error number: 3792, symbol: ER_RPL_ENCRYPTION_FAILED_TO_REMOVE_KEY.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_failed_to_remove_key = 3792;\n\n/// Server error specific to mysql. Error number: 3793, symbol: ER_RPL_ENCRYPTION_UNABLE_TO_CHANGE_OPTION.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_unable_to_change_option = 3793;\n\n/// Server error specific to mysql. Error number: 3794, symbol: ER_RPL_ENCRYPTION_MASTER_KEY_RECOVERY_FAILED.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_master_key_recovery_failed = 3794;\n\n/// Server error specific to mysql. Error number: 3795, symbol: ER_SLOW_LOG_MODE_IGNORED_WHEN_NOT_LOGGING_TO_FILE.\nBOOST_INLINE_CONSTEXPR int er_slow_log_mode_ignored_when_not_logging_to_file = 3795;\n\n/// Server error specific to mysql. Error number: 3796, symbol: ER_GRP_TRX_CONSISTENCY_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_grp_trx_consistency_not_allowed = 3796;\n\n/// Server error specific to mysql. Error number: 3797, symbol: ER_GRP_TRX_CONSISTENCY_BEFORE.\nBOOST_INLINE_CONSTEXPR int er_grp_trx_consistency_before = 3797;\n\n/// Server error specific to mysql. Error number: 3798, symbol: ER_GRP_TRX_CONSISTENCY_AFTER_ON_TRX_BEGIN.\nBOOST_INLINE_CONSTEXPR int er_grp_trx_consistency_after_on_trx_begin = 3798;\n\n/// Server error specific to mysql. Error number: 3799, symbol: ER_GRP_TRX_CONSISTENCY_BEGIN_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_grp_trx_consistency_begin_not_allowed = 3799;\n\n/// Server error specific to mysql. Error number: 3800, symbol: ER_FUNCTIONAL_INDEX_ROW_VALUE_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_functional_index_row_value_is_not_allowed = 3800;\n\n/// Server error specific to mysql. Error number: 3801, symbol: ER_RPL_ENCRYPTION_FAILED_TO_ENCRYPT.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_failed_to_encrypt = 3801;\n\n/// Server error specific to mysql. Error number: 3802, symbol: ER_PAGE_TRACKING_NOT_STARTED.\nBOOST_INLINE_CONSTEXPR int er_page_tracking_not_started = 3802;\n\n/// Server error specific to mysql. Error number: 3803, symbol: ER_PAGE_TRACKING_RANGE_NOT_TRACKED.\nBOOST_INLINE_CONSTEXPR int er_page_tracking_range_not_tracked = 3803;\n\n/// Server error specific to mysql. Error number: 3804, symbol: ER_PAGE_TRACKING_CANNOT_PURGE.\nBOOST_INLINE_CONSTEXPR int er_page_tracking_cannot_purge = 3804;\n\n/// Server error specific to mysql. Error number: 3805, symbol: ER_RPL_ENCRYPTION_CANNOT_ROTATE_BINLOG_MASTER_KEY.\nBOOST_INLINE_CONSTEXPR int er_rpl_encryption_cannot_rotate_binlog_master_key = 3805;\n\n/// Server error specific to mysql. Error number: 3806, symbol: ER_BINLOG_MASTER_KEY_RECOVERY_OUT_OF_COMBINATION.\nBOOST_INLINE_CONSTEXPR int er_binlog_master_key_recovery_out_of_combination = 3806;\n\n/// Server error specific to mysql. Error number: 3807, symbol: ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_OPERATE_KEY.\nBOOST_INLINE_CONSTEXPR int er_binlog_master_key_rotation_fail_to_operate_key = 3807;\n\n/// Server error specific to mysql. Error number: 3808, symbol: ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_ROTATE_LOGS.\nBOOST_INLINE_CONSTEXPR int er_binlog_master_key_rotation_fail_to_rotate_logs = 3808;\n\n/// Server error specific to mysql. Error number: 3809, symbol: ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_REENCRYPT_LOG.\nBOOST_INLINE_CONSTEXPR int er_binlog_master_key_rotation_fail_to_reencrypt_log = 3809;\n\n/// Server error specific to mysql. Error number: 3810, symbol: ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_CLEANUP_UNUSED_KEYS.\nBOOST_INLINE_CONSTEXPR int er_binlog_master_key_rotation_fail_to_cleanup_unused_keys = 3810;\n\n/// Server error specific to mysql. Error number: 3811, symbol: ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_CLEANUP_AUX_KEY.\nBOOST_INLINE_CONSTEXPR int er_binlog_master_key_rotation_fail_to_cleanup_aux_key = 3811;\n\n/// Server error specific to mysql. Error number: 3812, symbol: ER_NON_BOOLEAN_EXPR_FOR_CHECK_CONSTRAINT.\nBOOST_INLINE_CONSTEXPR int er_non_boolean_expr_for_check_constraint = 3812;\n\n/// Server error specific to mysql. Error number: 3813, symbol: ER_COLUMN_CHECK_CONSTRAINT_REFERENCES_OTHER_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_column_check_constraint_references_other_column = 3813;\n\n/// Server error specific to mysql. Error number: 3814, symbol: ER_CHECK_CONSTRAINT_NAMED_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_named_function_is_not_allowed = 3814;\n\n/// Server error specific to mysql. Error number: 3815, symbol: ER_CHECK_CONSTRAINT_FUNCTION_IS_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_function_is_not_allowed = 3815;\n\n/// Server error specific to mysql. Error number: 3816, symbol: ER_CHECK_CONSTRAINT_VARIABLES.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_variables = 3816;\n\n/// Server error specific to mysql. Error number: 3817, symbol: ER_CHECK_CONSTRAINT_ROW_VALUE.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_row_value = 3817;\n\n/// Server error specific to mysql. Error number: 3818, symbol: ER_CHECK_CONSTRAINT_REFERS_AUTO_INCREMENT_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_refers_auto_increment_column = 3818;\n\n/// Server error specific to mysql. Error number: 3819, symbol: ER_CHECK_CONSTRAINT_VIOLATED.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_violated = 3819;\n\n/// Server error specific to mysql. Error number: 3820, symbol: ER_CHECK_CONSTRAINT_REFERS_UNKNOWN_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_refers_unknown_column = 3820;\n\n/// Server error specific to mysql. Error number: 3821, symbol: ER_CHECK_CONSTRAINT_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_not_found = 3821;\n\n/// Server error specific to mysql. Error number: 3822, symbol: ER_CHECK_CONSTRAINT_DUP_NAME.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_dup_name = 3822;\n\n/// Server error specific to mysql. Error number: 3823, symbol: ER_CHECK_CONSTRAINT_CLAUSE_USING_FK_REFER_ACTION_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_check_constraint_clause_using_fk_refer_action_column = 3823;\n\n/// Server error specific to mysql. Error number: 3824, symbol: WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB.\nBOOST_INLINE_CONSTEXPR int warn_unencrypted_table_in_encrypted_db = 3824;\n\n/// Server error specific to mysql. Error number: 3825, symbol: ER_INVALID_ENCRYPTION_REQUEST.\nBOOST_INLINE_CONSTEXPR int er_invalid_encryption_request = 3825;\n\n/// Server error specific to mysql. Error number: 3826, symbol: ER_CANNOT_SET_TABLE_ENCRYPTION.\nBOOST_INLINE_CONSTEXPR int er_cannot_set_table_encryption = 3826;\n\n/// Server error specific to mysql. Error number: 3827, symbol: ER_CANNOT_SET_DATABASE_ENCRYPTION.\nBOOST_INLINE_CONSTEXPR int er_cannot_set_database_encryption = 3827;\n\n/// Server error specific to mysql. Error number: 3828, symbol: ER_CANNOT_SET_TABLESPACE_ENCRYPTION.\nBOOST_INLINE_CONSTEXPR int er_cannot_set_tablespace_encryption = 3828;\n\n/// Server error specific to mysql. Error number: 3829, symbol: ER_TABLESPACE_CANNOT_BE_ENCRYPTED.\nBOOST_INLINE_CONSTEXPR int er_tablespace_cannot_be_encrypted = 3829;\n\n/// Server error specific to mysql. Error number: 3830, symbol: ER_TABLESPACE_CANNOT_BE_DECRYPTED.\nBOOST_INLINE_CONSTEXPR int er_tablespace_cannot_be_decrypted = 3830;\n\n/// Server error specific to mysql. Error number: 3831, symbol: ER_TABLESPACE_TYPE_UNKNOWN.\nBOOST_INLINE_CONSTEXPR int er_tablespace_type_unknown = 3831;\n\n/// Server error specific to mysql. Error number: 3832, symbol: ER_TARGET_TABLESPACE_UNENCRYPTED.\nBOOST_INLINE_CONSTEXPR int er_target_tablespace_unencrypted = 3832;\n\n/// Server error specific to mysql. Error number: 3833, symbol: ER_CANNOT_USE_ENCRYPTION_CLAUSE.\nBOOST_INLINE_CONSTEXPR int er_cannot_use_encryption_clause = 3833;\n\n/// Server error specific to mysql. Error number: 3834, symbol: ER_INVALID_MULTIPLE_CLAUSES.\nBOOST_INLINE_CONSTEXPR int er_invalid_multiple_clauses = 3834;\n\n/// Server error specific to mysql. Error number: 3835, symbol: ER_UNSUPPORTED_USE_OF_GRANT_AS.\nBOOST_INLINE_CONSTEXPR int er_unsupported_use_of_grant_as = 3835;\n\n/// Server error specific to mysql. Error number: 3836, symbol: ER_UKNOWN_AUTH_ID_OR_ACCESS_DENIED_FOR_GRANT_AS.\nBOOST_INLINE_CONSTEXPR int er_uknown_auth_id_or_access_denied_for_grant_as = 3836;\n\n/// Server error specific to mysql. Error number: 3837, symbol: ER_DEPENDENT_BY_FUNCTIONAL_INDEX.\nBOOST_INLINE_CONSTEXPR int er_dependent_by_functional_index = 3837;\n\n/// Server error specific to mysql. Error number: 3838, symbol: ER_PLUGIN_NOT_EARLY.\nBOOST_INLINE_CONSTEXPR int er_plugin_not_early = 3838;\n\n/// Server error specific to mysql. Error number: 3839, symbol: ER_INNODB_REDO_LOG_ARCHIVE_START_SUBDIR_PATH.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_start_subdir_path = 3839;\n\n/// Server error specific to mysql. Error number: 3840, symbol: ER_INNODB_REDO_LOG_ARCHIVE_START_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_start_timeout = 3840;\n\n/// Server error specific to mysql. Error number: 3841, symbol: ER_INNODB_REDO_LOG_ARCHIVE_DIRS_INVALID.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_dirs_invalid = 3841;\n\n/// Server error specific to mysql. Error number: 3842, symbol: ER_INNODB_REDO_LOG_ARCHIVE_LABEL_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_label_not_found = 3842;\n\n/// Server error specific to mysql. Error number: 3843, symbol: ER_INNODB_REDO_LOG_ARCHIVE_DIR_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_dir_empty = 3843;\n\n/// Server error specific to mysql. Error number: 3844, symbol: ER_INNODB_REDO_LOG_ARCHIVE_NO_SUCH_DIR.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_no_such_dir = 3844;\n\n/// Server error specific to mysql. Error number: 3845, symbol: ER_INNODB_REDO_LOG_ARCHIVE_DIR_CLASH.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_dir_clash = 3845;\n\n/// Server error specific to mysql. Error number: 3846, symbol: ER_INNODB_REDO_LOG_ARCHIVE_DIR_PERMISSIONS.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_dir_permissions = 3846;\n\n/// Server error specific to mysql. Error number: 3847, symbol: ER_INNODB_REDO_LOG_ARCHIVE_FILE_CREATE.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_file_create = 3847;\n\n/// Server error specific to mysql. Error number: 3848, symbol: ER_INNODB_REDO_LOG_ARCHIVE_ACTIVE.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_active = 3848;\n\n/// Server error specific to mysql. Error number: 3849, symbol: ER_INNODB_REDO_LOG_ARCHIVE_INACTIVE.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_inactive = 3849;\n\n/// Server error specific to mysql. Error number: 3850, symbol: ER_INNODB_REDO_LOG_ARCHIVE_FAILED.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_failed = 3850;\n\n/// Server error specific to mysql. Error number: 3851, symbol: ER_INNODB_REDO_LOG_ARCHIVE_SESSION.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_log_archive_session = 3851;\n\n/// Server error specific to mysql. Error number: 3852, symbol: ER_STD_REGEX_ERROR.\nBOOST_INLINE_CONSTEXPR int er_std_regex_error = 3852;\n\n/// Server error specific to mysql. Error number: 3853, symbol: ER_INVALID_JSON_TYPE.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_type = 3853;\n\n/// Server error specific to mysql. Error number: 3854, symbol: ER_CANNOT_CONVERT_STRING.\nBOOST_INLINE_CONSTEXPR int er_cannot_convert_string = 3854;\n\n/// Server error specific to mysql. Error number: 3855, symbol: ER_DEPENDENT_BY_PARTITION_FUNC.\nBOOST_INLINE_CONSTEXPR int er_dependent_by_partition_func = 3855;\n\n/// Server error specific to mysql. Error number: 3856, symbol: ER_WARN_DEPRECATED_FLOAT_AUTO_INCREMENT.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_float_auto_increment = 3856;\n\n/// Server error specific to mysql. Error number: 3857, symbol: ER_RPL_CANT_STOP_SLAVE_WHILE_LOCKED_BACKUP.\nBOOST_INLINE_CONSTEXPR int er_rpl_cant_stop_slave_while_locked_backup = 3857;\n\n/// Server error specific to mysql. Error number: 3858, symbol: ER_WARN_DEPRECATED_FLOAT_DIGITS.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_float_digits = 3858;\n\n/// Server error specific to mysql. Error number: 3859, symbol: ER_WARN_DEPRECATED_FLOAT_UNSIGNED.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_float_unsigned = 3859;\n\n/// Server error specific to mysql. Error number: 3860, symbol: ER_WARN_DEPRECATED_INTEGER_DISPLAY_WIDTH.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_integer_display_width = 3860;\n\n/// Server error specific to mysql. Error number: 3861, symbol: ER_WARN_DEPRECATED_ZEROFILL.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_zerofill = 3861;\n\n/// Server error specific to mysql. Error number: 3862, symbol: ER_CLONE_DONOR.\nBOOST_INLINE_CONSTEXPR int er_clone_donor = 3862;\n\n/// Server error specific to mysql. Error number: 3863, symbol: ER_CLONE_PROTOCOL.\nBOOST_INLINE_CONSTEXPR int er_clone_protocol = 3863;\n\n/// Server error specific to mysql. Error number: 3864, symbol: ER_CLONE_DONOR_VERSION.\nBOOST_INLINE_CONSTEXPR int er_clone_donor_version = 3864;\n\n/// Server error specific to mysql. Error number: 3865, symbol: ER_CLONE_OS.\nBOOST_INLINE_CONSTEXPR int er_clone_os = 3865;\n\n/// Server error specific to mysql. Error number: 3866, symbol: ER_CLONE_PLATFORM.\nBOOST_INLINE_CONSTEXPR int er_clone_platform = 3866;\n\n/// Server error specific to mysql. Error number: 3867, symbol: ER_CLONE_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_clone_charset = 3867;\n\n/// Server error specific to mysql. Error number: 3868, symbol: ER_CLONE_CONFIG.\nBOOST_INLINE_CONSTEXPR int er_clone_config = 3868;\n\n/// Server error specific to mysql. Error number: 3869, symbol: ER_CLONE_SYS_CONFIG.\nBOOST_INLINE_CONSTEXPR int er_clone_sys_config = 3869;\n\n/// Server error specific to mysql. Error number: 3870, symbol: ER_CLONE_PLUGIN_MATCH.\nBOOST_INLINE_CONSTEXPR int er_clone_plugin_match = 3870;\n\n/// Server error specific to mysql. Error number: 3871, symbol: ER_CLONE_LOOPBACK.\nBOOST_INLINE_CONSTEXPR int er_clone_loopback = 3871;\n\n/// Server error specific to mysql. Error number: 3872, symbol: ER_CLONE_ENCRYPTION.\nBOOST_INLINE_CONSTEXPR int er_clone_encryption = 3872;\n\n/// Server error specific to mysql. Error number: 3873, symbol: ER_CLONE_DISK_SPACE.\nBOOST_INLINE_CONSTEXPR int er_clone_disk_space = 3873;\n\n/// Server error specific to mysql. Error number: 3874, symbol: ER_CLONE_IN_PROGRESS.\nBOOST_INLINE_CONSTEXPR int er_clone_in_progress = 3874;\n\n/// Server error specific to mysql. Error number: 3875, symbol: ER_CLONE_DISALLOWED.\nBOOST_INLINE_CONSTEXPR int er_clone_disallowed = 3875;\n\n/// Server error specific to mysql. Error number: 3876, symbol: ER_CANNOT_GRANT_ROLES_TO_ANONYMOUS_USER.\nBOOST_INLINE_CONSTEXPR int er_cannot_grant_roles_to_anonymous_user = 3876;\n\n/// Server error specific to mysql. Error number: 3877, symbol: ER_SECONDARY_ENGINE_PLUGIN.\nBOOST_INLINE_CONSTEXPR int er_secondary_engine_plugin = 3877;\n\n/// Server error specific to mysql. Error number: 3878, symbol: ER_SECOND_PASSWORD_CANNOT_BE_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_second_password_cannot_be_empty = 3878;\n\n/// Server error specific to mysql. Error number: 3879, symbol: ER_DB_ACCESS_DENIED.\nBOOST_INLINE_CONSTEXPR int er_db_access_denied = 3879;\n\n/// Server error specific to mysql. Error number: 3880, symbol: ER_DA_AUTH_ID_WITH_SYSTEM_USER_PRIV_IN_MANDATORY_ROLES.\nBOOST_INLINE_CONSTEXPR int er_da_auth_id_with_system_user_priv_in_mandatory_roles = 3880;\n\n/// Server error specific to mysql. Error number: 3881, symbol: ER_DA_RPL_GTID_TABLE_CANNOT_OPEN.\nBOOST_INLINE_CONSTEXPR int er_da_rpl_gtid_table_cannot_open = 3881;\n\n/// Server error specific to mysql. Error number: 3882, symbol: ER_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT.\nBOOST_INLINE_CONSTEXPR int er_geometry_in_unknown_length_unit = 3882;\n\n/// Server error specific to mysql. Error number: 3883, symbol: ER_DA_PLUGIN_INSTALL_ERROR.\nBOOST_INLINE_CONSTEXPR int er_da_plugin_install_error = 3883;\n\n/// Server error specific to mysql. Error number: 3884, symbol: ER_NO_SESSION_TEMP.\nBOOST_INLINE_CONSTEXPR int er_no_session_temp = 3884;\n\n/// Server error specific to mysql. Error number: 3885, symbol: ER_DA_UNKNOWN_ERROR_NUMBER.\nBOOST_INLINE_CONSTEXPR int er_da_unknown_error_number = 3885;\n\n/// Server error specific to mysql. Error number: 3886, symbol: ER_COLUMN_CHANGE_SIZE.\nBOOST_INLINE_CONSTEXPR int er_column_change_size = 3886;\n\n/// Server error specific to mysql. Error number: 3887, symbol: ER_REGEXP_INVALID_CAPTURE_GROUP_NAME.\nBOOST_INLINE_CONSTEXPR int er_regexp_invalid_capture_group_name = 3887;\n\n/// Server error specific to mysql. Error number: 3888, symbol: ER_DA_SSL_LIBRARY_ERROR.\nBOOST_INLINE_CONSTEXPR int er_da_ssl_library_error = 3888;\n\n/// Server error specific to mysql. Error number: 3889, symbol: ER_SECONDARY_ENGINE.\nBOOST_INLINE_CONSTEXPR int er_secondary_engine = 3889;\n\n/// Server error specific to mysql. Error number: 3890, symbol: ER_SECONDARY_ENGINE_DDL.\nBOOST_INLINE_CONSTEXPR int er_secondary_engine_ddl = 3890;\n\n/// Server error specific to mysql. Error number: 3891, symbol: ER_INCORRECT_CURRENT_PASSWORD.\nBOOST_INLINE_CONSTEXPR int er_incorrect_current_password = 3891;\n\n/// Server error specific to mysql. Error number: 3892, symbol: ER_MISSING_CURRENT_PASSWORD.\nBOOST_INLINE_CONSTEXPR int er_missing_current_password = 3892;\n\n/// Server error specific to mysql. Error number: 3893, symbol: ER_CURRENT_PASSWORD_NOT_REQUIRED.\nBOOST_INLINE_CONSTEXPR int er_current_password_not_required = 3893;\n\n/// Server error specific to mysql. Error number: 3894, symbol: ER_PASSWORD_CANNOT_BE_RETAINED_ON_PLUGIN_CHANGE.\nBOOST_INLINE_CONSTEXPR int er_password_cannot_be_retained_on_plugin_change = 3894;\n\n/// Server error specific to mysql. Error number: 3895, symbol: ER_CURRENT_PASSWORD_CANNOT_BE_RETAINED.\nBOOST_INLINE_CONSTEXPR int er_current_password_cannot_be_retained = 3895;\n\n/// Server error specific to mysql. Error number: 3896, symbol: ER_PARTIAL_REVOKES_EXIST.\nBOOST_INLINE_CONSTEXPR int er_partial_revokes_exist = 3896;\n\n/// Server error specific to mysql. Error number: 3897, symbol: ER_CANNOT_GRANT_SYSTEM_PRIV_TO_MANDATORY_ROLE.\nBOOST_INLINE_CONSTEXPR int er_cannot_grant_system_priv_to_mandatory_role = 3897;\n\n/// Server error specific to mysql. Error number: 3898, symbol: ER_XA_REPLICATION_FILTERS.\nBOOST_INLINE_CONSTEXPR int er_xa_replication_filters = 3898;\n\n/// Server error specific to mysql. Error number: 3899, symbol: ER_UNSUPPORTED_SQL_MODE.\nBOOST_INLINE_CONSTEXPR int er_unsupported_sql_mode = 3899;\n\n/// Server error specific to mysql. Error number: 3900, symbol: ER_REGEXP_INVALID_FLAG.\nBOOST_INLINE_CONSTEXPR int er_regexp_invalid_flag = 3900;\n\n/// Server error specific to mysql. Error number: 3901, symbol: ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_partial_revoke_and_db_grant_both_exists = 3901;\n\n/// Server error specific to mysql. Error number: 3902, symbol: ER_UNIT_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_unit_not_found = 3902;\n\n/// Server error specific to mysql. Error number: 3903, symbol: ER_INVALID_JSON_VALUE_FOR_FUNC_INDEX.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_value_for_func_index = 3903;\n\n/// Server error specific to mysql. Error number: 3904, symbol: ER_JSON_VALUE_OUT_OF_RANGE_FOR_FUNC_INDEX.\nBOOST_INLINE_CONSTEXPR int er_json_value_out_of_range_for_func_index = 3904;\n\n/// Server error specific to mysql. Error number: 3905, symbol: ER_EXCEEDED_MV_KEYS_NUM.\nBOOST_INLINE_CONSTEXPR int er_exceeded_mv_keys_num = 3905;\n\n/// Server error specific to mysql. Error number: 3906, symbol: ER_EXCEEDED_MV_KEYS_SPACE.\nBOOST_INLINE_CONSTEXPR int er_exceeded_mv_keys_space = 3906;\n\n/// Server error specific to mysql. Error number: 3907, symbol: ER_FUNCTIONAL_INDEX_DATA_IS_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_functional_index_data_is_too_long = 3907;\n\n/// Server error specific to mysql. Error number: 3908, symbol: ER_WRONG_MVI_VALUE.\nBOOST_INLINE_CONSTEXPR int er_wrong_mvi_value = 3908;\n\n/// Server error specific to mysql. Error number: 3909, symbol: ER_WARN_FUNC_INDEX_NOT_APPLICABLE.\nBOOST_INLINE_CONSTEXPR int er_warn_func_index_not_applicable = 3909;\n\n/// Server error specific to mysql. Error number: 3910, symbol: ER_GRP_RPL_UDF_ERROR.\nBOOST_INLINE_CONSTEXPR int er_grp_rpl_udf_error = 3910;\n\n/// Server error specific to mysql. Error number: 3911, symbol: ER_UPDATE_GTID_PURGED_WITH_GR.\nBOOST_INLINE_CONSTEXPR int er_update_gtid_purged_with_gr = 3911;\n\n/// Server error specific to mysql. Error number: 3912, symbol: ER_GROUPING_ON_TIMESTAMP_IN_DST.\nBOOST_INLINE_CONSTEXPR int er_grouping_on_timestamp_in_dst = 3912;\n\n/// Server error specific to mysql. Error number: 3913, symbol: ER_TABLE_NAME_CAUSES_TOO_LONG_PATH.\nBOOST_INLINE_CONSTEXPR int er_table_name_causes_too_long_path = 3913;\n\n/// Server error specific to mysql. Error number: 3914, symbol: ER_AUDIT_LOG_INSUFFICIENT_PRIVILEGE.\nBOOST_INLINE_CONSTEXPR int er_audit_log_insufficient_privilege = 3914;\n\n/// Server error specific to mysql. Error number: 3916, symbol: ER_DA_GRP_RPL_STARTED_AUTO_REJOIN.\nBOOST_INLINE_CONSTEXPR int er_da_grp_rpl_started_auto_rejoin = 3916;\n\n/// Server error specific to mysql. Error number: 3917, symbol: ER_SYSVAR_CHANGE_DURING_QUERY.\nBOOST_INLINE_CONSTEXPR int er_sysvar_change_during_query = 3917;\n\n/// Server error specific to mysql. Error number: 3918, symbol: ER_GLOBSTAT_CHANGE_DURING_QUERY.\nBOOST_INLINE_CONSTEXPR int er_globstat_change_during_query = 3918;\n\n/// Server error specific to mysql. Error number: 3919, symbol: ER_GRP_RPL_MESSAGE_SERVICE_INIT_FAILURE.\nBOOST_INLINE_CONSTEXPR int er_grp_rpl_message_service_init_failure = 3919;\n\n/// Server error specific to mysql. Error number: 3920, symbol: ER_CHANGE_MASTER_WRONG_COMPRESSION_ALGORITHM_CLIENT.\nBOOST_INLINE_CONSTEXPR int er_change_master_wrong_compression_algorithm_client = 3920;\n\n/// Server error specific to mysql. Error number: 3921, symbol: ER_CHANGE_MASTER_WRONG_COMPRESSION_LEVEL_CLIENT.\nBOOST_INLINE_CONSTEXPR int er_change_master_wrong_compression_level_client = 3921;\n\n/// Server error specific to mysql. Error number: 3922, symbol: ER_WRONG_COMPRESSION_ALGORITHM_CLIENT.\nBOOST_INLINE_CONSTEXPR int er_wrong_compression_algorithm_client = 3922;\n\n/// Server error specific to mysql. Error number: 3923, symbol: ER_WRONG_COMPRESSION_LEVEL_CLIENT.\nBOOST_INLINE_CONSTEXPR int er_wrong_compression_level_client = 3923;\n\n/// Server error specific to mysql. Error number: 3924, symbol: ER_CHANGE_MASTER_WRONG_COMPRESSION_ALGORITHM_LIST_CLIENT.\nBOOST_INLINE_CONSTEXPR int er_change_master_wrong_compression_algorithm_list_client = 3924;\n\n/// Server error specific to mysql. Error number: 3925, symbol: ER_CLIENT_PRIVILEGE_CHECKS_USER_CANNOT_BE_ANONYMOUS.\nBOOST_INLINE_CONSTEXPR int er_client_privilege_checks_user_cannot_be_anonymous = 3925;\n\n/// Server error specific to mysql. Error number: 3926, symbol: ER_CLIENT_PRIVILEGE_CHECKS_USER_DOES_NOT_EXIST.\nBOOST_INLINE_CONSTEXPR int er_client_privilege_checks_user_does_not_exist = 3926;\n\n/// Server error specific to mysql. Error number: 3927, symbol: ER_CLIENT_PRIVILEGE_CHECKS_USER_CORRUPT.\nBOOST_INLINE_CONSTEXPR int er_client_privilege_checks_user_corrupt = 3927;\n\n/// Server error specific to mysql. Error number: 3928, symbol: ER_CLIENT_PRIVILEGE_CHECKS_USER_NEEDS_RPL_APPLIER_PRIV.\nBOOST_INLINE_CONSTEXPR int er_client_privilege_checks_user_needs_rpl_applier_priv = 3928;\n\n/// Server error specific to mysql. Error number: 3929, symbol: ER_WARN_DA_PRIVILEGE_NOT_REGISTERED.\nBOOST_INLINE_CONSTEXPR int er_warn_da_privilege_not_registered = 3929;\n\n/// Server error specific to mysql. Error number: 3930, symbol: ER_CLIENT_KEYRING_UDF_KEY_INVALID.\nBOOST_INLINE_CONSTEXPR int er_client_keyring_udf_key_invalid = 3930;\n\n/// Server error specific to mysql. Error number: 3931, symbol: ER_CLIENT_KEYRING_UDF_KEY_TYPE_INVALID.\nBOOST_INLINE_CONSTEXPR int er_client_keyring_udf_key_type_invalid = 3931;\n\n/// Server error specific to mysql. Error number: 3932, symbol: ER_CLIENT_KEYRING_UDF_KEY_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_client_keyring_udf_key_too_long = 3932;\n\n/// Server error specific to mysql. Error number: 3933, symbol: ER_CLIENT_KEYRING_UDF_KEY_TYPE_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_client_keyring_udf_key_type_too_long = 3933;\n\n/// Server error specific to mysql. Error number: 3934, symbol: ER_JSON_SCHEMA_VALIDATION_ERROR_WITH_DETAILED_REPORT.\nBOOST_INLINE_CONSTEXPR int er_json_schema_validation_error_with_detailed_report = 3934;\n\n/// Server error specific to mysql. Error number: 3935, symbol: ER_DA_UDF_INVALID_CHARSET_SPECIFIED.\nBOOST_INLINE_CONSTEXPR int er_da_udf_invalid_charset_specified = 3935;\n\n/// Server error specific to mysql. Error number: 3936, symbol: ER_DA_UDF_INVALID_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_da_udf_invalid_charset = 3936;\n\n/// Server error specific to mysql. Error number: 3937, symbol: ER_DA_UDF_INVALID_COLLATION.\nBOOST_INLINE_CONSTEXPR int er_da_udf_invalid_collation = 3937;\n\n/// Server error specific to mysql. Error number: 3938, symbol: ER_DA_UDF_INVALID_EXTENSION_ARGUMENT_TYPE.\nBOOST_INLINE_CONSTEXPR int er_da_udf_invalid_extension_argument_type = 3938;\n\n/// Server error specific to mysql. Error number: 3939, symbol: ER_MULTIPLE_CONSTRAINTS_WITH_SAME_NAME.\nBOOST_INLINE_CONSTEXPR int er_multiple_constraints_with_same_name = 3939;\n\n/// Server error specific to mysql. Error number: 3940, symbol: ER_CONSTRAINT_NOT_FOUND.\nBOOST_INLINE_CONSTEXPR int er_constraint_not_found = 3940;\n\n/// Server error specific to mysql. Error number: 3941, symbol: ER_ALTER_CONSTRAINT_ENFORCEMENT_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_alter_constraint_enforcement_not_supported = 3941;\n\n/// Server error specific to mysql. Error number: 3942, symbol: ER_TABLE_VALUE_CONSTRUCTOR_MUST_HAVE_COLUMNS.\nBOOST_INLINE_CONSTEXPR int er_table_value_constructor_must_have_columns = 3942;\n\n/// Server error specific to mysql. Error number: 3943, symbol: ER_TABLE_VALUE_CONSTRUCTOR_CANNOT_HAVE_DEFAULT.\nBOOST_INLINE_CONSTEXPR int er_table_value_constructor_cannot_have_default = 3943;\n\n/// Server error specific to mysql. Error number: 3944, symbol: ER_CLIENT_QUERY_FAILURE_INVALID_NON_ROW_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_client_query_failure_invalid_non_row_format = 3944;\n\n/// Server error specific to mysql. Error number: 3945, symbol: ER_REQUIRE_ROW_FORMAT_INVALID_VALUE.\nBOOST_INLINE_CONSTEXPR int er_require_row_format_invalid_value = 3945;\n\n/// Server error specific to mysql. Error number: 3946, symbol: ER_FAILED_TO_DETERMINE_IF_ROLE_IS_MANDATORY.\nBOOST_INLINE_CONSTEXPR int er_failed_to_determine_if_role_is_mandatory = 3946;\n\n/// Server error specific to mysql. Error number: 3947, symbol: ER_FAILED_TO_FETCH_MANDATORY_ROLE_LIST.\nBOOST_INLINE_CONSTEXPR int er_failed_to_fetch_mandatory_role_list = 3947;\n\n/// Server error specific to mysql. Error number: 3948, symbol: ER_CLIENT_LOCAL_FILES_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_client_local_files_disabled = 3948;\n\n/// Server error specific to mysql. Error number: 3949, symbol: ER_IMP_INCOMPATIBLE_CFG_VERSION.\nBOOST_INLINE_CONSTEXPR int er_imp_incompatible_cfg_version = 3949;\n\n/// Server error specific to mysql. Error number: 3950, symbol: ER_DA_OOM.\nBOOST_INLINE_CONSTEXPR int er_da_oom = 3950;\n\n/// Server error specific to mysql. Error number: 3951, symbol: ER_DA_UDF_INVALID_ARGUMENT_TO_SET_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_da_udf_invalid_argument_to_set_charset = 3951;\n\n/// Server error specific to mysql. Error number: 3952, symbol: ER_DA_UDF_INVALID_RETURN_TYPE_TO_SET_CHARSET.\nBOOST_INLINE_CONSTEXPR int er_da_udf_invalid_return_type_to_set_charset = 3952;\n\n/// Server error specific to mysql. Error number: 3953, symbol: ER_MULTIPLE_INTO_CLAUSES.\nBOOST_INLINE_CONSTEXPR int er_multiple_into_clauses = 3953;\n\n/// Server error specific to mysql. Error number: 3954, symbol: ER_MISPLACED_INTO.\nBOOST_INLINE_CONSTEXPR int er_misplaced_into = 3954;\n\n/// Server error specific to mysql. Error number: 3955, symbol: ER_USER_ACCESS_DENIED_FOR_USER_ACCOUNT_BLOCKED_BY_PASSWORD_LOCK.\nBOOST_INLINE_CONSTEXPR int er_user_access_denied_for_user_account_blocked_by_password_lock = 3955;\n\n/// Server error specific to mysql. Error number: 3956, symbol: ER_WARN_DEPRECATED_YEAR_UNSIGNED.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_year_unsigned = 3956;\n\n/// Server error specific to mysql. Error number: 3957, symbol: ER_CLONE_NETWORK_PACKET.\nBOOST_INLINE_CONSTEXPR int er_clone_network_packet = 3957;\n\n/// Server error specific to mysql. Error number: 3958, symbol: ER_SDI_OPERATION_FAILED_MISSING_RECORD.\nBOOST_INLINE_CONSTEXPR int er_sdi_operation_failed_missing_record = 3958;\n\n/// Server error specific to mysql. Error number: 3959, symbol: ER_DEPENDENT_BY_CHECK_CONSTRAINT.\nBOOST_INLINE_CONSTEXPR int er_dependent_by_check_constraint = 3959;\n\n/// Server error specific to mysql. Error number: 3960, symbol: ER_GRP_OPERATION_NOT_ALLOWED_GR_MUST_STOP.\nBOOST_INLINE_CONSTEXPR int er_grp_operation_not_allowed_gr_must_stop = 3960;\n\n/// Server error specific to mysql. Error number: 3961, symbol: ER_WARN_DEPRECATED_JSON_TABLE_ON_ERROR_ON_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_json_table_on_error_on_empty = 3961;\n\n/// Server error specific to mysql. Error number: 3962, symbol: ER_WARN_DEPRECATED_INNER_INTO.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_inner_into = 3962;\n\n/// Server error specific to mysql. Error number: 3963, symbol: ER_WARN_DEPRECATED_VALUES_FUNCTION_ALWAYS_NULL.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_values_function_always_null = 3963;\n\n/// Server error specific to mysql. Error number: 3964, symbol: ER_WARN_DEPRECATED_SQL_CALC_FOUND_ROWS.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_sql_calc_found_rows = 3964;\n\n/// Server error specific to mysql. Error number: 3965, symbol: ER_WARN_DEPRECATED_FOUND_ROWS.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_found_rows = 3965;\n\n/// Server error specific to mysql. Error number: 3966, symbol: ER_MISSING_JSON_VALUE.\nBOOST_INLINE_CONSTEXPR int er_missing_json_value = 3966;\n\n/// Server error specific to mysql. Error number: 3967, symbol: ER_MULTIPLE_JSON_VALUES.\nBOOST_INLINE_CONSTEXPR int er_multiple_json_values = 3967;\n\n/// Server error specific to mysql. Error number: 3968, symbol: ER_HOSTNAME_TOO_LONG.\nBOOST_INLINE_CONSTEXPR int er_hostname_too_long = 3968;\n\n/// Server error specific to mysql. Error number: 3969, symbol: ER_WARN_CLIENT_DEPRECATED_PARTITION_PREFIX_KEY.\nBOOST_INLINE_CONSTEXPR int er_warn_client_deprecated_partition_prefix_key = 3969;\n\n/// Server error specific to mysql. Error number: 3970, symbol: ER_GROUP_REPLICATION_USER_EMPTY_MSG.\nBOOST_INLINE_CONSTEXPR int er_group_replication_user_empty_msg = 3970;\n\n/// Server error specific to mysql. Error number: 3971, symbol: ER_GROUP_REPLICATION_USER_MANDATORY_MSG.\nBOOST_INLINE_CONSTEXPR int er_group_replication_user_mandatory_msg = 3971;\n\n/// Server error specific to mysql. Error number: 3972, symbol: ER_GROUP_REPLICATION_PASSWORD_LENGTH.\nBOOST_INLINE_CONSTEXPR int er_group_replication_password_length = 3972;\n\n/// Server error specific to mysql. Error number: 3973, symbol: ER_SUBQUERY_TRANSFORM_REJECTED.\nBOOST_INLINE_CONSTEXPR int er_subquery_transform_rejected = 3973;\n\n/// Server error specific to mysql. Error number: 3974, symbol: ER_DA_GRP_RPL_RECOVERY_ENDPOINT_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_da_grp_rpl_recovery_endpoint_format = 3974;\n\n/// Server error specific to mysql. Error number: 3975, symbol: ER_DA_GRP_RPL_RECOVERY_ENDPOINT_INVALID.\nBOOST_INLINE_CONSTEXPR int er_da_grp_rpl_recovery_endpoint_invalid = 3975;\n\n/// Server error specific to mysql. Error number: 3976, symbol: ER_WRONG_VALUE_FOR_VAR_PLUS_ACTIONABLE_PART.\nBOOST_INLINE_CONSTEXPR int er_wrong_value_for_var_plus_actionable_part = 3976;\n\n/// Server error specific to mysql. Error number: 3977, symbol: ER_STATEMENT_NOT_ALLOWED_AFTER_START_TRANSACTION.\nBOOST_INLINE_CONSTEXPR int er_statement_not_allowed_after_start_transaction = 3977;\n\n/// Server error specific to mysql. Error number: 3978, symbol: ER_FOREIGN_KEY_WITH_ATOMIC_CREATE_SELECT.\nBOOST_INLINE_CONSTEXPR int er_foreign_key_with_atomic_create_select = 3978;\n\n/// Server error specific to mysql. Error number: 3979, symbol: ER_NOT_ALLOWED_WITH_START_TRANSACTION.\nBOOST_INLINE_CONSTEXPR int er_not_allowed_with_start_transaction = 3979;\n\n/// Server error specific to mysql. Error number: 3980, symbol: ER_INVALID_JSON_ATTRIBUTE.\nBOOST_INLINE_CONSTEXPR int er_invalid_json_attribute = 3980;\n\n/// Server error specific to mysql. Error number: 3981, symbol: ER_ENGINE_ATTRIBUTE_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_engine_attribute_not_supported = 3981;\n\n/// Server error specific to mysql. Error number: 3982, symbol: ER_INVALID_USER_ATTRIBUTE_JSON.\nBOOST_INLINE_CONSTEXPR int er_invalid_user_attribute_json = 3982;\n\n/// Server error specific to mysql. Error number: 3983, symbol: ER_INNODB_REDO_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_disabled = 3983;\n\n/// Server error specific to mysql. Error number: 3984, symbol: ER_INNODB_REDO_ARCHIVING_ENABLED.\nBOOST_INLINE_CONSTEXPR int er_innodb_redo_archiving_enabled = 3984;\n\n/// Server error specific to mysql. Error number: 3985, symbol: ER_MDL_OUT_OF_RESOURCES.\nBOOST_INLINE_CONSTEXPR int er_mdl_out_of_resources = 3985;\n\n/// Server error specific to mysql. Error number: 3986, symbol: ER_IMPLICIT_COMPARISON_FOR_JSON.\nBOOST_INLINE_CONSTEXPR int er_implicit_comparison_for_json = 3986;\n\n/// Server error specific to mysql. Error number: 3987, symbol: ER_FUNCTION_DOES_NOT_SUPPORT_CHARACTER_SET.\nBOOST_INLINE_CONSTEXPR int er_function_does_not_support_character_set = 3987;\n\n/// Server error specific to mysql. Error number: 3988, symbol: ER_IMPOSSIBLE_STRING_CONVERSION.\nBOOST_INLINE_CONSTEXPR int er_impossible_string_conversion = 3988;\n\n/// Server error specific to mysql. Error number: 3989, symbol: ER_SCHEMA_READ_ONLY.\nBOOST_INLINE_CONSTEXPR int er_schema_read_only = 3989;\n\n/// Server error specific to mysql. Error number: 3990, symbol: ER_RPL_ASYNC_RECONNECT_GTID_MODE_OFF.\nBOOST_INLINE_CONSTEXPR int er_rpl_async_reconnect_gtid_mode_off = 3990;\n\n/// Server error specific to mysql. Error number: 3991, symbol: ER_RPL_ASYNC_RECONNECT_AUTO_POSITION_OFF.\nBOOST_INLINE_CONSTEXPR int er_rpl_async_reconnect_auto_position_off = 3991;\n\n/// Server error specific to mysql. Error number: 3992, symbol: ER_DISABLE_GTID_MODE_REQUIRES_ASYNC_RECONNECT_OFF.\nBOOST_INLINE_CONSTEXPR int er_disable_gtid_mode_requires_async_reconnect_off = 3992;\n\n/// Server error specific to mysql. Error number: 3993, symbol: ER_DISABLE_AUTO_POSITION_REQUIRES_ASYNC_RECONNECT_OFF.\nBOOST_INLINE_CONSTEXPR int er_disable_auto_position_requires_async_reconnect_off = 3993;\n\n/// Server error specific to mysql. Error number: 3994, symbol: ER_INVALID_PARAMETER_USE.\nBOOST_INLINE_CONSTEXPR int er_invalid_parameter_use = 3994;\n\n/// Server error specific to mysql. Error number: 3995, symbol: ER_CHARACTER_SET_MISMATCH.\nBOOST_INLINE_CONSTEXPR int er_character_set_mismatch = 3995;\n\n/// Server error specific to mysql. Error number: 3996, symbol: ER_WARN_VAR_VALUE_CHANGE_NOT_SUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_warn_var_value_change_not_supported = 3996;\n\n/// Server error specific to mysql. Error number: 3997, symbol: ER_INVALID_TIME_ZONE_INTERVAL.\nBOOST_INLINE_CONSTEXPR int er_invalid_time_zone_interval = 3997;\n\n/// Server error specific to mysql. Error number: 3998, symbol: ER_INVALID_CAST.\nBOOST_INLINE_CONSTEXPR int er_invalid_cast = 3998;\n\n/// Server error specific to mysql. Error number: 3999, symbol: ER_HYPERGRAPH_NOT_SUPPORTED_YET.\nBOOST_INLINE_CONSTEXPR int er_hypergraph_not_supported_yet = 3999;\n\n/// Server error specific to mysql. Error number: 4000, symbol: ER_WARN_HYPERGRAPH_EXPERIMENTAL.\nBOOST_INLINE_CONSTEXPR int er_warn_hypergraph_experimental = 4000;\n\n/// Server error specific to mysql. Error number: 4001, symbol: ER_DA_NO_ERROR_LOG_PARSER_CONFIGURED.\nBOOST_INLINE_CONSTEXPR int er_da_no_error_log_parser_configured = 4001;\n\n/// Server error specific to mysql. Error number: 4002, symbol: ER_DA_ERROR_LOG_TABLE_DISABLED.\nBOOST_INLINE_CONSTEXPR int er_da_error_log_table_disabled = 4002;\n\n/// Server error specific to mysql. Error number: 4003, symbol: ER_DA_ERROR_LOG_MULTIPLE_FILTERS.\nBOOST_INLINE_CONSTEXPR int er_da_error_log_multiple_filters = 4003;\n\n/// Server error specific to mysql. Error number: 4004, symbol: ER_DA_CANT_OPEN_ERROR_LOG.\nBOOST_INLINE_CONSTEXPR int er_da_cant_open_error_log = 4004;\n\n/// Server error specific to mysql. Error number: 4005, symbol: ER_USER_REFERENCED_AS_DEFINER.\nBOOST_INLINE_CONSTEXPR int er_user_referenced_as_definer = 4005;\n\n/// Server error specific to mysql. Error number: 4006, symbol: ER_CANNOT_USER_REFERENCED_AS_DEFINER.\nBOOST_INLINE_CONSTEXPR int er_cannot_user_referenced_as_definer = 4006;\n\n/// Server error specific to mysql. Error number: 4007, symbol: ER_REGEX_NUMBER_TOO_BIG.\nBOOST_INLINE_CONSTEXPR int er_regex_number_too_big = 4007;\n\n/// Server error specific to mysql. Error number: 4008, symbol: ER_SPVAR_NONINTEGER_TYPE.\nBOOST_INLINE_CONSTEXPR int er_spvar_noninteger_type = 4008;\n\n/// Server error specific to mysql. Error number: 4009, symbol: WARN_UNSUPPORTED_ACL_TABLES_READ.\nBOOST_INLINE_CONSTEXPR int warn_unsupported_acl_tables_read = 4009;\n\n/// Server error specific to mysql. Error number: 4010, symbol: ER_BINLOG_UNSAFE_ACL_TABLE_READ_IN_DML_DDL.\nBOOST_INLINE_CONSTEXPR int er_binlog_unsafe_acl_table_read_in_dml_ddl = 4010;\n\n/// Server error specific to mysql. Error number: 4011, symbol: ER_STOP_REPLICA_MONITOR_IO_THREAD_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_stop_replica_monitor_io_thread_timeout = 4011;\n\n/// Server error specific to mysql. Error number: 4012, symbol: ER_STARTING_REPLICA_MONITOR_IO_THREAD.\nBOOST_INLINE_CONSTEXPR int er_starting_replica_monitor_io_thread = 4012;\n\n/// Server error specific to mysql. Error number: 4013, symbol: ER_CANT_USE_ANONYMOUS_TO_GTID_WITH_GTID_MODE_NOT_ON.\nBOOST_INLINE_CONSTEXPR int er_cant_use_anonymous_to_gtid_with_gtid_mode_not_on = 4013;\n\n/// Server error specific to mysql. Error number: 4014, symbol: ER_CANT_COMBINE_ANONYMOUS_TO_GTID_AND_AUTOPOSITION.\nBOOST_INLINE_CONSTEXPR int er_cant_combine_anonymous_to_gtid_and_autoposition = 4014;\n\n/// Server error specific to mysql. Error number: 4015, symbol: ER_ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS_REQUIRES_GTID_MODE_ON.\nBOOST_INLINE_CONSTEXPR int er_assign_gtids_to_anonymous_transactions_requires_gtid_mode_on = 4015;\n\n/// Server error specific to mysql. Error number: 4016, symbol: ER_SQL_SLAVE_SKIP_COUNTER_USED_WITH_GTID_MODE_ON.\nBOOST_INLINE_CONSTEXPR int er_sql_slave_skip_counter_used_with_gtid_mode_on = 4016;\n\n/// Server error specific to mysql. Error number: 4017, symbol: ER_USING_ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS_AS_LOCAL_OR_UUID.\nBOOST_INLINE_CONSTEXPR int er_using_assign_gtids_to_anonymous_transactions_as_local_or_uuid = 4017;\n\n/// Server error specific to mysql. Error number: 4018, symbol: ER_CANT_SET_ANONYMOUS_TO_GTID_AND_WAIT_UNTIL_SQL_THD_AFTER_GTIDS.\nBOOST_INLINE_CONSTEXPR int er_cant_set_anonymous_to_gtid_and_wait_until_sql_thd_after_gtids = 4018;\n\n/// Server error specific to mysql. Error number: 4019, symbol: ER_CANT_SET_SQL_AFTER_OR_BEFORE_GTIDS_WITH_ANONYMOUS_TO_GTID.\nBOOST_INLINE_CONSTEXPR int er_cant_set_sql_after_or_before_gtids_with_anonymous_to_gtid = 4019;\n\n/// Server error specific to mysql. Error number: 4020, symbol: ER_ANONYMOUS_TO_GTID_UUID_SAME_AS_GROUP_NAME.\nBOOST_INLINE_CONSTEXPR int er_anonymous_to_gtid_uuid_same_as_group_name = 4020;\n\n/// Server error specific to mysql. Error number: 4021, symbol: ER_CANT_USE_SAME_UUID_AS_GROUP_NAME.\nBOOST_INLINE_CONSTEXPR int er_cant_use_same_uuid_as_group_name = 4021;\n\n/// Server error specific to mysql. Error number: 4022, symbol: ER_GRP_RPL_RECOVERY_CHANNEL_STILL_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_grp_rpl_recovery_channel_still_running = 4022;\n\n/// Server error specific to mysql. Error number: 4023, symbol: ER_INNODB_INVALID_AUTOEXTEND_SIZE_VALUE.\nBOOST_INLINE_CONSTEXPR int er_innodb_invalid_autoextend_size_value = 4023;\n\n/// Server error specific to mysql. Error number: 4024, symbol: ER_INNODB_INCOMPATIBLE_WITH_TABLESPACE.\nBOOST_INLINE_CONSTEXPR int er_innodb_incompatible_with_tablespace = 4024;\n\n/// Server error specific to mysql. Error number: 4025, symbol: ER_INNODB_AUTOEXTEND_SIZE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_innodb_autoextend_size_out_of_range = 4025;\n\n/// Server error specific to mysql. Error number: 4026, symbol: ER_CANNOT_USE_AUTOEXTEND_SIZE_CLAUSE.\nBOOST_INLINE_CONSTEXPR int er_cannot_use_autoextend_size_clause = 4026;\n\n/// Server error specific to mysql. Error number: 4027, symbol: ER_ROLE_GRANTED_TO_ITSELF.\nBOOST_INLINE_CONSTEXPR int er_role_granted_to_itself = 4027;\n\n/// Server error specific to mysql. Error number: 4028, symbol: ER_TABLE_MUST_HAVE_A_VISIBLE_COLUMN.\nBOOST_INLINE_CONSTEXPR int er_table_must_have_a_visible_column = 4028;\n\n/// Server error specific to mysql. Error number: 4029, symbol: ER_INNODB_COMPRESSION_FAILURE.\nBOOST_INLINE_CONSTEXPR int er_innodb_compression_failure = 4029;\n\n/// Server error specific to mysql. Error number: 4030, symbol: ER_WARN_ASYNC_CONN_FAILOVER_NETWORK_NAMESPACE.\nBOOST_INLINE_CONSTEXPR int er_warn_async_conn_failover_network_namespace = 4030;\n\n/// Server error specific to mysql. Error number: 4031, symbol: ER_CLIENT_INTERACTION_TIMEOUT.\nBOOST_INLINE_CONSTEXPR int er_client_interaction_timeout = 4031;\n\n/// Server error specific to mysql. Error number: 4032, symbol: ER_INVALID_CAST_TO_GEOMETRY.\nBOOST_INLINE_CONSTEXPR int er_invalid_cast_to_geometry = 4032;\n\n/// Server error specific to mysql. Error number: 4033, symbol: ER_INVALID_CAST_POLYGON_RING_DIRECTION.\nBOOST_INLINE_CONSTEXPR int er_invalid_cast_polygon_ring_direction = 4033;\n\n/// Server error specific to mysql. Error number: 4034, symbol: ER_GIS_DIFFERENT_SRIDS_AGGREGATION.\nBOOST_INLINE_CONSTEXPR int er_gis_different_srids_aggregation = 4034;\n\n/// Server error specific to mysql. Error number: 4035, symbol: ER_RELOAD_KEYRING_FAILURE.\nBOOST_INLINE_CONSTEXPR int er_reload_keyring_failure = 4035;\n\n/// Server error specific to mysql. Error number: 4036, symbol: ER_SDI_GET_KEYS_INVALID_TABLESPACE.\nBOOST_INLINE_CONSTEXPR int er_sdi_get_keys_invalid_tablespace = 4036;\n\n/// Server error specific to mysql. Error number: 4037, symbol: ER_CHANGE_RPL_SRC_WRONG_COMPRESSION_ALGORITHM_SIZE.\nBOOST_INLINE_CONSTEXPR int er_change_rpl_src_wrong_compression_algorithm_size = 4037;\n\n/// Server error specific to mysql. Error number: 4039, symbol: ER_CANT_USE_SAME_UUID_AS_VIEW_CHANGE_UUID.\nBOOST_INLINE_CONSTEXPR int er_cant_use_same_uuid_as_view_change_uuid = 4039;\n\n/// Server error specific to mysql. Error number: 4040, symbol: ER_ANONYMOUS_TO_GTID_UUID_SAME_AS_VIEW_CHANGE_UUID.\nBOOST_INLINE_CONSTEXPR int er_anonymous_to_gtid_uuid_same_as_view_change_uuid = 4040;\n\n/// Server error specific to mysql. Error number: 4041, symbol: ER_GRP_RPL_VIEW_CHANGE_UUID_FAIL_GET_VARIABLE.\nBOOST_INLINE_CONSTEXPR int er_grp_rpl_view_change_uuid_fail_get_variable = 4041;\n\n/// Server error specific to mysql. Error number: 4042, symbol: ER_WARN_ADUIT_LOG_MAX_SIZE_AND_PRUNE_SECONDS.\nBOOST_INLINE_CONSTEXPR int er_warn_aduit_log_max_size_and_prune_seconds = 4042;\n\n/// Server error specific to mysql. Error number: 4043, symbol: ER_WARN_ADUIT_LOG_MAX_SIZE_CLOSE_TO_ROTATE_ON_SIZE.\nBOOST_INLINE_CONSTEXPR int er_warn_aduit_log_max_size_close_to_rotate_on_size = 4043;\n\n/// Server error specific to mysql. Error number: 4044, symbol: ER_KERBEROS_CREATE_USER.\nBOOST_INLINE_CONSTEXPR int er_kerberos_create_user = 4044;\n\n/// Server error specific to mysql. Error number: 4045, symbol: ER_INSTALL_PLUGIN_CONFLICT_CLIENT.\nBOOST_INLINE_CONSTEXPR int er_install_plugin_conflict_client = 4045;\n\n/// Server error specific to mysql. Error number: 4046, symbol: ER_DA_ERROR_LOG_COMPONENT_FLUSH_FAILED.\nBOOST_INLINE_CONSTEXPR int er_da_error_log_component_flush_failed = 4046;\n\n/// Server error specific to mysql. Error number: 4047, symbol: ER_WARN_SQL_AFTER_MTS_GAPS_GAP_NOT_CALCULATED.\nBOOST_INLINE_CONSTEXPR int er_warn_sql_after_mts_gaps_gap_not_calculated = 4047;\n\n/// Server error specific to mysql. Error number: 4048, symbol: ER_INVALID_ASSIGNMENT_TARGET.\nBOOST_INLINE_CONSTEXPR int er_invalid_assignment_target = 4048;\n\n/// Server error specific to mysql. Error number: 4049, symbol: ER_OPERATION_NOT_ALLOWED_ON_GR_SECONDARY.\nBOOST_INLINE_CONSTEXPR int er_operation_not_allowed_on_gr_secondary = 4049;\n\n/// Server error specific to mysql. Error number: 4050, symbol: ER_GRP_RPL_FAILOVER_CHANNEL_STATUS_PROPAGATION.\nBOOST_INLINE_CONSTEXPR int er_grp_rpl_failover_channel_status_propagation = 4050;\n\n/// Server error specific to mysql. Error number: 4051, symbol: ER_WARN_AUDIT_LOG_FORMAT_UNIX_TIMESTAMP_ONLY_WHEN_JSON.\nBOOST_INLINE_CONSTEXPR int er_warn_audit_log_format_unix_timestamp_only_when_json = 4051;\n\n/// Server error specific to mysql. Error number: 4052, symbol: ER_INVALID_MFA_PLUGIN_SPECIFIED.\nBOOST_INLINE_CONSTEXPR int er_invalid_mfa_plugin_specified = 4052;\n\n/// Server error specific to mysql. Error number: 4053, symbol: ER_IDENTIFIED_BY_UNSUPPORTED.\nBOOST_INLINE_CONSTEXPR int er_identified_by_unsupported = 4053;\n\n/// Server error specific to mysql. Error number: 4054, symbol: ER_INVALID_PLUGIN_FOR_REGISTRATION.\nBOOST_INLINE_CONSTEXPR int er_invalid_plugin_for_registration = 4054;\n\n/// Server error specific to mysql. Error number: 4055, symbol: ER_PLUGIN_REQUIRES_REGISTRATION.\nBOOST_INLINE_CONSTEXPR int er_plugin_requires_registration = 4055;\n\n/// Server error specific to mysql. Error number: 4056, symbol: ER_MFA_METHOD_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_mfa_method_exists = 4056;\n\n/// Server error specific to mysql. Error number: 4057, symbol: ER_MFA_METHOD_NOT_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_mfa_method_not_exists = 4057;\n\n/// Server error specific to mysql. Error number: 4058, symbol: ER_AUTHENTICATION_POLICY_MISMATCH.\nBOOST_INLINE_CONSTEXPR int er_authentication_policy_mismatch = 4058;\n\n/// Server error specific to mysql. Error number: 4059, symbol: ER_PLUGIN_REGISTRATION_DONE.\nBOOST_INLINE_CONSTEXPR int er_plugin_registration_done = 4059;\n\n/// Server error specific to mysql. Error number: 4060, symbol: ER_INVALID_USER_FOR_REGISTRATION.\nBOOST_INLINE_CONSTEXPR int er_invalid_user_for_registration = 4060;\n\n/// Server error specific to mysql. Error number: 4061, symbol: ER_USER_REGISTRATION_FAILED.\nBOOST_INLINE_CONSTEXPR int er_user_registration_failed = 4061;\n\n/// Server error specific to mysql. Error number: 4062, symbol: ER_MFA_METHODS_INVALID_ORDER.\nBOOST_INLINE_CONSTEXPR int er_mfa_methods_invalid_order = 4062;\n\n/// Server error specific to mysql. Error number: 4063, symbol: ER_MFA_METHODS_IDENTICAL.\nBOOST_INLINE_CONSTEXPR int er_mfa_methods_identical = 4063;\n\n/// Server error specific to mysql. Error number: 4064, symbol: ER_INVALID_MFA_OPERATIONS_FOR_PASSWORDLESS_USER.\nBOOST_INLINE_CONSTEXPR int er_invalid_mfa_operations_for_passwordless_user = 4064;\n\n/// Server error specific to mysql. Error number: 4065, symbol: ER_CHANGE_REPLICATION_SOURCE_NO_OPTIONS_FOR_GTID_ONLY.\nBOOST_INLINE_CONSTEXPR int er_change_replication_source_no_options_for_gtid_only = 4065;\n\n/// Server error specific to mysql. Error number: 4066, symbol: ER_CHANGE_REP_SOURCE_CANT_DISABLE_REQ_ROW_FORMAT_WITH_GTID_ONLY.\nBOOST_INLINE_CONSTEXPR int er_change_rep_source_cant_disable_req_row_format_with_gtid_only = 4066;\n\n/// Server error specific to mysql. Error number: 4067, symbol: ER_CHANGE_REP_SOURCE_CANT_DISABLE_AUTO_POSITION_WITH_GTID_ONLY.\nBOOST_INLINE_CONSTEXPR int er_change_rep_source_cant_disable_auto_position_with_gtid_only = 4067;\n\n/// Server error specific to mysql. Error number: 4068, symbol: ER_CHANGE_REP_SOURCE_CANT_DISABLE_GTID_ONLY_WITHOUT_POSITIONS.\nBOOST_INLINE_CONSTEXPR int er_change_rep_source_cant_disable_gtid_only_without_positions = 4068;\n\n/// Server error specific to mysql. Error number: 4069, symbol: ER_CHANGE_REP_SOURCE_CANT_DISABLE_AUTO_POS_WITHOUT_POSITIONS.\nBOOST_INLINE_CONSTEXPR int er_change_rep_source_cant_disable_auto_pos_without_positions = 4069;\n\n/// Server error specific to mysql. Error number: 4070, symbol: ER_CHANGE_REP_SOURCE_GR_CHANNEL_WITH_GTID_MODE_NOT_ON.\nBOOST_INLINE_CONSTEXPR int er_change_rep_source_gr_channel_with_gtid_mode_not_on = 4070;\n\n/// Server error specific to mysql. Error number: 4071, symbol: ER_CANT_USE_GTID_ONLY_WITH_GTID_MODE_NOT_ON.\nBOOST_INLINE_CONSTEXPR int er_cant_use_gtid_only_with_gtid_mode_not_on = 4071;\n\n/// Server error specific to mysql. Error number: 4072, symbol: ER_WARN_C_DISABLE_GTID_ONLY_WITH_SOURCE_AUTO_POS_INVALID_POS.\nBOOST_INLINE_CONSTEXPR int er_warn_c_disable_gtid_only_with_source_auto_pos_invalid_pos = 4072;\n\n/// Server error specific to mysql. Error number: 4073, symbol: ER_DA_SSL_FIPS_MODE_ERROR.\nBOOST_INLINE_CONSTEXPR int er_da_ssl_fips_mode_error = 4073;\n\n/// Server error specific to mysql. Error number: 4074, symbol: ER_VALUE_OUT_OF_RANGE.\nBOOST_INLINE_CONSTEXPR int er_value_out_of_range = 4074;\n\n/// Server error specific to mysql. Error number: 4075, symbol: ER_FULLTEXT_WITH_ROLLUP.\nBOOST_INLINE_CONSTEXPR int er_fulltext_with_rollup = 4075;\n\n/// Server error specific to mysql. Error number: 4076, symbol: ER_REGEXP_MISSING_RESOURCE.\nBOOST_INLINE_CONSTEXPR int er_regexp_missing_resource = 4076;\n\n/// Server error specific to mysql. Error number: 4077, symbol: ER_WARN_REGEXP_USING_DEFAULT.\nBOOST_INLINE_CONSTEXPR int er_warn_regexp_using_default = 4077;\n\n/// Server error specific to mysql. Error number: 4078, symbol: ER_REGEXP_MISSING_FILE.\nBOOST_INLINE_CONSTEXPR int er_regexp_missing_file = 4078;\n\n/// Server error specific to mysql. Error number: 4079, symbol: ER_WARN_DEPRECATED_COLLATION.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_collation = 4079;\n\n/// Server error specific to mysql. Error number: 4080, symbol: ER_CONCURRENT_PROCEDURE_USAGE.\nBOOST_INLINE_CONSTEXPR int er_concurrent_procedure_usage = 4080;\n\n/// Server error specific to mysql. Error number: 4081, symbol: ER_DA_GLOBAL_CONN_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_da_global_conn_limit = 4081;\n\n/// Server error specific to mysql. Error number: 4082, symbol: ER_DA_CONN_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_da_conn_limit = 4082;\n\n/// Server error specific to mysql. Error number: 4083, symbol: ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE_INSTANT.\nBOOST_INLINE_CONSTEXPR int er_alter_operation_not_supported_reason_column_type_instant = 4083;\n\n/// Server error specific to mysql. Error number: 4084, symbol: ER_WARN_SF_UDF_NAME_COLLISION.\nBOOST_INLINE_CONSTEXPR int er_warn_sf_udf_name_collision = 4084;\n\n/// Server error specific to mysql. Error number: 4085, symbol: ER_CANNOT_PURGE_BINLOG_WITH_BACKUP_LOCK.\nBOOST_INLINE_CONSTEXPR int er_cannot_purge_binlog_with_backup_lock = 4085;\n\n/// Server error specific to mysql. Error number: 4086, symbol: ER_TOO_MANY_WINDOWS.\nBOOST_INLINE_CONSTEXPR int er_too_many_windows = 4086;\n\n/// Server error specific to mysql. Error number: 4087, symbol: ER_MYSQLBACKUP_CLIENT_MSG.\nBOOST_INLINE_CONSTEXPR int er_mysqlbackup_client_msg = 4087;\n\n/// Server error specific to mysql. Error number: 4088, symbol: ER_COMMENT_CONTAINS_INVALID_STRING.\nBOOST_INLINE_CONSTEXPR int er_comment_contains_invalid_string = 4088;\n\n/// Server error specific to mysql. Error number: 4089, symbol: ER_DEFINITION_CONTAINS_INVALID_STRING.\nBOOST_INLINE_CONSTEXPR int er_definition_contains_invalid_string = 4089;\n\n/// Server error specific to mysql. Error number: 4090, symbol: ER_CANT_EXECUTE_COMMAND_WITH_ASSIGNED_GTID_NEXT.\nBOOST_INLINE_CONSTEXPR int er_cant_execute_command_with_assigned_gtid_next = 4090;\n\n/// Server error specific to mysql. Error number: 4091, symbol: ER_XA_TEMP_TABLE.\nBOOST_INLINE_CONSTEXPR int er_xa_temp_table = 4091;\n\n/// Server error specific to mysql. Error number: 4092, symbol: ER_INNODB_MAX_ROW_VERSION.\nBOOST_INLINE_CONSTEXPR int er_innodb_max_row_version = 4092;\n\n/// Server error specific to mysql. Error number: 4094, symbol: ER_OPERATION_NOT_ALLOWED_WHILE_PRIMARY_CHANGE_IS_RUNNING.\nBOOST_INLINE_CONSTEXPR int er_operation_not_allowed_while_primary_change_is_running = 4094;\n\n/// Server error specific to mysql. Error number: 4095, symbol: ER_WARN_DEPRECATED_DATETIME_DELIMITER.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_datetime_delimiter = 4095;\n\n/// Server error specific to mysql. Error number: 4096, symbol: ER_WARN_DEPRECATED_SUPERFLUOUS_DELIMITER.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_superfluous_delimiter = 4096;\n\n/// Server error specific to mysql. Error number: 4097, symbol: ER_CANNOT_PERSIST_SENSITIVE_VARIABLES.\nBOOST_INLINE_CONSTEXPR int er_cannot_persist_sensitive_variables = 4097;\n\n/// Server error specific to mysql. Error number: 4098, symbol: ER_WARN_CANNOT_SECURELY_PERSIST_SENSITIVE_VARIABLES.\nBOOST_INLINE_CONSTEXPR int er_warn_cannot_securely_persist_sensitive_variables = 4098;\n\n/// Server error specific to mysql. Error number: 4099, symbol: ER_WARN_TRG_ALREADY_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_warn_trg_already_exists = 4099;\n\n/// Server error specific to mysql. Error number: 4100, symbol: ER_IF_NOT_EXISTS_UNSUPPORTED_TRG_EXISTS_ON_DIFFERENT_TABLE.\nBOOST_INLINE_CONSTEXPR int er_if_not_exists_unsupported_trg_exists_on_different_table = 4100;\n\n/// Server error specific to mysql. Error number: 4101, symbol: ER_IF_NOT_EXISTS_UNSUPPORTED_UDF_NATIVE_FCT_NAME_COLLISION.\nBOOST_INLINE_CONSTEXPR int er_if_not_exists_unsupported_udf_native_fct_name_collision = 4101;\n\n/// Server error specific to mysql. Error number: 4102, symbol: ER_SET_PASSWORD_AUTH_PLUGIN_ERROR.\nBOOST_INLINE_CONSTEXPR int er_set_password_auth_plugin_error = 4102;\n\n/// Server error specific to mysql. Error number: 4105, symbol: ER_SRS_INVALID_LATITUDE_OF_ORIGIN.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_latitude_of_origin = 4105;\n\n/// Server error specific to mysql. Error number: 4106, symbol: ER_SRS_INVALID_LONGITUDE_OF_ORIGIN.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_longitude_of_origin = 4106;\n\n/// Server error specific to mysql. Error number: 4107, symbol: ER_SRS_UNUSED_PROJ_PARAMETER_PRESENT.\nBOOST_INLINE_CONSTEXPR int er_srs_unused_proj_parameter_present = 4107;\n\n/// Server error specific to mysql. Error number: 4108, symbol: ER_GIPK_COLUMN_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_gipk_column_exists = 4108;\n\n/// Server error specific to mysql. Error number: 4109, symbol: ER_GIPK_FAILED_AUTOINC_COLUMN_EXISTS.\nBOOST_INLINE_CONSTEXPR int er_gipk_failed_autoinc_column_exists = 4109;\n\n/// Server error specific to mysql. Error number: 4110, symbol: ER_GIPK_COLUMN_ALTER_NOT_ALLOWED.\nBOOST_INLINE_CONSTEXPR int er_gipk_column_alter_not_allowed = 4110;\n\n/// Server error specific to mysql. Error number: 4111, symbol: ER_DROP_PK_COLUMN_TO_DROP_GIPK.\nBOOST_INLINE_CONSTEXPR int er_drop_pk_column_to_drop_gipk = 4111;\n\n/// Server error specific to mysql. Error number: 4112, symbol: ER_CREATE_SELECT_WITH_GIPK_DISALLOWED_IN_SBR.\nBOOST_INLINE_CONSTEXPR int er_create_select_with_gipk_disallowed_in_sbr = 4112;\n\n/// Server error specific to mysql. Error number: 4113, symbol: ER_DA_EXPIRE_LOGS_DAYS_IGNORED.\nBOOST_INLINE_CONSTEXPR int er_da_expire_logs_days_ignored = 4113;\n\n/// Server error specific to mysql. Error number: 4114, symbol: ER_CTE_RECURSIVE_NOT_UNION.\nBOOST_INLINE_CONSTEXPR int er_cte_recursive_not_union = 4114;\n\n/// Server error specific to mysql. Error number: 4115, symbol: ER_COMMAND_BACKEND_FAILED_TO_FETCH_SECURITY_CTX.\nBOOST_INLINE_CONSTEXPR int er_command_backend_failed_to_fetch_security_ctx = 4115;\n\n/// Server error specific to mysql. Error number: 4116, symbol: ER_COMMAND_SERVICE_BACKEND_FAILED.\nBOOST_INLINE_CONSTEXPR int er_command_service_backend_failed = 4116;\n\n/// Server error specific to mysql. Error number: 4117, symbol: ER_CLIENT_FILE_PRIVILEGE_FOR_REPLICATION_CHECKS.\nBOOST_INLINE_CONSTEXPR int er_client_file_privilege_for_replication_checks = 4117;\n\n/// Server error specific to mysql. Error number: 4118, symbol: ER_GROUP_REPLICATION_FORCE_MEMBERS_COMMAND_FAILURE.\nBOOST_INLINE_CONSTEXPR int er_group_replication_force_members_command_failure = 4118;\n\n/// Server error specific to mysql. Error number: 4119, symbol: ER_WARN_DEPRECATED_IDENT.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_ident = 4119;\n\n/// Server error specific to mysql. Error number: 4120, symbol: ER_INTERSECT_ALL_MAX_DUPLICATES_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_intersect_all_max_duplicates_exceeded = 4120;\n\n/// Server error specific to mysql. Error number: 4121, symbol: ER_TP_QUERY_THRS_PER_GRP_EXCEEDS_TXN_THR_LIMIT.\nBOOST_INLINE_CONSTEXPR int er_tp_query_thrs_per_grp_exceeds_txn_thr_limit = 4121;\n\n/// Server error specific to mysql. Error number: 4122, symbol: ER_BAD_TIMESTAMP_FORMAT.\nBOOST_INLINE_CONSTEXPR int er_bad_timestamp_format = 4122;\n\n/// Server error specific to mysql. Error number: 4123, symbol: ER_SHAPE_PRIDICTION_UDF.\nBOOST_INLINE_CONSTEXPR int er_shape_pridiction_udf = 4123;\n\n/// Server error specific to mysql. Error number: 4124, symbol: ER_SRS_INVALID_HEIGHT.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_height = 4124;\n\n/// Server error specific to mysql. Error number: 4125, symbol: ER_SRS_INVALID_SCALING.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_scaling = 4125;\n\n/// Server error specific to mysql. Error number: 4126, symbol: ER_SRS_INVALID_ZONE_WIDTH.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_zone_width = 4126;\n\n/// Server error specific to mysql. Error number: 4127, symbol: ER_SRS_INVALID_LATITUDE_POLAR_STERE_VAR_A.\nBOOST_INLINE_CONSTEXPR int er_srs_invalid_latitude_polar_stere_var_a = 4127;\n\n/// Server error specific to mysql. Error number: 4128, symbol: ER_WARN_DEPRECATED_CLIENT_NO_SCHEMA_OPTION.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_client_no_schema_option = 4128;\n\n/// Server error specific to mysql. Error number: 4129, symbol: ER_TABLE_NOT_EMPTY.\nBOOST_INLINE_CONSTEXPR int er_table_not_empty = 4129;\n\n/// Server error specific to mysql. Error number: 4130, symbol: ER_TABLE_NO_PRIMARY_KEY.\nBOOST_INLINE_CONSTEXPR int er_table_no_primary_key = 4130;\n\n/// Server error specific to mysql. Error number: 4131, symbol: ER_TABLE_IN_SHARED_TABLESPACE.\nBOOST_INLINE_CONSTEXPR int er_table_in_shared_tablespace = 4131;\n\n/// Server error specific to mysql. Error number: 4132, symbol: ER_INDEX_OTHER_THAN_PK.\nBOOST_INLINE_CONSTEXPR int er_index_other_than_pk = 4132;\n\n/// Server error specific to mysql. Error number: 4133, symbol: ER_LOAD_BULK_DATA_UNSORTED.\nBOOST_INLINE_CONSTEXPR int er_load_bulk_data_unsorted = 4133;\n\n/// Server error specific to mysql. Error number: 4134, symbol: ER_BULK_EXECUTOR_ERROR.\nBOOST_INLINE_CONSTEXPR int er_bulk_executor_error = 4134;\n\n/// Server error specific to mysql. Error number: 4135, symbol: ER_BULK_READER_LIBCURL_INIT_FAILED.\nBOOST_INLINE_CONSTEXPR int er_bulk_reader_libcurl_init_failed = 4135;\n\n/// Server error specific to mysql. Error number: 4136, symbol: ER_BULK_READER_LIBCURL_ERROR.\nBOOST_INLINE_CONSTEXPR int er_bulk_reader_libcurl_error = 4136;\n\n/// Server error specific to mysql. Error number: 4137, symbol: ER_BULK_READER_SERVER_ERROR.\nBOOST_INLINE_CONSTEXPR int er_bulk_reader_server_error = 4137;\n\n/// Server error specific to mysql. Error number: 4138, symbol: ER_BULK_READER_COMMUNICATION_ERROR.\nBOOST_INLINE_CONSTEXPR int er_bulk_reader_communication_error = 4138;\n\n/// Server error specific to mysql. Error number: 4139, symbol: ER_BULK_LOAD_DATA_FAILED.\nBOOST_INLINE_CONSTEXPR int er_bulk_load_data_failed = 4139;\n\n/// Server error specific to mysql. Error number: 4140, symbol: ER_BULK_LOADER_COLUMN_TOO_BIG_FOR_LEFTOVER_BUFFER.\nBOOST_INLINE_CONSTEXPR int er_bulk_loader_column_too_big_for_leftover_buffer = 4140;\n\n/// Server error specific to mysql. Error number: 4141, symbol: ER_BULK_LOADER_COMPONENT_ERROR.\nBOOST_INLINE_CONSTEXPR int er_bulk_loader_component_error = 4141;\n\n/// Server error specific to mysql. Error number: 4142, symbol: ER_BULK_LOADER_FILE_CONTAINS_LESS_LINES_THAN_IGNORE_CLAUSE.\nBOOST_INLINE_CONSTEXPR int er_bulk_loader_file_contains_less_lines_than_ignore_clause = 4142;\n\n/// Server error specific to mysql. Error number: 4143, symbol: ER_BULK_PARSER_MISSING_ENCLOSED_BY.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_missing_enclosed_by = 4143;\n\n/// Server error specific to mysql. Error number: 4144, symbol: ER_BULK_PARSER_ROW_BUFFER_MAX_TOTAL_COLS_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_row_buffer_max_total_cols_exceeded = 4144;\n\n/// Server error specific to mysql. Error number: 4145, symbol: ER_BULK_PARSER_COPY_BUFFER_SIZE_EXCEEDED.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_copy_buffer_size_exceeded = 4145;\n\n/// Server error specific to mysql. Error number: 4146, symbol: ER_BULK_PARSER_UNEXPECTED_END_OF_INPUT.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_unexpected_end_of_input = 4146;\n\n/// Server error specific to mysql. Error number: 4147, symbol: ER_BULK_PARSER_UNEXPECTED_ROW_TERMINATOR.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_unexpected_row_terminator = 4147;\n\n/// Server error specific to mysql. Error number: 4148, symbol: ER_BULK_PARSER_UNEXPECTED_CHAR_AFTER_ENDING_ENCLOSED_BY.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_unexpected_char_after_ending_enclosed_by = 4148;\n\n/// Server error specific to mysql. Error number: 4149, symbol: ER_BULK_PARSER_UNEXPECTED_CHAR_AFTER_NULL_ESCAPE.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_unexpected_char_after_null_escape = 4149;\n\n/// Server error specific to mysql. Error number: 4150, symbol: ER_BULK_PARSER_UNEXPECTED_CHAR_AFTER_COLUMN_TERMINATOR.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_unexpected_char_after_column_terminator = 4150;\n\n/// Server error specific to mysql. Error number: 4151, symbol: ER_BULK_PARSER_INCOMPLETE_ESCAPE_SEQUENCE.\nBOOST_INLINE_CONSTEXPR int er_bulk_parser_incomplete_escape_sequence = 4151;\n\n/// Server error specific to mysql. Error number: 4152, symbol: ER_LOAD_BULK_DATA_FAILED.\nBOOST_INLINE_CONSTEXPR int er_load_bulk_data_failed = 4152;\n\n/// Server error specific to mysql. Error number: 4153, symbol: ER_LOAD_BULK_DATA_WRONG_VALUE_FOR_FIELD.\nBOOST_INLINE_CONSTEXPR int er_load_bulk_data_wrong_value_for_field = 4153;\n\n/// Server error specific to mysql. Error number: 4154, symbol: ER_LOAD_BULK_DATA_WARN_NULL_TO_NOTNULL.\nBOOST_INLINE_CONSTEXPR int er_load_bulk_data_warn_null_to_notnull = 4154;\n\n/// Server error specific to mysql. Error number: 4155, symbol: ER_REQUIRE_TABLE_PRIMARY_KEY_CHECK_GENERATE_WITH_GR.\nBOOST_INLINE_CONSTEXPR int er_require_table_primary_key_check_generate_with_gr = 4155;\n\n/// Server error specific to mysql. Error number: 4156, symbol: ER_CANT_CHANGE_SYS_VAR_IN_READ_ONLY_MODE.\nBOOST_INLINE_CONSTEXPR int er_cant_change_sys_var_in_read_only_mode = 4156;\n\n/// Server error specific to mysql. Error number: 4157, symbol: ER_INNODB_INSTANT_ADD_DROP_NOT_SUPPORTED_MAX_SIZE.\nBOOST_INLINE_CONSTEXPR int er_innodb_instant_add_drop_not_supported_max_size = 4157;\n\n/// Server error specific to mysql. Error number: 4158, symbol: ER_INNODB_INSTANT_ADD_NOT_SUPPORTED_MAX_FIELDS.\nBOOST_INLINE_CONSTEXPR int er_innodb_instant_add_not_supported_max_fields = 4158;\n\n/// Server error specific to mysql. Error number: 4159, symbol: ER_CANT_SET_PERSISTED.\nBOOST_INLINE_CONSTEXPR int er_cant_set_persisted = 4159;\n\n/// Server error specific to mysql. Error number: 4160, symbol: ER_INSTALL_COMPONENT_SET_NULL_VALUE.\nBOOST_INLINE_CONSTEXPR int er_install_component_set_null_value = 4160;\n\n/// Server error specific to mysql. Error number: 4161, symbol: ER_INSTALL_COMPONENT_SET_UNUSED_VALUE.\nBOOST_INLINE_CONSTEXPR int er_install_component_set_unused_value = 4161;\n\n/// Server error specific to mysql. Error number: 4162, symbol: ER_WARN_DEPRECATED_USER_DEFINED_COLLATIONS.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_user_defined_collations = 4162;\n\n/// Server error specific to mysql. Error number: 4163, symbol: ER_USER_LOCK_OVERLONG_NAME.\nBOOST_INLINE_CONSTEXPR int er_user_lock_overlong_name = 4163;\n\n/// Server error specific to mysql. Error number: 4164, symbol: ER_WARN_NO_SPACE_VERSION_COMMENT.\nBOOST_INLINE_CONSTEXPR int er_warn_no_space_version_comment = 4164;\n\n/// Server error specific to mysql. Error number: 4165, symbol: ER_VALIDATE_PASSWORD_INSUFFICIENT_CHANGED_CHARACTERS.\nBOOST_INLINE_CONSTEXPR int er_validate_password_insufficient_changed_characters = 4165;\n\n/// Server error specific to mysql. Error number: 4166, symbol: ER_WARN_DEPRECATED_WITH_NOTE.\nBOOST_INLINE_CONSTEXPR int er_warn_deprecated_with_note = 4166;\n\n}  // namespace mysql_server_errc\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/pfr.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_PFR_HPP\n#define BOOST_MYSQL_PFR_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/pfr/config.hpp>\n\n#if BOOST_PFR_ENABLED && defined(BOOST_MYSQL_CXX14)\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Static interface marker type to use Boost.PFR reflection with positional matching.\n * \\details\n * A marker type that satisfies the `StaticRow` concept.\n * When used within the static interface, modifies its behavior\n * for the marked type so that Boost.PFR is used for reflection, instead of Boost.Describe.\n * Field matching is performed by position, with the same algorithm used for `std::tuple`.\n * \\n\n * The underlying row type for this marker is `T`, i.e.\n * \\ref underlying_row_t \"underlying_row_t<pfr_by_position<T>>\" is an alias for `T`.\n * \\n\n * The type `T` must be a PFR-reflectable non-const object type.\n * \\n\n * This type is only defined if the macro `BOOST_PFR_ENABLED` is defined and set to `1`.\n */\ntemplate <class T>\nstruct pfr_by_position;\n\n#if BOOST_PFR_CORE_NAME_ENABLED\n\n/**\n * \\brief Static interface marker type to use Boost.PFR reflection with name-based field matching.\n * \\details\n * A marker type that satisfies the `StaticRow` concept.\n * When used within the static interface, modifies its behavior\n * for the marked type so that Boost.PFR is used for reflection, instead of Boost.Describe.\n * Field matching is performed by name, with the same algorithm used for Boost.Describe structs.\n * \\n\n * The underlying row type for this marker is `T`, i.e.\n * \\ref underlying_row_t \"underlying_row_t<pfr_by_name<T>>\" is an alias for `T`.\n * \\n\n * The type `T` must be a PFR-reflectable non-const object type.\n * \\n\n * This type is only defined if the macro `BOOST_PFR_CORE_NAME_ENABLED` is defined and set to `1`\n * (requires C++20).\n */\ntemplate <class T>\nstruct pfr_by_name;\n\n#endif\n\n}  // namespace mysql\n}  // namespace boost\n\n#include <boost/mysql/impl/pfr.hpp>\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/pipeline.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_PIPELINE_HPP\n#define BOOST_MYSQL_PIPELINE_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/config.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n#include <boost/mysql/detail/writable_field_traits.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/core/span.hpp>\n#include <boost/variant2/variant.hpp>\n\n#include <array>\n#include <cstdint>\n#include <utility>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief (EXPERIMENTAL) A variant-like type holding the response of a single pipeline stage.\n * \\details\n * This is a variant-like type, similar to `boost::system::result`. At any point in time,\n * it can contain: \\n\n *   \\li A \\ref statement. Will happen if the stage was a prepare statement that succeeded.\n *   \\li A \\ref results. Will happen if the stage was a query or statement execution that succeeded.\n *   \\li An \\ref error_code, \\ref diagnostics pair. Will happen if the stage failed, or if it succeeded but\n *       it doesn't yield a value (as in close statement, reset connection and set character set).\n *\n * \\par Experimental\n * This part of the API is experimental, and may change in successive\n * releases without previous notice.\n */\nclass stage_response\n{\n#ifndef BOOST_MYSQL_DOXYGEN\n    struct errcode_with_diagnostics\n    {\n        error_code ec;\n        diagnostics diag;\n    };\n\n    struct\n    {\n        variant2::variant<errcode_with_diagnostics, statement, results> value;\n\n        void emplace_results() { value.emplace<results>(); }\n        void emplace_error() { value.emplace<errcode_with_diagnostics>(); }\n        detail::execution_processor& get_processor()\n        {\n            return detail::access::get_impl(variant2::unsafe_get<2>(value));\n        }\n        void set_result(statement s) { value = s; }\n        void set_error(error_code ec, diagnostics&& diag)\n        {\n            value.emplace<0>(errcode_with_diagnostics{ec, std::move(diag)});\n        }\n    } impl_;\n\n    friend struct detail::access;\n#endif\n\n    bool has_error() const { return impl_.value.index() == 0u; }\n\n    BOOST_MYSQL_DECL\n    void check_has_results() const;\n\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details\n     * Constructs an object containing an empty error code and diagnostics.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    stage_response() = default;\n\n    /**\n     * \\brief Returns true if the object contains a statement.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool has_statement() const noexcept { return impl_.value.index() == 1u; }\n\n    /**\n     * \\brief Returns true if the object contains a results.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool has_results() const noexcept { return impl_.value.index() == 2u; }\n\n    /**\n     * \\brief Retrieves the contained error code.\n     * \\details\n     * If `*this` contains an error, retrieves it.\n     * Otherwise (if `this->has_statement() || this->has_results()`),\n     * returns an empty (default-constructed) error code.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    error_code error() const noexcept\n    {\n        return has_error() ? variant2::unsafe_get<0>(impl_.value).ec : error_code();\n    }\n\n    /**\n     * \\brief Retrieves the contained diagnostics (lvalue reference accessor).\n     * \\details\n     * If `*this` contains an error, retrieves the associated diagnostic information\n     * by copying it.\n     * Otherwise (if `this->has_statement() || this->has_results()`),\n     * returns an empty diagnostics object.\n     *\n     * \\par Exception safety\n     * Strong guarantee: memory allocations may throw.\n     */\n    diagnostics diag() const&\n    {\n        return has_error() ? variant2::unsafe_get<0>(impl_.value).diag : diagnostics();\n    }\n\n    /**\n     * \\brief Retrieves the contained diagnostics (rvalue reference accessor).\n     * \\details\n     * If `*this` contains an error, retrieves the associated diagnostic information\n     * by moving it.\n     * Otherwise (if `this->has_statement() || this->has_results()`),\n     * returns an empty (default-constructed) error.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    diagnostics diag() && noexcept\n    {\n        return has_error() ? variant2::unsafe_get<0>(std::move(impl_.value)).diag : diagnostics();\n    }\n\n    /**\n     * \\brief Retrieves the contained statement or throws an exception.\n     * \\details\n     * If `*this` contains an statement (`this->has_statement() == true`),\n     * retrieves it. Otherwise, throws an exception.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws on invalid input.\n     * \\throws std::invalid_argument If `*this` does not contain a statement.\n     */\n    BOOST_MYSQL_DECL\n    statement as_statement() const;\n\n    /**\n     * \\brief Retrieves the contained statement (unchecked accessor).\n     * \\details\n     * If `*this` contains an statement,\n     * retrieves it. Otherwise, the behavior is undefined.\n     *\n     * \\par Preconditions\n     * `this->has_statement() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    statement get_statement() const noexcept\n    {\n        BOOST_ASSERT(has_statement());\n        return variant2::unsafe_get<1>(impl_.value);\n    }\n\n    /**\n     * \\brief Retrieves the contained results or throws an exception.\n     * \\details\n     * If `*this` contains a `results` object (`this->has_results() == true`),\n     * retrieves a reference to it. Otherwise, throws an exception.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws on invalid input.\n     * \\throws std::invalid_argument If `this->has_results() == false`\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive\n     * and hasn't been assigned to.\n     */\n    const results& as_results() const&\n    {\n        check_has_results();\n        return variant2::unsafe_get<2>(impl_.value);\n    }\n\n    /// \\copydoc as_results\n    results&& as_results() &&\n    {\n        check_has_results();\n        return variant2::unsafe_get<2>(std::move(impl_.value));\n    }\n\n    /**\n     * \\brief Retrieves the contained results (unchecked accessor).\n     * \\details\n     * If `*this` contains a `results` object, retrieves a reference to it.\n     * Otherwise, the behavior is undefined.\n     *\n     * \\par Preconditions\n     * `this->has_results() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference is valid as long as `*this` is alive\n     * and hasn't been assigned to.\n     */\n    const results& get_results() const& noexcept\n    {\n        BOOST_ASSERT(has_results());\n        return variant2::unsafe_get<2>(impl_.value);\n    }\n\n    /// \\copydoc get_results\n    results&& get_results() && noexcept\n    {\n        BOOST_ASSERT(has_results());\n        return variant2::unsafe_get<2>(std::move(impl_.value));\n    }\n};\n\n/**\n * \\brief (EXPERIMENTAL) A pipeline request.\n * \\details\n * Contains a collection of pipeline stages, fully describing the work to be performed\n * by a pipeline operation.\n * Call any of the `add_xxx` functions to append new stages to the request.\n *\n * \\par Experimental\n * This part of the API is experimental, and may change in successive\n * releases without previous notice.\n */\nclass pipeline_request\n{\n#ifndef BOOST_MYSQL_DOXYGEN\n    struct impl_t\n    {\n        std::vector<std::uint8_t> buffer_;\n        std::vector<detail::pipeline_request_stage> stages_;\n    } impl_;\n\n    friend struct detail::access;\n#endif\n\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details Constructs an empty pipeline request, with no stages.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    pipeline_request() = default;\n\n    /**\n     * \\brief Adds a stage that executes a text query.\n     * \\details\n     * Creates a stage that will run `query` as a SQL query,\n     * like \\ref any_connection::execute.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Memory allocations may throw.\n     *\n     * \\par Object lifetimes\n     * query is copied into the request and need not be kept alive after this function returns.\n     */\n    BOOST_MYSQL_DECL\n    pipeline_request& add_execute(string_view query);\n\n    /**\n     * \\brief Adds a stage that executes a prepared statement.\n     * \\details\n     * Creates a stage that runs\n     * `stmt` bound to any parameters passed in `params`, like \\ref any_connection::execute\n     * and \\ref statement::bind. For example, `add_execute(stmt, 42, \"John\")` has\n     * effects equivalent to `conn.execute(stmt.bind(42, \"John\"))`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws if the supplied number of parameters doesn't match the number\n     * of parameters expected by the statement. Additionally, memory allocations may throw.\n     * \\throws std::invalid_argument If `sizeof...(params) != stmt.num_params()`\n     *\n     * \\par Preconditions\n     * The passed statement should be valid (`stmt.valid() == true`).\n     *\n     * \\par Object lifetimes\n     * Any objects pointed to by `params` are copied into the request and\n     * need not be kept alive after this function returns.\n     *\n     * \\par Type requirements\n     * Any type satisfying `WritableField` can be used as a parameter.\n     * This includes all types that can be used with \\ref statement::bind,\n     * including scalar types, strings, blobs and optionals.\n     */\n    template <BOOST_MYSQL_WRITABLE_FIELD... WritableField>\n    pipeline_request& add_execute(statement stmt, const WritableField&... params)\n    {\n        std::array<field_view, sizeof...(WritableField)> params_arr{{detail::to_field(params)...}};\n        return add_execute_range(stmt, params_arr);\n    }\n\n    /**\n     * \\brief Adds a stage that executes a prepared statement.\n     * \\details\n     * Creates a stage that runs\n     * `stmt` bound to any parameters passed in `params`, like \\ref any_connection::execute\n     * and \\ref statement::bind. For example, `add_execute_range(stmt, params)` has\n     * effects equivalent to `conn.execute(stmt.bind(params.begin(), params.end()))`.\n     * \\n\n     * This function can be used instead of \\ref add_execute when the number of actual parameters\n     * of a statement is not known at compile time.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws if the supplied number of parameters doesn't match the number\n     * of parameters expected by the statement. Additionally, memory allocations may throw.\n     * \\throws std::invalid_argument If `params.size() != stmt.num_params()`\n     *\n     * \\par Preconditions\n     * The passed statement should be valid (`stmt.valid() == true`).\n     *\n     * \\par Object lifetimes\n     * The `params` range is copied into the request and\n     * needs not be kept alive after this function returns.\n     */\n    BOOST_MYSQL_DECL\n    pipeline_request& add_execute_range(statement stmt, span<const field_view> params);\n\n    /**\n     * \\brief Adds a prepare statement stage.\n     * \\details\n     * Creates a stage that prepares a statement server-side. The resulting\n     * stage has effects equivalent to `conn.prepare_statement(stmt_sql)`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Memory allocations may throw.\n     *\n     * \\par Object lifetimes\n     * stmt_sql is copied into the request and need not be kept alive after this function returns.\n     */\n    BOOST_MYSQL_DECL\n    pipeline_request& add_prepare_statement(string_view stmt_sql);\n\n    /**\n     * \\brief Adds a close statement stage.\n     * \\details\n     * Creates a stage that closes a prepared statement. The resulting\n     * stage has effects equivalent to `conn.close_statement(stmt)`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Memory allocations may throw.\n     *\n     * \\par Preconditions\n     * The passed statement should be valid (`stmt.valid() == true`).\n     */\n    BOOST_MYSQL_DECL pipeline_request& add_close_statement(statement stmt);\n\n    /**\n     * \\brief Adds a reset connection stage.\n     * \\details\n     * Creates a stage that resets server-side session state. The resulting\n     * stage has effects equivalent to `conn.reset_connection()`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Memory allocations may throw.\n     */\n    BOOST_MYSQL_DECL pipeline_request& add_reset_connection();\n\n    /**\n     * \\brief Adds a set character set stage.\n     * \\details\n     * Creates a stage that sets the connection's character set.\n     * The resulting stage has effects equivalent to `conn.set_character_set(charset)`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Throws if the supplied character set name is not valid\n     * (i.e. `charset.name` contains non-ASCII characters).\n     * The check is performed as a hardening measure, and never happens with\n     * the character sets provided by this library.\n     *\n     * Additionally, memory allocations may throw.\n     * \\throws std::invalid_argument If `charset.name` contains non-ASCII characters.\n     *\n     * \\par Preconditions\n     * The passed character set should not be default-constructed\n     * (`charset.name != nullptr`).\n     */\n    BOOST_MYSQL_DECL pipeline_request& add_set_character_set(character_set charset);\n\n    /**\n     * \\brief Removes all stages in the pipeline request, making the object empty again.\n     * \\details\n     * Can be used to re-use a single request object for multiple pipeline operations.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    void clear() noexcept\n    {\n        impl_.buffer_.clear();\n        impl_.stages_.clear();\n    }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/pipeline.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/pool_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_POOL_PARAMS_HPP\n#define BOOST_MYSQL_POOL_PARAMS_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/optional/optional.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <string>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Configuration parameters for \\ref connection_pool.\n * \\details\n * This is an owning type.\n */\nstruct pool_params\n{\n    /**\n     * \\brief Determines how to establish a physical connection to the MySQL server.\n     * \\details\n     * Connections created by the pool will use this address to connect to the\n     * server. This can be either a host and port or a UNIX socket path.\n     * Defaults to (localhost, 3306).\n     */\n    any_address server_address;\n\n    /// User name that connections created by the pool should use to authenticate as.\n    std::string username;\n\n    /// Password that connections created by the pool should use.\n    std::string password;\n\n    /**\n     * \\brief Database name that connections created by the pool will use when connecting.\n     * \\details Leave it empty to select no database (this is the default).\n     */\n    std::string database;\n\n    /**\n     * \\brief Controls whether connections created by the pool will use TLS or not.\n     * \\details\n     * See \\ref ssl_mode for more information about the possible modes.\n     * This option is only relevant when `server_address.type() == address_type::host_and_port`.\n     * UNIX socket connections will never use TLS, regardless of this value.\n     */\n    ssl_mode ssl{ssl_mode::enable};\n\n    /**\n     * \\brief Whether to enable support for semicolon-separated text queries for connections created by the\n     * pool. \\details Disabled by default.\n     */\n    bool multi_queries{false};\n\n    /// Initial size (in bytes) of the internal buffer for the connections created by the pool.\n    std::size_t initial_buffer_size{default_initial_read_buffer_size};\n\n    /**\n     * \\brief Initial number of connections to create.\n     * \\details\n     * When \\ref connection_pool::async_run starts running, this number of connections\n     * will be created and connected.\n     */\n    std::size_t initial_size{1};\n\n    /**\n     * \\brief Max number of connections to create.\n     * \\details\n     * When a connection is requested, but all connections are in use, new connections\n     * will be created and connected up to this size.\n     * \\n\n     * Defaults to the maximum number of concurrent connections that MySQL\n     * servers allow by default. If you increase this value, increase the server's\n     * max number of connections, too (by setting the `max_connections` global variable).\n     * \\n\n     * This value must be `> 0` and `>= initial_size`.\n     */\n    std::size_t max_size{151};\n\n    /**\n     * \\brief The SSL context to use for connections using TLS.\n     * \\details\n     * If a non-empty value is provided, all connections created by the pool\n     * will use the passed context when using TLS. This allows setting TLS options\n     * to pool-created connections.\n     * \\n\n     * If an empty value is passed (the default) and the connections require TLS,\n     * an internal SSL context with suitable options will be created by the pool.\n     */\n    boost::optional<asio::ssl::context> ssl_ctx{};\n\n    /**\n     * \\brief The timeout to use when connecting.\n     * \\details\n     * Connections will be connected by the pool before being handed to the user\n     * (using \\ref any_connection::async_connect).\n     * If the operation takes longer than this timeout,\n     * the operation will be interrupted, considered as failed and retried later.\n     * \\n\n     * Set this timeout to zero to disable it.\n     * \\n\n     * This value must not be negative.\n     */\n    std::chrono::steady_clock::duration connect_timeout{std::chrono::seconds(20)};\n\n    /**\n     * \\brief The interval between connect attempts.\n     * \\details\n     * When session establishment fails, the operation will be retried until\n     * success. This value determines the interval between consecutive connection\n     * attempts.\n     * \\n\n     * This value must be greater than zero.\n     */\n    std::chrono::steady_clock::duration retry_interval{std::chrono::seconds(30)};\n\n    /**\n     * \\brief The health-check interval.\n     * \\details\n     * If a connection becomes idle and hasn't been handed to the user for\n     * `ping_interval`, a health-check will be performed (using \\ref any_connection::async_ping).\n     * Pings will be sent with a periodicity of `ping_interval` until the connection\n     * is handed to the user, or a ping fails.\n     *\n     * Set this interval to zero to disable pings.\n     *\n     * This value must not be negative. It should be smaller than the server's\n     * idle timeout (as determined by the\n     * <a\n     * href=\"https://dev.mysql.com/doc/refman/8.4/en/server-system-variables.html#sysvar_wait_timeout\">wait_timeout</a>\n     * session variable). Otherwise, the server might close connections\n     * without the pool detecting it.\n     */\n    std::chrono::steady_clock::duration ping_interval{std::chrono::hours(1)};\n\n    /**\n     * \\brief The timeout to use for pings and session resets.\n     * \\details\n     * If pings (as per \\ref any_connection::async_ping) or session resets\n     * (as per \\ref any_connection::async_reset_connection) take longer than this\n     * timeout, they will be cancelled, and the operation will be considered failed.\n     * \\n\n     * Set this timeout to zero to disable it.\n     * \\n\n     * This value must not be negative.\n     */\n    std::chrono::steady_clock::duration ping_timeout{std::chrono::seconds(10)};\n\n    /**\n     * \\brief Enables or disables thread-safety.\n     * \\details\n     * When set to `true`, the resulting connection pool are able to\n     * be shared between threads at the cost of some performance.\n     *\n     * Enabling thread safety for a pool creates an internal `asio::strand` object\n     * wrapping the executor passed to the pool's constructor.\n     * All state-mutating functions (including \\ref connection_pool::async_run,\n     * \\ref connection_pool::async_get_connection and returning connections)\n     * will be run through the created strand.\n     *\n     * Thread-safety doesn't extend to individual connections: \\ref pooled_connection\n     * objects can't be shared between threads. Thread-safety does not protect\n     * objects that don't belong to the pool. For instance, `asio::cancel_after`\n     * creates a timer that must be protected with a strand.\n     * Refer to\n     * <a href=\"../../connection_pool.html#mysql.connection_pool.thread_safe\">this\n     * page</a> for more info.\n     */\n    bool thread_safe{false};\n\n    /**\n     * \\brief The executor to be used by individual connections created by the pool.\n     * \\details\n     * If this member is set to a non-empty value\n     * (that is, `static_cast<bool>(connection_executor) == true`),\n     * individual connections will be created using this executor.\n     * Otherwise, connections will use the pool's executor\n     * (as per \\ref connection_pool::get_executor).\n     */\n    asio::any_io_executor connection_executor{};\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/results.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_RESULTS_HPP\n#define BOOST_MYSQL_RESULTS_HPP\n\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/resultset.hpp>\n#include <boost/mysql/resultset_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/results_impl.hpp>\n#include <boost/mysql/detail/results_iterator.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <stdexcept>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Holds the results of a SQL query (dynamic interface).\n * \\details\n * This object can store the results of single and multi resultset queries.\n * For the former, you use \\ref meta, \\ref rows, \\ref affected_rows and so on.\n * For the latter, this class is a random-access collection of \\ref resultset objects.\n * \\n\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe. \\n\n */\nclass results\n{\npublic:\n#ifdef BOOST_MYSQL_DOXYGEN\n    /**\n     * \\brief A random access iterator to an element.\n     * \\details The exact type of the iterator is unspecified.\n     */\n    using iterator = __see_below__;\n#else\n    using iterator = detail::results_iterator;\n#endif\n\n    /// \\copydoc iterator\n    using const_iterator = iterator;\n\n    /// A type that can hold elements in this collection with value semantics.\n    using value_type = resultset;\n\n    /// The reference type.\n    using reference = resultset_view;\n\n    /// \\copydoc reference\n    using const_reference = resultset_view;\n\n    /// An unsigned integer type to represent sizes.\n    using size_type = std::size_t;\n\n    /// A signed integer type used to represent differences.\n    using difference_type = std::ptrdiff_t;\n\n    /**\n     * \\brief Default constructor.\n     * \\details Constructs an empty results object, with `this->has_value() == false`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    results() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     */\n    results(const results& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * View objects obtained from `other` using \\ref rows and \\ref meta remain valid.\n     * Any other views and iterators referencing `other` are invalidated.\n     */\n    results(results&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * Views and iterators referencing `*this` are invalidated.\n     */\n    results& operator=(const results& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * View objects obtained from `other` using \\ref rows and \\ref meta remain valid.\n     * Any other views and iterators referencing `other` are invalidated. Views and iterators\n     * referencing `*this` are invalidated.\n     */\n    results& operator=(results&& other) = default;\n\n    /// Destructor\n    ~results() = default;\n\n    /**\n     * \\brief Returns whether the object holds a valid result.\n     * \\details Having `this->has_value()` is a precondition to call all data accessors.\n     * Objects populated by \\ref connection::execute and \\ref connection::async_execute\n     * are guaranteed to have `this->has_value() == true`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool has_value() const noexcept { return impl_.is_complete(); }\n\n    /**\n     * \\brief Returns the rows retrieved by the SQL query.\n     * \\details\n     * For operations returning more than one resultset, returns the rows\n     * for the first resultset.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    rows_view rows() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_rows(0);\n    }\n\n    /**\n     * \\brief Returns metadata about the columns in the query.\n     * \\details\n     * The returned collection will have as many \\ref metadata objects as columns retrieved by\n     * the SQL query, and in the same order.\n     * \\n\n     * For operations returning more than one resultset, returns metadata\n     * for the first resultset.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    metadata_collection_view meta() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_meta(0);\n    }\n\n    /**\n     * \\brief Returns the number of rows affected by the executed SQL statement.\n     * \\details\n     * Note that this is NOT the number of matched rows. If a row\n     * is matched but not affected, it won't be accounted for here.\n     *\n     * For operations returning more than one resultset, returns the\n     * first resultset's affected rows.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::uint64_t affected_rows() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_affected_rows(0);\n    }\n\n    /**\n     * \\brief Returns the last insert ID produced by the executed SQL statement.\n     * \\details\n     * For operations returning more than one resultset, returns the\n     * first resultset's last insert ID.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::uint64_t last_insert_id() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_last_insert_id(0);\n    }\n\n    /**\n     * \\brief Returns the number of warnings produced by the executed SQL statement.\n     * \\details\n     * For operations returning more than one resultset, returns the\n     * first resultset's warning count.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    unsigned warning_count() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_warning_count(0);\n    }\n\n    /**\n     * \\brief Returns additional text information about the execution of the SQL statement.\n     * \\details\n     * The format of this information is documented by MySQL <a\n     * href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html\">here</a>.\n     * \\n\n     * The returned string always uses ASCII encoding, regardless of the connection's character set.\n     * \\n\n     * For operations returning more than one resultset, returns the\n     * first resultset's info.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    string_view info() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_info(0);\n    }\n\n    /**\n     * \\brief Returns an iterator pointing to the first resultset that this object contains.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned iterator and any reference obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate iterators.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    iterator begin() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return iterator(&impl_, 0);\n    }\n\n    /**\n     * \\brief Returns an iterator pointing to one-past-the-last resultset that this object contains.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned iterator and any reference obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate iterators.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    iterator end() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return iterator(&impl_, size());\n    }\n\n    /**\n     * \\brief Returns the i-th resultset or throws an exception.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * Strong guranatee. Throws on invalid input.\n     * \\throws std::out_of_range `i >= this->size()`\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate references.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    inline resultset_view at(std::size_t i) const\n    {\n        BOOST_ASSERT(has_value());\n        if (i >= size())\n            BOOST_THROW_EXCEPTION(std::out_of_range(\"results::at: out of range\"));\n        return detail::access::construct<resultset_view>(impl_, i);\n    }\n\n    /**\n     * \\brief Returns the i-th resultset (unchecked access).\n     * \\par Preconditions\n     * `this->has_value() == true && i < this->size()`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate references.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    resultset_view operator[](std::size_t i) const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        BOOST_ASSERT(i < size());\n        return detail::access::construct<resultset_view>(impl_, i);\n    }\n\n    /**\n     * \\brief Returns the first resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate references.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    resultset_view front() const noexcept { return (*this)[0]; }\n\n    /**\n     * \\brief Returns the last resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate references.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    resultset_view back() const noexcept { return (*this)[size() - 1]; }\n\n    /**\n     * \\brief Returns whether the collection contains any resultset.\n     * \\details\n     * This function is provided for compatibility with standard collections,\n     * and always returns false, since any valid `results` contains at least one resultset.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool empty() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return false;\n    }\n\n    /**\n     * \\brief Returns the number of resultsets that this collection contains.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::size_t size() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.num_resultsets();\n    }\n\n    /**\n     * \\brief Returns the output parameters of a stored procedure call.\n     * \\details\n     * Relevant for `CALL` operations performed using prepared statements that\n     * bind placeholders to `OUT` or `INOUT` parameters. Returns a row containing a field per\n     * bound output parameter.\n     * \\n\n     * If this operation had no output parameters (e.g. it wasn't a `CALL`), returns an empty row.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this` is alive. Move operations invalidate references.\n     *\n     * \\par Complexity\n     * Linear on `this->size()`.\n     */\n    row_view out_params() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_.get_out_params();\n    }\n\nprivate:\n    detail::results_impl impl_;\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/resultset.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_RESULTSET_HPP\n#define BOOST_MYSQL_RESULTSET_HPP\n\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/resultset_view.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/assert.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief An owning resultset, containing metadata, rows and additional info.\n * \\details\n * Similar to \\ref results, but can only represent a single resultset (while `results` can hold\n * multiple resultsets). Can be used to take ownership of a \\ref resultset_view.\n */\nclass resultset\n{\npublic:\n    /**\n     * \\brief Constructs an empty resultset.\n     * \\details\n     * The constructed object has `this->has_value() == false`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    resultset() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s.\n     *\n     * \\par Complexity\n     * Linear on rows and metadata size for `other`.\n     */\n    resultset(const resultset& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Views obtained from `other` remain valid.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    resultset(resultset&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s. Views obtained from `*this`\n     * are invalidated.\n     *\n     * \\par Complexity\n     * Linear on rows and metadata size for `other`.\n     */\n    resultset& operator=(const resultset& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Views obtained from `*this` are invalidated. Views obtained from `other` remain valid.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    resultset& operator=(resultset&& other) = default;\n\n    /**\n     * \\brief Destructor.\n     */\n    ~resultset() = default;\n\n    /**\n     * \\brief Constructs a resultset object by taking ownership of a view.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `v`'s (the contents of `v` will be copied\n     * into `*this`).\n     *\n     * \\par Complexity\n     * Linear on rows and metadata size for `v`.\n     */\n    resultset(resultset_view v) { assign(v); }\n\n    /**\n     * \\brief Replaces the contents of `*this` with a \\ref resultset_view.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `v`'s (the contents of `v` will be copied\n     * into `*this`). Views obtained from `*this` are invalidated.\n     *\n     * \\par Complexity\n     * Linear on rows and metadata size for `v` and `*this`.\n     */\n    resultset& operator=(resultset_view v)\n    {\n        assign(v);\n        return *this;\n    }\n\n    /**\n     * \\brief Returns whether this object contains actual data or not.\n     * \\details\n     * Only returns true for default-constructed objects.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool has_value() const noexcept { return has_value_; }\n\n    /**\n     * \\brief Returns the rows that this resultset contains.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this`  or an object move-constructed from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    rows_view rows() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return rws_;\n    }\n\n    /**\n     * \\brief Returns metadata for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this`  or an object move-constructed from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    metadata_collection_view meta() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return meta_;\n    }\n\n    /**\n     * \\brief Returns the number of affected rows for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::uint64_t affected_rows() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return affected_rows_;\n    }\n\n    /**\n     * \\brief Returns the last insert ID for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::uint64_t last_insert_id() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return last_insert_id_;\n    }\n\n    /**\n     * \\brief Returns the number of warnings for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    unsigned warning_count() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return warnings_;\n    }\n\n    /**\n     * \\brief Returns additional information for this resultset.\n     * \\details\n     * The format of this information is documented by MySQL <a\n     * href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html\">here</a>.\n     * \\n\n     * The returned string always uses ASCII encoding, regardless of the connection's character set.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * `*this`  or an object move-constructed from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    string_view info() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return string_view(info_.data(), info_.size());\n    }\n\n    /**\n     * \\brief Returns whether this resultset represents a procedure OUT params.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool is_out_params() const noexcept\n    {\n        BOOST_ASSERT(has_value_);\n        return is_out_params_;\n    }\n\nprivate:\n    bool has_value_{false};\n    std::vector<metadata> meta_;\n    ::boost::mysql::rows rws_;\n    std::uint64_t affected_rows_{};\n    std::uint64_t last_insert_id_{};\n    std::uint16_t warnings_{};\n    std::vector<char> info_;\n    bool is_out_params_{false};\n\n    BOOST_MYSQL_DECL\n    void assign(resultset_view v);\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/resultset.ipp>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/resultset_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_RESULTSET_VIEW_HPP\n#define BOOST_MYSQL_RESULTSET_VIEW_HPP\n\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/results_impl.hpp>\n\n#include <boost/assert.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A non-owning reference to a resultset.\n * \\details\n * A `resultset_view` points to memory owned by an external object, usually a \\ref results.\n * The view and any other reference type obtained from it are valid as long as the\n * object they point to is alive.\n */\nclass resultset_view\n{\npublic:\n    /**\n     * \\brief Constructs a view with `this->has_value() == false`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    resultset_view() = default;\n\n    /**\n     * \\brief Returns whether this is a null view or not.\n     * \\details\n     * Only returns true for default-constructed views.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool has_value() const noexcept { return impl_ != nullptr; }\n\n    /**\n     * \\brief Returns the rows for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * the object that `*this` points to is alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    rows_view rows() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_rows(index_);\n    }\n\n    /**\n     * \\brief Returns metadata for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * the object that `*this` points to is alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    metadata_collection_view meta() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_meta(index_);\n    }\n\n    /**\n     * \\brief Returns the number of affected rows for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::uint64_t affected_rows() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_affected_rows(index_);\n    }\n\n    /**\n     * \\brief Returns the last insert ID for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::uint64_t last_insert_id() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_last_insert_id(index_);\n    }\n\n    /**\n     * \\brief Returns the number of warnings for this resultset.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    unsigned warning_count() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_warning_count(index_);\n    }\n\n    /**\n     * \\brief Returns additional information for this resultset.\n     * \\details\n     * The format of this information is documented by MySQL <a\n     * href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html\">here</a>.\n     * \\n\n     * The returned string always uses ASCII encoding, regardless of the connection's character set.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned reference and any other references obtained from it are valid as long as\n     * the object that `*this` points to is alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    string_view info() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_info(index_);\n    }\n\n    /**\n     * \\brief Returns whether this resultset represents a procedure OUT params.\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool is_out_params() const noexcept\n    {\n        BOOST_ASSERT(has_value());\n        return impl_->get_is_out_params(index_);\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    const resultset_view* operator->() const noexcept { return this; }\n#endif\n\nprivate:\n    const detail::results_impl* impl_{};\n    std::size_t index_{};\n\n    resultset_view(const detail::results_impl& impl, std::size_t index) noexcept : impl_(&impl), index_(index)\n    {\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/row.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ROW_HPP\n#define BOOST_MYSQL_ROW_HPP\n\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/mysql/detail/row_impl.hpp>\n\n#include <cstddef>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief An owning, read-only sequence of fields.\n * \\details\n * Although owning, `row` is read-only. It's optimized for memory re-use. If you need to mutate\n * fields, use a `std::vector<field>` instead (see \\ref row_view::as_vector and \\ref\n * row::as_vector).\n *\n * \\par Object lifetimes\n * A `row` object owns a chunk of memory in which it stores its elements. On element access (using\n * iterators, \\ref row::at or \\ref row::operator[]) it returns \\ref field_view's pointing into the\n * `row`'s internal storage. These views behave like references, and are valid as long as pointers,\n * iterators and references into the `row` remain valid.\n */\nclass row\n{\n    detail::row_impl impl_;\n\npublic:\n#ifdef BOOST_MYSQL_DOXYGEN\n    /**\n     * \\brief A random access iterator to an element.\n     * \\details The exact type of the iterator is unspecified.\n     */\n    using iterator = __see_below__;\n#else\n    using iterator = const field_view*;\n#endif\n\n    /// \\copydoc iterator\n    using const_iterator = iterator;\n\n    /// A type that can hold elements in this collection with value semantics.\n    using value_type = field;\n\n    /// The reference type.\n    using reference = field_view;\n\n    /// \\copydoc reference\n    using const_reference = field_view;\n\n    /// An unsigned integer type to represent sizes.\n    using size_type = std::size_t;\n\n    /// A signed integer type used to represent differences.\n    using difference_type = std::ptrdiff_t;\n\n    /**\n     * \\brief Constructs an empty row.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    row() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s.\n     *\n     * \\par Complexity\n     * Linear on `other.size()`.\n     */\n    row(const row& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Iterators and references (including \\ref row_view's and \\ref field_view's) to\n     * elements in `other` remain valid.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    row(row&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s. Iterators and references\n     * (including \\ref row_view's and \\ref field_view's) to elements in `*this` are invalidated.\n     *\n     * \\par Complexity\n     * Linear on `this->size()` and `other.size()`.\n     */\n    row& operator=(const row& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Iterators and references (including \\ref row_view's and \\ref field_view's) to\n     * elements in `*this` are invalidated. Iterators and references to elements in `other` remain\n     * valid.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    row& operator=(row&& other) = default;\n\n    /**\n     * \\brief Destructor.\n     */\n    ~row() = default;\n\n    /**\n     * \\brief Constructs a row from a \\ref row_view.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `r`'s (the contents of `r` will be copied\n     * into `*this`).\n     *\n     * \\par Complexity\n     * Linear on `r.size()`.\n     */\n    row(row_view r) : impl_(r.begin(), r.size()) {}\n\n    /**\n     * \\brief Replaces the contents with a \\ref row_view.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `r`'s (the contents of `r` will be copied\n     * into `*this`). Iterators and references (including \\ref row_view's and \\ref field_view's) to\n     * elements in `*this` are invalidated.\n     *\n     * \\par Complexity\n     * Linear on `this->size()` and `r.size()`.\n     */\n    row& operator=(row_view r)\n    {\n        impl_.assign(r.begin(), r.size());\n        return *this;\n    }\n\n    /// \\copydoc row_view::begin\n    const_iterator begin() const noexcept { return impl_.fields().data(); }\n\n    /// \\copydoc row_view::end\n    const_iterator end() const noexcept { return impl_.fields().data() + impl_.fields().size(); }\n\n    /// \\copydoc row_view::at\n    field_view at(std::size_t i) const { return impl_.fields().at(i); }\n\n    /// \\copydoc row_view::operator[]\n    field_view operator[](std::size_t i) const noexcept { return impl_.fields()[i]; }\n\n    /// \\copydoc row_view::front\n    field_view front() const noexcept { return impl_.fields().front(); }\n\n    /// \\copydoc row_view::back\n    field_view back() const noexcept { return impl_.fields().back(); }\n\n    /// \\copydoc row_view::empty\n    bool empty() const noexcept { return impl_.fields().empty(); }\n\n    /// \\copydoc row_view::size\n    std::size_t size() const noexcept { return impl_.fields().size(); }\n\n    /**\n     * \\brief Creates a \\ref row_view that references `*this`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view will be valid until any function that invalidates iterators and\n     * references is invoked on `*this` or `*this` is destroyed.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    operator row_view() const noexcept { return row_view(impl_.fields().data(), impl_.fields().size()); }\n\n    /// \\copydoc row_view::as_vector\n    template <class Allocator>\n    void as_vector(std::vector<field, Allocator>& out) const\n    {\n        out.assign(begin(), end());\n    }\n\n    /// \\copydoc row_view::as_vector\n    std::vector<field> as_vector() const { return std::vector<field>(begin(), end()); }\n};\n\n/**\n * \\relates row\n * \\brief Equality operator.\n * \\details The containers are considered equal if they have the same number of elements and they\n * all compare equal, as defined by \\ref field_view::operator==.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Complexity\n * Linear in `lhs.size()` and `rhs.size()`.\n */\ninline bool operator==(const row& lhs, const row& rhs) noexcept { return row_view(lhs) == row_view(rhs); }\n\n/**\n * \\relates row\n * \\brief Inequality operator.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Complexity\n * Linear in `lhs.size()` and `rhs.size()`.\n */\ninline bool operator!=(const row& lhs, const row& rhs) { return !(lhs == rhs); }\n\n/**\n * \\relates row\n * \\copydoc row::operator==(const row&,const row&)\n */\ninline bool operator==(const row& lhs, const row_view& rhs) noexcept { return row_view(lhs) == rhs; }\n\n/**\n * \\relates row\n * \\copydoc row::operator!=(const row&,const row&)\n */\ninline bool operator!=(const row& lhs, const row_view& rhs) noexcept { return !(lhs == rhs); }\n\n/**\n * \\relates row\n * \\copydoc row::operator==(const row&,const row&)\n */\ninline bool operator==(const row_view& lhs, const row& rhs) noexcept { return lhs == row_view(rhs); }\n\n/**\n * \\relates row\n * \\copydoc row::operator!=(const row&,const row&)\n */\ninline bool operator!=(const row_view& lhs, const row& rhs) noexcept { return !(lhs == rhs); }\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/row_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ROW_VIEW_HPP\n#define BOOST_MYSQL_ROW_VIEW_HPP\n\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <boost/throw_exception.hpp>\n\n#include <cstddef>\n#include <stdexcept>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A non-owning read-only reference to a sequence of fields.\n * \\details\n * A `row_view` points to memory owned by an external entity (like `string_view` does). The validity\n * of a `row_view` depends on how it was obtained:\n * \\n\n * \\li If it was constructed from a \\ref row object (by calling \\ref row::operator row_view()), the\n *     view acts as a reference to the row's allocated memory, and is valid as long as references\n *     to that row elements are valid.\n * \\li If it was obtained by indexing a \\ref rows object, the same applies.\n * \\li If it was obtained by indexing a \\ref rows_view object, it's valid as long as the\n *    `rows_view` is valid.\n * \\n\n * Calling any member function on an invalid view results in undefined behavior.\n * \\n\n * When indexed (by using iterators, \\ref row_view::at or \\ref row_view::operator[]), it returns\n * \\ref field_view elements that are valid as long as the underlying storage that `*this` points\n * to is valid. Destroying a `row_view` doesn't invalidate `field_view`s obtained from\n * it.\n * \\n Instances of this class are usually created by the library, not by the user.\n */\nclass row_view\n{\npublic:\n    /**\n     * \\brief Constructs an empty (but valid) view.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    row_view() = default;\n\n#ifdef BOOST_MYSQL_DOXYGEN\n    /**\n     * \\brief A random access iterator to an element.\n     * \\details The exact type of the iterator is unspecified.\n     */\n    using iterator = __see_below__;\n#else\n    using iterator = const field_view*;\n#endif\n\n    /// \\copydoc iterator\n    using const_iterator = iterator;\n\n    /// A type that can hold elements in this collection with value semantics.\n    using value_type = field;\n\n    /// The reference type.\n    using reference = field_view;\n\n    /// \\copydoc reference\n    using const_reference = field_view;\n\n    /// An unsigned integer type to represent sizes.\n    using size_type = std::size_t;\n\n    /// A signed integer type used to represent differences.\n    using difference_type = std::ptrdiff_t;\n\n    /**\n     * \\brief Returns an iterator to the first field in the row.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    iterator begin() const noexcept { return fields_; }\n\n    /**\n     * \\brief Returns an iterator to one-past-the-last field in the row.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    iterator end() const noexcept { return fields_ + size_; }\n\n    /**\n     * \\brief Returns the i-th element in the row or throws an exception.\n     * \\par Exception safety\n     * Strong guranatee. Throws on invalid input.\n     * \\throws std::out_of_range `i >= this->size()`\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    field_view at(std::size_t i) const\n    {\n        if (i >= size_)\n            BOOST_THROW_EXCEPTION(std::out_of_range(\"row_view::at\"));\n        return fields_[i];\n    }\n\n    /**\n     * \\brief Returns the i-th element in the row (unchecked access).\n     * \\par Preconditions\n     * `i < this->size()`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    field_view operator[](std::size_t i) const noexcept { return fields_[i]; }\n\n    /**\n     * \\brief Returns the first element in the row.\n     * \\par Preconditions\n     * `this->size() > 0`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    field_view front() const noexcept { return *fields_; }\n\n    /**\n     * \\brief Returns the last element in the row.\n     * \\par Preconditions\n     * `this->size() > 0`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    field_view back() const noexcept { return fields_[size_ - 1]; }\n\n    /**\n     * \\brief Returns true if there are no fields in the row (i.e. `this->size() == 0`).\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool empty() const noexcept { return size_ == 0; }\n\n    /**\n     * \\brief Returns the number of fields in the row.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::size_t size() const noexcept { return size_; }\n\n    /**\n     * \\brief Converts the row into a `std::vector` of \\ref field's.\n     * \\details As \\ref row objects are read-only, you can use this function if you need to mutate\n     * fields in a row.\n     *\n     * \\par Exception safety\n     * Basic guarantee. Allocations may throw.\n     *\n     * \\par Complexity\n     * Linear in `this->size()`.\n     */\n    template <class Allocator>\n    void as_vector(std::vector<field, Allocator>& out) const\n    {\n        out.assign(begin(), end());\n    }\n\n    /// \\copydoc as_vector\n    std::vector<field> as_vector() const { return std::vector<field>(begin(), end()); }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    // Required by iterators\n    const row_view* operator->() const noexcept { return this; }\n#endif\n\nprivate:\n    row_view(const field_view* f, std::size_t size) noexcept : fields_(f), size_(size) {}\n    const field_view* fields_{};\n    std::size_t size_{};\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n    friend class row;\n#endif\n};\n\n/**\n * \\relates row_view\n * \\brief Equality operator.\n * \\details The containers are considered equal if they have the same number of elements and they\n * all compare equal, as defined by \\ref field_view::operator==.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Complexity\n * Linear in `lhs.size()` and `rhs.size()`.\n */\ninline bool operator==(const row_view& lhs, const row_view& rhs) noexcept\n{\n    if (lhs.size() != rhs.size())\n        return false;\n    for (std::size_t i = 0; i < lhs.size(); ++i)\n    {\n        if (lhs[i] != rhs[i])\n            return false;\n    }\n    return true;\n}\n\n/**\n * \\relates row_view\n * \\brief Inequality operator.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Complexity\n * Linear in `lhs.size()` and `rhs.size()`.\n */\ninline bool operator!=(const row_view& lhs, const row_view& rhs) noexcept { return !(lhs == rhs); }\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/rows.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ROWS_HPP\n#define BOOST_MYSQL_ROWS_HPP\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/mysql/detail/row_impl.hpp>\n#include <boost/mysql/detail/rows_iterator.hpp>\n\n#include <boost/throw_exception.hpp>\n\n#include <stdexcept>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief An owning, read-only sequence of rows.\n * \\details\n * Models an owning, matrix-like container. Indexing a `rows` object (by using iterators,\n * \\ref rows::at or \\ref rows::operator[]) returns a \\ref row_view object, representing a\n * single row. All rows in the collection are the same size (as given by \\ref num_columns).\n * \\n\n * A `rows` object owns a chunk of memory in which it stores its elements. The \\ref rows_view\n * objects obtained on element access point into the `rows`' internal storage. These views (and any\n * \\ref row_view and \\ref field_view obtained from the former) behave\n * like references, and are valid as long as pointers, iterators and references into the `rows`\n * object remain valid.\n * \\n\n * Although owning, `rows` is read-only. It's optimized for memory re-use.\n */\nclass rows\n{\npublic:\n#ifdef BOOST_MYSQL_DOXYGEN\n    /**\n     * \\brief A random access iterator to an element.\n     * \\details The exact type of the iterator is unspecified.\n     */\n    using iterator = __see_below__;\n#else\n    using iterator = detail::rows_iterator;\n#endif\n\n    /// \\copydoc iterator\n    using const_iterator = iterator;\n\n    /**\n     * \\brief A type that can hold elements in this collection with value semantics.\n     * \\details Note that element accesors (like \\ref rows_view::operator[]) return \\ref reference\n     * objects instead of `value_type` objects. You can use this type if you need an owning class.\n     */\n    using value_type = row;\n\n    /// The reference type.\n    using reference = row_view;\n\n    /// \\copydoc reference\n    using const_reference = row_view;\n\n    /// An unsigned integer type to represent sizes.\n    using size_type = std::size_t;\n\n    /// A signed integer type used to represent differences.\n    using difference_type = std::ptrdiff_t;\n\n    /**\n     * \\brief Construct an empty `rows` object.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    rows() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s.\n     *\n     * \\par Complexity\n     * Linear on `other.size() * other.num_columns()`.\n     */\n    rows(const rows& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Iterators and references (including \\ref rows_view's, \\ref row_view's and \\ref\n     * field_view's) to elements in `other` remain valid.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    rows(rows&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s. Iterators and references\n     * (including \\ref rows_view's, \\ref row_view's and \\ref field_view's) to elements in `*this`\n     * are invalidated.\n     *\n     * \\par Complexity\n     * Linear on `this->size() * this->num_columns()` and `other.size() * other.num_columns()`.\n     */\n    rows& operator=(const rows& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Iterators and references (including \\ref rows_view's \\ref row_view's and \\ref\n     * field_view's) to elements in `*this` are invalidated. Iterators and references to elements in\n     * `other` remain valid.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    rows& operator=(rows&& other) = default;\n\n    /**\n     * \\brief Destructor.\n     */\n    ~rows() = default;\n\n    /**\n     * \\brief Constructs a rows object from a \\ref rows_view.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `r`'s (the contents of `r` will be copied\n     * into `*this`).\n     *\n     * \\par Complexity\n     * Linear on `r.size() * r.num_columns()`.\n     */\n    rows(const rows_view& r) : impl_(r.fields_, r.num_fields_), num_columns_(r.num_columns_) {}\n\n    /**\n     * \\brief Replaces the contents of `*this` with a \\ref rows_view.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `r`'s (the contents of `r` will be copied\n     * into `*this`). Iterators and references (including \\ref rows_view's \\ref row_view's and \\ref\n     * field_view's) to elements in `*this` are invalidated.\n     *\n     * \\par Complexity\n     * Linear on `r.size() * r.num_columns()`.\n     */\n    rows& operator=(const rows_view& rhs)\n    {\n        impl_.assign(rhs.fields_, rhs.num_fields_);\n        num_columns_ = rhs.num_columns_;\n        return *this;\n    }\n\n    /// \\copydoc rows_view::begin\n    iterator begin() const noexcept { return iterator(impl_.fields().data(), num_columns_, 0); }\n\n    /// \\copydoc rows_view::end\n    iterator end() const noexcept { return iterator(impl_.fields().data(), num_columns_, size()); }\n\n    /// \\copydoc rows_view::at\n    row_view at(std::size_t i) const\n    {\n        if (i >= size())\n            BOOST_THROW_EXCEPTION(std::out_of_range(\"rows::at\"));\n        return detail::row_slice(impl_.fields().data(), num_columns_, i);\n    }\n\n    /// \\copydoc rows_view::operator[]\n    row_view operator[](std::size_t i) const noexcept\n    {\n        BOOST_ASSERT(i < size());\n        return detail::row_slice(impl_.fields().data(), num_columns_, i);\n    }\n\n    /// \\copydoc rows_view::front\n    row_view front() const noexcept { return (*this)[0]; }\n\n    /// \\copydoc rows_view::back\n    row_view back() const noexcept { return (*this)[size() - 1]; }\n\n    /// \\copydoc rows_view::empty\n    bool empty() const noexcept { return impl_.fields().empty(); }\n\n    /// \\copydoc rows_view::size\n    std::size_t size() const noexcept { return num_columns_ == 0 ? 0 : impl_.fields().size() / num_columns_; }\n\n    /// \\copydoc rows_view::num_columns\n    std::size_t num_columns() const noexcept { return num_columns_; }\n\n    /**\n     * \\brief Creates a \\ref rows_view that references `*this`.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * The returned view will be valid until any function that invalidates iterators and\n     * references is invoked on `*this` or `*this` is destroyed.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    operator rows_view() const noexcept\n    {\n        return rows_view(impl_.fields().data(), impl_.fields().size(), num_columns_);\n    }\n\nprivate:\n    detail::row_impl impl_;\n    std::size_t num_columns_{};\n};\n\n/**\n * \\relates rows\n * \\brief Equality operator.\n * \\details The containers are considered equal if they have the same number of rows and\n * they all compare equal, as defined by \\ref row_view::operator==.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Complexity\n * Linear in `lhs.size() * lhs.num_columns()` and `rhs.size() * rhs.num_columns()`.\n */\ninline bool operator==(const rows& lhs, const rows& rhs) noexcept { return rows_view(lhs) == rows_view(rhs); }\n\n/**\n * \\relates rows\n * \\brief Inequality operator.\n *\n * \\par Exception safety\n * No-throw guarantee.\n *\n * \\par Complexity\n * Linear in `lhs.size() * lhs.num_columns()` and `rhs.size() * rhs.num_columns()`.\n */\ninline bool operator!=(const rows& lhs, const rows& rhs) noexcept { return !(lhs == rhs); }\n\n/**\n * \\relates rows\n * \\copydoc rows::operator==(const rows&, const rows&)\n */\ninline bool operator==(const rows_view& lhs, const rows& rhs) noexcept { return lhs == rows_view(rhs); }\n\n/**\n * \\relates rows\n * \\copydoc rows::operator!=(const rows&, const rows&)\n */\ninline bool operator!=(const rows_view& lhs, const rows& rhs) noexcept { return !(lhs == rhs); }\n\n/**\n * \\relates rows\n * \\copydoc rows::operator==(const rows&, const rows&)\n */\ninline bool operator==(const rows& lhs, const rows_view& rhs) noexcept { return rows_view(lhs) == rhs; }\n\n/**\n * \\relates rows\n * \\copydoc rows::operator!=(const rows&, const rows&)\n */\ninline bool operator!=(const rows& lhs, const rows_view& rhs) noexcept { return !(lhs == rhs); }\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/rows_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_ROWS_VIEW_HPP\n#define BOOST_MYSQL_ROWS_VIEW_HPP\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/rows_iterator.hpp>\n\n#include <boost/assert.hpp>\n#include <boost/throw_exception.hpp>\n\n#include <cstddef>\n#include <stdexcept>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A non-owning read-only reference to a sequence of rows.\n * \\details\n * Models a non-owning matrix-like container. Indexing a `rows_view` object (by using iterators,\n * \\ref rows_view::at or \\ref rows_view::operator[]) returns a \\ref row_view object, representing a\n * single row. All rows in the collection are the same size (as given by \\ref num_columns).\n * \\n\n * A `rows_view` object points to memory owned by an external entity (like `string_view` does). The\n * validity of a `rows_view` object depends on how it was obtained:\n * \\n\n * \\li If it was constructed from a \\ref rows object (by calling \\ref rows::operator rows_view()),\n *     the view acts as a reference to the `rows`' allocated memory, and is valid as long as\n *     references to that `rows` elements are valid.\n * \\li If it was obtained by calling \\ref connection::read_some_rows it's valid until the\n *     `connection` performs the next network call or is destroyed.\n * \\n\n * \\ref row_view's and \\ref field_view's obtained by using a `rows_view` object are valid as long as\n * the underlying storage that `*this` points to is valid. Destroying `*this` doesn't invalidate\n * such references.\n * \\n\n * Calling any member function on an invalid view results in undefined behavior.\n * \\n\n * Instances of this class are usually created by the library, not by the user.\n */\nclass rows_view\n{\npublic:\n#ifdef BOOST_MYSQL_DOXYGEN\n    /**\n     * \\brief A random access iterator to an element.\n     * \\details The exact type of the iterator is unspecified.\n     */\n    using iterator = __see_below__;\n#else\n    using iterator = detail::rows_iterator;\n#endif\n\n    /// \\copydoc iterator\n    using const_iterator = iterator;\n\n    /// A type that can hold elements in this collection with value semantics.\n    using value_type = row;\n\n    /// The reference type.\n    using reference = row_view;\n\n    /// \\copydoc reference\n    using const_reference = row_view;\n\n    /// An unsigned integer type to represent sizes.\n    using size_type = std::size_t;\n\n    /// A signed integer type used to represent differences.\n    using difference_type = std::ptrdiff_t;\n\n    /**\n     * \\brief Construct an empty (but valid) view.\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    rows_view() = default;\n\n    /**\n     * \\brief Returns an iterator to the first element in the collection.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    const_iterator begin() const noexcept { return iterator(fields_, num_columns_, 0); }\n\n    /**\n     * \\brief Returns an iterator to one-past-the-last element in the collection.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    const_iterator end() const noexcept { return iterator(fields_, num_columns_, size()); }\n\n    /**\n     * \\brief Returns the i-th row or throws an exception.\n     * \\par Exception safety\n     * Strong guranatee. Throws on invalid input.\n     * \\throws std::out_of_range `i >= this->size()`\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    row_view at(std::size_t i) const\n    {\n        if (i >= size())\n            BOOST_THROW_EXCEPTION(std::out_of_range(\"rows_view::at\"));\n        return detail::row_slice(fields_, num_columns_, i);\n    }\n\n    /**\n     * \\brief Returns the i-th row (unchecked access).\n     * \\par Preconditions\n     * `i < this->size()`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    row_view operator[](std::size_t i) const noexcept\n    {\n        BOOST_ASSERT(i < size());\n        return detail::row_slice(fields_, num_columns_, i);\n    }\n\n    /**\n     * \\brief Returns the first row.\n     * \\par Preconditions\n     * `this->size() > 0`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    row_view front() const noexcept { return (*this)[0]; }\n\n    /**\n     * \\brief Returns the last row.\n     * \\par Preconditions\n     * `this->size() > 0`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    row_view back() const noexcept { return (*this)[size() - 1]; }\n\n    /**\n     * \\brief Returns true if there are no rows in the collection (i.e. `this->size() == 0`)\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool empty() const noexcept { return num_fields_ == 0; }\n\n    /**\n     * \\brief Returns the number of rows in the collection.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::size_t size() const noexcept { return (num_columns_ == 0) ? 0 : (num_fields_ / num_columns_); }\n\n    /**\n     * \\brief Returns the number of elements each row in the collection has.\n     * \\details For every \\ref row_view object r obtained from this collection,\n     * `r.size() == this->num_columns()`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    std::size_t num_columns() const noexcept { return num_columns_; }\n\n    /**\n     * \\brief Equality operator.\n     * \\details The containers are considered equal if they have the same number of rows and\n     * they all compare equal, as defined by \\ref row_view::operator==.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Linear on `this->size() * this->num_columns()`.\n     */\n    bool operator==(const rows_view& rhs) const noexcept\n    {\n        if (num_fields_ != rhs.num_fields_ || num_columns_ != rhs.num_columns_)\n            return false;\n        for (std::size_t i = 0; i < num_fields_; ++i)\n        {\n            if (fields_[i] != rhs.fields_[i])\n                return false;\n        }\n        return true;\n    }\n\n    /**\n     * \\brief Inequality operator.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Linear on `this->size() * this->num_columns()`.\n     */\n    inline bool operator!=(const rows_view& rhs) const noexcept { return !(*this == rhs); }\n\nprivate:\n    const field_view* fields_{};\n    std::size_t num_fields_{};\n    std::size_t num_columns_{};\n\n    rows_view(const field_view* fields, std::size_t num_fields, std::size_t num_columns) noexcept\n        : fields_(fields), num_fields_(num_fields), num_columns_(num_columns)\n    {\n        BOOST_ASSERT(fields != nullptr || num_fields == 0);  // fields null => num_fields 0\n        BOOST_ASSERT(num_fields == 0 || num_columns != 0);   // num_fields != 0 => num_columns != 0\n        BOOST_ASSERT(num_columns == 0 || (num_fields % num_columns == 0));\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n    friend class rows;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/sequence.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_SEQUENCE_HPP\n#define BOOST_MYSQL_SEQUENCE_HPP\n\n#include <boost/mysql/detail/sequence.hpp>\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n#include <concepts>\n#endif\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief The return type of \\ref sequence.\n * \\details\n * Contains a range, a formatter function, and a glue string.\n * This type satisfies the `Formattable` concept.\n *\n * When formatted, \\ref format_function is invoked for each element\n * in \\ref range. The string \\ref glue is output raw (as per \\ref format_context_base::append_raw)\n * between consecutive invocations of the formatter function, generating an effect\n * similar to `std::ranges::views::join`.\n *\n * Don't instantiate this struct directly - use \\ref sequence, instead.\n *\n * \\par Type requirements\n *\n *   - Expressions `std::begin(range)` and `std::end(range)` should return an input iterator/sentinel\n *     pair that can be compared for (in)equality.\n *   - The expression `static_cast<const FormatFn&>(fn)(* std::begin(range), ctx)`\n *     should be well formed, with `ctx` begin a `format_context_base&`.\n */\ntemplate <class Range, class FormatFn>\n#if defined(BOOST_MYSQL_HAS_CONCEPTS)\n    requires detail::format_fn_for_range<FormatFn, Range>\n#endif\nstruct format_sequence\n{\n    /// The range to format.\n    Range range;\n\n    /// The format function to apply to each element in the range.\n    FormatFn format_function;\n\n    /// The string to output between range elements.\n    constant_string_view glue;\n};\n\n/**\n * \\brief The type of range produced by \\ref sequence.\n * \\details\n * This type trait can be used to obtain the range type produced\n * by calling \\ref sequence. This type is used as the `Range` template\n * parameter in \\ref format_sequence.\n *\n * By default, \\ref sequence copies its input range, unless\n * using `std::ref`. C arrays are copied into `std::array` objects.\n * This type trait accounts these transformations.\n *\n * Formally, given the input range type `T` (which can be a reference with cv-qualifiers):\n *\n *  - If `T` is a C array or a reference to one (as per `std::is_array`),\n *    and the array elements' type is `U`, yields `std::array<std::remove_cv_t<U>, N>`.\n *  - If `T` is a `std::reference_wrapper<U>` object, or a reference to one,\n *    yields `U&`.\n *  - Otherwise, yields `std::remove_cvref_t<T>`.\n *\n * Examples:\n *\n *  - `sequence_range_t<const std::vector<int>&>` is `std::vector<int>`.\n *  - `sequence_range_t<std::reference_wrapper<std::vector<int>>>` is `std::vector<int>&`.\n *  - `sequence_range_t<std::reference_wrapper<const std::vector<int>>>` is `const std::vector<int>&`.\n *  - `sequence_range_t<int(&)[4]>` is `std::array<int, 4>`.\n */\ntemplate <class T>\nusing sequence_range_t =\n#ifdef BOOST_MYSQL_DOXYGEN\n    __see_below__\n#else\n    typename detail::sequence_range_type<T>::type;\n#endif\n    ;\n\n/**\n * \\brief Creates an object that, when formatted, applies a per-element function to a range.\n * \\details\n * Objects returned by this function satisfy `Formattable`.\n * Formatting such objects invokes `fn` for each element\n * in `range`, outputting `glue` between invocations.\n * This generates an effect similar to `std::ranges::views::join`.\n *\n * By default, this function creates an owning object by decay-copying `range` into it.\n * C arrays are copied into `std::array` objects. This behavior can be disabled\n * by passing `std::reference_wrapper` objects, which are converted to references\n * (as `std::make_tuple` does). The \\ref sequence_range_t\n * type trait accounts for these transformations.\n *\n * Formally:\n *\n *   - If `Range` is a (possibly cv-qualified) C array reference (as per `std::is_array<Range>`),\n *     and the array has `N` elements of type `U`, the output range type is\n *     `std::array<std::remove_cv< U >, N>`, and the range is created as if `std::to_array` was called.\n *   - If `Range` is a `std::reference_wrapper< U >` object, or a reference to one,\n *     the output range type is `U&`. This effectively disables copying the input range.\n *     The resulting object will be a view type, and the caller is responsible for lifetime management.\n *   - Otherwise, the output range type is `std::remove_cvref_t<Range>`, and it will be\n *     created by forwarding the passed `range`.\n *\n * `FormatFn` is always decay-copied into the resulting object.\n *\n * The glue string is always stored as a view, as it should usually point to a compile-time constant.\n *\n * \\par Type requirements\n *\n * The resulting range and format function should be compatible, and any required\n * copy/move operations should be well defined. Formally:\n *\n *   - `std::decay_t<FormatFn>` should be a formatter function compatible with\n *     the elements of the output range. See \\ref format_sequence for the formal requirements.\n *   - If `Range` is a `std::reference_wrapper< U >`, or a reference to one,\n *     no further requirements are placed on `U`.\n *   - If `Range` is a lvalue reference to a C array, its elements should be copy-constructible\n *     (as per `std::to_array` requirements).\n *   - If `Range` is a rvalue reference to a C array, its elements should be move-constructible\n *     (as per `std::to_array` requirements).\n *   - Performing a decay-copy of `FormatFn` should be well defined.\n *\n * \\par Exception safety\n * Basic guarantee. Propagates any exception thrown when constructing the output\n * range and format function.\n */\ntemplate <class Range, class FormatFn>\n#if defined(BOOST_MYSQL_HAS_CONCEPTS)\n    requires std::constructible_from<typename std::decay<FormatFn>::type, FormatFn&&>\n#endif\nformat_sequence<sequence_range_t<Range>, typename std::decay<FormatFn>::type> sequence(\n    Range&& range,\n    FormatFn&& fn,\n    constant_string_view glue = \", \"\n)\n\n{\n    return {detail::cast_range(std::forward<Range>(range)), std::forward<FormatFn>(fn), glue};\n}\n\ntemplate <class Range, class FormatFn>\nstruct formatter<format_sequence<Range, FormatFn>>\n{\n    const char* parse(const char* begin, const char*) { return begin; }\n\n    void format(format_sequence<Range, FormatFn>& value, format_context_base& ctx) const\n    {\n        detail::do_format_sequence(value.range, value.format_function, value.glue, ctx);\n    }\n\n    void format(const format_sequence<Range, FormatFn>& value, format_context_base& ctx) const\n    {\n        detail::do_format_sequence(value.range, value.format_function, value.glue, ctx);\n    }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/src.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_SRC_HPP\n#define BOOST_MYSQL_SRC_HPP\n\n// This file is meant to be included once, in a translation unit of\n// the program, with the macro BOOST_MYSQL_SEPARATE_COMPILATION defined.\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifndef BOOST_MYSQL_SEPARATE_COMPILATION\n#error You need to define BOOST_MYSQL_SEPARATE_COMPILATION in all translation units that use the compiled version of Boost.MySQL, \\\n    as well as the one where this file is included.\n#endif\n\n#include <boost/mysql/impl/any_connection.ipp>\n#include <boost/mysql/impl/character_set.ipp>\n#include <boost/mysql/impl/column_type.ipp>\n#include <boost/mysql/impl/connection_impl.ipp>\n#include <boost/mysql/impl/connection_pool.ipp>\n#include <boost/mysql/impl/date.ipp>\n#include <boost/mysql/impl/datetime.ipp>\n#include <boost/mysql/impl/engine_impl_instantiations.ipp>\n#include <boost/mysql/impl/error_categories.ipp>\n#include <boost/mysql/impl/escape_string.ipp>\n#include <boost/mysql/impl/execution_state_impl.ipp>\n#include <boost/mysql/impl/field.ipp>\n#include <boost/mysql/impl/field_kind.ipp>\n#include <boost/mysql/impl/field_view.ipp>\n#include <boost/mysql/impl/format_sql.ipp>\n#include <boost/mysql/impl/internal/error/server_error_to_string.ipp>\n#include <boost/mysql/impl/is_fatal_error.ipp>\n#include <boost/mysql/impl/meta_check_context.ipp>\n#include <boost/mysql/impl/pipeline.ipp>\n#include <boost/mysql/impl/results_impl.ipp>\n#include <boost/mysql/impl/resultset.ipp>\n#include <boost/mysql/impl/row_impl.ipp>\n#include <boost/mysql/impl/static_execution_state_impl.ipp>\n#include <boost/mysql/impl/static_results_impl.ipp>\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/ssl_mode.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_SSL_MODE_HPP\n#define BOOST_MYSQL_SSL_MODE_HPP\n\nnamespace boost {\nnamespace mysql {\n\n/// Determines how to perform SSL negotiation with the server.\nenum class ssl_mode\n{\n    /// Never use TLS\n    disable,\n\n    /// Use TLS if the server supports it, fall back to non-encrypted connection if it does not.\n    enable,\n\n    /// Always use TLS; abort the connection if the server does not support it.\n    require\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/statement.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_STATEMENT_HPP\n#define BOOST_MYSQL_STATEMENT_HPP\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/writable_field_traits.hpp>\n\n#include <boost/assert.hpp>\n\n#include <cstdint>\n#include <tuple>\n#include <type_traits>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A statement with bound parameters, represented as a `std::tuple`.\n * \\details\n * This class satisfies `ExecutionRequest`. You can pass instances of this class to \\ref connection::execute,\n * \\ref connection::start_execution or their async counterparts.\n */\ntemplate <BOOST_MYSQL_WRITABLE_FIELD_TUPLE WritableFieldTuple>\nclass bound_statement_tuple;\n\n/**\n * \\brief A statement with bound parameters, represented as an iterator range.\n * \\details\n * This class satisfies `ExecutionRequest`. You can pass instances of this class to \\ref connection::execute,\n * \\ref connection::start_execution or their async counterparts.\n */\ntemplate <BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator>\nclass bound_statement_iterator_range;\n\n/**\n * \\brief Represents a server-side prepared statement.\n * \\details\n * This is a lightweight class, holding a handle to a server-side prepared statement.\n * \\n\n * Note that statement's destructor doesn't deallocate the statement from the\n * server, as this implies a network transfer that may fail.\n *\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe. \\n\n */\nclass statement\n{\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details Default constructed statements have `this->valid() == false`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    statement() = default;\n\n    /**\n     * \\brief Returns `true` if the object represents an actual server statement.\n     * \\details Calling any function other than assignment on a statement for which\n     * this function returns `false` results in undefined behavior.\n     * \\n\n     * Returns `false` for default-constructed statements.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool valid() const noexcept { return valid_; }\n\n    /**\n     * \\brief Returns a server-side identifier for the statement (unique in a per-connection basis).\n     * \\details Note that, once a statement is closed, the server may recycle its ID.\n     *\n     * \\par Preconditions\n     * `this->valid() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    std::uint32_t id() const noexcept\n    {\n        BOOST_ASSERT(valid());\n        return id_;\n    }\n\n    /**\n     * \\brief Returns the number of parameters that should be provided when executing the statement.\n     * \\par Preconditions\n     * `this->valid() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    unsigned num_params() const noexcept\n    {\n        BOOST_ASSERT(valid());\n        return num_params_;\n    }\n\n    /**\n     * \\brief Binds parameters to a statement.\n     * \\details\n     * Creates an object that packages `*this` and the statement actual parameters `params`.\n     * This object can be passed to \\ref connection::execute, \\ref connection::start_execution\n     * and their async counterparts.\n     * \\n\n     * The parameters are copied into a `std::tuple` by using `std::make_tuple`. This function\n     * only participates in overload resolution if `std::make_tuple(FWD(args)...)` yields a\n     * `WritableFieldTuple`. Equivalent to `this->bind(std::make_tuple(std::forward<T>(params)...))`.\n     * \\n\n     * This function doesn't involve communication with the server.\n     *\n     * \\par Preconditions\n     * `this->valid() == true`\n     * \\n\n     * \\par Exception safety\n     * Strong guarantee. Only throws if constructing any of the internal tuple elements throws.\n     */\n    template <class... T>\n#ifdef BOOST_MYSQL_DOXYGEN\n    bound_statement_tuple<std::tuple<__see_below__>>\n#else\n    auto\n#endif\n    bind(T&&... params) const->typename std::enable_if<\n        detail::is_writable_field_tuple<decltype(std::make_tuple(std::forward<T>(params)...))>::value,\n        bound_statement_tuple<decltype(std::make_tuple(std::forward<T>(params)...))>>::type\n    {\n        return bind(std::make_tuple(std::forward<T>(params)...));\n    }\n\n    /**\n     * \\brief Binds parameters to a statement.\n     * \\details\n     * Creates an object that packages `*this` and the statement actual parameters `params`.\n     * This object can be passed to \\ref connection::execute, \\ref connection::start_execution\n     * or their async counterparts.\n     * \\n\n     * The `params` tuple is decay-copied into the returned object.\n     * \\n\n     * This function doesn't involve communication with the server.\n     *\n     * \\par Preconditions\n     * `this->valid() == true`\n     * \\n\n     * \\par Exception safety\n     * Strong guarantee. Only throws if the decay-copy of the tuple throws.\n     */\n    template <\n        BOOST_MYSQL_WRITABLE_FIELD_TUPLE WritableFieldTuple,\n        typename EnableIf =\n            typename std::enable_if<detail::is_writable_field_tuple<WritableFieldTuple>::value>::type>\n    bound_statement_tuple<typename std::decay<WritableFieldTuple>::type> bind(WritableFieldTuple&& params\n    ) const;\n\n    /**\n     * \\brief Binds parameters to a statement (iterator range overload).\n     * \\details\n     * Creates an object that packages `*this` and the statement actual parameters, represented\n     * as the iterator range `[params_first, params_last)`.\n     * This object can be passed to \\ref connection::execute, \\ref connection::start_execution\n     * or their async counterparts.\n     * \\n\n     * This function doesn't involve communication with the server.\n     *\n     * \\par Preconditions\n     * `this->valid() == true`\n     * \\n\n     * \\par Exception safety\n     * Strong guarantee. Only throws if copy-constructing iterators throws.\n     */\n    template <\n        BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR FieldViewFwdIterator,\n        typename EnableIf = typename std::enable_if<\n            detail::is_field_view_forward_iterator<FieldViewFwdIterator>::value>::type>\n    bound_statement_iterator_range<FieldViewFwdIterator> bind(\n        FieldViewFwdIterator params_first,\n        FieldViewFwdIterator params_last\n    ) const;\n\nprivate:\n    bool valid_{false};\n    std::uint32_t id_{0};\n    std::uint16_t num_params_{0};\n\n    statement(std::uint32_t id, std::uint16_t num_params) noexcept\n        : valid_(true), id_(id), num_params_(num_params)\n    {\n    }\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#include <boost/mysql/impl/statement.hpp>\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/static_execution_state.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_STATIC_EXECUTION_STATE_HPP\n#define BOOST_MYSQL_STATIC_EXECUTION_STATE_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/static_execution_state_impl.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Holds state for multi-function SQL execution operations (static interface).\n * \\details\n * This class behaves like a state machine. The current state can be accessed using\n * \\ref should_start_op, \\ref should_read_rows, \\ref should_read_head\n * and \\ref complete. They are mutually exclusive.\n * More states may be added in the future as more protocol features are implemented.\n * \\n\n * Note that this class doesn't store rows anyhow. Row template parameters are\n * used to validate their compatibility with the data that will be returned by the server.\n *\n * \\tparam StaticRow The row or row types that will be returned by the server.\n * There must be one for every resultset returned by the query, and always at least one.\n * All the passed types must fulfill the `StaticRow` concept.\n *\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe.\n */\ntemplate <class... StaticRow>\nclass static_execution_state\n{\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details The constructed object is guaranteed to have\n     * `should_start_op() == true`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    static_execution_state() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s.\n     */\n    static_execution_state(const static_execution_state& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Views obtained from `other` remain valid.\n     */\n    static_execution_state(static_execution_state&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * `*this` lifetime will be independent of `other`'s. Views obtained from `*this`\n     * are invalidated.\n     */\n    static_execution_state& operator=(const static_execution_state& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * Views obtained from `*this` are invalidated. Views obtained from `other` remain valid.\n     */\n    static_execution_state& operator=(static_execution_state&& other) = default;\n\n    /**\n     * \\brief Returns whether `*this` is in the initial state.\n     * \\details\n     * Call \\ref connection::start_execution or \\ref connection::async_start_execution to move\n     * forward. No data is available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool should_start_op() const noexcept { return impl_.get_interface().is_reading_first(); }\n\n    /**\n     * \\brief Returns whether the next operation should be read resultset head.\n     * \\details\n     * Call \\ref connection::read_resultset_head or its async counterpart to move forward.\n     * Metadata and OK data for the previous resultset is available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool should_read_head() const noexcept { return impl_.get_interface().is_reading_first_subseq(); }\n\n    /**\n     * \\brief Returns whether the next operation should be read some rows.\n     * \\details\n     * Call \\ref connection::read_some_rows or its async counterpart to move forward.\n     * Metadata for the current resultset is available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool should_read_rows() const noexcept { return impl_.get_interface().is_reading_rows(); }\n\n    /**\n     * \\brief Returns whether all the messages generated by this operation have been read.\n     * \\details\n     * No further network calls are required to move forward. Metadata and OK data for the last\n     * resultset are available in this state.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool complete() const noexcept { return impl_.get_interface().is_complete(); }\n\n    /**\n     * \\brief Returns metadata about the columns in the query.\n     * \\details\n     * The returned collection will have as many \\ref metadata objects as columns retrieved by\n     * the SQL query, and in the same order. Note that this may not be the same order as in the `StaticRow`\n     * type, since columns may be mapped by name or discarded. This function returns the representation that\n     * was retrieved from the database.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     */\n    metadata_collection_view meta() const noexcept { return impl_.get_interface().meta(); }\n\n    /**\n     * \\brief Returns the number of rows affected by the SQL statement associated to this resultset.\n     * Note that this is NOT the number of matched rows. If a row\n     * is matched but not affected, it won't be accounted for here.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     */\n    std::uint64_t affected_rows() const noexcept { return impl_.get_interface().get_affected_rows(); }\n\n    /**\n     * \\brief Returns the last insert ID produced by the SQL statement associated to this resultset.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     */\n    std::uint64_t last_insert_id() const noexcept { return impl_.get_interface().get_last_insert_id(); }\n\n    /**\n     * \\brief Returns the number of warnings produced by the SQL statement associated to this resultset.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     */\n    unsigned warning_count() const noexcept { return impl_.get_interface().get_warning_count(); }\n\n    /**\n     * \\brief Returns additional text information about this resultset.\n     * \\details\n     * The format of this information is documented by MySQL <a\n     * href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html\">here</a>.\n     * \\n\n     * The returned string always uses ASCII encoding, regardless of the connection's character set.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     */\n    string_view info() const noexcept { return impl_.get_interface().get_info(); }\n\n    /**\n     * \\brief Returns whether the current resultset represents a procedure OUT params.\n     * \\par Preconditions\n     * `this->complete() == true || this->should_read_head() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    bool is_out_params() const noexcept { return impl_.get_interface().get_is_out_params(); }\n\nprivate:\n    detail::static_execution_state_impl<StaticRow...> impl_;\n\n    static_assert(sizeof...(StaticRow) > 0, \"static_execution_state requires one row type, at least\");\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif  // BOOST_MYSQL_CXX14\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/static_results.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_STATIC_RESULTS_HPP\n#define BOOST_MYSQL_STATIC_RESULTS_HPP\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/underlying_row.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/static_results_impl.hpp>\n\n#include <boost/assert.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Holds the results of a SQL query (static interface).\n * \\details\n * This object can store the results of single and multi resultset queries\n * in a type-safe manner.\n *\n * \\tparam StaticRow The row or row types that will be returned by the server.\n * There must be one for every resultset returned by the query, and always at least one.\n * All the passed types must fulfill the `StaticRow` concept.\n *\n * \\par Thread safety\n * Distinct objects: safe. \\n\n * Shared objects: unsafe. \\n\n */\ntemplate <class... StaticRow>\nclass static_results\n{\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details Constructs an empty results object, with `this->has_value() == false`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     */\n    static_results() = default;\n\n    /**\n     * \\brief Copy constructor.\n     * \\par Exception safety\n     * Strong guarantee. Internal allocations may throw.\n     */\n    static_results(const static_results& other) = default;\n\n    /**\n     * \\brief Move constructor.\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * View objects obtained from `other` remain valid.\n     */\n    static_results(static_results&& other) = default;\n\n    /**\n     * \\brief Copy assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * Views referencing `*this` are invalidated.\n     */\n    static_results& operator=(const static_results& other) = default;\n\n    /**\n     * \\brief Move assignment.\n     * \\par Exception safety\n     * Basic guarantee. Internal allocations may throw.\n     *\n     * \\par Object lifetimes\n     * View objects obtained from `other` remain valid.\n     * Views and referencing `*this` are invalidated.\n     */\n    static_results& operator=(static_results&& other) = default;\n\n    /// Destructor\n    ~static_results() = default;\n\n    /**\n     * \\brief Returns whether the object holds a valid result.\n     * \\details Having `this->has_value()` is a precondition to call all data accessors.\n     * Objects populated by \\ref connection::execute and \\ref connection::async_execute\n     * are guaranteed to have `this->has_value() == true`.\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    bool has_value() const noexcept { return impl_.get_interface().is_complete(); }\n\n    /**\n     * \\brief Returns the rows retrieved by the SQL query.\n     * \\details\n     *\n     * \\tparam I Resultset index. For operations returning more than one resultset, you can explicitly\n     * specify this parameter to obtain the rows contained in the i-th resultset. If left unspecified,\n     * rows for the first resultset are returned.\n     *\n     * \\return Returns a read-only span of the `I`-th row type.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    template <std::size_t I = 0>\n#ifdef BOOST_MYSQL_DOXYGEN\n    boost::span<const StaticRow... [I]>\n#else\n    detail::rows_span_t<I, StaticRow...>\n#endif\n    rows() const noexcept {\n        static_assert(I < sizeof...(StaticRow), \"Index I out of range\");\n        BOOST_ASSERT(has_value());\n        return impl_.template get_rows<I>();\n    }\n\n    /**\n     * \\brief Returns metadata about the columns in the query.\n     * \\details\n     * The returned collection will have as many \\ref metadata objects as columns retrieved by\n     * the SQL query, and in the same order. Note that this may not be the same order as in the `StaticRow`\n     * type, since columns may be mapped by name or discarded. This function returns the representation that\n     * was retrieved from the database.\n     *\n     * \\tparam I Resultset index. For operations returning more than one resultset, you can explicitly\n     * specify this parameter to obtain metadata for the i-th resultset. If left unspecified,\n     * metadata for the first resultset is returned.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    template <std::size_t I = 0>\n    metadata_collection_view meta() const noexcept\n    {\n        static_assert(I < sizeof...(StaticRow), \"Index I out of range\");\n        BOOST_ASSERT(has_value());\n        return impl_.get_interface().get_meta(I);\n    }\n\n    /**\n     * \\brief Returns the number of rows affected by the executed SQL statement.\n     * \\details\n     * Note that this is NOT the number of matched rows. If a row\n     * is matched but not affected, it won't be accounted for here.\n     *\n     * \\tparam I Resultset index. For operations returning more than one resultset, you can explicitly\n     * specify this parameter to obtain the number of affected rows by the i-th resultset. If left\n     * unspecified, the number of affected rows by the first resultset is returned.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    template <std::size_t I = 0>\n    std::uint64_t affected_rows() const noexcept\n    {\n        static_assert(I < sizeof...(StaticRow), \"Index I out of range\");\n        BOOST_ASSERT(has_value());\n        return impl_.get_interface().get_affected_rows(I);\n    }\n\n    /**\n     * \\brief Returns the last insert ID produced by the executed SQL statement.\n     * \\details\n     * \\tparam I Resultset index. For operations returning more than one resultset, you can explicitly\n     * specify this parameter to obtain the last insert ID for the i-th resultset. If left unspecified,\n     * the last insert ID for the first resultset is returned.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    template <std::size_t I = 0>\n    std::uint64_t last_insert_id() const noexcept\n    {\n        static_assert(I < sizeof...(StaticRow), \"I index out of range\");\n        BOOST_ASSERT(has_value());\n        return impl_.get_interface().get_last_insert_id(I);\n    }\n\n    /**\n     * \\brief Returns the number of warnings produced by the executed SQL statement.\n     * \\details\n     * \\tparam I Resultset index. For operations returning more than one resultset, you can explicitly\n     * specify this parameter to obtain the warning count for the i-th resultset. If left unspecified,\n     * the warning count for the first resultset is returned.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    template <std::size_t I = 0>\n    unsigned warning_count() const noexcept\n    {\n        static_assert(I < sizeof...(StaticRow), \"I index out of range\");\n        BOOST_ASSERT(has_value());\n        return impl_.get_interface().get_warning_count(I);\n    }\n\n    /**\n     * \\brief Returns additional text information about the execution of the SQL statement.\n     * \\details\n     * The format of this information is documented by MySQL <a\n     * href=\"https://dev.mysql.com/doc/c-api/8.0/en/mysql-info.html\">here</a>.\n     * \\n\n     * The returned string always uses ASCII encoding, regardless of the connection's character set.\n     *\n     * \\tparam I Resultset index. For operations returning more than one resultset, you can explicitly\n     * specify this parameter to obtain the value for the i-th resultset. If left unspecified,\n     * the value for the first resultset is returned.\n     *\n     * \\par Preconditions\n     * `this->has_value() == true`\n     *\n     * \\par Exception safety\n     * No-throw guarantee.\n     *\n     * \\par Object lifetimes\n     * This function returns a view object, with reference semantics. The returned view points into\n     * memory owned by `*this`, and will be valid as long as `*this` or an object move-constructed\n     * from `*this` are alive.\n     *\n     * \\par Complexity\n     * Constant.\n     */\n    template <std::size_t I = 0>\n    string_view info() const noexcept\n    {\n        static_assert(I < sizeof...(StaticRow), \"I index out of range\");\n        BOOST_ASSERT(has_value());\n        return impl_.get_interface().get_info(I);\n    }\n\nprivate:\n    detail::static_results_impl<StaticRow...> impl_;\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif  // BOOST_MYSQL_CXX14\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/string_view.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_STRING_VIEW_HPP\n#define BOOST_MYSQL_STRING_VIEW_HPP\n\n#include <boost/core/detail/string_view.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/// Type used to represent read-only string references, similar to `std::string_view`.\nusing string_view = boost::core::string_view;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/tcp.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TCP_HPP\n#define BOOST_MYSQL_TCP_HPP\n\n#include <boost/mysql/connection.hpp>\n\n#include <boost/asio/ip/tcp.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief (Legacy) A connection to MySQL over a TCP socket.\n *\n * \\par Legacy\n * New code should use \\ref any_connection instead of\n * \\ref connection and its helper typedefs, as it's simpler to use\n * and provides the same level of performance.\n */\nusing tcp_connection = connection<boost::asio::ip::tcp::socket>;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "include/boost/mysql/tcp_ssl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TCP_SSL_HPP\n#define BOOST_MYSQL_TCP_SSL_HPP\n\n#include <boost/mysql/connection.hpp>\n\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/ssl/stream.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief (Legacy) A connection to MySQL over a TCP socket using TLS.\n *\n * \\par Legacy\n * New code should use \\ref any_connection instead of\n * \\ref connection and its helper typedefs, as it's simpler to use\n * and provides the same level of performance.\n */\nusing tcp_ssl_connection = connection<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "include/boost/mysql/throw_on_error.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_THROW_ON_ERROR_HPP\n#define BOOST_MYSQL_THROW_ON_ERROR_HPP\n\n#include <boost/mysql/detail/throw_on_error_loc.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief (Legacy) Throws an exception in case of error, including diagnostic information.\n * \\details\n * If err indicates a failure (`err.failed() == true`), throws an exception that\n * derives from \\ref error_with_diagnostics. The exception will make\n * `diag` available in \\ref error_with_diagnostics::get_diagnostics.\n *\n * \\par Legacy\n * The introduction of \\ref with_diagnostics obsoletes almost all uses\n * of this function. New code should attempt to use \\ref with_diagnostics\n * instead of manually checking for errors.\n */\ninline void throw_on_error(error_code err, const diagnostics& diag = {})\n{\n    detail::throw_on_error_loc(err, diag, boost::source_location{});\n}\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/time.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TIME_HPP\n#define BOOST_MYSQL_TIME_HPP\n\n#include <boost/config.hpp>\n\n#include <chrono>\n\nnamespace boost {\nnamespace mysql {\n\n/// Type representing MySQL `TIME` data type.\nusing time = std::chrono::microseconds;\n\n/// The minimum allowed value for \\ref time.\nBOOST_INLINE_CONSTEXPR time min_time = -std::chrono::hours(839);\n\n/// The maximum allowed value for \\ref time.\nBOOST_INLINE_CONSTEXPR time max_time = std::chrono::hours(839);\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/underlying_row.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_UNDERLYING_ROW_HPP\n#define BOOST_MYSQL_UNDERLYING_ROW_HPP\n\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Type trait to retrieve the underlying row type.\n * \\details\n * Given an input type `T` satisfying the `StaticRow` concept,\n * this trait is an alias for its underlying row type. It is defined as follows:\n * \\n\n * \\li If `T` is a marker type, like \\ref pfr_by_name \"pfr_by_name< U >\", `underlying_row_t`\n *     is an alias for the marker's inner type `U`.\n * \\li If `T` is not a marker type (e.g. it's a Boost.Describe struct or a `std::tuple`),\n *     `underlying_row_t` is an alias for `T`.\n *\n * For instance, \\ref static_results::rows uses this trait to determine its return type.\n */\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nusing underlying_row_t =\n#ifdef BOOST_MYSQL_DOXYGEN\n    __see_below__\n#else\n    detail::underlying_row_t<StaticRow>\n#endif\n    ;\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/unix.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_UNIX_HPP\n#define BOOST_MYSQL_UNIX_HPP\n\n#include <boost/mysql/connection.hpp>\n\n#include <boost/asio/local/stream_protocol.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) || defined(BOOST_MYSQL_DOXYGEN)\n\n/**\n * \\brief (Legacy) A connection to MySQL over a UNIX domain socket.\n *\n * \\par Legacy\n * New code should use \\ref any_connection instead of\n * \\ref connection and its helper typedefs, as it's simpler to use\n * and provides the same level of performance.\n */\nusing unix_connection = connection<boost::asio::local::stream_protocol::socket>;\n\n#endif\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "include/boost/mysql/unix_ssl.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_UNIX_SSL_HPP\n#define BOOST_MYSQL_UNIX_SSL_HPP\n\n#include <boost/mysql/connection.hpp>\n\n#include <boost/asio/local/stream_protocol.hpp>\n#include <boost/asio/ssl/stream.hpp>\n\nnamespace boost {\nnamespace mysql {\n\n#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) || defined(BOOST_MYSQL_DOXYGEN)\n\n/**\n * \\brief (Legacy) A connection to MySQL over a UNIX domain socket over TLS.\n *\n * \\par Legacy\n * New code should not use this class. When using UNIX sockets, we recommend\n * using plaintext connections.\n */\nusing unix_ssl_connection = connection<boost::asio::ssl::stream<boost::asio::local::stream_protocol::socket>>;\n\n#endif\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "include/boost/mysql/with_diagnostics.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_WITH_DIAGNOSTICS_HPP\n#define BOOST_MYSQL_WITH_DIAGNOSTICS_HPP\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <type_traits>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief A completion token adapter used to include server diagnostics in exceptions.\n * \\details\n * When passed to an async initiating function, transforms its handler signature from `void(error_code, T...)`\n * to `void(std::exception_ptr, T...)`.\n * Uses knowledge of Boost.MySQL internals to grab any \\ref diagnostics\n * that the operation may produce to create a `std::exception_ptr` pointing to an \\ref error_with_diagnostics\n * object. On success, the generated `std::exception_ptr` will be `nullptr`.\n *\n * Using `with_diagnostics` to wrap tokens that throw exceptions (like `deferred` + `co_await` or\n * `yield_context`) enhances the thrown exceptions with diagnostics information, matching the ones thrown by\n * sync functions. If you don't use this token, Asio will use `system_error` exceptions, containing less info.\n *\n * This token can only be used with operations involving Boost.MySQL, as it relies on its internals.\n *\n * Like `asio::as_tuple`, this class wraps another completion token. For instance,\n * `with_diagnostics(asio::deferred)` will generate a deferred operation with an adapted\n * signature, which will throw `error_with_diagnostics` when `co_await`'ed.\n *\n * If this token is applied to a function with a handler signature that\n * does not match `void(error_code, T...)`, the token acts as a pass-through:\n * it does not modify the signature, and calls the underlying token's initiation directly.\n * This has the following implications:\n *\n *   - `asio::as_tuple(with_diagnostics(X))` is equivalent to `asio::as_tuple(X)`.\n *   - `asio::redirect_error(with_diagnostics(X))` is equivalent to `asio::redirect_error(X)`.\n *   - Tokens like `asio::as_tuple` and `asio::redirect_error` can be used as partial tokens\n *     when `with_diagnostics` is the default completion token, as is the case for \\ref any_connection.\n */\ntemplate <class CompletionToken>\nclass with_diagnostics_t\n{\n    CompletionToken impl_;\n\n#ifndef BOOST_MYSQL_DOXYGEN\n    friend struct detail::access;\n#endif\n\npublic:\n    /**\n     * \\brief Default constructor.\n     * \\details\n     * Only valid if `CompletionToken` is default-constructible.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Any exceptions thrown by default-constructing\n     * `CompletionToken` are propagated.\n     */\n    constexpr with_diagnostics_t() : impl_{} {}\n\n    /**\n     * \\brief Constructor.\n     * \\details\n     * The passed `token` should be convertible to `CompletionToken`.\n     *\n     * \\par Exception safety\n     * Strong guarantee. Any exceptions thrown by constructing `CompletionToken` are propagated.\n     */\n    template <class T>\n    constexpr explicit with_diagnostics_t(T&& token) : impl_(std::forward<T>(token))\n    {\n    }\n};\n\n/**\n * \\brief Creates a \\ref with_diagnostics_t from a completion token.\n * \\details\n * The passed token is decay-copied into the \\ref with_diagnostics_t object.\n *\n * \\par Exception safety\n * Strong guarantee. Any exceptions thrown by constructing `CompletionToken` are propagated.\n */\ntemplate <class CompletionToken>\nconstexpr with_diagnostics_t<typename std::decay<CompletionToken>::type> with_diagnostics(\n    CompletionToken&& token\n)\n{\n    return with_diagnostics_t<typename std::decay<CompletionToken>::type>(std::forward<CompletionToken>(token)\n    );\n}\n\n}  // namespace mysql\n}  // namespace boost\n\n#include <boost/mysql/impl/with_diagnostics.hpp>\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql/with_params.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_WITH_PARAMS_HPP\n#define BOOST_MYSQL_WITH_PARAMS_HPP\n\n#include <boost/mysql/constant_string_view.hpp>\n\n#include <boost/mysql/detail/format_sql.hpp>\n\n#include <tuple>\n#include <utility>\n\nnamespace boost {\nnamespace mysql {\n\n/**\n * \\brief Type trait that applies the transformation performed by `std::make_tuple` to a single element.\n * \\details\n * For example: \\n\n *   - `make_tuple_element_t<int>` yields `int` \\n\n *   - `make_tuple_element_t<const int&>` yields `int` \\n\n *   - `make_tuple_element_t<std::reference_wrapper<int>>` yields `int&` \\n\n * \\n\n * Consult the <a href=\"https://en.cppreference.com/w/cpp/utility/tuple/make_tuple\">`std::make_tuple`</a> docs\n * for more info.\n */\ntemplate <class T>\nusing make_tuple_element_t = typename std::tuple_element<0, decltype(std::make_tuple(std::declval<T&&>()))>::\n    type;\n\n/**\n * \\brief A query format string and format arguments that can be executed.\n * \\details\n * Contains a query with placeholders (i.e. `{}`) and a set of parameters to\n * expand such placeholders. Satisfies `ExecutionRequest` and can thus be passed\n * to \\ref any_connection::execute, \\ref any_connection::start_execution and its\n * async counterparts.\n * \\n\n * When executed, client-side SQL formatting is invoked\n * to expand the provided query with the supplied parameters. The resulting query is then sent to\n * the server for execution. Formally, given a `conn` variable of \\ref any_connection type,\n * the query is generated as if the following was called:\n * ```\n *   format_sql(\n *       this->query,\n *       conn.format_opts().value(),\n *       std::get<i>(this->args)... // for i in [0, sizeof...(Formattable))\n *   );\n * ```\n * \\n\n * Objects of this type are usually created using \\ref with_params, which\n * creates `args` by calling `std::make_tuple`.\n *\n * \\par Object lifetimes\n * The format string `query` is stored as a view, as a compile-time string should be used in most cases.\n * When using \\ref with_params, `args` will usually contain copies of the passed parameters\n * (as per <a href=\"https://en.cppreference.com/w/cpp/utility/tuple/make_tuple\">`std::make_tuple`</a>),\n * which is safe even when using async functions with deferred completion tokens.\n * You may disable such copies using `std::ref`, as you would when using `std::make_tuple`.\n *\n * \\par Errors\n * When passed to \\ref any_connection::execute, \\ref any_connection::start_execution or\n * its async counterparts, in addition to the usual network and server-generated errors,\n * `with_params_t` may generate the following errors: \\n\n *   - Any errors generated by \\ref format_sql. This includes errors due to invalid format\n *     strings and unformattable arguments (e.g. invalid UTF-8).\n *   - \\ref client_errc::unknown_character_set if the connection does not know the\n *     character set it's using when the query is executed (i.e. \\ref any_connection::current_character_set\n *     would return an error.\n */\ntemplate <BOOST_MYSQL_FORMATTABLE... Formattable>\nstruct with_params_t\n{\n    /// The query to be expanded and executed, which may contain `{}` placeholders.\n    constant_string_view query;\n\n    /// The arguments to use to expand the query.\n    std::tuple<Formattable...> args;\n};\n\n/**\n * \\brief Creates a query with parameters (client-side SQL formatting) that can be executed.\n * \\details\n * Creates a \\ref with_params_t object by packing the supplied arguments into a tuple,\n * calling <a href=\"https://en.cppreference.com/w/cpp/utility/tuple/make_tuple\">`std::make_tuple`</a>.\n * As per `std::make_tuple`, parameters will be decay-copied into the resulting object.\n * This behavior can be disabled by passing `std::reference_wrapper` objects, which are\n * transformed into references.\n * \\n\n * This function does not inspect the supplied query string and arguments.\n * Errors like missing format arguments are detected when the resulting object is executed.\n * This function does not involve communication with the server.\n * \\n\n * The passed `args` must either satisfy `Formattable`, or be `std::reference_wrapper<T>`\n * with `T` satisfying `Formattable`.\n * \\n\n * See \\ref with_params_t for details on how the execution request works.\n * \\n\n * \\par Exception safety\n * Strong guarantee. Any exception thrown when copying `args` will be propagated.\n * \\n\n */\ntemplate <class... FormattableOrRefWrapper>\nauto with_params(constant_string_view query, FormattableOrRefWrapper&&... args)\n    -> with_params_t<make_tuple_element_t<FormattableOrRefWrapper>...>\n{\n    return {query, std::make_tuple(std::forward<FormattableOrRefWrapper>(args)...)};\n}\n\n}  // namespace mysql\n}  // namespace boost\n\n#include <boost/mysql/impl/with_params.hpp>\n\n#endif\n"
  },
  {
    "path": "include/boost/mysql.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_HPP\n#define BOOST_MYSQL_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/bad_field_access.hpp>\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/buffer_params.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/connection.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/days.hpp>\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/escape_string.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_kind.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/is_fatal_error.hpp>\n#include <boost/mysql/mariadb_collations.hpp>\n#include <boost/mysql/mariadb_server_errc.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/mysql_server_errc.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/resultset.hpp>\n#include <boost/mysql/resultset_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/tcp.hpp>\n#include <boost/mysql/tcp_ssl.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n#include <boost/mysql/time.hpp>\n#include <boost/mysql/underlying_row.hpp>\n#include <boost/mysql/unix.hpp>\n#include <boost/mysql/unix_ssl.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#endif\n"
  },
  {
    "path": "index.html",
    "content": "<html>\n\n<head>\n    <title>Boost.MySQL</title>\n    <meta http-equiv=\"refresh\" content=\"0; URL=./doc/html/index.html\">\n</head>\n\n<body>\n    Automatic redirection failed, please go to\n    <a href=\"./doc/html/index.html\">./doc/html/index.html</a>\n    <hr>\n    <tt>\n        Boost.MySQL<br>\n        <br>\n        Copyright&nbsp;(C)&nbsp;2023&nbsp;Ruben&nbsp;Perez<br>\n        <br>\n        Distributed under the Boost Software License, Version 1.0.\n        (See accompanying file LICENSE_1_0.txt or copy at\n        <a href=http://www.boost.org/LICENSE_1_0.txt>http://www.boost.org/LICENSE_1_0.txt</a>) <br>\n        <br>\n    </tt>\n</body>\n\n</html>"
  },
  {
    "path": "meta/libraries.json",
    "content": "{\n    \"key\": \"mysql\",\n    \"name\": \"MySQL\",\n    \"authors\": [\n        \"Rubén Pérez\"\n    ],\n    \"description\": \"MySQL client library built on top of Boost.Asio.\",\n    \"category\": [\n        \"Concurrent\",\n        \"IO\"\n    ],\n    \"maintainers\": [\n        \"Rubén Pérez <rubenperez038@gmail.com>\"\n    ],\n    \"cxxstd\": \"11\"\n}"
  },
  {
    "path": "test/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Separately compiled Boost.MySQL and Boost.Asio\nadd_library(\n    boost_mysql_compiled\n    STATIC\n    common/src/boost_asio.cpp\n    common/src/boost_mysql.cpp\n)\ntarget_compile_definitions(\n    boost_mysql_compiled\n    PUBLIC\n    BOOST_ASIO_SEPARATE_COMPILATION\n    BOOST_MYSQL_SEPARATE_COMPILATION\n)\ntarget_link_libraries(boost_mysql_compiled PUBLIC boost_mysql)\nboost_mysql_test_target_settings(boost_mysql_compiled)\n\n# boost_mysql_testing contains common definitions, includes and settings.\n# Note: old versions of cmake require the sources passed to target_sources to be absolute\nadd_library(boost_mysql_testing INTERFACE)\ntarget_sources(\n    boost_mysql_testing\n    INTERFACE\n    ${CMAKE_CURRENT_SOURCE_DIR}/common/src/entry_point.cpp\n    ${CMAKE_CURRENT_SOURCE_DIR}/common/src/utils.cpp\n)\ntarget_link_libraries(\n    boost_mysql_testing\n    INTERFACE\n    boost_mysql_compiled\n    Boost::unit_test_framework\n    Boost::pfr\n)\ntarget_include_directories(\n    boost_mysql_testing\n    INTERFACE\n    common/include\n)\n\n# Unit testing\nadd_subdirectory(unit)\n\n# Integration testing\nif(BOOST_MYSQL_INTEGRATION_TESTS)\n    add_subdirectory(integration)\nendif()\n"
  },
  {
    "path": "test/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nrequire-b2 5.0.1 ;\nimport-search /boost/config/checks ;\n\nimport os ;\nimport path ;\nimport feature ;\nimport ac ;\nimport indirect ;\nimport config : requires ;\n\n# Support header-only builds\nfeature.feature boost.mysql.separate-compilation : on off : propagated composite ;\n\n# Support builds with BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT\nfeature.feature boost.mysql.use-ts-executor : off on : propagated composite ;\n\n# Support builds forcing !BOOST_ASIO_HAS_LOCAL_SOCKETS\nfeature.feature boost.mysql.disable-local-sockets : off on : propagated composite ;\n\n# Support valgrind\nfeature.feature boost.mysql.valgrind : off on : propagated composite ;\nfeature.compose <boost.mysql.valgrind>on : <define>BOOST_USE_VALGRIND ;\n\n# Configure openssl if it hasn't been done yet\nusing openssl ;\n\n# Provide a way to fail the build if OpenSSL is not found - used by CIs\nrule do_fail_impl ( a * )\n{\n    exit \"OpenSSL could not be found. Don't build target fail_if_no_openssl to skip this check\" ;\n}\n\nlocal do_fail = [ indirect.make do_fail_impl ] ;\n\nalias fail_if_no_openssl\n    : requirements\n        [ ac.check-library /openssl//ssl    : : <conditional>@$(do_fail) ]\n        [ ac.check-library /openssl//crypto : : <conditional>@$(do_fail) ]\n;\n\nexplicit fail_if_no_openssl ;\n\n# Requirements to use across targets\nlocal requirements =\n        <define>BOOST_ALL_NO_LIB=1\n        <define>BOOST_ASIO_NO_DEPRECATED=1\n        <define>BOOST_ASIO_DISABLE_BOOST_ARRAY=1\n        <define>BOOST_ASIO_DISABLE_BOOST_BIND=1\n        <define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1\n        <define>BOOST_ASIO_DISABLE_BOOST_REGEX=1\n        <define>BOOST_ASIO_DISABLE_BOOST_COROUTINE=1\n        <define>BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS=1\n        <define>BOOST_ALLOW_DEPRECATED_HEADERS=1\n        # Disable warning C4702: unreachable code, produced by Boost.Asio buffer.hpp\n        # Disable warning C4459: declaration xxx hides global declaration, produced by Boost.Asio win_iocp_file_service.ipp\n        # Remove /wd4100 when PFR fixes warnings\n        <toolset>msvc:<cxxflags>\"/bigobj /wd4702 /wd4100 /wd4459 /permissive-\"\n        <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1\n        <toolset>msvc:<define>_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING\n        <toolset>msvc:<define>_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING\n        <toolset>msvc:<define>_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING\n        <toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS # Required by Asio\n        # gcc-13+ doesn't understand view types and issues array bound warnings that don't make sense.\n        # -Wno-implicit-fallthrough is required by Asio SSL components\n        <toolset>gcc:<cxxflags>\"-Wno-dangling-reference -Wno-array-bounds -Wno-implicit-fallthrough\"\n        # gcc-13+ complains about TSAN not supporting std::atomic_thread_fence,\n        # used by Asio old net-ts type-erased executors.\n        <toolset>gcc,<thread-sanitizer>norecover:<cxxflags>-Wno-tsan\n        # gcc-11 emits spurious warnings for valid vector::insert ops\n        <toolset>gcc-11:<cxxflags>-Wno-stringop-overflow\n        # gcc-15 emits spurious warnings about uninitialized variables in coroutines\n        <toolset>gcc-15:<cxxflags>-Wno-maybe-uninitialized\n        # TODO: remove when PFR unused warnings are fixed\n        # https://github.com/boostorg/pfr/pull/187\n        <toolset>gcc:<cxxflags>-Wno-unused-parameter\n        <toolset>clang:<cxxflags>-Wno-unused-parameter\n        <target-os>linux:<define>_XOPEN_SOURCE=600\n        <target-os>linux:<define>_GNU_SOURCE=1\n        <target-os>windows:<define>_WIN32_WINNT=0x0601\n        <boost.mysql.use-ts-executor>on:<define>BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT\n        # Disable assertions when doing coverage, as they distort coverage data\n        <coverage>on:<define>BOOST_DISABLE_ASSERTS\n        <boost.mysql.disable-local-sockets>on:<define>BOOST_ASIO_DISABLE_LOCAL_SOCKETS\n    ;\n\nalias boost_mysql\n    :\n        $(boost_dependencies)/<warnings-as-errors>off\n        /openssl//ssl/<link>shared\n        /openssl//crypto/<link>shared\n    : requirements\n        [ requires\n            cxx11_defaulted_moves\n            cxx11_final\n            cxx11_hdr_array\n            cxx11_hdr_chrono\n            cxx11_hdr_tuple\n            cxx11_hdr_type_traits\n            cxx11_numeric_limits\n            cxx11_override\n            cxx11_smart_ptr\n            cxx11_trailing_result_types\n            cxx11_template_aliases\n            cxx11_variadic_templates\n        ]\n        [ ac.check-library /openssl//ssl    : <library>/openssl//ssl/<link>shared : <build>no ]\n        [ ac.check-library /openssl//crypto : <library>/openssl//crypto/<link>shared : <build>no ]\n        $(requirements)\n    : usage-requirements\n        $(requirements)\n    ;\n\nlib boost_mysql_compiled\n    :\n        common/src/boost_asio.cpp\n        boost_mysql\n    : requirements\n        <boost.mysql.separate-compilation>on:<source>common/src/boost_mysql.cpp\n        <boost.mysql.separate-compilation>on:<define>BOOST_MYSQL_SEPARATE_COMPILATION\n        <define>BOOST_ASIO_SEPARATE_COMPILATION\n        <link>static\n    : usage-requirements\n        <boost.mysql.separate-compilation>on:<define>BOOST_MYSQL_SEPARATE_COMPILATION\n        <define>BOOST_ASIO_SEPARATE_COMPILATION\n    ;\n\nalias common_test_sources\n    :\n        common/src/entry_point.cpp\n        common/src/utils.cpp\n    ;\n\n# Boost.Context causes failures with warnings-as-errors\n# under libc++, because it builds objects that raise a -stdlib=libc++ unused warning\nalias boost_context_lib : /boost/context//boost_context/<warnings-as-errors>off ;\n\n# Beast and JSON depend on Container, which causes trouble with <warnings-as-errors>on\nalias boost_beast_lib : /boost/beast//boost_beast/<warnings-as-errors>off ;\nalias boost_json_lib : /boost/json//boost_json/<warnings-as-errors>off ;\n\nalias boost_mysql_test\n    :\n        boost_mysql_compiled\n        # Unit test library generates some internal warnings we're not interested in\n        /boost/test//boost_unit_test_framework/<warnings-as-errors>off\n    : requirements\n        <link>static\n        <include>common/include\n    : usage-requirements\n        <include>common/include\n    ;\n\n# Mark a test as runnable using Valgrind. Some tests use\n# an intermediate Python runner, so just setting testing.launcher globally is incorrect\nalias launch_with_valgrind\n    : usage-requirements\n        <boost.mysql.valgrind>on:<testing.launcher>\"valgrind --leak-check=full --error-limit=yes --error-exitcode=1 --gen-suppressions=all\"\n    ;\n\nbuild-project unit ;\n"
  },
  {
    "path": "test/cmake_b2_separate_compilation_test/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# This is included in 02_integrating.qbk. If you change it, update these files, too.\n\ncmake_minimum_required(VERSION 3.5...3.22)\n\nproject(boost_mysql_example LANGUAGES CXX)\n\nfind_package(Boost REQUIRED COMPONENTS headers charconv)\nfind_package(Threads REQUIRED)\nfind_package(OpenSSL REQUIRED)\n\nadd_executable(\n    main\n    # Contains Boost.MySQL sources via #include <boost/mysql/src.hpp>\n    boost_mysql.cpp\n    # List any other .cpp your exe has here\n    main.cpp\n)\ntarget_link_libraries(main PRIVATE Boost::charconv Threads::Threads OpenSSL::Crypto OpenSSL::SSL)\n\n# We need to define BOOST_MYSQL_SEPARATE_COMPILATION in any code using Boost.MySQL in separate-build mode\ntarget_compile_definitions(main PRIVATE BOOST_MYSQL_SEPARATE_COMPILATION)\n\ninclude(CTest)\nadd_test(NAME main COMMAND main)\n"
  },
  {
    "path": "test/cmake_b2_separate_compilation_test/boost_mysql.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/src.hpp>\n"
  },
  {
    "path": "test/cmake_b2_separate_compilation_test/main.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/tcp_ssl.hpp>\n\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/system_executor.hpp>\n\nint main()\n{\n    boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);\n    boost::mysql::tcp_ssl_connection conn(boost::asio::system_executor{}, ssl_ctx);\n    return static_cast<int>(conn.uses_ssl());  // should be false for a non-connected connection\n}\n"
  },
  {
    "path": "test/cmake_b2_test/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# This is included in README.md and 02_integrating.qbk. If you change it, update these files, too.\n\ncmake_minimum_required(VERSION 3.5...3.22)\n\nproject(boost_mysql_example LANGUAGES CXX)\n\nfind_package(Boost REQUIRED COMPONENTS headers charconv)\nfind_package(Threads REQUIRED)\nfind_package(OpenSSL REQUIRED)\n\nadd_executable(main main.cpp)\ntarget_link_libraries(main PRIVATE Boost::charconv Threads::Threads OpenSSL::Crypto OpenSSL::SSL)\n\ninclude(CTest)\nadd_test(NAME main COMMAND main)\n"
  },
  {
    "path": "test/cmake_b2_test/main.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/tcp_ssl.hpp>\n\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/system_executor.hpp>\n\nint main()\n{\n    boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);\n    boost::mysql::tcp_ssl_connection conn(boost::asio::system_executor{}, ssl_ctx);\n    return static_cast<int>(conn.uses_ssl());  // should be false for a non-connected connection\n}\n"
  },
  {
    "path": "test/cmake_test/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\ncmake_minimum_required(VERSION 3.5...3.22)\n\nproject(cmake_subdir_test LANGUAGES CXX)\n\noption(BOOST_CI_INSTALL_TEST \"Whether to build install or add_subdirectory tests\" OFF)\n\nif(BOOST_CI_INSTALL_TEST)\n    find_package(boost_mysql REQUIRED)\nelse()\n    # Generated by boostdep --brief mysql\n    set(_DEPENDENCIES\n        # Primary dependencies\n        asio\n        assert\n        charconv\n        compat\n        config\n        core\n        describe\n        endian\n        intrusive\n        mp11\n        optional\n        pfr\n        system\n        throw_exception\n        variant2\n\n        # Secondary dependencies\n        align\n        context\n        date_time\n        container_hash\n        move\n        detail\n        predef\n        type_traits\n        utility\n        winapi\n        pool\n        smart_ptr\n        exception\n        algorithm\n        io\n        lexical_cast\n        numeric/conversion\n        range\n        tokenizer\n        preprocessor\n        array\n        bind\n        concept_check\n        \"function\"\n        iterator\n        mpl\n        regex\n        tuple\n        unordered\n        container\n        integer\n        conversion\n        function_types\n        fusion\n        functional\n        typeof\n    )\n\n    # Build our dependencies, so the targets Boost::xxx are defined\n    set(_BOOST_ROOT ../../../..)\n    foreach(_DEPENDENCY IN LISTS _DEPENDENCIES)\n        add_subdirectory(${_BOOST_ROOT}/libs/${_DEPENDENCY} boostorg/${_DEPENDENCY})\n    endforeach()\n\n    # Build our project\n    add_subdirectory(${_BOOST_ROOT}/libs/mysql boostorg/mysql)\nendif()\n\n# Copied from Alexander Grund's Boost.CI\nadd_executable(main main.cpp)\ntarget_link_libraries(main PRIVATE Boost::mysql)\n\nenable_testing()\nadd_test(NAME main COMMAND main)\n\nadd_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)\n"
  },
  {
    "path": "test/cmake_test/main.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/tcp.hpp>\n\n#include <boost/asio/system_executor.hpp>\n\nint main()\n{\n    boost::mysql::tcp_connection conn(boost::asio::system_executor{});\n    return static_cast<int>(conn.uses_ssl());  // should be false for a non-connected connection\n}\n"
  },
  {
    "path": "test/common/include/test_common/assert_buffer_equals.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_ASSERT_BUFFER_EQUALS_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_ASSERT_BUFFER_EQUALS_HPP\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct buffer_printer\n{\n    span<const std::uint8_t> buff;\n\n    constexpr buffer_printer(span<const std::uint8_t> b) noexcept : buff(b) {}\n};\n\nstd::ostream& operator<<(std::ostream& os, buffer_printer buff);\nbool buffer_equals(span<const std::uint8_t> b1, span<const std::uint8_t> b2);\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#define BOOST_MYSQL_ASSERT_BUFFER_EQUALS(b1, b2)                                            \\\n    BOOST_TEST(                                                                             \\\n        ::boost::mysql::test::buffer_equals(b1, b2),                                        \\\n        #b1 \" != \" #b2 \": \\nlhs: \" << ::boost::mysql::test::buffer_printer(b1)              \\\n                                   << \"\\nrhs: \" << ::boost::mysql::test::buffer_printer(b2) \\\n    )\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/buffer_concat.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_BUFFER_CONCAT_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_BUFFER_CONCAT_HPP\n\n#include <boost/core/span.hpp>\n\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline std::vector<std::uint8_t> concat(std::vector<std::uint8_t> lhs, const std::vector<std::uint8_t>& rhs)\n{\n    lhs.insert(lhs.end(), rhs.begin(), rhs.end());\n    return lhs;\n}\n\nclass buffer_builder\n{\n    std::vector<std::uint8_t> buff_;\n\npublic:\n    buffer_builder() = default;\n    buffer_builder& add(span<const std::uint8_t> value)\n    {\n        buff_.insert(buff_.end(), value.begin(), value.end());\n        return *this;\n    }\n    buffer_builder& add(const std::vector<std::uint8_t>& value)\n    {\n        return add(span<const std::uint8_t>(value));\n    }\n    std::vector<std::uint8_t> build() { return std::move(buff_); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/check_meta.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CHECK_META_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CHECK_META_HPP\n\n// This is a lighter check than integ tests' metadata_validator\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <initializer_list>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline void check_meta(metadata_collection_view meta, const std::vector<column_type>& expected_types)\n{\n    BOOST_TEST_REQUIRE(meta.size() == expected_types.size());\n    for (std::size_t i = 0; i < meta.size(); ++i)\n    {\n        BOOST_TEST(meta[i].type() == expected_types[i]);\n    }\n}\n\ninline void check_meta(\n    metadata_collection_view meta,\n    const std::vector<std::pair<column_type, string_view>>& expected\n)\n{\n    BOOST_TEST_REQUIRE(meta.size() == expected.size());\n    for (std::size_t i = 0; i < meta.size(); ++i)\n    {\n        BOOST_TEST(meta[i].type() == expected[i].first);\n        BOOST_TEST(meta[i].type() == expected[i].first);\n    }\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/ci_server.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CI_SERVER_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CI_SERVER_HPP\n\n#include <boost/config.hpp>\n\n#include <cstdlib>\n#include <string>\n\n// Constant and utilities to interact with the CI database server\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline std::string safe_getenv(const char* name, const char* default_value)\n{\n    // MSVC doesn't like getenv\n#ifdef BOOST_MSVC\n#pragma warning(push)\n#pragma warning(disable : 4996)\n#endif\n    const char* res = std::getenv(name);\n#ifdef BOOST_MSVC\n#pragma warning(pop)\n#endif\n    return res ? res : default_value;\n}\n\n// Interface\ninline std::string get_hostname() { return safe_getenv(\"BOOST_MYSQL_SERVER_HOST\", \"127.0.0.1\"); }\nconstexpr const char* integ_user = \"integ_user\";\nconstexpr const char* integ_passwd = \"integ_password\";\nconstexpr const char* integ_db = \"boost_mysql_integtests\";\nconstexpr const char* default_unix_path = \"/var/run/mysqld/mysqld.sock\";\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/create_basic.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CREATE_BASIC_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CREATE_BASIC_HPP\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ntemplate <class... Types>\nBOOST_CXX14_CONSTEXPR std::array<field_view, sizeof...(Types)> make_fv_arr(Types&&... args)\n{\n    return std::array<field_view, sizeof...(Types)>{{field_view(std::forward<Types>(args))...}};\n}\n\ntemplate <class... Types>\nstd::vector<field_view> make_fv_vector(Types&&... args)\n{\n    return std::vector<field_view>{field_view(std::forward<Types>(args))...};\n}\n\ninline row_view makerowv(const field_view* f, std::size_t size) noexcept\n{\n    return detail::access::construct<row_view>(f, size);\n}\n\ntemplate <class... Types>\nrow makerow(Types&&... args)\n{\n    auto fields = make_fv_arr(std::forward<Types>(args)...);\n    return row(makerowv(fields.data(), fields.size()));\n}\n\ninline rows_view makerowsv(const field_view* fields, std::size_t num_fields, std::size_t num_columns) noexcept\n{\n    return detail::access::construct<rows_view>(fields, num_fields, num_columns);\n}\n\ntemplate <class... Types>\nrows makerows(std::size_t num_columns, Types&&... args)\n{\n    auto fields = make_fv_arr(std::forward<Types>(args)...);\n    return rows(makerowsv(fields.data(), fields.size(), num_columns));\n}\n\nconstexpr time maket(int hours, int mins, int secs, int micros = 0)\n{\n    return std::chrono::hours(hours) + std::chrono::minutes(mins) + std::chrono::seconds(secs) +\n           std::chrono::microseconds(micros);\n}\n\ntemplate <std::size_t N>\nconstexpr string_view makesv(const char (&value)[N])\n{\n    static_assert(N >= 1, \"Expected a C-array literal\");\n    return string_view(value, N - 1);  // discard null terminator\n}\n\ntemplate <std::size_t N>\ninline string_view makesv(const std::uint8_t (&value)[N])\n{\n    return string_view(reinterpret_cast<const char*>(value), N);\n}\n\ninline string_view makesv(const std::uint8_t* value, std::size_t size)\n{\n    return string_view(reinterpret_cast<const char*>(value), size);\n}\n\ntemplate <std::size_t N>\nblob_view makebv(const char (&value)[N])\n{\n    static_assert(N >= 1, \"Expected a C-array literal\");\n    return blob_view(reinterpret_cast<const unsigned char*>(value),\n                     N - 1);  // discard null terminator\n}\n\ntemplate <std::size_t N>\nblob makeb(const char (&value)[N])\n{\n    auto bv = makebv(value);\n    return blob(bv.begin(), bv.end());\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* TEST_TEST_COMMON_HPP_ */\n"
  },
  {
    "path": "test/common/include/test_common/create_diagnostics.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CREATE_DIAGNOSTICS_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_CREATE_DIAGNOSTICS_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline diagnostics create_server_diag(string_view s)\n{\n    diagnostics res;\n    detail::access::get_impl(res).assign_server(s);\n    return res;\n}\n\ninline diagnostics create_client_diag(string_view s)\n{\n    diagnostics res;\n    detail::access::get_impl(res).assign_client(s);\n    return res;\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/has_ranges.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_HAS_RANGES_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_HAS_RANGES_HPP\n\n#include <boost/config.hpp>\n\n// libstdc++11 and below claim to support ranges, but basic piping fails to compile\n#ifdef __cpp_lib_ranges\n#if !defined(BOOST_LIBSTDCXX_VERSION) || BOOST_LIBSTDCXX_VERSION >= 120000\n#define BOOST_MYSQL_HAS_RANGES\n#endif\n#endif\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/io_context_fixture.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_IO_CONTEXT_FIXTURE_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_IO_CONTEXT_FIXTURE_HPP\n\n#include <boost/asio/io_context.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct io_context_fixture\n{\n    asio::io_context ctx;\n\n    // Checks that we effectively run out of work\n    ~io_context_fixture();\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/netfun_maker.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_NETFUN_MAKER_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_NETFUN_MAKER_HPP\n\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n\n#include <boost/system/system_error.hpp>\n\n#include <type_traits>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/network_result.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ntemplate <class Fn, class... Args>\nauto invoke_polyfill(Fn fn, Args&&... args) ->\n    typename std::enable_if<\n        std::is_function<typename std::remove_pointer<Fn>::type>::value,\n        decltype(fn(std::forward<Args>(args)...))>::type\n{\n    return fn(std::forward<Args>(args)...);\n}\n\ntemplate <class Pmem, class Obj, class... Args>\nauto invoke_polyfill(Pmem fn, Obj& obj, Args&&... args) ->\n    typename std::enable_if<\n        std::is_member_function_pointer<Pmem>::value,\n        decltype((obj.*fn)(std::forward<Args>(args)...))>::type\n{\n    return (obj.*fn)(std::forward<Args>(args)...);\n}\n\ntemplate <class T, class... InvokeArgs>\nvoid invoke_and_assign(network_result<T>& output, InvokeArgs&&... args)\n{\n    output.value = invoke_polyfill(std::forward<InvokeArgs>(args)...);\n}\n\ntemplate <class... InvokeArgs>\nvoid invoke_and_assign(network_result<void>&, InvokeArgs&&... args)\n{\n    invoke_polyfill(std::forward<InvokeArgs>(args)...);\n}\n\ntemplate <class R, class IOObject, class... Args>\nstruct netfun_maker_impl\n{\n    using signature = std::function<network_result<R>(IOObject&, Args...)>;\n\n    template <class Pfn>\n    static signature sync_errc(Pfn fn)\n    {\n        return [fn](IOObject& obj, Args... args) {\n            network_result<R> res{\n                common_server_errc::er_no,\n                create_server_diag(\"diagnostics not cleared properly\")\n            };\n            invoke_and_assign(res, fn, obj, std::forward<Args>(args)..., res.err, res.diag);\n            return res;\n        };\n    }\n\n    template <class Pfn>\n    static signature sync_errc_nodiag(Pfn fn)\n    {\n        return [fn](IOObject& obj, Args... args) {\n            network_result<R> res{common_server_errc::er_no, create_server_diag(\"<diagnostics unavailable>\")};\n            invoke_and_assign(res, fn, obj, std::forward<Args>(args)..., res.err);\n            return res;\n        };\n    }\n\n    template <class Pfn>\n    static signature sync_exc(Pfn fn)\n    {\n        return [fn](IOObject& obj, Args... args) {\n            network_result<R> res;\n            try\n            {\n                invoke_and_assign(res, fn, obj, std::forward<Args>(args)...);\n            }\n            catch (const boost::mysql::error_with_diagnostics& err)\n            {\n                res.err = err.code();\n                res.diag = err.get_diagnostics();\n            }\n            catch (const boost::system::system_error& err)\n            {\n                res.err = err.code();\n            }\n            return res;\n        };\n    }\n\n    template <class Pfn>\n    static signature async_diag(Pfn fn)\n    {\n        return [fn](IOObject& obj, Args... args) {\n            diagnostics diag;  // checks for clearing diag are performed by as_netresult\n            return invoke_polyfill(fn, obj, std::forward<Args>(args)..., diag, as_netresult).run();\n        };\n    }\n\n    template <class Pfn>\n    static signature async_nodiag(Pfn fn)\n    {\n        return [fn](IOObject& obj, Args... args) {\n            return invoke_polyfill(fn, obj, std::forward<Args>(args)..., as_netresult).run();\n        };\n    }\n};\n\ntemplate <class R, class Obj, class... Args>\nclass netfun_maker\n{\n    using impl = netfun_maker_impl<R, Obj&, Args...>;\n\npublic:\n    using signature = std::function<network_result<R>(Obj&, Args...)>;\n    using sig_sync_errc = R (Obj::*)(Args..., error_code&, diagnostics&);\n    using sig_sync_errc_nodiag = R (Obj::*)(Args..., error_code&);\n    using sig_sync_errc_nodiag_old =\n        error_code (Obj::*)(Args..., error_code&);  // support old Asio signatures\n    using sig_sync_exc = R (Obj::*)(Args...);\n    using sig_async_diag = runnable_network_result<R> (Obj::*)(Args..., diagnostics&, const as_netresult_t&);\n    using sig_async_nodiag = runnable_network_result<R> (Obj::*)(Args..., const as_netresult_t&);\n\n    static signature sync_errc(sig_sync_errc pfn) { return impl::sync_errc(pfn); }\n    static signature sync_errc_nodiag(sig_sync_errc_nodiag pfn) { return impl::sync_errc_nodiag(pfn); }\n    static signature sync_errc_nodiag(sig_sync_errc_nodiag_old pfn) { return impl::sync_errc_nodiag(pfn); }\n    static signature sync_exc(sig_sync_exc pfn) { return impl::sync_exc(pfn); }\n    static signature async_diag(sig_async_diag pfn) { return impl::async_diag(pfn); }\n    static signature async_nodiag(sig_async_nodiag pfn) { return impl::async_nodiag(pfn); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/network_result.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_NETWORK_RESULT_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_NETWORK_RESULT_HPP\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/associated_cancellation_slot.hpp>\n#include <boost/asio/associated_executor.hpp>\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/core/span.hpp>\n#include <boost/mp11/algorithm.hpp>\n#include <boost/mp11/integral.hpp>\n#include <boost/mp11/list.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <memory>\n#include <string>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/source_location.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct no_result\n{\n};\n\n// network_result: system::result-like type with helper functions\n// for tests\nstruct BOOST_ATTRIBUTE_NODISCARD network_result_base\n{\n    error_code err;\n    diagnostics diag;\n    bool was_immediate{};\n\n    network_result_base(error_code ec = {}, diagnostics d = {}) noexcept : err(ec), diag(std::move(d)) {}\n\n    void validate_immediate(bool expect_immediate, source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const;\n\n    void validate_no_error(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const;\n\n    // Use for functions without a diagnostics& parameter\n    void validate_no_error_nodiag(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const;\n\n    void validate_error(\n        error_code expected_err,\n        const diagnostics& expected_diag = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    ) const;\n\n    void validate_error(\n        common_server_errc expected_err,\n        string_view expected_msg = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    );\n\n    void validate_error(\n        client_errc expected_err,\n        string_view expected_msg = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    );\n\n    // Use when the exact message isn't known, but some of its contents are\n    void validate_error_contains(\n        error_code expected_err,\n        const std::vector<std::string>& pieces,\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    );\n\n    // Use when you don't care or can't determine the kind of error\n    void validate_any_error(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const;\n};\n\ntemplate <class R>\nstruct BOOST_ATTRIBUTE_NODISCARD network_result : network_result_base\n{\n    using value_type = typename std::conditional<std::is_same<R, void>::value, no_result, R>::type;\n    value_type value;\n\n    network_result() = default;\n    network_result(error_code ec, diagnostics diag, value_type value = {})\n        : network_result_base{ec, std::move(diag)}, value(std::move(value))\n    {\n    }\n\n    // Allow chaining\n    network_result<R>& validate_immediate(\n        bool expect_immediate,\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    )\n    {\n        network_result_base::validate_immediate(expect_immediate, loc);\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    value_type get(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        validate_no_error(loc);\n        return std::move(value);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    value_type get_nodiag(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        validate_no_error_nodiag(loc);\n        return std::move(value);\n    }\n};\n\n// Wraps a network_result and an executor. The result of as_netresult_t.\ntemplate <class R>\nstruct BOOST_ATTRIBUTE_NODISCARD runnable_network_result\n{\n    struct impl_t\n    {\n        asio::io_context& ctx;\n        network_result<R> netres{\n            common_server_errc::er_no,\n            create_server_diag(\"network_result_v2 - diagnostics not cleared\")\n        };\n        bool done{false};\n        bool was_immediate{false};\n\n        impl_t(asio::io_context& ctx) : ctx(ctx) {}\n    };\n\n    std::unique_ptr<impl_t> impl;\n\n    runnable_network_result(asio::io_context& ctx) : impl(new impl_t(ctx)) {}\n\n    asio::io_context& context() { return impl->ctx; }\n\n    network_result<R> run(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        poll_until(context(), &impl->done, loc);\n        return std::move(impl->netres);\n    }\n\n    void validate_no_error(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        std::move(*this).run(loc).validate_no_error(loc);\n    }\n\n    void validate_no_error_nodiag(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        std::move(*this).run(loc).validate_no_error_nodiag(loc);\n    }\n\n    void validate_error(\n        error_code expected_err,\n        const diagnostics& expected_diag = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    ) &&\n    {\n        std::move(*this).run(loc).validate_error(expected_err, expected_diag, loc);\n    }\n\n    void validate_error(\n        common_server_errc expected_err,\n        string_view expected_msg = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    ) &&\n    {\n        std::move(*this).run(loc).validate_error(expected_err, expected_msg, loc);\n    }\n\n    void validate_error(\n        client_errc expected_err,\n        string_view expected_msg = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    ) &&\n    {\n        std::move(*this).run(loc).validate_error(expected_err, expected_msg, loc);\n    }\n\n    // Use when the exact message isn't known, but some of its contents are\n    void validate_error_contains(\n        error_code expected_err,\n        const std::vector<std::string>& pieces,\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    ) &&\n    {\n        std::move(*this).run(loc).validate_error_contains(expected_err, pieces, loc);\n    }\n\n    // Use when you don't care or can't determine the kind of error\n    void validate_any_error(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        std::move(*this).run(loc).validate_any_error(loc);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    typename network_result<R>::value_type get(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        return std::move(*this).run(loc).get(loc);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    typename network_result<R>::value_type get_nodiag(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) &&\n    {\n        return std::move(*this).run(loc).get_nodiag(loc);\n    }\n};\n\nstruct as_netresult_t\n{\n};\n\nconstexpr as_netresult_t as_netresult{};\n\nnamespace test_detail {\n\ntemplate <class Signature>\nstruct as_netres_sig_to_rtype;\n\ntemplate <>\nstruct as_netres_sig_to_rtype<void(error_code)>\n{\n    using type = void;\n};\n\ntemplate <class T>\nstruct as_netres_sig_to_rtype<void(error_code, T)>\n{\n    using type = T;\n};\n\nclass as_netres_handler_base\n{\n    tracker_executor_result ex_;\n    tracker_executor_result immediate_ex_;\n    asio::cancellation_slot slot_;\n    const diagnostics* diag_ptr;\n\nprotected:\n    as_netres_handler_base(\n        asio::io_context& ctx,\n        asio::cancellation_slot slot,\n        const diagnostics* output_diag\n    );\n    void complete_base(error_code ec, network_result_base& netres) const;\n\npublic:\n    // Executor\n    using executor_type = asio::any_io_executor;\n    asio::any_io_executor get_executor() const { return ex_.ex; }\n\n    // Immediate executor\n    using immediate_executor_type = asio::any_io_executor;\n    asio::any_io_executor get_immediate_executor() const { return immediate_ex_.ex; }\n\n    // Cancellation slot\n    using cancellation_slot_type = asio::cancellation_slot;\n    asio::cancellation_slot get_cancellation_slot() const noexcept { return slot_; }\n};\n\ntemplate <class R>\nclass as_netres_handler : public as_netres_handler_base\n{\n    typename runnable_network_result<R>::impl_t* target_;\n\n    void complete(error_code ec) const\n    {\n        this->complete_base(ec, target_->netres);\n        target_->done = true;\n    }\n\npublic:\n    as_netres_handler(\n        runnable_network_result<R>& netresult,\n        const diagnostics* output_diag,\n        asio::cancellation_slot slot\n    )\n        : as_netres_handler_base(netresult.context(), slot, output_diag), target_(netresult.impl.get())\n    {\n    }\n\n    void operator()(error_code ec) const { complete(ec); }\n\n    template <class Arg>\n    void operator()(error_code ec, Arg&& arg) const\n    {\n        target_->netres.value = std::forward<Arg>(arg);\n        complete(ec);\n    }\n};\n\n}  // namespace test_detail\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\nnamespace boost {\nnamespace asio {\n\ntemplate <typename Signature>\nclass async_result<mysql::test::as_netresult_t, Signature>\n{\npublic:\n    using R = typename mysql::test::test_detail::as_netres_sig_to_rtype<Signature>::type;\n    using return_type = mysql::test::runnable_network_result<R>;\n\n    template <typename Initiation, typename... Args>\n    static return_type initiate(Initiation&& initiation, mysql::test::as_netresult_t token, Args&&... args)\n    {\n        // Try to find a diagnostics* within the argument list\n        using diag_pos = mp11::mp_find<mp11::mp_list<Args...>, mysql::diagnostics*>;\n        constexpr bool diag_found = diag_pos::value < sizeof...(Args);\n\n        // Dispatch\n        return do_initiate(\n            std::integral_constant<bool, diag_found>{},\n            diag_pos{},\n            std::forward<Initiation>(initiation),\n            token,\n            std::forward<Args>(args)...\n        );\n    }\n\n    // Common case optimization: diagnostics* is first\n    template <typename Initiation, typename... Args>\n    static return_type initiate(\n        Initiation&& initiation,\n        mysql::test::as_netresult_t token,\n        mysql::diagnostics* diag,\n        Args&&... args\n    )\n    {\n        return do_initiate_impl(\n            std::forward<Initiation>(initiation),\n            token,\n            diag,\n            diag,\n            std::forward<Args>(args)...\n        );\n    }\n\nprivate:\n    // A diagnostics* was found\n    template <std::size_t N, typename Initiation, typename... Args>\n    static return_type do_initiate(\n        std::true_type /* diag_found */,\n        mp11::mp_size_t<N> /* diag_pos */,\n        Initiation&& initiation,\n        mysql::test::as_netresult_t token,\n        Args&&... args\n    )\n    {\n        return do_initiate_impl(\n            std::forward<Initiation>(initiation),\n            token,\n            std::get<N>(std::tuple<Args&...>{args...}),\n            std::forward<Args>(args)...\n        );\n    }\n\n    // A diagnostics* was not found\n    template <std::size_t N, typename Initiation, typename... Args>\n    static return_type do_initiate(\n        std::false_type /* diag_found */,\n        mp11::mp_size_t<N> /* diag_pos */,\n        Initiation&& initiation,\n        mysql::test::as_netresult_t token,\n        Args&&... args\n    )\n    {\n        return do_initiate_impl(\n            std::forward<Initiation>(initiation),\n            token,\n            nullptr,\n            std::forward<Args>(args)...\n        );\n    }\n\n    template <typename Initiation, typename... Args>\n    static return_type do_initiate_impl(\n        Initiation&& initiation,\n        mysql::test::as_netresult_t token,\n        mysql::diagnostics* diag,\n        Args&&... args\n    )\n    {\n        // Retrieve the context associated to this operation.\n        // All our initiations have bound executors, to be compliant with asio::cancel_after\n        auto& ctx = static_cast<asio::io_context&>(asio::get_associated_executor(initiation).context());\n\n        // Verify that we correctly set diagnostics in all cases\n        if (diag)\n            *diag = mysql::test::create_server_diag(\"Diagnostics not cleared properly\");\n\n        // Create the return type\n        mysql::test::runnable_network_result<R> netres(ctx);\n\n        // Record that we're initiating\n        mysql::test::initiation_guard guard;\n\n        // Actually call the initiation function\n        std::forward<Initiation>(initiation)(\n            mysql::test::test_detail::as_netres_handler<R>(\n                netres,\n                diag,\n                asio::get_associated_cancellation_slot(token)\n            ),\n            std::forward<Args>(args)...\n        );\n\n        return netres;\n    }\n};\n\n}  // namespace asio\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/poll_until.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_POLL_UNTIL_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_POLL_UNTIL_HPP\n\n#include <boost/asio/io_context.hpp>\n\n#include <functional>\n\n#include \"test_common/source_location.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// poll until *done == true\nvoid poll_until(asio::io_context& ctx, const bool* done, source_location loc = BOOST_MYSQL_CURRENT_LOCATION);\n\n// poll until done() == true\nvoid poll_until(\n    asio::io_context& ctx,\n    const std::function<bool()>& done,\n    source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n);\n\n// run fn() in ctx, then poll until it completes\nvoid run_in_context(\n    asio::io_context& ctx,\n    const std::function<void()>& fn,\n    source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n);\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/printing.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_PRINTING_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_PRINTING_HPP\n\n#include <iosfwd>\n\nnamespace boost {\nnamespace mysql {\n\nenum class client_errc;\nstd::ostream& operator<<(std::ostream& os, client_errc v);\n\nenum class common_server_errc;\nstd::ostream& operator<<(std::ostream& os, common_server_errc v);\n\nclass diagnostics;\nstd::ostream& operator<<(std::ostream& os, const diagnostics& v);\n\nclass row_view;\nstd::ostream& operator<<(std::ostream& os, const row_view& v);\n\nclass row;\nstd::ostream& operator<<(std::ostream& os, const row& v);\n\nenum class metadata_mode;\nstd::ostream& operator<<(std::ostream& os, metadata_mode v);\n\nenum class ssl_mode;\nstd::ostream& operator<<(std::ostream& os, ssl_mode v);\n\nstruct character_set;\nbool operator==(const character_set& lhs, const character_set& rhs);\nstd::ostream& operator<<(std::ostream& os, const character_set& v);\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/source_location.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_SOURCE_LOCATION_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_SOURCE_LOCATION_HPP\n\n#include <boost/assert/source_location.hpp>\n\n// boost::source_location triggers a bug on gcc < 8 when using PCHs\n// BOOST_CURRENT_LOCATION complains about a redefinition of __PRETTY_FUNCTION__\n// when used as default argument\n#if defined(BOOST_GCC) && BOOST_GCC < 80000\n#define BOOST_MYSQL_CURRENT_LOCATION ::boost::source_location(__FILE__, __LINE__, \"\")\n#else\n#define BOOST_MYSQL_CURRENT_LOCATION BOOST_CURRENT_LOCATION\n#endif\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/stringize.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_STRINGIZE_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_STRINGIZE_HPP\n\n#include <sstream>\n#include <string>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline void stringize_helper(std::ostream&) noexcept {}\n\ntemplate <class T, class... Types>\nvoid stringize_helper(std::ostream& os, const T& input, const Types&... tail)\n{\n    os << input;\n    stringize_helper(os, tail...);\n}\n\ntemplate <class... Types>\nstd::string stringize(const Types&... inputs)\n{\n    std::ostringstream ss;\n    stringize_helper(ss, inputs...);\n    return ss.str();\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/tracker_executor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_TRACKER_EXECUTOR_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_TRACKER_EXECUTOR_HPP\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/core/span.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// A tracker executor wraps an any_io_executor and tracks execute calls.\n// Every executor has a distinct ID. When an executor starts executing\n// a function, its ID is pushed to a thread-local call stack, and popped\n// when the function returns.\n// This allows us to reliable check whether \"we're running in the context of executor X\"\nstruct tracker_executor_result\n{\n    int executor_id;\n    asio::any_io_executor ex;\n};\n\n// Create\ntracker_executor_result create_tracker_executor(asio::any_io_executor inner);\n\n// Get the executor call stack, as a span of IDs. Most recent call last.\nboost::span<const int> executor_stack();\n\n// Get the ID of a tracker executor, or -1 if it's not a tracker executor\nint get_executor_id(asio::any_io_executor);\n\n// We maintain a thread-local state variable that tracks whether we're running\n// in the context of an initiation function or not.\n// Use this guard when invoking initiation functions to set/clear the flag,\n// and the function below to check it.\nstruct initiation_guard\n{\n    initiation_guard();\n    initiation_guard(const initiation_guard&) = delete;\n    initiation_guard(initiation_guard&&) = delete;\n    initiation_guard& operator=(const initiation_guard&) = delete;\n    initiation_guard& operator=(initiation_guard&&) = delete;\n    ~initiation_guard();\n};\nbool is_initiation_function();\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/include/test_common/validate_string_contains.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_VALIDATE_STRING_CONTAINS_HPP\n#define BOOST_MYSQL_TEST_COMMON_INCLUDE_TEST_COMMON_VALIDATE_STRING_CONTAINS_HPP\n\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <string>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline void validate_string_contains(std::string value, const std::vector<std::string>& to_check)\n{\n    std::transform(value.begin(), value.end(), value.begin(), [](char c) {\n        return static_cast<char>(tolower(c));\n    });\n    for (const auto& elm : to_check)\n    {\n        BOOST_TEST(\n            value.find(elm) != std::string::npos,\n            \"Substring '\" << elm << \"' not found in '\" << value << \"'\"\n        );\n    }\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/common/src/boost_asio.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/impl/src.hpp>\n#include <boost/asio/ssl/impl/src.hpp>\n"
  },
  {
    "path": "test/common/src/boost_mysql.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/src.hpp>\n"
  },
  {
    "path": "test/common/src/entry_point.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/test/unit_test.hpp>\n\n#ifdef BOOST_TEST_ALTERNATIVE_INIT_API\nint main(int argc, char* argv[])\n{\n    return ::boost::unit_test::unit_test_main([] { return true; }, argc, argv);\n}\n#else\n::boost::unit_test::test_suite* init_unit_test_suite(int, char*[]) { return nullptr; }\n#endif\n"
  },
  {
    "path": "test/common/src/utils.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/execution/blocking.hpp>\n#include <boost/asio/execution/relationship.hpp>\n#include <boost/asio/execution_context.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/require.hpp>\n#include <boost/assert/source_location.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <atomic>\n#include <chrono>\n#include <cstring>\n#include <functional>\n#include <iomanip>\n#include <ostream>\n#include <thread>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n#include \"test_common/validate_string_contains.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\n//\n// assert_buffer_equals.hpp\n//\nstd::ostream& boost::mysql::test::operator<<(std::ostream& os, buffer_printer buff)\n{\n    os << std::setfill('0') << std::hex << \"{ \";\n    for (std::size_t i = 0; i < buff.buff.size(); ++i)\n    {\n        os << \"0x\" << std::setw(2) << static_cast<int>(buff.buff.data()[i]) << \", \";\n    }\n    return os << \"}\";\n}\n\nbool boost::mysql::test::buffer_equals(span<const std::uint8_t> b1, span<const std::uint8_t> b2)\n{\n    // If any of the buffers are empty (data() == nullptr), prevent\n    // calling memcmp (UB)\n    if (b1.size() == 0 || b2.size() == 0)\n        return b1.size() == 0 && b2.size() == 0;\n\n    if (b1.size() != b2.size())\n        return false;\n\n    return ::std::memcmp(b1.data(), b2.data(), b1.size()) == 0;\n}\n\n//\n// printing.hpp\n//\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, client_errc v) { return os << error_code(v); }\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, common_server_errc v) { return os << error_code(v); }\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const diagnostics& diag)\n{\n    const auto& impl = detail::access::get_impl(diag);\n    return os << \"diagnostics{ \" << (impl.is_server ? \".server_message\" : \".client_message\") << \" = \\\"\"\n              << impl.msg << \"\\\" }\";\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const row_view& value)\n{\n    os << '{';\n    if (!value.empty())\n    {\n        os << value[0];\n        for (auto it = std::next(value.begin()); it != value.end(); ++it)\n        {\n            os << \", \" << *it;\n        }\n    }\n    return os << '}';\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const row& r) { return os << row_view(r); }\n\nstatic const char* to_string(metadata_mode v)\n{\n    switch (v)\n    {\n    case metadata_mode::full: return \"metadata_mode::full\";\n    case metadata_mode::minimal: return \"metadata_mode::minimal\";\n    default: return \"<unknown metadata_mode>\";\n    }\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, metadata_mode v) { return os << ::to_string(v); }\n\nstatic const char* to_string(ssl_mode v)\n{\n    switch (v)\n    {\n    case ssl_mode::disable: return \"ssl_mode::disable\";\n    case ssl_mode::enable: return \"ssl_mode::enable\";\n    case ssl_mode::require: return \"ssl_mode::require\";\n    default: return \"<unknown ssl_mode>\";\n    }\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, ssl_mode v) { return os << ::to_string(v); }\n\n// character set\nbool boost::mysql::operator==(const character_set& lhs, const character_set& rhs)\n{\n    if (lhs.name == nullptr || rhs.name == nullptr)\n        return lhs.name == rhs.name;\n    return std::strcmp(lhs.name, rhs.name) == 0 && lhs.next_char == rhs.next_char;\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, const character_set& v)\n{\n    if (v.name == nullptr)\n        return os << \"character_set()\";\n    else\n        return os << \"character_set(\\\"\" << v.name << \"\\\", .next_char? = \" << static_cast<bool>(v.next_char)\n                  << \")\";\n}\n\n//\n// tracker_executor.hpp\n//\n\nnamespace {\n\n// Are we in the call stack of an initiating function?\nthread_local bool g_is_running_initiation = false;\n\n// Produce unique executor IDs (start in 1)\nstd::atomic_int next_executor_id{1};\n\n// The executor call stack\nthread_local std::vector<int> g_executor_call_stack;\n\n// Guard to remove an entry from the stack\nstruct executor_call_stack_guard\n{\n    executor_call_stack_guard(int executor_id) { g_executor_call_stack.push_back(executor_id); }\n    executor_call_stack_guard(const executor_call_stack_guard&) = delete;\n    executor_call_stack_guard(executor_call_stack_guard&&) = delete;\n    executor_call_stack_guard& operator=(const executor_call_stack_guard&) = delete;\n    executor_call_stack_guard& operator=(executor_call_stack_guard&&) = delete;\n    ~executor_call_stack_guard() { g_executor_call_stack.pop_back(); }\n};\n\n// Wraps a function object to insert tracking of the caller executor\ntemplate <class Function>\nstruct tracker_executor_function\n{\n    int executor_id;\n    Function fn;\n\n    void operator()()\n    {\n        executor_call_stack_guard guard(executor_id);\n        std::move(fn)();\n    }\n};\n\ntemplate <class Function>\ntracker_executor_function<typename std::decay<Function>::type> create_tracker_executor_function(\n    int executor_id,\n    Function&& fn\n)\n{\n    return {executor_id, std::forward<Function>(fn)};\n}\n\n}  // namespace\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass tracker_executor\n{\npublic:\n    tracker_executor(int id, boost::asio::any_io_executor ex) noexcept : id_(id), ex_(std::move(ex)) {}\n\n    bool operator==(const tracker_executor& rhs) const noexcept { return id_ == rhs.id_ && ex_ == rhs.ex_; }\n    bool operator!=(const tracker_executor& rhs) const noexcept { return !(*this == rhs); }\n    int id() const { return id_; }\n\n#ifdef BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT\n\n    // TS-executor interface\n    asio::execution_context& context() const noexcept { return ex_.context(); }\n    void on_work_started() const noexcept { ex_.on_work_started(); }\n    void on_work_finished() const noexcept { ex_.on_work_finished(); }\n\n    template <typename Function, typename Allocator>\n    void dispatch(Function&& f, const Allocator& a) const\n    {\n        ex_.dispatch(create_tracker_executor_function(id_, std::forward<Function>(f)), a);\n    }\n\n    template <typename Function, typename Allocator>\n    void post(Function&& f, const Allocator& a) const\n    {\n        ex_.post(create_tracker_executor_function(id_, std::forward<Function>(f)), a);\n    }\n\n    template <typename Function, typename Allocator>\n    void defer(Function&& f, const Allocator& a) const\n    {\n        ex_.defer(create_tracker_executor_function(id_, std::forward<Function>(f)), a);\n    }\n\n#else\n\n    // Standard executors interface\n    template <class Property>\n    tracker_executor require(\n        const Property& p,\n        typename std::enable_if<asio::can_require<asio::any_io_executor, Property>::value>::type* = nullptr\n    ) const\n    {\n        return tracker_executor(id_, asio::require(ex_, p));\n    }\n\n    template <class Property>\n    tracker_executor prefer(\n        const Property& p,\n        typename std::enable_if<asio::can_prefer<asio::any_io_executor, Property>::value>::type* = nullptr\n    ) const\n    {\n        return tracker_executor(id_, asio::prefer(ex_, p));\n    }\n\n    template <class Property>\n    auto query(\n        const Property& p,\n        typename std::enable_if<asio::can_query<asio::any_io_executor, Property>::value>::type* = nullptr\n    ) const -> decltype(asio::query(std::declval<boost::asio::any_io_executor>(), p))\n    {\n        return boost::asio::query(ex_, p);\n    }\n\n    template <typename Function>\n    void execute(Function&& f) const\n    {\n        ex_.execute(create_tracker_executor_function(id_, std::forward<Function>(f)));\n    }\n#endif\n\nprivate:\n    int id_;\n    boost::asio::any_io_executor ex_;\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n// Asio fails to detect that a type is equaility comparable under MSVC, so we need to do this\nnamespace boost {\nnamespace asio {\nnamespace traits {\n\ntemplate <>\nstruct equality_comparable<tracker_executor>\n{\n    static constexpr bool is_valid = true;\n    static constexpr bool is_noexcept = true;\n};\n\ntemplate <typename Function>\nstruct execute_member<tracker_executor, Function>\n{\n    static constexpr bool is_valid = true;\n    static constexpr bool is_noexcept = false;\n    using result_type = void;\n};\n\ntemplate <class Property>\nstruct require_member<\n    tracker_executor,\n    Property,\n    typename std::enable_if<asio::can_require<asio::any_io_executor, Property>::value>::type>\n{\n    static constexpr bool is_valid = true;\n    static constexpr bool is_noexcept = false;\n    using result_type = tracker_executor;\n};\n\ntemplate <typename Property>\nstruct prefer_member<\n    tracker_executor,\n    Property,\n    typename std::enable_if<asio::can_prefer<asio::any_io_executor, Property>::value>::type>\n{\n    static constexpr bool is_valid = true;\n    static constexpr bool is_noexcept = false;\n    using result_type = tracker_executor;\n};\n\ntemplate <typename Property>\nstruct query_member<\n    tracker_executor,\n    Property,\n    typename std::enable_if<asio::can_query<asio::any_io_executor, Property>::value>::type>\n{\n    static constexpr bool is_valid = true;\n    static constexpr bool is_noexcept = false;\n    using result_type = decltype(boost::asio::query(\n        std::declval<const any_io_executor&>(),\n        std::declval<const Property&>()\n    ));\n};\n\n}  // namespace traits\n}  // namespace asio\n}  // namespace boost\n\nboost::mysql::test::tracker_executor_result boost::mysql::test::create_tracker_executor(\n    asio::any_io_executor inner\n)\n{\n    int id = ++next_executor_id;\n    return {id, tracker_executor(id, std::move(inner))};\n}\n\nboost::span<const int> boost::mysql::test::executor_stack() { return g_executor_call_stack; }\n\nint boost::mysql::test::get_executor_id(asio::any_io_executor ex)\n{\n    auto* typed_ex = ex.target<tracker_executor>();\n    return typed_ex ? typed_ex->id() : -1;\n}\nboost::mysql::test::initiation_guard::initiation_guard()\n{\n    BOOST_ASSERT(!g_is_running_initiation);\n    g_is_running_initiation = true;\n}\n\nboost::mysql::test::initiation_guard::~initiation_guard()\n{\n    BOOST_ASSERT(g_is_running_initiation);\n    g_is_running_initiation = false;\n}\n\nbool boost::mysql::test::is_initiation_function() { return g_is_running_initiation; }\n\n//\n// poll_until.hpp\n//\n\nvoid boost::mysql::test::poll_until(asio::io_context& ctx, const bool* done, source_location loc)\n{\n    poll_until(ctx, [done]() { return *done; }, loc);\n}\n\nvoid boost::mysql::test::poll_until(\n    asio::io_context& ctx,\n    const std::function<bool()>& done,\n    source_location loc\n)\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc)\n    {\n        using std::chrono::steady_clock;\n\n        // Restart the context, in case it was stopped\n        ctx.restart();\n\n        // Poll until this time point\n        constexpr std::chrono::seconds timeout(15);\n        auto timeout_tp = steady_clock::now() + timeout;\n\n        // Perform the polling\n        while (!done() && steady_clock::now() < timeout_tp)\n        {\n            ctx.poll();\n            std::this_thread::yield();\n        }\n\n        // Check for timeout\n        BOOST_TEST_REQUIRE(done());\n    }\n}\n\nvoid boost::mysql::test::run_in_context(\n    asio::io_context& ctx,\n    const std::function<void()>& fn,\n    source_location loc\n)\n{\n    bool finished = false;\n    asio::dispatch(asio::bind_executor(ctx.get_executor(), [fn, &finished]() {\n        fn();\n        finished = true;\n    }));\n    poll_until(ctx, &finished, loc);\n}\n\n//\n// io_context_fixture.hpp\n//\nboost::mysql::test::io_context_fixture::~io_context_fixture()\n{\n    // Verify that our tests don't leave unfinished work\n    ctx.poll();\n    BOOST_TEST(ctx.stopped());\n}\n\n//\n// network_result.hpp\n//\n\nvoid boost::mysql::test::network_result_base::validate_immediate(bool expect_immediate, source_location loc)\n    const\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc) { BOOST_TEST(was_immediate == expect_immediate); }\n}\n\nvoid boost::mysql::test::network_result_base::validate_no_error(source_location loc) const\n{\n    validate_error(error_code(), diagnostics(), loc);\n}\n\nvoid boost::mysql::test::network_result_base::validate_no_error_nodiag(source_location loc) const\n{\n    validate_error(error_code(), create_server_diag(\"<diagnostics unavailable>\"), loc);\n}\n\nvoid boost::mysql::test::network_result_base::validate_error(\n    error_code expected_err,\n    const diagnostics& expected_diag,\n    source_location loc\n) const\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc)\n    {\n        BOOST_TEST(diag == expected_diag);\n        BOOST_TEST_REQUIRE(err == expected_err);\n    }\n}\n\nvoid boost::mysql::test::network_result_base::validate_error(\n    common_server_errc expected_err,\n    string_view expected_msg,\n    source_location loc\n)\n{\n    validate_error(expected_err, create_server_diag(expected_msg), loc);\n}\n\nvoid boost::mysql::test::network_result_base::validate_error(\n    client_errc expected_err,\n    string_view expected_msg,\n    source_location loc\n)\n{\n    validate_error(expected_err, create_client_diag(expected_msg), loc);\n}\n\nvoid boost::mysql::test::network_result_base::validate_error_contains(\n    error_code expected_err,\n    const std::vector<std::string>& pieces,\n    source_location loc\n)\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc)\n    {\n        validate_string_contains(diag.server_message(), pieces);\n        BOOST_TEST_REQUIRE(err == expected_err);\n    }\n}\n\nvoid boost::mysql::test::network_result_base::validate_any_error(source_location loc) const\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc) { BOOST_TEST_REQUIRE(err != error_code()); }\n}\n\nboost::mysql::test::test_detail::as_netres_handler_base::as_netres_handler_base(\n    asio::io_context& ctx,\n    asio::cancellation_slot slot,\n    const diagnostics* diag\n)\n    : ex_(create_tracker_executor(ctx.get_executor())),\n      immediate_ex_(create_tracker_executor(ctx.get_executor())),\n      slot_(slot),\n      diag_ptr(diag)\n{\n}\n\nvoid boost::mysql::test::test_detail::as_netres_handler_base::complete_base(\n    error_code ec,\n    network_result_base& netres\n) const\n{\n    // Are we in an immediate completion?\n    bool is_immediate = is_initiation_function();\n\n    // Check executor. The passed executor must be the top one in all cases.\n    // Immediate completions must be dispatched through the immediate executor, too.\n    // In all cases, we may encounter a bigger stack because of previous immediate completions.\n    const std::array<int, 1> stack_data_regular{{ex_.executor_id}};\n    const std::array<int, 2> stack_data_immediate{\n        {immediate_ex_.executor_id, ex_.executor_id}\n    };\n\n    // Expected top of the executor stack\n    boost::span<const int> expected_stack_top = is_immediate ? boost::span<const int>(stack_data_immediate)\n                                                             : boost::span<const int>(stack_data_regular);\n\n    // Actual top of the executor stack\n    auto actual_stack_top = executor_stack().last(\n        (std::min)(executor_stack().size(), expected_stack_top.size())\n    );\n\n    // Compare\n    BOOST_TEST(actual_stack_top == expected_stack_top, boost::test_tools::per_element());\n\n    // Assign error code and diagnostics\n    netres.err = ec;\n    if (diag_ptr)\n        netres.diag = *diag_ptr;\n    else\n        netres.diag = create_server_diag(\"<diagnostics unavailable>\");\n\n    // Record immediate-ness\n    netres.was_immediate = is_immediate;\n}"
  },
  {
    "path": "test/fuzzing/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport common ;\nimport regex ;\n\nlocal all_fuzzers = [ regex.replace-list\n    [ glob \"fuzz_*.cpp\" ] : \".cpp\" : \"\"\n] ;\n\n# Fuzzers that should use a longer time period\nlocal long_fuzzers =\n    fuzz_row\n    fuzz_text_field\n    fuzz_utf8mb4\n    fuzz_escape_string\n    fuzz_format_strings\n    fuzz_format_args\n    fuzz_format_sql_injection\n;\n\n\nfor local fuzzer in $(all_fuzzers)\n{\n    local fuzz_time = 10 ;\n    if $(fuzzer) in $(long_fuzzers)\n    {\n        fuzz_time = 30 ;\n    }\n\n    # Create the output corpus directories\n    make /tmp/corpus/$(fuzzer) : : common.MkDir ;\n    make /tmp/mincorpus/$(fuzzer) : : common.MkDir ;\n\n    # Build the fuzzer. Fail the build if openssl is not found\n    exe $(fuzzer)\n        : \n            /boost/mysql/test//boost_mysql\n            /boost/mysql/test//fail_if_no_openssl\n            $(fuzzer).cpp\n        : requirements\n            <include>../common/include\n            <debug-symbols>on\n            <optimization>speed\n            <address-sanitizer>on\n            <undefined-sanitizer>norecover\n            <cxxflags>-fsanitize=fuzzer\n            <linkflags>-fsanitize=fuzzer\n    ;\n\n    # Make sure that any old crashes are run without problems\n    local old_crashes = [ glob-tree-ex old_crashes/$(fuzzer) : * ] ;\n    if $(old_crashes)\n    {\n        run $(fuzzer)\n            : target-name $(fuzzer)-old-crashes\n            : input-files [ SORT $(old_crashes) ]\n        ;\n    }\n\n    # Run the fuzzer for a short while\n    run $(fuzzer)\n        : <testing.arg>\"/tmp/corpus/$(fuzzer) /tmp/seedcorpus/$(fuzzer) -max_total_time=$(fuzz_time)\"\n        : target-name $(fuzzer)-fuzzing\n        : requirements\n            <dependency>/tmp/corpus/$(fuzzer)\n    ;\n\n    # Minimize the corpus\n    run $(fuzzer)\n        : <testing.arg>\"/tmp/mincorpus/$(fuzzer) /tmp/corpus/$(fuzzer) -merge=1\"\n        : target-name $(fuzzer)-minimize-corpus\n        : requirements\n            <dependency>$(fuzzer)-fuzzing\n            <dependency>/tmp/corpus/$(fuzzer)\n            <dependency>/tmp/mincorpus/$(fuzzer)\n    ;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_auth_switch.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_auth_switch(const uint8_t* data, size_t size) noexcept\n{\n    auth_switch msg{};\n    auto ec = deserialize_auth_switch({data, size}, msg);\n    return !ec.failed() && msg.auth_data.empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_auth_switch(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_column_definition.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/coldef_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_column_definition(const uint8_t* data, size_t size) noexcept\n{\n    coldef_view msg{};\n    auto ec = deserialize_column_definition({data, size}, msg);\n    return !ec.failed() && msg.decimals;\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_column_definition(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_err_packet.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_err_packet(const uint8_t* data, size_t size) noexcept\n{\n    err_view msg{};\n    auto ec = deserialize_error_packet({data, size}, msg);\n    return !ec.failed() && msg.error_code;\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_err_packet(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_escape_string.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/escape_string.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <string>\n\nusing namespace boost::mysql;\n\nstatic bool bit_set(uint8_t value, size_t bit) { return value & (0x01 << bit); }\n\nstatic bool call_escape_string(const uint8_t* data, size_t size) noexcept\n{\n    // We need at least 1 byte (for options)\n    if (size < 1u)\n        return false;\n    const uint8_t* end = data + size;\n\n    // Options\n    bool backslash_slashes = bit_set(data[0], 0);\n    auto quot_ctx = bit_set(data[0], 1)\n                        ? (bit_set(data[0], 2) ? quoting_context::double_quote : quoting_context::backtick)\n                        : quoting_context::single_quote;\n    ++data;\n\n    // String to escape\n    string_view input(reinterpret_cast<const char*>(data), reinterpret_cast<const char*>(end));\n\n    // Perform the escaping\n    std::string escaped;\n    error_code ec = escape_string(input, {utf8mb4_charset, backslash_slashes}, quot_ctx, escaped);\n    return ec.failed() || escaped.empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    call_escape_string(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_execute_response.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_execute_response(const uint8_t* data, size_t size) noexcept\n{\n    boost::mysql::diagnostics diag;\n    auto msg = deserialize_execute_response({data, size}, db_flavor::mariadb, diag);\n    return msg.type == execute_response::type_t::error && diag.server_message().empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_execute_response(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_format_args.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/endian/conversion.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <utility>\n\nusing namespace boost::mysql;\n\nnamespace {\n\n// Helper for parsing the input sample from the binary string provided by the fuzzer\n// This follows a \"never fail\" approach\nclass sample_parser\n{\n    const uint8_t* it_;\n    const uint8_t* end_;\n\n    std::size_t size() const noexcept { return static_cast<std::size_t>(end_ - it_); }\n\n    template <class T>\n    T get()\n    {\n        if (size() < sizeof(T))\n            return T{};\n\n        auto res = boost::endian::endian_load<T, sizeof(T), boost::endian::order::little>(it_);\n        it_ += sizeof(T);\n        return res;\n    }\n\n    blob_view get_blob()\n    {\n        std::size_t len = get<uint8_t>() % 128u;\n        auto actual_len = (std::min)(len, size());\n        blob_view res(it_, actual_len);\n        it_ += actual_len;\n        return res;\n    }\n\n    string_view get_string()\n    {\n        auto res = get_blob();\n        return {reinterpret_cast<const char*>(res.data()), res.size()};\n    }\n\n    date get_date() { return date(get<uint16_t>(), get<uint8_t>(), get<uint8_t>()); }\n\n    datetime get_datetime()\n    {\n        return datetime(\n            get<uint16_t>(),\n            get<uint8_t>(),\n            get<uint8_t>(),\n            get<uint8_t>(),\n            get<uint8_t>(),\n            get<uint8_t>(),\n            get<uint32_t>()\n        );\n    }\n\n    boost::mysql::time get_time() { return boost::mysql::time(get<int64_t>()); }\n\n    format_arg get_format_arg(uint8_t type)\n    {\n        switch (type % 10)\n        {\n        case 0:\n        default: return format_arg(\"\", nullptr);\n        case 1: return format_arg(\"\", get<int64_t>());\n        case 2: return format_arg(\"\", get<uint64_t>());\n        case 3: return format_arg(\"\", get<float>());\n        case 4: return format_arg(\"\", get<double>());\n        case 5: return format_arg(\"\", get_string());\n        case 6: return format_arg(\"\", get_blob());\n        case 7: return format_arg(\"\", get_date());\n        case 8: return format_arg(\"\", get_datetime());\n        case 9: return format_arg(\"\", get_time());\n        }\n    }\n\npublic:\n    sample_parser(const uint8_t* data, size_t size) noexcept : it_(data), end_(data + size) {}\n\n    std::array<format_arg, 2> parse()\n    {\n        // Types\n        uint8_t type_code = get<uint8_t>();\n        uint8_t type0 = type_code & 0x0f;\n        uint8_t type1 = type_code & 0xf0 >> 4;\n\n        // Arguments\n        return {\n            {get_format_arg(type0), get_format_arg(type1)}\n        };\n    }\n};\n\n}  // namespace\n\nstatic bool call_format_sql(const uint8_t* data, size_t size) noexcept\n{\n    // Parse the sample\n    auto sample = sample_parser(data, size).parse();\n\n    // Use a format context so we can avoid exceptions\n    format_context ctx({utf8mb4_charset, true});\n    format_sql_to(ctx, \"{}, {}\", {sample[0], sample[1]});\n\n    return std::move(ctx).get().has_value();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    call_format_sql(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_format_identifier.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <utility>\n\nusing namespace boost::mysql;\n\nstatic bool call_format_sql(const uint8_t* data, size_t size) noexcept\n{\n    // The entire string is our identifier\n    string_view sample(reinterpret_cast<const char*>(data), size);\n\n    // Use a format context so we can avoid exceptions\n    format_context ctx({utf8mb4_charset, true});\n    format_sql_to(ctx, \"SELECT {:i};\", sample);\n\n    return std::move(ctx).get().has_value();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    call_format_sql(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_format_sql_injection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include <cstddef>\n#include <stdexcept>\n\n#include \"test_common/ci_server.hpp\"\n\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\n\n// Fuzzes format_sql in an attempt to find SQL injection vulnerabilities.\n// This is not a usual fuzzer, as it sends the generated SQL to a real server -\n// this is the only way to be truly sure that no injection took place\n\nnamespace {\n\nclass fuzzer\n{\n    asio::io_context ctx_;\n    any_connection conn_;\n\npublic:\n    fuzzer() : conn_(ctx_)\n    {\n        connect_params params{\n            host_and_port{test::get_hostname()},\n            test::integ_user,\n            test::integ_passwd,\n            test::integ_db,\n        };\n        params.ssl = ssl_mode::disable;\n        conn_.connect(params);\n    }\n\n    int test(const uint8_t* data, size_t size)\n    {\n        // Create the query\n        format_context ctx(conn_.format_opts().value());\n        format_sql_to(\n            ctx,\n            \"SELECT id FROM three_rows_table WHERE field_varchar = {}\",\n            string_view(reinterpret_cast<const char*>(data), size)\n        );\n        auto query = std::move(ctx).get();\n\n        // If the generated query contains an error, the input wasn't valid UTF-8 - reject the sample\n        if (query.has_error())\n            return -1;\n\n        // Execute it\n        results r;\n        conn_.execute(*query, r);\n\n        // Check that we didn't get excess data\n        auto retrieved_rows = r.rows().size();\n        if (retrieved_rows != 1u && retrieved_rows != 0u)\n            throw std::runtime_error(\"Retrieved more rows than expected\");\n\n        return 0;\n    }\n};\n\n}  // namespace\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    static fuzzer f;\n    return f.test(data, size);\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_format_strings.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n\nusing namespace boost::mysql;\n\n// This fuzzer focuses on format string parsing, rather than argument formatting\nstatic bool call_format_sql(const uint8_t* data, size_t size) noexcept\n{\n    // The format string is the entire input\n    string_view format_str(reinterpret_cast<const char*>(data), size);\n\n    // Use a format context to avoid exceptions\n    format_context ctx({utf8mb4_charset, true});\n\n    // Call format with some arguments\n    format_sql_to(\n        ctx,\n        runtime(format_str),\n        // clang-format off\n        {\n            {\"name\", \"A\\\\ 'val'\"        },\n            {\"val\",  date(2021, 10, 1)  },\n            {\"k\",    42                 },\n            {\"k2\",   10.0               },\n            {\"null\", nullptr            },\n        }  // clang-format on\n    );\n\n    return std::move(ctx).get().has_value();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    call_format_sql(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_handshake_server_response.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_handshake_server_response(const uint8_t* data, size_t size) noexcept\n{\n    boost::mysql::diagnostics diag;\n    auto msg = deserialize_handshake_server_response({data, size}, db_flavor::mysql, diag);\n    return msg.type == handshake_server_response::type_t::error && diag.server_message().empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_handshake_server_response(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_ok_packet.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/ok_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_ok_packet(const uint8_t* data, size_t size) noexcept\n{\n    ok_view msg{};\n    auto ec = deserialize_ok_packet({data, size}, msg);\n    return !ec.failed() && msg.is_out_params();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_ok_packet(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_ok_response.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_ok_response(const uint8_t* data, size_t size) noexcept\n{\n    boost::mysql::diagnostics diag;\n    bool backslash_escapes = true;\n    auto ec = deserialize_ok_response({data, size}, db_flavor::mariadb, diag, backslash_escapes);\n    return !ec.failed() && diag.server_message().empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_ok_response(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_prepare_stmt_response.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_prepare_stmt_response(const uint8_t* data, size_t size) noexcept\n{\n    boost::mysql::diagnostics diag;\n    prepare_stmt_response msg{};\n    auto ec = deserialize_prepare_stmt_response({data, size}, db_flavor::mariadb, msg, diag);\n    return !ec.failed() && diag.server_message().empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_prepare_stmt_response(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_row.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/flags.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/endian/conversion.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n\nusing namespace boost::mysql::detail;\nusing boost::span;\nusing boost::mysql::column_type;\nusing boost::mysql::field_view;\nusing boost::mysql::metadata;\n\nstruct input\n{\n    resultset_encoding encoding{resultset_encoding::text};\n    std::vector<metadata> meta;\n    span<const uint8_t> msg;\n};\n\nstatic input parse_input(const uint8_t* data, size_t size)\n{\n    input res;\n    res.msg = {data, size};\n    const uint8_t* it = data;\n\n    // Header[0][low 7 bits]: num_fields\n    // Header[0][high bit]: encoding\n    if (size < 1)\n        return res;\n\n    res.encoding = (*it & (1 << 7)) ? resultset_encoding::binary : resultset_encoding::text;\n    size_t num_fields = *it & (0xff >> 1);\n    ++it;\n\n    // As many meta blocks as num_fields\n    // meta[i] spans 2 bytes\n    // meta[i][0][low 7 bits]: column_type\n    // meta[i][0][high bit]: is unsigned flag\n    // meta[i][1]: decimals\n    size_t expected_size = 1 + 2 * num_fields;\n    if (size < expected_size)\n        return res;\n\n    res.meta.reserve(num_fields);\n    for (size_t i = 0; i < num_fields; ++i)\n    {\n        coldef_view coldef{};\n\n        // Type: low 7 bits\n        coldef.type = static_cast<column_type>(*it & (0xff >> 1));\n\n        // Flags: we seed it with some value, and change the flag we're interested in\n        coldef.flags = boost::endian::load_little_u16(data);\n        if (*it & (1 << 7))\n        {\n            coldef.flags |= column_flags::unsigned_;\n        }\n        else\n        {\n            coldef.flags &= ~column_flags::unsigned_;\n        }\n        ++it;\n\n        // Decimals\n        coldef.decimals = *it;\n        ++it;\n\n        // Done\n        res.meta.push_back(access::construct<metadata>(coldef, false));\n    }\n    res.msg = {it, size - expected_size};\n    return res;\n}\n\nstatic bool parse_row(const input& input) noexcept\n{\n    size_t num_fields = input.meta.size();\n    if (num_fields == 0u)\n        return false;\n    std::unique_ptr<field_view[]> fvs{new field_view[num_fields]};\n    auto ec = deserialize_row(input.encoding, input.msg, input.meta, span<field_view>(fvs.get(), num_fields));\n    if (ec.failed())\n        return false;\n    return num_fields > 0u && fvs[0].is_null();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_row(parse_input(data, size));\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_row_message.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\n// Note: recall that deserialize_row_message doesn't perform field deserialization\nstatic bool parse_row_response(const uint8_t* data, size_t size) noexcept\n{\n    boost::mysql::diagnostics diag;\n    auto msg = deserialize_row_message({data, size}, db_flavor::mariadb, diag);\n    return msg.type == row_message::type_t::error && diag.server_message().empty();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_row_response(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_server_hello.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\nusing namespace boost::mysql::detail;\n\nstatic bool parse_server_hello(const uint8_t* data, size_t size) noexcept\n{\n    boost::mysql::diagnostics diag;\n    server_hello msg{};\n    auto ec = deserialize_server_hello({data, size}, msg, diag);\n    return !ec.failed() && diag.server_message().empty() && msg.server == db_flavor::mariadb;\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_server_hello(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_text_field.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/flags.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\n#include <boost/endian/conversion.hpp>\n\n#include <cstddef>\n#include <cstdint>\n\nusing namespace boost::mysql::detail;\nusing boost::mysql::column_type;\nusing boost::mysql::field_view;\nusing boost::mysql::metadata;\nusing boost::mysql::string_view;\n\nstruct input\n{\n    metadata meta;\n    string_view msg;\n};\n\nstatic string_view sv_from_range(const uint8_t* data, size_t size)\n{\n    return string_view(reinterpret_cast<const char*>(data), size);\n}\n\nstatic input parse_input(const uint8_t* data, size_t size)\n{\n    // Samples have a 2-byte header specifying metadata\n    // meta[0][low 7 bits]: column_type\n    // meta[0][high bit]: is unsigned flag\n    // meta[1]: decimals\n    if (size < 2)\n        return input{metadata(), sv_from_range(data, size)};\n\n    coldef_view coldef{};\n\n    // Type: low 7 bits\n    coldef.type = static_cast<column_type>(data[0] & (0xff >> 1));\n\n    // Flags: we seed it with some value, and change the flag we're interested in\n    coldef.flags = boost::endian::load_little_u16(size >= 4 ? data + 2 : data);\n    if (data[0] & (1 << 7))\n    {\n        coldef.flags |= column_flags::unsigned_;\n    }\n    else\n    {\n        coldef.flags &= ~column_flags::unsigned_;\n    }\n\n    // Decimals\n    coldef.decimals = data[1];\n\n    // Done\n    return {\n        access::construct<metadata>(coldef, false),\n        sv_from_range(data + 2, size - 2),\n    };\n}\n\nstatic bool parse_field(const input& input) noexcept\n{\n    field_view fv;\n    auto ec = deserialize_text_field(input.msg, input.meta, fv);\n    if (ec != deserialize_errc::ok)\n        return false;\n    return !fv.is_null();\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    parse_field(parse_input(data, size));\n    return 0;\n}\n"
  },
  {
    "path": "test/fuzzing/fuzz_utf8mb4.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n\n#include <boost/mysql/impl/internal/call_next_char.hpp>\n\n#include <cstddef>\n#include <stdint.h>\n\nusing namespace boost::mysql;\n\nstatic bool iterate_utf8mb4_string(const uint8_t* data, size_t size) noexcept\n{\n    const char* it = reinterpret_cast<const char*>(data);\n    const char* last = it + size;\n\n    while (it < last)\n    {\n        std::size_t char_len = detail::call_next_char(utf8mb4_charset, it, last);\n        if (char_len == 0u)\n            return false;  // Invalid character\n        it += char_len;\n    }\n\n    return true;\n}\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)\n{\n    // Note: this code should never throw exceptions, for any kind of input\n    iterate_utf8mb4_string(data, size);\n    return 0;\n}\n"
  },
  {
    "path": "test/integration/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nadd_executable(\n    boost_mysql_integrationtests\n\n    # Utilities\n    src/server_features.cpp\n    src/metadata_validator.cpp\n    src/spotchecks_helpers.cpp\n    src/utils.cpp\n\n    # Actual tests\n    test/spotchecks.cpp\n    test/execution_requests.cpp\n    test/crud.cpp\n    test/handshake.cpp\n    test/prepared_statements.cpp\n    test/stored_procedures.cpp\n    test/multi_queries.cpp\n    test/static_interface.cpp\n    test/multi_function.cpp\n    test/reconnect.cpp\n    test/any_connection.cpp\n    test/character_set_tracking.cpp\n    test/connection_id.cpp\n    test/pipeline.cpp\n    test/connection_pool.cpp\n    test/db_specific.cpp\n    test/database_types.cpp\n\n    # Snippets\n    test/snippets/tutorials.cpp\n    test/snippets/overview.cpp\n    test/snippets/connection_establishment.cpp\n    test/snippets/text_queries.cpp\n    test/snippets/prepared_statements.cpp\n    test/snippets/dynamic_interface.cpp\n    test/snippets/static_interface.cpp\n    test/snippets/multi_resultset.cpp\n    test/snippets/multi_function.cpp\n    test/snippets/metadata.cpp\n    test/snippets/charsets.cpp\n    test/snippets/time_types.cpp\n    test/snippets/connection_pool.cpp\n    test/snippets/interfacing_sync_async.cpp\n    test/snippets/sql_formatting_advanced.cpp\n    test/snippets/sql_formatting_advanced_2.cpp\n    test/snippets/pipeline.cpp\n    test/snippets/templated_connection.cpp\n)\ntarget_include_directories(\n    boost_mysql_integrationtests\n    PRIVATE\n    include\n)\ntarget_link_libraries(\n    boost_mysql_integrationtests\n    PRIVATE\n    boost_mysql_testing\n)\nboost_mysql_test_target_settings(boost_mysql_integrationtests)\nif (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.16)\n    target_precompile_headers(\n        boost_mysql_integrationtests\n        PRIVATE\n        pch.hpp\n    )\nendif()\n\nadd_test(\n    NAME boost_mysql_integrationtests\n    COMMAND boost_mysql_integrationtests\n)\n"
  },
  {
    "path": "test/integration/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\ncpp-pch pch\n    :\n        pch.hpp\n        /boost/mysql/test//boost_mysql_test\n    ;\n\n\nrun \n        pch\n        /boost/mysql/test//common_test_sources\n        /boost/mysql/test//boost_mysql_test\n        /boost/mysql/test//launch_with_valgrind\n \n        # Utilities\n        src/server_features.cpp\n        src/metadata_validator.cpp\n        src/spotchecks_helpers.cpp\n        src/utils.cpp\n\n        # Actual tests\n        test/spotchecks.cpp\n        test/execution_requests.cpp\n        test/crud.cpp\n        test/handshake.cpp\n        test/prepared_statements.cpp\n        test/stored_procedures.cpp\n        test/multi_queries.cpp\n        test/static_interface.cpp\n        test/multi_function.cpp\n        test/reconnect.cpp\n        test/any_connection.cpp\n        test/character_set_tracking.cpp\n        test/connection_id.cpp\n        test/pipeline.cpp\n        test/connection_pool.cpp\n        test/db_specific.cpp\n        test/database_types.cpp\n\n        # Snippets\n        test/snippets/tutorials.cpp\n        test/snippets/overview.cpp\n        test/snippets/connection_establishment.cpp\n        test/snippets/text_queries.cpp\n        test/snippets/prepared_statements.cpp\n        test/snippets/dynamic_interface.cpp\n        test/snippets/static_interface.cpp\n        test/snippets/multi_resultset.cpp\n        test/snippets/multi_function.cpp\n        test/snippets/metadata.cpp\n        test/snippets/charsets.cpp\n        test/snippets/time_types.cpp\n        test/snippets/connection_pool.cpp\n        test/snippets/interfacing_sync_async.cpp\n        test/snippets/sql_formatting_advanced.cpp\n        test/snippets/sql_formatting_advanced_2.cpp\n        test/snippets/pipeline.cpp\n        test/snippets/templated_connection.cpp\n\n    : requirements\n        <include>include\n    : target-name boost_mysql_integrationtests\n    ;\n\n"
  },
  {
    "path": "test/integration/db_setup.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\n-- System variables\nSET NAMES utf8;\nSET session sql_mode = 'ALLOW_INVALID_DATES'; -- allow zero and invalid dates\nSET session time_zone = '+02:00'; -- arbitrary, but should match whatever we use in database_types\nSET global max_allowed_packet = 83886080; -- 0x5000000 - for max packet size tests\nSET global max_connections = 5000; -- thread safety tests use a lot of connections and may be run in parallel\n\nSTART TRANSACTION;\n\n-- Database\nDROP DATABASE IF EXISTS boost_mysql_integtests;\nCREATE DATABASE boost_mysql_integtests;\nUSE boost_mysql_integtests;\n\n-- Tables\nCREATE TABLE inserts_table (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    field_varchar VARCHAR(255) NOT NULL,\n    field_date DATE\n) ENGINE=INNODB;\n\nCREATE TABLE updates_table (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    field_varchar VARCHAR(255) NOT NULL,\n    field_int INT\n) ENGINE=INNODB;\nINSERT INTO updates_table (field_varchar, field_int)\nVALUES ('f0', 42), ('f1', 43), ('fnull', NULL);\n\nCREATE TABLE empty_table (\n    id INT,\n    field_varchar VARCHAR(255)\n);\n\nCREATE TABLE one_row_table (\n    id INT,\n    field_varchar VARCHAR(255)\n);\nINSERT INTO one_row_table VALUES (1, 'f0');\n\nCREATE TABLE two_rows_table (\n    id INT,\n    field_varchar VARCHAR(255)\n);\nINSERT INTO two_rows_table VALUES (1, 'f0'), (2, 'f1');\n\nCREATE TABLE three_rows_table (\n    id INT,\n    field_varchar VARCHAR(255)\n);\nINSERT INTO three_rows_table VALUES (1, 'f0'), (2, 'f1'), (3, 'f2');\n\nCREATE TABLE multifield_table(\n    id INT NOT NULL PRIMARY KEY,\n    field_varchar VARCHAR(255) NOT NULL,\n    field_int INT NOT NULL,\n    field_nullable FLOAT,\n    field_double DOUBLE NOT NULL\n);\nINSERT INTO multifield_table VALUES\n    (1, \"aaa\", 11, 1.1, 0.1),\n    (2, \"bbb\", 22, NULL, 0.2);\n\n-- Tables to test we retrieve correctly values of every possible type\n-- Every type gets a separate table. Each field within the table is a possible variant of this same type\n-- Every row is a test case, identified by the id column.\n\n--    Integer types\nCREATE TABLE types_tinyint(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed TINYINT,\n    field_unsigned TINYINT UNSIGNED,\n    field_width TINYINT(4),\n    field_zerofill TINYINT(6) ZEROFILL\n);\nINSERT INTO types_tinyint VALUES\n    (\"regular\",   20,   20,   20,      20),\n    (\"negative\", -20,   NULL, -20,     NULL),\n    (\"min\",      -0x80, 0,    NULL,       0),\n    (\"max\",       0x7f, 0xff, NULL,    NULL)\n;\n\nCREATE TABLE types_smallint(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed SMALLINT,\n    field_unsigned SMALLINT UNSIGNED,\n    field_width SMALLINT(8),\n    field_zerofill SMALLINT(7) ZEROFILL\n);\nINSERT INTO types_smallint VALUES\n    (\"regular\",   20,     20,     20,      20),\n    (\"negative\", -20,     NULL,   -20,     NULL),\n    (\"min\",      -0x8000, 0,      NULL,    0),\n    (\"max\",       0x7fff, 0xffff, NULL,    NULL)\n;\n\nCREATE TABLE types_mediumint(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed MEDIUMINT,\n    field_unsigned MEDIUMINT UNSIGNED,\n    field_width MEDIUMINT(8),\n    field_zerofill MEDIUMINT(7) ZEROFILL\n);\nINSERT INTO types_mediumint VALUES\n    (\"regular\",   20,       20,       20,      20),\n    (\"negative\", -20,       NULL,     -20,     NULL),   \n    (\"min\",      -0x800000, 0,        NULL,    0),\n    (\"max\",       0x7fffff, 0xffffff, NULL,    NULL)\n;\n\nCREATE TABLE types_int(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed INT,\n    field_unsigned INT UNSIGNED,\n    field_width INT(8),\n    field_zerofill INT(7) ZEROFILL\n);\nINSERT INTO types_int VALUES\n    (\"regular\",   20,         20,         20,      20),\n    (\"negative\", -20,         NULL,       -20,     NULL),   \n    (\"min\",      -0x80000000, 0,          NULL,    0),\n    (\"max\",       0x7fffffff, 0xffffffff, NULL,    NULL)\n;\n\nCREATE TABLE types_bigint(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed BIGINT,\n    field_unsigned BIGINT UNSIGNED,\n    field_width BIGINT(8),\n    field_zerofill BIGINT(7) ZEROFILL\n);\nINSERT INTO types_bigint VALUES\n    (\"regular\",   20,                 20,                 20,      20),\n    (\"negative\", -20,                 NULL,               -20,     NULL),   \n    (\"min\",      -0x8000000000000000, 0,                  NULL,    0),\n    (\"max\",       0x7fffffffffffffff, 0xffffffffffffffff, NULL,    NULL)\n;\n\nCREATE TABLE types_year(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_default YEAR\n);\nINSERT INTO types_year VALUES\n    (\"regular\", 2019),\n    (\"min\",     1901),\n    (\"max\",     2155),\n    (\"zero\",    0)\n;\n\nCREATE TABLE types_bool(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_default BOOL\n);\nINSERT INTO types_bool VALUES\n    (\"true\",  TRUE),\n    (\"false\", FALSE)\n;\n\nCREATE TABLE types_bit(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_1 BIT(1),\n    field_8 BIT(8),\n    field_14 BIT(14),\n    field_16 BIT(16),\n    field_24 BIT(24),\n    field_25 BIT(25),\n    field_32 BIT(32),\n    field_40 BIT(40),\n    field_48 BIT(48),\n    field_56 BIT(56),\n    field_64 BIT(64)\n);\nINSERT INTO types_bit VALUES\n    (\"min\",     0, 0x00, 0x0000, 0x0000, 0x000000, 0x0000000, 0x00000000, 0x0000000000, 0x000000000000, 0x00000000000000, 0x0000000000000000),\n    (\"regular\", 1, 0x9e, 0x1e2a, 0x1234, 0x123456, 0x154abe0, 0x12345678, 0x123456789a, 0x123456789abc, 0x123456789abcde, 0x1234567812345678),\n    (\"max\",     1, 0xff, 0x3fff, 0xffff, 0xffffff, 0x1ffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0xffffffffffffffff)\n;\n\n--   Floating point types\nCREATE TABLE types_float(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed FLOAT,\n    field_unsigned FLOAT UNSIGNED,\n    field_width FLOAT(30, 10),\n    field_zerofill FLOAT(20) ZEROFILL\n);\nINSERT INTO types_float VALUES\n    (\"zero\",                             0,        0,    0,        0),\n    (\"int_positive\",                     4,        NULL, NULL,     NULL),\n    (\"int_negative\",                     -4,       NULL, NULL,     NULL),\n    (\"fractional_positive\",              4.2,      4.2,  4.2,      4.2),\n    (\"fractional_negative\",              -4.2,     NULL, -4.2,     NULL),\n    (\"positive_exp_positive_int\",        3e20,     NULL, NULL,     NULL),\n    (\"positive_exp_negative_int\",        -3e20,    NULL, NULL,     NULL),\n    (\"positive_exp_positive_fractional\", 3.14e20,  NULL, NULL,  3.14e20),\n    (\"positive_exp_negative_fractional\", -3.14e20, NULL, NULL,  NULL),\n    (\"negative_exp_positive_fractional\", 3.14e-20, NULL, NULL,  3.14e-20)\n;\n\nCREATE TABLE types_double(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_signed DOUBLE,\n    field_unsigned DOUBLE UNSIGNED,\n    field_width DOUBLE(60, 10),\n    field_zerofill FLOAT(40) ZEROFILL\n);\nINSERT INTO types_double VALUES\n    (\"zero\",                             0,        0,    0,        0),\n    (\"int_positive\",                     4,        NULL, NULL,     NULL),\n    (\"int_negative\",                     -4,       NULL, NULL,     NULL),\n    (\"fractional_positive\",              4.2,      4.2,  4.2,      4.2),\n    (\"fractional_negative\",              -4.2,     NULL, -4.2,     NULL),\n    (\"positive_exp_positive_int\",        3e200,     NULL, NULL,     NULL),\n    (\"positive_exp_negative_int\",        -3e200,    NULL, NULL,     NULL),\n    (\"positive_exp_positive_fractional\", 3.14e200,  NULL, NULL,  3.14e200),\n    (\"positive_exp_negative_fractional\", -3.14e200, NULL, NULL,  NULL),\n    (\"negative_exp_positive_fractional\", 3.14e-200, NULL, NULL,  3.14e-200)\n;\n\n--    Dates and times\nCREATE TABLE types_date(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_date DATE\n);\nINSERT INTO types_date VALUES\n    (\"regular\",                 \"2010-03-28\"),\n    (\"leap_regular\",            \"1788-02-29\"),\n    (\"leap_400\",                \"2000-02-29\"),\n    (\"min\",                     \"0000-01-01\"),\n    (\"max\",                     \"9999-12-31\"),\n    (\"zero\",                    \"0000-00-00\"),\n    (\"yzero_mzero_dregular\",    \"0000-00-20\"),\n    (\"yzero_mregular_dzero\",    \"0000-11-00\"),\n    (\"yzero_invalid_date\",      \"0000-11-31\"),\n    (\"yregular_mzero_dzero\",    \"2020-00-00\"),\n    (\"yregular_mzero_dregular\", \"2020-00-20\"),\n    (\"yregular_mregular_dzero\", \"2020-11-00\"),\n    (\"yregular_invalid_date\",   \"2020-11-31\"),\n    (\"yregular_invalid_date_leapregular\", \"1999-02-29\"),\n    (\"yregular_invalid_date_leap100\",     \"1900-02-29\")\n;\n\n-- A bug in MySQL 5.x requires us to set this collation to binary to get the correct order\nCREATE TABLE types_datetime(\n    id VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL PRIMARY KEY,\n    field_0 DATETIME(0),\n    field_1 DATETIME(1),\n    field_2 DATETIME(2),\n    field_3 DATETIME(3),\n    field_4 DATETIME(4),\n    field_5 DATETIME(5),\n    field_6 DATETIME(6)\n);\n\n-- Values common to both datetime and timestamp\nINSERT INTO types_datetime VALUES\n    (\"date\",         \"2010-05-02 00:00:00\", \"2010-05-02 00:00:00\",   \"2010-05-02 00:00:00\",    \"2010-05-02 00:00:00\",     \"2010-05-02 00:00:00\",      \"2010-05-02 00:00:00\",       \"2010-05-02 00:00:00\"),\n    (\"date_leap4\",   \"2004-02-29 00:00:00\", \"2004-02-29 00:00:00\",   \"2004-02-29 00:00:00\",    \"2004-02-29 00:00:00\",     \"2004-02-29 00:00:00\",      \"2004-02-29 00:00:00\",       \"2004-02-29 00:00:00\"),\n    (\"date_leap400\", \"2000-02-29 00:00:00\", \"2000-02-29 00:00:00\",   \"2000-02-29 00:00:00\",    \"2000-02-29 00:00:00\",     \"2000-02-29 00:00:00\",      \"2000-02-29 00:00:00\",       \"2000-02-29 00:00:00\"),\n    (\"u\",            NULL,                  \"2010-05-02 00:00:00.1\", \"2010-05-02 00:00:00.12\", \"2010-05-02 00:00:00.123\", \"2010-05-02 00:00:00.1234\", \"2010-05-02 00:00:00.12345\", \"2010-05-02 00:00:00.123456\"),\n    (\"s\",            \"2010-05-02 00:00:50\", \"2010-05-02 00:00:50\",   \"2010-05-02 00:00:50\",    \"2010-05-02 00:00:50\",     \"2010-05-02 00:00:50\",      \"2010-05-02 00:00:50\",       \"2010-05-02 00:00:50\"), \n    (\"m\",            \"2010-05-02 00:01:00\", \"2010-05-02 00:01:00\",   \"2010-05-02 00:01:00\",    \"2010-05-02 00:01:00\",     \"2010-05-02 00:01:00\",      \"2010-05-02 00:01:00\",       \"2010-05-02 00:01:00\"),\n    (\"hs\",           \"2010-05-02 23:00:50\", \"2010-05-02 23:00:50\",   \"2010-05-02 23:00:50\",    \"2010-05-02 23:00:50\",     \"2010-05-02 23:00:50\",      \"2010-05-02 23:00:50\",       \"2010-05-02 23:00:50\"),\n    (\"ms\",           \"2010-05-02 00:01:50\", \"2010-05-02 00:01:50\",   \"2010-05-02 00:01:50\",    \"2010-05-02 00:01:50\",     \"2010-05-02 00:01:50\",      \"2010-05-02 00:01:50\",       \"2010-05-02 00:01:50\"),\n    (\"hu\",           NULL,                  \"2010-05-02 23:00:00.1\", \"2010-05-02 23:00:00.12\", \"2010-05-02 23:00:00.123\", \"2010-05-02 23:00:00.1234\", \"2010-05-02 23:00:00.12345\", \"2010-05-02 23:00:00.123456\"),\n    (\"mu\",           NULL,                  \"2010-05-02 00:01:00.1\", \"2010-05-02 00:01:00.12\", \"2010-05-02 00:01:00.123\", \"2010-05-02 00:01:00.1234\", \"2010-05-02 00:01:00.12345\", \"2010-05-02 00:01:00.123456\"),\n    (\"hmu\",          NULL,                  \"2010-05-02 23:01:00.1\", \"2010-05-02 23:01:00.12\", \"2010-05-02 23:01:00.123\", \"2010-05-02 23:01:00.1234\", \"2010-05-02 23:01:00.12345\", \"2010-05-02 23:01:00.123456\"),\n    (\"su\",           NULL,                  \"2010-05-02 00:00:50.1\", \"2010-05-02 00:00:50.12\", \"2010-05-02 00:00:50.123\", \"2010-05-02 00:00:50.1234\", \"2010-05-02 00:00:50.12345\", \"2010-05-02 00:00:50.123456\"),\n    (\"hsu\",          NULL,                  \"2010-05-02 23:00:50.1\", \"2010-05-02 23:00:50.12\", \"2010-05-02 23:00:50.123\", \"2010-05-02 23:00:50.1234\", \"2010-05-02 23:00:50.12345\", \"2010-05-02 23:00:50.123456\"),\n    (\"msu\",          NULL,                  \"2010-05-02 00:01:50.1\", \"2010-05-02 00:01:50.12\", \"2010-05-02 00:01:50.123\", \"2010-05-02 00:01:50.1234\", \"2010-05-02 00:01:50.12345\", \"2010-05-02 00:01:50.123456\"),\n    (\"h\",            \"2010-05-02 23:00:00\", \"2010-05-02 23:00:00\",   \"2010-05-02 23:00:00\",    \"2010-05-02 23:00:00\",     \"2010-05-02 23:00:00\",      \"2010-05-02 23:00:00\",       \"2010-05-02 23:00:00\"),\n    (\"hm\",           \"2010-05-02 23:01:00\", \"2010-05-02 23:01:00\",   \"2010-05-02 23:01:00\",    \"2010-05-02 23:01:00\",     \"2010-05-02 23:01:00\",      \"2010-05-02 23:01:00\",       \"2010-05-02 23:01:00\"),\n    (\"hms\",          \"2010-05-02 23:01:50\", \"2010-05-02 23:01:50\",   \"2010-05-02 23:01:50\",    \"2010-05-02 23:01:50\",     \"2010-05-02 23:01:50\",      \"2010-05-02 23:01:50\",       \"2010-05-02 23:01:50\"),\n    (\"hmsu\",         NULL,                  \"2010-05-02 23:01:50.1\", \"2010-05-02 23:01:50.12\", \"2010-05-02 23:01:50.123\", \"2010-05-02 23:01:50.1234\", \"2010-05-02 23:01:50.12345\", \"2010-05-02 23:01:50.123456\")\n;\n\nCREATE TABLE types_timestamp(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_0 TIMESTAMP(0) NULL DEFAULT NULL,\n    field_1 TIMESTAMP(1) NULL DEFAULT NULL,\n    field_2 TIMESTAMP(2) NULL DEFAULT NULL,\n    field_3 TIMESTAMP(3) NULL DEFAULT NULL,\n    field_4 TIMESTAMP(4) NULL DEFAULT NULL,\n    field_5 TIMESTAMP(5) NULL DEFAULT NULL,\n    field_6 TIMESTAMP(6) NULL DEFAULT NULL\n);\nINSERT INTO types_timestamp\nSELECT * FROM types_datetime;\n\n-- Values specific to datetimes\nINSERT INTO types_datetime VALUES\n    (\"min\",          \"0000-01-01\",          \"0000-01-01\",            \"0000-01-01\",             \"0000-01-01\",              \"0000-01-01\",               \"0000-01-01\",                \"0000-01-01\"),\n    (\"max\",          \"9999-12-31 23:59:59\", \"9999-12-31 23:59:59.9\", \"9999-12-31 23:59:59.99\", \"9999-12-31 23:59:59.999\", \"9999-12-31 23:59:59.9999\", \"9999-12-31 23:59:59.99999\", \"9999-12-31 23:59:59.999999\"),\n    \n    (\"date_zero\",                               \"0000-00-00 00:00:00\", \"0000-00-00 00:00:00.0\", \"0000-00-00 00:00:00.00\", \"0000-00-00 00:00:00.000\", \"0000-00-00 00:00:00.0000\", \"0000-00-00 00:00:00.00000\", \"0000-00-00 00:00:00.000000\"),\n    (\"date_yzero_mzero_dregular\",               \"0000-00-10 00:00:00\", \"0000-00-10 00:00:00.0\", \"0000-00-10 00:00:00.00\", \"0000-00-10 00:00:00.000\", \"0000-00-10 00:00:00.0000\", \"0000-00-10 00:00:00.00000\", \"0000-00-10 00:00:00.000000\"),\n    (\"date_yzero_mregular_dzero\",               \"0000-10-00 00:00:00\", \"0000-10-00 00:00:00.0\", \"0000-10-00 00:00:00.00\", \"0000-10-00 00:00:00.000\", \"0000-10-00 00:00:00.0000\", \"0000-10-00 00:00:00.00000\", \"0000-10-00 00:00:00.000000\"),\n    (\"date_yzero_invalid_date\",                 \"0000-11-31 00:00:00\", \"0000-11-31 00:00:00.0\", \"0000-11-31 00:00:00.00\", \"0000-11-31 00:00:00.000\", \"0000-11-31 00:00:00.0000\", \"0000-11-31 00:00:00.00000\", \"0000-11-31 00:00:00.000000\"),\n    (\"date_yregular_mzero_dzero\",               \"2020-00-00 00:00:00\", \"2020-00-00 00:00:00.0\", \"2020-00-00 00:00:00.00\", \"2020-00-00 00:00:00.000\", \"2020-00-00 00:00:00.0000\", \"2020-00-00 00:00:00.00000\", \"2020-00-00 00:00:00.000000\"),\n    (\"date_yregular_mzero_dregular\",            \"2020-00-10 00:00:00\", \"2020-00-10 00:00:00.0\", \"2020-00-10 00:00:00.00\", \"2020-00-10 00:00:00.000\", \"2020-00-10 00:00:00.0000\", \"2020-00-10 00:00:00.00000\", \"2020-00-10 00:00:00.000000\"),\n    (\"date_yregular_mregular_dzero\",            \"2020-10-00 00:00:00\", \"2020-10-00 00:00:00.0\", \"2020-10-00 00:00:00.00\", \"2020-10-00 00:00:00.000\", \"2020-10-00 00:00:00.0000\", \"2020-10-00 00:00:00.00000\", \"2020-10-00 00:00:00.000000\"),\n    (\"date_yregular_invalid_date\",              \"2020-11-31 00:00:00\", \"2020-11-31 00:00:00.0\", \"2020-11-31 00:00:00.00\", \"2020-11-31 00:00:00.000\", \"2020-11-31 00:00:00.0000\", \"2020-11-31 00:00:00.00000\", \"2020-11-31 00:00:00.000000\"),\n    (\"date_yregular_invalid_date_leapregular\",  \"1999-02-29 00:00:00\", \"1999-02-29 00:00:00.0\", \"1999-02-29 00:00:00.00\", \"1999-02-29 00:00:00.000\", \"1999-02-29 00:00:00.0000\", \"1999-02-29 00:00:00.00000\", \"1999-02-29 00:00:00.000000\"),\n    (\"date_yregular_invalid_date_leap100\",      \"1900-02-29 00:00:00\", \"1900-02-29 00:00:00.0\", \"1900-02-29 00:00:00.00\", \"1900-02-29 00:00:00.000\", \"1900-02-29 00:00:00.0000\", \"1900-02-29 00:00:00.00000\", \"1900-02-29 00:00:00.000000\"),\n    \n    (\"hms_zero\",                              \"0000-00-00 10:20:30\", \"0000-00-00 10:20:30.0\", \"0000-00-00 10:20:30.00\", \"0000-00-00 10:20:30.000\", \"0000-00-00 10:20:30.0000\", \"0000-00-00 10:20:30.00000\", \"0000-00-00 10:20:30.000000\"),\n    (\"hms_yzero_mzero_dregular\",              \"0000-00-10 10:20:30\", \"0000-00-10 10:20:30.0\", \"0000-00-10 10:20:30.00\", \"0000-00-10 10:20:30.000\", \"0000-00-10 10:20:30.0000\", \"0000-00-10 10:20:30.00000\", \"0000-00-10 10:20:30.000000\"),\n    (\"hms_yzero_mregular_dzero\",              \"0000-10-00 10:20:30\", \"0000-10-00 10:20:30.0\", \"0000-10-00 10:20:30.00\", \"0000-10-00 10:20:30.000\", \"0000-10-00 10:20:30.0000\", \"0000-10-00 10:20:30.00000\", \"0000-10-00 10:20:30.000000\"),\n    (\"hms_yzero_invalid_date\",                \"0000-11-31 10:20:30\", \"0000-11-31 10:20:30.0\", \"0000-11-31 10:20:30.00\", \"0000-11-31 10:20:30.000\", \"0000-11-31 10:20:30.0000\", \"0000-11-31 10:20:30.00000\", \"0000-11-31 10:20:30.000000\"),\n    (\"hms_yregular_mzero_dzero\",              \"2020-00-00 10:20:30\", \"2020-00-00 10:20:30.0\", \"2020-00-00 10:20:30.00\", \"2020-00-00 10:20:30.000\", \"2020-00-00 10:20:30.0000\", \"2020-00-00 10:20:30.00000\", \"2020-00-00 10:20:30.000000\"),\n    (\"hms_yregular_mzero_dregular\",           \"2020-00-10 10:20:30\", \"2020-00-10 10:20:30.0\", \"2020-00-10 10:20:30.00\", \"2020-00-10 10:20:30.000\", \"2020-00-10 10:20:30.0000\", \"2020-00-10 10:20:30.00000\", \"2020-00-10 10:20:30.000000\"),\n    (\"hms_yregular_mregular_dzero\",           \"2020-10-00 10:20:30\", \"2020-10-00 10:20:30.0\", \"2020-10-00 10:20:30.00\", \"2020-10-00 10:20:30.000\", \"2020-10-00 10:20:30.0000\", \"2020-10-00 10:20:30.00000\", \"2020-10-00 10:20:30.000000\"),\n    (\"hms_yregular_invalid_date\",             \"2020-11-31 10:20:30\", \"2020-11-31 10:20:30.0\", \"2020-11-31 10:20:30.00\", \"2020-11-31 10:20:30.000\", \"2020-11-31 10:20:30.0000\", \"2020-11-31 10:20:30.00000\", \"2020-11-31 10:20:30.000000\"),\n    (\"hms_yregular_invalid_date_leapregular\", \"1999-02-29 10:20:30\", \"1999-02-29 10:20:30.0\", \"1999-02-29 10:20:30.00\", \"1999-02-29 10:20:30.000\", \"1999-02-29 10:20:30.0000\", \"1999-02-29 10:20:30.00000\", \"1999-02-29 10:20:30.000000\"),\n    (\"hms_yregular_invalid_date_leap100\",     \"1900-02-29 10:20:30\", \"1900-02-29 10:20:30.0\", \"1900-02-29 10:20:30.00\", \"1900-02-29 10:20:30.000\", \"1900-02-29 10:20:30.0000\", \"1900-02-29 10:20:30.00000\", \"1900-02-29 10:20:30.000000\"),\n    \n    \n    (\"hmsu_zero\",                              \"0000-00-00 10:20:30\", \"0000-00-00 10:20:30.9\", \"0000-00-00 10:20:30.99\", \"0000-00-00 10:20:30.999\", \"0000-00-00 10:20:30.9999\", \"0000-00-00 10:20:30.99999\", \"0000-00-00 10:20:30.999999\"),\n    (\"hmsu_yzero_mzero_dregular\",              \"0000-00-10 10:20:30\", \"0000-00-10 10:20:30.9\", \"0000-00-10 10:20:30.99\", \"0000-00-10 10:20:30.999\", \"0000-00-10 10:20:30.9999\", \"0000-00-10 10:20:30.99999\", \"0000-00-10 10:20:30.999999\"),\n    (\"hmsu_yzero_mregular_dzero\",              \"0000-10-00 10:20:30\", \"0000-10-00 10:20:30.9\", \"0000-10-00 10:20:30.99\", \"0000-10-00 10:20:30.999\", \"0000-10-00 10:20:30.9999\", \"0000-10-00 10:20:30.99999\", \"0000-10-00 10:20:30.999999\"),\n    (\"hmsu_yzero_invalid_date\",                \"0000-11-31 10:20:30\", \"0000-11-31 10:20:30.9\", \"0000-11-31 10:20:30.99\", \"0000-11-31 10:20:30.999\", \"0000-11-31 10:20:30.9999\", \"0000-11-31 10:20:30.99999\", \"0000-11-31 10:20:30.999999\"),\n    (\"hmsu_yregular_mzero_dzero\",              \"2020-00-00 10:20:30\", \"2020-00-00 10:20:30.9\", \"2020-00-00 10:20:30.99\", \"2020-00-00 10:20:30.999\", \"2020-00-00 10:20:30.9999\", \"2020-00-00 10:20:30.99999\", \"2020-00-00 10:20:30.999999\"),\n    (\"hmsu_yregular_mzero_dregular\",           \"2020-00-10 10:20:30\", \"2020-00-10 10:20:30.9\", \"2020-00-10 10:20:30.99\", \"2020-00-10 10:20:30.999\", \"2020-00-10 10:20:30.9999\", \"2020-00-10 10:20:30.99999\", \"2020-00-10 10:20:30.999999\"),\n    (\"hmsu_yregular_mregular_dzero\",           \"2020-10-00 10:20:30\", \"2020-10-00 10:20:30.9\", \"2020-10-00 10:20:30.99\", \"2020-10-00 10:20:30.999\", \"2020-10-00 10:20:30.9999\", \"2020-10-00 10:20:30.99999\", \"2020-10-00 10:20:30.999999\"),\n    (\"hmsu_yregular_invalid_date\",             \"2020-11-31 10:20:30\", \"2020-11-31 10:20:30.9\", \"2020-11-31 10:20:30.99\", \"2020-11-31 10:20:30.999\", \"2020-11-31 10:20:30.9999\", \"2020-11-31 10:20:30.99999\", \"2020-11-31 10:20:30.999999\"),\n    (\"hmsu_yregular_invalid_date_leapregular\", \"1999-02-29 10:20:30\", \"1999-02-29 10:20:30.9\", \"1999-02-29 10:20:30.99\", \"1999-02-29 10:20:30.999\", \"1999-02-29 10:20:30.9999\", \"1999-02-29 10:20:30.99999\", \"1999-02-29 10:20:30.999999\"),\n    (\"hmsu_yregular_invalid_date_leap100\",     \"1900-02-29 10:20:30\", \"1900-02-29 10:20:30.9\", \"1900-02-29 10:20:30.99\", \"1900-02-29 10:20:30.999\", \"1900-02-29 10:20:30.9999\", \"1900-02-29 10:20:30.99999\", \"1900-02-29 10:20:30.999999\")\n;\n\n-- Values specific to timestamps\nINSERT INTO types_timestamp VALUES\n    (\"zero\", \"0000-00-00\",          \"0000-00-00\",            \"0000-00-00\",             \"0000-00-00\",              \"0000-00-00\",               \"0000-00-00\",                \"0000-00-00\"),\n    (\"min\",  \"1970-01-01 02:00:01\", \"1970-01-01 02:00:01.0\", \"1970-01-01 02:00:01.00\", \"1970-01-01 02:00:01.000\", \"1970-01-01 02:00:01.0000\", \"1970-01-01 02:00:01.00000\", \"1970-01-01 02:00:01.000000\"),\n    (\"max\",  \"2038-01-19 05:14:07\", \"2038-01-19 05:14:07.9\", \"2038-01-19 05:14:07.99\", \"2038-01-19 05:14:07.999\", \"2038-01-19 05:14:07.9999\", \"2038-01-19 05:14:07.99999\", \"2038-01-19 05:14:07.999999\")\n;\n\nCREATE TABLE types_time(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_0 TIME(0),\n    field_1 TIME(1),\n    field_2 TIME(2),\n    field_3 TIME(3),\n    field_4 TIME(4),\n    field_5 TIME(5),\n    field_6 TIME(6)\n);\nINSERT INTO types_time VALUES\n    (\"zero\",           \"00:00:00\",  \"00:00:00\",     \"00:00:00\",      \"00:00:00\",       \"00:00:00\",        \"00:00:00\",         \"00:00:00\"),\n    (\"d\",              \"48:00:00\",  \"48:00:00\",     \"48:00:00\",      \"48:00:00\",       \"48:00:00\",        \"48:00:00\",         \"48:00:00\"),\n    (\"negative_d\",     \"-48:00:00\", \"-48:00:00\",    \"-48:00:00\",     \"-48:00:00\",      \"-48:00:00\",       \"-48:00:00\",        \"-48:00:00\"),\n    (\"h\",              \"23:00:00\",  \"23:00:00\",     \"23:00:00\",      \"23:00:00\",       \"23:00:00\",        \"23:00:00\",         \"23:00:00\"),\n    (\"negative_h\",     \"-23:00:00\", \"-23:00:00\",    \"-23:00:00\",     \"-23:00:00\",      \"-23:00:00\",       \"-23:00:00\",        \"-23:00:00\"),\n    (\"dh\",             \"71:00:00\",  \"71:00:00\",     \"71:00:00\",      \"71:00:00\",       \"71:00:00\",        \"71:00:00\",         \"71:00:00\"),\n    (\"negative_dh\",    \"-71:00:00\", \"-71:00:00\",    \"-71:00:00\",     \"-71:00:00\",      \"-71:00:00\",       \"-71:00:00\",        \"-71:00:00\"),\n    (\"m\",              \"00:01:00\",  \"00:01:00\",     \"00:01:00\",      \"00:01:00\",       \"00:01:00\",        \"00:01:00\",         \"00:01:00\"),\n    (\"negative_m\",     \"-00:01:00\", \"-00:01:00\",    \"-00:01:00\",     \"-00:01:00\",      \"-00:01:00\",       \"-00:01:00\",        \"-00:01:00\"),\n    (\"dm\",             \"48:01:00\",  \"48:01:00\",     \"48:01:00\",      \"48:01:00\",       \"48:01:00\",        \"48:01:00\",         \"48:01:00\"),\n    (\"negative_dm\",    \"-48:01:00\", \"-48:01:00\",    \"-48:01:00\",     \"-48:01:00\",      \"-48:01:00\",       \"-48:01:00\",        \"-48:01:00\"),\n    (\"hm\",             \"23:01:00\",  \"23:01:00\",     \"23:01:00\",      \"23:01:00\",       \"23:01:00\",        \"23:01:00\",         \"23:01:00\"),\n    (\"negative_hm\",    \"-23:01:00\", \"-23:01:00\",    \"-23:01:00\",     \"-23:01:00\",      \"-23:01:00\",       \"-23:01:00\",        \"-23:01:00\"),\n    (\"dhm\",            \"71:01:00\",  \"71:01:00\",     \"71:01:00\",      \"71:01:00\",       \"71:01:00\",        \"71:01:00\",         \"71:01:00\"),\n    (\"negative_dhm\",   \"-71:01:00\", \"-71:01:00\",    \"-71:01:00\",     \"-71:01:00\",      \"-71:01:00\",       \"-71:01:00\",        \"-71:01:00\"),\n    (\"s\",              \"00:00:50\",  \"00:00:50\",     \"00:00:50\",      \"00:00:50\",       \"00:00:50\",        \"00:00:50\",         \"00:00:50\"),\n    (\"negative_s\",     \"-00:00:50\", \"-00:00:50\",    \"-00:00:50\",     \"-00:00:50\",      \"-00:00:50\",       \"-00:00:50\",        \"-00:00:50\"),\n    (\"ds\",             \"48:00:50\",  \"48:00:50\",     \"48:00:50\",      \"48:00:50\",       \"48:00:50\",        \"48:00:50\",         \"48:00:50\"),\n    (\"negative_ds\",    \"-48:00:50\", \"-48:00:50\",    \"-48:00:50\",     \"-48:00:50\",      \"-48:00:50\",       \"-48:00:50\",        \"-48:00:50\"),\n    (\"hs\",             \"23:00:50\",  \"23:00:50\",     \"23:00:50\",      \"23:00:50\",       \"23:00:50\",        \"23:00:50\",         \"23:00:50\"),\n    (\"negative_hs\",    \"-23:00:50\", \"-23:00:50\",    \"-23:00:50\",     \"-23:00:50\",      \"-23:00:50\",       \"-23:00:50\",        \"-23:00:50\"),\n    (\"dhs\",            \"71:00:50\",  \"71:00:50\",     \"71:00:50\",      \"71:00:50\",       \"71:00:50\",        \"71:00:50\",         \"71:00:50\"),\n    (\"negative_dhs\",   \"-71:00:50\", \"-71:00:50\",    \"-71:00:50\",     \"-71:00:50\",      \"-71:00:50\",       \"-71:00:50\",        \"-71:00:50\"),\n    (\"ms\",             \"00:01:50\",  \"00:01:50\",     \"00:01:50\",      \"00:01:50\",       \"00:01:50\",        \"00:01:50\",         \"00:01:50\"),\n    (\"negative_ms\",    \"-00:01:50\", \"-00:01:50\",    \"-00:01:50\",     \"-00:01:50\",      \"-00:01:50\",       \"-00:01:50\",        \"-00:01:50\"),\n    (\"dms\",            \"48:01:50\",  \"48:01:50\",     \"48:01:50\",      \"48:01:50\",       \"48:01:50\",        \"48:01:50\",         \"48:01:50\"),\n    (\"negative_dms\",   \"-48:01:50\", \"-48:01:50\",    \"-48:01:50\",     \"-48:01:50\",      \"-48:01:50\",       \"-48:01:50\",        \"-48:01:50\"),\n    (\"hms\",            \"23:01:50\",  \"23:01:50\",     \"23:01:50\",      \"23:01:50\",       \"23:01:50\",        \"23:01:50\",         \"23:01:50\"),\n    (\"negative_hms\",   \"-23:01:50\", \"-23:01:50\",    \"-23:01:50\",     \"-23:01:50\",      \"-23:01:50\",       \"-23:01:50\",        \"-23:01:50\"),\n    (\"dhms\",           \"71:01:50\",  \"71:01:50\",     \"71:01:50\",      \"71:01:50\",       \"71:01:50\",        \"71:01:50\",         \"71:01:50\"),\n    (\"negative_dhms\",  \"-71:01:50\", \"-71:01:50\",    \"-71:01:50\",     \"-71:01:50\",      \"-71:01:50\",       \"-71:01:50\",        \"-71:01:50\"),\n    (\"u\",              NULL,        \"00:00:00.1\",   \"00:00:00.12\",   \"00:00:00.123\",   \"00:00:00.1234\",   \"00:00:00.12345\",   \"00:00:00.123456\"),\n    (\"negative_u\",     NULL,        \"-00:00:00.1\",  \"-00:00:00.12\",  \"-00:00:00.123\",  \"-00:00:00.1234\",  \"-00:00:00.12345\",  \"-00:00:00.123456\"),\n    (\"du\",             NULL,        \"48:00:00.1\",   \"48:00:00.12\",   \"48:00:00.123\",   \"48:00:00.1234\",   \"48:00:00.12345\",   \"48:00:00.123456\"),\n    (\"negative_du\",    NULL,        \"-48:00:00.1\",  \"-48:00:00.12\",  \"-48:00:00.123\",  \"-48:00:00.1234\",  \"-48:00:00.12345\",  \"-48:00:00.123456\"),\n    (\"hu\",             NULL,        \"23:00:00.1\",   \"23:00:00.12\",   \"23:00:00.123\",   \"23:00:00.1234\",   \"23:00:00.12345\",   \"23:00:00.123456\"),\n    (\"negative_hu\",    NULL,        \"-23:00:00.1\",  \"-23:00:00.12\",  \"-23:00:00.123\",  \"-23:00:00.1234\",  \"-23:00:00.12345\",  \"-23:00:00.123456\"),\n    (\"dhu\",            NULL,        \"71:00:00.1\",   \"71:00:00.12\",   \"71:00:00.123\",   \"71:00:00.1234\",   \"71:00:00.12345\",   \"71:00:00.123456\"),\n    (\"negative_dhu\",   NULL,        \"-71:00:00.1\",  \"-71:00:00.12\",  \"-71:00:00.123\",  \"-71:00:00.1234\",  \"-71:00:00.12345\",  \"-71:00:00.123456\"),\n    (\"mu\",             NULL,        \"00:01:00.1\",   \"00:01:00.12\",   \"00:01:00.123\",   \"00:01:00.1234\",   \"00:01:00.12345\",   \"00:01:00.123456\"),\n    (\"negative_mu\",    NULL,        \"-00:01:00.1\",  \"-00:01:00.12\",  \"-00:01:00.123\",  \"-00:01:00.1234\",  \"-00:01:00.12345\",  \"-00:01:00.123456\"),\n    (\"dmu\",            NULL,        \"48:01:00.1\",   \"48:01:00.12\",   \"48:01:00.123\",   \"48:01:00.1234\",   \"48:01:00.12345\",   \"48:01:00.123456\"),\n    (\"negative_dmu\",   NULL,        \"-48:01:00.1\",  \"-48:01:00.12\",  \"-48:01:00.123\",  \"-48:01:00.1234\",  \"-48:01:00.12345\",  \"-48:01:00.123456\"),\n    (\"hmu\",            NULL,        \"23:01:00.1\",   \"23:01:00.12\",   \"23:01:00.123\",   \"23:01:00.1234\",   \"23:01:00.12345\",   \"23:01:00.123456\"),\n    (\"negative_hmu\",   NULL,        \"-23:01:00.1\",  \"-23:01:00.12\",  \"-23:01:00.123\",  \"-23:01:00.1234\",  \"-23:01:00.12345\",  \"-23:01:00.123456\"),\n    (\"dhmu\",           NULL,        \"71:01:00.1\",   \"71:01:00.12\",   \"71:01:00.123\",   \"71:01:00.1234\",   \"71:01:00.12345\",   \"71:01:00.123456\"),\n    (\"negative_dhmu\",  NULL,        \"-71:01:00.1\",  \"-71:01:00.12\",  \"-71:01:00.123\",  \"-71:01:00.1234\",  \"-71:01:00.12345\",  \"-71:01:00.123456\"),\n    (\"su\",             NULL,        \"00:00:50.1\",   \"00:00:50.12\",   \"00:00:50.123\",   \"00:00:50.1234\",   \"00:00:50.12345\",   \"00:00:50.123456\"),\n    (\"negative_su\",    NULL,        \"-00:00:50.1\",  \"-00:00:50.12\",  \"-00:00:50.123\",  \"-00:00:50.1234\",  \"-00:00:50.12345\",  \"-00:00:50.123456\"),\n    (\"dsu\",            NULL,        \"48:00:50.1\",   \"48:00:50.12\",   \"48:00:50.123\",   \"48:00:50.1234\",   \"48:00:50.12345\",   \"48:00:50.123456\"),\n    (\"negative_dsu\",   NULL,        \"-48:00:50.1\",  \"-48:00:50.12\",  \"-48:00:50.123\",  \"-48:00:50.1234\",  \"-48:00:50.12345\",  \"-48:00:50.123456\"),\n    (\"hsu\",            NULL,        \"23:00:50.1\",   \"23:00:50.12\",   \"23:00:50.123\",   \"23:00:50.1234\",   \"23:00:50.12345\",   \"23:00:50.123456\"),\n    (\"negative_hsu\",   NULL,        \"-23:00:50.1\",  \"-23:00:50.12\",  \"-23:00:50.123\",  \"-23:00:50.1234\",  \"-23:00:50.12345\",  \"-23:00:50.123456\"),\n    (\"dhsu\",           NULL,        \"71:00:50.1\",   \"71:00:50.12\",   \"71:00:50.123\",   \"71:00:50.1234\",   \"71:00:50.12345\",   \"71:00:50.123456\"),\n    (\"negative_dhsu\",  NULL,        \"-71:00:50.1\",  \"-71:00:50.12\",  \"-71:00:50.123\",  \"-71:00:50.1234\",  \"-71:00:50.12345\",  \"-71:00:50.123456\"),\n    (\"msu\",            NULL,        \"00:01:50.1\",   \"00:01:50.12\",   \"00:01:50.123\",   \"00:01:50.1234\",   \"00:01:50.12345\",   \"00:01:50.123456\"),\n    (\"negative_msu\",   NULL,        \"-00:01:50.1\",  \"-00:01:50.12\",  \"-00:01:50.123\",  \"-00:01:50.1234\",  \"-00:01:50.12345\",  \"-00:01:50.123456\"),\n    (\"dmsu\",           NULL,        \"48:01:50.1\",   \"48:01:50.12\",   \"48:01:50.123\",   \"48:01:50.1234\",   \"48:01:50.12345\",   \"48:01:50.123456\"),\n    (\"negative_dmsu\",  NULL,        \"-48:01:50.1\",  \"-48:01:50.12\",  \"-48:01:50.123\",  \"-48:01:50.1234\",  \"-48:01:50.12345\",  \"-48:01:50.123456\"),\n    (\"hmsu\",           NULL,        \"23:01:50.1\",   \"23:01:50.12\",   \"23:01:50.123\",   \"23:01:50.1234\",   \"23:01:50.12345\",   \"23:01:50.123456\"),\n    (\"negative_hmsu\",  NULL,        \"-23:01:50.1\",  \"-23:01:50.12\",  \"-23:01:50.123\",  \"-23:01:50.1234\",  \"-23:01:50.12345\",  \"-23:01:50.123456\"),\n    (\"dhmsu\",          NULL,        \"71:01:50.1\",   \"71:01:50.12\",   \"71:01:50.123\",   \"71:01:50.1234\",   \"71:01:50.12345\",   \"71:01:50.123456\"),\n    (\"negative_dhmsu\", NULL,        \"-71:01:50.1\",  \"-71:01:50.12\",  \"-71:01:50.123\",  \"-71:01:50.1234\",  \"-71:01:50.12345\",  \"-71:01:50.123456\"),\n    (\"min\",           \"-838:59:59\", \"-838:59:58.9\", \"-838:59:58.99\", \"-838:59:58.999\", \"-838:59:58.9999\", \"-838:59:58.99999\", \"-838:59:58.999999\"),\n    (\"max\",           \"838:59:59\",  \"838:59:58.9\",  \"838:59:58.99\",  \"838:59:58.999\",  \"838:59:58.9999\",  \"838:59:58.99999\",  \"838:59:58.999999\")\n;\n\nCREATE TABLE types_string(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_char CHAR(20),\n    field_varchar VARCHAR(30),\n    field_tinytext TINYTEXT,\n    field_text TEXT,\n    field_mediumtext MEDIUMTEXT,\n    field_longtext LONGTEXT,\n    field_text_bincol TEXT CHARACTER SET utf16 COLLATE utf16_bin,\n    field_enum ENUM(\"red\", \"green\", \"blue\"),\n    field_set SET(\"red\", \"green\", \"blue\")\n);\nINSERT INTO types_string VALUES\n    (\"regular\", \"test_char\", \"test_varchar\", \"test_tinytext\", \"test_text\", \"test_mediumtext\", \"test_longtext\", \"test_bincol\", \"red\", \"red,green\"),\n    (\"utf8\",    \"ñ\",         \"Ñ\",            \"á\",             \"é\",         \"í\",               \"ó\",             \"ú\",           NULL,  NULL),\n    (\"empty\",   \"\",          \"\",             \"\",              \"\",          \"\",                \"\",              \"\",            NULL,  \"\")\n;\n\n-- JSON is handled different by MySQL and MariaDB, so a separate table helps tests\n-- Having arrays in the json fields guarantees order, avoiding requiring parsing\n-- the json object to verify equality.\nCREATE TABLE types_json(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_json JSON\n);\nINSERT INTO types_json VALUES\n    (\"regular\",        '[null, 42, false, \"abc\", {\"key\": \"value\"}]'),\n    (\"unicode_escape\", '[\"\\\\u0000value\\\\u0000\"]'),\n    (\"utf8\",           '[\"adiós\"]'),\n    (\"empty\",          '{}')\n;\n\nCREATE TABLE types_binary(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_binary BINARY(10),\n    field_varbinary VARBINARY(30),\n    field_tinyblob TINYBLOB,\n    field_blob BLOB,\n    field_mediumblob MEDIUMBLOB,\n    field_longblob LONGBLOB\n);\nINSERT INTO types_binary VALUES\n    (\"regular\",  \"\\0_binary\", \"\\0_varbinary\", \"\\0_tinyblob\", \"\\0_blob\", \"\\0_mediumblob\", \"\\0_longblob\"),\n    (\"nonascii\", X'00FF',     X'01FE',        X'02FD',       X'03FC',   X'04FB',         X'05FA'),\n    (\"empty\",   \"\",          \"\",             \"\",            \"\",        \"\",              \"\")\n;\n\nCREATE TABLE types_not_implemented(\n    id VARCHAR(50) NOT NULL PRIMARY KEY,\n    field_decimal DECIMAL,\n    field_geometry GEOMETRY\n);\nINSERT INTO types_not_implemented VALUES\n    (\"regular\", 300, POINT(1, 2))\n;\n\nCREATE TABLE types_flags(\n    id VARCHAR(50) NOT NULL,\n    field_timestamp TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n    field_primary_key INT NOT NULL AUTO_INCREMENT,\n    field_not_null CHAR(8) NOT NULL DEFAULT \"\",\n    field_unique INT,\n    field_indexed INT,\n    PRIMARY KEY (field_primary_key, id),\n    UNIQUE KEY (field_unique),\n    KEY (field_indexed)\n);\nINSERT INTO types_flags VALUES\n    (\"default\", NULL, 50, \"char\", 21, 42)\n;\n\n-- Users\nDROP USER IF EXISTS 'integ_user'@'%';\nCREATE USER 'integ_user'@'%' IDENTIFIED BY 'integ_password';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'integ_user'@'%';\n\n-- Some containers don't allow remote root access. Enable it.\nCREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY ''; \nGRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;\n\n-- Stored procedures\nDELIMITER //\n\nCREATE PROCEDURE get_lock_checked(\n    IN lock_name VARCHAR(255),\n    IN timeout_seconds INT\n)\nBEGIN\n    DECLARE lock_status INT;\n    \n    -- Attempt to acquire the lock\n    SELECT GET_LOCK(lock_name, timeout_seconds) INTO lock_status;\n    \n    -- Check if the lock was acquired\n    IF lock_status <> 1 THEN\n        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Failed to acquire lock';\n    END IF;\nEND //\n\nCREATE PROCEDURE sp_insert(IN pin VARCHAR(255))\nBEGIN\n    INSERT INTO inserts_table (field_varchar) VALUES (pin);\nEND //\n\nCREATE PROCEDURE sp_select_1(IN pin VARCHAR(255))\nBEGIN\n    SELECT * FROM one_row_table;\nEND //\n\nCREATE PROCEDURE sp_select_2(IN pin1 VARCHAR(255), IN pin2 INT)\nBEGIN\n    SELECT * FROM one_row_table;\n    SELECT pin1, pin2;\nEND //\n\nCREATE PROCEDURE sp_outparams(\n    IN pin INT,\n    OUT pout INT,\n    INOUT pinout INT\n)\nBEGIN\n    SELECT * FROM one_row_table;\n    SET pout = pin;\n    SET pinout = pinout + 1;\nEND //\n\nCREATE PROCEDURE sp_signal()\nBEGIN\n    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred', MYSQL_ERRNO = 1002;\nEND //\n\nDELIMITER ;\n\nCOMMIT;\nFLUSH PRIVILEGES;"
  },
  {
    "path": "test/integration/db_setup_mnp.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\nUSE boost_mysql_integtests;\n\n-- Setup that requires the presence of the mysql_native_password functionality\nDROP USER IF EXISTS 'mysqlnp_user'@'%';\nCREATE USER 'mysqlnp_user'@'%' IDENTIFIED WITH 'mysql_native_password';\nALTER USER 'mysqlnp_user'@'%' IDENTIFIED BY 'mysqlnp_password';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'mysqlnp_user'@'%';\n\nDROP USER IF EXISTS 'mysqlnp_empty_password_user'@'%';\nCREATE USER 'mysqlnp_empty_password_user'@'%' IDENTIFIED WITH 'mysql_native_password';\nALTER USER 'mysqlnp_empty_password_user'@'%' IDENTIFIED BY '';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'mysqlnp_empty_password_user'@'%';\n\nFLUSH PRIVILEGES;\n"
  },
  {
    "path": "test/integration/db_setup_sha256.sql",
    "content": "--\n-- Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n--\n-- Distributed under the Boost Software License, Version 1.0. (See accompanying\n-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n--\n\nUSE boost_mysql_integtests;\n\n-- Setup that requires the presence of SHA256 functionality\n-- This one is used for unknown authentication plugin tests\nDROP USER IF EXISTS 'sha2p_user'@'%';\nCREATE USER 'sha2p_user'@'%' IDENTIFIED WITH 'sha256_password';\nALTER USER 'sha2p_user'@'%' IDENTIFIED BY 'sha2p_password';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'sha2p_user'@'%';\n\n-- User that uses the caching_sha2_password plugin\nDROP USER IF EXISTS 'csha2p_user'@'%';\nCREATE USER 'csha2p_user'@'%' IDENTIFIED WITH 'caching_sha2_password';\nALTER USER 'csha2p_user'@'%' IDENTIFIED BY 'csha2p_password';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'csha2p_user'@'%';\n\n-- User that uses the caching_sha2_password plugin with an empty password\nDROP USER IF EXISTS 'csha2p_empty_password_user'@'%';\nCREATE USER 'csha2p_empty_password_user'@'%' IDENTIFIED WITH 'caching_sha2_password';\nALTER USER 'csha2p_empty_password_user'@'%' IDENTIFIED BY '';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'csha2p_empty_password_user'@'%';\n\n-- User that uses the caching_sha2_password plugin with a password longer than the scramble\n-- (mora than 20 characters). Relevant for the slow path without TLS\nDROP USER IF EXISTS 'csha2p_long_password_user'@'%';\nCREATE USER 'csha2p_long_password_user'@'%' IDENTIFIED WITH 'caching_sha2_password';\nALTER USER 'csha2p_long_password_user'@'%' IDENTIFIED BY '1234567890abcdefghijklmnopqrstuvwxyz';\nGRANT ALL PRIVILEGES ON boost_mysql_integtests.* TO 'csha2p_long_password_user'@'%';\n\n\n\nFLUSH PRIVILEGES;\n"
  },
  {
    "path": "test/integration/include/test_integration/any_connection_fixture.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_ANY_CONNECTION_FIXTURE_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_ANY_CONNECTION_FIXTURE_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n\n#include <boost/assert/source_location.hpp>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/source_location.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct any_connection_fixture : io_context_fixture\n{\n    any_connection conn;\n\n    any_connection_fixture() : any_connection_fixture(any_connection_params{}) {}\n    any_connection_fixture(any_connection_params params);\n    any_connection_fixture(asio::ssl::context& ssl_ctx);\n    ~any_connection_fixture();\n\n    void connect(const connect_params& params, source_location loc = BOOST_MYSQL_CURRENT_LOCATION);\n    void connect(source_location loc = BOOST_MYSQL_CURRENT_LOCATION);\n    void start_transaction(source_location loc = BOOST_MYSQL_CURRENT_LOCATION);\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/connect_params_builder.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_CONNECT_PARAMS_BUILDER_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_CONNECT_PARAMS_BUILDER_HPP\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <cstdint>\n#include <string>\n\n#include \"test_common/ci_server.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass connect_params_builder\n{\n    handshake_params res_{integ_user, integ_passwd, integ_db};\n    any_address addr_;\n\npublic:\n    connect_params_builder() { addr_.emplace_host_and_port(get_hostname()); }\n\n    connect_params_builder& set_tcp(std::string hostname, unsigned short port)\n    {\n        addr_.emplace_host_and_port(std::move(hostname), port);\n        return *this;\n    }\n\n    connect_params_builder& set_unix()\n    {\n        addr_.emplace_unix_path(default_unix_path);\n        return *this;\n    }\n\n    connect_params_builder& credentials(string_view username, string_view passwd)\n    {\n        res_.set_username(username);\n        res_.set_password(passwd);\n        return *this;\n    }\n\n    connect_params_builder& database(string_view db)\n    {\n        res_.set_database(db);\n        return *this;\n    }\n\n    connect_params_builder& disable_ssl() { return ssl(ssl_mode::disable); }\n\n    connect_params_builder& ssl(ssl_mode ssl)\n    {\n        res_.set_ssl(ssl);\n        return *this;\n    }\n\n    connect_params_builder& multi_queries(bool v)\n    {\n        res_.set_multi_queries(v);\n        return *this;\n    }\n\n    connect_params_builder& collation(std::uint16_t v)\n    {\n        res_.set_connection_collation(v);\n        return *this;\n    }\n\n    handshake_params build_hparams() const { return res_; }\n\n    connect_params build();\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/metadata_validator.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_METADATA_VALIDATOR_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_METADATA_VALIDATOR_HPP\n\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass meta_validator\n{\npublic:\n    using flag_getter = bool (metadata::*)() const;\n    meta_validator(\n        std::string table,\n        std::string field,\n        column_type type,\n        std::vector<flag_getter> flags = {},\n        unsigned decimals = 0,\n        std::vector<flag_getter> ignore_flags = {}\n    )\n        : table_(std::move(table)),\n          org_table_(table_),\n          field_(std::move(field)),\n          org_field_(field_),\n          decimals_(decimals),\n          type_(type),\n          flags_(std::move(flags)),\n          ignore_flags_(std::move(ignore_flags))\n    {\n    }\n    meta_validator(\n        std::string table,\n        std::string org_table,\n        std::string field,\n        std::string org_field,\n        column_type type,\n        std::vector<flag_getter> flags = {},\n        unsigned decimals = 0,\n        std::vector<flag_getter> ignore_flags = {}\n    )\n        : table_(std::move(table)),\n          org_table_(std::move(org_table)),\n          field_(std::move(field)),\n          org_field_(std::move(org_field)),\n          decimals_(decimals),\n          type_(type),\n          flags_(std::move(flags)),\n          ignore_flags_(std::move(ignore_flags))\n    {\n    }\n    void validate(const metadata& value) const;\n    column_type type() const noexcept { return type_; }\n\nprivate:\n    std::string table_;\n    std::string org_table_;\n    std::string field_;\n    std::string org_field_;\n    unsigned decimals_;\n    column_type type_;\n    std::vector<flag_getter> flags_;\n    std::vector<flag_getter> ignore_flags_;\n};\n\nvoid validate_meta(const metadata_collection_view& actual, const std::vector<meta_validator>& expected);\nvoid validate_2fields_meta(metadata_collection_view fields, string_view table);\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif /* TEST_INTEGRATION_METADATA_VALIDATOR_HPP_ */\n"
  },
  {
    "path": "test/integration/include/test_integration/run_coro.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_RUN_CORO_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_RUN_CORO_HPP\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/io_context.hpp>\n\n#include <functional>\n\n#include \"test_common/source_location.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\nvoid run_coro(\n    asio::io_context& ctx,\n    std::function<boost::asio::awaitable<void>(void)> fn,\n    source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n);\n#endif\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/server_ca.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SERVER_CA_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SERVER_CA_HPP\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// The CA file that signed the server's certificate\nconstexpr const char CA_PEM[] = R\"%(-----BEGIN CERTIFICATE-----\nMIIDZzCCAk+gAwIBAgIUWznm2UoxXw3j7HCcp9PpiayTvFQwDQYJKoZIhvcNAQEL\nBQAwQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAMBgNVBAoM\nBW15c3FsMQ4wDAYDVQQDDAVteXNxbDAgFw0yMDA0MDQxNDMwMjNaGA8zMDE5MDgw\nNjE0MzAyM1owQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAM\nBgNVBAoMBW15c3FsMQ4wDAYDVQQDDAVteXNxbDCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAN0WYdvsDb+a0TxOGPejcwZT0zvTrf921mmDUlrLN1Z0hJ/S\nydgQCSD7Q+6za4lTFZCXcvs52xvvS2gfC0yXyYLCT/jA4RQRxuF+/+w1gDWEbGk0\nKzEpsBuKrEIvEaVdoS78SxInnW/aegshdrRRocp4JQ6KHsZgkLTxSwPfYSUmMUo0\ncRO0Q/ak3VK8NP13A6ZFvZjrBxjS3cSw9HqilgADcyj1D4EokvfI1C9LrgwgLlZC\nXVkjjBqqoMXGGlnXOEK+pm8bU68HM/QvMBkb1Amo8pioNaaYgqJUCP0Ch0iu1nUU\nHtsWt6emXv0jANgIW0oga7xcT4MDGN/M+IRWLTECAwEAAaNTMFEwHQYDVR0OBBYE\nFNxhaGwf5ePPhzK7yOAKD3VF6wm2MB8GA1UdIwQYMBaAFNxhaGwf5ePPhzK7yOAK\nD3VF6wm2MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAoeJCAX\nIDCFoAaZoQ1niI6Ac/cds8G8It0UCcFGSg+HrZ0YujJxWIruRCUG60Q2OAbEvn0+\nuRpTm+4tV1Wt92WFeuRyqkomozx0g4CyfsxGX/x8mLhKPFK/7K9iTXM4/t+xQC4f\nJ+iRmPVsMKQ8YsHYiWVhlOMH9XJQiqERCB2kOKJCH6xkaF2k0GbM2sGgbS7Z6lrd\nfsFTOIVx0VxLVsZnWX3byE9ghnDR5jn18u30Cpb/R/ShxNUGIHqRa4DkM5la6uZX\nW1fpSW11JBSUv4WnOO0C2rlIu7UJWOROqZZ0OsybPRGGwagcyff2qVRuI2XFvAMk\nOzBrmpfHEhF6NDU=\n-----END CERTIFICATE-----\n)%\";\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/server_features.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SERVER_FEATURES_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SERVER_FEATURES_HPP\n\n#include <boost/test/tree/decorator.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// What does the CI server deployment support?\n// We determine these from the command line arguments.\nstruct server_features\n{\n    // Is the server listening on a UNIX socket?\n    bool unix_sockets{true};\n\n    // Does the server support sha256 authentication methods?\n    // Includes caching_sha2_password and sha256_password\n    bool sha256{true};\n\n    // Does the server support the mysql_native_password authentication method?\n    bool mnp{true};\n\n    // Does the server support the dedicated JSON type?\n    bool json_type{true};\n\n    // Does the server support MySQL8+ specific regex error codes?\n    bool regex_error_codes{true};\n\n    // Does the server support MariaDB specific dup_query error codes?\n    bool dup_query_error_codes{true};\n};\n\nusing server_feature_t = bool server_features::*;\n\nserver_features get_server_features();\n\n// Decorators to skip tests if the given features are not enabled.\n// This is lazy because get_server_features requires access to getenv, not legal from global initializers.\nunit_test::precondition run_if(server_feature_t feature);\nunit_test::precondition run_if(server_feature_t feature1, server_feature_t feature2);\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/snippets/credentials.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_CREDENTIALS_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_CREDENTIALS_HPP\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nconstexpr const char* mysql_username = \"example_user\";\nconstexpr const char* mysql_password = \"example_password\";\nconstexpr const char* example_db = \"boost_mysql_examples\";\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/snippets/describe.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_DESCRIBE_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_DESCRIBE_HPP\n\n#include <boost/describe/class.hpp>\n#include <boost/optional/optional.hpp>\n\n#include <cstdint>\n#include <string>\n#include <tuple>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n//[describe_post\n// We can use a plain struct with ints and strings to describe our rows.\n// This must be placed at the namespace level\nstruct post\n{\n    int id;\n    std::string title;\n    std::string body;\n};\n\n// We use BOOST_DESCRIBE_STRUCT to add reflection capabilities to post.\n// We must list all the fields that should be populated by Boost.MySQL\nBOOST_DESCRIBE_STRUCT(post, (), (id, title, body))\n//]\n\n//[describe_stored_procedures\n// Describes the first resultset\nstruct company\n{\n    std::string id;\n    std::string name;\n    std::string tax_id;\n};\nBOOST_DESCRIBE_STRUCT(company, (), (id, name, tax_id))\n\n// Describes the second resultset\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n    boost::optional<std::uint64_t> salary;\n};\nBOOST_DESCRIBE_STRUCT(employee, (), (first_name, last_name, salary))\n\n// The last resultset will always be empty.\n// We can use an empty tuple to represent it.\nusing empty = std::tuple<>;\n//]\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/snippets/get_any_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_GET_ANY_CONNECTION_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_GET_ANY_CONNECTION_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct any_connection_and_context\n{\n    asio::io_context ctx;\n    any_connection conn{ctx.get_executor()};\n\n    any_connection_and_context()\n    {\n        // Connect\n        boost::mysql::connect_params params;\n        params.server_address.emplace_host_and_port(get_hostname());\n        params.username = mysql_username;\n        params.password = mysql_password;\n        params.database = \"boost_mysql_examples\";\n        params.ssl = ssl_mode::disable;\n        params.multi_queries = true;\n        conn.connect(params);\n    }\n};\n\ninline any_connection& get_any_connection()\n{\n    static any_connection_and_context obj;\n    return obj.conn;\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/snippets/get_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_GET_CONNECTION_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_GET_CONNECTION_HPP\n\n#include <boost/mysql/tcp.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct connection_and_context\n{\n    asio::io_context ctx;\n    tcp_connection conn{ctx.get_executor()};\n\n    connection_and_context()\n    {\n        // Resolve the hostname to get a collection of endpoints\n        boost::asio::ip::tcp::resolver resolver(ctx.get_executor());\n        auto endpoints = resolver.resolve(get_hostname(), boost::mysql::default_port_string);\n\n        // Connect\n        boost::mysql::handshake_params params(mysql_username, mysql_password, \"boost_mysql_examples\");\n        conn.connect(*endpoints.begin(), params);\n    }\n};\n\ninline tcp_connection& get_connection()\n{\n    static connection_and_context obj;\n    return obj.conn;\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/snippets/snippets_fixture.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_SNIPPETS_FIXTURE_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SNIPPETS_SNIPPETS_FIXTURE_HPP\n\n#include <boost/mysql/connect_params.hpp>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline connect_params snippets_connect_params()\n{\n    connect_params params;\n    params.server_address.emplace_host_and_port(get_hostname());\n    params.username = mysql_username;\n    params.password = mysql_password;\n    params.database = \"boost_mysql_examples\";\n    params.ssl = ssl_mode::disable;\n    params.multi_queries = true;\n    return params;\n}\n\nstruct snippets_fixture : any_connection_fixture\n{\n    snippets_fixture() { connect(snippets_connect_params()); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/spotchecks_helpers.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SPOTCHECKS_HELPERS_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_SPOTCHECKS_HELPERS_HPP\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/tcp.hpp>\n\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/core/span.hpp>\n\n#include <iosfwd>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/netfun_maker.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/static_rows.hpp\"\n#include \"test_integration/tcp_connection_fixture.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n#ifdef BOOST_MYSQL_CXX14\nusing static_state_t = static_execution_state<row_multifield>;\n#endif\n\n// Netmakers\ntemplate <class Conn>\nstruct netmakers_common\n{\n    using prepare_statement = netfun_maker<statement, Conn, string_view>;\n    using execute_query = netfun_maker<void, Conn, const string_view&, results&>;\n    using execute_statement = netfun_maker<\n        void,\n        Conn,\n        const bound_statement_tuple<std::tuple<int, int>>&,\n        results&>;\n    using start_execution = netfun_maker<void, Conn, const string_view&, execution_state&>;\n    using close_statement = netfun_maker<void, Conn, const statement&>;\n    using read_resultset_head = netfun_maker<void, Conn, execution_state&>;\n    using read_some_rows = netfun_maker<rows_view, Conn, execution_state&>;\n    using ping = netfun_maker<void, Conn>;\n    using reset_connection = netfun_maker<void, Conn>;\n    using close = netfun_maker<void, Conn>;\n\n#ifdef BOOST_MYSQL_CXX14\n    using start_execution_static = netfun_maker<void, Conn, const string_view&, static_state_t&>;\n    using read_some_rows_static = netfun_maker<\n        std::size_t,\n        Conn,\n        static_state_t&,\n        boost::span<row_multifield>>;\n#endif\n};\n\nstruct netmakers_connection : netmakers_common<tcp_connection>\n{\n    using connect_stream = netfun_maker<void, asio::ip::tcp::socket, const asio::ip::tcp::endpoint&>;\n    using handshake = netfun_maker<void, tcp_connection, const handshake_params&>;\n    using connect = netfun_maker<\n        void,\n        tcp_connection,\n        const asio::ip::tcp::endpoint&,\n        const handshake_params&>;\n    using quit = netfun_maker<void, tcp_connection>;\n};\n\nstruct netmakers_any : netmakers_common<any_connection>\n{\n    using connect = netfun_maker<void, any_connection, const connect_params&>;\n    using set_character_set = netfun_maker<void, any_connection, const character_set&>;\n    using run_pipeline = netfun_maker<\n        void,\n        any_connection,\n        const pipeline_request&,\n        std::vector<stage_response>&>;\n};\n\nstruct network_functions_connection\n{\n    using netmakers = netmakers_connection;\n\n    string_view name;\n    netmakers::prepare_statement::signature prepare_statement;\n    netmakers::execute_query::signature execute_query;\n    netmakers::execute_statement::signature execute_statement;\n    netmakers::start_execution::signature start_execution;\n    netmakers::close_statement::signature close_statement;\n    netmakers::read_resultset_head::signature read_resultset_head;\n    netmakers::read_some_rows::signature read_some_rows;\n    netmakers::ping::signature ping;\n    netmakers::reset_connection::signature reset_connection;\n    netmakers::close::signature close;\n#ifdef BOOST_MYSQL_CXX14\n    netmakers::start_execution_static::signature start_execution_static;\n    netmakers::read_some_rows_static::signature read_some_rows_static;\n#endif\n    netmakers::connect_stream::signature connect_stream;\n    netmakers::handshake::signature handshake;\n    netmakers::connect::signature connect;\n    netmakers::quit::signature quit;\n\n    static std::vector<network_functions_connection> all();\n    static std::vector<network_functions_connection> sync_and_async();\n};\nstd::ostream& operator<<(std::ostream& os, const network_functions_connection& v);\n\nstruct network_functions_any\n{\n    using netmakers = netmakers_any;\n\n    string_view name;\n    netmakers::prepare_statement::signature prepare_statement;\n    netmakers::execute_query::signature execute_query;\n    netmakers::execute_statement::signature execute_statement;\n    netmakers::start_execution::signature start_execution;\n    netmakers::close_statement::signature close_statement;\n    netmakers::read_resultset_head::signature read_resultset_head;\n    netmakers::read_some_rows::signature read_some_rows;\n    netmakers::ping::signature ping;\n    netmakers::reset_connection::signature reset_connection;\n    netmakers::close::signature close;\n#ifdef BOOST_MYSQL_CXX14\n    netmakers::start_execution_static::signature start_execution_static;\n    netmakers::read_some_rows_static::signature read_some_rows_static;\n#endif\n    netmakers::connect::signature connect;\n    netmakers::set_character_set::signature set_character_set;\n    netmakers::run_pipeline::signature run_pipeline;\n\n    static std::vector<network_functions_any> all();\n    static std::vector<network_functions_any> sync_and_async();\n};\nstd::ostream& operator<<(std::ostream& os, const network_functions_any& v);\n\n// Fixtures. Like tcp_connection_fixture and any_connection_fixture,\n// but using a network_functions value\nstruct netfn_fixture_connection : io_context_fixture\n{\n    tcp_connection conn{ctx};\n    network_functions_connection net;\n\n    netfn_fixture_connection(network_functions_connection n) : net(std::move(n))\n    {\n        conn.set_meta_mode(metadata_mode::full);\n    }\n    ~netfn_fixture_connection() { net.close(conn).validate_no_error(); }\n\n    void connect(connect_params_builder conn_params = {})\n    {\n        net.connect(conn, get_tcp_endpoint(), conn_params.build_hparams()).validate_no_error();\n    }\n};\n\nstruct netfn_fixture_any : io_context_fixture\n{\n    any_connection conn{ctx};\n    network_functions_any net;\n\n    netfn_fixture_any(network_functions_any n) : net(std::move(n))\n    {\n        conn.set_meta_mode(metadata_mode::full);\n    }\n    ~netfn_fixture_any() { net.close(conn).validate_no_error(); }\n\n    void connect(connect_params_builder conn_params = {})\n    {\n        net.connect(conn, conn_params.build()).validate_no_error();\n    }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/static_rows.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_STATIC_ROWS_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_STATIC_ROWS_HPP\n\n#include <boost/describe/class.hpp>\n#include <boost/describe/operators.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/optional/optional_io.hpp>\n\n#include <tuple>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct row_multifield\n{\n    boost::optional<float> field_nullable;\n    std::int32_t field_int;\n    std::string field_varchar;\n};\nBOOST_DESCRIBE_STRUCT(row_multifield, (), (field_nullable, field_int, field_varchar))\n\nstruct row_multifield_bad\n{\n    std::string field_varchar;\n    float field_nullable;\n    std::string field_int;\n    int field_missing;\n};\nBOOST_DESCRIBE_STRUCT(row_multifield_bad, (), (field_varchar, field_nullable, field_int, field_missing))\n\nstruct row_2fields\n{\n    boost::optional<int> id;\n    boost::optional<std::string> field_varchar;\n};\nBOOST_DESCRIBE_STRUCT(row_2fields, (), (id, field_varchar))\n\nusing empty = std::tuple<>;\n\n#ifdef BOOST_DESCRIBE_CXX14\nusing boost::describe::operators::operator==;\nusing boost::describe::operators::operator<<;\n#endif\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/integration/include/test_integration/tcp_connection_fixture.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_TCP_CONNECTION_FIXTURE_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_INCLUDE_TEST_INTEGRATION_TCP_CONNECTION_FIXTURE_HPP\n\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/tcp.hpp>\n\n#include <boost/assert/source_location.hpp>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/source_location.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct tcp_connection_fixture : io_context_fixture\n{\n    tcp_connection conn;\n\n    tcp_connection_fixture();\n    ~tcp_connection_fixture();\n\n    void connect(source_location loc = BOOST_MYSQL_CURRENT_LOCATION);\n    void connect(const handshake_params&, source_location loc = BOOST_MYSQL_CURRENT_LOCATION);\n};\n\nasio::ip::tcp::endpoint get_tcp_endpoint();\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "test/integration/pch.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_INTEGRATION_PCH_HPP\n#define BOOST_MYSQL_TEST_INTEGRATION_PCH_HPP\n\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/ssl/stream.hpp>\n#include <boost/assert/source_location.hpp>\n#include <boost/config.hpp>\n#include <boost/core/detail/string_view.hpp>\n#include <boost/core/span.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/describe/members.hpp>\n#include <boost/mp11.hpp>\n#include <boost/system/error_category.hpp>\n#include <boost/system/error_code.hpp>\n#include <boost/system/result.hpp>\n#include <boost/system/system_error.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/throw_exception.hpp>\n#include <boost/variant2/variant.hpp>\n\n#include <cassert>\n#include <chrono>\n#include <cstddef>\n#include <cstdint>\n#include <cstdlib>\n#include <cstring>\n#include <functional>\n#include <iterator>\n#include <ostream>\n#include <stdexcept>\n#include <string>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#endif\n"
  },
  {
    "path": "test/integration/src/metadata_validator.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_integration/metadata_validator.hpp\"\n\nusing namespace boost::mysql::test;\n\n#define MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(getter) \\\n    {                                             \\\n        #getter, &boost::mysql::metadata::getter  \\\n    }\n\nstatic struct flag_entry\n{\n    const char* name;\n    meta_validator::flag_getter getter;\n} flag_names[] = {\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_not_null),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_primary_key),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_unique_key),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_multiple_key),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_unsigned),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_zerofill),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_auto_increment),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(has_no_default_value),\n    MYSQL_TEST_FLAG_GETTER_NAME_ENTRY(is_set_to_now_on_update)\n};\n\nBOOST_TEST_DONT_PRINT_LOG_VALUE(std::vector<flag_entry>::iterator)\n\nstatic bool contains(\n    meta_validator::flag_getter flag,\n    const std::vector<meta_validator::flag_getter>& flagvec\n)\n{\n    return std::find(flagvec.begin(), flagvec.end(), flag) != flagvec.end();\n}\n\nvoid meta_validator::validate(const boost::mysql::metadata& value) const\n{\n    // Fixed fields\n    BOOST_TEST(value.database() == \"boost_mysql_integtests\");\n    BOOST_TEST(value.table() == table_);\n    BOOST_TEST(value.original_table() == org_table_);\n    BOOST_TEST(value.column_name() == field_);\n    BOOST_TEST(value.original_column_name() == org_field_);\n    BOOST_TEST(value.column_length() > 0u);\n    BOOST_TEST(value.type() == type_);\n    BOOST_TEST(value.decimals() == decimals_);\n\n    // Flags\n    std::vector<flag_entry> all_flags(std::begin(flag_names), std::end(flag_names));\n\n    for (flag_getter true_flag : flags_)\n    {\n        auto it = std::find_if(all_flags.begin(), all_flags.end(), [true_flag](const flag_entry& entry) {\n            return entry.getter == true_flag;\n        });\n        BOOST_TEST_REQUIRE(it != all_flags.end());                // no repeated flag\n        BOOST_TEST_REQUIRE(!contains(true_flag, ignore_flags_));  // ignore flags cannot be set to true\n        BOOST_TEST((value.*true_flag)(), it->name);\n        all_flags.erase(it);\n    }\n\n    for (const auto& entry : all_flags)\n    {\n        if (!contains(entry.getter, ignore_flags_))\n        {\n            BOOST_TEST(!(value.*entry.getter)(), entry.name);\n        }\n    }\n}\n\nvoid boost::mysql::test::validate_meta(\n    const metadata_collection_view& actual,\n    const std::vector<meta_validator>& expected\n)\n{\n    BOOST_TEST_REQUIRE(actual.size() == expected.size());\n    for (std::size_t i = 0; i < actual.size(); ++i)\n    {\n        expected[i].validate(actual[i]);\n    }\n}\n\nvoid boost::mysql::test::validate_2fields_meta(metadata_collection_view fields, string_view table)\n{\n    validate_meta(\n        fields,\n        {meta_validator(table, \"id\", column_type::int_),\n         meta_validator(table, \"field_varchar\", column_type::varchar)}\n    );\n}\n"
  },
  {
    "path": "test/integration/src/server_features.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/framework.hpp>\n#include <boost/test/tools/assertion_result.hpp>\n\n#include <algorithm>\n#include <iostream>\n#include <iterator>\n#include <vector>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/server_features.hpp\"\n\nusing namespace boost::mysql;\n\nstatic std::vector<string_view> split_list(string_view s)\n{\n    std::vector<string_view> res;\n    std::size_t pos = 0;\n    if (!s.empty())\n    {\n        while ((pos = s.find(' ')) != string_view::npos)\n        {\n            res.push_back(s.substr(0, pos));\n            s = s.substr(pos + 1);\n        }\n        res.push_back(s);\n    }\n    return res;\n}\n\nstatic test::server_features do_get_server_features()\n{\n    // Get the disabled feature list from the environment variable\n    auto disabled_features_str = test::safe_getenv(\"BOOST_MYSQL_DISABLED_SERVER_FEATURES\", \"\");\n\n    // Parse the disabled features list\n    auto disabled_features = split_list(disabled_features_str);\n\n    // The list of possible features\n    const struct possible_feature_t\n    {\n        string_view name;\n        test::server_feature_t ptr;\n    } possible_features[]{\n        {\"unix-sockets\",          &test::server_features::unix_sockets         },\n        {\"sha256\",                &test::server_features::sha256               },\n        {\"json-type\",             &test::server_features::json_type            },\n        {\"regex-error-codes\",     &test::server_features::regex_error_codes    },\n        {\"dup-query-error-codes\", &test::server_features::dup_query_error_codes},\n        {\"mnp\",                   &test::server_features::mnp                  },\n    };\n\n    // Match disabled features against the possible set\n    test::server_features res;\n    for (auto feature : disabled_features)\n    {\n        auto it = std::find_if(\n            std::begin(possible_features),\n            std::end(possible_features),\n            [feature](possible_feature_t v) { return v.name == feature; }\n        );\n        if (it == std::end(possible_features))\n        {\n            std::cerr << \"Unknown disabled feature: \" << feature << std::endl;\n            exit(1);\n        }\n        res.*it->ptr = false;\n    }\n\n    // Report the configuration\n    std::cout << \"Server features:\\n\";\n    for (auto feature : possible_features)\n    {\n        std::cout << \"+ \" << feature.name << \": \" << res.*feature.ptr << '\\n';\n    }\n    std::cout << '\\n';\n\n    // Done\n    return res;\n}\n\nboost::mysql::test::server_features boost::mysql::test::get_server_features()\n{\n    static server_features res = do_get_server_features();\n    return res;\n}\n\nboost::unit_test::precondition boost::mysql::test::run_if(server_feature_t feature)\n{\n    return unit_test::precondition([feature](unit_test::test_unit_id) {\n        return get_server_features().*feature;\n    });\n}\n\nboost::unit_test::precondition boost::mysql::test::run_if(\n    server_feature_t feature1,\n    server_feature_t feature2\n)\n{\n    return unit_test::precondition([=](unit_test::test_unit_id) {\n        const auto supported = get_server_features();\n        return supported.*feature1 && supported.*feature2;\n    });\n}\n"
  },
  {
    "path": "test/integration/src/spotchecks_helpers.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/ip/tcp.hpp>\n\n#include <ostream>\n#include <utility>\n\n#include \"test_integration/spotchecks_helpers.hpp\"\n\nusing namespace boost::mysql::test;\n\n// Network functions\n#define BOOST_MYSQL_MAKE_NETFN(conn, netm, fn, i)              \\\n    (i == 0   ? netmakers::netm::sync_errc(&conn::fn)          \\\n     : i == 1 ? netmakers::netm::sync_exc(&conn::fn)           \\\n     : i == 2 ? netmakers::netm::async_diag(&conn::async_##fn) \\\n              : netmakers::netm::async_nodiag(&conn::async_##fn))\n\nstatic constexpr const char* fn_names[] = {\"sync_errc\", \"sync_exc\", \"async_diag\", \"async_nodiag\"};\n\nstd::vector<network_functions_connection> boost::mysql::test::network_functions_connection::all()\n{\n    std::vector<network_functions_connection> res;\n\n    for (std::size_t i = 0; i < 4; ++i)\n    {\n        // connect_stream doesn't involve diagnostics\n        auto fn_connect_stream = (i == 0 || i == 1) ? netmakers::connect_stream::sync_errc_nodiag(\n                                                          &asio::ip::tcp::socket::connect\n                                                      )\n                                                    : netmakers::connect_stream::async_nodiag(\n                                                          &asio::ip::tcp::socket::async_connect\n                                                      );\n\n        res.push_back({\n            fn_names[i],\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, prepare_statement, prepare_statement, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, execute_query, execute, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, execute_statement, execute, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, start_execution, start_execution, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, close_statement, close_statement, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, read_resultset_head, read_resultset_head, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, read_some_rows, read_some_rows, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, ping, ping, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, reset_connection, reset_connection, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, close, close, i),\n#ifdef BOOST_MYSQL_CXX14\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, start_execution_static, start_execution, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, read_some_rows_static, read_some_rows, i),\n#endif\n            std::move(fn_connect_stream),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, handshake, handshake, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, connect, connect, i),\n            BOOST_MYSQL_MAKE_NETFN(tcp_connection, quit, quit, i),\n        });\n    }\n\n    return res;\n}\n\nstd::vector<network_functions_connection> boost::mysql::test::network_functions_connection::sync_and_async()\n{\n    auto all_fns = all();\n    return {std::move(all_fns[0]), std::move(all_fns[2])};\n}\n\nstd::ostream& boost::mysql::test::operator<<(std::ostream& os, const network_functions_connection& v)\n{\n    return os << v.name;\n}\n\nstd::vector<network_functions_any> boost::mysql::test::network_functions_any::all()\n{\n    std::vector<network_functions_any> res;\n\n    for (std::size_t i = 0; i < 4; ++i)\n    {\n        res.push_back({\n            fn_names[i],\n            BOOST_MYSQL_MAKE_NETFN(any_connection, prepare_statement, prepare_statement, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, execute_query, execute, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, execute_statement, execute, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, start_execution, start_execution, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, close_statement, close_statement, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, read_resultset_head, read_resultset_head, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, read_some_rows, read_some_rows, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, ping, ping, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, reset_connection, reset_connection, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, close, close, i),\n#ifdef BOOST_MYSQL_CXX14\n            BOOST_MYSQL_MAKE_NETFN(any_connection, start_execution_static, start_execution, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, read_some_rows_static, read_some_rows, i),\n#endif\n            BOOST_MYSQL_MAKE_NETFN(any_connection, connect, connect, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, set_character_set, set_character_set, i),\n            BOOST_MYSQL_MAKE_NETFN(any_connection, run_pipeline, run_pipeline, i),\n        });\n    }\n\n    return res;\n}\n\nstd::vector<network_functions_any> boost::mysql::test::network_functions_any::sync_and_async()\n{\n    auto all_fns = all();\n    return {std::move(all_fns[0]), std::move(all_fns[2])};\n}\n\nstd::ostream& boost::mysql::test::operator<<(std::ostream& os, const network_functions_any& v)\n{\n    return os << v.name;\n}"
  },
  {
    "path": "test/integration/src/utils.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/handshake_params.hpp>\n\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/assert/source_location.hpp>\n\n#include <exception>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/tcp_connection_fixture.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\n\n//\n// any_connection_fixture.hpp\n//\nstatic any_connection_params make_params(asio::ssl::context& ssl_ctx)\n{\n    any_connection_params res;\n    res.ssl_context = &ssl_ctx;\n    return res;\n}\n\nany_connection_fixture::any_connection_fixture(any_connection_params params) : conn(ctx, params)\n{\n    conn.set_meta_mode(metadata_mode::full);\n}\n\nany_connection_fixture::any_connection_fixture(asio::ssl::context& ssl_ctx)\n    : any_connection_fixture(make_params(ssl_ctx))\n{\n}\n\nany_connection_fixture::~any_connection_fixture() { conn.async_close(as_netresult).validate_no_error(); }\n\nvoid any_connection_fixture::connect(const connect_params& params, boost::source_location loc)\n{\n    conn.async_connect(params, as_netresult).validate_no_error(loc);\n}\n\nvoid any_connection_fixture::connect(boost::source_location loc)\n{\n    connect(connect_params_builder().ssl(ssl_mode::disable).build(), loc);\n}\n\nvoid any_connection_fixture::start_transaction(boost::source_location loc)\n{\n    results r;\n    conn.async_execute(\"START TRANSACTION\", r, as_netresult).validate_no_error(loc);\n}\n\n//\n// tcp_connection_fixture.hpp\n//\nstatic asio::ip::tcp::endpoint resolve_server_endpoint()\n{\n    asio::io_context ctx;\n    asio::ip::tcp::resolver resolver(ctx);\n    auto results = resolver.resolve(get_hostname(), default_port_string);\n    return *results.begin();\n}\n\ntcp_connection_fixture::tcp_connection_fixture() : conn(ctx) { conn.set_meta_mode(metadata_mode::full); }\n\ntcp_connection_fixture::~tcp_connection_fixture() { conn.async_close(as_netresult).validate_no_error(); }\n\nvoid tcp_connection_fixture::connect(boost::source_location loc)\n{\n    connect(connect_params_builder().build_hparams(), loc);\n}\n\nvoid tcp_connection_fixture::connect(const handshake_params& params, boost::source_location loc)\n{\n    conn.async_connect(get_tcp_endpoint(), params, as_netresult).validate_no_error(loc);\n}\n\nasio::ip::tcp::endpoint boost::mysql::test::get_tcp_endpoint()\n{\n    static auto res = resolve_server_endpoint();\n    return res;\n}\n\n//\n// connect_params_builder.hpp\n//\nconnect_params connect_params_builder::build()\n{\n    connect_params res;\n    res.server_address = std::move(addr_);\n    res.username = res_.username();\n    res.password = res_.password();\n    res.database = res_.database();\n    res.multi_queries = res_.multi_queries();\n    res.ssl = res_.ssl();\n    res.connection_collation = res_.connection_collation();\n    return res;\n}\n\n//\n// run_coro.hpp\n//\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\nvoid boost::mysql::test::run_coro(\n    asio::io_context& ctx,\n    std::function<boost::asio::awaitable<void>(void)> fn,\n    source_location loc\n)\n{\n    bool done = false;\n    boost::asio::co_spawn(ctx, fn, [&](std::exception_ptr ptr) {\n        done = true;\n        if (ptr)\n        {\n            std::rethrow_exception(ptr);\n        }\n    });\n    poll_until(ctx, &done, loc);\n}\n#endif"
  },
  {
    "path": "test/integration/test/any_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/engine_impl.hpp>\n\n#include <boost/mysql/impl/internal/variant_stream.hpp>\n\n#include <boost/asio/as_tuple.hpp>\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/local/basic_endpoint.hpp>\n#include <boost/asio/redirect_error.hpp>\n#include <boost/test/data/test_case.hpp>\n\n#include <chrono>\n#include <string>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/server_features.hpp\"\n#include \"test_integration/spotchecks_helpers.hpp\"\n\n// Additional spotchecks for any_connection\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing boost::test_tools::per_element;\n\nBOOST_AUTO_TEST_SUITE(test_any_connection)\n\n// any_connection can be used with UNIX sockets\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_DATA_TEST_CASE(unix_sockets, network_functions_any::sync_and_async())\n{\n    // Setup\n    netfn_fixture_any fix(sample);\n\n    // Connect\n    fix.connect(connect_params_builder().set_unix());\n    BOOST_TEST(!fix.conn.uses_ssl());\n\n    // We can prepare statements\n    auto stmt = fix.net.prepare_statement(fix.conn, \"SELECT ?, ?\").get();\n    BOOST_TEST(stmt.num_params() == 2u);\n\n    // We can execute queries\n    results r;\n    fix.net.execute_query(fix.conn, \"SELECT 'abc'\", r).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, \"abc\"), per_element());\n\n    // We can execute statements\n    fix.net.execute_statement(fix.conn, stmt.bind(42, 100), r).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 42, 100), per_element());\n\n    // We can get errors\n    fix.net.execute_query(fix.conn, \"SELECT * FROM bad_table\", r)\n        .validate_error(\n            common_server_errc::er_no_such_table,\n            \"Table 'boost_mysql_integtests.bad_table' doesn't exist\"\n        );\n\n    // We can terminate the connection\n    fix.net.close(fix.conn).validate_no_error();\n}\n#else\nBOOST_DATA_TEST_CASE(unix_sockets_not_supported, network_functions_any::sync_and_async())\n{\n    // Setup\n    netfn_fixture_any fix(sample);\n\n    // Attempting to connect yields an error\n    fix.net.connect(fix.conn, connect_params_builder().set_unix().build())\n        .validate_error(asio::error::operation_not_supported);\n}\n#endif\n\n// Backslash escapes\nBOOST_FIXTURE_TEST_CASE(backslash_escapes, any_connection_fixture)\n{\n    // Backslash escapes enabled by default\n    BOOST_TEST(conn.backslash_escapes());\n\n    // Connect doesn't change the value\n    conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n    BOOST_TEST(conn.backslash_escapes());\n    BOOST_TEST(conn.format_opts()->backslash_escapes);\n\n    // Setting the SQL mode to NO_BACKSLASH_ESCAPES updates the value\n    results r;\n    conn.async_execute(\"SET sql_mode = 'NO_BACKSLASH_ESCAPES'\", r, as_netresult).validate_no_error();\n    BOOST_TEST(!conn.backslash_escapes());\n    BOOST_TEST(!conn.format_opts()->backslash_escapes);\n\n    // Executing a different statement doesn't change the value\n    conn.async_execute(\"SELECT 1\", r, as_netresult).validate_no_error();\n    BOOST_TEST(!conn.backslash_escapes());\n    BOOST_TEST(!conn.format_opts()->backslash_escapes);\n\n    // Clearing the SQL mode updates the value\n    conn.async_execute(\"SET sql_mode = ''\", r, as_netresult).validate_no_error();\n    BOOST_TEST(conn.backslash_escapes());\n    BOOST_TEST(conn.format_opts()->backslash_escapes);\n\n    // Reconnecting clears the value\n    conn.async_execute(\"SET sql_mode = 'NO_BACKSLASH_ESCAPES'\", r, as_netresult).validate_no_error();\n    BOOST_TEST(!conn.backslash_escapes());\n    BOOST_TEST(!conn.format_opts()->backslash_escapes);\n    conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n    BOOST_TEST(conn.backslash_escapes());\n    BOOST_TEST(conn.format_opts()->backslash_escapes);\n}\n\n// Max buffer sizes\nBOOST_AUTO_TEST_CASE(max_buffer_size_success)\n{\n    // Create the connection\n    any_connection_params params;\n    params.initial_buffer_size = 512u;\n    params.max_buffer_size = 512u;\n    any_connection_fixture fix(params);\n\n    // Connect\n    fix.conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n\n    // Reading and writing almost 512 bytes works\n    results r;\n    auto q = format_sql(fix.conn.format_opts().value(), \"SELECT {}\", std::string(450, 'a'));\n    fix.conn.async_execute(q, r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, std::string(450, 'a')), per_element());\n}\n\nBOOST_AUTO_TEST_CASE(max_buffer_size_write_error)\n{\n    // Create the connection\n    any_connection_params params;\n    params.initial_buffer_size = 512u;\n    params.max_buffer_size = 512u;\n    any_connection_fixture fix(params);\n\n    // Connect\n    fix.conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n\n    // Trying to write more than 512 bytes fails\n    results r;\n    auto q = format_sql(fix.conn.format_opts().value(), \"SELECT LENGTH({})\", std::string(512, 'a'));\n    fix.conn.async_execute(q, r, as_netresult).validate_error(client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_CASE(max_buffer_size_read_error)\n{\n    // Create the connection\n    any_connection_params params;\n    params.initial_buffer_size = 512u;\n    params.max_buffer_size = 512u;\n    any_connection_fixture fix(params);\n\n    // Connect\n    fix.conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n\n    // Trying to read more than 512 bytes fails\n    results r;\n    fix.conn.async_execute(\"SELECT REPEAT('a', 512)\", r, as_netresult)\n        .validate_error(client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_FIXTURE_TEST_CASE(default_max_buffer_size_success, any_connection_fixture)\n{\n    // Connect\n    conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n\n    // Reading almost max_buffer_size works\n    execution_state st;\n    conn.async_start_execution(\"SELECT 1, REPEAT('a', 0x3f00000)\", st, as_netresult).validate_no_error();\n    auto rws = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rws.at(0).at(1).as_string().size() == 0x3f00000u);\n}\n\nBOOST_FIXTURE_TEST_CASE(default_max_buffer_size_error, any_connection_fixture)\n{\n    // Connect\n    conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n\n    // Trying to read more than max_buffer_size bytes fails\n    results r;\n    conn.async_execute(\"SELECT 1, REPEAT('a', 0x4000000)\", r, as_netresult)\n        .validate_error(client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_DATA_TEST_CASE(naggle_disabled, network_functions_any::sync_and_async())\n{\n    // Setup\n    netfn_fixture_any fix(sample);\n\n    // Connect\n    fix.net.connect(fix.conn, connect_params_builder().disable_ssl().build()).validate_no_error();\n\n    // Naggle's algorithm was disabled\n    asio::ip::tcp::no_delay opt;\n    static_cast<detail::engine_impl<detail::variant_stream>&>(detail::access::get_impl(fix.conn).get_engine())\n        .stream()\n        .socket()\n        .get_option(opt);\n    BOOST_TEST(opt.value() == true);\n}\n\n// Regression test: using a non-connected connection doesn't crash\nBOOST_FIXTURE_TEST_CASE(using_non_connected_connection, any_connection_fixture)\n{\n    conn.async_ping(as_netresult).validate_error(client_errc::not_connected);\n}\n\n// Spotcheck: we can use cancel_after and other tokens\n// that require initiations to have an associated executor\nBOOST_FIXTURE_TEST_CASE(cancel_after, any_connection_fixture)\n{\n    // The token to use\n    const auto token = asio::cancel_after(std::chrono::seconds(10), asio::deferred);\n\n    // Connect\n    conn.async_connect(connect_params_builder().build(), token)(as_netresult).validate_no_error();\n\n    // Execute\n    results result;\n    conn.async_execute(\"SELECT 'abc'\", result, token)(as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, \"abc\"), per_element());\n\n    // Start execution\n    execution_state st;\n    conn.async_start_execution(\"SELECT 'abc'\", st, token)(as_netresult).validate_no_error();\n    auto rws = conn.async_read_some_rows(st, token)(as_netresult).get();\n    BOOST_TEST(rws == makerows(1, \"abc\"), per_element());\n    conn.async_read_resultset_head(st, token)(as_netresult).validate_no_error();\n\n#ifdef BOOST_MYSQL_CXX14\n    // Start execution (static, for read_some_rows)\n    using tup_t = std::tuple<std::string>;\n    static_execution_state<tup_t> st2;\n    std::array<tup_t, 2> storage;\n    conn.async_start_execution(\"SELECT 'abc'\", st2, token)(as_netresult).validate_no_error();\n    std::size_t sz = conn.async_read_some_rows(st2, boost::span<tup_t>(storage), token)(as_netresult).get();\n    BOOST_TEST(sz == 1u);\n#endif\n\n    // Prepare & close statement\n    auto stmt = conn.async_prepare_statement(\"SELECT ?\", token)(as_netresult).get();\n    conn.async_close_statement(stmt, token)(as_netresult).validate_no_error();\n\n    // Reset connection & ping\n    conn.async_reset_connection(token)(as_netresult).validate_no_error();\n    conn.async_ping(token)(as_netresult).validate_no_error();\n\n    // Close\n    conn.async_close(token)(as_netresult).validate_no_error();\n}\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n// Spotcheck: we can co_await async functions in any_connection,\n// and this throws the right exception type\nBOOST_FIXTURE_TEST_CASE(default_token, any_connection_fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        // Connect\n        co_await conn.async_connect(connect_params_builder().build());\n\n        // Success case\n        results result;\n        co_await conn.async_execute(\"SELECT 'abc'\", result);\n        BOOST_TEST(result.rows() == makerows(1, \"abc\"), per_element());\n\n        // Error case\n        BOOST_CHECK_EXCEPTION(\n            co_await conn.async_execute(\"SELECT * FROM bad_table\", result),\n            error_with_diagnostics,\n            [](const error_with_diagnostics& err) {\n                BOOST_TEST(err.code() == common_server_errc::er_no_such_table);\n                BOOST_TEST(\n                    err.get_diagnostics() ==\n                    create_server_diag(\"Table 'boost_mysql_integtests.bad_table' doesn't exist\")\n                );\n                return true;\n            }\n        );\n\n        // Returning a value works\n        auto stmt = co_await conn.async_prepare_statement(\"SELECT ?\");\n        BOOST_TEST(stmt.valid());\n    });\n}\n\n// The pattern co_await conn.fn(..., cancel_after(10s)) works\nBOOST_FIXTURE_TEST_CASE(default_token_cancel_after, any_connection_fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        constexpr std::chrono::seconds timeout(10);\n\n        // Connect\n        co_await conn.async_connect(connect_params_builder().build(), asio::cancel_after(timeout));\n\n        // Returning a value works\n        auto stmt = co_await conn.async_prepare_statement(\"SELECT ?\", asio::cancel_after(timeout));\n        BOOST_TEST(stmt.valid());\n\n        // Error case\n        results result;\n        BOOST_CHECK_EXCEPTION(\n            co_await conn.async_execute(\"SELECT * FROM bad_table\", result, asio::cancel_after(timeout)),\n            error_with_diagnostics,\n            [](const error_with_diagnostics& err) {\n                BOOST_TEST(err.code() == common_server_errc::er_no_such_table);\n                BOOST_TEST(\n                    err.get_diagnostics() ==\n                    create_server_diag(\"Table 'boost_mysql_integtests.bad_table' doesn't exist\")\n                );\n                return true;\n            }\n        );\n    });\n}\n\n// Using as_tuple as partial token works\nBOOST_FIXTURE_TEST_CASE(default_token_as_tuple, any_connection_fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        // connect\n        auto [ec] = co_await conn.async_connect(connect_params_builder().build(), asio::as_tuple);\n        BOOST_TEST_REQUIRE(ec == error_code());\n\n        // Returning a value works\n        auto [ec2, stmt] = co_await conn.async_prepare_statement(\"SELECT ?\", asio::as_tuple);\n        BOOST_TEST_REQUIRE(ec2 == error_code());\n        BOOST_TEST(stmt.valid());\n\n        // Error case\n        results result;\n        auto [ec3] = co_await conn.async_execute(\"SELECT * FROM bad_table\", result, asio::as_tuple);\n        BOOST_TEST(ec3 == common_server_errc::er_no_such_table);\n    });\n}\n\n// Using redirect_error as partial token works\nBOOST_FIXTURE_TEST_CASE(default_token_redirect_error, any_connection_fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        // connect\n        error_code ec;\n        co_await conn.async_connect(connect_params_builder().build(), asio::redirect_error(ec));\n        BOOST_TEST_REQUIRE(ec == error_code());\n\n        // Returning a value works\n        auto stmt = co_await conn.async_prepare_statement(\"SELECT ?\", asio::redirect_error(ec));\n        BOOST_TEST_REQUIRE(ec == error_code());\n        BOOST_TEST(stmt.valid());\n\n        // Error case\n        results result;\n        co_await conn.async_execute(\"SELECT * FROM bad_table\", result, asio::redirect_error(ec));\n        BOOST_TEST(ec == common_server_errc::er_no_such_table);\n    });\n}\n\n#endif\n\n// Spotcheck: immediate completions dispatched to the immediate executor\nBOOST_FIXTURE_TEST_CASE(immediate_completions, any_connection_fixture)\n{\n    run_in_context(ctx, [this]() {\n        // Setup\n        connect();\n        results r;\n\n        // Prepare a statement\n        auto stmt = conn.async_prepare_statement(\"SELECT 1\", as_netresult).get();\n\n        // Executing with the wrong number of params is an immediate error\n        conn.async_execute(stmt.bind(0), r, as_netresult)\n            .run()\n            .validate_immediate(true)\n            .validate_error(client_errc::wrong_num_params);\n    });\n}\n\n// Spotcheck: attempting to run an async op in an engaged connection fails without UB\nBOOST_FIXTURE_TEST_CASE(op_in_progress_execute, io_context_fixture)\n{\n    // Setup\n    any_connection c1(ctx), c2(ctx);\n    results rlock, r1;\n    const auto params = connect_params_builder().disable_ssl().build();\n    c1.async_connect(params, as_netresult).validate_no_error();\n    c2.async_connect(params, as_netresult).validate_no_error();\n\n    // Get a unique lock name. We can use the connection id for this\n    const auto lock_name = std::to_string(c1.connection_id().value());\n\n    // Issue a long-running query by trying to acquire an acquired lock with a long timeout\n    c1.async_execute(with_params(\"CALL get_lock_checked({}, 60)\", lock_name), rlock, as_netresult)\n        .validate_no_error();\n    auto execute_res = c2.async_execute(\n        with_params(\"CALL get_lock_checked({}, 60)\", lock_name),\n        rlock,\n        as_netresult\n    );\n\n    // Other operations fail because the connection is engaged\n    c2.async_execute(\"SELECT 1\", r1, as_netresult).validate_error(client_errc::operation_in_progress);\n    c2.async_prepare_statement(\"SELECT 1\", as_netresult).validate_error(client_errc::operation_in_progress);\n    c2.async_reset_connection(as_netresult).validate_error(client_errc::operation_in_progress);\n    c2.async_connect(connect_params{}, as_netresult).validate_error(client_errc::operation_in_progress);\n    c2.async_close(as_netresult).validate_error(client_errc::operation_in_progress);\n\n    // Release the lock, so the query finishes\n    c1.async_execute(\"DO RELEASE_ALL_LOCKS()\", r1, as_netresult).validate_no_error();\n    std::move(execute_res).validate_no_error();\n\n    // The error is non-fatal: we can issue more queries\n    c2.async_execute(\"SELECT 1\", r1, as_netresult).validate_no_error();\n}\n\nBOOST_FIXTURE_TEST_CASE(op_in_progress_connect, any_connection_fixture)\n{\n    // Launch a connect op\n    const auto params = connect_params_builder().build();\n    auto connect_result = conn.async_connect(params, as_netresult);\n\n    // While in progress, launch another one, with different params.\n    // This fails with the expected error\n    conn.async_connect(\n            connect_params_builder().set_tcp(\"bad\", 1000).credentials(\"bad_username\", \"bad_password\").build(),\n            as_netresult\n    )\n        .validate_error(client_errc::operation_in_progress);\n\n    // The initial operation succeeds\n    std::move(connect_result).validate_no_error();\n\n    // The connection is usable\n    results r;\n    conn.async_execute(\"SELECT 1\", r, as_netresult).validate_no_error();\n}\n\n// Double close is safe\nBOOST_FIXTURE_TEST_CASE(double_close, any_connection_fixture)\n{\n    // Setup\n    connect();\n\n    // Close the connection\n    conn.async_close(as_netresult).validate_no_error();\n\n    // Closing again is OK\n    conn.async_close(as_netresult).validate_no_error();\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/integration/test/character_set_tracking.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/assert/source_location.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/source_location.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_character_set_tracking)\n\nstatic void validate_db_charset(\n    any_connection& conn,\n    string_view expected_charset,\n    boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n)\n{\n    // Issue the query\n    constexpr const char*\n        query = \"SELECT @@character_set_client, @@character_set_connection, @@character_set_results\";\n    results r;\n    conn.async_execute(query, r, as_netresult).validate_no_error(loc);\n\n    // Check\n    BOOST_TEST_CONTEXT(\"Called from \" << loc)\n    {\n        const auto expected = makerows(3, expected_charset, expected_charset, expected_charset);\n        BOOST_TEST(r.rows() == expected, per_element());\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(charset_lifecycle, any_connection_fixture)\n{\n    // Non-connected connections have an unknown charset\n    BOOST_TEST(conn.current_character_set().error() == client_errc::unknown_character_set);\n    BOOST_TEST(conn.format_opts().error() == client_errc::unknown_character_set);\n\n    // Connect with the default character set uses utf8mb4, both in the client\n    // and in the server. This double-checks that all supported servers support the\n    // collation we use by default.\n    connect();\n    BOOST_TEST(conn.current_character_set()->name == \"utf8mb4\");\n    BOOST_TEST(conn.format_opts()->charset.name == \"utf8mb4\");\n    validate_db_charset(conn, \"utf8mb4\");\n\n    // Using set_character_set updates the character set everywhere\n    character_set greek_charset{\"greek\", ascii_charset.next_char};\n    conn.async_set_character_set(greek_charset, as_netresult).validate_no_error();\n    BOOST_TEST(conn.current_character_set()->name == \"greek\");\n    BOOST_TEST(conn.format_opts()->charset.name == \"greek\");\n    validate_db_charset(conn, \"greek\");\n\n    // Using reset_connection wipes out client-side character set information\n    conn.async_reset_connection(as_netresult).validate_no_error();\n    BOOST_TEST(conn.current_character_set().error() == client_errc::unknown_character_set);\n    BOOST_TEST(conn.format_opts().error() == client_errc::unknown_character_set);\n\n    // We can use set_character_set to recover from this\n    conn.async_set_character_set(greek_charset, as_netresult).validate_no_error();\n    BOOST_TEST(conn.current_character_set()->name == \"greek\");\n    BOOST_TEST(conn.format_opts()->charset.name == \"greek\");\n    validate_db_charset(conn, \"greek\");\n}\n\n// For some collations, we set the tracked character set after handshake.\n// Check that all the collations that we know are supported by all the servers\n// that we support. If the collation is not supported, the server falls back to\n// a default charset, so we shouldn't be setting the value of the tracked character set.\nBOOST_FIXTURE_TEST_CASE(connect_with_known_collation, io_context_fixture)\n{\n    constexpr struct\n    {\n        const char* name;\n        std::uint16_t collation_id;\n        character_set charset;\n    } test_cases[] = {\n        {\"utf8mb4_bin\",        mysql_collations::utf8mb4_bin,        utf8mb4_charset},\n        {\"utf8mb4_general_ci\", mysql_collations::utf8mb4_general_ci, utf8mb4_charset},\n        {\"ascii_general_ci\",   mysql_collations::ascii_general_ci,   ascii_charset  },\n        {\"ascii_bin\",          mysql_collations::ascii_bin,          ascii_charset  },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            any_connection conn(ctx);\n\n            // Connect\n            conn.async_connect(connect_params_builder().collation(tc.collation_id).build(), as_netresult)\n                .validate_no_error();\n\n            // Check that the tracked character set and the one chosen by the DB match\n            BOOST_TEST(conn.current_character_set().value() == tc.charset);\n            validate_db_charset(conn, tc.charset.name);\n        }\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(connect_with_unknown_collation, any_connection_fixture)\n{\n    // Connect with a collation that some servers may not support, or that we don't know of\n    // utf8mb4_0900_ai_ci is not supported by MariaDB, triggers fallback\n    connect(connect_params_builder().collation(mysql_collations::utf8mb4_0900_ai_ci).build());\n    BOOST_TEST(conn.current_character_set().error() == client_errc::unknown_character_set);\n    BOOST_TEST(conn.format_opts().error() == client_errc::unknown_character_set);\n\n    // Explicitly setting the character set solves the issue\n    conn.async_set_character_set(ascii_charset, as_netresult).validate_no_error();\n    BOOST_TEST(conn.current_character_set()->name == \"ascii\");\n    validate_db_charset(conn, \"ascii\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/integration/test/connection_id.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/bind_cancellation_slot.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/optional/optional_io.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing boost::test_tools::per_element;\n\nBOOST_AUTO_TEST_SUITE(test_connection_id)\n\n// connection_id\nstd::uint32_t call_connection_id(any_connection& conn)\n{\n    results r;\n    conn.async_execute(\"SELECT CONNECTION_ID()\", r, as_netresult).validate_no_error();\n    return static_cast<std::uint32_t>(r.rows().at(0).at(0).as_uint64());\n}\n\nBOOST_FIXTURE_TEST_CASE(success, any_connection_fixture)\n{\n    // Before connection, connection_id returns an empty optional\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>());\n\n    // Connect\n    connect();\n\n    // The returned id matches CONNECTION_ID()\n    auto expected_id = call_connection_id(conn);\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(expected_id));\n\n    // Calling reset connection doesn't change the ID\n    conn.async_reset_connection(as_netresult).validate_no_error();\n    expected_id = call_connection_id(conn);\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(expected_id));\n\n    // Close the connection\n    conn.async_close(as_netresult).validate_no_error();\n\n    // After session termination, connection_id returns an empty optional\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>());\n\n    // If we re-establish the session, we get another connection id\n    connect();\n    auto expected_id_2 = call_connection_id(conn);\n    BOOST_TEST(expected_id_2 != expected_id);\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(expected_id_2));\n}\n\n// After a fatal error (where we didn't call async_close), re-establishing the session\n// updates the connection id\nBOOST_FIXTURE_TEST_CASE(after_error, any_connection_fixture)\n{\n    // Connect\n    connect();\n    auto id1 = call_connection_id(conn);\n\n    // Force a fatal error\n    results r;\n    asio::cancellation_signal sig;\n    auto execute_result = conn.async_execute(\n        \"DO SLEEP(60)\",\n        r,\n        asio::bind_cancellation_slot(sig.slot(), as_netresult)\n    );\n    sig.emit(asio::cancellation_type_t::terminal);\n    std::move(execute_result).validate_error(asio::error::operation_aborted);\n\n    // The id can be obtained even after the fatal error\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(id1));\n\n    // Reconnect\n    connect();\n    auto id2 = call_connection_id(conn);\n\n    // The new id can be obtained\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(id2));\n}\n\n// It's safe to obtain the connection id while an operation is in progress\nBOOST_FIXTURE_TEST_CASE(op_in_progress, any_connection_fixture)\n{\n    // Setup\n    connect();\n    const auto expected_id = call_connection_id(conn);\n\n    // Issue a query\n    results r;\n    auto execute_result = conn.async_execute(\"SELECT * FROM three_rows_table\", r, as_netresult);\n\n    // While in progress, obtain the connection id. We would usually do this to\n    // open a new connection and run a KILL statement. We don't do it here because\n    // it's unreliable as a test due to race conditions between sessions in the server.\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(expected_id));\n\n    // Finish\n    std::move(execute_result).validate_no_error();\n}\n\n// It's safe to obtain the connection id while a multi-function operation is in progress\nBOOST_FIXTURE_TEST_CASE(multi_function, any_connection_fixture)\n{\n    // Setup\n    connect();\n    const auto expected_id = call_connection_id(conn);\n\n    // Start a multi-function operation\n    execution_state st;\n    conn.async_start_execution(\"SELECT * FROM three_rows_table\", st, as_netresult).validate_no_error();\n\n    // Obtain the connection id\n    BOOST_TEST(conn.connection_id() == boost::optional<std::uint32_t>(expected_id));\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/integration/test/connection_pool.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/test/data/test_case.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <cstdint>\n#include <exception>\n#include <memory>\n#include <stdexcept>\n#include <utility>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/server_features.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\nnamespace data = boost::unit_test::data;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_connection_pool)\n\npool_params create_pool_params(std::size_t max_size = 151)\n{\n    pool_params res;\n    res.server_address.emplace_host_and_port(get_hostname());\n    res.username = integ_user;\n    res.password = integ_passwd;\n    res.database = integ_db;\n    res.ssl = ssl_mode::disable;\n    res.max_size = max_size;\n    return res;\n}\n\nstatic void check_run(error_code ec)\n{\n    // Should complete successfully\n    BOOST_TEST(ec == error_code());\n\n    // Should never complete immediately\n    BOOST_TEST(!is_initiation_function());\n}\n\nstruct fixture : io_context_fixture\n{\n    // async_get_connection actually passes nullptr as diagnostics* to initiation\n    // functions if no diagnostics is provided (unlike any_connection)\n    diagnostics diag;\n    results r;\n};\n\n// The pool and individual connections use the correct executors\nBOOST_FIXTURE_TEST_CASE(connection_executor, fixture)\n{\n    // Create two different executors\n    asio::any_io_executor pool_ex = asio::make_strand(ctx);\n    asio::any_io_executor conn_ex = ctx.get_executor();\n    BOOST_TEST((pool_ex != conn_ex));\n\n    // Create and run the pool\n    auto params = create_pool_params();\n    params.connection_executor = conn_ex;\n    connection_pool pool(pool_ex, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Check executors\n    BOOST_TEST((pool.get_executor() == pool_ex));\n    BOOST_TEST((conn->get_executor() == conn_ex));\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nBOOST_FIXTURE_TEST_CASE(pool_executors_thread_safe, fixture)\n{\n    // Create and run the pool\n    auto params = create_pool_params();\n    params.thread_safe = true;\n    connection_pool pool(ctx, create_pool_params());\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Check executors. The internal strand is never exposed,\n    // and doesn't get propagated to connections\n    BOOST_TEST((pool.get_executor() == ctx.get_executor()));\n    BOOST_TEST((conn->get_executor() == ctx.get_executor()));\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nBOOST_DATA_TEST_CASE_F(fixture, return_connection_with_reset, data::make({false, true}))\n{\n    // Create a pool with max_size 1, so the same connection gets always returned\n    auto params = create_pool_params(1);\n    params.thread_safe = sample;\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Alter session state\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_execute(\"SET @myvar = 'abc'\", r, as_netresult).validate_no_error();\n\n    // Return the connection\n    conn = pooled_connection();\n\n    // Get the same connection again\n    conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // The same connection is returned, but session state has been cleared\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_execute(\"SELECT @myvar\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, nullptr), per_element());\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nBOOST_DATA_TEST_CASE_F(fixture, return_connection_without_reset, data::make({false, true}))\n{\n    // Create a connection pool with max_size 1, so the same connection gets always returned\n    auto params = create_pool_params(1);\n    params.thread_safe = sample;\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Alter session state\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_execute(\"SET @myvar = 'abc'\", r, as_netresult).validate_no_error();\n\n    // Return the connection\n    conn.return_without_reset();\n    BOOST_TEST(!conn.valid());\n\n    // Get the same connection again\n    conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // The same connection is returned, and no reset has been issued\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_execute(\"SELECT @myvar\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, \"abc\"), per_element());\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n// pooled_connection destructor is equivalent to return_connection with reset\nBOOST_FIXTURE_TEST_CASE(pooled_connection_destructor, fixture)\n{\n    // Create a connection pool with max_size 1, so the same connection gets always returned\n    connection_pool pool(ctx, create_pool_params(1));\n    auto run_result = pool.async_run(as_netresult);\n\n    {\n        // Get a connection\n        auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n        // Alter session state\n        BOOST_TEST_REQUIRE(conn.valid());\n        conn->async_execute(\"SET @myvar = 'abc'\", r, as_netresult).validate_no_error();\n    }\n\n    // Get the same connection again\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // The same connection is returned, but session state has been cleared\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_execute(\"SELECT @myvar\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, nullptr), per_element());\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n// Pooled connections use utf8mb4\nstatic void validate_charset(any_connection& conn)\n{\n    // The connection knows its using utf8mb4\n    BOOST_TEST(conn.current_character_set()->name == \"utf8mb4\");\n    BOOST_TEST(conn.format_opts()->charset.name == \"utf8mb4\");\n\n    // The connection is actually using utf8mb4\n    results r;\n    conn.async_execute(\n            \"SELECT @@character_set_client, @@character_set_connection, @@character_set_results\",\n            r,\n            as_netresult\n    )\n        .validate_no_error();\n    BOOST_TEST(r.rows() == makerows(3, \"utf8mb4\", \"utf8mb4\", \"utf8mb4\"), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(charset, fixture)\n{\n    // Create and run the pool\n    connection_pool pool(ctx, create_pool_params(1));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n    validate_charset(conn.get());\n\n    // Return the connection and retrieve it again\n    conn = pooled_connection();\n    conn = pool.async_get_connection(diag, as_netresult).get();\n    validate_charset(conn.get());\n\n    // Return the connection without reset and retrieve it again\n    conn.return_without_reset();\n    conn = pool.async_get_connection(diag, as_netresult).get();\n    validate_charset(conn.get());\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nBOOST_FIXTURE_TEST_CASE(connections_created_if_required, fixture)\n{\n    connection_pool pool(ctx, create_pool_params());\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn1 = pool.async_get_connection(diag, as_netresult).get();\n\n    // Check that it works\n    BOOST_TEST_REQUIRE(conn1.valid());\n    conn1->async_execute(\"SET @myvar = '1'\", r, as_netresult).validate_no_error();\n\n    // Get another connection. This will create a new one, since the first one is in use\n    auto conn2 = pool.async_get_connection(diag, as_netresult).get();\n\n    // Check that it works\n    BOOST_TEST_REQUIRE(conn1.valid());\n    conn2->async_execute(\"SET @myvar = '2'\", r, as_netresult).validate_no_error();\n\n    // They are different connections\n    conn1->async_execute(\"SELECT @myvar\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, \"1\"), per_element());\n    conn2->async_execute(\"SELECT @myvar\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, \"2\"), per_element());\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nstd::int64_t get_connection_id(any_connection& conn)\n{\n    results r;\n    conn.async_execute(\"SELECT CONNECTION_ID()\", r, as_netresult).validate_no_error();\n    return r.rows().at(0).at(0).as_uint64();\n}\n\n// Regression check: https://github.com/boostorg/mysql/issues/395\n// If there are more outstanding connection requests than pending connections,\n// connections are created\nBOOST_FIXTURE_TEST_CASE(connections_created_if_requests_gt_pending, fixture)\n{\n    connection_pool pool(ctx, create_pool_params());\n    auto run_result = pool.async_run(as_netresult);\n\n    // Request several connections in parallel\n    auto conn1_result = pool.async_get_connection(diag, as_netresult);\n    auto conn2_result = pool.async_get_connection(diag, as_netresult);\n    auto conn3_result = pool.async_get_connection(diag, as_netresult);\n\n    // Resolve the requests\n    auto conn1 = std::move(conn1_result).get();\n    auto conn2 = std::move(conn2_result).get();\n    auto conn3 = std::move(conn3_result).get();\n\n    // They should be different connections\n    auto conn1_id = get_connection_id(conn1.get());\n    auto conn2_id = get_connection_id(conn2.get());\n    auto conn3_id = get_connection_id(conn3.get());\n    BOOST_TEST(conn1_id != conn2_id);\n    BOOST_TEST(conn1_id != conn3_id);\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nBOOST_FIXTURE_TEST_CASE(connection_upper_limit, fixture)\n{\n    connection_pool pool(ctx, create_pool_params(1));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Getting another connection will block until one is returned.\n    // Since we won't return the one we have, the function time outs\n    pool.async_get_connection(diag, asio::cancel_after(std::chrono::milliseconds(1), asio::deferred))(\n            as_netresult\n    )\n        .validate_error(client_errc::no_connection_available);\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n// If a connection is requested before calling run, we wait\nBOOST_DATA_TEST_CASE_F(fixture, get_connection_before_run, data::make({false, true}))\n{\n    auto params = create_pool_params(151);\n    params.thread_safe = sample;\n    connection_pool pool(ctx, std::move(params));\n\n    // Get some connections before calling run\n    auto getconn1_result = pool.async_get_connection(diag, as_netresult);\n    auto getconn2_result = pool.async_get_connection(diag, as_netresult);\n\n    // Call run\n    auto run_result = pool.async_run(as_netresult);\n\n    // Success\n    auto conn1 = std::move(getconn1_result).get();\n    auto conn2 = std::move(getconn2_result).get();\n\n    // They're different connections\n    BOOST_TEST(get_connection_id(conn1.get()) != get_connection_id(conn2.get()));\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\nBOOST_FIXTURE_TEST_CASE(cancel_run, fixture)\n{\n    // Construct a pool and run it\n    connection_pool pool(ctx, create_pool_params());\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Cancel. This will make run() return\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n\n    // Cancel again does nothing\n    pool.cancel();\n}\n\n// If the pool is cancelled before calling run, cancel still has effect\nBOOST_FIXTURE_TEST_CASE(cancel_before_run, fixture)\n{\n    // Create a pool\n    connection_pool pool(ctx, create_pool_params());\n\n    // Cancel\n    pool.cancel();\n\n    // Run returns immediately\n    pool.async_run(as_netresult).validate_no_error_nodiag();\n}\n\nBOOST_DATA_TEST_CASE_F(fixture, cancel_get_connection, data::make({false, true}))\n{\n    // Construct a pool and run it\n    auto params = create_pool_params(1);\n    params.thread_safe = sample;\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Try to get a new one. This will not complete, since there is no room for more connections\n    diagnostics diag2;\n    auto getconn_result = pool.async_get_connection(diag2, as_netresult);\n\n    // Cancel. This will make run and get_connection return\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n    std::move(getconn_result).validate_error(client_errc::pool_cancelled);\n\n    // Calling get_connection after cancel will error\n    pool.async_get_connection(diag, as_netresult).validate_error(client_errc::pool_cancelled);\n}\n\n// Connection pool's destructor cancels the pool\nBOOST_FIXTURE_TEST_CASE(destructor_cancel, fixture)\n{\n    // Construct a pool and run it\n    std::unique_ptr<connection_pool> pool{new connection_pool(ctx, create_pool_params(1))};\n    auto run_result = pool->async_run(as_netresult);\n\n    // Try to get 2 connections. The 2nd one blocks\n    auto conn = pool->async_get_connection(diag, as_netresult).get();\n    auto getconn_result = pool->async_get_connection(diag, as_netresult);\n\n    // Destroy the pool\n    pool.reset();\n\n    // Run returns and the connection request is cancelled\n    std::move(run_result).validate_no_error_nodiag();\n    std::move(getconn_result).validate_error(client_errc::pool_cancelled);\n}\n\n// Having a valid pooled_connection alive extends the pool's lifetime\nBOOST_DATA_TEST_CASE_F(fixture, pooled_connection_extends_pool_lifetime, data::make({false, true}))\n{\n    auto params = create_pool_params();\n    params.thread_safe = sample;\n    std::unique_ptr<connection_pool> pool(new connection_pool(ctx, std::move(params)));\n\n    // Run the pool\n    auto run_result = pool->async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool->async_get_connection(diag, as_netresult).get();\n\n    // Cancel and destroy\n    pool->cancel();\n    pool.reset();\n\n    // Wait for run to exit, since run extends lifetime, too\n    std::move(run_result).validate_no_error_nodiag();\n\n    // The connection we got can still be used and returned\n    // In thread-safe mode, strand dispatching doesn't cause lifetime problems\n    conn->async_ping(as_netresult).validate_no_error();\n    conn.return_without_reset();\n}\n\n// Having a packaged async_get_connection op extends lifetime\nBOOST_FIXTURE_TEST_CASE(async_get_connection_initiation_extends_pool_lifetime, fixture)\n{\n    std::unique_ptr<connection_pool> pool(new connection_pool(ctx, create_pool_params()));\n\n    // Create a packaged op\n    auto op = pool->async_get_connection(diag, boost::asio::deferred);\n\n    // Destroy the pool\n    pool.reset();\n\n    // We can run the operation without crashing, since it extends lifetime\n    std::move(op)(asio::cancel_after(std::chrono::nanoseconds(1), as_netresult))\n        .validate_error(client_errc::pool_not_running);\n}\n\n// In thread-safe mode, cancel() is dispatched to the strand, and doesn't cause lifetime issues\nBOOST_FIXTURE_TEST_CASE(cancel_extends_pool_lifetime, fixture)\n{\n    auto params = create_pool_params();\n    params.thread_safe = true;\n    std::unique_ptr<connection_pool> pool(new connection_pool(ctx, std::move(params)));\n\n    // Cancel\n    pool->cancel();\n\n    // Destroy the pool\n    pool.reset();\n\n    // Dispatch any pending handler. We didn't crash\n    ctx.poll();\n}\n\n// Spotcheck: the overload without diagnostics work\nBOOST_FIXTURE_TEST_CASE(get_connection_no_diag, fixture)\n{\n    connection_pool pool(ctx, create_pool_params());\n    auto run_result = pool.async_run(as_netresult);\n\n    auto conn = pool.async_get_connection(as_netresult).get_nodiag();\n    conn->async_ping(as_netresult).validate_no_error();\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\n// Spotcheck: pool works with unix sockets, too\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_FIXTURE_TEST_CASE(unix_sockets, fixture)\n{\n    // Create and run the pool\n    auto params = create_pool_params();\n    params.server_address.emplace_unix_path(default_unix_path);\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Verify that works\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_ping(as_netresult).validate_no_error();\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n#endif\n\n// Spotcheck: pool works with TLS\nBOOST_FIXTURE_TEST_CASE(ssl, fixture)\n{\n    // Create and run the pool\n    auto params = create_pool_params();\n    params.ssl = ssl_mode::require;\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Verify that works\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_ping(as_netresult).validate_no_error();\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n// Spotcheck: custom ctor params (SSL context and buffer size) can be passed to the connection pool\nBOOST_FIXTURE_TEST_CASE(custom_ctor_params, fixture)\n{\n    // Create and run the pool\n    auto params = create_pool_params();\n    params.ssl = ssl_mode::require;\n    params.ssl_ctx.emplace(asio::ssl::context::sslv23_client);\n    params.initial_buffer_size = 16u;\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Verify that works\n    BOOST_TEST_REQUIRE(conn.valid());\n    conn->async_ping(as_netresult).validate_no_error();\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n// Spotcheck: the pool can work with zero timeouts\nBOOST_FIXTURE_TEST_CASE(zero_timeuts, fixture)\n{\n    // Create and run the pool\n    auto params = create_pool_params();\n    params.max_size = 1u;  // so we force a reset\n    params.connect_timeout = std::chrono::seconds(0);\n    params.ping_timeout = std::chrono::seconds(0);\n    params.ping_interval = std::chrono::seconds(0);\n    connection_pool pool(ctx, std::move(params));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n    conn->async_ping(as_netresult).validate_no_error();\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n// Spotcheck: we can use completion tokens that require\n// initiations to have a bound executor, like cancel_after\n// This also tests that running ops with a connected cancel slot\n// without triggering cancellation doesn't crash\nBOOST_FIXTURE_TEST_CASE(cancel_after, fixture)\n{\n    constexpr std::chrono::seconds timeout(10);\n\n    connection_pool pool(ctx, create_pool_params());\n    pool.async_run(asio::cancel_after(timeout, check_run));\n\n    // Get a connection\n    auto conn = pool.async_get_connection(diag, asio::cancel_after(timeout, asio::deferred))(as_netresult)\n                    .get();\n    conn->async_ping(as_netresult).validate_no_error();\n\n    // Cleanup the pool\n    pool.cancel();\n}\n\n// Spotcheck: per-operation cancellation works with async_run\nBOOST_FIXTURE_TEST_CASE(async_run_per_operation_cancellation, fixture)\n{\n    connection_pool pool(ctx, create_pool_params());\n    pool.async_run(asio::cancel_after(std::chrono::microseconds(1), asio::deferred))(as_netresult)\n        .validate_no_error_nodiag();\n    pool.async_get_connection(diag, as_netresult).validate_error(client_errc::pool_cancelled);\n}\n\n// Spotcheck: per-operation cancellation works with async_get_connection\nBOOST_FIXTURE_TEST_CASE(async_get_connection_per_operation_cancellation, fixture)\n{\n    // Create and run the pool\n    connection_pool pool(ctx, create_pool_params(1));\n    auto run_result = pool.async_run(as_netresult);\n\n    // Get the only connection the pool has\n    auto conn = pool.async_get_connection(diag, as_netresult).get();\n\n    // Getting another connection times out\n    pool.async_get_connection(diag, asio::cancel_after(std::chrono::microseconds(1), asio::deferred))(\n            as_netresult\n    )\n        .validate_error(client_errc::no_connection_available);\n\n    // Cleanup the pool\n    pool.cancel();\n    std::move(run_result).validate_no_error_nodiag();\n}\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n// Spotcheck: we can co_await async functions in any_connection,\n// and this throws the right exception type\nBOOST_FIXTURE_TEST_CASE(default_token, fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        connection_pool pool(ctx, create_pool_params());\n\n        // Run can be used without a token. Defaults to with_diagnostics(deferred)\n        auto run_op = pool.async_run();\n\n        // Error case (pool not running)\n        BOOST_CHECK_EXCEPTION(\n            co_await pool.async_get_connection(asio::cancel_after(std::chrono::nanoseconds(1))),\n            error_with_diagnostics,\n            [](const error_with_diagnostics& err) {\n                BOOST_TEST(err.code() == client_errc::pool_not_running);\n                BOOST_TEST(err.get_diagnostics() == diagnostics());\n                return true;\n            }\n        );\n\n        // Run the pool\n        std::move(run_op)([](std::exception_ptr exc) {\n            if (exc)\n                std::rethrow_exception(exc);\n        });\n\n        // Success case\n        auto conn = co_await pool.async_get_connection();\n        co_await conn->async_ping();\n\n        // Finish\n        pool.cancel();\n    });\n}\n\n// cancel_after can be used as a partial token with async_run and async_get_connection.\nBOOST_FIXTURE_TEST_CASE(cancel_after_partial_token, fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        connection_pool pool(ctx, create_pool_params(1));\n\n        // Run can be used with cancel_after\n        asio::co_spawn(\n            ctx,\n            [&]() -> asio::awaitable<void> {\n                co_await pool.async_run(asio::cancel_after(std::chrono::seconds(1)));\n            },\n            [](std::exception_ptr exc) {\n                if (exc)\n                    std::rethrow_exception(exc);\n            }\n        );\n\n        // Success case\n        auto conn = co_await pool.async_get_connection(asio::cancel_after(std::chrono::seconds(1)));\n        co_await conn->async_ping();\n\n        // Error case (operation cancelled)\n        BOOST_CHECK_EXCEPTION(\n            co_await pool.async_get_connection(asio::cancel_after(std::chrono::nanoseconds(1))),\n            error_with_diagnostics,\n            [](const error_with_diagnostics& err) {\n                BOOST_TEST(err.code() == client_errc::no_connection_available);\n                BOOST_TEST(err.get_diagnostics() == diagnostics());\n                return true;\n            }\n        );\n\n        // Finish\n        pool.cancel();\n    });\n}\n\n#endif\n\n// Spotcheck: constructing a connection_pool with invalid params throws\nBOOST_AUTO_TEST_CASE(invalid_params)\n{\n    asio::io_context ctx;\n    pool_params params;\n    params.connect_timeout = std::chrono::seconds(-1);\n\n    BOOST_CHECK_EXCEPTION(\n        connection_pool(ctx, std::move(params)),\n        std::invalid_argument,\n        [](const std::invalid_argument& exc) {\n            return exc.what() == string_view(\"pool_params::connect_timeout must not be negative\");\n        }\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/integration/test/crud.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test_suite.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_crud)\n\n// Other SELECT statements are already covered\nBOOST_FIXTURE_TEST_CASE(query_empty_select, any_connection_fixture)\n{\n    connect();\n\n    // Issue query\n    results result;\n    conn.async_execute(\"SELECT * FROM empty_table\", result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST(result.size() == 1u);\n    validate_2fields_meta(result.meta(), \"empty_table\");\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(query_insert, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n\n    // Issue query\n    constexpr const char*\n        query = \"INSERT INTO inserts_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')\";\n    results result;\n    conn.async_execute(query, result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST(result.size() == 1u);\n    BOOST_TEST(result.meta().empty());\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 1u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() > 0u);\n    BOOST_TEST(result.info() == \"\");\n\n    // Verify insertion took place\n    conn.async_execute(\"SELECT COUNT(*) FROM inserts_table\", result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 1), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(query_update, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n\n    // Issue the query\n    results result;\n    conn.async_execute(\"UPDATE updates_table SET field_int = field_int+10\", result, as_netresult)\n        .validate_no_error();\n\n    // Validate results\n    BOOST_TEST(result.size() == 1u);\n    BOOST_TEST(result.meta().empty());\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 2u);  // there are 3 rows, but 1 has field_int = NULL\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"Rows matched: 3  Changed: 2  Warnings: 0\");\n\n    // Validate it took effect\n    conn.async_execute(\"SELECT field_int FROM updates_table WHERE field_varchar = 'f0'\", result, as_netresult)\n        .validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 52), per_element());  // initial value was 42\n}\n\nBOOST_FIXTURE_TEST_CASE(query_delete, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n\n    // Issue the query\n    results result;\n    conn.async_execute(\"DELETE FROM updates_table\", result, as_netresult).validate_no_error();\n\n    // Validate results\n    BOOST_TEST(result.size() == 1u);\n    BOOST_TEST(result.meta().empty());\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 3u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n\n    // Validate it took effect\n    conn.async_execute(\"SELECT COUNT(*) FROM updates_table\", result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 0), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(statement_update, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n\n    // Prepare the statement\n    constexpr const char* sql = \"UPDATE updates_table SET field_int = ? WHERE field_varchar = ?\";\n    auto stmt = conn.async_prepare_statement(sql, as_netresult).get();\n    BOOST_TEST(stmt.num_params() == 2u);\n\n    // Execute it\n    results result;\n    conn.execute(stmt.bind(200, \"f0\"), result);\n    BOOST_TEST(result.size() == 1u);\n    BOOST_TEST(result.meta().empty());\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 1u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"Rows matched: 1  Changed: 1  Warnings: 0\");\n\n    // Verify that it took effect\n    conn.async_execute(\"SELECT field_int FROM updates_table WHERE field_varchar = 'f0'\", result, as_netresult)\n        .validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 200), per_element());\n\n    // Close the statement\n    conn.async_close_statement(stmt, as_netresult).validate_no_error();\n}\n\nBOOST_FIXTURE_TEST_CASE(statement_delete, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n\n    // Prepare the statement\n    constexpr const char* sql = \"DELETE FROM updates_table WHERE field_varchar = ?\";\n    auto stmt = conn.async_prepare_statement(sql, as_netresult).get();\n    BOOST_TEST(stmt.num_params() == 1u);\n\n    // Execute it\n    results result;\n    conn.async_execute(stmt.bind(\"f0\"), result, as_netresult).validate_no_error();\n    BOOST_TEST(result.size() == 1u);\n    BOOST_TEST(result.meta().empty());\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 1u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n\n    // Validate it took effect\n    conn.async_execute(\"SELECT COUNT(*) FROM updates_table\", result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 2), per_element());\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_crud\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/database_types.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n/**\n * These tests try to cover a range of the possible types and values MySQL support.\n * We list here all the tables that look like types_*, its contents and metadata.\n * We try reading them using the text and binary protocols, and write them using the binary\n * protocol. Table definitions must match those in db_setup.sql\n */\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/tcp.hpp>\n\n#include <boost/describe/class.hpp>\n#include <boost/describe/members.hpp>\n#include <boost/describe/modifiers.hpp>\n#include <boost/describe/operators.hpp>\n#include <boost/mp11/algorithm.hpp>\n#include <boost/none.hpp>\n#include <boost/none_t.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <cstddef>\n#include <cstdint>\n#include <memory>\n#include <ostream>\n#include <stdint.h>\n#include <type_traits>\n#include <vector>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n#include \"test_integration/server_features.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::none;\nusing boost::optional;\n\nBOOST_AUTO_TEST_SUITE(test_database_types)\n\n#ifdef BOOST_MYSQL_CXX14\n\n// operator<< doesn't work for blob (vector<unsigned char>) or time (chrono::duration<...>)\ntemplate <class T, class = typename std::enable_if<boost::describe::has_describe_members<T>::value>::type>\nstd::ostream& operator<<(std::ostream& os, const T& v)\n{\n    os << '{';\n    boost::mp11::mp_for_each<boost::describe::describe_members<T, boost::describe::mod_public>>([&](auto D) {\n        os << \".\" << D.name << \" = \" << boost::mysql::detail::to_field(v.*D.pointer) << \", \";\n    });\n    return os << '}';\n}\nusing boost::describe::operators::operator==;\n\n#endif\n\n// Helpers\nusing flagsvec = std::vector<meta_validator::flag_getter>;\n\nconst flagsvec flags_unsigned{&metadata::is_unsigned};\nconst flagsvec flags_zerofill{&metadata::is_unsigned, &metadata::is_zerofill};\nconst flagsvec no_flags{};\n\nconstexpr format_options opts{utf8mb4_charset, true};\n\nstruct database_types_fixture : any_connection_fixture\n{\n    database_types_fixture()\n    {\n        // Connect\n        connect(connect_params_builder().multi_queries(true).build());\n\n        // Sets the time_zone to a well known value, so we can deterministically read TIMESTAMPs\n        // Sets also sql_mode to allow invalid dates\n        results result;\n        conn.async_execute(\n                \"SET session time_zone = '+02:00'; \"\n                \"SET session sql_mode = 'ALLOW_INVALID_DATES'\",\n                result,\n                as_netresult\n        )\n            .validate_no_error();\n    }\n};\n\nstruct table_base\n{\n    std::string name;\n    std::vector<meta_validator> metas;\n    std::vector<boost::mysql::row> rws;\n\n    table_base(std::string name) : name(std::move(name))\n    {\n        add_meta(\n            \"id\",\n            column_type::varchar,\n            flagsvec{\n                &metadata::is_primary_key,\n                &metadata::is_not_null,\n                &metadata::has_no_default_value,\n            }\n        );\n    }\n\n    virtual ~table_base() {}\n    virtual void select_static(any_connection& conn) = 0;\n\n    void add_meta(\n        std::string field,\n        column_type type,\n        flagsvec flags = {},\n        unsigned decimals = 0,\n        flagsvec ignore_flags = {}\n    )\n    {\n        metas.emplace_back(name, std::move(field), type, std::move(flags), decimals, std::move(ignore_flags));\n    }\n\n    void validate_rows(rows_view actual) const\n    {\n        // Sort the expected rows as the database retrieves it\n        std::vector<row> expected{rws.begin(), rws.end()};\n        std::sort(expected.begin(), expected.end(), [](row_view r1, row_view r2) {\n            return r1.at(0).as_string() < r2.at(0).as_string();\n        });\n\n        // Compare\n        BOOST_TEST(actual == expected, boost::test_tools::per_element());\n    }\n\n    std::string select_sql() const { return format_sql(opts, \"SELECT * FROM {:i} ORDER BY id\", name); }\n\n    std::string insert_sql_stmt() const\n    {\n        auto format_fn = [](const meta_validator&, format_context_base& ctx) { ctx.append_raw(\"?\"); };\n        return format_sql(opts, \"INSERT INTO {:i} VALUES ({})\", name, sequence(metas, format_fn));\n    }\n\n    std::string insert_sql() const\n    {\n        auto format_fn = [](row_view r, format_context_base& ctx) { format_sql_to(ctx, \"({})\", r); };\n        return format_sql(opts, \"INSERT INTO {:i} VALUES {}\", name, sequence(rws, format_fn));\n    }\n\n    std::string delete_sql() const { return format_sql(opts, \"DELETE FROM {:i}\", name); }\n};\n\ntemplate <class T>\nT convert_none(T v) noexcept\n{\n    return v;\n}\n\nstd::nullptr_t convert_none(boost::none_t) { return nullptr; }\n\ntemplate <class StaticRow>\nclass table : public table_base\n{\n    std::vector<StaticRow> static_rows_;\n\npublic:\n    using table_base::table_base;\n\n    template <typename... Args>\n    void add_row(const char* id, const Args&... args)\n    {\n        assert(sizeof...(Args) + 1 == metas.size());\n        static_rows_.push_back(StaticRow{id, args...});\n        rws.emplace_back(makerow(id, convert_none(args)...));\n    }\n\n#ifdef BOOST_MYSQL_CXX14\n    void select_static(any_connection& conn) override\n    {\n        // Execute the query\n        static_results<StaticRow> result;\n        conn.async_execute(select_sql(), result, as_netresult).validate_no_error();\n\n        // Validate metadata\n        validate_meta(result.meta(), metas);\n\n        // Validate the rows\n        std::vector<StaticRow> expected{static_rows_};\n        std::sort(expected.begin(), expected.end(), [](const StaticRow& r1, const StaticRow& r2) {\n            return r1.id < r2.id;\n        });\n        BOOST_TEST(result.rows() == expected, boost::test_tools::per_element());\n    }\n#else\n    void select_static(any_connection&) override {}\n#endif\n};\n\ntemplate <class StaticRow>\nstd::unique_ptr<table<StaticRow>> make_table(std::string name)\n{\n    return std::unique_ptr<table<StaticRow>>(new table<StaticRow>(std::move(name)));\n}\n\nusing table_ptr = std::unique_ptr<table_base>;\n\n// Int helpers\nvoid int_table_columns(table_base& output, column_type type)\n{\n    output.add_meta(\"field_signed\", type);\n    output.add_meta(\"field_unsigned\", type, flags_unsigned);\n    output.add_meta(\"field_width\", type);\n    output.add_meta(\"field_zerofill\", type, flags_zerofill);\n}\n\ntemplate <class SignedInt, class UnsignedInt>\nstruct int_table_row\n{\n    std::string id;\n    optional<SignedInt> field_signed;\n    optional<UnsignedInt> field_unsigned;\n    optional<SignedInt> field_width;\n    optional<UnsignedInt> field_zerofill;\n};\n\n// TINYINT\nusing tinyint_row = int_table_row<int8_t, uint8_t>;\nBOOST_DESCRIBE_STRUCT(tinyint_row, (), (id, field_signed, field_unsigned, field_width, field_zerofill))\n\nstatic table_ptr types_tinyint()\n{\n    auto res = make_table<tinyint_row>(\"types_tinyint\");\n    int_table_columns(*res, column_type::tinyint);\n\n    // clang-format off\n    res->add_row(\"regular\",  int8_t(20),    uint8_t(20),    int8_t(20),  uint8_t(20));\n    res->add_row(\"negative\", int8_t(-20),   none,           int8_t(-20), none);\n    res->add_row(\"min\",      int8_t(-0x80), uint8_t(0u),    none,        uint8_t(0u));\n    res->add_row(\"max\",      int8_t(0x7f),  uint8_t(0xffu), none,        none);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// SMALLINT\nusing smallint_row = int_table_row<int16_t, uint16_t>;\nBOOST_DESCRIBE_STRUCT(smallint_row, (), (id, field_signed, field_unsigned, field_width, field_zerofill))\n\nstatic table_ptr types_smallint()\n{\n    auto res = make_table<smallint_row>(\"types_smallint\");\n    int_table_columns(*res, column_type::smallint);\n\n    // clang-format off\n    res->add_row(\"regular\",  int16_t(20),      uint16_t(20u),     int16_t(20),  uint16_t(20u));\n    res->add_row(\"negative\", int16_t(-20),     none,              int16_t(-20), none);\n    res->add_row(\"min\",      int16_t(-0x8000), uint16_t(0u),      none,         uint16_t(0u));\n    res->add_row(\"max\",      int16_t(0x7fff),  uint16_t(0xffffu), none,         none);\n    // clang-format on\n    return table_ptr(std::move(res));  // This cast is required due to a bug in old clangs\n}\n\n// MEDIUMINT (row type shared with INT)\nusing int_row = int_table_row<int32_t, uint32_t>;\nBOOST_DESCRIBE_STRUCT(int_row, (), (id, field_signed, field_unsigned, field_width, field_zerofill))\n\nstatic table_ptr types_mediumint()\n{\n    auto res = make_table<int_row>(\"types_mediumint\");\n    int_table_columns(*res, column_type::mediumint);\n\n    // clang-format off\n    res->add_row(\"regular\",  int32_t(20),        uint32_t(20u),       int32_t(20),  uint32_t(20u));\n    res->add_row(\"negative\", int32_t(-20),       none,                int32_t(-20), none);\n    res->add_row(\"min\",      int32_t(-0x800000), uint32_t(0u),        none,         uint32_t(0u));\n    res->add_row(\"max\",      int32_t(0x7fffff),  uint32_t(0xffffffu), none,         none);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// INT\nstatic table_ptr types_int()\n{\n    auto res = make_table<int_row>(\"types_int\");\n    int_table_columns(*res, column_type::int_);\n\n    // clang-format off\n    res->add_row(\"regular\",  int32_t(20),            uint32_t(20u),         int32_t(20),  uint32_t(20u));\n    res->add_row(\"negative\", int32_t(-20),           none,                  int32_t(-20), none);\n    res->add_row(\"min\",      int32_t(-0x80000000LL), uint32_t(0u),          none,         0u);\n    res->add_row(\"max\",      int32_t(0x7fffffff),    uint32_t(0xffffffffu), none,         none);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// BIGINT\nusing bigint_row = int_table_row<int64_t, uint64_t>;\nBOOST_DESCRIBE_STRUCT(bigint_row, (), (id, field_signed, field_unsigned, field_width, field_zerofill))\n\nstatic table_ptr types_bigint()\n{\n    auto res = make_table<bigint_row>(\"types_bigint\");\n    int_table_columns(*res, column_type::bigint);\n\n    // clang-format off\n    res->add_row(\"regular\",   20,                     20u,                 20,   20u);\n    res->add_row(\"negative\", -20,                     none,                -20,  none);\n    res->add_row(\"min\",      -0x7fffffffffffffff - 1, 0u,                  none, 0u);\n    res->add_row(\"max\",       0x7fffffffffffffff,     0xffffffffffffffffu, none, none);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// YEAR\nstruct year_row\n{\n    std::string id;\n    optional<uint16_t> field_default;\n};\nBOOST_DESCRIBE_STRUCT(year_row, (), (id, field_default))\n\nstatic table_ptr types_year()\n{\n    auto res = make_table<year_row>(\"types_year\");\n    res->add_meta(\"field_default\", column_type::year, flags_zerofill);\n\n    // clang-format off\n    res->add_row(\"regular\", uint16_t(2019u));\n    res->add_row(\"min\",     uint16_t(1901u));\n    res->add_row(\"max\",     uint16_t(2155u));\n    res->add_row(\"zero\",    uint16_t(0u));\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// BOOL\nstruct bool_row\n{\n    std::string id;\n    optional<bool> field_default;\n};\nBOOST_DESCRIBE_STRUCT(bool_row, (), (id, field_default))\n\nstatic table_ptr types_bool()\n{\n    auto res = make_table<bool_row>(\"types_bool\");\n    res->add_meta(\"field_default\", column_type::tinyint);\n\n    res->add_row(\"true\", true);\n    res->add_row(\"false\", false);\n    return table_ptr(std::move(res));\n}\n\n// BIT\nstruct bit_row\n{\n    std::string id;\n    optional<uint64_t> field_1;\n    optional<uint64_t> field_8;\n    optional<uint64_t> field_14;\n    optional<uint64_t> field_16;\n    optional<uint64_t> field_24;\n    optional<uint64_t> field_25;\n    optional<uint64_t> field_32;\n    optional<uint64_t> field_40;\n    optional<uint64_t> field_48;\n    optional<uint64_t> field_56;\n    optional<uint64_t> field_64;\n};\nBOOST_DESCRIBE_STRUCT(\n    bit_row,\n    (),\n    (id,\n     field_1,\n     field_8,\n     field_14,\n     field_16,\n     field_24,\n     field_25,\n     field_32,\n     field_40,\n     field_48,\n     field_56,\n     field_64)\n)\n\nstatic table_ptr types_bit()\n{\n    auto res = make_table<bit_row>(\"types_bit\");\n    const char* columns[] = {\n        \"field_1\",\n        \"field_8\",\n        \"field_14\",\n        \"field_16\",\n        \"field_24\",\n        \"field_25\",\n        \"field_32\",\n        \"field_40\",\n        \"field_48\",\n        \"field_56\",\n        \"field_64\"\n    };\n    for (const char* col : columns)\n        res->add_meta(col, column_type::bit, flags_unsigned);\n\n    // clang-format off\n    res->add_row(\"min\",     0u, 0u,    0u,      0u,      0u,        0u,         0u,          0u,            0u,              0u,                0u);\n    res->add_row(\"regular\", 1u, 0x9eu, 0x1e2au, 0x1234u, 0x123456u, 0x154abe0u, 0x12345678u, 0x123456789au, 0x123456789abcu, 0x123456789abcdeu, 0x1234567812345678u);\n    res->add_row(\"max\",     1u, 0xffu, 0x3fffu, 0xffffu, 0xffffffu, 0x1ffffffu, 0xffffffffu, 0xffffffffffu, 0xffffffffffffu, 0xffffffffffffffu, 0xffffffffffffffffu);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// FLOAT\nstruct float_row\n{\n    std::string id;\n    optional<float> field_signed;\n    optional<float> field_unsigned;\n    optional<float> field_width;\n    optional<float> field_zerofill;\n};\nBOOST_DESCRIBE_STRUCT(float_row, (), (id, field_signed, field_unsigned, field_width, field_zerofill))\n\nstatic table_ptr types_float()\n{\n    auto res = make_table<float_row>(\"types_float\");\n    res->add_meta(\"field_signed\", column_type::float_, no_flags, 31);\n    res->add_meta(\"field_unsigned\", column_type::float_, flags_unsigned, 31);\n    res->add_meta(\"field_width\", column_type::float_, no_flags, 10);\n    res->add_meta(\"field_zerofill\", column_type::float_, flags_zerofill, 31);\n\n    // clang-format off\n    res->add_row(\"zero\",                              0.f,       0.f,   0.f,  0.f);\n    res->add_row(\"int_positive\",                      4.f,       none,  none, none);\n    res->add_row(\"int_negative\",                     -4.f,       none,  none, none);\n    res->add_row(\"fractional_positive\",               4.2f,      4.2f,  4.2f, 4.2f);\n    res->add_row(\"fractional_negative\",              -4.2f,      none, -4.2f, none);\n    res->add_row(\"positive_exp_positive_int\",         3e20f,     none,  none, none);\n    res->add_row(\"positive_exp_negative_int\",        -3e20f,     none,  none, none);\n    res->add_row(\"positive_exp_positive_fractional\",  3.14e20f,  none,  none, 3.14e20f);\n    res->add_row(\"positive_exp_negative_fractional\", -3.14e20f,  none,  none, none);\n    res->add_row(\"negative_exp_positive_fractional\",  3.14e-20f, none,  none, 3.14e-20f);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// DOUBLE\nstruct double_row\n{\n    std::string id;\n    optional<double> field_signed;\n    optional<double> field_unsigned;\n    optional<double> field_width;\n    optional<double> field_zerofill;\n};\nBOOST_DESCRIBE_STRUCT(double_row, (), (id, field_signed, field_unsigned, field_width, field_zerofill))\n\nstatic table_ptr types_double()\n{\n    auto res = make_table<double_row>(\"types_double\");\n    res->add_meta(\"field_signed\", column_type::double_, no_flags, 31);\n    res->add_meta(\"field_unsigned\", column_type::double_, flags_unsigned, 31);\n    res->add_meta(\"field_width\", column_type::double_, no_flags, 10);\n    res->add_meta(\"field_zerofill\", column_type::double_, flags_zerofill, 31);\n\n    // clang-format off\n    res->add_row(\"zero\",                              0.,        0.,   0.,   0.);\n    res->add_row(\"int_positive\",                      4.,        none, none, none);\n    res->add_row(\"int_negative\",                     -4.,        none, none, none);\n    res->add_row(\"fractional_positive\",               4.2,       4.2,   4.2, 4.2);\n    res->add_row(\"fractional_negative\",              -4.2,       none, -4.2, none);\n    res->add_row(\"positive_exp_positive_int\",         3e200,     none, none, none);\n    res->add_row(\"positive_exp_negative_int\",        -3e200,     none, none, none);\n    res->add_row(\"positive_exp_positive_fractional\",  3.14e200,  none, none, 3.14e200);\n    res->add_row(\"positive_exp_negative_fractional\", -3.14e200,  none, none, none);\n    res->add_row(\"negative_exp_positive_fractional\",  3.14e-200, none, none, 3.14e-200);\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// DATE\nstruct date_row\n{\n    std::string id;\n    optional<date> field_date;\n};\nBOOST_DESCRIBE_STRUCT(date_row, (), (id, field_date))\n\nstatic table_ptr types_date()\n{\n    auto res = make_table<date_row>(\"types_date\");\n    res->add_meta(\"field_date\", column_type::date);\n\n    // clang-format off\n    res->add_row(\"regular\",                           date(2010u, 3u, 28u));\n    res->add_row(\"leap_regular\",                      date(1788u, 2u, 29u));\n    res->add_row(\"leap_400\",                          date(2000u, 2u, 29u));\n    res->add_row(\"min\",                               date(0u, 1u, 01u));\n    res->add_row(\"max\",                               date(9999u, 12u, 31u));\n    res->add_row(\"zero\",                              date(0u, 0u, 0u));\n    res->add_row(\"yzero_mzero_dregular\",              date(0u, 0u, 20u));\n    res->add_row(\"yzero_mregular_dzero\",              date(0u, 11u, 0u));\n    res->add_row(\"yzero_invalid_date\",                date(0u, 11u, 31u));\n    res->add_row(\"yregular_mzero_dzero\",              date(2020u, 0u, 0u));\n    res->add_row(\"yregular_mzero_dregular\",           date(2020u, 0u, 20u));\n    res->add_row(\"yregular_mregular_dzero\",           date(2020u, 11u, 0u));\n    res->add_row(\"yregular_invalid_date\",             date(2020u, 11u, 31u));\n    res->add_row(\"yregular_invalid_date_leapregular\", date(1999u, 2u, 29u));\n    res->add_row(\"yregular_invalid_date_leap100\",     date(1900u, 2u, 29u));\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// DATETIME and TIMESTAMP (they share row definition)\nstruct datetime_row\n{\n    std::string id;\n    optional<datetime> field_0;\n    optional<datetime> field_1;\n    optional<datetime> field_2;\n    optional<datetime> field_3;\n    optional<datetime> field_4;\n    optional<datetime> field_5;\n    optional<datetime> field_6;\n};\nBOOST_DESCRIBE_STRUCT(datetime_row, (), (id, field_0, field_1, field_2, field_3, field_4, field_5, field_6))\n\nvoid datetime_timestamp_common_rows(table<datetime_row>& res)\n{\n    // clang-format off\n    res.add_row(\"date\",         datetime(2010, 5, 2, 0, 0, 0, 0),   datetime(2010, 5, 2, 0, 0, 0, 0),           datetime(2010, 5, 2, 0, 0, 0, 0),           datetime(2010, 5, 2, 0, 0, 0, 0),           datetime(2010, 5, 2, 0, 0, 0, 0),           datetime(2010, 5, 2, 0, 0, 0, 0),           datetime(2010, 5, 2, 0, 0, 0, 0));\n    res.add_row(\"date_leap4\",   datetime(2004, 2, 29, 0, 0, 0, 0),  datetime(2004, 2, 29, 0, 0, 0, 0),          datetime(2004, 2, 29, 0, 0, 0, 0),          datetime(2004, 2, 29, 0, 0, 0, 0),          datetime(2004, 2, 29, 0, 0, 0, 0),          datetime(2004, 2, 29, 0, 0, 0, 0),          datetime(2004, 2, 29, 0, 0, 0, 0));\n    res.add_row(\"date_leap400\", datetime(2000, 2, 29, 0, 0, 0, 0),  datetime(2000, 2, 29, 0, 0, 0, 0),          datetime(2000, 2, 29, 0, 0, 0, 0),          datetime(2000, 2, 29, 0, 0, 0, 0),          datetime(2000, 2, 29, 0, 0, 0, 0),          datetime(2000, 2, 29, 0, 0, 0, 0),          datetime(2000, 2, 29, 0, 0, 0, 0));\n    res.add_row(\"u\",            none,                               datetime(2010, 5, 2, 0, 0, 0, 100000),      datetime(2010, 5, 2, 0, 0, 0, 120000),      datetime(2010, 5, 2, 0, 0, 0, 123000),      datetime(2010, 5, 2, 0, 0, 0, 123400),      datetime(2010, 5, 2, 0, 0, 0, 123450),      datetime(2010, 5, 2, 0, 0, 0, 123456));\n    res.add_row(\"s\",            datetime(2010, 5, 2, 0, 0, 50, 0),  datetime(2010, 5, 2, 0, 0, 50, 0),          datetime(2010, 5, 2, 0, 0, 50, 0),          datetime(2010, 5, 2, 0, 0, 50, 0),          datetime(2010, 5, 2, 0, 0, 50, 0),          datetime(2010, 5, 2, 0, 0, 50, 0),          datetime(2010, 5, 2, 0, 0, 50, 0)), \n    res.add_row(\"m\",            datetime(2010, 5, 2, 0, 1, 0, 0),   datetime(2010, 5, 2, 0, 1, 0, 0),           datetime(2010, 5, 2, 0, 1, 0, 0),           datetime(2010, 5, 2, 0, 1, 0, 0),           datetime(2010, 5, 2, 0, 1, 0, 0),           datetime(2010, 5, 2, 0, 1, 0, 0),           datetime(2010, 5, 2, 0, 1, 0, 0));\n    res.add_row(\"hs\",           datetime(2010, 5, 2, 23, 0, 50, 0), datetime(2010, 5, 2, 23, 0, 50, 0),         datetime(2010, 5, 2, 23, 0, 50, 0),         datetime(2010, 5, 2, 23, 0, 50, 0),         datetime(2010, 5, 2, 23, 0, 50, 0),         datetime(2010, 5, 2, 23, 0, 50, 0),         datetime(2010, 5, 2, 23, 0, 50, 0));\n    res.add_row(\"ms\",           datetime(2010, 5, 2, 0, 1, 50, 0),  datetime(2010, 5, 2, 0, 1, 50, 0),          datetime(2010, 5, 2, 0, 1, 50, 0),          datetime(2010, 5, 2, 0, 1, 50, 0),          datetime(2010, 5, 2, 0, 1, 50, 0),          datetime(2010, 5, 2, 0, 1, 50, 0),          datetime(2010, 5, 2, 0, 1, 50, 0));\n    res.add_row(\"hu\",           none,                               datetime(2010, 5, 2, 23, 0, 0, 100000),     datetime(2010, 5, 2, 23, 0, 0, 120000),     datetime(2010, 5, 2, 23, 0, 0, 123000),     datetime(2010, 5, 2, 23, 0, 0, 123400),     datetime(2010, 5, 2, 23, 0, 0, 123450),     datetime(2010, 5, 2, 23, 0, 0, 123456));\n    res.add_row(\"mu\",           none,                               datetime(2010, 5, 2, 0, 1, 0, 100000),      datetime(2010, 5, 2, 0, 1, 0, 120000),      datetime(2010, 5, 2, 0, 1, 0, 123000),      datetime(2010, 5, 2, 0, 1, 0, 123400),      datetime(2010, 5, 2, 0, 1, 0, 123450),      datetime(2010, 5, 2, 0, 1, 0, 123456));\n    res.add_row(\"hmu\",          none,                               datetime(2010, 5, 2, 23, 1, 0, 100000),     datetime(2010, 5, 2, 23, 1, 0, 120000),     datetime(2010, 5, 2, 23, 1, 0, 123000),     datetime(2010, 5, 2, 23, 1, 0, 123400),     datetime(2010, 5, 2, 23, 1, 0, 123450),     datetime(2010, 5, 2, 23, 1, 0, 123456));\n    res.add_row(\"su\",           none,                               datetime(2010, 5, 2, 0, 0, 50, 100000),     datetime(2010, 5, 2, 0, 0, 50, 120000),     datetime(2010, 5, 2, 0, 0, 50, 123000),     datetime(2010, 5, 2, 0, 0, 50, 123400),     datetime(2010, 5, 2, 0, 0, 50, 123450),     datetime(2010, 5, 2, 0, 0, 50, 123456));\n    res.add_row(\"hsu\",          none,                               datetime(2010, 5, 2, 23, 0, 50, 100000),    datetime(2010, 5, 2, 23, 0, 50, 120000),    datetime(2010, 5, 2, 23, 0, 50, 123000),    datetime(2010, 5, 2, 23, 0, 50, 123400),    datetime(2010, 5, 2, 23, 0, 50, 123450),    datetime(2010, 5, 2, 23, 0, 50, 123456));\n    res.add_row(\"msu\",          none,                               datetime(2010, 5, 2, 0, 1, 50, 100000),     datetime(2010, 5, 2, 0, 1, 50, 120000),     datetime(2010, 5, 2, 0, 1, 50, 123000),     datetime(2010, 5, 2, 0, 1, 50, 123400),     datetime(2010, 5, 2, 0, 1, 50, 123450),     datetime(2010, 5, 2, 0, 1, 50, 123456));\n    res.add_row(\"h\",            datetime(2010, 5, 2, 23, 0, 0, 0),  datetime(2010, 5, 2, 23, 0, 0, 0),          datetime(2010, 5, 2, 23, 0, 0, 0),          datetime(2010, 5, 2, 23, 0, 0, 0),          datetime(2010, 5, 2, 23, 0, 0, 0),          datetime(2010, 5, 2, 23, 0, 0, 0),          datetime(2010, 5, 2, 23, 0, 0, 0));\n    res.add_row(\"hm\",           datetime(2010, 5, 2, 23, 1, 0, 0),  datetime(2010, 5, 2, 23, 1, 0, 0),          datetime(2010, 5, 2, 23, 1, 0, 0),          datetime(2010, 5, 2, 23, 1, 0, 0),          datetime(2010, 5, 2, 23, 1, 0, 0),          datetime(2010, 5, 2, 23, 1, 0, 0),          datetime(2010, 5, 2, 23, 1, 0, 0));\n    res.add_row(\"hms\",          datetime(2010, 5, 2, 23, 1, 50, 0), datetime(2010, 5, 2, 23, 1, 50, 0),         datetime(2010, 5, 2, 23, 1, 50, 0),         datetime(2010, 5, 2, 23, 1, 50, 0),         datetime(2010, 5, 2, 23, 1, 50, 0),         datetime(2010, 5, 2, 23, 1, 50, 0),         datetime(2010, 5, 2, 23, 1, 50, 0));\n    res.add_row(\"hmsu\",         none,                               datetime(2010, 5, 2, 23, 1, 50, 100000),    datetime(2010, 5, 2, 23, 1, 50, 120000),    datetime(2010, 5, 2, 23, 1, 50, 123000),    datetime(2010, 5, 2, 23, 1, 50, 123400),    datetime(2010, 5, 2, 23, 1, 50, 123450),    datetime(2010, 5, 2, 23, 1, 50, 123456));\n    // clang-format on\n}\n\nstatic table_ptr types_datetime()\n{\n    auto res = make_table<datetime_row>(\"types_datetime\");\n    res->add_meta(\"field_0\", column_type::datetime, no_flags, 0, flags_unsigned);\n    res->add_meta(\"field_1\", column_type::datetime, no_flags, 1, flags_unsigned);\n    res->add_meta(\"field_2\", column_type::datetime, no_flags, 2, flags_unsigned);\n    res->add_meta(\"field_3\", column_type::datetime, no_flags, 3, flags_unsigned);\n    res->add_meta(\"field_4\", column_type::datetime, no_flags, 4, flags_unsigned);\n    res->add_meta(\"field_5\", column_type::datetime, no_flags, 5, flags_unsigned);\n    res->add_meta(\"field_6\", column_type::datetime, no_flags, 6, flags_unsigned);\n\n    datetime_timestamp_common_rows(*res);\n\n    // clang-format off\n    res->add_row(\"min\",                                     datetime(0, 1, 1, 0, 0, 0, 0),         datetime(0, 1, 1, 0, 0, 0, 0),              datetime(0, 1, 1, 0, 0, 0, 0),              datetime(0, 1, 1, 0, 0, 0, 0),              datetime(0, 1, 1, 0, 0, 0, 0),              datetime(0, 1, 1, 0, 0, 0, 0),              datetime(0, 1, 1, 0, 0, 0, 0));\n    res->add_row(\"max\",                                     datetime(9999, 12, 31, 23, 59, 59, 0), datetime(9999, 12, 31, 23, 59, 59, 900000), datetime(9999, 12, 31, 23, 59, 59, 990000), datetime(9999, 12, 31, 23, 59, 59, 999000), datetime(9999, 12, 31, 23, 59, 59, 999900), datetime(9999, 12, 31, 23, 59, 59, 999990), datetime(9999, 12, 31, 23, 59, 59, 999999));\n    res->add_row(\"date_zero\",                               datetime(   0,  0,  0,  0,  0,  0, 0), datetime(   0,  0,  0,  0,  0,  0, 0),      datetime(   0,  0,  0,  0,  0,  0,  0),     datetime(   0,  0,  0,  0,  0,  0,   0),    datetime(   0,  0,  0,  0,  0,  0,    0),   datetime(   0,  0,  0,  0,  0,  0,     0),  datetime(   0,  0,  0,  0,  0,  0,      0));\n    res->add_row(\"date_yzero_mzero_dregular\",               datetime(   0,  0, 10,  0,  0,  0, 0), datetime(   0,  0, 10,  0,  0,  0, 0),      datetime(   0,  0, 10,  0,  0,  0,  0),     datetime(   0,  0, 10,  0,  0,  0,   0),    datetime(   0,  0, 10,  0,  0,  0,    0),   datetime(   0,  0, 10,  0,  0,  0,     0),  datetime(   0,  0, 10,  0,  0,  0,      0));\n    res->add_row(\"date_yzero_mregular_dzero\",               datetime(   0, 10,  0,  0,  0,  0, 0), datetime(   0, 10,  0,  0,  0,  0, 0),      datetime(   0, 10,  0,  0,  0,  0,  0),     datetime(   0, 10,  0,  0,  0,  0,   0),    datetime(   0, 10,  0,  0,  0,  0,    0),   datetime(   0, 10,  0,  0,  0,  0,     0),  datetime(   0, 10,  0,  0,  0,  0,      0));\n    res->add_row(\"date_yzero_invalid_date\",                 datetime(   0, 11, 31,  0,  0,  0, 0), datetime(   0, 11, 31,  0,  0,  0, 0),      datetime(   0, 11, 31,  0,  0,  0,  0),     datetime(   0, 11, 31,  0,  0,  0,   0),    datetime(   0, 11, 31,  0,  0,  0,    0),   datetime(   0, 11, 31,  0,  0,  0,     0),  datetime(   0, 11, 31,  0,  0,  0,      0));\n    res->add_row(\"date_yregular_mzero_dzero\",               datetime(2020,  0,  0,  0,  0,  0, 0), datetime(2020,  0,  0,  0,  0,  0, 0),      datetime(2020,  0,  0,  0,  0,  0,  0),     datetime(2020,  0,  0,  0,  0,  0,   0),    datetime(2020,  0,  0,  0,  0,  0,    0),   datetime(2020,  0,  0,  0,  0,  0,     0),  datetime(2020,  0,  0,  0,  0,  0,      0));\n    res->add_row(\"date_yregular_mzero_dregular\",            datetime(2020,  0, 10,  0,  0,  0, 0), datetime(2020,  0, 10,  0,  0,  0, 0),      datetime(2020,  0, 10,  0,  0,  0,  0),     datetime(2020,  0, 10,  0,  0,  0,   0),    datetime(2020,  0, 10,  0,  0,  0,    0),   datetime(2020,  0, 10,  0,  0,  0,     0),  datetime(2020,  0, 10,  0,  0,  0,      0));\n    res->add_row(\"date_yregular_mregular_dzero\",            datetime(2020, 10,  0,  0,  0,  0, 0), datetime(2020, 10,  0,  0,  0,  0, 0),      datetime(2020, 10,  0,  0,  0,  0,  0),     datetime(2020, 10,  0,  0,  0,  0,   0),    datetime(2020, 10,  0,  0,  0,  0,    0),   datetime(2020, 10,  0,  0,  0,  0,     0),  datetime(2020, 10,  0,  0,  0,  0,      0));\n    res->add_row(\"date_yregular_invalid_date\",              datetime(2020, 11, 31,  0,  0,  0, 0), datetime(2020, 11, 31,  0,  0,  0, 0),      datetime(2020, 11, 31,  0,  0,  0,  0),     datetime(2020, 11, 31,  0,  0,  0,   0),    datetime(2020, 11, 31,  0,  0,  0,    0),   datetime(2020, 11, 31,  0,  0,  0,     0),  datetime(2020, 11, 31,  0,  0,  0,      0));\n    res->add_row(\"date_yregular_invalid_date_leapregular\",  datetime(1999,  2, 29,  0,  0,  0, 0), datetime(1999,  2, 29,  0,  0,  0, 0),      datetime(1999,  2, 29,  0,  0,  0,  0),     datetime(1999,  2, 29,  0,  0,  0,   0),    datetime(1999,  2, 29,  0,  0,  0,    0),   datetime(1999,  2, 29,  0,  0,  0,     0),  datetime(1999,  2, 29,  0,  0,  0,      0));\n    res->add_row(\"date_yregular_invalid_date_leap100\",      datetime(1900,  2, 29,  0,  0,  0, 0), datetime(1900,  2, 29,  0,  0,  0, 0),      datetime(1900,  2, 29,  0,  0,  0,  0),     datetime(1900,  2, 29,  0,  0,  0,   0),    datetime(1900,  2, 29,  0,  0,  0,    0),   datetime(1900,  2, 29,  0,  0,  0,     0),  datetime(1900,  2, 29,  0,  0,  0,      0)),\n    res->add_row(\"hms_zero\",                                datetime(   0,  0,  0, 10, 20, 30, 0), datetime(   0,  0,  0, 10, 20, 30, 0),      datetime(   0,  0,  0, 10, 20, 30,  0),     datetime(   0,  0,  0, 10, 20, 30,   0),    datetime(   0,  0,  0, 10, 20, 30,    0),   datetime(   0,  0,  0, 10, 20, 30,     0),  datetime(   0,  0,  0, 10, 20, 30,      0));\n    res->add_row(\"hms_yzero_mzero_dregular\",                datetime(   0,  0, 10, 10, 20, 30, 0), datetime(   0,  0, 10, 10, 20, 30, 0),      datetime(   0,  0, 10, 10, 20, 30,  0),     datetime(   0,  0, 10, 10, 20, 30,   0),    datetime(   0,  0, 10, 10, 20, 30,    0),   datetime(   0,  0, 10, 10, 20, 30,     0),  datetime(   0,  0, 10, 10, 20, 30,      0));\n    res->add_row(\"hms_yzero_mregular_dzero\",                datetime(   0, 10,  0, 10, 20, 30, 0), datetime(   0, 10,  0, 10, 20, 30, 0),      datetime(   0, 10,  0, 10, 20, 30,  0),     datetime(   0, 10,  0, 10, 20, 30,   0),    datetime(   0, 10,  0, 10, 20, 30,    0),   datetime(   0, 10,  0, 10, 20, 30,     0),  datetime(   0, 10,  0, 10, 20, 30,      0));\n    res->add_row(\"hms_yzero_invalid_date\",                  datetime(   0, 11, 31, 10, 20, 30, 0), datetime(   0, 11, 31, 10, 20, 30, 0),      datetime(   0, 11, 31, 10, 20, 30,  0),     datetime(   0, 11, 31, 10, 20, 30,   0),    datetime(   0, 11, 31, 10, 20, 30,    0),   datetime(   0, 11, 31, 10, 20, 30,     0),  datetime(   0, 11, 31, 10, 20, 30,      0));\n    res->add_row(\"hms_yregular_mzero_dzero\",                datetime(2020,  0,  0, 10, 20, 30, 0), datetime(2020,  0,  0, 10, 20, 30, 0),      datetime(2020,  0,  0, 10, 20, 30,  0),     datetime(2020,  0,  0, 10, 20, 30,   0),    datetime(2020,  0,  0, 10, 20, 30,    0),   datetime(2020,  0,  0, 10, 20, 30,     0),  datetime(2020,  0,  0, 10, 20, 30,      0));\n    res->add_row(\"hms_yregular_mzero_dregular\",             datetime(2020,  0, 10, 10, 20, 30, 0), datetime(2020,  0, 10, 10, 20, 30, 0),      datetime(2020,  0, 10, 10, 20, 30,  0),     datetime(2020,  0, 10, 10, 20, 30,   0),    datetime(2020,  0, 10, 10, 20, 30,    0),   datetime(2020,  0, 10, 10, 20, 30,     0),  datetime(2020,  0, 10, 10, 20, 30,      0));\n    res->add_row(\"hms_yregular_mregular_dzero\",             datetime(2020, 10,  0, 10, 20, 30, 0), datetime(2020, 10,  0, 10, 20, 30, 0),      datetime(2020, 10,  0, 10, 20, 30,  0),     datetime(2020, 10,  0, 10, 20, 30,   0),    datetime(2020, 10,  0, 10, 20, 30,    0),   datetime(2020, 10,  0, 10, 20, 30,     0),  datetime(2020, 10,  0, 10, 20, 30,      0));\n    res->add_row(\"hms_yregular_invalid_date\",               datetime(2020, 11, 31, 10, 20, 30, 0), datetime(2020, 11, 31, 10, 20, 30, 0),      datetime(2020, 11, 31, 10, 20, 30,  0),     datetime(2020, 11, 31, 10, 20, 30,   0),    datetime(2020, 11, 31, 10, 20, 30,    0),   datetime(2020, 11, 31, 10, 20, 30,     0),  datetime(2020, 11, 31, 10, 20, 30,      0));\n    res->add_row(\"hms_yregular_invalid_date_leapregular\",   datetime(1999,  2, 29, 10, 20, 30, 0), datetime(1999,  2, 29, 10, 20, 30, 0),      datetime(1999,  2, 29, 10, 20, 30,  0),     datetime(1999,  2, 29, 10, 20, 30,   0),    datetime(1999,  2, 29, 10, 20, 30,    0),   datetime(1999,  2, 29, 10, 20, 30,     0),  datetime(1999,  2, 29, 10, 20, 30,      0));\n    res->add_row(\"hms_yregular_invalid_date_leap100\",       datetime(1900,  2, 29, 10, 20, 30, 0), datetime(1900,  2, 29, 10, 20, 30, 0),      datetime(1900,  2, 29, 10, 20, 30,  0),     datetime(1900,  2, 29, 10, 20, 30,   0),    datetime(1900,  2, 29, 10, 20, 30,    0),   datetime(1900,  2, 29, 10, 20, 30,     0),  datetime(1900,  2, 29, 10, 20, 30,      0)),\n    res->add_row(\"hmsu_zero\",                               datetime(   0,  0,  0, 10, 20, 30, 0), datetime(   0,  0,  0, 10, 20, 30, 900000), datetime(   0,  0,  0, 10, 20, 30, 990000), datetime(   0,  0,  0, 10, 20, 30, 999000), datetime(   0,  0,  0, 10, 20, 30, 999900), datetime(   0,  0,  0, 10, 20, 30, 999990), datetime(   0,  0,  0, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yzero_mzero_dregular\",               datetime(   0,  0, 10, 10, 20, 30, 0), datetime(   0,  0, 10, 10, 20, 30, 900000), datetime(   0,  0, 10, 10, 20, 30, 990000), datetime(   0,  0, 10, 10, 20, 30, 999000), datetime(   0,  0, 10, 10, 20, 30, 999900), datetime(   0,  0, 10, 10, 20, 30, 999990), datetime(   0,  0, 10, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yzero_mregular_dzero\",               datetime(   0, 10,  0, 10, 20, 30, 0), datetime(   0, 10,  0, 10, 20, 30, 900000), datetime(   0, 10,  0, 10, 20, 30, 990000), datetime(   0, 10,  0, 10, 20, 30, 999000), datetime(   0, 10,  0, 10, 20, 30, 999900), datetime(   0, 10,  0, 10, 20, 30, 999990), datetime(   0, 10,  0, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yzero_invalid_date\",                 datetime(   0, 11, 31, 10, 20, 30, 0), datetime(   0, 11, 31, 10, 20, 30, 900000), datetime(   0, 11, 31, 10, 20, 30, 990000), datetime(   0, 11, 31, 10, 20, 30, 999000), datetime(   0, 11, 31, 10, 20, 30, 999900), datetime(   0, 11, 31, 10, 20, 30, 999990), datetime(   0, 11, 31, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yregular_mzero_dzero\",               datetime(2020,  0,  0, 10, 20, 30, 0), datetime(2020,  0,  0, 10, 20, 30, 900000), datetime(2020,  0,  0, 10, 20, 30, 990000), datetime(2020,  0,  0, 10, 20, 30, 999000), datetime(2020,  0,  0, 10, 20, 30, 999900), datetime(2020,  0,  0, 10, 20, 30, 999990), datetime(2020,  0,  0, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yregular_mzero_dregular\",            datetime(2020,  0, 10, 10, 20, 30, 0), datetime(2020,  0, 10, 10, 20, 30, 900000), datetime(2020,  0, 10, 10, 20, 30, 990000), datetime(2020,  0, 10, 10, 20, 30, 999000), datetime(2020,  0, 10, 10, 20, 30, 999900), datetime(2020,  0, 10, 10, 20, 30, 999990), datetime(2020,  0, 10, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yregular_mregular_dzero\",            datetime(2020, 10,  0, 10, 20, 30, 0), datetime(2020, 10,  0, 10, 20, 30, 900000), datetime(2020, 10,  0, 10, 20, 30, 990000), datetime(2020, 10,  0, 10, 20, 30, 999000), datetime(2020, 10,  0, 10, 20, 30, 999900), datetime(2020, 10,  0, 10, 20, 30, 999990), datetime(2020, 10,  0, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yregular_invalid_date\",              datetime(2020, 11, 31, 10, 20, 30, 0), datetime(2020, 11, 31, 10, 20, 30, 900000), datetime(2020, 11, 31, 10, 20, 30, 990000), datetime(2020, 11, 31, 10, 20, 30, 999000), datetime(2020, 11, 31, 10, 20, 30, 999900), datetime(2020, 11, 31, 10, 20, 30, 999990), datetime(2020, 11, 31, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yregular_invalid_date_leapregular\",  datetime(1999,  2, 29, 10, 20, 30, 0), datetime(1999,  2, 29, 10, 20, 30, 900000), datetime(1999,  2, 29, 10, 20, 30, 990000), datetime(1999,  2, 29, 10, 20, 30, 999000), datetime(1999,  2, 29, 10, 20, 30, 999900), datetime(1999,  2, 29, 10, 20, 30, 999990), datetime(1999,  2, 29, 10, 20, 30, 999999));\n    res->add_row(\"hmsu_yregular_invalid_date_leap100\",      datetime(1900,  2, 29, 10, 20, 30, 0), datetime(1900,  2, 29, 10, 20, 30, 900000), datetime(1900,  2, 29, 10, 20, 30, 990000), datetime(1900,  2, 29, 10, 20, 30, 999000), datetime(1900,  2, 29, 10, 20, 30, 999900), datetime(1900,  2, 29, 10, 20, 30, 999990), datetime(1900,  2, 29, 10, 20, 30, 999999));\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\nstatic table_ptr types_timestamp()\n{\n    auto res = make_table<datetime_row>(\"types_timestamp\");\n    res->add_meta(\"field_0\", column_type::timestamp, no_flags, 0, flags_unsigned);\n    res->add_meta(\"field_1\", column_type::timestamp, no_flags, 1, flags_unsigned);\n    res->add_meta(\"field_2\", column_type::timestamp, no_flags, 2, flags_unsigned);\n    res->add_meta(\"field_3\", column_type::timestamp, no_flags, 3, flags_unsigned);\n    res->add_meta(\"field_4\", column_type::timestamp, no_flags, 4, flags_unsigned);\n    res->add_meta(\"field_5\", column_type::timestamp, no_flags, 5, flags_unsigned);\n    res->add_meta(\"field_6\", column_type::timestamp, no_flags, 6, flags_unsigned);\n\n    datetime_timestamp_common_rows(*res);\n\n    // clang-format off\n    res->add_row(\"zero\", datetime(),                            datetime(),                                 datetime(),                                 datetime(),                                 datetime(),                                 datetime(),                                 datetime());\n    res->add_row(\"min\",  datetime(1970,  1,  1,  2,  0,  1, 0), datetime(1970,  1,  1,  2,  0,  1, 0),      datetime(1970,  1,  1,  2,  0,  1,  0),     datetime(1970,  1,  1,  2,  0,  1,   0),    datetime(1970,  1,  1,  2,  0,  1,    0),   datetime(1970,  1,  1,  2,  0,  1,     0),  datetime(1970,  1,  1,  2,  0,  1,      0));\n    res->add_row(\"max\",  datetime(2038,  1, 19,  5, 14,  7, 0), datetime(2038,  1, 19,  5, 14,  7, 900000), datetime(2038,  1, 19,  5, 14,  7, 990000), datetime(2038,  1, 19,  5, 14,  7, 999000), datetime(2038,  1, 19,  5, 14,  7, 999900), datetime(2038,  1, 19,  5, 14,  7, 999990), datetime(2038,  1, 19,  5, 14,  7, 999999));\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// TIME\nstruct time_row\n{\n    std::string id;\n    optional<boost::mysql::time> field_0;\n    optional<boost::mysql::time> field_1;\n    optional<boost::mysql::time> field_2;\n    optional<boost::mysql::time> field_3;\n    optional<boost::mysql::time> field_4;\n    optional<boost::mysql::time> field_5;\n    optional<boost::mysql::time> field_6;\n};\nBOOST_DESCRIBE_STRUCT(time_row, (), (id, field_0, field_1, field_2, field_3, field_4, field_5, field_6))\n\nstatic table_ptr types_time()\n{\n    auto res = make_table<time_row>(\"types_time\");\n    res->add_meta(\"field_0\", column_type::time, no_flags, 0, flags_unsigned);\n    res->add_meta(\"field_1\", column_type::time, no_flags, 1, flags_unsigned);\n    res->add_meta(\"field_2\", column_type::time, no_flags, 2, flags_unsigned);\n    res->add_meta(\"field_3\", column_type::time, no_flags, 3, flags_unsigned);\n    res->add_meta(\"field_4\", column_type::time, no_flags, 4, flags_unsigned);\n    res->add_meta(\"field_5\", column_type::time, no_flags, 5, flags_unsigned);\n    res->add_meta(\"field_6\", column_type::time, no_flags, 6, flags_unsigned);\n\n    // clang-format off\n    res->add_row(\"zero\",            maket( 0,  0,  0),  maket( 0,  0,  0),          maket( 0,  0,  0),          maket( 0,  0,  0),          maket( 0,  0,  0),          maket( 0,  0,  0),          maket( 0,  0,  0));\n    res->add_row(\"d\",               maket(48,  0,  0),  maket(48,  0,  0),          maket(48,  0,  0),          maket(48,  0,  0),          maket(48,  0,  0),          maket(48,  0,  0),          maket(48,  0,  0));\n    res->add_row(\"negative_d\",     -maket(48,  0,  0), -maket(48,  0,  0),         -maket(48,  0,  0),         -maket(48,  0,  0),         -maket(48,  0,  0),         -maket(48,  0,  0),         -maket(48,  0,  0));\n    res->add_row(\"h\",               maket(23,  0,  0),  maket(23,  0,  0),          maket(23,  0,  0),          maket(23,  0,  0),          maket(23,  0,  0),          maket(23,  0,  0),          maket(23,  0,  0));\n    res->add_row(\"negative_h\",     -maket(23,  0,  0), -maket(23,  0,  0),         -maket(23,  0,  0),         -maket(23,  0,  0),         -maket(23,  0,  0),         -maket(23,  0,  0),         -maket(23,  0,  0));\n    res->add_row(\"dh\",              maket(71,  0,  0),  maket(71,  0,  0),          maket(71,  0,  0),          maket(71,  0,  0),          maket(71,  0,  0),          maket(71,  0,  0),          maket(71,  0,  0));\n    res->add_row(\"negative_dh\",    -maket(71,  0,  0), -maket(71,  0,  0),         -maket(71,  0,  0),         -maket(71,  0,  0),         -maket(71,  0,  0),         -maket(71,  0,  0),         -maket(71,  0,  0));\n    res->add_row(\"m\",               maket( 0,  1,  0),  maket( 0,  1,  0),          maket( 0,  1,  0),          maket( 0,  1,  0),          maket( 0,  1,  0),          maket( 0,  1,  0),          maket( 0,  1,  0));\n    res->add_row(\"negative_m\",     -maket( 0,  1,  0), -maket( 0,  1,  0),         -maket( 0,  1,  0),         -maket( 0,  1,  0),         -maket( 0,  1,  0),         -maket( 0,  1,  0),         -maket( 0,  1,  0));\n    res->add_row(\"dm\",              maket(48,  1,  0),  maket(48,  1,  0),          maket(48,  1,  0),          maket(48,  1,  0),          maket(48,  1,  0),          maket(48,  1,  0),          maket(48,  1,  0));\n    res->add_row(\"negative_dm\",    -maket(48,  1,  0), -maket(48,  1,  0),         -maket(48,  1,  0),         -maket(48,  1,  0),         -maket(48,  1,  0),         -maket(48,  1,  0),         -maket(48,  1,  0));\n    res->add_row(\"hm\",              maket(23,  1,  0),  maket(23,  1,  0),          maket(23,  1,  0),          maket(23,  1,  0),          maket(23,  1,  0),          maket(23,  1,  0),          maket(23,  1,  0));\n    res->add_row(\"negative_hm\",    -maket(23,  1,  0), -maket(23,  1,  0),         -maket(23,  1,  0),         -maket(23,  1,  0),         -maket(23,  1,  0),         -maket(23,  1,  0),         -maket(23,  1,  0));\n    res->add_row(\"dhm\",             maket(71,  1,  0),  maket(71,  1,  0),          maket(71,  1,  0),          maket(71,  1,  0),          maket(71,  1,  0),          maket(71,  1,  0),          maket(71,  1,  0));\n    res->add_row(\"negative_dhm\",   -maket(71,  1,  0), -maket(71,  1,  0),         -maket(71,  1,  0),         -maket(71,  1,  0),         -maket(71,  1,  0),         -maket(71,  1,  0),         -maket(71,  1,  0));\n    res->add_row(\"s\",               maket( 0,  0, 50),  maket( 0,  0, 50),          maket( 0,  0, 50),          maket( 0,  0, 50),          maket( 0,  0, 50),          maket( 0,  0, 50),          maket( 0,  0, 50));\n    res->add_row(\"negative_s\",     -maket( 0,  0, 50), -maket( 0,  0, 50),         -maket( 0,  0, 50),         -maket( 0,  0, 50),         -maket( 0,  0, 50),         -maket( 0,  0, 50),         -maket( 0,  0, 50));\n    res->add_row(\"ds\",              maket(48,  0, 50),  maket(48,  0, 50),          maket(48,  0, 50),          maket(48,  0, 50),          maket(48,  0, 50),          maket(48,  0, 50),          maket(48,  0, 50));\n    res->add_row(\"negative_ds\",    -maket(48,  0, 50), -maket(48,  0, 50),         -maket(48,  0, 50),         -maket(48,  0, 50),         -maket(48,  0, 50),         -maket(48,  0, 50),         -maket(48,  0, 50));\n    res->add_row(\"hs\",              maket(23,  0, 50),  maket(23,  0, 50),          maket(23,  0, 50),          maket(23,  0, 50),          maket(23,  0, 50),          maket(23,  0, 50),          maket(23,  0, 50));\n    res->add_row(\"negative_hs\",    -maket(23,  0, 50), -maket(23,  0, 50),         -maket(23,  0, 50),         -maket(23,  0, 50),         -maket(23,  0, 50),         -maket(23,  0, 50),         -maket(23,  0, 50));\n    res->add_row(\"dhs\",             maket(71,  0, 50),  maket(71,  0, 50),          maket(71,  0, 50),          maket(71,  0, 50),          maket(71,  0, 50),          maket(71,  0, 50),          maket(71,  0, 50));\n    res->add_row(\"negative_dhs\",   -maket(71,  0, 50), -maket(71,  0, 50),         -maket(71,  0, 50),         -maket(71,  0, 50),         -maket(71,  0, 50),         -maket(71,  0, 50),         -maket(71,  0, 50));\n    res->add_row(\"ms\",              maket( 0,  1, 50),  maket( 0,  1, 50),          maket( 0,  1, 50),          maket( 0,  1, 50),          maket( 0,  1, 50),          maket( 0,  1, 50),          maket( 0,  1, 50));\n    res->add_row(\"negative_ms\",    -maket( 0,  1, 50), -maket( 0,  1, 50),         -maket( 0,  1, 50),         -maket( 0,  1, 50),         -maket( 0,  1, 50),         -maket( 0,  1, 50),         -maket( 0,  1, 50));\n    res->add_row(\"dms\",             maket(48,  1, 50),  maket(48,  1, 50),          maket(48,  1, 50),          maket(48,  1, 50),          maket(48,  1, 50),          maket(48,  1, 50),          maket(48,  1, 50));\n    res->add_row(\"negative_dms\",   -maket(48,  1, 50), -maket(48,  1, 50),         -maket(48,  1, 50),         -maket(48,  1, 50),         -maket(48,  1, 50),         -maket(48,  1, 50),         -maket(48,  1, 50));\n    res->add_row(\"hms\",             maket(23,  1, 50),  maket(23,  1, 50),          maket(23,  1, 50),          maket(23,  1, 50),          maket(23,  1, 50),          maket(23,  1, 50),          maket(23,  1, 50));\n    res->add_row(\"negative_hms\",   -maket(23,  1, 50), -maket(23,  1, 50),         -maket(23,  1, 50),         -maket(23,  1, 50),         -maket(23,  1, 50),         -maket(23,  1, 50),         -maket(23,  1, 50));\n    res->add_row(\"dhms\",            maket(71,  1, 50),  maket(71,  1, 50),          maket(71,  1, 50),          maket(71,  1, 50),          maket(71,  1, 50),          maket(71,  1, 50),          maket(71,  1, 50));\n    res->add_row(\"negative_dhms\",  -maket(71,  1, 50), -maket(71,  1, 50),         -maket(71,  1, 50),         -maket(71,  1, 50),         -maket(71,  1, 50),         -maket(71,  1, 50),         -maket(71,  1, 50));\n    res->add_row(\"u\",              none,                maket( 0,  0,  0, 100000),  maket( 0,  0,  0, 120000),  maket( 0,  0,  0, 123000),  maket( 0,  0,  0, 123400),  maket( 0,  0,  0, 123450),  maket( 0,  0,  0,  123456));\n    res->add_row(\"negative_u\",     none,               -maket( 0,  0,  0, 100000), -maket( 0,  0,  0, 120000), -maket( 0,  0,  0, 123000), -maket( 0,  0,  0, 123400), -maket( 0,  0,  0, 123450), -maket( 0,  0,  0,  123456));\n    res->add_row(\"du\",             none,                maket(48,  0,  0, 100000),  maket(48,  0,  0, 120000),  maket(48,  0,  0, 123000),  maket(48,  0,  0, 123400),  maket(48,  0,  0, 123450),  maket(48,  0,  0,  123456));\n    res->add_row(\"negative_du\",    none,               -maket(48,  0,  0, 100000), -maket(48,  0,  0, 120000), -maket(48,  0,  0, 123000), -maket(48,  0,  0, 123400), -maket(48,  0,  0, 123450), -maket(48,  0,  0,  123456));\n    res->add_row(\"hu\",             none,                maket(23,  0,  0, 100000),  maket(23,  0,  0, 120000),  maket(23,  0,  0, 123000),  maket(23,  0,  0, 123400),  maket(23,  0,  0, 123450),  maket(23,  0,  0,  123456));\n    res->add_row(\"negative_hu\",    none,               -maket(23,  0,  0, 100000), -maket(23,  0,  0, 120000), -maket(23,  0,  0, 123000), -maket(23,  0,  0, 123400), -maket(23,  0,  0, 123450), -maket(23,  0,  0,  123456));\n    res->add_row(\"dhu\",            none,                maket(71,  0,  0, 100000),  maket(71,  0,  0, 120000),  maket(71,  0,  0, 123000),  maket(71,  0,  0, 123400),  maket(71,  0,  0, 123450),  maket(71,  0,  0,  123456));\n    res->add_row(\"negative_dhu\",   none,               -maket(71,  0,  0, 100000), -maket(71,  0,  0, 120000), -maket(71,  0,  0, 123000), -maket(71,  0,  0, 123400), -maket(71,  0,  0, 123450), -maket(71,  0,  0,  123456));\n    res->add_row(\"mu\",             none,                maket( 0,  1,  0, 100000),  maket( 0,  1,  0, 120000),  maket( 0,  1,  0, 123000),  maket( 0,  1,  0, 123400),  maket( 0,  1,  0, 123450),  maket( 0,  1,  0,  123456));\n    res->add_row(\"negative_mu\",    none,               -maket( 0,  1,  0, 100000), -maket( 0,  1,  0, 120000), -maket( 0,  1,  0, 123000), -maket( 0,  1,  0, 123400), -maket( 0,  1,  0, 123450), -maket( 0,  1,  0,  123456));\n    res->add_row(\"dmu\",            none,                maket(48,  1,  0, 100000),  maket(48,  1,  0, 120000),  maket(48,  1,  0, 123000),  maket(48,  1,  0, 123400),  maket(48,  1,  0, 123450),  maket(48,  1,  0,  123456));\n    res->add_row(\"negative_dmu\",   none,               -maket(48,  1,  0, 100000), -maket(48,  1,  0, 120000), -maket(48,  1,  0, 123000), -maket(48,  1,  0, 123400), -maket(48,  1,  0, 123450), -maket(48,  1,  0,  123456));\n    res->add_row(\"hmu\",            none,                maket(23,  1,  0, 100000),  maket(23,  1,  0, 120000),  maket(23,  1,  0, 123000),  maket(23,  1,  0, 123400),  maket(23,  1,  0, 123450),  maket(23,  1,  0,  123456));\n    res->add_row(\"negative_hmu\",   none,               -maket(23,  1,  0, 100000), -maket(23,  1,  0, 120000), -maket(23,  1,  0, 123000), -maket(23,  1,  0, 123400), -maket(23,  1,  0, 123450), -maket(23,  1,  0,  123456));\n    res->add_row(\"dhmu\",           none,                maket(71,  1,  0, 100000),  maket(71,  1,  0, 120000),  maket(71,  1,  0, 123000),  maket(71,  1,  0, 123400),  maket(71,  1,  0, 123450),  maket(71,  1,  0,  123456));\n    res->add_row(\"negative_dhmu\",  none,               -maket(71,  1,  0, 100000), -maket(71,  1,  0, 120000), -maket(71,  1,  0, 123000), -maket(71,  1,  0, 123400), -maket(71,  1,  0, 123450), -maket(71,  1,  0,  123456));\n    res->add_row(\"su\",             none,                maket( 0,  0, 50, 100000),  maket( 0,  0, 50, 120000),  maket( 0,  0, 50, 123000),  maket( 0,  0, 50, 123400),  maket( 0,  0, 50, 123450),  maket( 0,  0, 50,  123456));\n    res->add_row(\"negative_su\",    none,               -maket( 0,  0, 50, 100000), -maket( 0,  0, 50, 120000), -maket( 0,  0, 50, 123000), -maket( 0,  0, 50, 123400), -maket( 0,  0, 50, 123450), -maket( 0,  0, 50,  123456));\n    res->add_row(\"dsu\",            none,                maket(48,  0, 50, 100000),  maket(48,  0, 50, 120000),  maket(48,  0, 50, 123000),  maket(48,  0, 50, 123400),  maket(48,  0, 50, 123450),  maket(48,  0, 50,  123456));\n    res->add_row(\"negative_dsu\",   none,               -maket(48,  0, 50, 100000), -maket(48,  0, 50, 120000), -maket(48,  0, 50, 123000), -maket(48,  0, 50, 123400), -maket(48,  0, 50, 123450), -maket(48,  0, 50,  123456));\n    res->add_row(\"hsu\",            none,                maket(23,  0, 50, 100000),  maket(23,  0, 50, 120000),  maket(23,  0, 50, 123000),  maket(23,  0, 50, 123400),  maket(23,  0, 50, 123450),  maket(23,  0, 50,  123456));\n    res->add_row(\"negative_hsu\",   none,               -maket(23,  0, 50, 100000), -maket(23,  0, 50, 120000), -maket(23,  0, 50, 123000), -maket(23,  0, 50, 123400), -maket(23,  0, 50, 123450), -maket(23,  0, 50,  123456));\n    res->add_row(\"dhsu\",           none,                maket(71,  0, 50, 100000),  maket(71,  0, 50, 120000),  maket(71,  0, 50, 123000),  maket(71,  0, 50, 123400),  maket(71,  0, 50, 123450),  maket(71,  0, 50,  123456));\n    res->add_row(\"negative_dhsu\",  none,               -maket(71,  0, 50, 100000), -maket(71,  0, 50, 120000), -maket(71,  0, 50, 123000), -maket(71,  0, 50, 123400), -maket(71,  0, 50, 123450), -maket(71,  0, 50,  123456));\n    res->add_row(\"msu\",            none,                maket( 0,  1, 50, 100000),  maket( 0,  1, 50, 120000),  maket( 0,  1, 50, 123000),  maket( 0,  1, 50, 123400),  maket( 0,  1, 50, 123450),  maket( 0,  1, 50,  123456));\n    res->add_row(\"negative_msu\",   none,               -maket( 0,  1, 50, 100000), -maket( 0,  1, 50, 120000), -maket( 0,  1, 50, 123000), -maket( 0,  1, 50, 123400), -maket( 0,  1, 50, 123450), -maket( 0,  1, 50,  123456));\n    res->add_row(\"dmsu\",           none,                maket(48,  1, 50, 100000),  maket(48,  1, 50, 120000),  maket(48,  1, 50, 123000),  maket(48,  1, 50, 123400),  maket(48,  1, 50, 123450),  maket(48,  1, 50,  123456));\n    res->add_row(\"negative_dmsu\",  none,               -maket(48,  1, 50, 100000), -maket(48,  1, 50, 120000), -maket(48,  1, 50, 123000), -maket(48,  1, 50, 123400), -maket(48,  1, 50, 123450), -maket(48,  1, 50,  123456));\n    res->add_row(\"hmsu\",           none,                maket(23,  1, 50, 100000),  maket(23,  1, 50, 120000),  maket(23,  1, 50, 123000),  maket(23,  1, 50, 123400),  maket(23,  1, 50, 123450),  maket(23,  1, 50,  123456));\n    res->add_row(\"negative_hmsu\",  none,               -maket(23,  1, 50, 100000), -maket(23,  1, 50, 120000), -maket(23,  1, 50, 123000), -maket(23,  1, 50, 123400), -maket(23,  1, 50, 123450), -maket(23,  1, 50,  123456));\n    res->add_row(\"dhmsu\",          none,                maket(71,  1, 50, 100000),  maket(71,  1, 50, 120000),  maket(71,  1, 50, 123000),  maket(71,  1, 50, 123400),  maket(71,  1, 50, 123450),  maket(71,  1, 50,  123456));\n    res->add_row(\"negative_dhmsu\", none,               -maket(71,  1, 50, 100000), -maket(71,  1, 50, 120000), -maket(71,  1, 50, 123000), -maket(71,  1, 50, 123400), -maket(71,  1, 50, 123450), -maket(71,  1, 50,  123456));\n    res->add_row(\"min\",            -maket(838, 59, 59),-maket(838,59, 58, 900000), -maket(838, 59, 58, 990000),-maket(838, 59, 58, 999000),-maket(838, 59, 58, 999900),-maket(838,59, 58, 999990), -maket(838,59, 58,  999999));\n    res->add_row(\"max\",             maket(838, 59, 59), maket(838,59, 58, 900000),  maket(838, 59, 58, 990000), maket(838, 59, 58, 999000), maket(838, 59, 58, 999900), maket(838,59, 58, 999990),  maket(838,59, 58,  999999));\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// string types\nstruct string_row\n{\n    std::string id;\n    optional<std::string> field_char;\n    optional<std::string> field_varchar;\n    optional<std::string> field_tinytext;\n    optional<std::string> field_text;\n    optional<std::string> field_mediumtext;\n    optional<std::string> field_longtext;\n    optional<std::string> field_text_bincol;\n    optional<std::string> field_enum;\n    optional<std::string> field_set;\n};\nBOOST_DESCRIBE_STRUCT(\n    string_row,\n    (),\n    (id,\n     field_char,\n     field_varchar,\n     field_tinytext,\n     field_text,\n     field_mediumtext,\n     field_longtext,\n     field_text_bincol,\n     field_enum,\n     field_set)\n)\n\nstatic table_ptr types_string()\n{\n    auto res = make_table<string_row>(\"types_string\");\n    res->add_meta(\"field_char\", column_type::char_);\n    res->add_meta(\"field_varchar\", column_type::varchar);\n    res->add_meta(\"field_tinytext\", column_type::text);\n    res->add_meta(\"field_text\", column_type::text);\n    res->add_meta(\"field_mediumtext\", column_type::text);\n    res->add_meta(\"field_longtext\", column_type::text);\n    res->add_meta(\"field_text_bincol\", column_type::text);\n    res->add_meta(\"field_enum\", column_type::enum_);\n    res->add_meta(\"field_set\", column_type::set);\n\n    using std::string;\n\n    // clang-format off\n    res->add_row(\"regular\", string(\"test_char\"), string(\"test_varchar\"), string(\"test_tinytext\"), string(\"test_text\"), string(\"test_mediumtext\"), string(\"test_longtext\"), string(\"test_bincol\"), string(\"red\"),    string(\"red,green\"));\n    res->add_row(\"utf8\",    string(\"\\xc3\\xb1\"),  string(\"\\xc3\\x91\"),     string(\"\\xc3\\xa1\"),      string(\"\\xc3\\xa9\"),  string(\"\\xc3\\xad\"),        string(\"\\xc3\\xb3\"),      string(\"\\xc3\\xba\"),    none,             none);\n    res->add_row(\"empty\",   string(),            string(),               string(),                string(),            string(),                  string(),                string(),              none,             string());\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// JSON\nstruct json_row\n{\n    std::string id;\n    optional<std::string> field_json;\n};\nBOOST_DESCRIBE_STRUCT(json_row, (), (id, field_json))\n\nstatic table_ptr types_json()\n{\n    // MariaDB doesn't have a dedicated column type, so there is a difference in metadata.\n    // Values should be the same, though.\n    auto res = make_table<json_row>(\"types_json\");\n    res->add_meta(\"field_json\", get_server_features().json_type ? column_type::json : column_type::text);\n\n    using std::string;\n\n    // clang-format off\n    res->add_row(\"regular\",        string(R\"([null, 42, false, \"abc\", {\"key\": \"value\"}])\"));\n    res->add_row(\"unicode_escape\", string(R\"([\"\\u0000value\\u0000\"])\"));\n    res->add_row(\"utf8\",           string(\"[\\\"adi\\xc3\\xb3s\\\"]\"));\n    res->add_row(\"empty\",          string(\"{}\"));\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// Binary types\nstruct binary_row\n{\n    std::string id;\n    optional<blob> field_binary;\n    optional<blob> field_varbinary;\n    optional<blob> field_tinyblob;\n    optional<blob> field_blob;\n    optional<blob> field_mediumblob;\n    optional<blob> field_longblob;\n};\nBOOST_DESCRIBE_STRUCT(\n    binary_row,\n    (),\n    (id, field_binary, field_varbinary, field_tinyblob, field_blob, field_mediumblob, field_longblob)\n)\n\nstatic table_ptr types_binary()\n{\n    auto res = make_table<binary_row>(\"types_binary\");\n    res->add_meta(\"field_binary\", column_type::binary);\n    res->add_meta(\"field_varbinary\", column_type::varbinary);\n    res->add_meta(\"field_tinyblob\", column_type::blob);\n    res->add_meta(\"field_blob\", column_type::blob);\n    res->add_meta(\"field_mediumblob\", column_type::blob);\n    res->add_meta(\"field_longblob\", column_type::blob);\n\n    // clang-format off\n    res->add_row(\"regular\",  makeb(\"\\0_binary\\0\\0\"),          makeb(\"\\0_varbinary\"),  makeb(\"\\0_tinyblob\"),  makeb(\"\\0_blob\"),  makeb(\"\\0_mediumblob\"), makeb(\"\\0_longblob\"));\n    res->add_row(\"nonascii\", makeb(\"\\0\\xff\\0\\0\\0\\0\\0\\0\\0\\0\"), makeb(\"\\1\\xfe\"),        makeb(\"\\2\\xfd\"),       makeb(\"\\3\\xfc\"),   makeb(\"\\4\\xfb\"),        makeb(\"\\5\\xfa\"));\n    res->add_row(\"empty\",    makeb(\"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"),   blob(),                 blob(),                blob(),            blob(),                 blob());\n    // clang-format on\n    return table_ptr(std::move(res));\n}\n\n// These types don't have a better representation, and we represent\n// them as strings or binary\nstruct not_implemented_row\n{\n    std::string id;\n    optional<std::string> field_decimal;\n    optional<blob> field_geometry;\n};\nBOOST_DESCRIBE_STRUCT(not_implemented_row, (), (id, field_decimal, field_geometry))\n\nstatic table_ptr types_not_implemented()\n{\n    auto res = make_table<not_implemented_row>(\"types_not_implemented\");\n    res->add_meta(\"field_decimal\", column_type::decimal);\n    res->add_meta(\"field_geometry\", column_type::geometry);\n\n    blob geometry_value{0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n                        0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40};\n\n    res->add_row(\"regular\", std::string(\"300\"), geometry_value);\n    return table_ptr(std::move(res));\n}\n\n// Tests for certain metadata flags\nstruct flags_row\n{\n    std::string id;\n    optional<datetime> field_timestamp;\n    int field_primary_key;\n    std::string field_not_null;\n    optional<int> field_unique;\n    optional<int> field_indexed;\n};\nBOOST_DESCRIBE_STRUCT(\n    flags_row,\n    (),\n    (id, field_timestamp, field_primary_key, field_not_null, field_unique, field_indexed)\n)\n\nstatic table_ptr types_flags()\n{\n    auto res = make_table<flags_row>(\"types_flags\");\n    res->add_meta(\n        \"field_timestamp\",\n        column_type::timestamp,\n        flagsvec{&metadata::is_set_to_now_on_update},\n        0,\n        flags_unsigned\n    );\n    res->add_meta(\n        \"field_primary_key\",\n        column_type::int_,\n        flagsvec{&metadata::is_primary_key, &metadata::is_not_null, &metadata::is_auto_increment}\n    );\n    res->add_meta(\"field_not_null\", column_type::char_, flagsvec{&metadata::is_not_null});\n    res->add_meta(\"field_unique\", column_type::int_, flagsvec{&metadata::is_unique_key});\n    res->add_meta(\"field_indexed\", column_type::int_, flagsvec{&metadata::is_multiple_key});\n\n    res->add_row(\"default\", none, 50, \"char\", 21, 42);\n    return table_ptr(std::move(res));\n}\n\nstd::vector<table_ptr> make_all_tables()\n{\n    std::vector<table_ptr> res;\n    res.push_back(types_tinyint());\n    res.push_back(types_smallint());\n    res.push_back(types_mediumint());\n    res.push_back(types_int());\n    res.push_back(types_bigint());\n    res.push_back(types_year());\n    res.push_back(types_bool());\n    res.push_back(types_bit());\n    res.push_back(types_float());\n    res.push_back(types_double());\n    res.push_back(types_date());\n    res.push_back(types_datetime());\n    res.push_back(types_timestamp());\n    res.push_back(types_time());\n    res.push_back(types_string());\n    res.push_back(types_json());\n    res.push_back(types_binary());\n    res.push_back(types_not_implemented());\n    res.push_back(types_flags());\n    return res;\n}\n\nconst std::vector<table_ptr>& all_tables()\n{\n    static std::vector<table_ptr> res = make_all_tables();\n    return res;\n}\n\nBOOST_FIXTURE_TEST_CASE(query_read, database_types_fixture)\n{\n    for (const auto& table : all_tables())\n    {\n        BOOST_TEST_CONTEXT(table->name)\n        {\n            // Execute the query\n            results result;\n            conn.async_execute(table->select_sql(), result, as_netresult).validate_no_error();\n\n            // Validate the received contents\n            validate_meta(result.meta(), table->metas);\n            table->validate_rows(result.rows());\n        }\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(sql_format_query_write, database_types_fixture)\n{\n    start_transaction();\n\n    for (const auto& table : all_tables())\n    {\n        BOOST_TEST_CONTEXT(table->name)\n        {\n            // Remove all contents from the table\n            results result;\n            conn.async_execute(table->delete_sql(), result, as_netresult).validate_no_error();\n\n            // Insert all the contents again\n            conn.async_execute(table->insert_sql(), result, as_netresult).validate_no_error();\n\n            // Query them again and verify the insertion was okay\n            conn.async_execute(table->select_sql(), result, as_netresult).validate_no_error();\n            validate_meta(result.meta(), table->metas);\n            table->validate_rows(result.rows());\n        }\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(statement_read, database_types_fixture)\n{\n    for (const auto& table : all_tables())\n    {\n        BOOST_TEST_CONTEXT(table->name)\n        {\n            // Prepare the statement\n            auto stmt = conn.async_prepare_statement(table->select_sql(), as_netresult).get();\n\n            // Execute it with the provided parameters\n            results result;\n            conn.async_execute(stmt.bind(), result, as_netresult).validate_no_error();\n\n            // Validate the received contents\n            validate_meta(result.meta(), table->metas);\n            table->validate_rows(result.rows());\n        }\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(statement_write, database_types_fixture)\n{\n    start_transaction();\n\n    for (const auto& table : all_tables())\n    {\n        BOOST_TEST_CONTEXT(table->name)\n        {\n            // Prepare the statements\n            auto insert_stmt = conn.async_prepare_statement(table->insert_sql_stmt(), as_netresult).get();\n            auto query_stmt = conn.async_prepare_statement(table->select_sql(), as_netresult).get();\n\n            // Remove all contents from the table\n            results result;\n            conn.async_execute(table->delete_sql(), result, as_netresult).validate_no_error();\n\n            // Insert all the contents again\n            for (const auto& row : table->rws)\n            {\n                conn.async_execute(insert_stmt.bind(row.begin(), row.end()), result, as_netresult)\n                    .validate_no_error();\n            }\n\n            // Query them again and verify the insertion was okay\n            conn.async_execute(query_stmt.bind(), result, as_netresult).validate_no_error();\n            validate_meta(result.meta(), table->metas);\n            table->validate_rows(result.rows());\n        }\n    }\n}\n\n#ifdef BOOST_MYSQL_CXX14\nBOOST_FIXTURE_TEST_CASE(static_interface, database_types_fixture)\n{\n    for (const auto& table : all_tables())\n    {\n        BOOST_TEST_CONTEXT(table->name)\n        {\n            // All the test is type-specific\n            table->select_static(conn);\n        }\n    }\n}\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()  // test_database_types\n"
  },
  {
    "path": "test/integration/test/db_specific.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/mariadb_server_errc.hpp>\n#include <boost/mysql/mysql_server_errc.hpp>\n#include <boost/mysql/results.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/server_features.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_db_specific)\n\nBOOST_TEST_DECORATOR(*run_if(&server_features::regex_error_codes))\nBOOST_FIXTURE_TEST_CASE(mysql_specific_error_code, any_connection_fixture)\n{\n    connect();\n    results result;\n\n    // This is reported as a common, less descriptive error in MySQL5 and MariaDB\n    error_code expected_ec(mysql_server_errc::er_regexp_mismatched_paren, get_mysql_server_category());\n    conn.async_execute(\"select * from one_row_table where field_varchar regexp '(('\", result, as_netresult)\n        .validate_error(expected_ec, create_server_diag(\"Mismatched parenthesis in regular expression.\"));\n}\n\nBOOST_TEST_DECORATOR(*run_if(&server_features::dup_query_error_codes))\nBOOST_FIXTURE_TEST_CASE(mariadb_specific_error_code, any_connection_fixture)\n{\n    connect();\n    results result;\n\n    // This is reported as a common error in MySQL5 and MySQL8\n    error_code expected_ec(mariadb_server_errc::er_dup_query_name, get_mariadb_server_category());\n    conn.async_execute(\"WITH abc AS (SELECT 1), abc as (SELECT 2) SELECT * FROM abc\", result, as_netresult)\n        .validate_error(expected_ec, create_server_diag(\"Duplicate query name `abc` in WITH clause\"));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/execution_requests.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/deferred.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <forward_list>\n#include <functional>\n#include <string>\n#include <vector>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/has_ranges.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n\n#ifdef BOOST_MYSQL_HAS_RANGES\n#include <ranges>\n#endif\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\nnamespace asio = boost::asio;\n\n// Cover all possible execution requests for execute() and async_execute()\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_execution_requests)\n\nBOOST_FIXTURE_TEST_CASE(query, any_connection_fixture)\n{\n    // Setup\n    connect();\n    results r;\n    execution_state st;\n\n    // execute\n    conn.async_execute(\"SELECT 1\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, 1), per_element());\n\n    // types convertible to string_view work\n    conn.async_execute(std::string(\"SELECT 1\"), r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, 1), per_element());\n\n    // spotcheck: start execution with a text query works\n    conn.async_start_execution(\"SELECT 1\", st, as_netresult).validate_no_error();\n    auto rws = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rws == makerows(1, 1), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(stmt_tuple, any_connection_fixture)\n{\n    // Also verifies that tuples correctly apply the writable field transformation\n    // Setup\n    connect();\n    results r;\n    execution_state st;\n    auto stmt = conn.async_prepare_statement(\"SELECT ?, ?\", as_netresult).get();\n    BOOST_TEST_REQUIRE(stmt.num_params() == 2u);\n\n    // execute\n    conn.async_execute(stmt.bind(\"42\", boost::optional<int>(13)), r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, \"42\", 13), per_element());\n\n    // references work\n    std::string s = \"abcdef\";\n    auto op = conn.async_execute(stmt.bind(std::ref(s), 21), r, asio::deferred);\n    s = \"opqrs\";\n    std::move(op)(as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, \"opqrs\", 21), per_element());\n\n    // spotcheck: start execution with tuples works\n    conn.async_start_execution(stmt.bind(\"abc\", boost::optional<int>()), st, as_netresult)\n        .validate_no_error();\n    auto rws = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rws == makerows(2, \"abc\", nullptr), per_element());\n\n    // spotcheck: errors correctly detected\n    conn.async_execute(stmt.bind(\"42\"), r, as_netresult).validate_error(client_errc::wrong_num_params);\n\n    // spotcheck: lvalues work\n    const auto bound_stmt = stmt.bind(\"42\", boost::optional<int>());\n    conn.async_execute(bound_stmt, r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, \"42\", nullptr), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(stmt_range, any_connection_fixture)\n{\n    // Setup\n    connect();\n    results r;\n    execution_state st;\n    std::forward_list<field_view> params{field_view(42), field_view(\"abc\")};\n    auto stmt = conn.async_prepare_statement(\"SELECT ?, ?\", as_netresult).get();\n    BOOST_TEST_REQUIRE(stmt.num_params() == 2u);\n\n    // execute\n    conn.async_execute(stmt.bind(params.begin(), params.end()), r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 42, \"abc\"), per_element());\n\n    // spotcheck: statement with ranges work with start execution\n    conn.async_start_execution(stmt.bind(params.begin(), params.end()), st, as_netresult).validate_no_error();\n    auto rws = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rws == makerows(2, 42, \"abc\"), per_element());\n\n    // Regression check: executing with a type convertible (but not equal) to field_view works\n    const std::vector<field> owning_params{field_view(50), field_view(\"luv\")};\n    conn.async_execute(stmt.bind(owning_params.begin(), owning_params.end()), r, as_netresult)\n        .validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 50, \"luv\"), per_element());\n\n    // Spotcheck: errors detected\n    auto too_few_params = make_fv_arr(1);\n    conn.async_execute(stmt.bind(too_few_params.begin(), too_few_params.end()), r, as_netresult)\n        .validate_error(client_errc::wrong_num_params);\n\n    // Spotchecks: lvalues work\n    auto bound_stmt = stmt.bind(params.begin(), params.end());\n    conn.async_execute(bound_stmt, r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 42, \"abc\"), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(with_params_, any_connection_fixture)\n{\n    // Setup\n    connect();\n    results r;\n    execution_state st;\n\n    // execute\n    conn.async_execute(with_params(\"SELECT {}, {}\", 42, \"abc\"), r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 42, \"abc\"), per_element());\n\n    // spotcheck: can be used with start_execution\n    conn.async_start_execution(with_params(\"SELECT {}, {}\", 42, \"abc\"), st, as_netresult).validate_no_error();\n    auto rws = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rws == makerows(2, 42, \"abc\"), per_element());\n\n    // references work\n    std::string s = \"abcdef\";\n    auto op = conn.async_execute(with_params(\"SELECT {}, {}\", 42, std::ref(s)), r, asio::deferred);\n    s = \"opqrs\";\n    std::move(op)(as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 42, \"opqrs\"), per_element());\n\n    // Queries without parameters work\n    conn.async_execute(with_params(\"SELECT '{{}}'\"), r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, \"{}\"), per_element());\n\n    // lvalues work\n    const auto req = with_params(\"SELECT {}, {}\", \"42\", boost::optional<int>(100));\n    conn.async_execute(req, r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, \"42\", 100), per_element());\n\n#ifdef BOOST_MYSQL_HAS_RANGES\n    // Regression check: mutable ranges work\n    std::vector<int> nums{2, 5, 10, 20};\n    auto is_even = [](int i) { return i % 2 == 0; };\n    conn.async_execute(with_params(\"SELECT {}\", std::ranges::views::filter(nums, is_even)), r, as_netresult)\n        .validate_no_error();\n    BOOST_TEST(r.rows() == makerows(3, 2, 10, 20), per_element());\n#endif\n\n    // Error: unformattable values\n    conn.async_execute(with_params(\"SELECT {}\", \"bad\\xffutf8\"), r, as_netresult)\n        .validate_error(client_errc::invalid_encoding);\n\n    // Error: unknown charset\n    conn.async_reset_connection(as_netresult).validate_no_error();\n    conn.async_execute(with_params(\"SELECT {}\", 42), r, as_netresult)\n        .validate_error(client_errc::unknown_character_set);\n}\n\n// Spotcheck: with_params() is owning, and can be safely used\n// together with sequence() in deferred ops without incurring in lifetime problems\nBOOST_FIXTURE_TEST_CASE(with_params_sequence_deferred, any_connection_fixture)\n{\n    // Setup\n    connect();\n    results r;\n    auto fn = [](int value, format_context_base& fmt_ctx) { fmt_ctx.append_value(value); };\n\n    // Create a deferred op\n    auto op = conn.async_execute(\n        with_params(\"SELECT {}, {}\", sequence(std::vector<int>{3, 4, 7}, fn, \" + \"), std::string(10, 'a')),\n        r,\n        asio::deferred\n    );\n\n    // Run it\n    std::move(op)(as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(2, 14, \"aaaaaaaaaa\"), per_element());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/handshake.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/tcp_ssl.hpp>\n#include <boost/mysql/unix.hpp>\n#include <boost/mysql/unix_ssl.hpp>\n\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/local/stream_protocol.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/ssl/host_name_verification.hpp>\n#include <boost/asio/ssl/verify_mode.hpp>\n#include <boost/assert/source_location.hpp>\n#include <boost/test/data/monomorphic/collection.hpp>\n#include <boost/test/data/test_case.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <ostream>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/netfun_maker.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/source_location.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/server_ca.hpp\"\n#include \"test_integration/server_features.hpp\"\n#include \"test_integration/tcp_connection_fixture.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\nnamespace asio = boost::asio;\nnamespace data = boost::unit_test::data;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake)\n\n// Handshake is the most convoluted part of MySQL protocol,\n// and is in active development in current MySQL versions.\n// We try to test all combinations of auth methods/transports.\n// Note that fixtures take care of closing the connection can be closed successfully\nstruct transport_test_case\n{\n    string_view name;\n    connect_params params;\n    bool expect_ssl;\n};\nstd::ostream& operator<<(std::ostream& os, const transport_test_case& tc) { return os << tc.name; }\n\nstd::vector<transport_test_case> make_all_transports()\n{\n    std::vector<transport_test_case> res{\n        {\"tcp\",     connect_params_builder().ssl(ssl_mode::disable).build(), false},\n        {\"tcp_ssl\", connect_params_builder().ssl(ssl_mode::require).build(), true },\n    };\n\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\n    if (get_server_features().unix_sockets)\n    {\n        res.push_back({\"unix\", connect_params_builder().set_unix().build(), false});\n    }\n#endif\n\n    return res;\n}\n\nauto all_transports = make_all_transports();\n\n// Check whether the connection is using SSL or not\ntemplate <class Conn>\nvoid check_ssl(Conn& conn, bool expected, boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION)\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc)\n    {\n        // Check that the client thinks it's using SSL\n        BOOST_TEST(conn.uses_ssl() == expected);\n\n        // Check that the server is using SSL\n        results r;\n        conn.async_execute(\"SHOW STATUS LIKE 'ssl_version'\", r, as_netresult).validate_no_error(loc);\n        bool server_tls = r.rows().at(0).at(1).as_string().starts_with(\"TLS\");\n        BOOST_TEST(server_tls == expected);\n    }\n}\n\n// mysql_native_password\nBOOST_TEST_DECORATOR(*run_if(&server_features::mnp))\nBOOST_AUTO_TEST_SUITE(mysql_native_password)\n\nconstexpr const char* regular_user = \"mysqlnp_user\";\nconstexpr const char* regular_passwd = \"mysqlnp_password\";\nconstexpr const char* empty_user = \"mysqlnp_empty_password_user\";\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, regular_password, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = regular_user;\n    params.password = regular_passwd;\n\n    // Handshake succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, sample.expect_ssl);\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, empty_password, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = empty_user;\n    params.password = \"\";\n\n    // Handshake succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, sample.expect_ssl);\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, bad_password, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = regular_user;\n    params.password = \"bad_password\";\n\n    // Handshake fails with the expected error code\n    conn.async_connect(params, as_netresult)\n        .validate_error_contains(common_server_errc::er_access_denied_error, {\"access denied\", regular_user});\n}\n\n// Spotcheck: mysql_native_password works with old connection\nBOOST_FIXTURE_TEST_CASE(tcp_connection_, tcp_connection_fixture)\n{\n    // Connect succeeds\n    conn.async_connect(\n            get_tcp_endpoint(),\n            connect_params_builder().credentials(regular_user, regular_passwd).build_hparams(),\n            as_netresult\n    )\n        .validate_no_error();\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // mysql_native_password\n\n// caching_sha2_password\n// https://dev.mysql.com/doc/refman/8.4/en/caching-sha2-pluggable-authentication.html\n// The plugin has a server-wide cache that influences the message exchange.\n// We acquire a named lock to avoid race conditions with other test runs\n// (which happens in b2 builds).\nstruct caching_sha2_lock : any_connection_fixture\n{\n    caching_sha2_lock()\n    {\n        // Connect\n        conn.async_connect(connect_params_builder().credentials(\"root\", \"\").build(), as_netresult)\n            .validate_no_error();\n\n        // Acquire the lock, using a long timeout\n        results r;\n        conn.async_execute(\"CALL get_lock_checked('sha256_cache', 3600)\", r, as_netresult)\n            .validate_no_error();\n\n        // The lock is released on fixture destruction, when the connection is closed\n    }\n};\n\nconstexpr const char* regular_user = \"csha2p_user\";\nconstexpr const char* regular_passwd = \"csha2p_password\";\nconstexpr const char* empty_user = \"csha2p_empty_password_user\";\n\nBOOST_TEST_DECORATOR(*run_if(&server_features::sha256))\nBOOST_AUTO_TEST_SUITE(caching_sha2_password, *boost::unit_test::fixture<caching_sha2_lock>())\n\nstatic void load_sha256_cache(std::string user, std::string password)\n{\n    // Connecting as the given user loads the cache\n    any_connection_fixture fix;\n    fix.conn\n        .async_connect(\n            connect_params_builder().credentials(std::move(user), std::move(password)).build(),\n            as_netresult\n        )\n        .validate_no_error();\n}\n\nstatic void clear_sha256_cache()\n{\n    // Issuing a FLUSH PRIVILEGES clears the cache\n    any_connection_fixture fix;\n    fix.conn.async_connect(connect_params_builder().credentials(\"root\", \"\").build(), as_netresult)\n        .validate_no_error();\n\n    results result;\n    fix.conn.async_execute(\"FLUSH PRIVILEGES\", result, as_netresult).validate_no_error();\n};\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, cache_hit, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = regular_user;\n    params.password = regular_passwd;\n    load_sha256_cache(regular_user, regular_passwd);\n\n    // Handshake succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, sample.expect_ssl);\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, cache_miss, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = regular_user;\n    params.password = regular_passwd;\n    clear_sha256_cache();\n\n    // Handshake succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, sample.expect_ssl);\n}\n\n// The protocol behaves differently with empty passwords\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, empty_password_cache_hit, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = empty_user;\n    params.password = \"\";\n    load_sha256_cache(empty_user, \"\");\n\n    // Handshake succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, sample.expect_ssl);\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, empty_password_cache_miss, all_transports)\n{\n    // Setup\n    connect_params params = sample.params;\n    params.username = empty_user;\n    params.password = \"\";\n    clear_sha256_cache();\n\n    // Handshake succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, sample.expect_ssl);\n}\n\n// Passwords longer than the scramble work correctly.\n// This is only relevant for cache misses over insecure channels.\nBOOST_FIXTURE_TEST_CASE(long_password_cache_miss, any_connection_fixture)\n{\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::disable)\n                      .credentials(\"csha2p_long_password_user\", \"1234567890abcdefghijklmnopqrstuvwxyz\")\n                      .build();\n    clear_sha256_cache();\n    conn.async_connect(params, as_netresult).validate_no_error();\n}\n\nBOOST_FIXTURE_TEST_CASE(bad_password_cache_hit, any_connection_fixture)\n{\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::disable)\n                      .credentials(regular_user, \"bad_password\")\n                      .build();\n    load_sha256_cache(regular_user, regular_passwd);\n    conn.async_connect(params, as_netresult)\n        .validate_error_contains(common_server_errc::er_access_denied_error, {\"access denied\", regular_user});\n}\n\nBOOST_FIXTURE_TEST_CASE(bad_password_cache_miss, any_connection_fixture)\n{\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::disable)\n                      .credentials(regular_user, \"bad_password\")\n                      .build();\n    clear_sha256_cache();\n    conn.async_connect(params, as_netresult)\n        .validate_error_contains(common_server_errc::er_access_denied_error, {\"access denied\", regular_user});\n}\n\n// Spotcheck: an invalid DB error after a cache miss works\nBOOST_FIXTURE_TEST_CASE(bad_db_cache_miss, any_connection_fixture)\n{\n    // Setup\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::disable)\n                      .credentials(regular_user, regular_passwd)\n                      .database(\"bad_db\")\n                      .build();\n    clear_sha256_cache();\n\n    // Connect fails\n    conn.async_connect(params, as_netresult)\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'csha2p_user'@'%' to database 'bad_db'\"\n        );\n}\n\n// Spotcheck: an invalid DB error after a cache hit works\nBOOST_FIXTURE_TEST_CASE(bad_db_cache_hit, any_connection_fixture)\n{\n    // Setup\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::disable)\n                      .credentials(regular_user, regular_passwd)\n                      .database(\"bad_db\")\n                      .build();\n    load_sha256_cache(regular_user, regular_passwd);\n\n    // Connect fails\n    conn.async_connect(params, as_netresult)\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'csha2p_user'@'%' to database 'bad_db'\"\n        );\n}\n\n// Spotcheck: caching_sha2_password works with old connection\nBOOST_FIXTURE_TEST_CASE(tcp_ssl_connection_, io_context_fixture)\n{\n    // Setup\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n    tcp_ssl_connection conn(ctx, ssl_ctx);\n    auto params = connect_params_builder().credentials(regular_user, regular_passwd).build_hparams();\n\n    // Connect succeeds\n    conn.async_connect(get_tcp_endpoint(), params, as_netresult).validate_no_error();\n\n    // Close succeeds\n    conn.async_close(as_netresult).validate_no_error();\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // caching_sha2_password\n\n// SSL certificate validation\n// This also tests that we can pass a custom ssl::context to connections\nBOOST_AUTO_TEST_SUITE(ssl_certificate_validation)\n\nBOOST_AUTO_TEST_CASE(certificate_valid)\n{\n    // Setup\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n    ssl_ctx.set_verify_mode(boost::asio::ssl::verify_peer);\n    ssl_ctx.add_certificate_authority(boost::asio::buffer(CA_PEM));\n    any_connection_fixture fix(ssl_ctx);\n\n    // Connect works\n    fix.conn.async_connect(connect_params_builder().ssl(ssl_mode::require).build(), as_netresult)\n        .validate_no_error();\n    check_ssl(fix.conn, true);\n}\n\nBOOST_AUTO_TEST_CASE(certificate_invalid)\n{\n    // Setup\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n    ssl_ctx.set_verify_mode(boost::asio::ssl::verify_peer);\n    any_connection_fixture fix(ssl_ctx);\n\n    // Connect fails\n    auto err = fix.conn.async_connect(connect_params_builder().ssl(ssl_mode::require).build(), as_netresult)\n                   .run()\n                   .err;\n    BOOST_TEST(err.message().find(\"certificate verify failed\") != std::string::npos);\n}\n\nBOOST_AUTO_TEST_CASE(custom_certificate_verification_success)\n{\n    // Setup\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n    ssl_ctx.set_verify_mode(boost::asio::ssl::verify_peer);\n    ssl_ctx.add_certificate_authority(boost::asio::buffer(CA_PEM));\n    ssl_ctx.set_verify_callback(boost::asio::ssl::host_name_verification(\"mysql\"));\n    any_connection_fixture fix(ssl_ctx);\n\n    // Connect succeeds\n    fix.conn.async_connect(connect_params_builder().ssl(ssl_mode::require).build(), as_netresult)\n        .validate_no_error();\n    check_ssl(fix.conn, true);\n}\n\nBOOST_AUTO_TEST_CASE(custom_certificate_verification_error)\n{\n    // Setup\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n    ssl_ctx.set_verify_mode(boost::asio::ssl::verify_peer);\n    ssl_ctx.add_certificate_authority(boost::asio::buffer(CA_PEM));\n    ssl_ctx.set_verify_callback(boost::asio::ssl::host_name_verification(\"host.name\"));\n    any_connection_fixture fix(ssl_ctx);\n\n    // Connect fails\n    auto err = fix.conn.async_connect(connect_params_builder().ssl(ssl_mode::require).build(), as_netresult)\n                   .run()\n                   .err;\n    BOOST_TEST(err.message().find(\"certificate verify failed\") != std::string::npos);\n}\n\n// Spotcheck: a custom SSL context can be used with old connections\nBOOST_FIXTURE_TEST_CASE(tcp_ssl_connection_, io_context_fixture)\n{\n    // Setup\n    asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n    ssl_ctx.set_verify_mode(boost::asio::ssl::verify_peer);\n    ssl_ctx.add_certificate_authority(boost::asio::buffer(CA_PEM));\n    ssl_ctx.set_verify_callback(boost::asio::ssl::host_name_verification(\"host.name\"));\n    tcp_ssl_connection conn(ctx, ssl_ctx);\n    auto params = connect_params_builder().build_hparams();\n\n    // Connect fails\n    auto err = conn.async_connect(get_tcp_endpoint(), params, as_netresult).run().err;\n    BOOST_TEST(err.message().find(\"certificate verify failed\") != std::string::npos);\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // ssl_certificate_validation\n\nBOOST_AUTO_TEST_SUITE(ssl_mode_)\n\n// All our CI servers support SSL, so enable should behave like required\nBOOST_FIXTURE_TEST_CASE(any_enable, any_connection_fixture)\n{\n    // Setup\n    auto params = connect_params_builder().ssl(ssl_mode::enable).build();\n\n    // Connect succeeds\n    conn.async_connect(params, as_netresult).validate_no_error();\n    check_ssl(conn, true);\n}\n\n// connection<>: all ssl modes work as disabled if the stream doesn't support ssl\nBOOST_DATA_TEST_CASE_F(\n    tcp_connection_fixture,\n    non_ssl_stream,\n    data::make({ssl_mode::disable, ssl_mode::enable, ssl_mode::require})\n)\n{\n    // Physical connect\n    conn.stream().async_connect(get_tcp_endpoint(), as_netresult).validate_no_error_nodiag();\n\n    // Handshake succeeds\n    conn.async_handshake(connect_params_builder().ssl(sample).build_hparams(), as_netresult)\n        .validate_no_error();\n    check_ssl(conn, false);\n}\n\n// connection<>: disable can be used to effectively disable SSL\nBOOST_AUTO_TEST_CASE(ssl_stream)\n{\n    struct\n    {\n        string_view name;\n        ssl_mode mode;\n        bool expect_ssl;\n    } test_cases[] = {\n        {\"disable\", ssl_mode::disable, false},\n        {\"enable\",  ssl_mode::enable,  true },\n        {\"require\", ssl_mode::require, true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            asio::ssl::context ssl_ctx(asio::ssl::context::tls_client);\n            tcp_ssl_connection conn(fix.ctx, ssl_ctx);\n            auto params = connect_params_builder().ssl(tc.mode).build_hparams();\n\n            // Handshake succeeds\n            conn.async_connect(get_tcp_endpoint(), params, as_netresult).validate_no_error();\n            check_ssl(conn, tc.expect_ssl);\n\n            // Close succeeds\n            conn.async_close(as_netresult).validate_no_error();\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// Old tcp_ssl_connection, unix_connection, unix_ssl_connection\n// can establish and terminate connections, using sync and async fns\nBOOST_AUTO_TEST_SUITE(connection_stream_types)\n\ntemplate <class Conn>\nstruct fixture;\n\ntemplate <>\nstruct fixture<tcp_ssl_connection> : io_context_fixture\n{\n    asio::ssl::context ssl_ctx{asio::ssl::context::tls_client};\n    tcp_ssl_connection conn{ctx, ssl_ctx};\n\n    using endpoint_type = asio::ip::tcp::endpoint;\n    static endpoint_type get_endpoint() { return get_tcp_endpoint(); }\n    static bool expect_ssl() { return true; }\n};\n\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\ntemplate <>\nstruct fixture<unix_connection> : io_context_fixture\n{\n    unix_connection conn{ctx};\n\n    using endpoint_type = asio::local::stream_protocol::endpoint;\n    static endpoint_type get_endpoint() { return default_unix_path; }\n    static bool expect_ssl() { return false; }\n};\n\ntemplate <>\nstruct fixture<unix_ssl_connection> : io_context_fixture\n{\n    asio::ssl::context ssl_ctx{asio::ssl::context::tls_client};\n    unix_ssl_connection conn{ctx, ssl_ctx};\n\n    using endpoint_type = asio::local::stream_protocol::endpoint;\n    static endpoint_type get_endpoint() { return default_unix_path; }\n    static bool expect_ssl() { return true; }\n};\n#endif\n\ntemplate <class Conn>\nvoid do_connect_close_test()\n{\n    using fixture_type = fixture<Conn>;\n    using netmaker_connect = netfun_maker<\n        void,\n        Conn,\n        const typename fixture_type::endpoint_type&,\n        const handshake_params&>;\n    using netmaker_execute = netfun_maker<void, Conn, const string_view&, results&>;\n    using netmaker_close = netfun_maker<void, Conn>;\n\n    struct\n    {\n        string_view name;\n        typename netmaker_connect::signature connect;\n        typename netmaker_execute::signature execute;\n        typename netmaker_close::signature close;\n    } test_cases[] = {\n        {\"sync\",\n         netmaker_connect::sync_errc(&Conn::connect),\n         netmaker_execute::sync_errc(&Conn::execute),\n         netmaker_close::sync_errc(&Conn::close)       },\n        {\"async\",\n         netmaker_connect::async_diag(&Conn::async_connect),\n         netmaker_execute::async_diag(&Conn::async_execute),\n         netmaker_close::async_diag(&Conn::async_close)},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture_type fix;\n\n            // Connect\n            tc.connect(fix.conn, fix.get_endpoint(), connect_params_builder().build_hparams())\n                .validate_no_error();\n\n            // Check whether the connection is using SSL\n            check_ssl(fix.conn, fix.expect_ssl());\n\n            // The connection is usable\n            results r;\n            tc.execute(fix.conn, \"SELECT 'abc'\", r).validate_no_error();\n            BOOST_TEST(r.rows() == makerows(1, \"abc\"), per_element());\n\n            // Closing succeeds\n            tc.close(fix.conn).validate_no_error();\n        }\n    }\n}\n\ntemplate <class Conn>\nvoid do_handshake_quit_test()\n{\n    using fixture_type = fixture<Conn>;\n    using socket_type = typename Conn::stream_type::lowest_layer_type;\n    using netmaker_connect = netfun_maker<void, socket_type, const typename fixture_type::endpoint_type&>;\n    using netmaker_handshake = netfun_maker<void, Conn, const handshake_params&>;\n    using netmaker_execute = netfun_maker<void, Conn, const string_view&, results&>;\n    using netmaker_quit = netfun_maker<void, Conn>;\n\n    struct\n    {\n        string_view name;\n        typename netmaker_connect::signature connect;\n        typename netmaker_handshake::signature handshake;\n        typename netmaker_execute::signature execute;\n        typename netmaker_quit::signature quit;\n    } test_cases[] = {\n        {\"sync\",\n         netmaker_connect::sync_errc_nodiag(&socket_type::connect),\n         netmaker_handshake::sync_errc(&Conn::handshake),\n         netmaker_execute::sync_errc(&Conn::execute),\n         netmaker_quit::sync_errc(&Conn::quit)       },\n        {\"async\",\n         netmaker_connect::async_nodiag(&socket_type::async_connect),\n         netmaker_handshake::async_diag(&Conn::async_handshake),\n         netmaker_execute::async_diag(&Conn::async_execute),\n         netmaker_quit::async_diag(&Conn::async_quit)},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture_type fix;\n\n            // Connect\n            tc.connect(fix.conn.stream().lowest_layer(), fix.get_endpoint()).validate_no_error_nodiag();\n            tc.handshake(fix.conn, connect_params_builder().build_hparams()).validate_no_error();\n\n            // Check whether the connection uses SSL\n            check_ssl(fix.conn, fix.expect_ssl());\n\n            // The connection is usable\n            results r;\n            tc.execute(fix.conn, \"SELECT 'abc'\", r).validate_no_error();\n            BOOST_TEST(r.rows() == makerows(1, \"abc\"), per_element());\n\n            // Quitting succeeds\n            tc.quit(fix.conn).validate_no_error();\n            fix.conn.stream().lowest_layer().close();\n        }\n    }\n}\n\n// tcp_ssl\nBOOST_AUTO_TEST_CASE(tcp_ssl_connect_close) { do_connect_close_test<tcp_ssl_connection>(); }\nBOOST_AUTO_TEST_CASE(tcp_ssl_handshake_quit) { do_handshake_quit_test<tcp_ssl_connection>(); }\n\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\n// unix\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_AUTO_TEST_CASE(unix_connection_connect_close) { do_connect_close_test<unix_connection>(); }\n\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_AUTO_TEST_CASE(unix_connection_handshake_quit) { do_handshake_quit_test<unix_connection>(); }\n\n// unix ssl\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_AUTO_TEST_CASE(unix_ssl_connection_connect_close) { do_connect_close_test<unix_ssl_connection>(); }\n\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_AUTO_TEST_CASE(unix_ssl_connection_handshake_quit) { do_handshake_quit_test<unix_ssl_connection>(); }\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// Other handshake tests\nBOOST_FIXTURE_TEST_CASE(no_database, any_connection_fixture)\n{\n    // Connect succeeds\n    conn.async_connect(connect_params_builder().database(\"\").build(), as_netresult).validate_no_error();\n\n    // No database selected\n    results r;\n    conn.async_execute(\"SELECT DATABASE()\", r, as_netresult).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, nullptr), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(bad_database, any_connection_fixture)\n{\n    // Connect fails\n    conn.async_connect(connect_params_builder().database(\"bad_db\").build(), as_netresult)\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'integ_user'@'%' to database 'bad_db'\"\n        );\n}\n\nBOOST_TEST_DECORATOR(*run_if(&server_features::sha256))\nBOOST_FIXTURE_TEST_CASE(unknown_auth_plugin, any_connection_fixture)\n{\n    // Note: sha256_password is not supported, so it's an unknown plugin to us\n    // Setup\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::require)\n                      .credentials(\"sha2p_user\", \"sha2p_password\")\n                      .build();\n\n    // Connect fails\n    conn.async_connect(params, as_netresult).validate_error(client_errc::unknown_auth_plugin);\n}\n\nBOOST_FIXTURE_TEST_CASE(bad_user, any_connection_fixture)\n{\n    // unreliable without SSL. If the default plugin requires SSL\n    // (like SHA256), this would fail with 'ssl required'\n    // Setup\n    auto params = connect_params_builder()\n                      .ssl(ssl_mode::require)\n                      .credentials(\"non_existing_user\", \"bad_password\")\n                      .build();\n\n    // Connect fails\n    auto err = conn.async_connect(params, as_netresult).run().err;\n    BOOST_TEST((err.category() == get_common_server_category() || err.category() == get_client_category()));\n    BOOST_TEST(err != error_code());  // may be access denied or unknown auth plugin\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_handshake\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/multi_function.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::test_tools::per_element;\n\n// Most of the multi-function API is covered in other sections\n// (e.g. multi-function with the static interface is covered in static_interface.cpp).\n// This file contains the tests than are specific to multi-function and don't belong to any other section.\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_multi_function)\n\n// If we start a multi-function operation and we try to run any other operation, the latter fails without\n// undefined behavior\nBOOST_FIXTURE_TEST_CASE(status_checks, any_connection_fixture)\n{\n    connect();\n\n    // Start the operation\n    execution_state st;\n    conn.async_start_execution(\"SELECT * FROM empty_table\", st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // If we try to start any other operation here, an error is issued\n    results r;\n    conn.async_execute(\"SELECT 1\", r, as_netresult).validate_error(client_errc::engaged_in_multi_function);\n    conn.async_prepare_statement(\"SELECT 1\", as_netresult)\n        .validate_error(client_errc::engaged_in_multi_function);\n    conn.async_ping(as_netresult).validate_error(client_errc::engaged_in_multi_function);\n\n    // The error is non-fatal: once we finish with the multi-function operation,\n    // we can keep using the connection\n    auto rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rv == rows_view(), per_element());\n    conn.async_execute(\"SELECT 1\", r, as_netresult).validate_no_error();\n}\n\n// We don't mess up with status in case of errors\nBOOST_FIXTURE_TEST_CASE(status_checks_errors, any_connection_fixture)\n{\n    connect();\n\n    // Start the operation, which finishes with an error\n    execution_state st;\n    conn.async_start_execution(\"SELECT * FROM bad_table\", st, as_netresult)\n        .validate_error(\n            common_server_errc::er_no_such_table,\n            \"Table 'boost_mysql_integtests.bad_table' doesn't exist\"\n        );\n\n    // We can keep using the connection\n    results r;\n    conn.async_execute(\"SELECT 1\", r, as_netresult).validate_no_error();\n}\n\n// connect works to reconnect the connection,\n// even if we're in the middle of a multi-function operation\nBOOST_FIXTURE_TEST_CASE(connect_during_multi_function, any_connection_fixture)\n{\n    connect();\n\n    // Start the operation, which finishes with an error\n    execution_state st;\n    conn.async_start_execution(\"SELECT * FROM empty_table\", st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // We can keep use connect here, and we get a usable connection\n    conn.async_connect(connect_params_builder().disable_ssl().build(), as_netresult).validate_no_error();\n    conn.async_ping(as_netresult).validate_no_error();\n}\n\n// close can be called even if we're in the middle of a multi-function operation\nBOOST_FIXTURE_TEST_CASE(close_during_multi_function, any_connection_fixture)\n{\n    // Connect with TLS enabled\n    conn.async_connect(connect_params_builder().build(), as_netresult).validate_no_error();\n\n    // Start the operation, which finishes with an error\n    execution_state st;\n    conn.async_start_execution(\"SELECT * FROM empty_table\", st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // We can use close here without errors\n    conn.async_close(as_netresult).validate_no_error();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/multi_queries.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n#include \"test_integration/tcp_connection_fixture.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_multi_queries)\n\nBOOST_FIXTURE_TEST_CASE(empty_results, any_connection_fixture)\n{\n    // Setup\n    constexpr const char* query =\n        \"INSERT INTO inserts_table (field_varchar) VALUES ('abc');\"\n        \"INSERT INTO inserts_table (field_varchar) VALUES ('def');\"\n        \"DELETE FROM updates_table\";\n    connect(connect_params_builder().disable_ssl().multi_queries(true).build());\n    start_transaction();\n\n    // Run the query\n    results result;\n    conn.async_execute(query, result, as_netresult).validate_no_error();\n\n    // Validate results\n    BOOST_TEST_REQUIRE(result.size() == 3u);\n\n    BOOST_TEST(result[0].meta().size() == 0u);\n    BOOST_TEST(result[0].rows() == rows());\n    BOOST_TEST(result[0].affected_rows() == 1u);\n    BOOST_TEST(result[0].warning_count() == 0u);\n    BOOST_TEST(result[0].last_insert_id() > 0u);\n    BOOST_TEST(result[0].info() == \"\");\n    BOOST_TEST(!result[0].is_out_params());\n\n    BOOST_TEST(result[1].meta().size() == 0u);\n    BOOST_TEST(result[1].rows() == rows());\n    BOOST_TEST(result[1].affected_rows() == 1u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() > 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(!result[1].is_out_params());\n\n    BOOST_TEST(result[2].meta().size() == 0u);\n    BOOST_TEST(result[2].rows() == rows());\n    BOOST_TEST(result[2].affected_rows() == 3u);\n    BOOST_TEST(result[2].warning_count() == 0u);\n    BOOST_TEST(result[2].last_insert_id() == 0u);\n    BOOST_TEST(result[2].info() == \"\");\n    BOOST_TEST(!result[2].is_out_params());\n}\n\nBOOST_FIXTURE_TEST_CASE(data_results, any_connection_fixture)\n{\n    // Setup\n    connect(connect_params_builder().disable_ssl().multi_queries(true).build());\n    start_transaction();\n    constexpr const char* query =\n        \"SELECT * FROM one_row_table;\"\n        \"SELECT * FROM empty_table;\"\n        \"DELETE FROM updates_table\";\n\n    // Execute\n    results result;\n    conn.async_execute(query, result, as_netresult).validate_no_error();\n\n    // Validate results\n    BOOST_TEST_REQUIRE(result.size() == 3u);\n\n    validate_2fields_meta(result[0].meta(), \"one_row_table\");\n    BOOST_TEST(result[0].rows() == makerows(2, 1, \"f0\"));\n    BOOST_TEST(result[0].affected_rows() == 0u);\n    BOOST_TEST(result[0].warning_count() == 0u);\n    BOOST_TEST(result[0].last_insert_id() == 0u);\n    BOOST_TEST(result[0].info() == \"\");\n    BOOST_TEST(!result[0].is_out_params());\n\n    validate_2fields_meta(result[1].meta(), \"empty_table\");\n    BOOST_TEST(result[1].rows() == makerows(2));\n    BOOST_TEST(result[1].affected_rows() == 0u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() == 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(!result[1].is_out_params());\n\n    BOOST_TEST(result[2].meta().size() == 0u);\n    BOOST_TEST(result[2].rows() == rows());\n    BOOST_TEST(result[2].affected_rows() == 3u);\n    BOOST_TEST(result[2].warning_count() == 0u);\n    BOOST_TEST(result[2].last_insert_id() == 0u);\n    BOOST_TEST(result[2].info() == \"\");\n    BOOST_TEST(!result[2].is_out_params());\n}\n\nBOOST_FIXTURE_TEST_CASE(error_not_enabled, any_connection_fixture)\n{\n    // Setup\n    connect(connect_params_builder().disable_ssl().build());\n\n    // Execute fails\n    results result;\n    conn.async_execute(\"SELECT 1; SELECT 2\", result, as_netresult)\n        .validate_error_contains(\n            common_server_errc::er_parse_error,\n            {\"you have an error in your sql syntax\"}\n        );\n}\n\n// Spotcheck: old connection can do multi-queries\nBOOST_FIXTURE_TEST_CASE(tcp_connection_enable, tcp_connection_fixture)\n{\n    connect(connect_params_builder().multi_queries(true).build_hparams());\n\n    // Execute succeeds\n    results result;\n    conn.async_execute(\"SELECT 1; SELECT 2\", result, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(result.size() == 2u);\n    BOOST_TEST(result.at(0).rows() == makerows(1, 1), per_element());\n    BOOST_TEST(result.at(1).rows() == makerows(1, 2), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(tcp_connection_disabled, tcp_connection_fixture)\n{\n    // Setup\n    connect();\n\n    // Execute succeeds\n    results result;\n    conn.async_execute(\"SELECT 1; SELECT 2\", result, as_netresult)\n        .validate_error_contains(\n            common_server_errc::er_parse_error,\n            {\"you have an error in your sql syntax\"}\n        );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/pipeline.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/pipeline.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <vector>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_pipeline)\n\nBOOST_FIXTURE_TEST_CASE(success, any_connection_fixture)\n{\n    // Setup\n    connect();\n    pipeline_request req;\n    std::vector<stage_response> res;\n\n    // Populate the request\n    req.add_reset_connection()\n        .add_execute(\"SET @myvar = 15\")\n        .add_prepare_statement(\"SELECT * FROM one_row_table WHERE id = ?\");\n\n    // Run it\n    conn.async_run_pipeline(req, res, as_netresult).validate_no_error();\n\n    // Check results\n    BOOST_TEST_REQUIRE(res.size() == 3u);\n    BOOST_TEST(res[0].error() == error_code());\n    BOOST_TEST(res[0].diag() == diagnostics());\n    BOOST_TEST(!res[0].has_results());\n    BOOST_TEST(!res[0].has_statement());\n    BOOST_TEST(res[1].has_results());\n    auto stmt = res[2].as_statement();\n    BOOST_TEST(stmt.valid());\n    BOOST_TEST(conn.current_character_set().error() == client_errc::unknown_character_set);\n\n    // Re-populate the pipeline, with different stages\n    req.clear();\n    req.add_set_character_set(utf8mb4_charset)\n        .add_execute(stmt, 0)\n        .add_execute_range(stmt, std::vector<field_view>{field_view(1)})\n        .add_close_statement(stmt);\n\n    // Run it\n    conn.async_run_pipeline(req, res, as_netresult).validate_no_error();\n\n    // Check results\n    BOOST_TEST_REQUIRE(res.size() == 4u);\n    BOOST_TEST(res[0].error() == error_code());\n    BOOST_TEST(res[0].diag() == diagnostics());\n    BOOST_TEST(!res[0].has_results());\n    BOOST_TEST(!res[0].has_statement());\n    BOOST_TEST(res[1].as_results().rows() == rows(), per_element());\n    BOOST_TEST(res[2].as_results().rows() == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST(res[3].error() == error_code());\n    BOOST_TEST(res[3].diag() == diagnostics());\n    BOOST_TEST(!res[3].has_results());\n    BOOST_TEST(!res[3].has_statement());\n}\n\nBOOST_FIXTURE_TEST_CASE(errors, any_connection_fixture)\n{\n    // Setup\n    connect();\n    pipeline_request req;\n    std::vector<stage_response> res;\n\n    // Populate the request with some successes and some errors\n    req.add_execute(\"SET @myvar = 42\")                                                   // OK\n        .add_prepare_statement(\"SELECT * FROM bad_table WHERE id = ?\")                   // error: bad table\n        .add_execute(\"\")                                                                 // error: empty query\n        .add_execute(\"SELECT @myvar\")                                                    // OK\n        .add_set_character_set(character_set{\"bad_charset\", utf8mb4_charset.next_char})  // bad charset\n        .add_execute(\"SELECT 'abc'\");                                                    // OK\n\n    // Run it. The result of the operation is the first encountered error\n    conn.async_run_pipeline(req, res, as_netresult)\n        .validate_error(\n            common_server_errc::er_no_such_table,\n            \"Table 'boost_mysql_integtests.bad_table' doesn't exist\"\n        );\n\n    // Check results\n    BOOST_TEST_REQUIRE(res.size() == 6u);\n    BOOST_TEST(res[0].has_results());\n    BOOST_TEST(res[1].error() == common_server_errc::er_no_such_table);\n    BOOST_TEST(res[1].diag() == create_server_diag(\"Table 'boost_mysql_integtests.bad_table' doesn't exist\"));\n    BOOST_TEST(res[2].error() == common_server_errc::er_empty_query);\n    BOOST_TEST(res[2].diag() == create_server_diag(\"Query was empty\"));\n    BOOST_TEST(res[3].as_results().rows() == makerows(1, 42), per_element());\n    BOOST_TEST(res[4].error() == common_server_errc::er_unknown_character_set);\n    BOOST_TEST(res[4].diag() == create_server_diag(\"Unknown character set: 'bad_charset'\"));\n    BOOST_TEST(res[5].as_results().rows() == makerows(1, \"abc\"), per_element());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/prepared_statements.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_prepared_statements)\n\nBOOST_FIXTURE_TEST_CASE(multiple_executions, any_connection_fixture)\n{\n    connect();\n    results result;\n\n    // Prepare a statement\n    constexpr const char* sql = \"SELECT * FROM two_rows_table WHERE id = ? OR field_varchar = ?\";\n    auto stmt = conn.async_prepare_statement(sql, as_netresult).get();\n\n    // Execute it. Only one row will be returned (because of the id)\n    conn.async_execute(stmt.bind(1, \"non_existent\"), result, as_netresult).validate_no_error();\n    validate_2fields_meta(result.meta(), \"two_rows_table\");\n    BOOST_TEST(result.rows() == makerows(2, 1, \"f0\"), per_element());\n\n    // Execute it again, but with different values. This time, two rows are returned\n    conn.async_execute(stmt.bind(1, \"f1\"), result, as_netresult).validate_no_error();\n    validate_2fields_meta(result.meta(), \"two_rows_table\");\n    BOOST_TEST(result.rows() == makerows(2, 1, \"f0\", 2, \"f1\"), per_element());\n\n    // Close it\n    conn.async_close_statement(stmt, as_netresult).validate_no_error();\n}\n\nBOOST_FIXTURE_TEST_CASE(multiple_statements, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n    results result;\n\n    // Prepare an update and a select\n    constexpr const char* update_sql = \"UPDATE updates_table SET field_int = ? WHERE field_varchar = ?\";\n    constexpr const char* select_sql = \"SELECT field_int FROM updates_table WHERE field_varchar = ?\";\n    auto stmt_update = conn.async_prepare_statement(update_sql, as_netresult).get();\n    auto stmt_select = conn.async_prepare_statement(select_sql, as_netresult).get();\n    BOOST_TEST(stmt_update.num_params() == 2u);\n    BOOST_TEST(stmt_select.num_params() == 1u);\n    BOOST_TEST(stmt_update.id() != stmt_select.id());\n\n    // Execute update\n    conn.async_execute(stmt_update.bind(210, \"f0\"), result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.meta().size() == 0u);\n    BOOST_TEST(result.affected_rows() == 1u);\n\n    // Execute select\n    conn.async_execute(stmt_select.bind(\"f0\"), result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 210), per_element());\n\n    // Execute update again\n    conn.async_execute(stmt_update.bind(220, \"f0\"), result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.meta().size() == 0u);\n    BOOST_TEST(result.affected_rows() == 1u);\n\n    // Update no longer needed, close it\n    conn.async_close_statement(stmt_update, as_netresult).validate_no_error();\n\n    // Execute select again\n    conn.async_execute(stmt_select.bind(\"f0\"), result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, 220), per_element());\n\n    // Close select\n    conn.async_close_statement(stmt_select, as_netresult).validate_no_error();\n}\n\nBOOST_FIXTURE_TEST_CASE(statement_without_params, any_connection_fixture)\n{\n    connect();\n\n    // Prepare the statement\n    auto stmt = conn.async_prepare_statement(\"SELECT * FROM empty_table\", as_netresult).get();\n    BOOST_TEST(stmt.valid());\n    BOOST_TEST(stmt.num_params() == 0u);\n\n    // Execute doesn't error\n    results result;\n    conn.async_execute(stmt.bind(), result, as_netresult).validate_no_error();\n    validate_2fields_meta(result.meta(), \"empty_table\");\n    BOOST_TEST(result.rows() == rows(), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(wrong_num_params, any_connection_fixture)\n{\n    connect();\n\n    // Prepare the statement\n    auto stmt = conn.async_prepare_statement(\"SELECT * FROM empty_table\", as_netresult).get();\n    BOOST_TEST(stmt.valid());\n    BOOST_TEST(stmt.num_params() == 0u);\n\n    // Execute fails appropriately\n    results result;\n    conn.async_execute(stmt.bind(42), result, as_netresult).validate_error(client_errc::wrong_num_params);\n}\n\nBOOST_FIXTURE_TEST_CASE(multi_function, any_connection_fixture)\n{\n    connect();\n\n    // Prepare the statement\n    auto stmt = conn.async_prepare_statement(\"SELECT * FROM three_rows_table\", as_netresult).get();\n\n    // Execute it\n    execution_state st;\n    conn.async_start_execution(stmt.bind(), st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // We don't know how many rows there will be in each batch,\n    // but they will come in order\n    std::size_t call_count = 0;\n    std::vector<row> all_rows;\n    while (st.should_read_rows() && call_count <= 4)\n    {\n        ++call_count;\n        for (row_view rv : conn.async_read_some_rows(st, as_netresult).get())\n            all_rows.emplace_back(rv);\n    }\n\n    // Verify rows\n    BOOST_TEST(all_rows == makerows(2, 1, \"f0\", 2, \"f1\", 3, \"f2\"), per_element());\n\n    // Verify eof\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n\n    // Reading again does nothing\n    auto rws = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rws == rows(), per_element());\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_prepared_statements\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/reconnect.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/bind_cancellation_slot.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/data/monomorphic.hpp>\n#include <boost/test/data/test_case.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/server_features.hpp\"\n#include \"test_integration/spotchecks_helpers.hpp\"\n#include \"test_integration/tcp_connection_fixture.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_reconnect)\n\nauto connection_samples = network_functions_connection::sync_and_async();\nauto any_samples = network_functions_any::sync_and_async();\nauto any_samples_grid = boost::unit_test::data::make(any_samples) *\n                        boost::unit_test::data::make({ssl_mode::disable, ssl_mode::require});\n\n// Old connection can reconnect after close if the stream is not SSL\nBOOST_DATA_TEST_CASE(reconnect_after_close_connection, connection_samples)\n{\n    netfn_fixture_connection fix(sample);\n\n    // Connect and use the connection\n    results r;\n    fix.net.connect(fix.conn, get_tcp_endpoint(), connect_params_builder().build_hparams())\n        .validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n\n    // Close\n    fix.net.close(fix.conn).validate_no_error();\n\n    // Reopen and use the connection normally\n    fix.net.connect(fix.conn, get_tcp_endpoint(), connect_params_builder().build_hparams())\n        .validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n}\n\n// any_connection can reconnect after close, even if the stream uses ssl\nBOOST_DATA_TEST_CASE(reconnect_after_close_any, any_samples_grid, p0, p1)\n{\n    netfn_fixture_any fix(p0);\n    ssl_mode mode = p1;\n\n    // Connect and use the connection\n    results r;\n    fix.net.connect(fix.conn, connect_params_builder().ssl(mode).build()).validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n\n    // Close\n    fix.net.close(fix.conn).validate_no_error();\n\n    // Reopen and use the connection normally\n    fix.net.connect(fix.conn, connect_params_builder().ssl(mode).build()).validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n}\n\n// Old connection can reconnect after handshake failure if the stream is not SSL\nBOOST_DATA_TEST_CASE(reconnect_after_handshake_error_connection, connection_samples)\n{\n    netfn_fixture_connection fix(sample);\n\n    // Error during server handshake\n    fix.net.connect(fix.conn, get_tcp_endpoint(), connect_params_builder().database(\"bad_db\").build_hparams())\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'integ_user'@'%' to database 'bad_db'\"\n        );\n\n    // Reopen with correct parameters and use the connection normally\n    results r;\n    fix.net.connect(fix.conn, get_tcp_endpoint(), connect_params_builder().build_hparams())\n        .validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n}\n\n// any_connection can reconnect after a handshake failure, even if SSL is used\nBOOST_DATA_TEST_CASE(reconnect_after_handshake_error_any, any_samples_grid, p0, p1)\n{\n    netfn_fixture_any fix(p0);\n    ssl_mode mode = p1;\n\n    // Error during server handshake\n    fix.net.connect(fix.conn, connect_params_builder().ssl(mode).database(\"bad_db\").build())\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'integ_user'@'%' to database 'bad_db'\"\n        );\n\n    // Reopen with correct parameters and use the connection normally\n    results r;\n    fix.net.connect(fix.conn, connect_params_builder().ssl(mode).build()).validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n}\n\n// any_connection can reconnect while it's connected\nBOOST_DATA_TEST_CASE(reconnect_while_connected, any_samples_grid, p0, p1)\n{\n    netfn_fixture_any fix(p0);\n    ssl_mode mode = p1;\n\n    // Connect and use the connection\n    results r;\n    fix.net.connect(fix.conn, connect_params_builder().ssl(mode).build()).validate_no_error();\n    fix.net.execute_query(fix.conn, \"SELECT * FROM empty_table\", r).validate_no_error();\n\n    // We can safely connect again\n    fix.net.connect(fix.conn, connect_params_builder().ssl(mode).credentials(\"root\", \"\").build())\n        .validate_no_error();\n\n    // We've logged in as root. May be root@% or root@localhost\n    fix.net.execute_query(fix.conn, \"SELECT SUBSTRING_INDEX(CURRENT_USER(), '@', 1)\", r).validate_no_error();\n    BOOST_TEST(r.rows() == makerows(1, \"root\"), per_element());\n\n    // Close succeeds\n    fix.net.close(fix.conn).validate_no_error();\n}\n\nBOOST_FIXTURE_TEST_CASE(reconnect_after_cancel, any_connection_fixture)\n{\n    // Setup\n    results r;\n    connect();\n\n    // Kick an operation that ends up cancelled\n    asio::cancellation_signal sig;\n    auto netres = conn.async_execute(\n        \"DO SLEEP(2)\",\n        r,\n        asio::bind_cancellation_slot(sig.slot(), as_netresult)\n    );\n\n    // Return to the event loop and emit the signal\n    asio::post(asio::bind_executor(ctx, [&]() {\n        // Emit the signal\n        sig.emit(asio::cancellation_type::terminal);\n    }));\n\n    // Wait for the operation to finish\n    std::move(netres).validate_error(asio::error::operation_aborted);\n\n    // We can connect again and use the connection\n    connect();\n    conn.async_execute(\"SELECT 42\", r, as_netresult).validate_no_error();\n}\n\n// any_connection can change the stream type used by successive connect calls\nBOOST_AUTO_TEST_CASE(change_stream_type)\n{\n    // Helpers\n    const auto tcp_params = connect_params_builder().ssl(ssl_mode::disable).build();\n    const auto tcp_ssl_params = connect_params_builder().ssl(ssl_mode::require).build();\n    const auto unix_params = connect_params_builder().set_unix().build();\n\n    // Samples\n    struct test_case_t\n    {\n        string_view name;\n        const network_functions_any& fns;\n        connect_params first_params;\n        connect_params second_params;\n    };\n\n    std::vector<test_case_t> test_cases{\n        {\"sync_tcp_tcpssl\",  any_samples[0], tcp_params,     tcp_ssl_params},\n        {\"async_tcp_tcpssl\", any_samples[1], tcp_params,     tcp_ssl_params},\n        {\"async_tcpssl_tcp\", any_samples[1], tcp_ssl_params, tcp_params    },\n    };\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\n    if (get_server_features().unix_sockets)\n    {\n        test_cases.push_back({\"sync_unix_tcpssl\", any_samples[0], unix_params, tcp_ssl_params});\n        test_cases.push_back({\"async_unix_tcpssl\", any_samples[1], unix_params, tcp_ssl_params});\n        test_cases.push_back({\"async_tcpssl_unix\", any_samples[1], tcp_ssl_params, unix_params});\n        test_cases.push_back({\"async_tcp_unix\", any_samples[1], tcp_params, unix_params});\n    }\n#endif\n\n    // Actual test\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            netfn_fixture_any fix(tc.fns);\n\n            // Connect with the first stream type\n            fix.net.connect(fix.conn, tc.first_params).validate_no_error();\n            fix.net.ping(fix.conn).validate_no_error();\n\n            // Connect with the second stream type\n            fix.net.connect(fix.conn, tc.second_params).validate_no_error();\n            fix.net.ping(fix.conn).validate_no_error();\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_reconnect\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/charsets.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cassert>\n#include <cstddef>\n\nnamespace mysql = boost::mysql;\n\nnamespace {\n\n//[charsets_next_char\n// next_char must interpret input as a string encoded according to the\n// utf8mb4 character set and return the size of the first character,\n// or 0 if the byte sequence does not represent a valid character.\n// It must not throw exceptions.\nstd::size_t utf8mb4_next_char(boost::span<const unsigned char> input)\n{\n    // Input strings are never empty - they always have 1 byte, at least.\n    assert(!input.empty());\n\n    // In UTF8, we need to look at the first byte to know the character's length\n    auto first_char = input[0];\n\n    if (first_char < 0x80)\n    {\n        // 0x00 to 0x7F: ASCII range. The character is 1 byte long\n        return 1;\n    }\n    else if (first_char <= 0xc1)\n    {\n        // 0x80 to 0xc1: invalid. No UTF8 character starts with such a byte\n        return 0;\n    }\n    else if (first_char <= 0xdf)\n    {\n        // 0xc2 to 0xdf: two byte characters.\n        // It's vital that we check that the characters are valid. Otherwise, vulnerabilities can arise.\n\n        // Check that the string has enough bytes\n        if (input.size() < 2u)\n            return 0;\n\n        // The second byte must be between 0x80 and 0xbf. Otherwise, the character is invalid\n        // Do not skip this check - otherwise escaping will yield invalid results\n        if (input[1] < 0x80 || input[1] > 0xbf)\n            return 0;\n\n        // Valid, 2 byte character\n        return 2;\n    }\n    // Omitted: 3 and 4 byte long characters\n    else\n    {\n        return 0;\n    }\n}\n//]\n\nBOOST_AUTO_TEST_CASE(section_charsets)\n{\n    {\n        // Verify that utf8mb4_next_char can be used in a character_set\n        mysql::character_set charset{\"utf8mb4\", utf8mb4_next_char};\n\n        // It works for valid input\n        unsigned char buff_valid[] = {0xc3, 0xb1, 0x50};\n        BOOST_TEST(charset.next_char({buff_valid, sizeof(buff_valid)}) == 2u);\n\n        // It works for invalid input\n        unsigned char buff_invalid[] = {0xc3, 0xff, 0x50};\n        BOOST_TEST(charset.next_char({buff_invalid, sizeof(buff_invalid)}) == 0u);\n    }\n}\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/snippets/connection_establishment.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/io_context_fixture.hpp\"\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nBOOST_FIXTURE_TEST_CASE(section_connection_establishment, io_context_fixture)\n{\n    {\n        //[section_connection_establishment_max_buffer_size\n        // Increase the max buffer size to 512MB.\n        // This allows reading individual rows as big as 512MB.\n        // This is only required if each individual row is extremely big,\n        // and is not required for many smaller rows.\n        mysql::any_connection_params conn_params;\n        conn_params.max_buffer_size = 0x20000000;\n\n        // Create the connection\n        mysql::any_connection conn(ctx, conn_params);\n\n        // Connect and use the connection normally\n        //]\n    }\n}\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/connection_pool.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/asio/thread_pool.hpp>\n#include <boost/asio/use_future.hpp>\n#include <boost/config.hpp>\n#include <boost/system/error_code.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace mysql::test;\n\nnamespace {\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n//[connection_pool_get_connection\n// Use connection pools for functions that will be called\n// repeatedly during the application lifetime.\n// An HTTP server handler function is a good candidate.\nasio::awaitable<std::int64_t> get_num_employees(mysql::connection_pool& pool)\n{\n    // Get a fresh connection from the pool.\n    // pooled_connection is a proxy to an any_connection object.\n    mysql::pooled_connection conn = co_await pool.async_get_connection();\n\n    // Use pooled_connection::operator-> to access the underlying any_connection.\n    // Let's use the connection\n    mysql::results result;\n    co_await conn->async_execute(\"SELECT COUNT(*) FROM employee\", result);\n    co_return result.rows().at(0).at(0).as_int64();\n\n    // When conn is destroyed, the connection is returned to the pool\n}\n//]\n\nasio::awaitable<void> return_without_reset(mysql::connection_pool& pool)\n{\n    //[connection_pool_return_without_reset\n    // Get a connection from the pool\n    mysql::pooled_connection conn = co_await pool.async_get_connection();\n\n    // Use the connection in a way that doesn't mutate session state.\n    // We're not setting variables, preparing statements or starting transactions,\n    // so it's safe to skip reset\n    mysql::results result;\n    co_await conn->async_execute(\"SELECT COUNT(*) FROM employee\", result);\n\n    // Explicitly return the connection to the pool, skipping reset\n    conn.return_without_reset();\n    //]\n}\n\nasio::awaitable<void> apply_timeout(mysql::connection_pool& pool)\n{\n    //[connection_pool_apply_timeout\n    // Get a connection from the pool, but don't wait more than 5 seconds\n    auto conn = co_await pool.async_get_connection(asio::cancel_after(std::chrono::seconds(5)));\n    //]\n\n    conn.return_without_reset();\n}\n\n//[connection_pool_thread_safe_use\n// A function that handles a user session in a server\nasio::awaitable<void> handle_session(mysql::connection_pool& pool)\n{\n    // CAUTION: asio::cancel_after creates a timer that is *not* part of the pool's state.\n    // The timer is not protected by the pool's strand.\n    // This coroutine must be run within a strand for this to be safe\n    using namespace std::chrono_literals;\n    co_await pool.async_get_connection(asio::cancel_after(30s));\n\n    // Use the connection\n}\n//]\n#endif\n\n#ifndef BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES\n//[connection_pool_thread_safe_callbacks\n// Holds per-session state\nclass session_handler : public std::enable_shared_from_this<session_handler>\n{\n    // The connection pool\n    mysql::connection_pool& pool_;\n\n    // A strand object, unique to this session\n    asio::strand<asio::any_io_executor> strand_;\n\npublic:\n    // pool.get_executor() points to the execution context that was used\n    // to create the pool, and never to the pool's internal strand\n    session_handler(mysql::connection_pool& pool)\n        : pool_(pool), strand_(asio::make_strand(pool.get_executor()))\n    {\n    }\n\n    void start()\n    {\n        // Enters the strand. The passed function will be executed through the strand.\n        // If the initiation is run outside the strand, a race condition will occur.\n        asio::dispatch(asio::bind_executor(strand_, [self = shared_from_this()] { self->get_connection(); }));\n    }\n\n    void get_connection()\n    {\n        // This function will run within the strand. Binding the passed callback to\n        // the strand will make async_get_connection run it within the strand, too.\n        pool_.async_get_connection(asio::cancel_after(\n            std::chrono::seconds(30),\n            asio::bind_executor(\n                strand_,\n                [self = shared_from_this()](boost::system::error_code, mysql::pooled_connection) {\n                    // Use the connection as required\n                }\n            )\n        ));\n    }\n};\n\nvoid handle_session_v2(mysql::connection_pool& pool)\n{\n    // Start the callback chain\n    std::make_shared<session_handler>(pool)->start();\n}\n//]\n#endif\n\nBOOST_AUTO_TEST_CASE(section_connection_pool)\n{\n    auto server_hostname = get_hostname();\n\n    {\n        //[connection_pool_create\n        // pool_params contains configuration for the pool.\n        // You must specify enough information to establish a connection,\n        // including the server address and credentials.\n        // You can configure a lot of other things, like pool limits\n        mysql::pool_params params;\n        params.server_address.emplace_host_and_port(server_hostname);\n        params.username = mysql_username;\n        params.password = mysql_password;\n        params.database = \"boost_mysql_examples\";\n\n        // The I/O context, required by all I/O operations\n        asio::io_context ctx;\n\n        // Construct a pool of connections. The context will be used internally\n        // to create the connections and other I/O objects\n        mysql::connection_pool pool(ctx, std::move(params));\n\n        // You need to call async_run on the pool before doing anything useful with it.\n        // async_run creates connections and keeps them healthy. It must be called\n        // only once per pool.\n        // The detached completion token means that we don't want to be notified when\n        // the operation ends. It's similar to a no-op callback.\n        pool.async_run(asio::detached);\n        //]\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n        run_coro(ctx, [&pool]() -> asio::awaitable<void> {\n            co_await get_num_employees(pool);\n            pool.cancel();\n        });\n#endif\n    }\n    {\n        asio::io_context ctx;\n\n        //[connection_pool_configure_size\n        mysql::pool_params params;\n\n        // Set the usual params\n        params.server_address.emplace_host_and_port(server_hostname);\n        params.username = mysql_username;\n        params.password = mysql_password;\n        params.database = \"boost_mysql_examples\";\n\n        // Create 10 connections at startup, and allow up to 1000 connections\n        params.initial_size = 10;\n        params.max_size = 1000;\n\n        mysql::connection_pool pool(ctx, std::move(params));\n        //]\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n        pool.async_run(asio::detached);\n        run_coro(ctx, [&pool]() -> asio::awaitable<void> {\n            co_await return_without_reset(pool);\n            co_await apply_timeout(pool);\n            pool.cancel();\n        });\n#endif\n    }\n    {\n        //[connection_pool_thread_safe_create\n        // The I/O context, required by all I/O operations.\n        // This is like an io_context, but with 5 threads running it.\n        asio::thread_pool ctx(5);\n\n        // The usual pool configuration params\n        mysql::pool_params params;\n        params.server_address.emplace_host_and_port(server_hostname);\n        params.username = mysql_username;\n        params.password = mysql_password;\n        params.database = \"boost_mysql_examples\";\n        params.thread_safe = true;  // enable thread safety\n\n        // Construct a thread-safe pool\n        mysql::connection_pool pool(ctx, std::move(params));\n        pool.async_run(asio::detached);\n\n        // We can now pass a reference to pool to other threads,\n        // and call async_get_connection concurrently without problem.\n        // Individual connections are still not thread-safe.\n        //]\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n        //[connection_pool_thread_safe_spawn\n        // OK: the entire coroutine runs within a strand.\n        // In a typical server setup, each request usually gets its own strand,\n        // so it can run in parallel with other requests.\n        asio::co_spawn(\n            asio::make_strand(ctx),  // If we removed this make_strand, we would have a race condition\n            [&pool] { return handle_session(pool); },\n            asio::detached\n        );\n        //]\n#endif\n#ifndef BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES\n        handle_session_v2(pool);\n#endif\n        pool.cancel();\n        ctx.join();\n    }\n}\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/dynamic_interface.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n#include <string>\n\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing mysql::string_view;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nasio::awaitable<void> section_main(mysql::any_connection& conn)\n{\n    {\n        //[dynamic_views\n        // Populate a results object\n        mysql::results result;\n        co_await conn.async_execute(\"SELECT 'Hello world'\", result);\n\n        // results::rows() returns a rows_view. The underlying memory is owned by the results object\n        mysql::rows_view all_rows = result.rows();\n\n        // Indexing a rows_view yields a row_view. The underlying memory is owned by the results object\n        mysql::row_view first_row = all_rows.at(0);\n\n        // Indexing a row_view yields a field_view. The underlying memory is owned by the results object\n        mysql::field_view first_field = first_row.at(0);  // Contains the string \"Hello world\"\n\n        //]\n        BOOST_TEST(first_field.as_string() == \"Hello world\");\n\n        //[dynamic_taking_ownership\n        // You may use all_rows_owning after result has gone out of scope\n        mysql::rows all_rows_owning{all_rows};\n\n        // You may use first_row_owning after result has gone out of scope\n        mysql::row first_row_owning{first_row};\n\n        // You may use first_field_owning after result has gone out of scope\n        mysql::field first_field_owning{first_field};\n        //]\n    }\n    {\n        //[dynamic_using_fields\n        mysql::results result;\n        co_await conn.async_execute(\"SELECT 'abc', 42\", result);\n\n        // Obtain a field's underlying value using the is_xxx and get_xxx accessors\n        mysql::field_view f = result.rows().at(0).at(0);  // f points to the string \"abc\"\n        if (f.is_string())\n        {\n            // we know it's a string, unchecked access\n            string_view s = f.get_string();\n            std::cout << s << std::endl;  // Use the string as required\n        }\n        else\n        {\n            // Oops, something went wrong - schema mismatch?\n        }\n\n        // Alternative: use the as_xxx accessor\n        f = result.rows().at(0).at(1);\n        std::int64_t value = f.as_int64();  // Checked access. Throws if f doesn't contain an int\n        std::cout << value << std::endl;    // Use the int as required\n\n        //]\n    }\n    {\n        //[dynamic_handling_nulls\n        mysql::results result;\n\n        // Create some test data\n        co_await conn.async_execute(\n            R\"%(\n                CREATE TEMPORARY TABLE products (\n                    id VARCHAR(50) PRIMARY KEY,\n                    description VARCHAR(256)\n                );\n                INSERT INTO products VALUES ('PTT', 'Potatoes'), ('CAR', NULL)\n            )%\",\n            result\n        );\n\n        // Retrieve the data. Note that some fields are NULL\n        co_await conn.async_execute(\"SELECT id, description FROM products\", result);\n\n        for (mysql::row_view r : result.rows())\n        {\n            mysql::field_view description_fv = r.at(1);\n            if (description_fv.is_null())\n            {\n                // Handle the NULL value\n                // Note: description_fv.is_string() will return false here; NULL is represented as a separate\n                // type\n                std::cout << \"No description for product_id \" << r.at(0) << std::endl;\n            }\n            else\n            {\n                // Handle the non-NULL case. Get the underlying value and use it as you want\n                // If there is any schema mismatch (and description was not defined as VARCHAR), this will\n                // throw\n                string_view description = description_fv.as_string();\n\n                // Use description as required\n                std::cout << \"product_id \" << r.at(0) << \": \" << description << std::endl;\n            }\n        }\n        //]\n\n        conn.async_execute(\"DROP TABLE products\", result, as_netresult).validate_no_error();\n    }\n    {\n        //[dynamic_field_accessor_references\n        mysql::field f(\"my_string\");     // constructs a field that owns the string \"my_string\"\n        std::string& s = f.as_string();  // s points into f's storage\n        s.push_back('2');                // f now holds \"my_string2\"\n\n        //]\n\n        BOOST_TEST(s == \"my_string2\");\n    }\n    {\n        //[dynamic_field_assignment\n        mysql::field f(\"my_string\");  // constructs a field that owns the string \"my_string\"\n        f = 42;                       // destroys \"my_string\" and stores the value 42 as an int64\n\n        //]\n\n        BOOST_TEST(f.as_int64() == 42);\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(section_dynamic, snippets_fixture)\n{\n    run_coro(ctx, [&] { return section_main(conn); });\n}\n\n}  // namespace\n\n#endif\n"
  },
  {
    "path": "test/integration/test/snippets/interfacing_sync_async.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/config.hpp>\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/asio/thread_pool.hpp>\n#include <boost/asio/use_future.hpp>\n#include <boost/config.hpp>\n#include <boost/core/ignore_unused.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/system/system_error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <exception>\n#include <future>\n#include <optional>\n#include <string>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace mysql::test;\n\nnamespace {\n\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n    std::optional<std::int64_t> salary;\n};\nBOOST_DESCRIBE_STRUCT(employee, (), (first_name, last_name, salary))\n\nnamespace v1 {\n\n//[interfacing_sync_async_v1\n// Gets an employee's name given their ID, using a connection pool. This is a sync function.\nstd::optional<employee> get_employee_by_id(mysql::connection_pool& pool, std::int64_t id)\n{\n    // Get a connection from the pool. This will launch the operation, but won't wait for it\n    std::future<mysql::pooled_connection> fut = pool.async_get_connection(asio::use_future);\n\n    // Block the current thread until the operation completes.\n    // As we will explain later, you need a thread running your execution context for this to complete\n    mysql::pooled_connection conn = fut.get();\n\n    // There is a sync version of execute, so we can use it\n    mysql::static_results<employee> r;\n    conn->execute(mysql::with_params(\"SELECT * FROM employee WHERE id = {}\", id), r);\n\n    // Done\n    return r.rows().empty() ? std::optional<employee>() : r.rows()[0];\n}\n//]\n\n}  // namespace v1\n\nnamespace v2 {\n\nBOOST_ATTRIBUTE_UNUSED\n//[interfacing_sync_async_v2\nstd::optional<employee> get_employee_by_id(mysql::connection_pool& pool, std::int64_t id)\n{\n    using namespace std::chrono_literals;\n\n    // Do NOT do this!! This is a race condition!!\n    auto fut = pool.async_get_connection(asio::cancel_after(10s, asio::use_future));\n\n    // ...\n    //<-\n    boost::ignore_unused(id);\n    return {};\n    //->\n}\n//]\n\n}  // namespace v2\n\nnamespace v3 {\n\n// clang-format off\n//[interfacing_sync_async_v3\nstd::optional<employee> get_employee_by_id(mysql::connection_pool& pool, std::int64_t id)\n{\n    using namespace std::chrono_literals;\n\n    // Create a strand for this operation. Strands require an underlying\n    // executor. Use the pool's executor, which points to the thread_pool we created.\n    auto strand = asio::make_strand(pool.get_executor());\n\n    // First enter the strand with asio::dispatch, then call async_get_connection through the strand.\n    // asio::dispatch + asio::bind_executor is Asio's standard way to \"run a function in an executor\"\n    std::future<mysql::pooled_connection> fut = asio::dispatch(\n        // bind_executor binds an executor to a completion token.\n        // deferred creates an async chain\n        asio::bind_executor(\n            strand,\n            asio::deferred([&] {\n                // This function will be called when we're in the strand and determines what to do next\n                return pool.async_get_connection(\n                    asio::cancel_after(10s, asio::bind_executor(strand, asio::deferred))\n                );\n            })\n        )\n    )(asio::use_future); // Initiate the chain and convert it into a future\n\n    // Wait for the async chain to finish\n    mysql::pooled_connection conn = fut.get();\n\n    // Execute as in the previous version\n    mysql::static_results<employee> r;\n    conn->execute(mysql::with_params(\"SELECT * FROM employee WHERE id = {}\", id), r);\n    return r.rows().empty() ? std::optional<employee>() : r.rows()[0];\n}\n//]\n// clang-format on\n\n}  // namespace v3\n\nBOOST_AUTO_TEST_CASE(section_interfacing_sync_async_v1_v3)\n{\n    auto server_hostname = get_hostname();\n\n    //[interfacing_sync_async_v1_init\n    // Initialization code - run this once at program startup\n\n    // Execution context, required to run all async operations.\n    // This is equivalent to using asio::io_context and a thread that calls run()\n    asio::thread_pool ctx(1);  // Use only one thread\n\n    // Create the connection pool\n    mysql::pool_params params;\n    params.server_address.emplace_host_and_port(server_hostname);\n    params.username = mysql_username;\n    params.password = mysql_password;\n    params.database = \"boost_mysql_examples\";\n    params.thread_safe = true;  // allow initiating async_get_connection from any thread\n    mysql::connection_pool pool(ctx, std::move(params));\n    pool.async_run(asio::detached);\n    //]\n\n    // Check that everything's OK. v2 omitted because it's a race condition\n    v1::get_employee_by_id(pool, 1);\n    v3::get_employee_by_id(pool, 2);\n}\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\nnamespace v4 {\n\n//[interfacing_sync_async_v4\n// Gets an employee's name given their ID, using a connection pool. This is a sync function.\nstd::optional<employee> get_employee_by_id(mysql::connection_pool& pool, std::int64_t id)\n{\n    using namespace std::chrono_literals;\n\n    // Spawn a coroutine in the pool's executor - that is, in the thread_pool.\n    // Since the pool has only one thread, and all code in the coroutine runs within that thread,\n    // there is no need for a strand here.\n    // co_spawn is an async operation, and can be used with asio::use_future\n    std::future<std::optional<employee>> fut = asio::co_spawn(\n        pool.get_executor(),\n        [&pool, id]() -> asio::awaitable<std::optional<employee>> {\n            // Get a connection from the pool\n            auto conn = co_await pool.async_get_connection(asio::cancel_after(30s));\n\n            // Execute\n            mysql::static_results<employee> r;\n            co_await conn->async_execute(\n                mysql::with_params(\"SELECT * FROM employee WHERE id = {}\", id),\n                r,\n                asio::cancel_after(30s)\n            );\n\n            // Done\n            co_return r.rows().empty() ? std::optional<employee>() : r.rows()[0];\n        },\n        asio::use_future\n    );\n\n    // Wait for the future\n    return fut.get();\n}\n//]\n\n}  // namespace v4\n#endif\n\nnamespace v5 {\n\n//[interfacing_sync_async_v5\n// Gets an employee's name given their ID, using a connection pool. This is a sync function.\nstd::optional<employee> get_employee_by_id(mysql::connection_pool& pool, std::int64_t id)\n{\n    using namespace std::chrono_literals;\n\n    // A promise, so we can wait for the task to complete\n    std::promise<std::optional<employee>> prom;\n\n    // These temporary variables should be kept alive until all async operations\n    // complete, so they're declared here\n    mysql::pooled_connection conn;\n    mysql::static_results<employee> r;\n\n    // Ensure that everything runs within the thread pool\n    asio::dispatch(asio::bind_executor(pool.get_executor(), [&] {\n        // Get a connection from the pool\n        pool.async_get_connection(asio::cancel_after(\n            30s,\n            [&](boost::system::error_code ec, mysql::pooled_connection temp_conn) {\n                if (ec)\n                {\n                    // If there was an error getting the connection, complete the promise and return\n                    prom.set_exception(std::make_exception_ptr(boost::system::system_error(ec)));\n                }\n                else\n                {\n                    // Store the connection somewhere. If it gets destroyed, it's returned to the pool\n                    conn = std::move(temp_conn);\n\n                    // Start executing the query\n                    conn->async_execute(\n                        mysql::with_params(\"SELECT * FROM employee WHERE id = {}\", id),\n                        r,\n                        asio::cancel_after(\n                            30s,\n                            [&](boost::system::error_code ec) {\n                                if (ec)\n                                {\n                                    // If there was an error, complete the promise and return\n                                    prom.set_exception(std::make_exception_ptr(boost::system::system_error(ec)\n                                    ));\n                                }\n                                else\n                                {\n                                    // Done\n                                    prom.set_value(\n                                        r.rows().empty() ? std::optional<employee>() : r.rows()[0]\n                                    );\n                                }\n                            }\n                        )\n                    );\n                }\n            }\n        ));\n    }));\n\n    return prom.get_future().get();\n}\n//]\n\n}  // namespace v5\n\nBOOST_AUTO_TEST_CASE(section_interfacing_sync_async_v4_v5)\n{\n    auto server_hostname = get_hostname();\n\n    //[interfacing_sync_async_v4_init\n    // Initialization code - run this once at program startup\n\n    // Execution context, required to run all async operations.\n    // This is equivalent to asio::io_context plus a thread calling run()\n    asio::thread_pool ctx(1);\n\n    // Create the connection pool. The pool is NOT thread-safe\n    mysql::pool_params params;\n    params.server_address.emplace_host_and_port(server_hostname);\n    params.username = mysql_username;\n    params.password = mysql_password;\n    params.database = \"boost_mysql_examples\";\n    mysql::connection_pool pool(ctx, std::move(params));\n\n    // Run the pool. async_run should be executed in the thread_pool's thread -\n    // otherwise, we have a race condition\n    asio::dispatch(asio::bind_executor(ctx.get_executor(), [&] { pool.async_run(asio::detached); }));\n//]\n\n// Check that everything's OK\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n    v4::get_employee_by_id(pool, 0xfffff);\n#endif\n    v5::get_employee_by_id(pool, 1);\n}\n\n}  // namespace\n\n#endif"
  },
  {
    "path": "test/integration/test/snippets/metadata.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_integration/snippets/get_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nBOOST_AUTO_TEST_CASE(section_metadata)\n{\n    auto& conn = get_connection();\n\n    //[metadata\n    // By default, a connection has metadata_mode::minimal\n    results result;\n    conn.execute(\"SELECT 1 AS my_field\", result);\n    string_view colname = result.meta()[0].column_name();\n\n    // colname will be empty because conn.meta_mode() == metadata_mode::minimal\n    BOOST_TEST(colname == \"\");\n\n    // If you are using metadata names, set the connection's metadata_mode\n    conn.set_meta_mode(metadata_mode::full);\n    conn.execute(\"SELECT 1 AS my_field\", result);\n    colname = result.meta()[0].column_name();\n    BOOST_TEST(colname == \"my_field\");\n    //]\n\n    conn.set_meta_mode(metadata_mode::minimal);\n}\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/multi_function.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstddef>\n#include <iostream>\n#include <string>\n\n#include \"test_integration/snippets/describe.hpp\"\n#include \"test_integration/snippets/get_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nstatic std::string get_company_id() { return \"HGS\"; }\n\nBOOST_AUTO_TEST_CASE(section_multi_function)\n{\n    auto& conn = get_connection();\n\n    {\n        //[multi_function_setup\n        const char* table_definition = R\"%(\n            CREATE TEMPORARY TABLE posts (\n                id INT PRIMARY KEY AUTO_INCREMENT,\n                title VARCHAR (256) NOT NULL,\n                body TEXT NOT NULL\n            )\n        )%\";\n        //]\n\n        results result;\n        conn.execute(table_definition, result);\n        conn.execute(\n            R\"%(\n                INSERT INTO posts (title, body) VALUES\n                    ('Post 1', 'A very long post body'),\n                    ('Post 2', 'An even longer post body')\n            )%\",\n            result\n        );\n\n        //[multi_function_dynamic_start\n        // st will hold information about the operation being executed.\n        // It must be passed to any successive operations for this execution\n        execution_state st;\n\n        // Sends the query and reads response and meta, but not the rows\n        conn.start_execution(\"SELECT title, body FROM posts\", st);\n        //]\n\n        //[multi_function_dynamic_read\n        // st.complete() returns true once the OK packet is received\n        while (!st.complete())\n        {\n            // row_batch will be valid until conn performs the next network operation\n            rows_view row_batch = conn.read_some_rows(st);\n\n            for (row_view post : row_batch)\n            {\n                // Process post as required\n                std::cout << \"Title:\" << post.at(0) << std::endl;\n            }\n        }\n        //]\n    }\n#ifdef BOOST_MYSQL_CXX14\n    {\n        //[multi_function_static_start\n        // st will hold information about the operation being executed.\n        // It must be passed to any successive operations for this execution\n        static_execution_state<post> st;\n\n        // Sends the query and reads response and meta, but not the rows.\n        // If there is any schema mismatch between the declared row type and\n        // what the server returned, start_execution will detect it and fail\n        conn.start_execution(\"SELECT id, title, body FROM posts\", st);\n        //]\n\n        //[multi_function_static_read\n        // storage will be filled with the read rows. You can use any other contiguous range.\n        std::array<post, 20> posts;\n\n        // st.complete() returns true once the OK packet is received\n        while (!st.complete())\n        {\n            std::size_t read_rows = conn.read_some_rows(st, boost::span<post>(posts));\n            for (const post& p : boost::span<post>(posts.data(), read_rows))\n            {\n                // Process post as required\n                std::cout << \"Title \" << p.title << std::endl;\n            }\n        }\n        //]\n\n        results result;\n        conn.execute(\"DROP TABLE posts\", result);\n    }\n#endif\n    {\n        //[multi_function_stored_procedure_dynamic\n        // Get the company ID to retrieve, possibly from the user\n        std::string company_id = get_company_id();\n\n        // Call the procedure\n        execution_state st;\n        statement stmt = conn.prepare_statement(\"CALL get_employees(?)\");\n        conn.start_execution(stmt.bind(company_id), st);\n\n        // The above code will generate 3 resultsets\n        // Read the 1st one, which contains the matched companies\n        while (st.should_read_rows())\n        {\n            rows_view company_batch = conn.read_some_rows(st);\n\n            // Use the retrieved companies as required\n            for (row_view company : company_batch)\n            {\n                std::cout << \"Company: \" << company.at(1).as_string() << \"\\n\";\n            }\n        }\n\n        // Move on to the 2nd one, containing the employees for these companies\n        conn.read_resultset_head(st);\n        while (st.should_read_rows())\n        {\n            rows_view employee_batch = conn.read_some_rows(st);\n\n            // Use the retrieved employees as required\n            for (row_view employee : employee_batch)\n            {\n                std::cout << \"Employee \" << employee.at(0).as_string() << \" \" << employee.at(1).as_string()\n                          << \"\\n\";\n            }\n        }\n\n        // The last one is an empty resultset containing information about the\n        // CALL statement itself. We're not interested in this\n        conn.read_resultset_head(st);\n        assert(st.complete());\n        //]\n    }\n#ifdef BOOST_MYSQL_CXX14\n    {\n        //[multi_function_stored_procedure_static\n        // Get the company ID to retrieve, possibly from the user\n        std::string company_id = get_company_id();\n\n        // Our procedure generates three resultsets. We must pass each row type\n        // to static_execution_state as template parameters\n        using empty = std::tuple<>;\n        static_execution_state<company, employee, empty> st;\n\n        // Call the procedure\n        statement stmt = conn.prepare_statement(\"CALL get_employees(?)\");\n        conn.start_execution(stmt.bind(company_id), st);\n\n        // Read the 1st one, which contains the matched companies\n        std::array<company, 5> companies;\n        while (st.should_read_rows())\n        {\n            std::size_t read_rows = conn.read_some_rows(st, boost::span<company>(companies));\n\n            // Use the retrieved companies as required\n            for (const company& c : boost::span<company>(companies.data(), read_rows))\n            {\n                std::cout << \"Company: \" << c.name << \"\\n\";\n            }\n        }\n\n        // Move on to the 2nd one, containing the employees for these companies\n        conn.read_resultset_head(st);\n        std::array<employee, 20> employees;\n        while (st.should_read_rows())\n        {\n            std::size_t read_rows = conn.read_some_rows(st, boost::span<employee>(employees));\n\n            // Use the retrieved companies as required\n            for (const employee& emp : boost::span<employee>(employees.data(), read_rows))\n            {\n                std::cout << \"Employee \" << emp.first_name << \" \" << emp.last_name << \"\\n\";\n            }\n        }\n\n        // The last one is an empty resultset containing information about the\n        // CALL statement itself. We're not interested in this\n        conn.read_resultset_head(st);\n        assert(st.complete());\n        //]\n    }\n#endif\n}\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/snippets/multi_resultset.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/resultset_view.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/static_results.hpp>\n\n#include <boost/core/ignore_unused.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <iostream>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/snippets/describe.hpp\"\n#include \"test_integration/snippets/get_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nstd::int64_t get_employee_id() { return 42; }\n\nBOOST_AUTO_TEST_CASE(section_multi_resultset)\n{\n    auto& conn = get_connection();\n\n    {\n        //[multi_resultset_call_dynamic\n\n        // We're using the dynamic interface. results can stored multiple resultsets\n        results result;\n\n        // The procedure parameter, employee_id, will likely be obtained from an untrusted source,\n        // so we will use a prepared statement\n        statement get_employee_stmt = conn.prepare_statement(\"CALL get_employees(?)\");\n\n        // Obtain the parameters required to call the statement, e.g. from a file or HTTP message\n        std::int64_t employee_id = get_employee_id();\n\n        // Call the statement\n        conn.execute(get_employee_stmt.bind(employee_id), result);\n\n        // results can be used as a random-access collection of resultsets.\n        // result.at(0).rows() returns the matched companies, if any\n        rows_view matched_company = result.at(0).rows();\n\n        // We can do the same to access the matched employees\n        rows_view matched_employees = result.at(1).rows();\n\n        // Use matched_company and matched_employees as required\n        //]\n\n        boost::ignore_unused(matched_company);\n        boost::ignore_unused(matched_employees);\n    }\n#ifdef BOOST_MYSQL_CXX14\n    {\n        //[multi_resultset_call_static\n        // We must list all the resultset types the operation returns as template arguments\n        static_results<company, employee, empty> result;\n        conn.execute(\"CALL get_employees('HGS')\", result);\n\n        // We can use rows<0>() to access the rows for the first resultset\n        if (result.rows<0>().empty())\n        {\n            std::cout << \"Company not found\" << std::endl;\n        }\n        else\n        {\n            const company& comp = result.rows<0>()[0];\n            std::cout << \"Company name: \" << comp.name << \", tax_id: \" << comp.tax_id << std::endl;\n        }\n\n        // rows<1>() will return the rows for the second resultset\n        for (const employee& emp : result.rows<1>())\n        {\n            std::cout << \"Employee \" << emp.first_name << \" \" << emp.last_name << std::endl;\n        }\n        //]\n    }\n#endif\n    {\n        //[multi_resultset_out_params\n        // To retrieve output parameters, you must use prepared statements. Text queries don't support this\n        // We specify placeholders for both IN and OUT parameters\n        statement stmt = conn.prepare_statement(\"CALL create_employee(?, ?, ?, ?)\");\n\n        // When executing the statement, we provide an actual value for the IN parameters,\n        // and a dummy value for the OUT parameter. This value will be ignored, but it's required by the\n        // protocol\n        results result;\n        conn.execute(stmt.bind(\"HGS\", \"John\", \"Doe\", nullptr), result);\n\n        // Retrieve output parameters. This row_view has an element per\n        // OUT or INOUT parameter that used a ? placeholder\n        row_view output_params = result.out_params();\n        std::int64_t new_employee_id = output_params.at(0).as_int64();\n        //]\n\n        boost::ignore_unused(new_employee_id);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(section_multi_resultset_multi_queries)\n{\n    boost::asio::io_context ctx;\n    boost::asio::ip::tcp::resolver resolver(ctx.get_executor());\n    tcp_connection conn(ctx.get_executor());\n\n    auto endpoint = *resolver.resolve(get_hostname(), default_port_string).begin();\n\n    //[multi_resultset_multi_queries\n    // The username and password to use\n    boost::mysql::handshake_params params(\n        mysql_username,         // username, as a string\n        mysql_password,         // password, as a string\n        \"boost_mysql_examples\"  // database\n    );\n\n    // Allows running multiple semicolon-separated in a single call.\n    // We must set this before calling connect\n    params.set_multi_queries(true);\n\n    // Connect to the server specifying that we want support for multi-queries\n    conn.connect(endpoint, params);\n\n    // We can now use the multi-query feature.\n    // This will result in three resultsets, one per query.\n    results result;\n    conn.execute(\n        R\"(\n            CREATE TEMPORARY TABLE posts (\n                id INT PRIMARY KEY AUTO_INCREMENT,\n                title VARCHAR (256),\n                body TEXT\n            );\n            INSERT INTO posts (title, body) VALUES ('Breaking news', 'Something happened!');\n            SELECT COUNT(*) FROM posts;\n        )\",\n        result\n    );\n    //]\n\n    //[multi_resultset_results_as_collection\n    // result is actually a random-access collection of resultsets.\n    // The INSERT is the 2nd query, so we can access its resultset like this:\n    boost::mysql::resultset_view insert_result = result.at(1);\n\n    // A resultset has metadata, rows, and additional data, like the last insert ID:\n    std::int64_t post_id = insert_result.last_insert_id();\n\n    // The SELECT result is the third one, so we can access it like this:\n    boost::mysql::resultset_view select_result = result.at(2);\n\n    // select_result is a view that points into result.\n    // We can take ownership of it using the resultset class:\n    boost::mysql::resultset owning_select_result(select_result);  // valid even after result is destroyed\n\n    // We can access rows of resultset objects as usual:\n    std::int64_t num_posts = owning_select_result.rows().at(0).at(0).as_int64();\n    //]\n\n    boost::ignore_unused(post_id);\n    boost::ignore_unused(num_posts);\n}\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/snippets/overview.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/experimental/cancellation_condition.hpp>\n#include <boost/asio/experimental/parallel_group.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/redirect_error.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <string>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\ninline namespace overview {\n//[overview_static_struct\n// This must be placed at namespace scope.\n// Should contain a member for each field of interest present in our query.\n// Declaration order doesn't need to match field order in the query.\n// Field names should match the ones in our query\nstruct employee\n{\n    std::int64_t id;\n    std::string first_name;\n    std::string last_name;\n};\n//]\n}  // namespace overview\n\nnamespace {\n\nasio::awaitable<void> overview_coro(mysql::any_connection& conn)\n{\n    std::string server_hostname = get_hostname();\n    int employee_id = 1;\n    const char* new_name = \"John\";\n\n    auto& ctx = static_cast<asio::io_context&>((co_await asio::this_coro::executor).context());\n\n    {\n        //[overview_connect\n        // The hostname, username, password and database to use.\n        mysql::connect_params params;\n        params.server_address.emplace_host_and_port(server_hostname);  // hostname\n        params.username = mysql_username;\n        params.password = mysql_password;\n        params.database = \"boost_mysql_examples\";\n\n        // Connect to the server\n        co_await conn.async_connect(params);\n        //]\n    }\n    {\n        //[overview_text_query\n        // Executes 'SELECT 1' and reads the resulting rows into memory\n        mysql::results result;\n        co_await conn.async_execute(\"SELECT 1\", result);\n        //]\n    }\n\n    {\n        //[overview_with_params\n        // If employee_id is 42, executes 'SELECT first_name FROM employee WHERE id = 42'\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\"SELECT first_name FROM employee WHERE id = {}\", employee_id),\n            result\n        );\n        //]\n    }\n\n    {\n        //[overview_statement\n        // First prepare the statement. Parsing happens server-side.\n        mysql::statement stmt = co_await conn.async_prepare_statement(\n            \"SELECT first_name FROM employee WHERE company_id = ?\"\n        );\n\n        // Now execute it. Parameter substitution happens server-side.\n        mysql::results result;\n        co_await conn.async_execute(stmt.bind(employee_id), result);\n        //]\n    }\n    {\n        //[overview_ifaces_dynamic\n        // Passing a results to async_execute selects the dynamic interface\n        mysql::results result;\n        co_await conn.async_execute(\"SELECT id, first_name, last_name FROM employee\", result);\n\n        // Every employee is a collection of fields, which are variant-like objects\n        // that represent data. We use as_string() to cast them to the appropriate type\n        for (mysql::row_view emp : result.rows())\n        {\n            std::cout << \"First name: \" << emp.at(1).as_string() << \", last name: \" << emp.at(2).as_string()\n                      << std::endl;\n        }\n        //]\n    }\n#if BOOST_PFR_CORE_NAME_ENABLED\n    {\n        // The struct definition is included above this\n        //[overview_ifaces_static\n        //\n        // This must be placed inside your function or method:\n        //\n\n        // Passing a static_results to async_execute selects the static interface\n        mysql::static_results<mysql::pfr_by_name<employee>> result;\n        co_await conn.async_execute(\"SELECT id, first_name, last_name FROM employee\", result);\n\n        // Query results are parsed directly into your own type\n        for (const employee& emp : result.rows())\n        {\n            std::cout << \"First name: \" << emp.first_name << \", last name: \" << emp.last_name << std::endl;\n        }\n        //]\n    }\n#endif\n    {\n        //[overview_update\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\"UPDATE employee SET first_name = {} WHERE id = {}\", new_name, employee_id),\n            result\n        );\n        //]\n    }\n#if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)\n    {\n        try\n        {\n            //[overview_async_parallel\n            // This is an error: a single connection can't run two operations\n            // in parallel. Create more connections or use connection_pool, instead.\n            mysql::results result1, result2;\n            co_await asio::experimental::make_parallel_group(\n                conn.async_execute(\"SELECT 1\", result1, asio::deferred),\n                conn.async_execute(\"SELECT 2\", result2, asio::deferred)\n            )\n                .async_wait(asio::experimental::wait_for_all(), asio::deferred);\n            //]\n        }\n        catch (const mysql::error_with_diagnostics& err)\n        {\n            BOOST_TEST(err.code() == mysql::client_errc::operation_in_progress);\n        }\n    }\n#endif\n    {\n        //[overview_no_exceptions\n        mysql::error_code ec;\n        mysql::diagnostics diag;\n        mysql::results result;\n\n        // The provided SQL is invalid. The server will return an error.\n        // ec will be set to a non-zero value, and diag will be populated\n        co_await conn.async_execute(\"this is not SQL!\", result, diag, asio::redirect_error(ec));\n        if (ec)\n        {\n            // The error code will likely report a syntax error\n            std::cout << \"Operation failed with error code: \" << ec << '\\n';\n\n            // diag.server_message() will contain the classic phrase\n            // \"You have an error in your SQL syntax; check the manual...\"\n            // Bear in mind that server_message() may contain user input, so treat it with caution\n            std::cout << \"Server diagnostics: \" << diag.server_message() << std::endl;\n        }\n        //]\n        BOOST_TEST(ec != mysql::error_code());\n    }\n    {\n        //[overview_multifn\n        // execution_state stores state about our operation, and must be passed to all functions\n        mysql::execution_state st;\n\n        // Writes the query request and reads the server response, but not the rows\n        co_await conn.async_start_execution(\"SELECT first_name, last_name FROM employee\", st);\n\n        // Reads all the returned rows, in batches.\n        // st.should_read_rows() returns false once there are no more rows to read\n        while (st.should_read_rows())\n        {\n            // row_batch will be valid until conn performs the next network operation\n            mysql::rows_view row_batch = co_await conn.async_read_some_rows(st);\n\n            for (mysql::row_view emp : row_batch)\n            {\n                // Process the employee as required\n                std::cout << \"Name:\" << emp.at(0) << \" \" << emp.at(1) << std::endl;\n            }\n        }\n        //]\n    }\n    {\n        //[overview_pool_create\n        // pool_params contains configuration for the pool.\n        // You must specify enough information to establish a connection,\n        // including the server address and credentials.\n        // You can configure a lot of other things, like pool limits\n        mysql::pool_params params;\n        params.server_address.emplace_host_and_port(server_hostname);\n        params.username = mysql_username;\n        params.password = mysql_password;\n        params.database = \"boost_mysql_examples\";\n\n        // Construct a pool of connections. The execution context will be used internally\n        // to create the connections and other I/O objects\n        mysql::connection_pool pool(ctx, std::move(params));\n\n        // You need to call async_run on the pool before doing anything useful with it.\n        // async_run creates connections and keeps them healthy. It must be called\n        // only once per pool.\n        // The detached completion token means that we don't want to be notified when\n        // the operation ends. It's similar to a no-op callback.\n        pool.async_run(asio::detached);\n        //]\n\n        // If we don't use the pool, we may leave unfinished work in the context\n        co_await pool.async_get_connection();\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(section_overview, any_connection_fixture)\n{\n    run_coro(ctx, [&]() { return overview_coro(conn); });\n}\n\n}  // namespace\n\n#endif"
  },
  {
    "path": "test/integration/test/snippets/pipeline.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/system/system_error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <vector>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/snippets/get_any_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_CASE(section_pipeline)\n{\n    auto& conn = get_any_connection();\n\n    //[pipeline_request\n    // Create a pipeline request and add three stages to it.\n    // When run, this pipeline will set the connection's character set to utf8mb4\n    // and prepare two statements.\n    pipeline_request req;\n    req.add_set_character_set(utf8mb4_charset)\n        .add_prepare_statement(\"INSERT INTO audit_log (t, msg) VALUES (?, ?)\")\n        .add_prepare_statement(\"INSERT INTO employee (company_id, first_name, last_name) VALUES (?, ?, ?)\");\n    //]\n\n    //[pipeline_run\n    // Run the pipeline request req, and store responses into res\n    // stage_response is a variant-like type that can store the response\n    // of any stage type (including results and statements).\n    std::vector<stage_response> res;\n    conn.run_pipeline(req, res);\n    //]\n\n    //[pipeline_results\n    // The 2nd and 3rd stages were statement preparation requests,\n    // so res[1] and res[2] contain statement objects\n    statement stmt1 = res[1].as_statement();\n    statement stmt2 = res[2].as_statement();\n    //]\n\n    BOOST_TEST(stmt1.valid());\n    BOOST_TEST(stmt2.valid());\n}\n\nBOOST_AUTO_TEST_CASE(section_pipeline_errors)\n{\n    auto& conn = get_any_connection();\n\n    //[pipeline_errors\n    // The second step in the pipeline will fail, the other ones will succeeded\n    pipeline_request req;\n    req.add_set_character_set(utf8mb4_charset)\n        .add_prepare_statement(\"INSERT INTO bad_table (t, msg) VALUES (?, ?)\")  // will fail\n        .add_prepare_statement(\"INSERT INTO employee (company_id, first_name, last_name) VALUES (?, ?, ?)\");\n\n    std::vector<stage_response> res;\n    error_code ec;\n    diagnostics diag;\n\n    conn.run_pipeline(req, res, ec, diag);\n\n    // The overall operation failed\n    BOOST_TEST(ec == common_server_errc::er_no_such_table);\n\n    // You can check which stages failed using .error()\n    BOOST_TEST(res[0].error() == error_code());\n    BOOST_TEST(res[1].error() == common_server_errc::er_no_such_table);\n    BOOST_TEST(res[2].error() == error_code());\n    //]\n}\n\nBOOST_AUTO_TEST_CASE(section_pipeline_pitfalls)\n{\n    auto& conn = get_any_connection();\n\n    {\n        //[pipeline_pitfalls_bad\n        // This doesn't behave correctly - DO NOT DO THIS\n        // The first INSERT will fail due to a failed foreign key check (there is no such company),\n        // but COMMIT will still be run, thus leaving us with an inconsistent data model\n        pipeline_request req;\n\n        req.add_execute(\"START TRANSACTION\")\n            .add_execute(\n                \"INSERT INTO employee (first_name, last_name, company_id) VALUES ('John', 'Doe', 'bad')\"\n            )\n            .add_execute(\"INSERT INTO logs VALUES ('Inserted 1 employee')\")\n            .add_execute(\"COMMIT\");\n        //]\n\n        std::vector<stage_response> res;\n        error_code ec;\n        diagnostics diag;\n        conn.run_pipeline(req, res, ec, diag);\n        BOOST_TEST(ec == common_server_errc::er_no_referenced_row_2);\n    }\n\n    {\n        try\n        {\n            //[pipeline_pitfalls_good\n            const char* sql =\n                \"START TRANSACTION;\"\n                \"INSERT INTO employee (first_name, last_name, company_id) VALUES ('John', 'Doe', 'bad');\"\n                \"INSERT INTO logs VALUES ('Inserted 1 employee');\"\n                \"COMMIT\";\n\n            // After the first INSERT fails, nothing else will be run. This is what we want.\n            // Note that you need to enable multi queries when connecting to be able to run this.\n            results r;\n            conn.execute(sql, r);\n            //]\n        }\n        catch (const boost::system::system_error& err)\n        {\n            BOOST_TEST(err.code() == common_server_errc::er_no_referenced_row_2);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(section_pipeline_reference)\n{\n    auto& conn = get_any_connection();\n    results result;\n    std::vector<stage_response> pipe_res;\n\n    // Execute\n    {\n        pipeline_request req;\n        auto stmt = conn.prepare_statement(\"SELECT ?, ?, ?\");\n\n        //[pipeline_reference_execute\n        // Text query\n        req.add_execute(\"SELECT 1\");\n\n        // Prepared statement, with number of parameters known at compile time\n        req.add_execute(stmt, \"John\", \"Doe\", 42);\n\n        // Prepared statement, with number of parameters unknown at compile time\n        std::vector<field_view> params{\n            /* ... */\n            //<-\n            field_view(\"Janet\"),\n            field_view(\"Joyce\"),\n            field_view(50)\n            //->\n        };\n        req.add_execute_range(stmt, params);\n        //]\n\n        conn.run_pipeline(req, pipe_res);\n        BOOST_TEST(pipe_res.at(0).as_results().rows() == makerows(1, 1), per_element());\n        BOOST_TEST(pipe_res.at(1).as_results().rows() == makerows(3, \"John\", \"Doe\", 42), per_element());\n        BOOST_TEST(pipe_res.at(2).as_results().rows() == makerows(3, \"Janet\", \"Joyce\", 50), per_element());\n    }\n    {\n        auto stmt = conn.prepare_statement(\"SELECT ?, ?, ?\");\n\n        //[pipeline_reference_execute_equivalent\n        // Text query\n        conn.execute(\"SELECT 1\", result);\n        //<-\n        BOOST_TEST(result.rows() == makerows(1, 1), per_element());\n        //->\n\n        // Prepared statement, with number of parameters known at compile time\n        conn.execute(stmt.bind(\"John\", \"Doe\", 42), result);\n        //<-\n        BOOST_TEST(result.rows() == makerows(3, \"John\", \"Doe\", 42), per_element());\n        //->\n\n        // Prepared statement, with number of parameters unknown at compile time\n        std::vector<field_view> params{\n            /* ... */\n            //<-\n            field_view(\"Janet\"),\n            field_view(\"Joyce\"),\n            field_view(50)\n            //->\n        };\n        conn.execute(stmt.bind(params.begin(), params.end()), result);\n        //]\n\n        BOOST_TEST(result.rows() == makerows(3, \"Janet\", \"Joyce\", 50), per_element());\n    }\n\n    // Prepare statement\n    {\n        pipeline_request req;\n\n        //[pipeline_reference_prepare_statement\n        req.add_prepare_statement(\"SELECT * FROM employee WHERE id = ?\");\n        //]\n\n        conn.run_pipeline(req, pipe_res);\n        BOOST_TEST(pipe_res.at(0).as_statement().valid());\n    }\n    {\n        //[pipeline_reference_prepare_statement_equivalent\n        statement stmt = conn.prepare_statement(\"SELECT * FROM employee WHERE id = ?\");\n        //]\n\n        BOOST_TEST(stmt.valid());\n    }\n\n    // Close statement\n    {\n        pipeline_request req;\n        auto stmt = conn.prepare_statement(\"SELECT 1\");\n\n        //[pipeline_reference_close_statement\n        req.add_close_statement(stmt);\n        //]\n\n        conn.run_pipeline(req, pipe_res);\n    }\n    {\n        auto stmt = conn.prepare_statement(\"SELECT 1\");\n\n        //[pipeline_reference_close_statement_equivalent\n        conn.close_statement(stmt);\n        //]\n    }\n\n    // Reset connection\n    {\n        pipeline_request req;\n\n        //[pipeline_reference_reset_connection\n        req.add_reset_connection();\n        //]\n    }\n    {\n        //[pipeline_reference_reset_connection_equivalent\n        conn.reset_connection();\n        //]\n    }\n\n    // Set character set\n    {\n        pipeline_request req;\n        //[pipeline_reference_set_character_set\n        req.add_set_character_set(utf8mb4_charset);\n        //]\n    }\n    {\n        //[pipeline_reference_set_character_set_equivalent\n        conn.set_character_set(utf8mb4_charset);\n        //]\n    }\n}\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/prepared_statements.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/asio/io_context.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <optional>\n#include <string_view>\n#include <vector>\n\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace mysql::test;\n\nnamespace {\n\n//[prepared_statements_execute_null\n// Inserts a new employee into the database.\n// We may not have the salary information for some people,\n// so we represent the value as an optional\nasio::awaitable<void> insert_employee(\n    mysql::any_connection& conn,\n    const mysql::statement& stmt,\n    std::string_view first_name,\n    std::string_view last_name,\n    std::optional<int> salary,\n    std::string_view company_id\n)\n{\n    // If salary has a value, an integer will be sent to the server.\n    // Otherwise, a NULL value will be sent\n    mysql::results result;\n    co_await conn.async_execute(stmt.bind(first_name, last_name, salary, company_id), result);\n}\n//]\n\n//[prepared_statements_iterator_range\n// Executes the passed statement with the given parameters.\nasio::awaitable<void> execute_statement(\n    mysql::any_connection& conn,\n    const mysql::statement& stmt,\n    const std::vector<mysql::field>& params\n)\n{\n    mysql::results result;\n    co_await conn.async_execute(stmt.bind(params.begin(), params.end()), result);\n\n    // Do something useful with result\n}\n//]\n\nasio::awaitable<void> section_main(mysql::any_connection& conn)\n{\n    {\n        //[prepared_statements_prepare\n        // Ask the server to prepare a statement to insert a new employee.\n        // statement is a lightweight handle to the server-side statement.\n        // Each ? is a parameter\n        mysql::statement stmt = co_await conn.async_prepare_statement(\n            \"INSERT INTO employee (first_name, last_name, salary, company_id) VALUES (?, ?, ?, ?)\"\n        );\n        //]\n\n        //[prepared_statements_execute\n        // Bind and execute the statement. You must pass one parameter per '?' placeholder in the statement.\n        // In the real world, parameters should be runtime values, rather than constants.\n        // Note that bind() does not involve communication with the server\n        mysql::results result;\n        co_await conn.async_execute(stmt.bind(\"John\", \"Doe\", 40000, \"HGS\"), result);\n        //]\n\n        //[prepared_statements_close\n        // Deallocate the statement from the server.\n        // Note that closing the connection will also deallocate the statement.\n        co_await conn.async_close_statement(stmt);\n        //]\n    }\n\n    {\n        //[prepared_statements_casting\n        // Prepare the statement\n        mysql::statement stmt = co_await conn.async_prepare_statement(\n            \"INSERT INTO employee (first_name, last_name, salary, company_id) VALUES (?, ?, ?, ?)\"\n        );\n\n        // Execute it, passing an 8 byte unsigned integer as the salary value.\n        // The salary column was created as an INT (4 byte, signed integer).\n        // MySQL will cast the value server-side, and emit an error only if the supplied\n        // value is out of range of the target type\n        std::uint64_t salary = 45000;\n        mysql::results result;\n        co_await conn.async_execute(stmt.bind(\"John\", \"Doe\", salary, \"HGS\"), result);\n        //]\n\n        // Verify that everything's OK with the insertion function\n        co_await insert_employee(conn, stmt, \"John\", \"Doe\", {}, \"HGS\");\n\n        // Verify that everything's OK with the range execution function\n        // Note: don't inline params in the execute_statement call, as it triggers a gcc ICE\n        const std::vector<mysql::field> params{\n            mysql::field_view(\"John\"),\n            mysql::field_view(\"Doe\"),\n            mysql::field_view(35000),\n            mysql::field_view(\"HGS\")\n        };\n        co_await execute_statement(conn, stmt, params);\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(section_prepared_statements, snippets_fixture)\n{\n    run_coro(ctx, [this]() { return section_main(conn); });\n}\n\n}  // namespace\n\n#endif\n"
  },
  {
    "path": "test/integration/test/snippets/sql_formatting_advanced.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/io_context.hpp>\n#include <boost/assert/source_location.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/system/result.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cmath>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"test_common/has_ranges.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/source_location.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n#include <string_view>\n#endif\n#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE\n#include <memory_resource>\n#endif\n#ifdef BOOST_MYSQL_HAS_RANGES\n#include <ranges>\n#endif\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace mysql::test;\n\ninline namespace sql_formatting {\n//[sql_formatting_formatter_specialization\n// We want to add formatting support for employee\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n    std::string company_id;\n};\n//<-\n}  // namespace sql_formatting\n//->\nnamespace boost {\nnamespace mysql {\n\ntemplate <>\nstruct formatter<employee>\n{\n    // formatter<T> should define the following functions:\n    //    const char* parse(const char* first, const char*);\n    //    void format(const T&, format_context_base&) const;\n\n    const char* parse(const char* begin, const char* /* end */)\n    {\n        // Parse any format specifiers for this type.\n        // [begin, end) points to the range of characters holding the format specifier string\n        // We should return a pointer to the first unparsed character.\n        // We don't support any specifiers for this type, so we return the begin pointer.\n        return begin;\n    }\n\n    void format(const employee& emp, format_context_base& ctx) const\n    {\n        // Perform the actual formatting by appending characters to ctx.\n        // We usually use format_sql_to to achieve this.\n        // We will make this suitable for INSERT statements\n        format_sql_to(ctx, \"{}, {}, {}\", emp.first_name, emp.last_name, emp.company_id);\n    }\n};\n\n}  // namespace mysql\n}  // namespace boost\n//]\n\nnamespace {\n\n// Used to verify that the generated query is well-formed\nvoid run_query(\n    mysql::any_connection& conn,\n    mysql::string_view q,\n    boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n)\n{\n    mysql::results r;\n    conn.async_execute(q, r, as_netresult).validate_no_error(loc);\n}\n\n#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL) && !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)\n//[sql_formatting_incremental_fn\n// Compose a query that retrieves all employees in a company,\n// with an optional limit\nstd::string compose_select_query(\n    mysql::format_options opts,\n    std::string_view company_id,\n    std::optional<long> limit\n)\n{\n    // format_context will accumulate the query as we compose it\n    mysql::format_context ctx(opts);\n\n    // format_sql_to expands a format string and appends the result\n    // to a format context. This way, we can build our query in smaller pieces\n    // Add all the query except for the LIMIT clause\n    mysql::format_sql_to(ctx, \"SELECT * FROM employee WHERE company_id = {}\", company_id);\n\n    if (limit)\n    {\n        // Add the LIMIT clause\n        mysql::format_sql_to(ctx, \" LIMIT {}\", *limit);\n    }\n\n    // Retrieve the generated query string.\n    // get() returns a boost::system::result<std::string> that\n    // contains an error if any of the format operations failed.\n    // Calling value() will throw on error, like format_sql does\n    return std::move(ctx).get().value();\n}\n//]\n#endif\n\nBOOST_AUTO_TEST_CASE(section_sql_formatting)\n{\n    snippets_fixture fix;  // Prevent name shadowing warnings under MSVC with ctx\n    auto& conn = fix.conn;\n    const auto opts = conn.format_opts().value();\n\n    {\n        //[sql_formatting_format_sql\n        // Compose the SQL query without executing it.\n        // format_opts returns a system::result<format_options>,\n        // contains settings like the current character set.\n        // If the connection is using an unknown character set, this will throw an error.\n        std::string query = mysql::format_sql(\n            conn.format_opts().value(),\n            \"SELECT id, salary FROM employee WHERE last_name = {}\",\n            \"Doe\"\n        );\n\n        BOOST_TEST(query == \"SELECT id, salary FROM employee WHERE last_name = 'Doe'\");\n        //]\n\n        run_query(conn, query);\n    }\n#if !defined(BOOST_NO_CXX17_HDR_OPTIONAL) && !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)\n    {\n        //[sql_formatting_incremental_use\n        std::string query = compose_select_query(conn.format_opts().value(), \"HGS\", {});\n        BOOST_TEST(query == \"SELECT * FROM employee WHERE company_id = 'HGS'\");\n        //<-\n        run_query(conn, query);\n        //->\n\n        query = compose_select_query(conn.format_opts().value(), \"HGS\", 50);\n        BOOST_TEST(query == \"SELECT * FROM employee WHERE company_id = 'HGS' LIMIT 50\");\n        //]\n\n        run_query(conn, query);\n    }\n#endif\n    {\n        //[sql_formatting_sequence_1\n        // Employee is a plain struct, not formattable by default\n        std::vector<employee> employees{\n            {\"John\", \"Doe\",   \"HGS\"},\n            {\"Kate\", \"Smith\", \"AWC\"},\n        };\n        std::string query = format_sql(\n            conn.format_opts().value(),\n            \"INSERT INTO employee (first_name, last_name, company_id) VALUES {}\",\n            mysql::sequence(\n                employees,\n                [](const employee& e, mysql::format_context_base& ctx) {\n                    // This function will be called for each element in employees,\n                    // and should format a single element into the passed ctx.\n                    // Commas will be inserted separating elements.\n                    format_sql_to(ctx, \"({}, {}, {})\", e.first_name, e.last_name, e.company_id);\n                }\n            )\n        );\n        BOOST_TEST(\n            query ==\n            \"INSERT INTO employee (first_name, last_name, company_id) VALUES \"\n            \"('John', 'Doe', 'HGS'), ('Kate', 'Smith', 'AWC')\"\n        );\n        //]\n        run_query(conn, query);\n    }\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n    {\n        //[sql_formatting_sequence_2\n        // A collection of filters to apply to a query\n        std::vector<std::pair<std::string_view, std::string_view>> filters{\n            {\"company_id\", \"HGS\" },\n            {\"first_name\", \"John\"},\n        };\n\n        std::string query = format_sql(\n            conn.format_opts().value(),\n            \"SELECT * FROM employee WHERE {}\",\n            mysql::sequence(\n                filters,\n                [](const std::pair<std::string_view, std::string_view>& f, mysql::format_context_base& ctx) {\n                    // Compose a single filter\n                    format_sql_to(ctx, \"{:i} = {}\", f.first, f.second);\n                },\n                \" AND \"  // glue string: separate each element with AND clauses\n            )\n        );\n\n        BOOST_TEST(query == \"SELECT * FROM employee WHERE `company_id` = 'HGS' AND `first_name` = 'John'\");\n        //]\n        run_query(conn, query);\n    }\n#endif\n\n    {\n        //[sql_formatting_specifiers\n        std::string query = mysql::format_sql(\n            conn.format_opts().value(),\n            \"SELECT id, last_name FROM employee ORDER BY {:i} DESC\",\n            \"company_id\"\n        );\n\n        BOOST_TEST(query == \"SELECT id, last_name FROM employee ORDER BY `company_id` DESC\");\n        //]\n\n        run_query(conn, query);\n    }\n    {\n        //[sql_formatting_specifiers_explicit_indices\n        std::string query = mysql::format_sql(\n            conn.format_opts().value(),\n            \"SELECT id, last_name FROM employee ORDER BY {0:i} DESC\",\n            \"company_id\"\n        );\n        //]\n\n        BOOST_TEST(query == \"SELECT id, last_name FROM employee ORDER BY `company_id` DESC\");\n        run_query(conn, query);\n    }\n    {\n        //[sql_formatting_formatter_use\n        // We can now use employee as a built-in value\n        std::string query = mysql::format_sql(\n            conn.format_opts().value(),\n            \"INSERT INTO employee (first_name, last_name, company_id) VALUES ({}), ({})\",\n            employee{\"John\", \"Doe\", \"HGS\"},\n            employee{\"Rick\", \"Johnson\", \"AWC\"}\n        );\n\n        BOOST_TEST(\n            query ==\n            \"INSERT INTO employee (first_name, last_name, company_id) VALUES \"\n            \"('John', 'Doe', 'HGS'), ('Rick', 'Johnson', 'AWC')\"\n        );\n        //]\n\n        run_query(conn, query);\n    }\n    {\n        //[sql_formatting_auto_indexing\n        BOOST_TEST(\n            mysql::format_sql(opts, \"SELECT {}, {}, {}\", 42, \"abc\", nullptr) == \"SELECT 42, 'abc', NULL\"\n        );\n        //]\n    }\n    {\n        //[sql_formatting_manual_auto_mix\n        try\n        {\n            // Mixing manual and auto indexing is illegal. This will throw an exception.\n            mysql::format_sql(opts, \"SELECT {0}, {}\", 42);\n            //<-\n            BOOST_TEST(false);\n            //->\n        }\n        catch (const boost::system::system_error& err)\n        {\n            BOOST_TEST(err.code() == mysql::client_errc::format_string_manual_auto_mix);\n        }\n        //]\n    }\n    {\n        //[sql_formatting_unused_args\n        // This is OK\n        std::string query = mysql::format_sql(opts, \"SELECT {}\", 42, \"abc\");\n        //]\n        BOOST_TEST(query == \"SELECT 42\");\n    }\n    {\n        //[sql_formatting_brace_literal\n        BOOST_TEST(\n            format_sql(opts, \"SELECT 'Brace literals: {{ and }}'\") == \"SELECT 'Brace literals: { and }'\"\n        );\n        //]\n    }\n    {\n        //[sql_formatting_format_double_error\n        try\n        {\n            // We're trying to format a double infinity value, which is not\n            // supported by MySQL. This will throw an exception.\n            std::string formatted_query = mysql::format_sql(opts, \"SELECT {}\", HUGE_VAL);\n            //<-\n            BOOST_TEST(false);\n            boost::ignore_unused(formatted_query);\n            //->\n        }\n        catch (const boost::system::system_error& err)\n        {\n            BOOST_TEST(err.code() == mysql::client_errc::unformattable_value);\n        }\n        //]\n    }\n    {\n        //[sql_formatting_no_exceptions\n        // ctx contains an error code that tracks whether any error happened\n        mysql::format_context ctx(opts);\n\n        // We're trying to format a infinity, which is an error. This\n        // will set the error state, but won't throw.\n        mysql::format_sql_to(ctx, \"SELECT {}, {}\", HUGE_VAL, 42);\n\n        // The error state gets checked at this point. Since it is set,\n        // res will contain an error.\n        boost::system::result<std::string> res = std::move(ctx).get();\n        BOOST_TEST(!res.has_value());\n        BOOST_TEST(res.has_error());\n        BOOST_TEST(res.error() == mysql::client_errc::unformattable_value);\n        // res.value() would throw an error, like format_sql would\n        //]\n    }\n#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE\n    {\n        //[sql_formatting_custom_string\n        // Create a format context that uses std::pmr::string\n        mysql::basic_format_context<std::pmr::string> ctx(conn.format_opts().value());\n\n        // Compose your query as usual\n        mysql::format_sql_to(ctx, \"SELECT * FROM employee WHERE id = {}\", 42);\n\n        // Retrieve the query as usual\n        std::pmr::string query = std::move(ctx).get().value();\n        //]\n\n        BOOST_TEST(query == \"SELECT * FROM employee WHERE id = 42\");\n        run_query(conn, query);\n    }\n#endif\n    {\n        //[sql_formatting_memory_reuse\n        // we want to re-use memory held by storage\n        std::string storage;\n\n        // storage is moved into ctx by the constructor. If any memory\n        // had been allocated by the string, it will be re-used.\n        mysql::format_context ctx(conn.format_opts().value(), std::move(storage));\n\n        // Use ctx as you normally would\n        mysql::format_sql_to(ctx, \"SELECT {}\", 42);\n\n        // When calling get(), the string is moved out of the context\n        std::string query = std::move(ctx).get().value();\n        //]\n\n        BOOST_TEST(query == \"SELECT 42\");\n    }\n}\n\nBOOST_AUTO_TEST_CASE(section_sql_formatting_reference)\n{\n    {\n        using namespace boost::mysql;\n        using boost::optional;\n        const mysql::format_options opts{mysql::utf8mb4_charset, true};\n\n        //[sql_formatting_reference_signed\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", 42) == \"SELECT 42\"\n            //<-\n        );\n        //->\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", -1) == \"SELECT -1\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_unsigned\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", 42u) == \"SELECT 42\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_bool\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", false) == \"SELECT 0\"\n            //<-\n        );\n        //->\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", true) == \"SELECT 1\"\n            //<-\n        );\n        //->\n        //]\n\n        // clang-format off\n        //[sql_formatting_reference_string\n        // Without format specifier: escaped, quoted string value\n        //<-\n        BOOST_TEST(\n        //->\n        format_sql(opts, \"SELECT {}\", \"Hello world\") == \"SELECT 'Hello world'\"\n        //<-\n        );\n        BOOST_TEST(\n        //->\n        format_sql(opts, \"SELECT {}\", \"Hello 'world'\") == R\"(SELECT 'Hello \\'world\\'')\"\n        //<-\n        );\n        //->\n\n        // {:i}: escaped, quoted dynamic identifier\n        //<-\n        BOOST_TEST(\n        //->\n        format_sql(opts, \"SELECT {:i} FROM t\", \"salary\") == \"SELECT `salary` FROM t\"\n        //<-\n        );\n        BOOST_TEST(\n        //->\n        format_sql(opts, \"SELECT {:i} FROM t\", \"sal`ary\") == \"SELECT `sal``ary` FROM t\"\n        //<-\n        );\n        //->\n\n        // {:r}: raw, unescaped SQL. WARNING: incorrect use can cause vulnerabilities\n        //<-\n        BOOST_TEST(\n        //->\n        format_sql(opts, \"SELECT * FROM t WHERE id = 42 {:r} salary > 20000\", \"OR\") ==\n            \"SELECT * FROM t WHERE id = 42 OR salary > 20000\"\n        //<-\n        );\n        //->\n        //]\n        // clang-format on\n\n        //[sql_formatting_reference_blob\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", blob{0x00, 0x48, 0xff}) == R\"(SELECT x'0048ff')\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_float\n        //<-\n        BOOST_TEST(\n            //->\n            // Equivalent to format_sql(opts, \"SELECT {}\", static_cast<double>(4.2f))\n            // Note that MySQL uses doubles for all floating point literals\n            format_sql(opts, \"SELECT {}\", 4.2f) == \"SELECT 4.199999809265137e+00\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_double\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", 4.2) == \"SELECT 4.2e+00\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_date\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", date(2021, 1, 2)) == \"SELECT '2021-01-02'\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_datetime\n        //<-\n        BOOST_TEST(\n            // clang-format off\n            //->\n            format_sql(opts, \"SELECT {}\", datetime(2021, 1, 2, 23, 51, 14)) == \"SELECT '2021-01-02 23:51:14.000000'\"\n            //<-\n            // clang-format on\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_time\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", std::chrono::seconds(121)) == \"SELECT '00:02:01.000000'\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_nullptr\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", nullptr) == \"SELECT NULL\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_optional\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", optional<int>(42)) == \"SELECT 42\"\n            //<-\n        );\n        //->\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", optional<int>()) == \"SELECT NULL\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_field\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", field(42)) == \"SELECT 42\"\n            //<-\n        );\n        //->\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", field(\"abc\")) == \"SELECT 'abc'\"\n            //<-\n        );\n        //->\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", field()) == \"SELECT NULL\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_ranges\n        //<-\n        BOOST_TEST(\n            //->\n            // long is a WritableField\n            format_sql(opts, \"SELECT {}\", std::vector<long>{1, 5, 20}) == \"SELECT 1, 5, 20\"\n            //<-\n        );\n//->\n\n//<-\n#ifdef BOOST_MYSQL_HAS_RANGES\n        BOOST_TEST(\n            //->\n            // C++20 ranges and other custom ranges accepted\n            format_sql(opts, \"SELECT {}\", std::vector<long>{1, 5, 20} | std::ranges::views::take(2)) ==\n            \"SELECT 1, 5\"\n            //<-\n        );\n#endif\n        //->\n\n        //<-\n        BOOST_TEST(\n            //->\n            // Apply the 'i' specifier to each element in the sequence\n            format_sql(\n                opts,\n                \"SELECT {::i} FROM employee\",\n                std::vector<string_view>{\"first_name\", \"last_name\"}\n            ) == \"SELECT `first_name`, `last_name` FROM employee\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_sequence\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(\n                opts,\n                \"SELECT {}\",\n                sequence(\n                    std::vector<int>{1, 5, 20},\n                    [](int val, format_context_base& ctx) { format_sql_to(ctx, \"{}+1\", val); }\n                )\n            ) == \"SELECT 1+1, 5+1, 20+1\"\n            //<-\n        );\n        //->\n        //]\n\n        //[sql_formatting_reference_formattable_ref\n        //<-\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {}\", formattable_ref(42)) == \"SELECT 42\"\n            //<-\n        );\n        BOOST_TEST(\n            //->\n            format_sql(opts, \"SELECT {:i} FROM t\", formattable_ref(\"salary\")) == \"SELECT `salary` FROM t\"\n            //<-\n        );\n        //->\n        //]\n    }\n}\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/sql_formatting_advanced_2.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n// This contains a different definition of formatter<employee>\n// Having it separate avoids problems\n\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/network_result.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\nnamespace mysql = boost::mysql;\nusing namespace mysql::test;\n\nnamespace {\n\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n    std::string company_id;\n};\n\n}  // namespace\n\nnamespace boost {\nnamespace mysql {\n\n//[sql_formatting_formatter_specialization_specifiers\ntemplate <>\nstruct formatter<employee>\n{\n    // Should we format our employee as an INSERT or an UPDATE?\n    // This flag is set by parse and used by format\n    bool format_as_update{false};\n\n    const char* parse(const char* it, const char* end)\n    {\n        // Parse any format specifiers for this type.\n        // We recognize the 'u' specifier, which means that we should\n        // format the type for an UPDATE statement, instead of an INSERT\n        // If no specifier is found, default to INSERT\n        // Note that the range may be empty, so we must check for this condition\n        if (it != end && *it == 'u')\n        {\n            // The 'u' specifier is present, record it\n            format_as_update = true;\n\n            // Mark the current character as parsed\n            ++it;\n        }\n\n        // Return a pointer to the first unparsed character.\n        // If we didn't manage to parse the entire character range, an error will be emitted.\n        // The library already takes care of this.\n        return it;\n    }\n\n    void format(const employee& emp, format_context_base& ctx) const\n    {\n        if (format_as_update)\n        {\n            // This should be suitable to be placed in an UPDATE ... SET statement\n            format_sql_to(\n                ctx,\n                \"first_name={}, last_name={}, company_id={}\",\n                emp.first_name,\n                emp.last_name,\n                emp.company_id\n            );\n        }\n        else\n        {\n            // Format only the values, as in INSERT statements\n            format_sql_to(ctx, \"{}, {}, {}\", emp.first_name, emp.last_name, emp.company_id);\n        }\n    }\n};\n//]\n\n}  // namespace mysql\n}  // namespace boost\n\nnamespace {\n\nBOOST_FIXTURE_TEST_CASE(section_sql_formatting_formatter_specifiers, snippets_fixture)\n{\n    mysql::results r;\n\n    //[sql_formatting_formatter_use_specifiers\n    // We can now use the 'u' specifier with employee\n    std::string query = mysql::format_sql(\n        conn.format_opts().value(),\n        \"UPDATE employee SET {:u} WHERE id = {}\",\n        employee{\"John\", \"Doe\", \"HGS\"},\n        42\n    );\n\n    BOOST_TEST(\n        query == \"UPDATE employee SET first_name='John', last_name='Doe', company_id='HGS' WHERE id = 42\"\n    );\n    //<-\n    conn.async_execute(query, r, as_netresult).validate_no_error();\n    //->\n\n    // If no format specifier is provided, we get the old behavior\n    query = mysql::format_sql(\n        conn.format_opts().value(),\n        \"INSERT INTO employee (first_name, last_name, company_id) VALUES ({}), ({})\",\n        employee{\"John\", \"Doe\", \"HGS\"},\n        employee{\"Rick\", \"Johnson\", \"AWC\"}\n    );\n\n    BOOST_TEST(\n        query ==\n        \"INSERT INTO employee (first_name, last_name, company_id) VALUES \"\n        \"('John', 'Doe', 'HGS'), ('Rick', 'Johnson', 'AWC')\"\n    );\n    //]\n    conn.async_execute(query, r, as_netresult).validate_no_error();\n}\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/snippets/static_interface.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/static_results.hpp>\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/as_tuple.hpp>\n#include <boost/asio/awaitable.hpp>\n#include <boost/config.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <string>\n#include <tuple>\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\nnamespace asio = boost::asio;\nnamespace mysql = boost::mysql;\nusing namespace mysql::test;\n\n// PFR types can't be placed in anonymous namespaces\nnamespace snippets_static {\n\n//\n// Main explanation. These snippets require C++20\n//\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n//[static_interface_describe_employee_v1\n// We can use a plain struct with ints and strings to describe our rows.\nstruct employee_v1\n{\n    int id;\n    std::string first_name;\n    std::string last_name;\n};\n\n// This must be placed at the namespace level. It adds reflection capabilities to our struct\nBOOST_DESCRIBE_STRUCT(employee_v1, (), (id, first_name, last_name))\n//]\n\n//[static_interface_describe_statistics\nstruct statistics\n{\n    std::string company;\n    double average;\n    double max_value;\n};\nBOOST_DESCRIBE_STRUCT(statistics, (), (company, average, max_value))\n//]\n\n//[static_interface_describe_employee_v2\n// If we try to query the employee table with this struct definition,\n// an error will be issued because salary can be NULL in the database,\n// but not in the C++ type\nstruct employee_v2\n{\n    int id;\n    std::string first_name;\n    std::string last_name;\n    unsigned salary;\n};\nBOOST_DESCRIBE_STRUCT(employee_v2, (), (id, first_name, last_name, salary))\n//]\n\n//[static_interface_describe_employee_v3\nstruct employee_v3\n{\n    int id;\n    std::string first_name;\n    std::string last_name;\n    std::optional<unsigned> salary;  // salary might be NULL in the database\n};\nBOOST_DESCRIBE_STRUCT(employee_v3, (), (id, first_name, last_name, salary))\n//]\n\n//[static_interface_pfr_employee\n// employee_v4 doesn't contain any metadata - we're not using BOOST_DESCRIBE_STRUCT here\nstruct employee_v4\n{\n    int id;\n    std::string first_name;\n    std::string last_name;\n    std::optional<unsigned> salary;\n};\n//]\n\nasio::awaitable<void> section_main(mysql::any_connection& conn)\n{\n    {\n        //[static_interface_query\n        mysql::static_results<employee_v1> result;\n        co_await conn.async_execute(\"SELECT id, first_name, last_name FROM employee LIMIT 10\", result);\n\n        for (const employee_v1& emp : result.rows())\n        {\n            // Process the employee as required\n            std::cout << \"ID: \" << emp.id << \": \" << emp.first_name << ' ' << emp.last_name << \"\\n\";\n        }\n        //]\n    }\n    {\n        //[static_interface_field_order\n        // Summing 0e0 is MySQL way to cast a DECIMAL field to DOUBLE\n        constexpr const char* sql = R\"%(\n            SELECT\n                IFNULL(AVG(salary), 0.0) + 0e0 AS average,\n                IFNULL(MAX(salary), 0.0) + 0e0 AS max_value,\n                company_id AS company\n            FROM employee\n            GROUP BY company_id\n        )%\";\n\n        mysql::static_results<statistics> result;\n        co_await conn.async_execute(sql, result);\n        //]\n    }\n    {\n        // Check that the optional version works\n        mysql::static_results<employee_v3> result;\n        co_await conn.async_execute(\"SELECT * FROM employee LIMIT 1\", result);\n    }\n#if BOOST_PFR_CORE_NAME_ENABLED\n    {\n        //[static_interface_pfr_by_name\n        // pfr_by_name is a marker type. It tells static_results to use\n        // Boost.PFR for reflection, instead of Boost.Describe.\n        mysql::static_results<mysql::pfr_by_name<employee_v4>> result;\n\n        // As with Boost.Describe, query fields are matched to struct\n        // members by name. This means that the fields in the query\n        // may appear in any order.\n        co_await conn.async_execute(\"SELECT * FROM employee LIMIT 10\", result);\n\n        // Note that result.rows() is a span of employee_v4 objects,\n        // rather than pfr_by_name<employee_v4> objects. employee_v4\n        // is the underlying row type for pfr_by_name<employee_v4>\n        for (const employee_v4& emp : result.rows())\n        {\n            // Process the employee as required\n            std::cout << \"ID: \" << emp.id << \": \" << emp.first_name << ' ' << emp.last_name << \"\\n\";\n        }\n        //]\n    }\n    {\n        //[static_interface_pfr_by_position\n        // pfr_by_position is another marker type.\n        // Fields in employee_v4 must appear in the same order as in the query,\n        // as matching will be done by position.\n        mysql::static_results<mysql::pfr_by_position<employee_v4>> result;\n        co_await conn.async_execute(\"SELECT id, first_name, last_name, salary FROM employee\", result);\n\n        // The underlying row type is employee_v4\n        for (const employee_v4& emp : result.rows())\n        {\n            // Process the employee as required\n            std::cout << \"ID: \" << emp.id << \": \" << emp.first_name << ' ' << emp.last_name << \"\\n\";\n        }\n        //]\n    }\n#endif\n    {\n        //[static_interface_tuples\n        mysql::static_results<std::tuple<std::int64_t>> result;\n        co_await conn.async_execute(\"SELECT COUNT(*) FROM employee\", result);\n        std::cout << \"Number of employees: \" << std::get<0>(result.rows()[0]) << \"\\n\";\n        //]\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(section_static_interface, snippets_fixture)\n{\n    run_coro(ctx, [this] { return section_main(conn); });\n}\n\nBOOST_FIXTURE_TEST_CASE(section_static_interface_error, snippets_fixture)\n{\n    // Check the nullability error. At the moment, this is a fatal error,\n    // so it must be run in a separate test case\n    mysql::static_results<employee_v2> result;\n    conn.async_execute(\"SELECT * FROM employee LIMIT 1\", result, as_netresult)\n        .validate_error(\n            mysql::client_errc::metadata_check_failed,\n            \"NULL checks failed for field 'salary': the database type may be NULL, but the C++ type cannot. \"\n            \"Use std::optional<T> or boost::optional<T>\"\n        );\n}\n\n#endif\n\n//\n// Comparison table. This part does not require C++20,\n// since the table has a \"C++ standard required\" field.\n// We want all type definitions here to be similar.\n//\n\nnamespace descr_type {\n//[static_interface_comparison_describe_struct\n// Definition should be at namespace scope\nstruct employee\n{\n    int id;\n    std::string first_name;\n    std::string last_name;\n};\nBOOST_DESCRIBE_STRUCT(employee, (), (id, first_name, last_name))\n//]\n}  // namespace descr_type\n\nnamespace pfr_type {\n//[static_interface_comparison_pfr_struct\n// Definition should be at namespace scope\nstruct employee\n{\n    int id;\n    std::string first_name;\n    std::string last_name;\n};\n//]\n}  // namespace pfr_type\n\nBOOST_FIXTURE_TEST_CASE(section_static_interface_comparison_table, snippets_fixture)\n{\n    // Left as sync because the table has a \"C++ standard required\" field\n    // that is < C++20 for most of the techniques\n    {\n        using namespace descr_type;\n        //[static_interface_comparison_describe\n        // Usage\n        mysql::static_results<employee> result;\n        conn.execute(\"SELECT first_name, last_name, id FROM employee\", result);\n        //]\n    }\n#if BOOST_PFR_CORE_NAME_ENABLED\n    {\n        using namespace pfr_type;\n        //[static_interface_comparison_pfr_by_name\n        // Usage\n        mysql::static_results<mysql::pfr_by_name<employee>> result;\n        conn.execute(\"SELECT first_name, last_name, id FROM employee\", result);\n        //]\n    }\n#endif\n#if BOOST_PFR_USE_CPP17\n    {\n        using namespace pfr_type;\n        //[static_interface_comparison_pfr_by_position\n        // Usage\n        mysql::static_results<mysql::pfr_by_position<employee>> result;\n        conn.execute(\"SELECT id, first_name, last_name FROM employee\", result);\n        //]\n    }\n#endif\n    {\n        //[static_interface_comparison_tuples\n        using tuple_t = std::tuple<int, std::string, std::string>;\n        mysql::static_results<tuple_t> result;\n        conn.execute(\"SELECT id, first_name, last_name FROM employee\", result);\n        //]\n    }\n}\n\n}  // namespace snippets_static\n\n#endif\n"
  },
  {
    "path": "test/integration/test/snippets/templated_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/defaults.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/tcp.hpp>\n#include <boost/mysql/tcp_ssl.hpp>\n#include <boost/mysql/unix.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/connect.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/server_features.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace mysql::test;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(section_templated_connection)\n\nBOOST_AUTO_TEST_CASE(creation)\n{\n    auto server_hostname = get_hostname();\n\n    //[templated_connection_creation\n    // The execution context, required for all I/O operations\n    asio::io_context ctx;\n\n    // The SSL context, required for connections that use TLS.\n    asio::ssl::context ssl_ctx(asio::ssl::context::tlsv12_client);\n\n    // Construct the connection. The arguments are forwarded\n    // to the stream type (asio::ssl::stream<asio::ip::tcp::socket>).\n    mysql::tcp_ssl_connection conn(ctx, ssl_ctx);\n    //]\n\n    //[templated_connection_connect\n    // Resolve the hostname to get a collection of endpoints.\n    // default_port_string is MySQL's default port, 3306\n    // Hostname resolution may yield more than one host\n    asio::ip::tcp::resolver resolver(ctx);\n    auto endpoints = resolver.resolve(server_hostname, mysql::default_port_string);\n\n    // Parameters specifying how to perform the MySQL handshake operation.\n    // Similar to connect_params, but doesn't contain the server address and is non-owning\n    mysql::handshake_params params(\n        mysql_username,\n        mysql_password,\n        \"boost_mysql_examples\"  // database to use\n    );\n\n    // Connect to the server using the first endpoint returned by the resolver\n    conn.connect(*endpoints.begin(), params);\n    //]\n\n    //[templated_connection_use\n    // Issue a query, as you would with any_connection\n    mysql::results result;\n    conn.execute(\"SELECT 1\", result);\n    //]\n\n    //[templated_connection_close\n    conn.close();\n    //]\n}\n\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\nBOOST_TEST_DECORATOR(*run_if(&server_features::unix_sockets))\nBOOST_AUTO_TEST_CASE(unix_sockets)\n{\n    //[templated_connection_unix\n    // The execution context, required for all I/O operations\n    asio::io_context ctx;\n\n    // A UNIX connection requires only an execution context\n    mysql::unix_connection conn(ctx);\n\n    // The socket path where the server is listening\n    asio::local::stream_protocol::endpoint ep(\"/var/run/mysqld/mysqld.sock\");\n\n    // MySQL handshake parameters, as in the TCP case.\n    mysql::handshake_params params(\n        mysql_username,\n        mysql_password,\n        \"boost_mysql_examples\"  // database to use\n    );\n\n    // Connect to the server\n    conn.connect(ep, params);\n\n    // Use the connection normally\n    //]\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(handshake_quit)\n{\n    auto server_hostname = get_hostname();\n\n    //[templated_connection_handshake_quit\n    // The execution context, required for all I/O operations\n    asio::io_context ctx;\n\n    // The SSL context, required for connections that use TLS.\n    asio::ssl::context ssl_ctx(asio::ssl::context::tlsv12_client);\n\n    // We're using TLS over TCP\n    mysql::tcp_ssl_connection conn(ctx, ssl_ctx);\n\n    // Resolve the server hostname into endpoints\n    asio::ip::tcp::resolver resolver(ctx);\n    auto endpoints = resolver.resolve(server_hostname, mysql::default_port_string);\n\n    // Connect the underlying stream manually.\n    // asio::connect tries every endpoint in the passed sequence\n    // until one succeeds. any_connection uses this internally.\n    // lowest_layer obtains the underlying socket from the ssl::stream\n    asio::connect(conn.stream().lowest_layer(), endpoints);\n\n    // Perform MySQL session establishment.\n    // This will also perform the TLS handshake, if required.\n    mysql::handshake_params params(\n        mysql_username,\n        mysql_password,\n        \"boost_mysql_examples\"  // database to use\n    );\n    conn.handshake(params);\n\n    // Use the connection normally\n    mysql::results result;\n    conn.execute(\"SELECT 1\", result);\n\n    // Terminate the connection. This also performs the TLS shutdown.\n    conn.quit();\n\n    // Close the underlying stream.\n    // The connection's destructor also closes the socket,\n    // but doing it explicitly will throw in case of error.\n    conn.stream().lowest_layer().close();\n    //]\n}\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\nBOOST_FIXTURE_TEST_CASE(with_diagnostics_, io_context_fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        // Setup\n        mysql::tcp_connection conn(ctx);\n        asio::ip::tcp::resolver resolv(ctx);\n        auto endpoints = co_await resolv.async_resolve(get_hostname(), mysql::default_port_string);\n        mysql::handshake_params hparams(mysql_username, mysql_password);\n        co_await conn.async_connect(*endpoints.begin(), hparams, mysql::with_diagnostics(asio::deferred));\n        mysql::results result;\n\n        //[templated_connection_with_diagnostics\n        co_await conn.async_execute(\"SELECT 1\", result, mysql::with_diagnostics(asio::deferred));\n        //]\n    });\n}\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/text_queries.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/asio/awaitable.hpp>\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <optional>\n#include <string>\n#include <vector>\n\n#include \"test_common/printing.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nstd::string get_name() { return \"John\"; }\n\nasio::awaitable<void> section_main(mysql::any_connection& conn)\n{\n    {\n        //[text_queries_with_params_simple\n        std::string employee_name = get_name();  // employee_name is an untrusted string\n        mysql::results result;\n\n        // Expand the query and execute it. The expansion happens client-side.\n        // If employee_name is \"John\", the executed query would be:\n        // \"SELECT id, salary FROM employee WHERE last_name = 'John'\"\n        co_await conn.async_execute(\n            mysql::with_params(\"SELECT id, salary FROM employee WHERE last_name = {}\", employee_name),\n            result\n        );\n        //]\n    }\n\n    {\n        //[text_queries_with_params_scalars\n        // Will execute \"SELECT id FROM employee WHERE salary > 42000\"\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\"SELECT id FROM employee WHERE salary > {}\", 42000),\n            result\n        );\n        //]\n    }\n\n    {\n        //[text_queries_with_params_optionals\n        std::optional<std::int64_t> salary;  // get salary from a possibly untrusted source\n        mysql::results result;\n\n        // Depending on whether salary has a value or not, executes:\n        // \"UPDATE employee SET salary = 42000 WHERE id = 1\"\n        // \"UPDATE employee SET salary = NULL WHERE id = 1\"\n        co_await conn.async_execute(\n            mysql::with_params(\"UPDATE employee SET salary = {} WHERE id = {}\", salary, 1),\n            result\n        );\n        //]\n    }\n\n    {\n        //[text_queries_with_params_ranges\n        mysql::results result;\n        std::vector<long> ids{1, 5, 20};\n\n        // Executes \"SELECT * FROM employee WHERE id IN (1, 5, 20)\"\n        // std::ref saves a copy\n        co_await conn.async_execute(\n            mysql::with_params(\"SELECT * FROM employee WHERE id IN ({})\", std::ref(ids)),\n            result\n        );\n        //]\n    }\n\n    {\n        //[text_queries_with_params_manual_indices\n        // Recall that you need to set connect_params::multi_queries to true when connecting\n        // before running semicolon-separated queries. Executes:\n        // \"UPDATE employee SET first_name = 'John' WHERE id = 42; SELECT * FROM employee WHERE id = 42\"\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\n                \"UPDATE employee SET first_name = {1} WHERE id = {0}; SELECT * FROM employee WHERE id = {0}\",\n                42,\n                \"John\"\n            ),\n            result\n        );\n        //]\n    }\n\n    {\n        //[text_queries_with_params_invalid_encoding\n        try\n        {\n            // If the connection is using UTF-8 (the default), this will throw an error,\n            // because the string to be formatted is not valid UTF-8.\n            // The query never reaches the server.\n            mysql::results result;\n            co_await conn.async_execute(mysql::with_params(\"SELECT {}\", \"bad\\xff UTF-8\"), result);\n            //<-\n            BOOST_TEST(false);\n            //->\n        }\n        catch (const boost::system::system_error& err)\n        {\n            BOOST_TEST(err.code() == mysql::client_errc::invalid_encoding);\n        }\n        //]\n    }\n\n    {\n        try\n        {\n            //[text_queries_with_params_empty_ranges\n            // If ids.empty(), generates \"SELECT * FROM employee WHERE id IN ()\", which is a syntax error.\n            // This is not a security issue for this query, but may be exploitable in more involved scenarios.\n            // Queries involving only scalar values (as opposed to ranges) are not affected by this.\n            // It is your responsibility to check for conditions like ids.empty(), as client-side SQL\n            // formatting does not understand your queries.\n            std::vector<int> ids;\n            mysql::results r;\n            co_await conn.async_execute(\n                mysql::with_params(\"SELECT * FROM employee WHERE id IN ({})\", ids),\n                r\n            );\n            //]\n            BOOST_TEST(false);\n        }\n        catch (const mysql::error_with_diagnostics&)\n        {\n            // The exact error code may vary\n        }\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(section_text_queries, snippets_fixture)\n{\n    run_coro(ctx, [this] { return section_main(conn); });\n}\n\n}  // namespace\n\n#endif\n"
  },
  {
    "path": "test/integration/test/snippets/time_types.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <iostream>\n\n#include \"test_integration/snippets/get_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nBOOST_AUTO_TEST_CASE(section_time_types)\n{\n    auto& conn = get_connection();\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n    {\n        //[time_types_date_as_local_time_point\n        date d(2020, 2, 19);                                   // d holds \"2020-02-19\"\n        std::chrono::local_days tp = d.as_local_time_point();  // now use tp normally\n\n        //]\n        BOOST_TEST(date(tp) == d);\n    }\n#endif\n    {\n        //[time_types_date_valid\n        date d1(2020, 2, 19);  // regular date\n        bool v1 = d1.valid();  // true\n        date d2(2020, 0, 19);  // invalid date\n        bool v2 = d2.valid();  // false\n\n        //]\n        BOOST_TEST(v1);\n        BOOST_TEST(!v2);\n    }\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n    {\n        //[time_types_date_get_local_time_point\n        date d = /* obtain a date somehow */ date(2020, 2, 29);\n        if (d.valid())\n        {\n            // Same as as_time_point, but doesn't check for validity\n            // Caution: be sure to check for validity.\n            // If d is not valid, get_time_point results in undefined behavior\n            std::chrono::local_days tp = d.get_local_time_point();\n\n            // Use tp as required\n            std::cout << tp.time_since_epoch().count() << std::endl;\n        }\n        else\n        {\n            // the date is invalid\n            std::cout << \"Invalid date\" << std::endl;\n        }\n        //]\n    }\n#endif\n    {\n        //[time_types_date_as_time_point\n        date d(2020, 2, 19);  // d holds \"2020-02-19\"\n\n        // date::time_point is a std::chrono::time_point that uses std::chrono::system_clock\n        // tp is a local time, rather than UTC\n        // tp holds the same time_since_epoch() than d.as_local_time_point()\n        date::time_point tp = d.as_time_point();\n\n        //]\n        BOOST_TEST(date(tp) == d);\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n        BOOST_TEST(tp.time_since_epoch() == d.as_local_time_point().time_since_epoch());\n#endif\n    }\n\n    {\n        //[time_types_datetime\n        datetime dt1(2020, 10, 11, 10, 20, 59, 123456);  // regular datetime 2020-10-11 10:20:59.123456\n        bool v1 = dt1.valid();                           // true\n        datetime dt2(2020, 0, 11, 10, 20, 59);           // invalid datetime 2020-00-10 10:20:59.000000\n        bool v2 = dt2.valid();                           // false\n\n//<-\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n        //->\n\n        // local_time_point is a std::chrono::local_time with microsecond resolution\n        // Only available if your compiler supports C++20 calendar types\n        datetime::local_time_point tp = dt1.as_local_time_point();\n//<-\n#endif\n        //->\n\n        // If you're using an older compiler, use as_time_point.\n        // tp2 uses std::chrono::system_clock and microsecond resolution.\n        // tp2 should be interpreted as a local time, rather than UTC\n        datetime::time_point tp2 = dt1.as_time_point();\n\n        //]\n        BOOST_TEST(v1);\n        BOOST_TEST(!v2);\n        BOOST_TEST(datetime(tp2) == dt1);\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n        BOOST_TEST(tp2.time_since_epoch() == tp.time_since_epoch());\n#endif\n    }\n    {\n        //[time_types_timestamp_setup\n        results result;\n        conn.execute(\n            R\"%(\n                CREATE TEMPORARY TABLE events (\n                    id INT PRIMARY KEY AUTO_INCREMENT,\n                    t TIMESTAMP,\n                    contents VARCHAR(256)\n                )\n            )%\",\n            result\n        );\n        //]\n\n        //[time_types_timestamp_stmts\n        auto insert_stmt = conn.prepare_statement(\"INSERT INTO events (t, contents) VALUES (?, ?)\");\n        auto select_stmt = conn.prepare_statement(\"SELECT id, t, contents FROM events WHERE t > ?\");\n        //]\n\n        //[time_types_timestamp_set_time_zone\n        // This change has session scope. All operations after this query\n        // will now use UTC for TIMESTAMPs. Other sessions will not see the change.\n        // If you need to reconnect the connection, you need to run this again.\n        // If your MySQL server supports named time zones, you can also use\n        // \"SET time_zone = 'UTC'\"\n        conn.execute(\"SET time_zone = '+00:00'\", result);\n        //]\n\n        //[time_types_timestamp_insert\n        // Get the timestamp of the event. This may have been provided by an external system\n        // For the sake of example, we will use the current timestamp\n        datetime event_timestamp = datetime::now();\n\n        // event_timestamp will be interpreted as UTC if you have run SET time_zone\n        conn.execute(insert_stmt.bind(event_timestamp, \"Something happened\"), result);\n        //]\n\n        //[time_types_timestamp_select\n        // Get the timestamp threshold from the user. We will use a constant for the sake of example\n        datetime threshold = datetime(2022, 1, 1);  // get events that happened after 2022-01-01 UTC\n\n        // threshold will be interpreted as UTC. The retrieved events will have their\n        // `t` column in UTC\n        conn.execute(select_stmt.bind(threshold), result);\n        //]\n    }\n}\n\n}  // namespace\n"
  },
  {
    "path": "test/integration/test/snippets/tutorials.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pfr.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#if defined(BOOST_ASIO_HAS_CO_AWAIT) && BOOST_PFR_CORE_NAME_ENABLED\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/resultset_view.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/static_results.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/asio/as_tuple.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/read.hpp>\n#include <boost/asio/steady_timer.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/core/ignore_unused.hpp>\n#include <boost/system/error_code.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <string>\n#include <tuple>\n\n#include \"test_common/ci_server.hpp\"\n#include \"test_integration/run_coro.hpp\"\n#include \"test_integration/snippets/credentials.hpp\"\n#include \"test_integration/snippets/snippets_fixture.hpp\"\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace mysql::test;\n\n// Common\ninline namespace tutorials {\nstruct employee\n{\n    std::string first_name;\n    std::string last_name;\n};\n}  // namespace tutorials\n\nnamespace {\n\n//\n// Tutorial 4: static interface\n//\nBOOST_FIXTURE_TEST_CASE(section_tutorial_static_interface, snippets_fixture)\n{\n    mysql::results result;\n    conn.execute(\"SELECT first_name, last_name FROM employee WHERE id = 1\", result);\n    auto print_employee = [](mysql::string_view, mysql::string_view) {};\n\n    //[tutorial_static_casts\n    mysql::row_view employee = result.rows().at(0);\n    print_employee(employee.at(0).as_string(), employee.at(1).as_string());\n    //]\n}\n\n//\n// Tutorial 5: updates and txns\n//\nasio::awaitable<void> tutorial_updates_transactions(mysql::any_connection& conn)\n{\n    const char* new_first_name = \"John\";\n    int employee_id = 1;\n\n    {\n        //[tutorial_updates_transactions_update\n        // Run an UPDATE. We can use with_params to compose it, too\n        // If new_first_name contains 'John' and employee_id contains 42, this will run:\n        //    UPDATE employee SET first_name = 'John' WHERE id = 42\n        // result contains an empty resultset: it has no rows\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\n                \"UPDATE employee SET first_name = {} WHERE id = {}\",\n                new_first_name,\n                employee_id\n            ),\n            result\n        );\n        //]\n        //[tutorial_updates_transactions_select\n        // Retrieve the newly created employee.\n        // As we will see, this is a potential race condition\n        // that can be avoided with transactions.\n        co_await conn.async_execute(\n            mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n            result\n        );\n\n        if (result.rows().empty())\n        {\n            std::cout << \"No employee with ID = \" << employee_id << std::endl;\n        }\n        else\n        {\n            std::cout << \"Updated: \" << result.rows().at(0).at(0) << \" \" << result.rows().at(0).at(1)\n                      << std::endl;\n        }\n        //]\n    }\n    {\n        //[tutorial_updates_transactions_txn\n        mysql::results empty_result, select_result;\n\n        // Start a transaction block. Subsequent statements will belong\n        // to the transaction block, until a COMMIT or ROLLBACK is encountered,\n        // or the connection is closed.\n        // START TRANSACTION returns no rows.\n        co_await conn.async_execute(\"START TRANSACTION\", empty_result);\n\n        // Run the UPDATE as we did before\n        co_await conn.async_execute(\n            mysql::with_params(\n                \"UPDATE employee SET first_name = {} WHERE id = {}\",\n                new_first_name,\n                employee_id\n            ),\n            empty_result\n        );\n\n        // Run the SELECT. If a row is returned here, it is the one\n        // that we modified.\n        co_await conn.async_execute(\n            mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n            select_result\n        );\n\n        // Commit the transaction. This makes the updated row visible\n        // to other transactions and releases any locked rows.\n        co_await conn.async_execute(\"COMMIT\", empty_result);\n\n        // Process the retrieved rows\n        if (select_result.rows().empty())\n        {\n            std::cout << \"No employee with ID = \" << employee_id << std::endl;\n        }\n        else\n        {\n            std::cout << \"Updated: \" << select_result.rows().at(0).at(0) << \" \"\n                      << select_result.rows().at(0).at(1) << std::endl;\n        }\n        //]\n    }\n    {\n        //[tutorial_updates_transactions_multi_queries\n        // Run the 4 statements in a single round-trip.\n        // If an error is encountered, successive statements won't be executed\n        // and the transaction won't be committed.\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\n                \"START TRANSACTION;\"\n                \"UPDATE employee SET first_name = {} WHERE id = {};\"\n                \"SELECT first_name, last_name FROM employee WHERE id = {};\"\n                \"COMMIT\",\n                new_first_name,\n                employee_id,\n                employee_id\n            ),\n            result\n        );\n        //]\n\n        //[tutorial_updates_transactions_dynamic_results\n        // Get the 3rd resultset. resultset_view API is similar to results\n        mysql::resultset_view select_result = result.at(2);\n        if (select_result.rows().empty())\n        {\n            std::cout << \"No employee with ID = \" << employee_id << std::endl;\n        }\n        else\n        {\n            std::cout << \"Updated: \" << select_result.rows().at(0).at(0) << \" \"\n                      << select_result.rows().at(0).at(1) << std::endl;\n        }\n        //]\n    }\n    {\n        //[tutorial_updates_transactions_manual_indices\n        // {0} will be replaced by the first format arg, {1} by the second\n        mysql::results result;\n        co_await conn.async_execute(\n            mysql::with_params(\n                \"START TRANSACTION;\"\n                \"UPDATE employee SET first_name = {0} WHERE id = {1};\"\n                \"SELECT first_name, last_name FROM employee WHERE id = {1};\"\n                \"COMMIT\",\n                new_first_name,\n                employee_id\n            ),\n            result\n        );\n        //]\n    }\n}\n\nBOOST_FIXTURE_TEST_CASE(section_tutorial_updates_transactions, snippets_fixture)\n{\n    run_coro(ctx, [&]() { return tutorial_updates_transactions(conn); });\n}\n\n//\n// Tutorial 6: connection pool\n//\nmysql::pool_params create_pool_params()\n{\n    mysql::pool_params res;\n    res.server_address.emplace_host_and_port(get_hostname());\n    res.username = mysql_username;\n    res.password = mysql_password;\n    res.database = \"boost_mysql_examples\";\n    return res;\n}\n\nBOOST_FIXTURE_TEST_CASE(section_tutorial_connection_pool, snippets_fixture)\n{\n    run_coro(ctx, [&]() -> asio::awaitable<void> {\n        mysql::connection_pool pool(ctx, create_pool_params());\n        pool.async_run(asio::detached);\n\n        //[tutorial_connection_pool_get_connection\n        // Get a connection from the pool.\n        // This will wait until a healthy connection is ready to be used.\n        // pooled_connection grants us exclusive access to the connection until\n        // the object is destroyed\n        mysql::pooled_connection conn = co_await pool.async_get_connection();\n        //]\n    });\n}\n\n//\n// Tutorial 7: error handling\n//\nvoid log_error(const char*, boost::system::error_code) {}\n\n//[tutorial_error_handling_db_nodiag\nasio::awaitable<std::string> get_employee_details(mysql::connection_pool& pool, std::int64_t employee_id)\n{\n    // Get a connection from the pool.\n    // This will wait until a healthy connection is ready to be used.\n    // ec is an error code, conn is a pooled_connection\n    auto [ec, conn] = co_await pool.async_get_connection(asio::as_tuple);\n    if (ec)\n    {\n        // A connection couldn't be obtained.\n        // This may be because a timeout happened.\n        log_error(\"Error in async_get_connection\", ec);\n        co_return \"ERROR\";\n    }\n\n    // Use the connection normally to query the database.\n    mysql::static_results<mysql::pfr_by_name<employee>> result;\n    auto [ec2] = co_await conn->async_execute(\n        mysql::with_params(\"SELECT first_name, last_name FROM employee WHERE id = {}\", employee_id),\n        result,\n        asio::as_tuple\n    );\n    if (ec2)\n    {\n        log_error(\"Error running query\", ec);\n        co_return \"ERROR\";\n    }\n\n    // Handle the result as we did in the previous tutorial\n    //<-\n    co_return \"\";\n    //->\n}\n//]\n\n[[maybe_unused]]\n//[tutorial_error_handling_session_as_tuple\nasio::awaitable<void> handle_session(mysql::connection_pool& pool, asio::ip::tcp::socket client_socket)\n{\n    // Read the request from the client.\n    unsigned char message[8]{};\n    auto [ec1, bytes_read] = co_await asio::async_read(client_socket, asio::buffer(message), asio::as_tuple);\n    if (ec1)\n    {\n        log_error(\"Error reading from the socket\", ec1);\n        co_return;\n    }\n\n    // Process the request as before (omitted)\n    //<-\n    boost::ignore_unused(pool);\n    std::string response;\n    //->\n\n    // Write the response back to the client.\n    auto [ec2, bytes_written] = co_await asio::async_write(\n        client_socket,\n        asio::buffer(response),\n        asio::as_tuple\n    );\n    if (ec2)\n    {\n        log_error(\"Error writing to the socket\", ec2);\n        co_return;\n    }\n}\n//]\n\nasio::awaitable<void> tutorial_error_handling()\n{\n    // Setup\n    mysql::connection_pool pool(co_await asio::this_coro::executor, create_pool_params());\n    asio::steady_timer cv(co_await asio::this_coro::executor, (std::chrono::steady_clock::time_point::max)());\n    pool.async_run([&](mysql::error_code) { cv.cancel(); });\n\n    {\n        //[tutorial_error_handling_callbacks\n        // Function to call when async_get_connection completes\n        auto on_available_connection = [](boost::system::error_code ec, mysql::pooled_connection conn) {\n            // Do something useful with the connection\n            //<-\n            BOOST_TEST(ec == mysql::error_code());\n            BOOST_TEST(conn.valid());\n            //->\n        };\n\n        // Start the operation. on_available_connection will be called when the operation\n        // completes. on_available_connection is the completion token.\n        // When a callback is passed, async_get_connection returns void,\n        // so we can't use co_await with it.\n        pool.async_get_connection(on_available_connection);\n        //]\n    }\n\n    {\n        //[tutorial_error_handling_default_tokens\n        // These two lines are equivalent.\n        // Both of them can be read as \"I want to use C++20 coroutines as my completion style\"\n        auto conn1 = co_await pool.async_get_connection();\n        auto conn2 = co_await pool.async_get_connection(mysql::with_diagnostics(asio::deferred));\n        //]\n\n        BOOST_TEST(conn1.valid());\n        BOOST_TEST(conn2.valid());\n    }\n    {\n        //[tutorial_error_handling_adapter_tokens\n        // Enable the use of the \"s\" suffix for std::chrono::seconds\n        using namespace std::chrono_literals;\n\n        // The following two lines are equivalent.\n        // Both get a connection, waiting no more than 20s before cancelling the operation.\n        // If no token is passed to cancel_after, the default one will be used,\n        // which transforms the operation into an awaitable.\n        // asio::cancel_after(20s) is usually termed \"partial completion token\"\n        auto conn1 = co_await pool.async_get_connection(asio::cancel_after(20s));\n        auto conn2 = co_await pool.async_get_connection(\n            asio::cancel_after(20s, mysql::with_diagnostics(asio::deferred))\n        );\n        //]\n\n        BOOST_TEST(conn1.valid());\n        BOOST_TEST(conn2.valid());\n    }\n\n    {\n        //[tutorial_error_handling_as_tuple\n        // Passing asio::as_tuple transforms the operation's handler signature:\n        //    Original:    void(error_code, mysql::pooled_connection)\n        //    Transformed: void(std::tuple<error_code, mysql::pooled_connection>)\n        // The transformed signature no longer has an error_code as first parameter,\n        // so no automatic error code to exception transformation happens.\n        std::tuple<boost::system::error_code, mysql::pooled_connection>\n            res = co_await pool.async_get_connection(asio::as_tuple);\n        //]\n\n        BOOST_TEST(std::get<0>(res) == mysql::error_code());\n    }\n\n    {\n        //[tutorial_error_handling_as_tuple_structured_bindings\n        // ec is an error_code, conn is the mysql::pooled_connection.\n        // If the operation fails, ec will be non-empty.\n        auto [ec, conn] = co_await pool.async_get_connection(asio::as_tuple);\n        //]\n\n        BOOST_TEST(ec == mysql::error_code());\n        BOOST_TEST(conn.valid());\n    }\n\n    {\n        //[tutorial_error_handling_as_tuple_default_tokens\n        // The following two lines are equivalent.\n        // Both of them produce an awaitable that produces a tuple when awaited.\n        auto [ec1, conn1] = co_await pool.async_get_connection(asio::as_tuple);\n        auto [ec2, conn2] = co_await pool.async_get_connection(\n            asio::as_tuple(mysql::with_diagnostics(asio::deferred))\n        );\n        //]\n\n        BOOST_TEST(ec1 == mysql::error_code());\n        BOOST_TEST(ec2 == mysql::error_code());\n        BOOST_TEST(conn1.valid());\n        BOOST_TEST(conn2.valid());\n    }\n\n    {\n        using namespace std::chrono_literals;\n\n        //[tutorial_error_handling_as_tuple_cancel_after\n        // ec is an error_code, conn is the mysql::pooled_connection\n        // Apply a timeout and don't throw on error\n        auto [ec, conn] = co_await pool.async_get_connection(asio::cancel_after(20s, asio::as_tuple));\n        //]\n\n        BOOST_TEST(ec == mysql::error_code());\n        BOOST_TEST(conn.valid());\n    }\n\n    // Call the functions requiring a pool\n    co_await get_employee_details(pool, 1);\n\n    // Cancel the pool and wait run to return, so no work is left in the io_context\n    pool.cancel();\n    boost::ignore_unused(co_await cv.async_wait(asio::as_tuple));\n}\n\nBOOST_FIXTURE_TEST_CASE(section_tutorial_error_handling, io_context_fixture)\n{\n    run_coro(ctx, &tutorial_error_handling);\n}\n\n}  // namespace\n\n#endif\n"
  },
  {
    "path": "test/integration/test/spotchecks.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/tcp.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/data/test_case.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstddef>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n#include \"test_integration/spotchecks_helpers.hpp\"\n#include \"test_integration/static_rows.hpp\"\n#include \"test_integration/tcp_connection_fixture.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing boost::test_tools::per_element;\n\n// These tests aim to cover the 4 overloads we have for each network function,\n// both for the old templated connection and for any_connection.\n// A success and an error case is included for each function.\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_spotchecks)\n\n// Functions for each connection type\nstatic auto fns_connection = network_functions_connection::all();\nstatic auto fns_any = network_functions_any::all();\n\n// Simplify defining test cases involving both connection types\n// The resulting test case gets the fixture (fix) and the network functions (fn) as args\n#define BOOST_MYSQL_SPOTCHECK_TEST(name)                    \\\n    template <class FixtureType>                            \\\n    void do_##name(FixtureType& fix);                       \\\n    BOOST_DATA_TEST_CASE(name##_connection, fns_connection) \\\n    {                                                       \\\n        netfn_fixture_connection fix{sample};               \\\n        do_##name(fix);                                     \\\n    }                                                       \\\n    BOOST_DATA_TEST_CASE(name##_any, fns_any)               \\\n    {                                                       \\\n        netfn_fixture_any fix{sample};                      \\\n        do_##name(fix);                                     \\\n    }                                                       \\\n    template <class FixtureType>                            \\\n    void do_##name(FixtureType& fix)\n\n// prepare statement\nBOOST_MYSQL_SPOTCHECK_TEST(prepare_statement_success)\n{\n    // Setup\n    fix.connect();\n\n    // Call the function\n    statement stmt = fix.net.prepare_statement(fix.conn, \"SELECT * FROM empty_table WHERE id IN (?, ?)\")\n                         .get();\n\n    // Validate the result\n    BOOST_TEST_REQUIRE(stmt.valid());\n    BOOST_TEST(stmt.id() > 0u);\n    BOOST_TEST(stmt.num_params() == 2u);\n\n    // It can be executed\n    results result;\n    fix.net.execute_statement(fix.conn, stmt.bind(10, 20), result).validate_no_error();\n    BOOST_TEST(result.rows().empty());\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(prepare_statement_error)\n{\n    // Setup\n    fix.connect();\n\n    // Call the function\n    fix.net.prepare_statement(fix.conn, \"SELECT * FROM bad_table WHERE id IN (?, ?)\")\n        .validate_error(\n            common_server_errc::er_no_such_table,\n            \"Table 'boost_mysql_integtests.bad_table' doesn't exist\"\n        );\n}\n\n// execute\nBOOST_MYSQL_SPOTCHECK_TEST(execute_success)\n{\n    // Setup\n    fix.connect();\n\n    // Call the function\n    results result;\n    fix.net.execute_query(fix.conn, \"SELECT 'hello', 42\", result).validate_no_error();\n\n    // Check results\n    BOOST_TEST(result.rows().size() == 1u);\n    BOOST_TEST(result.rows()[0] == makerow(\"hello\", 42), per_element());\n    BOOST_TEST(result.meta().size() == 2u);\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(execute_error)\n{\n    // Setup\n    fix.connect();\n\n    // Call the function\n    results result;\n    fix.net.execute_query(fix.conn, \"SELECT field_varchar, field_bad FROM one_row_table\", result)\n        .validate_error_contains(common_server_errc::er_bad_field_error, {\"unknown column\", \"field_bad\"});\n}\n\n// Start execution\nBOOST_MYSQL_SPOTCHECK_TEST(start_execution_success)\n{\n    // Setup\n    fix.connect();\n\n    // Call the function\n    execution_state st;\n    fix.net.start_execution(fix.conn, \"SELECT * FROM empty_table\", st).validate_no_error();\n\n    // Check results\n    BOOST_TEST(st.should_read_rows());\n    validate_2fields_meta(st.meta(), \"empty_table\");\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(start_execution_error)\n{\n    // Setup\n    fix.connect();\n\n    // Call the function\n    execution_state st;\n    fix.net.start_execution(fix.conn, \"SELECT field_varchar, field_bad FROM one_row_table\", st)\n        .validate_error_contains(common_server_errc::er_bad_field_error, {\"unknown column\", \"field_bad\"});\n}\n\n// Close statement\nBOOST_MYSQL_SPOTCHECK_TEST(close_statement_success)\n{\n    // Setup\n    fix.connect();\n\n    // Prepare a statement\n    statement stmt = fix.net.prepare_statement(fix.conn, \"SELECT * FROM empty_table WHERE id IN (?, ?)\")\n                         .get();\n\n    // Close the statement\n    fix.net.close_statement(fix.conn, stmt).validate_no_error();\n\n    // The statement is no longer valid\n    results result;\n    fix.net.execute_statement(fix.conn, stmt.bind(1, 2), result).validate_any_error();\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(close_statement_error)\n{\n    // Setup\n    fix.connect();\n\n    // Prepare a statement\n    statement stmt = fix.net.prepare_statement(fix.conn, \"SELECT * FROM empty_table WHERE id IN (?, ?)\")\n                         .get();\n\n    // Close the connection\n    fix.net.close(fix.conn).validate_no_error();\n\n    // Close the statement fails, as it requires communication with the server\n    fix.net.close_statement(fix.conn, stmt).validate_error(client_errc::not_connected);\n}\n\n// Read resultset head\nBOOST_MYSQL_SPOTCHECK_TEST(read_resultset_head_success)\n{\n    // Setup\n    fix.connect(connect_params_builder().multi_queries(true));\n\n    // Generate an execution state\n    execution_state st;\n    fix.net.start_execution(fix.conn, \"SELECT 4.2e0; SELECT * FROM empty_table\", st).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // Read the 1st resultset\n    auto rws = fix.net.read_some_rows(fix.conn, st).get();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(st.meta()[0].type() == column_type::double_);\n    BOOST_TEST(rws == makerows(1, 4.2), per_element());\n\n    // Read head\n    fix.net.read_resultset_head(fix.conn, st).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    validate_2fields_meta(st.meta(), \"empty_table\");\n\n    // Reading head again does nothing\n    fix.net.read_resultset_head(fix.conn, st).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    validate_2fields_meta(st.meta(), \"empty_table\");\n\n    // We can read rows now\n    rws = fix.net.read_some_rows(fix.conn, st).get();\n    BOOST_TEST(rws == rows(), per_element());\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(read_resultset_head_error)\n{\n    // Setup\n    fix.connect(connect_params_builder().multi_queries(true));\n\n    // Generate an execution state\n    execution_state st;\n    fix.net.start_execution(fix.conn, \"SELECT * FROM empty_table; SELECT bad_field FROM one_row_table\", st)\n        .validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // Read the OK packet to finish 1st resultset\n    fix.net.read_some_rows(fix.conn, st).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n\n    // Read head for the 2nd resultset. This one contains an error, which is detected when reading head.\n    fix.net.read_resultset_head(fix.conn, st)\n        .validate_error(common_server_errc::er_bad_field_error, \"Unknown column 'bad_field' in 'field list'\");\n}\n\n// Read some rows\nBOOST_MYSQL_SPOTCHECK_TEST(read_some_rows_success)\n{\n    // Setup\n    fix.connect();\n\n    // Generate an execution state\n    execution_state st;\n    fix.net.start_execution(fix.conn, \"SELECT * FROM one_row_table\", st).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // Read once. st may or may not be complete, depending\n    // on how the buffer reallocated memory\n    auto rows = fix.net.read_some_rows(fix.conn, st).get();\n    BOOST_TEST((rows == makerows(2, 1, \"f0\")));\n\n    // Reading again should complete st\n    rows = fix.net.read_some_rows(fix.conn, st).get();\n    BOOST_TEST(rows.empty());\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n\n    // Reading again does nothing\n    rows = fix.net.read_some_rows(fix.conn, st).get();\n    BOOST_TEST(rows.empty());\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(read_some_rows_error)\n{\n    // Setup\n    fix.connect();\n\n    // Generate an execution state\n    execution_state st;\n    fix.net.start_execution(fix.conn, \"SELECT * FROM one_row_table\", st).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // Close the connection\n    fix.net.close(fix.conn).validate_no_error();\n\n    // Trying to read rows errors\n    fix.net.read_some_rows(fix.conn, st).validate_error(client_errc::not_connected);\n}\n\n// Ping\nBOOST_MYSQL_SPOTCHECK_TEST(ping_success)\n{\n    // Setup\n    fix.connect();\n\n    // Success\n    fix.net.ping(fix.conn).validate_no_error();\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(ping_error)\n{\n    // Pinging an unconnected connection fails\n    fix.net.ping(fix.conn).validate_error(client_errc::not_connected);\n}\n\n// Reset connection\nBOOST_MYSQL_SPOTCHECK_TEST(reset_connection_success)\n{\n    // Setup\n    fix.connect();\n\n    // Set some variable\n    results result;\n    fix.net.execute_query(fix.conn, \"SET @myvar = 42\", result).validate_no_error();\n\n    // Reset connection\n    fix.net.reset_connection(fix.conn).validate_no_error();\n\n    // The variable has been reset\n    fix.net.execute_query(fix.conn, \"SELECT @myvar\", result).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, nullptr), per_element());\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(reset_connection_error)\n{\n    // Resetting an unconnected connection fails\n    fix.net.reset_connection(fix.conn).validate_error(client_errc::not_connected);\n}\n\n// Close connection. There is no way to trigger an error here.\nBOOST_MYSQL_SPOTCHECK_TEST(close_success)\n{\n    // Setup\n    fix.connect();\n\n    // Close\n    fix.net.close(fix.conn).validate_no_error();\n\n    // We are no longer able to query\n    results result;\n    fix.net.execute_query(fix.conn, \"SELECT 1\", result).validate_error(client_errc::not_connected);\n}\n\n// Read some rows (static version). This is the only one\n// that is a separate overload.\n#ifdef BOOST_MYSQL_CXX14\nBOOST_MYSQL_SPOTCHECK_TEST(read_some_rows_static_success)\n{\n    // Setup\n    fix.connect();\n    static_state_t st;\n\n    // Start\n    fix.net.start_execution_static(fix.conn, \"SELECT * FROM multifield_table WHERE id = 1\", st)\n        .validate_no_error();\n    BOOST_TEST(st.should_read_rows());\n\n    // Read rows\n    std::array<row_multifield, 2> storage;\n    std::size_t num_rows = fix.net.read_some_rows_static(fix.conn, st, storage).get();\n    row_multifield expected_multifield{boost::optional<float>(1.1f), 11, std::string(\"aaa\")};  // MSVC 14.1\n    BOOST_TEST(num_rows == 1u);\n    BOOST_TEST(storage[0] == expected_multifield);\n\n    // Finish\n    num_rows = fix.net.read_some_rows_static(fix.conn, st, storage).get();\n    BOOST_TEST(num_rows == 0u);\n    BOOST_TEST(st.complete());\n}\n\nBOOST_MYSQL_SPOTCHECK_TEST(read_some_rows_static_error)\n{\n    // Setup\n    fix.connect(connect_params_builder().multi_queries(true));\n    static_state_t st;\n\n    // Start\n    fix.net.start_execution_static(fix.conn, \"SELECT * FROM multifield_table WHERE id = 42; SELECT 1\", st)\n        .validate_no_error();\n    BOOST_TEST(st.should_read_rows());\n\n    // No rows matched, so reading rows reads the OK packet. This will report the num resultsets mismatch\n    std::array<row_multifield, 2> storage;\n    fix.net.read_some_rows_static(fix.conn, st, storage).validate_error(client_errc::num_resultsets_mismatch);\n}\n#endif\n\n//\n// functions specific to old connection\n//\n\n// Handshake\nBOOST_DATA_TEST_CASE_F(tcp_connection_fixture, handshake_success, fns_connection)\n{\n    // Setup\n    const network_functions_connection& fn = sample;\n    fn.connect_stream(conn.stream(), get_tcp_endpoint()).validate_no_error_nodiag();\n\n    // Call the function\n    fn.handshake(conn, connect_params_builder().build_hparams()).validate_no_error();\n\n    // The connection is usable\n    fn.ping(conn).validate_no_error();\n}\n\nBOOST_DATA_TEST_CASE_F(tcp_connection_fixture, handshake_error, fns_connection)\n{\n    // Setup\n    const network_functions_connection& fn = sample;\n    fn.connect_stream(conn.stream(), get_tcp_endpoint()).validate_no_error_nodiag();\n\n    // Call the function\n    fn.handshake(conn, connect_params_builder().database(\"bad_db\").build_hparams())\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'integ_user'@'%' to database 'bad_db'\"\n        );\n}\n\n// Connect\nBOOST_DATA_TEST_CASE_F(tcp_connection_fixture, connect_connection_success, fns_connection)\n{\n    // Setup\n    const network_functions_connection& fn = sample;\n\n    // Call the function\n    fn.connect(conn, get_tcp_endpoint(), connect_params_builder().build_hparams()).validate_no_error();\n\n    // The connection is usable\n    fn.ping(conn).validate_no_error();\n}\n\nBOOST_DATA_TEST_CASE_F(tcp_connection_fixture, connect_connection_error, fns_connection)\n{\n    // Setup\n    const network_functions_connection& fn = sample;\n\n    // Call the function\n    fn.connect(conn, get_tcp_endpoint(), connect_params_builder().database(\"bad_db\").build_hparams())\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'integ_user'@'%' to database 'bad_db'\"\n        );\n}\n\n// Quit. TODO: write a unit test spotcheck for errors\nBOOST_DATA_TEST_CASE_F(tcp_connection_fixture, quit_success, fns_connection)\n{\n    // Setup\n    const network_functions_connection& fn = sample;\n    connect();\n\n    // Quit\n    fn.quit(conn).validate_no_error();\n}\n\n//\n// functions specific to any_connection\n//\n\n// Connect\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, connect_any_success, fns_any)\n{\n    // Setup\n    const network_functions_any& fn = sample;\n\n    // Call the function\n    fn.connect(conn, connect_params_builder().ssl(ssl_mode::require).build()).validate_no_error();\n\n    // The connection is usable\n    fn.ping(conn).validate_no_error();\n\n    // Closing works\n    fn.close(conn).validate_no_error();\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, connect_any_error, fns_any)\n{\n    // Setup\n    const network_functions_any& fn = sample;\n\n    // Call the function\n    fn.connect(conn, connect_params_builder().ssl(ssl_mode::require).database(\"bad_db\").build())\n        .validate_error(\n            common_server_errc::er_dbaccess_denied_error,\n            \"Access denied for user 'integ_user'@'%' to database 'bad_db'\"\n        );\n}\n\n// Set character set\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, set_character_set_success, fns_any)\n{\n    // Setup\n    const network_functions_any& fn = sample;\n    connect();\n\n    // Call the function\n    fn.set_character_set(conn, ascii_charset).validate_no_error();\n\n    // Success\n    BOOST_TEST(conn.current_character_set()->name == \"ascii\");\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, set_character_set_error, fns_any)\n{\n    // Setup\n    const network_functions_any& fn = sample;\n    connect();\n\n    // Call the function\n    fn.set_character_set(conn, character_set{\"bad_charset\", nullptr})\n        .validate_error(common_server_errc::er_unknown_character_set, \"Unknown character set: 'bad_charset'\");\n\n    // Success\n    BOOST_TEST(conn.current_character_set()->name == \"utf8mb4\");\n}\n\n// Run pipeline\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, run_pipeline_success, fns_any)\n{\n    // Setup\n    const network_functions_any& fn = sample;\n    pipeline_request req;\n    req.add_set_character_set(ascii_charset).add_execute(\"SET @myvar = 42\").add_execute(\"SELECT @myvar\");\n    std::vector<stage_response> res;\n    connect();\n\n    // Run the function\n    fn.run_pipeline(conn, req, res).validate_no_error();\n\n    // Success\n    BOOST_TEST(conn.current_character_set().value() == ascii_charset);\n    BOOST_TEST_REQUIRE(res.size() == 3u);\n    BOOST_TEST(res.at(0).error() == error_code());\n    BOOST_TEST(res.at(0).diag() == diagnostics());\n    BOOST_TEST(res.at(1).as_results().rows() == rows(), per_element());\n    BOOST_TEST(res.at(2).as_results().rows() == makerows(1, 42), per_element());\n}\n\nBOOST_DATA_TEST_CASE_F(any_connection_fixture, run_pipeline_error, fns_any)\n{\n    // Setup\n    const network_functions_any& fn = sample;\n    pipeline_request req;\n    req.add_execute(\"SET @myvar = 42\")\n        .add_prepare_statement(\"SELECT * FROM bad_table\")\n        .add_execute(\"SELECT @myvar\");\n    std::vector<stage_response> res;\n    connect();\n\n    // Run the function\n    fn.run_pipeline(conn, req, res)\n        .validate_error(\n            common_server_errc::er_no_such_table,\n            \"Table 'boost_mysql_integtests.bad_table' doesn't exist\"\n        );\n\n    // Stages 0 and 2 were executed successfully\n    BOOST_TEST(res.size() == 3u);\n    BOOST_TEST(res[0].as_results().rows() == rows(), per_element());\n    BOOST_TEST(res[1].error() == common_server_errc::er_no_such_table);\n    BOOST_TEST(res[1].diag() == create_server_diag(\"Table 'boost_mysql_integtests.bad_table' doesn't exist\"));\n    BOOST_TEST(res[2].as_results().rows() == makerows(1, 42), per_element());\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_spotchecks\n\n}  // namespace"
  },
  {
    "path": "test/integration/test/static_interface.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/pfr.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n#include <boost/mysql/static_results.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/describe/operators.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/optional/optional_io.hpp>\n#include <boost/pfr/ops.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstdint>\n#include <tuple>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/connect_params_builder.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n#include \"test_integration/static_rows.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::test_tools::per_element;\n\n// Note: the dynamic interface is already covered by stored_procedures, multi_queries, prepared_statements and\n// spotchecks\n\nBOOST_AUTO_TEST_SUITE(test_static_iface)\n\n// A row type like row_multifield, but without Describe metadata\nstruct row_multifield_pfr\n{\n    boost::optional<float> field_nullable;\n    std::int32_t field_int;\n    std::string field_varchar;\n};\n\n// Same, but only with literal fields (required by PFR in C++14 mode)\nstruct row_multifield_pfr_literal\n{\n    std::int64_t id;\n    std::int32_t field_int;\n    double field_double;\n};\n\nvoid validate_multifield_meta(metadata_collection_view meta)\n{\n    check_meta(\n        meta,\n        {\n            column_type::int_,\n            column_type::varchar,\n            column_type::int_,\n            column_type::float_,\n            column_type::double_,\n        }\n    );\n}\n\nstd::array<row_multifield, 2> expected_multifield_rows()\n{\n    return {\n        {\n         {1.1f, 11, \"aaa\"},\n         {{}, 22, \"bbb\"},\n         }\n    };\n}\n\nconstexpr const char* multifield_bad_msg =\n    \"NULL checks failed for field 'field_nullable': the database type may be NULL, but the C++ type \"\n    \"cannot. Use std::optional<T> or boost::optional<T>\\n\"\n    \"Incompatible types for field 'field_int': C++ type 'string' is not compatible with DB type 'INT'\\n\"\n    \"Field 'field_missing' is not present in the data returned by the server\";\n\nBOOST_AUTO_TEST_SUITE(singlefn)\n\nBOOST_FIXTURE_TEST_CASE(describe_structs, any_connection_fixture)\n{\n    connect();\n\n    static_results<row_multifield> result;\n    conn.async_execute(\"SELECT * FROM multifield_table ORDER BY id\", result, as_netresult)\n        .validate_no_error();\n\n    // Verify results\n    validate_multifield_meta(result.meta());\n    BOOST_TEST(result.rows() == expected_multifield_rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(tuples, any_connection_fixture)\n{\n    connect();\n\n    using tuple_t = std::tuple<int, std::string, int, boost::optional<float>>;  // trailing fields discarded\n    static_results<tuple_t> result;\n    conn.async_execute(\"SELECT * FROM multifield_table ORDER BY id\", result, as_netresult)\n        .validate_no_error();\n\n    // Verify results\n    validate_multifield_meta(result.meta());\n    BOOST_TEST_REQUIRE(result.rows().size() == 2u);\n    BOOST_TEST((result.rows()[0] == tuple_t{1, \"aaa\", 11, 1.1f}));\n    BOOST_TEST((result.rows()[1] == tuple_t{2, \"bbb\", 22, {}}));\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n\n#if BOOST_PFR_CORE_NAME_ENABLED\nBOOST_FIXTURE_TEST_CASE(pfr_structs_by_name, any_connection_fixture)\n{\n    connect();\n\n    static_results<pfr_by_name<row_multifield_pfr>> result;\n    conn.async_execute(\"SELECT * FROM multifield_table ORDER BY id\", result, as_netresult)\n        .validate_no_error();\n\n    // Verify results\n    validate_multifield_meta(result.meta());\n    BOOST_TEST_REQUIRE(result.rows().size() == 2u);\n    BOOST_TEST(boost::pfr::eq(result.rows()[0], row_multifield_pfr{1.1f, 11, \"aaa\"}));\n    BOOST_TEST(boost::pfr::eq(result.rows()[1], row_multifield_pfr{{}, 22, \"bbb\"}));\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n#endif\n\n#if BOOST_PFR_ENABLED && defined(BOOST_MYSQL_CXX14)\nBOOST_FIXTURE_TEST_CASE(pfr_structs_by_position, any_connection_fixture)\n{\n    connect();\n\n    static_results<pfr_by_position<row_multifield_pfr_literal>> result;\n    conn.async_execute(\n            \"SELECT id, field_int, field_double FROM multifield_table ORDER BY id\",\n            result,\n            as_netresult\n    )\n        .validate_no_error();\n\n    // Verify results\n    check_meta(result.meta(), {column_type::int_, column_type::int_, column_type::double_});\n    BOOST_TEST_REQUIRE(result.rows().size() == 2u);\n    BOOST_TEST(boost::pfr::eq(result.rows()[0], row_multifield_pfr_literal{1, 11, 0.1}));\n    BOOST_TEST(boost::pfr::eq(result.rows()[1], row_multifield_pfr_literal{2, 22, 0.2}));\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n#endif\n\n// This spotchecks having a repeated empty row type, too\nBOOST_FIXTURE_TEST_CASE(multi_resultset, any_connection_fixture)\n{\n    connect(connect_params_builder().multi_queries(true).build());\n    start_transaction();\n\n    static_results<row_multifield, empty, row_2fields, empty> result;\n    constexpr const char* query =\n        \"SELECT * FROM multifield_table;\"\n        \"DELETE FROM updates_table;\"\n        \"SELECT * FROM one_row_table;\"\n        \"SET @v1 = 2\";\n    conn.async_execute(query, result, as_netresult).validate_no_error();\n\n    // Validate results\n    validate_multifield_meta(result.meta<0>());\n    BOOST_TEST(result.rows<0>() == expected_multifield_rows(), per_element());\n    BOOST_TEST(result.affected_rows<0>() == 0u);\n    BOOST_TEST(result.warning_count<0>() == 0u);\n    BOOST_TEST(result.last_insert_id<0>() == 0u);\n    BOOST_TEST(result.info<0>() == \"\");\n\n    BOOST_TEST(result.meta<1>().size() == 0u);\n    BOOST_TEST(result.rows<1>().size() == 0u);\n    BOOST_TEST(result.affected_rows<1>() == 3u);\n    BOOST_TEST(result.warning_count<1>() == 0u);\n    BOOST_TEST(result.last_insert_id<1>() == 0u);\n    BOOST_TEST(result.info<1>() == \"\");\n\n    const row_2fields expected_2fields[]{\n        {1, std::string(\"f0\")}\n    };\n    validate_2fields_meta(result.meta<2>(), \"one_row_table\");\n    BOOST_TEST(result.rows<2>() == expected_2fields, per_element());\n    BOOST_TEST(result.affected_rows<2>() == 0u);\n    BOOST_TEST(result.warning_count<2>() == 0u);\n    BOOST_TEST(result.last_insert_id<2>() == 0u);\n    BOOST_TEST(result.info<2>() == \"\");\n\n    BOOST_TEST(result.meta<3>().size() == 0u);\n    BOOST_TEST(result.rows<3>().size() == 0u);\n    BOOST_TEST(result.affected_rows<3>() == 0u);\n    BOOST_TEST(result.warning_count<3>() == 0u);\n    BOOST_TEST(result.last_insert_id<3>() == 0u);\n    BOOST_TEST(result.info<3>() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(metadata_check_failed, any_connection_fixture)\n{\n    connect();\n\n    static_results<row_multifield_bad> result;\n    conn.async_execute(\"SELECT * FROM multifield_table ORDER BY id\", result, as_netresult)\n        .validate_error(client_errc::metadata_check_failed, multifield_bad_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(metadata_check_failed_empty_resultset, any_connection_fixture)\n{\n    connect();\n\n    const char* expected_msg =\n        \"Field in position 0 can't be mapped: there are more fields in your C++ data type than in your query\";\n    static_results<std::tuple<int>> result;\n    conn.async_execute(\"SET @v1 = 2\", result, as_netresult)\n        .validate_error(client_errc::metadata_check_failed, expected_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(metadata_check_failed_subsequent_resultset, any_connection_fixture)\n{\n    connect(connect_params_builder().multi_queries(true).build());\n\n    static_results<empty, row_multifield_bad> result;\n    conn.async_execute(\"SET @v1 = 2; SELECT * FROM multifield_table ORDER BY id\", result, as_netresult)\n        .validate_error(client_errc::metadata_check_failed, multifield_bad_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(num_resultsets_mismatch, any_connection_fixture)\n{\n    connect();\n\n    static_results<row_2fields, empty> result;\n    conn.async_execute(\"SELECT * FROM one_row_table\", result, as_netresult)\n        .validate_error(client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(num_resultsets_mismatch_empty_resultset, any_connection_fixture)\n{\n    connect();\n\n    static_results<empty, empty> result;\n    conn.async_execute(\"SET @v1 = 2\", result, as_netresult)\n        .validate_error(client_errc::num_resultsets_mismatch);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(multi_function)\nBOOST_FIXTURE_TEST_CASE(describe_structs, any_connection_fixture)\n{\n    connect();\n\n    // Start\n    static_execution_state<row_multifield> result;\n    conn.async_start_execution(\"SELECT * FROM multifield_table WHERE id = 1\", result, as_netresult)\n        .validate_no_error();\n    validate_multifield_meta(result.meta());\n    BOOST_TEST(result.should_read_rows());\n\n    // Read rows\n    std::array<row_multifield, 3> rws;\n    std::size_t num_rows = conn.async_read_some_rows(result, span<row_multifield>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((rws[0] == row_multifield{1.1f, 11, \"aaa\"}));\n\n    // Read again, in case the EOF came separately\n    num_rows = conn.async_read_some_rows(result, span<row_multifield>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 0u);\n    BOOST_TEST(result.complete());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(tuples, any_connection_fixture)\n{\n    connect();\n\n    using tuple_t = std::tuple<int, std::string, int>;  // trailing fields discarded\n\n    // Start\n    static_execution_state<tuple_t> result;\n    conn.async_start_execution(\"SELECT * FROM multifield_table WHERE id = 1\", result, as_netresult)\n        .validate_no_error();\n    validate_multifield_meta(result.meta());\n    BOOST_TEST(result.should_read_rows());\n\n    // Read rows\n    std::array<tuple_t, 3> rws;\n    std::size_t num_rows = conn.async_read_some_rows(result, span<tuple_t>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((rws[0] == tuple_t{1, \"aaa\", 11}));\n\n    // Read again, in case the EOF came separately\n    num_rows = conn.async_read_some_rows(result, span<tuple_t>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 0u);\n    BOOST_TEST(result.complete());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n\n#if BOOST_PFR_CORE_NAME_ENABLED\nBOOST_FIXTURE_TEST_CASE(pfr_structs_by_name, any_connection_fixture)\n{\n    connect();\n\n    // Start\n    static_execution_state<pfr_by_name<row_multifield_pfr>> result;\n    conn.async_start_execution(\"SELECT * FROM multifield_table WHERE id = 1\", result, as_netresult)\n        .validate_no_error();\n    validate_multifield_meta(result.meta());\n    BOOST_TEST(result.should_read_rows());\n\n    // Read rows\n    std::array<row_multifield_pfr, 3> rws;\n    std::size_t num_rows = conn.async_read_some_rows(result, span<row_multifield_pfr>(rws), as_netresult)\n                               .get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST(boost::pfr::eq(rws[0], row_multifield_pfr{1.1f, 11, \"aaa\"}));\n\n    // Read again, in case the EOF came separately\n    num_rows = conn.async_read_some_rows(result, span<row_multifield_pfr>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 0u);\n    BOOST_TEST(result.complete());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n#endif\n\n#if BOOST_PFR_ENABLED && defined(BOOST_MYSQL_CXX14)\nBOOST_FIXTURE_TEST_CASE(pfr_structs_by_position, any_connection_fixture)\n{\n    connect();\n\n    // Start\n    static_execution_state<pfr_by_position<row_multifield_pfr_literal>> result;\n    conn.async_start_execution(\n            \"SELECT id, field_int, field_double FROM multifield_table WHERE id = 1\",\n            result,\n            as_netresult\n    )\n        .validate_no_error();\n    check_meta(result.meta(), {column_type::int_, column_type::int_, column_type::double_});\n    BOOST_TEST(result.should_read_rows());\n\n    // Read rows\n    std::array<row_multifield_pfr_literal, 3> rws;\n    auto num_rows = conn.async_read_some_rows(result, span<row_multifield_pfr_literal>(rws), as_netresult)\n                        .get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST(boost::pfr::eq(rws[0], row_multifield_pfr_literal{1, 11, 0.1}));\n\n    // Read again, in case the EOF came separately\n    num_rows = conn.async_read_some_rows(result, span<row_multifield_pfr_literal>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 0u);\n    BOOST_TEST(result.complete());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n#endif\n\n// This spotchecks having repeated empty row types, too\nBOOST_FIXTURE_TEST_CASE(multi_resultset, any_connection_fixture)\n{\n    connect(connect_params_builder().multi_queries(true).build());\n    start_transaction();\n\n    // Start\n    constexpr const char* query =\n        \"SELECT * FROM multifield_table WHERE id = 1;\"\n        \"DELETE FROM updates_table;\"\n        \"SELECT * FROM one_row_table;\"\n        \"SET @v1 = 2\";\n    static_execution_state<row_multifield, empty, row_2fields, empty> result;\n    conn.async_start_execution(query, result, as_netresult).validate_no_error();\n    validate_multifield_meta(result.meta());\n    BOOST_TEST(result.should_read_rows());\n\n    // Read rows (r1)\n    std::array<row_multifield, 3> rws;\n    std::size_t num_rows = conn.async_read_some_rows(result, span<row_multifield>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((rws[0] == row_multifield{1.1f, 11, \"aaa\"}));\n\n    // Read again, in case the EOF came separately (r1)\n    num_rows = conn.async_read_some_rows(result, span<row_multifield>(rws), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 0u);\n    BOOST_TEST(result.should_read_head());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n\n    // Next resultset (r2, empty)\n    conn.async_read_resultset_head(result, as_netresult).validate_no_error();\n    BOOST_TEST(result.should_read_head());\n    BOOST_TEST(result.meta().size() == 0u);\n    BOOST_TEST(result.affected_rows() == 3u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n\n    // Next resultset (r3)\n    conn.async_read_resultset_head(result, as_netresult).validate_no_error();\n    BOOST_TEST(result.should_read_rows());\n    validate_2fields_meta(result.meta(), \"one_row_table\");\n\n    // Read rows (r3)\n    std::array<row_2fields, 3> rws2;\n    num_rows = conn.async_read_some_rows(result, span<row_2fields>(rws2), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((rws2[0] == row_2fields{1, std::string(\"f0\")}));\n\n    // Read again, in case the EOF came separately (r3)\n    num_rows = conn.async_read_some_rows(result, span<row_2fields>(rws2), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 0u);\n    BOOST_TEST(result.should_read_head());\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n\n    // Next resultset (r4, empty)\n    conn.async_read_resultset_head(result, as_netresult).validate_no_error();\n    BOOST_TEST(result.complete());\n    BOOST_TEST(result.meta().size() == 0u);\n    BOOST_TEST(result.affected_rows() == 0u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);\n    BOOST_TEST(result.info() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(metadata_check_failed, any_connection_fixture)\n{\n    connect();\n\n    static_execution_state<row_multifield_bad> result;\n    conn.async_start_execution(\"SELECT * FROM multifield_table ORDER BY id\", result, as_netresult)\n        .validate_error(client_errc::metadata_check_failed, multifield_bad_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(metadata_check_failed_empty_resultset, any_connection_fixture)\n{\n    connect();\n\n    const char* expected_msg =\n        \"Field in position 0 can't be mapped: there are more fields in your C++ data type than in your query\";\n    static_execution_state<std::tuple<int>> result;\n    conn.async_start_execution(\"SET @v1 = 2\", result, as_netresult)\n        .validate_error(client_errc::metadata_check_failed, expected_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(num_resultsets_mismatch, any_connection_fixture)\n{\n    connect();\n\n    static_execution_state<row_2fields, empty> result;\n\n    // Start execution\n    conn.async_start_execution(\"SELECT * FROM empty_table\", result, as_netresult).validate_no_error();\n\n    // Error is detected when reading the OK packet in read_some_rows\n    std::array<row_2fields, 3> storage;\n    conn.async_read_some_rows(result, span<row_2fields>(storage), as_netresult)\n        .validate_error(client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(num_resultsets_mismatch_empty_resultset, any_connection_fixture)\n{\n    connect();\n\n    // Start\n    static_execution_state<empty, empty> result;\n    conn.async_start_execution(\"SET @v1 = 2\", result, as_netresult)\n        .validate_error(client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(metadata_check_failed_subsequent_resultset, any_connection_fixture)\n{\n    connect(connect_params_builder().multi_queries(true).build());\n\n    static_execution_state<empty, row_multifield_bad> result;\n\n    // Start execution goes OK\n    conn.async_start_execution(\"SET @v1 = 2; SELECT * FROM multifield_table\", result, as_netresult)\n        .validate_no_error();\n\n    // Error is detected when reading next head\n    conn.async_read_resultset_head(result, as_netresult)\n        .validate_error(client_errc::metadata_check_failed, multifield_bad_msg);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/integration/test/stored_procedures.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_integration/any_connection_fixture.hpp\"\n#include \"test_integration/metadata_validator.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_stored_procedures)\n\nBOOST_FIXTURE_TEST_CASE(without_selects, any_connection_fixture)\n{\n    connect();\n    start_transaction();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_insert(?)\", as_netresult).get();\n\n    // Call the procedure\n    results result;\n    conn.async_execute(stmt.bind(\"abc\"), result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST_REQUIRE(result.size() == 1u);\n    BOOST_TEST(result.meta().size() == 0u);\n    BOOST_TEST(result.rows() == rows(), per_element());\n    BOOST_TEST(result.affected_rows() == 1u);\n    BOOST_TEST(result.warning_count() == 0u);\n    BOOST_TEST(result.last_insert_id() == 0u);  // this refers to the CALL, not to the INSERT\n    BOOST_TEST(result.info() == \"\");\n    BOOST_TEST(result.out_params() == row_view());\n\n    // Verify it took place\n    conn.async_execute(\"SELECT field_varchar FROM inserts_table\", result, as_netresult).validate_no_error();\n    BOOST_TEST(result.rows() == makerows(1, \"abc\"), per_element());\n}\n\nBOOST_FIXTURE_TEST_CASE(with_one_select, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_select_1(?)\", as_netresult).get();\n\n    // Call the procedure\n    results result;\n    conn.async_execute(stmt.bind(\"abc\"), result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST_REQUIRE(result.size() == 2u);\n    validate_2fields_meta(result[0].meta(), \"one_row_table\");\n    BOOST_TEST(result[0].rows() == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST(result[0].affected_rows() == 0u);\n    BOOST_TEST(result[0].warning_count() == 0u);\n    BOOST_TEST(result[0].last_insert_id() == 0u);\n    BOOST_TEST(result[0].info() == \"\");\n    BOOST_TEST(result[1].meta().size() == 0u);\n    BOOST_TEST(result[1].rows() == rows(), per_element());\n    BOOST_TEST(result[1].affected_rows() == 0u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() == 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(result.out_params() == row_view());\n}\n\nBOOST_FIXTURE_TEST_CASE(with_two_selects, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_select_2(?, ?)\", as_netresult).get();\n\n    // Call the procedure\n    results result;\n    conn.async_execute(stmt.bind(\"abc\", 42), result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST_REQUIRE(result.size() == 3u);\n    validate_2fields_meta(result[0].meta(), \"one_row_table\");\n    BOOST_TEST(result[0].rows() == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST(result[0].affected_rows() == 0u);\n    BOOST_TEST(result[0].warning_count() == 0u);\n    BOOST_TEST(result[0].last_insert_id() == 0u);\n    BOOST_TEST(result[0].info() == \"\");\n    check_meta(result[1].meta(), {column_type::varchar, column_type::int_});\n    BOOST_TEST(result[1].rows() == makerows(2, \"abc\", 42), per_element());\n    BOOST_TEST(result[1].affected_rows() == 0u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() == 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(result[2].meta().size() == 0u);\n    BOOST_TEST(result[2].rows() == rows(), per_element());\n    BOOST_TEST(result[2].affected_rows() == 0u);\n    BOOST_TEST(result[2].warning_count() == 0u);\n    BOOST_TEST(result[2].last_insert_id() == 0u);\n    BOOST_TEST(result[2].info() == \"\");\n    BOOST_TEST(result.out_params() == row_view());\n}\n\nBOOST_FIXTURE_TEST_CASE(with_two_selects_multifn, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_select_2(?, ?)\", as_netresult).get();\n\n    // Call the procedure\n    execution_state st;\n    conn.async_start_execution(stmt.bind(\"abc\", 42), st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    validate_2fields_meta(st.meta(), \"one_row_table\");\n\n    // Read rows for the 1st select\n    auto rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(rv == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n    BOOST_TEST(!st.is_out_params());\n\n    // Read 2nd resultset's head\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    check_meta(st.meta(), {column_type::varchar, column_type::int_});\n\n    // Read 2nd resultset's rows\n    rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(rv == makerows(2, \"abc\", 42), per_element());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n    BOOST_TEST(!st.is_out_params());\n\n    // Read final resultset\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.meta().size() == 0u);\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n    BOOST_TEST(!st.is_out_params());\n}\n\nBOOST_FIXTURE_TEST_CASE(output_params_not_bound, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_outparams(?, @var1, @var2)\", as_netresult).get();\n\n    // Call the procedure\n    results result;\n    conn.async_execute(stmt.bind(10), result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST_REQUIRE(result.size() == 2u);\n    validate_2fields_meta(result[0].meta(), \"one_row_table\");\n    BOOST_TEST(result[0].rows() == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST(result[1].meta().size() == 0u);\n    BOOST_TEST(result[1].rows() == rows(), per_element());\n    BOOST_TEST(result[1].affected_rows() == 0u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() == 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(result.out_params() == row_view());\n}\n\nBOOST_FIXTURE_TEST_CASE(output_params_bound, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_outparams(?, ?, ?)\", as_netresult).get();\n\n    // Call the procedure\n    results result;\n    conn.async_execute(stmt.bind(10, nullptr, 30), result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST_REQUIRE(result.size() == 3u);\n    validate_2fields_meta(result[0].meta(), \"one_row_table\");\n    BOOST_TEST(result[0].rows() == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST(!result[0].is_out_params());\n    check_meta(result[1].meta(), {column_type::int_, column_type::int_});\n    BOOST_TEST(result[1].rows() == makerows(2, 10, 31), per_element());\n    BOOST_TEST(result[1].affected_rows() == 0u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() == 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(result[1].is_out_params());\n    BOOST_TEST(result[2].meta().size() == 0u);\n    BOOST_TEST(result[2].rows() == rows(), per_element());\n    BOOST_TEST(result[2].affected_rows() == 0u);\n    BOOST_TEST(result[2].warning_count() == 0u);\n    BOOST_TEST(result[2].last_insert_id() == 0u);\n    BOOST_TEST(result[2].info() == \"\");\n    BOOST_TEST(!result[2].is_out_params());\n    BOOST_TEST(result.out_params() == makerow(10, 31));\n}\n\nBOOST_FIXTURE_TEST_CASE(output_params_bound_multifn, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_outparams(?, ?, ?)\", as_netresult).get();\n\n    // Call the procedure\n    execution_state st;\n    conn.async_start_execution(stmt.bind(10, nullptr, 30), st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    validate_2fields_meta(st.meta(), \"one_row_table\");\n\n    // 1st resultset, rows\n    auto rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST(rv == makerows(2, 1, \"f0\"), per_element());\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(!st.is_out_params());\n\n    // out params, head\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    check_meta(st.meta(), {column_type::int_, column_type::int_});\n\n    // out params, rows and eof\n    rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(rv == makerows(2, 10, 31), per_element());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n    BOOST_TEST(st.is_out_params());\n\n    // final eof\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.meta().size() == 0u);\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.info() == \"\");\n    BOOST_TEST(!st.is_out_params());\n}\n\nBOOST_FIXTURE_TEST_CASE(with_signal, any_connection_fixture)\n{\n    connect();\n\n    // Statement\n    auto stmt = conn.async_prepare_statement(\"CALL sp_signal()\", as_netresult).get();\n\n    // Call the procedure. It should fail, since we're invoking SIGNAL\n    results result;\n    conn.async_execute(stmt.bind(), result, as_netresult)\n        .validate_error(common_server_errc::er_no, \"An error occurred\");\n}\n\nBOOST_FIXTURE_TEST_CASE(with_query, any_connection_fixture)\n{\n    connect();\n\n    // Call the procedure\n    results result;\n    conn.async_execute(\"CALL sp_outparams(42, @var1, @var2)\", result, as_netresult).validate_no_error();\n\n    // Verify results\n    BOOST_TEST_REQUIRE(result.size() == 2u);\n    validate_2fields_meta(result[0].meta(), \"one_row_table\");\n    BOOST_TEST(result[0].rows() == makerows(2, 1, \"f0\"));\n    BOOST_TEST(result[1].meta().size() == 0u);\n    BOOST_TEST(result[1].rows() == rows(), per_element());\n    BOOST_TEST(result[1].affected_rows() == 0u);\n    BOOST_TEST(result[1].warning_count() == 0u);\n    BOOST_TEST(result[1].last_insert_id() == 0u);\n    BOOST_TEST(result[1].info() == \"\");\n    BOOST_TEST(result.out_params() == row_view());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/thread_safety/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport os ;\n\n# The hostname to use for tests\nlocal hostname = [ os.environ BOOST_MYSQL_SERVER_HOST ] ;\nif $(hostname) = \"\"\n{\n    hostname = \"127.0.0.1\" ;\n}\n\nlocal tests = \n    connection_pool\n    connection_pool_two_contexts\n    connection_pool_coroutines\n    connection_pool_external_strand\n    connection_pool_cancel\n    connection_pool_cancel_get_connection\n;\n\nfor test in $(tests)\n{\n    # TSAN seems to raise a false positive with libc++ shared_ptr/weak_ptr, used in this test\n    local libcpp_exclusion ;\n    if $(test) = \"connection_pool_cancel_get_connection\" {\n        libcpp_exclusion = <stdlib>libc++:<build>no ;\n    }\n\n    # In OSX, tsan reports a race condition in Asio's kqueue reactor. Ignore this for now.\n    # Net TS executors use std::atomic_thread_fence, unsupported by TSAN, which yields false positives.\n    # gcc-5 seems to emit incorrect tsan instrumentation code for static initializations\n    # (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68338)\n    run\n            /boost/mysql/test//boost_mysql_compiled\n            $(test).cpp\n        : requirements\n            <testing.arg>$(hostname)\n            <target-os>darwin:<build>no\n            <boost.mysql.use-ts-executor>on:<build>no\n            <toolset>gcc-5:<build>no\n            $(libcpp_exclusion)\n            <thread-sanitizer>norecover\n        : target-name $(test)\n    ;\n}\n"
  },
  {
    "path": "test/thread_safety/connection_pool.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/detached.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n#include <cstddef>\n\n#include \"tsan_pool_common.hpp\"\n\nusing boost::mysql::error_code;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nclass task\n{\n    mysql::connection_pool& pool_;\n    coordinator& coord_;\n    mysql::results r_;\n    mysql::diagnostics diag_;\n    mysql::pooled_connection conn_;\n\npublic:\n    task(mysql::connection_pool& pool, coordinator& coord) : pool_(pool), coord_(coord) {}\n\n    void start_get_connection()\n    {\n        pool_.async_get_connection(diag_, [this](error_code ec, mysql::pooled_connection c) {\n            check_ec(ec, diag_);\n            conn_ = std::move(c);\n            start_execute();\n        });\n    }\n\n    void start_execute()\n    {\n        conn_->async_execute(\"SELECT 1\", r_, diag_, [this](error_code ec) {\n            check_ec(ec, diag_);\n            conn_ = boost::mysql::pooled_connection();\n            if (coord_.on_iteration_finish())\n            {\n                start_get_connection();\n            }\n        });\n    }\n};\n\nvoid run(const char* hostname)\n{\n    // Setup\n    asio::thread_pool ctx(8);\n    mysql::connection_pool pool(ctx, create_pool_params(hostname));\n    coordinator coord(pool);\n    std::vector<task> tasks;\n\n    // Run the pool\n    pool.async_run(asio::detached);\n\n    // Create tasks\n    for (std::size_t i = 0; i < num_tasks; ++i)\n        tasks.emplace_back(pool, coord);\n\n    // Launch\n    for (auto& t : tasks)\n        t.start_get_connection();\n\n    // Run\n    ctx.join();\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 2)\n    {\n        usage(argv[0]);\n    }\n\n    run(argv[1]);\n}\n"
  },
  {
    "path": "test/thread_safety/connection_pool_cancel.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/pool_params.hpp>\n\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n#include <memory>\n\n#include \"tsan_pool_common.hpp\"\n\nusing boost::mysql::error_code;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nvoid run(const char* hostname)\n{\n    // Setup\n    asio::thread_pool ctx(8);\n\n    for (int i = 0; i < 20; ++i)\n    {\n        // Create a pool\n        auto pool = std::make_shared<mysql::connection_pool>(ctx, create_pool_params(hostname, 10));\n\n        // Run the pool within the thread pool\n        asio::post(asio::bind_executor(ctx.get_executor(), [pool]() { pool->async_run(asio::detached); }));\n\n        // Issue a cancellation\n        asio::post(asio::bind_executor(ctx.get_executor(), [pool]() { pool->cancel(); }));\n    }\n\n    // Run\n    ctx.join();\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 2)\n    {\n        usage(argv[0]);\n    }\n\n    run(argv[1]);\n}\n"
  },
  {
    "path": "test/thread_safety/connection_pool_cancel_get_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n#include <algorithm>\n#include <chrono>\n#include <cstddef>\n\n#include \"tsan_pool_common.hpp\"\n\nusing boost::mysql::error_code;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nclass task\n{\n    mysql::connection_pool& pool_;\n    coordinator& coord_;\n    asio::strand<asio::any_io_executor> strand_;\n    mysql::results r_;\n    mysql::diagnostics diag_;\n    mysql::pooled_connection conn_;\n    std::chrono::milliseconds timeout_{1};  // make it likely to get some cancellations\n\npublic:\n    task(mysql::connection_pool& pool, coordinator& coord)\n        : pool_(pool), coord_(coord), strand_(asio::make_strand(pool_.get_executor()))\n    {\n    }\n\n    void start()\n    {\n        // get_connection should be run within a strand because cancel_after implies\n        // a parallel operation. This is orthogonal to the pool's thread-safety\n        // (this is strand is per-task, the pool's is shared between all tasks).\n        asio::dispatch(asio::bind_executor(strand_, [this]() { start_get_connection(); }));\n    }\n\n    void start_get_connection()\n    {\n        pool_.async_get_connection(\n            diag_,\n            asio::cancel_after(\n                timeout_,\n                asio::bind_executor(\n                    strand_,\n                    [this](error_code ec, mysql::pooled_connection c) {\n                        if (ec == boost::mysql::client_errc::no_connection_available)\n                        {\n                            // We got a cancellation. Increase timeout so we don't get stuck\n                            // and try again\n                            timeout_ *= 2;\n                            start_get_connection();\n                        }\n                        else\n                        {\n                            check_ec(ec, diag_);\n                            conn_ = std::move(c);\n                            start_execute();\n                        }\n                    }\n                )\n            )\n        );\n    }\n\n    void start_execute()\n    {\n        auto callback = [this](error_code ec) {\n            check_ec(ec, diag_);\n            conn_ = boost::mysql::pooled_connection();\n            if (coord_.on_iteration_finish())\n            {\n                start_get_connection();\n            }\n        };\n        conn_->async_execute(\"SELECT 1\", r_, diag_, asio::bind_executor(strand_, std::move(callback)));\n    }\n\n    bool had_cancellations() const { return timeout_.count() > 1; }\n};\n\nvoid run(const char* hostname)\n{\n    // Setup\n    asio::thread_pool ctx(8);\n    mysql::pool_params params;\n    mysql::connection_pool pool(ctx, create_pool_params(hostname));\n    coordinator coord(pool);\n    std::vector<task> tasks;\n\n    // Run the pool\n    pool.async_run(asio::detached);\n\n    // Create connections\n    for (std::size_t i = 0; i < num_tasks; ++i)\n        tasks.emplace_back(pool, coord);\n\n    // Launch\n    for (auto& t : tasks)\n        t.start();\n\n    // Run\n    ctx.join();\n\n    // Verify that at least one task had a cancellation\n    if (!std::any_of(tasks.begin(), tasks.end(), [](const task& t) { return t.had_cancellations(); }))\n    {\n        std::cerr << \"No task had any cancellations\\n\";\n        exit(1);\n    }\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 2)\n    {\n        usage(argv[0]);\n    }\n\n    run(argv[1]);\n}\n"
  },
  {
    "path": "test/thread_safety/connection_pool_coroutines.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/co_spawn.hpp>\n#include <boost/asio/this_coro.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n#include <cstddef>\n#include <exception>\n\n#include \"tsan_pool_common.hpp\"\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nasio::awaitable<void> task(mysql::connection_pool& pool, coordinator& coord)\n{\n    mysql::results r;\n\n    do\n    {\n        // Coroutine handlers always have a bound executor.\n        // Verify that we achieve thread-safety even in this case (regression check)\n        // Exercise return_without_reset, too\n        auto conn = co_await pool.async_get_connection();\n        co_await conn->async_execute(\"SELECT 1\", r);\n        conn.return_without_reset();\n    } while (coord.on_iteration_finish());\n}\n\nvoid rethrow_on_err(std::exception_ptr err)\n{\n    if (err)\n        std::rethrow_exception(err);\n}\n\nvoid run(const char* hostname)\n{\n    // Setup\n    asio::thread_pool ctx(8);\n    mysql::pool_params params;\n    mysql::connection_pool pool(ctx, create_pool_params(hostname));\n    coordinator coord(pool);\n\n    // The pool should be thread-safe even if we pass a token with a custom\n    // executor to async_run (as happens with coroutines)\n    asio::co_spawn(ctx, [&]() -> asio::awaitable<void> { co_await pool.async_run(); }, rethrow_on_err);\n\n    // Create and launch tasks\n    for (std::size_t i = 0; i < num_tasks; ++i)\n    {\n        asio::co_spawn(ctx, [&]() -> asio::awaitable<void> { return task(pool, coord); }, rethrow_on_err);\n    }\n\n    // Run\n    ctx.join();\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 2)\n    {\n        usage(argv[0]);\n    }\n\n    run(argv[1]);\n}\n\n#else\n\nint main() { std::cout << \"Sorry, your compiler doesn't support C++20 coroutines\\n\"; }\n\n#endif\n"
  },
  {
    "path": "test/thread_safety/connection_pool_external_strand.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n#include <cstddef>\n\n#include \"tsan_pool_common.hpp\"\n\nusing boost::mysql::error_code;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\n\nnamespace {\n\nclass task\n{\n    mysql::connection_pool& pool_;\n    coordinator& coord_;\n    asio::strand<asio::any_io_executor> strand_;\n    mysql::results r_;\n    mysql::diagnostics diag_;\n    mysql::pooled_connection conn_;\n\npublic:\n    task(mysql::connection_pool& pool, coordinator& coord, asio::strand<asio::any_io_executor> strand)\n        : pool_(pool), coord_(coord), strand_(std::move(strand))\n    {\n    }\n\n    void start() { enter_strand(); }\n\n    void enter_strand()\n    {\n        asio::dispatch(asio::bind_executor(strand_, [this]() { start_get_connection(); }));\n    }\n\n    void start_get_connection()\n    {\n        pool_.async_get_connection(diag_, [this](error_code ec, mysql::pooled_connection c) {\n            check_ec(ec, diag_);\n            conn_ = std::move(c);\n            exit_strand();\n        });\n    }\n\n    void exit_strand()\n    {\n        asio::post(asio::bind_executor(strand_.get_inner_executor(), [this]() { start_execute(); }));\n    }\n\n    void start_execute()\n    {\n        conn_->async_execute(\"SELECT 1\", r_, diag_, [this](error_code ec) {\n            check_ec(ec, diag_);\n            asio::dispatch(asio::bind_executor(strand_, [this]() { return_connection(); }));\n        });\n    }\n\n    void return_connection()\n    {\n        // Returning a connection must happen within the strand\n        conn_ = boost::mysql::pooled_connection();\n        if (coord_.on_iteration_finish())\n        {\n            start_get_connection();\n        }\n    }\n};\n\n// Tests that we can build a thread-safe connection pool ourselves,\n// by passing a strand as the pool executor\nvoid run(const char* hostname)\n{\n    // Setup\n    asio::thread_pool ctx(8);\n    auto strand = asio::make_strand(ctx);\n    auto params = create_pool_params(hostname);\n    params.thread_safe = false;\n    params.connection_executor = ctx.get_executor();\n    mysql::connection_pool pool(strand, std::move(params));\n    coordinator coord(pool);\n    std::vector<task> tasks;\n\n    // Run the pool\n    pool.async_run(asio::detached);\n\n    // Create tasks\n    for (std::size_t i = 0; i < num_tasks; ++i)\n        tasks.emplace_back(pool, coord, strand);\n\n    // Launch\n    for (auto& t : tasks)\n        t.start();\n\n    // Run\n    ctx.join();\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 2)\n    {\n        usage(argv[0]);\n    }\n\n    run(argv[1]);\n}\n"
  },
  {
    "path": "test/thread_safety/connection_pool_two_contexts.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/thread_pool.hpp>\n\n#include <cstddef>\n\n#include \"tsan_pool_common.hpp\"\n\nusing boost::mysql::error_code;\nusing namespace boost::mysql::test;\nnamespace mysql = boost::mysql;\nnamespace asio = boost::asio;\n\nnamespace {\n\nclass task\n{\n    mysql::connection_pool& pool_;\n    coordinator& coord_;\n    asio::any_io_executor token_ex_;\n    mysql::results r_;\n    mysql::diagnostics diag_;\n    mysql::pooled_connection conn_;\n\npublic:\n    task(mysql::connection_pool& pool, coordinator& coord, asio::any_io_executor token_ex)\n        : pool_(pool), coord_(coord), token_ex_(std::move(token_ex))\n    {\n    }\n\n    void start_get_connection()\n    {\n        // Verify that we achieve thread-safety even if the token\n        // has a bound executor associated to an execution context different\n        // from the one that the pool is using (regression check).\n        pool_.async_get_connection(\n            diag_,\n            asio::bind_executor(\n                token_ex_,\n                [this](error_code ec, mysql::pooled_connection c) {\n                    check_ec(ec, diag_);\n                    conn_ = std::move(c);\n                    start_execute();\n                }\n            )\n        );\n    }\n\n    void start_execute()\n    {\n        conn_->async_execute(\"SELECT 1\", r_, diag_, [this](error_code ec) {\n            check_ec(ec, diag_);\n            conn_ = boost::mysql::pooled_connection();\n            if (coord_.on_iteration_finish())\n            {\n                start_get_connection();\n            }\n        });\n    }\n};\n\nvoid run(const char* hostname)\n{\n    // Setup\n    asio::thread_pool pool_ctx(8);\n    asio::thread_pool external_ctx(4);\n    mysql::connection_pool pool(pool_ctx, create_pool_params(hostname));\n    coordinator coord(pool);\n    std::vector<task> tasks;\n\n    // The pool should be thread-safe even if we pass a token with a custom\n    // executor to async_run\n    pool.async_run(asio::bind_executor(external_ctx.get_executor(), asio::detached));\n\n    // Create tasks\n    for (std::size_t i = 0; i < num_tasks; ++i)\n        tasks.emplace_back(pool, coord, external_ctx.get_executor());\n\n    // Launch\n    for (auto& t : tasks)\n        t.start_get_connection();\n\n    // Run\n    pool_ctx.join();\n    external_ctx.join();\n}\n\n}  // namespace\n\nint main(int argc, char** argv)\n{\n    if (argc != 2)\n    {\n        usage(argv[0]);\n    }\n\n    run(argv[1]);\n}\n"
  },
  {
    "path": "test/thread_safety/tsan_pool_common.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_THREAD_SAFETY_TSAN_POOL_COMMON_HPP\n#define BOOST_MYSQL_TEST_THREAD_SAFETY_TSAN_POOL_COMMON_HPP\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n\n#include <atomic>\n#include <cstddef>\n#include <cstdlib>\n#include <iostream>\n#include <mutex>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Exit on error (thread-safe)\ninline void check_ec(error_code ec, diagnostics& diag)\n{\n    if (ec)\n    {\n        static std::mutex mtx;\n        std::lock_guard<std::mutex> guard{mtx};\n        std::cerr << ec << \", \" << diag.server_message() << std::endl;\n        exit(1);\n    }\n}\n\n// Constants\nconstexpr int num_tasks = 100;\nconstexpr int iterations_per_task = 20;\n\n// Coordinate tasks\nclass coordinator\n{\n    std::atomic_int remaining_queries_{num_tasks * iterations_per_task};\n    std::atomic_int outstanding_tasks_{num_tasks};\n    connection_pool& pool_;\n\n    void on_task_finish()\n    {\n        if (--outstanding_tasks_ == 0)\n            pool_.cancel();\n    }\n\npublic:\n    coordinator(connection_pool& pool) : pool_(pool) {}\n\n    // Call after a task finishes an iteration. Returns true if we should continue\n    bool on_iteration_finish()\n    {\n        bool should_continue = (--remaining_queries_ > 0);\n        if (!should_continue)\n            on_task_finish();\n        return should_continue;\n    }\n};\n\n// Default pool params\ninline pool_params create_pool_params(const char* hostname, std::size_t initial_size = 1)\n{\n    pool_params params;\n    params.server_address.emplace_host_and_port(hostname);\n    params.username = \"integ_user\";\n    params.password = \"integ_password\";\n    params.initial_size = initial_size;\n    params.max_size = num_tasks - 10;       // create some contention\n    params.ssl = mysql::ssl_mode::require;  // double check sharing SSL contexts is OK\n    params.thread_safe = true;\n    return params;\n}\n\ninline void usage(const char* progname)\n{\n    std::cerr << \"Usage: \" << progname << \" <hostname>\\n\";\n    exit(1);\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/CMakeLists.txt",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nadd_executable(\n    boost_mysql_unittests\n\n    # Helpers\n    src/utils.cpp\n\n    # Actual tests\n    test/protocol/static_buffer.cpp\n    test/protocol/capabilities.cpp\n    test/protocol/null_bitmap.cpp\n    test/protocol/protocol_field_type.cpp\n    test/protocol/frame_header.cpp\n    test/protocol/serialization_context.cpp\n    test/protocol/deserialization_context.cpp\n    test/protocol/protocol_types.cpp\n    test/protocol/text_protocol.cpp\n    test/protocol/binary_protocol.cpp\n    test/protocol/serialization.cpp\n    test/protocol/deserialization.cpp\n\n    test/sansio/read_buffer.cpp\n    test/sansio/message_reader.cpp\n    test/sansio/top_level_algo.cpp\n\n    test/sansio/handshake/handshake.cpp\n    test/sansio/handshake/handshake_mnp.cpp\n    test/sansio/handshake/handshake_mnp_hash_password.cpp\n    test/sansio/handshake/handshake_csha2p.cpp\n    test/sansio/handshake/handshake_csha2p_hash_password.cpp\n    test/sansio/handshake/handshake_csha2p_encrypt_password.cpp\n    test/sansio/handshake/handshake_capabilities.cpp\n    test/sansio/handshake/handshake_connection_state_data.cpp\n    test/sansio/read_resultset_head.cpp\n    test/sansio/start_execution.cpp\n    test/sansio/read_some_rows.cpp\n    test/sansio/read_some_rows_dynamic.cpp\n    test/sansio/execute.cpp\n    test/sansio/close_statement.cpp\n    test/sansio/set_character_set.cpp\n    test/sansio/ping.cpp\n    test/sansio/reset_connection.cpp\n    test/sansio/prepare_statement.cpp\n    test/sansio/run_pipeline.cpp\n    test/sansio/quit_connection.cpp\n    test/sansio/close_connection.cpp\n\n    test/execution_processor/execution_processor.cpp\n    test/execution_processor/execution_state_impl.cpp\n    test/execution_processor/static_execution_state_impl.cpp\n    test/execution_processor/results_impl.cpp\n    test/execution_processor/static_results_impl.cpp\n\n    test/connection_pool/sansio_connection_node.cpp\n    test/connection_pool/connection_pool_impl.cpp\n\n    test/detail/datetime.cpp\n    test/detail/row_impl.cpp\n    test/detail/rows_iterator.cpp\n    test/detail/execution_concepts.cpp\n    test/detail/writable_field_traits.cpp\n    test/detail/socket_stream.cpp\n    test/detail/connect_params_helpers.cpp\n    test/detail/output_string.cpp\n    test/detail/engine_impl.cpp\n    test/detail/intermediate_handler.cpp\n\n    test/detail/typing/meta_check_context.cpp\n    test/detail/typing/pos_map.cpp\n    test/detail/typing/readable_field_traits.cpp\n    test/detail/typing/row_traits.cpp\n\n    test/impl/dt_to_string.cpp\n    test/impl/ssl_context_with_default.cpp\n    test/impl/next_power_of_two.cpp\n    test/impl/variant_stream.cpp\n\n    test/spotchecks/connection_use_after_move.cpp\n    test/spotchecks/default_completion_tokens.cpp\n    test/spotchecks/read_some_rows_static.cpp\n    test/spotchecks/multifn.cpp\n    test/spotchecks/execution_requests.cpp\n    test/spotchecks/misc.cpp\n\n    test/format_sql/formattable.cpp\n    test/format_sql/basic_format_context.cpp\n    test/format_sql/individual_value.cpp\n    test/format_sql/formattable_ref.cpp\n    test/format_sql/ranges.cpp\n    test/format_sql/sequence.cpp\n    test/format_sql/custom_formatter.cpp\n    test/format_sql/format_strings.cpp\n    test/format_sql/api.cpp\n\n    test/execution_state.cpp\n    test/static_execution_state.cpp\n    test/results.cpp\n    test/static_results.cpp\n    test/resultset_view.cpp\n    test/resultset.cpp\n    test/client_errc.cpp\n    test/column_type.cpp\n    test/common_server_errc.cpp\n    test/mysql_server_errc.cpp\n    test/mariadb_server_errc.cpp\n    test/is_fatal_error.cpp\n    test/connection.cpp\n    test/date.cpp\n    test/datetime.cpp\n    test/field_view.cpp\n    test/field.cpp\n    test/row_view.cpp\n    test/row.cpp\n    test/rows_view.cpp\n    test/rows.cpp\n    test/metadata.cpp\n    test/diagnostics.cpp\n    test/statement.cpp\n    test/throw_on_error.cpp\n    test/any_address.cpp\n    test/any_connection.cpp\n    test/pool_params.cpp\n    test/connection_pool.cpp\n    test/character_set.cpp\n    test/escape_string.cpp\n    test/constant_string_view.cpp\n    test/pfr.cpp\n    test/pipeline.cpp\n    test/with_diagnostics.cpp\n)\ntarget_include_directories(\n    boost_mysql_unittests\n    PRIVATE\n    \"include\"\n)\ntarget_link_libraries(\n    boost_mysql_unittests\n    PRIVATE\n    boost_mysql_testing\n)\nif (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.16)\n    target_precompile_headers(\n        boost_mysql_unittests\n        PRIVATE\n        pch.hpp\n    )\nendif()\nboost_mysql_test_target_settings(boost_mysql_unittests)\n\nadd_test(\n    NAME boost_mysql_unittests\n    COMMAND boost_mysql_unittests\n)\n\n# Tests edge cases when encrypting passwords that require mocking OpenSSL.\n# This executable should not link to any OpenSSL libraries.\nadd_executable(\n    boost_mysql_test_csha2p_encrypt_password_errors\n    test_csha2p_encrypt_password_errors.cpp\n)\ntarget_include_directories(\n    boost_mysql_test_csha2p_encrypt_password_errors\n    PRIVATE\n    ${CMAKE_CURRENT_SOURCE_DIR}/../../include # our own includes\n    ${OPENSSL_INCLUDE_DIR} # we only need the includes\n)\ntarget_link_libraries(\n    boost_mysql_test_csha2p_encrypt_password_errors\n    PRIVATE\n    Boost::unit_test_framework\n    Boost::assert\n    Boost::config\n    Boost::container\n    Boost::core\n    Boost::system\n)\ntarget_compile_features(\n    boost_mysql_test_csha2p_encrypt_password_errors\n    INTERFACE\n    cxx_std_11\n)\nboost_mysql_test_target_settings(boost_mysql_test_csha2p_encrypt_password_errors)\nadd_test(\n    NAME boost_mysql_test_csha2p_encrypt_password_errors\n    COMMAND boost_mysql_test_csha2p_encrypt_password_errors\n)\n"
  },
  {
    "path": "test/unit/Jamfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\ncpp-pch pch\n    :\n        pch.hpp\n        /boost/mysql/test//boost_mysql_test\n    ;\n\nrun\n        pch\n        /boost/mysql/test//common_test_sources\n        /boost/mysql/test//boost_mysql_test\n        /boost/mysql/test//launch_with_valgrind\n\n        # Helpers\n        src/utils.cpp\n\n        # Actual tests\n        test/protocol/static_buffer.cpp\n        test/protocol/capabilities.cpp\n        test/protocol/null_bitmap.cpp\n        test/protocol/protocol_field_type.cpp\n        test/protocol/frame_header.cpp\n        test/protocol/serialization_context.cpp\n        test/protocol/deserialization_context.cpp\n        test/protocol/protocol_types.cpp\n        test/protocol/text_protocol.cpp\n        test/protocol/binary_protocol.cpp\n        test/protocol/serialization.cpp\n        test/protocol/deserialization.cpp\n\n        test/sansio/read_buffer.cpp\n        test/sansio/message_reader.cpp\n        test/sansio/top_level_algo.cpp\n\n        test/sansio/handshake/handshake.cpp\n        test/sansio/handshake/handshake_mnp.cpp\n        test/sansio/handshake/handshake_mnp_hash_password.cpp\n        test/sansio/handshake/handshake_csha2p.cpp\n        test/sansio/handshake/handshake_csha2p_hash_password.cpp\n        test/sansio/handshake/handshake_csha2p_encrypt_password.cpp\n        test/sansio/handshake/handshake_capabilities.cpp\n        test/sansio/handshake/handshake_connection_state_data.cpp\n        test/sansio/read_resultset_head.cpp\n        test/sansio/start_execution.cpp\n        test/sansio/read_some_rows.cpp\n        test/sansio/read_some_rows_dynamic.cpp\n        test/sansio/execute.cpp\n        test/sansio/close_statement.cpp\n        test/sansio/set_character_set.cpp\n        test/sansio/ping.cpp\n        test/sansio/reset_connection.cpp\n        test/sansio/prepare_statement.cpp\n        test/sansio/run_pipeline.cpp\n        test/sansio/quit_connection.cpp\n        test/sansio/close_connection.cpp\n\n        test/execution_processor/execution_processor.cpp\n        test/execution_processor/execution_state_impl.cpp\n        test/execution_processor/static_execution_state_impl.cpp\n        test/execution_processor/results_impl.cpp\n        test/execution_processor/static_results_impl.cpp\n\n        test/connection_pool/sansio_connection_node.cpp\n        test/connection_pool/connection_pool_impl.cpp\n\n        test/detail/datetime.cpp\n        test/detail/row_impl.cpp\n        test/detail/rows_iterator.cpp\n        test/detail/execution_concepts.cpp\n        test/detail/writable_field_traits.cpp\n        test/detail/socket_stream.cpp\n        test/detail/connect_params_helpers.cpp\n        test/detail/output_string.cpp\n        test/detail/engine_impl.cpp\n        test/detail/intermediate_handler.cpp\n\n        test/detail/typing/meta_check_context.cpp\n        test/detail/typing/pos_map.cpp\n        test/detail/typing/readable_field_traits.cpp\n        test/detail/typing/row_traits.cpp\n\n        test/impl/dt_to_string.cpp\n        test/impl/ssl_context_with_default.cpp\n        test/impl/next_power_of_two.cpp\n        test/impl/variant_stream.cpp\n\n        test/spotchecks/connection_use_after_move.cpp\n        test/spotchecks/default_completion_tokens.cpp\n        test/spotchecks/read_some_rows_static.cpp\n        test/spotchecks/multifn.cpp\n        test/spotchecks/execution_requests.cpp\n        test/spotchecks/misc.cpp\n\n        test/format_sql/formattable.cpp\n        test/format_sql/basic_format_context.cpp\n        test/format_sql/individual_value.cpp\n        test/format_sql/formattable_ref.cpp\n        test/format_sql/ranges.cpp\n        test/format_sql/sequence.cpp\n        test/format_sql/custom_formatter.cpp\n        test/format_sql/format_strings.cpp\n        test/format_sql/api.cpp\n\n        test/execution_state.cpp\n        test/static_execution_state.cpp\n        test/results.cpp\n        test/static_results.cpp\n        test/resultset_view.cpp\n        test/resultset.cpp\n        test/client_errc.cpp\n        test/column_type.cpp\n        test/common_server_errc.cpp\n        test/mysql_server_errc.cpp\n        test/mariadb_server_errc.cpp\n        test/is_fatal_error.cpp\n        test/connection.cpp\n        test/date.cpp\n        test/datetime.cpp\n        test/field_view.cpp\n        test/field.cpp\n        test/row_view.cpp\n        test/row.cpp\n        test/rows_view.cpp\n        test/rows.cpp\n        test/metadata.cpp\n        test/diagnostics.cpp\n        test/statement.cpp\n        test/throw_on_error.cpp\n        test/any_address.cpp\n        test/any_connection.cpp\n        test/pool_params.cpp\n        test/connection_pool.cpp\n        test/character_set.cpp\n        test/escape_string.cpp\n        test/constant_string_view.cpp\n        test/pfr.cpp\n        test/pipeline.cpp\n        test/with_diagnostics.cpp\n\n    : requirements\n        <include>include\n    : target-name boost_mysql_unittests\n    ;\n\n\n# Tests edge cases when encrypting passwords that require mocking OpenSSL.\n# It looks like this works even if boost_mysql links to the SSL libraries.\nrun test_csha2p_encrypt_password_errors.cpp\n    /boost/mysql/test//boost_mysql\n    /boost/test//boost_unit_test_framework/<warnings-as-errors>off\n;\n"
  },
  {
    "path": "test/unit/include/test_unit/algo_test.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_ALGO_TEST_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_ALGO_TEST_HPP\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <boost/config.hpp>\n#include <boost/core/span.hpp>\n#include <boost/optional/optional.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\n#include \"test_common/source_location.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// A type-erased reference to an algorithm\nclass any_algo_ref\n{\n    template <class Algo>\n    static detail::next_action do_resume(\n        void* self,\n        detail::connection_state_data& st,\n        diagnostics& diag,\n        error_code ec\n    )\n    {\n        return static_cast<Algo*>(self)->resume(st, diag, ec);\n    }\n\n    using fn_t = detail::next_action (*)(void*, detail::connection_state_data&, diagnostics&, error_code);\n\n    void* algo_{};\n    fn_t fn_{};\n\npublic:\n    template <class Algo, class = typename std::enable_if<!std::is_same<Algo, any_algo_ref>::value>::type>\n    any_algo_ref(Algo& algo) noexcept : algo_(&algo), fn_(&do_resume<Algo>)\n    {\n    }\n\n    detail::next_action resume(detail::connection_state_data& st, diagnostics& diag, error_code ec)\n    {\n        return fn_(algo_, st, diag, ec);\n    }\n};\n\nclass BOOST_ATTRIBUTE_NODISCARD algo_test\n{\n    struct step_t\n    {\n        detail::next_action_type type;\n        std::vector<std::uint8_t> bytes;\n        error_code result;\n        bool check;\n    };\n\n    std::vector<step_t> steps_;\n\n    // Monitor connection_state_data for relevant changes\n    struct expected_state_changes_t\n    {\n        boost::optional<detail::connection_status> status;\n        boost::optional<detail::db_flavor> flavor;\n        boost::optional<detail::capabilities> current_capabilities;\n        boost::optional<std::uint32_t> connection_id;\n        boost::optional<bool> tls_supported;\n        boost::optional<bool> tls_active;\n        boost::optional<bool> backslash_escapes;\n        boost::optional<character_set> current_charset;\n    } state_changes_;\n\n    class state_checker;\n\n    static void handle_read(detail::connection_state_data& st, const step_t& op);\n\n    detail::next_action run_algo_until_step(\n        any_algo_ref algo,\n        detail::connection_state_data& st,\n        diagnostics& diag,\n        std::size_t num_steps_to_run\n    ) const;\n\n    algo_test& add_step(\n        detail::next_action_type act_type,\n        std::vector<std::uint8_t> bytes,\n        error_code ec,\n        bool check = true\n    );\n\n    void check_impl(\n        any_algo_ref algo,\n        detail::connection_state_data& st,\n        error_code expected_ec,\n        const diagnostics& expected_diag,\n        source_location loc\n    ) const;\n\n    std::size_t num_steps() const { return steps_.size(); }\n\n    void check_network_errors_impl(\n        any_algo_ref algo,\n        detail::connection_state_data& st,\n        std::size_t step_number,\n        source_location loc\n    ) const;\n\npublic:\n    algo_test() = default;\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_write(std::vector<std::uint8_t> bytes, error_code result = {})\n    {\n        return add_step(detail::next_action_type::write, std::move(bytes), result);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_any_write(error_code result = {})\n    {\n        return add_step(detail::next_action_type::write, {}, result, false);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_read(std::vector<std::uint8_t> result_bytes)\n    {\n        return add_step(detail::next_action_type::read, std::move(result_bytes), error_code());\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_read(error_code result) { return add_step(detail::next_action_type::read, {}, result); }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_ssl_handshake(error_code result = {})\n    {\n        return add_step(detail::next_action_type::ssl_handshake, {}, result);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_ssl_shutdown(error_code result = {})\n    {\n        return add_step(detail::next_action_type::ssl_shutdown, {}, result);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& expect_close(error_code result = {})\n    {\n        return add_step(detail::next_action_type::close, {}, result);\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_status(detail::connection_status expected)\n    {\n        state_changes_.status = expected;\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_capabilities(detail::capabilities expected)\n    {\n        state_changes_.current_capabilities = expected;\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_connection_id(std::uint32_t expected)\n    {\n        state_changes_.connection_id = expected;\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_flavor(detail::db_flavor expected)\n    {\n        state_changes_.flavor = expected;\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_tls_active(bool expected)\n    {\n        state_changes_.tls_active = expected;\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_current_charset(character_set expected)\n    {\n        state_changes_.current_charset = expected;\n        return *this;\n    }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    algo_test& will_set_backslash_escapes(bool expected)\n    {\n        state_changes_.backslash_escapes = expected;\n        return *this;\n    }\n\n    template <class AlgoFixture>\n    void check(\n        AlgoFixture& fix,\n        error_code expected_ec = {},\n        const diagnostics& expected_diag = {},\n        source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    ) const\n    {\n        check_impl(fix.algo, fix.st, expected_ec, expected_diag, loc);\n    }\n\n    template <class AlgoFixture>\n    void check_network_errors(source_location loc = BOOST_MYSQL_CURRENT_LOCATION) const\n    {\n        for (std::size_t i = 0; i < num_steps(); ++i)\n        {\n            AlgoFixture fix;\n            check_network_errors_impl(fix.algo, fix.st, i, loc);\n        }\n    }\n};\n\nstruct algo_fixture_base\n{\n    static constexpr std::size_t default_max_buffsize = 4u * 1024u * 1024u;\n\n    detail::connection_state_data st;\n\n    algo_fixture_base(std::size_t max_buffer_size = default_max_buffsize)\n        : st(max_buffer_size, max_buffer_size)\n    {\n        st.status = detail::connection_status::ready;\n        st.write_buffer.push_back(0xff);  // Check that we clear the write buffer at each step\n    }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_coldef_frame.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_COLDEF_FRAME_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_COLDEF_FRAME_HPP\n\n#include <boost/mysql/detail/coldef_view.hpp>\n\n#include \"test_unit/create_frame.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstd::vector<std::uint8_t> create_coldef_body(const detail::coldef_view& pack);\n\ninline std::vector<std::uint8_t> create_coldef_frame(std::uint8_t seqnum, const detail::coldef_view& coldef)\n{\n    return create_frame(seqnum, create_coldef_body(coldef));\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_err.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_ERR_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_ERR_HPP\n\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\n#include \"test_unit/create_frame.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstd::vector<std::uint8_t> serialize_err_impl(detail::err_view pack, bool with_header);\n\nclass err_builder\n{\n    detail::err_view err_{};\n    std::uint8_t seqnum_{};\n\npublic:\n    err_builder() = default;\n    err_builder& code(std::uint16_t v) noexcept\n    {\n        err_.error_code = v;\n        return *this;\n    }\n    err_builder& code(common_server_errc v) noexcept { return code(static_cast<std::uint16_t>(v)); }\n    err_builder& message(string_view v) noexcept\n    {\n        err_.error_message = v;\n        return *this;\n    }\n    err_builder& seqnum(std::uint8_t v) noexcept\n    {\n        seqnum_ = v;\n        return *this;\n    }\n    std::vector<std::uint8_t> build_body_without_header() const { return serialize_err_impl(err_, false); }\n    std::vector<std::uint8_t> build_body() const { return serialize_err_impl(err_, true); }\n    std::vector<std::uint8_t> build_frame() const { return create_frame(seqnum_, build_body()); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_execution_processor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_EXECUTION_PROCESSOR_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_EXECUTION_PROCESSOR_HPP\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <cstddef>\n\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ninline void add_meta(detail::execution_processor& proc, const std::vector<detail::coldef_view>& meta)\n{\n    diagnostics diag;\n    proc.on_num_meta(meta.size());\n    for (const auto& m : meta)\n    {\n        auto err = proc.on_meta(m, diag);\n        throw_on_error(err, diag);\n    }\n}\n\ninline void add_meta(detail::execution_processor& proc, const std::vector<column_type>& types)\n{\n    diagnostics diag;\n    proc.on_num_meta(types.size());\n    for (auto type : types)\n    {\n        auto err = proc.on_meta(meta_builder().type(type).build_coldef(), diag);\n        throw_on_error(err, diag);\n    }\n}\n\n// This is only applicable for results types (not for execution_state types)\ntemplate <class... T>\nvoid add_row(detail::execution_processor& proc, const T&... args)\n{\n    auto serialized_row = create_text_row_body(args...);\n    std::vector<field_view> fields;\n    proc.on_row_batch_start();\n    auto err = proc.on_row(serialized_row, detail::output_ref(), fields);\n    throw_on_error(err);\n    proc.on_row_batch_finish();\n}\n\ninline void add_ok(detail::execution_processor& proc, const detail::ok_view& pack)\n{\n    diagnostics diag;\n    error_code err;\n    if (proc.is_reading_head())\n        err = proc.on_head_ok_packet(pack, diag);\n    else\n        err = proc.on_row_ok_packet(pack);\n    throw_on_error(err, diag);\n}\n\ntemplate <class T>\nauto get_iface(T& obj) -> decltype(detail::access::get_impl(obj).get_interface())\n{\n    return detail::access::get_impl(obj).get_interface();\n}\n\n// Generic facility to manipulate any execution processor\n// It's not owning to support any processor type without templates\nclass exec_access\n{\n    detail::execution_processor& res_;\n\npublic:\n    exec_access(detail::execution_processor& obj) noexcept : res_(obj) {}\n\n    exec_access& reset(\n        detail::resultset_encoding enc = detail::resultset_encoding::text,\n        metadata_mode mode = metadata_mode::minimal\n    )\n    {\n        res_.reset(enc, mode);\n        return *this;\n    }\n    exec_access& seqnum(std::uint8_t v)\n    {\n        res_.sequence_number() = v;\n        return *this;\n    }\n    exec_access& meta(const std::vector<column_type>& types)\n    {\n        add_meta(res_, types);\n        return *this;\n    }\n    exec_access& meta(const std::vector<detail::coldef_view>& meta)\n    {\n        add_meta(res_, meta);\n        return *this;\n    }\n    template <class... Args>\n    exec_access& row(const Args&... args)\n    {\n        add_row(res_, args...);\n        return *this;\n    }\n    exec_access& ok(const detail::ok_view& pack)\n    {\n        add_ok(res_, pack);\n        return *this;\n    }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_frame.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_FRAME_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_FRAME_HPP\n\n#include <boost/core/span.hpp>\n\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstd::vector<std::uint8_t> create_frame(std::uint8_t seqnum, span<const std::uint8_t> body);\n\ninline std::vector<std::uint8_t> create_frame(std::uint8_t seqnum, const std::vector<std::uint8_t>& body)\n{\n    return create_frame(seqnum, boost::span<const std::uint8_t>(body));\n}\n\ninline std::vector<std::uint8_t> create_empty_frame(std::uint8_t seqnum)\n{\n    return create_frame(seqnum, boost::span<const std::uint8_t>());\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_meta.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_META_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_META_HPP\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/flags.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass meta_builder\n{\n    detail::coldef_view coldef_{};\n\npublic:\n    meta_builder()\n    {\n        coldef_.collation_id = 33;  // utf8_general_ci\n        coldef_.type = column_type::enum_;\n    }\n    meta_builder& database(string_view v) noexcept\n    {\n        coldef_.database = v;\n        return *this;\n    }\n    meta_builder& table(string_view v) noexcept\n    {\n        coldef_.table = v;\n        return *this;\n    }\n    meta_builder& org_table(string_view v) noexcept\n    {\n        coldef_.org_table = v;\n        return *this;\n    }\n    meta_builder& name(string_view v) noexcept\n    {\n        coldef_.name = v;\n        return *this;\n    }\n    meta_builder& org_name(string_view v) noexcept\n    {\n        coldef_.org_name = v;\n        return *this;\n    }\n    meta_builder& collation_id(std::uint16_t v) noexcept\n    {\n        coldef_.collation_id = v;\n        return *this;\n    }\n    meta_builder& column_length(std::uint32_t v) noexcept\n    {\n        coldef_.column_length = v;\n        return *this;\n    }\n    meta_builder& type(column_type v) noexcept\n    {\n        coldef_.type = v;\n        return *this;\n    }\n    meta_builder& flags(std::uint16_t v) noexcept\n    {\n        coldef_.flags = v;\n        return *this;\n    }\n    meta_builder& unsigned_flag(bool v) noexcept\n    {\n        if (v)\n            coldef_.flags |= detail::column_flags::unsigned_;\n        else\n            coldef_.flags &= ~detail::column_flags::unsigned_;\n        return *this;\n    }\n    meta_builder& nullable(bool v) noexcept\n    {\n        if (v)\n            coldef_.flags &= ~detail::column_flags::not_null;\n        else\n            coldef_.flags |= detail::column_flags::not_null;\n        return *this;\n    }\n    meta_builder& zerofill(bool v) noexcept\n    {\n        if (v)\n            coldef_.flags &= ~detail::column_flags::zerofill;\n        else\n            coldef_.flags |= detail::column_flags::zerofill;\n        return *this;\n    }\n    meta_builder& decimals(std::uint8_t v) noexcept\n    {\n        coldef_.decimals = v;\n        return *this;\n    }\n    metadata build() const { return detail::access::construct<metadata>(coldef_, true); }\n    detail::coldef_view build_coldef() const noexcept { return coldef_; }\n};\n\ninline metadata create_meta(column_type type) { return meta_builder().type(type).build(); }\ninline std::vector<metadata> create_metas(const std::vector<column_type>& types)\n{\n    std::vector<metadata> res;\n    res.reserve(types.size());\n    for (column_type t : types)\n        res.push_back(create_meta(t));\n    return res;\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_ok.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_OK_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_OK_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/flags.hpp>\n#include <boost/mysql/detail/ok_view.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass ok_builder\n{\n    detail::ok_view ok_{};\n\n    void flag(std::uint16_t f, bool value) noexcept\n    {\n        if (value)\n            ok_.status_flags |= f;\n        else\n            ok_.status_flags &= ~f;\n    }\n\npublic:\n    ok_builder() = default;\n    ok_builder& affected_rows(std::uint64_t v) noexcept\n    {\n        ok_.affected_rows = v;\n        return *this;\n    }\n    ok_builder& last_insert_id(std::uint64_t v) noexcept\n    {\n        ok_.last_insert_id = v;\n        return *this;\n    }\n    ok_builder& warnings(std::uint16_t v) noexcept\n    {\n        ok_.warnings = v;\n        return *this;\n    }\n    ok_builder& flags(std::uint16_t v) noexcept\n    {\n        ok_.status_flags = v;\n        return *this;\n    }\n    ok_builder& more_results(bool v) noexcept\n    {\n        flag(detail::status_flags::more_results, v);\n        return *this;\n    }\n    ok_builder& out_params(bool v) noexcept\n    {\n        flag(detail::status_flags::out_params, v);\n        return *this;\n    }\n    ok_builder& no_backslash_escapes(bool v) noexcept\n    {\n        flag(detail::status_flags::no_backslash_escapes, v);\n        return *this;\n    }\n    ok_builder& info(string_view v) noexcept\n    {\n        ok_.info = v;\n        return *this;\n    }\n    detail::ok_view build() const noexcept { return ok_; }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_ok_frame.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_OK_FRAME_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_OK_FRAME_HPP\n\n#include <boost/mysql/detail/ok_view.hpp>\n\n#include \"test_unit/create_frame.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstd::vector<std::uint8_t> serialize_ok_impl(const detail::ok_view& pack, std::uint8_t header);\n\ninline std::vector<std::uint8_t> create_ok_body(const detail::ok_view& ok)\n{\n    return serialize_ok_impl(ok, 0x00);\n}\n\ninline std::vector<std::uint8_t> create_eof_body(const detail::ok_view& ok)\n{\n    return serialize_ok_impl(ok, 0xfe);\n}\n\ninline std::vector<std::uint8_t> create_ok_frame(std::uint8_t seqnum, const detail::ok_view& ok)\n{\n    return create_frame(seqnum, create_ok_body(ok));\n}\n\ninline std::vector<std::uint8_t> create_eof_frame(std::uint8_t seqnum, const detail::ok_view& ok)\n{\n    return create_frame(seqnum, create_eof_body(ok));\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_prepare_statement_response.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_PREPARE_STATEMENT_RESPONSE_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_PREPARE_STATEMENT_RESPONSE_HPP\n\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass prepare_stmt_response_builder\n{\n    std::uint8_t seqnum_{};\n    std::uint32_t statement_id_{0};\n    std::uint16_t num_columns_{0};\n    std::uint16_t num_params_{0};\n\npublic:\n    prepare_stmt_response_builder() = default;\n\n    prepare_stmt_response_builder& seqnum(std::uint8_t v)\n    {\n        seqnum_ = v;\n        return *this;\n    }\n\n    prepare_stmt_response_builder& id(std::uint32_t v)\n    {\n        statement_id_ = v;\n        return *this;\n    }\n\n    prepare_stmt_response_builder& num_columns(std::uint16_t v)\n    {\n        num_columns_ = v;\n        return *this;\n    }\n\n    prepare_stmt_response_builder& num_params(std::uint16_t v)\n    {\n        num_params_ = v;\n        return *this;\n    }\n\n    std::vector<std::uint8_t> build() const;\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_query_frame.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_QUERY_FRAME_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_QUERY_FRAME_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <cstdint>\n#include <vector>\n\n#include \"test_unit/create_frame.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstd::vector<std::uint8_t> create_query_body_impl(std::uint8_t command_id, string_view sql);\n\ninline std::vector<std::uint8_t> create_query_frame(std::uint8_t seqnum, string_view sql)\n{\n    return create_frame(seqnum, create_query_body_impl(0x03, sql));\n}\n\ninline std::vector<std::uint8_t> create_prepare_statement_frame(std::uint8_t seqnum, string_view sql)\n{\n    return create_frame(seqnum, create_query_body_impl(0x16, sql));\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_row_message.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_ROW_MESSAGE_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_ROW_MESSAGE_HPP\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/create_frame.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstd::vector<std::uint8_t> serialize_text_row_impl(span<const field_view> fields);\n\ntemplate <class... Args>\nstd::vector<std::uint8_t> create_text_row_body(const Args&... args)\n{\n    return serialize_text_row_impl(make_fv_arr(args...));\n}\n\ntemplate <class... Args>\nstd::vector<std::uint8_t> create_text_row_message(std::uint8_t seqnum, const Args&... args)\n{\n    return create_frame(seqnum, create_text_row_body(args...));\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/create_statement.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_STATEMENT_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CREATE_STATEMENT_HPP\n\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass statement_builder\n{\n    std::uint32_t id_{};\n    std::uint16_t num_params_{};\n\npublic:\n    statement_builder() = default;\n    statement_builder& id(std::uint32_t v) noexcept\n    {\n        id_ = v;\n        return *this;\n    }\n    statement_builder& num_params(std::uint16_t v) noexcept\n    {\n        num_params_ = v;\n        return *this;\n    }\n    statement build() { return detail::access::construct<statement>(id_, num_params_); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/custom_allocator.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CUSTOM_ALLOCATOR_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_CUSTOM_ALLOCATOR_HPP\n\n#include <cstddef>\n#include <memory>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ntemplate <class T>\nstruct custom_allocator\n{\n    using value_type = T;\n\n    custom_allocator() noexcept {}\n\n    template <class U>\n    custom_allocator(const custom_allocator<U>&) noexcept\n    {\n    }\n\n    T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); }\n    void deallocate(T* p, std::size_t n) { return std::allocator<T>().deallocate(p, n); }\n};\n\ntemplate <class T>\nstruct custom_allocator_no_defctor : custom_allocator<T>\n{\n    custom_allocator_no_defctor(int) noexcept {}\n};\n\ntemplate <class T, class U>\nconstexpr bool operator==(const custom_allocator<T>&, const custom_allocator<U>&) noexcept\n{\n    return true;\n}\n\ntemplate <class T, class U>\nconstexpr bool operator!=(const custom_allocator<T>&, const custom_allocator<U>&) noexcept\n{\n    return false;\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/fail_count.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_FAIL_COUNT_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_FAIL_COUNT_HPP\n\n#include <boost/mysql/error_code.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Inspired by Beast's fail count\nclass fail_count\n{\n    std::size_t fail_after_;\n    std::size_t num_calls_{0};\n    error_code err_;\n\npublic:\n    static constexpr std::size_t never_fail = std::size_t(-1);\n    explicit fail_count(\n        std::size_t fail_after = never_fail,\n        error_code err = make_error_code(std::errc::io_error)\n    ) noexcept\n        : fail_after_(fail_after), err_(err)\n    {\n    }\n    error_code maybe_fail() noexcept { return num_calls_++ >= fail_after_ ? err_ : error_code(); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/ff_charset.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_FF_CHARSET_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_FF_CHARSET_HPP\n\n#include <boost/mysql/character_set.hpp>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// A hypothetical character set with rules that may confuse formatting algorithms.\n// Some MySQL charsets (e.g. gbk) contain ASCII-compatible continuation characters, like this one.\ninline std::size_t ff_charset_next_char(boost::span<const unsigned char> r)\n{\n    if (r[0] == 0xff)  // 0xff marks a two-byte character\n        return r.size() > 1u ? 2u : 0u;\n    return 1u;\n};\nconstexpr character_set ff_charset{\"ff_charset\", ff_charset_next_char};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/mock_execution_processor.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_MOCK_EXECUTION_PROCESSOR_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_MOCK_EXECUTION_PROCESSOR_HPP\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n\n#include <boost/config.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n\n#include \"test_unit/fail_count.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass mock_execution_processor : public detail::execution_processor\n{\n    struct num_calls_t\n    {\n        std::size_t reset{};\n        std::size_t on_num_meta{};\n        std::size_t on_meta{};\n        std::size_t on_head_ok_packet{};\n        std::size_t on_row_batch_start{};\n        std::size_t on_row_batch_finish{};\n        std::size_t on_row{};\n        std::size_t on_row_ok_packet{};\n    };\n\npublic:\n    // Validate the number of calls safely\n    class num_calls_validator\n    {\n        num_calls_t expected_{};\n        num_calls_t actual_{};\n\n    public:\n        num_calls_validator(num_calls_t actual) noexcept : actual_(actual) {}\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& reset(std::size_t v) noexcept\n        {\n            expected_.reset = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_num_meta(std::size_t v) noexcept\n        {\n            expected_.on_num_meta = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_meta(std::size_t v) noexcept\n        {\n            expected_.on_meta = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_head_ok_packet(std::size_t v) noexcept\n        {\n            expected_.on_head_ok_packet = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_row_batch_start(std::size_t v) noexcept\n        {\n            expected_.on_row_batch_start = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_row_batch_finish(std::size_t v) noexcept\n        {\n            expected_.on_row_batch_finish = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_row(std::size_t v) noexcept\n        {\n            expected_.on_row = v;\n            return *this;\n        }\n\n        BOOST_ATTRIBUTE_NODISCARD\n        num_calls_validator& on_row_ok_packet(std::size_t v) noexcept\n        {\n            expected_.on_row_ok_packet = v;\n            return *this;\n        }\n\n        void validate()\n        {\n            BOOST_TEST(expected_.reset == actual_.reset);\n            BOOST_TEST(expected_.on_num_meta == actual_.on_num_meta);\n            BOOST_TEST(expected_.on_meta == actual_.on_meta);\n            BOOST_TEST(expected_.on_head_ok_packet == actual_.on_head_ok_packet);\n            BOOST_TEST(expected_.on_row_batch_start == actual_.on_row_batch_start);\n            BOOST_TEST(expected_.on_row_batch_finish == actual_.on_row_batch_finish);\n            BOOST_TEST(expected_.on_row == actual_.on_row);\n            BOOST_TEST(expected_.on_row_ok_packet == actual_.on_row_ok_packet);\n        }\n    };\n\n    mock_execution_processor() = default;\n    std::uint64_t affected_rows() const noexcept { return ok_packet_.affected_rows; }\n    std::uint64_t last_insert_id() const noexcept { return ok_packet_.last_insert_id; }\n    string_view info() const noexcept { return ok_packet_.info; }\n    std::size_t num_meta() const noexcept { return num_meta_; }\n    const std::vector<metadata>& meta() const noexcept { return meta_; }\n    const std::vector<detail::output_ref>& refs() const noexcept { return refs_; }\n\n    BOOST_ATTRIBUTE_NODISCARD\n    num_calls_validator num_calls() noexcept { return num_calls_validator(num_calls_); }\n\n    void set_fail_count(fail_count fc, diagnostics diag = diagnostics())\n    {\n        fc_ = fc;\n        diag_ = std::move(diag);\n    }\n\nprivate:\n    // Data\n    num_calls_t num_calls_;\n    struct\n    {\n        std::uint64_t affected_rows{};\n        std::uint64_t last_insert_id{};\n        std::string info;\n    } ok_packet_{};\n    std::size_t num_meta_{};\n    std::vector<metadata> meta_;\n    std::vector<detail::output_ref> refs_;\n    fail_count fc_;\n    diagnostics diag_;\n\n    // Helpers\n    error_code maybe_fail(diagnostics& diag)\n    {\n        auto err = fc_.maybe_fail();\n        if (err)\n        {\n            diag = diag_;\n        }\n        return err;\n    }\n\n    void handle_ok(const detail::ok_view& pack)\n    {\n        ok_packet_.affected_rows = pack.affected_rows;\n        ok_packet_.last_insert_id = pack.last_insert_id;\n        ok_packet_.info = pack.info;\n    }\n\nprotected:\n    void reset_impl() noexcept override { ++num_calls_.reset; }\n    error_code on_head_ok_packet_impl(const detail::ok_view& pack, diagnostics& diag) override\n    {\n        ++num_calls_.on_head_ok_packet;\n        handle_ok(pack);\n        return maybe_fail(diag);\n    }\n    void on_num_meta_impl(std::size_t num_meta) override\n    {\n        ++num_calls_.on_num_meta;\n        num_meta_ = num_meta;\n    }\n    error_code on_meta_impl(const detail::coldef_view& coldef, bool is_last, diagnostics& diag) override\n    {\n        ++num_calls_.on_meta;\n        meta_.push_back(detail::access::construct<metadata>(coldef, true));\n        return is_last ? maybe_fail(diag) : error_code();\n    }\n    void on_row_batch_start_impl() override { ++num_calls_.on_row_batch_start; }\n    void on_row_batch_finish_impl() override { ++num_calls_.on_row_batch_finish; }\n    error_code on_row_impl(span<const std::uint8_t>, const detail::output_ref& ref, std::vector<field_view>&)\n        override\n    {\n        ++num_calls_.on_row;\n        refs_.push_back(ref);\n        return fc_.maybe_fail();\n    }\n    error_code on_row_ok_packet_impl(const detail::ok_view& pack) override\n    {\n        ++num_calls_.on_row_ok_packet;\n        handle_ok(pack);\n        return fc_.maybe_fail();\n    }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/mock_message.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_MOCK_MESSAGE_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_MOCK_MESSAGE_HPP\n\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstdint>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct mock_message\n{\n    span<const std::uint8_t> data;\n\n    void serialize(detail::serialization_context& ctx) const { ctx.add(data); }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/mock_timer.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_MOCK_TIMER_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_MOCK_TIMER_HPP\n\n#include <boost/asio/basic_waitable_timer.hpp>\n#include <boost/asio/wait_traits.hpp>\n\n#include <chrono>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Like steady_clock, but the current time can be set within tests\nstruct mock_clock\n{\n    using rep = typename std::chrono::steady_clock::rep;\n    using period = typename std::chrono::steady_clock::period;\n    using duration = typename std::chrono::steady_clock::duration;\n    using time_point = typename std::chrono::steady_clock::time_point;\n    static constexpr bool is_steady = true;\n    static time_point now();\n    static void advance_time_by(std::chrono::steady_clock::duration dur);\n};\n\n// Helper typedef\nusing mock_timer = asio::basic_waitable_timer<mysql::test::mock_clock>;\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\nnamespace boost {\nnamespace asio {\n\n// Specialization suitable to use for tests. Instructs Asio to\n// create physical timers that wait for a zero duration, effectively\n// causing Asio's timer service to poll for ready handlers\ntemplate <>\nstruct wait_traits<mysql::test::mock_clock>\n{\n    static std::chrono::steady_clock::duration to_wait_duration(std::chrono::steady_clock::duration)\n    {\n        return std::chrono::nanoseconds(0);\n    }\n\n    static std::chrono::steady_clock::duration to_wait_duration(std::chrono::steady_clock::time_point)\n    {\n        return std::chrono::nanoseconds(0);\n    }\n};\n\n}  // namespace asio\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/printing.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_PRINTING_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_PRINTING_HPP\n\n#include <cstdint>\n#include <iosfwd>\n\nnamespace boost {\nnamespace mysql {\n\n// address_type\nenum class address_type;\nstd::ostream& operator<<(std::ostream& os, address_type value);\n\nnamespace detail {\n\n// capabilities\nenum class capabilities : std::uint32_t;\nstd::ostream& operator<<(std::ostream& os, capabilities caps);\n\n// db_flavor\nenum class db_flavor;\nstd::ostream& operator<<(std::ostream& os, db_flavor value);\n\n// resultset_encoding\nenum class resultset_encoding;\nstd::ostream& operator<<(std::ostream& os, resultset_encoding t);\n\n// connection_status\nenum class connection_status;\nstd::ostream& operator<<(std::ostream& os, connection_status t);\n\n// results_iterator\nclass results_iterator;\nstd::ostream& operator<<(std::ostream& os, const results_iterator& it);\n\n// next_action_type\nenum class next_action_type;\nstd::ostream& operator<<(std::ostream& os, next_action_type t);\n\n// pipeline_stage_kind\nenum class pipeline_stage_kind;\nstd::ostream& operator<<(std::ostream& os, pipeline_stage_kind v);\n\n// pipeline_request_stage\nstruct pipeline_request_stage;\nbool operator==(const pipeline_request_stage& lhs, const pipeline_request_stage& rhs);\nstd::ostream& operator<<(std::ostream& os, pipeline_request_stage v);\n\n// node_status (pool)\nenum class node_status;\nstd::ostream& operator<<(std::ostream& os, node_status v);\n\n// collection_state (pool)\nenum class collection_state;\nstd::ostream& operator<<(std::ostream& os, collection_state v);\n\n// next_connection_action (pool)\nenum class next_connection_action;\nstd::ostream& operator<<(std::ostream& os, next_connection_action v);\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/row_identity.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_ROW_IDENTITY_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_ROW_IDENTITY_HPP\n\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n// A StaticRow type, for testing purposes, that inherits all row traits from the passed type.\n// Used to verify that we correctly use underlying_row to go from marker types to row types.\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Marker type\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nstruct row_identity;\n\n}  // namespace test\n\nnamespace detail {\n\n// row traits\ntemplate <BOOST_MYSQL_STATIC_ROW StaticRow>\nclass row_traits<test::row_identity<StaticRow>, false> : public row_traits<StaticRow>\n{\n};\n\n}  // namespace detail\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/serialize_to_vector.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_SERIALIZE_TO_VECTOR_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_SERIALIZE_TO_VECTOR_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <vector>\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\ntemplate <class Fn>\nstd::vector<std::uint8_t> serialize_to_vector(const Fn& serialize_fn)\n{\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, static_cast<std::size_t>(-1), detail::disable_framing);\n    serialize_fn(ctx);\n    BOOST_TEST(ctx.error() == error_code());\n    return buff;\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/test_any_connection.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_TEST_ANY_CONNECTION_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_TEST_ANY_CONNECTION_HPP\n\n#include <boost/mysql/any_connection.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <boost/asio/io_context.hpp>\n\n#include \"test_unit/test_stream.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nany_connection create_test_any_connection(\n    asio::io_context& ctx,\n    any_connection_params params = {},\n    detail::connection_status initial_status = detail::connection_status::ready\n);\ntest_stream& get_stream(any_connection& conn);\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/include/test_unit/test_stream.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_TEST_STREAM_HPP\n#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_TEST_STREAM_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/asio/any_completion_handler.hpp>\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/buffer.hpp>\n#include <boost/core/span.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <set>\n#include <vector>\n\n#include \"test_unit/fail_count.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nclass test_stream\n{\npublic:\n    test_stream(asio::any_io_executor ex) : ex_(std::move(ex)) {}\n\n    // Support the layered stream model\n    using lowest_layer_type = test_stream;\n    lowest_layer_type& lowest_layer() noexcept { return *this; }\n    const lowest_layer_type& lowest_layer() const noexcept { return *this; }\n\n    // Setters\n    test_stream& add_bytes(const std::vector<std::uint8_t>& bytes)\n    {\n        return add_bytes(span<const std::uint8_t>(bytes));\n    }\n    test_stream& add_bytes(span<const std::uint8_t> bytes);\n    test_stream& add_break(std::size_t byte_num);\n    test_stream& add_break() { return add_break(bytes_to_read_.size()); }\n    test_stream& set_write_break_size(std::size_t size) noexcept\n    {\n        write_break_size_ = size;\n        return *this;\n    }\n    test_stream& set_fail_count(const fail_count& fc) noexcept\n    {\n        fail_count_ = fc;\n        return *this;\n    }\n\n    // Getting test results\n    std::size_t num_bytes_read() const noexcept { return num_bytes_read_; }\n    std::size_t num_unread_bytes() const noexcept { return bytes_to_read_.size() - num_bytes_read_; }\n    const std::vector<std::uint8_t>& bytes_written() const noexcept { return bytes_written_; }\n\n    // Executor\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return ex_; }\n\n    // Reading\n    std::size_t read_some(asio::mutable_buffer, error_code& ec);\n    void async_read_some(asio::mutable_buffer, asio::any_completion_handler<void(error_code, std::size_t)>);\n\n    // Writing\n    std::size_t write_some(asio::const_buffer, error_code& ec);\n    void async_write_some(asio::const_buffer, asio::any_completion_handler<void(error_code, std::size_t)>);\n\nprivate:\n    std::vector<std::uint8_t> bytes_to_read_;\n    std::set<std::size_t> read_break_offsets_;\n    std::size_t num_bytes_read_{0};\n    std::vector<std::uint8_t> bytes_written_;\n    fail_count fail_count_;\n    std::size_t write_break_size_{1024};  // max number of bytes to be written in each write_some\n    asio::any_io_executor ex_;\n\n    std::size_t get_size_to_read(std::size_t buffer_size) const;\n    std::size_t do_read(asio::mutable_buffer buff, error_code& ec);\n    std::size_t do_write(asio::const_buffer buff, error_code& ec);\n\n    struct read_op;\n    struct write_op;\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif"
  },
  {
    "path": "test/unit/pch.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_PCH_HPP\n#define BOOST_MYSQL_TEST_UNIT_PCH_HPP\n\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/assert.hpp>\n#include <boost/config.hpp>\n#include <boost/core/detail/string_view.hpp>\n#include <boost/core/span.hpp>\n#include <boost/endian/conversion.hpp>\n#include <boost/mp11.hpp>\n#include <boost/system/error_category.hpp>\n#include <boost/system/error_code.hpp>\n#include <boost/system/result.hpp>\n#include <boost/system/system_error.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/throw_exception.hpp>\n#include <boost/variant2/variant.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <cstdint>\n#include <cstdlib>\n#include <cstring>\n#include <functional>\n#include <iterator>\n#include <ostream>\n#include <stdexcept>\n#include <string>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#endif\n"
  },
  {
    "path": "test/unit/src/utils.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/engine_impl.hpp>\n#include <boost/mysql/detail/engine_stream_adaptor.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n#include <boost/mysql/detail/results_iterator.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp>\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n#include <boost/mysql/impl/internal/protocol/frame_header.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <boost/asio/buffer.hpp>\n#include <boost/asio/compose.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/post.hpp>\n\n#include <algorithm>\n#include <array>\n#include <chrono>\n#include <cstdint>\n#include <cstring>\n#include <ostream>\n#include <utility>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_prepare_statement_response.hpp\"\n#include \"test_unit/create_query_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/mock_timer.hpp\"\n#include \"test_unit/printing.hpp\"\n#include \"test_unit/serialize_to_vector.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n#include \"test_unit/test_stream.hpp\"\n\nusing std::chrono::steady_clock;\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\n//\n// algo_test.hpp\n//\nvoid boost::mysql::test::algo_test::handle_read(detail::connection_state_data& st, const step_t& op)\n{\n    if (!op.result)\n    {\n        std::size_t bytes_transferred = 0;\n        while (!st.reader.done() && bytes_transferred < op.bytes.size())\n        {\n            auto ec = st.reader.prepare_buffer();\n            BOOST_TEST_REQUIRE(ec == error_code());\n            auto buff = st.reader.buffer();\n            std::size_t size_to_copy = (std::min)(op.bytes.size() - bytes_transferred, buff.size());\n            std::memcpy(buff.data(), op.bytes.data() + bytes_transferred, size_to_copy);\n            bytes_transferred += size_to_copy;\n            st.reader.resume(size_to_copy);\n        }\n        BOOST_TEST_REQUIRE(st.reader.done());\n        BOOST_TEST_REQUIRE(st.reader.error() == error_code());\n    }\n}\n\ndetail::next_action boost::mysql::test::algo_test::run_algo_until_step(\n    any_algo_ref algo,\n    detail::connection_state_data& st,\n    diagnostics& diag,\n    std::size_t num_steps_to_run\n) const\n{\n    BOOST_ASSERT(num_steps_to_run <= num_steps());\n\n    // Start the op\n    auto act = algo.resume(st, diag, error_code());\n\n    // Go through the requested steps\n    for (std::size_t i = 0; i < num_steps_to_run; ++i)\n    {\n        BOOST_TEST_CONTEXT(\"Step \" << i << \", error_code=\" << (act.is_done() ? act.error() : error_code()))\n        {\n            const auto& step = steps_[i];\n            BOOST_TEST_REQUIRE(act.type() == step.type);\n            if (step.type == detail::next_action_type::read)\n                handle_read(st, step);\n            else if (step.type == detail::next_action_type::write)\n            {\n                if (step.check)\n                    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(act.write_args().buffer, step.bytes);\n            }\n            // Other actions don't need any handling\n\n            act = algo.resume(st, diag, step.result);\n        }\n    }\n\n    return act;\n}\n\nboost::mysql::test::algo_test& boost::mysql::test::algo_test::add_step(\n    detail::next_action_type act_type,\n    std::vector<std::uint8_t> bytes,\n    error_code ec,\n    bool check\n)\n{\n    steps_.push_back(step_t{act_type, std::move(bytes), ec, check});\n    return *this;\n}\n\n// Utility to implement state tracking\nclass boost::mysql::test::algo_test::state_checker\n{\n    // The tracked state\n    detail::connection_state_data& st_;\n\n    // The values we expect to get after running the algorithm.\n    // If a change is not in expected_state_changes_t, the value shouldn't change\n    detail::connection_status expected_status;\n    detail::db_flavor expected_flavor;\n    detail::capabilities expected_capabilities;\n    std::uint32_t expected_connection_id;\n    metadata_mode expected_meta_mode;\n    bool expected_tls_supported;\n    bool expected_tls_active;\n    bool expected_backslash_escapes;\n    character_set expected_charset;\n\npublic:\n    state_checker(detail::connection_state_data& st, const expected_state_changes_t& changes) noexcept\n        : st_(st),\n          expected_status(changes.status.value_or(st.status)),\n          expected_flavor(changes.flavor.value_or(st.flavor)),\n          expected_capabilities(changes.current_capabilities.value_or(st.current_capabilities)),\n          expected_connection_id(changes.connection_id.value_or(st.connection_id)),\n          expected_meta_mode(st.meta_mode),  // no algorithm should modify this\n          expected_tls_supported(changes.tls_active.value_or(st.tls_supported)),\n          expected_tls_active(changes.tls_active.value_or(st.tls_active)),\n          expected_backslash_escapes(changes.backslash_escapes.value_or(st.backslash_escapes)),\n          expected_charset(changes.current_charset.value_or(st.current_charset))\n    {\n    }\n\n    void check() const\n    {\n        BOOST_TEST(st_.status == expected_status);\n        BOOST_TEST(st_.flavor == expected_flavor);\n        BOOST_TEST(st_.current_capabilities == expected_capabilities);\n        BOOST_TEST(st_.connection_id == expected_connection_id);\n        BOOST_TEST(st_.meta_mode == expected_meta_mode);\n        BOOST_TEST(st_.tls_supported == expected_tls_supported);\n        BOOST_TEST(st_.tls_active == expected_tls_active);\n        BOOST_TEST(st_.backslash_escapes == expected_backslash_escapes);\n        BOOST_TEST(st_.current_charset == expected_charset);\n        BOOST_TEST(!st_.op_in_progress);  // No algorithm should modify this\n    }\n};\n\nvoid boost::mysql::test::algo_test::check_network_errors_impl(\n    any_algo_ref algo,\n    detail::connection_state_data& st,\n    std::size_t step_number,\n    source_location loc\n) const\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc << \" at step \" << step_number)\n    {\n        BOOST_ASSERT(step_number < num_steps());\n\n        // Record the current state, to check that what we changed was on purpose\n        state_checker checker(st, state_changes_);\n\n        // Run all the steps that shouldn't cause an error\n        diagnostics diag;  // Clearing diagnostics is not the algo's responsibility\n        auto act = run_algo_until_step(algo, st, diag, step_number);\n        BOOST_TEST_REQUIRE(act.type() == steps_[step_number].type);\n\n        // Trigger an error in the requested step\n        act = algo.resume(st, diag, asio::error::bad_descriptor);\n\n        // The operation finished and returned the network error\n        BOOST_TEST_REQUIRE(act.type() == detail::next_action_type::none);\n        BOOST_TEST(act.error() == error_code(asio::error::bad_descriptor));\n        BOOST_TEST(diag == diagnostics());\n\n        // Check state changes\n        checker.check();\n    }\n}\n\nvoid boost::mysql::test::algo_test::check_impl(\n    any_algo_ref algo,\n    detail::connection_state_data& st,\n    error_code expected_ec,\n    const diagnostics& expected_diag,\n    source_location loc\n) const\n{\n    BOOST_TEST_CONTEXT(\"Called from \" << loc)\n    {\n        // Record the current state, to check that what we changed was on purpose\n        state_checker checker(st, state_changes_);\n\n        // Run the op until completion\n        diagnostics diag;  // Clearing diagnostics is not the algo's responsibility\n        auto act = run_algo_until_step(algo, st, diag, steps_.size());\n\n        // Check that we've finished\n        BOOST_TEST_REQUIRE(act.type() == detail::next_action_type::none);\n\n        // Check results\n        BOOST_TEST(act.error() == expected_ec);\n        BOOST_TEST(diag == expected_diag);\n\n        // Check state changes\n        checker.check();\n    }\n}\n\n//\n// create_frame.hpp\n//\nstd::vector<std::uint8_t> boost::mysql::test::create_frame(std::uint8_t seqnum, span<const std::uint8_t> body)\n{\n    BOOST_ASSERT(body.size() <= 0xffffff);  // it should fit in a single frame\n\n    // Compose the frame header\n    std::array<std::uint8_t, detail::frame_header_size> frame_header{};\n    detail::serialize_frame_header(\n        frame_header,\n        detail::frame_header{static_cast<std::uint32_t>(body.size()), seqnum}\n    );\n\n    // Compose the frame.\n    // Inserting the header separately (instead of using the range constructor)\n    // avoids spurious gcc warnings\n    std::vector<std::uint8_t> res;\n    res.insert(res.end(), frame_header.begin(), frame_header.end());\n    res.insert(res.end(), body.begin(), body.end());\n    return res;\n}\n\n//\n// create_ok_frame.hpp\n//\nstd::vector<std::uint8_t> boost::mysql::test::serialize_ok_impl(\n    const detail::ok_view& pack,\n    std::uint8_t header\n)\n{\n    return serialize_to_vector([=](detail::serialization_context& ctx) {\n        ctx.serialize(\n            detail::int1{header},\n            detail::int_lenenc{pack.affected_rows},\n            detail::int_lenenc{pack.last_insert_id},\n            detail::int2{pack.status_flags},\n            detail::int2{pack.warnings}\n        );\n        // When info is empty, it's actually omitted in the ok_packet\n        if (!pack.info.empty())\n        {\n            detail::string_lenenc{pack.info}.serialize(ctx);\n        }\n    });\n}\n\n//\n// create_coldef_frame.hpp\n//\nstd::vector<std::uint8_t> boost::mysql::test::create_coldef_body(const detail::coldef_view& pack)\n{\n    auto to_protocol_type = [](column_type t) {\n        // Note: we perform an approximate mapping, good enough for unit tests.\n        // The actual mapping is not one to one and depends on flags\n        using detail::protocol_field_type;\n        switch (t)\n        {\n        case column_type::tinyint: return protocol_field_type::tiny;\n        case column_type::smallint: return protocol_field_type::short_;\n        case column_type::mediumint: return protocol_field_type::int24;\n        case column_type::int_: return protocol_field_type::long_;\n        case column_type::bigint: return protocol_field_type::longlong;\n        case column_type::float_: return protocol_field_type::float_;\n        case column_type::double_: return protocol_field_type::double_;\n        case column_type::decimal: return protocol_field_type::newdecimal;\n        case column_type::bit: return protocol_field_type::bit;\n        case column_type::year: return protocol_field_type::year;\n        case column_type::time: return protocol_field_type::time;\n        case column_type::date: return protocol_field_type::date;\n        case column_type::datetime: return protocol_field_type::datetime;\n        case column_type::timestamp: return protocol_field_type::timestamp;\n        case column_type::char_: return protocol_field_type::string;\n        case column_type::varchar: return protocol_field_type::var_string;\n        case column_type::binary: return protocol_field_type::string;\n        case column_type::varbinary: return protocol_field_type::var_string;\n        case column_type::text: return protocol_field_type::blob;\n        case column_type::blob: return protocol_field_type::blob;\n        case column_type::enum_: return protocol_field_type::enum_;\n        case column_type::set: return protocol_field_type::set;\n        case column_type::json: return protocol_field_type::json;\n        case column_type::geometry: return protocol_field_type::geometry;\n        default: BOOST_ASSERT(false); return protocol_field_type::var_string;  // LCOV_EXCL_LINE\n        }\n    };\n\n    return serialize_to_vector([=](detail::serialization_context& ctx) {\n        ctx.serialize(\n            detail::string_lenenc{\"def\"},\n            detail::string_lenenc{pack.database},\n            detail::string_lenenc{pack.table},\n            detail::string_lenenc{pack.org_table},\n            detail::string_lenenc{pack.name},\n            detail::string_lenenc{pack.org_name},\n            detail::int_lenenc{0x0c},  // length of fixed fields\n            detail::int2{pack.collation_id},\n            detail::int4{pack.column_length},\n            detail::int1{static_cast<std::uint8_t>(to_protocol_type(pack.type))},\n            detail::int2{pack.flags},\n            detail::int1{pack.decimals},\n            detail::int2{0}  // padding\n        );\n    });\n}\n\n//\n// create_err.hpp\n//\nstd::vector<std::uint8_t> boost::mysql::test::serialize_err_impl(detail::err_view pack, bool with_header)\n{\n    return serialize_to_vector([=](detail::serialization_context& ctx) {\n        if (with_header)\n            ctx.add(0xff);  // header\n        ctx.serialize(\n            detail::int2{pack.error_code},\n            detail::string_fixed<1>{},  // SQL state marker\n            detail::string_fixed<5>{},  // SQL state\n            detail::string_eof{pack.error_message}\n        );\n    });\n}\n\n//\n// create_prepare_statement_response.hpp\n//\nstd::vector<std::uint8_t> boost::mysql::test::prepare_stmt_response_builder::build() const\n{\n    auto body = serialize_to_vector([this](detail::serialization_context& ctx) {\n        ctx.serialize(\n            detail::int1{0u},             // OK header\n            detail::int4{statement_id_},  // statement_id\n            detail::int2{num_columns_},   // num columns\n            detail::int2{num_params_},    // num_params\n            detail::int1{0u},             // reserved\n            detail::int2{90u}             // warning_count\n        );\n    });\n    return create_frame(seqnum_, body);\n}\n\n//\n// create_query_frame\n//\nstd::vector<std::uint8_t> boost::mysql::test::create_query_body_impl(std::uint8_t command_id, string_view sql)\n{\n    return serialize_to_vector([=](detail::serialization_context& ctx) {\n        ctx.add(command_id);\n        ctx.add(detail::to_span(sql));\n    });\n}\n\n//\n// create_row_message.hpp\n//\nstd::vector<std::uint8_t> boost::mysql::test::serialize_text_row_impl(span<const field_view> fields)\n{\n    return serialize_to_vector([=](detail::serialization_context& ctx) {\n        for (field_view f : fields)\n        {\n            std::string s;\n            switch (f.kind())\n            {\n            case field_kind::int64: s = std::to_string(f.get_int64()); break;\n            case field_kind::uint64: s = std::to_string(f.get_uint64()); break;\n            case field_kind::float_: s = std::to_string(f.get_float()); break;\n            case field_kind::double_: s = std::to_string(f.get_double()); break;\n            case field_kind::string: s = f.get_string(); break;\n            case field_kind::blob: s.assign(f.get_blob().begin(), f.get_blob().end()); break;\n            case field_kind::null: ctx.add(std::uint8_t(0xfb)); continue;\n            default: throw std::runtime_error(\"create_text_row_message: type not implemented\");\n            }\n            detail::string_lenenc{s}.serialize(ctx);\n        }\n    });\n}\n\n//\n// mock_timer.hpp\n//\n// The current time\nstatic thread_local steady_clock::time_point g_mock_now{};\n\nboost::mysql::test::mock_clock::time_point boost::mysql::test::mock_clock::now() { return g_mock_now; }\n\nvoid boost::mysql::test::mock_clock::advance_time_by(steady_clock::duration dur) { g_mock_now += dur; }\n\n//\n// test_stream.hpp\n//\n\nstd::size_t boost::mysql::test::test_stream::get_size_to_read(std::size_t buffer_size) const\n{\n    auto it = read_break_offsets_.upper_bound(num_bytes_read_);\n    std::size_t max_bytes_by_break = it == read_break_offsets_.end() ? std::size_t(-1)\n                                                                     : *it - num_bytes_read_;\n    return (std::min)({num_unread_bytes(), buffer_size, max_bytes_by_break});\n}\n\nstd::size_t boost::mysql::test::test_stream::do_read(asio::mutable_buffer buff, error_code& ec)\n{\n    // Fail count\n    error_code err = fail_count_.maybe_fail();\n    if (err)\n    {\n        ec = err;\n        return 0;\n    }\n\n    // If the user requested some bytes but we don't have any,\n    // fail. In the real world, the stream would block until more\n    // bytes are received, but this is a test, and this condition\n    // indicates an error.\n    if (num_unread_bytes() == 0 && buff.size() != 0)\n    {\n        ec = boost::asio::error::eof;\n        return 0;\n    }\n\n    // Actually read\n    std::size_t bytes_to_transfer = get_size_to_read(buff.size());\n    if (bytes_to_transfer)\n    {\n        std::memcpy(buff.data(), bytes_to_read_.data() + num_bytes_read_, bytes_to_transfer);\n        num_bytes_read_ += bytes_to_transfer;\n    }\n\n    // Clear errors\n    ec = error_code();\n\n    return bytes_to_transfer;\n}\n\nstd::size_t boost::mysql::test::test_stream::do_write(asio::const_buffer buff, error_code& ec)\n{\n    // Fail count\n    error_code err = fail_count_.maybe_fail();\n    if (err)\n    {\n        ec = err;\n        return 0;\n    }\n\n    // Actually write\n    std::size_t num_bytes_to_transfer = (std::min)(buff.size(), write_break_size_);\n    span<const std::uint8_t> span_to_transfer(\n        static_cast<const std::uint8_t*>(buff.data()),\n        num_bytes_to_transfer\n    );\n    bytes_written_.insert(bytes_written_.end(), span_to_transfer.begin(), span_to_transfer.end());\n\n    // Clear errors\n    ec = error_code();\n\n    return num_bytes_to_transfer;\n}\n\nstruct boost::mysql::test::test_stream::read_op\n{\n    test_stream& stream_;\n    asio::mutable_buffer buff_;\n    bool has_posted_{};\n\n    read_op(test_stream& stream, asio::mutable_buffer buff) noexcept : stream_(stream), buff_(buff) {};\n\n    template <class Self>\n    void operator()(Self& self)\n    {\n        if (!has_posted_)\n        {\n            // Post\n            has_posted_ = true;\n            asio::post(stream_.get_executor(), std::move(self));\n        }\n        else\n        {\n            // Complete\n            error_code err;\n            std::size_t bytes_read = stream_.do_read(buff_, err);\n            self.complete(err, bytes_read);\n        }\n    }\n};\n\nstruct boost::mysql::test::test_stream::write_op\n{\n    test_stream& stream_;\n    asio::const_buffer buff_;\n    bool has_posted_{};\n\n    write_op(test_stream& stream, asio::const_buffer buff) noexcept : stream_(stream), buff_(buff) {};\n\n    template <class Self>\n    void operator()(Self& self)\n    {\n        // Post\n        if (!has_posted_)\n        {\n            has_posted_ = true;\n            asio::post(stream_.get_executor(), std::move(self));\n        }\n        else\n        {\n            error_code err;\n            std::size_t bytes_written = stream_.do_write(buff_, err);\n            self.complete(err, bytes_written);\n        }\n    }\n};\n\nstd::size_t boost::mysql::test::test_stream::read_some(asio::mutable_buffer buff, error_code& ec)\n{\n    return do_read(buff, ec);\n}\nvoid boost::mysql::test::test_stream::async_read_some(\n    asio::mutable_buffer buff,\n    asio::any_completion_handler<void(error_code, std::size_t)> handler\n)\n{\n    asio::async_compose<\n        asio::any_completion_handler<void(error_code, std::size_t)>,\n        void(error_code, std::size_t)>(read_op(*this, buff), handler, get_executor());\n}\n\nstd::size_t boost::mysql::test::test_stream::write_some(boost::asio::const_buffer buff, error_code& ec)\n{\n    return do_write(buff, ec);\n}\n\nvoid boost::mysql::test::test_stream::async_write_some(\n    asio::const_buffer buff,\n    asio::any_completion_handler<void(error_code, std::size_t)> handler\n)\n{\n    asio::async_compose<\n        asio::any_completion_handler<void(error_code, std::size_t)>,\n        void(error_code, std::size_t)>(write_op(*this, buff), handler, get_executor());\n}\n\ntest_stream& boost::mysql::test::test_stream::add_bytes(span<const std::uint8_t> bytes)\n{\n    bytes_to_read_.insert(bytes_to_read_.end(), bytes.begin(), bytes.end());\n    return *this;\n}\n\ntest_stream& boost::mysql::test::test_stream::add_break(std::size_t byte_num)\n{\n    BOOST_ASSERT(byte_num <= bytes_to_read_.size());\n    read_break_offsets_.insert(byte_num);\n    return *this;\n}\n\n//\n// printing.hpp\n//\n\n// address_type\nstatic const char* to_string(address_type v)\n{\n    switch (v)\n    {\n    case address_type::host_and_port: return \"address_type::host_and_port\";\n    case address_type::unix_path: return \"address_type::unix_path\";\n    default: return \"<unknown address_type>\";\n    }\n}\n\nstd::ostream& boost::mysql::operator<<(std::ostream& os, address_type v) { return os << ::to_string(v); }\n\n// capabilities\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, capabilities v)\n{\n    return os << \"capabilities{\" << static_cast<std::uint32_t>(v) << \"}\";\n}\n\n// db_flavor\nstatic const char* to_string(detail::db_flavor v)\n{\n    switch (v)\n    {\n    case detail::db_flavor::mysql: return \"db_flavor::mysql\";\n    case detail::db_flavor::mariadb: return \"db_flavor::mariadb\";\n    default: return \"<unknown db_flavor>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, db_flavor v) { return os << ::to_string(v); }\n\n// resultset_encoding\nstatic const char* to_string(detail::resultset_encoding v)\n{\n    switch (v)\n    {\n    case detail::resultset_encoding::text: return \"resultset_encoding::text\";\n    case detail::resultset_encoding::binary: return \"resultset_encoding::binary\";\n    default: return \"<unknown resultset_encoding>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, detail::resultset_encoding v)\n{\n    return os << ::to_string(v);\n}\n\n// connection_status\nstatic const char* to_string(detail::connection_status v)\n{\n    switch (v)\n    {\n    case detail::connection_status::ready: return \"connection_status::ready\";\n    case detail::connection_status::not_connected: return \"connection_status::not_connected\";\n    case detail::connection_status::engaged_in_multi_function:\n        return \"connection_status::engaged_in_multi_function\";\n    default: return \"<unknown connection_status>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, detail::connection_status v)\n{\n    return os << ::to_string(v);\n}\n\n// results_iterator\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, const results_iterator& it)\n{\n    return os << \"results_iterator{ .self = \" << static_cast<const void*>(it.obj())\n              << \", .index = \" << it.index() << \"}\";\n}\n\n// next_action_type;\nstatic const char* to_string(detail::next_action_type v)\n{\n    switch (v)\n    {\n    case detail::next_action_type::none: return \"next_action_type::none\";\n    case detail::next_action_type::read: return \"next_action_type::read\";\n    case detail::next_action_type::write: return \"next_action_type::write\";\n    case detail::next_action_type::ssl_handshake: return \"next_action_type::ssl_handshake\";\n    case detail::next_action_type::ssl_shutdown: return \"next_action_type::ssh_shutdown\";\n    default: return \"<unknown next_action_type>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, next_action_type v)\n{\n    return os << ::to_string(v);\n}\n\n// pipeline_stage_kind\nstatic const char* to_string(detail::pipeline_stage_kind v)\n{\n    switch (v)\n    {\n    case detail::pipeline_stage_kind::execute: return \"pipeline_stage_kind::execute\";\n    case detail::pipeline_stage_kind::prepare_statement: return \"pipeline_stage_kind::prepare_statement\";\n    case detail::pipeline_stage_kind::close_statement: return \"pipeline_stage_kind::close_statement\";\n    case detail::pipeline_stage_kind::reset_connection: return \"pipeline_stage_kind::reset_connection\";\n    case detail::pipeline_stage_kind::set_character_set: return \"pipeline_stage_kind::set_character_set\";\n    case detail::pipeline_stage_kind::ping: return \"pipeline_stage_kind::ping\";\n    default: return \"<unknown pipeline_stage_kind>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, pipeline_stage_kind v)\n{\n    return os << ::to_string(v);\n}\n\n// pipeline_request_stage\nbool boost::mysql::detail::operator==(const pipeline_request_stage& lhs, const pipeline_request_stage& rhs)\n{\n    if (lhs.kind != rhs.kind || lhs.seqnum != rhs.seqnum)\n        return false;\n    switch (lhs.kind)\n    {\n    case pipeline_stage_kind::execute: return lhs.stage_specific.enc == rhs.stage_specific.enc;\n    case pipeline_stage_kind::set_character_set:\n        return lhs.stage_specific.charset == rhs.stage_specific.charset;\n    default: return true;\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, pipeline_request_stage v)\n{\n    os << \"pipeline_request_stage{ .kind = \" << v.kind << \", .seqnum = \" << +v.seqnum;\n    switch (v.kind)\n    {\n    case pipeline_stage_kind::execute: os << \", .enc = \" << v.stage_specific.enc; break;\n    case pipeline_stage_kind::set_character_set: os << \", .charset = \" << v.stage_specific.charset; break;\n    default: break;\n    }\n    return os << \" }\";\n}\n\n// node_status\nstatic const char* to_string(detail::node_status v)\n{\n    switch (v)\n    {\n    case detail::node_status::initial: return \"node_status::initial\";\n    case detail::node_status::connect_in_progress: return \"node_status::connect_in_progress\";\n    case detail::node_status::sleep_connect_failed_in_progress:\n        return \"node_status::sleep_connect_failed_in_progress\";\n    case detail::node_status::reset_in_progress: return \"node_status::reset_in_progress\";\n    case detail::node_status::ping_in_progress: return \"node_status::ping_in_progress\";\n    case detail::node_status::idle: return \"node_status::idle\";\n    case detail::node_status::in_use: return \"node_status::in_use\";\n    default: return \"<unknown node_status>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, node_status v)\n{\n    return os << ::to_string(v);\n}\n\n// collection_state\nstatic const char* to_string(detail::collection_state v)\n{\n    switch (v)\n    {\n    case detail::collection_state::needs_collect: return \"collection_state::needs_collect\";\n    case detail::collection_state::needs_collect_with_reset:\n        return \"collection_state::needs_collect_with_reset\";\n    case detail::collection_state::none: return \"collection_state::none\";\n    default: return \"<unknown collection_state>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, collection_state v)\n{\n    return os << ::to_string(v);\n}\n\nstatic const char* to_string(detail::next_connection_action v)\n{\n    switch (v)\n    {\n    case detail::next_connection_action::none: return \"next_connection_action::none\";\n    case detail::next_connection_action::connect: return \"next_connection_action::connect\";\n    case detail::next_connection_action::sleep_connect_failed:\n        return \"next_connection_action::sleep_connect_failed\";\n    case detail::next_connection_action::idle_wait: return \"next_connection_action::idle_wait\";\n    case detail::next_connection_action::reset: return \"next_connection_action::reset\";\n    case detail::next_connection_action::ping: return \"next_connection_action::ping\";\n    default: return \"<unknown next_connection_action>\";\n    }\n}\n\nstd::ostream& boost::mysql::detail::operator<<(std::ostream& os, next_connection_action v)\n{\n    return os << ::to_string(v);\n}\n\n//\n// test_any_connection.hpp\n//\nboost::mysql::any_connection boost::mysql::test::create_test_any_connection(\n    asio::io_context& ctx,\n    any_connection_params params,\n    detail::connection_status initial_status\n)\n{\n    auto res = any_connection(detail::access::construct<any_connection>(\n        std::unique_ptr<detail::engine>(\n            new detail::engine_impl<detail::engine_stream_adaptor<test_stream>>(ctx.get_executor())\n        ),\n        params\n    ));\n    detail::access::get_impl(res).get_state().data().status = initial_status;\n    return res;\n}\n\ntest_stream& boost::mysql::test::get_stream(any_connection& conn)\n{\n    return detail::stream_from_engine<test_stream>(detail::access::get_impl(conn).get_engine());\n}"
  },
  {
    "path": "test/unit/test/any_address.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_address.hpp>\n\n#include <boost/test/tools/context.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <memory>\n#include <string>\n\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_any_address)\n\n// Helper for C++11\nstatic host_and_port make_hport(std::string host, unsigned short port)\n{\n    host_and_port res;\n    res.host = std::move(host);\n    res.port = port;\n    return res;\n}\n\nstatic std::unique_ptr<any_address> make_address_ptr(any_address from)\n{\n    return std::unique_ptr<any_address>{new any_address(std::move(from))};\n}\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    // Default constructed addresses are empty host and ports\n    any_address addr;\n    BOOST_TEST(addr.type() == address_type::host_and_port);\n    BOOST_TEST(addr.hostname() == \"\");\n    BOOST_TEST(addr.port() == (unsigned short)3306);\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_host_and_port)\n{\n    // Setup\n    host_and_port hp = make_hport(\"abcd\", 2000);\n\n    // Construct\n    any_address addr(hp);\n    hp = make_hport(\"0000\", 1111);  // lifetime check\n\n    // Check\n    BOOST_TEST(addr.type() == address_type::host_and_port);\n    BOOST_TEST(addr.hostname() == \"abcd\");\n    BOOST_TEST(addr.port() == (unsigned short)2000);\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_unix_path)\n{\n    // Setup\n    unix_path p{\"/var/sock\"};\n\n    // Construct\n    any_address addr(p);\n    p.path = \"/aaa/bbbb\";  // lifetime check\n\n    // Check\n    BOOST_TEST(addr.type() == address_type::unix_path);\n    BOOST_TEST(addr.unix_socket_path() == \"/var/sock\");\n}\n\nBOOST_AUTO_TEST_CASE(copy_ctor)\n{\n    // Setup\n    auto addr = make_address_ptr(make_hport(\"abcd\", 2000));\n\n    // Construct\n    any_address addr2(*addr);\n    addr.reset();  // lifetime check\n\n    // Check\n    BOOST_TEST(addr2.type() == address_type::host_and_port);\n    BOOST_TEST(addr2.hostname() == \"abcd\");\n    BOOST_TEST(addr2.port() == (unsigned short)2000);\n}\n\nBOOST_AUTO_TEST_CASE(move_ctor)\n{\n    // Setup\n    auto addr = make_address_ptr(make_hport(\"abcd\", 2000));\n\n    // Construct\n    any_address addr2(std::move(*addr));\n    addr.reset();  // lifetime check\n\n    // Check\n    BOOST_TEST(addr2.type() == address_type::host_and_port);\n    BOOST_TEST(addr2.hostname() == \"abcd\");\n    BOOST_TEST(addr2.port() == (unsigned short)2000);\n}\n\nBOOST_AUTO_TEST_CASE(copy_assign)\n{\n    // Setup\n    auto addr = make_address_ptr(unix_path{\"/var/blah\"});\n    any_address addr2(make_hport(\"blah\", 9999));\n\n    // Assign\n    addr2 = *addr;\n    addr.reset();  // lifetime check\n\n    // Check\n    BOOST_TEST(addr2.type() == address_type::unix_path);\n    BOOST_TEST(addr2.unix_socket_path() == \"/var/blah\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assign)\n{\n    //  Setup\n    auto addr = make_address_ptr(make_hport(\"abcd\", 2000));\n    any_address addr2(unix_path{\"/var/sock\"});\n\n    // Assign\n    addr2 = std::move(*addr);\n    addr.reset();  // lifetime check\n\n    // Check\n    BOOST_TEST(addr2.type() == address_type::host_and_port);\n    BOOST_TEST(addr2.hostname() == \"abcd\");\n    BOOST_TEST(addr2.port() == (unsigned short)2000);\n}\n\nBOOST_AUTO_TEST_CASE(const_accessors_host_and_port)\n{\n    // host and port accessors can be called on const objects\n    const any_address addr{make_hport(\"abcd\", 2000)};\n    BOOST_TEST(addr.type() == address_type::host_and_port);\n    BOOST_TEST(addr.hostname() == \"abcd\");\n    BOOST_TEST(addr.port() == (unsigned short)2000);\n}\n\nBOOST_AUTO_TEST_CASE(const_accessors_unix_socket)\n{\n    // UNIX socket accessors can be called on const objects\n    const any_address addr{unix_path{\"/var/sock\"}};\n    BOOST_TEST(addr.type() == address_type::unix_path);\n    BOOST_TEST(addr.unix_socket_path() == \"/var/sock\");\n}\n\nBOOST_AUTO_TEST_CASE(emplace_host_and_port)\n{\n    // Changing type\n    any_address addr{unix_path{\"/var/sock\"}};\n    addr.emplace_host_and_port(\"abcd\", 2000);\n    BOOST_TEST(addr.type() == address_type::host_and_port);\n    BOOST_TEST(addr.hostname() == \"abcd\");\n    BOOST_TEST(addr.port() == (unsigned short)2000);\n\n    // Without changing type\n    addr.emplace_host_and_port(\"def\", 3000);\n    BOOST_TEST(addr.type() == address_type::host_and_port);\n    BOOST_TEST(addr.hostname() == \"def\");\n    BOOST_TEST(addr.port() == (unsigned short)3000);\n\n    // Default port value\n    addr.emplace_host_and_port(\"aaa\");\n    BOOST_TEST(addr.type() == address_type::host_and_port);\n    BOOST_TEST(addr.hostname() == \"aaa\");\n    BOOST_TEST(addr.port() == (unsigned short)3306);\n}\n\nBOOST_AUTO_TEST_CASE(emplace_unix_path)\n{\n    // Changing type\n    any_address addr{make_hport(\"abcd\", 2000)};\n    addr.emplace_unix_path(\"/var/sock\");\n    BOOST_TEST(addr.type() == address_type::unix_path);\n    BOOST_TEST(addr.unix_socket_path() == \"/var/sock\");\n\n    // Without changing type\n    addr.emplace_unix_path(\"/var/blah\");\n    BOOST_TEST(addr.type() == address_type::unix_path);\n    BOOST_TEST(addr.unix_socket_path() == \"/var/blah\");\n}\n\nBOOST_AUTO_TEST_CASE(operator_eq_ne)\n{\n    // For regression check: UNIX socket paths should compare equal\n    // whether they were created directly or via emplace\n    any_address addr_unix(make_hport(\"abcd\", 3306));\n    addr_unix.emplace_unix_path(\"abcd\");\n\n    struct\n    {\n        const char* name;\n        any_address addr1;\n        any_address addr2;\n        bool equals;\n    } test_cases[] = {\n        {\"host_and_port_eq\", make_hport(\"abc\", 2000), make_hport(\"abc\", 2000), true},\n        {\"host_and_port_eq_default\", host_and_port{}, host_and_port{}, true},\n        {\"host_and_port_ne_host\", make_hport(\"abcd\", 2000), make_hport(\"abc\", 2000), false},\n        {\"host_and_port_ne_port\", make_hport(\"abcd\", 2001), make_hport(\"abcd\", 2000), false},\n        {\"host_and_port_ne_all\", make_hport(\"abc\", 2001), make_hport(\"abcd\", 2000), false},\n\n        {\"unix_eq\", unix_path{\"/var/sock\"}, unix_path{\"/var/sock\"}, true},\n        {\"unix_eq_default\", unix_path{}, unix_path{}, true},\n        {\"unix_ne\", unix_path{\"/sock1\"}, unix_path{\"/sock2\"}, false},\n        {\"unix_emplace_regression\", addr_unix, unix_path{\"abcd\"}, true},\n\n        {\"type_ne\", make_hport(\"abcd\", 0), unix_path{\"abcd\"}, false},\n        {\"type_ne_empty\", host_and_port{}, unix_path{}, false},\n        {\"all_ne\", make_hport(\"abcd\", 2000), unix_path{\"/var/sock\"}, false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST((tc.addr1 == tc.addr2) == tc.equals);\n            BOOST_TEST((tc.addr2 == tc.addr1) == tc.equals);\n            BOOST_TEST((tc.addr1 != tc.addr2) == !tc.equals);\n            BOOST_TEST((tc.addr2 != tc.addr1) == !tc.equals);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/unit/test/any_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <exception>\n#include <stdexcept>\n#include <tuple>\n\n#include \"test_common/printing.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing asio::deferred;\n\nBOOST_AUTO_TEST_SUITE(test_any_connection)\n\nBOOST_AUTO_TEST_CASE(init_ctor)\n{\n    asio::io_context ctx;\n    any_connection c{ctx.get_executor()};\n    BOOST_TEST((c.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(init_ctor_execution_context)\n{\n    asio::io_context ctx;\n    any_connection c{ctx};\n    BOOST_TEST((c.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(init_ctor_with_buffer_size)\n{\n    asio::io_context ctx;\n    any_connection_params params;\n    params.initial_buffer_size = 512u;\n    any_connection c{ctx.get_executor(), params};\n    BOOST_TEST((c.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(init_ctor_max_buffer_size_eq_size)\n{\n    asio::io_context ctx;\n    any_connection_params params;\n    params.initial_buffer_size = 512u;\n    params.max_buffer_size = 512u;\n    any_connection c{ctx.get_executor(), params};\n    BOOST_TEST((c.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(init_ctor_error_max_buffer_size)\n{\n    asio::io_context ctx;\n    any_connection_params params;\n    params.initial_buffer_size = 513u;\n    params.max_buffer_size = 512u;\n    BOOST_CHECK_THROW(any_connection(ctx, params), std::invalid_argument);\n}\n\n// move ctor\nBOOST_AUTO_TEST_CASE(move_ctor)\n{\n    asio::io_context ctx;\n    any_connection c1{ctx.get_executor()};\n    any_connection c2{std::move(c1)};\n    BOOST_TEST((c2.get_executor() == ctx.get_executor()));\n}\n\n// move assign\nBOOST_AUTO_TEST_CASE(move_assign_to_moved_from)\n{\n    asio::io_context ctx;\n    any_connection moved_from{ctx.get_executor()};\n    any_connection other{std::move(moved_from)};\n    any_connection conn{ctx.get_executor()};\n    moved_from = std::move(conn);\n    BOOST_TEST((moved_from.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(move_assign_to_valid)\n{\n    asio::io_context ctx;\n    any_connection c1{ctx.get_executor()};\n    any_connection c2{ctx.get_executor()};\n    c1 = std::move(c2);\n    BOOST_TEST((c1.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(set_meta_mode)\n{\n    asio::io_context ctx;\n\n    // Default metadata mode\n    any_connection conn{ctx.get_executor()};\n    BOOST_TEST(conn.meta_mode() == metadata_mode::minimal);\n\n    // Setting it causes effect\n    conn.set_meta_mode(metadata_mode::full);\n    BOOST_TEST(conn.meta_mode() == metadata_mode::full);\n}\n\n// spotcheck: deferred compiles even in C++11\nvoid deferred_spotcheck()\n{\n    asio::io_context ctx;\n    auto conn = test::create_test_any_connection(ctx);\n    connect_params params;\n    diagnostics diag;\n    results result;\n    execution_state st;\n    statement stmt;\n\n    (void)conn.async_connect(params, deferred);\n    (void)conn.async_connect(params, diag, deferred);\n\n    (void)conn.async_execute(\"SELECT 1\", result, deferred);\n    (void)conn.async_execute(\"SELECT 1\", result, diag, deferred);\n\n    (void)conn.async_start_execution(\"SELECT 1\", st, deferred);\n    (void)conn.async_start_execution(\"SELECT 1\", st, diag, deferred);\n\n    (void)conn.async_read_some_rows(st, deferred);\n    (void)conn.async_read_some_rows(st, diag, deferred);\n\n#ifdef BOOST_MYSQL_CXX14\n    static_execution_state<std::tuple<>> st2;\n    (void)conn.async_read_some_rows(st2, boost::span<std::tuple<>>{}, deferred);\n    (void)conn.async_read_some_rows(st2, boost::span<std::tuple<>>{}, diag, deferred);\n#endif\n\n    (void)conn.async_read_resultset_head(st, deferred);\n    (void)conn.async_read_resultset_head(st, diag, deferred);\n\n    (void)conn.async_prepare_statement(\"SELECT 1\", deferred);\n    (void)conn.async_prepare_statement(\"SELECT 1\", diag, deferred);\n\n    (void)conn.async_close_statement(stmt, deferred);\n    (void)conn.async_close_statement(stmt, diag, deferred);\n\n    (void)conn.async_reset_connection(deferred);\n    (void)conn.async_reset_connection(diag, deferred);\n\n    (void)conn.async_ping(deferred);\n    (void)conn.async_ping(diag, deferred);\n\n    (void)conn.async_close(deferred);\n    (void)conn.async_close(diag, deferred);\n}\n\n// Spotcheck: all any_connection functions support default completion tokens\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\nasio::awaitable<void> spotcheck_default_tokens()\n{\n    asio::io_context ctx;\n    auto conn = test::create_test_any_connection(ctx);\n    connect_params params;\n    diagnostics diag;\n    results result;\n    execution_state st;\n    statement stmt;\n    static_execution_state<std::tuple<>> st2;\n\n    co_await conn.async_connect(params);\n    co_await conn.async_connect(params, diag);\n\n    co_await conn.async_execute(\"SELECT 1\", result);\n    co_await conn.async_execute(\"SELECT 1\", result, diag);\n\n    co_await conn.async_start_execution(\"SELECT 1\", st);\n    co_await conn.async_start_execution(\"SELECT 1\", st, diag);\n\n    co_await conn.async_read_some_rows(st);\n    co_await conn.async_read_some_rows(st, diag);\n\n    co_await conn.async_read_some_rows(st2, boost::span<std::tuple<>>{});\n    co_await conn.async_read_some_rows(st2, boost::span<std::tuple<>>{}, diag);\n\n    co_await conn.async_read_resultset_head(st);\n    co_await conn.async_read_resultset_head(st, diag);\n\n    co_await conn.async_prepare_statement(\"SELECT 1\");\n    co_await conn.async_prepare_statement(\"SELECT 1\", diag);\n\n    co_await conn.async_close_statement(stmt);\n    co_await conn.async_close_statement(stmt, diag);\n\n    co_await conn.async_reset_connection();\n    co_await conn.async_reset_connection(diag);\n\n    co_await conn.async_ping();\n    co_await conn.async_ping(diag);\n\n    co_await conn.async_close();\n    co_await conn.async_close(diag);\n}\n#endif\n\n// Spotcheck: any_connection ops support partial tokens,\n// and they get passed the correct default token\ntemplate <class T, class... SigArgs, class... Rest>\nvoid check_op(asio::deferred_async_operation<void(T, SigArgs...), Rest...>)\n{\n    static_assert(std::is_same<T, std::exception_ptr>::value, \"\");\n}\n\nvoid spotcheck_partial_tokens()\n{\n    asio::io_context ctx;\n    auto conn = test::create_test_any_connection(ctx);\n    connect_params params;\n    diagnostics diag;\n    results result;\n    execution_state st;\n    statement stmt;\n    auto tok = asio::cancel_after(std::chrono::seconds(10));\n\n    check_op(conn.async_connect(params, tok));\n    check_op(conn.async_connect(params, diag, tok));\n\n    check_op(conn.async_execute(\"SELECT 1\", result, tok));\n    check_op(conn.async_execute(\"SELECT 1\", result, diag, tok));\n\n    check_op(conn.async_start_execution(\"SELECT 1\", st, tok));\n    check_op(conn.async_start_execution(\"SELECT 1\", st, diag, tok));\n\n    check_op(conn.async_read_some_rows(st, tok));\n    check_op(conn.async_read_some_rows(st, diag, tok));\n\n#ifdef BOOST_MYSQL_CXX14\n    static_execution_state<std::tuple<>> st2;\n    check_op(conn.async_read_some_rows(st2, boost::span<std::tuple<>>{}, tok));\n    check_op(conn.async_read_some_rows(st2, boost::span<std::tuple<>>{}, diag, tok));\n#endif\n\n    check_op(conn.async_read_resultset_head(st, tok));\n    check_op(conn.async_read_resultset_head(st, diag, tok));\n\n    check_op(conn.async_prepare_statement(\"SELECT 1\", tok));\n    check_op(conn.async_prepare_statement(\"SELECT 1\", diag, tok));\n\n    check_op(conn.async_close_statement(stmt, tok));\n    check_op(conn.async_close_statement(stmt, diag, tok));\n\n    check_op(conn.async_reset_connection(tok));\n    check_op(conn.async_reset_connection(diag, tok));\n\n    check_op(conn.async_ping(tok));\n    check_op(conn.async_ping(diag, tok));\n\n    check_op(conn.async_close(tok));\n    check_op(conn.async_close(diag, tok));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/character_set.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/call_next_char.hpp>\n\n#include <boost/test/tools/context.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <string>\n\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_character_set)\n\n// Helper\nstatic std::size_t call_next_char(const character_set& charset, string_view s) noexcept\n{\n    return detail::call_next_char(charset, s.data(), s.data() + s.size());\n}\n\nBOOST_AUTO_TEST_CASE(utf8mb4_single_byte_valid)\n{\n    for (int i = 0; i < 0x80; ++i)\n    {\n        BOOST_TEST_CONTEXT(i)\n        {\n            // Exactly the required space\n            char str[2]{static_cast<char>(i), '\\0'};\n            auto actual_len = detail::call_next_char(utf8mb4_charset, str, str + 1);\n            BOOST_TEST(actual_len == 1u);\n\n            // Extra space\n            actual_len = detail::call_next_char(utf8mb4_charset, str, str + 2);\n            BOOST_TEST(actual_len == 1u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(utf8mb4_multibyte_valid)\n{\n    // Cases are structured depending on the first byte.\n    // We cover all possible first bytes, with some casuistic for each value.\n    struct\n    {\n        string_view name;\n        string_view input;\n        std::size_t expected;\n    } test_cases[] = {\n  // 2 byte characters. We perform some extra tests for c2 and c3\n        {\"c2 min (U+0080)\",          \"\\xc2\\x80\",         2u},\n        {\"c2 reg (U+0095)\",          \"\\xc2\\x95\",         2u},\n        {\"c2 max (U+00BF)\",          \"\\xc2\\xbf\",         2u},\n        {\"c3 min (U+00C0)\",          \"\\xc3\\x80\",         2u},\n        {\"c3 reg (U+00E7)\",          \"\\xc3\\xa7\",         2u},\n        {\"c3 max (U+00FF)\",          \"\\xc3\\xbf\",         2u},\n\n // c4-df behave the same as c2-c3, so only min and max\n        {\"c4 min (U+0100)\",          \"\\xc4\\x80\",         2u},\n        {\"c4 max (U+013F)\",          \"\\xc4\\xbf\",         2u},\n        {\"c5 min (U+0140)\",          \"\\xc5\\x80\",         2u},\n        {\"c5 max (U+017F)\",          \"\\xc5\\xbf\",         2u},\n        {\"c6 min (U+0180)\",          \"\\xc6\\x80\",         2u},\n        {\"c6 max (U+01BF)\",          \"\\xc6\\xbf\",         2u},\n        {\"c7 min (U+01C0)\",          \"\\xc7\\x80\",         2u},\n        {\"c7 max (U+01FF)\",          \"\\xc7\\xbf\",         2u},\n        {\"c8 min (U+0200)\",          \"\\xc8\\x80\",         2u},\n        {\"c8 max (U+023F)\",          \"\\xc8\\xbf\",         2u},\n        {\"c9 min (U+0240)\",          \"\\xc9\\x80\",         2u},\n        {\"c9 max (U+027F)\",          \"\\xc9\\xbf\",         2u},\n        {\"ca min (U+0280)\",          \"\\xca\\x80\",         2u},\n        {\"ca max (U+02BF)\",          \"\\xca\\xbf\",         2u},\n        {\"cb min (U+02C0)\",          \"\\xcb\\x80\",         2u},\n        {\"cb max (U+02FF)\",          \"\\xcb\\xbf\",         2u},\n        {\"cc min (U+0300)\",          \"\\xcc\\x80\",         2u},\n        {\"cc max (U+033F)\",          \"\\xcc\\xbf\",         2u},\n        {\"cd min (U+0340)\",          \"\\xcd\\x80\",         2u},\n        {\"cd max (U+037F)\",          \"\\xcd\\xbf\",         2u},\n        {\"ce min (U+0380)\",          \"\\xce\\x80\",         2u},\n        {\"ce max (U+03BF)\",          \"\\xce\\xbf\",         2u},\n        {\"cf min (U+03C0)\",          \"\\xcf\\x80\",         2u},\n        {\"cf max (U+03FF)\",          \"\\xcf\\xbf\",         2u},\n        {\"d0 min (U+0400)\",          \"\\xd0\\x80\",         2u},\n        {\"d0 max (U+043F)\",          \"\\xd0\\xbf\",         2u},\n        {\"d1 min (U+0440)\",          \"\\xd1\\x80\",         2u},\n        {\"d1 max (U+047F)\",          \"\\xd1\\xbf\",         2u},\n        {\"d2 min (U+0480)\",          \"\\xd2\\x80\",         2u},\n        {\"d2 max (U+04BF)\",          \"\\xd2\\xbf\",         2u},\n        {\"d3 min (U+04C0)\",          \"\\xd3\\x80\",         2u},\n        {\"d3 max (U+04FF)\",          \"\\xd3\\xbf\",         2u},\n        {\"d4 min (U+0500)\",          \"\\xd4\\x80\",         2u},\n        {\"d4 max (U+053F)\",          \"\\xd4\\xbf\",         2u},\n        {\"d5 min (U+0540)\",          \"\\xd5\\x80\",         2u},\n        {\"d5 max (U+057F)\",          \"\\xd5\\xbf\",         2u},\n        {\"d6 min (U+0580)\",          \"\\xd6\\x80\",         2u},\n        {\"d6 max (U+05BF)\",          \"\\xd6\\xbf\",         2u},\n        {\"d7 min (U+05C0)\",          \"\\xd7\\x80\",         2u},\n        {\"d7 max (U+05FF)\",          \"\\xd7\\xbf\",         2u},\n        {\"d8 min (U+0600)\",          \"\\xd8\\x80\",         2u},\n        {\"d8 max (U+063F)\",          \"\\xd8\\xbf\",         2u},\n        {\"d9 min (U+0640)\",          \"\\xd9\\x80\",         2u},\n        {\"d9 max (U+067F)\",          \"\\xd9\\xbf\",         2u},\n        {\"da min (U+0680)\",          \"\\xda\\x80\",         2u},\n        {\"da max (U+06BF)\",          \"\\xda\\xbf\",         2u},\n        {\"db min (U+06C0)\",          \"\\xdb\\x80\",         2u},\n        {\"db max (U+06FF)\",          \"\\xdb\\xbf\",         2u},\n        {\"dc min (U+0700)\",          \"\\xdc\\x80\",         2u},\n        {\"dc max (U+073F)\",          \"\\xdc\\xbf\",         2u},\n        {\"dd min (U+0740)\",          \"\\xdd\\x80\",         2u},\n        {\"dd max (U+077F)\",          \"\\xdd\\xbf\",         2u},\n        {\"de min (U+0780)\",          \"\\xde\\x80\",         2u},\n        {\"de max (U+07BF)\",          \"\\xde\\xbf\",         2u},\n        {\"df min (U+07C0)\",          \"\\xdf\\x80\",         2u},\n        {\"df max (U+07FF)\",          \"\\xdf\\xbf\",         2u},\n\n // 3 byte characters. We perform some extra tests for e0 and e1\n        {\"e0 min min (U+0800)\",      \"\\xe0\\xa0\\x80\",     3u},\n        {\"e0 min reg (U+0835)\",      \"\\xe0\\xa0\\xb5\",     3u},\n        {\"e0 min max (U+083F)\",      \"\\xe0\\xa0\\xbf\",     3u},\n        {\"e0 reg min (U+0900)\",      \"\\xe0\\xa4\\x80\",     3u},\n        {\"e0 reg reg (U+0920)\",      \"\\xe0\\xa4\\xa0\",     3u},\n        {\"e0 reg max (U+093F)\",      \"\\xe0\\xa4\\xbf\",     3u},\n        {\"e0 max min (U+0FC0)\",      \"\\xe0\\xbf\\x80\",     3u},\n        {\"e0 max reg (U+0FE0)\",      \"\\xe0\\xbf\\xa0\",     3u},\n        {\"e0 max max (U+0FFF)\",      \"\\xe0\\xbf\\xbf\",     3u},\n\n        {\"e1 min min (U+1000)\",      \"\\xe1\\x80\\x80\",     3u},\n        {\"e1 min max (U+103F)\",      \"\\xe1\\x80\\xbf\",     3u},\n        {\"e1 max min (U+1FC0)\",      \"\\xe1\\xbf\\x80\",     3u},\n        {\"e1 max max (U+1FFF)\",      \"\\xe1\\xbf\\xbf\",     3u},\n\n // e2-ec behave like e1\n        {\"e2 min (U+2000)\",          \"\\xe2\\x80\\x80\",     3u},\n        {\"e2 max (U+2FFF)\",          \"\\xe2\\xbf\\xbf\",     3u},\n        {\"e3 min (U+3000)\",          \"\\xe3\\x80\\x80\",     3u},\n        {\"e3 max (U+3FFF)\",          \"\\xe3\\xbf\\xbf\",     3u},\n        {\"e4 min (U+4000)\",          \"\\xe4\\x80\\x80\",     3u},\n        {\"e4 max (U+4FFF)\",          \"\\xe4\\xbf\\xbf\",     3u},\n        {\"e5 min (U+5000)\",          \"\\xe5\\x80\\x80\",     3u},\n        {\"e5 max (U+5FFF)\",          \"\\xe5\\xbf\\xbf\",     3u},\n        {\"e6 min (U+6000)\",          \"\\xe6\\x80\\x80\",     3u},\n        {\"e6 max (U+6FFF)\",          \"\\xe6\\xbf\\xbf\",     3u},\n        {\"e7 min (U+7000)\",          \"\\xe7\\x80\\x80\",     3u},\n        {\"e7 max (U+7FFF)\",          \"\\xe7\\xbf\\xbf\",     3u},\n        {\"e8 min (U+8000)\",          \"\\xe8\\x80\\x80\",     3u},\n        {\"e8 max (U+8FFF)\",          \"\\xe8\\xbf\\xbf\",     3u},\n        {\"e9 min (U+9000)\",          \"\\xe9\\x80\\x80\",     3u},\n        {\"e9 max (U+9FFF)\",          \"\\xe9\\xbf\\xbf\",     3u},\n        {\"ea min (U+A000)\",          \"\\xea\\x80\\x80\",     3u},\n        {\"ea max (U+AFFF)\",          \"\\xea\\xbf\\xbf\",     3u},\n        {\"eb min (U+B000)\",          \"\\xeb\\x80\\x80\",     3u},\n        {\"eb max (U+BFFF)\",          \"\\xeb\\xbf\\xbf\",     3u},\n        {\"ec min (U+C000)\",          \"\\xec\\x80\\x80\",     3u},\n        {\"ec max (U+CFFF)\",          \"\\xec\\xbf\\xbf\",     3u},\n\n // ed is different because of surrogates (code points U+D800 to U+DFFF)\n        {\"ed min (U+D000)\",          \"\\xed\\x80\\x80\",     3u},\n        {\"ed reg (U+D631)\",          \"\\xed\\x98\\xb1\",     3u},\n        {\"ed max (U+D7FF)\",          \"\\xed\\x9f\\xbf\",     3u},\n\n // ee-ef behave like e1\n        {\"ee min (U+E000)\",          \"\\xee\\x80\\x80\",     3u},\n        {\"ee max (U+EFFF)\",          \"\\xee\\xbf\\xbf\",     3u},\n        {\"ef min (U+F000)\",          \"\\xef\\x80\\x80\",     3u},\n        {\"ef max (U+FFFF)\",          \"\\xef\\xbf\\xbf\",     3u},\n\n // 4 byte characters - we perform some extra testing for f0\n        {\"f0 min min min (U+10000)\", \"\\xf0\\x90\\x80\\x80\", 4u},\n        {\"f0 min min max (U+1003F)\", \"\\xf0\\x90\\x80\\xbf\", 4u},\n        {\"f0 min max min (U+10FC0)\", \"\\xf0\\x90\\xbf\\x80\", 4u},\n        {\"f0 min max max (U+10FFF)\", \"\\xf0\\x90\\xbf\\xbf\", 4u},\n        {\"f0 max min min (U+3F000)\", \"\\xf0\\xbf\\x80\\x80\", 4u},\n        {\"f0 max min max (U+3F03F)\", \"\\xf0\\xbf\\x80\\xbf\", 4u},\n        {\"f0 max max min (U+3FFC0)\", \"\\xf0\\xbf\\xbf\\x80\", 4u},\n        {\"f0 max max max (U+3FFFF)\", \"\\xf0\\xbf\\xbf\\xbf\", 4u},\n\n        {\"f1 min (U+40000)\",         \"\\xf1\\x80\\x80\\x80\", 4u},\n        {\"f1 max (U+7FFFF)\",         \"\\xf1\\xbf\\xbf\\xbf\", 4u},\n        {\"f2 min (U+80000)\",         \"\\xf2\\x80\\x80\\x80\", 4u},\n        {\"f2 max (U+BFFFF)\",         \"\\xf2\\xbf\\xbf\\xbf\", 4u},\n        {\"f3 min (U+C0000)\",         \"\\xf3\\x80\\x80\\x80\", 4u},\n        {\"f3 max (U+FFFFF)\",         \"\\xf3\\xbf\\xbf\\xbf\", 4u},\n\n // The last allowable code point is U+10FFFF\n        {\"f4 min (U+100000)\",        \"\\xf4\\x80\\x80\\x80\", 4u},\n        {\"f4 max (U+10FFFF)\",        \"\\xf4\\x8f\\xbf\\xbf\", 4u},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Exactly the required space\n            auto actual_len = call_next_char(utf8mb4_charset, tc.input);\n            BOOST_TEST(actual_len == tc.expected);\n\n            // Extra space\n            auto extra_space_input = std::string(tc.input) + \"abc\";\n            actual_len = call_next_char(utf8mb4_charset, extra_space_input);\n            BOOST_TEST(actual_len == tc.expected);\n\n            // Not enough space (end of data before the end of the byte sequence)\n            auto not_enough_input = tc.input.substr(1);\n            actual_len = call_next_char(utf8mb4_charset, not_enough_input);\n            BOOST_TEST(actual_len == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(utf8mb4_invalid_start_byte)\n{\n    constexpr unsigned char bytes[] = {\n        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n        0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\n        0xc0, 0xc1, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,\n    };\n\n    for (const auto b : bytes)\n    {\n        BOOST_TEST_CONTEXT(+b)\n        {\n            auto input = static_cast<char>(b);\n            auto size = detail::call_next_char(utf8mb4_charset, &input, &input + 1);\n            BOOST_TEST(size == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(utf8mb4_invalid_continuation)\n{\n    struct\n    {\n        string_view name;\n        string_view input;\n    } test_cases[] = {\n  // 2 byte characters\n        {\"c2 zero\",             makesv(\"\\xc2\\x00\")        },\n        {\"c2 ltmin\",            \"\\xc2\\x7f\"                },\n        {\"c2 gtmax\",            \"\\xc2\\xc0\"                },\n        {\"c2 max\",              \"\\xc2\\xff\"                },\n        {\"c3 ltmin\",            \"\\xc3\\x7f\"                },\n        {\"c3 gtmax\",            \"\\xc3\\xc0\"                },\n        {\"c4 ltmin\",            \"\\xc4\\x7f\"                },\n        {\"c4 gtmax\",            \"\\xc4\\xc0\"                },\n        {\"c5 ltmin\",            \"\\xc5\\x7f\"                },\n        {\"c5 gtmax\",            \"\\xc5\\xc0\"                },\n        {\"c6 ltmin\",            \"\\xc6\\x7f\"                },\n        {\"c6 gtmax\",            \"\\xc6\\xc0\"                },\n        {\"c7 ltmin\",            \"\\xc7\\x7f\"                },\n        {\"c7 gtmax\",            \"\\xc7\\xc0\"                },\n        {\"c8 ltmin\",            \"\\xc8\\x7f\"                },\n        {\"c8 gtmax\",            \"\\xc8\\xc0\"                },\n        {\"c9 ltmin\",            \"\\xc9\\x7f\"                },\n        {\"c9 gtmax\",            \"\\xc9\\xc0\"                },\n        {\"ca ltmin\",            \"\\xca\\x7f\"                },\n        {\"ca gtmax\",            \"\\xca\\xc0\"                },\n        {\"cb ltmin\",            \"\\xcb\\x7f\"                },\n        {\"cb gtmax\",            \"\\xcb\\xc0\"                },\n        {\"cc ltmin\",            \"\\xcc\\x7f\"                },\n        {\"cc gtmax\",            \"\\xcc\\xc0\"                },\n        {\"cd ltmin\",            \"\\xcd\\x7f\"                },\n        {\"cd gtmax\",            \"\\xcd\\xc0\"                },\n        {\"ce ltmin\",            \"\\xce\\x7f\"                },\n        {\"ce gtmax\",            \"\\xce\\xc0\"                },\n        {\"cf ltmin\",            \"\\xcf\\x7f\"                },\n        {\"cf gtmax\",            \"\\xcf\\xc0\"                },\n        {\"d0 ltmin\",            \"\\xd0\\x7f\"                },\n        {\"d0 gtmax\",            \"\\xd0\\xc0\"                },\n        {\"d1 ltmin\",            \"\\xd1\\x7f\"                },\n        {\"d1 gtmax\",            \"\\xd1\\xc0\"                },\n        {\"d2 ltmin\",            \"\\xd2\\x7f\"                },\n        {\"d2 gtmax\",            \"\\xd2\\xc0\"                },\n        {\"d3 ltmin\",            \"\\xd3\\x7f\"                },\n        {\"d3 gtmax\",            \"\\xd3\\xc0\"                },\n        {\"d4 ltmin\",            \"\\xd4\\x7f\"                },\n        {\"d4 gtmax\",            \"\\xd4\\xc0\"                },\n        {\"d5 ltmin\",            \"\\xd5\\x7f\"                },\n        {\"d5 gtmax\",            \"\\xd5\\xc0\"                },\n        {\"d6 ltmin\",            \"\\xd6\\x7f\"                },\n        {\"d6 gtmax\",            \"\\xd6\\xc0\"                },\n        {\"d7 ltmin\",            \"\\xd7\\x7f\"                },\n        {\"d7 gtmax\",            \"\\xd7\\xc0\"                },\n        {\"d8 ltmin\",            \"\\xd8\\x7f\"                },\n        {\"d8 gtmax\",            \"\\xd8\\xc0\"                },\n        {\"d9 ltmin\",            \"\\xd9\\x7f\"                },\n        {\"d9 gtmax\",            \"\\xd9\\xc0\"                },\n        {\"da ltmin\",            \"\\xda\\x7f\"                },\n        {\"da gtmax\",            \"\\xda\\xc0\"                },\n        {\"db ltmin\",            \"\\xdb\\x7f\"                },\n        {\"db gtmax\",            \"\\xdb\\xc0\"                },\n        {\"dc ltmin\",            \"\\xdc\\x7f\"                },\n        {\"dc gtmax\",            \"\\xdc\\xc0\"                },\n        {\"dd ltmin\",            \"\\xdd\\x7f\"                },\n        {\"dd gtmax\",            \"\\xdd\\xc0\"                },\n        {\"de ltmin\",            \"\\xde\\x7f\"                },\n        {\"de gtmax\",            \"\\xde\\xc0\"                },\n        {\"df ltmin\",            \"\\xdf\\x7f\"                },\n        {\"df gtmax\",            \"\\xdf\\xc0\"                },\n\n // 3 byte chars (e0 is special)\n        {\"e0 ltmin ok\",         \"\\xe0\\x9f\\x91\"            },\n        {\"e0 gtmax ok\",         \"\\xe0\\xc0\\x91\"            },\n        {\"e0 ok ltmin\",         \"\\xe0\\xa0\\x7F\"            },\n        {\"e0 ok gtmax\",         \"\\xe0\\xa0\\xc0\"            },\n\n        {\"e1 ltmin ok\",         \"\\xe1\\x7f\\x91\"            },\n        {\"e1 gtmax ok\",         \"\\xe1\\xc0\\x91\"            },\n        {\"e1 ok ltmin\",         \"\\xe1\\xa0\\x7F\"            },\n        {\"e1 ok gtmax\",         \"\\xe1\\xa0\\xc0\"            },\n\n        {\"e2 ltmin ok\",         \"\\xe2\\x7f\\x91\"            },\n        {\"e2 gtmax ok\",         \"\\xe2\\xc0\\x91\"            },\n        {\"e2 ok ltmin\",         \"\\xe2\\xa0\\x7F\"            },\n        {\"e2 ok gtmax\",         \"\\xe2\\xa0\\xc0\"            },\n\n        {\"e3 ltmin ok\",         \"\\xe3\\x7f\\x91\"            },\n        {\"e3 gtmax ok\",         \"\\xe3\\xc0\\x91\"            },\n        {\"e3 ok ltmin\",         \"\\xe3\\xa0\\x7F\"            },\n        {\"e3 ok gtmax\",         \"\\xe3\\xa0\\xc0\"            },\n\n        {\"e4 ltmin ok\",         \"\\xe4\\x7f\\x91\"            },\n        {\"e4 gtmax ok\",         \"\\xe4\\xc0\\x91\"            },\n        {\"e4 ok ltmin\",         \"\\xe4\\xa0\\x7F\"            },\n        {\"e4 ok gtmax\",         \"\\xe4\\xa0\\xc0\"            },\n\n        {\"e5 ltmin ok\",         \"\\xe5\\x7f\\x91\"            },\n        {\"e5 gtmax ok\",         \"\\xe5\\xc0\\x91\"            },\n        {\"e5 ok ltmin\",         \"\\xe5\\xa0\\x7F\"            },\n        {\"e5 ok gtmax\",         \"\\xe5\\xa0\\xc0\"            },\n\n        {\"e6 ltmin ok\",         \"\\xe6\\x7f\\x91\"            },\n        {\"e6 gtmax ok\",         \"\\xe6\\xc0\\x91\"            },\n        {\"e6 ok ltmin\",         \"\\xe6\\xa0\\x7F\"            },\n        {\"e6 ok gtmax\",         \"\\xe6\\xa0\\xc0\"            },\n\n        {\"e7 ltmin ok\",         \"\\xe7\\x7f\\x91\"            },\n        {\"e7 gtmax ok\",         \"\\xe7\\xc0\\x91\"            },\n        {\"e7 ok ltmin\",         \"\\xe7\\xa0\\x7F\"            },\n        {\"e7 ok gtmax\",         \"\\xe7\\xa0\\xc0\"            },\n\n        {\"e8 ltmin ok\",         \"\\xe8\\x7f\\x91\"            },\n        {\"e8 gtmax ok\",         \"\\xe8\\xc0\\x91\"            },\n        {\"e8 ok ltmin\",         \"\\xe8\\xa0\\x7F\"            },\n        {\"e8 ok gtmax\",         \"\\xe8\\xa0\\xc0\"            },\n\n        {\"e9 ltmin ok\",         \"\\xe9\\x7f\\x91\"            },\n        {\"e9 gtmax ok\",         \"\\xe9\\xc0\\x91\"            },\n        {\"e9 ok ltmin\",         \"\\xe9\\xa0\\x7F\"            },\n        {\"e9 ok gtmax\",         \"\\xe9\\xa0\\xc0\"            },\n\n        {\"ea ltmin ok\",         \"\\xea\\x7f\\x91\"            },\n        {\"ea gtmax ok\",         \"\\xea\\xc0\\x91\"            },\n        {\"ea ok ltmin\",         \"\\xea\\xa0\\x7F\"            },\n        {\"ea ok gtmax\",         \"\\xea\\xa0\\xc0\"            },\n\n        {\"eb ltmin ok\",         \"\\xeb\\x7f\\x91\"            },\n        {\"eb gtmax ok\",         \"\\xeb\\xc0\\x91\"            },\n        {\"eb ok ltmin\",         \"\\xeb\\xa0\\x7F\"            },\n        {\"eb ok gtmax\",         \"\\xeb\\xa0\\xc0\"            },\n\n        {\"ec ltmin ok\",         \"\\xec\\x7f\\x91\"            },\n        {\"ec gtmax ok\",         \"\\xec\\xc0\\x91\"            },\n        {\"ec ok ltmin\",         \"\\xec\\xa0\\x7F\"            },\n        {\"ec ok gtmax\",         \"\\xec\\xa0\\xc0\"            },\n\n // ed is special because it includes surrogates\n        {\"ed ltmin ok\",         \"\\xed\\x7f\\x91\"            },\n        {\"ed gtmax ok\",         \"\\xed\\xc0\\x91\"            },\n        {\"ed ok ltmin\",         \"\\xed\\xa0\\x7F\"            },\n        {\"ed ok gtmax\",         \"\\xed\\xa0\\xc0\"            },\n        {\"ed surrogate min\",    \"\\xed\\xa0\\x80\"            },\n        {\"ed surrogate reg\",    \"\\xed\\xa1\\x92\"            },\n        {\"ed surrogate max\",    \"\\xed\\xbf\\xbf\"            },\n\n // ee and ef behave like e1\n        {\"ee ltmin ok\",         \"\\xee\\x7f\\x91\"            },\n        {\"ee gtmax ok\",         \"\\xee\\xc0\\x91\"            },\n        {\"ee ok ltmin\",         \"\\xee\\xa0\\x7F\"            },\n        {\"ee ok gtmax\",         \"\\xee\\xa0\\xc0\"            },\n\n        {\"ef ltmin ok\",         \"\\xef\\x7f\\x91\"            },\n        {\"ef gtmax ok\",         \"\\xef\\xc0\\x91\"            },\n        {\"ef ok ltmin\",         \"\\xef\\xa0\\x7F\"            },\n        {\"ef ok gtmax\",         \"\\xef\\xa0\\xc0\"            },\n\n // 4 byte characters. f0 is special\n        {\"f0 ltmin ok ok\",      \"\\xf0\\x8f\\x80\\x80\"        },\n        {\"f0 gtmax ok ok\",      \"\\xf0\\xc0\\x80\\x80\"        },\n        {\"f0 ok ltmin ok\",      \"\\xf0\\xa1\\x7f\\xa3\"        },\n        {\"f0 ok gtmax ok\",      \"\\xf0\\xa1\\xc0\\xa3\"        },\n        {\"f0 ok ok ltmin\",      \"\\xf0\\xa1\\xa2\\x7f\"        },\n        {\"f0 ok ok gtmax\",      \"\\xf0\\xa1\\xa2\\xc0\"        },\n\n        {\"f1 ltmin ok ok\",      \"\\xf1\\x7f\\x80\\x80\"        },\n        {\"f1 gtmax ok ok\",      \"\\xf1\\xc0\\x80\\x80\"        },\n        {\"f1 ok ltmin ok\",      \"\\xf1\\xa1\\x7f\\xa3\"        },\n        {\"f1 ok gtmax ok\",      \"\\xf1\\xa1\\xc0\\xa3\"        },\n        {\"f1 ok ok ltmin\",      \"\\xf1\\xa1\\xa2\\x7f\"        },\n        {\"f1 ok ok gtmax\",      \"\\xf1\\xa1\\xa2\\xc0\"        },\n\n        {\"f2 ltmin ok ok\",      \"\\xf2\\x7f\\x80\\x80\"        },\n        {\"f2 gtmax ok ok\",      \"\\xf2\\xc0\\x80\\x80\"        },\n        {\"f2 ok ltmin ok\",      \"\\xf2\\xa1\\x7f\\xa3\"        },\n        {\"f2 ok gtmax ok\",      \"\\xf2\\xa1\\xc0\\xa3\"        },\n        {\"f2 ok ok ltmin\",      \"\\xf2\\xa1\\xa2\\x7f\"        },\n        {\"f2 ok ok gtmax\",      \"\\xf2\\xa1\\xa2\\xc0\"        },\n\n        {\"f3 ltmin ok ok\",      \"\\xf3\\x7f\\x80\\x80\"        },\n        {\"f3 gtmax ok ok\",      \"\\xf3\\xc0\\x80\\x80\"        },\n        {\"f3 ok ltmin ok\",      \"\\xf3\\xa1\\x7f\\xa3\"        },\n        {\"f3 ok gtmax ok\",      \"\\xf3\\xa1\\xc0\\xa3\"        },\n        {\"f3 ok ok ltmin\",      \"\\xf3\\xa1\\xa2\\x7f\"        },\n        {\"f3 ok ok gtmax\",      \"\\xf3\\xa1\\xa2\\xc0\"        },\n\n // f4 is also special because it's the end of the unicode range\n        {\"f4 ltmin ok ok\",      \"\\xf4\\x7f\\x80\\x80\"        },\n        {\"f4 gtmax ok ok\",      \"\\xf4\\x90\\x80\\x80\"        },\n        {\"f4 ok ltmin ok\",      \"\\xf4\\xa1\\x7f\\xa3\"        },\n        {\"f4 ok gtmax ok\",      \"\\xf4\\xa1\\xc0\\xa3\"        },\n        {\"f4 ok ok ltmin\",      \"\\xf4\\xa1\\xa2\\x7f\"        },\n        {\"f4 ok ok gtmax\",      \"\\xf4\\xa1\\xa2\\xc0\"        },\n\n // overlong characters\n        {\"overlong / 2byte\",    \"\\xc0\\xaf\"                },\n        {\"overlong / 3byte\",    \"\\xe0\\x80\\xaf\"            },\n        {\"overlong / 4byte\",    \"\\xf0\\x80\\x80\\xaf\"        },\n        {\"overlong / 5byte\",    \"\\xf8\\x80\\x80\\x80\\xaf\"    },\n        {\"overlong / 6byte\",    \"\\xf8\\x80\\x80\\x80\\x80\\xaf\"},\n        {\"overlong U+007F\",     \"\\xc1\\xbf\"                },\n        {\"overlong U+07FF\",     \"\\xe0\\x9f\\xbf\"            },\n        {\"overlong U+FFFF\",     \"\\xf0\\x8f\\xbf\\xbf\"        },\n        {\"overlong U+001FFFFF\", \"\\xf8\\x87\\xbf\\xbf\\xbf\"    },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // add some extra continuation bytes, so we never fail because of lack of space\n            auto input = std::string(tc.input) + \"\\x91\\x91\";\n            auto size = call_next_char(utf8mb4_charset, input);\n            BOOST_TEST(size == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(ascii)\n{\n    // valid\n    for (std::size_t i = 0; i <= 0x7f; ++i)\n    {\n        BOOST_TEST_CONTEXT(i)\n        {\n            char str[2]{static_cast<char>(i), '\\0'};\n            auto size = detail::call_next_char(ascii_charset, str, str + 2);\n            BOOST_TEST(size == 1u);\n        }\n    }\n\n    // invalid\n    for (std::size_t i = 0x80; i <= 0xff; ++i)\n    {\n        BOOST_TEST_CONTEXT(i)\n        {\n            char str[2]{static_cast<char>(i), '\\0'};\n            auto size = detail::call_next_char(ascii_charset, str, str + 2);\n            BOOST_TEST(size == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/unit/test/client_errc.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/stringize.hpp\"\n\nusing namespace boost::mysql;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_client_errc)\n\nBOOST_AUTO_TEST_SUITE(error_to_string_)\n\nBOOST_AUTO_TEST_CASE(regular)\n{\n    BOOST_TEST(error_code(client_errc::sequence_number_mismatch).message() == \"Mismatched sequence numbers\");\n}\n\nBOOST_AUTO_TEST_CASE(unknown_error)\n{\n    BOOST_TEST(error_code(static_cast<client_errc>(0xfffefdfc)).message() == \"<unknown MySQL client error>\");\n}\n\nBOOST_AUTO_TEST_CASE(coverage)\n{\n    // Check that no value causes problems.\n    // Ensure that all branches of the switch/case are covered\n    for (int i = 1; i <= 31; ++i)\n    {\n        BOOST_TEST_CONTEXT(i)\n        {\n            BOOST_TEST(error_code(static_cast<client_errc>(i)).message() != \"<unknown MySQL client error>\");\n        }\n    }\n}\nBOOST_AUTO_TEST_SUITE_END()  // error_to_string_\n\nBOOST_AUTO_TEST_CASE(error_code_from_errc)\n{\n    error_code code(client_errc::protocol_value_error);\n    BOOST_TEST(code.value() == static_cast<int>(client_errc::protocol_value_error));\n    BOOST_TEST(&code.category() == &boost::mysql::get_client_category());  // categories are not printable\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_client_errc\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/column_type.cpp",
    "content": "//\n// Copyright (c) 2026 Vladislav Soulgard (vsoulgard at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <string>\n#include <sstream>\n#include <iostream>\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_column_type)\n\nstd::string to_string(column_type t)\n{\n    std::ostringstream oss;\n    auto& result = oss << t;\n    BOOST_TEST(!oss.fail());\n    // Check if operator<< return same stream object\n    BOOST_TEST(&result == &oss);\n    return oss.str();\n}\n\nBOOST_AUTO_TEST_CASE(stream_operator_basic)\n{\n    // Numeric types\n    BOOST_TEST(to_string(column_type::tinyint) == \"tinyint\");\n    BOOST_TEST(to_string(column_type::smallint) == \"smallint\");\n    BOOST_TEST(to_string(column_type::mediumint) == \"mediumint\");\n    BOOST_TEST(to_string(column_type::int_) == \"int_\");\n    BOOST_TEST(to_string(column_type::bigint) == \"bigint\");\n    \n    // Floating-point types\n    BOOST_TEST(to_string(column_type::float_) == \"float_\");\n    BOOST_TEST(to_string(column_type::double_) == \"double_\");\n    BOOST_TEST(to_string(column_type::decimal) == \"decimal\");\n    \n    // Special types\n    BOOST_TEST(to_string(column_type::bit) == \"bit\");\n    BOOST_TEST(to_string(column_type::year) == \"year\");\n    \n    // Date/time types\n    BOOST_TEST(to_string(column_type::time) == \"time\");\n    BOOST_TEST(to_string(column_type::date) == \"date\");\n    BOOST_TEST(to_string(column_type::datetime) == \"datetime\");\n    BOOST_TEST(to_string(column_type::timestamp) == \"timestamp\");\n    \n    // String types\n    BOOST_TEST(to_string(column_type::char_) == \"char_\");\n    BOOST_TEST(to_string(column_type::varchar) == \"varchar\");\n    BOOST_TEST(to_string(column_type::binary) == \"binary\");\n    BOOST_TEST(to_string(column_type::varbinary) == \"varbinary\");\n    \n    // Large object types\n    BOOST_TEST(to_string(column_type::text) == \"text\");\n    BOOST_TEST(to_string(column_type::blob) == \"blob\");\n    \n    // Special MySQL types\n    BOOST_TEST(to_string(column_type::enum_) == \"enum_\");\n    BOOST_TEST(to_string(column_type::set) == \"set\");\n    BOOST_TEST(to_string(column_type::json) == \"json\");\n    BOOST_TEST(to_string(column_type::geometry) == \"geometry\");\n}\n\nBOOST_AUTO_TEST_CASE(stream_operator_unknown)\n{\n    // Unknown type\n    BOOST_TEST(to_string(column_type::unknown) == \"<unknown column type>\");\n\n    // Incorrect value\n    BOOST_TEST(to_string(static_cast<column_type>(999)) == \"<unknown column type>\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/common_server_errc.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/common_server_errc.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <limits>\n\nusing namespace boost::mysql;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_common_server_errc)\n\nBOOST_AUTO_TEST_CASE(error_to_string_regular)\n{\n    struct\n    {\n        const char* name;\n        int err;\n        const char* expected_msg;\n    } test_cases[] = {\n        {\"int_min\",                  (std::numeric_limits<int>::min)(),                     \"<unknown server error>\"     },\n        {\"zero\",                     0,                                                     \"<unknown server error>\"     },\n        {\"lt_min\",                   999,                                                   \"<unknown server error>\"     },\n        {\"min\",                      1000,                                                  \"er_hashchk\"                 },\n        {\"unused_intermediate_code\", 1150,                                                  \"<unknown server error>\"     },\n        {\"db_specific\",              1076,                                                  \"<unknown server error>\"     },\n        {\"regular\",                  static_cast<int>(common_server_errc::er_bad_db_error), \"er_bad_db_error\"            },\n        {\"max\",                      1879,                                                  \"er_innodb_ft_aux_not_hex_id\"},\n        {\"gt_max\",                   1880,                                                  \"<unknown server error>\"     },\n        {\"3000_range\",               3000,                                                  \"<unknown server error>\"     },\n        {\"int_max\",                  (std::numeric_limits<int>::max)(),                     \"<unknown server error>\"     }\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST(error_code(static_cast<common_server_errc>(tc.err)).message() == tc.expected_msg);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_to_string_coverage)\n{\n    // Check that no value causes problems.\n    for (int i = 1000; i <= 1880; ++i)\n    {\n        BOOST_CHECK_NO_THROW(error_code(static_cast<common_server_errc>(i)).message());\n    }\n}\n\nBOOST_AUTO_TEST_CASE(make_error_code)\n{\n    error_code code(common_server_errc::er_bad_db_error);\n    BOOST_TEST(code.value() == static_cast<int>(common_server_errc::er_bad_db_error));\n    BOOST_TEST(&code.category() == &get_common_server_category());  // categories are not printable\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/buffer_params.hpp>\n#include <boost/mysql/connection.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/tcp.hpp>\n#include <boost/mysql/tcp_ssl.hpp>\n\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing asio::deferred;\n\nBOOST_AUTO_TEST_SUITE(test_connection_)\n\nBOOST_AUTO_TEST_CASE(init_ctor)\n{\n    asio::io_context ctx;\n    tcp_connection c{ctx.get_executor()};\n    BOOST_TEST((c.get_executor() == ctx.get_executor()));\n    BOOST_TEST((c.stream().get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(init_ctor_with_buffer_params)\n{\n    asio::io_context ctx;\n    tcp_connection c{buffer_params(4096), ctx.get_executor()};\n    BOOST_TEST((c.get_executor() == ctx.get_executor()));\n    BOOST_TEST((c.stream().get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(init_ctor_with_buffer_params_rvalue)\n{\n    asio::io_context ctx;\n    tcp_connection::stream_type sock{ctx.get_executor()};\n    tcp_connection c{buffer_params(4096), std::move(sock)};\n    BOOST_CHECK_NO_THROW(c.stream().get_executor());\n}\n\n// move ctor\nBOOST_AUTO_TEST_CASE(move_ctor)\n{\n    asio::io_context ctx;\n    tcp_connection c1{ctx.get_executor()};\n    tcp_connection c2{std::move(c1)};\n    BOOST_TEST((c2.get_executor() == ctx.get_executor()));\n}\n\n// move assign\nBOOST_AUTO_TEST_CASE(move_assign_to_moved_from)\n{\n    asio::io_context ctx;\n    tcp_connection moved_from{ctx.get_executor()};\n    tcp_connection other{std::move(moved_from)};\n    tcp_connection conn{ctx.get_executor()};\n    moved_from = std::move(conn);\n    BOOST_TEST((moved_from.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(move_assign_to_valid)\n{\n    asio::io_context ctx;\n    tcp_connection c1{ctx.get_executor()};\n    tcp_connection c2{ctx.get_executor()};\n    c1 = std::move(c2);\n    BOOST_TEST((c1.get_executor() == ctx.get_executor()));\n}\n\nBOOST_AUTO_TEST_CASE(set_meta_mode)\n{\n    asio::io_context ctx;\n\n    // Default metadata mode\n    tcp_connection conn{ctx.get_executor()};\n    BOOST_TEST(conn.meta_mode() == metadata_mode::minimal);\n\n    // Setting it causes effect\n    conn.set_meta_mode(metadata_mode::full);\n    BOOST_TEST(conn.meta_mode() == metadata_mode::full);\n}\n\n// rebind_executor\nusing other_exec = asio::strand<asio::any_io_executor>;\nstatic_assert(\n    std::is_same<\n        typename tcp_connection::rebind_executor<other_exec>::other,\n        connection<asio::basic_stream_socket<asio::ip::tcp, other_exec>>>::value,\n    \"\"\n);\nstatic_assert(\n    std::is_same<\n        typename tcp_ssl_connection::rebind_executor<other_exec>::other,\n        connection<asio::ssl::stream<asio::basic_stream_socket<asio::ip::tcp, other_exec>>>>::value,\n    \"\"\n);\n\n// Verify that connection doesn't cause compilation errors for a minimal stream type\nstruct stream_archetype\n{\n    // Executor\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return {}; }\n\n    // Reading\n    std::size_t read_some(asio::mutable_buffer, error_code&) { return 0; }\n\n    template <class CompletionToken>\n    void async_read_some(asio::mutable_buffer, CompletionToken&&)\n    {\n    }\n\n    // Writing\n    std::size_t write_some(asio::const_buffer, error_code&) { return 0; }\n\n    template <class CompletionToken>\n    void async_write_some(asio::const_buffer, CompletionToken&&)\n    {\n    }\n};\n\nconnection<stream_archetype> archetype_conn;\n\n// spotcheck: deferred compiles even in C++11\nvoid deferred_spotcheck()\n{\n    asio::io_context ctx;\n    tcp_connection conn(ctx);\n    handshake_params params(\"myuser\", \"mypasswd\");\n    asio::ip::tcp::endpoint ep;\n    diagnostics diag;\n    results result;\n    execution_state st;\n    statement stmt;\n    std::string str;\n    const std::string const_str;\n\n    (void)conn.async_handshake(params, deferred);\n    (void)conn.async_handshake(params, diag, deferred);\n\n    (void)conn.async_execute(\"SELECT 1\", result, deferred);\n    (void)conn.async_execute(str, result, deferred);\n    (void)conn.async_execute(const_str, result, deferred);\n    (void)conn.async_execute(\"SELECT 1\", result, diag, deferred);\n    (void)conn.async_execute(str, result, diag, deferred);\n    (void)conn.async_execute(const_str, result, diag, deferred);\n\n    (void)conn.async_start_execution(\"SELECT 1\", st, deferred);\n    (void)conn.async_start_execution(str, st, deferred);\n    (void)conn.async_start_execution(const_str, st, deferred);\n    (void)conn.async_start_execution(\"SELECT 1\", st, diag, deferred);\n    (void)conn.async_start_execution(str, st, diag, deferred);\n    (void)conn.async_start_execution(const_str, st, diag, deferred);\n\n    (void)conn.async_read_some_rows(st, deferred);\n    (void)conn.async_read_some_rows(st, diag, deferred);\n\n    (void)conn.async_read_resultset_head(st, deferred);\n    (void)conn.async_read_resultset_head(st, diag, deferred);\n\n    (void)conn.async_prepare_statement(\"SELECT 1\", deferred);\n    (void)conn.async_prepare_statement(\"SELECT 1\", diag, deferred);\n\n    (void)conn.async_close_statement(stmt, deferred);\n    (void)conn.async_close_statement(stmt, diag, deferred);\n\n    (void)conn.async_reset_connection(deferred);\n    (void)conn.async_reset_connection(diag, deferred);\n\n    (void)conn.async_ping(deferred);\n    (void)conn.async_ping(diag, deferred);\n\n    (void)conn.async_quit(deferred);\n    (void)conn.async_quit(diag, deferred);\n\n    (void)conn.async_close(deferred);\n    (void)conn.async_close(diag, deferred);\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_connection\n"
  },
  {
    "path": "test/unit/test/connection_pool/connection_pool_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/connection_node.hpp>\n#include <boost/mysql/impl/internal/connection_pool/connection_pool_impl.hpp>\n#include <boost/mysql/impl/internal/connection_pool/internal_pool_params.hpp>\n#include <boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp>\n\n#include <boost/asio/any_completion_handler.hpp>\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/bind_cancellation_slot.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/bind_immediate_executor.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/compose.hpp>\n#include <boost/asio/coroutine.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/experimental/channel.hpp>\n#include <boost/asio/experimental/channel_error.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/steady_timer.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/assert/source_location.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/data/test_case.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <cstddef>\n#include <memory>\n#include <ostream>\n#include <utility>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/source_location.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n#include \"test_unit/mock_timer.hpp\"\n#include \"test_unit/printing.hpp\"\n\n// These tests rely on channels, which are not compatible with this\n// See https://github.com/chriskohlhoff/asio/issues/1398\n#ifndef BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing boost::test_tools::per_element;\nusing detail::node_status;\nusing std::chrono::steady_clock;\nnamespace data = boost::unit_test::data;\n\n/**\n * These tests verify step-by-step that all interactions between\n * elements in connection_pool work as intended. They use the templating\n * on IoTraits to mock out I/O objects. This allows for fast and reliable tests.\n * Boost.Asio lacks testing infrastructure, so we've coded some here.\n * These are complex tests.\n */\n\nBOOST_AUTO_TEST_SUITE(test_connection_pool_impl)\n\nenum class fn_type\n{\n    connect,\n    pipeline,\n    ping,\n};\n\nstd::ostream& operator<<(std::ostream& os, fn_type t)\n{\n    switch (t)\n    {\n    case fn_type::connect: return os << \"fn_type::connect\";\n    case fn_type::pipeline: return os << \"fn_type::pipeline\";\n    case fn_type::ping: return os << \"fn_type::ping\";\n    default: return os << \"<unknown fn_type>\";\n    }\n}\n\n// A mock for mysql::any_connection. This allows us to control\n// when and how operations like async_connect or async_ping complete,\n// make assertions on the passed parameters, and force error conditions.\n// By default, mocked operations stay outstanding until they're acknowledged\n// by the test by calling mock_connection::step. step will wait until the appropriate\n// mocked function is called and will make the outstanding operation complete with\n// the passed error_code/diagnostics. All this synchronization uses channels.\nclass mock_connection\n{\n    struct impl_t\n    {\n        asio::experimental::channel<void(error_code, fn_type)> to_test_chan_;\n        asio::experimental::channel<void(error_code, diagnostics)> from_test_chan_;\n\n        // Transforms the channel-specific cancel code into asio::error::operation_aborted,\n        // which is returned by connections when operations get cancelled\n        static error_code transform_ec(error_code input)\n        {\n            return input == asio::experimental::channel_errc::channel_cancelled\n                       ? asio::error::operation_aborted\n                       : input;\n        }\n\n        // Code shared between all mocked ops\n        struct mocked_op\n        {\n            impl_t& obj;\n            fn_type op_type;\n            diagnostics* diag;\n\n            template <class Self>\n            void operator()(Self& self)\n            {\n                // Notify the test that we're about to do op_type\n                obj.to_test_chan_.async_send(error_code(), op_type, std::move(self));\n            }\n\n            template <class Self>\n            void operator()(Self& self, error_code ec)\n            {\n                if (ec)\n                {\n                    // We were cancelled\n                    self.complete(transform_ec(ec));\n                }\n                else\n                {\n                    // Read from the test what we should return\n                    obj.from_test_chan_.async_receive(std::move(self));\n                }\n            }\n\n            template <class Self>\n            void operator()(Self& self, error_code ec, diagnostics recv_diag)\n            {\n                // Done\n                if (diag)\n                    *diag = std::move(recv_diag);\n                self.complete(transform_ec(ec));\n            }\n        };\n\n        template <class CompletionToken>\n        auto op_impl(fn_type op_type, diagnostics* diag, CompletionToken&& token)\n            -> decltype(asio::async_compose<CompletionToken, void(error_code)>(\n                std::declval<mocked_op>(),\n                token,\n                asio::any_io_executor()\n            ))\n        {\n            return asio::async_compose<CompletionToken, void(error_code)>(\n                mocked_op{*this, op_type, diag},\n                token,\n                to_test_chan_.get_executor()\n            );\n        }\n\n    } impl_;\n\n    struct step_op\n    {\n        impl_t& obj;\n        fn_type expected_op_type;\n        error_code op_ec;\n        diagnostics op_diag;\n\n        template <class Self>\n        void operator()(Self& self)\n        {\n            // Wait until the code under test performs the operation we want\n            obj.to_test_chan_.async_receive(std::move(self));\n        }\n\n        template <class Self>\n        void operator()(Self& self, error_code ec, fn_type actual_op_type)\n        {\n            // Verify it was actually what we wanted\n            BOOST_TEST(ec == error_code());\n            BOOST_TEST(actual_op_type == expected_op_type);\n\n            // Tell the operation what its result should be\n            obj.from_test_chan_.async_send(op_ec, std::move(op_diag), std::move(self));\n        }\n\n        template <class Self>\n        void operator()(Self& self, error_code ec)\n        {\n            // Done\n            BOOST_TEST(ec == error_code());\n            self.complete(error_code());\n        }\n    };\n\n    static void check_stages(const pipeline_request& req)\n    {\n        const detail::pipeline_request_stage expected_stages[] = {\n            {detail::pipeline_stage_kind::reset_connection,  1, {}             },\n            {detail::pipeline_stage_kind::set_character_set, 1, utf8mb4_charset},\n        };\n        BOOST_TEST(detail::access::get_impl(req).stages_ == expected_stages, per_element());\n    }\n\n    static void set_response(std::vector<stage_response>& res)\n    {\n        // Response should have two items, set to empty errors\n        res.resize(2);\n        for (auto& item : res)\n            detail::access::get_impl(item).emplace_error();\n    }\n\npublic:\n    boost::mysql::any_connection_params ctor_params;\n    boost::mysql::connect_params last_connect_params;\n\n    mock_connection(asio::any_io_executor ex, boost::mysql::any_connection_params ctor_params)\n        : impl_{ex, ex}, ctor_params(ctor_params)\n    {\n    }\n\n    template <class CompletionToken>\n    auto async_connect(const connect_params& params, diagnostics& diag, CompletionToken&& token)\n        -> decltype(impl_.op_impl(fn_type::connect, &diag, std::forward<CompletionToken>(token)))\n    {\n        last_connect_params = params;\n        return impl_.op_impl(fn_type::connect, &diag, std::forward<CompletionToken>(token));\n    }\n\n    template <class CompletionToken>\n    auto async_ping(CompletionToken&& token)\n        -> decltype(impl_.op_impl(fn_type::ping, nullptr, std::forward<CompletionToken>(token)))\n    {\n        return impl_.op_impl(fn_type::ping, nullptr, std::forward<CompletionToken>(token));\n    }\n\n    template <class CompletionToken>\n    auto async_run_pipeline(\n        const pipeline_request& req,\n        std::vector<stage_response>& res,\n        CompletionToken&& token\n    ) -> decltype(impl_.op_impl(fn_type::pipeline, nullptr, std::forward<CompletionToken>(token)))\n    {\n        check_stages(req);\n        set_response(res);  // This should technically happen after initiation, but is enough for these tests\n        return impl_.op_impl(fn_type::pipeline, nullptr, std::forward<CompletionToken>(token));\n    }\n\n    template <class CompletionToken>\n    auto step(fn_type expected_op_type, CompletionToken&& token, error_code ec = {}, diagnostics diag = {})\n        -> decltype(asio::async_compose<CompletionToken, void(error_code)>(\n            step_op{impl_, expected_op_type, ec, std::move(diag)},\n            token,\n            impl_.from_test_chan_\n        ))\n    {\n        return asio::async_compose<CompletionToken, void(error_code)>(\n            step_op{impl_, expected_op_type, ec, std::move(diag)},\n            token,\n            impl_.from_test_chan_\n        );\n    }\n};\n\nstruct mock_pooled_connection;\nusing mock_node = detail::basic_connection_node<mock_connection, mock_clock>;\nusing mock_pool = detail::basic_pool_impl<mock_connection, mock_clock, mock_pooled_connection>;\n\n// Mock for pooled_connection\nstruct mock_pooled_connection\n{\n    std::shared_ptr<mock_pool> pool;\n    mock_node* node{};\n\n    mock_pooled_connection() = default;\n    mock_pooled_connection(mock_node& node, std::shared_ptr<mock_pool> pool) noexcept\n        : pool(std::move(pool)), node(&node)\n    {\n    }\n};\n\n// Helper class to launch an async_get_connection and then wait for it\n// and validate its results\nclass get_connection_task\n{\n    struct impl_t\n    {\n        bool called{};\n        mock_pool& pool;\n        mock_node* actual_node{};\n        mock_pool* actual_pool{};\n        error_code actual_ec;\n        bool was_immediate{};  // was the completion immediate?\n        asio::cancellation_signal sig;\n\n        impl_t(mock_pool& p) : pool(p) {}\n    };\n\n    struct handler\n    {\n        tracker_executor_result ex_result;\n        tracker_executor_result immediate_ex_result;\n        std::shared_ptr<impl_t> state;\n        bool bind_slot;\n\n        handler(std::shared_ptr<impl_t> st, bool bind_slot)\n            : ex_result(create_tracker_executor(st->pool.get_executor())),\n              immediate_ex_result(create_tracker_executor(st->pool.get_executor())),\n              state(std::move(st)),\n              bind_slot(bind_slot)\n        {\n        }\n\n        using executor_type = asio::any_io_executor;\n        executor_type get_executor() const { return ex_result.ex; }\n\n        using immediate_executor_type = asio::any_io_executor;\n        immediate_executor_type get_immediate_executor() const { return immediate_ex_result.ex; }\n\n        using cancellation_slot_type = asio::cancellation_slot;\n        cancellation_slot_type get_cancellation_slot() const\n        {\n            return bind_slot ? state->sig.slot() : asio::cancellation_slot();\n        }\n\n        void operator()(error_code ec, mock_pooled_connection conn)\n        {\n            // Check executor\n            bool was_immediate = is_initiation_function();\n            if (was_immediate)\n            {\n                // An immediate completion dispatches to the immediate executor,\n                // then to the token's executor\n                const int expected_stack[] = {immediate_ex_result.executor_id, ex_result.executor_id};\n                BOOST_TEST(executor_stack() == expected_stack, per_element());\n            }\n            else\n            {\n                const int expected_stack[] = {ex_result.executor_id};\n                BOOST_TEST(executor_stack() == expected_stack, per_element());\n            }\n\n            // If the pool was thread-safe, the callback should never be happening from\n            // the pool's strand\n            if (state->pool.params().thread_safe)\n            {\n                BOOST_TEST(!state->pool.strand().running_in_this_thread());\n            }\n\n            state->was_immediate = was_immediate;\n            state->actual_node = conn.node;\n            state->actual_pool = conn.pool.get();\n            state->actual_ec = ec;\n            state->called = true;\n        }\n    };\n\n    std::shared_ptr<impl_t> impl_;\n\n    void wait_impl(\n        mock_node* expected_node,\n        error_code expected_ec,\n        bool expect_immediate,\n        boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    )\n    {\n        auto& ctx = static_cast<asio::io_context&>(impl_->pool.get_executor().context());\n        poll_until(ctx, &impl_->called, loc);\n        BOOST_TEST_CONTEXT(\"Called from \" << loc)\n        {\n            auto* expected_pool = expected_ec ? nullptr : &impl_->pool;\n            BOOST_TEST(impl_->actual_ec == expected_ec);\n            BOOST_TEST(impl_->actual_pool == expected_pool);\n            BOOST_TEST(impl_->actual_node == expected_node);\n            BOOST_TEST(impl_->was_immediate == expect_immediate);\n        }\n    }\n\npublic:\n    get_connection_task(mock_pool& pool, diagnostics* diag, bool bind_slot = true)\n        : impl_(std::make_shared<impl_t>(pool))\n    {\n        // Call the initiating function.\n        // We need to dispatch it so the initiation runs in the io_context, and we can see immediate\n        // completions\n        auto impl = impl_;\n        asio::dispatch(asio::bind_executor(pool.get_executor(), [impl, &pool, diag, bind_slot]() {\n            // Mark that we're calling an initiating function\n            initiation_guard guard;\n\n            // Initiate\n            pool.async_get_connection(diag, handler{impl, bind_slot});\n        }));\n    }\n\n    void wait(\n        mock_node& expected_node,\n        bool expect_immediate,\n        boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    )\n    {\n        wait_impl(&expected_node, error_code(), expect_immediate, loc);\n    }\n\n    void wait(\n        error_code expected_ec,\n        bool expect_immediate,\n        boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    )\n    {\n        wait_impl(nullptr, expected_ec, expect_immediate, loc);\n    }\n\n    void cancel(asio::cancellation_type_t type = asio::cancellation_type_t::terminal)\n    {\n        impl_->sig.emit(type);\n    }\n};\n\nstd::shared_ptr<mock_pool> create_mock_pool(asio::io_context& ctx, pool_params&& params)\n{\n    return std::make_shared<mock_pool>(ctx.get_executor(), std::move(params));\n}\n\nclass fixture : public io_context_fixture\n{\nprivate:\n    // Pool (must be created using dynamic memory)\n    std::shared_ptr<mock_pool> pool_;\n    bool run_finished_{false};\n\npublic:\n    fixture(pool_params&& params, bool call_run = true) : pool_(create_mock_pool(ctx, std::move(params)))\n    {\n        if (call_run)\n            run();\n    }\n\n    ~fixture()\n    {\n        // Finish the pool\n        pool_->cancel();\n        poll_until(ctx, &run_finished_);\n    }\n\n    void run()\n    {\n        pool_->async_run([this](error_code ec) {\n            run_finished_ = true;\n            BOOST_TEST(ec == error_code());\n        });\n    }\n\n    mock_pool& pool() { return *pool_; }\n\n    get_connection_task create_task(diagnostics* diag = nullptr, bool bind_slot = true)\n    {\n        return get_connection_task(*pool_, diag, bind_slot);\n    }\n\n    void check_shared_st(\n        const diagnostics& expected_diag,\n        std::size_t expected_num_pending,\n        std::size_t expected_num_idle\n    )\n    {\n        const auto& st = pool_->shared_state();\n        BOOST_TEST(st.last_connect_diag == expected_diag);\n        BOOST_TEST(st.num_pending_connections == expected_num_pending);\n        BOOST_TEST(st.idle_list.size() == expected_num_idle);\n    }\n\n    // Waits for a status on a certain node\n    void wait_for_status(\n        mock_node& node,\n        node_status status,\n        boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    )\n    {\n        poll_until(ctx, [&node, status]() { return node.status() == status; }, loc);\n    }\n\n    // Waits until there is at least num_nodes connections in the list\n    void wait_for_num_nodes(std::size_t num_nodes, boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION)\n    {\n        poll_until(ctx, [this, num_nodes]() { return pool_->nodes().size() == num_nodes; }, loc);\n    }\n\n    // Wrapper for calling mock_connection::step()\n    void step(\n        mock_node& node,\n        fn_type next_act,\n        error_code ec = {},\n        diagnostics diag = {},\n        boost::source_location loc = BOOST_MYSQL_CURRENT_LOCATION\n    )\n    {\n        node.connection().step(next_act, as_netresult, ec, diag).validate_no_error_nodiag(loc);\n    }\n\n    std::size_t num_pending_requests() const { return pool_->shared_state().num_pending_requests; }\n};\n\n// connection lifecycle\nBOOST_AUTO_TEST_CASE(lifecycle_connect_error)\n{\n    // Setup\n    const auto connect_diag = create_server_diag(\"Connection error!\");\n    const auto expected_diag = create_server_diag(\n        \"Last connection attempt failed with: er_aborting_connection [mysql.common-server:1152]: Connection \"\n        \"error!\"\n    );\n    pool_params params;\n    params.retry_interval = std::chrono::seconds(2);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connection trying to connect\n    fix.wait_for_status(node, node_status::connect_in_progress);\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // Connect fails, so the connection goes to sleep. Diagnostics are stored in shared state.\n    fix.step(node, fn_type::connect, common_server_errc::er_aborting_connection, connect_diag);\n    fix.wait_for_status(node, node_status::sleep_connect_failed_in_progress);\n    fix.check_shared_st(expected_diag, 1, 0);\n\n    // Advance until it's time to retry again\n    mock_clock::advance_time_by(std::chrono::seconds(2));\n    fix.wait_for_status(node, node_status::connect_in_progress);\n    fix.check_shared_st(expected_diag, 1, 0);\n\n    // Connection connects successfully this time. Diagnostics have\n    // been cleared and the connection is marked as idle\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_connect_timeout)\n{\n    // Setup\n    pool_params params;\n    params.connect_timeout = std::chrono::seconds(5);\n    params.retry_interval = std::chrono::seconds(2);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connection trying to connect\n    fix.wait_for_status(node, node_status::connect_in_progress);\n\n    // Timeout elapses. Connect is considered failed\n    const auto expected_diag = create_client_diag(\"Last connection attempt timed out\");\n    mock_clock::advance_time_by(std::chrono::seconds(5));\n    fix.wait_for_status(node, node_status::sleep_connect_failed_in_progress);\n    fix.check_shared_st(expected_diag, 1, 0);\n\n    // Advance until it's time to retry again\n    mock_clock::advance_time_by(std::chrono::seconds(2));\n    fix.wait_for_status(node, node_status::connect_in_progress);\n    fix.check_shared_st(expected_diag, 1, 0);\n\n    // Connection connects successfully this time\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_return_without_reset)\n{\n    // Setup\n    fixture fix(pool_params{});\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n\n    // Simulate a user picking the connection\n    node.mark_as_in_use();\n    fix.check_shared_st(diagnostics(), 0, 0);\n\n    // Simulate a user returning the connection (without reset)\n    fix.pool().return_connection(node, false);\n\n    // The connection goes back to idle without invoking resets\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_reset_success)\n{\n    // Setup\n    fixture fix(pool_params{});\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected, then pick it up\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    node.mark_as_in_use();\n\n    // Simulate a user returning the connection (with reset)\n    fix.pool().return_connection(node, true);\n\n    // A reset is issued\n    fix.wait_for_status(node, node_status::reset_in_progress);\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // Successful reset makes the connection idle again\n    fix.step(node, fn_type::pipeline);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_reset_error)\n{\n    // Setup\n    fixture fix(pool_params{});\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connect, pick up and return a connection\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    node.mark_as_in_use();\n    fix.pool().return_connection(node, true);\n    fix.wait_for_status(node, node_status::reset_in_progress);\n\n    // Reset fails. This triggers a reconnection. Diagnostics are not saved\n    fix.step(node, fn_type::pipeline, common_server_errc::er_aborting_connection);\n    fix.wait_for_status(node, node_status::connect_in_progress);\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // Reconnect succeeds. We're idle again\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_reset_timeout)\n{\n    // Setup\n    pool_params params;\n    params.ping_timeout = std::chrono::seconds(1);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connect, pick up and return a connection\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    node.mark_as_in_use();\n    fix.pool().return_connection(node, true);\n    fix.wait_for_status(node, node_status::reset_in_progress);\n\n    // Reset times out. This triggers a reconnection\n    mock_clock::advance_time_by(std::chrono::seconds(1));\n    fix.wait_for_status(node, node_status::connect_in_progress);\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // Reconnect succeeds. We're idle again\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_reset_timeout_disabled)\n{\n    // Setup\n    pool_params params;\n    params.ping_timeout = std::chrono::seconds(0);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connect, pick up and return a connection\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    node.mark_as_in_use();\n    fix.pool().return_connection(node, true);\n    fix.wait_for_status(node, node_status::reset_in_progress);\n\n    // Reset doesn't time out, regardless of how much time we wait\n    mock_clock::advance_time_by(std::chrono::hours(9999));\n    poll_until(fix.ctx, [&]() { return node.status() == node_status::reset_in_progress; });\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // Reset succeeds\n    fix.step(node, fn_type::pipeline);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_ping_success)\n{\n    // Setup\n    pool_params params;\n    params.ping_interval = std::chrono::seconds(100);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n\n    // Wait until ping interval ellapses. This triggers a ping\n    mock_clock::advance_time_by(std::chrono::seconds(100));\n    fix.wait_for_status(node, node_status::ping_in_progress);\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // After ping succeeds, connection goes back to idle\n    fix.step(node, fn_type::ping);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_ping_error)\n{\n    // Setup\n    pool_params params;\n    params.ping_interval = std::chrono::seconds(100);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n\n    // Wait until ping interval ellapses\n    mock_clock::advance_time_by(std::chrono::seconds(100));\n\n    // Ping fails. This triggers a reconnection. Diagnostics are not saved\n    fix.step(node, fn_type::ping, common_server_errc::er_aborting_connection);\n    fix.wait_for_status(node, node_status::connect_in_progress);\n    fix.check_shared_st(diagnostics(), 1, 0);\n\n    // Reconnection succeeds\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_ping_timeout)\n{\n    // Setup\n    pool_params params;\n    params.ping_interval = std::chrono::seconds(100);\n    params.ping_timeout = std::chrono::seconds(2);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n\n    // Wait until ping interval ellapses\n    mock_clock::advance_time_by(std::chrono::seconds(100));\n    fix.wait_for_status(node, node_status::ping_in_progress);\n\n    // Ping times out. This triggers a reconnection. Diagnostics are not saved\n    mock_clock::advance_time_by(std::chrono::seconds(2));\n    fix.wait_for_status(node, node_status::connect_in_progress);\n\n    // Reconnection succeeds\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_ping_timeout_disabled)\n{\n    // Setup\n    pool_params params;\n    params.ping_interval = std::chrono::seconds(100);\n    params.ping_timeout = std::chrono::seconds(0);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n\n    // Wait until ping interval ellapses\n    mock_clock::advance_time_by(std::chrono::seconds(100));\n    fix.wait_for_status(node, node_status::ping_in_progress);\n\n    // Ping doesn't time out, regardless of how much we wait\n    mock_clock::advance_time_by(std::chrono::hours(9999));\n    poll_until(fix.ctx, [&]() { return node.status() == node_status::ping_in_progress; });\n\n    // Ping succeeds\n    fix.step(node, fn_type::ping);\n    fix.wait_for_status(node, node_status::idle);\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\nBOOST_AUTO_TEST_CASE(lifecycle_ping_disabled)\n{\n    // Setup\n    pool_params params;\n    params.ping_interval = std::chrono::seconds(0);\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Wait until a connection is successfully connected\n    fix.step(node, fn_type::connect);\n    fix.wait_for_status(node, node_status::idle);\n\n    // Connection won't ping, regardless of how much time we wait\n    mock_clock::advance_time_by(std::chrono::hours(9999));\n    poll_until(fix.ctx, [&]() { return node.status() == node_status::idle; });\n    fix.check_shared_st(diagnostics(), 0, 1);\n}\n\n// async_get_connection. Some cases are run with/without binding a cancel slot,\n// and in thread-safe/unsafe mode\nBOOST_AUTO_TEST_CASE(get_connection_immediate_completion)\n{\n    struct\n    {\n        bool bind_slot;\n        bool thread_safe;\n    } test_cases[] = {\n        {false, false},\n        {true,  false},\n        {false, true },\n        {true,  true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(\"bind_slot: \" << tc.bind_slot << \", thread_safe: \" << tc.thread_safe)\n        {\n            // Setup\n            pool_params params;\n            params.thread_safe = tc.thread_safe;\n            fixture fix(std::move(params));\n\n            fix.wait_for_num_nodes(1);\n            auto& node = fix.pool().nodes().front();\n\n            // Wait for a connection to be ready\n            fix.step(node, fn_type::connect);\n            fix.wait_for_status(node, node_status::idle);\n            BOOST_TEST(fix.num_pending_requests() == 0u);\n\n            // A request for a connection is issued. The request completes immediately.\n            // In thread-safe mode, we still need to exit the strand, so we won't see an inline\n            // completion\n            fix.create_task(nullptr, tc.bind_slot).wait(node, !tc.thread_safe);\n            BOOST_TEST(node.status() == node_status::in_use);\n            BOOST_TEST(fix.pool().nodes().size() == 1u);\n            BOOST_TEST(fix.num_pending_requests() == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_wait_success)\n{\n    struct\n    {\n        bool bind_slot;\n        bool thread_safe;\n    } test_cases[] = {\n        {false, false},\n        {true,  false},\n        {false, true },\n        {true,  true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(\"bind_slot: \" << tc.bind_slot << \", thread_safe: \" << tc.thread_safe)\n        {\n            // Setup\n            pool_params params;\n            params.retry_interval = std::chrono::seconds(2);\n            params.thread_safe = tc.thread_safe;\n            fixture fix(std::move(params));\n\n            fix.wait_for_num_nodes(1);\n            auto& node = fix.pool().nodes().front();\n\n            // Connection tries to connect and fails\n            fix.step(node, fn_type::connect, common_server_errc::er_aborting_connection);\n            fix.wait_for_status(node, node_status::sleep_connect_failed_in_progress);\n\n            // A request for a connection is issued. The request doesn't find\n            // any available connection, and the current one is pending, so no new connections are created\n            auto task = fix.create_task(nullptr, tc.bind_slot);\n            fix.ctx.poll();\n            BOOST_TEST(fix.pool().nodes().size() == 1u);\n            BOOST_TEST(fix.num_pending_requests() == 1u);\n\n            // Retry interval ellapses and connection retries and succeeds\n            mock_clock::advance_time_by(std::chrono::seconds(2));\n            fix.step(node, fn_type::connect);\n\n            // Request is fulfilled\n            task.wait(node, false);\n            BOOST_TEST(node.status() == node_status::in_use);\n            BOOST_TEST(fix.pool().nodes().size() == 1u);\n            BOOST_TEST(fix.num_pending_requests() == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_wait_before_run)\n{\n    // Getting connections before async_run gets called waits\n    // Setup\n    fixture fix(pool_params{}, false);  // don't call run\n\n    // Two requests are issued (> initial_size). They don't create new nodes and wait\n    auto task1 = fix.create_task();\n    auto task2 = fix.create_task();\n    fix.ctx.poll();\n    BOOST_TEST(fix.pool().nodes().size() == 0u);\n    BOOST_TEST(fix.num_pending_requests() == 2u);\n\n    // Run the pool. Two nodes are created\n    fix.run();\n    fix.wait_for_num_nodes(2);\n    auto& node1 = fix.pool().nodes().front();\n    auto& node2 = fix.pool().nodes().back();\n    BOOST_TEST(fix.num_pending_requests() == 2u);\n\n    // The two connections become ready, and the tasks complete\n    fix.step(node1, fn_type::connect);\n    fix.step(node2, fn_type::connect);\n    task1.wait(node1, false);\n    task2.wait(node2, false);\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_wait_op_cancelled)\n{\n    // verify that cancelling works for all cancel types and thread-safety modes\n    struct\n    {\n        string_view name;\n        asio::cancellation_type_t cancel_type;\n        bool thread_safe;\n    } test_cases[]{\n        {\"terminal\",      asio::cancellation_type_t::terminal, false},\n        {\"partial\",       asio::cancellation_type_t::partial,  false},\n        {\"total\",         asio::cancellation_type_t::total,    false},\n        {\"safe_terminal\", asio::cancellation_type_t::terminal, true },\n        {\"safe_partial\",  asio::cancellation_type_t::partial,  true },\n        {\"safe_total\",    asio::cancellation_type_t::total,    true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(pool_params{});\n            diagnostics diag;\n\n            fix.wait_for_num_nodes(1);\n\n            // A request for a connection is issued. The request doesn't find\n            // any available connection, and the current one is pending, so no new connections are created\n            auto task = fix.create_task(&diag);\n            fix.ctx.poll();\n            BOOST_TEST(fix.pool().nodes().size() == 1u);\n            BOOST_TEST(fix.num_pending_requests() == 1u);\n\n            // The connection fails to connect\n            fix.step(\n                *fix.pool().nodes().begin(),\n                fn_type::connect,\n                common_server_errc::er_bad_db_error,\n                create_server_diag(\"Bad db\")\n            );\n\n            // The request gets cancelled. Appropriate diagnostics are returned\n            task.cancel(tc.cancel_type);\n            task.wait(client_errc::no_connection_available, false);\n            BOOST_TEST(\n                diag ==\n                create_server_diag(\n                    \"Last connection attempt failed with: er_bad_db_error [mysql.common-server:1049]: Bad db\"\n                )\n            );\n            BOOST_TEST(fix.pool().nodes().size() == 1u);\n            BOOST_TEST(fix.num_pending_requests() == 0u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_wait_op_cancelled_no_diag_available)\n{\n    // No diagnostics are returned if the first connect op hasn't finished yet\n    // Setup\n    fixture fix(pool_params{});\n    diagnostics diag;\n\n    // A request for a connection is issued\n    auto task = fix.create_task(&diag);\n    fix.ctx.poll();\n\n    // The request gets cancelled. No diagnostics is available, so nothing is returned\n    task.cancel();\n    task.wait(client_errc::no_connection_available, false);\n    BOOST_TEST(diag == diagnostics());\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_wait_op_cancelled_timeout)\n{\n    // When connect times out, appropriate diagnostics are generated\n    // Setup\n    pool_params params;\n    params.connect_timeout = std::chrono::seconds(5);\n    fixture fix(std::move(params));\n    diagnostics diag;\n\n    fix.wait_for_num_nodes(1);\n\n    // A request for a connection is issued. The request doesn't find\n    // any available connection, and the current one is pending, so no new connections are created\n    auto task = fix.create_task(&diag);\n    fix.ctx.poll();\n    BOOST_TEST(fix.pool().nodes().size() == 1u);\n    BOOST_TEST(fix.num_pending_requests() == 1u);\n\n    // The connection attempt times out\n    mock_clock::advance_time_by(std::chrono::seconds(6));\n    fix.wait_for_status(fix.pool().nodes().front(), node_status::sleep_connect_failed_in_progress);\n\n    // The request gets cancelled. We get the expected error\n    task.cancel();\n    task.wait(client_errc::no_connection_available, false);\n    BOOST_TEST(diag == create_client_diag(\"Last connection attempt timed out\"));\n    BOOST_TEST(fix.pool().nodes().size() == 1u);\n    BOOST_TEST(fix.num_pending_requests() == 0u);\n}\n\nBOOST_DATA_TEST_CASE_F(\n    io_context_fixture,\n    get_connection_wait_op_cancelled_pool_not_running,\n    data::make({false, true})\n)\n{\n    // If the op is cancelled because the pool is not running, appropriate diagnostics are issued\n    // Setup\n    pool_params params;\n    params.thread_safe = sample;\n    auto pool = create_mock_pool(ctx, std::move(params));\n    diagnostics diag;\n\n    // A request for a connection is issued. The request finds the pool not running,\n    // and waits\n    get_connection_task task(*pool, &diag);\n    ctx.poll();\n    BOOST_TEST(pool->shared_state().num_pending_requests == 1u);\n\n    // The request gets cancelled. We get the expected error\n    task.cancel();\n    task.wait(client_errc::pool_not_running, false);\n    BOOST_TEST(diag == diagnostics());\n    BOOST_TEST(pool->shared_state().num_pending_requests == 0u);\n\n    pool->cancel();\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_wait_op_cancelled_diag_nullptr)\n{\n    // We don't crash if diag is nullptr\n    // Setup\n    fixture fix(pool_params{});\n\n    fix.wait_for_num_nodes(1);\n\n    // A request for a connection is issued. The request doesn't find\n    // any available connection, and the current one is pending, so no new connections are created\n    auto task = fix.create_task(nullptr);\n    fix.ctx.poll();\n    BOOST_TEST(fix.pool().nodes().size() == 1u);\n\n    // The connection fails to connect\n    fix.step(\n        *fix.pool().nodes().begin(),\n        fn_type::connect,\n        common_server_errc::er_bad_db_error,\n        create_server_diag(\"Bad db\")\n    );\n\n    // The request gets cancelled\n    task.cancel();\n    task.wait(client_errc::no_connection_available, false);\n    BOOST_TEST(fix.pool().nodes().size() == 1u);\n}\n\nBOOST_DATA_TEST_CASE(get_connection_wait_pool_cancelled, data::make({false, true}))\n{\n    // Setup\n    pool_params params;\n    params.thread_safe = sample;\n    fixture fix(std::move(params));\n    diagnostics diag;\n\n    fix.wait_for_num_nodes(1);\n\n    // A request for a connection is issued. The request doesn't find\n    // any available connection, and the current one is pending, so no new connections are created\n    auto task = fix.create_task(&diag);\n    fix.ctx.poll();\n    BOOST_TEST(fix.pool().nodes().size() == 1u);\n    BOOST_TEST(fix.num_pending_requests() == 1u);\n\n    // The connection fails to connect\n    fix.step(\n        *fix.pool().nodes().begin(),\n        fn_type::connect,\n        common_server_errc::er_bad_db_error,\n        create_server_diag(\"Bad db\")\n    );\n\n    // The pool gets cancelled\n    fix.pool().cancel();\n\n    // This causes the request to get cancelled.\n    // No diagnostics are provided here, as they're usually misleading\n    task.wait(client_errc::pool_cancelled, false);\n    BOOST_TEST(diag == diagnostics());\n    BOOST_TEST(fix.num_pending_requests() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_connection_creation)\n{\n    // Setup\n    pool_params params;\n    params.initial_size = 1;\n    params.max_size = 2;\n    fixture fix(std::move(params));\n\n    fix.wait_for_num_nodes(1);\n    auto& node1 = fix.pool().nodes().front();\n\n    // Wait for a connection to be ready, then get it from the pool\n    fix.step(node1, fn_type::connect);\n    fix.wait_for_status(node1, node_status::idle);\n    fix.create_task().wait(node1, true);\n    BOOST_TEST(fix.num_pending_requests() == 0u);\n\n    // Another request is issued. The connection we have is in use, so another one is created.\n    // Since this is not immediate, the task will need to wait\n    auto task2 = fix.create_task();\n    fix.ctx.poll();\n    auto node2 = &*std::next(fix.pool().nodes().begin());\n    BOOST_TEST(fix.num_pending_requests() == 1u);\n\n    // Connection connects successfully and is handed to us\n    fix.step(*node2, fn_type::connect);\n    task2.wait(*node2, false);\n    BOOST_TEST(node2->status() == node_status::in_use);\n    BOOST_TEST(fix.pool().nodes().size() == 2u);\n    BOOST_TEST(fix.num_pending_requests() == 0u);\n\n    // Another request is issued. All connections are in use but max size is already\n    // reached, so no new connection is created\n    auto task3 = fix.create_task();\n    fix.ctx.poll();\n    BOOST_TEST(fix.pool().nodes().size() == 2u);\n    BOOST_TEST(fix.num_pending_requests() == 1u);\n\n    // When one of the connections is returned, the request is fulfilled\n    fix.pool().return_connection(*node2, false);\n    task3.wait(*node2, false);\n    BOOST_TEST(fix.pool().nodes().size() == 2u);\n    BOOST_TEST(fix.num_pending_requests() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_multiple_requests)\n{\n    // Setup\n    pool_params params;\n    params.initial_size = 1;\n    params.max_size = 2;\n    fixture fix(std::move(params));\n\n    // 1 connection node is initially created\n    fix.wait_for_num_nodes(1);\n\n    // Issue some parallel requests\n    auto task1 = fix.create_task();\n    auto task2 = fix.create_task();\n    auto task3 = fix.create_task();\n    auto task4 = fix.create_task(nullptr);\n    auto task5 = fix.create_task();\n\n    // This should create the other node\n    fix.wait_for_num_nodes(2);\n    BOOST_TEST(fix.num_pending_requests() == 5u);\n\n    // Two connections can be created. These fulfill two requests\n    auto node1 = &fix.pool().nodes().front();\n    auto node2 = &*std::next(fix.pool().nodes().begin());\n    fix.step(*node1, fn_type::connect);\n    fix.step(*node2, fn_type::connect);\n    task1.wait(*node1, false);\n    task2.wait(*node2, false);\n    BOOST_TEST(fix.num_pending_requests() == 3u);\n\n    // task4 gets cancelled\n    task4.cancel();\n    task4.wait(client_errc::no_connection_available, false);\n    BOOST_TEST(fix.num_pending_requests() == 2u);\n\n    // A connection is returned. The first task to enter is served\n    fix.pool().return_connection(*node1, true);\n    fix.step(*node1, fn_type::pipeline);\n    task3.wait(*node1, false);\n    BOOST_TEST(fix.num_pending_requests() == 1u);\n\n    // The next connection to be returned is for task5\n    fix.pool().return_connection(*node2, false);\n    task5.wait(*node2, false);\n\n    // Done\n    BOOST_TEST(fix.pool().nodes().size() == 2u);\n    BOOST_TEST(fix.num_pending_requests() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(get_connection_supports_cancel_type)\n{\n    using ct = asio::cancellation_type_t;\n\n    struct\n    {\n        string_view name;\n        asio::cancellation_type_t input;\n        bool expected;\n    } test_cases[] = {\n        {\"none\",                       ct::none,                               false},\n        {\"all\",                        ct::all,                                true },\n        {\"terminal\",                   ct::terminal,                           true },\n        {\"partial\",                    ct::partial,                            true },\n        {\"total\",                      ct::total,                              true },\n        {\"terminal | partial\",         ct::terminal | ct::partial,             true },\n        {\"terminal | total\",           ct::terminal | ct::total,               true },\n        {\"partial | total\",            ct::partial | ct::total,                true },\n        {\"total | terminal | partial\", ct::total | ct::terminal | ct::partial, true },\n        {\"unknown\",                    static_cast<ct>(0xf000),                false},\n        {\"unknown | terminal\",         static_cast<ct>(0xf000) | ct::terminal, true },\n        {\"unknown | total\",            static_cast<ct>(0xf000) | ct::total,    true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST(mock_pool::get_connection_supports_cancel_type(tc.input) == tc.expected);\n        }\n    }\n}\n\n// async_run\nBOOST_AUTO_TEST_CASE(run_supports_cancel_type)\n{\n    using ct = asio::cancellation_type_t;\n\n    struct\n    {\n        string_view name;\n        asio::cancellation_type_t input;\n        bool expected;\n    } test_cases[] = {\n        {\"none\",                       ct::none,                               false},\n        {\"all\",                        ct::all,                                true },\n        {\"terminal\",                   ct::terminal,                           true },\n        {\"partial\",                    ct::partial,                            true },\n        {\"total\",                      ct::total,                              false},\n        {\"terminal | partial\",         ct::terminal | ct::partial,             true },\n        {\"terminal | total\",           ct::terminal | ct::total,               true },\n        {\"partial | total\",            ct::partial | ct::total,                true },\n        {\"total | terminal | partial\", ct::total | ct::terminal | ct::partial, true },\n        {\"unknown\",                    static_cast<ct>(0xf000),                false},\n        {\"unknown | terminal\",         static_cast<ct>(0xf000) | ct::terminal, true },\n        {\"unknown | total\",            static_cast<ct>(0xf000) | ct::total,    false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST(mock_pool::run_supports_cancel_type(tc.input) == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(run_op_cancel)\n{\n    struct test_case\n    {\n        string_view name;\n        asio::cancellation_type_t cancel_type;\n        bool thread_safe;\n    } test_cases[]{\n        {\"terminal\",      asio::cancellation_type_t::terminal, false},\n        {\"partial\",       asio::cancellation_type_t::partial,  false},\n        {\"safe_terminal\", asio::cancellation_type_t::terminal, true },\n        {\"safe_partial\",  asio::cancellation_type_t::partial,  true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Create a pool\n            io_context_fixture fix;\n            pool_params params;\n            params.thread_safe = tc.thread_safe;\n            auto pool = create_mock_pool(fix.ctx, std::move(params));\n\n            // Run with a bound signal\n            bool run_finished = false;\n            asio::cancellation_signal sig;\n            pool->async_run(asio::bind_cancellation_slot(sig.slot(), [&run_finished](error_code ec) {\n                run_finished = true;\n                BOOST_TEST(ec == error_code());\n            }));\n\n            // Emit the signal. run should finish\n            sig.emit(tc.cancel_type);\n            poll_until(fix.ctx, &run_finished);\n\n            // The pool has effectively been cancelled, as if cancel() had been called\n            get_connection_task(*pool, nullptr).wait(client_errc::pool_cancelled, !tc.thread_safe);\n        }\n    }\n}\n\n// async_run with a bound signal that doesn't get emitted doesn't cause trouble\nBOOST_FIXTURE_TEST_CASE(run_bound_signal, io_context_fixture)\n{\n    // Create a pool\n    pool_params params;\n    params.thread_safe = true;\n    auto pool = create_mock_pool(ctx, std::move(params));\n\n    // Run with a bound signal\n    bool run_finished = false;\n    asio::cancellation_signal sig;\n    pool->async_run(asio::bind_cancellation_slot(sig.slot(), [&run_finished](error_code ec) {\n        run_finished = true;\n        BOOST_TEST(ec == error_code());\n    }));\n\n    // Cancel (but not using the signal)\n    pool->cancel();\n\n    // Finish successfully\n    poll_until(ctx, &run_finished);\n}\n\n// pool size 0 works\nBOOST_AUTO_TEST_CASE(initial_size_0)\n{\n    // Setup\n    pool_params params;\n    params.initial_size = 0;\n    fixture fix(std::move(params));\n\n    // No connections created at this point. A connection request arrives\n    BOOST_TEST(fix.pool().nodes().size() == 0u);\n    auto task = fix.create_task();\n\n    // This creates a new connection, which fulfills the request\n    fix.ctx.poll();\n    BOOST_TEST(fix.pool().nodes().size() == 1u);\n    fix.step(fix.pool().nodes().front(), fn_type::connect);\n    task.wait(fix.pool().nodes().front(), false);\n}\n\n// pool_params have the intended effect\nBOOST_AUTO_TEST_CASE(params_ssl_ctx_buffsize)\n{\n    // Setup. Pass a custom ssl context and buffer size\n    // SSL context matching is performed using the underlying handle\n    // because ssl::context provides no way to query the options previously set\n    pool_params params;\n    params.ssl_ctx.emplace(boost::asio::ssl::context::tlsv12_client);\n    params.initial_buffer_size = 16u;\n    auto handle = params.ssl_ctx->native_handle();\n    fixture fix(std::move(params));\n\n    // Wait for the node to be created\n    fix.wait_for_num_nodes(1);\n\n    // Check\n    auto ctor_params = fix.pool().nodes().front().connection().ctor_params;\n    BOOST_TEST_REQUIRE(ctor_params.ssl_context != nullptr);\n    BOOST_TEST(ctor_params.ssl_context->native_handle() == handle);\n    BOOST_TEST(ctor_params.initial_buffer_size == 16u);\n}\n\nBOOST_AUTO_TEST_CASE(params_connect_1)\n{\n    // Setup\n    pool_params params;\n    params.server_address.emplace_host_and_port(\"myhost\", 1234);\n    params.username = \"myuser\";\n    params.password = \"mypasswd\";\n    params.database = \"mydb\";\n    params.ssl = boost::mysql::ssl_mode::disable;\n    params.multi_queries = true;\n    fixture fix(std::move(params));\n\n    // Wait for the node to be created\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connect\n    fix.step(node, fn_type::connect);\n\n    // Check params\n    const auto& cparams = node.connection().last_connect_params;\n    BOOST_TEST(cparams.connection_collation == mysql_collations::utf8mb4_general_ci);\n    BOOST_TEST(cparams.server_address.hostname() == \"myhost\");\n    BOOST_TEST(cparams.server_address.port() == std::uint16_t(1234));\n    BOOST_TEST(cparams.username == \"myuser\");\n    BOOST_TEST(cparams.password == \"mypasswd\");\n    BOOST_TEST(cparams.database == \"mydb\");\n    BOOST_TEST(cparams.ssl == boost::mysql::ssl_mode::disable);\n    BOOST_TEST(cparams.multi_queries == true);\n}\n\nBOOST_AUTO_TEST_CASE(params_connect_2)\n{\n    // Setup\n    pool_params params;\n    params.server_address.emplace_unix_path(\"/mysock\");\n    params.username = \"myuser2\";\n    params.password = \"mypasswd2\";\n    params.database = \"mydb2\";\n    params.ssl = boost::mysql::ssl_mode::require;\n    params.multi_queries = false;\n    fixture fix(std::move(params));\n\n    // Wait for the node to be created\n    fix.wait_for_num_nodes(1);\n    auto& node = fix.pool().nodes().front();\n\n    // Connect\n    fix.step(node, fn_type::connect);\n\n    // Check params\n    const auto& cparams = node.connection().last_connect_params;\n    BOOST_TEST(cparams.connection_collation == mysql_collations::utf8mb4_general_ci);\n    BOOST_TEST(cparams.server_address.unix_socket_path() == \"/mysock\");\n    BOOST_TEST(cparams.username == \"myuser2\");\n    BOOST_TEST(cparams.password == \"mypasswd2\");\n    BOOST_TEST(cparams.database == \"mydb2\");\n    BOOST_TEST(cparams.ssl == boost::mysql::ssl_mode::require);\n    BOOST_TEST(cparams.multi_queries == false);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/unit/test/connection_pool/sansio_connection_node.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/mysql_server_errc.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <string>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing detail::collection_state;\nusing detail::next_connection_action;\nusing detail::node_status;\nusing detail::num_connections_to_create;\nusing detail::sansio_connection_node;\n\nBOOST_AUTO_TEST_SUITE(test_sansio_connection_node)\n\nenum hooks_t : int\n{\n    enter_idle = 1,\n    exit_idle = 2,\n    enter_pending = 4,\n    exit_pending = 8,\n};\n\nstruct mock_node : public sansio_connection_node<mock_node>\n{\n    using sansio_connection_node<mock_node>::sansio_connection_node;\n\n    std::size_t num_entering_idle{};\n    std::size_t num_exiting_idle{};\n    std::size_t num_entering_pending{};\n    std::size_t num_exiting_pending{};\n\n    void entering_idle() { ++num_entering_idle; }\n    void exiting_idle() { ++num_exiting_idle; }\n    void entering_pending() { ++num_entering_pending; }\n    void exiting_pending() { ++num_exiting_pending; }\n\n    void clear_hooks()\n    {\n        num_entering_idle = 0;\n        num_exiting_idle = 0;\n        num_entering_pending = 0;\n        num_exiting_pending = 0;\n    }\n\n    void check(node_status expected_status, int hooks)\n    {\n        BOOST_TEST(status() == expected_status);\n        BOOST_TEST(num_entering_idle == (hooks & enter_idle ? 1u : 0u));\n        BOOST_TEST(num_exiting_idle == (hooks & exit_idle ? 1u : 0u));\n        BOOST_TEST(num_entering_pending == (hooks & enter_pending ? 1u : 0u));\n        BOOST_TEST(num_exiting_pending == (hooks & exit_pending ? 1u : 0u));\n        clear_hooks();\n    }\n};\n\n// Success state transitions\nBOOST_AUTO_TEST_CASE(normal_lifecyle)\n{\n    // Initial\n    mock_node nod;\n    nod.check(node_status::initial, 0);\n\n    // First resume yields connect\n    auto act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::connect);\n    nod.check(node_status::connect_in_progress, enter_pending);\n\n    // Connect success\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, exit_pending | enter_idle);\n\n    // Connection taken by user\n    nod.mark_as_in_use();\n    nod.check(node_status::in_use, exit_idle);\n\n    // Connection returned by user\n    act = nod.resume(error_code(), collection_state::needs_collect_with_reset);\n    BOOST_TEST(act == next_connection_action::reset);\n    nod.check(node_status::reset_in_progress, enter_pending);\n\n    // Reset successful\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, exit_pending | enter_idle);\n\n    // Terminate\n    nod.cancel();\n    act = nod.resume(error_code(), collection_state::needs_collect_with_reset);\n    BOOST_TEST(act == next_connection_action::none);\n}\n\nBOOST_AUTO_TEST_CASE(collect_without_reset)\n{\n    // Initial: connection idle\n    mock_node nod(node_status::idle);\n\n    // Connection taken by the user\n    nod.mark_as_in_use();\n    nod.check(node_status::in_use, exit_idle);\n\n    // Connection returned without reset\n    auto act = nod.resume(error_code(), collection_state::needs_collect);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, enter_idle);\n}\n\nBOOST_AUTO_TEST_CASE(collect_still_in_use)\n{\n    // Initial: connection idle\n    mock_node nod(node_status::idle);\n\n    // Connection taken by the user\n    nod.mark_as_in_use();\n    nod.check(node_status::in_use, exit_idle);\n\n    // Idle wait finishes but the connection is still in use\n    auto act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::in_use, 0);\n}\n\nBOOST_AUTO_TEST_CASE(ping_success)\n{\n    // Connection idle\n    mock_node nod(node_status::idle);\n\n    // Time elapses and the connection is not taken by the user\n    auto act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::ping);\n    nod.check(node_status::ping_in_progress, exit_idle | enter_pending);\n\n    // Ping succeeds, we're idle again\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, exit_pending | enter_idle);\n}\n\n// Error state transitions\nBOOST_AUTO_TEST_CASE(connect_error)\n{\n    // Connection trying to connect\n    mock_node nod(node_status::connect_in_progress);\n\n    // Fail connecting\n    auto act = nod.resume(asio::error::operation_aborted, collection_state::none);\n    BOOST_TEST(act == next_connection_action::sleep_connect_failed);\n    nod.check(node_status::sleep_connect_failed_in_progress, 0);\n\n    // Sleep done\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::connect);\n    nod.check(node_status::connect_in_progress, 0);\n\n    // Connect success\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, exit_pending | enter_idle);\n}\n\nBOOST_AUTO_TEST_CASE(ping_error)\n{\n    // Connection idle\n    mock_node nod(node_status::idle);\n\n    // Time elapses and the connection is not taken by the user\n    auto act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::ping);\n    nod.check(node_status::ping_in_progress, exit_idle | enter_pending);\n\n    // Ping fails\n    act = nod.resume(asio::error::operation_aborted, collection_state::none);\n    BOOST_TEST(act == next_connection_action::connect);\n    nod.check(node_status::connect_in_progress, 0);\n\n    // Connect succeeds, we're idle again\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, exit_pending | enter_idle);\n}\n\nBOOST_AUTO_TEST_CASE(reset_error)\n{\n    // Connection in use\n    mock_node nod(node_status::in_use);\n\n    // Returned by the user\n    auto act = nod.resume(error_code(), collection_state::needs_collect_with_reset);\n    BOOST_TEST(act == next_connection_action::reset);\n    nod.check(node_status::reset_in_progress, enter_pending);\n\n    // Reset fails\n    act = nod.resume(asio::error::operation_aborted, collection_state::none);\n    BOOST_TEST(act == next_connection_action::connect);\n    nod.check(node_status::connect_in_progress, 0);\n\n    // Connect succeeds, we're idle again\n    act = nod.resume(error_code(), collection_state::none);\n    BOOST_TEST(act == next_connection_action::idle_wait);\n    nod.check(node_status::idle, exit_pending | enter_idle);\n}\n\nBOOST_AUTO_TEST_CASE(sleep_between_retries_fail)\n{\n    // Note: this is an edge case. This op should not fail unless\n    // canceled, and this would come with a cancel() call\n\n    // Connection trying to connect\n    mock_node nod(node_status::connect_in_progress);\n\n    // Fail connecting\n    auto act = nod.resume(asio::error::operation_aborted, collection_state::none);\n    BOOST_TEST(act == next_connection_action::sleep_connect_failed);\n    nod.check(node_status::sleep_connect_failed_in_progress, 0);\n\n    // Sleep reports an error. It will get ignored\n    act = nod.resume(asio::error::operation_aborted, collection_state::none);\n    BOOST_TEST(act == next_connection_action::connect);\n    nod.check(node_status::connect_in_progress, 0);\n}\n\nBOOST_AUTO_TEST_CASE(idle_wait_fail)\n{\n    // Note: this is an edge case. This op should not fail unless\n    // canceled, and this would come with a cancel() call\n\n    // Connection idle\n    mock_node nod(node_status::idle);\n\n    // Idle wait failed. Error gets ignored\n    auto act = nod.resume(asio::error::operation_aborted, collection_state::none);\n    BOOST_TEST(act == next_connection_action::ping);\n    nod.check(node_status::ping_in_progress, exit_idle | enter_pending);\n}\n\nBOOST_AUTO_TEST_CASE(idle_wait_fail_in_use)\n{\n    // Note: this is an edge case. This op should not fail unless\n    // canceled, and this would come with a cancel() call\n\n    // Connection in use\n    mock_node nod(node_status::in_use);\n\n    // Idle wait failed. Error gets ignored\n    auto act = nod.resume(asio::error::operation_aborted, collection_state::needs_collect_with_reset);\n    BOOST_TEST(act == next_connection_action::reset);\n    nod.check(node_status::reset_in_progress, enter_pending);\n}\n\n// Cancellations\nBOOST_AUTO_TEST_CASE(cancel)\n{\n    struct\n    {\n        node_status initial_status;\n        int hooks;\n    } test_cases[] = {\n        {node_status::connect_in_progress,              exit_pending},\n        {node_status::sleep_connect_failed_in_progress, exit_pending},\n        {node_status::idle,                             exit_idle   },\n        {node_status::in_use,                           0           },\n        {node_status::ping_in_progress,                 exit_pending},\n        {node_status::reset_in_progress,                exit_pending},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.initial_status)\n        {\n            mock_node nod(tc.initial_status);\n\n            // Cancel\n            nod.cancel();\n\n            // Next action will always return none\n            auto act = nod.resume(asio::error::operation_aborted, collection_state::none);\n            BOOST_TEST(act == next_connection_action::none);\n            nod.check(node_status::terminated, tc.hooks);\n\n            // Cancel again does nothing\n            nod.cancel();\n            act = nod.resume(asio::error::operation_aborted, collection_state::none);\n            BOOST_TEST(act == next_connection_action::none);\n            nod.check(node_status::terminated, 0);\n        }\n    }\n}\n\n// Connect diagnostics creation\nBOOST_AUTO_TEST_CASE(create_connect_diagnostics_)\n{\n    struct\n    {\n        string_view name;\n        error_code input_ec;\n        diagnostics input_diag;\n        diagnostics expected;\n    } test_cases[]{\n        // Success\n        {\"no_error\", error_code(), diagnostics(), diagnostics()},\n\n        // Edge case: no error but diagnostics is set. Just ignore its value\n        {\"no_error_diag\", error_code(), create_server_diag(\"something\"), diagnostics()},\n\n        // Timeout (operation_aborted) gets special handling\n        {\"timeout\",\n         asio::error::operation_aborted,\n         diagnostics(),\n         create_client_diag(\"Last connection attempt timed out\")},\n\n        // Network error numbers are OS-specific\n        {\"network_error\",\n         asio::error::network_reset,\n         diagnostics(),\n         create_client_diag(\n             \"Last connection attempt failed with: \" + error_code(asio::error::network_reset).message() +\n             \" [system:\" + std::to_string(static_cast<int>(asio::error::network_reset)) + \"]\"\n         )},\n\n        // Common server, with diagnostics\n        {\"server_error_diag\",\n         common_server_errc::er_no_such_table,\n         create_server_diag(\"Table 'abc' does not exist\"),\n         create_server_diag(\"Last connection attempt failed with: er_no_such_table \"\n                            \"[mysql.common-server:1146]: Table 'abc' does not exist\")},\n\n        // Common server, without diagnostics. Results in a client message, because it contains no server\n        // output\n        {\"server_error_nodiag\",\n         common_server_errc::er_no_such_table,\n         create_server_diag(\"\"),\n         create_client_diag(\"Last connection attempt failed with: er_no_such_table [mysql.common-server:1146]\"\n         )},\n\n        // MySQL/MariaDB specific errors\n        {\"specific_server_error\",\n         error_code(mysql_server_errc::er_binlog_fatal_error, get_mysql_server_category()),\n         create_server_diag(\"something failed\"),\n         create_server_diag(\"Last connection attempt failed with: er_binlog_fatal_error \"\n                            \"[mysql.mysql-server:1593]: something failed\")},\n\n        // A client error with diagnostics\n        {\"client_error_diag\",\n         client_errc::auth_plugin_requires_ssl,\n         create_client_diag(\"Something client-side failed\"),\n         create_client_diag(\"Last connection attempt failed with: The authentication plugin requires the \"\n                            \"connection to use SSL [mysql.client:7]: Something client-side failed\")},\n\n        // A client error, no diagnostics\n        {\"client_error_nodiag\",\n         client_errc::auth_plugin_requires_ssl,\n         diagnostics(),\n         create_client_diag(\"Last connection attempt failed with: The authentication plugin requires the \"\n                            \"connection to use SSL [mysql.client:7]\")},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            const auto actual = detail::create_connect_diagnostics(tc.input_ec, tc.input_diag);\n            BOOST_TEST(actual == tc.expected);\n        }\n    }\n}\n\n// Initial cases (when the pool starts running)\nBOOST_AUTO_TEST_CASE(num_connections_to_create_initial)\n{\n    // Order: initial, max, current, pending connections, pending requests\n\n    // default\n    BOOST_TEST(num_connections_to_create(1, 151, 0, 0, 0) == 1u);\n\n    // increased initial_size\n    BOOST_TEST(num_connections_to_create(5, 151, 0, 0, 0) == 5u);\n\n    // initial_size == max_size\n    BOOST_TEST(num_connections_to_create(151, 151, 0, 0, 0) == 151u);\n\n    // with pending requests\n    BOOST_TEST(num_connections_to_create(1, 151, 0, 0, 5) == 5u);\n\n    // with pending requests < initial size\n    BOOST_TEST(num_connections_to_create(6, 151, 0, 0, 5) == 6u);\n\n    // with pending requests > max size\n    BOOST_TEST(num_connections_to_create(5, 151, 0, 0, 200) == 151u);\n}\n\n// Pool resize cases (when the pool is already running, and more connections are required)\nBOOST_AUTO_TEST_CASE(num_connections_to_create_resize)\n{\n    // Order: initial, max, current, pending connections, pending requests\n\n    // all connections are in use\n    BOOST_TEST(num_connections_to_create(1, 151, 1, 0, 1) == 1u);\n    BOOST_TEST(num_connections_to_create(1, 151, 5, 0, 1) == 1u);\n\n    // all connections are in use and there are already requests waiting for pending connections\n    BOOST_TEST(num_connections_to_create(1, 151, 10, 1, 2) == 1u);\n    BOOST_TEST(num_connections_to_create(1, 151, 10, 2, 3) == 1u);\n    BOOST_TEST(num_connections_to_create(1, 151, 10, 2, 5) == 3u);\n\n    // creating connections would exceed the limit\n    BOOST_TEST(num_connections_to_create(1, 151, 149, 0, 3) == 2u);\n    BOOST_TEST(num_connections_to_create(1, 151, 150, 1, 3) == 1u);\n    BOOST_TEST(num_connections_to_create(1, 151, 151, 2, 3) == 0u);\n\n    // there are enough pending connections (e.g. we're struggling to connect)\n    BOOST_TEST(num_connections_to_create(1, 151, 10, 10, 3) == 0u);\n    BOOST_TEST(num_connections_to_create(1, 151, 10, 10, 9) == 0u);\n    BOOST_TEST(num_connections_to_create(1, 151, 10, 10, 10) == 0u);\n\n    // edge case: we don't have the required initial connections created yet\n    BOOST_TEST(num_connections_to_create(10, 151, 3, 0, 2) == 7u);\n    BOOST_TEST(num_connections_to_create(10, 151, 3, 2, 4) == 7u);\n    BOOST_TEST(num_connections_to_create(10, 151, 3, 2, 20) == 18u);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/connection_pool.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/connection_pool.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/pool_params.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/connection_pool_fwd.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/connection_node.hpp>\n#include <boost/mysql/impl/internal/connection_pool/connection_pool_impl.hpp>\n#include <boost/mysql/impl/internal/connection_pool/sansio_connection_node.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/test/tools/old/interface.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/test/unit_test_suite.hpp>\n\n#include <memory>\n\n#include \"test_common/printing.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing detail::collection_state;\n\nBOOST_AUTO_TEST_SUITE(test_pooled_connection)\n\n// We use access::construct to build valid pooled_connection's instead of\n// calling async_get_connection because it's faster and allows inspection of internals\nstruct pooled_connection_fixture\n{\n    asio::io_context ctx;\n    std::shared_ptr<detail::pool_impl> pool{\n        std::make_shared<detail::pool_impl>(ctx.get_executor(), pool_params{})\n    };\n\n    std::unique_ptr<detail::connection_node> create_node()\n    {\n        return std::unique_ptr<detail::connection_node>{new detail::connection_node(\n            pool->params(),\n            ctx.get_executor(),\n            ctx.get_executor(),\n            pool->shared_state(),\n            &pool->reset_pipeline_request()\n        )};\n    }\n\n    pooled_connection create_valid_connection(detail::connection_node& node)\n    {\n        return detail::access::construct<pooled_connection>(node, pool);\n    }\n};\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    // Default-constructed connections are always invalid\n    pooled_connection conn;\n    BOOST_TEST(!conn.valid());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_ctor_valid, pooled_connection_fixture)\n{\n    // Setup\n    auto node = create_node();\n    auto conn = create_valid_connection(*node);\n    BOOST_TEST(conn.valid());\n\n    // The moved-from connection is invalid. The node isn't marked as collectable\n    pooled_connection conn2(std::move(conn));\n    BOOST_TEST(conn2.valid());\n    BOOST_TEST(!conn.valid());\n    BOOST_TEST(node->get_collection_state() == collection_state::none);\n}\n\nBOOST_AUTO_TEST_CASE(move_ctor_invalid)\n{\n    // Move constructing from an invalid connection works\n    pooled_connection conn;\n    pooled_connection conn2(std::move(conn));\n    BOOST_TEST(!conn.valid());\n    BOOST_TEST(!conn2.valid());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_valid_valid, pooled_connection_fixture)\n{\n    // Setup\n    auto node = create_node();\n    auto node2 = create_node();\n    auto conn = create_valid_connection(*node);\n    auto conn2 = create_valid_connection(*node2);\n\n    // The source is left invalid. The source node is owned by the target,\n    // and the original target node is marked for collection\n    conn = std::move(conn2);\n    BOOST_TEST(conn.valid());\n    BOOST_TEST(!conn2.valid());\n    BOOST_TEST(node->get_collection_state() == collection_state::needs_collect_with_reset);\n    BOOST_TEST(node2->get_collection_state() == collection_state::none);\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_valid_invalid, pooled_connection_fixture)\n{\n    // Setup\n    auto node = create_node();\n    auto conn = create_valid_connection(*node);\n    pooled_connection conn2;\n\n    // Assigning an invalid node will mark the target for collection\n    conn = std::move(conn2);\n    BOOST_TEST(!conn.valid());\n    BOOST_TEST(!conn2.valid());\n    BOOST_TEST(node->get_collection_state() == collection_state::needs_collect_with_reset);\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_invalid_valid, pooled_connection_fixture)\n{\n    // Setup\n    auto node = create_node();\n    pooled_connection conn;\n    auto conn2 = create_valid_connection(*node);\n\n    // Assigning a valid connection will just transfer ownership\n    conn = std::move(conn2);\n    BOOST_TEST(conn.valid());\n    BOOST_TEST(!conn2.valid());\n    BOOST_TEST(node->get_collection_state() == collection_state::none);\n}\n\nBOOST_AUTO_TEST_CASE(move_ctor_invalid_invalid)\n{\n    // Setup\n    pooled_connection conn;\n    pooled_connection conn2;\n\n    // Moving an invalid source to an invalid target works\n    conn = std::move(conn2);\n    BOOST_TEST(!conn.valid());\n    BOOST_TEST(!conn2.valid());\n}\n\nBOOST_FIXTURE_TEST_CASE(return_without_reset, pooled_connection_fixture)\n{\n    // Setup\n    auto node = create_node();\n    auto node2 = create_node();\n    auto conn = create_valid_connection(*node);\n\n    // Returning without reset makes the connection invalid and sets\n    // collection state\n    conn.return_without_reset();\n    BOOST_TEST(!conn.valid());\n    BOOST_TEST(node->get_collection_state() == collection_state::needs_collect);\n    ctx.poll();\n\n    // Regression check: the reference to the pool is released\n    BOOST_TEST(pool.use_count() == 1);\n\n    // Assigning to the returned node works\n    auto conn2 = create_valid_connection(*node2);\n    conn = std::move(conn2);\n    BOOST_TEST(conn.valid());\n    BOOST_TEST(node->get_collection_state() == collection_state::needs_collect);\n}\n\nBOOST_FIXTURE_TEST_CASE(const_accessors, pooled_connection_fixture)\n{\n    // Const get() and operator-> work\n    auto node = create_node();\n    const auto conn = create_valid_connection(*node);\n    BOOST_CHECK_NO_THROW(conn.get());\n    BOOST_CHECK_NO_THROW(conn->uses_ssl());\n}\n\nBOOST_FIXTURE_TEST_CASE(nonconst_accessors, pooled_connection_fixture)\n{\n    // Non-const get() and operator-> work\n    auto node = create_node();\n    auto conn = create_valid_connection(*node);\n    BOOST_CHECK_NO_THROW(conn.get());\n    BOOST_CHECK_NO_THROW(conn->get_executor());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(test_connection_pool)\n\n// Tests for pool constructors, assignments, and the valid() function\nstruct pool_fixture\n{\n    asio::io_context ctx;\n    connection_pool pool{ctx, pool_params{}};\n};\n\nBOOST_AUTO_TEST_CASE(ctor_from_executor)\n{\n    // Construct\n    asio::io_context ctx;\n    connection_pool pool(ctx.get_executor(), pool_params{});\n\n    // Executors are correct\n    BOOST_TEST((pool.get_executor() == ctx.get_executor()));\n    BOOST_TEST((detail::access::get_impl(pool)->connection_ex() == ctx.get_executor()));\n\n    // The pool is valid\n    BOOST_TEST(pool.valid());\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_execution_context)\n{\n    // Construct\n    asio::io_context ctx;\n    connection_pool pool(ctx, pool_params{});\n\n    // Executors are correct\n    BOOST_TEST((pool.get_executor() == ctx.get_executor()));\n    BOOST_TEST((detail::access::get_impl(pool)->connection_ex() == ctx.get_executor()));\n\n    // The pool is valid\n    BOOST_TEST(pool.valid());\n}\n\nBOOST_AUTO_TEST_CASE(get_executor_thread_safe)\n{\n    // Construct\n    asio::io_context ctx;\n    pool_params params;\n    params.thread_safe = true;\n    connection_pool pool(ctx, std::move(params));\n\n    // get_executor() should return ctx's executor, not any internally created strand\n    BOOST_TEST((pool.get_executor() == ctx.get_executor()));\n}\n\nBOOST_FIXTURE_TEST_CASE(move_ctor_valid, pool_fixture)\n{\n    // Move-constructing a pool leaves the original object invalid\n    connection_pool pool2(std::move(pool));\n    BOOST_TEST(!pool.valid());\n    BOOST_TEST(pool2.valid());\n\n    // The new pool works\n    BOOST_CHECK_NO_THROW(pool2.cancel());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_ctor_invalid, pool_fixture)\n{\n    // Move-constructing a pool from an invalid object yields an invalid object\n    connection_pool pool2(std::move(pool));\n    connection_pool pool3(std::move(pool));\n    BOOST_TEST(!pool.valid());\n    BOOST_TEST(!pool3.valid());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_valid_valid, pool_fixture)\n{\n    // Move-assigning a pool leaves the source invalid\n    connection_pool pool2(ctx, pool_params());\n    pool2 = std::move(pool);\n    BOOST_TEST(!pool.valid());\n    BOOST_TEST(pool2.valid());\n\n    // The assigned pool works\n    BOOST_CHECK_NO_THROW(pool2.cancel());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_valid_invalid, pool_fixture)\n{\n    // Move-assigning from an invalid pool yields an invalid pool\n    connection_pool pool2(std::move(pool));\n    pool2 = std::move(pool);\n    BOOST_TEST(!pool.valid());\n    BOOST_TEST(!pool2.valid());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_invalid_valid, pool_fixture)\n{\n    // Move-assigning to an invalid pool works\n    connection_pool pool2(std::move(pool));\n    pool = std::move(pool2);\n    BOOST_TEST(pool.valid());\n    BOOST_TEST(!pool2.valid());\n\n    // The assigned pool works\n    BOOST_CHECK_NO_THROW(pool.cancel());\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assign_invalid_invalid, pool_fixture)\n{\n    // Move-assigning between invalid pools works\n    connection_pool pool2(std::move(pool));\n    connection_pool pool3(std::move(pool2));\n    pool = std::move(pool2);\n    BOOST_TEST(!pool.valid());\n    BOOST_TEST(!pool2.valid());\n}\n\n// Regression check: deferred works even in C++11\nvoid deferred_spotcheck()\n{\n    asio::io_context ctx;\n    connection_pool pool(ctx, pool_params());\n    diagnostics diag;\n\n    (void)pool.async_run(asio::deferred);\n    (void)pool.async_get_connection(diag, asio::deferred);\n    (void)pool.async_get_connection(asio::deferred);\n}\n\n// Spotcheck: all pool functions support default completion tokens\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\nasio::awaitable<void> spotcheck_default_tokens()\n{\n    asio::io_context ctx;\n    connection_pool pool(ctx, pool_params());\n    diagnostics diag;\n\n    co_await pool.async_run();\n    co_await pool.async_get_connection(diag);\n    co_await pool.async_get_connection();\n}\n#endif\n\n// Spotcheck: connection_pool ops support partial tokens,\n// and they get passed the correct default token\ntemplate <class T, class... SigArgs, class... Rest>\nvoid check_op(asio::deferred_async_operation<void(T, SigArgs...), Rest...>)\n{\n    static_assert(std::is_same<T, std::exception_ptr>::value, \"\");\n}\n\n// run has a different signature\ntemplate <class T, class... Rest>\nvoid check_run_op(asio::deferred_async_operation<void(T), Rest...>)\n{\n    static_assert(std::is_same<T, error_code>::value, \"\");\n}\n\nvoid spotcheck_partial_tokens()\n{\n    asio::io_context ctx;\n    connection_pool pool(ctx, pool_params());\n    diagnostics diag;\n    auto tok = asio::cancel_after(std::chrono::seconds(10));\n\n    check_op(pool.async_run(tok));\n    check_op(pool.async_get_connection(diag, tok));\n    check_op(pool.async_get_connection(tok));\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/unit/test/constant_string_view.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n#include <string_view>\n#endif\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_constant_string_view)\n\n// Use constant_string_view in a regular, runtime function. This mimics real use.\nstring_view f(constant_string_view arg) noexcept { return arg.get(); }\n\n// Checks that SFINAE in constant_string_view constructor works.\nint f(int arg) noexcept { return arg; }\n\n#ifndef BOOST_NO_CXX14_CONSTEXPR\nBOOST_AUTO_TEST_CASE(ctor_string_view)\n{\n    constexpr string_view s(\"abcd\", 4);  // ctor from const char* is C++17 constexpr because traits\n    BOOST_TEST(f(s) == \"abcd\");\n}\n#endif\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nBOOST_AUTO_TEST_CASE(ctor_std_string_view)\n{\n    constexpr std::string_view s = \"abcd\";\n    BOOST_TEST(f(s) == \"abcd\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(ctor_c_string)\n{\n    constexpr const char* s = \"abcd\";\n    BOOST_TEST(f(s) == \"abcd\");\n}\n\nBOOST_AUTO_TEST_CASE(ctor_string_literal) { BOOST_TEST(f(\"abcd\") == \"abcd\"); }\n\nBOOST_AUTO_TEST_CASE(constructor_sfinae)\n{\n    // This wouldn't compile if we blindly accepted any T as argument for constant_string_view ctor\n    BOOST_TEST(f(42) == 42);\n}\n\nBOOST_AUTO_TEST_CASE(copy_move)\n{\n    // Copy/move operations don't conflict with templated constructors\n    const constant_string_view s1{\"abcd\"};\n    constant_string_view s2(s1);\n    constant_string_view s3(std::move(s2));\n    s2 = s1;\n    s3 = std::move(s2);\n}\n\nBOOST_AUTO_TEST_CASE(runtime_c_str)\n{\n    const char* s = \"abc\";\n    BOOST_TEST(f(runtime(s)) == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(runtime_string_view)\n{\n    string_view s = \"abc\";\n    BOOST_TEST(f(runtime(s)) == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(runtime_string)\n{\n    std::string s = \"abc\";\n    BOOST_TEST(f(runtime(s)) == \"abc\");\n}\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nBOOST_AUTO_TEST_CASE(runtime_std_string_view)\n{\n    std::string_view s = \"abc\";\n    BOOST_TEST(f(runtime(s)) == \"abc\");\n}\n#endif\n\n// Constexpr-ness checks\nstatic constexpr string_view abcd_str(\"abcd\", 4);  // ctor from const char* is C++17 constexpr because traits\nstatic_assert(!constant_string_view(abcd_str).get().empty(), \"\");\nstatic_assert(!runtime(abcd_str).get().empty(), \"\");\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/date.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/days.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <stdexcept>\n\n#include \"test_common/stringize.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\n// Note: most of the algorithms have been thoroughly covered in\n// detail/auxiliar/datetime.cpp, so just spotchecks here\n\nBOOST_AUTO_TEST_SUITE(test_date)\n\nBOOST_AUTO_TEST_CASE(default_constructor)\n{\n    date d;\n    BOOST_TEST(d.year() == 0);\n    BOOST_TEST(d.month() == 0);\n    BOOST_TEST(d.day() == 0);\n    BOOST_TEST(!d.valid());\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_time_point_valid)\n{\n    struct\n    {\n        int days_since_epoch;\n        std::uint16_t year;\n        std::uint8_t month;\n        std::uint8_t day;\n    } test_cases[] = {\n        {2932896, 9999, 12, 31},\n        {0,       1970, 1,  1 },\n        {-719528, 0,    1,  1 },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.days_since_epoch)\n        {\n            date::time_point tp(days(tc.days_since_epoch));\n            date d(tp);\n            BOOST_TEST(d.valid());\n            BOOST_TEST(d.year() == tc.year);\n            BOOST_TEST(d.month() == tc.month);\n            BOOST_TEST(d.day() == tc.day);\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n            date d2(std::chrono::local_days(std::chrono::days(tc.days_since_epoch)));\n            BOOST_TEST(d2.valid());\n            BOOST_TEST(d2.year() == tc.year);\n            BOOST_TEST(d2.month() == tc.month);\n            BOOST_TEST(d2.day() == tc.day);\n#endif\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_time_point_invalid)\n{\n    BOOST_CHECK_THROW(date(date::time_point(days(2932897))), std::out_of_range);\n    BOOST_CHECK_THROW(date(date::time_point(days(-719529))), std::out_of_range);\n    BOOST_CHECK_THROW(date(date::time_point(days(INT_MAX))), std::out_of_range);\n    BOOST_CHECK_THROW(date(date::time_point(days(INT_MIN))), std::out_of_range);\n}\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\nBOOST_AUTO_TEST_CASE(ctor_from_local_days_invalid)\n{\n    BOOST_CHECK_THROW(date(std::chrono::local_days(std::chrono::days(2932897))), std::out_of_range);\n    BOOST_CHECK_THROW(date(std::chrono::local_days(std::chrono::days(-719529))), std::out_of_range);\n    BOOST_CHECK_THROW(date(std::chrono::local_days(std::chrono::days(INT_MAX))), std::out_of_range);\n    BOOST_CHECK_THROW(date(std::chrono::local_days(std::chrono::days(INT_MIN))), std::out_of_range);\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(valid)\n{\n    BOOST_TEST(date(2020, 1, 1).valid());\n    BOOST_TEST(date(2020, 2, 29).valid());\n    BOOST_TEST(!date(2019, 2, 29).valid());\n    BOOST_TEST(!date(0xffff, 0xff, 0xff).valid());\n}\n\nBOOST_AUTO_TEST_CASE(get_time_point)\n{\n    BOOST_TEST(date(9999, 12, 31).get_time_point().time_since_epoch().count() == 2932896);\n    BOOST_TEST(date(2024, 5, 17).get_time_point().time_since_epoch().count() == 19860);\n    BOOST_TEST(date(0, 1, 1).get_time_point().time_since_epoch().count() == -719528);\n}\n\nBOOST_AUTO_TEST_CASE(as_time_point)\n{\n    BOOST_TEST(date(9999, 12, 31).as_time_point().time_since_epoch().count() == 2932896);\n    BOOST_TEST(date(0, 1, 1).as_time_point().time_since_epoch().count() == -719528);\n    BOOST_TEST(date(2024, 5, 17).as_time_point().time_since_epoch().count() == 19860);\n    BOOST_CHECK_THROW(date().as_time_point(), std::invalid_argument);\n    BOOST_CHECK_THROW(date(2019, 2, 29).as_time_point(), std::invalid_argument);\n}\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\nBOOST_AUTO_TEST_CASE(get_local_time_point)\n{\n    BOOST_TEST(date(9999, 12, 31).get_local_time_point().time_since_epoch().count() == 2932896);\n    BOOST_TEST(date(2024, 5, 17).as_local_time_point().time_since_epoch().count() == 19860);\n    BOOST_TEST(date(0, 1, 1).get_local_time_point().time_since_epoch().count() == -719528);\n}\n\nBOOST_AUTO_TEST_CASE(as_local_time_point)\n{\n    BOOST_TEST(date(9999, 12, 31).as_local_time_point().time_since_epoch().count() == 2932896);\n    BOOST_TEST(date(0, 1, 1).as_local_time_point().time_since_epoch().count() == -719528);\n    BOOST_TEST(date(2024, 5, 17).as_local_time_point().time_since_epoch().count() == 19860);\n    BOOST_CHECK_THROW(date().as_local_time_point(), std::invalid_argument);\n    BOOST_CHECK_THROW(date(2019, 2, 29).as_local_time_point(), std::invalid_argument);\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(operator_equals)\n{\n    struct\n    {\n        const char* name;\n        date d1;\n        date d2;\n        bool equal;\n    } test_cases[] = {\n        {\"equal\",           date(2020,   2,    29),   date(2020,   2,    29),   true },\n        {\"equal_invalid\",   date(0,      0,    0),    date(0,      0,    0),    true },\n        {\"equal_max\",       date(0xffff, 0xff, 0xff), date(0xffff, 0xff, 0xff), true },\n        {\"different_year\",  date(2020,   1,    31),   date(2019,   1,    31),   false},\n        {\"different_month\", date(2020,   1,    10),   date(2020,   2,    10),   false},\n        {\"different_day\",   date(2020,   1,    10),   date(2020,   1,    11),   false},\n        {\"all_different\",   date(2020,   1,    1),    date(2021,   2,    2),    false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST((tc.d1 == tc.d2) == tc.equal);\n            BOOST_TEST((tc.d2 == tc.d1) == tc.equal);\n            BOOST_TEST((tc.d1 != tc.d2) == !tc.equal);\n            BOOST_TEST((tc.d2 != tc.d1) == !tc.equal);\n        }\n    }\n}\n\n// operator stream is implemented in terms of to_string (see dt_to_string.hpp)\nBOOST_AUTO_TEST_CASE(operator_stream)\n{\n    BOOST_TEST(stringize(date(2022, 1, 3)) == \"2022-01-03\");\n    BOOST_TEST(stringize(date(2023, 12, 31)) == \"2023-12-31\");\n    BOOST_TEST(stringize(date(0, 0, 0)) == \"0000-00-00\");\n    BOOST_TEST(stringize(date(0xffff, 0xff, 0xff)) == \"65535-255-255\");\n}\n\nBOOST_AUTO_TEST_CASE(now)\n{\n    auto d = date::now();\n    BOOST_TEST_REQUIRE(d.valid());\n    BOOST_TEST(d.year() > 2020u);\n    BOOST_TEST(d.year() < 2100u);\n}\n\n// Make sure constxpr can actually be used in a constexpr context\nBOOST_AUTO_TEST_CASE(constexpr_fns_cxx11)\n{\n    constexpr date d0{};\n    static_assert(!d0.valid(), \"\");\n    static_assert(d0.year() == 0, \"\");\n    static_assert(d0.month() == 0, \"\");\n    static_assert(d0.day() == 0, \"\");\n\n    constexpr date d1(2020, 10, 1);\n    static_assert(d1.valid(), \"\");\n    static_assert(d1.year() == 2020, \"\");\n    static_assert(d1.month() == 10, \"\");\n    static_assert(d1.day() == 1, \"\");\n\n    static_assert(d0 == date(), \"\");\n    static_assert(d0 != d1, \"\");\n}\n\n#ifndef BOOST_NO_CXX14_CONSTEXPR\nBOOST_AUTO_TEST_CASE(constexpr_fns_cxx14)\n{\n    constexpr date d0(date::time_point(days(2932896)));\n    static_assert(d0 == date(9999, 12, 31), \"\");\n\n    constexpr auto tp1 = d0.get_time_point();\n    static_assert(tp1 == date::time_point(days(2932896)), \"\");\n\n    constexpr auto tp2 = d0.as_time_point();\n    static_assert(tp2 == tp1, \"\");\n}\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/datetime.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <cstdint>\n#include <limits>\n#include <stdexcept>\n\n#include \"test_common/stringize.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_datetime)\n\n// Helpers\ndatetime from_timestamp(std::int64_t micros_since_epoch)\n{\n    return datetime(datetime::time_point(datetime::time_point::duration(micros_since_epoch)));\n}\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\ndatetime from_local_timestamp(std::int64_t micros_since_epoch)\n{\n    return datetime(datetime::local_time_point(datetime::local_time_point::duration(micros_since_epoch)));\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    datetime d;\n    BOOST_TEST(d.year() == 0u);\n    BOOST_TEST(d.month() == 0u);\n    BOOST_TEST(d.day() == 0u);\n    BOOST_TEST(d.hour() == 0u);\n    BOOST_TEST(d.minute() == 0u);\n    BOOST_TEST(d.second() == 0u);\n    BOOST_TEST(d.microsecond() == 0u);\n    BOOST_TEST(!d.valid());\n}\n\n// Also verifies that all the passed datetimes are considered valid\nBOOST_AUTO_TEST_CASE(from_to_time_point)\n{\n    struct\n    {\n        const char* name;\n        std::int64_t micros_since_epoch;\n        datetime d;\n    } test_cases[] = {\n        {\"date\",                   1272758400000000,   datetime(2010, 5,  2,  0,  0,  0,  0)     },\n        {\"date_leap4\",             1078012800000000,   datetime(2004, 2,  29, 0,  0,  0,  0)     },\n        {\"date_leap400\",           951782400000000,    datetime(2000, 2,  29, 0,  0,  0,  0)     },\n        {\"u\",                      1272758400123456,   datetime(2010, 5,  2,  0,  0,  0,  123456)},\n        {\"s\",                      1272758450000000,   datetime(2010, 5,  2,  0,  0,  50, 0)     },\n        {\"m\",                      1272758460000000,   datetime(2010, 5,  2,  0,  1,  0,  0)     },\n        {\"hs\",                     1272841250000000,   datetime(2010, 5,  2,  23, 0,  50, 0)     },\n        {\"ms\",                     1272758510000000,   datetime(2010, 5,  2,  0,  1,  50, 0)     },\n        {\"hu\",                     1272841200123456,   datetime(2010, 5,  2,  23, 0,  0,  123456)},\n        {\"mu\",                     1272758460123456,   datetime(2010, 5,  2,  0,  1,  0,  123456)},\n        {\"hmu\",                    1272841260123456,   datetime(2010, 5,  2,  23, 1,  0,  123456)},\n        {\"su\",                     1272758450123456,   datetime(2010, 5,  2,  0,  0,  50, 123456)},\n        {\"hsu\",                    1272841250123456,   datetime(2010, 5,  2,  23, 0,  50, 123456)},\n        {\"msu\",                    1272758510123456,   datetime(2010, 5,  2,  0,  1,  50, 123456)},\n        {\"h\",                      1272841200000000,   datetime(2010, 5,  2,  23, 0,  0,  0)     },\n        {\"hm\",                     1272841260000000,   datetime(2010, 5,  2,  23, 1,  0,  0)     },\n        {\"hms\",                    1272841310000000,   datetime(2010, 5,  2,  23, 1,  50, 0)     },\n        {\"hmsu\",                   1272841310123456,   datetime(2010, 5,  2,  23, 1,  50, 123456)},\n        {\"hmsu_minfraction\",       1262307661000001,   datetime(2010, 1,  1,  1,  1,  1,  1)     },\n        {\"hmsu_halffraction1\",     1276601369499999,   datetime(2010, 6,  15, 11, 29, 29, 499999)},\n        {\"hmsu_halffraction2\",     1276605030500000,   datetime(2010, 6,  15, 12, 30, 30, 500000)},\n        {\"hmsu_maxfraction2\",      1293839999999999,   datetime(2010, 12, 31, 23, 59, 59, 999999)},\n\n        {\"neg_date\",               -86400000000,       datetime(1969, 12, 31, 0,  0,  0,  0)     },\n        {\"neg_date_2\",             -3 * 86400000000,   datetime(1969, 12, 29, 0,  0,  0,  0)     },\n        {\"neg_date_leap4\",         -11544768000000000, datetime(1604, 2,  29, 0,  0,  0,  0)     },\n        {\"neg_date_leap400\",       -11670998400000000, datetime(1600, 2,  29, 0,  0,  0,  0)     },\n        {\"neg_u\",                  -84239999876544,    datetime(1967, 5,  2,  0,  0,  0,  123456)},\n        {\"neg_s\",                  -84239950000000,    datetime(1967, 5,  2,  0,  0,  50, 0)     },\n        {\"neg_m\",                  -84239940000000,    datetime(1967, 5,  2,  0,  1,  0,  0)     },\n        {\"neg_hs\",                 -84157150000000,    datetime(1967, 5,  2,  23, 0,  50, 0)     },\n        {\"neg_ms\",                 -84239890000000,    datetime(1967, 5,  2,  0,  1,  50, 0)     },\n        {\"neg_hu\",                 -84157199876544,    datetime(1967, 5,  2,  23, 0,  0,  123456)},\n        {\"neg_mu\",                 -84239939876544,    datetime(1967, 5,  2,  0,  1,  0,  123456)},\n        {\"neg_hmu\",                -84157139876544,    datetime(1967, 5,  2,  23, 1,  0,  123456)},\n        {\"neg_su\",                 -84239949876544,    datetime(1967, 5,  2,  0,  0,  50, 123456)},\n        {\"neg_hsu\",                -84157149876544,    datetime(1967, 5,  2,  23, 0,  50, 123456)},\n        {\"neg_msu\",                -84239889876544,    datetime(1967, 5,  2,  0,  1,  50, 123456)},\n        {\"neg_h\",                  -84157200000000,    datetime(1967, 5,  2,  23, 0,  0,  0)     },\n        {\"neg_hm\",                 -84157140000000,    datetime(1967, 5,  2,  23, 1,  0,  0)     },\n        {\"neg_hms\",                -84157090000000,    datetime(1967, 5,  2,  23, 1,  50, 0)     },\n        {\"neg_hmsu\",               -84157089876544,    datetime(1967, 5,  2,  23, 1,  50, 123456)},\n        {\"neg_hmsu_minfraction\",   -1893452338999999,  datetime(1910, 1,  1,  1,  1,  1,  1)     },\n        {\"neg_hmsu_halffraction1\", -3141376230500001,  datetime(1870, 6,  15, 11, 29, 29, 499999)},\n        {\"neg_hmsu_halffraction2\", -5697430169500000,  datetime(1789, 6,  15, 12, 30, 30, 500000)},\n        {\"neg_hmsu_maxfraction2\",  -47114438400000001, datetime(476,  12, 31, 23, 59, 59, 999999)},\n\n        {\"epoch\",                  0,                  datetime(1970, 1,  1,  0,  0,  0,  0)     },\n        {\"min\",                    -62167219200000000, datetime(0,    1,  1,  0,  0,  0,  0)     },\n        {\"max\",                    253402300799999999, datetime(9999, 12, 31, 23, 59, 59, 999999)},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // valid\n            BOOST_TEST(tc.d.valid());\n\n            // From time_point\n            datetime actual_dt = from_timestamp(tc.micros_since_epoch);\n            BOOST_TEST(actual_dt == tc.d);\n\n            // To time_point\n            auto tp = tc.d.get_time_point();\n            BOOST_TEST(tp.time_since_epoch().count() == tc.micros_since_epoch);\n        }\n    }\n}\n\n// All cases that are accepeted by datetime but don't represent actual datetimes\nBOOST_AUTO_TEST_CASE(valid_false)\n{\n    struct\n    {\n        const char* name;\n        datetime d;\n    } test_cases[] = {\n        {\"date_yregular_invalid_date\",             datetime(2020,   11,   31,   0,    0,    0,    0)         },\n        {\"date_yregular_invalid_date_leap100\",     datetime(1900,   2,    29,   0,    0,    0,    0)         },\n        {\"date_yregular_invalid_date_leapregular\", datetime(1999,   2,    29,   0,    0,    0,    0)         },\n        {\"date_yregular_mregular_dzero\",           datetime(2020,   10,   0,    0,    0,    0,    0)         },\n        {\"date_yregular_mzero_dregular\",           datetime(2020,   0,    10,   0,    0,    0,    0)         },\n        {\"date_yregular_mzero_dzero\",              datetime(2020,   0,    0,    0,    0,    0,    0)         },\n        {\"date_yzero_invalid_date\",                datetime(0,      11,   31,   0,    0,    0,    0)         },\n        {\"date_yzero_mregular_dzero\",              datetime(0,      10,   0,    0,    0,    0,    0)         },\n        {\"date_yzero_mzero_dregular\",              datetime(0,      0,    10,   0,    0,    0,    0)         },\n        {\"date_zero\",                              datetime(0,      0,    0,    0,    0,    0,    0)         },\n        {\"hms_yregular_invalid_date\",              datetime(2020,   11,   31,   10,   20,   30,   0)         },\n        {\"hms_yregular_invalid_date_leap100\",      datetime(1900,   2,    29,   10,   20,   30,   0)         },\n        {\"hms_yregular_invalid_date_leapregular\",  datetime(1999,   2,    29,   10,   20,   30,   0)         },\n        {\"hms_yregular_mregular_dzero\",            datetime(2020,   10,   0,    10,   20,   30,   0)         },\n        {\"hms_yregular_mzero_dregular\",            datetime(2020,   0,    10,   10,   20,   30,   0)         },\n        {\"hms_yregular_mzero_dzero\",               datetime(2020,   0,    0,    10,   20,   30,   0)         },\n        {\"hms_yzero_invalid_date\",                 datetime(0,      11,   31,   10,   20,   30,   0)         },\n        {\"hms_yzero_mregular_dzero\",               datetime(0,      10,   0,    10,   20,   30,   0)         },\n        {\"hms_yzero_mzero_dregular\",               datetime(0,      0,    10,   10,   20,   30,   0)         },\n        {\"hms_zero\",                               datetime(0,      0,    0,    10,   20,   30,   0)         },\n        {\"hmsu_yregular_invalid_date\",             datetime(2020,   11,   31,   10,   20,   30,   999999)    },\n        {\"hmsu_yregular_invalid_date_leap100\",     datetime(1900,   2,    29,   10,   20,   30,   999999)    },\n        {\"hmsu_yregular_invalid_date_leapregular\", datetime(1999,   2,    29,   10,   20,   30,   999999)    },\n        {\"hmsu_yregular_mregular_dzero\",           datetime(2020,   10,   0,    10,   20,   30,   999999)    },\n        {\"hmsu_yregular_mzero_dregular\",           datetime(2020,   0,    10,   10,   20,   30,   999999)    },\n        {\"hmsu_yregular_mzero_dzero\",              datetime(2020,   0,    0,    10,   20,   30,   999999)    },\n        {\"hmsu_yzero_invalid_date\",                datetime(0,      11,   31,   10,   20,   30,   999999)    },\n        {\"hmsu_yzero_mregular_dzero\",              datetime(0,      10,   0,    10,   20,   30,   999999)    },\n        {\"hmsu_yzero_mzero_dregular\",              datetime(0,      0,    10,   10,   20,   30,   999999)    },\n        {\"hmsu_zero\",                              datetime(0,      0,    0,    10,   20,   30,   999999)    },\n        {\"invalid_hour\",                           datetime(2010,   5,    22,   24,   0,    0,    0)         },\n        {\"invalid_minute\",                         datetime(2010,   5,    22,   23,   60,   0,    0)         },\n        {\"invalid_second\",                         datetime(2010,   5,    22,   23,   59,   60,   0)         },\n        {\"invalid_microsecond\",                    datetime(2010,   5,    22,   23,   59,   59,   1000000)   },\n        {\"max_year\",                               datetime(0xffff, 5,    2,    23,   1,    50,   123456)    },\n        {\"max_month\",                              datetime(2010,   0xff, 2,    23,   1,    50,   123456)    },\n        {\"max_day\",                                datetime(2010,   5,    0xff, 23,   1,    50,   123456)    },\n        {\"max_hour\",                               datetime(2010,   5,    2,    0xff, 1,    50,   123456)    },\n        {\"max_minute\",                             datetime(2010,   5,    2,    23,   0xff, 50,   123456)    },\n        {\"max_second\",                             datetime(2010,   5,    2,    23,   1,    0xff, 123456)    },\n        {\"max_microsecond\",                        datetime(2010,   5,    2,    23,   1,    50,   0xffffffff)},\n        {\"max\",                                    datetime(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff)},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { BOOST_TEST(!tc.d.valid()); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_time_point_invalid)\n{\n    BOOST_CHECK_THROW(from_timestamp(253402300799999999 + 1), std::out_of_range);\n    BOOST_CHECK_THROW(from_timestamp(-62167219200000000 - 1), std::out_of_range);\n    BOOST_CHECK_THROW(from_timestamp((std::numeric_limits<std::int64_t>::max)()), std::out_of_range);\n    BOOST_CHECK_THROW(from_timestamp((std::numeric_limits<std::int64_t>::min)()), std::out_of_range);\n}\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\nBOOST_AUTO_TEST_CASE(ctor_from_local_time_point)\n{\n    BOOST_TEST(from_local_timestamp(253402300799999999) == datetime(9999, 12, 31, 23, 59, 59, 999999));\n    BOOST_TEST(from_local_timestamp(1715966176806454) == datetime(2024, 5, 17, 17, 16, 16, 806454));\n    BOOST_TEST(from_local_timestamp(-62167219200000000) == datetime(0, 1, 1));\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_local_time_point_invalid)\n{\n    BOOST_CHECK_THROW(from_local_timestamp(253402300799999999 + 1), std::out_of_range);\n    BOOST_CHECK_THROW(from_local_timestamp(-62167219200000000 - 1), std::out_of_range);\n    BOOST_CHECK_THROW(from_local_timestamp((std::numeric_limits<std::int64_t>::max)()), std::out_of_range);\n    BOOST_CHECK_THROW(from_local_timestamp((std::numeric_limits<std::int64_t>::min)()), std::out_of_range);\n}\n#endif\n\n// spotcheck, uses the same routines as get_time_point\nBOOST_AUTO_TEST_CASE(as_time_point)\n{\n    datetime d1(2010, 12, 31, 23, 59, 59, 999999);\n    BOOST_TEST(d1.as_time_point().time_since_epoch().count() == 1293839999999999);\n\n    datetime d2(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff);\n    BOOST_CHECK_THROW(d2.as_time_point(), std::invalid_argument);\n}\n\n#ifdef BOOST_MYSQL_HAS_LOCAL_TIME\n// spotcheck, uses the same routines as get_time_point\nBOOST_AUTO_TEST_CASE(as_local_time_point)\n{\n    datetime d1(2010, 12, 31, 23, 59, 59, 999999);\n    BOOST_TEST(d1.as_local_time_point().time_since_epoch().count() == 1293839999999999);\n\n    datetime d2(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff);\n    BOOST_CHECK_THROW(d2.as_local_time_point(), std::invalid_argument);\n}\n\n// spotcheck, uses the same routines as get_time_point\nBOOST_AUTO_TEST_CASE(get_local_time_point)\n{\n    datetime d(2010, 12, 31, 23, 59, 59, 999999);\n    BOOST_TEST(d.get_local_time_point().time_since_epoch().count() == 1293839999999999);\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(operator_equals)\n{\n    datetime maxdt(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff);\n\n    // clang-format off\n    struct\n    {\n        const char* name;\n        datetime d1;\n        datetime d2;\n        bool equal;\n    } test_cases[] = {\n        {\"equal\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 2, 29, 1, 2, 10, 9), true},\n        {\"equal_invalid\", datetime(0, 0, 0, 0, 0, 0, 0), datetime(0, 0, 0, 0, 0, 0, 0), true},\n        {\"equal_max\", maxdt, maxdt, true},\n        {\"ne_year\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2019, 2, 29, 1, 2, 10, 9), false},\n        {\"ne_month\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 1, 29, 1, 2, 10, 9), false},\n        {\"ne_day\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 2, 28, 1, 2, 10, 9), false},\n        {\"ne_hour\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 2, 29, 2, 2, 10, 9), false},\n        {\"ne_min\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 2, 29, 1, 3, 10, 9), false},\n        {\"ne_sec\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 2, 29, 1, 2, 11, 9), false},\n        {\"ne_micro\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2020, 2, 29, 1, 2, 10, 98), false},\n        {\"ne_all\", datetime(2020, 2, 29, 1, 2, 10, 9), datetime(2019, 5, 10, 0xff, 21, 101, 98), false},\n    };\n    // clang-format on\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST((tc.d1 == tc.d2) == tc.equal);\n            BOOST_TEST((tc.d2 == tc.d1) == tc.equal);\n            BOOST_TEST((tc.d1 != tc.d2) == !tc.equal);\n            BOOST_TEST((tc.d2 != tc.d1) == !tc.equal);\n        }\n    }\n}\n\n// operator<< is implemented in terms of datetime_to_string (see dt_to_string.hpp)\nBOOST_AUTO_TEST_CASE(operator_stream)\n{\n    BOOST_TEST(stringize(datetime(2023, 1, 2, 12, 10, 1, 0)) == \"2023-01-02 12:10:01.000000\");\n    BOOST_TEST(stringize(datetime(2022, 12, 31)) == \"2022-12-31 00:00:00.000000\");\n    BOOST_TEST(stringize(datetime(2020, 3, 2, 23, 59, 59, 12345)) == \"2020-03-02 23:59:59.012345\");\n    BOOST_TEST(stringize(datetime()) == \"0000-00-00 00:00:00.000000\");\n    BOOST_TEST(\n        stringize(datetime(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff)) ==\n        \"65535-255-255 255:255:255.4294967295\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(now)\n{\n    auto d = datetime::now();\n    BOOST_TEST_REQUIRE(d.valid());\n    BOOST_TEST(d.year() > 2020u);\n    BOOST_TEST(d.year() < 2100u);\n}\n\n// Make sure constxpr can actually be used in a constexpr context\nBOOST_AUTO_TEST_CASE(constexpr_fns_cxx11)\n{\n    constexpr datetime d0{};\n    static_assert(!d0.valid(), \"\");\n    static_assert(d0.year() == 0, \"\");\n    static_assert(d0.month() == 0, \"\");\n    static_assert(d0.day() == 0, \"\");\n    static_assert(d0.hour() == 0, \"\");\n    static_assert(d0.minute() == 0, \"\");\n    static_assert(d0.second() == 0, \"\");\n    static_assert(d0.microsecond() == 0, \"\");\n\n    constexpr datetime d1(2020, 10, 1, 23, 20, 59, 123456);\n    static_assert(d1.valid(), \"\");\n    static_assert(d1.year() == 2020, \"\");\n    static_assert(d1.month() == 10, \"\");\n    static_assert(d1.day() == 1, \"\");\n    static_assert(d1.hour() == 23, \"\");\n    static_assert(d1.minute() == 20, \"\");\n    static_assert(d1.second() == 59, \"\");\n    static_assert(d1.microsecond() == 123456, \"\");\n\n    static_assert(d0 == datetime(), \"\");\n    static_assert(d0 != d1, \"\");\n}\n\n#ifndef BOOST_NO_CXX14_CONSTEXPR\nBOOST_AUTO_TEST_CASE(constexpr_fns_cxx14)\n{\n    constexpr datetime d0(datetime::time_point(datetime::time_point::duration(1272841310123456)));\n    static_assert(d0 == datetime(2010, 5, 2, 23, 1, 50, 123456), \"\");\n\n    constexpr auto tp1 = d0.get_time_point();\n    static_assert(tp1.time_since_epoch().count() == 1272841310123456, \"\");\n\n    constexpr auto tp2 = d0.as_time_point();\n    static_assert(tp2 == tp1, \"\");\n}\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/connect_params_helpers.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/connect_params.hpp>\n#include <boost/mysql/ssl_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/connect_params_helpers.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/printing.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::detail;\nusing boost::mysql::address_type;\nusing boost::mysql::connect_params;\nusing boost::mysql::ssl_mode;\nusing boost::mysql::string_view;\n\nBOOST_AUTO_TEST_SUITE(test_connect_params_helpers)\n\nBOOST_AUTO_TEST_CASE(adjust_ssl_mode_)\n{\n    struct\n    {\n        string_view name;\n        address_type addr_type;\n        ssl_mode input;\n        ssl_mode expected;\n    } test_cases[] = {\n        {\"tcp_disable\",  address_type::host_and_port, ssl_mode::disable, ssl_mode::disable},\n        {\"tcp_enable\",   address_type::host_and_port, ssl_mode::enable,  ssl_mode::enable },\n        {\"tcp_require\",  address_type::host_and_port, ssl_mode::require, ssl_mode::require},\n        {\"unix_disable\", address_type::unix_path,     ssl_mode::disable, ssl_mode::disable},\n        {\"unix_enable\",  address_type::unix_path,     ssl_mode::enable,  ssl_mode::disable},\n        {\"unix_require\", address_type::unix_path,     ssl_mode::require, ssl_mode::disable},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            auto actual = adjust_ssl_mode(tc.input, tc.addr_type);\n            BOOST_TEST(actual == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(make_hparams_1)\n{\n    connect_params input;\n    input.server_address.emplace_host_and_port(\"myhost\", 2000);\n    input.username = \"myuser\";\n    input.password = \"mypass\";\n    input.database = \"mydb\";\n    input.connection_collation = std::uint16_t(100);\n    input.ssl = ssl_mode::require;\n    input.multi_queries = true;\n\n    auto hparams = make_hparams(input);\n\n    BOOST_TEST(hparams.username() == \"myuser\");\n    BOOST_TEST(hparams.password() == \"mypass\");\n    BOOST_TEST(hparams.database() == \"mydb\");\n    BOOST_TEST(hparams.connection_collation() == std::uint16_t(100));\n    BOOST_TEST(hparams.ssl() == ssl_mode::require);\n    BOOST_TEST(hparams.multi_queries());\n}\n\nBOOST_AUTO_TEST_CASE(make_hparams_2)\n{\n    connect_params input;\n    input.server_address.emplace_unix_path(\"/var/sock\");\n    input.username = \"myuser2\";\n    input.password = \"mypass2\";\n    input.database = \"mydb2\";\n    input.connection_collation = std::uint16_t(200);\n    input.ssl = ssl_mode::require;\n    input.multi_queries = false;\n\n    auto hparams = make_hparams(input);\n\n    BOOST_TEST(hparams.username() == \"myuser2\");\n    BOOST_TEST(hparams.password() == \"mypass2\");\n    BOOST_TEST(hparams.database() == \"mydb2\");\n    BOOST_TEST(hparams.connection_collation() == std::uint16_t(200));\n    BOOST_TEST(hparams.ssl() == ssl_mode::disable);  // SSL mode was adjusted (UNIX)\n    BOOST_TEST(!hparams.multi_queries());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/datetime.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/datetime.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <array>\n#include <cstdint>\n#include <limits>\n#include <string>\n\n#include \"test_common/stringize.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql::detail;\n\n// These tests are very extensive in range. Making them parameterized\n// proves very runtime expensive. We rather use plain loops. Using plain\n// BOOST_TEST() also increases runtime way too much\n\nBOOST_AUTO_TEST_SUITE(test_datetime_detail)\n\nclass test_state\n{\n    // Context\n    std::uint16_t year_{};\n    std::uint8_t month_{};\n    std::uint8_t day_{};\n\npublic:\n    void set_context(std::uint16_t year, std::uint8_t month, std::uint8_t day) noexcept\n    {\n        year_ = year;\n        month_ = month;\n        day_ = day;\n    }\n\n    template <class T1, class T2>\n    void assert_equals(const T1& v1, const T2& v2, int line)\n    {\n        if (v1 != v2)\n        {\n            auto msg = stringize(\n                __FILE__,\n                \":\",\n                line,\n                \" (year=\",\n                year_,\n                \", month=\",\n                +month_,\n                \", day=\",\n                +day_,\n                \"): \",\n                v1,\n                \" != \",\n                v2\n            );\n            BOOST_TEST(v1 == v2, msg);\n        }\n    }\n};\n\n#define BOOST_MYSQL_ASSERT_EQ(st, v1, v2) st.assert_equals(v1, v2, __LINE__)\n\n// Helpers\nconstexpr std::uint16_t leap_years[] = {\n    1804, 1808, 1812, 1816, 1820, 1824, 1828, 1832, 1836, 1840, 1844, 1848, 1852, 1856, 1860, 1864, 1868,\n    1872, 1876, 1880, 1884, 1888, 1892, 1896, 1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936, 1940,\n    1944, 1948, 1952, 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000, 2004, 2008,\n    2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, 2044, 2048, 2052, 2056, 2060, 2064, 2068, 2072, 2076,\n    2080, 2084, 2088, 2092, 2096, 2104, 2108, 2112, 2116, 2120, 2124, 2128, 2132, 2136, 2140, 2144, 2148,\n    2152, 2156, 2160, 2164, 2168, 2172, 2176, 2180, 2184, 2188, 2192, 2196, 2204,\n};\n\nbool is_leap_year(std::uint16_t y)\n{\n    return std::binary_search(std::begin(leap_years), std::end(leap_years), y);\n}\n\nstd::uint8_t last_day_of_month(std::uint8_t month)  // doesn't take leap years into account\n{\n    constexpr std::uint8_t last_month_days[] = {31u, 28u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u};\n    assert(month >= 1 && month <= 12);\n    return last_month_days[month - 1];\n}\n\nBOOST_AUTO_TEST_SUITE(is_valid_)\n\n// thorough coverage for 400 years\nBOOST_AUTO_TEST_CASE(coverage)\n{\n    test_state st;\n\n    for (std::uint16_t year = 1804; year <= 2204; ++year)\n    {\n        bool leap = is_leap(year);\n        for (std::uint8_t month = 1; month <= 12; ++month)\n        {\n            std::uint8_t last_month_day = month == 2 && leap ? 29u : last_day_of_month(month);\n            for (std::uint8_t day = 1; day <= 32; ++day)\n            {\n                st.set_context(year, month, day);\n\n                BOOST_MYSQL_ASSERT_EQ(st, (is_valid(year, month, day)), (day <= last_month_day));\n            }\n        }\n    }\n}\n\n// spotchecks for certain invalid dates\nBOOST_AUTO_TEST_CASE(invalid_spotchecks)\n{\n    // year out of range of MySQL validity\n    BOOST_TEST(!is_valid(10000u, 1u, 1u));\n    BOOST_TEST(!is_valid(0xffffu, 1u, 1u));\n\n    // month out of range\n    BOOST_TEST(!is_valid(2010u, 13u, 1u));\n    BOOST_TEST(!is_valid(2010u, 0u, 1u));\n    BOOST_TEST(!is_valid(2010u, 0xffu, 1u));\n\n    // day out of range\n    BOOST_TEST(!is_valid(2019u, 2u, 29u));\n    BOOST_TEST(!is_valid(2010u, 2u, 32u));\n    BOOST_TEST(!is_valid(2010u, 2u, 0u));\n    BOOST_TEST(!is_valid(2010u, 2u, 0xffu));\n\n    // combinations\n    BOOST_TEST(!is_valid(0u, 0u, 0u));\n    BOOST_TEST(!is_valid(0xffffu, 0xffu, 0xffu));\n    BOOST_TEST(!is_valid(2010u, 0u, 0u));\n    BOOST_TEST(!is_valid(0xffffu, 42u, 0xffu));\n}\n\n// spotchecks for certain valid dates\nBOOST_AUTO_TEST_CASE(valid_spotchecks)\n{\n    BOOST_TEST(is_valid(0u, 1u, 1u));\n    BOOST_TEST(is_valid(2020u, 2u, 29u));\n    BOOST_TEST(is_valid(9999u, 1u, 1u));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// ymd_to_days, days_to_ymd\n// Helper function that actually performs the assertions for us\nvoid ymd_years_test(test_state& st, std::uint16_t year, std::uint8_t month, std::uint8_t day, int num_days)\n{\n    st.set_context(year, month, day);\n\n    BOOST_MYSQL_ASSERT_EQ(st, is_valid(year, month, day), true);\n    BOOST_MYSQL_ASSERT_EQ(st, ymd_to_days(year, month, day), num_days);\n    std::uint16_t output_year{};\n    std::uint8_t output_month{}, output_day{};\n    bool ok = days_to_ymd(num_days, output_year, output_month, output_day);\n\n    BOOST_MYSQL_ASSERT_EQ(st, ok, true);\n    BOOST_MYSQL_ASSERT_EQ(st, output_day, day);\n    BOOST_MYSQL_ASSERT_EQ(st, output_month, month);\n    BOOST_MYSQL_ASSERT_EQ(st, output_year, year);\n}\n\nBOOST_AUTO_TEST_CASE(ymd_to_days_days_to_ymd)\n{\n    test_state st;\n\n    // Starting from 1970, going up\n    int num_days = 0;\n\n    for (std::uint16_t year = 1970u; year <= 2204u; ++year)\n    {\n        for (std::uint8_t month = 1u; month <= 12u; ++month)\n        {\n            std::uint8_t last_month_day = month == 2u && is_leap_year(year) ? 29u : last_day_of_month(month);\n            for (std::uint8_t day = 1u; day <= last_month_day; ++day)\n            {\n                ymd_years_test(st, year, month, day, num_days++);\n            }\n        }\n    }\n\n    // Starting from 1970, going down\n    num_days = -1;\n\n    for (std::uint16_t year = 1969u; year >= 1804u; --year)\n    {\n        for (std::uint8_t month = 12u; month >= 1u; --month)\n        {\n            std::uint8_t last_month_day = month == 2u && is_leap_year(year) ? 29u : last_day_of_month(month);\n            for (std::uint8_t day = last_month_day; day >= 1u; --day)\n            {\n                ymd_years_test(st, year, month, day, num_days--);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(ymd_to_days_spotcheck)\n{\n    BOOST_TEST(ymd_to_days(0, 1, 1) == -719528);\n    BOOST_TEST(ymd_to_days(1970, 1, 1) == 0);\n    BOOST_TEST(ymd_to_days(9999, 12, 31) == 2932896);\n}\n\n// Verify range checks work\nBOOST_AUTO_TEST_CASE(days_to_ymd_limits)\n{\n    // Just in the lower limit\n    std::uint16_t years;\n    std::uint8_t month, day;\n    bool ok = days_to_ymd(-719528, years, month, day);\n    BOOST_TEST(ok);\n    BOOST_TEST(years == 0);\n    BOOST_TEST(month == 1);\n    BOOST_TEST(day == 1);\n\n    // Below lower limit\n    BOOST_TEST(!days_to_ymd(-719529, years, month, day));\n    BOOST_TEST(!days_to_ymd((std::numeric_limits<int>::min)(), years, month, day));\n\n    // Just in the upper limit\n    ok = days_to_ymd(2932896, years, month, day);\n    BOOST_TEST(ok);\n    BOOST_TEST(years == 9999);\n    BOOST_TEST(month == 12);\n    BOOST_TEST(day == 31);\n\n    // Above the upper limit. 719468 is a magic number used within the algorithm that\n    // was found to cause signed int overflow\n    BOOST_TEST(!days_to_ymd(2932897, years, month, day));\n    BOOST_TEST(!days_to_ymd((std::numeric_limits<int>::max)() - 719467, years, month, day));\n    BOOST_TEST(!days_to_ymd((std::numeric_limits<int>::max)() - 719468, years, month, day));\n    BOOST_TEST(!days_to_ymd((std::numeric_limits<int>::max)() - 719469, years, month, day));\n    BOOST_TEST(!days_to_ymd((std::numeric_limits<int>::max)(), years, month, day));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/engine_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/any_resumable_ref.hpp>\n#include <boost/mysql/detail/engine_impl.hpp>\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/asio/any_completion_handler.hpp>\n#include <boost/asio/any_io_executor.hpp>\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/bind_cancellation_slot.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/buffer.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/coroutine.hpp>\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/dispatch.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/post.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <ostream>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/netfun_maker.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql::detail;\nnamespace asio = boost::asio;\nusing boost::mysql::error_code;\nusing boost::test_tools::per_element;\n\nBOOST_AUTO_TEST_SUITE(test_engine_impl)\n\n// Satisfies the EngineStream concept\nclass mock_engine_stream\n{\n    asio::any_io_executor ex_;\n    error_code op_error_;  // Operations complete with this error code\n\n    std::size_t size_or_zero(std::size_t sz) const { return op_error_ ? 0u : sz; }\n\n    void record_read_call(asio::mutable_buffer buff, bool use_ssl)\n    {\n        calls.push_back(next_action::read({\n            {static_cast<std::uint8_t*>(buff.data()), buff.size()},\n            use_ssl\n        }));\n    }\n\n    void record_write_call(asio::const_buffer buff, bool use_ssl)\n    {\n        calls.push_back(next_action::write({\n            {static_cast<const std::uint8_t*>(buff.data()), buff.size()},\n            use_ssl\n        }));\n    }\n\n    template <class CompletionToken>\n    void complete_immediate(CompletionToken&& token)\n    {\n        asio::post(ex_, asio::deferred([this]() {\n                       return asio::deferred.values(op_error_);\n                   }))(std::forward<CompletionToken>(token));\n    }\n\n    template <class CompletionToken>\n    void complete_immediate(CompletionToken&& token, std::size_t bytes)\n    {\n        asio::post(ex_, asio::deferred([this, bytes]() {\n                       return asio::deferred.values(op_error_, size_or_zero(bytes));\n                   }))(std::forward<CompletionToken>(token));\n    }\n\npublic:\n    std::vector<next_action> calls;\n\n    mock_engine_stream(asio::any_io_executor ex, error_code op_error = error_code())\n        : ex_(std::move(ex)), op_error_(op_error)\n    {\n    }\n\n    using executor_type = asio::any_io_executor;\n    executor_type get_executor() { return ex_; }\n\n    bool supports_ssl() const { return true; }\n\n    void set_endpoint(const void*) {}\n\n    // Reading\n    std::size_t read_some(asio::mutable_buffer buff, bool use_ssl, error_code& ec)\n    {\n        record_read_call(buff, use_ssl);\n        ec = op_error_;\n        return size_or_zero(buff.size());\n    }\n\n    template <class CompletionToken>\n    void async_read_some(asio::mutable_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        record_read_call(buff, use_ssl);\n        complete_immediate(std::forward<CompletionToken>(token), buff.size());\n    }\n\n    // Writing\n    std::size_t write_some(asio::const_buffer buff, bool use_ssl, error_code& ec)\n    {\n        record_write_call(buff, use_ssl);\n        ec = op_error_;\n        return size_or_zero(buff.size());\n    }\n\n    template <class CompletionToken>\n    void async_write_some(asio::const_buffer buff, bool use_ssl, CompletionToken&& token)\n    {\n        record_write_call(buff, use_ssl);\n        complete_immediate(std::forward<CompletionToken>(token), buff.size());\n    }\n\n    // SSL\n    void ssl_handshake(error_code& ec)\n    {\n        calls.push_back(next_action::ssl_handshake());\n        ec = op_error_;\n    }\n\n    template <class CompletionToken>\n    void async_ssl_handshake(CompletionToken&& token)\n    {\n        calls.push_back(next_action::ssl_handshake());\n        complete_immediate(std::forward<CompletionToken>(token));\n    }\n\n    void ssl_shutdown(error_code& ec)\n    {\n        calls.push_back(next_action::ssl_shutdown());\n        ec = op_error_;\n    }\n\n    template <class CompletionToken>\n    void async_ssl_shutdown(CompletionToken&& token)\n    {\n        calls.push_back(next_action::ssl_shutdown());\n        complete_immediate(std::forward<CompletionToken>(token));\n    }\n\n    // Connect and close\n    void connect(const void* server_address, error_code& ec)\n    {\n        calls.push_back(next_action::connect(server_address));\n        ec = op_error_;\n    }\n\n    template <class CompletionToken>\n    void async_connect(const void* server_address, CompletionToken&& token)\n    {\n        calls.push_back(next_action::connect(server_address));\n        complete_immediate(std::forward<CompletionToken>(token));\n    }\n\n    void close(error_code& ec)\n    {\n        calls.push_back(next_action::close());\n        ec = op_error_;\n    }\n};\n\n// Helpers to run the sync and async versions uniformly.\n// engine_impl must be adapted because async_run() takes a completion handler,\n// rather than a generic completion token\nstruct test_engine\n{\n    engine_impl<mock_engine_stream> value;\n\n    struct initiation_t\n    {\n        asio::any_io_executor ex;\n\n        // Required for compatibility with as_netresult\n        using executor_type = asio::any_io_executor;\n        executor_type get_executor() const { return ex; }\n\n        void operator()(\n            asio::any_completion_handler<void(error_code)> handler,\n            engine* eng,\n            any_resumable_ref resumable\n        ) const\n        {\n            eng->async_run(resumable, std::move(handler));\n        }\n    };\n\n    void run(any_resumable_ref resumable, error_code& err) { value.run(resumable, err); }\n\n    template <class CompletionToken>\n    auto async_run(any_resumable_ref resumable, CompletionToken&& token)\n        -> decltype(asio::async_initiate<CompletionToken, void(error_code)>(\n            initiation_t{value.get_executor()},\n            token,\n            &value,\n            resumable\n        ))\n    {\n        return asio::async_initiate<CompletionToken, void(error_code)>(\n            initiation_t{value.get_executor()},\n            token,\n            &value,\n            resumable\n        );\n    }\n};\n\nusing netmaker_t = netfun_maker<void, test_engine, any_resumable_ref>;\nconst auto sync_fn = netmaker_t::sync_errc_nodiag(&test_engine::run);\nconst auto async_fn = netmaker_t::async_nodiag(&test_engine::async_run);\nusing signature_t = netmaker_t::signature;\n\n// A mock for a sans-io algorithm. Can be converted to any_resumable_ref\nstruct mock_algo\n{\n    struct call_args\n    {\n        error_code ec;\n        std::size_t bytes_transferred;\n\n        bool operator==(const call_args& rhs) const\n        {\n            return ec == rhs.ec && bytes_transferred == rhs.bytes_transferred;\n        }\n\n        friend std::ostream& operator<<(std::ostream& os, const call_args& v)\n        {\n            return os << \"{\" << v.ec << \", \" << v.bytes_transferred << \"}\";\n        }\n    };\n\n    std::size_t current_call{0};\n    std::vector<next_action> acts;\n    std::vector<call_args> calls;\n\n    mock_algo(next_action act) : acts{act} {}\n    mock_algo(next_action act1, next_action act2) : acts{act1, act2} {}\n\n    void check_calls(const std::vector<call_args>& expected) { BOOST_TEST(calls == expected, per_element()); }\n\n    next_action resume(error_code ec, std::size_t bytes_transferred)\n    {\n        calls.push_back(call_args{ec, bytes_transferred});\n        auto idx = current_call++;\n        return idx < acts.size() ? acts[idx] : next_action();\n    }\n};\n\n// returning next_action::read calls the relevant stream function\nBOOST_AUTO_TEST_CASE(next_action_read)\n{\n    struct\n    {\n        const char* name;\n        signature_t fn;\n        bool ssl_active;\n    } test_cases[] = {\n        {\"sync_ssl_active\",    sync_fn,  true },\n        {\"sync_ssl_inactive\",  sync_fn,  false},\n        {\"async_ssl_active\",   async_fn, true },\n        {\"async_ssl_inactive\", async_fn, false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            std::array<std::uint8_t, 8> buff{};\n            mock_algo algo(next_action::read({buff, tc.ssl_active}));\n            test_engine eng{fix.ctx.get_executor()};\n\n            tc.fn(eng, any_resumable_ref(algo)).validate_no_error_nodiag();\n            BOOST_TEST(eng.value.stream().calls.size() == 1u);\n            BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::read);\n            BOOST_TEST(eng.value.stream().calls[0].read_args().use_ssl == tc.ssl_active);\n            BOOST_TEST(eng.value.stream().calls[0].read_args().buffer.data() == buff.data());\n            BOOST_TEST(eng.value.stream().calls[0].read_args().buffer.size() == buff.size());\n            algo.check_calls({\n                {error_code(), 0u},\n                {error_code(), 8u}\n            });\n            // The testing infrastructure checks that we post correctly in async functions\n        }\n    }\n}\n\n// returning next_action::write calls the relevant stream function\nBOOST_AUTO_TEST_CASE(next_action_write)\n{\n    struct\n    {\n        const char* name;\n        signature_t fn;\n        bool ssl_active;\n    } test_cases[] = {\n        {\"sync_ssl_active\",    sync_fn,  true },\n        {\"sync_ssl_inactive\",  sync_fn,  false},\n        {\"async_ssl_active\",   async_fn, true },\n        {\"async_ssl_inactive\", async_fn, false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            const std::array<std::uint8_t, 4> buff{};\n            mock_algo algo(next_action::write({buff, tc.ssl_active}));\n            test_engine eng{fix.ctx.get_executor()};\n\n            tc.fn(eng, any_resumable_ref(algo)).validate_no_error_nodiag();\n            BOOST_TEST(eng.value.stream().calls.size() == 1u);\n            BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::write);\n            BOOST_TEST(eng.value.stream().calls[0].write_args().use_ssl == tc.ssl_active);\n            BOOST_TEST(eng.value.stream().calls[0].write_args().buffer.data() == buff.data());\n            BOOST_TEST(eng.value.stream().calls[0].write_args().buffer.size() == buff.size());\n            algo.check_calls({\n                {error_code(), 0u},\n                {error_code(), 4u}\n            });\n            // The testing infrastructure checks that we post correctly in async functions\n        }\n    }\n}\n\n// returning next_action::connect calls the relevant stream function\nBOOST_AUTO_TEST_CASE(next_action_connect)\n{\n    struct\n    {\n        const char* name;\n        signature_t fn;\n    } test_cases[] = {\n        {\"sync\",  sync_fn },\n        {\"async\", async_fn},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            const int server_address = 42;  // The connect arg is just a const void* that is passed around\n            io_context_fixture fix;\n            mock_algo algo(next_action::connect(&server_address));\n            test_engine eng{fix.ctx.get_executor()};\n\n            tc.fn(eng, any_resumable_ref(algo)).validate_no_error_nodiag();\n            BOOST_TEST(eng.value.stream().calls.size() == 1u);\n            BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::connect);\n            BOOST_TEST(eng.value.stream().calls[0].connect_endpoint() == &server_address);\n            algo.check_calls({\n                {error_code(), 0u},\n                {error_code(), 0u}\n            });\n            // The testing infrastructure checks that we post correctly in async functions\n        }\n    }\n}\n\n// returning next_action::ssl_handshake/ssl_shutdown/close calls the relevant stream function\nBOOST_AUTO_TEST_CASE(next_action_other)\n{\n    struct\n    {\n        const char* name;\n        signature_t fn;\n        next_action act;\n    } test_cases[] = {\n        {\"ssl_handshake_sync\",  sync_fn,  next_action::ssl_handshake()},\n        {\"ssl_handshake_async\", async_fn, next_action::ssl_handshake()},\n        {\"ssl_shutdown_sync\",   sync_fn,  next_action::ssl_shutdown() },\n        {\"ssl_shutdown_async\",  async_fn, next_action::ssl_shutdown() },\n        {\"close_sync\",          sync_fn,  next_action::close()        },\n        {\"close_async\",         async_fn, next_action::close()        },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            mock_algo algo(tc.act);\n            test_engine eng{fix.ctx.get_executor()};\n\n            tc.fn(eng, any_resumable_ref(algo)).validate_no_error_nodiag();\n            BOOST_TEST(eng.value.stream().calls.size() == 1u);\n            BOOST_TEST(eng.value.stream().calls[0].type() == tc.act.type());\n            algo.check_calls({\n                {error_code(), 0u},\n                {error_code(), 0u}\n            });\n            // The testing infrastructure checks that we post correctly in async functions\n        }\n    }\n}\n\n// Stream errors get propagated to the algorithm and don't exit the loop\nBOOST_AUTO_TEST_CASE(stream_errors)\n{\n    std::array<std::uint8_t, 8> buff{};\n    const std::array<std::uint8_t, 4> cbuff{};\n    constexpr int server_address = 42;\n\n    struct\n    {\n        const char* name;\n        signature_t fn;\n        next_action act;\n    } test_cases[] = {\n        {\"read_sync\",           sync_fn,  next_action::read({buff, false})     },\n        {\"read_async\",          async_fn, next_action::read({buff, false})     },\n        {\"write_sync\",          sync_fn,  next_action::write({cbuff, false})   },\n        {\"write_async\",         async_fn, next_action::write({cbuff, false})   },\n        {\"connect_sync\",        sync_fn,  next_action::connect(&server_address)},\n        {\"connect_async\",       async_fn, next_action::connect(&server_address)},\n        {\"ssl_handshake_sync\",  sync_fn,  next_action::ssl_handshake()         },\n        {\"ssl_handshake_async\", async_fn, next_action::ssl_handshake()         },\n        {\"ssl_shutdown_sync\",   sync_fn,  next_action::ssl_shutdown()          },\n        {\"ssl_shutdown_async\",  async_fn, next_action::ssl_shutdown()          },\n        {\"close_sync\",          sync_fn,  next_action::close()                 },\n        {\"close_async\",         async_fn, next_action::close()                 },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            mock_algo algo(tc.act);\n            test_engine eng{\n                {fix.ctx.get_executor(), asio::error::already_open}\n            };\n\n            tc.fn(eng, any_resumable_ref(algo))\n                .validate_no_error_nodiag();  // Error gets swallowed by the algo\n            BOOST_TEST(eng.value.stream().calls.size() == 1u);\n            BOOST_TEST(eng.value.stream().calls[0].type() == tc.act.type());\n            algo.check_calls({\n                {error_code(),              0u},\n                {asio::error::already_open, 0u}\n            });\n            // The testing infrastructure checks that we post correctly in async functions\n        }\n    }\n}\n\n// Returning an error or next_action() from resume in the first call works correctly\nBOOST_AUTO_TEST_CASE(resume_error_immediate_sync)\n{\n    struct\n    {\n        const char* name;\n        error_code ec;\n    } test_cases[] = {\n        {\"success\", error_code()        },\n        {\"error\",   asio::error::no_data},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            mock_algo algo(next_action(tc.ec));\n            test_engine eng{fix.ctx.get_executor()};\n\n            sync_fn(eng, any_resumable_ref(algo))\n                .validate_error(tc.ec, create_server_diag(\"<diagnostics unavailable>\"));\n            BOOST_TEST(eng.value.stream().calls.size() == 0u);\n            algo.check_calls({\n                {error_code(), 0u}\n            });\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(resume_error_immediate_async)\n{\n    struct\n    {\n        const char* name;\n        error_code ec;\n    } test_cases[] = {\n        {\"success\", error_code()        },\n        {\"error\",   asio::error::no_data},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // We need to call the initiation function from a context thread\n            // to get immediate completions\n            io_context_fixture fix;\n            run_in_context(fix.ctx, [&]() {\n                // Setup\n                mock_algo algo(next_action(tc.ec));\n                test_engine eng{fix.ctx.get_executor()};\n\n                // Run the function\n                eng.async_run(any_resumable_ref(algo), as_netresult)\n                    .run()\n                    .validate_immediate(true)\n                    .validate_error(tc.ec, create_server_diag(\"<diagnostics unavailable>\"));\n\n                // Check\n                BOOST_TEST(eng.value.stream().calls.size() == 0u);\n                algo.check_calls({\n                    {error_code(), 0u}\n                });\n            });\n        }\n    }\n}\n\n// Returning an error or next_action() from resume in successive calls works correctly\nBOOST_AUTO_TEST_CASE(resume_error_successive_calls)\n{\n    struct\n    {\n        const char* name;\n        signature_t fn;\n        error_code ec;\n    } test_cases[] = {\n        {\"success_sync\",  sync_fn,  error_code()        },\n        {\"success_async\", async_fn, error_code()        },\n        {\"error_sync\",    sync_fn,  asio::error::no_data},\n        {\"error_async\",   async_fn, asio::error::no_data},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            mock_algo algo(next_action::ssl_handshake(), next_action(tc.ec));\n            test_engine eng{fix.ctx.get_executor()};\n\n            tc.fn(eng, any_resumable_ref(algo))\n                .validate_error(tc.ec, create_server_diag(\"<diagnostics unavailable>\"));\n            BOOST_TEST(eng.value.stream().calls.size() == 1u);\n            BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::ssl_handshake);\n            algo.check_calls({\n                {error_code(), 0u},\n                {error_code(), 0u}\n            });\n        }\n    }\n}\n\n// Regression tests for https://github.com/boostorg/mysql/issues/199\n// If a cancellation signal is emitted after an operation completes successfully\n// and before its handler gets called, engine uses the composed op's cancellation\n// state and resumes the algorithm with a cancelled error code\nBOOST_FIXTURE_TEST_CASE(cancel_during_post, io_context_fixture)\n{\n    // Setup\n    mock_algo algo(next_action::ssl_handshake());\n    test_engine eng{ctx.get_executor()};\n    asio::cancellation_signal sig;\n\n    // Start the operation. The mock stream will immediately complete the requested operation\n    // by calling asio::post.\n    auto run_result = eng.async_run(\n        any_resumable_ref(algo),\n        asio::bind_cancellation_slot(sig.slot(), as_netresult)\n    );\n\n    // At this point, the completion hasn't been called yet, since run() hasn't been called.\n    // Emit the cancellation signal\n    sig.emit(asio::cancellation_type_t::terminal);\n\n    // Run until completion\n    std::move(run_result).validate_no_error_nodiag();\n\n    // The algorithm was resumed with the relevant error\n    BOOST_TEST(eng.value.stream().calls.size() == 1u);\n    BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::ssl_handshake);\n    algo.check_calls({\n        {error_code(),                   0u},\n        {asio::error::operation_aborted, 0u}\n    });\n}\n\n// We do nothing for cancellation types != terminal\nBOOST_FIXTURE_TEST_CASE(cancel_during_post_cancel_type_non_terminal, io_context_fixture)\n{\n    // Setup\n    mock_algo algo(next_action::ssl_handshake());\n    test_engine eng{ctx.get_executor()};\n    asio::cancellation_signal sig;\n\n    // Start the operation. The mock stream will immediately complete the requested operation\n    // by calling asio::post.\n    auto run_result = eng.async_run(\n        any_resumable_ref(algo),\n        asio::bind_cancellation_slot(sig.slot(), as_netresult)\n    );\n\n    // At this point, the completion hasn't been called yet, since run() hasn't been called.\n    // Emit the cancellation signal\n    sig.emit(asio::cancellation_type_t::total);\n\n    // Run until completion\n    std::move(run_result).validate_no_error_nodiag();\n\n    // The cancellation is ignored because algorithms don't support total cancellation\n    BOOST_TEST(eng.value.stream().calls.size() == 1u);\n    BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::ssl_handshake);\n    algo.check_calls({\n        {error_code(), 0u},\n        {error_code(), 0u}\n    });\n}\n\n// If the operation failed with another error code, we don't override it\nBOOST_FIXTURE_TEST_CASE(cancel_during_post_other_error, io_context_fixture)\n{\n    // Setup\n    mock_algo algo(next_action::ssl_handshake());\n    test_engine eng{\n        {ctx.get_executor(), asio::error::network_reset}\n    };\n    asio::cancellation_signal sig;\n\n    // Start the operation. The mock stream will immediately complete the requested operation\n    // by calling asio::post.\n    auto run_result = eng.async_run(\n        any_resumable_ref(algo),\n        asio::bind_cancellation_slot(sig.slot(), as_netresult)\n    );\n\n    // At this point, the completion hasn't been called yet, since run() hasn't been called.\n    // Emit the cancellation signal\n    sig.emit(asio::cancellation_type_t::terminal);\n\n    // Run until completion\n    std::move(run_result).validate_no_error_nodiag();\n\n    // The cancellation didn't override the operation's error code\n    BOOST_TEST(eng.value.stream().calls.size() == 1u);\n    BOOST_TEST(eng.value.stream().calls[0].type() == next_action_type::ssl_handshake);\n    algo.check_calls({\n        {error_code(),               0u},\n        {asio::error::network_reset, 0u}\n    });\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/execution_concepts.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/execution_concepts.hpp>\n\n#include <string>\n#include <string_view>\n\nusing namespace boost::mysql;\nusing boost::mysql::detail::execution_state_type;\nusing boost::mysql::detail::is_execution_request;\nusing boost::mysql::detail::results_type;\n\nnamespace {\n\n// -----\n// is_execution_request\n// -----\n\n// strings\nstatic_assert(is_execution_request<std::string>::value, \"\");\nstatic_assert(is_execution_request<const std::string&>::value, \"\");\nstatic_assert(is_execution_request<std::string&&>::value, \"\");\nstatic_assert(is_execution_request<std::string&>::value, \"\");\n\nstatic_assert(is_execution_request<string_view>::value, \"\");\nstatic_assert(is_execution_request<const string_view&>::value, \"\");\nstatic_assert(is_execution_request<string_view&&>::value, \"\");\n\nstatic_assert(is_execution_request<std::string_view>::value, \"\");\nstatic_assert(is_execution_request<const std::string_view&>::value, \"\");\nstatic_assert(is_execution_request<std::string_view&&>::value, \"\");\n\nstatic_assert(is_execution_request<const char*>::value, \"\");\n\nstatic_assert(is_execution_request<const char[14]>::value, \"\");\nstatic_assert(is_execution_request<const char (&)[14]>::value, \"\");\n\n// tuple statements\nusing tup_type = std::tuple<int, const char*, std::nullptr_t>;\nstatic_assert(is_execution_request<bound_statement_tuple<tup_type>>::value, \"\");\nstatic_assert(is_execution_request<const bound_statement_tuple<tup_type>&>::value, \"\");\nstatic_assert(is_execution_request<bound_statement_tuple<tup_type>&>::value, \"\");\nstatic_assert(is_execution_request<bound_statement_tuple<tup_type>&&>::value, \"\");\n\nstatic_assert(is_execution_request<bound_statement_tuple<std::tuple<>>>::value, \"\");\n\nstatic_assert(!is_execution_request<tup_type>::value, \"\");\nstatic_assert(!is_execution_request<const tup_type&>::value, \"\");\nstatic_assert(!is_execution_request<tup_type&>::value, \"\");\nstatic_assert(!is_execution_request<tup_type&&>::value, \"\");\n\n// iterator range statements\nstatic_assert(is_execution_request<bound_statement_iterator_range<field_view*>>::value, \"\");\nstatic_assert(is_execution_request<const bound_statement_iterator_range<field_view*>&>::value, \"\");\nstatic_assert(is_execution_request<bound_statement_iterator_range<field_view*>&>::value, \"\");\nstatic_assert(is_execution_request<bound_statement_iterator_range<field_view*>&&>::value, \"\");\n\nstatic_assert(!is_execution_request<field_view*>::value, \"\");\n\n// with_params\nstatic_assert(is_execution_request<with_params_t<>>::value, \"\");\nstatic_assert(is_execution_request<with_params_t<int>>::value, \"\");\nstatic_assert(is_execution_request<with_params_t<int, float>>::value, \"\");\nstatic_assert(is_execution_request<with_params_t<const std::string&, float>>::value, \"\");\n\nstatic_assert(is_execution_request<with_params_t<int>&>::value, \"\");\nstatic_assert(is_execution_request<const with_params_t<int>&>::value, \"\");\nstatic_assert(is_execution_request<with_params_t<int>&&>::value, \"\");\nstatic_assert(is_execution_request<with_params_t<const std::string&>&&>::value, \"\");\n\n// Other stuff\nstatic_assert(!is_execution_request<field_view>::value, \"\");\nstatic_assert(!is_execution_request<int>::value, \"\");\nstatic_assert(!is_execution_request<std::nullptr_t>::value, \"\");\n\nusing row1 = std::tuple<int, float>;\nusing row2 = std::tuple<double>;\n\n// -----\n// execution_state_type\n// -----\nstatic_assert(!execution_state_type<std::string>, \"\");\nstatic_assert(!execution_state_type<int>, \"\");\nstatic_assert(!execution_state_type<results>, \"\");\nstatic_assert(!execution_state_type<static_results<row1>>, \"\");\nstatic_assert(!execution_state_type<static_results<row1, row2>>, \"\");\nstatic_assert(execution_state_type<execution_state>, \"\");\nstatic_assert(execution_state_type<static_execution_state<row1>>, \"\");\nstatic_assert(execution_state_type<static_execution_state<row1, row2>>, \"\");\n\n// -----\n// results_type\n// -----\nstatic_assert(!results_type<std::string>, \"\");\nstatic_assert(!results_type<int>, \"\");\nstatic_assert(!results_type<execution_state>, \"\");\nstatic_assert(!results_type<static_execution_state<row1>>, \"\");\nstatic_assert(!results_type<static_execution_state<row1, row2>>, \"\");\nstatic_assert(results_type<results>, \"\");\nstatic_assert(results_type<static_results<row1>>, \"\");\nstatic_assert(results_type<static_results<row1, row2>>, \"\");\n\n}  // namespace\n\n#endif\n"
  },
  {
    "path": "test/unit/test/detail/intermediate_handler.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/intermediate_handler.hpp>\n\n#include <boost/asio/associated_allocator.hpp>\n#include <boost/asio/associated_cancellation_slot.hpp>\n#include <boost/asio/associated_executor.hpp>\n#include <boost/asio/associated_immediate_executor.hpp>\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/bind_allocator.hpp>\n#include <boost/asio/bind_cancellation_slot.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/bind_immediate_executor.hpp>\n#include <boost/asio/cancellation_signal.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n#include \"test_unit/custom_allocator.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_intermediate_handler)\n\n//\n// intermediate_handler. Verify that associated characteristics are propagated\n//\n\n// Initiation object that checks the expected values and calls the handler\nstruct initiate_check\n{\n    template <class Handler>\n    void operator()(\n        Handler&& handler,\n        int expected_ex_id,\n        int expected_immediate_ex_id,\n        asio::cancellation_slot expected_slot\n    )\n    {\n        // Associated executor propagated\n        auto ex = asio::get_associated_executor(handler);\n        BOOST_TEST(get_executor_id(ex) == expected_ex_id);\n\n        // Immediate executor propagated\n        auto immediate_ex = asio::get_associated_immediate_executor(handler, ex);\n        BOOST_TEST(get_executor_id(immediate_ex) == expected_immediate_ex_id);\n\n        // Cancellation slot propagated\n        auto slot = asio::get_associated_cancellation_slot(handler);\n        BOOST_TEST((slot == expected_slot));\n\n        // Allocator propagated\n        using alloc_t = decltype(asio::get_associated_allocator(handler));\n        static_assert(std::is_same<alloc_t, custom_allocator<void>>::value, \"\");\n\n        // Just call the handler\n        handler(client_errc::wrong_num_params, 42);\n    }\n};\n\n// Handler fn required by intermediate_handler\nstruct handler_fn\n{\n    int value;\n\n    template <class Handler>\n    void operator()(Handler&& handler, error_code ec, int v)\n    {\n        BOOST_TEST(ec == client_errc::wrong_num_params);\n        BOOST_TEST(v == 42);\n        handler(ec, v + value);\n    }\n};\n\n// Initiates using an intermediate handler\ntemplate <class CompletionToken>\nvoid async_check(\n    int expected_ex_id,\n    int expected_immediate_ex_id,\n    asio::cancellation_slot expected_slot,\n    CompletionToken&& token\n)\n{\n    auto actual_handler = detail::make_intermediate_handler(\n        handler_fn{3},\n        std::forward<CompletionToken>(token)\n    );\n    asio::async_initiate<decltype(actual_handler), void(error_code, int)>(\n        initiate_check{},\n        actual_handler,\n        expected_ex_id,\n        expected_immediate_ex_id,\n        expected_slot\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE(immediate_handler_propagates_properties, io_context_fixture)\n{\n    // Setup\n    auto ex_result = create_tracker_executor(ctx.get_executor());\n    auto immediate_ex_result = create_tracker_executor(ctx.get_executor());\n    asio::cancellation_signal sig;\n    custom_allocator<void> alloc;\n    bool called = false;\n    auto final_handler = [&](error_code ec, int value) {\n        BOOST_TEST(ec == client_errc::wrong_num_params);\n        BOOST_TEST(value == 45);\n        called = true;\n    };\n\n    // Invoke the operation\n    async_check(\n        ex_result.executor_id,\n        immediate_ex_result.executor_id,\n        sig.slot(),\n        asio::bind_executor(\n            ex_result.ex,\n            asio::bind_immediate_executor(\n                immediate_ex_result.ex,\n                asio::bind_cancellation_slot(\n                    sig.slot(),\n                    asio::bind_allocator(alloc, std::move(final_handler))\n                )\n            )\n        )\n    );\n\n    // Sanity check\n    BOOST_TEST(called);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/output_string.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/output_string.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <string>\n\n#include \"test_unit/custom_allocator.hpp\"\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_output_string)\n\nstruct other_traits : std::char_traits<char>\n{\n};\n\nusing string_with_alloc = std::basic_string<char, std::char_traits<char>, test::custom_allocator<char>>;\nusing string_no_defctor = std::\n    basic_string<char, std::char_traits<char>, test::custom_allocator_no_defctor<char>>;\nusing string_with_traits = std::basic_string<char, other_traits>;\n\nstruct output_string_archetype\n{\n    std::size_t num_appends{};\n\n    // No default constructor\n    output_string_archetype(int, float, char) {}\n\n    // No copy operations\n    output_string_archetype(const output_string_archetype&) = delete;\n    output_string_archetype& operator=(const output_string_archetype&) = delete;\n\n    // Move operations allowed\n    output_string_archetype(output_string_archetype&&) {}\n    output_string_archetype& operator=(output_string_archetype&&) { return *this; };\n\n    // Adequate member functions\n    void append(const char*, std::size_t) { ++num_appends; }\n    void clear() {}\n};\n\n//\n// output_string_ref\n//\nBOOST_AUTO_TEST_CASE(ref_string)\n{\n    // A reference can be created from a std::string\n    std::string s(\"abcd\");\n    auto ref = detail::output_string_ref::create(s);\n\n    // Appending works\n    ref.append(\" hello\");\n    BOOST_TEST(s == \"abcd hello\");\n    ref.append(\" world\");\n    BOOST_TEST(s == \"abcd hello world\");\n\n    // Append with zero length is okay\n    ref.append(string_view());\n    BOOST_TEST(s == \"abcd hello world\");\n}\n\nBOOST_AUTO_TEST_CASE(ref_string_with_alloc)\n{\n    // A reference can be created from a std::basic_string with custom allocator\n    string_with_alloc s(\"abcd\");\n    auto ref = detail::output_string_ref::create(s);\n\n    // Appending works\n    ref.append(\" hello\");\n    BOOST_TEST(s == \"abcd hello\");\n    ref.append(\" world\");\n    BOOST_TEST(s == \"abcd hello world\");\n\n    // Append with zero length is okay\n    ref.append(string_view());\n    BOOST_TEST(s == \"abcd hello world\");\n}\n\nBOOST_AUTO_TEST_CASE(ref_archetype)\n{\n    // A reference can be created from the archetype\n    output_string_archetype s(1, 1.0, 'a');\n    auto ref = detail::output_string_ref::create(s);\n\n    // Appending works\n    ref.append(\" hello\");\n    BOOST_TEST(s.num_appends == 1u);\n    ref.append(\" world\");\n    BOOST_TEST(s.num_appends == 2u);\n\n    // Append with zero length doesn't reach the actual function\n    ref.append(string_view());\n    BOOST_TEST(s.num_appends == 2u);\n}\n\n//\n// output_string\n//\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n\nusing boost::mysql::detail::output_string;\n\n// std::basic_string can be used as long as it's using char\nstatic_assert(output_string<std::string>);\nstatic_assert(output_string<string_with_alloc>);\nstatic_assert(output_string<string_no_defctor>);\nstatic_assert(output_string<string_with_traits>);\n\n// Archetype allowed\nstatic_assert(output_string<output_string_archetype>);\n\n// Other types disallowed\nstatic_assert(!output_string<int>);\nstatic_assert(!output_string<float>);\nstatic_assert(!output_string<const char*>);\nstatic_assert(!output_string<char[20]>);\nstatic_assert(!output_string<std::vector<char>>);\n\n// Strings with other character types disallowed\nstatic_assert(!output_string<std::wstring>);\nstatic_assert(!output_string<std::u32string>);\n\n// References not allowed\nstatic_assert(!output_string<std::string&>);\nstatic_assert(!output_string<const std::string&>);\nstatic_assert(!output_string<std::string&&>);\nstatic_assert(!output_string<const std::string&&>);\n\n// Views not allowed\nstatic_assert(!output_string<string_view>);\n\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/row_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/mysql/detail/row_impl.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::mysql::detail::row_impl;\n\nBOOST_AUTO_TEST_SUITE(test_row_impl)\n\ntemplate <class... T>\nrow_impl makerowimpl(T&&... args)\n{\n    auto fields = make_fv_arr(std::forward<T>(args)...);\n    return row_impl(fields.data(), fields.size());\n}\n\ntemplate <class... T>\nvoid add_fields(row_impl& r, T&&... args)\n{\n    auto fields = make_fv_arr(std::forward<T>(args)...);\n    std::copy(fields.begin(), fields.end(), r.add_fields(fields.size()).data());\n}\n\n// An array and vector with all scalar types\nstd::vector<field_view> make_scalar_vector()\n{\n    return make_fv_vector(\n        42,\n        42u,\n        4.2f,\n        4.2,\n        date(2020, 1, 2),\n        datetime(2020, 10, 10),\n        maket(10, 1, 1),\n        nullptr\n    );\n}\n\nvoid hard_clear(std::vector<field_view>& res)\n{\n    for (auto& f : res)\n        f = field_view();\n}\n\n// Check that references to certain row_impl's contents survive an operation\nstruct reference_checker\n{\n    const field_view* ptr;\n\n    reference_checker(const row_impl& r) : ptr(r.fields().data()) {}\n\n    void check(const row_impl& new_row) { BOOST_TEST(ptr == new_row.fields().data()); }\n};\n\nstruct reference_checker_strs : reference_checker\n{\n    std::size_t string_index, blob_index;  // indices in the row where a string/blob field resides\n    const char* string_ptr;\n    const unsigned char* blob_ptr;\n\n    static void assert_ptrs_equal(const char* ptr1, const char* ptr2)\n    {\n        // Otherwise, UTF thinks it's a C string, tries to print it and causes Valgrind errors\n        BOOST_TEST(static_cast<const void*>(ptr1) == static_cast<const void*>(ptr2));\n    }\n\n    reference_checker_strs(const row_impl& r, std::size_t string_index, std::size_t blob_index)\n        : reference_checker(r),\n          string_index(string_index),\n          blob_index(blob_index),\n          string_ptr(r.fields().at(string_index).as_string().data()),\n          blob_ptr(r.fields().at(blob_index).as_blob().data())\n    {\n    }\n\n    void check(const row_impl& new_row)\n    {\n        reference_checker::check(new_row);\n        assert_ptrs_equal(string_ptr, new_row.fields().at(string_index).as_string().data());\n        BOOST_TEST(blob_ptr == new_row.fields().at(blob_index).as_blob().data());\n    }\n};\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    row_impl r;\n    BOOST_TEST(r.fields().empty());\n}\n\nBOOST_AUTO_TEST_SUITE(ctor_from_span)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    std::vector<field_view> fields;\n    row_impl r(fields.data(), fields.size());\n    BOOST_TEST(r.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_strings)\n{\n    auto fields = make_scalar_vector();\n    row_impl r(fields.data(), fields.size());\n\n    // Fields still valid even when the original source of the view changed\n    hard_clear(fields);\n    BOOST_TEST(r.fields() == make_scalar_vector());\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    std::string s1(\"test\"), s2(\"othertest\");\n    blob b{0x00, 0xab, 0xf5};\n    auto fields = make_fv_arr(s1, s2, 50, b);\n    row_impl r(fields.data(), fields.size());\n\n    // Fields still valid even when the original strings changed\n    s1 = \"jkiop\";\n    s2 = \"abcdef\";\n    b = {0xff, 0xa4, 0x02};\n    BOOST_TEST(r.fields().size() == 4u);\n    BOOST_TEST(r.fields()[0] == field_view(\"test\"));\n    BOOST_TEST(r.fields()[1] == field_view(\"othertest\"));\n    BOOST_TEST(r.fields()[2] == field_view(50));\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(r.fields()[3].as_blob(), blob({0x00, 0xab, 0xf5}));\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    std::string s;\n    blob b;\n    auto fields = make_fv_arr(s, 50, b);\n    row_impl r(fields.data(), fields.size());\n\n    // Fields still valid even when the original strings changed\n    s = \"other\";\n    b = {0xff, 0xa4, 0x02};\n    BOOST_TEST(r.fields().size() == 3u);\n    BOOST_TEST(r.fields()[0] == field_view(\"\"));\n    BOOST_TEST(r.fields()[1] == field_view(50));\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(r.fields()[2].as_blob(), blob());\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_ctor)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_impl r1;\n    row_impl r2(r1);\n    r1 = makerowimpl(42, \"test\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_strings)\n{\n    auto fields = make_scalar_vector();\n    row_impl r1(fields.data(), fields.size());\n    row_impl r2(r1);\n    r1 = makerowimpl(42, \"test\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields() == make_scalar_vector());\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    row_impl r1 = makerowimpl(\"\", 42, \"test\", makebv(\"\\0\\3\\2\"));\n    row_impl r2(r1);\n    r1 = makerowimpl(\"another_string\", 4.2f, \"\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields().size() == 4u);\n    BOOST_TEST(r2.fields()[0] == field_view(\"\"));\n    BOOST_TEST(r2.fields()[1] == field_view(42));\n    BOOST_TEST(r2.fields()[2] == field_view(\"test\"));\n    BOOST_TEST(r2.fields()[3] == field_view(makebv(\"\\0\\3\\2\")));\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    row_impl r1 = makerowimpl(\"\", 42, blob_view());\n    row_impl r2(r1);\n    r1 = makerowimpl(\"another_string\", 4.2f, \"\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields().size() == 3u);\n    BOOST_TEST(r2.fields()[0] == field_view(\"\"));\n    BOOST_TEST(r2.fields()[1] == field_view(42));\n    BOOST_TEST(r2.fields()[2] == field_view(blob_view()));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_ctor)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_impl r1;\n\n    // References should remain valid\n    reference_checker refcheck(r1);\n\n    row_impl r2(std::move(r1));\n    r1 = makerowimpl(42, \"test\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields().empty());\n    refcheck.check(r2);\n}\n\nBOOST_AUTO_TEST_CASE(non_strings)\n{\n    auto fields = make_scalar_vector();\n    row_impl r1(fields.data(), fields.size());\n\n    // References, pointers, etc. should remain valid\n    reference_checker refcheck(r1);\n\n    row_impl r2(std::move(r1));\n    r1 = makerowimpl(42, \"test\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields() == make_scalar_vector());\n    refcheck.check(r2);\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    row_impl r1 = makerowimpl(\"\", 42, \"test\", makebv(\"\\0\\5\\xff\"));\n\n    // References, pointers, etc should remain valid\n    reference_checker_strs refcheck(r1, 2, 3);\n\n    // Move\n    row_impl r2(std::move(r1));\n    r1 = makerowimpl(\"another_string\", 4.2f, \"\", makebv(\"\\1\\5\\xab\"));  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields().size() == 4u);\n    BOOST_TEST(r2.fields()[0] == field_view(\"\"));\n    BOOST_TEST(r2.fields()[1] == field_view(42));\n    BOOST_TEST(r2.fields()[2] == field_view(\"test\"));\n    BOOST_TEST(r2.fields()[3] == field_view(makebv(\"\\0\\5\\xff\")));\n\n    // References, pointers, etc still valid\n    refcheck.check(r2);\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    row_impl r1 = makerowimpl(\"\", 42, blob_view());\n\n    // Move\n    row_impl r2(std::move(r1));\n    r1 = makerowimpl(\"another_string\", 4.2f, \"\", makebv(\"\\1\\5\\xab\"));  // r2 should be independent of r1\n\n    BOOST_TEST(r2.fields() == make_fv_vector(\"\", 42, blob_view()));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_assignment)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_impl r1 = makerowimpl(42, \"abcdef\");\n    row_impl r2;\n    r1 = r2;\n    r2 = makerowimpl(90, nullptr);  // r1 is independent of r2\n    BOOST_TEST(r1.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_strings)\n{\n    auto fields = make_scalar_vector();\n    row_impl r1 = makerowimpl(42, \"abcdef\");\n    row_impl r2(fields.data(), fields.size());\n    r1 = r2;\n    r2 = makerowimpl(\"abc\", 80, nullptr);  // r1 is independent of r2\n\n    BOOST_TEST(r1.fields() == make_scalar_vector());\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    row_impl r1 = makerowimpl(42, \"abcdef\", makebv(\"\\0\\1\\2\"));\n    row_impl r2 = makerowimpl(\"a_very_long_string\", nullptr, \"\", makebv(\"\\3\\4\\5\"));\n    r1 = r2;\n    r2 = makerowimpl(\"another_string\", 90, \"yet_another\");  // r1 is independent of r2\n\n    BOOST_TEST(r1.fields() == make_fv_vector(\"a_very_long_string\", nullptr, \"\", makebv(\"\\3\\4\\5\")));\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    row_impl r1 = makerowimpl(42, \"abcdef\", makebv(\"\\0\\1\\2\"));\n    row_impl r2 = makerowimpl(nullptr, \"\", blob_view());\n    r1 = r2;\n    r2 = makerowimpl(\"another_string\", 90, \"yet_another\");  // r1 is independent of r2\n\n    BOOST_TEST(r1.fields() == make_fv_vector(nullptr, \"\", blob_view()));\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs_empty_to)\n{\n    row_impl r1;\n    row_impl r2 = makerowimpl(\"abc\", nullptr, \"bcd\", makebv(\"\\1\\2\\3\"));\n    r1 = r2;\n\n    BOOST_TEST(r1.fields() == make_fv_vector(\"abc\", nullptr, \"bcd\", makebv(\"\\1\\2\\3\")));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment_empty)\n{\n    row_impl r;\n    const row_impl& ref = r;\n    r = ref;\n\n    BOOST_TEST(r.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment_non_empty)\n{\n    row_impl r = makerowimpl(\"abc\", 50u, \"fgh\");\n    const row_impl& ref = r;\n    r = ref;\n\n    BOOST_TEST(r.fields() == make_fv_vector(\"abc\", 50u, \"fgh\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_assignment)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_impl r1 = makerowimpl(42, \"abcdef\");\n    row_impl r2;\n\n    reference_checker refcheck(r2);\n\n    r1 = std::move(r2);\n    r2 = makerowimpl(90, nullptr);  // r1 is independent of r2\n    BOOST_TEST(r1.fields().empty());\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(non_strings)\n{\n    auto fields = make_scalar_vector();\n    row_impl r1 = makerowimpl(42, \"abcdef\");\n    row_impl r2(fields.data(), fields.size());\n\n    // References should remain valid\n    reference_checker refcheck(r2);\n\n    r1 = std::move(r2);\n    r2 = makerowimpl(\"abc\", 80, nullptr);  // r1 is independent of r2\n\n    BOOST_TEST(r1.fields() == make_scalar_vector());\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    row_impl r1 = makerowimpl(42, \"abcdef\", makebv(\"\\0\\4\\1\"));\n    row_impl r2 = makerowimpl(\"a_very_long_string\", nullptr, \"\", makebv(\"\\7\\1\\2\"));\n\n    // References, pointers, etc should remain valid\n    reference_checker_strs refcheck(r2, 0, 3);\n\n    // Move\n    r1 = std::move(r2);\n    r2 = makerowimpl(\"another_string\", 90, \"yet_another\", makebv(\"\\0\\0\"));  // r1 is independent of r2\n\n    BOOST_TEST(r1.fields() == make_fv_vector(\"a_very_long_string\", nullptr, \"\", makebv(\"\\7\\1\\2\")));\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    row_impl r1 = makerowimpl(42, \"abcdef\", makebv(\"\\0\\4\\1\"));\n    row_impl r2 = makerowimpl(\"\", blob_view());\n\n    // References, pointers, etc should remain valid\n    reference_checker_strs refcheck(r2, 0, 1);\n\n    // Move\n    r1 = std::move(r2);\n    r2 = makerowimpl(\"another_string\", 90);  // r1 is independent of r2\n\n    BOOST_TEST(r1.fields() == make_fv_vector(\"\", blob_view()));\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs_empty_to)\n{\n    row_impl r1;\n    row_impl r2 = makerowimpl(\"abc\", nullptr, \"bcd\", makebv(\"\\0\\2\\5\"));\n\n    // References, pointers, etc should remain valid\n    reference_checker_strs refcheck(r2, 2, 3);\n\n    r1 = std::move(r2);\n\n    BOOST_TEST(r1.fields() == make_fv_vector(\"abc\", nullptr, \"bcd\", makebv(\"\\0\\2\\5\")));\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment_empty)\n{\n    row_impl r;\n    row_impl&& ref = std::move(r);\n    r = std::move(ref);\n\n    // r is in a valid but unspecified state; can be assigned to\n    r = makerowimpl(\"abcdef\");\n    BOOST_TEST(r.fields() == make_fv_vector(\"abcdef\"));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment_non_empty)\n{\n    row_impl r = makerowimpl(\"abc\", 50u, \"fgh\", makebv(\"\\0\\4\"));\n    row_impl&& ref = std::move(r);\n    r = std::move(ref);  // this should leave r in a valid but unspecified state\n\n    // r is in a valid but unspecified state; can be assigned to\n    r = makerowimpl(\"abcdef\");\n    BOOST_TEST(r.fields() == make_fv_vector(\"abcdef\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(assignment_from_span)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_impl r = makerowimpl(42, \"abcdef\", makebv(\"\\0\\xae\"));\n    r.assign(nullptr, 0);\n    BOOST_TEST(r.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(empty_non_null)\n{\n    field_view f;\n    row_impl r = makerowimpl(42, \"abcdef\", makebv(\"\\0\\xae\"));\n    r.assign(&f, 0);\n    BOOST_TEST(r.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_strings)\n{\n    row_impl r = makerowimpl(42, \"abcdef\");\n    auto fields = make_scalar_vector();\n    r.assign(fields.data(), fields.size());\n    hard_clear(fields);  // r should be independent of the original fields\n\n    BOOST_TEST(r.fields() == make_scalar_vector());\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    std::string s1(\"a_very_long_string\"), s2(\"abc\");\n    blob b{0x00, 0xfa};\n    row_impl r = makerowimpl(42, \"haksj\", makebv(\"\\0\\1\"));\n    auto fields = make_fv_arr(s1, nullptr, s2, b);\n\n    r.assign(fields.data(), fields.size());\n    fields = make_fv_arr(\"abc\", 42u, 9, nullptr);  // r should be independent of the original fields\n    s1 = \"another_string\";                         // r should be independent of the original strings\n    s2 = \"yet_another\";\n    b = {0xac, 0x32, 0x21, 0x50};\n\n    BOOST_TEST(r.fields() == make_fv_vector(\"a_very_long_string\", nullptr, \"abc\", makebv(\"\\0\\xfa\")));\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    std::string s(\"\");\n    blob b;\n    row_impl r = makerowimpl(42, \"haksj\", makebv(\"\\0\\1\"));\n    auto fields = make_fv_arr(s, b);\n\n    r.assign(fields.data(), fields.size());\n    fields = make_fv_arr(0, 0);  // r should be independent of the original fields\n    s = \"another_string\";        // r should be independent of the original strings\n    b = {0xac, 0x32, 0x21, 0x50};\n\n    BOOST_TEST(r.fields() == make_fv_vector(\"\", blob_view()));\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs_empty_to)\n{\n    row_impl r;\n    auto fields = make_fv_arr(\"abc\", nullptr, \"bcd\", makebv(\"\\0\\3\"));\n    r.assign(fields.data(), fields.size());\n\n    BOOST_TEST(r.fields() == make_fv_vector(\"abc\", nullptr, \"bcd\", makebv(\"\\0\\3\")));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    row_impl r = makerowimpl(\"abcdef\", 42, \"plk\", makebv(\"\\0\\1\"));\n    r.assign(r.fields().data(), r.fields().size());\n\n    BOOST_TEST(r.fields() == make_fv_vector(\"abcdef\", 42, \"plk\", makebv(\"\\0\\1\")));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment_empty)\n{\n    row_impl r;\n    r.assign(r.fields().data(), r.fields().size());\n    BOOST_TEST(r.fields().empty());\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment_cleared)\n{\n    row_impl r = makerowimpl(42, \"abc\");\n    r.clear();\n    r.assign(r.fields().data(), r.fields().size());\n    BOOST_TEST(r.fields().empty());\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(add_fields_)\nBOOST_AUTO_TEST_CASE(empty_collection)\n{\n    row_impl r;\n    auto storage = r.add_fields(2);\n    BOOST_TEST(r.fields().size() == 2u);\n    BOOST_TEST(storage.data() == r.fields().data());\n    BOOST_TEST(storage.size() == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty_collection)\n{\n    row_impl r = makerowimpl(nullptr, nullptr);\n    auto storage = r.add_fields(3);\n    BOOST_TEST(r.fields().size() == 5u);\n    BOOST_TEST(storage.data() == r.fields().data() + 2);\n    BOOST_TEST(storage.size() == 3u);\n}\n\nBOOST_AUTO_TEST_CASE(zero_fields)\n{\n    row_impl r = makerowimpl(nullptr, nullptr);\n    auto storage = r.add_fields(0);\n    BOOST_TEST(r.fields().size() == 2u);\n    BOOST_TEST(storage.data() == r.fields().data() + 2);\n    BOOST_TEST(storage.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(empty_collection_zero_fields)\n{\n    row_impl r;\n    auto storage = r.add_fields(0);\n    BOOST_TEST(r.fields().size() == 0u);\n    BOOST_TEST(storage.data() == r.fields().data());\n    BOOST_TEST(storage.size() == 0u);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_strings_as_offsets)\nBOOST_AUTO_TEST_CASE(scalars)\n{\n    row_impl r;\n    add_fields(r, nullptr, 42, 10.0f, date(2020, 10, 1));\n    r.copy_strings_as_offsets(0, 4);\n    r.offsets_to_string_views();\n    BOOST_TEST(r.fields() == make_fv_vector(nullptr, 42, 10.f, date(2020, 10, 1)));\n}\n\nBOOST_AUTO_TEST_CASE(strings_blobs)\n{\n    row_impl r;\n    std::string s = \"abc\";\n    blob b{0x01, 0x02, 0x03};\n    add_fields(r, nullptr, s, 10.f, b);\n    r.copy_strings_as_offsets(1, 3);\n    s = \"ghi\";\n    b = {0xff, 0xff, 0xff};\n    r.offsets_to_string_views();\n    BOOST_TEST(r.fields() == make_fv_vector(nullptr, \"abc\", 10.f, makebv(\"\\1\\2\\3\")));\n}\n\nBOOST_AUTO_TEST_CASE(empty_strings_blobs)\n{\n    row_impl r;\n    std::string s = \"\";\n    blob b{};\n    add_fields(r, nullptr, s, 10.f, b);\n    r.copy_strings_as_offsets(1, 3);\n    s = \"ghi\";\n    b = {0xff, 0xff, 0xff};\n    r.offsets_to_string_views();\n    BOOST_TEST(r.fields() == make_fv_vector(nullptr, \"\", 10.f, makebv(\"\")));\n}\n\nBOOST_AUTO_TEST_CASE(buffer_relocation)\n{\n    row_impl r;\n    std::string s = \"abc\";\n    add_fields(r, nullptr, s);\n    r.copy_strings_as_offsets(0, 2);\n    s = \"ghi\";\n\n    blob b{0x01, 0x02, 0x03};\n    add_fields(r, 10.f, b);\n    r.copy_strings_as_offsets(2, 2);\n\n    s = \"\";\n    b = {};\n    add_fields(r, s, b);\n    r.copy_strings_as_offsets(4, 2);\n    b = {0x01, 0x02};\n\n    s = \"this is a long string\";\n    add_fields(r, s);\n    r.copy_strings_as_offsets(6, 1);\n    s = \"another long string\";\n\n    r.offsets_to_string_views();\n    BOOST_TEST(\n        r.fields() ==\n        make_fv_vector(nullptr, \"abc\", 10.f, makebv(\"\\1\\2\\3\"), \"\", makebv(\"\"), \"this is a long string\")\n    );\n}\n\nBOOST_AUTO_TEST_CASE(empty_range)\n{\n    std::string s = \"abc\";\n    row_impl r = makerowimpl(nullptr, 42);\n    r.copy_strings_as_offsets(0, 0);\n    r.offsets_to_string_views();\n    BOOST_TEST(r.fields() == make_fv_vector(nullptr, 42));\n}\n\nBOOST_AUTO_TEST_CASE(empty_collection)\n{\n    row_impl r;\n    r.copy_strings_as_offsets(0, 0);\n    r.offsets_to_string_views();\n    BOOST_TEST(r.fields().empty());\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/rows_iterator.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/rows.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/rows_iterator.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <stdexcept>\n#include <tuple>\n#include <utility>\n\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_TEST_DONT_PRINT_LOG_VALUE(boost::mysql::detail::rows_iterator)\n\nBOOST_AUTO_TEST_SUITE(test_rows_iterator)\n\n// Provide a uniform interface for both rows and rows_view types,\n// so we can use template tests to reduce duplication\nstruct rows_view_wrapper\n{\n    std::vector<field_view> fields;\n    rows_view r;\n\n    rows_view_wrapper() = default;\n\n    template <typename... Args>\n    rows_view_wrapper(std::size_t num_columns, Args&&... args)\n        : fields(make_fv_vector(std::forward<Args>(args)...)),\n          r(makerowsv(fields.data(), sizeof...(args), num_columns))\n    {\n    }\n\n    using iterator = rows_view::const_iterator;\n\n    rows_view::const_iterator begin() const noexcept { return r.begin(); }\n    rows_view::const_iterator end() const noexcept { return r.end(); }\n};\n\nstruct rows_wrapper\n{\n    rows r;\n\n    rows_wrapper() = default;\n\n    template <typename... Args>\n    rows_wrapper(std::size_t num_columns, Args&&... args)\n    {\n        auto fields = make_fv_arr(std::forward<Args>(args)...);\n        r = makerowsv(fields.data(), fields.size(), num_columns);\n    }\n\n    using iterator = rows::const_iterator;\n\n    rows::const_iterator begin() const noexcept { return r.begin(); }\n    rows::const_iterator end() const noexcept { return r.end(); }\n};\n\nusing rows_types = std::tuple<rows_view_wrapper, rows_wrapper>;\n\nBOOST_AUTO_TEST_SUITE(range_iteration)\nBOOST_AUTO_TEST_CASE_TEMPLATE(empty, RowType, rows_types)\n{\n    RowType r;\n    std::vector<row_view> fv(r.begin(), r.end());\n    BOOST_TEST(fv.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(one_row_one_column, RowType, rows_types)\n{\n    RowType r(1, 42);\n    std::vector<row_view> fv(r.begin(), r.end());\n    BOOST_TEST(fv.size() == 1u);\n    BOOST_TEST(fv[0] == makerow(42));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(one_row_several_columns, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\");\n    std::vector<row_view> fv(r.begin(), r.end());\n    BOOST_TEST(fv.size() == 1u);\n    BOOST_TEST(fv[0] == makerow(80u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(one_column_several_rows, RowType, rows_types)\n{\n    RowType r(1, 42, \"abc\");\n    std::vector<row_view> fv(r.begin(), r.end());\n    BOOST_TEST(fv.size() == 2u);\n    BOOST_TEST(fv[0] == makerow(42));\n    BOOST_TEST(fv[1] == makerow(\"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(several_rows_several_columns, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 0u, nullptr);\n    std::vector<row_view> fv(r.begin(), r.end());\n    BOOST_TEST(fv.size() == 3u);\n    BOOST_TEST(fv[0] == makerow(80u, \"abc\"));\n    BOOST_TEST(fv[1] == makerow(72u, \"cde\"));\n    BOOST_TEST(fv[2] == makerow(0u, nullptr));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(prefix_increment, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\");\n    auto it = r.begin();\n    BOOST_TEST(*it == makerow(80u, \"abc\"));\n\n    // Increment to a dereferenceable state\n    BOOST_TEST(&++it == &it);\n    BOOST_TEST(*it == makerow(72u, \"cde\"));\n\n    // Increment to one-past-the-end\n    BOOST_TEST(&++it == &it);\n    BOOST_TEST(it == r.end());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(postfix_increment, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\");\n    auto it = r.begin();\n    BOOST_TEST(*it == makerow(80u, \"abc\"));\n\n    // Increment to a dereferenceable state\n    auto itcopy = it++;\n    BOOST_TEST(*itcopy == makerow(80u, \"abc\"));\n    BOOST_TEST(*it == makerow(72u, \"cde\"));\n\n    // Increment to one-past-the-end\n    itcopy = it++;\n    BOOST_TEST(*itcopy == makerow(72u, \"cde\"));\n    BOOST_TEST(it == r.end());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(prefix_decrement, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\");\n    auto it = r.end();\n\n    // Decrement to a dereferenceable state\n    BOOST_TEST(&--it == &it);\n    BOOST_TEST(*it == makerow(72u, \"cde\"));\n\n    // Decrement it again\n    BOOST_TEST(&--it == &it);\n    BOOST_TEST(*it == makerow(80u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(postfix_decrement, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\");\n    auto it = r.end();\n\n    // Decrement to a dereferenceable state\n    auto itcopy = it--;\n    BOOST_TEST(itcopy == r.end());\n    BOOST_TEST(*it == makerow(72u, \"cde\"));\n\n    // Decrement it again\n    itcopy = it--;\n    BOOST_TEST(*itcopy == makerow(72u, \"cde\"));\n    BOOST_TEST(*it == makerow(80u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(plus_equals, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it = r.begin();\n\n    // Increment to a dereferenceable state\n    it += 3;\n    BOOST_TEST(*it == makerow(0u, nullptr));\n\n    // Increment to one-past-the-end\n    it += 1;\n    BOOST_TEST(it == r.end());\n\n    // Increment by a negative number\n    it += (-2);\n    BOOST_TEST(*it == makerow(90u, \"fff\"));\n\n    // Increment by zero (noop)\n    it += 0;\n    BOOST_TEST(*it == makerow(90u, \"fff\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(plus_equals_empty, RowType, rows_types)\n{\n    RowType r;\n    auto it = r.begin();\n    it += 0;\n    BOOST_TEST(it == r.begin());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(minus_equals, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it = r.end();\n\n    // Decrement to a dereferenceable state\n    it -= 2;\n    BOOST_TEST(*it == makerow(90u, \"fff\"));\n\n    // Decrement to begin\n    it -= 2;\n    BOOST_TEST(*it == makerow(80u, \"abc\"));\n\n    // Decrement by a negative number\n    it -= (-1);\n    BOOST_TEST(*it == makerow(72u, \"cde\"));\n\n    // Decrement by zero (noop)\n    it -= 0;\n    BOOST_TEST(*it == makerow(72u, \"cde\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(minus_equals_empty, RowType, rows_types)\n{\n    RowType r;\n    auto it = r.begin();\n    it -= 0;\n    BOOST_TEST(it == r.begin());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(iterator_plus_ptrdiff, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it1 = r.begin();\n\n    // Increment to a dereferenceable state\n    auto it2 = it1 + 3;\n    BOOST_TEST(*it1 == makerow(80u, \"abc\"));\n    BOOST_TEST(*it2 == makerow(0u, nullptr));\n\n    // Increment to one-past-the-end\n    auto it3 = it2 + 1;\n    BOOST_TEST(*it2 == makerow(0u, nullptr));\n    BOOST_TEST(it3 == r.end());\n\n    // Increment by a negative number\n    auto it4 = it3 + (-2);\n    BOOST_TEST(it3 == r.end());\n    BOOST_TEST(*it4 == makerow(90u, \"fff\"));\n\n    // Increment by zero (noop)\n    auto it5 = it4 + 0;\n    BOOST_TEST(*it4 == makerow(90u, \"fff\"));\n    BOOST_TEST(*it5 == makerow(90u, \"fff\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(iterator_plus_ptrdiff_empty, RowType, rows_types)\n{\n    RowType r;\n    BOOST_TEST(r.begin() + 0 == r.begin());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(ptrdiff_plus_iterator, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it1 = r.begin();\n\n    // Increment to a dereferenceable state\n    auto it2 = 3 + it1;\n    BOOST_TEST(*it1 == makerow(80u, \"abc\"));\n    BOOST_TEST(*it2 == makerow(0u, nullptr));\n\n    // Increment to one-past-the-end\n    auto it3 = 1 + it2;\n    BOOST_TEST(*it2 == makerow(0u, nullptr));\n    BOOST_TEST(it3 == r.end());\n\n    // Increment by a negative number\n    auto it4 = (-2) + it3;\n    BOOST_TEST(it3 == r.end());\n    BOOST_TEST(*it4 == makerow(90u, \"fff\"));\n\n    // Increment by zero (noop)\n    auto it5 = 0 + it4;\n    BOOST_TEST(*it4 == makerow(90u, \"fff\"));\n    BOOST_TEST(*it5 == makerow(90u, \"fff\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(ptrdiff_plus_iterator_empty, RowType, rows_types)\n{\n    RowType r;\n    BOOST_TEST(0 + r.begin() == r.begin());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(iterator_minus_ptrdiff, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it1 = r.end();\n\n    // Decrement to a dereferenceable state\n    auto it2 = it1 - 3;\n    BOOST_TEST(it1 == r.end());\n    BOOST_TEST(*it2 == makerow(72u, \"cde\"));\n\n    // Decrement to begin\n    auto it3 = it2 - 1;\n    BOOST_TEST(*it2 == makerow(72u, \"cde\"));\n    BOOST_TEST(*it3 == makerow(80u, \"abc\"));\n\n    // Decrement by a negative number\n    auto it4 = it3 - (-2);\n    BOOST_TEST(*it3 == makerow(80u, \"abc\"));\n    BOOST_TEST(*it4 == makerow(90u, \"fff\"));\n\n    // Increment by zero (noop)\n    auto it5 = it4 - 0;\n    BOOST_TEST(*it4 == makerow(90u, \"fff\"));\n    BOOST_TEST(*it5 == makerow(90u, \"fff\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(iterator_minus_ptrdiff_empty, RowType, rows_types)\n{\n    RowType r;\n    BOOST_TEST(r.begin() - 0 == r.begin());\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(iterator_minus_iterator, RowType, rows_types)\n{\n    using It = typename RowType::iterator;\n\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it1 = r.begin();\n    auto it2 = r.begin() + 1;\n    auto it3 = r.begin() + 2;\n    auto it4 = r.begin() + 3;\n    auto itend = r.end();\n\n    // Positive\n    BOOST_TEST(it2 - it1 == 1);\n    BOOST_TEST(it3 - it2 == 1);\n    BOOST_TEST(it3 - it1 == 2);\n    BOOST_TEST(it4 - it2 == 2);\n    BOOST_TEST(itend - it4 == 1);\n    BOOST_TEST(itend - it1 == 4);\n\n    // Negative\n    BOOST_TEST(it1 - it2 == -1);\n    BOOST_TEST(it2 - it3 == -1);\n    BOOST_TEST(it1 - it3 == -2);\n    BOOST_TEST(it2 - it4 == -2);\n    BOOST_TEST(it4 - itend == -1);\n    BOOST_TEST(it1 - itend == -4);\n\n    // Zero\n    BOOST_TEST(It(it1) - It(it1) == 0);\n    BOOST_TEST(It(it2) - It(it2) == 0);\n    BOOST_TEST(It(itend) - It(itend) == 0);\n\n    // Self subtract\n    BOOST_TEST(it1 - it1 == 0);\n    BOOST_TEST(it2 - it2 == 0);\n    BOOST_TEST(itend - itend == 0);\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(iterator_minus_iterator_empty, RowType, rows_types)\n{\n    RowType r;\n    BOOST_TEST(r.begin() - r.begin() == 0);\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(square_brackets, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it = r.begin() + 1;\n\n    BOOST_TEST(it[-1] == makerow(80u, \"abc\"));\n    BOOST_TEST(it[0] == makerow(72u, \"cde\"));\n    BOOST_TEST(it[1] == makerow(90u, \"fff\"));\n    BOOST_TEST(it[2] == makerow(0u, nullptr));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(arrow, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it = r.begin() + 1;\n\n    BOOST_TEST(it->size() == 2u);\n    BOOST_TEST(it->front() == field_view(72u));\n    BOOST_TEST(it->back() == field_view(\"cde\"));\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(operator_equals, RowType, rows_types)\n{\n    using It = typename RowType::iterator;\n    RowType empty;\n    RowType nonempty(2, 80u, \"abc\", 72u, \"cde\");\n\n    struct\n    {\n        const char* name;\n        It it1;\n        It it2;\n        bool is_equal;\n    } test_cases[] = {\n        {\"value_initialized\",               It(),                 It(),                 true },\n        {\"empty_begin_empty_begin\",         empty.begin(),        empty.begin(),        true },\n        {\"empty_begin_empty_end\",           empty.begin(),        empty.end(),          true },\n        {\"empty_end_empty_end\",             empty.end(),          empty.end(),          true },\n        {\"nonempty_begin_nonempty_begin\",   nonempty.begin(),     nonempty.begin(),     true },\n        {\"nonempty_begin_nonempty_middle\",  nonempty.begin(),     nonempty.begin() + 1, false},\n        {\"nonempty_middle_nonempty_middle\", nonempty.begin() + 1, nonempty.begin() + 1, true },\n        {\"nonempty_begin_nonempty_end\",     nonempty.begin(),     nonempty.end(),       false},\n        {\"nonempty_end_nonempty_end\",       nonempty.end(),       nonempty.end(),       true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            if (tc.is_equal)\n            {\n                BOOST_TEST(tc.it1 == tc.it2);\n                BOOST_TEST(tc.it2 == tc.it1);\n                BOOST_TEST(!(tc.it1 != tc.it2));\n                BOOST_TEST(!(tc.it2 != tc.it1));\n            }\n            else\n            {\n                BOOST_TEST(!(tc.it1 == tc.it2));\n                BOOST_TEST(!(tc.it2 == tc.it1));\n                BOOST_TEST(tc.it1 != tc.it2);\n                BOOST_TEST(tc.it2 != tc.it1);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(operator_lt_lte_gt_gte, RowType, rows_types)\n{\n    RowType r(2, 80u, \"abc\", 72u, \"cde\", 90u, \"fff\", 0u, nullptr);\n    auto it1 = r.begin();\n    auto it2 = r.begin() + 1;\n    auto it2copy = it2;\n    auto it3 = r.begin() + 2;\n    auto it4 = r.begin() + 3;\n    auto itend = r.end();\n    auto itendcopy = itend;\n\n    // it1-it2\n    BOOST_TEST(it1 < it2);\n    BOOST_TEST(it1 <= it2);\n    BOOST_TEST(!(it1 > it2));\n    BOOST_TEST(!(it1 >= it2));\n\n    // it2 with itself\n    BOOST_TEST(!(it2 < it2copy));\n    BOOST_TEST(it2 <= it2copy);\n    BOOST_TEST(!(it2 > it2copy));\n    BOOST_TEST(it2 >= it2copy);\n\n    // it3-it1\n    BOOST_TEST(!(it3 < it1));\n    BOOST_TEST(!(it3 <= it1));\n    BOOST_TEST(it3 > it1);\n    BOOST_TEST(it3 >= it1);\n\n    // it4-itend\n    BOOST_TEST(it4 < itend);\n    BOOST_TEST(it4 <= itend);\n    BOOST_TEST(!(it4 > itend));\n    BOOST_TEST(!(it4 >= itend));\n\n    // itend with itself\n    BOOST_TEST(!(itend < itendcopy));\n    BOOST_TEST(itend <= itendcopy);\n    BOOST_TEST(!(itend > itendcopy));\n    BOOST_TEST(itend >= itendcopy);\n}\n\nBOOST_AUTO_TEST_CASE_TEMPLATE(operator_lt_lte_gt_gte_empty, RowType, rows_types)\n{\n    RowType r;\n    auto it1 = r.begin();\n    auto it2 = r.end();\n\n    BOOST_TEST(!(it1 < it2));\n    BOOST_TEST(it1 <= it2);\n    BOOST_TEST(!(it1 > it2));\n    BOOST_TEST(it1 >= it2);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/socket_stream.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/socket_stream.hpp>\n\n#include <boost/asio/buffered_stream.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/ip/udp.hpp>\n#include <boost/asio/local/stream_protocol.hpp>\n#include <boost/asio/ssl/stream.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/asio/windows/stream_handle.hpp>\n\nusing namespace boost::mysql::detail;\nnamespace asio = boost::asio;\n\nnamespace {\n\nstruct stream_archetype\n{\n    using lowest_layer_type = asio::ip::tcp::socket;\n    lowest_layer_type& lowest_layer() noexcept\n    {\n        static asio::io_context ctx;\n        static lowest_layer_type res{ctx};\n        return res;\n    }\n};\n\nstruct stream_bad_type\n{\n    using lowest_layer_type = asio::ip::udp::socket;\n    lowest_layer_type& lowest_layer() noexcept\n    {\n        static asio::io_context ctx;\n        static lowest_layer_type res{ctx};\n        return res;\n    }\n};\n\n// The streams we regularly use are accepted\nstatic_assert(is_socket_stream<asio::ip::tcp::socket>::value, \"\");\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\nstatic_assert(is_socket_stream<asio::local::stream_protocol::socket>::value, \"\");\n#endif\nstatic_assert(is_socket_stream<asio::ssl::stream<asio::ip::tcp::socket>>::value, \"\");\n\n// Regular streams with more exotic arguments are also accepted\nstatic_assert(is_socket_stream<asio::ssl::stream<asio::ip::tcp::socket&>>::value, \"\");\nstatic_assert(\n    is_socket_stream<asio::ip::tcp::socket::rebind_executor<asio::io_context::executor_type>::other>::value,\n    \"\"\n);\n\n// Having several layers works\nstatic_assert(is_socket_stream<asio::buffered_stream<asio::ip::tcp::socket>>::value, \"\");\nstatic_assert(is_socket_stream<asio::ssl::stream<asio::buffered_stream<asio::ip::tcp::socket>>>::value, \"\");\n\n// A minimal archetype is accepted\nstatic_assert(is_socket_stream<stream_archetype>::value, \"\");\n\n// Bad lowest_layer_type\nstatic_assert(!is_socket_stream<stream_bad_type>::value, \"\");\n\n// Stream that is not a socket\n#ifdef BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE\nstatic_assert(!is_socket_stream<asio::windows::stream_handle>::value, \"\");\n#endif\n\n// No lowest_layer_type\nstatic_assert(!is_socket_stream<int>::value, \"\");\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/detail/typing/meta_check_context.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/typing/meta_check_context.hpp>\n#include <boost/mysql/detail/typing/pos_map.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_meta.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::mysql::detail::meta_check_context;\nusing boost::mysql::detail::name_table_t;\nusing boost::mysql::detail::pos_absent;\n\nBOOST_AUTO_TEST_SUITE(test_meta_check_context)\n\n// Get the error message from the context\nstd::string get_errors(const meta_check_context& ctx)\n{\n    diagnostics diag;\n    ctx.check_errors(diag);\n    return diag.client_message();\n}\n\nBOOST_AUTO_TEST_CASE(column_type_to_str_)\n{\n    struct\n    {\n        column_type type;\n        bool is_unsigned;\n        string_view expected;\n    } test_cases[] = {\n        {column_type::tinyint,         false, \"TINYINT\"              },\n        {column_type::tinyint,         true,  \"TINYINT UNSIGNED\"     },\n        {column_type::smallint,        false, \"SMALLINT\"             },\n        {column_type::smallint,        true,  \"SMALLINT UNSIGNED\"    },\n        {column_type::mediumint,       false, \"MEDIUMINT\"            },\n        {column_type::mediumint,       true,  \"MEDIUMINT UNSIGNED\"   },\n        {column_type::int_,            false, \"INT\"                  },\n        {column_type::int_,            true,  \"INT UNSIGNED\"         },\n        {column_type::bigint,          false, \"BIGINT\"               },\n        {column_type::bigint,          true,  \"BIGINT UNSIGNED\"      },\n        {column_type::year,            false, \"YEAR\"                 },\n        {column_type::year,            true,  \"YEAR\"                 },\n        {column_type::float_,          false, \"FLOAT\"                },\n        {column_type::float_,          true,  \"FLOAT\"                },\n        {column_type::double_,         false, \"DOUBLE\"               },\n        {column_type::double_,         true,  \"DOUBLE\"               },\n        {column_type::date,            false, \"DATE\"                 },\n        {column_type::datetime,        false, \"DATETIME\"             },\n        {column_type::timestamp,       false, \"TIMESTAMP\"            },\n        {column_type::time,            false, \"TIME\"                 },\n        {column_type::char_,           false, \"CHAR\"                 },\n        {column_type::varchar,         false, \"VARCHAR\"              },\n        {column_type::text,            false, \"TEXT\"                 },\n        {column_type::enum_,           false, \"ENUM\"                 },\n        {column_type::set,             false, \"SET\"                  },\n        {column_type::decimal,         false, \"DECIMAL\"              },\n        {column_type::json,            false, \"JSON\"                 },\n        {column_type::binary,          false, \"BINARY\"               },\n        {column_type::varbinary,       false, \"VARBINARY\"            },\n        {column_type::blob,            false, \"BLOB\"                 },\n        {column_type::geometry,        false, \"GEOMETRY\"             },\n        {static_cast<column_type>(76), true,  \"<unknown column type>\"}\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.expected)\n        {\n            auto meta = meta_builder().type(tc.type).unsigned_flag(tc.is_unsigned).build();\n            BOOST_TEST(detail::column_type_to_str(meta) == tc.expected);\n        }\n    }\n}\n\n// Common data\nconst metadata meta[] = {\n    meta_builder().type(column_type::bigint).build(),\n    meta_builder().type(column_type::bit).build(),\n    meta_builder().type(column_type::varchar).build(),\n    meta_builder().type(column_type::blob).build(),\n};\nconst string_view names[] = {\"f1\", \"f2\", \"f3\"};\n\nBOOST_AUTO_TEST_CASE(accessors_fields_present)\n{\n    const std::size_t pos_map[] = {2, 0, 1};\n    meta_check_context ctx(pos_map, names, meta);\n\n    // Field 0\n    BOOST_TEST(ctx.current_meta().type() == column_type::varchar);\n    BOOST_TEST(!ctx.is_current_field_absent());\n    ctx.advance();\n\n    // Field 1\n    BOOST_TEST(ctx.current_meta().type() == column_type::bigint);\n    BOOST_TEST(!ctx.is_current_field_absent());\n    ctx.advance();\n\n    // Field 2\n    BOOST_TEST(ctx.current_meta().type() == column_type::bit);\n    BOOST_TEST(!ctx.is_current_field_absent());\n}\n\nBOOST_AUTO_TEST_CASE(accessors_some_fields_absent)\n{\n    const std::size_t pos_map[] = {1, pos_absent, 0};\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n\n    // Field 0\n    BOOST_TEST(ctx.current_meta().type() == column_type::bit);\n    BOOST_TEST(!ctx.is_current_field_absent());\n    ctx.advance();\n\n    // Field 1\n    BOOST_TEST(ctx.is_current_field_absent());\n    ctx.advance();\n\n    // Field 2\n    BOOST_TEST(ctx.current_meta().type() == column_type::bigint);\n    BOOST_TEST(!ctx.is_current_field_absent());\n}\n\nBOOST_AUTO_TEST_CASE(accessors_all_fields_absent)\n{\n    const std::size_t pos_map[] = {pos_absent, pos_absent, pos_absent};\n    meta_check_context ctx(pos_map, name_table_t(), metadata_collection_view());\n\n    // Field 0\n    BOOST_TEST(ctx.is_current_field_absent());\n    ctx.advance();\n\n    // Field 1\n    BOOST_TEST(ctx.is_current_field_absent());\n    ctx.advance();\n\n    // Field 2\n    BOOST_TEST(ctx.is_current_field_absent());\n}\n\nBOOST_AUTO_TEST_CASE(nullability)\n{\n    const std::size_t pos_map[] = {0, 1, 2};\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n\n    // Nullability not checked by default\n    BOOST_TEST(!ctx.nullability_checked());\n\n    // Explicitly setting it works\n    ctx.set_nullability_checked();\n    BOOST_TEST(ctx.nullability_checked());\n\n    // Advancing resets it\n    ctx.advance();\n    BOOST_TEST(!ctx.nullability_checked());\n\n    // Advancing again does nothing\n    ctx.advance();\n    BOOST_TEST(!ctx.nullability_checked());\n}\n\nBOOST_AUTO_TEST_CASE(add_field_absent_error_named)\n{\n    const std::size_t pos_map[] = {1, pos_absent, 0};\n    const char* expected = \"Field 'f2' is not present in the data returned by the server\";\n\n    meta_check_context ctx(pos_map, names, meta);\n    ctx.advance();\n    ctx.add_field_absent_error();\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(add_field_absent_error_unnamed)\n{\n    const std::size_t pos_map[] = {0, pos_absent};\n    const char* expected =\n        \"Field in position 1 can't be mapped: there are more fields in your C++ data type than in your query\";\n\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n    ctx.advance();\n    ctx.add_field_absent_error();\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(add_incompatible_types_error_named)\n{\n    const std::size_t pos_map[] = {1, 2, 0};\n    const char* expected =\n        \"Incompatible types for field 'f2': C++ type 'cpp_type' is not compatible with DB type 'VARCHAR'\";\n\n    meta_check_context ctx(pos_map, names, meta);\n    ctx.advance();\n    ctx.add_type_mismatch_error(\"cpp_type\");\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(add_incompatible_types_error_unnamed)\n{\n    const std::size_t pos_map[] = {0, 1, 2};\n    const char* expected =\n        \"Incompatible types for field in position 1: C++ type 'other_type' is not compatible with DB type \"\n        \"'BIT'\";\n\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n    ctx.advance();\n    ctx.add_type_mismatch_error(\"other_type\");\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(add_nullability_error_named)\n{\n    const std::size_t pos_map[] = {1, 2, 0};\n    const char* expected =\n        \"NULL checks failed for field 'f1': the database type may be NULL, but the C++ type cannot. \"\n        \"Use std::optional<T> or boost::optional<T>\";\n\n    meta_check_context ctx(pos_map, names, meta);\n    ctx.add_nullability_error();\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(add_nullability_error_unnamed)\n{\n    const std::size_t pos_map[] = {0, 1, 2};\n    const char* expected =\n        \"NULL checks failed for field in position 0: the database type may be NULL, but the C++ type \"\n        \"cannot. Use std::optional<T> or boost::optional<T>\";\n\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n    ctx.add_nullability_error();\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(several_errors)\n{\n    const std::size_t pos_map[] = {3, pos_absent, 0};\n    // clang-format off\n    const char* expected = \n        \"NULL checks failed for field 'f1': the database type may be NULL, but the C++ type cannot. Use std::optional<T> or boost::optional<T>\\n\"\n        \"Field 'f2' is not present in the data returned by the server\\n\"\n        \"Incompatible types for field 'f3': C++ type 'cpp_type' is not compatible with DB type 'BIGINT'\\n\"\n        \"NULL checks failed for field 'f3': the database type may be NULL, but the C++ type cannot. Use std::optional<T> or boost::optional<T>\";\n    // clang-format on\n\n    meta_check_context ctx(pos_map, names, meta);\n    ctx.add_nullability_error();\n    ctx.advance();\n    ctx.add_field_absent_error();\n    ctx.advance();\n    ctx.add_type_mismatch_error(\"cpp_type\");\n    ctx.add_nullability_error();\n    BOOST_TEST(get_errors(ctx) == expected);\n}\n\nBOOST_AUTO_TEST_CASE(check_errors_no_error)\n{\n    const std::size_t pos_map[] = {0, 1};\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n    diagnostics diag;\n    error_code err = ctx.check_errors(diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n    BOOST_TEST(diag.server_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(check_errors_with_error)\n{\n    const std::size_t pos_map[] = {0, 1};\n    const char* expected_msg =\n        \"Incompatible types for field in position 0: C++ type 'cpp_type' is not compatible with DB type \"\n        \"'BIGINT'\";\n\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n    ctx.add_type_mismatch_error(\"cpp_type\");\n    diagnostics diag;\n    error_code err = ctx.check_errors(diag);\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n    BOOST_TEST(diag.server_message() == \"\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/typing/pos_map.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/metadata.hpp>\n\n#include <boost/mysql/detail/typing/pos_map.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/create_meta.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::mysql::detail::map_field_view;\nusing boost::mysql::detail::map_metadata;\nusing boost::mysql::detail::name_table_t;\nusing boost::mysql::detail::pos_absent;\nusing boost::mysql::detail::pos_map_add_field;\nusing boost::mysql::detail::pos_map_reset;\n\nBOOST_AUTO_TEST_SUITE(test_pos_map)\n\nBOOST_AUTO_TEST_CASE(reset_empty)\n{\n    span<std::size_t> map{};\n    BOOST_CHECK_NO_THROW(pos_map_reset(map));\n}\n\nBOOST_AUTO_TEST_CASE(reset_nonempty)\n{\n    std::array<std::size_t, 4> storage{\n        {42, 43, 44, 45}\n    };\n    span<std::size_t> map(storage.data(), 3);\n\n    pos_map_reset(map);\n    BOOST_TEST(map[0] == pos_absent);\n    BOOST_TEST(map[1] == pos_absent);\n    BOOST_TEST(map[2] == pos_absent);\n    BOOST_TEST(storage[3] == 45u);  // didn't modify any extra storage\n}\n\nBOOST_AUTO_TEST_CASE(add_field_empty)\n{\n    span<std::size_t> map{};\n    name_table_t name_table{};\n    BOOST_CHECK_NO_THROW(pos_map_add_field(map, name_table, 0, \"f1\"));\n}\n\nBOOST_AUTO_TEST_CASE(add_field_unnamed)\n{\n    // Setup\n    std::array<std::size_t, 4> map{\n        {42, 43, 44}\n    };\n    name_table_t name_table{};\n    pos_map_reset(map);\n\n    // Add first field\n    pos_map_add_field(map, name_table, 0, \"f1\");\n    BOOST_TEST(map[0] == 0u);\n    BOOST_TEST(map[1] == pos_absent);\n    BOOST_TEST(map[2] == pos_absent);\n\n    // Add second field\n    pos_map_add_field(map, name_table, 1, \"f2\");\n    BOOST_TEST(map[0] == 0u);\n    BOOST_TEST(map[1] == 1u);\n    BOOST_TEST(map[2] == pos_absent);\n\n    // Add third field\n    pos_map_add_field(map, name_table, 2, \"f3\");\n    BOOST_TEST(map[0] == 0u);\n    BOOST_TEST(map[1] == 1u);\n    BOOST_TEST(map[2] == 2u);\n\n    // Any further trailing fields are discarded\n    BOOST_CHECK_NO_THROW(pos_map_add_field(map, name_table, 3, \"f3\"));\n    BOOST_CHECK_NO_THROW(pos_map_add_field(map, name_table, 4, \"f4\"));\n    BOOST_TEST(map[0] == 0u);\n    BOOST_TEST(map[1] == 1u);\n    BOOST_TEST(map[2] == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(add_field_named)\n{\n    // Setup\n    const string_view name_table[] = {\"f1\", \"f2\", \"f3\", \"f4\"};\n    std::array<std::size_t, 4> map{{}};\n    pos_map_reset(map);\n\n    // Add first field\n    pos_map_add_field(map, name_table, 0, \"f2\");\n    BOOST_TEST(map[0] == pos_absent);\n    BOOST_TEST(map[1] == 0u);\n    BOOST_TEST(map[2] == pos_absent);\n    BOOST_TEST(map[3] == pos_absent);\n\n    // Add second field\n    pos_map_add_field(map, name_table, 1, \"f4\");\n    BOOST_TEST(map[0] == pos_absent);\n    BOOST_TEST(map[1] == 0u);\n    BOOST_TEST(map[2] == pos_absent);\n    BOOST_TEST(map[3] == 1u);\n\n    // Add a non-existing field\n    pos_map_add_field(map, name_table, 2, \"fnonexistent\");\n    BOOST_TEST(map[0] == pos_absent);\n    BOOST_TEST(map[1] == 0u);\n    BOOST_TEST(map[2] == pos_absent);\n    BOOST_TEST(map[3] == 1u);\n\n    // Add third field\n    pos_map_add_field(map, name_table, 3, \"f1\");\n    BOOST_TEST(map[0] == 3u);\n    BOOST_TEST(map[1] == 0u);\n    BOOST_TEST(map[2] == pos_absent);\n    BOOST_TEST(map[3] == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(map_metadata_)\n{\n    const std::array<std::size_t, 3> map{\n        {1, 0, 2}\n    };\n    const metadata meta[] = {\n        meta_builder().type(column_type::bigint).build(),\n        meta_builder().type(column_type::char_).build(),\n        meta_builder().type(column_type::blob).build(),\n    };\n\n    BOOST_TEST(map_metadata(map, 0, meta).type() == column_type::char_);\n    BOOST_TEST(map_metadata(map, 1, meta).type() == column_type::bigint);\n    BOOST_TEST(map_metadata(map, 2, meta).type() == column_type::blob);\n}\n\nBOOST_AUTO_TEST_CASE(map_field_view_)\n{\n    const std::array<std::size_t, 3> map{\n        {1, 0, 2}\n    };\n    const auto fv = make_fv_arr(10, \"abc\", nullptr);\n\n    BOOST_TEST(map_field_view(map, 0, fv) == field_view(\"abc\"));\n    BOOST_TEST(map_field_view(map, 1, fv) == field_view(10));\n    BOOST_TEST(map_field_view(map, 2, fv) == field_view());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/typing/readable_field_traits.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/mysql/detail/typing/meta_check_context.hpp>\n#include <boost/mysql/detail/typing/pos_map.hpp>\n#include <boost/mysql/detail/typing/readable_field_traits.hpp>\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/optional/optional_io.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <limits>\n#include <string>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/custom_allocator.hpp\"\n\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::mysql::detail::is_readable_field;\nusing boost::mysql::detail::meta_check_context;\nusing boost::mysql::detail::name_table_t;\nusing boost::mysql::detail::pos_absent;\nusing boost::mysql::detail::readable_field_traits;\n\n// Don't attempt to print std::chrono values\nBOOST_TEST_DONT_PRINT_LOG_VALUE(boost::mysql::time)\n\nBOOST_AUTO_TEST_SUITE(test_readable_field_traits)\n\n//\n// readable_field\n//\n\nstruct other_traits : std::char_traits<char>\n{\n};\nusing string_with_alloc = std::basic_string<char, std::char_traits<char>, custom_allocator<char>>;\nusing string_with_traits = std::basic_string<char, other_traits>;\nusing blob_with_alloc = std::vector<unsigned char, custom_allocator<unsigned char>>;\nusing detail::meta_check_field;\n\nstruct unrelated\n{\n};\n\nstatic_assert(is_readable_field<unsigned char>::value, \"\");\nstatic_assert(is_readable_field<signed char>::value, \"\");\nstatic_assert(is_readable_field<char>::value, \"\");\nstatic_assert(is_readable_field<short>::value, \"\");\nstatic_assert(is_readable_field<unsigned short>::value, \"\");\nstatic_assert(is_readable_field<int>::value, \"\");\nstatic_assert(is_readable_field<unsigned int>::value, \"\");\nstatic_assert(is_readable_field<long>::value, \"\");\nstatic_assert(is_readable_field<unsigned long>::value, \"\");\nstatic_assert(is_readable_field<long long>::value, \"\");\nstatic_assert(is_readable_field<unsigned long long>::value, \"\");\nstatic_assert(is_readable_field<std::int8_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint8_t>::value, \"\");\nstatic_assert(is_readable_field<std::int16_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint16_t>::value, \"\");\nstatic_assert(is_readable_field<std::int32_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint32_t>::value, \"\");\nstatic_assert(is_readable_field<std::int64_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint64_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_least8_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_least8_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_least16_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_least16_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_least32_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_least32_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_least64_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_least64_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_fast8_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_fast8_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_fast16_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_fast16_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_fast32_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_fast32_t>::value, \"\");\nstatic_assert(is_readable_field<std::int_fast64_t>::value, \"\");\nstatic_assert(is_readable_field<std::uint_fast64_t>::value, \"\");\nstatic_assert(is_readable_field<float>::value, \"\");\nstatic_assert(is_readable_field<double>::value, \"\");\nstatic_assert(is_readable_field<boost::mysql::date>::value, \"\");\nstatic_assert(is_readable_field<boost::mysql::datetime>::value, \"\");\nstatic_assert(is_readable_field<boost::mysql::time>::value, \"\");\nstatic_assert(is_readable_field<bool>::value, \"\");\n\n// string types\nstatic_assert(is_readable_field<std::string>::value, \"\");\nstatic_assert(is_readable_field<string_with_alloc>::value, \"\");\nstatic_assert(!is_readable_field<string_with_traits>::value, \"\");\nstatic_assert(!is_readable_field<std::wstring>::value, \"\");\nstatic_assert(!is_readable_field<string_view>::value, \"\");\n\n// blob types\nstatic_assert(is_readable_field<blob>::value, \"\");\nstatic_assert(is_readable_field<blob_with_alloc>::value, \"\");\nstatic_assert(!is_readable_field<blob_view>::value, \"\");\n\n// references not accepted\nstatic_assert(!is_readable_field<int&>::value, \"\");\nstatic_assert(!is_readable_field<const int&>::value, \"\");\nstatic_assert(!is_readable_field<int&&>::value, \"\");\nstatic_assert(!is_readable_field<const int&>::value, \"\");\nstatic_assert(!is_readable_field<std::string&>::value, \"\");\n\n// optionals\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nstatic_assert(is_readable_field<std::optional<int>>::value, \"\");\nstatic_assert(is_readable_field<std::optional<std::string>>::value, \"\");\n#endif\nstatic_assert(is_readable_field<boost::optional<blob>>::value, \"\");\nstatic_assert(is_readable_field<boost::optional<datetime>>::value, \"\");\nstatic_assert(!is_readable_field<boost::optional<void*>>::value, \"\");\nstatic_assert(!is_readable_field<boost::optional<unrelated>>::value, \"\");\n\n// other types not accepted\nstatic_assert(!is_readable_field<std::nullptr_t>::value, \"\");\nstatic_assert(!is_readable_field<field_view>::value, \"\");\nstatic_assert(!is_readable_field<field>::value, \"\");\nstatic_assert(!is_readable_field<const char*>::value, \"\");\nstatic_assert(!is_readable_field<void*>::value, \"\");\nstatic_assert(!is_readable_field<unrelated>::value, \"\");\nstatic_assert(!is_readable_field<const field_view*>::value, \"\");\n\n// const-qualified objects are not accepted\nstatic_assert(!is_readable_field<const int>::value, \"\");\nstatic_assert(!is_readable_field<const std::string>::value, \"\");\nstatic_assert(!is_readable_field<boost::optional<const int>>::value, \"\");\n\nBOOST_AUTO_TEST_SUITE(meta_check_field_)\n\nusing single_field_check_fn = void (*)(meta_check_context&);\n\nconstexpr struct cpp_type_descriptor\n{\n    const char* name;\n    single_field_check_fn check_fn;\n} cpp_type_descriptors[] = {\n    {\"int8_t\",   &meta_check_field<std::int8_t>       },\n    {\"uint8_t\",  &meta_check_field<std::uint8_t>      },\n    {\"int16_t\",  &meta_check_field<std::int16_t>      },\n    {\"uint16_t\", &meta_check_field<std::uint16_t>     },\n    {\"int32_t\",  &meta_check_field<std::int32_t>      },\n    {\"uint32_t\", &meta_check_field<std::uint32_t>     },\n    {\"int64_t\",  &meta_check_field<std::int64_t>      },\n    {\"uint64_t\", &meta_check_field<std::uint64_t>     },\n    {\"bool\",     &meta_check_field<bool>              },\n    {\"float\",    &meta_check_field<float>             },\n    {\"double\",   &meta_check_field<double>            },\n    {\"date\",     &meta_check_field<date>              },\n    {\"datetime\", &meta_check_field<datetime>          },\n    {\"time\",     &meta_check_field<boost::mysql::time>},\n    {\"string\",   &meta_check_field<std::string>       },\n    {\"blob\",     &meta_check_field<blob>              },\n};\nconstexpr auto cpp_type_descriptors_size = sizeof(cpp_type_descriptors) / sizeof(cpp_type_descriptor);\n\nconstexpr struct db_type_descriptor\n{\n    const char* name;\n    const char* pretty_name;\n    column_type type;\n    bool is_unsigned;\n} db_type_descriptors[] = {\n    {\"TINYINT\",               \"tinyint\",    column_type::tinyint,   false},\n    {\"TINYINT UNSIGNED\",      \"tinyintu\",   column_type::tinyint,   true },\n    {\"SMALLINT\",              \"smallint\",   column_type::smallint,  false},\n    {\"SMALLINT UNSIGNED\",     \"smallintu\",  column_type::smallint,  true },\n    {\"MEDIUMINT\",             \"mediumint\",  column_type::mediumint, false},\n    {\"MEDIUMINT UNSIGNED\",    \"mediumintu\", column_type::mediumint, true },\n    {\"INT\",                   \"int\",        column_type::int_,      false},\n    {\"INT UNSIGNED\",          \"intu\",       column_type::int_,      true },\n    {\"BIGINT\",                \"bigint\",     column_type::bigint,    false},\n    {\"BIGINT UNSIGNED\",       \"bigintu\",    column_type::bigint,    true },\n    {\"YEAR\",                  \"year\",       column_type::year,      true },\n    {\"BIT\",                   \"bit\",        column_type::bit,       true },\n    {\"FLOAT\",                 \"float\",      column_type::float_,    false},\n    {\"DOUBLE\",                \"double\",     column_type::double_,   false},\n    {\"DATE\",                  \"date\",       column_type::date,      false},\n    {\"DATETIME\",              \"datetime\",   column_type::datetime,  false},\n    {\"TIMESTAMP\",             \"timestamp\",  column_type::timestamp, false},\n    {\"TIME\",                  \"time\",       column_type::time,      false},\n    {\"CHAR\",                  \"char\",       column_type::char_,     false},\n    {\"VARCHAR\",               \"varchar\",    column_type::varchar,   false},\n    {\"TEXT\",                  \"text\",       column_type::text,      false},\n    {\"ENUM\",                  \"enum\",       column_type::enum_,     false},\n    {\"SET\",                   \"set\",        column_type::set,       false},\n    {\"JSON\",                  \"json\",       column_type::json,      false},\n    {\"DECIMAL\",               \"decimal\",    column_type::decimal,   false},\n    {\"BINARY\",                \"binary\",     column_type::binary,    false},\n    {\"VARBINARY\",             \"varbinary\",  column_type::varbinary, false},\n    {\"BLOB\",                  \"blob\",       column_type::blob,      false},\n    {\"GEOMETRY\",              \"geometry\",   column_type::geometry,  false},\n    {\"<unknown column type>\", \"unknown\",    column_type::unknown,   false},\n};\nconstexpr auto db_type_descriptors_size = sizeof(db_type_descriptors) / sizeof(db_type_descriptor);\n\nstruct compat_matrix_row\n{\n    std::array<bool, cpp_type_descriptors_size> compat;\n};\n\n// Looks like clang-format crashes when it sees this\n// clang-format off\nconstexpr std::array<compat_matrix_row, db_type_descriptors_size> compat_matrix{{\n    {{{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0}}},  // TINYINT\n    {{{0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // TINYINT UNSIGNED\n    {{{0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}},  // SMALLINT\n    {{{0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // SMALLINT UNSIGNED\n    {{{0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}},  // MEDIUMINT\n    {{{0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // MEDIUMINT UNSIGNED\n    {{{0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}},  // INT\n    {{{0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // INT UNSIGNED\n    {{{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}},  // BIGINT\n    {{{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // BIGINT UNSIGNED\n    {{{0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // YEAR\n    {{{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}}},  // BIT\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0}}},  // FLOAT\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}},  // DOUBLE\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}},  // DATE\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}}},  // DATETIME\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}}},  // TIMESTAMP\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}}},  // TIME\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // CHAR\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // VARCHAR\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // TEXT\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // ENUM\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // SET\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // JSON\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}}},  // DECIMAL\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}},  // BINARY\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}},  // VARBINARY\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}},  // BLOB\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}},  // GEOMETRY\n    {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}},  // UNKNOWN\n}};\n// clang-format on\n\nBOOST_AUTO_TEST_CASE(basic_types_compatible)\n{\n    for (std::size_t i = 0; i < db_type_descriptors_size; ++i)\n    {\n        const auto& row = compat_matrix.at(i);\n        for (std::size_t j = 0; j < cpp_type_descriptors_size; ++j)\n        {\n            if (!row.compat.at(j))\n                continue;\n            auto db_desc = db_type_descriptors[i];\n            auto cpp_desc = cpp_type_descriptors[j];\n            BOOST_TEST_CONTEXT(db_desc.pretty_name << \"_\" << cpp_desc.name)\n            {\n                const std::size_t pos_map[] = {0};\n                const metadata meta[] = {\n                    meta_builder()\n                        .type(db_desc.type)\n                        .unsigned_flag(db_desc.is_unsigned)\n                        .nullable(false)\n                        .build(),\n                };\n                meta_check_context ctx(pos_map, name_table_t(), meta);\n\n                cpp_desc.check_fn(ctx);\n                diagnostics diag;\n                auto err = ctx.check_errors(diag);\n                BOOST_TEST(err == error_code());\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(basic_types_incompatible)\n{\n    for (std::size_t i = 0; i < db_type_descriptors_size; ++i)\n    {\n        const auto& row = compat_matrix.at(i);\n        for (std::size_t j = 0; j < cpp_type_descriptors_size; ++j)\n        {\n            if (row.compat.at(j))\n                continue;\n            auto db_desc = db_type_descriptors[i];\n            auto cpp_desc = cpp_type_descriptors[j];\n\n            BOOST_TEST_CONTEXT(db_desc.pretty_name << \"_\" << cpp_desc.name)\n            {\n                const std::size_t pos_map[] = {0};\n                const metadata meta[] = {\n                    meta_builder()\n                        .type(db_desc.type)\n                        .unsigned_flag(db_desc.is_unsigned)\n                        .nullable(false)\n                        .build(),\n                };\n                meta_check_context ctx(pos_map, name_table_t(), meta);\n\n                cpp_desc.check_fn(ctx);\n                diagnostics diag;\n                auto err = ctx.check_errors(diag);\n\n                BOOST_TEST(err == client_errc::metadata_check_failed);\n                std::string msg = \"Incompatible types for field in position 0: C++ type '\" +\n                                  std::string(cpp_desc.name) + \"' is not compatible with DB type '\" +\n                                  std::string(db_desc.name) + \"'\";\n                BOOST_TEST(diag.client_message() == msg);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(nullable_error)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::float_).unsigned_flag(false).nullable(true).build(),\n    };\n    const std::size_t pos_map[] = {0};\n    meta_check_context ctx(pos_map, name_table_t(), meta);\n\n    meta_check_field<double>(ctx);\n    diagnostics diag;\n    auto err = ctx.check_errors(diag);\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(\n        diag.client_message() ==\n        \"NULL checks failed for field in position 0: the database type may be NULL, but the C++ type cannot. \"\n        \"Use std::optional<T> or boost::optional<T>\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(optionals)\n{\n    struct\n    {\n        const char* name;\n        single_field_check_fn check_fn;\n        bool nullable;\n    } test_cases[] = {\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n        {\"std_optional_not_nullable\",   &meta_check_field<std::optional<double>>,   false},\n        {\"std_optional_nullable\",       &meta_check_field<std::optional<double>>,   true },\n#endif\n        {\"boost_optional_not_nullable\", &meta_check_field<boost::optional<double>>, false},\n        {\"boost_optional_nullable\",     &meta_check_field<boost::optional<double>>, true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            const std::size_t pos_map[] = {0};\n            const metadata meta[] = {\n                meta_builder().type(column_type::float_).unsigned_flag(false).nullable(tc.nullable).build(),\n            };\n            meta_check_context ctx(pos_map, name_table_t(), meta);\n\n            tc.check_fn(ctx);\n            diagnostics diag;\n            auto err = ctx.check_errors(diag);\n            BOOST_TEST(err == error_code());\n        }\n    }\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(parse_)\n\ntemplate <class T>\nstruct parse_and_check\n{\n    T expected;\n\n    parse_and_check(T expected) : expected(std::move(expected)) {}\n\n    void operator()(field_view from) const\n    {\n        T actual{};\n        auto err = readable_field_traits<T>::parse(from, actual);\n        BOOST_TEST(err == error_code());\n        BOOST_TEST(actual == expected);\n    }\n};\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    struct\n    {\n        const char* name;\n        field_view from;\n        std::function<void(field_view)> fn;\n    } test_cases[] = {\n        {\"int8_signed_regular\", field_view(42), parse_and_check<std::int8_t>(42)},\n        {\"int8_signed_min\", field_view(-0x80), parse_and_check<std::int8_t>(-0x80)},\n        {\"int8_signed_max\", field_view(0x7f), parse_and_check<std::int8_t>(0x7f)},\n        {\"int8_unsigned_regular\", field_view(42u), parse_and_check<std::int8_t>(42u)},\n        {\"int8_unsigned_max\", field_view(0x7fu), parse_and_check<std::int8_t>(0x7fu)},\n\n        {\"uint8_regular\", field_view(42u), parse_and_check<std::uint8_t>(42u)},\n        {\"uint8_min\", field_view(0u), parse_and_check<std::uint8_t>(0u)},\n        {\"uint8_max\", field_view(0xffu), parse_and_check<std::uint8_t>(0xffu)},\n\n        {\"int16_signed_regular\", field_view(42), parse_and_check<std::int16_t>(42)},\n        {\"int16_signed_min\", field_view(-0x8000), parse_and_check<std::int16_t>(-0x8000)},\n        {\"int16_signed_max\", field_view(0x7f00), parse_and_check<std::int16_t>(0x7f00)},\n        {\"int16_unsigned_regular\", field_view(42u), parse_and_check<std::int16_t>(42u)},\n        {\"int16_unsigned_max\", field_view(0x7f00u), parse_and_check<std::int16_t>(0x7f00u)},\n\n        {\"uint16_regular\", field_view(42u), parse_and_check<std::uint16_t>(42u)},\n        {\"uint16_min\", field_view(0u), parse_and_check<std::uint16_t>(0u)},\n        {\"uint16_max\", field_view(0xffffu), parse_and_check<std::uint16_t>(0xffffu)},\n\n        {\"int32_signed_regular\", field_view(42), parse_and_check<std::int32_t>(42)},\n        {\"int32_signed_min\", field_view(-0x80000000LL), parse_and_check<std::int32_t>(-0x80000000LL)},\n        {\"int32_signed_max\", field_view(0x7f000000), parse_and_check<std::int32_t>(0x7f000000)},\n        {\"int32_unsigned_regular\", field_view(42u), parse_and_check<std::int32_t>(42u)},\n        {\"int32_unsigned_max\", field_view(0x7f000000u), parse_and_check<std::int32_t>(0x7f000000u)},\n\n        {\"uint32_regular\", field_view(42u), parse_and_check<std::uint32_t>(42u)},\n        {\"uint32_min\", field_view(0u), parse_and_check<std::uint32_t>(0u)},\n        {\"uint32_max\", field_view(0xffffffffu), parse_and_check<std::uint32_t>(0xffffffffu)},\n\n        {\"int64_signed_regular\", field_view(42), parse_and_check<std::int64_t>(42)},\n        {\"int64_signed_min\",\n         field_view(-0x7fffffffffffffff - 1),\n         parse_and_check<std::int64_t>(-0x7fffffffffffffff - 1)},\n        {\"int64_signed_max\", field_view(0x7f00000000000000), parse_and_check<std::int64_t>(0x7f00000000000000)\n        },\n        {\"int64_unsigned_regular\", field_view(42u), parse_and_check<std::int64_t>(42u)},\n        {\"int64_unsigned_max\",\n         field_view(0x7f00000000000000u),\n         parse_and_check<std::int64_t>(0x7f00000000000000u)},\n\n        {\"uint64_regular\", field_view(42u), parse_and_check<std::uint64_t>(42u)},\n        {\"uint64_min\", field_view(0u), parse_and_check<std::uint64_t>(0u)},\n        {\"uint64_max\", field_view(0xffffffffffffffffu), parse_and_check<std::uint64_t>(0xffffffffffffffffu)},\n\n        {\"bool_zero\", field_view(0), parse_and_check<bool>(false)},\n        {\"bool_one\", field_view(1), parse_and_check<bool>(true)},\n        {\"bool_other\", field_view(2), parse_and_check<bool>(true)},\n\n        {\"float\", field_view(4.2f), parse_and_check<float>(4.2f)},\n\n        {\"double_float\", field_view(4.2f), parse_and_check<double>(4.2f)},\n        {\"double_double\", field_view(4.2), parse_and_check<double>(4.2)},\n\n        {\"date\", field_view(date(2020, 1, 2)), parse_and_check<date>(date(2020, 1, 2))},\n        {\"datetime\", field_view(datetime(2020, 1, 2)), parse_and_check<datetime>(datetime(2020, 1, 2))},\n        {\"time\", field_view(maket(10, 1, 1)), parse_and_check<boost::mysql::time>(maket(10, 1, 1))},\n        {\"string\", field_view(\"abc\"), parse_and_check<std::string>(\"abc\")},\n        {\"blob\", field_view(makebv(\"\\0\\1\")), parse_and_check<blob>({0, 1})},\n\n        {\"boost_optional_empty\",\n         field_view(),\n         parse_and_check<boost::optional<float>>(boost::optional<float>())},\n        {\"boost_optional_nonempty\",\n         field_view(4.2f),\n         parse_and_check<boost::optional<float>>(boost::optional<float>(4.2f))},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { tc.fn(tc.from); }\n    }\n}\n\n// std::optional, which doesn't implement equality or stream operators\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nBOOST_AUTO_TEST_CASE(std_optional_null)\n{\n    std::optional<int> actual = 42;\n    auto err = readable_field_traits<std::optional<int>>::parse(field_view(), actual);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(!actual.has_value());\n}\n\nBOOST_AUTO_TEST_CASE(std_optional_not_null)\n{\n    std::optional<int> actual;\n    auto err = readable_field_traits<std::optional<int>>::parse(field_view(42), actual);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST_REQUIRE(actual.has_value());\n    BOOST_TEST(actual.value() == 42);\n}\n#endif\n\ntemplate <class T>\nerror_code parse_and_discard(field_view f)\n{\n    T t;\n    return readable_field_traits<T>::parse(f, t);\n}\n\nBOOST_AUTO_TEST_CASE(errors)\n{\n    field_view i64_absmin((std::numeric_limits<std::int64_t>::min)());\n    field_view i64_absmax((std::numeric_limits<std::int64_t>::max)());\n    field_view ui64_absmax((std::numeric_limits<std::uint64_t>::max)());\n\n    struct\n    {\n        const char* name;\n        field_view from;\n        error_code (*parse_fn)(field_view);\n    } test_cases[] = {\n        {\"int8_null\",                       field_view(),                    parse_and_discard<std::int8_t>                 },\n        {\"int8_badtype\",                    field_view(4.2),                 parse_and_discard<std::int8_t>                 },\n        {\"int8_signed_ltmin\",               field_view(-0x81),               parse_and_discard<std::int8_t>                 },\n        {\"int8_signed_gtmax\",               field_view(0x80),                parse_and_discard<std::int8_t>                 },\n        {\"int8_signed_absmin\",              i64_absmin,                      parse_and_discard<std::int8_t>                 },\n        {\"int8_signed_absmax\",              i64_absmax,                      parse_and_discard<std::int8_t>                 },\n        {\"int8_unsigned_gtmax\",             field_view(0x80u),               parse_and_discard<std::int8_t>                 },\n        {\"int8_unsigned_absmax\",            ui64_absmax,                     parse_and_discard<std::int8_t>                 },\n\n        {\"uint8_null\",                      field_view(),                    parse_and_discard<std::uint8_t>                },\n        {\"uint8_badtype\",                   field_view(4.2),                 parse_and_discard<std::uint8_t>                },\n        {\"uint8_gtmax\",                     field_view(0x100u),              parse_and_discard<std::uint8_t>                },\n        {\"uint8_absmax\",                    ui64_absmax,                     parse_and_discard<std::uint8_t>                },\n\n        {\"int16_null\",                      field_view(),                    parse_and_discard<std::int16_t>                },\n        {\"int16_badtype\",                   field_view(4.2),                 parse_and_discard<std::int16_t>                },\n        {\"int16_signed_ltmin\",              field_view(-0x8001),             parse_and_discard<std::int16_t>                },\n        {\"int16_signed_gtmax\",              field_view(0x8000),              parse_and_discard<std::int16_t>                },\n        {\"int16_signed_absmin\",             i64_absmin,                      parse_and_discard<std::int16_t>                },\n        {\"int16_signed_absmax\",             i64_absmax,                      parse_and_discard<std::int16_t>                },\n        {\"int16_unsigned_gtmax\",            field_view(0x8000u),             parse_and_discard<std::int16_t>                },\n        {\"int16_unsigned_absmax\",           ui64_absmax,                     parse_and_discard<std::int16_t>                },\n\n        {\"uint16_null\",                     field_view(),                    parse_and_discard<std::uint16_t>               },\n        {\"uint16_badtype\",                  field_view(4.2),                 parse_and_discard<std::uint16_t>               },\n        {\"uint16_gtmax\",                    field_view(0x10000u),            parse_and_discard<std::uint16_t>               },\n        {\"uint16_absmax\",                   ui64_absmax,                     parse_and_discard<std::uint16_t>               },\n\n        {\"int32_null\",                      field_view(),                    parse_and_discard<std::int32_t>                },\n        {\"int32_badtype\",                   field_view(4.2),                 parse_and_discard<std::int32_t>                },\n        {\"int32_signed_ltmin\",              field_view(-0x80000001LL),       parse_and_discard<std::int32_t>                },\n        {\"int32_signed_gtmax\",              field_view(0x80000000L),         parse_and_discard<std::int32_t>                },\n        {\"int32_signed_absmin\",             i64_absmin,                      parse_and_discard<std::int32_t>                },\n        {\"int32_signed_absmax\",             i64_absmax,                      parse_and_discard<std::int32_t>                },\n        {\"int32_unsigned_gtmax\",            field_view(0x80000000uL),        parse_and_discard<std::int32_t>                },\n        {\"int32_unsigned_absmax\",           ui64_absmax,                     parse_and_discard<std::int32_t>                },\n\n        {\"uint32_null\",                     field_view(),                    parse_and_discard<std::uint32_t>               },\n        {\"uint32_badtype\",                  field_view(\"abc\"),               parse_and_discard<std::uint32_t>               },\n        {\"uint32_gtmax\",                    field_view(0x100000000u),        parse_and_discard<std::uint32_t>               },\n        {\"uint32_absmax\",                   ui64_absmax,                     parse_and_discard<std::uint32_t>               },\n\n        {\"int64_null\",                      field_view(),                    parse_and_discard<std::int64_t>                },\n        {\"int64_badtype\",                   field_view(4.1f),                parse_and_discard<std::int64_t>                },\n        {\"int64_unsigned_gtmax\",            field_view(0x8000000000000000u), parse_and_discard<std::int64_t>                },\n        {\"int64_unsigned_absmax\",           ui64_absmax,                     parse_and_discard<std::int64_t>                },\n\n        {\"uint64_null\",                     field_view(),                    parse_and_discard<std::uint64_t>               },\n        {\"uint64_badtype\",                  field_view(\"abc\"),               parse_and_discard<std::uint64_t>               },\n\n        {\"bool_null\",                       field_view(),                    parse_and_discard<bool>                        },\n        {\"bool_badtype\",                    field_view(\"abc\"),               parse_and_discard<bool>                        },\n\n        {\"float_null\",                      field_view(),                    parse_and_discard<float>                       },\n        {\"float_badtype\",                   field_view(42),                  parse_and_discard<float>                       },\n\n        {\"double_null\",                     field_view(),                    parse_and_discard<double>                      },\n        {\"double_badtype\",                  field_view(\"abc\"),               parse_and_discard<double>                      },\n\n        {\"date_null\",                       field_view(),                    parse_and_discard<date>                        },\n        {\"date_badtype\",                    field_view(1.1),                 parse_and_discard<date>                        },\n\n        {\"datetime_null\",                   field_view(),                    parse_and_discard<datetime>                    },\n        {\"datetime_badtype\",                field_view(\"abc\"),               parse_and_discard<datetime>                    },\n\n        {\"time_null\",                       field_view(),                    parse_and_discard<boost::mysql::time>          },\n        {\"time_badtype\",                    field_view(30),                  parse_and_discard<boost::mysql::time>          },\n\n        {\"string_null\",                     field_view(),                    parse_and_discard<std::string>                 },\n        {\"string_badtype\",                  field_view(makebv(\"abc\")),       parse_and_discard<std::string>                 },\n\n        {\"blob_null\",                       field_view(),                    parse_and_discard<blob>                        },\n        {\"blob_badtype\",                    field_view(\"abc\"),               parse_and_discard<blob>                        },\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n        {\"std_optional_underlying_error\",   field_view(\"a\"),                 parse_and_discard<std::optional<std::int8_t>>  },\n#endif\n        {\"boost_optional_underlying_error\", field_view(\"a\"),                 parse_and_discard<boost::optional<std::int8_t>>},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST(tc.parse_fn(tc.from) == client_errc::static_row_parsing_error);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/detail/typing/row_traits.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/typing/pos_map.hpp>\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/describe/class.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <tuple>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/row_identity.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing detail::get_row_name_table;\nusing detail::get_row_size;\nusing detail::get_type_index;\nusing detail::index_not_found;\nusing detail::is_static_row;\nusing detail::meta_check_impl;\nusing detail::name_table_t;\nusing detail::parse;\nusing detail::pos_absent;\n\n//\n// Some test rows, used for parse() tests.\n//\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nstruct test_row\n{\n    std::int32_t i{};\n    float f{};\n    double double_field{};\n};\n\nstruct test_empty_row\n{\n};\n\nstruct test_nonreadable_row\n{\n};\n\n}  // namespace test\n\nnamespace detail {\n\ntemplate <>\nclass row_traits<test_row, false>\n{\npublic:\n    using underlying_row_type = test_row;\n    using field_types = std::tuple<int, float, double>;\n    name_table_t name_table() const noexcept { return {}; }\n\n    template <class F>\n    static void for_each_member(underlying_row_type& to, F&& f)\n    {\n        f(to.i);\n        f(to.f);\n        f(to.double_field);\n    }\n};\n\ntemplate <>\nclass row_traits<test_empty_row, false>\n{\npublic:\n    using underlying_row_type = test_empty_row;\n    using field_types = std::tuple<>;\n    name_table_t name_table() const noexcept { return {}; }\n\n    template <class F>\n    static void for_each_member(underlying_row_type&, F&&)\n    {\n    }\n};\n\ntemplate <>\nclass row_traits<test_nonreadable_row, false>\n{\npublic:\n    using underlying_row_type = test_nonreadable_row;\n    using field_types = std::tuple<int, char*>;\n    name_table_t name_table() const noexcept { return {}; }\n\n    template <class F>\n    static void for_each_member(underlying_row_type&, F&&)\n    {\n    }\n};\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nBOOST_AUTO_TEST_SUITE(test_row_traits)\n\n// a struct without any relationship with this lib\nstruct unrelated\n{\n};\n\n// Helper for name tables - this forces printing them on error\nstatic void compare_name_tables(name_table_t lhs, name_table_t rhs)\n{\n    std::vector<string_view> lhsvec(lhs.begin(), lhs.end());\n    std::vector<string_view> rhsvec(rhs.begin(), rhs.end());\n    BOOST_TEST(lhsvec == rhsvec);\n}\n\n//\n// is_row_type concept: doesn't inspect individual fields\n//\nstatic_assert(is_static_row<test_row>, \"\");\nstatic_assert(is_static_row<test_empty_row>, \"\");\nstatic_assert(is_static_row<test_nonreadable_row>, \"\");\n\nstatic_assert(!is_static_row<unrelated>, \"\");\nstatic_assert(!is_static_row<int>, \"\");\nstatic_assert(!is_static_row<row>, \"\");\nstatic_assert(!is_static_row<test_row&>, \"\");\nstatic_assert(!is_static_row<const test_row&>, \"\");\nstatic_assert(!is_static_row<test_row&&>, \"\");\nstatic_assert(!is_static_row<const test_row&&>, \"\");\nstatic_assert(!is_static_row<test_row*>, \"\");\n\n//\n// get_row_size: counts the number of fields\n//\nstatic_assert(get_row_size<test_row>() == 3u, \"\");\nstatic_assert(get_row_size<test_empty_row>() == 0u, \"\");\n\n//\n// meta_check\n// We test meta_check via meta_check_impl because it allows us to inject name\n// tables and field types without specializing the traits class\n//\nBOOST_AUTO_TEST_SUITE(meta_check_)\n\nconst metadata meta[] = {\n    meta_builder().type(column_type::tinyint).unsigned_flag(false).nullable(false).build(),\n    meta_builder().type(column_type::varchar).nullable(false).build(),\n    meta_builder().type(column_type::float_).nullable(false).build(),\n};\n\nBOOST_AUTO_TEST_CASE(positional_success)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<int, std::string, float>;\n    const std::size_t pos_map[] = {0, 1, 2};\n    diagnostics diag;\n\n    auto err = detail::meta_check_impl<types>(name_table_t(), pos_map, meta, diag);\n\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(positional_success_trailing_fields)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<int, std::string>;\n    const std::size_t pos_map[] = {0, 1};\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(name_table_t(), pos_map, meta, diag);\n\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(positional_missing_fields)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<int, std::string, float, int, int>;\n    const std::size_t pos_map[] = {0, 1, 2, pos_absent, pos_absent};\n    const char* expected_msg =\n        \"Field in position 3 can't be mapped: there are more fields in your C++ data type than in your query\"\n        \"\\n\"\n        \"Field in position 4 can't be mapped: there are more fields in your C++ data type than in your query\";\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(name_table_t(), pos_map, meta, diag);\n\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_AUTO_TEST_CASE(positional_no_fields)\n{\n    using types = std::tuple<int, std::string>;\n    const std::size_t pos_map[] = {pos_absent, pos_absent};\n    const char* expected_msg =\n        \"Field in position 0 can't be mapped: there are more fields in your C++ data type than in your query\"\n        \"\\n\"\n        \"Field in position 1 can't be mapped: there are more fields in your C++ data type than in your query\";\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(name_table_t(), pos_map, metadata_collection_view(), diag);\n\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_AUTO_TEST_CASE(named_success)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<float, int, std::string>;\n    const std::size_t pos_map[] = {2, 0, 1};\n    const string_view names[] = {\"f1\", \"f2\", \"f3\"};\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(names, pos_map, meta, diag);\n\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(named_success_extra_fields)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<std::string, int>;\n    const std::size_t pos_map[] = {1, 0};\n    const string_view names[] = {\"f1\", \"f2\"};\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(names, pos_map, meta, diag);\n\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(named_absent_fields)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<std::string, int, float>;\n    const std::size_t pos_map[] = {pos_absent, 0, pos_absent};\n    const string_view names[] = {\"f1\", \"f2\", \"f3\"};\n    const char* expected_msg =\n        \"Field 'f1' is not present in the data returned by the server\"\n        \"\\n\"\n        \"Field 'f3' is not present in the data returned by the server\";\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(names, pos_map, meta, diag);\n\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_AUTO_TEST_CASE(named_no_fields)\n{\n    using types = std::tuple<int, int>;\n    const std::size_t pos_map[] = {pos_absent, pos_absent};\n    const string_view names[] = {\"f1\", \"f2\"};\n    const char* expected_msg =\n        \"Field 'f1' is not present in the data returned by the server\"\n        \"\\n\"\n        \"Field 'f2' is not present in the data returned by the server\";\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(names, pos_map, metadata_collection_view(), diag);\n\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_AUTO_TEST_CASE(failed_checks)\n{\n    // meta is: TINYINT, VARCHAR, FLOAT\n    using types = std::tuple<float, float, float>;\n    const std::size_t pos_map[] = {2, 1, 0};\n    const string_view names[] = {\"f1\", \"f2\", \"f3\"};\n    const char* expected_msg =\n        \"Incompatible types for field 'f2': C++ type 'float' is not compatible with DB type 'VARCHAR'\"\n        \"\\n\"\n        \"Incompatible types for field 'f3': C++ type 'float' is not compatible with DB type 'TINYINT'\";\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(names, pos_map, meta, diag);\n\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_AUTO_TEST_CASE(all_fields_discarded)\n{\n    using types = std::tuple<>;\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(name_table_t(), span<const std::size_t>(), meta, diag);\n\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(empty)\n{\n    using types = std::tuple<>;\n    diagnostics diag;\n\n    auto err = meta_check_impl<types>(\n        name_table_t(),\n        boost::span<const std::size_t>(),\n        metadata_collection_view(),\n        diag\n    );\n\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n//\n// parse: we use the test row types, which implement compliant traits, to test.\n//\nBOOST_AUTO_TEST_SUITE(parse_)\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", 42, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    test_row value;\n    auto err = parse<row_identity<test_row>>(pos_map, fv, value);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(value.i == 42);\n    BOOST_TEST(value.f == 4.3f);\n    BOOST_TEST(value.double_field == 8.1);\n}\n\nBOOST_AUTO_TEST_CASE(one_error)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", nullptr, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    test_row value;\n    auto err = parse<row_identity<test_row>>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(several_errors)\n{\n    // int, float, double\n    // we return the first error only\n    const auto fv = make_fv_arr(8.1, \"abc\", 0xffffffffffffffff, nullptr);\n    const std::size_t pos_map[] = {2, 3, 0};\n    test_row value;\n    auto err = parse<row_identity<test_row>>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(error_success_interleaved)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", 42, nullptr);\n    const std::size_t pos_map[] = {2, 3, 0};\n    test_row value;\n    auto err = parse<row_identity<test_row>>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(all_fields_discarded)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", 42, nullptr);\n    test_empty_row value;\n    auto err = parse<row_identity<test_empty_row>>(span<const std::size_t>(), fv, value);\n    BOOST_TEST(err == error_code());\n}\n\nBOOST_AUTO_TEST_CASE(no_fields)\n{\n    test_empty_row value;\n    auto err = parse<row_identity<test_empty_row>>(\n        span<const std::size_t>(),\n        span<const field_view>(),\n        value\n    );\n    BOOST_TEST(err == error_code());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n//\n// Describe structs\n//\nBOOST_AUTO_TEST_SUITE(describe_structs)\n\nstruct sempty\n{\n};\nBOOST_DESCRIBE_STRUCT(sempty, (), ())\n\nstruct s1\n{\n    std::int32_t i;\n};\nBOOST_DESCRIBE_STRUCT(s1, (), (i))\n\nstruct s2\n{\n    std::int32_t i;\n    float f;\n};\nBOOST_DESCRIBE_STRUCT(s2, (), (i, f))\n\nstruct sinherit : s2\n{\n    double double_field;\n};\nBOOST_DESCRIBE_STRUCT(sinherit, (s2), (double_field))\n\nstruct sbad\n{\n    int i;\n    unrelated f;\n    double d;\n};\nBOOST_DESCRIBE_STRUCT(sbad, (), (i, f, d))\n\n// is_row_type\nstatic_assert(is_static_row<sempty>, \"\");\nstatic_assert(is_static_row<s1>, \"\");\nstatic_assert(is_static_row<s2>, \"\");\nstatic_assert(is_static_row<sinherit>, \"\");\nstatic_assert(is_static_row<sbad>, \"\");\n\n// size\nstatic_assert(get_row_size<sempty>() == 0u, \"\");\nstatic_assert(get_row_size<s1>() == 1u, \"\");\nstatic_assert(get_row_size<s2>() == 2u, \"\");\nstatic_assert(get_row_size<sinherit>() == 3u, \"\");\n\n// name table\nBOOST_AUTO_TEST_CASE(get_row_name_table_)\n{\n    const string_view expected_s1[] = {\"i\"};\n    const string_view expected_s2[] = {\"i\", \"f\"};\n    const string_view expected_sinherit[] = {\"i\", \"f\", \"double_field\"};\n\n    compare_name_tables(get_row_name_table<sempty>(), name_table_t());\n    compare_name_tables(get_row_name_table<s1>(), expected_s1);\n    compare_name_tables(get_row_name_table<s2>(), expected_s2);\n    compare_name_tables(get_row_name_table<sinherit>(), expected_sinherit);\n}\n\n// meta check\nBOOST_AUTO_TEST_CASE(meta_check_ok)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::float_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n        meta_builder().type(column_type::smallint).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {2, 0, 1};\n    diagnostics diag;\n    auto err = detail::meta_check<sinherit>(pos_map, meta, diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_fail)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::tinyint).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {0, 1, 2};\n    diagnostics diag;\n    auto err = detail::meta_check<sinherit>(pos_map, meta, diag);\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(\n        diag.client_message() ==\n        \"Incompatible types for field 'f': C++ type 'float' is not compatible with DB type 'DOUBLE'\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_empty_struct)\n{\n    diagnostics diag;\n    auto err = detail::meta_check<sempty>(span<const std::size_t>(), metadata_collection_view(), diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\n// parsing\nBOOST_AUTO_TEST_CASE(parse_success)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", 42, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    sinherit value;\n    auto err = parse<sinherit>(pos_map, fv, value);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(value.i == 42);\n    BOOST_TEST(value.f == 4.3f);\n    BOOST_TEST(value.double_field == 8.1);\n}\n\nBOOST_AUTO_TEST_CASE(parse_error)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", nullptr, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    sinherit value;\n    auto err = parse<sinherit>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(parse_empty_struct)\n{\n    sempty value;\n    auto err = parse<sempty>(span<const std::size_t>(), span<const field_view>(), value);\n    BOOST_TEST(err == error_code());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n//\n// tuples\n//\nBOOST_AUTO_TEST_SUITE(tuples)\n\n// type definitions\nusing tempty = std::tuple<>;\nusing t1 = std::tuple<double>;\nusing t2 = std::tuple<std::int32_t, float>;\nusing t3 = std::tuple<std::string, std::int32_t, double>;\nusing tbad = std::tuple<int, unrelated, double>;\n\n// is_row_type concept: doesn't inspect individual fields\nstatic_assert(is_static_row<tempty>, \"\");\nstatic_assert(is_static_row<t1>, \"\");\nstatic_assert(is_static_row<t2>, \"\");\nstatic_assert(is_static_row<t3>, \"\");\nstatic_assert(is_static_row<tbad>, \"\");\n\n// size\nstatic_assert(get_row_size<tempty>() == 0, \"\");\nstatic_assert(get_row_size<t1>() == 1, \"\");\nstatic_assert(get_row_size<t2>() == 2, \"\");\nstatic_assert(get_row_size<t3>() == 3, \"\");\n\n// name tables\nBOOST_AUTO_TEST_CASE(get_row_name_table_)\n{\n    compare_name_tables(get_row_name_table<tempty>(), name_table_t());\n    compare_name_tables(get_row_name_table<t1>(), name_table_t());\n    compare_name_tables(get_row_name_table<t2>(), name_table_t());\n    compare_name_tables(get_row_name_table<t3>(), name_table_t());\n}\n\n// meta check\nBOOST_AUTO_TEST_CASE(meta_check_ok)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::varchar).nullable(false).build(),\n        meta_builder().type(column_type::int_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {0, 1, 2};\n    diagnostics diag;\n    auto err = detail::meta_check<t3>(pos_map, meta, diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_fail)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::varchar).nullable(false).build(),\n        meta_builder().type(column_type::bigint).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {0, 1, 2};\n    diagnostics diag;\n    auto err = detail::meta_check<t3>(pos_map, meta, diag);\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(\n        diag.client_message() ==\n        \"Incompatible types for field in position 1: C++ type 'int32_t' is not compatible with DB type \"\n        \"'BIGINT'\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_empty)\n{\n    diagnostics diag;\n    auto err = detail::meta_check<tempty>(span<const std::size_t>(), metadata_collection_view(), diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\n// parsing\nBOOST_AUTO_TEST_CASE(parse_success)\n{\n    // string, int, double\n    const auto fv = make_fv_arr(\"abc\", 42, 9.1, \"jkl\");\n    const std::size_t pos_map[] = {0, 1, 2};\n    t3 value;\n    auto err = parse<t3>(pos_map, fv, value);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(std::get<0>(value) == \"abc\");\n    BOOST_TEST(std::get<1>(value) == 42);\n    BOOST_TEST(std::get<2>(value) == 9.1);\n}\n\nBOOST_AUTO_TEST_CASE(parse_error)\n{\n    // string, int, double\n    const auto fv = make_fv_arr(\"abc\", nullptr, 4.3, \"jkl\");\n    const std::size_t pos_map[] = {0, 1, 2};\n    t3 value;\n    auto err = parse<t3>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(parse_empty_tuple)\n{\n    tempty value;\n    auto err = parse<tempty>(span<const std::size_t>(), span<const field_view>(), value);\n    BOOST_TEST(err == error_code());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n//\n// get_type_index\n//\nusing r1 = std::tuple<int>;\nusing r2 = std::tuple<float>;\nusing r3 = std::tuple<double>;\nusing ri1 = row_identity<r1>;\nusing ri2 = row_identity<r2>;\nusing ri3 = row_identity<r3>;\n\n// Unique types\nstatic_assert(get_type_index<r1, r1, r2, r3>() == 0u, \"\");\nstatic_assert(get_type_index<r2, r1, r2, r3>() == 1u, \"\");\nstatic_assert(get_type_index<r3, r1, r2, r3>() == 2u, \"\");\n\n// Unique types having a different underlying_row type\nstatic_assert(get_type_index<r1, ri1, ri2, ri3>() == 0u, \"\");\nstatic_assert(get_type_index<r2, ri1, ri2, ri3>() == 1u, \"\");\nstatic_assert(get_type_index<r3, ri1, ri2, ri3>() == 2u, \"\");\nstatic_assert(get_type_index<r2, ri1, ri2, r3>() == 1u, \"\");  // mixes are okay\n\n// Single, repeated type\nstatic_assert(get_type_index<r1, r1, r1, r1>() == 0u, \"\");\nstatic_assert(get_type_index<r1, ri1, ri1, ri1>() == 0u, \"\");\nstatic_assert(get_type_index<r1, r1, ri1, ri1>() == 0u, \"\");\nstatic_assert(get_type_index<r1, ri1, r1, r1>() == 0u, \"\");\n\n// Multiple, repeated types\nstatic_assert(get_type_index<r1, r1, r2, r1, r3, r1, r2, r3, r1>() == 0u, \"\");\nstatic_assert(get_type_index<r2, r1, r2, r1, r3, r1, r2, r3, r1>() == 1u, \"\");\nstatic_assert(get_type_index<r3, r1, r2, r1, r3, r1, r2, r3, r1>() == 2u, \"\");\nstatic_assert(get_type_index<r1, ri1, r2, r1, r3, r1, r2, r3, r1>() == 0u, \"\");\n\n// Single type\nstatic_assert(get_type_index<r1, r1>() == 0u, \"\");\nstatic_assert(get_type_index<r1, ri1>() == 0u, \"\");\n\n// Not found\nstatic_assert(get_type_index<r1>() == index_not_found, \"\");\nstatic_assert(get_type_index<r1, r2>() == index_not_found, \"\");\nstatic_assert(get_type_index<r1, r2, r2, r3, r2>() == index_not_found, \"\");\nstatic_assert(get_type_index<r1, ri2, r2, r3, r2>() == index_not_found, \"\");\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/unit/test/detail/writable_field_traits.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/writable_field_traits.hpp>\n\n#include <boost/config.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <atomic>\n#include <cstddef>\n#include <cstdint>\n#include <forward_list>\n#include <iosfwd>\n#include <iterator>\n#include <limits>\n#include <list>\n#include <memory>\n#include <set>\n#include <string>\n#include <vector>\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/custom_allocator.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::mysql::detail::is_field_view_forward_iterator;\nusing boost::mysql::detail::is_writable_field;\nusing boost::mysql::detail::is_writable_field_tuple;\nusing boost::mysql::detail::writable_field_traits;\nusing std::tuple;\n\nBOOST_AUTO_TEST_SUITE(test_writable_field_traits)\n\nstruct other_traits : std::char_traits<char>\n{\n};\n\nusing string_with_alloc = std::basic_string<char, std::char_traits<char>, custom_allocator<char>>;\nusing string_no_defctor = std::basic_string<char, std::char_traits<char>, custom_allocator_no_defctor<char>>;\nusing string_with_traits = std::basic_string<char, other_traits>;\nusing blob_with_alloc = std::vector<unsigned char, custom_allocator<unsigned char>>;\n\nstruct unrelated\n{\n};\n\n//\n// writable_field\n//\n// field_view accepted. References not accepted\nstatic_assert(is_writable_field<field_view>::value, \"\");\nstatic_assert(is_writable_field<const field_view>::value, \"\");\nstatic_assert(!is_writable_field<field_view&>::value, \"\");\nstatic_assert(!is_writable_field<const field_view&>::value, \"\");\nstatic_assert(!is_writable_field<field_view&&>::value, \"\");\n\nstatic_assert(is_writable_field<field>::value, \"\");\nstatic_assert(is_writable_field<const field>::value, \"\");\nstatic_assert(!is_writable_field<field&>::value, \"\");\nstatic_assert(!is_writable_field<const field&>::value, \"\");\nstatic_assert(!is_writable_field<field&&>::value, \"\");\n\n// scalars accepted\nstatic_assert(is_writable_field<std::nullptr_t>::value, \"\");\nstatic_assert(is_writable_field<unsigned char>::value, \"\");\nstatic_assert(is_writable_field<signed char>::value, \"\");\nstatic_assert(is_writable_field<short>::value, \"\");\nstatic_assert(is_writable_field<unsigned short>::value, \"\");\nstatic_assert(is_writable_field<int>::value, \"\");\nstatic_assert(is_writable_field<unsigned int>::value, \"\");\nstatic_assert(is_writable_field<long>::value, \"\");\nstatic_assert(is_writable_field<unsigned long>::value, \"\");\nstatic_assert(is_writable_field<float>::value, \"\");\nstatic_assert(is_writable_field<double>::value, \"\");\nstatic_assert(is_writable_field<boost::mysql::date>::value, \"\");\nstatic_assert(is_writable_field<boost::mysql::datetime>::value, \"\");\nstatic_assert(is_writable_field<boost::mysql::time>::value, \"\");\nstatic_assert(!is_writable_field<int&>::value, \"\");\nstatic_assert(!is_writable_field<const int&>::value, \"\");\nstatic_assert(!is_writable_field<int&&>::value, \"\");\nstatic_assert(!is_writable_field<const double&>::value, \"\");\nstatic_assert(!is_writable_field<const boost::mysql::date&>::value, \"\");\n\n// durations accepted as long as they can be converted to time\nstatic_assert(is_writable_field<std::chrono::hours>::value, \"\");\nstatic_assert(is_writable_field<std::chrono::minutes>::value, \"\");\nstatic_assert(is_writable_field<std::chrono::seconds>::value, \"\");\nstatic_assert(is_writable_field<std::chrono::milliseconds>::value, \"\");\nstatic_assert(is_writable_field<std::chrono::microseconds>::value, \"\");\nstatic_assert(!is_writable_field<std::chrono::nanoseconds>::value, \"\");\n\n// characters (except signed/unsigned char) not accepted\nstatic_assert(!is_writable_field<char>::value, \"\");\nstatic_assert(!is_writable_field<const char>::value, \"\");\nstatic_assert(!is_writable_field<std::atomic_char>::value, \"\");\nstatic_assert(!is_writable_field<wchar_t>::value, \"\");\nstatic_assert(!is_writable_field<char16_t>::value, \"\");\nstatic_assert(!is_writable_field<char32_t>::value, \"\");\n#ifdef __cpp_char8_t\nstatic_assert(!is_writable_field<char8_t>::value, \"\");\n#endif\nstatic_assert(!is_writable_field<char&>::value, \"\");\nstatic_assert(!is_writable_field<const char&>::value, \"\");\nstatic_assert(!is_writable_field<char&&>::value, \"\");\n\n// bool accepted\nstatic_assert(is_writable_field<bool>::value, \"\");\nstatic_assert(!is_writable_field<bool&>::value, \"\");\nstatic_assert(!is_writable_field<const bool&>::value, \"\");\n\n// string types\nstatic_assert(is_writable_field<const char*>::value, \"\");\nstatic_assert(is_writable_field<std::string>::value, \"\");\nstatic_assert(is_writable_field<string_with_alloc>::value, \"\");\nstatic_assert(is_writable_field<string_no_defctor>::value, \"\");\nstatic_assert(is_writable_field<string_view>::value, \"\");\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nstatic_assert(is_writable_field<std::string_view>::value, \"\");\n#endif\nstatic_assert(!is_writable_field<string_with_traits>::value, \"\");\nstatic_assert(!is_writable_field<std::wstring>::value, \"\");\nstatic_assert(!is_writable_field<std::string&>::value, \"\");\nstatic_assert(!is_writable_field<const std::string&>::value, \"\");\nstatic_assert(!is_writable_field<std::string&&>::value, \"\");\n\n// blob types\nstatic_assert(is_writable_field<blob>::value, \"\");\nstatic_assert(is_writable_field<blob_view>::value, \"\");\nstatic_assert(is_writable_field<blob_with_alloc>::value, \"\");\nstatic_assert(!is_writable_field<blob&>::value, \"\");\nstatic_assert(!is_writable_field<const blob&>::value, \"\");\n\n// optional types accepted\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nstatic_assert(is_writable_field<std::optional<int>>::value, \"\");\nstatic_assert(is_writable_field<std::optional<std::string>>::value, \"\");\nstatic_assert(is_writable_field<std::optional<string_no_defctor>>::value, \"\");\nstatic_assert(!is_writable_field<std::optional<int>&>::value, \"\");\nstatic_assert(!is_writable_field<const std::optional<int>&>::value, \"\");\nstatic_assert(!is_writable_field<std::optional<int>&&>::value, \"\");\n#endif\nstatic_assert(is_writable_field<boost::optional<string_view>>::value, \"\");\nstatic_assert(is_writable_field<boost::optional<blob_view>>::value, \"\");\nstatic_assert(is_writable_field<boost::optional<string_no_defctor>>::value, \"\");\n\n// optional of other stuff not accepted\nstatic_assert(!is_writable_field<boost::optional<void*>>::value, \"\");\nstatic_assert(!is_writable_field<boost::optional<unrelated>>::value, \"\");\nstatic_assert(!is_writable_field<boost::optional<int&>>::value, \"\");\n\n// other stuff not accepted\nstatic_assert(!is_writable_field<void*>::value, \"\");\nstatic_assert(!is_writable_field<field*>::value, \"\");\nstatic_assert(!is_writable_field<field_view*>::value, \"\");\nstatic_assert(!is_writable_field<unrelated>::value, \"\");\nstatic_assert(!is_writable_field<unrelated*>::value, \"\");\n\n//\n// writable_field_tuple\n//\n// Empty tuples accepted\nstatic_assert(is_writable_field_tuple<tuple<>>::value, \"\");\nstatic_assert(is_writable_field_tuple<tuple<>&>::value, \"\");\nstatic_assert(is_writable_field_tuple<const tuple<>&>::value, \"\");\nstatic_assert(is_writable_field_tuple<tuple<>&&>::value, \"\");\n\n// Tuples of field likes accepted\nstatic_assert(is_writable_field_tuple<tuple<int, std::string&, const char*>>::value, \"\");\nstatic_assert(is_writable_field_tuple<tuple<field_view, string_view, int&&>>::value, \"\");\nstatic_assert(is_writable_field_tuple<tuple<boost::optional<int>, string_view, blob&&>>::value, \"\");\n\n// References accepted\nstatic_assert(is_writable_field_tuple<tuple<int, float&, std::string&&>&>::value, \"\");\nstatic_assert(is_writable_field_tuple<const tuple<int, float&, std::string&&>&>::value, \"\");\nstatic_assert(is_writable_field_tuple<tuple<int, float&, std::string&&>&&>::value, \"\");\n\n// Tuples of other stuff not accepted\nstatic_assert(!is_writable_field_tuple<tuple<int, std::ostream&>>::value, \"\");\nstatic_assert(!is_writable_field_tuple<tuple<std::ostream&, char>>::value, \"\");\nstatic_assert(!is_writable_field_tuple<tuple<std::ostream&, char>&>::value, \"\");\nstatic_assert(!is_writable_field_tuple<tuple<boost::optional<void*>, char>&>::value, \"\");\n\n// Non-tuples not accepted\nstatic_assert(!is_writable_field_tuple<int>::value, \"\");\nstatic_assert(!is_writable_field_tuple<std::array<int, 1>>::value, \"\");\nstatic_assert(!is_writable_field_tuple<field_view>::value, \"\");\n\n//\n// field_view iterator\n//\n\n// Pointers. Note that field_view* const is not considered an iterator\nstatic_assert(is_field_view_forward_iterator<field_view*>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<const field_view*>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<field*>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<const field*>::value, \"\");\n\n// Array iterators\nstatic_assert(is_field_view_forward_iterator<std::array<field_view, 10>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::array<field_view, 10>::const_iterator>::value, \"\");\n\nstatic_assert(is_field_view_forward_iterator<std::array<field, 10>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::array<field, 10>::const_iterator>::value, \"\");\n\n// Vector iterators\nstatic_assert(is_field_view_forward_iterator<std::vector<field_view>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::vector<field_view>::const_iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::vector<field_view>::reverse_iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::vector<field_view>::const_reverse_iterator>::value, \"\");\nstatic_assert(\n    is_field_view_forward_iterator<std::vector<std::reference_wrapper<field_view>>::iterator>::value,\n    \"\"\n);\n\nstatic_assert(is_field_view_forward_iterator<std::vector<field>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::vector<field>::const_iterator>::value, \"\");\n\n// forward_list iterators\nstatic_assert(is_field_view_forward_iterator<std::forward_list<field_view>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::forward_list<field_view>::const_iterator>::value, \"\");\n\nstatic_assert(is_field_view_forward_iterator<std::forward_list<field>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::forward_list<field>::const_iterator>::value, \"\");\n\n// list iterators\nstatic_assert(is_field_view_forward_iterator<std::list<field_view>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::list<field_view>::const_iterator>::value, \"\");\n\nstatic_assert(is_field_view_forward_iterator<std::list<field>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::list<field>::const_iterator>::value, \"\");\n\n// set iterators\nstatic_assert(is_field_view_forward_iterator<std::set<field_view>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::set<field_view>::const_iterator>::value, \"\");\n\nstatic_assert(is_field_view_forward_iterator<std::set<field>::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<std::set<field>::const_iterator>::value, \"\");\n\n// row_view iterators\nstatic_assert(is_field_view_forward_iterator<row_view::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<row_view::const_iterator>::value, \"\");\n\n// row iterators\nstatic_assert(is_field_view_forward_iterator<row::iterator>::value, \"\");\nstatic_assert(is_field_view_forward_iterator<row::const_iterator>::value, \"\");\n\n// iterators whose reference type doesn't match\nstatic_assert(!is_field_view_forward_iterator<std::vector<field_view*>::iterator>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<std::vector<int>::iterator>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<std::string::iterator>::value, \"\");\n\n// types that aren't iterators\nstatic_assert(!is_field_view_forward_iterator<field_view>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<int>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<std::string>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<std::vector<int>>::value, \"\");\n\n// References to iterators are not accepted\nstatic_assert(!is_field_view_forward_iterator<field_view*&>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<row::iterator&>::value, \"\");\nstatic_assert(!is_field_view_forward_iterator<const row::iterator&>::value, \"\");\n\nBOOST_AUTO_TEST_CASE(to_field_)\n{\n    using detail::to_field;\n\n    std::int64_t int64max = (std::numeric_limits<std::int64_t>::max)();\n    std::uint64_t uint64max = (std::numeric_limits<std::uint64_t>::max)();\n    datetime dt{2020, 1, 2, 23};\n    auto t = maket(45, 1, 2);\n    std::string s = \"ljk\";\n    blob b{3, 4, 5};\n    field f(\"tgh\");\n\n    // Scalars\n    BOOST_TEST(to_field(std::int8_t(90)) == field_view(90));\n    BOOST_TEST(to_field(std::uint8_t(90u)) == field_view(90u));\n    BOOST_TEST(to_field(std::int16_t(0xabc)) == field_view(0xabc));\n    BOOST_TEST(to_field(std::uint16_t(0xaabbu)) == field_view(0xaabbu));\n    BOOST_TEST(to_field(std::int32_t(90)) == field_view(90));\n    BOOST_TEST(to_field(std::uint32_t(90u)) == field_view(90u));\n    BOOST_TEST(to_field(int64max) == field_view(int64max));\n    BOOST_TEST(to_field(uint64max) == field_view(uint64max));\n    BOOST_TEST(to_field(false) == field_view(0));\n    BOOST_TEST(to_field(true) == field_view(1));\n    BOOST_TEST(to_field(4.2f) == field_view(4.2f));\n    BOOST_TEST(to_field(4.2) == field_view(4.2));\n    BOOST_TEST(to_field(date(2020, 1, 2)) == field_view(date(2020, 1, 2)));\n    BOOST_TEST(to_field(dt) == field_view(dt));\n    BOOST_TEST(to_field(t) == field_view(t));\n\n    // Strings\n    BOOST_TEST(to_field(s) == field_view(\"ljk\"));\n    BOOST_TEST(to_field(static_cast<const std::string&>(s)) == field_view(\"ljk\"));\n    BOOST_TEST(to_field(string_view(\"abc\")) == field_view(\"abc\"));\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n    BOOST_TEST(to_field(std::string_view(\"abc\")) == field_view(\"abc\"));\n#endif\n    BOOST_TEST(to_field(static_cast<const char*>(\"abc\")) == field_view(\"abc\"));\n\n    // Blobs\n    BOOST_TEST(to_field(b) == field_view(makebv(\"\\3\\4\\5\")));\n    BOOST_TEST(to_field(static_cast<const blob&>(b)) == field_view(makebv(\"\\3\\4\\5\")));\n    BOOST_TEST(to_field(makebv(\"\\1\\2\\3\")) == field_view(makebv(\"\\1\\2\\3\")));\n\n    // Optionals\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n    BOOST_TEST(to_field(std::optional<int>()) == field_view());\n    BOOST_TEST(to_field(std::optional<int>(42)) == field_view(42));\n#endif\n    BOOST_TEST(to_field(boost::optional<float>()) == field_view());\n    BOOST_TEST(to_field(boost::optional<float>(4.2f)) == field_view(4.2f));\n\n    // Field types\n    BOOST_TEST(to_field(f) == field_view(\"tgh\"));\n    BOOST_TEST(to_field(field_view(50)) == field_view(50));\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/diagnostics.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_diagnostics)\n\nBOOST_AUTO_TEST_CASE(operator_equals)\n{\n    // Both empty\n    BOOST_TEST(diagnostics() == diagnostics());\n\n    // Same message\n    BOOST_TEST(create_server_diag(\"abc\") == create_server_diag(\"abc\"));\n\n    // Empty vs. message\n    BOOST_TEST(!(diagnostics() == create_server_diag(\"abc\")));\n\n    // Different messages\n    BOOST_TEST(!(create_server_diag(\"def\") == create_server_diag(\"abc\")));\n\n    // Same message, client vs. server\n    BOOST_TEST(!(create_server_diag(\"abc\") == create_client_diag(\"abc\")));\n}\n\nBOOST_AUTO_TEST_CASE(operator_not_equals)\n{\n    BOOST_TEST(!(diagnostics() != diagnostics()));\n    BOOST_TEST(!(create_server_diag(\"abc\") != create_server_diag(\"abc\")));\n    BOOST_TEST(diagnostics() != create_server_diag(\"abc\"));\n    BOOST_TEST(create_server_diag(\"def\") != create_server_diag(\"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(message_accessors)\n{\n    auto diag = create_server_diag(\"abc\");\n    BOOST_TEST(diag.client_message() == \"\");\n    BOOST_TEST(diag.server_message() == \"abc\");\n\n    diag = create_client_diag(\"def\");\n    BOOST_TEST(diag.client_message() == \"def\");\n    BOOST_TEST(diag.server_message() == \"\");\n\n    diag = diagnostics();\n    BOOST_TEST(diag.client_message() == \"\");\n    BOOST_TEST(diag.server_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(clear)\n{\n    // Clearing server diagnostics\n    auto diag_server = create_server_diag(\"abc\");\n    diag_server.clear();\n    BOOST_TEST(diag_server.client_message() == \"\");\n    BOOST_TEST(diag_server.server_message() == \"\");\n\n    // Clearing client diagnostics\n    auto diag_client = create_client_diag(\"def\");\n    diag_client.clear();\n    BOOST_TEST(diag_client.client_message() == \"\");\n    BOOST_TEST(diag_client.server_message() == \"\");\n\n    // Client/server is appropriately reset\n    BOOST_TEST(diag_server == diag_client);\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_diagnostics\n"
  },
  {
    "path": "test/unit/test/escape_string.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/escape_string.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <string>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/custom_allocator.hpp\"\n#include \"test_unit/ff_charset.hpp\"\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_escape_string)\n\n//\n// Escaping using backslashes\n//\nBOOST_AUTO_TEST_CASE(backslashes_utf8mb4_valid)\n{\n    char all_ascii_noescape_storage[] = {\n        '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\x07', '\\x08', '\\x09', '\\x0b', '\\x0c', '\\x0e',\n        '\\x0f', '\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17', '\\x18', '\\x19', '\\x1b',\n        '\\x1c', '\\x1d', '\\x1e', '\\x1f', ' ',    '!',    '#',    '%',    '&',    '(',    ')',    '*',\n        '+',    ',',    '-',    '.',    '/',    '0',    '1',    '2',    '3',    '4',    '5',    '6',\n        '7',    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',    '@',    'A',    'B',\n        'C',    'D',    'E',    'F',    'G',    'H',    'I',    'J',    'K',    'L',    'M',    'N',\n        'O',    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',    'X',    'Y',    'Z',\n        '[',    ']',    '^',    '_',    '`',    'a',    'b',    'c',    'd',    'e',    'f',    'g',\n        'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',    'p',    'q',    'r',    's',\n        't',    'u',    'v',    'w',    'x',    'y',    'z',    '{',    '|',    '}',    '~',\n    };\n    string_view all_ascii_noescape(all_ascii_noescape_storage, sizeof(all_ascii_noescape_storage));\n\n    struct\n    {\n        string_view name;\n        string_view input;\n        string_view expected;\n    } test_cases[] = {\n        {\"empty\",                  \"\",                                      \"\"                                             },\n        {\"no_escape_ascii\",        \"this is A test string\",                 \"this is A test string\"                        },\n        {\"all_noescape_ascii\",     all_ascii_noescape,                      all_ascii_noescape                             },\n        {\"escape_dquote\",          R\"(this has \"dquotes\")\",                 R\"(this has \\\"dquotes\\\")\"                      },\n        {\"escape_squote\",          R\"(this has 'squotes')\",                 R\"(this has \\'squotes\\')\"                      },\n        {\"escape_backslash\",       R\"(this has \\a backslash\\)\",             R\"(this has \\\\a backslash\\\\)\"                  },\n        {\"escape_null\",            test::makesv(\"this has \\0 null \\0\"),     R\"(this has \\0 null \\0)\"                       },\n        {\"escape_ctrlz\",           \"this has \\x1a Ctrl+Z \\x1a\",             R\"(this has \\Z Ctrl+Z \\Z)\"                     },\n        {\"escape_newline\",         \"this has \\n newline \\n\",                R\"(this has \\n newline \\n)\"                    },\n        {\"escape_carriage_return\", \"this has \\r car ret \\r\",                R\"(this has \\r car ret \\r)\"                    },\n        {\"all_escape_chars\",       \"\\\"''\\\\\\\"\\n\\r\\\\\",                        R\"(\\\"\\'\\'\\\\\\\"\\n\\r\\\\)\"                          },\n        {\"start_escape_char\",      \"\\\"abc\",                                 R\"(\\\"abc)\"                                     },\n        {\"end_escape_char\",        \"abc\\\"\",                                 R\"(abc\\\")\"                                     },\n        {\"single_escape_char\",     \"'\",                                     \"\\\\'\"                                          },\n        {\"utf8_2byte\",             \"2byte \\\" \\xc3\\xb1 UTF-8\\\\ \\xc3\\xb2 \\\\\", \"2byte \\\\\\\" \\xc3\\xb1 UTF-8\\\\\\\\ \\xc3\\xb2 \\\\\\\\\"\n        },\n        {\"utf8_3byte\",             \"3byte '\\xef\\xbf\\xbf UTF-8'\",            \"3byte \\\\'\\xef\\xbf\\xbf UTF-8\\\\'\"               },\n        {\"utf8_4byte\",             \"4byte \\r'\\xf0\\x90\\x80\\x80 UTF-8\\n\",     \"4byte \\\\r\\\\'\\xf0\\x90\\x80\\x80 UTF-8\\\\n\"        },\n // Some typical injection payloads\n        {\"injection_1\",            R\"(\\\\)\",                                 R\"(\\\\\\\\)\"                                      },\n        {\"injection_2\",            R\"(' or \")\",                             R\"(\\' or \\\")\"                                  },\n        {\"injection_3\",            R\"(-- or #)\",                            R\"(-- or #)\"                                   },\n        {\"injection_4\",            R\"(' OR '1)\",                            R\"(\\' OR \\'1)\"                                 },\n        {\"injection_5\",            R\"(' OR 1 -- -)\",                        R\"(\\' OR 1 -- -)\"                              },\n        {\"injection_6\",            R\"(\" OR \"\" = \")\",                        R\"(\\\" OR \\\"\\\" = \\\")\"                           },\n        {\"injection_7\",            R\"(\" OR 1 = 1 -- -)\",                    R\"(\\\" OR 1 = 1 -- -)\"                          },\n        {\"injection_8\",            R\"(' OR '' = ')\",                        R\"(\\' OR \\'\\' = \\')\"                           },\n        {\"injection_9\",            R\"('=')\",                                R\"(\\'=\\')\"                                     },\n        {\"injection_10\",           R\"('LIKE')\",                             R\"(\\'LIKE\\')\"                                  },\n        {\"injection_11\",           R\"('=0--+)\",                             R\"(\\'=0--+)\"                                   },\n        {\"injection_12\",           R\"(' OR 'x'='x)\",                        R\"(\\' OR \\'x\\'=\\'x)\"                           },\n        {\"injection_13\",           R\"(' AND id IS NULL; --)\",               R\"(\\' AND id IS NULL; --)\"                     },\n        {\"injection_14\",           R\"('''''''''''''UNION SELECT '2)\",       R\"(\\'\\'\\'\\'\\'\\'\\'\\'\\'\\'\\'\\'\\'UNION SELECT \\'2)\"},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            std::string output = \"abc\";\n            auto ec = escape_string(tc.input, {utf8mb4_charset, true}, quoting_context::double_quote, output);\n            BOOST_TEST(ec == error_code());\n            BOOST_TEST(output == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(backslashes_utf8mb4_invalid)\n{\n    // \\xc0\\x80 is an overlong 0 character\n    std::string output = \"abc\";\n    auto ec = escape_string(\n        \"This 'has' invalid \\xc0\\x80 chars\\\\\",\n        {utf8mb4_charset, true},\n        quoting_context::double_quote,\n        output\n    );\n    BOOST_TEST(ec == client_errc::invalid_encoding);\n}\n\nBOOST_AUTO_TEST_CASE(backslashes_multibyte_ascii_compatible_chars)\n{\n    // Edge cases for encodings allowing character representations that could confuse the algorithm.\n    // xff\\\" and \\xff\\\\ are multibyte sequences, so they don't get escaped. Other chars are escaped.\n    string_view s = \"This is \\\\ a string \\xff\\\\ with a weird \\xff\\\" encoding \\\"\";\n    std::string output = \"abc\";\n\n    auto ec = escape_string(s, {test::ff_charset, true}, quoting_context::double_quote, output);\n\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(output == \"This is \\\\\\\\ a string \\xff\\\\ with a weird \\xff\\\" encoding \\\\\\\"\");\n}\n\n//\n// Escaping doubling quotes\n//\nBOOST_AUTO_TEST_CASE(quotes_utf8mb4_valid)\n{\n    std::string all_ascii_noescape;\n    all_ascii_noescape.reserve(0x80);\n    for (int i = 0; i < 0x80; ++i)\n    {\n        char c = static_cast<char>(i);\n        if (c != '\"')\n            all_ascii_noescape.push_back(c);\n    }\n\n    struct\n    {\n        string_view name;\n        string_view input;\n        string_view expected;\n    } test_cases[] = {\n        {\"empty\",              \"\",                                      \"\"                                       },\n        {\"no_escape_ascii\",    \"this is A test string\",                 \"this is A test string\"                  },\n        {\"all_noescape_ascii\", all_ascii_noescape,                      all_ascii_noescape                       },\n        {\"escape_quotes\",      R\"(this has \"dquotes\")\",                 R\"(this has \"\"dquotes\"\")\"                },\n        {\"other_escape_chars\", R\"('squotes' \"and\" `backticks`\\)\",       R\"('squotes' \"\"and\"\" `backticks`\\)\"      },\n        {\"all_escape_chars\",   R\"(\"\"\"\"\")\",                              R\"(\"\"\"\"\"\"\"\"\"\")\"                          },\n        {\"start_escape_char\",  \"\\\"abc\",                                 R\"(\"\"abc)\"                               },\n        {\"end_escape_char\",    \"abc\\\"\",                                 R\"(abc\"\")\"                               },\n        {\"single_escape_char\", \"\\\"\",                                    R\"(\"\")\"                                  },\n        {\"utf8_2byte\",         \"2byte \\\" \\xc3\\xb1 UTF-8\\\\ \\xc3\\xb2 \\\\\", \"2byte \\\"\\\" \\xc3\\xb1 UTF-8\\\\ \\xc3\\xb2 \\\\\"},\n        {\"utf8_3byte\",         \"3byte \\\"\\xef\\xbf\\xbf UTF-8\\\"\",          \"3byte \\\"\\\"\\xef\\xbf\\xbf UTF-8\\\"\\\"\"       },\n        {\"utf8_4byte\",         \"4byte \\\"\\xf0\\x90\\x80\\x80 UTF-8\\\"\",      \"4byte \\\"\\\"\\xf0\\x90\\x80\\x80 UTF-8\\\"\\\"\"   },\n // Some typical injection payloads\n        {\"injection_1\",        R\"(\\\\)\",                                 R\"(\\\\)\"                                  },\n        {\"injection_2\",        R\"(' or \")\",                             R\"(' or \"\")\"                             },\n        {\"injection_3\",        R\"(-- or #)\",                            R\"(-- or #)\"                             },\n        {\"injection_4\",        R\"(' OR '1)\",                            R\"(' OR '1)\"                             },\n        {\"injection_5\",        R\"(' OR 1 -- -)\",                        R\"(' OR 1 -- -)\"                         },\n        {\"injection_6\",        R\"(\" OR \"\" = \")\",                        R\"(\"\" OR \"\"\"\" = \"\")\"                     },\n        {\"injection_7\",        R\"(\" OR 1 = 1 -- -)\",                    R\"(\"\" OR 1 = 1 -- -)\"                    },\n        {\"injection_8\",        R\"(' OR '' = ')\",                        R\"(' OR '' = ')\"                         },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            std::string output = \"abc\";\n            auto\n                ec = escape_string(tc.input, {utf8mb4_charset, false}, quoting_context::double_quote, output);\n            BOOST_TEST(ec == error_code());\n            BOOST_TEST(output == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(quotes_quoting_contexts)\n{\n    // Test through all quoting contexts\n    string_view input = R\"(A \"string\" that 'contains' some `quotes` \\'\"`)\";\n\n    struct\n    {\n        string_view name;\n        quoting_context quot_ctx;\n        string_view expected;\n    } test_cases[] = {\n        {\"dquote\",   quoting_context::double_quote, R\"(A \"\"string\"\" that 'contains' some `quotes` \\'\"\"`)\"},\n        {\"squote\",   quoting_context::single_quote, R\"(A \"string\" that ''contains'' some `quotes` \\''\"`)\"},\n        {\"backtick\", quoting_context::backtick,     R\"(A \"string\" that 'contains' some ``quotes`` \\'\"``)\"},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            std::string output = \"abc\";\n            auto ec = escape_string(input, {utf8mb4_charset, false}, tc.quot_ctx, output);\n            BOOST_TEST(ec == error_code());\n            BOOST_TEST(output == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(quotes_utf8mb4_invalid)\n{\n    // \\xc3\\\\ is an attempt to smuggle a backslash as an invalid 2 byte UTF8 sequence\n    std::string output = \"abc\";\n    auto ec = escape_string(\n        \"This \\\"has\\\" invalid \\xc3\\\\ chars\",\n        {utf8mb4_charset, false},\n        quoting_context::double_quote,\n        output\n    );\n    BOOST_TEST(ec == client_errc::invalid_encoding);\n}\n\nBOOST_AUTO_TEST_CASE(quotes_multibyte_ascii_compatible_chars)\n{\n    // Edge cases for encodings allowing character representations that could confuse the algorithm.\n    // \\xff\\\" is a multibyte sequence, so it doesn't get escaped. Other chars are escaped.\n    string_view s = \"This is \\\" a string \\xfe\\\" with a weird \\xff\\\" encoding \\\"\";\n    std::string output = \"abc\";\n\n    auto ec = escape_string(s, {test::ff_charset, false}, quoting_context::double_quote, output);\n\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(output == \"This is \\\"\\\" a string \\xfe\\\"\\\" with a weird \\xff\\\" encoding \\\"\\\"\");\n}\n\nBOOST_AUTO_TEST_CASE(parameter_coverage)\n{\n    // Test that the different combination of parameters dispatch\n    // to the algorithm they should (backslashes or quotes)\n    string_view input = \"This \\\"has\\\" 'squotes'\\n, `backticks`, and \\\\\";\n\n    struct\n    {\n        string_view name;\n        bool backslash_escapes;\n        quoting_context quot_ctx;\n        string_view expected;\n    } test_cases[] = {\n        {\"escapes_dquotes\",\n         true,  quoting_context::double_quote,\n         \"This \\\\\\\"has\\\\\\\" \\\\'squotes\\\\'\\\\n, `backticks`, and \\\\\\\\\"},\n        {\"escapes_squotes\",\n         true,  quoting_context::single_quote,\n         \"This \\\\\\\"has\\\\\\\" \\\\'squotes\\\\'\\\\n, `backticks`, and \\\\\\\\\"},\n        {\"escapes_backticks\",\n         true,  quoting_context::backtick,\n         \"This \\\"has\\\" 'squotes'\\n, ``backticks``, and \\\\\"         },\n\n        {\"no_escapes_dquotes\",\n         false, quoting_context::double_quote,\n         \"This \\\"\\\"has\\\"\\\" 'squotes'\\n, `backticks`, and \\\\\"       },\n        {\"no_escapes_squotes\",\n         false, quoting_context::single_quote,\n         \"This \\\"has\\\" ''squotes''\\n, `backticks`, and \\\\\"         },\n        {\"no_escapes_backticks\",\n         false, quoting_context::backtick,\n         \"This \\\"has\\\" 'squotes'\\n, ``backticks``, and \\\\\"         },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            std::string output = \"abc\";\n            auto ec = escape_string(input, {utf8mb4_charset, tc.backslash_escapes}, tc.quot_ctx, output);\n            BOOST_TEST(ec == error_code());\n            BOOST_TEST(output == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(other_string_types)\n{\n    // Spotcheck: escape_string can be used with string types != std::string\n    std::basic_string<char, std::char_traits<char>, test::custom_allocator<char>> output = \"abc\";\n    auto ec = escape_string(\"some 'value'\", {utf8mb4_charset, true}, quoting_context::single_quote, output);\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(output == R\"(some \\'value\\')\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/execution_processor/execution_processor.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/mock_execution_processor.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nusing boost::mysql::column_type;\nusing boost::mysql::diagnostics;\nusing boost::mysql::error_code;\nusing boost::mysql::metadata_mode;\nusing boost::mysql::string_view;\nusing boost::mysql::throw_on_error;\n\nnamespace {\n\nclass spy_execution_processor : public mock_execution_processor\n{\npublic:\n    struct\n    {\n        bool is_last;\n    } on_meta_call;\n\nprivate:\n    error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) override\n    {\n        on_meta_call.is_last = is_last;\n        return mock_execution_processor::on_meta_impl(coldef, is_last, diag);\n    }\n};\n\nvoid check_reading_first(const execution_processor& st)\n{\n    BOOST_TEST(st.is_reading_first());\n    BOOST_TEST(!st.is_reading_first_subseq());\n    BOOST_TEST(st.is_reading_head());\n    BOOST_TEST(!st.is_reading_meta());\n    BOOST_TEST(!st.is_reading_rows());\n    BOOST_TEST(!st.is_complete());\n}\n\nvoid check_reading_first_subseq(const execution_processor& st)\n{\n    BOOST_TEST(!st.is_reading_first());\n    BOOST_TEST(st.is_reading_first_subseq());\n    BOOST_TEST(st.is_reading_head());\n    BOOST_TEST(!st.is_reading_meta());\n    BOOST_TEST(!st.is_reading_rows());\n    BOOST_TEST(!st.is_complete());\n}\n\nvoid check_reading_meta(const execution_processor& st)\n{\n    BOOST_TEST(!st.is_reading_first());\n    BOOST_TEST(!st.is_reading_first_subseq());\n    BOOST_TEST(!st.is_reading_head());\n    BOOST_TEST(st.is_reading_meta());\n    BOOST_TEST(!st.is_reading_rows());\n    BOOST_TEST(!st.is_complete());\n}\n\nvoid check_reading_rows(const execution_processor& st)\n{\n    BOOST_TEST(!st.is_reading_first());\n    BOOST_TEST(!st.is_reading_first_subseq());\n    BOOST_TEST(!st.is_reading_head());\n    BOOST_TEST(!st.is_reading_meta());\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST(!st.is_complete());\n}\n\nvoid check_complete(const execution_processor& st)\n{\n    BOOST_TEST(!st.is_reading_first());\n    BOOST_TEST(!st.is_reading_first_subseq());\n    BOOST_TEST(!st.is_reading_head());\n    BOOST_TEST(!st.is_reading_meta());\n    BOOST_TEST(!st.is_reading_rows());\n    BOOST_TEST(st.is_complete());\n}\n\nBOOST_AUTO_TEST_SUITE(test_execution_processor)\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    mock_execution_processor p;\n    check_reading_first(p);\n    BOOST_TEST(p.encoding() == resultset_encoding::text);\n    BOOST_TEST(p.sequence_number() == 0u);\n    BOOST_TEST(p.meta_mode() == metadata_mode::minimal);\n}\n\nBOOST_AUTO_TEST_CASE(reset)\n{\n    mock_execution_processor p;\n    p.on_num_meta(42);\n    p.sequence_number() = 42u;\n    p.reset(resultset_encoding::binary, metadata_mode::full);\n    check_reading_first(p);\n    BOOST_TEST(p.encoding() == resultset_encoding::binary);\n    BOOST_TEST(p.sequence_number() == 0u);\n    BOOST_TEST(p.meta_mode() == metadata_mode::full);\n}\n\nBOOST_AUTO_TEST_CASE(states)\n{\n    mock_execution_processor p;\n    diagnostics diag;\n\n    check_reading_first(p);\n\n    p.on_num_meta(1);\n    check_reading_meta(p);\n\n    auto err = p.on_meta(meta_builder().build_coldef(), diag);\n    throw_on_error(err, diag);\n    check_reading_rows(p);\n\n    err = p.on_row_ok_packet(ok_builder().more_results(true).build());\n    throw_on_error(err, diag);\n    check_reading_first_subseq(p);\n\n    err = p.on_head_ok_packet(ok_builder().build(), diag);\n    throw_on_error(err, diag);\n    check_complete(p);\n}\n\nBOOST_AUTO_TEST_CASE(on_meta_one_column)\n{\n    spy_execution_processor p;\n    diagnostics diag;\n    p.reset(resultset_encoding::text, metadata_mode::minimal);\n    p.on_num_meta(1);\n\n    auto err = p.on_meta(meta_builder().type(column_type::bit).build_coldef(), diag);\n\n    // Verify\n    BOOST_TEST(err == error_code());\n    p.num_calls().reset(1).on_num_meta(1).on_meta(1).validate();\n    check_meta(p.meta(), {column_type::bit});\n    BOOST_TEST(p.on_meta_call.is_last);\n}\n\nBOOST_AUTO_TEST_CASE(on_meta_several_columns)\n{\n    spy_execution_processor p;\n    diagnostics diag;\n    p.reset(resultset_encoding::text, metadata_mode::full);\n    p.on_num_meta(2);\n\n    // 1st field\n    auto err = p.on_meta(meta_builder().type(column_type::bit).build_coldef(), diag);\n\n    // Verify\n    BOOST_TEST(err == error_code());\n    p.num_calls().reset(1).on_num_meta(1).on_meta(1).validate();\n    check_meta(p.meta(), {column_type::bit});\n    BOOST_TEST(!p.on_meta_call.is_last);\n\n    // 2nd column\n    err = p.on_meta(meta_builder().type(column_type::varchar).build_coldef(), diag);\n\n    // Verify\n    BOOST_TEST(err == error_code());\n    p.num_calls().reset(1).on_num_meta(1).on_meta(2).validate();\n    check_meta(p.meta(), {column_type::bit, column_type::varchar});\n    BOOST_TEST(p.on_meta_call.is_last);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/execution_processor/execution_processor_helpers.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HELPERS_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HELPERS_HPP\n\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n\n#include <boost/mysql/detail/coldef_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n\n// Throughout execution_processor tests we use a set of common values for\n// metadata and OK packets. Definitions here to reduce duplication\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Metadata creation\ninline detail::coldef_view create_meta_r1_0()\n{\n    return meta_builder().type(column_type::tinyint).name(\"ftiny\").nullable(false).build_coldef();\n}\ninline detail::coldef_view create_meta_r1_1()\n{\n    return meta_builder().type(column_type::varchar).name(\"fvarchar\").nullable(false).build_coldef();\n}\ninline std::vector<detail::coldef_view> create_meta_r1()\n{\n    return {\n        create_meta_r1_0(),\n        create_meta_r1_1(),\n    };\n}\n\ninline detail::coldef_view create_meta_r2_0()\n{\n    return meta_builder().type(column_type::bigint).name(\"fbigint\").nullable(false).build_coldef();\n}\ninline std::vector<detail::coldef_view> create_meta_r2()\n{\n    return {\n        create_meta_r2_0(),\n    };\n}\n\ninline detail::coldef_view create_meta_r3_0()\n{\n    return meta_builder().type(column_type::float_).name(\"ffloat\").nullable(false).build_coldef();\n}\ninline detail::coldef_view create_meta_r3_1()\n{\n    return meta_builder().type(column_type::double_).name(\"fdouble\").nullable(false).build_coldef();\n}\ninline detail::coldef_view create_meta_r3_2()\n{\n    return meta_builder().type(column_type::tinyint).name(\"ftiny\").nullable(false).build_coldef();\n}\ninline std::vector<detail::coldef_view> create_meta_r3()\n{\n    return {\n        create_meta_r3_0(),\n        create_meta_r3_1(),\n        create_meta_r3_2(),\n    };\n}\n\n// Metadata checking\ninline void check_meta_r1(metadata_collection_view meta)\n{\n    check_meta(meta, {column_type::tinyint, column_type::varchar});\n}\n\ninline void check_meta_r2(metadata_collection_view meta) { check_meta(meta, {column_type::bigint}); }\n\ninline void check_meta_r3(metadata_collection_view meta)\n{\n    check_meta(meta, {column_type::float_, column_type::double_, column_type::tinyint});\n}\n\ninline void check_meta_empty(metadata_collection_view meta) { BOOST_TEST(meta.size() == 0u); }\n\n// OK packet creation\ninline detail::ok_view create_ok_r1(bool more_results = false)\n{\n    return ok_builder()\n        .affected_rows(1)\n        .last_insert_id(2)\n        .warnings(4)\n        .info(\"Information\")\n        .more_results(more_results)\n        .build();\n}\n\ninline detail::ok_view create_ok_r2(bool more_results = false)\n{\n    return ok_builder()\n        .affected_rows(5)\n        .last_insert_id(6)\n        .warnings(8)\n        .info(\"more_info\")\n        .more_results(more_results)\n        .out_params(true)\n        .build();\n}\n\ninline detail::ok_view create_ok_r3()\n{\n    return ok_builder().affected_rows(10).last_insert_id(11).warnings(12).info(\"\").build();\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/execution_processor/execution_state_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/execution_processor/execution_state_impl.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"execution_processor_helpers.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::mysql::detail::execution_state_impl;\nusing boost::mysql::detail::output_ref;\nusing boost::mysql::detail::resultset_encoding;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_execution_state_impl)\n\n// OK packet checking\nvoid check_ok_r1(const execution_state_impl& st)\n{\n    BOOST_TEST(st.get_affected_rows() == 1u);\n    BOOST_TEST(st.get_last_insert_id() == 2u);\n    BOOST_TEST(st.get_warning_count() == 4u);\n    BOOST_TEST(st.get_info() == \"Information\");\n    BOOST_TEST(st.get_is_out_params() == false);\n}\n\nvoid check_ok_r2(const execution_state_impl& st)\n{\n    BOOST_TEST(st.get_affected_rows() == 5u);\n    BOOST_TEST(st.get_last_insert_id() == 6u);\n    BOOST_TEST(st.get_warning_count() == 8u);\n    BOOST_TEST(st.get_info() == \"more_info\");\n    BOOST_TEST(st.get_is_out_params() == true);\n}\n\nvoid check_ok_r3(const execution_state_impl& st)\n{\n    BOOST_TEST(st.get_affected_rows() == 10u);\n    BOOST_TEST(st.get_last_insert_id() == 11u);\n    BOOST_TEST(st.get_warning_count() == 12u);\n    BOOST_TEST(st.get_info() == \"\");\n    BOOST_TEST(st.get_is_out_params() == false);\n}\n\nstruct fixture\n{\n    std::vector<field_view> fields;\n    execution_state_impl st;\n    boost::mysql::diagnostics diag;\n};\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_data, fixture)\n{\n    // Initial. Verify that we clear any previous result\n    exec_access(st)\n        .reset(resultset_encoding::binary)\n        .meta({column_type::geometry})\n        .ok(ok_builder().affected_rows(1).last_insert_id(2).warnings(3).more_results(true).info(\"abc\").build()\n        );\n\n    // Reset\n    st.reset(resultset_encoding::text, metadata_mode::full);\n    BOOST_TEST(st.is_reading_first());\n\n    // Head indicates resultset with metadata\n    st.on_num_meta(2);\n    BOOST_TEST(st.is_reading_meta());\n\n    // First metadata\n    auto err = st.on_meta(create_meta_r1_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Second metadata, ready to read rows\n    err = st.on_meta(create_meta_r1_1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r1(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(10, \"abc\");\n    auto r2 = create_text_row_body(20, \"cdef\");\n    err = st.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    err = st.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(fields == make_fv_vector(10, \"abc\", 20, \"cdef\"));\n\n    // End of resultset\n    err = st.on_row_ok_packet(create_ok_r1());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r1(st.meta());\n    check_ok_r1(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_empty, fixture)\n{\n    // Directly end of resultet, no meta\n    auto err = st.on_head_ok_packet(create_ok_r1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_empty(st.meta());\n    check_ok_r1(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_data, fixture)\n{\n    // Resultset r1 (rows are not stored anyhow in execution states)\n    add_meta(st, create_meta_r1());\n\n    // OK packet indicates more results\n    auto err = st.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_r1(st.meta());\n    check_ok_r1(st);\n\n    // Resultset r2: indicates resultset with meta\n    st.on_num_meta(1);\n    BOOST_TEST(st.is_reading_meta());\n\n    // First packet\n    err = st.on_meta(create_meta_r2_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r2(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(90u);\n    err = st.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST(fields == make_fv_vector(90u));\n\n    // OK packet, no more resultsets\n    err = st.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r2(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_data, fixture)\n{\n    // Resultset r1\n    add_ok(st, create_ok_r1(true));\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r1(st);\n\n    // Resultset r2: indicates data\n    st.on_num_meta(1);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Metadata packet\n    auto err = st.on_meta(create_meta_r2_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r2(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(90u);\n    auto r2 = create_text_row_body(100u);\n    err = st.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    err = st.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n\n    // Final OK packet\n    err = st.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r2(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_empty, fixture)\n{\n    // Resultset r1\n    add_meta(st, create_meta_r1());\n\n    // OK packet indicates more results\n    auto err = st.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_r1(st.meta());\n    check_ok_r1(st);\n\n    // OK packet for 2nd result\n    err = st.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_empty, fixture)\n{\n    // OK packet indicates more results\n    auto err = st.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r1(st);\n\n    // OK packet for 2nd result\n    err = st.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_empty_empty_data, fixture)\n{\n    // Two first resultsets\n    add_ok(st, create_ok_r1(true));\n    auto err = st.on_head_ok_packet(create_ok_r2(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n\n    // Resultset r3: head indicates resultset with metadata\n    st.on_num_meta(3);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Metadata\n    err = st.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_meta());\n\n    err = st.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_meta());\n\n    err = st.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r3(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(4.2f, 90.0, 9);\n    err = st.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST(fields == make_fv_vector(4.2f, 90.0, 9));\n\n    // End of resultset\n    err = st.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r3(st.meta());\n    check_ok_r3(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_data_empty_data, fixture)\n{\n    // Two first resultsets\n    exec_access(st).meta(create_meta_r1()).ok(create_ok_r1(true));\n    auto err = st.on_head_ok_packet(create_ok_r2(true), diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n\n    // Resultset r3: head indicates resultset with metadata\n    st.on_num_meta(3);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Metadata\n    err = st.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    err = st.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    err = st.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r3(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(4.2f, 90.0, 9);\n    err = st.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(fields == make_fv_vector(4.2f, 90.0, 9));\n\n    // End of resultset\n    err = st.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r3(st.meta());\n    check_ok_r3(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(info_string_ownserhip, fixture)\n{\n    // OK packet received, doesn't own the string\n    std::string info = \"Some info\";\n    auto err = st.on_head_ok_packet(ok_builder().more_results(true).info(info).build(), diag);\n    throw_on_error(err, diag);\n\n    // st does, so changing info doesn't affect\n    info = \"other info\";\n    BOOST_TEST(st.get_info() == \"Some info\");\n\n    // Repeat the process for row OK packet\n    st.on_num_meta(1);\n    err = st.on_meta(meta_builder().build_coldef(), diag);\n    throw_on_error(err, diag);\n    err = st.on_row_ok_packet(ok_builder().info(info).build());\n    throw_on_error(err, diag);\n    info = \"abcdfefgh\";\n    BOOST_TEST(st.get_info() == \"other info\");\n}\n\nBOOST_FIXTURE_TEST_CASE(error_deserializing_row, fixture)\n{\n    add_meta(st, create_meta_r1());\n    auto bad_row = create_text_row_body(42, \"abc\");\n    bad_row.push_back(0xff);\n\n    auto err = st.on_row(bad_row, output_ref(), fields);\n\n    BOOST_TEST(err == client_errc::extra_bytes);\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_minimal, fixture)\n{\n    st.reset(resultset_encoding::text, metadata_mode::minimal);\n    add_meta(st, create_meta_r1());\n    BOOST_TEST(st.meta()[0].column_name() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_full, fixture)\n{\n    st.reset(resultset_encoding::text, metadata_mode::full);\n    add_meta(st, create_meta_r1());\n    BOOST_TEST(st.meta()[0].column_name() == \"ftiny\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/execution_processor/results_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/execution_processor/results_impl.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"execution_processor_helpers.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::mysql::detail::output_ref;\nusing boost::mysql::detail::results_impl;\nusing boost::mysql::detail::resultset_container;\nusing boost::mysql::detail::resultset_encoding;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_results_impl)\n\n// OK packet checking\nvoid check_ok_r1(const results_impl& st, std::size_t idx)\n{\n    BOOST_TEST(st.get_affected_rows(idx) == 1u);\n    BOOST_TEST(st.get_last_insert_id(idx) == 2u);\n    BOOST_TEST(st.get_warning_count(idx) == 4u);\n    BOOST_TEST(st.get_info(idx) == \"Information\");\n    BOOST_TEST(st.get_is_out_params(idx) == false);\n}\n\nvoid check_ok_r2(const results_impl& st, std::size_t idx)\n{\n    BOOST_TEST(st.get_affected_rows(idx) == 5u);\n    BOOST_TEST(st.get_last_insert_id(idx) == 6u);\n    BOOST_TEST(st.get_warning_count(idx) == 8u);\n    BOOST_TEST(st.get_info(idx) == \"more_info\");\n    BOOST_TEST(st.get_is_out_params(idx) == true);\n}\n\nvoid check_ok_r3(const results_impl& st, std::size_t idx)\n{\n    BOOST_TEST(st.get_affected_rows(idx) == 10u);\n    BOOST_TEST(st.get_last_insert_id(idx) == 11u);\n    BOOST_TEST(st.get_warning_count(idx) == 12u);\n    BOOST_TEST(st.get_info(idx) == \"\");\n    BOOST_TEST(st.get_is_out_params(idx) == false);\n}\n\nBOOST_AUTO_TEST_SUITE(resultset_container_)\nBOOST_AUTO_TEST_CASE(append_from_empty)\n{\n    // Initial\n    resultset_container c;\n    BOOST_TEST(c.empty());\n    BOOST_TEST(c.size() == 0u);\n\n    // Append first\n    c.emplace_back().num_rows = 1;\n    BOOST_TEST(!c.empty());\n    BOOST_TEST(c.size() == 1u);\n    BOOST_TEST(c[0].num_rows == 1u);\n    BOOST_TEST(c.back().num_rows == 1u);\n\n    // Append second\n    c.emplace_back().num_rows = 2;\n    BOOST_TEST(!c.empty());\n    BOOST_TEST(c.size() == 2u);\n    BOOST_TEST(c[0].num_rows == 1u);\n    BOOST_TEST(c[1].num_rows == 2u);\n    BOOST_TEST(c.back().num_rows == 2u);\n\n    // Append third\n    c.emplace_back().num_rows = 3;\n    BOOST_TEST(!c.empty());\n    BOOST_TEST(c.size() == 3u);\n    BOOST_TEST(c[0].num_rows == 1u);\n    BOOST_TEST(c[1].num_rows == 2u);\n    BOOST_TEST(c[2].num_rows == 3u);\n    BOOST_TEST(c.back().num_rows == 3u);\n}\n\nBOOST_AUTO_TEST_CASE(append_from_cleared)\n{\n    // Initial\n    resultset_container c;\n    c.emplace_back().num_rows = 42u;\n    c.emplace_back().num_rows = 43u;\n\n    // Clear\n    c.clear();\n    BOOST_TEST(c.empty());\n    BOOST_TEST(c.size() == 0u);\n\n    // Append first\n    c.emplace_back().num_rows = 1;\n    BOOST_TEST(!c.empty());\n    BOOST_TEST(c.size() == 1u);\n    BOOST_TEST(c[0].num_rows == 1u);\n    BOOST_TEST(c.back().num_rows == 1u);\n\n    // Append second\n    c.emplace_back().num_rows = 2;\n    BOOST_TEST(!c.empty());\n    BOOST_TEST(c.size() == 2u);\n    BOOST_TEST(c[0].num_rows == 1u);\n    BOOST_TEST(c[1].num_rows == 2u);\n    BOOST_TEST(c.back().num_rows == 2u);\n\n    // Append third\n    c.emplace_back().num_rows = 3;\n    BOOST_TEST(!c.empty());\n    BOOST_TEST(c.size() == 3u);\n    BOOST_TEST(c[0].num_rows == 1u);\n    BOOST_TEST(c[1].num_rows == 2u);\n    BOOST_TEST(c[2].num_rows == 3u);\n    BOOST_TEST(c.back().num_rows == 3u);\n}\n\nBOOST_AUTO_TEST_CASE(clear_empty)\n{\n    // Initial\n    resultset_container c;\n    c.clear();\n    BOOST_TEST(c.empty());\n    BOOST_TEST(c.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(several_clears)\n{\n    // Initial\n    resultset_container c;\n    c.emplace_back().num_rows = 42u;\n\n    // Clear\n    c.clear();\n    BOOST_TEST(c.empty());\n    BOOST_TEST(c.size() == 0u);\n\n    // Append again\n    c.emplace_back().num_rows = 1;\n    c.emplace_back().num_rows = 2;\n\n    // Clear again\n    c.clear();\n    BOOST_TEST(c.empty());\n    BOOST_TEST(c.size() == 0u);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nstruct fixture\n{\n    diagnostics diag;\n    std::vector<field_view> fields;\n    results_impl r;\n};\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_data, fixture)\n{\n    // Initial. Check that we reset any previous state\n    exec_access(r)\n        .meta({column_type::geometry})\n        .row(makebv(\"\\0\\0\"))\n        .row(makebv(\"abc\"))\n        .ok(ok_builder().affected_rows(40).info(\"some_info\").more_results(true).build())\n        .meta({column_type::varchar, column_type::mediumint})\n        .row(\"aaaa\", 42)\n        .ok(ok_builder().info(\"more_info\").more_results(true).build());\n    r.reset(resultset_encoding::text, metadata_mode::minimal);\n    BOOST_TEST(r.is_reading_first());\n\n    // Head indicates resultset with two columns\n    r.on_num_meta(2);\n    BOOST_TEST(r.is_reading_meta());\n\n    // First meta\n    auto err = r.on_meta(create_meta_r1_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Second meta, ready to read rows\n    err = r.on_meta(create_meta_r1_1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Rows\n    auto r1 = create_text_row_body(42, \"abc\");\n    r.on_row_batch_start();\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // End of resultset\n    err = r.on_row_ok_packet(create_ok_r1());\n    throw_on_error(err, diag);\n    r.on_row_batch_finish();  // EOF is part of the batch\n\n    // Verify results\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_ok_r1(r, 0);\n    BOOST_TEST(r.num_resultsets() == 1u);\n    BOOST_TEST(r.get_rows(0) == makerows(2, 42, \"abc\"));\n    BOOST_TEST(r.get_out_params() == row_view());\n    BOOST_TEST(fields.empty());  // unused\n}\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_empty, fixture)\n{\n    // Initial\n    BOOST_TEST(r.is_reading_first());\n\n    // End of resultset\n    auto err = r.on_head_ok_packet(create_ok_r1(), diag);\n    throw_on_error(err, diag);\n\n    // verify\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_ok_r1(r, 0);\n    BOOST_TEST(r.num_resultsets() == 1u);\n    BOOST_TEST(r.get_rows(0) == rows_view());\n    BOOST_TEST(r.get_out_params() == row_view());\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_data, fixture)\n{\n    // Resultset r1\n    exec_access(r).meta(create_meta_r1()).row(42, \"abc\").row(50, \"def\");\n\n    // OK packet indicates more results\n    auto err = r.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // Resultset r2: indicates resultset with meta\n    r.on_num_meta(1);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Meta\n    err = r.on_meta(create_meta_r2_0(), diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Row\n    auto r1 = create_text_row_body(70);\n    r.on_row_batch_start();\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n\n    // OK packet, no more resultsets\n    err = r.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n    r.on_row_batch_finish();\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    BOOST_TEST(r.num_resultsets() == 2u);\n    BOOST_TEST(r.get_rows(0) == makerows(2, 42, \"abc\", 50, \"def\"));\n    BOOST_TEST(r.get_rows(1) == makerows(1, 70));\n    BOOST_TEST(r.get_out_params() == makerow(70));\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_data, fixture)\n{\n    // Empty resultset r1, indicating more results\n    auto err = r.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // Resultset r2: indicates data\n    r.on_num_meta(1);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Metadata packet\n    err = r.on_meta(create_meta_r2_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Rows\n    auto r1 = create_text_row_body(70);\n    r.on_row_batch_start();\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Final OK packet\n    err = r.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n    r.on_row_batch_finish();\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    BOOST_TEST(r.num_resultsets() == 2u);\n    BOOST_TEST(r.get_rows(0) == rows_view());\n    BOOST_TEST(r.get_rows(1) == makerows(1, 70));\n    BOOST_TEST(r.get_out_params() == makerow(70));\n}\n\n// Note: this tests also an edge case where a resultset indicates\n// that contains OUT parameters but is empty\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_empty, fixture)\n{\n    // Resultset r1\n    exec_access(r).meta(create_meta_r1()).row(42, \"abc\").row(50, \"def\");\n\n    // OK packet indicates more results\n    auto err = r.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // OK packet for 2nd result\n    err = r.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_empty(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    BOOST_TEST(r.num_resultsets() == 2u);\n    BOOST_TEST(r.get_rows(0) == makerows(2, 42, \"abc\", 50, \"def\"));\n    BOOST_TEST(r.get_rows(1) == rows_view());\n    BOOST_TEST(r.get_out_params() == row_view());\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_empty, fixture)\n{\n    // Resultset r1\n    auto err = r.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // OK packet for 2nd result\n    err = r.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_meta_empty(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    BOOST_TEST(r.num_resultsets() == 2u);\n    BOOST_TEST(r.get_rows(0) == rows_view());\n    BOOST_TEST(r.get_rows(1) == rows_view());\n    BOOST_TEST(r.get_out_params() == row_view());\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_empty_empty_data, fixture)\n{\n    // First resultset\n    add_ok(r, create_ok_r1(true));\n\n    // Second resultset: OK packet indicates more results\n    auto err = r.on_head_ok_packet(create_ok_r2(true), diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // Resultset r3: head indicates resultset with metadata\n    r.on_num_meta(3);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Metadata\n    err = r.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Read rows\n    auto r1 = create_text_row_body(4.2f, 5.0, 8);\n    auto r2 = create_text_row_body(42.0f, 50.0, 80);\n    r.on_row_batch_start();\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    err = r.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n\n    // End of resultset\n    err = r.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n    r.on_row_batch_finish();\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_meta_empty(r.get_meta(1));\n    check_meta_r3(r.get_meta(2));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_ok_r3(r, 2);\n    BOOST_TEST(r.num_resultsets() == 3u);\n    BOOST_TEST(r.get_rows(0) == rows_view());\n    BOOST_TEST(r.get_rows(1) == rows_view());\n    BOOST_TEST(r.get_rows(2) == makerows(3, 4.2f, 5.0, 8, 42.0f, 50.0, 80));\n    BOOST_TEST(r.get_out_params() == row_view());\n}\n\n// Verify that we do row slicing correctly\nBOOST_FIXTURE_TEST_CASE(three_resultsets_data_data_data, fixture)\n{\n    // Two first resultets\n    exec_access(r)\n        .meta(create_meta_r1())\n        .row(42, \"abc\")\n        .row(50, \"def\")\n        .ok(create_ok_r1(true))\n        .meta(create_meta_r2())\n        .row(60);\n\n    // OK packet indicates more results\n    auto err = r.on_row_ok_packet(create_ok_r2(true));\n    throw_on_error(err, diag);\n\n    // Third resultset meta\n    r.on_num_meta(3);\n    err = r.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n\n    // Rows\n    auto r1 = create_text_row_body(4.2f, 5.0, 8);\n    auto r2 = create_text_row_body(42.0f, 50.0, 80);\n    r.on_row_batch_start();\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    err = r.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n    r.on_row_batch_finish();\n\n    // OK packet\n    err = r.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n\n    // Check results\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_meta_r3(r.get_meta(2));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_ok_r3(r, 2);\n    BOOST_TEST(r.num_resultsets() == 3u);\n    BOOST_TEST(r.get_rows(0) == makerows(2, 42, \"abc\", 50, \"def\"));\n    BOOST_TEST(r.get_rows(1) == makerows(1, 60));\n    BOOST_TEST(r.get_rows(2) == makerows(3, 4.2f, 5.0, 8, 42.0f, 50.0, 80));\n    BOOST_TEST(r.get_out_params() == makerow(60));\n}\n\nBOOST_FIXTURE_TEST_CASE(info_string_ownserhip, fixture)\n{\n    // Head OK packet\n    std::string info = \"Some info\";\n    auto err = r.on_head_ok_packet(ok_builder().more_results(true).info(info).build(), diag);\n    throw_on_error(err, diag);\n\n    // Empty OK packet\n    info = \"\";\n    err = r.on_head_ok_packet(ok_builder().more_results(true).info(info).build(), diag);\n\n    // Row OK packet\n    info = \"other info\";\n    add_meta(r, create_meta_r2());\n    err = r.on_row_ok_packet(ok_builder().info(info).build());\n    info = \"abcdfefgh\";\n    BOOST_TEST(r.get_info(0) == \"Some info\");\n    BOOST_TEST(r.get_info(1) == \"\");\n    BOOST_TEST(r.get_info(2) == \"other info\");\n}\n\nBOOST_FIXTURE_TEST_CASE(multiple_row_batches, fixture)\n{\n    // Initial\n    add_meta(r, create_meta_r1());\n\n    // Buffers\n    auto r1 = create_text_row_body(42, \"abc\");\n    auto r2 = create_text_row_body(50, \"bdef\");\n    auto r3 = create_text_row_body(60, \"pov\");\n\n    // First batch\n    r.on_row_batch_start();\n    auto err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err);\n    err = r.on_row(r2, output_ref(), fields);\n    throw_on_error(err);\n    r.on_row_batch_finish();\n\n    // Second batch (only one row)\n    r.on_row_batch_start();\n    err = r.on_row(r3, output_ref(), fields);\n    throw_on_error(err);\n\n    // End of resultset\n    err = r.on_row_ok_packet(create_ok_r1());\n    throw_on_error(err);\n    r.on_row_batch_finish();\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    BOOST_TEST(r.num_resultsets() == 1u);\n    BOOST_TEST(r.get_rows(0) == makerows(2, 42, \"abc\", 50, \"bdef\", 60, \"pov\"));\n}\n\nBOOST_FIXTURE_TEST_CASE(empty_row_batch, fixture)\n{\n    // Initial\n    add_meta(r, create_meta_r1());\n\n    // No rows, directly eof\n    r.on_row_batch_start();\n    auto err = r.on_row_ok_packet(create_ok_r1());\n    throw_on_error(err);\n    r.on_row_batch_finish();\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    BOOST_TEST(r.num_resultsets() == 1u);\n    BOOST_TEST(r.get_rows(0) == makerows(2));  // empty but with 2 cols\n}\n\nBOOST_FIXTURE_TEST_CASE(error_deserializing_row, fixture)\n{\n    add_meta(r, create_meta_r1());\n    auto bad_row = create_text_row_body(42, \"abc\");\n    bad_row.push_back(0xff);\n\n    r.on_row_batch_start();\n    auto err = r.on_row(bad_row, output_ref(), fields);\n    r.on_row_batch_finish();\n\n    BOOST_TEST(err == client_errc::extra_bytes);\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_minimal, fixture)\n{\n    exec_access(r)\n        .reset(resultset_encoding::text, metadata_mode::minimal)\n        .meta(create_meta_r1())\n        .ok(create_ok_r1());\n\n    BOOST_TEST(r.get_meta(0)[0].column_name() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_full, fixture)\n{\n    exec_access(r)\n        .reset(resultset_encoding::text, metadata_mode::full)\n        .meta(create_meta_r1())\n        .ok(create_ok_r1());\n\n    BOOST_TEST(r.get_meta(0)[0].column_name() == \"ftiny\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/execution_processor/static_execution_processor_helpers.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_EXECUTION_PROCESSOR_STATIC_EXECUTION_PROCESSOR_HELPERS_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_EXECUTION_PROCESSOR_STATIC_EXECUTION_PROCESSOR_HELPERS_HPP\n\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/metadata_collection_view.hpp>\n\n#include <boost/describe/class.hpp>\n#include <boost/describe/operators.hpp>\n\n// Throughout execution_processor tests we use a set of common values for rows.\n// Definitions here to reduce duplication\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Row types\nstruct row1\n{\n    std::string fvarchar;\n    std::int16_t ftiny;\n};\nBOOST_DESCRIBE_STRUCT(row1, (), (fvarchar, ftiny))\n\nusing row1_tuple = std::tuple<std::int16_t, std::string>;\n\nstruct row2\n{\n    std::int64_t fbigint;\n};\nBOOST_DESCRIBE_STRUCT(row2, (), (fbigint))\n\nusing row2_tuple = std::tuple<std::int64_t>;\n\n// This is doing field reordering by name\nstruct row3\n{\n    double fdouble;\n    std::int8_t ftiny;\n    float ffloat;\n};\nBOOST_DESCRIBE_STRUCT(row3, (), (fdouble, ftiny, ffloat))\n\nusing row3_tuple = std::tuple<float, double, std::int8_t>;\n\nstruct empty\n{\n};\nBOOST_DESCRIBE_STRUCT(empty, (), ())\n\n// For tests verifying that field selection works\nstruct row3_selection\n{\n    std::int8_t ftiny;\n    float ffloat;\n};\nBOOST_DESCRIBE_STRUCT(row3_selection, (), (ftiny, ffloat))\nusing row3_selection_tuple = std::tuple<float, double>;\n\n#ifdef BOOST_DESCRIBE_CXX14\nusing boost::describe::operators::operator==;\nusing boost::describe::operators::operator<<;\n#endif\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/execution_processor/static_execution_state_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/execution_processor/static_execution_state_impl.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"execution_processor_helpers.hpp\"\n#include \"static_execution_processor_helpers.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/printing.hpp\"\n#include \"test_unit/row_identity.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::mysql::detail::static_execution_state_impl;\nusing detail::resultset_encoding;\nusing detail::static_execution_state_erased_impl;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_static_execution_state_impl)\n\n// OK packet data checking\nvoid check_ok_r1(const static_execution_state_erased_impl& st)\n{\n    BOOST_TEST(st.get_affected_rows() == 1u);\n    BOOST_TEST(st.get_last_insert_id() == 2u);\n    BOOST_TEST(st.get_warning_count() == 4u);\n    BOOST_TEST(st.get_info() == \"Information\");\n    BOOST_TEST(st.get_is_out_params() == false);\n}\n\nvoid check_ok_r2(const static_execution_state_erased_impl& st)\n{\n    BOOST_TEST(st.get_affected_rows() == 5u);\n    BOOST_TEST(st.get_last_insert_id() == 6u);\n    BOOST_TEST(st.get_warning_count() == 8u);\n    BOOST_TEST(st.get_info() == \"more_info\");\n    BOOST_TEST(st.get_is_out_params() == true);\n}\n\nvoid check_ok_r3(const static_execution_state_erased_impl& st)\n{\n    BOOST_TEST(st.get_affected_rows() == 10u);\n    BOOST_TEST(st.get_last_insert_id() == 11u);\n    BOOST_TEST(st.get_warning_count() == 12u);\n    BOOST_TEST(st.get_info() == \"\");\n    BOOST_TEST(st.get_is_out_params() == false);\n}\n\nstruct fixture\n{\n    diagnostics diag;\n    std::vector<field_view> fields;\n};\n\n// We use row_identity to make sure we use underlying_row_t when required\ntemplate <class... StaticRow>\nusing static_execst_t = static_execution_state_impl<row_identity<StaticRow>...>;\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_data, fixture)\n{\n    // Initial. Verify that we clear any previous result\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n    exec_access(st)\n        .reset(resultset_encoding::binary)\n        .meta({\n            meta_builder().type(column_type::smallint).name(\"ftiny\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::text).name(\"fvarchar\").nullable(false).build_coldef(),\n        })\n        .ok(ok_builder().affected_rows(1).last_insert_id(2).warnings(3).info(\"abc\").build());\n\n    // Reset\n    st.reset(resultset_encoding::text, metadata_mode::full);\n    BOOST_TEST(st.is_reading_first());\n\n    // Head indicates resultset with metadata\n    st.on_num_meta(2);\n    BOOST_TEST(st.is_reading_meta());\n\n    // First metadata\n    auto err = st.on_meta(create_meta_r1_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Second metadata, ready to read rows\n    err = st.on_meta(create_meta_r1_1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r1(st.meta());\n\n    // Rows\n    row1 storage[2]{};\n    auto r1 = create_text_row_body(10, \"abc\");\n    auto r2 = create_text_row_body(20, \"cdef\");\n\n    err = st.on_row(r1, stp.make_output_ref(span<row1>(storage), 0), fields);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST((storage[0] == row1{\"abc\", 10}));\n    BOOST_TEST(storage[1] == row1{});\n\n    err = st.on_row(r2, stp.make_output_ref(span<row1>(storage), 1), fields);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST((storage[0] == row1{\"abc\", 10}));\n    BOOST_TEST((storage[1] == row1{\"cdef\", 20}));\n\n    // End of resultset\n    err = st.on_row_ok_packet(create_ok_r1());\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(st.is_complete());\n    check_meta_r1(st.meta());\n    check_ok_r1(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_empty, fixture)\n{\n    static_execst_t<empty> stp;\n    auto& st = stp.get_interface();\n\n    auto err = st.on_head_ok_packet(create_ok_r1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_empty(st.meta());\n    check_ok_r1(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_data, fixture)\n{\n    // Resultset r1 (rows are not stored anyhow in execution states)\n    static_execst_t<row1, row2> stp;\n    auto& st = stp.get_interface();\n    exec_access(st).reset(resultset_encoding::text).meta(create_meta_r1());\n\n    // OK packet indicates more results\n    auto err = st.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_r1(st.meta());\n    check_ok_r1(st);\n\n    // Resultset r2: indicates resultset with meta\n    st.on_num_meta(1);\n    BOOST_TEST(st.is_reading_meta());\n\n    // First packet\n    err = st.on_meta(create_meta_r2_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r2(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(90u);\n    row2 storage[2]{};\n    err = st.on_row(r1, stp.make_output_ref(span<row2>(storage), 0), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST(storage[0] == row2{90u});\n    BOOST_TEST(storage[1] == row2{});\n\n    // OK packet, no more resultsets\n    err = st.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r2(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_data, fixture)\n{\n    static_execst_t<empty, row2> stp;\n    auto& st = stp.get_interface();\n\n    // Resultset r1\n    auto err = st.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r1(st);\n\n    // Resultset r2: indicates data\n    st.on_num_meta(1);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Metadata packet\n    err = st.on_meta(create_meta_r2_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r2(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(90u);\n    auto r2 = create_text_row_body(100u);\n    row2 storage[2]{};\n    err = st.on_row(r1, stp.make_output_ref(span<row2>(storage), 0), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST(storage[0] == row2{90u});\n    BOOST_TEST(storage[1] == row2{});\n\n    err = st.on_row(r2, stp.make_output_ref(span<row2>(storage), 1), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST(storage[0] == row2{90u});\n    BOOST_TEST(storage[1] == row2{100u});\n\n    // Final OK packet\n    err = st.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r2(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_empty, fixture)\n{\n    // Resultset r1\n    static_execst_t<row1, empty> stp;\n    auto& st = stp.get_interface();\n    exec_access(st).reset(resultset_encoding::text).meta(create_meta_r1());\n\n    // OK packet indicates more results\n    auto err = st.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_r1(st.meta());\n    check_ok_r1(st);\n\n    // OK packet for 2nd result\n    err = st.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_empty, fixture)\n{\n    static_execst_t<empty, empty> stp;\n    auto& st = stp.get_interface();\n\n    // OK packet indicates more results\n    auto err = st.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r1(st);\n\n    // OK packet for 2nd result\n    err = st.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_empty_empty_data, fixture)\n{\n    // First resultset\n    static_execst_t<empty, empty, row3> stp;\n    auto& st = stp.get_interface();\n    add_ok(st, create_ok_r1(true));\n\n    // OK packet for second resultset indicates more results\n    auto err = st.on_head_ok_packet(create_ok_r2(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n\n    // Resultset r3: head indicates resultset with metadata\n    st.on_num_meta(3);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Metadata\n    err = st.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_meta());\n\n    err = st.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_meta());\n\n    err = st.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r3(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(4.2f, 90.0, 9);\n    row3 storage[1]{};\n    err = st.on_row(r1, stp.make_output_ref(span<row3>(storage), 0), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    BOOST_TEST((storage[0] == row3{90.0, 9, 4.2f}));\n\n    // End of resultset\n    err = st.on_row_ok_packet(create_ok_r3());\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(st.is_complete());\n    check_meta_r3(st.meta());\n    check_ok_r3(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_data_empty_data, fixture)\n{\n    // First resultset\n    static_execst_t<row1, empty, row3> stp;\n    auto& st = stp.get_interface();\n    exec_access(st).meta(create_meta_r1()).ok(create_ok_r1(true));\n\n    // OK packet indicates more results\n    auto err = st.on_head_ok_packet(create_ok_r2(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_first_subseq());\n    check_meta_empty(st.meta());\n    check_ok_r2(st);\n\n    // Resultset r3: head indicates resultset with metadata\n    st.on_num_meta(3);\n    BOOST_TEST(st.is_reading_meta());\n\n    // Metadata\n    err = st.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n\n    err = st.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n\n    err = st.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_reading_rows());\n    check_meta_r3(st.meta());\n\n    // Rows\n    auto r1 = create_text_row_body(4.2f, 90.0, 9);\n    row3 storage[1]{};\n    err = st.on_row(r1, stp.make_output_ref(span<row3>(storage), 0), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST((storage[0] == row3{90.0, 9, 4.2f}));\n\n    // End of resultset\n    err = st.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n    BOOST_TEST(st.is_complete());\n    check_meta_r3(st.meta());\n    check_ok_r3(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(info_string_ownserhip_head_ok, fixture)\n{\n    static_execst_t<empty> stp;\n    auto& st = stp.get_interface();\n\n    // OK packet received, doesn't own the string\n    std::string info = \"Some info\";\n    auto err = st.on_head_ok_packet(ok_builder().info(info).build(), diag);\n    throw_on_error(err, diag);\n\n    // st does, so changing info doesn't affect\n    info = \"other info\";\n    BOOST_TEST(st.get_info() == \"Some info\");\n}\n\nBOOST_FIXTURE_TEST_CASE(info_string_ownserhip_row_ok, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n\n    // OK packet received, doesn't own the string\n    std::string info = \"Some info\";\n    auto err = st.on_row_ok_packet(ok_builder().info(info).build());\n    throw_on_error(err, diag);\n\n    // st does, so changing info doesn't affect\n    info = \"abcdfefgh\";\n    BOOST_TEST(st.get_info() == \"Some info\");\n}\n\nBOOST_FIXTURE_TEST_CASE(repeated_row_types, fixture)\n{\n    // Ready to read rows\n    static_execst_t<row1, row1> stp;\n    auto& st = stp.get_interface();\n    exec_access(st).meta(create_meta_r1()).ok(create_ok_r1(true)).meta(create_meta_r1());\n\n    // Rows use type index 0, since they're the same type as resultset one's rows\n    auto r1 = create_text_row_body(10, \"abc\");\n    row1 storage[1]{};\n    auto err = st.on_row(r1, stp.make_output_ref(span<row1>(storage), 0), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST((storage[0] == row1{\"abc\", 10}));\n}\n\n// Verify that we clear the fields before adding new ones\nBOOST_FIXTURE_TEST_CASE(storage_reuse, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n\n    // Rows\n    auto r1 = create_text_row_body(42, \"abc\");\n    auto r2 = create_text_row_body(43, \"def\");\n    row1 storage[2]{};\n    auto err = st.on_row(r1, stp.make_output_ref(span<row1>(storage), 0), fields);\n    throw_on_error(err, diag);\n    err = st.on_row(r2, stp.make_output_ref(span<row1>(storage), 1), fields);\n    throw_on_error(err, diag);\n\n    // Verify results\n    BOOST_TEST((storage[0] == row1{\"abc\", 42}));\n    BOOST_TEST((storage[1] == row1{\"def\", 43}));\n    BOOST_TEST(fields.size() == 2u);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_meta_mismatch, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n\n    st.on_num_meta(1);\n    auto err = st.on_meta(\n        meta_builder().type(column_type::bigint).name(\"fvarchar\").nullable(false).build_coldef(),\n        diag\n    );\n\n    const char* expected_msg =\n        \"Incompatible types for field 'fvarchar': C++ type 'string' is not compatible with DB type 'BIGINT'\\n\"\n        \"Field 'ftiny' is not present in the data returned by the server\";\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_meta_mismatch_head, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n\n    auto err = st.on_head_ok_packet(create_ok_r1(), diag);\n    const char* expected_msg =\n        \"Field 'fvarchar' is not present in the data returned by the server\\n\"\n        \"Field 'ftiny' is not present in the data returned by the server\";\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_deserializing_row, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n    auto bad_row = create_text_row_body(42, \"abc\");\n    bad_row.push_back(0xff);\n\n    row1 storage[1]{};\n    auto err = st.on_row(bad_row, stp.make_output_ref(span<row1>(storage), 0), fields);\n    BOOST_TEST(err == client_errc::extra_bytes);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_parsing_row, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n    auto bad_row = create_text_row_body(nullptr, \"abc\");  // should not be NULL\n\n    row1 storage[1]{};\n    auto err = st.on_row(bad_row, stp.make_output_ref(span<row1>(storage), 0), fields);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_type_index_mismatch, fixture)\n{\n    static_execst_t<row1, row2> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n    auto r1 = create_text_row_body(42, \"abc\");\n\n    row2 storage[1]{};\n    auto err = st.on_row(r1, stp.make_output_ref(span<row2>(storage), 0), fields);\n    BOOST_TEST(err == client_errc::row_type_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_few_resultsets_empty, fixture)\n{\n    static_execst_t<empty, row2> stp;\n    auto& st = stp.get_interface();\n\n    auto err = st.on_head_ok_packet(create_ok_r1(), diag);\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_many_resultsets_empty, fixture)\n{\n    static_execst_t<empty> stp;\n    auto& st = stp.get_interface();\n\n    auto err = st.on_head_ok_packet(create_ok_r1(true), diag);\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_few_resultsets_data, fixture)\n{\n    static_execst_t<row1, row2> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n\n    auto err = st.on_row_ok_packet(create_ok_r1());\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_many_resultsets_data, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n    add_meta(st, create_meta_r1());\n\n    auto err = st.on_row_ok_packet(create_ok_r1(true));\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nstruct ctor_assign_fixture\n{\n    // Using row3 because it has more fields, to verify pos_map\n    using st_t = static_execst_t<row1, row3>;\n\n    std::unique_ptr<st_t> stp_old{new st_t{}};\n\n    ctor_assign_fixture()\n    {\n        // Create and populate an object. Having it in the heap should make it easier to detect dangling\n        // pointers\n        add_meta(stp_old->get_interface(), create_meta_r1());\n        add_ok(stp_old->get_interface(), create_ok_r1(true));\n    }\n\n    // Checks that we correctly performed the copy/move, and that the object works\n    // without dangling parts\n    static void check_object(st_t& stp)\n    {\n        auto& st = stp.get_interface();\n\n        // Data has been copied\n        BOOST_TEST(st.is_reading_first_subseq());\n        check_meta_r1(st.meta());\n        check_ok_r1(st);\n\n        // External data (pos_map and fields) does not dangle\n        add_meta(st, create_meta_r3());\n        check_meta_r3(st.meta());\n\n        auto r1 = create_text_row_body(4.2f, 90.0, 9);\n        row3 storage[1]{};\n        std::vector<field_view> fields;\n        auto err = st.on_row(r1, stp.make_output_ref(span<row3>(storage), 0), fields);\n        BOOST_TEST(err == error_code());\n        BOOST_TEST((storage[0] == row3{90.0, 9, 4.2f}));\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE(copy_ctor, ctor_assign_fixture)\n{\n    // Copy construct\n    st_t stp{*stp_old};\n    stp_old.reset();\n\n    // Check\n    check_object(stp);\n}\n\nBOOST_FIXTURE_TEST_CASE(move_ctor, ctor_assign_fixture)\n{\n    // Move construct\n    st_t stp{std::move(*stp_old)};\n    stp_old.reset();\n\n    // Check\n    check_object(stp);\n}\n\nBOOST_FIXTURE_TEST_CASE(copy_assignment, ctor_assign_fixture)\n{\n    // Create and populate the object we'll assign to\n    st_t stp;\n    add_meta(\n        stp.get_interface(),\n        {\n            meta_builder().type(column_type::smallint).name(\"ftiny\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::text).name(\"fvarchar\").nullable(false).build_coldef(),\n        }\n    );\n\n    // Assign\n    stp = *stp_old;\n    stp_old.reset();\n\n    // Check\n    check_object(stp);\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assignment, ctor_assign_fixture)\n{\n    // Create and populate the object we'll assign to\n    st_t stp;\n    add_meta(\n        stp.get_interface(),\n        {\n            meta_builder().type(column_type::smallint).name(\"ftiny\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::text).name(\"fvarchar\").nullable(false).build_coldef(),\n        }\n    );\n\n    // Assign\n    stp = std::move(*stp_old);\n    stp_old.reset();\n\n    // Check\n    check_object(stp);\n}\n\n// Regression checks\nBOOST_AUTO_TEST_CASE(tuples)\n{\n    std::vector<field_view> fields;\n    static_execst_t<row1_tuple, std::tuple<>, row3_tuple> stp;\n    auto& st = stp.get_interface();\n\n    // Meta r1\n    add_meta(st, create_meta_r1());\n\n    // Rows r1\n    row1_tuple storage_1[2]{};\n    auto r1 = create_text_row_body(10, \"abc\");\n    auto err = st.on_row(r1, stp.make_output_ref(span<row1_tuple>(storage_1), 0), fields);\n    throw_on_error(err);\n    BOOST_TEST((storage_1[0] == row1_tuple{std::uint16_t(10), \"abc\"}));\n\n    // EOF r1\n    add_ok(st, create_ok_r1(true));\n    check_ok_r1(st);\n\n    // EOF r2\n    add_ok(st, create_ok_r2(true));\n    check_ok_r2(st);\n\n    // Meta r3\n    add_meta(st, create_meta_r3());\n\n    // Rows r3\n    row3_tuple storage_3[2]{};\n    auto r3 = create_text_row_body(4.2f, 90.0, 9);\n    err = st.on_row(r3, stp.make_output_ref(span<row3_tuple>(storage_3), 0), fields);\n    throw_on_error(err);\n    BOOST_TEST((storage_3[0] == row3_tuple{4.2f, 90.0, std::uint8_t(9)}));\n\n    // OK r3\n    add_ok(st, create_ok_r3());\n    check_ok_r3(st);\n}\n\nBOOST_AUTO_TEST_CASE(field_selection_structs)\n{\n    std::vector<field_view> fields;\n    static_execst_t<row3_selection> stp;\n    auto& st = stp.get_interface();\n\n    // Meta\n    add_meta(st, create_meta_r3());\n\n    // Rows\n    row3_selection storage[1]{};\n    auto r1 = create_text_row_body(4.2f, 90.0, 9);\n    auto err = st.on_row(r1, stp.make_output_ref(span<row3_selection>(storage), 0), fields);\n    throw_on_error(err);\n    BOOST_TEST((storage[0] == row3_selection{9, 4.2f}));\n\n    // EOF\n    add_ok(st, create_ok_r3());\n    check_ok_r3(st);\n}\n\nBOOST_AUTO_TEST_CASE(field_selection_tuples)\n{\n    std::vector<field_view> fields;\n    static_execst_t<row3_selection_tuple> stp;\n    auto& st = stp.get_interface();\n\n    // Meta\n    add_meta(st, create_meta_r3());\n\n    // Rows\n    row3_selection_tuple storage[1]{};\n    auto r1 = create_text_row_body(4.2f, 90.0, 9);\n    auto err = st.on_row(r1, stp.make_output_ref(span<row3_selection_tuple>(storage), 0), fields);\n    throw_on_error(err);\n    BOOST_TEST((storage[0] == row3_selection_tuple{4.2f, 90.0}));\n\n    // EOF\n    add_ok(st, create_ok_r3());\n    check_ok_r3(st);\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_minimal, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n\n    st.reset(resultset_encoding::text, metadata_mode::minimal);\n    add_meta(st, create_meta_r1());\n    BOOST_TEST(st.meta()[0].column_name() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_full, fixture)\n{\n    static_execst_t<row1> stp;\n    auto& st = stp.get_interface();\n\n    st.reset(resultset_encoding::text, metadata_mode::full);\n    add_meta(st, create_meta_r1());\n    BOOST_TEST(st.meta()[0].column_name() == \"ftiny\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n\n#endif\n"
  },
  {
    "path": "test/unit/test/execution_processor/static_results_impl.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/execution_processor/static_results_impl.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"execution_processor_helpers.hpp\"\n#include \"static_execution_processor_helpers.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/printing.hpp\"\n#include \"test_unit/row_identity.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing detail::output_ref;\nusing detail::resultset_encoding;\nusing detail::static_results_erased_impl;\nusing detail::static_results_impl;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_static_results_impl)\n\n// Row checking\ntemplate <class T>\nvoid check_rows(boost::span<const T> actual, const std::vector<T>& expected)\n{\n    std::vector<T> actualv(actual.begin(), actual.end());\n    BOOST_TEST(actualv == expected);\n}\n\n// OK packet checking\nvoid check_ok_r1(const static_results_erased_impl& r, std::size_t idx)\n{\n    BOOST_TEST(r.get_affected_rows(idx) == 1u);\n    BOOST_TEST(r.get_last_insert_id(idx) == 2u);\n    BOOST_TEST(r.get_warning_count(idx) == 4u);\n    BOOST_TEST(r.get_info(idx) == \"Information\");\n    BOOST_TEST(r.get_is_out_params(idx) == false);\n}\n\nvoid check_ok_r2(const static_results_erased_impl& r, std::size_t idx)\n{\n    BOOST_TEST(r.get_affected_rows(idx) == 5u);\n    BOOST_TEST(r.get_last_insert_id(idx) == 6u);\n    BOOST_TEST(r.get_warning_count(idx) == 8u);\n    BOOST_TEST(r.get_info(idx) == \"more_info\");\n    BOOST_TEST(r.get_is_out_params(idx) == true);\n}\n\nvoid check_ok_r3(const static_results_erased_impl& r, std::size_t idx)\n{\n    BOOST_TEST(r.get_affected_rows(idx) == 10u);\n    BOOST_TEST(r.get_last_insert_id(idx) == 11u);\n    BOOST_TEST(r.get_warning_count(idx) == 12u);\n    BOOST_TEST(r.get_info(idx) == \"\");\n    BOOST_TEST(r.get_is_out_params(idx) == false);\n}\n\nstruct fixture\n{\n    diagnostics diag;\n    std::vector<field_view> fields;\n};\n\n// We use row_identity to make sure we use underlying_row_t when required\ntemplate <class... StaticRow>\nusing static_res_t = static_results_impl<row_identity<StaticRow>...>;\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_data, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n\n    // Initial\n    BOOST_TEST(r.is_reading_first());\n\n    // Head indicates resultset with two columns\n    r.on_num_meta(2);\n    BOOST_TEST(r.is_reading_meta());\n\n    // First meta\n    auto err = r.on_meta(create_meta_r1_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Second meta, ready to read rows\n    err = r.on_meta(create_meta_r1_1(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Rows\n    auto r1 = create_text_row_body(42, \"abc\");\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // End of resultset\n    err = r.on_row_ok_packet(create_ok_r1());\n    throw_on_error(err, diag);\n\n    // Verify results\n    std::vector<row1> expected_r1{\n        {\"abc\", 42}\n    };\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_ok_r1(r, 0);\n    check_rows(rt.get_rows<0>(), expected_r1);\n}\n\nBOOST_FIXTURE_TEST_CASE(one_resultset_empty, fixture)\n{\n    static_res_t<empty> rt;\n    auto& r = rt.get_interface();\n\n    // Initial\n    BOOST_TEST(r.is_reading_first());\n\n    // End of resultset\n    auto err = r.on_head_ok_packet(create_ok_r1(), diag);\n    throw_on_error(err, diag);\n\n    // verify\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_ok_r1(r, 0);\n    BOOST_TEST(rt.get_rows<0>().size() == 0u);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_data, fixture)\n{\n    // Resultset r1\n    static_res_t<row1, row2> rt;\n    auto& r = rt.get_interface();\n    exec_access(r).meta(create_meta_r1()).row(42, \"abc\").row(50, \"def\");\n\n    // OK packet indicates more results\n    auto err = r.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // Resultset r2: indicates resultset with meta\n    r.on_num_meta(1);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Meta\n    err = r.on_meta(create_meta_r2_0(), diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Row\n    auto r1 = create_text_row_body(70);\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n\n    // OK packet, no more resultsets\n    err = r.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n\n    // Verify\n    std::vector<row1> expected_r1{\n        {\"abc\", 42},\n        {\"def\", 50}\n    };\n    std::vector<row2> expected_r2{{70}};\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_rows(rt.get_rows<0>(), expected_r1);\n    check_rows(rt.get_rows<1>(), expected_r2);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_data, fixture)\n{\n    static_res_t<empty, row2> rt;\n    auto& r = rt.get_interface();\n\n    // Empty resultset r1, indicating more results\n    auto err = r.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // Resultset r2: indicates data\n    r.on_num_meta(1);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Metadata packet\n    err = r.on_meta(create_meta_r2_0(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Rows\n    auto r1 = create_text_row_body(70);\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Final OK packet\n    err = r.on_row_ok_packet(create_ok_r2());\n    throw_on_error(err, diag);\n\n    // Verify\n    std::vector<row2> expected_r2{{70}};\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    BOOST_TEST(rt.get_rows<0>().empty());\n    check_rows(rt.get_rows<1>(), expected_r2);\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_data_empty, fixture)\n{\n    // Resultset r1\n    static_res_t<row1, empty> rt;\n    auto& r = rt.get_interface();\n    exec_access(r).meta(create_meta_r1()).row(42, \"abc\").row(50, \"def\");\n\n    // OK packet indicates more results\n    auto err = r.on_row_ok_packet(create_ok_r1(true));\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // OK packet for 2nd result\n    err = r.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n\n    // Verify\n    std::vector<row1> expected_r1{\n        {\"abc\", 42},\n        {\"def\", 50}\n    };\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_empty(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_rows(rt.get_rows<0>(), expected_r1);\n    BOOST_TEST(rt.get_rows<1>().empty());\n}\n\nBOOST_FIXTURE_TEST_CASE(two_resultsets_empty_empty, fixture)\n{\n    static_res_t<empty, empty> rt;\n    auto& r = rt.get_interface();\n\n    // Resultset r1\n    auto err = r.on_head_ok_packet(create_ok_r1(true), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // OK packet for 2nd result\n    err = r.on_head_ok_packet(create_ok_r2(), diag);\n    throw_on_error(err, diag);\n\n    // Verify\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_meta_empty(r.get_meta(1));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    BOOST_TEST(rt.get_rows<0>().empty());\n    BOOST_TEST(rt.get_rows<1>().empty());\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_empty_empty_data, fixture)\n{\n    // First resultset\n    static_res_t<empty, empty, row3> rt;\n    auto& r = rt.get_interface();\n    add_ok(r, create_ok_r1(true));\n\n    // Second resultset: OK packet indicates more results\n    auto err = r.on_head_ok_packet(create_ok_r2(true), diag);\n    BOOST_TEST(r.is_reading_first_subseq());\n\n    // Resultset r3: head indicates resultset with metadata\n    r.on_num_meta(3);\n    BOOST_TEST(r.is_reading_meta());\n\n    // Metadata\n    err = r.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n    BOOST_TEST(r.is_reading_rows());\n\n    // Read rows\n    auto r1 = create_text_row_body(4.2f, 5.0, 8);\n    auto r2 = create_text_row_body(42.0f, 50.0, 80);\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    err = r.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n\n    // End of resultset\n    err = r.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n\n    // Verify\n    std::vector<row3> expected_r3{\n        {5.0,  8,  4.2f },\n        {50.0, 80, 42.0f}\n    };\n    BOOST_TEST(r.is_complete());\n    check_meta_empty(r.get_meta(0));\n    check_meta_empty(r.get_meta(1));\n    check_meta_r3(r.get_meta(2));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_ok_r3(r, 2);\n    BOOST_TEST(rt.get_rows<0>().empty());\n    BOOST_TEST(rt.get_rows<1>().empty());\n    check_rows(rt.get_rows<2>(), expected_r3);\n}\n\nBOOST_FIXTURE_TEST_CASE(three_resultsets_data_data_data, fixture)\n{\n    // Two first resultets\n    static_res_t<row1, row2, row3> rt;\n    auto& r = rt.get_interface();\n    exec_access(r)\n        .meta(create_meta_r1())\n        .row(42, \"abc\")\n        .row(50, \"def\")\n        .ok(create_ok_r1(true))\n        .meta(create_meta_r2())\n        .row(60);\n\n    // OK packet indicates more results\n    auto err = r.on_row_ok_packet(create_ok_r2(true));\n    throw_on_error(err, diag);\n\n    // Third resultset meta\n    r.on_num_meta(3);\n    err = r.on_meta(create_meta_r3_0(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_1(), diag);\n    throw_on_error(err, diag);\n    err = r.on_meta(create_meta_r3_2(), diag);\n    throw_on_error(err, diag);\n\n    // Rows\n    auto r1 = create_text_row_body(4.2f, 5.0, 8);\n    auto r2 = create_text_row_body(42.0f, 50.0, 80);\n    err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    err = r.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n\n    // OK packet\n    err = r.on_row_ok_packet(create_ok_r3());\n    throw_on_error(err, diag);\n\n    // Verify\n    std::vector<row1> expected_r1{\n        {\"abc\", 42},\n        {\"def\", 50}\n    };\n    std::vector<row2> expected_r2{{60}};\n    std::vector<row3> expected_r3{\n        {5.0,  8,  4.2f },\n        {50.0, 80, 42.0f}\n    };\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_meta_r3(r.get_meta(2));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_ok_r3(r, 2);\n    check_rows(rt.get_rows<0>(), expected_r1);\n    check_rows(rt.get_rows<1>(), expected_r2);\n    check_rows(rt.get_rows<2>(), expected_r3);\n}\n\n// Verify that reset clears all previous state\nBOOST_FIXTURE_TEST_CASE(reset, fixture)\n{\n    // Previous state\n    static_res_t<row1, row2, empty> rt;\n    auto& r = rt.get_interface();\n    exec_access(r)\n        .meta({\n            meta_builder().type(column_type::tinyint).name(\"ftiny\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::varchar).name(\"fvarchar\").nullable(false).build_coldef(),\n        })\n        .row(21, \"a string\")\n        .row(90, \"another string\")\n        .ok(create_ok_r1(true))\n        .meta({\n            meta_builder().type(column_type::bigint).name(\"fbigint\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::char_).name(\"unrelated_field\").nullable(false).build_coldef(),\n        })\n        .row(10, \"aaa\")\n        .row(2000, \"bbb\")\n        .ok(create_ok_r2(true));\n\n    r.on_num_meta(3);\n    auto err = r.on_meta(\n        meta_builder().type(column_type::float_).name(\"other\").nullable(false).build_coldef(),\n        diag\n    );\n    throw_on_error(err, diag);\n\n    // Reset\n    r.reset(detail::resultset_encoding::text, metadata_mode::minimal);\n    BOOST_TEST(r.is_reading_first());\n\n    // Use the object\n    add_meta(r, create_meta_r1());\n    add_row(r, 42, \"abc\");\n    add_row(r, 50, \"def\");\n    add_ok(r, create_ok_r1(true));\n\n    add_meta(r, create_meta_r2());\n    add_row(r, 100);\n    add_ok(r, create_ok_r2(true));\n\n    add_ok(r, create_ok_r3());\n\n    // Verify\n    std::vector<row1> expected_r1{\n        {\"abc\", 42},\n        {\"def\", 50}\n    };\n    std::vector<row2> expected_r2{{100}};\n    BOOST_TEST(r.is_complete());\n    check_meta_r1(r.get_meta(0));\n    check_meta_r2(r.get_meta(1));\n    check_meta_empty(r.get_meta(2));\n    check_ok_r1(r, 0);\n    check_ok_r2(r, 1);\n    check_ok_r3(r, 2);\n    check_rows(rt.get_rows<0>(), expected_r1);\n    check_rows(rt.get_rows<1>(), expected_r2);\n    BOOST_TEST(rt.get_rows<2>().empty());\n}\n\nBOOST_FIXTURE_TEST_CASE(info_string_ownserhip, fixture)\n{\n    static_res_t<empty, empty, row2> rt;\n    auto& r = rt.get_interface();\n\n    // Head OK packet\n    std::string info = \"Some info\";\n    auto err = r.on_head_ok_packet(ok_builder().more_results(true).info(info).build(), diag);\n    throw_on_error(err, diag);\n\n    // Empty OK packet\n    info = \"\";\n    err = r.on_head_ok_packet(ok_builder().more_results(true).info(info).build(), diag);\n\n    // Row OK packet\n    info = \"other info\";\n    add_meta(r, create_meta_r2());\n    err = r.on_row_ok_packet(ok_builder().info(info).build());\n    info = \"abcdfefgh\";\n    BOOST_TEST(r.get_info(0) == \"Some info\");\n    BOOST_TEST(r.get_info(1) == \"\");\n    BOOST_TEST(r.get_info(2) == \"other info\");\n}\n\n// Verify that we clear the fields before adding new ones\nBOOST_FIXTURE_TEST_CASE(storage_reuse, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n    add_meta(r, create_meta_r1());\n\n    // Rows\n    auto r1 = create_text_row_body(42, \"abc\");\n    auto r2 = create_text_row_body(43, \"def\");\n    auto err = r.on_row(r1, output_ref(), fields);\n    throw_on_error(err, diag);\n    err = r.on_row(r2, output_ref(), fields);\n    throw_on_error(err, diag);\n\n    // End of resultset\n    add_ok(r, create_ok_r1());\n\n    // Verify results\n    std::vector<row1> expected_r1{\n        {\"abc\", 42},\n        {\"def\", 43},\n    };\n    BOOST_TEST(fields.size() == 2u);\n    check_rows(rt.get_rows<0>(), expected_r1);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_meta_mismatch, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n\n    r.on_num_meta(1);\n    auto err = r.on_meta(\n        meta_builder().type(column_type::bigint).name(\"fvarchar\").nullable(false).build_coldef(),\n        diag\n    );\n\n    const char* expected_msg =\n        \"Incompatible types for field 'fvarchar': C++ type 'string' is not compatible with DB type 'BIGINT'\\n\"\n        \"Field 'ftiny' is not present in the data returned by the server\";\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_meta_mismatch_head, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n\n    auto err = r.on_head_ok_packet(create_ok_r1(), diag);\n    const char* expected_msg =\n        \"Field 'fvarchar' is not present in the data returned by the server\\n\"\n        \"Field 'ftiny' is not present in the data returned by the server\";\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(diag.client_message() == expected_msg);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_deserializing_row, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n    add_meta(r, create_meta_r1());\n    auto bad_row = create_text_row_body(42, \"abc\");\n    bad_row.push_back(0xff);\n\n    auto err = r.on_row(bad_row, output_ref(), fields);\n\n    BOOST_TEST(err == client_errc::extra_bytes);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_parsing_row, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n    add_meta(r, create_meta_r1());\n    auto bad_row = create_text_row_body(nullptr, \"abc\");  // should not be NULL\n\n    auto err = r.on_row(bad_row, output_ref(), fields);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_few_resultsets_empty, fixture)\n{\n    static_res_t<empty, row2> rt;\n    auto& r = rt.get_interface();\n\n    auto err = r.on_head_ok_packet(create_ok_r1(), diag);\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_many_resultsets_empty, fixture)\n{\n    static_res_t<empty> rt;\n    auto& r = rt.get_interface();\n\n    auto err = r.on_head_ok_packet(create_ok_r1(true), diag);\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_few_resultsets_data, fixture)\n{\n    static_res_t<row1, row2> rt;\n    auto& r = rt.get_interface();\n    add_meta(r, create_meta_r1());\n\n    auto err = r.on_row_ok_packet(create_ok_r1());\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_too_many_resultsets_data, fixture)\n{\n    static_res_t<row1> rt;\n    auto& r = rt.get_interface();\n    add_meta(r, create_meta_r1());\n\n    auto err = r.on_row_ok_packet(create_ok_r1(true));\n    BOOST_TEST(err == client_errc::num_resultsets_mismatch);\n}\n\nstruct ctor_assign_fixture\n{\n    using results_t = static_res_t<row1, row2>;\n\n    std::unique_ptr<results_t> rt_old{new results_t{}};\n\n    ctor_assign_fixture()\n    {\n        // Create and populate an object. Having it in the heap should make it easier to detect dangling\n        // pointers\n        exec_access(rt_old->get_interface())\n            .meta(create_meta_r1())\n            .row(42, \"abc\")\n            .row(50, \"def\")\n            .ok(create_ok_r1(true))\n            .meta(create_meta_r2())\n            .row(400)\n            .ok(create_ok_r2());\n    }\n\n    // Checks that we correctly performed the copy/move, and that the object works\n    // without dangling parts\n    static void check_object(results_t& rt)\n    {\n        auto& r = rt.get_interface();\n\n        // Data has been copied, and external data (like rows) doesn't dangle\n        std::vector<row1> expected_r1{\n            {\"abc\", 42},\n            {\"def\", 50}\n        };\n        std::vector<row2> expected_r2{{400}};\n        BOOST_TEST(r.is_complete());\n        check_meta_r1(r.get_meta(0));\n        check_meta_r2(r.get_meta(1));\n        check_rows(rt.get_rows<0>(), expected_r1);\n        check_rows(rt.get_rows<1>(), expected_r2);\n        check_ok_r1(r, 0);\n        check_ok_r2(r, 1);\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE(copy_ctor, ctor_assign_fixture)\n{\n    // Copy construct\n    results_t rt{*rt_old};\n    rt_old.reset();\n\n    // Check\n    check_object(rt);\n}\n\nBOOST_FIXTURE_TEST_CASE(move_ctor, ctor_assign_fixture)\n{\n    // Move construct\n    results_t rt{std::move(*rt_old)};\n    rt_old.reset();\n\n    // Check\n    check_object(rt);\n}\n\nBOOST_FIXTURE_TEST_CASE(copy_assignment, ctor_assign_fixture)\n{\n    // Create and populate the object we'll assign to\n    results_t rt;\n    add_meta(\n        rt.get_interface(),\n        {\n            meta_builder().type(column_type::smallint).name(\"ftiny\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::text).name(\"fvarchar\").nullable(false).build_coldef(),\n        }\n    );\n\n    // Assign\n    rt = *rt_old;\n    rt_old.reset();\n\n    // Check\n    check_object(rt);\n}\n\nBOOST_FIXTURE_TEST_CASE(move_assignment, ctor_assign_fixture)\n{\n    // Create and populate the object we'll assign to\n    results_t rt;\n    add_meta(\n        rt.get_interface(),\n        {\n            meta_builder().type(column_type::smallint).name(\"ftiny\").nullable(false).build_coldef(),\n            meta_builder().type(column_type::text).name(\"fvarchar\").nullable(false).build_coldef(),\n        }\n    );\n\n    // Assign\n    rt = std::move(*rt_old);\n    rt_old.reset();\n\n    // Check\n    check_object(rt);\n}\n\n// Regression checks\nBOOST_AUTO_TEST_CASE(tuples)\n{\n    std::vector<field_view> fields;\n    static_res_t<row1_tuple, empty, row3_tuple> stp;\n    auto& st = stp.get_interface();\n\n    // Meta r1\n    add_meta(st, create_meta_r1());\n\n    // Rows r1\n    auto r1 = create_text_row_body(10, \"abc\");\n    auto err = st.on_row(r1, output_ref(), fields);\n    throw_on_error(err);\n\n    // EOF r1\n    add_ok(st, create_ok_r1(true));\n\n    // EOF r2\n    add_ok(st, create_ok_r2(true));\n\n    // Meta r3\n    add_meta(st, create_meta_r3());\n\n    // Rows r3\n    auto r3 = create_text_row_body(4.2f, 90.0, 9);\n    err = st.on_row(r3, output_ref(), fields);\n    throw_on_error(err);\n\n    // OK r3\n    add_ok(st, create_ok_r3());\n\n    // Verify\n    std::vector<row1_tuple> expected_r1{\n        row1_tuple{std::uint16_t(10), \"abc\"}\n    };\n    std::vector<row3_tuple> expected_r3{\n        row3_tuple{4.2f, 90.0, std::uint8_t(9)}\n    };\n    BOOST_TEST(st.is_complete());\n    check_meta_r1(st.get_meta(0));\n    check_meta_empty(st.get_meta(1));\n    check_meta_r3(st.get_meta(2));\n    check_rows(stp.get_rows<0>(), expected_r1);\n    BOOST_TEST(stp.get_rows<1>().empty());\n    check_rows(stp.get_rows<2>(), expected_r3);\n    check_ok_r1(st, 0);\n    check_ok_r2(st, 1);\n    check_ok_r3(st, 2);\n}\n\nBOOST_AUTO_TEST_CASE(field_selection_structs)\n{\n    std::vector<field_view> fields;\n    static_res_t<row3_selection> stp;\n    auto& st = stp.get_interface();\n\n    // Meta\n    add_meta(st, create_meta_r3());\n\n    // Row\n    add_row(st, 4.2f, 90.0, 9);\n\n    // EOF\n    add_ok(st, create_ok_r3());\n\n    // Verify\n    std::vector<row3_selection> expected{\n        row3_selection{9, 4.2f}\n    };\n    BOOST_TEST(st.is_complete());\n    check_meta_r3(st.get_meta(0));\n    check_rows(stp.get_rows<0>(), expected);\n    check_ok_r3(st, 0);\n}\n\nBOOST_AUTO_TEST_CASE(field_selection_tuples)\n{\n    std::vector<field_view> fields;\n    static_res_t<row3_selection_tuple> stp;\n    auto& st = stp.get_interface();\n\n    // Meta\n    add_meta(st, create_meta_r3());\n\n    // Row\n    add_row(st, 4.2f, 90.0, 9);\n\n    // EOF\n    add_ok(st, create_ok_r3());\n\n    // Verify\n    std::vector<row3_selection_tuple> expected{\n        row3_selection_tuple{4.2f, 90.0}\n    };\n    BOOST_TEST(st.is_complete());\n    check_meta_r3(st.get_meta(0));\n    check_rows(stp.get_rows<0>(), expected);\n    check_ok_r3(st, 0);\n}\n\nBOOST_AUTO_TEST_CASE(repeated_row_types)\n{\n    std::vector<field_view> fields;\n    static_res_t<row1, row1, row2, row1> stp;\n    auto& st = stp.get_interface();\n\n    // 1st resultset\n    add_meta(st, create_meta_r1());\n    add_row(st, 42, \"aaa\");\n    add_row(st, 43, \"bbb\");\n    add_ok(st, create_ok_r1(true));\n\n    // 2nd resultset\n    add_meta(st, create_meta_r1());\n    add_row(st, 44, \"ccc\");\n    add_ok(st, create_ok_r1(true));\n\n    // 3rd resultset\n    add_meta(st, create_meta_r2());\n    add_row(st, 900);\n    add_ok(st, create_ok_r2(true));\n\n    // 4th resultset\n    add_meta(st, create_meta_r1());\n    add_row(st, 45, \"ddd\");\n    add_ok(st, create_ok_r3());\n\n    // Verify\n    std::vector<row1> expected_r1{\n        row1{\"aaa\", 42},\n        row1{\"bbb\", 43}\n    };\n    std::vector<row1> expected_r2{\n        row1{\"ccc\", 44}\n    };\n    std::vector<row2> expected_r3{row2{900}};\n    std::vector<row1> expected_r4{\n        row1{\"ddd\", 45}\n    };\n    BOOST_TEST(st.is_complete());\n    check_meta_r1(st.get_meta(0));\n    check_meta_r1(st.get_meta(1));\n    check_meta_r2(st.get_meta(2));\n    check_meta_r1(st.get_meta(3));\n    check_rows(stp.get_rows<0>(), expected_r1);\n    check_rows(stp.get_rows<1>(), expected_r2);\n    check_rows(stp.get_rows<2>(), expected_r3);\n    check_rows(stp.get_rows<3>(), expected_r4);\n    check_ok_r1(st, 0);\n    check_ok_r1(st, 1);\n    check_ok_r2(st, 2);\n    check_ok_r3(st, 3);\n}\n\nBOOST_AUTO_TEST_CASE(all_fields_discarded)\n{\n    std::vector<field_view> fields;\n    static_res_t<empty, empty> stp;\n    auto& st = stp.get_interface();\n\n    // 1st resultset\n    add_meta(st, create_meta_r1());\n    add_row(st, 42, \"aaa\");\n    add_row(st, 43, \"bbb\");\n    add_ok(st, create_ok_r1(true));\n\n    // 2nd resultset\n    add_meta(st, create_meta_r2());\n    add_row(st, 900);\n    add_ok(st, create_ok_r2());\n\n    // Verify\n    BOOST_TEST(st.is_complete());\n    check_meta_r1(st.get_meta(0));\n    check_meta_r2(st.get_meta(1));\n    check_rows(stp.get_rows<0>(), {empty{}, empty{}});\n    check_rows(stp.get_rows<1>(), {empty{}});\n    check_ok_r1(st, 0);\n    check_ok_r2(st, 1);\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_minimal, fixture)\n{\n    static_res_t<row1> stp;\n    auto& st = stp.get_interface();\n\n    exec_access(st)\n        .reset(resultset_encoding::text, metadata_mode::minimal)\n        .meta(create_meta_r1())\n        .row(42, \"aaa\")\n        .ok(create_ok_r1());\n\n    BOOST_TEST(st.get_meta(0)[0].column_name() == \"\");\n}\n\nBOOST_FIXTURE_TEST_CASE(meta_mode_full, fixture)\n{\n    static_res_t<row1> stp;\n    auto& st = stp.get_interface();\n\n    exec_access(st)\n        .reset(resultset_encoding::text, metadata_mode::full)\n        .meta(create_meta_r1())\n        .row(42, \"aaa\")\n        .ok(create_ok_r1());\n\n    BOOST_TEST(st.get_meta(0)[0].column_name() == \"ftiny\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n\n#endif  // BOOST_MYSQL_CXX14\n"
  },
  {
    "path": "test/unit/test/execution_state.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_execution_state)\n\n// The functionality has been tested in execution_state_impl already.\n// Just spotchecks here\nBOOST_AUTO_TEST_CASE(spotchecks)\n{\n    std::vector<field_view> fields;\n    execution_state st;\n    auto& impl = get_iface(st);\n    diagnostics diag;\n\n    // Initial\n    BOOST_TEST(st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    BOOST_TEST(st.meta().size() == 0u);\n\n    // Reset\n    impl.reset(detail::resultset_encoding::text, metadata_mode::minimal);\n    BOOST_TEST(st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(!st.complete());\n\n    // Meta\n    add_meta(impl, {meta_builder().type(column_type::varchar).build_coldef()});\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::varchar});\n\n    // Reading a row leaves it in the same state\n    auto r1 = create_text_row_body(\"abc\");\n    auto err = impl.on_row(r1, detail::output_ref(), fields);\n    throw_on_error(err);\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    BOOST_TEST(fields == make_fv_vector(\"abc\"));\n\n    // End of first resultset\n    add_ok(\n        impl,\n        ok_builder()\n            .affected_rows(1)\n            .last_insert_id(2)\n            .warnings(4)\n            .info(\"abc\")\n            .more_results(true)\n            .out_params(true)\n            .build()\n    );\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::varchar});\n    BOOST_TEST(st.affected_rows() == 1u);\n    BOOST_TEST(st.last_insert_id() == 2u);\n    BOOST_TEST(st.warning_count() == 4u);\n    BOOST_TEST(st.info() == \"abc\");\n    BOOST_TEST(st.is_out_params());\n\n    // Second resultset meta\n    add_meta(impl, {meta_builder().type(column_type::tinyint).build_coldef()});\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::tinyint});\n\n    // Complete\n    add_ok(impl, ok_builder().affected_rows(5).last_insert_id(6).warnings(7).info(\"bhu\").build());\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(st.complete());\n    check_meta(st.meta(), {column_type::tinyint});\n    BOOST_TEST(st.affected_rows() == 5u);\n    BOOST_TEST(st.last_insert_id() == 6u);\n    BOOST_TEST(st.warning_count() == 7u);\n    BOOST_TEST(st.info() == \"bhu\");\n    BOOST_TEST(!st.is_out_params());\n}\n\nstd::unique_ptr<execution_state> create_heap_state()\n{\n    std::unique_ptr<execution_state> st{new execution_state};\n    add_meta(get_iface(*st), {meta_builder().type(column_type::varchar).build_coldef()});\n    add_ok(get_iface(*st), ok_builder().info(\"small\").build());\n    return st;\n}\n\n// Verify that the lifetime guarantees we make are correct\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Having this in heap helps detect lifetime issues\n    auto st = create_heap_state();\n\n    // Obtain references\n    auto meta = st->meta();\n    auto info = st->info();\n\n    // Move construct\n    execution_state st2(std::move(*st));\n    st.reset();\n\n    // Make sure that views are still valid\n    check_meta(meta, {column_type::varchar});\n    BOOST_TEST(info == \"small\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(st2.complete());\n    check_meta(st2.meta(), {column_type::varchar});\n    BOOST_TEST(st2.info() == \"small\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assignment)\n{\n    // Having this in heap helps detect lifetime issues\n    auto st = create_heap_state();\n\n    // Obtain references\n    auto meta = st->meta();\n    auto info = st->info();\n\n    // Move assign\n    execution_state st2;\n    st2 = std::move(*st);\n    st.reset();\n\n    // Make sure that views are still valid\n    check_meta(meta, {column_type::varchar});\n    BOOST_TEST(info == \"small\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(st2.complete());\n    check_meta(st2.meta(), {column_type::varchar});\n    BOOST_TEST(st2.info() == \"small\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/field.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/stringize.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\n// Don't attempt to print std::chrono values\nBOOST_TEST_DONT_PRINT_LOG_VALUE(boost::mysql::time)\n\nBOOST_AUTO_TEST_SUITE(test_field)\n\nBOOST_AUTO_TEST_SUITE(constructors)\nBOOST_AUTO_TEST_CASE(default_constructor)\n{\n    field v;\n    BOOST_TEST(v.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(copy_scalar)\n{\n    field v(42);\n    field v2(v);\n    BOOST_TEST(v2.as_int64() == 42);\n}\n\nBOOST_AUTO_TEST_CASE(copy_string)\n{\n    std::string s(\"test\");\n    field v(s);\n    field v2(v);\n    BOOST_TEST(v2.as_string() == \"test\");\n\n    // Changing the value of v doesn't affect v2\n    v = \"other\";\n    BOOST_TEST(v2.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(copy_blob)\n{\n    blob b({0xff, 0x01, 0x02});\n    field v(blob{b});\n    field v2(v);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v2.as_blob(), b);\n\n    // Changing the value of v doesn't affect v2\n    v = \"other\";\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v2.as_blob(), b);\n}\n\nBOOST_AUTO_TEST_CASE(move)\n{\n    field f(\"test\");\n    field v(std::move(f));\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_nullptr)\n{\n    field v(nullptr);\n    BOOST_TEST(v.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(from_u8)\n{\n    field v(std::uint8_t(0xfe));\n    BOOST_TEST(v.as_uint64() == 0xfeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u16)\n{\n    field v(std::uint16_t(0xfefe));\n    BOOST_TEST(v.as_uint64() == 0xfefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u32)\n{\n    field v(std::uint32_t(0xfefefefe));\n    BOOST_TEST(v.as_uint64() == 0xfefefefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u64)\n{\n    field v(std::uint64_t(0xfefefefefefefefe));\n    BOOST_TEST(v.as_uint64() == 0xfefefefefefefefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_s8)\n{\n    field v(std::int8_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s16)\n{\n    field v(std::int16_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s32)\n{\n    field v(std::int32_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s64)\n{\n    field v(std::int64_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_char_array)\n{\n    field v(\"test\");\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_c_str)\n{\n    const char* str = \"test\";\n    field v(str);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_boost_string_view)\n{\n    string_view sv(\"test123\", 4);\n    field v(sv);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nBOOST_AUTO_TEST_CASE(from_std_string_view)\n{\n    std::string_view sv(\"test123\", 4);\n    field v(sv);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(from_string_rvalue)\n{\n    field v(std::string(\"test\"));\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_string_lvalue)\n{\n    std::string s(\"test\");\n    field v(s);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_blob_rvalue)\n{\n    field v(blob{0x02, 0x03});\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), (blob{0x02, 0x03}));\n}\n\nBOOST_AUTO_TEST_CASE(from_blob_lvalue)\n{\n    blob b{0x02, 0x03};\n    field v(b);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), (blob{0x02, 0x03}));\n}\n\nBOOST_AUTO_TEST_CASE(from_float)\n{\n    field v(4.2f);\n    BOOST_TEST(v.as_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(from_double)\n{\n    field v(4.2);\n    BOOST_TEST(v.as_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(from_date)\n{\n    date d(2022u, 4u, 1u);\n    field v(d);\n    BOOST_TEST(v.as_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_datetime)\n{\n    datetime d(2022u, 4u, 1u, 21u);\n    field v(d);\n    BOOST_TEST(v.as_datetime() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_time)\n{\n    auto t = maket(20, 10, 1);\n    field v(t);\n    BOOST_TEST(v.as_time() == t);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_null)\n{\n    field_view fv;\n    field f(fv);\n    BOOST_TEST(f.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_int64)\n{\n    field_view fv(-1);\n    field f(fv);\n    BOOST_TEST(f.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_uint64)\n{\n    field_view fv(42u);\n    field f(fv);\n    BOOST_TEST(f.as_uint64() == 42u);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_string)\n{\n    std::string s(\"test\");\n    field_view fv(s);\n    field f(fv);\n    s = \"other\";  // changing the source string shouldn't modify the value\n    BOOST_TEST(f.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_blob)\n{\n    blob b{0x02, 0x00, 0x01};\n    field_view fv(b);\n    field f(fv);\n    b[0] = 0xff;  // changing the source string shouldn't modify the value\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.as_blob(), (blob{0x02, 0x00, 0x01}));\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_float)\n{\n    field_view fv(4.2f);\n    field f(fv);\n    BOOST_TEST(f.as_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_double)\n{\n    field_view fv(4.2);\n    field f(fv);\n    BOOST_TEST(f.as_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_date)\n{\n    date d(2020u, 1u, 2u);\n    field_view fv(d);\n    field f(fv);\n    BOOST_TEST(f.as_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_datetime)\n{\n    datetime d(2020u, 1u, 2u);\n    field_view fv(d);\n    field f(fv);\n    BOOST_TEST(f.as_datetime() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_time)\n{\n    auto t = maket(9, 1, 2);\n    field_view fv(t);\n    field f(fv);\n    BOOST_TEST(f.as_time() == t);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(assignment)\nBOOST_AUTO_TEST_CASE(copy_scalar)\n{\n    field v(42);\n    field v2(5.6);\n    v = v2;\n    BOOST_TEST(v.as_double() == 5.6);\n}\n\nBOOST_AUTO_TEST_CASE(copy_string)\n{\n    field v(42);\n    field v2(\"test\");\n    v = v2;\n    BOOST_TEST(v.as_string() == \"test\");\n\n    // Changing the value of v2 doesn't affect v\n    v2.as_string() = \"other\";\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(copy_blob)\n{\n    field v(42);\n    field v2(blob{0x00, 0x02});\n    v = v2;\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), (blob{0x00, 0x02}));\n\n    // Changing the value of v2 doesn't affect v\n    v2.as_blob()[0] = 0xff;\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), (blob{0x00, 0x02}));\n}\n\nBOOST_AUTO_TEST_CASE(self_copy)\n{\n    field v(\"test\");\n    const auto& ref = v;\n    v = ref;\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(move)\n{\n    field v(42);\n    field v2(\"test\");\n    v = std::move(v2);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(self_move)\n{\n    field v(\"test\");\n    auto&& ref = v;\n    v = std::move(ref);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_nullptr)\n{\n    field v(42);\n    v = nullptr;\n    BOOST_TEST(v.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(from_u8)\n{\n    field v(9.2f);\n    v = std::uint8_t(0xfe);\n    BOOST_TEST(v.as_uint64() == 0xfeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u16)\n{\n    field v(9.2f);\n    v = std::uint16_t(0xfefe);\n    BOOST_TEST(v.as_uint64() == 0xfefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u32)\n{\n    field v(9.2f);\n    v = std::uint32_t(0xfefefefe);\n    BOOST_TEST(v.as_uint64() == 0xfefefefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u64)\n{\n    field v(9.2f);\n    v = std::uint64_t(0xfefefefefefefefe);\n    BOOST_TEST(v.as_uint64() == 0xfefefefefefefefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_s8)\n{\n    field v(9.2f);\n    v = std::int8_t(-1);\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s16)\n{\n    field v(9.2f);\n    v = std::int16_t(-1);\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s32)\n{\n    field v(9.2f);\n    v = std::int32_t(-1);\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s64)\n{\n    field v(9.2f);\n    v = std::int64_t(-1);\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_char_array)\n{\n    field v(9.2f);\n    v = \"test\";\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_c_str)\n{\n    const char* str = \"test\";\n    field v(9.2f);\n    v = str;\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_boost_string_view)\n{\n    string_view sv(\"test123\", 4);\n    field v(9.2f);\n    v = sv;\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nBOOST_AUTO_TEST_CASE(from_std_string_view)\n{\n    std::string_view sv(\"test123\", 4);\n    field v(9.2f);\n    v = sv;\n    BOOST_TEST(v.as_string() == \"test\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(from_string_rvalue)\n{\n    field v(9.2f);\n    v = std::string(\"test\");\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_string_lvalue)\n{\n    std::string s(\"test\");\n    field v(9.2f);\n    v = s;\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_blob_rvalue)\n{\n    field v(9.2f);\n    v = blob{0x00, 0x02};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), (blob{0x00, 0x02}));\n}\n\nBOOST_AUTO_TEST_CASE(from_blob_lvalue)\n{\n    blob b{0x00, 0x02};\n    field v(9.2f);\n    v = b;\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), (blob{0x00, 0x02}));\n}\n\nBOOST_AUTO_TEST_CASE(from_float)\n{\n    field v(\"test\");\n    v = 4.2f;\n    BOOST_TEST(v.as_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(from_double)\n{\n    field v(\"test\");\n    v = 4.2;\n    BOOST_TEST(v.as_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(from_date)\n{\n    date d(2022u, 4u, 1u);\n    field v(\"test\");\n    v = d;\n    BOOST_TEST(v.as_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_datetime)\n{\n    datetime d(2022u, 4u, 1u, 21u);\n    field v(\"test\");\n    v = d;\n    BOOST_TEST(v.as_datetime() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_time)\n{\n    auto t = maket(20, 10, 1);\n    field v(\"test\");\n    v = t;\n    BOOST_TEST(v.as_time() == t);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_null)\n{\n    field_view fv;\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_int64)\n{\n    field_view fv(-1);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_uint64)\n{\n    field_view fv(42u);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_uint64() == 42u);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_string)\n{\n    field_view fv(\"test\");\n    field f(1);\n    f = fv;\n    BOOST_TEST(f.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_blob)\n{\n    field_view fv(makebv(\"\\0\\1\\0\"));\n    field f(1);\n    f = fv;\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.as_blob(), (blob{0x00, 0x01, 0x00}));\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_float)\n{\n    field_view fv(4.2f);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_double)\n{\n    field_view fv(4.2);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_date)\n{\n    date d(2020u, 1u, 2u);\n    field_view fv(d);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_datetime)\n{\n    datetime d(2020u, 1u, 2u);\n    field_view fv(d);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_datetime() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_field_view_time)\n{\n    auto t = maket(9, 1, 2);\n    field_view fv(t);\n    field f(\"test\");\n    f = fv;\n    BOOST_TEST(f.as_time() == t);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(accesors)\n\n// clang-format off\nstruct\n{\n    const char* name;\n    const field f;\n    field_kind expected_kind;\n    bool is_null, is_int64, is_uint64, is_string, is_blob, is_float, is_double, is_date, is_datetime, is_time;\n} test_cases [] = {\n    // name       field                           kind                  null,  i64    u64    str    blob   float  double date   dt    time \n    { \"null\",     field(),                        field_kind::null,     true,  false, false, false, false, false, false, false, false, false },\n    { \"int64\",    field(42),                      field_kind::int64,    false, true,  false, false, false, false, false, false, false, false },\n    { \"uint64\",   field(42u),                     field_kind::uint64,   false, false, true,  false, false, false, false, false, false, false },\n    { \"string\",   field(\"test\"),                  field_kind::string,   false, false, false, true,  false, false, false, false, false, false },\n    { \"blob\",     field(blob{0x00, 0x01}),        field_kind::blob,     false, false, false, false, true,  false, false, false, false, false },\n    { \"float\",    field(4.2f),                    field_kind::float_,   false, false, false, false, false, true,  false, false, false, false },\n    { \"double\",   field(4.2),                     field_kind::double_,  false, false, false, false, false, false, true,  false, false, false },\n    { \"date\",     field(date(2020u, 1u, 1u)),     field_kind::date,     false, false, false, false, false, false, false, true,  false, false },\n    { \"datetime\", field(datetime(2020u, 1u, 1u)), field_kind::datetime, false, false, false, false, false, false, false, false, true,  false },\n    { \"time\",     field(maket(20, 1, 1)),         field_kind::time,     false, false, false, false, false, false, false, false, false, true },\n};\n// clang-format on\n\nBOOST_AUTO_TEST_CASE(kind)\n{\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST(tc.f.kind() == tc.expected_kind, tc.name);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(is)\n{\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST(tc.f.is_null() == tc.is_null);\n            BOOST_TEST(tc.f.is_int64() == tc.is_int64);\n            BOOST_TEST(tc.f.is_uint64() == tc.is_uint64);\n            BOOST_TEST(tc.f.is_string() == tc.is_string);\n            BOOST_TEST(tc.f.is_blob() == tc.is_blob);\n            BOOST_TEST(tc.f.is_float() == tc.is_float);\n            BOOST_TEST(tc.f.is_double() == tc.is_double);\n            BOOST_TEST(tc.f.is_date() == tc.is_date);\n            BOOST_TEST(tc.f.is_datetime() == tc.is_datetime);\n            BOOST_TEST(tc.f.is_time() == tc.is_time);\n        }\n    }\n}\n\n// We check both const and non-const versions\nBOOST_AUTO_TEST_CASE(as_exceptions)\n{\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            if (tc.is_int64)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_int64());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_int64());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_int64(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_int64(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_uint64)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_uint64());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_uint64());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_uint64(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_uint64(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_string)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_string());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_string());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_string(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_string(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_blob)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_blob());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_blob());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_blob(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_blob(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_float)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_float());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_float());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_float(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_float(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_double)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_double());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_double());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_double(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_double(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_date)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_date());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_date());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_date(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_date(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_datetime)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_datetime());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_datetime());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_datetime(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_datetime(), boost::mysql::bad_field_access);\n            }\n\n            if (tc.is_time)\n            {\n                BOOST_CHECK_NO_THROW(tc.f.as_time());\n                BOOST_CHECK_NO_THROW(field(tc.f).as_time());\n            }\n            else\n            {\n                BOOST_CHECK_THROW(tc.f.as_time(), boost::mysql::bad_field_access);\n                BOOST_CHECK_THROW(field(tc.f).as_time(), boost::mysql::bad_field_access);\n            }\n        }\n    }\n}\n\n// Success cases (the type matches the called function)\nBOOST_AUTO_TEST_CASE(int64)\n{\n    field f(-1);\n    BOOST_TEST(f.as_int64() == -1);\n    BOOST_TEST(f.get_int64() == -1);\n\n    f.as_int64() = -3;\n    BOOST_TEST(f.as_int64() == -3);\n\n    f.get_int64() = -4;\n    BOOST_TEST(f.as_int64() == -4);\n\n    const field f2(-1);\n    BOOST_TEST(f2.as_int64() == -1);\n    BOOST_TEST(f2.get_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(uint64)\n{\n    field f(42u);\n    BOOST_TEST(f.as_uint64() == 42u);\n    BOOST_TEST(f.get_uint64() == 42u);\n\n    f.as_uint64() = 44u;\n    BOOST_TEST(f.as_uint64() == 44u);\n\n    f.get_uint64() = 45u;\n    BOOST_TEST(f.as_uint64() == 45u);\n\n    const field f2(42u);\n    BOOST_TEST(f2.as_uint64() == 42u);\n    BOOST_TEST(f2.get_uint64() == 42u);\n}\n\nBOOST_AUTO_TEST_CASE(string)\n{\n    field f(\"test\");\n    BOOST_TEST(f.as_string() == \"test\");\n    BOOST_TEST(f.get_string() == \"test\");\n\n    f.as_string() = \"test3\";\n    BOOST_TEST(f.as_string() == \"test3\");\n\n    f.get_string() = \"test4\";\n    BOOST_TEST(f.as_string() == \"test4\");\n\n    const field f2(\"test\");\n    BOOST_TEST(f2.as_string() == \"test\");\n    BOOST_TEST(f2.get_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(blob_)\n{\n    field f(blob{0x00, 0x01});\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.as_blob(), (blob{0x00, 0x01}));\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.get_blob(), (blob{0x00, 0x01}));\n\n    f.as_blob() = blob{0x00, 0x07};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.as_blob(), (blob{0x00, 0x07}));\n\n    f.get_blob().push_back(0xff);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.as_blob(), (blob{0x00, 0x07, 0xff}));\n\n    const field f2(blob{0xff, 0xfe});\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f2.as_blob(), (blob{0xff, 0xfe}));\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f2.get_blob(), (blob{0xff, 0xfe}));\n}\n\nBOOST_AUTO_TEST_CASE(float_)\n{\n    field f(4.2f);\n    BOOST_TEST(f.as_float() == 4.2f);\n    BOOST_TEST(f.get_float() == 4.2f);\n\n    f.as_float() = 4.4f;\n    BOOST_TEST(f.as_float() == 4.4f);\n\n    f.get_float() = 4.5f;\n    BOOST_TEST(f.as_float() == 4.5f);\n\n    const field f2(4.2f);\n    BOOST_TEST(f2.as_float() == 4.2f);\n    BOOST_TEST(f2.get_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(double_)\n{\n    field f(4.2);\n    BOOST_TEST(f.as_double() == 4.2);\n    BOOST_TEST(f.get_double() == 4.2);\n\n    f.as_double() = 4.4;\n    BOOST_TEST(f.as_double() == 4.4);\n\n    f.get_double() = 4.5;\n    BOOST_TEST(f.as_double() == 4.5);\n\n    const field f2(4.2);\n    BOOST_TEST(f2.as_double() == 4.2);\n    BOOST_TEST(f2.get_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(date_)\n{\n    date d1(2020u, 1u, 1u);\n    date d2(2020u, 3u, 3u);\n    date d3(2020u, 4u, 4u);\n\n    field f(d1);\n    BOOST_TEST(f.as_date() == d1);\n    BOOST_TEST(f.get_date() == d1);\n\n    f.as_date() = d2;\n    BOOST_TEST(f.as_date() == d2);\n\n    f.get_date() = d3;\n    BOOST_TEST(f.as_date() == d3);\n\n    const field f2(d1);\n    BOOST_TEST(f2.as_date() == d1);\n    BOOST_TEST(f2.get_date() == d1);\n}\n\nBOOST_AUTO_TEST_CASE(datetime_)\n{\n    datetime d1(2020u, 1u, 1u);\n    datetime d2(2020u, 3u, 3u);\n    datetime d3(2020u, 4u, 4u);\n\n    field f(d1);\n    BOOST_TEST(f.as_datetime() == d1);\n    BOOST_TEST(f.get_datetime() == d1);\n\n    f.as_datetime() = d2;\n    BOOST_TEST(f.as_datetime() == d2);\n\n    f.get_datetime() = d3;\n    BOOST_TEST(f.as_datetime() == d3);\n\n    const field f2(d1);\n    BOOST_TEST(f2.as_datetime() == d1);\n    BOOST_TEST(f2.get_datetime() == d1);\n}\n\nBOOST_AUTO_TEST_CASE(time)\n{\n    auto t1 = maket(8, 1, 1);\n    auto t2 = maket(10, 3, 3);\n    auto t3 = maket(11, 4, 4);\n\n    field f(t1);\n    BOOST_TEST(f.as_time() == t1);\n    BOOST_TEST(f.get_time() == t1);\n\n    f.as_time() = t2;\n    BOOST_TEST(f.as_time() == t2);\n\n    f.get_time() = t3;\n    BOOST_TEST(f.as_time() == t3);\n\n    const field f2(t1);\n    BOOST_TEST(f2.as_time() == t1);\n    BOOST_TEST(f2.get_time() == t1);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\n// The returned field_view changes accordingly\n// when we change the field\nBOOST_AUTO_TEST_CASE(operator_field_view)\n{\n    // Initial construction\n    field f(\"test\");\n    field_view fv(f);\n    BOOST_TEST(fv.as_string() == \"test\");\n\n    // Mutating the underlying value is reflected in the view\n    f.as_string().append(\"abcd\");\n    BOOST_TEST(fv.as_string() == \"testabcd\");\n\n    // Changing the type is also reflected\n    f = 42;\n    BOOST_TEST(fv.as_int64() == 42);\n\n    // Same for scalars\n    f.as_int64() = -1;\n    BOOST_TEST(fv.as_int64() == -1);\n}\n\n// operator== relies on field_view's operator==, so only\n// a small subset of tests here\nBOOST_AUTO_TEST_SUITE(operator_equals)\nBOOST_AUTO_TEST_CASE(field_field)\n{\n    BOOST_TEST(field(42) == field(42));\n    BOOST_TEST(!(field(42) != field(42)));\n\n    BOOST_TEST(!(field(42) == field(\"test\")));\n    BOOST_TEST(field(42) != field(\"test\"));\n}\n\nBOOST_AUTO_TEST_CASE(fieldview_field)\n{\n    BOOST_TEST(field_view(42) == field(42));\n    BOOST_TEST(!(field_view(42) != field(42)));\n\n    BOOST_TEST(!(field_view(42) == field(\"test\")));\n    BOOST_TEST(field_view(42) != field(\"test\"));\n}\n\nBOOST_AUTO_TEST_CASE(field_fieldview)\n{\n    BOOST_TEST(field(42) == field_view(42));\n    BOOST_TEST(!(field(42) != field_view(42)));\n\n    BOOST_TEST(!(field(42) == field_view(\"test\")));\n    BOOST_TEST(field(42) != field_view(\"test\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\n// operator<< relies on field_view's operator<<, so only\n// a small subset of tests here\nBOOST_AUTO_TEST_CASE(operator_stream)\n{\n    BOOST_TEST(stringize(field()) == \"<NULL>\");\n    BOOST_TEST(stringize(field(-1)) == \"-1\");\n    BOOST_TEST(stringize(field(42)) == \"42\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/field_view.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <sstream>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\n// Don't attempt to print std::chrono values\nBOOST_TEST_DONT_PRINT_LOG_VALUE(boost::mysql::time)\n\nBOOST_AUTO_TEST_SUITE(test_field_view)\n\nBOOST_AUTO_TEST_SUITE(constructors)\nBOOST_AUTO_TEST_CASE(default_constructor)\n{\n    field_view v;\n    BOOST_TEST(v.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(copy)\n{\n    field_view v(32);\n    field_view v2(v);\n    BOOST_TEST(v2.as_int64() == 32);\n}\n\nBOOST_AUTO_TEST_CASE(move)\n{\n    field_view v(field_view(32));\n    BOOST_TEST(v.as_int64() == 32);\n}\n\nBOOST_AUTO_TEST_CASE(from_nullptr)\n{\n    field_view v(nullptr);\n    BOOST_TEST(v.is_null());\n}\n\nBOOST_AUTO_TEST_CASE(from_u8)\n{\n    field_view v(std::uint8_t(0xfe));\n    BOOST_TEST(v.as_uint64() == 0xfeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u16)\n{\n    field_view v(std::uint16_t(0xfefe));\n    BOOST_TEST(v.as_uint64() == 0xfefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u32)\n{\n    field_view v(std::uint32_t(0xfefefefe));\n    BOOST_TEST(v.as_uint64() == 0xfefefefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_u64)\n{\n    field_view v(std::uint64_t(0xfefefefefefefefe));\n    BOOST_TEST(v.as_uint64() == 0xfefefefefefefefeu);\n}\n\nBOOST_AUTO_TEST_CASE(from_s8)\n{\n    field_view v(std::int8_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s16)\n{\n    field_view v(std::int16_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s32)\n{\n    field_view v(std::int32_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_s64)\n{\n    field_view v(std::int64_t(-1));\n    BOOST_TEST(v.as_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(from_char_array)\n{\n    field_view v(\"test\");\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_c_str)\n{\n    const char* str = \"test\";\n    field_view v(str);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_string_view)\n{\n    string_view sv(\"test123\", 4);\n    field_view v(sv);\n    BOOST_TEST(v.as_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(from_blob_view)\n{\n    std::uint8_t buff[] = {0x00, 0x01, 0x02};\n    field_view v{blob_view(buff)};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v.as_blob(), buff);\n}\n\nBOOST_AUTO_TEST_CASE(from_float)\n{\n    field_view v(4.2f);\n    BOOST_TEST(v.as_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(from_double)\n{\n    field_view v(4.2);\n    BOOST_TEST(v.as_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(from_date)\n{\n    date d(2022, 4, 1);\n    field_view v(d);\n    BOOST_TEST(v.as_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_datetime)\n{\n    datetime d(2022u, 4u, 1u, 21u);\n    field_view v(d);\n    BOOST_TEST(v.as_datetime() == d);\n}\n\nBOOST_AUTO_TEST_CASE(from_time)\n{\n    auto t = maket(20, 10, 1);\n    field_view v(t);\n    BOOST_TEST(v.as_time() == t);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(accesors)\n\n// Owning fields, to create references to them in the table below\nfield f_null;\nfield f_int64(50);\nfield f_uint64(50u);\nfield f_string(\"long_test_string\");\nfield f_blob(blob{0x00, 0x01, 0x02, 0x03});\nfield f_float(4.2f);\nfield f_double(5.0);\nfield f_date(date(2020u, 1u, 1u));\nfield f_datetime(datetime(2019u, 1u, 1u));\nfield f_time(maket(9, 1, 0));\n\n// clang-format off\nstruct\n{\n    const char* name;\n    field_view field;\n    field_kind expected_kind;\n    bool is_null, is_int64, is_uint64, is_string, is_blob, is_float, is_double, is_date, is_datetime, is_time;\n} test_cases [] = {\n    // name           field                                kind                  null,  i64    u64    str    blob   float  double date   dt     time \n    { \"null\",         field_view(),                        field_kind::null,     true,  false, false, false, false, false, false, false, false, false },\n    { \"int64\",        field_view(42),                      field_kind::int64,    false, true,  false, false, false, false, false, false, false, false },\n    { \"uint64\",       field_view(42u),                     field_kind::uint64,   false, false, true,  false, false, false, false, false, false, false },\n    { \"string\",       field_view(\"test\"),                  field_kind::string,   false, false, false, true,  false, false, false, false, false, false },\n    { \"blob\",         field_view(makebv(\"\\0\\1\\xff\")),      field_kind::blob,     false, false, false, false, true,  false, false, false, false, false },\n    { \"float\",        field_view(4.2f),                    field_kind::float_,   false, false, false, false, false, true,  false, false, false, false },\n    { \"double\",       field_view(4.2),                     field_kind::double_,  false, false, false, false, false, false, true,  false, false, false },\n    { \"date\",         field_view(date(2020u, 1u, 1u)),     field_kind::date,     false, false, false, false, false, false, false, true,  false, false },\n    { \"datetime\",     field_view(datetime(2020u, 1u, 1u)), field_kind::datetime, false, false, false, false, false, false, false, false, true,  false },\n    { \"time\",         field_view(maket(20u, 1u, 1u)),      field_kind::time,     false, false, false, false, false, false, false, false, false, true },\n    { \"ref_null\",     field_view(f_null),                  field_kind::null,     true,  false, false, false, false, false, false, false, false, false },\n    { \"ref_int64\",    field_view(f_int64),                 field_kind::int64,    false, true,  false, false, false, false, false, false, false, false },\n    { \"ref_uint64\",   field_view(f_uint64),                field_kind::uint64,   false, false, true,  false, false, false, false, false, false, false },\n    { \"ref_string\",   field_view(f_string),                field_kind::string,   false, false, false, true,  false, false, false, false, false, false },\n    { \"ref_blob\",     field_view(f_blob),                  field_kind::blob,     false, false, false, false, true,  false, false, false, false, false },\n    { \"ref_float\",    field_view(f_float),                 field_kind::float_,   false, false, false, false, false, true,  false, false, false, false },\n    { \"ref_double\",   field_view(f_double),                field_kind::double_,  false, false, false, false, false, false, true,  false, false, false },\n    { \"ref_date\",     field_view(f_date),                  field_kind::date,     false, false, false, false, false, false, false, true,  false, false },\n    { \"ref_datetime\", field_view(f_datetime),              field_kind::datetime, false, false, false, false, false, false, false, false, true,  false },\n    { \"ref_time\",     field_view(f_time),                  field_kind::time,     false, false, false, false, false, false, false, false, false, true },\n};\n// clang-format on\n\nBOOST_AUTO_TEST_CASE(kind)\n{\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST(tc.field.kind() == tc.expected_kind, tc.name);\n    }\n}\n\nBOOST_AUTO_TEST_CASE(is)\n{\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            BOOST_TEST(tc.field.is_null() == tc.is_null);\n            BOOST_TEST(tc.field.is_int64() == tc.is_int64);\n            BOOST_TEST(tc.field.is_uint64() == tc.is_uint64);\n            BOOST_TEST(tc.field.is_string() == tc.is_string);\n            BOOST_TEST(tc.field.is_blob() == tc.is_blob);\n            BOOST_TEST(tc.field.is_float() == tc.is_float);\n            BOOST_TEST(tc.field.is_double() == tc.is_double);\n            BOOST_TEST(tc.field.is_date() == tc.is_date);\n            BOOST_TEST(tc.field.is_datetime() == tc.is_datetime);\n            BOOST_TEST(tc.field.is_time() == tc.is_time);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(as_exceptions)\n{\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            if (tc.is_int64)\n                BOOST_CHECK_NO_THROW(tc.field.as_int64());\n            else\n                BOOST_CHECK_THROW(tc.field.as_int64(), boost::mysql::bad_field_access);\n\n            if (tc.is_uint64)\n                BOOST_CHECK_NO_THROW(tc.field.as_uint64());\n            else\n                BOOST_CHECK_THROW(tc.field.as_uint64(), boost::mysql::bad_field_access);\n\n            if (tc.is_string)\n                BOOST_CHECK_NO_THROW(tc.field.as_string());\n            else\n                BOOST_CHECK_THROW(tc.field.as_string(), boost::mysql::bad_field_access);\n\n            if (tc.is_blob)\n                BOOST_CHECK_NO_THROW(tc.field.as_blob());\n            else\n                BOOST_CHECK_THROW(tc.field.as_blob(), boost::mysql::bad_field_access);\n\n            if (tc.is_float)\n                BOOST_CHECK_NO_THROW(tc.field.as_float());\n            else\n                BOOST_CHECK_THROW(tc.field.as_float(), boost::mysql::bad_field_access);\n\n            if (tc.is_double)\n                BOOST_CHECK_NO_THROW(tc.field.as_double());\n            else\n                BOOST_CHECK_THROW(tc.field.as_double(), boost::mysql::bad_field_access);\n\n            if (tc.is_date)\n                BOOST_CHECK_NO_THROW(tc.field.as_date());\n            else\n                BOOST_CHECK_THROW(tc.field.as_date(), boost::mysql::bad_field_access);\n\n            if (tc.is_datetime)\n                BOOST_CHECK_NO_THROW(tc.field.as_datetime());\n            else\n                BOOST_CHECK_THROW(tc.field.as_datetime(), boost::mysql::bad_field_access);\n\n            if (tc.is_time)\n                BOOST_CHECK_NO_THROW(tc.field.as_time());\n            else\n                BOOST_CHECK_THROW(tc.field.as_time(), boost::mysql::bad_field_access);\n        }\n    }\n}\n\n// Success cases (the type matches the called function)\nBOOST_AUTO_TEST_CASE(int64)\n{\n    field_view f(-1);\n    BOOST_TEST(f.as_int64() == -1);\n    BOOST_TEST(f.get_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(uint64)\n{\n    field_view f(42u);\n    BOOST_TEST(f.as_uint64() == 42u);\n    BOOST_TEST(f.get_uint64() == 42u);\n}\n\nBOOST_AUTO_TEST_CASE(string)\n{\n    field_view f(\"test\");\n    BOOST_TEST(f.as_string() == \"test\");\n    BOOST_TEST(f.get_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(blob_)\n{\n    std::uint8_t buff[] = {0x00, 0x0f, 0x01};\n    field_view f{blob_view(buff)};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.as_blob(), buff);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(f.get_blob(), buff);\n}\n\nBOOST_AUTO_TEST_CASE(float_)\n{\n    field_view f(4.2f);\n    BOOST_TEST(f.as_float() == 4.2f);\n    BOOST_TEST(f.get_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(double_)\n{\n    field_view f(4.2);\n    BOOST_TEST(f.as_double() == 4.2);\n    BOOST_TEST(f.get_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(date_)\n{\n    date d(2020u, 1u, 2u);\n    field_view f(d);\n    BOOST_TEST(f.as_date() == d);\n    BOOST_TEST(f.get_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(datetime_)\n{\n    datetime dt(2020u, 1u, 2u);\n    field_view f(dt);\n    BOOST_TEST(f.as_datetime() == dt);\n    BOOST_TEST(f.get_datetime() == dt);\n}\n\nBOOST_AUTO_TEST_CASE(time)\n{\n    auto t = maket(2020, 1, 2);\n    field_view f(t);\n    BOOST_TEST(f.as_time() == t);\n    BOOST_TEST(f.get_time() == t);\n}\n\nBOOST_AUTO_TEST_CASE(ref_int64)\n{\n    field f(-1);\n    field_view fv(f);\n    BOOST_TEST(fv.as_int64() == -1);\n    BOOST_TEST(fv.get_int64() == -1);\n}\n\nBOOST_AUTO_TEST_CASE(ref_uint64)\n{\n    field f(42u);\n    field_view fv(f);\n    BOOST_TEST(fv.as_uint64() == 42u);\n    BOOST_TEST(fv.get_uint64() == 42u);\n}\n\nBOOST_AUTO_TEST_CASE(ref_string)\n{\n    field f(\"test\");\n    field_view fv(f);\n    BOOST_TEST(fv.as_string() == \"test\");\n    BOOST_TEST(fv.get_string() == \"test\");\n}\n\nBOOST_AUTO_TEST_CASE(ref_blob)\n{\n    std::uint8_t buff[] = {0x00, 0x01, 0x02};\n    field f{blob(std::begin(buff), std::end(buff))};\n    field_view fv(f);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(fv.as_blob(), buff);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(fv.get_blob(), buff);\n}\n\nBOOST_AUTO_TEST_CASE(ref_float)\n{\n    field f(4.2f);\n    field_view fv(f);\n    BOOST_TEST(fv.as_float() == 4.2f);\n    BOOST_TEST(fv.get_float() == 4.2f);\n}\n\nBOOST_AUTO_TEST_CASE(ref_double)\n{\n    field f(4.2);\n    field_view fv(f);\n    BOOST_TEST(fv.as_double() == 4.2);\n    BOOST_TEST(fv.get_double() == 4.2);\n}\n\nBOOST_AUTO_TEST_CASE(ref_date)\n{\n    date d(2020u, 1u, 2u);\n    field f(d);\n    field_view fv(f);\n    BOOST_TEST(fv.as_date() == d);\n    BOOST_TEST(fv.get_date() == d);\n}\n\nBOOST_AUTO_TEST_CASE(ref_datetime)\n{\n    datetime dt(2020u, 1u, 2u);\n    field f(dt);\n    field_view fv(f);\n    BOOST_TEST(fv.as_datetime() == dt);\n    BOOST_TEST(fv.get_datetime() == dt);\n}\n\nBOOST_AUTO_TEST_CASE(ref_time)\n{\n    auto t = maket(2020, 1, 2);\n    field f(t);\n    field_view fv(t);\n    BOOST_TEST(fv.as_time() == t);\n    BOOST_TEST(fv.get_time() == t);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE(operator_equals)\n{\n    // clang-format off\n    struct\n    {\n        const char* name;\n        field_view f1;\n        field_view f2;\n        bool is_equal;\n    } test_cases [] = {\n        { \"null_null\", field_view(), field_view(), true, },\n        { \"null_int64\", field_view(), field_view(-1), false },\n        { \"null_uint64\", field_view(), field_view(42), false },\n        { \"null_string\", field_view(), field_view(\"<NULL>\"), false },\n        { \"null_blob\", field_view(), field_view(blob_view()), false },\n        { \"null_float\", field_view(), field_view(4.2f), false },\n        { \"null_double\", field_view(), field_view(4.3), false },\n        { \"null_date\", field_view(), field_view(date(2020u, 1u, 2u)), false },\n        { \"null_datetime\", field_view(), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"null_time\", field_view(), field_view(maket(23, 1, 1)), false },\n\n        { \"int64_int64_same\", field_view(42), field_view(42), true },\n        { \"int64_int64_different\", field_view(42), field_view(-1), false },\n        { \"int64_uint64_same\", field_view(42), field_view(42u), true },\n        { \"int64_uint64_different\", field_view(42), field_view(43u), false },\n        { \"int64_uint64_zero\", field_view(0), field_view(0u), true },\n        { \"int64_uint64_lt0\", field_view(-1), field_view(42u), false },\n        { \"int64_uint64_gtmax\", field_view(42), field_view(0xffffffffffffffffu), false },\n        { \"int64_uint64_lt0gtmax\", field_view(-1), field_view(0xffffffffffffffffu), false },\n        { \"int64_string\", field_view(42), field_view(\"42\"), false },\n        { \"int64_blob\", field_view(42), field_view(makebv(\"42\")), false },\n        { \"int64_float\", field_view(42), field_view(42.0f), false },\n        { \"int64_double\", field_view(42), field_view(42.0), false },\n        { \"int64_date\", field_view(42), field_view(date(2020u, 1u, 1u)), false },\n        { \"int64_datetime\", field_view(42), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"int64_time\", field_view(42), field_view(maket(20, 1, 1)), false },\n\n        { \"uint64_uint64_same\", field_view(0xffffffffffffffffu), field_view(0xffffffffffffffffu), true },\n        { \"uint64_uint64_different\", field_view(42u), field_view(31u), false },\n        { \"uint64_string\", field_view(42u), field_view(\"42\"), false },\n        { \"uint64_blob\", field_view(42u), field_view(makebv(\"42\")), false },\n        { \"uint64_float\", field_view(42u), field_view(42.0f), false },\n        { \"uint64_double\", field_view(42u), field_view(42.0), false },\n        { \"uint64_date\", field_view(42u), field_view(date(2020u, 1u, 1u)), false },\n        { \"uint64_datetime\", field_view(42u), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"uint64_time\", field_view(42u), field_view(maket(20, 1, 1)), false },\n\n        { \"string_string_same\", field_view(\"test\"), field_view(\"test\"), true },\n        { \"string_string_different\", field_view(\"test\"), field_view(\"test2\"), false },\n        { \"string_blob\", field_view(\"test\"), field_view(makebv(\"test\")), false },\n        { \"string_float\", field_view(\"4.2\"), field_view(4.2f), false },\n        { \"string_double\", field_view(\"4.2\"), field_view(4.2), false },\n        { \"string_date\", field_view(\"2020-01-01\"), field_view(date(2020u, 1u, 1u)), false },\n        { \"string_datetime\", field_view(\"test\"), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"string_time\", field_view(\"test\"), field_view(maket(8, 1, 1)), false },\n        \n        { \"blob_blob_same\", field_view(makebv(\"\\0test\")), field_view(makebv(\"\\0test\")), true },\n        { \"blob_blob_different\", field_view(makebv(\"\\0test\")), field_view(makebv(\"\\0test2\")), false },\n        { \"blob_blob_different_same_size\", field_view(makebv(\"\\0test\")), field_view(makebv(\"\\1test\")), false },\n        { \"blob_blob_same_empty\", field_view(blob_view()), field_view(blob_view()), true },\n        { \"blob_blob_different_empty\", field_view(blob_view()), field_view(makebv(\"\\0test\")), false },\n        { \"blob_float\", field_view(makebv(\"\\x40\\x86\\x66\\x66\")), field_view(4.2f), false },\n        { \"blob_double\", field_view(makebv(\"4.2\")), field_view(4.2), false },\n        { \"blob_date\", field_view(makebv(\"2020-01-01\")), field_view(date(2020u, 1u, 1u)), false },\n        { \"blob_datetime\", field_view(makebv(\"test\")), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"blob_time\", field_view(makebv(\"test\")), field_view(maket(8, 1, 1)), false },\n\n        { \"float_float_same\", field_view(4.2f), field_view(4.2f), true },\n        { \"float_float_different\", field_view(4.2f), field_view(0.0f), false },\n        { \"float_double\", field_view(4.2f), field_view(4.2), false },\n        { \"float_date\", field_view(4.2f), field_view(date(2020u, 1u, 2u)), false },\n        { \"float_datetime\", field_view(4.2f), field_view(datetime(2020u, 1u, 2u)), false },\n        { \"float_time\", field_view(4.2f), field_view(maket(20, 1, 2)), false },\n\n        { \"double_double_same\", field_view(4.2), field_view(4.2), true },\n        { \"double_double_different\", field_view(4.2), field_view(-1.0), false },\n        { \"double_date\", field_view(4.2), field_view(date(2020u, 1u, 1u)), false },\n        { \"double_datetime\", field_view(4.2), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"double_time\", field_view(4.2), field_view(maket(9, 1, 1)), false },\n\n        { \"date_date_same\", field_view(date(2020u, 1u, 1u)), field_view(date(2020u, 1u, 1u)), true },\n        { \"date_date_different\", field_view(date(2020u, 1u, 1u)), field_view(date(2019u, 1u, 1u)), false },\n        { \"date_datetime\", field_view(date(2020u, 1u, 1u)), field_view(datetime(2020u, 1u, 1u)), false },\n        { \"date_time\", field_view(date(2020u, 1u, 1u)), field_view(maket(9, 1, 1)), false },\n\n        { \"datetime_datetime_same\", field_view(datetime(2020u, 1u, 1u, 10u)), field_view(datetime(2020u, 1u, 1u, 10u)), true },\n        { \"datetime_datetime_different\", field_view(datetime(2020u, 1u, 1u, 10u)), field_view(datetime(2020u, 1u, 1u, 9u)), false },\n        { \"datetime_time\", field_view(datetime(2020u, 1u, 1u)), field_view(maket(20, 1, 1)), false },\n\n        { \"time_time_same\", field_view(maket(20, 1, 1)), field_view(maket(20, 1, 1)), true },\n        { \"time_time_different\", field_view(maket(20, 1, 1)), field_view(maket(20, 1, 1, 10)), false },\n    };\n    // clang-format on\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // We compare regular field_view's and field_view's holding\n            // pointers to fields, using the same cases to reduce duplication\n            field owning_1(tc.f1);\n            field owning_2(tc.f2);\n\n            field_view f1 = tc.f1;\n            field_view f2 = tc.f2;\n\n            field_view fref1(owning_1);\n            field_view fref2(owning_2);\n\n            if (tc.is_equal)\n            {\n                BOOST_TEST(f1 == f2);\n                BOOST_TEST(f2 == f1);\n                BOOST_TEST(fref1 == fref2);\n                BOOST_TEST(fref2 == fref1);\n                BOOST_TEST(f1 == fref2);\n                BOOST_TEST(fref2 == f1);\n\n                BOOST_TEST(!(f1 != f2));\n            }\n            else\n            {\n                BOOST_TEST(!(f1 == f2));\n                BOOST_TEST(!(f2 == f1));\n                BOOST_TEST(!(fref1 == fref2));\n                BOOST_TEST(!(fref2 == fref1));\n                BOOST_TEST(!(f1 == fref2));\n                BOOST_TEST(!(fref2 == f1));\n\n                BOOST_TEST(tc.f1 != tc.f2);\n                BOOST_TEST(tc.f2 != tc.f1);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(operator_equals_self_compare)\n{\n    // clang-format off\n    struct\n    {\n        const char* name;\n        field_view f;\n    } test_cases [] = {\n        { \"null\", field_view() },\n        { \"int64\", field_view(40), },\n        { \"uint64\", field_view(42u) },\n        { \"string\", field_view(\"test\") },\n        { \"blob\", field_view(makebv(\"\\0\\0ab\\1\")) },\n        { \"float\", field_view(4.2f) },\n        { \"double\", field_view(5.0) },\n        { \"date\", field_view(date(2020u, 1u, 1u)) },\n        { \"datetime\", field_view(datetime(2020u, 1u, 1u)) },\n        { \"time\", field_view(maket(8, 1, 1)) }\n    };\n    // clang-format on\n\n    for (const auto& tc : test_cases)\n    {\n        // Regular field_view\n        BOOST_TEST(tc.f == tc.f);\n\n        // Reference to an owning field\n        field owning_field(tc.f);\n        field_view fref(owning_field);\n        BOOST_TEST(fref == fref);\n    }\n}\n\n// operator<<\nstruct stream_sample\n{\n    std::string name;\n    field_view input;\n    std::string expected;\n\n    template <class T>\n    stream_sample(std::string&& name, const T& input, std::string&& expected)\n        : name(std::move(name)), input(input), expected(std::move(expected))\n    {\n    }\n};\n\nBOOST_AUTO_TEST_CASE(operator_stream)\n{\n    struct owning_fields_t\n    {\n        field f_null{};\n        field f_int64{-1};\n        field f_uint64{50u};\n        field f_string{\"long_test_string\"};\n        field f_blob{\n            blob{0x00, 0x32, 0x01}\n        };\n        field f_float{4.2f};\n        field f_double{5.1};\n        field f_date{date(2020u, 1u, 1u)};\n        field f_datetime{datetime(2019u, 1u, 1u, 21u, 19u, 1u, 9u)};\n        field f_time{maket(9, 1, 0, 210)};\n    };\n    static owning_fields_t owning_fields;\n\n    struct test_case_t\n    {\n        string_view name;\n        field_view input;\n        string_view expected;\n    } test_cases[] = {\n        // Field views holding values\n        {\"null\", field_view(), \"<NULL>\"},\n        {\"i64_positive\", field_view(std::int64_t(42)), \"42\"},\n        {\"i64_negative\", field_view(std::int64_t(-90)), \"-90\"},\n        {\"i64_zero\", field_view(std::int64_t(0)), \"0\"},\n        {\"u64_positive\", field_view(std::uint64_t(42)), \"42\"},\n        {\"u64_zero\", field_view(std::uint64_t(0)), \"0\"},\n        {\"string_view\", field_view(\"a_string\"), \"a_string\"},\n        {\"blob_empty\", field_view(blob_view()), \"{}\"},\n        {\"blob_one_elm\", field_view(makebv(\"\\4\")), \"{ 0x04 }\"},\n        {\"blob_two_elms\", field_view(makebv(\"\\4\\5\")), \"{ 0x04, 0x05 }\"},\n        {\"blob_several_elms\", field_view(makebv(\"\\0\\x0a\\x2f\\xff\")), \"{ 0x00, 0x0a, 0x2f, 0xff }\"},\n        {\"blob_padding\",\n         field_view(makebv(\"\\x0e\\x0f\\x0a\\x0b\\x1f\\x20\\x7f\\x80\\xff\")),\n         \"{ 0x0e, 0x0f, 0x0a, 0x0b, 0x1f, 0x20, 0x7f, 0x80, 0xff }\"},\n        {\"float\", field_view(2.43f), \"2.43\"},\n        {\"double\", field_view(8.12), \"8.12\"},\n        {\"date\", field_view(date(2020, 1, 19)), \"2020-01-19\"},\n        {\"datetime\", field_view(datetime(2020, 1, 19, 11, 30, 21, 98765)), \"2020-01-19 11:30:21.098765\"},\n        {\"time\", field_view(-maket(12, 1, 5, 345)), \"-12:01:05.000345\"},\n\n        // Field views holding pointers to fields\n        {\"ref_null\", field_view(owning_fields.f_null), \"<NULL>\"},\n        {\"ref_int64\", field_view(owning_fields.f_int64), \"-1\"},\n        {\"ref_uint64\", field_view(owning_fields.f_uint64), \"50\"},\n        {\"ref_string\", field_view(owning_fields.f_string), \"long_test_string\"},\n        {\"ref_blob\", field_view(owning_fields.f_blob), \"{ 0x00, 0x32, 0x01 }\"},\n        {\"ref_float\", field_view(owning_fields.f_float), \"4.2\"},\n        {\"ref_double\", field_view(owning_fields.f_double), \"5.1\"},\n        {\"ref_date\", field_view(owning_fields.f_date), \"2020-01-01\"},\n        {\"ref_datetime\", field_view(owning_fields.f_datetime), \"2019-01-01 21:19:01.000009\"},\n        {\"ref_time\", field_view(owning_fields.f_time), \"09:01:00.000210\"},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            std::ostringstream ss;\n            ss << tc.input;\n            BOOST_TEST(ss.str() == tc.expected);\n        }\n    }\n}\n\n// Make sure constxpr can actually be used in a constexpr context\n// C++14+ only\n#ifndef BOOST_NO_CXX14_CONSTEXPR\n\nBOOST_AUTO_TEST_SUITE(constexpr_fns)\n\nBOOST_AUTO_TEST_CASE(null)\n{\n    constexpr field_view v{};\n    constexpr field_view v2(nullptr);\n    static_assert(v.is_null(), \"\");\n    static_assert(v == v2, \"\");\n    static_assert(!(v != v2), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(int64)\n{\n    constexpr field_view v(60);\n    static_assert(v.is_int64(), \"\");\n    static_assert(v.as_int64() == 60, \"\");\n    static_assert(v.get_int64() == 60, \"\");\n    static_assert(v == field_view(60), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(uint64)\n{\n    constexpr field_view v(60u);\n    static_assert(v.is_uint64(), \"\");\n    static_assert(v.as_uint64() == 60u, \"\");\n    static_assert(v.get_uint64() == 60u, \"\");\n    static_assert(v == field_view(60u), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(string)\n{\n    constexpr field_view v(makesv(\"test\"));\n    static_assert(v.is_string(), \"\");\n    static_assert(v.as_string()[0] == 't', \"\");\n    static_assert(v.get_string()[0] == 't', \"\");\n    // string_view comparison uses char_traits::compare, which is not constexpr in C++14\n}\n\nBOOST_AUTO_TEST_CASE(blob)\n{\n    constexpr field_view v{blob_view()};\n    static_assert(v.is_blob(), \"\");\n    static_assert(v.as_blob().empty(), \"\");\n    static_assert(v.get_blob().empty(), \"\");\n    // blob comparison is not constexpr\n}\n\nBOOST_AUTO_TEST_CASE(float_)\n{\n    constexpr field_view v(4.2f);\n    static_assert(v.is_float(), \"\");\n    static_assert(v.as_float() == 4.2f, \"\");\n    static_assert(v.get_float() == 4.2f, \"\");\n    static_assert(v == field_view(4.2f), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(double_)\n{\n    constexpr field_view v(4.2);\n    static_assert(v.is_double(), \"\");\n    static_assert(v.as_double() == 4.2, \"\");\n    static_assert(v.get_double() == 4.2, \"\");\n    static_assert(v == field_view(4.2), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(date_)\n{\n    constexpr date d(2020, 1, 1);\n    constexpr field_view v(d);\n    static_assert(v.is_date(), \"\");\n    static_assert(v.as_date() == d, \"\");\n    static_assert(v.get_date() == d, \"\");\n    static_assert(v == field_view(d), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(datetime_)\n{\n    constexpr datetime d(2020u, 1u, 1u);\n    constexpr field_view v(d);\n    static_assert(v.is_datetime(), \"\");\n    static_assert(v.as_datetime() == d, \"\");\n    static_assert(v.get_datetime() == d, \"\");\n    static_assert(v == field_view(d), \"\");\n}\n\nBOOST_AUTO_TEST_CASE(time)\n{\n    constexpr auto t = maket(8, 1, 1);\n    constexpr field_view v(t);\n    static_assert(v.is_time(), \"\");\n    static_assert(v.as_time() == t, \"\");\n    static_assert(v.get_time() == t, \"\");\n    static_assert(v == field_view(t), \"\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif  // BOOST_NO_CXX14_CONSTEXPR\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/format_sql/api.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cmath>\n#include <initializer_list>\n#include <string>\n\n#include \"format_common.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/custom_allocator.hpp\"\n#include \"test_unit/ff_charset.hpp\"\n\n//\n// Contains spotchecks verifying that the main success and error cases\n// work using each of the APIs.\n//\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_format_sql_api)\n\nusing string_with_alloc = std::basic_string<char, std::char_traits<char>, custom_allocator<char>>;\n\nconstexpr format_options opts{utf8mb4_charset, true};\n\n//\n// format_sql\n//\nBOOST_AUTO_TEST_CASE(format_sql_success)\n{\n    constexpr const char* format_str = \"SELECT * FROM {:i} WHERE id = {} OR name = {}\";\n    auto str = format_sql(opts, format_str, \"my`table\", 42, \"Joh'n\");\n    BOOST_TEST(str == R\"(SELECT * FROM `my``table` WHERE id = 42 OR name = 'Joh\\'n')\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_invalid_args)\n{\n    // When passed invalid arguments (like strings with invalid UTF-8 or NaNs) we throw\n    BOOST_CHECK_EXCEPTION(\n        format_sql(opts, \"SELECT {}\", \"Invalid\\xffUTF8\"),\n        boost::system::system_error,\n        [&](const boost::system::system_error& err) {\n            std::string expected_diag =\n                \"A string passed to a formatting function contains a byte sequence that can't be decoded \"\n                \"with the current character set. [mysql.client:17]\";\n            BOOST_TEST(err.code() == client_errc::invalid_encoding);\n            BOOST_TEST(err.what() == expected_diag);\n            return true;\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_invalid_format_string)\n{\n    // When passed an invalid format string, we throw\n    BOOST_CHECK_EXCEPTION(\n        format_sql(opts, \"SELECT {not_found}\", 42),\n        boost::system::system_error,\n        [&](const boost::system::system_error& err) {\n            std::string expected_diag =\n                \"A format argument referenced by a format string was not found. Check the number of format \"\n                \"arguments passed and their names. [mysql.client:23]\";\n            BOOST_TEST(err.code() == client_errc::format_arg_not_found);\n            BOOST_TEST(err.what() == expected_diag);\n            return true;\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_initializer_list)\n{\n    std::initializer_list<format_arg> args{\n        {\"name\", \"value\"}\n    };\n    BOOST_TEST(format_sql(opts, \"SELECT {name}\", args) == \"SELECT 'value'\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_empty_initializer_list)\n{\n    BOOST_TEST(format_sql(opts, \"SELECT 42\", {}) == \"SELECT 42\");\n}\n\n//\n// Formatting using format_sql_to\n//\nBOOST_AUTO_TEST_CASE(format_sql_to_success)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT * FROM {:i} WHERE id = {} OR name = {}\", \"my`table\", 42, \"Joh'n\");\n    BOOST_TEST(\n        std::move(ctx).get().value() == R\"(SELECT * FROM `my``table` WHERE id = 42 OR name = 'Joh\\'n')\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_append)\n{\n    // The output string is not cleared by format_sql_to, allowing appending\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT {}\", 42);\n    format_sql_to(ctx, \", {}, {}\", \"'John'\", \"\\\"Doe\\\"\");\n    BOOST_TEST(std::move(ctx).get().value() == R\"(SELECT 42, '\\'John\\'', '\\\"Doe\\\"')\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_custom_type)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT {}\", custom::condition{\"number\", 42});\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT `number`=42\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_no_arguments)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT 42\");\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT 42\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_custom_charset)\n{\n    // The character set is honored by the format string and by format args\n    format_context ctx({ff_charset, true});\n    format_sql_to(ctx, \"SELECT \\xff{ {}\", \"Joh\\xff'n'\");\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT \\xff{ 'Joh\\xff'n\\\\''\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_backslash_escapes)\n{\n    // The backslash escapes options is honored\n    format_context ctx({utf8mb4_charset, false});\n    format_sql_to(ctx, \"SELECT {}\", \"Joh'n\");\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT 'Joh''n'\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_custom_string)\n{\n    // We can use format_sql_to with contexts that are not format_context\n    using context_t = basic_format_context<string_with_alloc>;\n\n    context_t ctx(opts);\n    format_sql_to(ctx, \"SELECT * FROM {:i} WHERE id = {} OR name = {}\", \"myt`able\", 42, \"Joh'n\");\n    BOOST_TEST(\n        std::move(ctx).get().value() == R\"(SELECT * FROM `myt``able` WHERE id = 42 OR name = 'Joh\\'n')\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_invalid_arg)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT {}, {}\", \"Bad\\xc5\", 42);\n    BOOST_TEST(std::move(ctx).get().error() == client_errc::invalid_encoding);\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_invalid_format_string)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT {broken\", 42);\n    BOOST_TEST(std::move(ctx).get().error() == client_errc::format_string_invalid_syntax);\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_initializer_list)\n{\n    format_context ctx(opts);\n    std::initializer_list<format_arg> args{\n        {\"name\", \"abc\"}\n    };\n    format_sql_to(ctx, \"SELECT {name}\", args);\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT 'abc'\");\n}\n\nBOOST_AUTO_TEST_CASE(format_sql_to_empty_initializer_list)\n{\n    format_context ctx(opts);\n    format_sql_to(ctx, \"SELECT 42\", {});\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT 42\");\n}\n\n//\n// Formatting using format_context: verify that we can achieve similar results as using format_sql\n//\n\nBOOST_AUTO_TEST_CASE(format_context_success)\n{\n    // Helper\n    auto get = [](format_context_base& ctx) { return static_cast<format_context&&>(ctx).get().value(); };\n\n    // Empty\n    BOOST_TEST(format_context(opts).get().value() == \"\");\n\n    // Raw\n    BOOST_TEST(get(format_context(opts).append_raw(\"SELECT 'abc'\")) == \"SELECT 'abc'\");\n\n    // Value\n    BOOST_TEST(get(format_context(opts).append_value(42)) == \"42\");\n    BOOST_TEST(get(format_context(opts).append_value(\"a str'ing\")) == \"'a str\\\\'ing'\");\n    BOOST_TEST(get(format_context(opts).append_value(true)) == \"1\");\n\n    // Specifiers work\n    BOOST_TEST(get(format_context(opts).append_value(\"abc`d\", \"i\")) == \"`abc``d`\");\n\n    // Custom values work\n    BOOST_TEST(get(format_context(opts).append_value(custom::condition{\"id\", 42})) == \"`id`=42\");\n\n    // Raw/value combinations\n    BOOST_TEST(get(format_context(opts).append_raw(\"SELECT \").append_value(42)) == \"SELECT 42\");\n    BOOST_TEST(get(format_context(opts).append_value(42).append_raw(\" OR 1=1\")) == \"42 OR 1=1\");\n    BOOST_TEST(\n        get(format_context(opts).append_raw(\"SELECT \").append_raw(\"* FROM \").append_value(\"myt\", \"i\")) ==\n        \"SELECT * FROM `myt`\"\n    );\n    BOOST_TEST(\n        get(format_context(opts).append_raw(\"SELECT \").append_value(42).append_raw(\" OR 1=1\")) ==\n        \"SELECT 42 OR 1=1\"\n    );\n    BOOST_TEST(\n        get(format_context(opts).append_value(42).append_value(nullptr).append_raw(\" OR 1=1\")) ==\n        \"42NULL OR 1=1\"\n    );\n    BOOST_TEST(\n        get(format_context(opts)\n                .append_raw(\"SELECT \")\n                .append_value(42)\n                .append_raw(\" UNION SELECT \")\n                .append_value(true)\n                .append_raw(\" UNION SELECT 'abc'\")) == \"SELECT 42 UNION SELECT 1 UNION SELECT 'abc'\"\n    );\n}\n\n// charset and backslash_escapes options are honored\nBOOST_AUTO_TEST_CASE(format_context_charset)\n{\n    format_options opts_charset{ff_charset, true};\n\n    format_context ctx(opts_charset);\n    ctx.append_raw(\"SELECT '\\xff{abc' + \")\n        .append_value(\"abd\\xff{}\")\n        .append_raw(\" + \")\n        .append_value(\"i`d`ent\\xff`ifier\", \"i\");\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT '\\xff{abc' + 'abd\\xff{}' + `i``d``ent\\xff`ifier`\");\n}\n\nBOOST_AUTO_TEST_CASE(format_context_backslashes)\n{\n    format_options opts_charset{ff_charset, false};\n\n    format_context ctx(opts_charset);\n    ctx.append_raw(\"SELECT \").append_value(\"ab'cd\\\"ef\").append_raw(\" + \").append_value(\"identif`ier\", \"i\");\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT 'ab''cd\\\"ef' + `identif``ier`\");\n}\n\nBOOST_AUTO_TEST_CASE(format_context_error)\n{\n    // Helper\n    auto get = [](format_context_base& ctx) { return static_cast<format_context&&>(ctx).get().error(); };\n\n    // Just an error\n    BOOST_TEST(get(format_context(opts).append_value(\"bad\\xff\")) == client_errc::invalid_encoding);\n\n    // Raw/error combinations\n    BOOST_TEST(\n        get(format_context(opts).append_raw(\"SELECT \").append_value(\"bad\\xff\")) ==\n        client_errc::invalid_encoding\n    );\n    BOOST_TEST(\n        get(format_context(opts).append_value(\"bad\\xff\").append_raw(\"SELECT 1\")) ==\n        client_errc::invalid_encoding\n    );\n    BOOST_TEST(\n        get(format_context(opts).append_raw(\"SELECT 1\").append_value(\"bad\\xff\").append_raw(\"SELECT 1\")) ==\n        client_errc::invalid_encoding\n    );\n\n    // Error/value combinations: we keep errors even after appending correct values\n    BOOST_TEST(\n        get(format_context(opts).append_value(\"abc\").append_value(\"bad\\xff\")) == client_errc::invalid_encoding\n    );\n    BOOST_TEST(\n        get(format_context(opts).append_value(\"bad\\xff\").append_value(\"abc\")) == client_errc::invalid_encoding\n    );\n    BOOST_TEST(\n        get(format_context(opts)\n                .append_raw(\"SELECT * FROM \")\n                .append_value(\"bad\\xff\", \"i\")\n                .append_raw(\" WHERE id=\")\n                .append_value(42)) == client_errc::invalid_encoding\n    );\n\n    // We only keep the first error\n    BOOST_TEST(\n        get(format_context(opts).append_value(\"bad\\xff\").append_raw(\"abc\").append_value(HUGE_VAL)) ==\n        client_errc::invalid_encoding\n    );\n\n    // Spotcheck: invalid floats are diagnosed correctly\n    BOOST_TEST(get(format_context(opts).append_value(HUGE_VAL)) == client_errc::unformattable_value);\n\n    // Spotcheck: invalid specifiers are diagnosed correctly\n    BOOST_TEST(\n        get(format_context(opts).append_value(\"abc\", \"u\")) == client_errc::format_string_invalid_specifier\n    );\n}\n\n// Spotcheck: we can use string types that are not std::string with format context\nBOOST_AUTO_TEST_CASE(format_context_custom_string)\n{\n    using context_t = basic_format_context<string_with_alloc>;\n\n    context_t ctx(opts);\n    ctx.append_raw(\"SELECT * FROM \")\n        .append_value(\"myt`able\", \"i\")\n        .append_raw(\" WHERE id = \")\n        .append_value(42)\n        .append_raw(\" OR name = \")\n        .append_value(\"Joh'n\");\n    BOOST_TEST(\n        std::move(ctx).get().value() == R\"(SELECT * FROM `myt``able` WHERE id = 42 OR name = 'Joh\\'n')\"\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/format_sql/basic_format_context.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_basic_format_context)\n\nstatic format_options opts{utf8mb4_charset, true};\nstatic format_options ascii_opts{ascii_charset, true};\n\n// An OutputString with the bare minimum members\nstruct string_archetype\n{\n    std::string impl;\n\n    // No default constructor\n    string_archetype(int) {}\n\n    // No copy operations\n    string_archetype(const string_archetype&) = delete;\n    string_archetype& operator=(const string_archetype&) = delete;\n\n    // Move operations allowed\n    string_archetype(string_archetype&&) = default;\n    string_archetype& operator=(string_archetype&&) = default;\n\n    // Adequate member functions\n    void append(const char* data, std::size_t size) { impl.append(data, size); }\n    void clear() { impl.clear(); }\n};\n\n// An OutputString that is also default constructible\nstruct string_archetype_defctor : string_archetype\n{\n    string_archetype_defctor() : string_archetype(42) {}\n};\n\nusing archetype_context = basic_format_context<string_archetype>;\n\nBOOST_AUTO_TEST_CASE(ctor_without_storage)\n{\n    // Construct\n    basic_format_context<string_archetype_defctor> ctx(opts);\n\n    // Check error state and options\n    BOOST_TEST(ctx.error_state() == error_code());\n    BOOST_TEST(ctx.format_opts().charset.name == \"utf8mb4\");\n\n    // Can be used to append and result can be retrieved\n    ctx.append_raw(\"SELECT \").append_value(42);\n    BOOST_TEST(std::move(ctx).get().value().impl == \"SELECT 42\");\n}\n\nBOOST_AUTO_TEST_CASE(ctor_with_storage)\n{\n    // The string to move from. Heap helps asan detect memory errors\n    std::unique_ptr<string_archetype> s(new string_archetype(100));\n    s->impl = \"abcd\";\n\n    // Construct\n    archetype_context ctx(opts, std::move(*s));\n    s.reset();\n\n    // Check error state and options\n    BOOST_TEST(ctx.error_state() == error_code());\n    BOOST_TEST(ctx.format_opts().charset.name == \"utf8mb4\");\n\n    // Can be used to append and result can be retrieved\n    ctx.append_raw(\"SELECT \").append_value(42);\n    BOOST_TEST(std::move(ctx).get().value().impl == \"SELECT 42\");\n}\n\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Move source. Heap helps asan\n    std::unique_ptr<archetype_context> source{new archetype_context(opts, string_archetype(42))};\n    source->append_raw(\"SELECT \");\n\n    // Construct\n    archetype_context ctx(std::move(*source));\n    source.reset();\n\n    // Check error state and options\n    BOOST_TEST(ctx.error_state() == error_code());\n    BOOST_TEST(ctx.format_opts().charset.name == \"utf8mb4\");\n\n    // Can be used to append and result can be retrieved\n    ctx.append_value(42);\n    BOOST_TEST(std::move(ctx).get().value().impl == \"SELECT 42\");\n}\n\nBOOST_AUTO_TEST_CASE(move_constructor_error)\n{\n    // Move source. Heap helps asan\n    std::unique_ptr<archetype_context> source{new archetype_context(opts, string_archetype(42))};\n    source->add_error(client_errc::extra_bytes);\n\n    // Construct\n    archetype_context ctx(std::move(*source));\n    source.reset();\n\n    // Error state is propagated\n    BOOST_TEST(ctx.error_state() == client_errc::extra_bytes);\n    BOOST_TEST(std::move(ctx).get().error() == client_errc::extra_bytes);\n}\n\nBOOST_AUTO_TEST_CASE(move_assign)\n{\n    // Move source. Heap helps asan\n    std::unique_ptr<archetype_context> source{new archetype_context(opts, string_archetype(42))};\n    source->append_raw(\"SELECT \");\n    archetype_context ctx(ascii_opts, string_archetype(42));\n    ctx.append_raw(\"abc\").add_error(client_errc::wrong_num_params);\n\n    // Assign\n    ctx = std::move(*source);\n    source.reset();\n\n    // Check error state and options\n    BOOST_TEST(ctx.error_state() == error_code());\n    BOOST_TEST(ctx.format_opts().charset.name == \"utf8mb4\");\n\n    // Can be used to append and result can be retrieved\n    ctx.append_value(42);\n    BOOST_TEST(std::move(ctx).get().value().impl == \"SELECT 42\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assign_error)\n{\n    // Move source. Heap helps asan\n    std::unique_ptr<archetype_context> source{new archetype_context(opts, string_archetype(42))};\n    source->add_error(client_errc::extra_bytes);\n    archetype_context ctx(ascii_opts, string_archetype(42));\n\n    // Assign\n    ctx = std::move(*source);\n    source.reset();\n\n    // Error state is propagated\n    BOOST_TEST(ctx.error_state() == client_errc::extra_bytes);\n    BOOST_TEST(std::move(ctx).get().error() == client_errc::extra_bytes);\n}\n\n// Spotcheck: format_context move operations work\nBOOST_AUTO_TEST_CASE(string_format_context)\n{\n    // Constructor from storage\n    std::string storage = \"abcde\";\n    format_context ctx(opts, std::move(storage));\n\n    // Check\n    BOOST_TEST(ctx.error_state() == error_code());\n    BOOST_TEST(ctx.format_opts().charset.name == \"utf8mb4\");\n\n    // Move construction\n    ctx.append_raw(\"SELECT \");\n    format_context ctx2(std::move(ctx));\n    ctx2.append_value(42);\n    BOOST_TEST(std::move(ctx2).get().value() == \"SELECT 42\");\n\n    // Move assignment\n    format_context ctx3(ascii_opts);\n    ctx3.append_raw(\"def\");\n    ctx = std::move(ctx3);\n    BOOST_TEST(std::move(ctx).get().value() == \"def\");\n}\n\n// Spotcheck: append_raw works with empty strings\nBOOST_AUTO_TEST_CASE(append_raw_empty_string)\n{\n    // Context\n    format_context ctx(opts);\n\n    // With the empty context\n    ctx.append_raw(\"\");\n\n    // With contents already present\n    ctx.append_raw(\"SELECT \").append_value(42).append_raw(\"\");\n\n    BOOST_TEST(std::move(ctx).get().value() == \"SELECT 42\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/unit/test/format_sql/custom_formatter.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <initializer_list>\n\n#include \"format_common.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// When formatted, outputs the spec to the output context\nstruct echo_spec\n{\n};\n\n// Parse returns begin + N\ntemplate <std::size_t N>\nstruct parse_consume\n{\n};\n\n// Format may call set_error\nstruct maybe_error\n{\n    bool do_error;\n};\n\n// Only non-const formattable\nstruct only_nonconst_lvalues\n{\n    int id;\n};\n\n// Formatter has overloads for both const and non-const values\nstruct const_and_nonconst\n{\n};\n\n}  // namespace test\n\ntemplate <>\nstruct formatter<echo_spec>\n{\n    string_view spec;\n\n    const char* parse(const char* it, const char* end)\n    {\n        spec = {it, end};\n        return end;\n    }\n\n    void format(echo_spec, format_context_base& ctx) const { ctx.append_raw(runtime(spec)); }\n};\n\ntemplate <std::size_t N>\nstruct formatter<parse_consume<N>>\n{\n    const char* parse(const char* it, const char*) { return it + N; }\n    void format(parse_consume<N>, format_context_base&) const {}\n};\n\ntemplate <>\nstruct formatter<maybe_error>\n{\n    const char* parse(const char* it, const char*) { return it; }\n\n    void format(maybe_error v, format_context_base& ctx) const\n    {\n        if (v.do_error)\n            ctx.add_error(client_errc::unformattable_value);\n        else\n            format_sql_to(ctx, \"{}\", v.do_error);\n    };\n};\n\ntemplate <>\nstruct formatter<only_nonconst_lvalues>\n{\n    const char* parse(const char* it, const char*) { return it; }\n    void format(only_nonconst_lvalues& val, format_context_base& ctx) const\n    {\n        format_sql_to(ctx, \"only_nonconst_lvalues({})\", val.id);\n    }\n};\n\ntemplate <>\nstruct formatter<const_and_nonconst>\n{\n    const char* parse(const char* it, const char*) { return it; }\n    void format(const_and_nonconst&, format_context_base& ctx) const { ctx.append_raw(\"nonconst\"); }\n    void format(const const_and_nonconst&, format_context_base& ctx) const { ctx.append_raw(\"const\"); }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\nBOOST_AUTO_TEST_SUITE(test_format_sql_custom)\n\nconstexpr format_options opts{utf8mb4_charset, true};\n\n// We pass the correct format spec to parse\nBOOST_AUTO_TEST_CASE(parse_passed_format_specs)\n{\n    std::initializer_list<format_arg> named_args{\n        {\"name\", echo_spec{}}\n    };\n\n    // No spec\n    BOOST_TEST(format_sql(opts, \"{}\", echo_spec{}) == \"\");\n    BOOST_TEST(format_sql(opts, \"{:}\", echo_spec{}) == \"\");\n    BOOST_TEST(format_sql(opts, \"{0}\", echo_spec{}) == \"\");\n    BOOST_TEST(format_sql(opts, \"{0:}\", echo_spec{}) == \"\");\n    BOOST_TEST(format_sql(opts, \"{name}\", named_args) == \"\");\n    BOOST_TEST(format_sql(opts, \"{name:}\", named_args) == \"\");\n\n    // Single char\n    BOOST_TEST(format_sql(opts, \"{:k}\", echo_spec{}) == \"k\");\n    BOOST_TEST(format_sql(opts, \"{0:u}\", echo_spec{}) == \"u\");\n    BOOST_TEST(format_sql(opts, \"{name:p}\", named_args) == \"p\");\n\n    // Multiple chars\n    BOOST_TEST(format_sql(opts, \"{:some}\", echo_spec{}) == \"some\");\n    BOOST_TEST(format_sql(opts, \"{0:chars}\", echo_spec{}) == \"chars\");\n    BOOST_TEST(format_sql(opts, \"{name:here}\", named_args) == \"here\");\n\n    // All ASCII characters allowed, except for {}\n    BOOST_TEST(\n        format_sql(opts, \"{:abcdefghijklmnopqrstuvwxyz}\", echo_spec{}) == \"abcdefghijklmnopqrstuvwxyz\"\n    );\n    BOOST_TEST(\n        format_sql(opts, \"{0:ABCDEFGHIJKLMNOPQRSTUVWXYZ}\", echo_spec{}) == \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    );\n    BOOST_TEST(format_sql(opts, \"{name:0abAZ12 3456789}\", named_args) == \"0abAZ12 3456789\");\n    BOOST_TEST(\n        format_sql(opts, \"{:!\\\"#$%&'()*+,-./:;<=>?@[]\\\\^_`|~}\", echo_spec{}) ==\n        \"!\\\"#$%&'()*+,-./:;<=>?@[]\\\\^_`|~\"\n    );\n}\n\n// Returning something != end in parse is an error\nBOOST_AUTO_TEST_CASE(parse_error)\n{\n    BOOST_TEST(\n        format_single_error(\"{:abc}\", parse_consume<0>()) == client_errc::format_string_invalid_specifier\n    );\n    BOOST_TEST(\n        format_single_error(\"{:abc}\", parse_consume<1>()) == client_errc::format_string_invalid_specifier\n    );\n    BOOST_TEST(\n        format_single_error(\"{:abc}\", parse_consume<2>()) == client_errc::format_string_invalid_specifier\n    );\n    BOOST_TEST(format_single_error(\"{:abc}\", parse_consume<3>()) == error_code());\n}\n\n// Formatters may accept values by const/non-const lvalue reference,\n// and constness in format_sql is correctly propagated to them.\n// This is used internally by sequence(), because some ranges are non-const.\n// Not part of the public API - only const formatters are exposed\nBOOST_AUTO_TEST_CASE(format_only_nonconst)\n{\n    // This would be the case of filter_view\n    only_nonconst_lvalues lval{42};\n    BOOST_TEST(format_sql(opts, \"{}\", lval) == \"only_nonconst_lvalues(42)\");\n    BOOST_TEST(format_sql(opts, \"{}\", only_nonconst_lvalues{80}) == \"only_nonconst_lvalues(80)\");\n}\n\nBOOST_AUTO_TEST_CASE(format_const_nonconst)\n{\n    // Can appear in generic code\n    const_and_nonconst lval{};\n    const const_and_nonconst clval{};\n    BOOST_TEST(format_sql(opts, \"{}\", lval) == \"nonconst\");\n    BOOST_TEST(format_sql(opts, \"{}\", clval) == \"const\");\n    BOOST_TEST(format_sql(opts, \"{}\", const_and_nonconst{}) == \"nonconst\");\n    BOOST_TEST(format_sql(opts, \"{}\", std::move(clval)) == \"const\");\n}\n\n// format can call add_error to report problems\nBOOST_AUTO_TEST_CASE(format_add_error)\n{\n    BOOST_TEST(format_single_error(\"SELECT {};\", maybe_error{true}) == client_errc::unformattable_value);\n    BOOST_TEST(format_sql(opts, \"SELECT {};\", maybe_error{false}) == \"SELECT 0;\");\n}\n\n// Spotcheck on a realistic type\nBOOST_AUTO_TEST_CASE(spotcheck)\n{\n    BOOST_TEST(format_sql(opts, \"{}\", custom::condition{\"myfield\", 42}) == \"`myfield`=42\");\n    BOOST_TEST(format_sql(opts, \"{:s}\", custom::condition{\"myfield\", 42}) == \"`myfield` = 42\");\n    BOOST_TEST(\n        format_single_error(\"{:i}\", custom::condition{\"myfield\", 42}) ==\n        client_errc::format_string_invalid_specifier\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()"
  },
  {
    "path": "test/unit/test/format_sql/format_common.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_FORMAT_SQL_FORMAT_COMMON_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_FORMAT_SQL_FORMAT_COMMON_HPP\n\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <string>\n#include <vector>\n\n#include \"test_unit/custom_allocator.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nusing string_with_alloc = std::basic_string<char, std::char_traits<char>, custom_allocator<char>>;\nusing blob_with_alloc = std::vector<unsigned char, custom_allocator<unsigned char>>;\n\ntemplate <class Arg>\nerror_code format_single_error(constant_string_view format_str, const Arg& arg)\n{\n    format_context ctx({utf8mb4_charset, true});\n    format_sql_to(ctx, format_str, arg);\n    return std::move(ctx).get().error();\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n// Field with a custom formatter\nnamespace custom {\n\nstruct condition\n{\n    boost::mysql::string_view name;\n    int value;\n};\n\n}  // namespace custom\n\nnamespace boost {\nnamespace mysql {\n\ntemplate <>\nstruct formatter<custom::condition>\n{\n    bool space{false};\n\n    const char* parse(const char* it, const char* end)\n    {\n        if (it != end && *it == 's')\n        {\n            space = true;\n            ++it;\n        }\n        return it;\n    }\n\n    void format(const custom::condition& v, format_context_base& ctx) const\n    {\n        if (space)\n            format_sql_to(ctx, \"{:i} = {}\", v.name, v.value);\n        else\n            format_sql_to(ctx, \"{:i}={}\", v.name, v.value);\n    }\n};\n\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/format_sql/format_strings.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/system/system_error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/ff_charset.hpp\"\n\nusing namespace boost::mysql;\n\n//\n// Format strings: covers expanding a format string into an actual query\n// using format_sql. This is specific to format_sql. Assumes that formatting\n// individual arguments works\n//\nBOOST_AUTO_TEST_SUITE(test_format_strings)\n\nconstexpr format_options opts{utf8mb4_charset, true};\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    // Empty string\n    BOOST_TEST(format_sql(opts, \"\") == \"\");\n\n    // String without replacements\n    BOOST_TEST(format_sql(opts, \"SELECT 1\") == \"SELECT 1\");\n\n    // Escaped curly braces\n    BOOST_TEST(format_sql(opts, \"SELECT '{{}}'\", 42) == \"SELECT '{}'\");\n    BOOST_TEST(format_sql(opts, \"SELECT '{{'\", 42) == \"SELECT '{'\");\n    BOOST_TEST(format_sql(opts, \"SELECT '}}'\", 42) == \"SELECT '}'\");\n    BOOST_TEST(format_sql(opts, \"SELECT '{{{{}}}}'\", 42) == \"SELECT '{{}}'\");\n    BOOST_TEST(format_sql(opts, \"SELECT '}}}}{{'\", 42) == \"SELECT '}}{'\");\n    BOOST_TEST(format_sql(opts, \"{{{}}}\", 42) == \"{42}\");\n    BOOST_TEST(format_sql(opts, \"SELECT '{{0}}'\", 42) == \"SELECT '{0}'\");\n    BOOST_TEST(format_sql(opts, \"SELECT '{{name}}'\", 42) == \"SELECT '{name}'\");\n\n    // One format arg, possibly with text around it\n    BOOST_TEST(format_sql(opts, \"SELECT {}\", 42) == \"SELECT 42\");                // text{}\n    BOOST_TEST(format_sql(opts, \"{} OR 1=1\", 42) == \"42 OR 1=1\");                // {} text\n    BOOST_TEST(format_sql(opts, \"{}\", 42) == \"42\");                              // {}\n    BOOST_TEST(format_sql(opts, \"SELECT {} OR 1=1\", 42) == \"SELECT 42 OR 1=1\");  // text{}text\n\n    // Two format args\n    BOOST_TEST(format_sql(opts, \"{}{}\", 42, \"abc\") == \"42'abc'\");        // {}{}\n    BOOST_TEST(format_sql(opts, \"{} + {}\", 42, \"abc\") == \"42 + 'abc'\");  // {}text{}\n    BOOST_TEST(\n        format_sql(opts, \"WHERE a={} OR b={} OR 1=1\", 42, \"abc\") == \"WHERE a=42 OR b='abc' OR 1=1\"\n    );  // text{}text{}text\n    BOOST_TEST(format_sql(opts, \"SELECT {} OR 1=1\", 42) == \"SELECT 42 OR 1=1\");\n\n    // More format args\n    BOOST_TEST(format_sql(opts, \"IN({}, {}, {}, {})\", 1, 5, 2, \"'abc'\") == \"IN(1, 5, 2, '\\\\'abc\\\\'')\");\n\n    // Explicit positional args\n    BOOST_TEST(format_sql(opts, \"SELECT {0}\", 42) == \"SELECT 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {1}, {0}\", 42, \"abc\") == \"SELECT 'abc', 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {0}, {0}\", 42) == \"SELECT 42, 42\");  // repeated\n\n    // Specifiers work with positional args\n    BOOST_TEST(format_sql(opts, \"SELECT {1:i};\", 42, \"abc\") == \"SELECT `abc`;\");\n    BOOST_TEST(format_sql(opts, \"SELECT {0:r};\", \"abc\") == \"SELECT abc;\");\n\n    // Unused arguments are ignored\n    BOOST_TEST(format_sql(opts, \"SELECT {}\", 42, \"abc\", nullptr) == \"SELECT 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {2}, {1}\", 42, \"abc\", nullptr, 4.2) == \"SELECT NULL, 'abc'\");\n\n    // Indices with leading zeroes are parsed correctly and not interpreted as octal\n    BOOST_TEST(format_sql(opts, \"SELECT {010}\", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) == \"SELECT 10\");\n\n    // spotcheck: {} characters in string values are not treated specially\n    BOOST_TEST(format_sql(opts, \"CONCAT({}, {})\", \"{}\", \"a{b}c\") == \"CONCAT('{}', 'a{b}c')\");\n    BOOST_TEST(format_sql(opts, \"CONCAT({}, {})\", \"{\", \"a}c\") == \"CONCAT('{', 'a}c')\");\n    BOOST_TEST(format_sql(opts, \"CONCAT({}, {})\", \"{{}}\", \"{{1}}\") == \"CONCAT('{{}}', '{{1}}')\");\n    BOOST_TEST(format_sql(opts, \"CONCAT({}, {})\", \"'\\\\{\", \"\\\"}\") == \"CONCAT('\\\\'\\\\\\\\{', '\\\\\\\"}')\");\n\n    // Format strings with non-ascii (but valid) characters\n    BOOST_TEST(format_sql(opts, \"SELECT `e\\xc3\\xb1u` + {};\", 42) == \"SELECT `e\\xc3\\xb1u` + 42;\");\n    BOOST_TEST(format_sql(opts, \"\\xc3\\xb1{}\", \"abc\") == \"\\xc3\\xb1'abc'\");\n\n    // Empty specifiers allowed, they do nothing\n    BOOST_TEST(format_sql(opts, \"SELECT {:};\", 42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, \"SELECT {0:};\", 42) == \"SELECT 42;\");\n}\n\nBOOST_AUTO_TEST_CASE(success_named_args)\n{\n    // clang-format off\n    BOOST_TEST(format_sql(opts, \"SELECT {val}\", {{\"val\", 42}}) == \"SELECT 42\");\n    BOOST_TEST(\n        format_sql(opts, \"SELECT {val2}, {val}\", {{\"val\", 42}, {\"val2\", \"abc\"}}) == \"SELECT 'abc', 42\"\n    );\n    BOOST_TEST(format_sql(opts, \"SELECT {Str1_geName}\", {{\"Str1_geName\", 42}}) == \"SELECT 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {_name}\", {{\"_name\", 42}}) == \"SELECT 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {name123}\", {{\"name123\", 42}}) == \"SELECT 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {NAME}\", {{\"NAME\", 42}}) == \"SELECT 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {a}\", {{\"a\", 42}}) == \"SELECT 42\");\n\n    // Named arguments can be referenced by position and automatically, too\n    BOOST_TEST(format_sql(opts, \"SELECT {}, {}\", {{\"val\", 42}, {\"other\", 50}}) == \"SELECT 42, 50\");\n    BOOST_TEST(format_sql(opts, \"SELECT {1}, {0}\", {{\"val\", 42}, {\"other\", 50}}) == \"SELECT 50, 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {}, {val}\", {{\"val\", 42}, {\"other\", 50}}) == \"SELECT 42, 42\");\n    BOOST_TEST(format_sql(opts, \"SELECT {1}, {val}\", {{\"val\", 42}, {\"other\", 50}}) == \"SELECT 50, 42\");\n\n    // Unused arguments are ignored\n    BOOST_TEST(format_sql(opts, \"SELECT {value}\", {{\"a\", 10}, {\"value\", 42}, {\"a\", \"ac\"}}) == \"SELECT 42\");\n\n    // Format specifiers allowed\n    BOOST_TEST(format_sql(opts, \"SELECT {name:i};\", {{\"name\", \"value\"}}) == \"SELECT `value`;\");\n\n    // Empty specifiers allowed\n    BOOST_TEST(format_sql(opts, \"SELECT {name:};\", {{\"name\", 42}}) == \"SELECT 42;\");\n    // clang-format on\n}\n\n// backslash_escapes and character set are propagated\nBOOST_AUTO_TEST_CASE(options_propagated)\n{\n    format_options opts_charset{test::ff_charset, true};\n    format_options opts_backslashes{test::ff_charset, false};\n\n    // Charset affects format strings\n    BOOST_TEST(format_sql(opts_charset, \"SELECT \\xffh + {};\", 42) == \"SELECT \\xffh + 42;\");\n\n    // Charset affects string values and identifiers\n    BOOST_TEST(format_sql(opts_charset, \"SELECT {};\", \"ab\\xff''\") == \"SELECT 'ab\\xff'\\\\'';\");\n    BOOST_TEST(format_sql(opts_charset, \"SELECT {:i};\", \"ab\\xff``\") == \"SELECT `ab\\xff````;\");\n\n    // Backslash escapes affects how string values are escaped\n    BOOST_TEST(format_sql(opts_backslashes, \"SELECT {};\", \"ab'cd\") == \"SELECT 'ab''cd';\");\n    BOOST_TEST(format_sql(opts_backslashes, \"SELECT {};\", \"ab\\\"cd\") == \"SELECT 'ab\\\"cd';\");\n}\n\n// In a character set with ASCII-compatible continuation characters, we correctly\n// interpret {} characters as continuations, rather than trying to expand them\nBOOST_AUTO_TEST_CASE(brace_continuation)\n{\n    format_options custom_opts{test::ff_charset, true};\n\n    BOOST_TEST(format_sql(custom_opts, \"SELECT \\xff{ + {};\", 42) == \"SELECT \\xff{ + 42;\");\n    BOOST_TEST(format_sql(custom_opts, \"SELECT \\xff} + {};\", 42) == \"SELECT \\xff} + 42;\");\n    BOOST_TEST(format_sql(custom_opts, \"SELECT \\xff{}} + {};\", 42) == \"SELECT \\xff{} + 42;\");\n}\n\nBOOST_AUTO_TEST_CASE(error)\n{\n    struct\n    {\n        string_view name;\n        string_view format_str;\n        error_code expected_ec;\n    } test_cases[] = {\n        // Simply invalid\n        {\"unbalanced_{\",             \"SELECT { bad\",               client_errc::format_string_invalid_syntax   },\n        {\"unbalanced_{_eof\",         \"SELECT {\",                   client_errc::format_string_invalid_syntax   },\n        {\"unbalanced_}\",             \"SELECT } bad\",               client_errc::format_string_invalid_syntax   },\n        {\"unbalanced_}_after_field\", \"SELECT {}} bad\",             client_errc::format_string_invalid_syntax   },\n        {\"unbalanced_}_eof\",         \"SELECT }\",                   client_errc::format_string_invalid_syntax   },\n        {\"invalid_character\",        \"SELECT \\xc3 bad\",            client_errc::format_string_invalid_encoding },\n\n        // Named argument problems\n        {\"name_starts_number\",       \"SELECT {0name}\",             client_errc::format_string_invalid_syntax   },\n        {\"name_starts_invalid\",      \"SELECT {!name}\",             client_errc::format_string_invalid_syntax   },\n        {\"name_ends_invalid\",        \"SELECT {name!}\",             client_errc::format_string_invalid_syntax   },\n        {\"name_contains_invalid\",    \"SELECT {na'me}\",             client_errc::format_string_invalid_syntax   },\n        {\"name_spaces\",              \"SELECT { name }\",            client_errc::format_string_invalid_syntax   },\n        {\"name_non_ascii\",           \"SELECT {e\\xc3\\xb1p}\",        client_errc::format_string_invalid_syntax   },\n        {\"name_eof\",                 \"SELECT {name\",               client_errc::format_string_invalid_syntax   },\n        {\"name_not_found\",           \"SELECT {name} {bad}\",        client_errc::format_arg_not_found           },\n        {\"name_spec_nonascii\",       \"SELECT {name:\\xc3\\xb1}\",     client_errc::format_string_invalid_syntax   },\n        {\"name_spec_{\",              \"SELECT {name:i{}\",           client_errc::format_string_invalid_syntax   },\n        {\"name_spec_}\",              \"SELECT {name:i}}\",           client_errc::format_string_invalid_syntax   },\n        {\"name_spec_{}\",             \"SELECT {name:i{}}\",          client_errc::format_string_invalid_syntax   },\n        {\"name_spec_eof\",            \"SELECT {name:eof\",           client_errc::format_string_invalid_syntax   },\n        {\"name_spec_invalid\",        \"SELECT {name:d}\",            client_errc::format_string_invalid_specifier},\n\n        // Explicit indexing problems\n        {\"index_hex\",                \"SELECT {0x10}\",              client_errc::format_string_invalid_syntax   },\n        {\"index_hex_noprefix\",       \"SELECT {1a}\",                client_errc::format_string_invalid_syntax   },\n        {\"index_spaces\",             \"SELECT { 1 }\",               client_errc::format_string_invalid_syntax   },\n        {\"index_eof\",                \"SELECT {0\",                  client_errc::format_string_invalid_syntax   },\n        {\"index_gt_max\",             \"SELECT {65536}\",             client_errc::format_string_invalid_syntax   },\n        {\"index_negative\",           \"SELECT {-1}\",                client_errc::format_string_invalid_syntax   },\n        {\"index_float\",              \"SELECT {4.2}\",               client_errc::format_string_invalid_syntax   },\n        {\"index_not_found\",          \"SELECT {2}\",                 client_errc::format_arg_not_found           },\n        {\"index_to_manual\",          \"SELECT {0}, {}\",             client_errc::format_string_manual_auto_mix  },\n        {\"index_spec_nonascii\",      \"SELECT {0:\\xff}\",            client_errc::format_string_invalid_syntax   },\n        {\"index_spec_{\",             \"SELECT {0:i{}\",              client_errc::format_string_invalid_syntax   },\n        {\"index_spec_range_{\",       \"SELECT {0:i:{}\",             client_errc::format_string_invalid_syntax   },\n        {\"index_spec_{}\",            \"SELECT {0:i{}}\",             client_errc::format_string_invalid_syntax   },\n        {\"index_spec_eof\",           \"SELECT {0:eof\",              client_errc::format_string_invalid_syntax   },\n        {\"index_spec_range_eof\",     \"SELECT {0:i:\",               client_errc::format_string_invalid_syntax   },\n        {\"index_spec_invalid\",       \"SELECT {0:i}\",               client_errc::format_string_invalid_specifier},\n\n        // Auto indexing problems\n        {\"auto_replacement_inside\",  \"SELECT { {} }\",              client_errc::format_string_invalid_syntax   },\n        {\"auto_too_many_args\",       \"SELECT {}, {}, {}\",          client_errc::format_arg_not_found           },\n        {\"auto_to_manual\",           \"SELECT {}, {0}\",             client_errc::format_string_manual_auto_mix  },\n        {\"auto_spec_nonascii\",       \"SELECT {:\\xff}\",             client_errc::format_string_invalid_syntax   },\n        {\"auto_spec_{\",              \"SELECT {:i{}\",               client_errc::format_string_invalid_syntax   },\n        {\"auto_spec_{}\",             \"SELECT {:i{}}\",              client_errc::format_string_invalid_syntax   },\n        {\"auto_spec_eof\",            \"SELECT {:\",                  client_errc::format_string_invalid_syntax   },\n        {\"auto_spec_invalid\",        \"SELECT {:b}\",                client_errc::format_string_invalid_specifier},\n\n        // Specs containing non-printable ASCII characters are rejected\n        {\"spec_zero\",                test::makesv(\"SELECT {:\\0}\"), client_errc::format_string_invalid_syntax   },\n        {\"spec_ctrl_1\",              \"SELECT {:\\1}\",               client_errc::format_string_invalid_syntax   },\n        {\"spec_ctrl_mid\",            \"SELECT {:\\x10}\",             client_errc::format_string_invalid_syntax   },\n        {\"spec_ctrl_high\",           \"SELECT {:\\x19}\",             client_errc::format_string_invalid_syntax   },\n        {\"spec_del\",                 \"SELECT {:\\x7f}\",             client_errc::format_string_invalid_syntax   },\n        {\"spec_nonascii\",            \"SELECT {:\\x80}\",             client_errc::format_string_invalid_syntax   },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            format_context ctx(opts);\n            // clang-format off\n            format_sql_to(ctx, runtime(tc.format_str), {{\"number\", 42}, {\"name\", \"abc\"}});\n            // clang-format on\n            BOOST_TEST(std::move(ctx).get().error() == tc.expected_ec);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/format_sql/formattable.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n#include <boost/mysql/rows.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/sequence.hpp>\n\n#include <boost/optional/optional.hpp>\n\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"format_common.hpp\"\n#include \"test_common/has_ranges.hpp\"\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n#include <string_view>\n#endif\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n#ifdef BOOST_MYSQL_HAS_RANGES\n#include <ranges>\n#endif\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing mysql_time = boost::mysql::time;\nusing std::vector;\n\n// We have a type trait (is_formattable_type) for C++ < 20,\n// and a concept (formattable), for C++ >= 20. This macro checks both without repetition\n\n#ifdef BOOST_MYSQL_HAS_CONCEPTS\n#define BOOST_MYSQL_CHECK_FORMATTABLE(type, expected)         \\\n    static_assert(detail::formattable<type> == expected, \"\"); \\\n    static_assert(detail::is_formattable_type<type>() == expected, \"\");\n#else\n#define BOOST_MYSQL_CHECK_FORMATTABLE(type, expected) \\\n    static_assert(detail::is_formattable_type<type>() == expected, \"\");\n#endif\n\n// field and field_view accepted (writable fields)\nBOOST_MYSQL_CHECK_FORMATTABLE(field_view, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(field, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(field&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(const field&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(field&&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(const field&&, true)\n\n// Scalars accepted (writable fields)\nBOOST_MYSQL_CHECK_FORMATTABLE(std::nullptr_t, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(unsigned char, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(signed char, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(short, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(unsigned short, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(int, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(unsigned int, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(long, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(unsigned long, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(float, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(double, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(date, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(datetime, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(mysql_time, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(bool, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(int&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(bool&, true)\n\n// characters (except signed/unsigned char) not accepted\nBOOST_MYSQL_CHECK_FORMATTABLE(char, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(wchar_t, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(char16_t, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(char32_t, false)\n#ifdef __cpp_char8_t\nBOOST_MYSQL_CHECK_FORMATTABLE(char8_t, false)\n#endif\nBOOST_MYSQL_CHECK_FORMATTABLE(char&, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(const char, false)\n\n// Strings (writable fields)\nBOOST_MYSQL_CHECK_FORMATTABLE(std::string, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(string_with_alloc, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(string_view, true)\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nBOOST_MYSQL_CHECK_FORMATTABLE(std::string_view, true)\n#endif\nBOOST_MYSQL_CHECK_FORMATTABLE(const char*, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(char[16], true)\nBOOST_MYSQL_CHECK_FORMATTABLE(std::string&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(std::wstring, false)\n\n// Blobs\nBOOST_MYSQL_CHECK_FORMATTABLE(blob, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(blob_view, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(blob_with_alloc, true)\n\n// optional types accepted (writable fields)\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nBOOST_MYSQL_CHECK_FORMATTABLE(std::optional<int>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(std::optional<std::string>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(std::optional<int>&, true)\n#endif\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<string_view>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<blob>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<void*>, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<format_options>, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<int&>, false)\n\n// Types with custom formatters accepted, but not optionals\nBOOST_MYSQL_CHECK_FORMATTABLE(custom::condition, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(custom::condition&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(const custom::condition&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(custom::condition&&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(const custom::condition&&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(custom::condition*, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<custom::condition>, false)\n\n// Ranges of writable fields accepted (spotchecks)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<int>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<int>&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(const vector<int>&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<int>&&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<string_view>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<field>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<field_view>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(row_view, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(row, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<boost::optional<int>>, true)\n\n// Ranges of types with custom formatters accepted\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<custom::condition>, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<custom::condition>&, true)\nBOOST_MYSQL_CHECK_FORMATTABLE(const vector<custom::condition>&, true)\n\n// Ranges of ranges are not formattable\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<vector<int>>, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<vector<int>>&, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(const vector<vector<int>>&, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<vector<int>>&&, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(rows_view, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(rows, false)\n\n// optional<range> isn't formattable\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<vector<int>>, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(boost::optional<row>, false)\n\n// Ranges of unrelated types aren't formattable\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<const void*>, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(vector<std::wstring>, false)\n\n// non-const ranges (e.g. filter_view) are formattable if passed as non-const\n#ifdef BOOST_MYSQL_HAS_RANGES\nusing filter_t = decltype(std::declval<const vector<int>&>() | std::ranges::views::filter([](int) {\n                              return true;\n                          }));\n\nBOOST_MYSQL_CHECK_FORMATTABLE(filter_t, true);\nBOOST_MYSQL_CHECK_FORMATTABLE(filter_t&, true);\nBOOST_MYSQL_CHECK_FORMATTABLE(const filter_t&, false);\nBOOST_MYSQL_CHECK_FORMATTABLE(filter_t&&, true);\nBOOST_MYSQL_CHECK_FORMATTABLE(const filter_t&&, false);\n#endif\n\n// sequence is formattable\nusing format_fn_t = void (*)(int, format_context_base&);\nusing format_seq_t = format_sequence<std::vector<int>, format_fn_t>;\nBOOST_MYSQL_CHECK_FORMATTABLE(format_seq_t, true)\n\n// other stuff not accepted\nBOOST_MYSQL_CHECK_FORMATTABLE(void*, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(field*, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(field_view*, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(format_options, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(const format_options, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(format_options&, false)\nBOOST_MYSQL_CHECK_FORMATTABLE(format_arg, false)\n"
  },
  {
    "path": "test/unit/test/format_sql/formattable_ref.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/format_sql.hpp>\n\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <type_traits>\n#include <vector>\n\n#include \"format_common.hpp\"\n\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_formattable_ref)\n\nconstexpr format_options opts{utf8mb4_charset, true};\nconstexpr const char* single_fmt = \"SELECT {};\";\n\n//\n// Basic operations on formattable_ref work\n//\nBOOST_AUTO_TEST_CASE(copy_ctor)\n{\n    // Regression check: the universal reference ctor. is suitably constrained\n    static_assert(std::is_trivially_copy_constructible<formattable_ref>::value, \"\");\n\n    formattable_ref ref1{42};\n    formattable_ref ref2{ref1};\n    BOOST_TEST(format_sql(opts, single_fmt, ref2) == \"SELECT 42;\");\n}\n\nBOOST_AUTO_TEST_CASE(move_ctor)\n{\n    // Regression check: the universal reference ctor. is suitably constrained\n    static_assert(std::is_trivially_move_constructible<formattable_ref>::value, \"\");\n\n    formattable_ref ref1{42};\n    formattable_ref ref2{std::move(ref1)};\n    BOOST_TEST(format_sql(opts, single_fmt, ref2) == \"SELECT 42;\");\n}\n\n// The universal reference ctor. is SFINAE friendly\nstruct unrelated\n{\n};\n\nstd::true_type f(unrelated) { return {}; }\nstd::false_type f(formattable_ref) { return {}; }\n\nstatic_assert(decltype(f(unrelated{}))::value, \"SFINAE check failed\");\n\n//\n// Formatting a formattable_ref works\n//\nBOOST_AUTO_TEST_CASE(formatting)\n{\n    // Scalar values\n    BOOST_TEST(format_sql(opts, single_fmt, formattable_ref{\"abc\"}) == \"SELECT 'abc';\");\n\n    // Optionals\n    BOOST_TEST(format_sql(opts, single_fmt, formattable_ref{boost::optional<int>{}}) == \"SELECT NULL;\");\n\n    // Fields\n    BOOST_TEST(format_sql(opts, single_fmt, formattable_ref{field_view(42)}) == \"SELECT 42;\");\n\n    // Ranges\n    std::vector<int> vals{4, 10, 1};\n    BOOST_TEST(format_sql(opts, single_fmt, formattable_ref{vals}) == \"SELECT 4, 10, 1;\");\n\n    // Types with custom formatter\n    custom::condition cond{\"key\", 10};\n    BOOST_TEST(format_sql(opts, single_fmt, formattable_ref{cond}) == \"SELECT `key`=10;\");\n    BOOST_TEST(format_sql(opts, single_fmt, formattable_ref{custom::condition(cond)}) == \"SELECT `key`=10;\");\n\n    // Specifiers\n    BOOST_TEST(format_sql(opts, \"{:s}\", formattable_ref{cond}) == \"`key` = 10\");\n}\n\nBOOST_AUTO_TEST_CASE(range_of_refs)\n{\n    std::vector<formattable_ref> args{42, \"abc\", nullptr};\n    BOOST_TEST(format_sql(opts, single_fmt, args) == \"SELECT 42, 'abc', NULL;\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/format_sql/individual_value.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/config.hpp>\n#include <boost/core/ignore_unused.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <limits>\n#include <string>\n\n#include \"format_common.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n#include <string_view>\n#endif\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing mysql_time = boost::mysql::time;\n\n//\n// Verify that formatting individual values work. This is tested using format_sql\n// because it's convenient, but also covers basic_format_context\n//\nBOOST_AUTO_TEST_SUITE(test_format_sql_individual_value)\n\nconstexpr format_options opts{utf8mb4_charset, true};\nconstexpr const char* single_fmt = \"SELECT {};\";\nconstexpr const char* identifier_fmt = \"SELECT {:i} FROM myt\";\nconstexpr const char* raw_fmt = \"SELECT {:r};\";\n\nBOOST_AUTO_TEST_CASE(null_)\n{\n    // nullptr interpreted as NULL\n    BOOST_TEST(format_sql(opts, single_fmt, nullptr) == \"SELECT NULL;\");\n}\n\nBOOST_AUTO_TEST_CASE(signed_char)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (signed char)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (signed char)-1) == \"SELECT -1;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (signed char)-128) == \"SELECT -128;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (signed char)127) == \"SELECT 127;\");\n}\n\nBOOST_AUTO_TEST_CASE(unsigned_char)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned char)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned char)0) == \"SELECT 0;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned char)0xff) == \"SELECT 255;\");\n}\n\nBOOST_AUTO_TEST_CASE(short_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (short)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (short)-1) == \"SELECT -1;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (short)-32768) == \"SELECT -32768;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (short)32767) == \"SELECT 32767;\");\n}\n\nBOOST_AUTO_TEST_CASE(unsigned_short)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned short)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned short)0) == \"SELECT 0;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned short)0xffff) == \"SELECT 65535;\");\n}\n\nBOOST_AUTO_TEST_CASE(int_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (int)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (int)-1) == \"SELECT -1;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (int)-0x7fffffff - 1) == \"SELECT -2147483648;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (int)0x7fffffff) == \"SELECT 2147483647;\");\n}\n\nBOOST_AUTO_TEST_CASE(unsigned_int)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned int)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned int)0) == \"SELECT 0;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned int)0xffffffff) == \"SELECT 4294967295;\");\n}\n\nBOOST_AUTO_TEST_CASE(long_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (long)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (long)-1) == \"SELECT -1;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (long)0x7fffffff) == \"SELECT 2147483647;\");\n}\n\nBOOST_AUTO_TEST_CASE(unsigned_long)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned long)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned long)0) == \"SELECT 0;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned long)0xffffffff) == \"SELECT 4294967295;\");\n}\n\nBOOST_AUTO_TEST_CASE(long_long)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (long long)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (long long)-1) == \"SELECT -1;\");\n    BOOST_TEST(\n        format_sql(opts, single_fmt, (long long)(-0x7fffffffffffffff - 1)) == \"SELECT -9223372036854775808;\"\n    );\n    BOOST_TEST(format_sql(opts, single_fmt, (long long)0x7fffffffffffffff) == \"SELECT 9223372036854775807;\");\n}\n\nBOOST_AUTO_TEST_CASE(unsigned_long_long)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned long long)42) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, (unsigned long long)0) == \"SELECT 0;\");\n    BOOST_TEST(\n        format_sql(opts, single_fmt, (unsigned long long)0xffffffffffffffff) == \"SELECT 18446744073709551615;\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(bool_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, true) == \"SELECT 1;\");\n    BOOST_TEST(format_sql(opts, single_fmt, false) == \"SELECT 0;\");\n}\n\nBOOST_AUTO_TEST_CASE(double_)\n{\n    // doubles have many different cases that may cause trouble\n    struct\n    {\n        string_view name;\n        double value;\n        string_view expected;\n    } test_cases[] = {\n        {\"regular\",               4.2,                      \"4.2e+00\"                 },\n        {\"regular_precision\",     4.298238239237823287327,  \"4.298238239237823e+00\"   },\n        {\"exp\",                   5.1e+23,                  \"5.1e+23\"                 },\n        {\"exp_precision\",         4.2982382392378232e+67,   \"4.2982382392378234e+67\"  },\n        {\"max\",                   1.7976931348623157e+308,  \"1.7976931348623157e+308\" },\n        {\"regular_neg\",           -4.2,                     \"-4.2e+00\"                },\n        {\"regular_precision_neg\", -4.298238239237823287327, \"-4.298238239237823e+00\"  },\n        {\"exp_neg\",               -5.1e+23,                 \"-5.1e+23\"                },\n        {\"max_neg\",               -1.7976931348623157e+308, \"-1.7976931348623157e+308\"},\n        {\"zero\",                  0.0,                      \"0e+00\"                   },\n        {\"zero_neg\",              -0.0,                     \"-0e+00\"                  },\n        {\"expneg\",                4.2e-12,                  \"4.2e-12\"                 },\n        {\"expneg_precision\",      4.2872383293922839e-45,   \"4.2872383293922836e-45\"  },\n        {\"min\",                   2.2250738585072014e-308,  \"2.2250738585072014e-308\" },\n        {\"min_neg\",               -2.2250738585072014e-308, \"-2.2250738585072014e-308\"},\n        {\"denorm\",                -4.2872383293922839e-309, \"-4.287238329392283e-309\" },\n        {\"min_denorm\",            5e-324,                   \"5e-324\"                  },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            auto str = format_sql(opts, \"{}\", tc.value);\n            BOOST_TEST(str == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(float_)\n{\n    // floats are converted to double before formatting, since MySQL\n    // interprets all floating point literals as doubles\n    struct\n    {\n        string_view name;\n        float value;\n        string_view expected;\n    } test_cases[] = {\n        {\"regular\",               4.2f,                      \"4.199999809265137e+00\"  },\n        {\"regular_precision\",     4.298238239237823287327f,  \"4.298238277435303e+00\"  },\n        {\"exp\",                   5.1e+23f,                  \"5.100000157096095e+23\"  },\n        {\"exp_precision\",         4.2982382392378232e+35f,   \"4.298238339685548e+35\"  },\n        {\"max\",                   3.4028234663852886e+38f,   \"3.4028234663852886e+38\" },\n        {\"regular_neg\",           -4.2f,                     \"-4.199999809265137e+00\" },\n        {\"regular_precision_neg\", -4.298238239237823287327f, \"-4.298238277435303e+00\" },\n        {\"exp_neg\",               -5.1e+23f,                 \"-5.100000157096095e+23\" },\n        {\"max_neg\",               -3.4028234663852886e+38f,  \"-3.4028234663852886e+38\"},\n        {\"zero\",                  0.0f,                      \"0e+00\"                  },\n        {\"zero_neg\",              -0.0f,                     \"-0e+00\"                 },\n        {\"expneg\",                4.2e-12f,                  \"4.200000156689976e-12\"  },\n        {\"expneg_precision\",      4.2872383293922839e-23f,   \"4.2872384543670994e-23\" },\n        {\"min\",                   1.1754944e-38f,            \"1.1754943508222875e-38\" },\n        {\"min_neg\",               -1.1754944e-38f,           \"-1.1754943508222875e-38\"},\n        {\"denorm\",                -4.2872383293922839e-39f,  \"-4.287239020438634e-39\" },\n        {\"min_denorm\",            1.401298464324817e-45f,    \"1.401298464324817e-45\"  },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            auto str = format_sql(opts, \"{}\", tc.value);\n            BOOST_TEST(str == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(string_literal)\n{\n    // As values\n    BOOST_TEST(format_sql(opts, single_fmt, \"abc\") == \"SELECT 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, \"abc'\\\\ OR 1=1\") == \"SELECT 'abc\\\\'\\\\\\\\ OR 1=1';\");\n    BOOST_TEST(format_sql(opts, single_fmt, \"hola \\xc3\\xb1!\") == \"SELECT 'hola \\xc3\\xb1!';\");\n    BOOST_TEST(format_sql(opts, single_fmt, \"\") == \"SELECT '';\");\n\n    // As identifiers\n    BOOST_TEST(format_sql(opts, identifier_fmt, \"myfield\") == \"SELECT `myfield` FROM myt\");\n    BOOST_TEST(format_sql(opts, identifier_fmt, \"inj`ect'ion\") == \"SELECT `inj``ect'ion` FROM myt\");\n    BOOST_TEST(\n        format_sql(opts, identifier_fmt, \"mo`e\\\\inj``ectionatt\\nemmpts`\") ==\n        \"SELECT `mo``e\\\\inj````ectionatt\\nemmpts``` FROM myt\"\n    );\n\n    // Empty identifiers are not valid in MySQL but they shouldn't case formatting problems.\n    // They are correctly rejected by MySQL (they don't cause problems)\n    BOOST_TEST(format_sql(opts, identifier_fmt, \"\") == \"SELECT `` FROM myt\");\n\n    // As raw\n    BOOST_TEST(format_sql(opts, raw_fmt, \"abc\") == \"SELECT abc;\");              // regular\n    BOOST_TEST(format_sql(opts, raw_fmt, \"\") == \"SELECT ;\");                    // empty\n    BOOST_TEST(format_sql(opts, raw_fmt, \"a\\\\'\\\"b`c\") == \"SELECT a\\\\'\\\"b`c;\");  // we don't escape\n    BOOST_TEST(format_sql(opts, raw_fmt, \"a\\xff bc\") == \"SELECT a\\xff bc;\");    // we don't check charset\n}\n\nBOOST_AUTO_TEST_CASE(c_str)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, static_cast<const char*>(\"abc\")) == \"SELECT 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, static_cast<const char*>(\"\")) == \"SELECT '';\");\n}\n\nBOOST_AUTO_TEST_CASE(string)\n{\n    std::string lval = \"I'm an lvalue\";\n    const std::string clval = \"I'm const\";\n    BOOST_TEST(format_sql(opts, single_fmt, lval) == \"SELECT 'I\\\\'m an lvalue';\");\n    BOOST_TEST(format_sql(opts, single_fmt, clval) == \"SELECT 'I\\\\'m const';\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::string(\"abc\")) == \"SELECT 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::string()) == \"SELECT '';\");\n    BOOST_TEST(format_sql(opts, single_fmt, string_with_alloc(\"abc'\")) == \"SELECT 'abc\\\\'';\");\n\n    // specifiers work\n    BOOST_TEST(format_sql(opts, identifier_fmt, lval) == \"SELECT `I'm an lvalue` FROM myt\");\n    BOOST_TEST(format_sql(opts, identifier_fmt, clval) == \"SELECT `I'm const` FROM myt\");\n    BOOST_TEST(format_sql(opts, identifier_fmt, std::string(\"abc\")) == \"SELECT `abc` FROM myt\");\n    BOOST_TEST(format_sql(opts, identifier_fmt, string_with_alloc(\"abc\")) == \"SELECT `abc` FROM myt\");\n}\n\nBOOST_AUTO_TEST_CASE(string_view_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, string_view(\"abc\")) == \"SELECT 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, string_view(\"abc'\\\\ OR 1=1\")) == \"SELECT 'abc\\\\'\\\\\\\\ OR 1=1';\");\n    BOOST_TEST(format_sql(opts, single_fmt, string_view()) == \"SELECT '';\");\n\n    // specifiers work\n    BOOST_TEST(format_sql(opts, identifier_fmt, string_view(\"abc\")) == \"SELECT `abc` FROM myt\");\n}\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\nBOOST_AUTO_TEST_CASE(std_string_view)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, std::string_view(\"abc\")) == \"SELECT 'abc';\");\n    BOOST_TEST(\n        format_sql(opts, single_fmt, std::string_view(\"abc'\\\\ OR 1=1\")) == \"SELECT 'abc\\\\'\\\\\\\\ OR 1=1';\"\n    );\n    BOOST_TEST(format_sql(opts, single_fmt, std::string_view()) == \"SELECT '';\");\n\n    // specifiers work\n    BOOST_TEST(format_sql(opts, identifier_fmt, std::string_view(\"abc\")) == \"SELECT `abc` FROM myt\");\n}\n#endif\n\n// blob: encoded as a hex string\nBOOST_AUTO_TEST_CASE(blob_)\n{\n    blob lval{0x01, 0x00, 0x5c};\n    const blob clval{0x20, 0x71, 0xff};\n    BOOST_TEST(format_sql(opts, single_fmt, lval) == \"SELECT x'01005c';\");\n    BOOST_TEST(format_sql(opts, single_fmt, clval) == \"SELECT x'2071ff';\");\n    BOOST_TEST(format_sql(opts, single_fmt, blob{0x00, 0x2c}) == \"SELECT x'002c';\");\n}\n\nBOOST_AUTO_TEST_CASE(blob_coverage)\n{\n    struct\n    {\n        string_view name;\n        const blob input;\n        string_view expected;\n    } test_cases[] = {\n        {\"empty\",           {},                                                                            \"SELECT x'';\"        },\n        {\"injection_chars\", {0x5c, 0x5c, 0x27},                                                            \"SELECT x'5c5c27';\"  }, // 5c = backslash, 27 = single quote\n        {\"all_zeros\",       {0x00, 0x00, 0x00, 0x00},                                                      \"SELECT x'00000000';\"},\n\n        // Check that we encode all possible byte values correctly\n        {\"bytes_00_3f\",\n         {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n          0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,\n          0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,\n          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f},\n         \"SELECT x'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\"\n         \"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f';\"                                                   },\n        {\"bytes_40_7f\",\n         {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,\n          0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\n          0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\n          0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f},\n         \"SELECT x'404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162\"\n         \"636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f';\"                                                         },\n        {\"bytes_80_bf\",\n         {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n          0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n          0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n          0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf},\n         \"SELECT x'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\"\n         \"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf';\"                                                   },\n        {\"bytes_c0_ff\",\n         {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\n          0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\n          0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\n          0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff},\n         \"SELECT x'c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf\"\n         \"e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff';\"                                                   },\n\n        // We use a 64 byte buffer for the formatting operation. Update these if the buffer size changes.\n        {\"31_bytes\",\n         {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n          0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f},\n         \"SELECT x'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f';\"                                          },\n        {\"32_bytes\",\n         {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,\n          0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,\n          0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20},\n         \"SELECT x'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20';\"                                        },\n        {\"33_bytes\",\n         {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,\n          0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n          0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21},\n         \"SELECT x'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021';\"                                      },\n        {\"63_bytes\",\n         {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n          0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n          0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n          0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe},\n         \"SELECT x'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\"\n         \"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe';\"                                                     },\n        {\"64_bytes\",\n         {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n          0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n          0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n          0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf},\n         \"SELECT x'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\"\n         \"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf';\"                                                   },\n        {\"65_bytes\",\n         {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,\n          0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,\n          0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,\n          0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,\n          0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0},\n         \"SELECT x'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\"\n         \"a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0';\"                                                 },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { BOOST_TEST(format_sql(opts, single_fmt, tc.input) == tc.expected); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(blob_view_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, makebv(\"hello\\\\\")) == \"SELECT x'68656c6c6f5c';\");\n    BOOST_TEST(format_sql(opts, single_fmt, makebv(\"hello \\xc3\\xb1!\")) == \"SELECT x'68656c6c6f20c3b121';\");\n    BOOST_TEST(format_sql(opts, single_fmt, makebv(\"hello \\xc3'!\")) == \"SELECT x'68656c6c6f20c32721';\");\n    BOOST_TEST(format_sql(opts, single_fmt, blob_view()) == \"SELECT x'';\");\n}\n\nBOOST_AUTO_TEST_CASE(blob_array)\n{\n    // Collections of unsigned char are formatted as blob if they're convertible to span<const unsigned char>\n    std::array<unsigned char, 4> arr{\n        {5, 1, 0, 0xab}\n    };\n    const std::array<unsigned char, 4> carr{\n        {0xde, 0xad, 0xbe, 0xef}\n    };\n\n    BOOST_TEST(format_sql(opts, single_fmt, arr) == \"SELECT x'050100ab';\");\n    BOOST_TEST(format_sql(opts, single_fmt, carr) == \"SELECT x'deadbeef';\");\n}\n\nBOOST_AUTO_TEST_CASE(date_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, date(2021, 1, 20)) == \"SELECT '2021-01-20';\");\n    BOOST_TEST(format_sql(opts, single_fmt, date()) == \"SELECT '0000-00-00';\");\n    BOOST_TEST(format_sql(opts, single_fmt, date(0xffff, 0xff, 0xff)) == \"SELECT '65535-255-255';\");\n}\n\nBOOST_AUTO_TEST_CASE(datetime_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, datetime(2021, 1, 20)) == \"SELECT '2021-01-20 00:00:00.000000';\");\n    BOOST_TEST(\n        format_sql(opts, single_fmt, datetime(1998, 1, 1, 21, 3, 5, 12)) ==\n        \"SELECT '1998-01-01 21:03:05.000012';\"\n    );\n    BOOST_TEST(format_sql(opts, single_fmt, datetime()) == \"SELECT '0000-00-00 00:00:00.000000';\");\n    BOOST_TEST(\n        format_sql(opts, single_fmt, datetime(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff)) ==\n        \"SELECT '65535-255-255 255:255:255.4294967295';\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(time_)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, maket(127, 1, 10, 123)) == \"SELECT '127:01:10.000123';\");\n    BOOST_TEST(format_sql(opts, single_fmt, -maket(9, 1, 10)) == \"SELECT '-09:01:10.000000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, mysql_time()) == \"SELECT '00:00:00.000000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, (mysql_time::min)()) == \"SELECT '-2562047788:00:54.775808';\");\n    BOOST_TEST(format_sql(opts, single_fmt, (mysql_time::max)()) == \"SELECT '2562047788:00:54.775807';\");\n}\n\nBOOST_AUTO_TEST_CASE(duration)\n{\n    // Durations work as long as they're compatible with time\n    using namespace std::chrono;\n\n    BOOST_TEST(format_sql(opts, single_fmt, hours(21)) == \"SELECT '21:00:00.000000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, minutes(3)) == \"SELECT '00:03:00.000000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, seconds(-10)) == \"SELECT '-00:00:10.000000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, milliseconds(-9)) == \"SELECT '-00:00:00.009000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, microseconds(3214)) == \"SELECT '00:00:00.003214';\");\n}\n\nBOOST_AUTO_TEST_CASE(field_view_)\n{\n    field referenced(\"def\\\\\");\n    BOOST_TEST(format_sql(opts, single_fmt, field_view()) == \"SELECT NULL;\");\n    BOOST_TEST(format_sql(opts, single_fmt, field_view(42)) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, field_view(\"'abc'\")) == \"SELECT '\\\\'abc\\\\'';\");\n    BOOST_TEST(format_sql(opts, single_fmt, field_view(referenced)) == \"SELECT 'def\\\\\\\\';\");\n}\n\nBOOST_AUTO_TEST_CASE(field_)\n{\n    field f_lval(\"hol\\\"a\");\n    const field f_clval(42);\n    BOOST_TEST(format_sql(opts, single_fmt, field()) == \"SELECT NULL;\");\n    BOOST_TEST(format_sql(opts, single_fmt, field(4.2)) == \"SELECT 4.2e+00;\");\n    BOOST_TEST(format_sql(opts, single_fmt, f_lval) == \"SELECT 'hol\\\\\\\"a';\");\n    BOOST_TEST(format_sql(opts, single_fmt, f_clval) == \"SELECT 42;\");\n}\n\nBOOST_AUTO_TEST_CASE(boost_optional)\n{\n    boost::optional<std::string> o_lval(\"abc\");\n    boost::optional<const std::string> co_lval(\"ab'c\");\n    const boost::optional<std::string> o_clval(\"\\\\\");\n    const boost::optional<const std::string> co_clval(\"abdef\");\n    BOOST_TEST(format_sql(opts, single_fmt, boost::optional<int>()) == \"SELECT NULL;\");\n    BOOST_TEST(format_sql(opts, single_fmt, boost::optional<int>(42)) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, o_lval) == \"SELECT 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, co_lval) == \"SELECT 'ab\\\\'c';\");\n    BOOST_TEST(format_sql(opts, single_fmt, o_clval) == \"SELECT '\\\\\\\\';\");\n    BOOST_TEST(format_sql(opts, single_fmt, co_clval) == \"SELECT 'abdef';\");\n}\n\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nBOOST_AUTO_TEST_CASE(std_optional)\n{\n    std::optional<std::string> o_lval(\"abc\");\n    std::optional<const std::string> co_lval(\"ab'c\");\n    const std::optional<std::string> o_clval(\"\\\\\");\n    const std::optional<const std::string> co_clval(\"abdef\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::optional<int>()) == \"SELECT NULL;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::optional<int>(42)) == \"SELECT 42;\");\n    BOOST_TEST(format_sql(opts, single_fmt, o_lval) == \"SELECT 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, co_lval) == \"SELECT 'ab\\\\'c';\");\n    BOOST_TEST(format_sql(opts, single_fmt, o_clval) == \"SELECT '\\\\\\\\';\");\n    BOOST_TEST(format_sql(opts, single_fmt, co_clval) == \"SELECT 'abdef';\");\n}\n#endif\n\n//\n// Errors when formatting individual fields\n//\n\n// Make code less verbose\nconstexpr auto spec_err = client_errc::format_string_invalid_specifier;\n\nBOOST_AUTO_TEST_CASE(null_error)\n{\n    // Specifiers rejected\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", nullptr) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(integers_error)\n{\n    // Specifiers rejected\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (signed char)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (unsigned char)0xff) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (short)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:r}\", (unsigned short)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (int)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:d}\", (int)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {: }\", (int)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {::}\", (int)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (unsigned int)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (long)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (unsigned long)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (long long)42) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", (unsigned long long)42) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(bool_error)\n{\n    // Specifiers rejected\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", true) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:r}\", false) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(double_error)\n{\n    using double_limits = std::numeric_limits<double>;\n\n    // double inf and nan not supported\n    BOOST_TEST(format_single_error(\"{}\", double_limits::infinity()) == client_errc::unformattable_value);\n    BOOST_TEST(format_single_error(\"{}\", -double_limits::infinity()) == client_errc::unformattable_value);\n    BOOST_TEST(format_single_error(\"{}\", double_limits::quiet_NaN()) == client_errc::unformattable_value);\n\n    // Specifiers rejected\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", 21.0e10) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {: f}\", 0.0) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(float_error)\n{\n    using float_limits = std::numeric_limits<float>;\n\n    // float inf and nan not supported\n    BOOST_TEST(format_single_error(\"{}\", float_limits::infinity()) == client_errc::unformattable_value);\n    BOOST_TEST(format_single_error(\"{}\", -float_limits::infinity()) == client_errc::unformattable_value);\n    BOOST_TEST(format_single_error(\"{}\", float_limits::quiet_NaN()) == client_errc::unformattable_value);\n\n    // Specifiers rejected\n    BOOST_TEST(format_single_error(\"SELECT {:i}\", 4.2f) == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {: f}\", 4.2f) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(string_error)\n{\n    // strings with invalid characters\n    BOOST_TEST(format_single_error(\"{}\", \"a\\xc3'\") == client_errc::invalid_encoding);\n    BOOST_TEST(format_single_error(\"{}\", \"a\\xc3\\''\") == client_errc::invalid_encoding);\n    BOOST_TEST(format_single_error(\"{}\", \"a\\xff\\xff\") == client_errc::invalid_encoding);\n\n    // identifiers with invalid characters\n    BOOST_TEST(format_single_error(\"{:i}\", \"a\\xd8\") == client_errc::invalid_encoding);\n    BOOST_TEST(format_single_error(\"{:i}\", \"a\\xc3 \") == client_errc::invalid_encoding);\n\n    // unknown specifiers are rejected\n    BOOST_TEST(format_single_error(\"SELECT {:x}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:s}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:d}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:>}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {::}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:id}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:ir}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:ri}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:sd}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i:}\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:i }\", \"abc\") == spec_err);\n    BOOST_TEST(format_single_error(\"SELECT {:ivery long [value] with\\\" quotes'}\", \"abc\") == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(blob_error)\n{\n    // blobs reject specifiers\n    blob lval{0x01, 0x00, 0x5c};\n    const blob clval{0x20, 0x71, 0xff};\n    BOOST_TEST(format_single_error(\"{:i}\", lval) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", clval) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", blob_view(clval)) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(date_error)\n{\n    // date reject specifiers\n    BOOST_TEST(format_single_error(\"{:i}\", date(2021, 1, 20)) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(datetime_error)\n{\n    // datetime reject specifiers\n    BOOST_TEST(format_single_error(\"{:i}\", datetime(1998, 1, 1, 21, 3, 5, 12)) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(duration_error)\n{\n    // durations reject specifiers\n    BOOST_TEST(format_single_error(\"{:i}\", maket(9, 1, 10)) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", std::chrono::hours(9)) == spec_err);\n}\n\nBOOST_AUTO_TEST_CASE(field_view_error)\n{\n    // field_view rejects specifiers, even if the underlying type would support them\n    BOOST_TEST(format_single_error(\"{:i}\", field_view()) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", field_view(\"abc\")) == spec_err);\n    BOOST_TEST(format_single_error(\"{:r}\", field_view(\"abc\")) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", field_view(42)) == spec_err);\n\n    // Errors applicable to the contained type\n    BOOST_TEST(format_single_error(\"{}\", field_view(\"a\\xc3'\")) == client_errc::invalid_encoding);\n    BOOST_TEST(\n        format_single_error(\"{}\", field_view(std::numeric_limits<double>::infinity())) ==\n        client_errc::unformattable_value\n    );\n}\n\nBOOST_AUTO_TEST_CASE(field_error)\n{\n    // Same as field_view\n    BOOST_TEST(format_single_error(\"{:i}\", field(\"abc\")) == spec_err);\n    BOOST_TEST(format_single_error(\"{}\", field(\"a\\xc3'\")) == client_errc::invalid_encoding);\n    BOOST_TEST(\n        format_single_error(\"{}\", field(std::numeric_limits<double>::infinity())) ==\n        client_errc::unformattable_value\n    );\n}\n\n// Apply the same test to boost and std optional types\ntemplate <template <class> class Optional>\nvoid optional_error_test()\n{\n    Optional<std::string> o_lval(\"abc\");\n    Optional<const std::string> co_lval(\"ab'c\");\n    const Optional<std::string> o_clval(\"\\\\\");\n    const Optional<const std::string> co_clval(\"abdef\");\n\n    // optionals rejects specifiers, even if the underlying type would support them\n    BOOST_TEST(format_single_error(\"{:i}\", o_lval) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", co_lval) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", o_clval) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", co_clval) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", Optional<std::string>(\"abc\")) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", Optional<std::string>()) == spec_err);\n    BOOST_TEST(format_single_error(\"{:r}\", Optional<std::string>(\"abc\")) == spec_err);\n    BOOST_TEST(format_single_error(\"{:i}\", Optional<int>(42)) == spec_err);\n\n    // Errors applicable to the contained type\n    BOOST_TEST(\n        format_single_error(\"{}\", Optional<std::string>(\"b\\xff\\xff\")) == client_errc::invalid_encoding\n    );\n    BOOST_TEST(\n        format_single_error(\"{}\", Optional<double>(std::numeric_limits<double>::infinity())) ==\n        client_errc::unformattable_value\n    );\n}\n\nBOOST_AUTO_TEST_CASE(boost_optional_error) { optional_error_test<boost::optional>(); }\n\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nBOOST_AUTO_TEST_CASE(std_optional_error) { optional_error_test<std::optional>(); }\n#endif\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/format_sql/ranges.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/config.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <forward_list>\n#include <iterator>\n#include <vector>\n\n#include \"format_common.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/has_ranges.hpp\"\n#include \"test_common/printing.hpp\"\n\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n#include <string_view>\n#endif\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\n#include <optional>\n#endif\n#ifdef BOOST_MYSQL_HAS_RANGES\n#include <ranges>\n#endif\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing mysql_time = boost::mysql::time;\n\n//\n// Verify that the default formatting for ranges works\n//\nBOOST_AUTO_TEST_SUITE(test_format_sql_ranges)\n\nconstexpr format_options opts{utf8mb4_charset, true};\nconstexpr const char* single_fmt = \"SELECT {};\";\n\n//\n// Different element types\n//\nBOOST_AUTO_TEST_CASE(elm_integral)\n{\n    // Note: unsigned char is formatted as a blob, instead\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<signed char>{42, -1}) == \"SELECT 42, -1;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<short>{42, 10}) == \"SELECT 42, 10;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<unsigned short>{0, 10}) == \"SELECT 0, 10;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<int>{-1, 8}) == \"SELECT -1, 8;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<unsigned>{10, 8}) == \"SELECT 10, 8;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<long>{10, 8}) == \"SELECT 10, 8;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<unsigned long>{10, 8}) == \"SELECT 10, 8;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<long long>{10, 8}) == \"SELECT 10, 8;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<unsigned long long>{10, 8}) == \"SELECT 10, 8;\");\n\n    std::array<bool, 2> arr_of_bool{\n        {true, false}\n    };\n    BOOST_TEST(format_sql(opts, single_fmt, arr_of_bool) == \"SELECT 1, 0;\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_floating_point)\n{\n    BOOST_TEST(\n        format_sql(opts, single_fmt, std::vector<float>{4.2f, 0.0f}) == \"SELECT 4.199999809265137e+00, 0e+00;\"\n    );\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<double>{4.2, 0.0}) == \"SELECT 4.2e+00, 0e+00;\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_string)\n{\n    BOOST_TEST(\n        format_sql(opts, single_fmt, std::vector<const char*>{\"abc\", \"buf\"}) == \"SELECT 'abc', 'buf';\"\n    );\n    BOOST_TEST(\n        format_sql(opts, single_fmt, std::vector<std::string>{\"abc\", \"buf\"}) == \"SELECT 'abc', 'buf';\"\n    );\n    BOOST_TEST(\n        format_sql(opts, single_fmt, std::vector<string_view>{\"abc\", \"buf\"}) == \"SELECT 'abc', 'buf';\"\n    );\n#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW\n    BOOST_TEST(\n        format_sql(opts, single_fmt, std::vector<std::string_view>{\"abc\", \"buf\"}) == \"SELECT 'abc', 'buf';\"\n    );\n#endif\n\n    // Specifiers handled correctly\n    BOOST_TEST(\n        format_sql(opts, \"FROM {::i};\", std::vector<const char*>{\"abc\", \"buf\"}) == \"FROM `abc`, `buf`;\"\n    );\n    BOOST_TEST(format_sql(opts, \"FROM {::r};\", std::vector<string_view>{\"SELECT\", \"*\"}) == \"FROM SELECT, *;\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_blob)\n{\n    std::vector<blob> blobs{\n        {0x01, 0x00},\n        {0xff, 0x2c}\n    };\n    std::vector<blob_view> blob_views{\n        makebv(\"hello\\\\\"),\n        makebv(\"hello \\xc3\\xb1!\"),\n    };\n\n    BOOST_TEST(format_sql(opts, single_fmt, blobs) == \"SELECT x'0100', x'ff2c';\");\n    BOOST_TEST(format_sql(opts, single_fmt, blob_views) == \"SELECT x'68656c6c6f5c', x'68656c6c6f20c3b121';\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_date)\n{\n    std::vector<date> dates{\n        {2021, 1,  20},\n        {2020, 10, 1 }\n    };\n    BOOST_TEST(format_sql(opts, single_fmt, dates) == \"SELECT '2021-01-20', '2020-10-01';\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_datetime)\n{\n    std::vector<datetime> datetimes{\n        {2021, 1, 20, 21, 49, 21, 912},\n        {2020, 10, 1, 10, 1, 2}\n    };\n    BOOST_TEST(\n        format_sql(opts, single_fmt, datetimes) ==\n        \"SELECT '2021-01-20 21:49:21.000912', '2020-10-01 10:01:02.000000';\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(elm_duration)\n{\n    std::vector<mysql_time> times{maket(20, 1, 2, 1234), maket(1, 2, 3)};\n    std::vector<std::chrono::seconds> secs{std::chrono::seconds(20), std::chrono::seconds(61)};\n\n    BOOST_TEST(format_sql(opts, single_fmt, times) == \"SELECT '20:01:02.001234', '01:02:03.000000';\");\n    BOOST_TEST(format_sql(opts, single_fmt, secs) == \"SELECT '00:00:20.000000', '00:01:01.000000';\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_field)\n{\n    std::vector<field> fields{field(\"abc\"), field(42)};\n    BOOST_TEST(format_sql(opts, single_fmt, make_fv_vector(10, \"42\", nullptr)) == \"SELECT 10, '42', NULL;\");\n    BOOST_TEST(format_sql(opts, single_fmt, fields) == \"SELECT 'abc', 42;\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_boost_optional)\n{\n    std::vector<boost::optional<int>> optionals{42, 10, {}};\n    BOOST_TEST(format_sql(opts, single_fmt, optionals) == \"SELECT 42, 10, NULL;\");\n}\n\n#ifndef BOOST_NO_CXX17_HDR_OPTIONAL\nBOOST_AUTO_TEST_CASE(elm_std_optional)\n{\n    std::vector<std::optional<std::string>> optionals{\"abc\", {}, \"d\"};\n    BOOST_TEST(format_sql(opts, single_fmt, optionals) == \"SELECT 'abc', NULL, 'd';\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(elm_custom_type)\n{\n    std::vector<custom::condition> conds{\n        {\"f1\", 42},\n        {\"f2\", 60},\n    };\n\n    BOOST_TEST(format_sql(opts, single_fmt, conds) == \"SELECT `f1`=42, `f2`=60;\");\n\n    // Specifiers are correctly passed to custom types\n    BOOST_TEST(format_sql(opts, \"SELECT {::s};\", conds) == \"SELECT `f1` = 42, `f2` = 60;\");\n}\n\n//\n// Different range types\n//\nBOOST_AUTO_TEST_CASE(range_c_array)\n{\n    const int values[] = {42, 60};\n    BOOST_TEST(format_sql(opts, single_fmt, values) == \"SELECT 42, 60;\");\n}\n\nBOOST_AUTO_TEST_CASE(range_std_array)\n{\n    std::array<int, 2> values{\n        {42, 60}\n    };\n    BOOST_TEST(format_sql(opts, single_fmt, values) == \"SELECT 42, 60;\");\n}\n\nBOOST_AUTO_TEST_CASE(range_forward_list)\n{\n    std::forward_list<int> values{\n        {42, 60}\n    };\n    BOOST_TEST(format_sql(opts, \"SELECT {};\", values) == \"SELECT 42, 60;\");\n}\n\nBOOST_AUTO_TEST_CASE(range_const)\n{\n    const std::vector<int> values{42, 60};\n    BOOST_TEST(format_sql(opts, \"SELECT {};\", values) == \"SELECT 42, 60;\");\n}\n\n#ifdef BOOST_MYSQL_HAS_RANGES\nBOOST_AUTO_TEST_CASE(range_input_iterator)\n{\n    std::istringstream str(\"1 5 15\");\n    std::ranges::subrange subr{std::istream_iterator<int>(str), std::istream_iterator<int>()};\n    BOOST_TEST(format_sql(opts, single_fmt, subr) == \"SELECT 1, 5, 15;\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(range_row)\n{\n    auto r = makerow(42, \"abc\");\n    BOOST_TEST(format_sql(opts, single_fmt, r) == \"SELECT 42, 'abc';\");\n    BOOST_TEST(format_sql(opts, single_fmt, row_view(r)) == \"SELECT 42, 'abc';\");\n}\n\n#ifdef BOOST_MYSQL_HAS_RANGES\nBOOST_AUTO_TEST_CASE(range_not_common)\n{\n    // Sentinel type != iterator type\n    auto r = std::ranges::views::iota(5) | std::ranges::views::take(3);\n    static_assert(!std::is_same_v<decltype(r.begin()), decltype(r.end())>);\n    BOOST_TEST(format_sql(opts, single_fmt, r) == \"SELECT 5, 6, 7;\");\n}\n\nBOOST_AUTO_TEST_CASE(range_not_const)\n{\n    std::vector<long> values{4, 10, 1, 21};\n    auto r = values | std::ranges::views::filter([](long v) { return v >= 10; });\n    BOOST_TEST(format_sql(opts, single_fmt, r) == \"SELECT 10, 21;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::move(r)) == \"SELECT 10, 21;\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(vector_of_bool)\n{\n    std::vector<bool> values{true, false};\n    BOOST_TEST(format_sql(opts, single_fmt, values) == \"SELECT 1, 0;\");\n}\n\n// Different number of elements\nBOOST_AUTO_TEST_CASE(num_elms)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<long>{}) == \"SELECT ;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<long>{10}) == \"SELECT 10;\");\n    BOOST_TEST(format_sql(opts, single_fmt, std::vector<long>{1, 2, 3, 4}) == \"SELECT 1, 2, 3, 4;\");\n}\n\n// Empty specs do nothing\nBOOST_AUTO_TEST_CASE(empty_specs)\n{\n    std::vector<const char*> elms{\"abc\", \"def\"};\n    BOOST_TEST(format_sql(opts, \"SELECT {:};\", elms) == \"SELECT 'abc', 'def';\");\n    BOOST_TEST(format_sql(opts, \"SELECT {::};\", elms) == \"SELECT 'abc', 'def';\");\n}\n\n//\n// Errors\n//\nBOOST_AUTO_TEST_CASE(error_underlying_type_doesnt_support_spec)\n{\n    // The underlying type must be string for 'i' to be supported\n    BOOST_TEST(\n        format_single_error(\"{::i}\", make_fv_arr(\"abc\", \"def\")) ==\n        client_errc::format_string_invalid_specifier\n    );\n\n    // int does not support 'r'\n    BOOST_TEST(\n        format_single_error(\"{::r}\", std::vector<int>{1, 2}) == client_errc::format_string_invalid_specifier\n    );\n}\n\nBOOST_AUTO_TEST_CASE(error_parsing_spec)\n{\n    // These are rejected by the collection spec parser\n    string_view test_cases[] = {\n        \"{:a}\",\n        \"{:a:}\",\n        \"{:a:i}\",\n        \"{:[]:}\",\n    };\n\n    for (auto s : test_cases)\n    {\n        BOOST_TEST_CONTEXT(s)\n        {\n            std::vector<const char*> coll{\"abc\", \"def\"};\n            BOOST_TEST(format_single_error(runtime(s), coll) == client_errc::format_string_invalid_specifier);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_formatting_element)\n{\n    std::vector<const char*> coll{\"abc\", \"d\\xffpol\", \"aaaaa\"};\n    BOOST_TEST(format_single_error(single_fmt, coll) == client_errc::invalid_encoding);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/format_sql/sequence.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/constant_string_view.hpp>\n#include <boost/mysql/format_sql.hpp>\n#include <boost/mysql/sequence.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <forward_list>\n#include <functional>\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <vector>\n\n#include \"format_common.hpp\"\n#include \"test_common/has_ranges.hpp\"\n#include \"test_common/printing.hpp\"\n\n#ifdef BOOST_MYSQL_HAS_RANGES\n#include <ranges>\n#endif\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_format_sql_sequence)\n\nconstexpr format_options opts{utf8mb4_charset, true};\nconstexpr const char* single_fmt = \"SELECT {};\";\n\n//\n// sequence_range_t type trait\n//\ntemplate <class Input, class Expected>\nconstexpr bool check_sequence_range()\n{\n    return std::is_same<sequence_range_t<Input>, Expected>::value;\n}\n\nusing intvec = std::vector<int>;\n\n// Regular values kept\nstatic_assert(check_sequence_range<intvec, intvec>(), \"\");\nstatic_assert(check_sequence_range<std::forward_list<int>, std::forward_list<int>>(), \"\");\n\n// References and cv-qualifiers stripped\nstatic_assert(check_sequence_range<intvec&, intvec>(), \"\");\nstatic_assert(check_sequence_range<intvec&&, intvec>(), \"\");\nstatic_assert(check_sequence_range<const intvec&, intvec>(), \"\");\nstatic_assert(check_sequence_range<const intvec&&, intvec>(), \"\");\nstatic_assert(check_sequence_range<const intvec, intvec>(), \"\");\n\n// Reference wrappers converted to references\nstatic_assert(check_sequence_range<std::reference_wrapper<intvec>, intvec&>(), \"\");\nstatic_assert(check_sequence_range<std::reference_wrapper<const intvec>, const intvec&>(), \"\");\nstatic_assert(check_sequence_range<std::reference_wrapper<intvec>&, intvec&>(), \"\");\nstatic_assert(check_sequence_range<std::reference_wrapper<const intvec>&, const intvec&>(), \"\");\nstatic_assert(check_sequence_range<const std::reference_wrapper<intvec>&, intvec&>(), \"\");\nstatic_assert(check_sequence_range<const std::reference_wrapper<const intvec>&, const intvec&>(), \"\");\nstatic_assert(check_sequence_range<std::reference_wrapper<intvec>&&, intvec&>(), \"\");\nstatic_assert(check_sequence_range<std::reference_wrapper<const intvec>&&, const intvec&>(), \"\");\nstatic_assert(check_sequence_range<const std::reference_wrapper<intvec>, intvec&>(), \"\");\nstatic_assert(check_sequence_range<const std::reference_wrapper<const intvec>, const intvec&>(), \"\");\n\n// C arrays converted to std::array\nstatic_assert(check_sequence_range<int (&)[2], std::array<int, 2>>(), \"\");\nstatic_assert(check_sequence_range<int (&&)[2], std::array<int, 2>>(), \"\");\nstatic_assert(check_sequence_range<const int (&)[2], std::array<int, 2>>(), \"\");\nstatic_assert(check_sequence_range<const int (&&)[2], std::array<int, 2>>(), \"\");\n\n//\n// Different element types\n//\nBOOST_AUTO_TEST_CASE(elm_type_formattable)\n{\n    // We don't invoke the default formatter\n    auto fn = [](int v, format_context_base& ctx) { format_sql_to(ctx, \"{}\", v * v); };\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(std::vector<int>{1, 2, 3}, fn)) == \"SELECT 1, 4, 9;\");\n}\n\nBOOST_AUTO_TEST_CASE(elm_type_not_formattable)\n{\n    struct S\n    {\n        int v;\n    } elms[] = {{1}, {2}, {3}};\n    auto fn = [](S v, format_context_base& ctx) { format_sql_to(ctx, \"{}\", v.v); };\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(elms, fn)) == \"SELECT 1, 2, 3;\");\n}\n\n//\n// Different function types\n//\nBOOST_AUTO_TEST_CASE(fn_type_convertible)\n{\n    std::vector<const char*> elms{\"abc\", \"def\"};\n    auto fn = [](string_view s, format_context_base& ctx) { format_sql_to(ctx, \"{:i}\", s); };\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(elms, fn)) == \"SELECT `abc`, `def`;\");\n}\n\nBOOST_AUTO_TEST_CASE(fn_decay_copied)\n{\n    std::vector<long> elms{1, 2};\n    auto seq = sequence(elms, [](long v, format_context_base& ctx) {\n        format_sql_to(ctx, \"{}\", std::to_string(v));\n    });\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '2';\");\n}\n\n// Different glues\nBOOST_AUTO_TEST_CASE(glue)\n{\n    struct\n    {\n        string_view name;\n        string_view glue;\n        string_view expected;\n    } test_cases[] = {\n        {\"regular\",         \" OR \",   \"1 OR 2 OR 3\"    },\n        {\"braces\",          \"{}\",     \"1{}2{}3\"        },\n        {\"invalid_utf8\",    \" \\xff \", \"1 \\xff 2 \\xff 3\"},\n        {\"escapable_chars\", \"'`\",     \"1'`2'`3\"        },\n        {\"empty\",           \"\",       \"123\"            },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            std::array<int, 3> arr{\n                {1, 2, 3}\n            };\n            auto fn = [](int v, format_context_base& ctx) { format_sql_to(ctx, \"{}\", v); };\n\n            BOOST_TEST(format_sql(opts, \"{}\", sequence(arr, fn, runtime(tc.glue))) == tc.expected);\n        }\n    }\n}\n\n//\n// Different range types\n//\n\nconstexpr struct fmt_as_str_t\n{\n    void operator()(int v, format_context_base& ctx) const { format_sql_to(ctx, \"{}\", std::to_string(v)); };\n} fmt_as_str{};\n\nBOOST_AUTO_TEST_CASE(range_c_array)\n{\n    int arr[] = {1, 4, 2};\n    auto seq = sequence(arr, fmt_as_str);\n    static_assert(std::is_same<decltype(seq), format_sequence<std::array<int, 3>, fmt_as_str_t>>::value, \"\");\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\nBOOST_AUTO_TEST_CASE(range_const_c_array)\n{\n    const int arr[] = {1, 4, 2};\n    auto seq = sequence(arr, fmt_as_str);\n    static_assert(std::is_same<decltype(seq), format_sequence<std::array<int, 3>, fmt_as_str_t>>::value, \"\");\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\n// MSVC 14.1 rvalue references to C arrays don't work\n#if !BOOST_WORKAROUND(BOOST_MSVC, < 1920)\nBOOST_AUTO_TEST_CASE(range_move_only_c_array)\n{\n    std::unique_ptr<int> arr[] = {std::unique_ptr<int>(new int(10)), std::unique_ptr<int>(new int(20))};\n    auto fn = [](const std::unique_ptr<int>& ptr, format_context_base& ctx) { ctx.append_value(*ptr); };\n    auto seq = sequence(std::move(arr), fn);\n    static_assert(\n        std::is_same<decltype(seq), format_sequence<std::array<std::unique_ptr<int>, 2>, decltype(fn)>>::\n            value,\n        \"\"\n    );\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT 10, 20;\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(range_std_array)\n{\n    std::array<int, 3> arr{\n        {1, 4, 2}\n    };\n    auto seq = sequence(arr, fmt_as_str);\n    static_assert(std::is_same<decltype(seq), format_sequence<std::array<int, 3>, fmt_as_str_t>>::value, \"\");\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\nBOOST_AUTO_TEST_CASE(range_ref)\n{\n    std::vector<int> vec{1, 4, 2};\n    auto seq = sequence(std::ref(vec), fmt_as_str);\n    static_assert(std::is_same<decltype(seq), format_sequence<std::vector<int>&, fmt_as_str_t>>::value, \"\");\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\nBOOST_AUTO_TEST_CASE(range_const_ref)\n{\n    const std::vector<int> vec{1, 4, 2};\n    auto seq = sequence(std::ref(vec), fmt_as_str);\n    static_assert(\n        std::is_same<decltype(seq), format_sequence<const std::vector<int>&, fmt_as_str_t>>::value,\n        \"\"\n    );\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\nBOOST_AUTO_TEST_CASE(range_forward_list)\n{\n    std::forward_list<int> col{1, 4, 2};\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(col, fmt_as_str)) == \"SELECT '1', '4', '2';\");\n}\n\n#ifdef BOOST_MYSQL_HAS_RANGES\nBOOST_AUTO_TEST_CASE(range_input_iterator)\n{\n    std::istringstream str(\"1 4 2\");\n    std::ranges::subrange subr{std::istream_iterator<int>(str), std::istream_iterator<int>()};\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(subr, fmt_as_str)) == \"SELECT '1', '4', '2';\");\n}\n#endif\n\n#ifdef BOOST_MYSQL_HAS_RANGES\nBOOST_AUTO_TEST_CASE(range_not_common)\n{\n    // Sentinel type != iterator type\n    auto r = std::ranges::views::iota(5) | std::ranges::views::take(3);\n    static_assert(!std::is_same_v<decltype(r.begin()), decltype(r.end())>);\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(r, fmt_as_str)) == \"SELECT '5', '6', '7';\");\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(std::move(r), fmt_as_str)) == \"SELECT '5', '6', '7';\");\n}\n\nBOOST_AUTO_TEST_CASE(range_not_const)\n{\n    // We decay-copy the range, so this works even if the range is const\n    std::vector<long> values{4, 10, 1, 21};\n    const auto r = values | std::ranges::views::filter([](long v) { return v >= 10; });\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(r, fmt_as_str)) == \"SELECT '10', '21';\");\n}\n#endif\n\nBOOST_AUTO_TEST_CASE(range_vector_of_bool)\n{\n    std::vector<bool> values{true, false};\n    auto fn = [](bool v, format_context_base& ctx) { format_sql_to(ctx, \"{}\", v ? \"true\" : \"false\"); };\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(values, fn)) == \"SELECT 'true', 'false';\");\n}\n\n// Different number of elements\nBOOST_AUTO_TEST_CASE(num_elms)\n{\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(std::vector<int>{}, fmt_as_str)) == \"SELECT ;\");\n    BOOST_TEST(format_sql(opts, single_fmt, sequence(std::vector<int>{1}, fmt_as_str)) == \"SELECT '1';\");\n}\n\n// Spotcheck: lvalues work\nBOOST_AUTO_TEST_CASE(lvalue)\n{\n    auto seq = sequence(std::vector<int>{1, 4, 2}, fmt_as_str);\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\nBOOST_AUTO_TEST_CASE(const_lvalue)\n{\n    const auto seq = sequence(std::vector<int>{1, 4, 2}, fmt_as_str);\n    BOOST_TEST(format_sql(opts, single_fmt, seq) == \"SELECT '1', '4', '2';\");\n}\n\n//\n// Error cases\n//\nBOOST_AUTO_TEST_CASE(error_nonempty_spec)\n{\n    string_view test_cases[] = {\n        \"{:i}\",\n        \"{:other}\",\n        \"{::}\",\n        \"{::i}\",\n        \"{:i:}\",\n        \"{:i:i}\",\n    };\n\n    for (auto fmt : test_cases)\n    {\n        BOOST_TEST_CONTEXT(fmt)\n        {\n            BOOST_TEST(\n                format_single_error(runtime(fmt), sequence(std::vector<int>{10}, fmt_as_str)) ==\n                client_errc::format_string_invalid_specifier\n            );\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_formatting_element)\n{\n    auto fn = [](int v, format_context_base& ctx) {\n        if (v == 42)\n            ctx.add_error(client_errc::wrong_num_params);\n        format_sql_to(ctx, \"{}\", v);\n    };\n    std::vector<int> col{1, 42, 10};\n    BOOST_TEST(format_single_error(\"{}\", sequence(col, fn)) == client_errc::wrong_num_params);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/impl/dt_to_string.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/time.hpp>\n\n#include <boost/mysql/impl/internal/dt_to_string.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <cstdint>\n#include <random>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/stringize.hpp\"\n\n// These tests use heap-allocated buffers for all cases because it helps asan detect overflows\n\nusing namespace boost::mysql;\nusing test::maket;\n\nBOOST_AUTO_TEST_SUITE(test_dt_to_string)\n\n// A wrapper around std::random to generate integers using a uniform distribution\ntemplate <class IntType>\nclass int_generator\n{\n    std::mt19937 mt_{std::random_device{}()};\n    std::uniform_int_distribution<IntType> dist_;\n\npublic:\n    int_generator(IntType a, IntType b) : dist_(a, b) {}\n    IntType generate() { return dist_(mt_); }\n};\n\n// Represents a broken date/datetime/time component. Used in all coverage tests\ntemplate <class IntType>\nstruct component_value\n{\n    const char* name;\n    IntType value;\n    const char* repr;\n};\n\n// date\nstatic std::string invoke_to_string(date d)\n{\n    std::string res(32, '\\0');\n    std::size_t sz = detail::date_to_string(d.year(), d.month(), d.day(), boost::span<char, 32>(&res[0], 32));\n    res.resize(sz);\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(date_coverage)\n{\n    // We use a dot product to cover common cases\n    component_value<std::uint16_t> year_values[] = {\n        {\"min\",      0,      \"0000\" },\n        {\"onedig\",   1,      \"0001\" },\n        {\"twodig\",   98,     \"0098\" },\n        {\"threedig\", 789,    \"0789\" },\n        {\"regular\",  1999,   \"1999\" },\n        {\"fourdig\",  9999,   \"9999\" },\n        {\"max\",      0xffff, \"65535\"},\n    };\n\n    component_value<std::uint8_t> month_values[] = {\n        {\"zero\", 0,    \"00\" },\n        {\"1dig\", 2,    \"02\" },\n        {\"2dig\", 12,   \"12\" },\n        {\"max\",  0xff, \"255\"},\n    };\n\n    component_value<std::uint8_t> day_values[] = {\n        {\"zero\", 0,    \"00\" },\n        {\"1dig\", 1,    \"01\" },\n        {\"2dig\", 31,   \"31\" },\n        {\"max\",  0xff, \"255\"},\n    };\n\n    for (const auto& year : year_values)\n    {\n        for (const auto& month : month_values)\n        {\n            for (const auto& day : day_values)\n            {\n                BOOST_TEST_CONTEXT(\"year=\" << year.name << \", month=\" << month.name << \", day=\" << day.name)\n                {\n                    // Expected value\n                    auto expected = test::stringize(year.repr, '-', month.repr, '-', day.repr);\n\n                    // Input value\n                    date d(year.value, month.value, day.value);\n\n                    // Call the function. Using a heap-allocated buffer helps detect overruns\n                    auto actual = invoke_to_string(d);\n\n                    // Check\n                    BOOST_TEST(actual == expected);\n                }\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(date_padding)\n{\n    // Double-check we correctly pad, regardless of the number\n    // All dates below 9999-xx-xx should have 10 characters\n    constexpr std::size_t expected_size = 10;\n\n    // Day\n    for (std::uint8_t day = 0u; day <= 31u; ++day)\n    {\n        BOOST_TEST_CONTEXT(day)\n        {\n            date d(2021, 1, day);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Month\n    for (std::uint8_t month = 0u; month <= 12u; ++month)\n    {\n        BOOST_TEST_CONTEXT(month)\n        {\n            date d(2021, month, 12);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Year. Iterating all values is too costly, so we check some random ones\n    int_generator<std::uint16_t> year_gen(std::uint16_t(0), std::uint16_t(9999));\n    for (int i = 0; i < 30; ++i)\n    {\n        std::uint16_t year = year_gen.generate();\n        BOOST_TEST_CONTEXT(year)\n        {\n            date d(year, 2, 12);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n}\n\n// datetime\nstatic std::string invoke_to_string(datetime d)\n{\n    std::string res(64, '\\0');\n    std::size_t sz = detail::datetime_to_string(\n        d.year(),\n        d.month(),\n        d.day(),\n        d.hour(),\n        d.minute(),\n        d.second(),\n        d.microsecond(),\n        boost::span<char, 64>(&res[0], 64)\n    );\n    res.resize(sz);\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(datetime_coverage)\n{\n    // We use a dot product to cover common cases\n    constexpr component_value<std::uint16_t> year_values[] = {\n        {\"min\",       0,      \"0000\" },\n        {\"onedig\",    1,      \"0001\" },\n        {\"twodig\",    98,     \"0098\" },\n        {\"threedig\",  789,    \"0789\" },\n        {\"regular\",   1999,   \"1999\" },\n        {\"max_mysql\", 9999,   \"9999\" },\n        {\"max\",       0xffff, \"65535\"},\n    };\n\n    constexpr component_value<std::uint8_t> month_values[] = {\n        {\"zero\",   0,    \"00\" },\n        {\"onedig\", 2,    \"02\" },\n        {\"twodig\", 12,   \"12\" },\n        {\"max\",    0xff, \"255\"},\n    };\n\n    constexpr component_value<std::uint8_t> day_values[] = {\n        {\"zero\",   0,    \"00\" },\n        {\"onedig\", 1,    \"01\" },\n        {\"twodig\", 31,   \"31\" },\n        {\"max\",    0xff, \"255\"},\n    };\n\n    constexpr component_value<std::uint8_t> hours_values[] = {\n        {\"zero\",   0,    \"00\" },\n        {\"onedig\", 5,    \"05\" },\n        {\"twodig\", 23,   \"23\" },\n        {\"max\",    0xff, \"255\"},\n    };\n\n    constexpr component_value<std::uint8_t> mins_secs_values[] = {\n        {\"zero\",   0,    \"00\" },\n        {\"onedig\", 5,    \"05\" },\n        {\"twodig\", 59,   \"59\" },\n        {\"max\",    0xff, \"255\"},\n    };\n\n    constexpr component_value<std::uint32_t> micros_values[] = {\n        {\"zero\",      0,          \"000000\"    },\n        {\"onedig\",    5,          \"000005\"    },\n        {\"twodig\",    50,         \"000050\"    },\n        {\"max_mysql\", 999999,     \"999999\"    },\n        {\"max\",       0xffffffff, \"4294967295\"},\n    };\n\n    // clang-format off\n    for (const auto& year : year_values)\n    {\n    for (const auto& month : month_values)\n    {\n    for (const auto& day : day_values)\n    {\n    for (const auto& hours : hours_values)\n    {\n    for (const auto& mins : mins_secs_values)\n    {\n    for (const auto& secs : mins_secs_values)\n    {\n    for (const auto& micros : micros_values)\n    {\n        BOOST_TEST_CONTEXT(\n            \"year=\" << year.name << \", month=\" << month.name << \"day=\" << day.name <<\n            \"hour=\" << hours.name << \", mins=\" << mins.name << \", secs=\" << secs.name <<\n            \"micros=\" << micros.name\n        )\n        {\n            // Expected value\n            std::string expected = test::stringize(\n                year.repr, '-', month.repr, '-', day.repr, ' ',\n                hours.repr, ':', mins.repr, ':', secs.repr,\n                '.', micros.repr\n            );\n\n            // Input value\n            datetime dt(\n                year.value,\n                month.value,\n                day.value,\n                hours.value,\n                mins.value,\n                secs.value,\n                micros.value\n            );\n\n            // Call the function\n            auto actual = invoke_to_string(dt);\n\n            // Check\n            BOOST_TEST(actual == expected);\n        }\n    }\n    }\n    }\n    }\n    }\n    }\n    }\n    // clang-format on\n}\n\nBOOST_AUTO_TEST_CASE(datetime_padding)\n{\n    // Double-check we correctly pad, regardless of the number\n    // All datetimes below 9999-xx-xx xx:xx:xx.xxxxxx should have 26 characters\n    constexpr std::size_t expected_size = 26;\n\n    // Year. Iterating all values is too costly, so we check some random ones\n    int_generator<std::uint16_t> year_gen(std::uint16_t(0), std::uint16_t(9999));\n    for (int i = 0; i < 30; ++i)\n    {\n        std::uint16_t year = year_gen.generate();\n        BOOST_TEST_CONTEXT(year)\n        {\n            datetime d(year, 2, 12);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Month\n    for (std::uint8_t month = 0u; month <= 31u; ++month)\n    {\n        BOOST_TEST_CONTEXT(month)\n        {\n            datetime d(2021, month, 12);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Day\n    for (std::uint8_t day = 0u; day <= 31u; ++day)\n    {\n        BOOST_TEST_CONTEXT(day)\n        {\n            datetime d(2021, 1, day);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Hour\n    for (std::uint8_t hour = 0u; hour <= 23u; ++hour)\n    {\n        BOOST_TEST_CONTEXT(hour)\n        {\n            datetime d(2021, 1, 3, hour, 10, 15);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Minute\n    for (std::uint8_t minute = 0u; minute <= 59u; ++minute)\n    {\n        BOOST_TEST_CONTEXT(minute)\n        {\n            datetime d(2021, 1, 3, 10, minute, 15);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Second\n    for (std::uint8_t second = 0u; second <= 59u; ++second)\n    {\n        BOOST_TEST_CONTEXT(second)\n        {\n            datetime d(2021, 1, 3, 10, 43, second);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n\n    // Microsecond. Same as for year\n    int_generator<std::uint32_t> micro_gen(std::uint32_t(0), std::uint32_t(999999));\n    for (int i = 0; i < 50; ++i)\n    {\n        std::uint32_t micro = micro_gen.generate();\n        BOOST_TEST_CONTEXT(micro)\n        {\n            datetime d(2021, 1, 3, 10, 43, 10, micro);\n            BOOST_TEST(invoke_to_string(d).size() == expected_size);\n        }\n    }\n}\n\n// time\nstatic std::string invoke_to_string(::boost::mysql::time t)\n{\n    std::string res(64, '\\0');\n    std::size_t sz = detail::time_to_string(t, boost::span<char, 64>(&res[0], 64));\n    res.resize(sz);\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(time_minmax)\n{\n    // Double-check C++ min/max work (regression check)\n    BOOST_TEST(invoke_to_string((::boost::mysql::time::min)()) == \"-2562047788:00:54.775808\");\n    BOOST_TEST(\n        invoke_to_string((::boost::mysql::time::min)() + std::chrono::microseconds(1)) ==\n        \"-2562047788:00:54.775807\"\n    );\n    BOOST_TEST(invoke_to_string((::boost::mysql::time::max)()) == \"2562047788:00:54.775807\");\n    BOOST_TEST(\n        invoke_to_string((::boost::mysql::time::max)() - std::chrono::microseconds(1)) ==\n        \"2562047788:00:54.775806\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(time_coverage)\n{\n    // We use a dot product to cover common cases\n    constexpr component_value<int> sign_values[] = {\n        {\"positive\", 1,  \"\" },\n        {\"negative\", -1, \"-\"}\n    };\n\n    constexpr component_value<int> hours_values[] = {\n        {\"zero\",      0,   \"00\" },\n        {\"onedigit\",  5,   \"05\" },\n        {\"twodigits\", 23,  \"23\" },\n        {\"max\",       838, \"838\"}\n    };\n\n    constexpr component_value<int> mins_secs_values[] = {\n        {\"zero\",      0,  \"00\"},\n        {\"onedigit\",  5,  \"05\"},\n        {\"twodigits\", 59, \"59\"}\n    };\n\n    constexpr component_value<int> micros_values[] = {\n        {\"zero\",      0,      \"000000\"},\n        {\"onedigit\",  5,      \"000005\"},\n        {\"twodigits\", 50,     \"000050\"},\n        {\"max\",       999999, \"999999\"},\n    };\n\n    // clang-format off\n    for (const auto& sign : sign_values)\n    {\n    for (const auto& hours : hours_values)\n    {\n    for (const auto& mins : mins_secs_values)\n    {\n    for (const auto& secs : mins_secs_values)\n    {\n    for (const auto& micros : micros_values)\n    {\n        BOOST_TEST_CONTEXT(\n            \"sign=\" << sign.name << \", hours=\" << hours.name <<  \", mins=\" << mins.name <<\n            \", secs=\" << secs.name << \"micros=\" << micros.name\n        )\n        {\n            // Input value\n            auto t = sign.value * test::maket(hours.value, mins.value, secs.value, micros.value);\n            if (sign.value == -1 && t == test::maket(0, 0, 0))\n            {\n                // This case makes no sense, as negative zero is represented as zero\n                continue;\n            }\n\n            // Expected value\n            auto expected = test::stringize(\n                sign.repr, hours.repr, ':', mins.repr, ':', secs.repr, '.', micros.repr\n            );\n\n            // Call the function\n            auto actual = invoke_to_string(t);\n\n            // Check\n            BOOST_TEST(actual == expected);\n\n        }\n    }\n    }\n    }\n    }\n    }\n    // clang-format on\n}\n\nBOOST_AUTO_TEST_CASE(time_padding)\n{\n    // Double-check we correctly pad, regardless of the number\n    // All times below xx:xx:xx.xxxxxx should have 15 characters\n    constexpr std::size_t expected_size = 15;\n\n    // Hour\n    for (std::uint8_t hour = 0u; hour <= 99u; ++hour)\n    {\n        BOOST_TEST_CONTEXT(hour)\n        {\n            auto t = maket(hour, 11, 20);\n            BOOST_TEST(invoke_to_string(t).size() == expected_size);\n        }\n    }\n\n    // Minute\n    for (std::uint8_t minute = 0u; minute <= 59u; ++minute)\n    {\n        BOOST_TEST_CONTEXT(minute)\n        {\n            auto t = maket(12, minute, 20);\n            BOOST_TEST(invoke_to_string(t).size() == expected_size);\n        }\n    }\n\n    // Second\n    for (std::uint8_t second = 0u; second <= 59u; ++second)\n    {\n        BOOST_TEST_CONTEXT(second)\n        {\n            auto t = maket(12, 10, second);\n            BOOST_TEST(invoke_to_string(t).size() == expected_size);\n        }\n    }\n\n    // Microsecond. Iterating over all micros is too costly, so we test some random ones\n    int_generator<std::uint32_t> micro_gen(std::uint32_t(0), std::uint32_t(999999));\n    for (int i = 0; i < 50; ++i)\n    {\n        std::uint32_t micro = micro_gen.generate();\n        BOOST_TEST_CONTEXT(micro)\n        {\n            auto t = maket(12, 10, 34, micro);\n            BOOST_TEST(invoke_to_string(t).size() == expected_size);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/impl/next_power_of_two.cpp",
    "content": "//\n// Copyright (c) 2026 Vladislav Soulgard (vsoulgard at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/next_power_of_two.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n\nusing namespace boost::mysql::detail;\n\nBOOST_AUTO_TEST_SUITE(test_next_power_of_two)\n\nBOOST_AUTO_TEST_CASE(basic)\n{\n    // n = 0 (special case)\n    BOOST_TEST(next_power_of_two<std::size_t>(0u) == 1u);\n    \n    // n is already power of two\n    BOOST_TEST(next_power_of_two<std::size_t>(1u) == 1u);\n    BOOST_TEST(next_power_of_two<std::size_t>(2u) == 2u);\n    BOOST_TEST(next_power_of_two<std::size_t>(4u) == 4u);\n    BOOST_TEST(next_power_of_two<std::size_t>(8u) == 8u);\n    BOOST_TEST(next_power_of_two<std::size_t>(16u) == 16u);\n    BOOST_TEST(next_power_of_two<std::size_t>(32u) == 32u);\n    BOOST_TEST(next_power_of_two<std::size_t>(64u) == 64u);\n    BOOST_TEST(next_power_of_two<std::size_t>(128u) == 128u);\n    \n    // n just below power of two\n    BOOST_TEST(next_power_of_two<std::size_t>(3u) == 4u);\n    BOOST_TEST(next_power_of_two<std::size_t>(7u) == 8u);\n    BOOST_TEST(next_power_of_two<std::size_t>(15u) == 16u);\n    BOOST_TEST(next_power_of_two<std::size_t>(31u) == 32u);\n    BOOST_TEST(next_power_of_two<std::size_t>(63u) == 64u);\n    BOOST_TEST(next_power_of_two<std::size_t>(127u) == 128u);\n    \n    // n just above power of two\n    BOOST_TEST(next_power_of_two<std::size_t>(5u) == 8u);\n    BOOST_TEST(next_power_of_two<std::size_t>(9u) == 16u);\n    BOOST_TEST(next_power_of_two<std::size_t>(17u) == 32u);\n    BOOST_TEST(next_power_of_two<std::size_t>(33u) == 64u);\n    BOOST_TEST(next_power_of_two<std::size_t>(65u) == 128u);\n    BOOST_TEST(next_power_of_two<std::size_t>(129u) == 256u);\n\n    // n is random value\n    BOOST_TEST(next_power_of_two<std::size_t>(6u) == 8u);\n    BOOST_TEST(next_power_of_two<std::size_t>(13u) == 16u);\n    BOOST_TEST(next_power_of_two<std::size_t>(21u) == 32u);\n    BOOST_TEST(next_power_of_two<std::size_t>(45u) == 64u);\n    BOOST_TEST(next_power_of_two<std::size_t>(89u) == 128u);\n    BOOST_TEST(next_power_of_two<std::size_t>(200u) == 256u);\n    BOOST_TEST(next_power_of_two<std::size_t>(300u) == 512u);\n    BOOST_TEST(next_power_of_two<std::size_t>(400u) == 512u);\n    BOOST_TEST(next_power_of_two<std::size_t>(505u) == 512u);\n    BOOST_TEST(next_power_of_two<std::size_t>(888u) == 1024u);\n}\n\nBOOST_AUTO_TEST_CASE(different_types)\n{\n    // uint8_t\n    BOOST_TEST(next_power_of_two<std::uint8_t>(0u) == 1u);\n    BOOST_TEST(next_power_of_two<std::uint8_t>(62u) == 64u);\n    BOOST_TEST(next_power_of_two<std::uint8_t>(100u) == 128u);\n    BOOST_TEST(next_power_of_two<std::uint8_t>(128u) == 128u);\n    \n    // uint16_t\n    BOOST_TEST(next_power_of_two<std::uint16_t>(0u) == 1u);\n    BOOST_TEST(next_power_of_two<std::uint16_t>(1000u) == 1024u);\n    BOOST_TEST(next_power_of_two<std::uint16_t>(16383u) == 16384u);\n    BOOST_TEST(next_power_of_two<std::uint16_t>(32768u) == 32768u);\n    \n    // uint32_t\n    BOOST_TEST(next_power_of_two<std::uint32_t>(0u) == 1u);\n    BOOST_TEST(next_power_of_two<std::uint32_t>(100000u) == 131072u);\n    BOOST_TEST(next_power_of_two<std::uint32_t>(1u << 30) == 1u << 30);\n    BOOST_TEST(next_power_of_two<std::uint32_t>((1u << 30) + 1) == 1u << 31);\n    \n    // uint64_t\n    BOOST_TEST(next_power_of_two<std::uint64_t>(0u) == 1u);\n    BOOST_TEST(next_power_of_two<std::uint64_t>(1ull << 40) == 1ull << 40);\n    BOOST_TEST(next_power_of_two<std::uint64_t>((1ull << 40) + 1) == 1ull << 41);\n    BOOST_TEST(next_power_of_two<std::uint64_t>(1ull << 62) == 1ull << 62);\n    BOOST_TEST(next_power_of_two<std::uint64_t>((1ull << 62) + 1) == 1ull << 63);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/impl/ssl_context_with_default.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/ssl_context_with_default.hpp>\n\n#include <boost/asio/ssl/context.hpp>\n#include <boost/test/unit_test.hpp>\n\nusing namespace boost::mysql::detail;\n\nBOOST_AUTO_TEST_SUITE(test_ssl_context_with_default)\n\nBOOST_AUTO_TEST_CASE(no_external_context)\n{\n    // No external SSL context is passed\n    ssl_context_with_default ctx_with_default(nullptr);\n\n    // Nothing created on construction\n    BOOST_TEST(ctx_with_default.get_ptr() == nullptr);\n\n    // Calling get uses the default context singleton\n    auto& ctx = ctx_with_default.get();\n    auto handle = ctx.native_handle();\n    BOOST_TEST(handle != nullptr);\n\n    // Calling get again return the same context\n    auto handle2 = ctx_with_default.get().native_handle();\n    BOOST_TEST(handle == handle2);\n}\n\nBOOST_AUTO_TEST_CASE(external_context)\n{\n    // Create an external SSL context\n    boost::asio::ssl::context ctx(boost::asio::ssl::context::tls_client);\n    auto handle = ctx.native_handle();\n\n    // Pass it to the object\n    ssl_context_with_default ctx_with_default(&ctx);\n    BOOST_TEST(ctx_with_default.get_ptr() == &ctx);\n\n    // Calling get returns the passed context\n    auto handle2 = ctx_with_default.get().native_handle();\n    BOOST_TEST(handle == handle2);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/impl/variant_stream.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_address.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/variant_stream.hpp>\n\n#include <boost/asio/cancellation_type.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/asio/generic/stream_protocol.hpp>\n#include <boost/asio/ip/address.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/local/stream_protocol.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/tools/detail/per_element_manip.hpp>\n#include <boost/test/tools/detail/print_helper.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <ostream>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing asio::cancellation_type_t;\nusing asio::ip::tcp;\nusing boost::test_tools::per_element;\nusing detail::vsconnect_action_type;\n\nstatic const char* act_type_to_string(vsconnect_action_type act)\n{\n    switch (act)\n    {\n    case vsconnect_action_type::resolve: return \"vsconnect_action_type::resolve\";\n    case vsconnect_action_type::connect: return \"vsconnect_action_type::connect\";\n    case vsconnect_action_type::immediate: return \"vsconnect_action_type::immediate\";\n    case vsconnect_action_type::none: return \"vsconnect_action_type::none\";\n    default: return \"<unknown vsconnect_action_type>\";\n    }\n}\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\nstd::ostream& operator<<(std::ostream& os, vsconnect_action_type act)\n{\n    return os << act_type_to_string(act);\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nBOOST_TEST_DONT_PRINT_LOG_VALUE(boost::asio::generic::stream_protocol::endpoint)\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_variant_stream)\n\nstruct fixture : io_context_fixture\n{\n    detail::variant_stream_state st{ctx.get_executor(), nullptr};\n    any_address addr;\n\n    static std::array<tcp::endpoint, 2> tcp_endpoints()\n    {\n        return {\n            {\n             tcp::endpoint(asio::ip::make_address(\"192.168.10.1\"), 1234),\n             tcp::endpoint(asio::ip::make_address(\"fe76::abab:4567:72b4:9876\"), 1234),\n             }\n        };\n    }\n\n    static tcp::resolver::results_type make_resolver_results(boost::span<const tcp::endpoint> endpoints)\n    {\n        return tcp::resolver::results_type::create(endpoints.begin(), endpoints.end(), \"my_host\", \"1234\");\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE(tcp_success, fixture)\n{\n    // Setup\n    addr.emplace_host_and_port(\"my_host\", 1234);\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: we should resolve\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::resolve);\n    BOOST_TEST(*act.data.resolve.hostname == \"my_host\");\n    BOOST_TEST(*act.data.resolve.service == \"1234\");\n\n    // Resolving done: we should connect\n    auto endpoints = tcp_endpoints();\n    auto r = make_resolver_results(endpoints);\n    act = algo.resume(error_code(), &r, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::connect);\n    BOOST_TEST(act.data.connect == endpoints, per_element());\n\n    // Connect done: success\n    st.sock.open(asio::ip::tcp::v4());  // Simulate a connection - otherwise setting sock options fails\n    act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == error_code());\n}\n\nBOOST_FIXTURE_TEST_CASE(tcp_error_resolve, fixture)\n{\n    // Setup\n    addr.emplace_host_and_port(\"my_host\", 1234);\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: we should resolve\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::resolve);\n    BOOST_TEST(*act.data.resolve.hostname == \"my_host\");\n    BOOST_TEST(*act.data.resolve.service == \"1234\");\n\n    // Resolving error: done\n    asio::ip::tcp::resolver::results_type r;\n    act = algo.resume(asio::error::connection_reset, &r, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == asio::error::connection_reset);\n}\n\nBOOST_FIXTURE_TEST_CASE(tcp_error_connect, fixture)\n{\n    // Setup\n    addr.emplace_host_and_port(\"my_host\", 1234);\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: we should resolve\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::resolve);\n    BOOST_TEST(*act.data.resolve.hostname == \"my_host\");\n    BOOST_TEST(*act.data.resolve.service == \"1234\");\n\n    // Resolving done: we should connect\n    auto endpoints = tcp_endpoints();\n    auto r = make_resolver_results(endpoints);\n    act = algo.resume(error_code(), &r, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::connect);\n    BOOST_TEST(act.data.connect == endpoints, per_element());\n\n    // Connect failed: done. No socket option is set\n    act = algo.resume(asio::error::connection_reset, nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == asio::error::connection_reset);\n}\n\n#ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS\nBOOST_FIXTURE_TEST_CASE(unix_success, fixture)\n{\n    // Setup\n    addr.emplace_unix_path(\"/my/path\");\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: we should connect\n    const asio::local::stream_protocol::endpoint endpoints[]{\"/my/path\"};\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::connect);\n    BOOST_TEST(act.data.connect == endpoints, per_element());\n\n    // Connect done: success. No socket option is set\n    act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == error_code());\n}\n\nBOOST_FIXTURE_TEST_CASE(unix_error_connect, fixture)\n{\n    // Setup\n    addr.emplace_unix_path(\"/my/path\");\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: we should connect\n    const asio::local::stream_protocol::endpoint endpoints[]{\"/my/path\"};\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::connect);\n    BOOST_TEST(act.data.connect == endpoints, per_element());\n\n    // Connect failed: done. No socket option is set\n    act = algo.resume(asio::error::network_reset, nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == asio::error::network_reset);\n}\n#else\nBOOST_FIXTURE_TEST_CASE(unix_unsupported, fixture)\n{\n    // Setup\n    addr.emplace_unix_path(\"/my/path\");\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: immediate completion\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::immediate);\n\n    // Resuming again yields the error\n    act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == asio::error::operation_not_supported);\n}\n#endif\n\n// Cancellation: we use the cancellation state and error on cancellation\n// Only relevant in the TCP case, as UNIX connect is a single operation\n// If the cancellation state contains the terminal type, we fail\nBOOST_FIXTURE_TEST_CASE(cancellation_contains_terminal, fixture)\n{\n    struct\n    {\n        const char* name;\n        cancellation_type_t cancellation_state;\n    } test_cases[] = {\n        {\"terminal\", cancellation_type_t::terminal},\n        {\"all\",      cancellation_type_t::all     },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            addr.emplace_host_and_port(\"my_host\", 1234);\n            detail::variant_stream_connect_algo algo{st, addr};\n\n            // Initiate: we should resolve\n            auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n            BOOST_TEST(act.type == vsconnect_action_type::resolve);\n\n            // Resolving finished successfully, but the cancellation state is set\n            auto endpoints = tcp_endpoints();\n            auto r = make_resolver_results(endpoints);\n            act = algo.resume(error_code(), &r, tc.cancellation_state);\n            BOOST_TEST(act.type == vsconnect_action_type::none);\n            BOOST_TEST(act.data.err == asio::error::operation_aborted);\n        }\n    }\n}\n\n// Since we only support terminal cancellation, we ignore other cancellation types\nBOOST_FIXTURE_TEST_CASE(cancellation_no_terminal, fixture)\n{\n    struct\n    {\n        const char* name;\n        cancellation_type_t cancellation_state;\n    } test_cases[] = {\n        {\"partial\",       cancellation_type_t::partial                             },\n        {\"total\",         cancellation_type_t::total                               },\n        {\"partial+total\", cancellation_type_t::partial | cancellation_type_t::total},\n        {\"other\",         static_cast<cancellation_type_t>(0x80)                   },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            addr.emplace_host_and_port(\"my_host\", 1234);\n            detail::variant_stream_connect_algo algo{st, addr};\n\n            // Initiate: we should resolve\n            auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n            BOOST_TEST(act.type == vsconnect_action_type::resolve);\n            BOOST_TEST(*act.data.resolve.hostname == \"my_host\");\n            BOOST_TEST(*act.data.resolve.service == \"1234\");\n\n            // Resolving done: we should connect\n            auto endpoints = tcp_endpoints();\n            auto r = make_resolver_results(endpoints);\n            act = algo.resume(error_code(), &r, tc.cancellation_state);\n            BOOST_TEST(act.type == vsconnect_action_type::connect);\n            BOOST_TEST(act.data.connect == endpoints, per_element());\n\n            // Connect done: success\n            // Simulate a connection - otherwise setting sock options fails\n            st.sock.open(asio::ip::tcp::v4());\n            act = algo.resume(error_code(), nullptr, tc.cancellation_state);\n            BOOST_TEST(act.type == vsconnect_action_type::none);\n            BOOST_TEST(act.data.err == error_code());\n        }\n    }\n}\n\n// If there is an I/O error and the cancellation state is set, the error wins\nBOOST_FIXTURE_TEST_CASE(cancellation_error, fixture)\n{\n    // Setup\n    addr.emplace_host_and_port(\"my_host\", 1234);\n    detail::variant_stream_connect_algo algo{st, addr};\n\n    // Initiate: we should resolve\n    auto act = algo.resume(error_code(), nullptr, cancellation_type_t::none);\n    BOOST_TEST(act.type == vsconnect_action_type::resolve);\n    BOOST_TEST(*act.data.resolve.hostname == \"my_host\");\n    BOOST_TEST(*act.data.resolve.service == \"1234\");\n\n    // Resolving error, and the cancellation state is set\n    asio::ip::tcp::resolver::results_type r;\n    act = algo.resume(asio::error::connection_reset, &r, cancellation_type_t::terminal);\n    BOOST_TEST(act.type == vsconnect_action_type::none);\n    BOOST_TEST(act.data.err == asio::error::connection_reset);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/is_fatal_error.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/is_fatal_error.hpp>\n#include <boost/mysql/mariadb_server_errc.hpp>\n#include <boost/mysql/mysql_server_errc.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/asio/ssl/error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <system_error>\n\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_CASE(test_is_fatal_error)\n{\n    // Helpers\n    auto make_mysql_code = [](int value) { return error_code(value, get_mysql_server_category()); };\n    auto make_mariadb_code = [](int value) { return error_code(value, get_mysql_server_category()); };\n    auto make_openssl_code = [](int value) { return error_code(value, asio::error::get_ssl_category()); };\n\n    struct\n    {\n        string_view name;\n        error_code input;\n        bool expected;\n    } test_cases[] = {\n        // No error\n        {\"success\",                         error_code(),                                                   false},\n\n        // Network errors\n        {\"net_eof\",                         asio::error::connection_aborted,                                true },\n        {\"net_cancelled\",                   asio::error::operation_aborted,                                 true },\n        {\"net_reset\",                       asio::error::network_reset,                                     true },\n\n        // SSL, generated by asio\n        {\"ssl_stream\",                      asio::ssl::error::stream_errors::stream_truncated,              true },\n\n        // SSL, generated by openssl (any numeric value may be produced)\n        {\"ssl_openssl\",                     make_openssl_code(1623),                                        true },\n\n        // Other system errors\n        {\"system\",                          make_error_code(std::errc::broken_pipe),                        true },\n\n        // Client errors affecting frame parsing\n        {\"incomplete_message\",              client_errc::incomplete_message,                                true },\n        {\"protocol_value_error\",            client_errc::protocol_value_error,                              true },\n        {\"extra_bytes\",                     client_errc::extra_bytes,                                       true },\n        {\"sequence_number_mismatch\",        client_errc::sequence_number_mismatch,                          true },\n        {\"max_buffer_size_exceeded\",        client_errc::max_buffer_size_exceeded,                          true },\n\n        // Client errors affecting the static interface\n        {\"metadata_check_failed\",           client_errc::metadata_check_failed,                             true },\n        {\"num_resultsets_mismatch\",         client_errc::num_resultsets_mismatch,                           true },\n        {\"row_type_mismatch\",               client_errc::row_type_mismatch,                                 true },\n        {\"static_row_parsing_error\",        client_errc::static_row_parsing_error,                          true },\n\n        // Client errors affecting handshake\n        {\"server_unsupported\",              client_errc::server_unsupported,                                true },\n        {\"unknown_auth_plugin\",             client_errc::unknown_auth_plugin,                               true },\n        {\"auth_plugin_requires_ssl\",        client_errc::auth_plugin_requires_ssl,                          true },\n        {\"server_doesnt_support_ssl\",       client_errc::server_doesnt_support_ssl,                         true },\n        {\"bad_handshake_packet_type\",       client_errc::bad_handshake_packet_type,                         true },\n\n        // Other client errors\n        {\"wrong_num_params\",                client_errc::wrong_num_params,                                  false},\n        {\"pool_not_running\",                client_errc::pool_not_running,                                  false},\n        {\"invalid_encoding\",                client_errc::invalid_encoding,                                  false},\n        {\"unformattable_value\",             client_errc::unformattable_value,                               false},\n        {\"format_string_invalid_syntax\",    client_errc::format_string_invalid_syntax,                      false},\n        {\"format_string_invalid_encoding\",  client_errc::format_string_invalid_encoding,                    false},\n        {\"format_string_manual_auto_mix\",   client_errc::format_string_manual_auto_mix,                     false},\n        {\"format_string_invalid_specifier\", client_errc::format_string_invalid_specifier,                   false},\n        {\"format_arg_not_found\",            client_errc::format_arg_not_found,                              false},\n        {\"unknown_character_set\",           client_errc::unknown_character_set,                             false},\n        {\"operation_in_progress\",           client_errc::operation_in_progress,                             false},\n\n        // Fatal server errors\n        {\"ER_UNKNOWN_COM_ERROR\",            common_server_errc::er_unknown_com_error,                       true },\n        {\"ER_ABORTING_CONNECTION\",          common_server_errc::er_aborting_connection,                     true },\n        {\"ER_NET_PACKET_TOO_LARGE\",         common_server_errc::er_net_packet_too_large,                    true },\n        {\"ER_NET_PACKET_TOO_LARGE\",         common_server_errc::er_net_packet_too_large,                    true },\n        {\"ER_NET_READ_ERROR_FROM_PIPE\",     common_server_errc::er_net_read_error_from_pipe,                true },\n        {\"ER_NET_FCNTL_ERROR\",              common_server_errc::er_net_fcntl_error,                         true },\n        {\"ER_NET_PACKETS_OUT_OF_ORDER\",     common_server_errc::er_net_packets_out_of_order,                true },\n        {\"ER_NET_UNCOMPRESS_ERROR\",         common_server_errc::er_net_uncompress_error,                    true },\n        {\"ER_NET_READ_ERROR\",               common_server_errc::er_net_read_error,                          true },\n        {\"ER_NET_READ_INTERRUPTED\",         common_server_errc::er_net_read_interrupted,                    true },\n        {\"ER_NET_ERROR_ON_WRITE\",           common_server_errc::er_net_error_on_write,                      true },\n        {\"ER_NET_WRITE_INTERRUPTED\",        common_server_errc::er_net_write_interrupted,                   true },\n        {\"ER_MALFORMED_PACKET\",             common_server_errc::er_malformed_packet,                        true },\n        {\"ER_ZLIB_Z_MEM_ERROR\",             common_server_errc::er_zlib_z_mem_error,                        true },\n        {\"ER_ZLIB_Z_BUF_ERROR\",             common_server_errc::er_zlib_z_buf_error,                        true },\n        {\"ER_ZLIB_Z_DATA_ERROR\",            common_server_errc::er_zlib_z_data_error,                       true },\n\n        // Non-fatal server errors\n        {\"ER_NO_SUCH_TABLE\",                common_server_errc::er_no_such_table,                           false},\n        {\"ER_BAD_DB_ERROR\",                 common_server_errc::er_bad_db_error,                            false},\n\n        // Server-specific or user-defined errors\n        {\"mysql_specific\",                  make_mysql_code(mysql_server_errc::er_invalid_cast),            false},\n        {\"mariadb_specific\",                make_mariadb_code(mariadb_server_errc::er_gis_different_srids), false},\n        {\"mysql_user_defined\",              make_mysql_code(9812),                                          false},\n        {\"mariadb_user_defined\",            make_mariadb_code(9812),                                        false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {  // Call fn and check\n            BOOST_TEST(is_fatal_error(tc.input) == tc.expected);\n        }\n    }\n}\n"
  },
  {
    "path": "test/unit/test/mariadb_server_errc.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/mariadb_server_errc.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <limits>\n\nusing namespace boost::mysql;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_mariadb_server_errc)\n\nstd::string error_to_string(int val)\n{\n    error_code ec{val, get_mariadb_server_category()};\n    return ec.message();\n}\n\nBOOST_AUTO_TEST_CASE(error_to_string_regular)\n{\n    struct\n    {\n        const char* name;\n        int code;\n        const char* expected_msg;\n    } test_cases[] = {\n        {\"int_min\",           (std::numeric_limits<int>::min)(), \"<unknown MariaDB-specific server error>\"    },\n        {\"zero\",              0,                                 \"<unknown MariaDB-specific server error>\"    },\n        {\"common_min\",        1000,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"common_repurposed\", 1076,                              \"er_binlog_cant_delete_gtid_domain\"          }, // != in MySQL\n        {\"common_max\",        1879,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"specific1_min\",     1901,                              \"er_generated_column_function_is_not_allowed\"},\n        {\"specific1_max\",     1982,                              \"warn_innodb_partition_option_ignored\"       },\n        {\"specific1_gtmax\",   1983,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"specific2_ltmin\",   2999,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"specific2_min\",     3000,                              \"er_file_corrupt\"                            },\n        {\"specific2_regular\", 3015,                              \"er_engine_out_of_memory\"                    },\n        {\"specific2_max\",     3060,                              \"er_alter_operation_not_supported_reason_gis\"},\n        {\"specific2_gtmax\",   3061,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"specific3_ltmin\",   3999,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"specific3_min\",     4002,                              \"er_with_col_wrong_list\"                     },\n        {\"specific3_regular\", 4025,                              \"er_constraint_failed\"                       },\n        {\"gt_max\",            5000,                              \"<unknown MariaDB-specific server error>\"    },\n        {\"int_max\",           (std::numeric_limits<int>::max)(), \"<unknown MariaDB-specific server error>\"    },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { BOOST_TEST(error_to_string(tc.code) == tc.expected_msg); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_to_string_coverage)\n{\n    // Check that no value causes problems.\n    // Ensure that all branches of the switch/case are covered\n    // Valid error ranges are 1000-2000 and 3000-5000\n    for (int i = 1000; i < 2000; ++i)\n    {\n        BOOST_CHECK_NO_THROW(error_to_string(i));\n    }\n    for (int i = 3000; i < 5000; ++i)\n    {\n        BOOST_CHECK_NO_THROW(error_to_string(i));\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/metadata.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/coldef_view.hpp>\n#include <boost/mysql/detail/flags.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <cstring>\n#include <memory>\n\n#include \"test_unit/create_meta.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace collations = boost::mysql::mysql_collations;\nnamespace column_flags = boost::mysql::detail::column_flags;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_metadata)\n\n// Creates a metadata object in dynamic memory, to help sanitizers detect memory errors\nstd::unique_ptr<metadata> create_dynamic_meta(const detail::coldef_view& coldef, bool copy_strings)\n{\n    return std::unique_ptr<metadata>(new metadata(detail::access::construct<metadata>(coldef, copy_strings)));\n}\n\n// Default constructing metadata objects should be well defined\nBOOST_AUTO_TEST_CASE(default_constructor)\n{\n    // Setup\n    metadata meta;\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.table() == \"\");\n    BOOST_TEST(meta.original_table() == \"\");\n    BOOST_TEST(meta.column_name() == \"\");\n    BOOST_TEST(meta.original_column_name() == \"\");\n    BOOST_TEST(meta.column_collation() == 0u);\n    BOOST_TEST(meta.column_length() == 0u);\n    BOOST_TEST(meta.type() == column_type::tinyint);\n    BOOST_TEST(meta.decimals() == 0u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Init ctor, copy_strings=false, there are strings to be copied in the packet\nBOOST_AUTO_TEST_CASE(init_nocopy)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"db\")\n                    .table(\"tab\")\n                    .org_table(\"org_tab\")\n                    .name(\"field\")\n                    .org_name(\"org_field\")\n                    .collation_id(42)\n                    .type(column_type::bigint)\n                    .column_length(100)\n                    .decimals(200)\n                    .flags(column_flags::pri_key)\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Strings were not copied. The rest of the fields were copied\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.table() == \"\");\n    BOOST_TEST(meta.original_table() == \"\");\n    BOOST_TEST(meta.column_name() == \"\");\n    BOOST_TEST(meta.original_column_name() == \"\");\n    BOOST_TEST(meta.column_collation() == 42u);\n    BOOST_TEST(meta.column_length() == 100u);\n    BOOST_TEST(meta.type() == column_type::bigint);\n    BOOST_TEST(meta.decimals() == 200u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Init ctor, copy_strings=false, strings in the packet are empty\nBOOST_AUTO_TEST_CASE(init_nocopy_empty_strings)\n{\n    // Setup\n    auto pack = meta_builder().database(\"\").table(\"\").org_table(\"\").name(\"\").org_name(\"\").build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Strings are also empty, no UB happens\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.table() == \"\");\n    BOOST_TEST(meta.original_table() == \"\");\n    BOOST_TEST(meta.column_name() == \"\");\n    BOOST_TEST(meta.original_column_name() == \"\");\n}\n\n// String in dynamic storage, to help sanitizers catch memory bugs\nstruct dynamic_string\n{\n    std::unique_ptr<char[]> storage;\n    std::size_t size;\n\n    explicit dynamic_string(string_view from) : storage(new char[from.size()]), size(from.size())\n    {\n        std::memcpy(storage.get(), from.data(), from.size());\n    }\n\n    string_view get() const { return string_view(storage.get(), size); }\n};\n\n// Init ctor, copy_strings=true, ensure that lifetime guarantees are met\nBOOST_AUTO_TEST_CASE(init_copy_lifetimes)\n{\n    // Construct some strings in dynamic storage, to help catch memory bugs\n    dynamic_string db(\"db\"), table(\"tab\"), org_table(\"original_tab\"), name(\"nam\"), org_name(\"original_nam\");\n\n    // Build\n    auto pack = meta_builder()\n                    .database(db.get())\n                    .table(table.get())\n                    .org_table(org_table.get())\n                    .name(name.get())\n                    .org_name(org_name.get())\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Destroy the original strings\n    db.storage.reset();\n    table.storage.reset();\n    org_table.storage.reset();\n    name.storage.reset();\n    org_name.storage.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"tab\");\n    BOOST_TEST(meta.original_table() == \"original_tab\");\n    BOOST_TEST(meta.column_name() == \"nam\");\n    BOOST_TEST(meta.original_column_name() == \"original_nam\");\n}\n\n// Init ctor, copy_strings=true, db is empty\nBOOST_AUTO_TEST_CASE(init_copy_db_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"\")\n                    .table(\"Some table value\")\n                    .org_table(\"Some other original table value\")\n                    .name(\"The name of the column\")\n                    .org_name(\"The name of the original column\")\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"The name of the column\");\n    BOOST_TEST(meta.original_column_name() == \"The name of the original column\");\n}\n\n// Same for table\nBOOST_AUTO_TEST_CASE(init_copy_table_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"Database value\")\n                    .table(string_view())\n                    .org_table(\"Some other original table value\")\n                    .name(\"The name of the column\")\n                    .org_name(\"The name of the original column\")\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"Database value\");\n    BOOST_TEST(meta.table() == \"\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"The name of the column\");\n    BOOST_TEST(meta.original_column_name() == \"The name of the original column\");\n}\n\n// Same for original table\nBOOST_AUTO_TEST_CASE(init_copy_org_table_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"A database\")\n                    .table(\"Some table value\")\n                    .org_table(string_view())\n                    .name(\"The name of the column\")\n                    .org_name(\"The name of the original column\")\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"A database\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"\");\n    BOOST_TEST(meta.column_name() == \"The name of the column\");\n    BOOST_TEST(meta.original_column_name() == \"The name of the original column\");\n}\n\n// Same for name\nBOOST_AUTO_TEST_CASE(init_copy_name_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"A database\")\n                    .table(\"Some table value\")\n                    .org_table(\"Some other original table value\")\n                    .name(string_view())\n                    .org_name(\"The name of the original column\")\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"A database\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"\");\n    BOOST_TEST(meta.original_column_name() == \"The name of the original column\");\n}\n\n// Same for org_name\nBOOST_AUTO_TEST_CASE(init_copy_org_name_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"A database\")\n                    .table(\"Some table value\")\n                    .org_table(\"Some other original table value\")\n                    .name(\"The name of the column\")\n                    .org_name(string_view())\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"A database\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"The name of the column\");\n    BOOST_TEST(meta.original_column_name() == \"\");\n}\n\n// Same, but many strings are empty\nBOOST_AUTO_TEST_CASE(init_copy_many_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"A database\")\n                    .table(string_view())\n                    .org_table(string_view())\n                    .name(\"The name of the column\")\n                    .org_name(string_view())\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"A database\");\n    BOOST_TEST(meta.table() == \"\");\n    BOOST_TEST(meta.original_table() == \"\");\n    BOOST_TEST(meta.column_name() == \"The name of the column\");\n    BOOST_TEST(meta.original_column_name() == \"\");\n}\n\n// Same, but all strings are empty\nBOOST_AUTO_TEST_CASE(init_copy_all_empty)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(string_view())\n                    .table(string_view())\n                    .org_table(string_view())\n                    .name(string_view())\n                    .org_name(string_view())\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.table() == \"\");\n    BOOST_TEST(meta.original_table() == \"\");\n    BOOST_TEST(meta.column_name() == \"\");\n    BOOST_TEST(meta.original_column_name() == \"\");\n}\n\n// copy=true does not affect how non string fields are processed\nBOOST_AUTO_TEST_CASE(init_copy_nonstrings)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .collation_id(42)\n                    .column_length(200)\n                    .type(column_type::bigint)\n                    .decimals(100)\n                    .flags(column_flags::pri_key)\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Check\n    BOOST_TEST(meta.column_collation() == 42u);\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::bigint);\n    BOOST_TEST(meta.decimals() == 100u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Copy ctor handles strings correctly\nBOOST_AUTO_TEST_CASE(copy_constructor)\n{\n    // Setup. Use both long and short strings to catch any SBO problems\n    auto pack = meta_builder()\n                    .database(\"db\")\n                    .table(\"Some table value\")\n                    .org_table(\"Some other original table value\")\n                    .name(\"name\")\n                    .org_name(\"The original name of the database column\")\n                    .column_length(200)\n                    .type(column_type::blob)\n                    .decimals(12)\n                    .collation_id(1234)\n                    .flags(column_flags::pri_key)\n                    .build_coldef();\n    auto meta_orig = detail::access::construct<metadata>(pack, true);\n\n    // Copy construct\n    metadata meta(meta_orig);\n\n    // Invalidate the original object\n    meta_orig = detail::access::construct<metadata>(detail::coldef_view{}, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"name\");\n    BOOST_TEST(meta.original_column_name() == \"The original name of the database column\");\n    BOOST_TEST(meta.column_collation() == 1234u);\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::blob);\n    BOOST_TEST(meta.decimals() == 12u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Double-check that no SBO problems happen\nBOOST_AUTO_TEST_CASE(copy_constructor_sbo)\n{\n    // Setup. Create the original object in dynamic memory to help sanitizers\n    auto pack = meta_builder()\n                    .database(\"db\")\n                    .table(\"tab\")\n                    .org_table(\"ot\")\n                    .name(\"nam\")\n                    .org_name(\"on\")\n                    .build_coldef();\n    auto meta_orig = create_dynamic_meta(pack, true);\n\n    // Copy construct\n    metadata meta(*meta_orig);\n\n    // Destroy the original object\n    meta_orig.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"tab\");\n    BOOST_TEST(meta.original_table() == \"ot\");\n    BOOST_TEST(meta.column_name() == \"nam\");\n    BOOST_TEST(meta.original_column_name() == \"on\");\n}\n\n// Copy constructor works without strings, too\nBOOST_AUTO_TEST_CASE(copy_constructor_no_strings)\n{\n    // Setup. Use both long and short strings to catch any SBO problems\n    auto pack = meta_builder().column_length(200).type(column_type::blob).build_coldef();\n    auto meta_orig = detail::access::construct<metadata>(pack, false);\n\n    // Copy construct\n    metadata meta(meta_orig);\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::blob);\n}\n\n// Move ctor handles strings correctly\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Setup. Use both long and short strings to catch any SBO problems\n    auto pack = meta_builder()\n                    .database(\"db\")\n                    .table(\"Some table value\")\n                    .org_table(\"Some other original table value\")\n                    .name(\"name\")\n                    .org_name(\"The original name of the database column\")\n                    .column_length(200)\n                    .type(column_type::blob)\n                    .decimals(12)\n                    .collation_id(1234)\n                    .flags(column_flags::pri_key)\n                    .build_coldef();\n    auto meta_orig = detail::access::construct<metadata>(pack, true);\n\n    // Move construct\n    metadata meta(std::move(meta_orig));\n\n    // Invalidate the original object\n    meta_orig = detail::access::construct<metadata>(detail::coldef_view{}, true);\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"name\");\n    BOOST_TEST(meta.original_column_name() == \"The original name of the database column\");\n    BOOST_TEST(meta.column_collation() == 1234u);\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::blob);\n    BOOST_TEST(meta.decimals() == 12u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Double-check that no SBO problems happen\nBOOST_AUTO_TEST_CASE(move_constructor_sbo)\n{\n    // Setup. Create the original object in dynamic memory to help sanitizers\n    auto pack = meta_builder()\n                    .database(\"db\")\n                    .table(\"tab\")\n                    .org_table(\"ot\")\n                    .name(\"nam\")\n                    .org_name(\"on\")\n                    .build_coldef();\n    auto meta_orig = create_dynamic_meta(pack, true);\n\n    // Move construct\n    metadata meta(std::move(*meta_orig));\n\n    // Destroy the original object\n    meta_orig.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"tab\");\n    BOOST_TEST(meta.original_table() == \"ot\");\n    BOOST_TEST(meta.column_name() == \"nam\");\n    BOOST_TEST(meta.original_column_name() == \"on\");\n}\n\n// Move constructor works without strings, too\nBOOST_AUTO_TEST_CASE(move_constructor_no_strings)\n{\n    // Setup\n    auto pack = meta_builder().column_length(200).type(column_type::blob).build_coldef();\n    auto meta_orig = detail::access::construct<metadata>(pack, false);\n\n    // Copy construct\n    metadata meta(std::move(meta_orig));\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::blob);\n}\n\n// Copy assignment handles strings correctly\nBOOST_AUTO_TEST_CASE(copy_assign)\n{\n    // Setup. Use both long and short strings to catch any SBO problems\n    auto pack_orig = meta_builder()\n                         .database(\"db\")\n                         .table(\"Some table value\")\n                         .org_table(\"Some other original table value\")\n                         .name(\"name\")\n                         .org_name(\"The original name of the database column\")\n                         .column_length(200)\n                         .type(column_type::blob)\n                         .decimals(12)\n                         .collation_id(1234)\n                         .flags(column_flags::pri_key)\n                         .build_coldef();\n    auto meta_orig = create_dynamic_meta(pack_orig, true);\n    auto pack = meta_builder()\n                    .database(\"other_db\")\n                    .table(\"another tbl\")\n                    .org_table(\"original tbl\")\n                    .name(string_view())\n                    .org_name(\"Some test\")\n                    .column_length(10)\n                    .type(column_type::varbinary)\n                    .decimals(10)\n                    .collation_id(42)\n                    .flags(column_flags::not_null)\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Copy assign\n    meta = *meta_orig;\n\n    // Destroy the original object\n    meta_orig.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"name\");\n    BOOST_TEST(meta.original_column_name() == \"The original name of the database column\");\n    BOOST_TEST(meta.column_collation() == 1234u);\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::blob);\n    BOOST_TEST(meta.decimals() == 12u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Copy assignment works without strings, too\nBOOST_AUTO_TEST_CASE(copy_assign_no_strings)\n{\n    // Setup\n    auto pack_orig = meta_builder().type(column_type::blob).decimals(12).build_coldef();\n    auto meta_orig = create_dynamic_meta(pack_orig, false);\n    auto pack = meta_builder().type(column_type::varbinary).decimals(10).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Copy assign\n    meta = *meta_orig;\n\n    // Destroy the original object\n    meta_orig.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.type() == column_type::blob);\n    BOOST_TEST(meta.decimals() == 12u);\n}\n\n// Self copy-assign works\nBOOST_AUTO_TEST_CASE(copy_assign_self)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .database(\"Some value\")\n                    .name(\"Some name\")\n                    .type(column_type::binary)\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Assign\n    const auto& meta_ref = meta;  // avoid warnings\n    meta = meta_ref;\n\n    // Check\n    BOOST_TEST(meta.database() == \"Some value\");\n    BOOST_TEST(meta.column_name() == \"Some name\");\n    BOOST_TEST(meta.type() == column_type::binary);\n}\n\n// Move assignment handles strings correctly\nBOOST_AUTO_TEST_CASE(move_assign)\n{\n    // Setup. Use both long and short strings to catch any SBO problems\n    auto pack_orig = meta_builder()\n                         .database(\"db\")\n                         .table(\"Some table value\")\n                         .org_table(\"Some other original table value\")\n                         .name(\"name\")\n                         .org_name(\"The original name of the database column\")\n                         .column_length(200)\n                         .type(column_type::blob)\n                         .decimals(12)\n                         .collation_id(1234)\n                         .flags(column_flags::pri_key)\n                         .build_coldef();\n    auto meta_orig = create_dynamic_meta(pack_orig, true);\n    auto pack = meta_builder()\n                    .database(\"other_db\")\n                    .table(\"another tbl\")\n                    .org_table(\"original tbl\")\n                    .name(string_view())\n                    .org_name(\"Some test\")\n                    .column_length(10)\n                    .type(column_type::varbinary)\n                    .decimals(10)\n                    .collation_id(42)\n                    .flags(column_flags::not_null)\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, true);\n\n    // Move assign\n    meta = std::move(*meta_orig);\n\n    // Destroy the original object\n    meta_orig.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"db\");\n    BOOST_TEST(meta.table() == \"Some table value\");\n    BOOST_TEST(meta.original_table() == \"Some other original table value\");\n    BOOST_TEST(meta.column_name() == \"name\");\n    BOOST_TEST(meta.original_column_name() == \"The original name of the database column\");\n    BOOST_TEST(meta.column_collation() == 1234u);\n    BOOST_TEST(meta.column_length() == 200u);\n    BOOST_TEST(meta.type() == column_type::blob);\n    BOOST_TEST(meta.decimals() == 12u);\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Move assignment works without strings, too\nBOOST_AUTO_TEST_CASE(move_assign_no_strings)\n{\n    // Setup. Use both long and short strings to catch any SBO problems\n    auto pack_orig = meta_builder().type(column_type::blob).decimals(12).build_coldef();\n    auto meta_orig = create_dynamic_meta(pack_orig, false);\n    auto pack = meta_builder().type(column_type::varbinary).decimals(10).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Move assign\n    meta = std::move(*meta_orig);\n\n    // Destroy the original object\n    meta_orig.reset();\n\n    // Check\n    BOOST_TEST(meta.database() == \"\");\n    BOOST_TEST(meta.type() == column_type::blob);\n    BOOST_TEST(meta.decimals() == 12u);\n}\n\n// Flags\nBOOST_AUTO_TEST_CASE(flags_not_null)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::not_null).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_pri_key)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::pri_key).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_unique_key)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::unique_key).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_multiple_key)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::multiple_key).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_unsigned)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::unsigned_).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_zerofill)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::zerofill).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_auto_increment)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::auto_increment).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_no_default_value)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::no_default_value).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\nBOOST_AUTO_TEST_CASE(flags_on_update_now)\n{\n    // Setup\n    auto pack = meta_builder().flags(column_flags::on_update_now).build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(!meta.is_not_null());\n    BOOST_TEST(!meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(!meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(meta.is_set_to_now_on_update());\n}\n\n// Several flags are set\nBOOST_AUTO_TEST_CASE(flags_several)\n{\n    // Setup\n    auto pack = meta_builder()\n                    .flags(column_flags::pri_key | column_flags::auto_increment | column_flags::not_null)\n                    .build_coldef();\n    auto meta = detail::access::construct<metadata>(pack, false);\n\n    // Check\n    BOOST_TEST(meta.is_not_null());\n    BOOST_TEST(meta.is_primary_key());\n    BOOST_TEST(!meta.is_unique_key());\n    BOOST_TEST(!meta.is_multiple_key());\n    BOOST_TEST(!meta.is_unsigned());\n    BOOST_TEST(!meta.is_zerofill());\n    BOOST_TEST(meta.is_auto_increment());\n    BOOST_TEST(!meta.has_no_default_value());\n    BOOST_TEST(!meta.is_set_to_now_on_update());\n}\n\n// Some flags are not exposed\nBOOST_AUTO_TEST_CASE(flags_ignored)\n{\n    struct\n    {\n        string_view name;\n        std::uint16_t flags;\n    } test_cases[] = {\n        {\"binary\",    column_flags::binary                                          },\n        {\"enum\",      column_flags::enum_                                           },\n        {\"timestamp\", column_flags::timestamp                                       },\n        {\"set\",       column_flags::set                                             },\n        {\"part_key\",  column_flags::part_key                                        },\n        {\"num\",       column_flags::num                                             },\n        {\"mixed\",     column_flags::binary | column_flags::enum_ | column_flags::set},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            auto pack = meta_builder().flags(tc.flags).build_coldef();\n            auto meta = detail::access::construct<metadata>(pack, false);\n\n            // Check\n            BOOST_TEST(!meta.is_not_null());\n            BOOST_TEST(!meta.is_primary_key());\n            BOOST_TEST(!meta.is_unique_key());\n            BOOST_TEST(!meta.is_multiple_key());\n            BOOST_TEST(!meta.is_unsigned());\n            BOOST_TEST(!meta.is_zerofill());\n            BOOST_TEST(!meta.is_auto_increment());\n            BOOST_TEST(!meta.has_no_default_value());\n            BOOST_TEST(!meta.is_set_to_now_on_update());\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_metadata\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/mysql_server_errc.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/mysql_server_errc.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <limits>\n\nusing namespace boost::mysql;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_mysql_server_errc)\n\nstd::string error_to_string(int val)\n{\n    error_code ec{val, get_mysql_server_category()};\n    return ec.message();\n}\n\nBOOST_AUTO_TEST_CASE(error_to_string_regular)\n{\n    struct\n    {\n        const char* name;\n        int code;\n        const char* expected_msg;\n    } test_cases[] = {\n        {\"int_min\",           (std::numeric_limits<int>::min)(), \"<unknown MySQL-specific server error>\"  },\n        {\"zero\",              0,                                 \"<unknown MySQL-specific server error>\"  },\n        {\"common_min\",        1000,                              \"<unknown MySQL-specific server error>\"  },\n        {\"common_repurposed\", 1076,                              \"er_ready\"                               }, // != in MariaDB\n        {\"common_max\",        1879,                              \"<unknown MySQL-specific server error>\"  },\n        {\"specific1_min\",     1880,                              \"er_old_temporals_upgraded\"              },\n        {\"specific1_max\",     1888,                              \"er_found_missing_gtids\"                 },\n        {\"specific1_gtmax\",   1889,                              \"<unknown MySQL-specific server error>\"  },\n        {\"specific2_ltmin\",   2999,                              \"<unknown MySQL-specific server error>\"  },\n        {\"specific2_min\",     3000,                              \"er_file_corrupt\"                        },\n        {\"specific2_regular\", 3015,                              \"er_engine_out_of_memory\"                },\n        {\"specific2_max\",     3238,                              \"er_aes_invalid_kdf_option_size\"         },\n        {\"specific2_gtmax\",   3239,                              \"<unknown MySQL-specific server error>\"  },\n        {\"specific3_ltmin\",   3499,                              \"<unknown MySQL-specific server error>\"  },\n        {\"specific3_min\",     3500,                              \"er_unsupport_compressed_temporary_table\"},\n        {\"specific3_regular\", 3532,                              \"er_rename_role\"                         },\n        {\"gt_max\",            5000,                              \"<unknown MySQL-specific server error>\"  },\n        {\"int_max\",           (std::numeric_limits<int>::max)(), \"<unknown MySQL-specific server error>\"  },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { BOOST_TEST(error_to_string(tc.code) == tc.expected_msg); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_to_string_coverage)\n{\n    // Check that no value causes problems.\n    // Ensure that all branches of the switch/case are covered\n    // Valid error ranges are 1000-2000 and 3000-5000\n    for (int i = 1000; i < 2000; ++i)\n    {\n        BOOST_CHECK_NO_THROW(error_to_string(i));\n    }\n    for (int i = 3000; i < 5000; ++i)\n    {\n        BOOST_CHECK_NO_THROW(error_to_string(i));\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/pfr.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pfr.hpp>\n\n#if BOOST_PFR_ENABLED && defined(BOOST_MYSQL_CXX14)\n\n#include <boost/mysql/detail/typing/pos_map.hpp>\n#include <boost/mysql/detail/typing/row_traits.hpp>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_meta.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nusing boost::test_tools::per_element;\nusing detail::get_row_name_table;\nusing detail::get_row_size;\nusing detail::is_pfr_reflectable;\nusing detail::is_static_row;\nusing detail::name_table_t;\n\nBOOST_AUTO_TEST_SUITE(test_row_traits_pfr)\n\nstruct empty\n{\n};\n\nstruct s1\n{\n    std::int32_t i;\n    float f;\n    double double_field;\n};\n\nstruct s2\n{\n    std::uint64_t s;\n};\n\nstruct sbad\n{\n    int i;\n    void* non_readable_field;\n    double d;\n};\n\nunion test_union\n{\n    int i;\n    float f;\n};\n\n// is_pfr_reflectable\nstatic_assert(is_pfr_reflectable<empty>(), \"\");\nstatic_assert(is_pfr_reflectable<s1>(), \"\");\nstatic_assert(is_pfr_reflectable<s2>(), \"\");\nstatic_assert(!is_pfr_reflectable<const s1>(), \"\");\nstatic_assert(!is_pfr_reflectable<s1&>(), \"\");\nstatic_assert(!is_pfr_reflectable<const s1&>(), \"\");\nstatic_assert(!is_pfr_reflectable<s1&&>(), \"\");\nstatic_assert(!is_pfr_reflectable<const s1&&>(), \"\");\nstatic_assert(!is_pfr_reflectable<test_union>(), \"\");\nstatic_assert(!is_pfr_reflectable<s1[10]>(), \"\");\nstatic_assert(!is_pfr_reflectable<int>(), \"\");\nstatic_assert(!is_pfr_reflectable<const char*>(), \"\");\nstatic_assert(!is_pfr_reflectable<s1*>(), \"\");\n\n//\n// pfr_by_name\n//\n#if BOOST_PFR_CORE_NAME_ENABLED\n\nBOOST_AUTO_TEST_SUITE(pfr_by_name_)\n\n// is_row_type\nstatic_assert(is_static_row<pfr_by_name<empty>>, \"\");\nstatic_assert(is_static_row<pfr_by_name<s1>>, \"\");\nstatic_assert(is_static_row<pfr_by_name<s2>>, \"\");\nstatic_assert(is_static_row<pfr_by_name<sbad>>, \"\");\n\n// size\nstatic_assert(get_row_size<pfr_by_name<empty>>() == 0u, \"\");\nstatic_assert(get_row_size<pfr_by_name<s1>>() == 3u, \"\");\nstatic_assert(get_row_size<pfr_by_name<s2>>() == 1u, \"\");\n\n// name table\nBOOST_AUTO_TEST_CASE(get_row_name_table_)\n{\n    const string_view expected_s1[] = {\"i\", \"f\", \"double_field\"};\n    const string_view expected_s2[] = {\"s\"};\n\n    BOOST_TEST(get_row_name_table<pfr_by_name<empty>>() == name_table_t(), per_element());\n    BOOST_TEST(get_row_name_table<pfr_by_name<s1>>() == expected_s1, per_element());\n    BOOST_TEST(get_row_name_table<pfr_by_name<s2>>() == expected_s2, per_element());\n}\n\n// meta check\nBOOST_AUTO_TEST_CASE(meta_check_ok)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::float_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n        meta_builder().type(column_type::smallint).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {2, 0, 1};\n    diagnostics diag;\n    auto err = detail::meta_check<pfr_by_name<s1>>(pos_map, meta, diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_fail)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::tinyint).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {0, 1, 2};\n    diagnostics diag;\n    auto err = detail::meta_check<pfr_by_name<s1>>(pos_map, meta, diag);\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(\n        diag.client_message() ==\n        \"Incompatible types for field 'f': C++ type 'float' is not compatible with DB type 'DOUBLE'\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_empty_struct)\n{\n    diagnostics diag;\n    auto err = detail::meta_check<pfr_by_name<empty>>(\n        boost::span<const std::size_t>(),\n        metadata_collection_view(),\n        diag\n    );\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\n// parsing\nBOOST_AUTO_TEST_CASE(parse_success)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", 42, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    s1 value;\n    auto err = detail::parse<pfr_by_name<s1>>(pos_map, fv, value);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(value.i == 42);\n    BOOST_TEST(value.f == 4.3f);\n    BOOST_TEST(value.double_field == 8.1);\n}\n\nBOOST_AUTO_TEST_CASE(parse_error)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", nullptr, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    s1 value;\n    auto err = detail::parse<pfr_by_name<s1>>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(parse_empty_struct)\n{\n    empty value;\n    auto err = detail::parse<pfr_by_name<empty>>(\n        boost::span<const std::size_t>(),\n        boost::span<const field_view>(),\n        value\n    );\n    BOOST_TEST(err == error_code());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n#endif\n\n//\n// pfr_by_position\n//\nBOOST_AUTO_TEST_SUITE(pfr_by_position_)\n\n// is_row_type\nstatic_assert(is_static_row<pfr_by_position<empty>>, \"\");\nstatic_assert(is_static_row<pfr_by_position<s1>>, \"\");\nstatic_assert(is_static_row<pfr_by_position<s2>>, \"\");\nstatic_assert(is_static_row<pfr_by_position<sbad>>, \"\");\n\n// size\nstatic_assert(get_row_size<pfr_by_position<empty>>() == 0u, \"\");\nstatic_assert(get_row_size<pfr_by_position<s1>>() == 3u, \"\");\nstatic_assert(get_row_size<pfr_by_position<s2>>() == 1u, \"\");\n\n// name table\nstatic_assert(get_row_name_table<pfr_by_position<empty>>().size() == 0u, \"\");\nstatic_assert(get_row_name_table<pfr_by_position<s1>>().size() == 0u, \"\");\nstatic_assert(get_row_name_table<pfr_by_position<s2>>().size() == 0u, \"\");\n\n// meta check\nBOOST_AUTO_TEST_CASE(meta_check_ok)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::float_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n        meta_builder().type(column_type::smallint).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {2, 0, 1};\n    diagnostics diag;\n    auto err = detail::meta_check<pfr_by_position<s1>>(pos_map, meta, diag);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_fail)\n{\n    const metadata meta[] = {\n        meta_builder().type(column_type::tinyint).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n        meta_builder().type(column_type::double_).nullable(false).build(),\n    };\n    const std::size_t pos_map[] = {0, 1, 2};\n    diagnostics diag;\n    auto err = detail::meta_check<pfr_by_position<s1>>(pos_map, meta, diag);\n    BOOST_TEST(err == client_errc::metadata_check_failed);\n    BOOST_TEST(\n        diag.client_message() ==\n        \"Incompatible types for field in position 1: C++ type 'float' is not compatible with DB type 'DOUBLE'\"\n    );\n}\n\nBOOST_AUTO_TEST_CASE(meta_check_empty_struct)\n{\n    diagnostics diag;\n    auto err = detail::meta_check<pfr_by_position<empty>>(\n        boost::span<const std::size_t>(),\n        metadata_collection_view(),\n        diag\n    );\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(diag.client_message() == \"\");\n}\n\n// parsing\nBOOST_AUTO_TEST_CASE(parse_success)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", 42, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    s1 value;\n    auto err = detail::parse<pfr_by_position<s1>>(pos_map, fv, value);\n    BOOST_TEST(err == error_code());\n    BOOST_TEST(value.i == 42);\n    BOOST_TEST(value.f == 4.3f);\n    BOOST_TEST(value.double_field == 8.1);\n}\n\nBOOST_AUTO_TEST_CASE(parse_error)\n{\n    // int, float, double\n    const auto fv = make_fv_arr(8.1, \"abc\", nullptr, 4.3f);\n    const std::size_t pos_map[] = {2, 3, 0};\n    s1 value;\n    auto err = detail::parse<pfr_by_position<s1>>(pos_map, fv, value);\n    BOOST_TEST(err == client_errc::static_row_parsing_error);\n}\n\nBOOST_AUTO_TEST_CASE(parse_empty_struct)\n{\n    empty value;\n    auto err = detail::parse<pfr_by_position<empty>>(\n        boost::span<const std::size_t>(),\n        boost::span<const field_view>(),\n        value\n    );\n    BOOST_TEST(err == error_code());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/unit/test/pipeline.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/core/ignore_unused.hpp>\n#include <boost/core/span.hpp>\n#include <boost/optional/optional.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <stdexcept>\n#include <type_traits>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_query_frame.hpp\"\n#include \"test_unit/create_statement.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::test_tools::per_element;\nusing detail::pipeline_request_stage;\nusing detail::pipeline_stage_kind;\nusing detail::resultset_encoding;\n\nBOOST_AUTO_TEST_SUITE(test_pipeline)\n\n// Validates the exception thrown when adding a statement execution with wrong number of params\nstatic auto stmt_exc_validator = [](const std::invalid_argument& exc) {\n    BOOST_TEST(\n        string_view(exc.what()) == \"Wrong number of actual parameters supplied to a prepared statement\"\n    );\n    return true;\n};\n\nBOOST_AUTO_TEST_SUITE(stage_response_)\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    // Construct\n    stage_response r;\n\n    // Contains an empty error\n    BOOST_TEST(!r.has_results());\n    BOOST_TEST(!r.has_statement());\n    BOOST_TEST(r.error() == error_code());\n    BOOST_TEST(r.diag() == diagnostics());\n    BOOST_TEST(std::move(r).diag() == diagnostics());\n}\n\nBOOST_AUTO_TEST_CASE(underlying_error)\n{\n    // Setup\n    stage_response r;\n    detail::access::get_impl(r).set_error(client_errc::invalid_encoding, create_server_diag(\"my_message\"));\n\n    // Check\n    BOOST_TEST(!r.has_results());\n    BOOST_TEST(!r.has_statement());\n    BOOST_TEST(r.error() == client_errc::invalid_encoding);\n    BOOST_TEST(r.diag() == create_server_diag(\"my_message\"));\n    BOOST_TEST(std::move(r).diag() == create_server_diag(\"my_message\"));\n}\n\nBOOST_AUTO_TEST_CASE(underlying_statement)\n{\n    // Setup\n    stage_response r;\n    detail::access::get_impl(r).set_result(statement_builder().id(3).build());\n\n    // Check\n    BOOST_TEST(!r.has_results());\n    BOOST_TEST(r.has_statement());\n    BOOST_TEST(r.as_statement().id() == 3u);\n    BOOST_TEST(r.get_statement().id() == 3u);\n\n    // error(), diag() can be called and return empty objects\n    BOOST_TEST(r.error() == error_code());\n    BOOST_TEST(r.diag() == diagnostics());\n    BOOST_TEST(std::move(r).diag() == diagnostics());\n}\n\nBOOST_AUTO_TEST_CASE(underlying_results)\n{\n    // Setup\n    stage_response r;\n    detail::access::get_impl(r).emplace_results();\n    add_ok(detail::access::get_impl(r).get_processor(), ok_builder().info(\"some_info\").build());\n\n    // Check\n    BOOST_TEST(r.has_results());\n    BOOST_TEST(!r.has_statement());\n    BOOST_TEST(r.get_results().info() == \"some_info\");\n    BOOST_TEST(r.as_results().info() == \"some_info\");\n\n    // Rvalue reference accessors work\n    results&& ref1 = std::move(r).get_results();\n    results&& ref2 = std::move(r).as_results();\n    boost::ignore_unused(ref1);\n    boost::ignore_unused(ref2);\n\n    // error(), diag() can be called and return empty objects\n    BOOST_TEST(r.error() == error_code());\n    BOOST_TEST(r.diag() == diagnostics());\n    BOOST_TEST(std::move(r).diag() == diagnostics());\n}\n\nBOOST_AUTO_TEST_CASE(as_results_error)\n{\n    // Empty error\n    stage_response r;\n    BOOST_CHECK_THROW(r.as_results(), std::invalid_argument);\n    BOOST_CHECK_THROW(std::move(r).as_results(), std::invalid_argument);\n\n    // Non-empty error\n    detail::access::get_impl(r).set_error(client_errc::extra_bytes, create_client_diag(\"my_msg\"));\n    BOOST_CHECK_THROW(r.as_results(), std::invalid_argument);\n    BOOST_CHECK_THROW(std::move(r).as_results(), std::invalid_argument);\n\n    // Statement\n    detail::access::get_impl(r).set_result(statement_builder().build());\n    BOOST_CHECK_THROW(r.as_results(), std::invalid_argument);\n    BOOST_CHECK_THROW(std::move(r).as_results(), std::invalid_argument);\n}\n\nBOOST_AUTO_TEST_CASE(as_statement_error)\n{\n    // Empty error\n    stage_response r;\n    BOOST_CHECK_THROW(r.as_statement(), std::invalid_argument);\n\n    // Non-empty error\n    detail::access::get_impl(r).set_error(client_errc::extra_bytes, create_client_diag(\"my_msg\"));\n    BOOST_CHECK_THROW(r.as_statement(), std::invalid_argument);\n\n    // results\n    detail::access::get_impl(r).emplace_results();\n    BOOST_CHECK_THROW(r.as_statement(), std::invalid_argument);\n}\n\nBOOST_AUTO_TEST_CASE(change_type)\n{\n    stage_response r;\n\n    // Set results\n    detail::access::get_impl(r).emplace_results();\n    BOOST_TEST(r.has_results());\n\n    // Set an error\n    detail::access::get_impl(r).set_error(client_errc::extra_bytes, create_client_diag(\"abc\"));\n    BOOST_TEST(!r.has_results());\n    BOOST_TEST(r.error() == client_errc::extra_bytes);\n    BOOST_TEST(r.diag() == create_client_diag(\"abc\"));\n\n    // Reset the error\n    detail::access::get_impl(r).emplace_error();\n    BOOST_TEST(r.error() == error_code());\n    BOOST_TEST(r.diag() == diagnostics());\n\n    // Set a statement\n    detail::access::get_impl(r).set_result(statement_builder().build());\n    BOOST_TEST(r.has_statement());\n\n    // Set results again\n    detail::access::get_impl(r).emplace_results();\n    BOOST_TEST(r.has_results());\n    BOOST_TEST(!r.has_statement());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(pipeline_request_)\n\n// Helper to check the contents of a pipeline_request\nvoid check_pipeline(\n    const pipeline_request& req,\n    const std::vector<std::uint8_t>& expected_buffer,\n    boost::span<const detail::pipeline_request_stage> expected_stages\n)\n{\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(detail::access::get_impl(req).buffer_, expected_buffer);\n    BOOST_TEST(detail::access::get_impl(req).stages_ == expected_stages, per_element());\n}\n\n// Helper for pipelines with a single request\nvoid check_pipeline_single(\n    const pipeline_request& req,\n    const std::vector<std::uint8_t>& expected_buffer,\n    detail::pipeline_request_stage expected_stage\n)\n{\n    check_pipeline(req, expected_buffer, {&expected_stage, 1});\n}\n\n// Text query\nBOOST_AUTO_TEST_CASE(add_execute_text_query)\n{\n    pipeline_request req;\n    req.add_execute(\"SELECT 1\");\n    check_pipeline_single(\n        req,\n        create_query_frame(0, \"SELECT 1\"),\n        {pipeline_stage_kind::execute, 1u, resultset_encoding::text}\n    );\n}\n\n// Statement, passing parameters as individual arguments\nBOOST_AUTO_TEST_CASE(add_execute_statement)\n{\n    pipeline_request req;\n    req.add_execute(statement_builder().id(2).num_params(3).build(), 42, \"abc\", nullptr);\n    check_pipeline_single(\n        req,\n        {0x1e, 0x00, 0x00, 0x00, 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,\n         0x00, 0x00, 0x04, 0x01, 0x08, 0x00, 0xfe, 0x00, 0x06, 0x00, 0x2a, 0x00,\n         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63},\n        {pipeline_stage_kind::execute, 1u, resultset_encoding::binary}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(add_execute_statement_writable_fields)\n{\n    // We run the required writable field transformations\n    pipeline_request req;\n    req.add_execute(\n        statement_builder().id(2).num_params(3).build(),\n        boost::optional<int>(42),\n        \"abc\",\n        boost::optional<int>()\n    );\n    check_pipeline_single(\n        req,\n        {0x1e, 0x00, 0x00, 0x00, 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,\n         0x00, 0x00, 0x04, 0x01, 0x08, 0x00, 0xfe, 0x00, 0x06, 0x00, 0x2a, 0x00,\n         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63},\n        {pipeline_stage_kind::execute, 1u, resultset_encoding::binary}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(execute_statement_no_params)\n{\n    pipeline_request req;\n    req.add_execute(statement_builder().id(2).num_params(0).build());\n    check_pipeline_single(\n        req,\n        {0x0a, 0x00, 0x00, 0x00, 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},\n        {pipeline_stage_kind::execute, 1u, resultset_encoding::binary}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(add_execute_statement_too_few_params)\n{\n    pipeline_request req;\n    BOOST_CHECK_EXCEPTION(\n        req.add_execute(statement_builder().num_params(2).build(), 10),\n        std::invalid_argument,\n        stmt_exc_validator\n    );\n    check_pipeline(req, {}, {});  // Request unmodified\n}\n\nBOOST_AUTO_TEST_CASE(add_execute_statement_too_many_params)\n{\n    pipeline_request req;\n    BOOST_CHECK_EXCEPTION(\n        req.add_execute(statement_builder().num_params(2).build(), 10, 20, 30),\n        std::invalid_argument,\n        stmt_exc_validator\n    );\n    check_pipeline(req, {}, {});  // Request unmodified\n}\n\n// Statement, passing parameters as a range\nBOOST_AUTO_TEST_CASE(add_execute_statement_range)\n{\n    pipeline_request req;\n    req.add_execute_range(statement_builder().id(2).num_params(3).build(), make_fv_arr(42, \"abc\", nullptr));\n    check_pipeline_single(\n        req,\n        {0x1e, 0x00, 0x00, 0x00, 0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,\n         0x00, 0x00, 0x04, 0x01, 0x08, 0x00, 0xfe, 0x00, 0x06, 0x00, 0x2a, 0x00,\n         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x61, 0x62, 0x63},\n        {pipeline_stage_kind::execute, 1u, resultset_encoding::binary}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(add_execute_statement_range_too_few_params)\n{\n    pipeline_request req;\n    BOOST_CHECK_EXCEPTION(\n        req.add_execute_range(statement_builder().num_params(2).build(), make_fv_arr(42)),\n        std::invalid_argument,\n        stmt_exc_validator\n    );\n    check_pipeline(req, {}, {});  // Request unmodified\n}\n\nBOOST_AUTO_TEST_CASE(add_execute_statement_range_too_many_params)\n{\n    pipeline_request req;\n    BOOST_CHECK_EXCEPTION(\n        req.add_execute_range(statement_builder().num_params(2).build(), make_fv_arr(42, nullptr, \"abc\")),\n        std::invalid_argument,\n        stmt_exc_validator\n    );\n    check_pipeline(req, {}, {});  // Request unmodified\n}\n\n// prepare statement\nBOOST_AUTO_TEST_CASE(add_prepare_statement)\n{\n    pipeline_request req;\n    req.add_prepare_statement(\"SELECT 1\");\n    check_pipeline_single(\n        req,\n        create_prepare_statement_frame(0, \"SELECT 1\"),\n        {pipeline_stage_kind::prepare_statement, 1u, {}}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(add_prepare_statement_empty)\n{\n    // Empty prepare statements don't produce problems\n    pipeline_request req;\n    req.add_prepare_statement(\"\");\n    check_pipeline_single(\n        req,\n        create_prepare_statement_frame(0, \"\"),\n        {pipeline_stage_kind::prepare_statement, 1u, {}}\n    );\n}\n\n// close statement\nBOOST_AUTO_TEST_CASE(add_close_statement)\n{\n    pipeline_request req;\n    req.add_close_statement(statement_builder().id(3).num_params(1).build());\n    check_pipeline_single(\n        req,\n        create_frame(0, {0x19, 0x03, 0x00, 0x00, 0x00}),\n        {pipeline_stage_kind::close_statement, 1u, {}}\n    );\n}\n\n// reset connection\nBOOST_AUTO_TEST_CASE(add_reset_connection)\n{\n    pipeline_request req;\n    req.add_reset_connection();\n    check_pipeline_single(req, create_frame(0, {0x1f}), {pipeline_stage_kind::reset_connection, 1u, {}});\n}\n\n// set character set\nBOOST_AUTO_TEST_CASE(add_set_character_set)\n{\n    pipeline_request req;\n    req.add_set_character_set(utf8mb4_charset);\n    check_pipeline_single(\n        req,\n        create_query_frame(0, \"SET NAMES 'utf8mb4'\"),\n        {pipeline_stage_kind::set_character_set, 1u, utf8mb4_charset}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(add_set_character_set_escapes)\n{\n    // We don't create SQL injection vulnerabilities while composing SET NAMES\n    character_set charset{\"inj'ection\", utf8mb4_charset.next_char};\n    pipeline_request req;\n    req.add_set_character_set(charset);\n    check_pipeline_single(\n        req,\n        create_query_frame(0, \"SET NAMES 'inj\\\\'ection'\"),\n        {pipeline_stage_kind::set_character_set, 1u, charset}\n    );\n}\n\nBOOST_AUTO_TEST_CASE(add_set_character_set_error)\n{\n    // If a character set name that can't be securely escaped gets passed, we throw\n    pipeline_request req;\n    BOOST_CHECK_EXCEPTION(\n        req.add_set_character_set(character_set{\"bad\\xff\", utf8mb4_charset.next_char}),\n        std::invalid_argument,\n        [](const std::invalid_argument& exc) {\n            BOOST_TEST(string_view(exc.what()) == \"Invalid character set name\");\n            return true;\n        }\n    );\n    check_pipeline(req, {}, {});  // request unmodified\n}\n\n// Several stages\nBOOST_AUTO_TEST_CASE(add_incrementally)\n{\n    // Default ctor creates an empty request\n    pipeline_request req;\n    check_pipeline(req, {}, {});\n\n    // Add a reset connection stage\n    req.add_reset_connection();\n    std::vector<pipeline_request_stage> expected_stages{\n        {pipeline_stage_kind::reset_connection, 1u, {}}\n    };\n    check_pipeline(req, create_frame(0, {0x1f}), expected_stages);\n\n    // Add an execution stage\n    req.add_execute(\"SELECT 1\");\n    expected_stages = {\n        {pipeline_stage_kind::reset_connection, 1u, {}                      },\n        {pipeline_stage_kind::execute,          1u, resultset_encoding::text}\n    };\n    check_pipeline(req, concat(create_frame(0, {0x1f}), create_query_frame(0, \"SELECT 1\")), expected_stages);\n}\n\nBOOST_AUTO_TEST_CASE(all_stage_kinds)\n{\n    // Setup\n    pipeline_request req;\n\n    // Add stages\n    req.add_reset_connection()\n        .add_execute(\"SELECT 1\")\n        .add_prepare_statement(\"SELECT ?\")\n        .add_set_character_set(utf8mb4_charset)\n        .add_close_statement(statement_builder().id(8).build());\n\n    // Check\n    auto expected_buffer = buffer_builder()\n                               .add(create_frame(0, {0x1f}))\n                               .add(create_query_frame(0, \"SELECT 1\"))\n                               .add(create_prepare_statement_frame(0, \"SELECT ?\"))\n                               .add(create_query_frame(0, \"SET NAMES 'utf8mb4'\"))\n                               .add(create_frame(0, {0x19, 0x08, 0x00, 0x00, 0x00}))\n                               .build();\n    const std::array<pipeline_request_stage, 5> expected_stages{\n        {\n         {pipeline_stage_kind::reset_connection, 1u, {}},\n         {pipeline_stage_kind::execute, 1u, resultset_encoding::text},\n         {pipeline_stage_kind::prepare_statement, 1u, {}},\n         {pipeline_stage_kind::set_character_set, 1u, utf8mb4_charset},\n         {pipeline_stage_kind::close_statement, 1u, {}},\n         }\n    };\n    check_pipeline(req, expected_buffer, expected_stages);\n}\n\nBOOST_AUTO_TEST_CASE(clear)\n{\n    // Create a pipeline request with some steps\n    pipeline_request req;\n    req.add_reset_connection().add_set_character_set(utf8mb4_charset).add_execute(\"SELECT 1\");\n\n    // Clear the pipeline\n    req.clear();\n    check_pipeline(req, {}, {});\n\n    // Add some stages again\n    req.add_execute(\"abc\").add_close_statement(statement_builder().id(7).build());\n\n    // Check\n    const std::array<pipeline_request_stage, 2> expected_stages{\n        {\n         {pipeline_stage_kind::execute, 1u, resultset_encoding::text},\n         {pipeline_stage_kind::close_statement, 1u, {}},\n         }\n    };\n    check_pipeline(\n        req,\n        concat(create_query_frame(0, \"abc\"), create_frame(0, {0x19, 0x07, 0x00, 0x00, 0x00})),\n        expected_stages\n    );\n}\n\nBOOST_AUTO_TEST_CASE(clear_empty)\n{\n    // Clearing an empty pipeline is a no-op\n    pipeline_request req;\n    req.clear();\n    check_pipeline(req, {}, {});\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/pool_params.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/pool_params.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/connection_pool/internal_pool_params.hpp>\n\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/strand.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <chrono>\n#include <stdexcept>\n\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_pool_params)\n\nBOOST_AUTO_TEST_CASE(invalid_params)\n{\n    struct\n    {\n        string_view name;\n        void (*params_fn)(pool_params&);\n        string_view expected_msg;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"max_size 0\",\n            [](pool_params& p) { p.max_size = 0; },\n            \"pool_params::max_size must be greater than zero\"\n        },\n        {\n            \"initial_size > max_size\",\n            [](pool_params& p) { p.max_size = 100; p.initial_size = 101; },\n            \"pool_params::max_size must be greater than pool_params::initial_size\"\n        },\n        {\n            \"connect_timeout < 0\",\n            [](pool_params& p) { p.connect_timeout = std::chrono::seconds(-1); },\n            \"pool_params::connect_timeout must not be negative\"\n        },\n        {\n            \"connect_timeout < 0 min\",\n            [](pool_params& p) { p.connect_timeout = (std::chrono::steady_clock::duration::min)(); },\n            \"pool_params::connect_timeout must not be negative\"\n        },\n        {\n            \"retry_interval == 0\",\n            [](pool_params& p) { p.retry_interval = std::chrono::seconds(0); },\n            \"pool_params::retry_interval must be greater than zero\"\n        },\n        {\n            \"retry_interval < 0\",\n            [](pool_params& p) { p.retry_interval = std::chrono::seconds(-1); },\n            \"pool_params::retry_interval must be greater than zero\"\n        },\n        {\n            \"retry_interval < 0 min\",\n            [](pool_params& p) { p.retry_interval = (std::chrono::steady_clock::duration::min)(); },\n            \"pool_params::retry_interval must be greater than zero\"\n        },\n        {\n            \"ping_interval < 0\",\n            [](pool_params& p) { p.ping_interval = std::chrono::seconds(-1); },\n            \"pool_params::ping_interval must not be negative\"\n        },\n        {\n            \"ping_interval < 0 min\",\n            [](pool_params& p) { p.ping_interval = (std::chrono::steady_clock::duration::min)(); },\n            \"pool_params::ping_interval must not be negative\"\n        },\n        {\n            \"ping_timeout < 0\",\n            [](pool_params& p) { p.ping_timeout = std::chrono::seconds(-1); },\n            \"pool_params::ping_timeout must not be negative\"\n        },\n        {\n            \"ping_timeout < 0 min\",\n            [](pool_params& p) { p.ping_timeout = (std::chrono::steady_clock::duration::min)(); },\n            \"pool_params::ping_timeout must not be negative\"\n        },\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            pool_params params;\n            tc.params_fn(params);\n            auto matcher = [&tc](const std::invalid_argument& err) { return err.what() == tc.expected_msg; };\n            BOOST_CHECK_EXCEPTION(detail::check_validity(params), std::invalid_argument, matcher);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(valid_params)\n{\n    struct\n    {\n        string_view name;\n        void (*params_fn)(pool_params&);\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"initial_size == 0\",\n            [](pool_params& p) { p.initial_size = 0; },\n        },\n        {\n            \"initial_size == max_size\",\n            [](pool_params& p) { p.max_size = 100; p.initial_size = 100; },\n        },\n        {\n            \"connect_timeout == 0\",\n            [](pool_params& p) { p.connect_timeout = std::chrono::seconds(0); },\n        },\n        {\n            \"connect_timeout == max\",\n            [](pool_params& p) { p.connect_timeout = (std::chrono::steady_clock::duration::max)(); },\n        },\n        {\n            \"retry_interval == max\",\n            [](pool_params& p) { p.retry_interval = (std::chrono::steady_clock::duration::max)(); },\n        },\n        {\n            \"ping_interval == 0\",\n            [](pool_params& p) { p.ping_interval = std::chrono::seconds(0); },\n        },\n        {\n            \"ping_interval == max\",\n            [](pool_params& p) { p.ping_interval = (std::chrono::steady_clock::duration::max)(); },\n        },\n        {\n            \"ping_timeout == 0\",\n            [](pool_params& p) { p.ping_timeout = std::chrono::seconds(0); },\n        },\n        {\n            \"ping_timeout == max\",\n            [](pool_params& p) { p.ping_timeout = (std::chrono::steady_clock::duration::max)(); },\n        },\n        {\n            \"thread_safe == true\",\n            [](pool_params& p) { p.thread_safe = true; },\n        }\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            pool_params params;\n            tc.params_fn(params);\n            BOOST_CHECK_NO_THROW(detail::check_validity(params));\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/protocol/binary_protocol.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n\n#include \"operators.hpp\"\n#include \"serialization_test.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/create_meta.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing detail::deserialize_errc;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_binary_protocol)\n\n// Adapt field_view to be Serializable\nstruct field_view_adaptor\n{\n    field_view fv;\n\n    void serialize(detail::serialization_context& ctx) { detail::serialize_binary_field(ctx, fv); }\n};\n\nBOOST_AUTO_TEST_CASE(serialize)\n{\n    std::uint8_t blob_buffer[] = {0x70, 0x00, 0x01};\n    struct\n    {\n        const char* name;\n        field_view value;\n        std::vector<std::uint8_t> serialized;\n    } test_cases[]{\n        // Strings and ints: extensive testing already done. Ensure\n        // we call the right function\n        {\"string\", field_view(\"abc\"), {0x03, 0x61, 0x62, 0x63}},\n        {\"blob\", field_view(blob_view(blob_buffer)), {0x03, 0x70, 0x00, 0x01}},\n        {\"uint64\",\n         field_view(std::uint64_t(0xf8f9fafbfcfdfeff)),\n         {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}},\n        {\"int64\",\n         field_view(std::int64_t(-0x0706050403020101)),\n         {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}},\n\n        {\"float_fractional_negative\", field_view(-4.2f), {0x66, 0x66, 0x86, 0xc0}},\n        {\"float_fractional_positive\", field_view(4.2f), {0x66, 0x66, 0x86, 0x40}},\n        {\"float_positive_exp_positive_fractional\", field_view(3.14e20f), {0x01, 0x2d, 0x88, 0x61}},\n        {\"float_zero\", field_view(0.0f), {0x00, 0x00, 0x00, 0x00}},\n\n        {\"double_fractional_negative\", field_view(-4.2), {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0xc0}},\n        {\"double_fractional_positive\", field_view(4.2), {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40}},\n        {\"double_positive_exp_positive_fractional\",\n         field_view(3.14e200),\n         {0xce, 0x46, 0x3c, 0x76, 0x9c, 0x68, 0x90, 0x69}},\n        {\"double_zero\", field_view(0.0), {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n\n        {\"date_regular\", field_view(date(2010u, 3u, 28u)), {0x04, 0xda, 0x07, 0x03, 0x1c}},\n        {\"date_min\", field_view(date(1000u, 1u, 1u)), {0x04, 0xe8, 0x03, 0x01, 0x01}},\n        {\"date_mysqlmax\", field_view(date(9999u, 12u, 31u)), {0x04, 0x0f, 0x27, 0x0c, 0x1f}},\n        {\"date_max\", field_view(date(0xffff, 0xff, 0xff)), {0x04, 0xff, 0xff, 0xff, 0xff}},\n        {\"date_zero\", field_view(date()), {0x04, 0x00, 0x00, 0x00, 0x00}},\n\n        {\"datetime_regular\",\n         field_view(datetime(2010u, 1u, 1u, 23u, 1u, 59u, 967510u)),\n         {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00}},\n        {\"datetime_min\",\n         field_view(datetime(0, 1, 1)),\n         {0x0b, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n        {\"datetime_mysqlmax\",\n         field_view(datetime(9999, 12, 31, 23, 59, 59, 999999)),\n         {0x0b, 0x0f, 0x27, 0x0c, 0x1f, 0x17, 0x3b, 0x3b, 0x3f, 0x42, 0x0f, 0x00}},\n        {\"datetime_max\",\n         field_view(datetime(0xffff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xffffffff)),\n         {0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},\n        {\"datetime_zero\",\n         field_view(datetime()),\n         {0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},\n\n        {\"time_positive_u\",\n         field_view(maket(0, 0, 0, 321000)),\n         {0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00}},\n        {\"time_positive_hmsu\",\n         field_view(maket(838, 59, 58, 999000)),\n         {0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00}},\n        {\"time_negative_u\",\n         field_view(-maket(0, 0, 0, 321000)),\n         {0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00}},\n        {\"time_negative_hmsu\",\n         field_view(-maket(838, 59, 58, 999000)),\n         {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00}},\n\n        // NULL is transmitted as the NULL bitmap, so nothing is expected as output\n        {\"null\", field_view(), {}},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { do_serialize_test(field_view_adaptor{tc.value}, tc.serialized); }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE(deserialize_success)\n\nstruct success_sample\n{\n    std::string name;\n    deserialization_buffer from;\n    field_view expected;\n    metadata meta;\n\n    template <class T>\n    success_sample(std::string name, std::vector<std::uint8_t> from, T&& expected_value, metadata meta)\n        : name(std::move(name)),\n          from(std::move(from)),\n          expected(std::forward<T>(expected_value)),\n          meta(std::move(meta))\n    {\n    }\n};\n\nvoid add_string_samples(std::vector<success_sample>& output)\n{\n    output.push_back(\n        success_sample(\"varchar\", {0x04, 0x74, 0x65, 0x73, 0x74}, \"test\", create_meta(column_type::varchar))\n    );\n    output.push_back(\n        success_sample(\"char\", {0x04, 0x74, 0x65, 0x73, 0x74}, \"test\", create_meta(column_type::char_))\n    );\n    output.push_back(\n        success_sample(\"text\", {0x04, 0x74, 0x65, 0x73, 0x74}, \"test\", create_meta(column_type::text))\n    );\n    output.push_back(\n        success_sample(\"enum\", {0x04, 0x74, 0x65, 0x73, 0x74}, \"test\", create_meta(column_type::enum_))\n    );\n    output.push_back(\n        success_sample(\"set\", {0x04, 0x74, 0x65, 0x73, 0x74}, \"test\", create_meta(column_type::set))\n    );\n    output.push_back(success_sample(\"decimal\", {0x02, 0x31, 0x30}, \"10\", create_meta(column_type::decimal)));\n    output.push_back(success_sample(\"json\", {0x02, 0x7b, 0x7d}, \"{}\", create_meta(column_type::json)));\n}\n\nvoid add_blob_samples(std::vector<success_sample>& output)\n{\n    static constexpr std::uint8_t buff[] = {0x01, 0x00, 0x73, 0x74};\n\n    output.push_back(success_sample(\n        \"varbinary\",\n        {0x04, 0x01, 0x00, 0x73, 0x74},\n        blob_view(buff),\n        create_meta(column_type::varbinary)\n    ));\n    output.push_back(success_sample(\n        \"binary\",\n        {0x04, 0x01, 0x00, 0x73, 0x74},\n        blob_view(buff),\n        create_meta(column_type::binary)\n    ));\n    output.push_back(success_sample(\n        \"blob\",\n        {0x04, 0x01, 0x00, 0x73, 0x74},\n        blob_view(buff),\n        create_meta(column_type::blob)\n    ));\n    output.push_back(success_sample(\n        \"geometry\",\n        {0x04, 0x01, 0x00, 0x73, 0x74},\n        blob_view(buff),\n        create_meta(column_type::geometry)\n    ));\n\n    // Anything we don't know what it is, we interpret as a blob\n    output.push_back(success_sample(\n        \"unknown_protocol_type\",\n        {0x04, 0x01, 0x00, 0x73, 0x74},\n        blob_view(buff),\n        create_meta(column_type::unknown)\n    ));\n}\n\n// Note: these employ regular integer deserialization functions, which have\n// already been tested\nvoid add_int_samples(std::vector<success_sample>& output)\n{\n    output.push_back(success_sample(\n        \"tinyint_unsigned\",\n        {0x14},\n        std::uint64_t(20),\n        meta_builder().type(column_type::tinyint).unsigned_flag(true).build()\n    ));\n    output.push_back(\n        success_sample(\"tinyint_signed\", {0xec}, std::int64_t(-20), create_meta(column_type::tinyint))\n    );\n\n    output.push_back(success_sample(\n        \"smallint_unsigned\",\n        {0x14, 0x00},\n        std::uint64_t(20),\n        meta_builder().type(column_type::smallint).unsigned_flag(true).build()\n    ));\n    output.push_back(\n        success_sample(\"smallint_signed\", {0xec, 0xff}, std::int64_t(-20), create_meta(column_type::smallint))\n    );\n\n    output.push_back(success_sample(\n        \"mediumint_unsigned\",\n        {0x14, 0x00, 0x00, 0x00},\n        std::uint64_t(20),\n        meta_builder().type(column_type::mediumint).unsigned_flag(true).build()\n    ));\n    output.push_back(success_sample(\n        \"mediumint_signed\",\n        {0xec, 0xff, 0xff, 0xff},\n        std::int64_t(-20),\n        create_meta(column_type::mediumint)\n    ));\n\n    output.push_back(success_sample(\n        \"int_unsigned\",\n        {0x14, 0x00, 0x00, 0x00},\n        std::uint64_t(20),\n        meta_builder().type(column_type::int_).unsigned_flag(true).build()\n    ));\n    output.push_back(success_sample(\n        \"int_signed\",\n        {0xec, 0xff, 0xff, 0xff},\n        std::int64_t(-20),\n        create_meta(column_type::int_)\n    ));\n\n    output.push_back(success_sample(\n        \"bigint_unsigned\",\n        {0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n        std::uint64_t(20),\n        meta_builder().type(column_type::bigint).unsigned_flag(true).build()\n    ));\n    output.push_back(success_sample(\n        \"bigint_signed\",\n        {0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n        std::int64_t(-20),\n        create_meta(column_type::bigint)\n    ));\n\n    output.push_back(success_sample(\n        \"year\",\n        {0xe3, 0x07},\n        std::uint64_t(2019),\n        meta_builder().type(column_type::year).unsigned_flag(true).build()\n    ));\n}\n\n// bit\nvoid add_bit_types(std::vector<success_sample>& output)\n{\n    auto meta = meta_builder().type(column_type::bit).unsigned_flag(true).build();\n\n    output.push_back(success_sample(\"bit_8\", {0x01, 0x12}, std::uint64_t(0x12), meta));\n    output.push_back(success_sample(\"bit_16\", {0x02, 0x12, 0x34}, std::uint64_t(0x1234), meta));\n    output.push_back(success_sample(\"bit_24\", {0x03, 0x12, 0x34, 0x56}, std::uint64_t(0x123456), meta));\n    output.push_back(success_sample(\"bit_32\", {0x04, 0x12, 0x34, 0x56, 0x78}, std::uint64_t(0x12345678), meta)\n    );\n    output.push_back(\n        success_sample(\"bit_40\", {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a}, std::uint64_t(0x123456789a), meta)\n    );\n    output.push_back(success_sample(\n        \"bit_48\",\n        {0x06, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc},\n        std::uint64_t(0x123456789abc),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"bit_56\",\n        {0x07, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde},\n        std::uint64_t(0x123456789abcde),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"bit_64\",\n        {0x08, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},\n        std::uint64_t(0x123456789abcdef0),\n        meta\n    ));\n}\n\nvoid add_float_samples(std::vector<success_sample>& output)\n{\n    auto meta = create_meta(column_type::float_);\n    output.push_back(success_sample(\"fractional_negative\", {0x66, 0x66, 0x86, 0xc0}, -4.2f, meta));\n    output.push_back(success_sample(\"fractional_positive\", {0x66, 0x66, 0x86, 0x40}, 4.2f, meta));\n    output.push_back(\n        success_sample(\"positive_exp_positive_fractional\", {0x01, 0x2d, 0x88, 0x61}, 3.14e20f, meta)\n    );\n    output.push_back(success_sample(\"zero\", {0x00, 0x00, 0x00, 0x00}, 0.0f, meta));\n}\n\nvoid add_double_samples(std::vector<success_sample>& output)\n{\n    auto meta = create_meta(column_type::double_);\n    output.push_back(\n        success_sample(\"fractional_negative\", {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0xc0}, -4.2, meta)\n    );\n    output.push_back(\n        success_sample(\"fractional_positive\", {0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40}, 4.2, meta)\n    );\n    output.push_back(success_sample(\n        \"positive_exp_positive_fractional\",\n        {0xce, 0x46, 0x3c, 0x76, 0x9c, 0x68, 0x90, 0x69},\n        3.14e200,\n        meta\n    ));\n    output.push_back(success_sample(\"zero\", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0.0, meta));\n}\n\nvoid add_date_samples(std::vector<success_sample>& output)\n{\n    auto meta = create_meta(column_type::date);\n    output.push_back(success_sample(\"regular\", {0x04, 0xda, 0x07, 0x03, 0x1c}, date(2010u, 3u, 28u), meta));\n    output.push_back(success_sample(\"min\", {0x04, 0x00, 0x00, 0x01, 0x01}, date(0u, 1u, 1u), meta));\n    output.push_back(success_sample(\"max\", {0x04, 0x0f, 0x27, 0x0c, 0x1f}, date(9999u, 12u, 31u), meta));\n    output.push_back(success_sample(\"empty\", {0x00}, date(), meta));\n    output.push_back(success_sample(\"zero\", {0x04, 0x00, 0x00, 0x00, 0x00}, date(), meta));\n    output.push_back(success_sample(\"zero_month\", {0x04, 0xda, 0x07, 0x00, 0x01}, date(2010u, 0u, 1u), meta));\n    output.push_back(success_sample(\"zero_day\", {0x04, 0xda, 0x07, 0x01, 0x00}, date(2010u, 1u, 0u), meta));\n    output.push_back(\n        success_sample(\"zero_month_day\", {0x04, 0xda, 0x07, 0x00, 0x00}, date(2010u, 0u, 0u), meta)\n    );\n    output.push_back(\n        success_sample(\"invalid_date\", {0x04, 0xda, 0x07, 0x0b, 0x1f}, date(2010u, 11u, 31u), meta)\n    );\n}\n\nvoid add_datetime_samples(column_type type, std::vector<success_sample>& output)\n{\n    auto meta = create_meta(type);\n    output.push_back(\n        success_sample(\"only_date\", {0x04, 0xda, 0x07, 0x01, 0x01}, datetime(2010u, 1u, 1u), meta)\n    );\n    output.push_back(success_sample(\n        \"date_h\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x14, 0x00, 0x00},\n        datetime(2010u, 1u, 1u, 20u, 0u, 0u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_m\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00},\n        datetime(2010u, 1u, 1u, 0u, 1u, 0u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hm\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x03, 0x02, 0x00},\n        datetime(2010u, 1u, 1u, 3u, 2u, 0u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_s\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x01},\n        datetime(2010u, 1u, 1u, 0u, 0u, 1u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_ms\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x00, 0x3b, 0x01},\n        datetime(2010u, 1u, 1u, 0u, 59u, 1u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hs\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x05, 0x00, 0x01},\n        datetime(2010u, 1u, 1u, 5u, 0u, 1u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hms\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b},\n        datetime(2010u, 1u, 1u, 23u, 1u, 59u, 0u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_u\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x78, 0xd4, 0x03, 0x00},\n        datetime(2010u, 1u, 1u, 0u, 0u, 0u, 251000u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x00, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 23u, 0u, 0u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_mu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x00, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 0u, 1u, 0u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hmu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x00, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 23u, 1u, 0u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_su\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x00, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 0u, 0u, 59u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_msu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x00, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 0u, 1u, 59u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x00, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 23u, 0u, 59u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 1u, 23u, 1u, 59u, 967510u),\n        meta\n    ));\n\n    // Invalid datetimes (because their date is invalid)\n    output.push_back(success_sample(\"empty\", {0x00}, datetime(), meta));\n    output.push_back(success_sample(\"only_date_zeros\", {0x04, 0x00, 0x00, 0x00, 0x00}, datetime(), meta));\n    output.push_back(success_sample(\n        \"only_date_invalid_date\",\n        {0x04, 0xda, 0x07, 0x0b, 0x1f},\n        datetime(2010u, 11u, 31u),\n        meta\n    ));\n    output.push_back(\n        success_sample(\"only_date_zero_month\", {0x04, 0xda, 0x07, 0x00, 0x01}, datetime(2010u, 0u, 1u), meta)\n    );\n    output.push_back(\n        success_sample(\"only_date_zero_day\", {0x04, 0xda, 0x07, 0x01, 0x00}, datetime(2010u, 1u, 0u), meta)\n    );\n    output.push_back(success_sample(\n        \"only_date_zero_month_day\",\n        {0x04, 0xda, 0x07, 0x00, 0x00},\n        datetime(2010u, 0u, 0u),\n        meta\n    ));\n\n    output.push_back(\n        success_sample(\"date_hms_zeros\", {0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, datetime(), meta)\n    );\n    output.push_back(success_sample(\n        \"date_hms_invalid_date\",\n        {0x07, 0xda, 0x07, 0x0b, 0x1f, 0x17, 0x01, 0x3b},\n        datetime(2010u, 11u, 31u, 23u, 1u, 59u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hms_zero_month\",\n        {0x07, 0xda, 0x07, 0x00, 0x01, 0x17, 0x01, 0x3b},\n        datetime(2010u, 0u, 1u, 23u, 1u, 59u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hms_zero_day\",\n        {0x07, 0xda, 0x07, 0x01, 0x00, 0x17, 0x01, 0x3b},\n        datetime(2010u, 1u, 0u, 23u, 1u, 59u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hms_zero_month_day\",\n        {0x07, 0xda, 0x07, 0x00, 0x00, 0x17, 0x01, 0x3b},\n        datetime(2010u, 0u, 0u, 23u, 1u, 59u),\n        meta\n    ));\n\n    output.push_back(success_sample(\n        \"date_hmsu_zeros\",\n        {0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n        datetime(),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hmsu_invalid_date\",\n        {0x0b, 0xda, 0x07, 0x0b, 0x1f, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 11u, 31u, 23u, 1u, 59u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hmsu_zero_month\",\n        {0x0b, 0xda, 0x07, 0x00, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 0u, 1u, 23u, 1u, 59u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hmsu_zero_day\",\n        {0x0b, 0xda, 0x07, 0x01, 0x00, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 1u, 0u, 23u, 1u, 59u, 967510u),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"date_hmsu_zero_month_day\",\n        {0x0b, 0xda, 0x07, 0x00, 0x00, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        datetime(2010u, 0u, 0u, 23u, 1u, 59u, 967510u),\n        meta\n    ));\n}\n\nvoid add_time_samples(std::vector<success_sample>& output)\n{\n    auto meta = create_meta(column_type::time);\n    output.push_back(success_sample(\"zero\", {0x00}, maket(0, 0, 0), meta));\n    output.push_back(success_sample(\n        \"positive_d\",\n        {0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n        maket(48, 0, 0, 0),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"positive_h\",\n        {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00},\n        maket(21, 0, 0, 0),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"positive_m\",\n        {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00},\n        maket(0, 40, 0),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"positive_s\",\n        {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15},\n        maket(0, 0, 21),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"positive_u\",\n        {0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00},\n        maket(0, 0, 0, 321000),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"positive_hmsu\",\n        {0x0c, 0x00, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00},\n        maket(838, 59, 58, 999000),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_d\",\n        {0x08, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n        -maket(48, 0, 0, 0),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_h\",\n        {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00},\n        -maket(21, 0, 0, 0),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_m\",\n        {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00},\n        -maket(0, 40, 0),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_s\",\n        {0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15},\n        -maket(0, 0, 21),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_u\",\n        {0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe5, 0x04, 0x00},\n        -maket(0, 0, 0, 321000),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_hmsu\",\n        {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00},\n        -maket(838, 59, 58, 999000),\n        meta\n    ));\n    output.push_back(success_sample(\n        \"negative_sign_not_one\",\n        {0x0c, 0x03, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x58, 0x3e, 0x0f, 0x00},\n        -maket(838, 59, 58, 999000),\n        meta\n    ));\n}\n\nstd::vector<success_sample> make_all_samples()\n{\n    std::vector<success_sample> res;\n    add_string_samples(res);\n    add_blob_samples(res);\n    add_int_samples(res);\n    add_bit_types(res);\n    add_float_samples(res);\n    add_double_samples(res);\n    add_date_samples(res);\n    add_datetime_samples(column_type::datetime, res);\n    add_datetime_samples(column_type::timestamp, res);\n    add_time_samples(res);\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    for (const auto& tc : make_all_samples())\n    {\n        BOOST_TEST_CONTEXT(\"type=\" << tc.meta.type() << \", name=\" << tc.name)\n        {\n            const auto& buffer = tc.from;\n            detail::deserialization_context ctx(buffer);\n\n            field_view actual_value;\n            auto err = deserialize_binary_field(ctx, tc.meta, actual_value);\n\n            BOOST_TEST(err == deserialize_errc::ok);\n            BOOST_TEST(actual_value == tc.expected);\n            BOOST_TEST(ctx.first() == buffer.data() + buffer.size());  // all bytes consumed\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(deserialize_error)\n\nstruct error_sample\n{\n    std::string name;\n    deserialization_buffer from;\n    metadata meta;\n    deserialize_errc expected_err;\n\n    error_sample(\n        std::string&& name,\n        deserialization_buffer&& from,\n        metadata meta,\n        deserialize_errc expected_err = deserialize_errc::protocol_value_error\n    )\n        : name(std::move(name)), from(std::move(from)), meta(std::move(meta)), expected_err(expected_err)\n    {\n    }\n};\n\nvoid add_int_samples(column_type type, std::size_t num_bytes, std::vector<error_sample>& output)\n{\n    output.emplace_back(error_sample(\n        \"signed_not_enough_space\",\n        deserialization_buffer(num_bytes, 0x0a),\n        create_meta(type),\n        deserialize_errc::incomplete_message\n    ));\n    output.emplace_back(error_sample(\n        \"unsigned_not_enough_space\",\n        deserialization_buffer(num_bytes, 0x0a),\n        meta_builder().type(type).unsigned_flag(true).build(),\n        deserialize_errc::incomplete_message\n    ));\n}\n\nvoid add_bit_samples(std::vector<error_sample>& output)\n{\n    auto meta = meta_builder().type(column_type::bit).unsigned_flag(true).build();\n\n    output.emplace_back(error_sample(\n        \"bit_error_deserializing_string_view\",\n        {0x01},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.emplace_back(error_sample(\"bit_string_view_too_short\", {0x00}, meta));\n    output.emplace_back(error_sample(\n        \"bit_string_view_too_long\",\n        {0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09},\n        meta\n    ));\n}\n\nvoid add_float_samples(std::vector<error_sample>& output)\n{\n    auto meta = create_meta(column_type::float_);\n\n    output.push_back(\n        error_sample(\"not_enough_space\", {0x01, 0x02, 0x03}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(error_sample(\"inf\", {0x00, 0x00, 0x80, 0x7f}, meta));\n    output.push_back(error_sample(\"minus_inf\", {0x00, 0x00, 0x80, 0xff}, meta));\n    output.push_back(error_sample(\"nan\", {0xff, 0xff, 0xff, 0x7f}, meta));\n    output.push_back(error_sample(\"minus_nan\", {0xff, 0xff, 0xff, 0xff}, meta));\n}\n\nvoid add_double_samples(std::vector<error_sample>& output)\n{\n    auto meta = create_meta(column_type::double_);\n\n    output.push_back(error_sample(\n        \"not_enough_space\",\n        {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\"inf\", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f}, meta));\n    output.push_back(error_sample(\"minus_inf\", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff}, meta));\n    output.push_back(error_sample(\"nan\", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, meta));\n    output.push_back(error_sample(\"minus_nan\", {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, meta));\n}\n\n// Based on correct, regular date {0x04, 0xda, 0x07, 0x03, 0x1c}\nvoid add_date_samples(std::vector<error_sample>& output)\n{\n    auto meta = create_meta(column_type::date);\n\n    output.push_back(error_sample(\"empty\", {}, meta, deserialize_errc::incomplete_message));\n    output.push_back(error_sample(\"incomplete_year\", {0x04, 0xda}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(\n        error_sample(\"no_month_day\", {0x04, 0xda, 0x07}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(\n        error_sample(\"no_day\", {0x04, 0xda, 0x07, 0x03}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(error_sample(\n        \"invalid_year\",\n        {0x04, 0x10, 0x27, 0x03, 0x1c},  // year 10000\n        meta\n    ));\n    output.push_back(error_sample(\"invalid_year_max\", {0x04, 0xff, 0xff, 0x03, 0x1c}, meta));\n    output.push_back(error_sample(\"invalid_month\", {0x04, 0xda, 0x07, 13, 0x1c}, meta));\n    output.push_back(error_sample(\"invalid_month_max\", {0x04, 0xda, 0x07, 0xff, 0x1c}, meta));\n    output.push_back(error_sample(\"invalid_day\", {0x04, 0xda, 0x07, 0x03, 32}, meta));\n    output.push_back(error_sample(\"invalid_day_max\", {0x04, 0xda, 0x07, 0x03, 0xff}, meta));\n    output.push_back(error_sample(\"protocol_max\", {0xff, 0xff, 0xff, 0xff, 0xff}, meta));\n}\n\n// Based on correct datetime {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e,\n// 0x00}\nvoid add_datetime_samples(column_type type, std::vector<error_sample>& output)\n{\n    auto meta = create_meta(type);\n\n    output.push_back(error_sample(\"empty\", {}, meta, deserialize_errc::incomplete_message));\n    output.push_back(\n        error_sample(\"incomplete_date\", {0x04, 0xda, 0x07, 0x01}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(error_sample(\n        \"no_hours_mins_secs\",\n        {0x07, 0xda, 0x07, 0x01, 0x01},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\n        \"no_mins_secs\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x17},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\n        \"no_secs\",\n        {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\n        \"incomplete_micros\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\"invalid_year_d\", {0x04, 0x10, 0x27, 0x01, 0x01}, meta));  // year 10000\n    output.push_back(error_sample(\"invalid_year_hms\", {0x07, 0x10, 0x27, 0x01, 0x01, 0x17, 0x01, 0x3b}, meta)\n    );\n    output.push_back(error_sample(\n        \"invalid_year_hmsu\",\n        {0x0b, 0x10, 0x27, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_year_max_hmsu\",\n        {0x0b, 0xff, 0xff, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\"invalid_hour_hms\", {0x07, 0xda, 0x07, 0x01, 0x01, 24, 0x01, 0x3b}, meta));\n    output.push_back(error_sample(\n        \"invalid_hour_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 24, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_hour_max_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0xff, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\"invalid_min_hms\", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 60, 0x3b}, meta));\n    output.push_back(error_sample(\n        \"invalid_min_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 60, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_min_max_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0xff, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\"invalid_sec_hms\", {0x07, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 60}, meta));\n    output.push_back(error_sample(\n        \"invalid_sec_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 60, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_sec_max_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0xff, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_micro_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0x40, 0x42, 0xf4, 0x00},\n        meta\n    ));  // 1M\n    output.push_back(error_sample(\n        \"invalid_micro_max_hmsu\",\n        {0x0b, 0xda, 0x07, 0x01, 0x01, 0x17, 0x01, 0x3b, 0xff, 0xff, 0xff, 0xff},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_hour_invalid_date\",\n        {0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_min_invalid_date\",\n        {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0xff, 0x3b, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_sec_invalid_date\",\n        {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0xff, 0x56, 0xc3, 0x0e, 0x00},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"invalid_micro_invalid_date\",\n        {0x0b, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0x3b, 0xff, 0xff, 0xff, 0xff},\n        meta\n    ));\n    output.push_back(error_sample(\n        \"protocol_max\",\n        {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n        meta\n    ));\n}\n\nvoid add_time_samples(std::vector<error_sample>& output)\n{\n    auto meta = create_meta(column_type::time);\n\n    output.push_back(error_sample(\"empty\", {}, meta, deserialize_errc::incomplete_message));\n    output.push_back(\n        error_sample(\"no_sign_days_hours_mins_secs\", {0x08}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(\n        error_sample(\"no_days_hours_mins_secs\", {0x08, 0x01}, meta, deserialize_errc::incomplete_message)\n    );\n    output.push_back(error_sample(\n        \"no_hours_mins_secs\",\n        {0x08, 0x01, 0x22, 0x00, 0x00, 0x00},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\n        \"no_mins_secs\",\n        {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\n        \"no_secs\",\n        {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n    output.push_back(error_sample(\n        \"no_micros\",\n        {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a},\n        meta,\n        deserialize_errc::incomplete_message\n    ));\n\n    std::pair<const char*, std::vector<std::uint8_t>> out_of_range_cases[]{\n        {\"invalid_days\",       {0x08, 0x00, 35, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a}                          },\n        {\"invalid_days_max\",   {0x08, 0x00, 0xff, 0xff, 0xff, 0xff, 0x16, 0x3b, 0x3a}                        },\n        {\"invalid_hours\",      {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 24, 0x3b, 0x3a}                          },\n        {\"invalid_hours_max\",  {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3a}                        },\n        {\"invalid_mins\",       {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 60, 0x3a}                          },\n        {\"invalid_mins_max\",   {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0xff, 0x3a}                        },\n        {\"invalid_secs\",       {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 60}                          },\n        {\"invalid_secs_max\",   {0x08, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0xff}                        },\n        {\"invalid_micros\",     {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0x40, 0x42, 0xf4, 0x00}},\n        {\"invalid_micros_max\", {0x0c, 0x01, 0x22, 0x00, 0x00, 0x00, 0x16, 0x3b, 0x3a, 0xff, 0xff, 0xff, 0xff}\n        },\n    };\n\n    for (auto& c : out_of_range_cases)\n    {\n        // Positive\n        c.second[1] = 0x00;\n        output.emplace_back(c.first + std::string(\"_positive\"), deserialization_buffer(c.second), meta);\n\n        // Negative\n        c.second[1] = 0x01;\n        output.emplace_back(c.first + std::string(\"_negative\"), deserialization_buffer(c.second), meta);\n    }\n}\n\nstd::vector<error_sample> make_all_samples()\n{\n    std::vector<error_sample> res;\n    add_int_samples(column_type::tinyint, 0, res);\n    add_int_samples(column_type::smallint, 1, res);\n    add_int_samples(column_type::mediumint, 3, res);\n    add_int_samples(column_type::int_, 3, res);\n    add_int_samples(column_type::bigint, 7, res);\n    add_int_samples(column_type::year, 1, res);\n    add_bit_samples(res);\n    add_float_samples(res);\n    add_double_samples(res);\n    add_date_samples(res);\n    add_datetime_samples(column_type::datetime, res);\n    add_datetime_samples(column_type::timestamp, res);\n    add_time_samples(res);\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(error)\n{\n    for (const auto& tc : make_all_samples())\n    {\n        BOOST_TEST_CONTEXT(\"type=\" << tc.meta.type() << \", name=\" << tc.name)\n        {\n            detail::deserialization_context ctx(tc.from);\n\n            field_view actual_value;\n            auto err = deserialize_binary_field(ctx, tc.meta, actual_value);\n\n            BOOST_TEST(err == tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/protocol/capabilities.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing detail::capabilities;\nusing detail::has_capabilities;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_capabilities)\n\nBOOST_AUTO_TEST_CASE(operator_or)\n{\n    // Two != flags\n    BOOST_TEST((capabilities::long_password | capabilities::long_flag) == static_cast<capabilities>(5));\n\n    // Same flag\n    BOOST_TEST((capabilities::long_flag | capabilities::long_flag) == capabilities::long_flag);\n\n    // Big values\n    BOOST_TEST(\n        (capabilities::long_password | capabilities::remember_options) ==\n        static_cast<capabilities>(1 | (1 << 31))\n    );\n}\n\nBOOST_AUTO_TEST_CASE(operator_and)\n{\n    // Single flag present\n    BOOST_TEST((static_cast<capabilities>(5) & capabilities::long_password) == capabilities::long_password);\n\n    // Single flag absent\n    BOOST_TEST((static_cast<capabilities>(5) & capabilities::odbc) == capabilities{});\n\n    // Multiple flags\n    BOOST_TEST(\n        (static_cast<capabilities>(11) & static_cast<capabilities>(67)) == static_cast<capabilities>(3)\n    );\n\n    // Big values\n    BOOST_TEST(\n        (static_cast<capabilities>(0xffffffff) & capabilities::remember_options) ==\n        capabilities::remember_options\n    );\n}\n\nBOOST_AUTO_TEST_CASE(has_capabilities_)\n{\n    constexpr auto search = capabilities::connect_with_db | capabilities::ssl | capabilities::compress;\n\n    // No capabilities present\n    BOOST_TEST(!has_capabilities(capabilities{}, search));\n\n    // Some present, but not all\n    BOOST_TEST(!has_capabilities(capabilities::connect_with_db | capabilities::compress, search));\n\n    // Some present, but not all. Some unrelated are present\n    BOOST_TEST(!has_capabilities(\n        capabilities::connect_with_db | capabilities::compress | capabilities::long_flag,\n        search\n    ));\n\n    // Only the requested ones are present\n    BOOST_TEST(has_capabilities(search, search));\n\n    // Has the requested ones, plus extra ones\n    BOOST_TEST(has_capabilities(static_cast<capabilities>(0xffffffff), search));\n\n    // Searching for only one capability works\n    BOOST_TEST(\n        has_capabilities(capabilities::connect_with_db | capabilities::compress, capabilities::compress)\n    );\n    BOOST_TEST(\n        !has_capabilities(capabilities::connect_with_db | capabilities::compress, capabilities::long_flag)\n    );\n\n    // Searching for the empty set always returns true\n    BOOST_TEST(has_capabilities(capabilities::connect_with_db | capabilities::compress, capabilities{}));\n    BOOST_TEST(has_capabilities(static_cast<capabilities>(0xffffffff), capabilities{}));\n}\n\nBOOST_AUTO_TEST_SUITE_END()  // test_capabilities\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/protocol/deserialization.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/deserialization.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <memory>\n\n#include \"operators.hpp\"\n#include \"serialization_test.hpp\"\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nnamespace collations = boost::mysql::mysql_collations;\nusing boost::span;\nusing boost::mysql::client_errc;\nusing boost::mysql::column_type;\nusing boost::mysql::common_server_errc;\nusing boost::mysql::date;\nusing boost::mysql::datetime;\nusing boost::mysql::diagnostics;\nusing boost::mysql::error_code;\nusing boost::mysql::field_view;\nusing boost::mysql::get_mariadb_server_category;\nusing boost::mysql::get_mysql_server_category;\nusing boost::mysql::metadata;\nusing boost::mysql::string_view;\n\nBOOST_TEST_DONT_PRINT_LOG_VALUE(execute_response::type_t)\nBOOST_TEST_DONT_PRINT_LOG_VALUE(row_message::type_t)\nBOOST_TEST_DONT_PRINT_LOG_VALUE(handshake_server_response::type_t)\n\nBOOST_AUTO_TEST_SUITE(test_deserialization)\n\n//\n// OK packets\n//\nBOOST_AUTO_TEST_CASE(ok_view_success)\n{\n    struct\n    {\n        const char* name;\n        ok_view expected;\n        deserialization_buffer serialized;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"successful_update\",\n            ok_builder()\n                .affected_rows(4)\n                .last_insert_id(0)\n                .flags(34)\n                .warnings(0)\n                .info(\"Rows matched: 5  Changed: 4  Warnings: 0\")\n                .build(),\n            {0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28, 0x52, 0x6f, 0x77, 0x73, 0x20, 0x6d, 0x61, 0x74, 0x63,\n             0x68, 0x65, 0x64, 0x3a, 0x20, 0x35, 0x20, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x3a,\n             0x20, 0x34, 0x20, 0x20, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x3a, 0x20, 0x30},\n        },\n        {\n            \"successful_insert\",\n            ok_builder()\n                .affected_rows(1)\n                .last_insert_id(6)\n                .flags(2)\n                .warnings(0)\n                .info(\"\")\n                .build(),\n            {0x01, 0x06, 0x02, 0x00, 0x00, 0x00},\n        },\n        {\n            \"successful_login\",\n            ok_builder()\n                .affected_rows(0)\n                .last_insert_id(0)\n                .flags(0x02)\n                .warnings(0)\n                .info(\"\")\n                .build(),\n            {0x00, 0x00, 0x02, 0x00, 0x00, 0x00},\n        }\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            ok_view actual{};\n            error_code err = deserialize_ok_packet(tc.serialized, actual);\n\n            // No error\n            BOOST_TEST(err == error_code());\n\n            // Actual value\n            BOOST_TEST(actual.affected_rows == tc.expected.affected_rows);\n            BOOST_TEST(actual.last_insert_id == tc.expected.last_insert_id);\n            BOOST_TEST(actual.status_flags == tc.expected.status_flags);\n            BOOST_TEST(actual.warnings == tc.expected.warnings);\n            BOOST_TEST(actual.info == tc.expected.info);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(ok_view_error)\n{\n    struct\n    {\n        const char* name;\n        client_errc expected_err;\n        deserialization_buffer serialized;\n    } test_cases[] = {\n        {\"empty\",                client_errc::incomplete_message, {}                                                    },\n        {\"error_affected_rows\",  client_errc::incomplete_message, {0xff}                                                },\n        {\"error_last_insert_id\", client_errc::incomplete_message, {0x01, 0xff}                                          },\n        {\"error_last_insert_id\", client_errc::incomplete_message, {0x01, 0x06, 0x02}                                    },\n        {\"error_warnings\",       client_errc::incomplete_message, {0x01, 0x06, 0x02, 0x00, 0x00}                        },\n        {\"error_info\",           client_errc::incomplete_message, {0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x28}            },\n        {\"extra_bytes\",          client_errc::extra_bytes,        {0x01, 0x06, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}}\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            ok_view value{};\n            error_code err = deserialize_ok_packet(tc.serialized, value);\n            BOOST_TEST(err == tc.expected_err);\n        }\n    }\n}\n\n//\n// error packets\n//\nBOOST_AUTO_TEST_CASE(err_view_success)\n{\n    struct\n    {\n        const char* name;\n        err_view expected;\n        deserialization_buffer serialized;\n        bool has_sql_state;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"wrong_use_database\",\n            {1049, \"Unknown database 'a'\"},\n            {0x19, 0x04, 0x23, 0x34, 0x32, 0x30, 0x30, 0x30, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77,\n             0x6e, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x27, 0x61, 0x27},\n            true,\n        },\n        {\n            \"unknown_table\",\n            {1146, \"Table 'awesome.unknown' doesn't exist\"},\n            {0x7a, 0x04, 0x23, 0x34, 0x32, 0x53, 0x30, 0x32, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x27,\n             0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x2e, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e,\n             0x27, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74},\n            true,\n        },\n        {\n            \"failed_login\",\n            {1045, \"Access denied for user 'root'@'localhost' (using password: YES)\"},\n            {0x15, 0x04, 0x23, 0x32, 0x38, 0x30, 0x30, 0x30, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20,\n             0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x75, 0x73, 0x65, 0x72,\n             0x20, 0x27, 0x72, 0x6f, 0x6f, 0x74, 0x27, 0x40, 0x27, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68,\n             0x6f, 0x73, 0x74, 0x27, 0x20, 0x28, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x70, 0x61, 0x73,\n             0x73, 0x77, 0x6f, 0x72, 0x64, 0x3a, 0x20, 0x59, 0x45, 0x53, 0x29},\n            true,\n        },\n        {\n            \"no_error_message\",\n            {1045, \"\"},\n            {0x15, 0x04, 0x23, 0x32, 0x38, 0x30, 0x30, 0x30},\n            true,\n        },\n        {\n            \"nosqlstate_too_many_connections\",\n            {1040, \"Too many connections\"},\n            {0x10, 0x04, 0x54, 0x6f, 0x6f, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20,\n             0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73},\n            false,\n        },\n        {\n            \"nosqlstate_empty_err_msg\",\n            {1040, \"\"},\n            {0x10, 0x04},\n            false,\n        },\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            err_view actual{};\n            error_code err = deserialize_error_packet(tc.serialized, actual, tc.has_sql_state);\n\n            // No error\n            BOOST_TEST(err == error_code());\n\n            // Actual value\n            BOOST_TEST(actual.error_code == tc.expected.error_code);\n            BOOST_TEST(actual.error_message == tc.expected.error_message);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(err_view_error)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer serialized;\n        bool has_sql_state;\n    } test_cases[] = {\n        {\"empty\",                       {},                       true },\n        {\"error_error_code\",            {0x15},                   true },\n        {\"error_sql_state_marker\",      {0x15, 0x04},             true },\n        {\"error_sql_state\",             {0x15, 0x04, 0x23, 0x32}, true },\n        {\"nosqlstate_empty\",            {},                       false},\n        {\"nosqlstate_error_error_code\", {0x15},                   false},\n    };\n    // Note: not possible to get extra bytes here, since the last field is a string_eof\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            err_view value{};\n            error_code err = deserialize_error_packet(tc.serialized, value, tc.has_sql_state);\n            BOOST_TEST(err == client_errc::incomplete_message);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(process_error_packet_)\n{\n    // It's OK to use err_builder() here, since the deserialization function\n    // has already been tested\n    struct\n    {\n        const char* name;\n        db_flavor flavor;\n        deserialization_buffer serialized;\n        error_code ec;\n        const char* msg;\n    } test_cases[] = {\n        {\"bad_error_packet\", db_flavor::mariadb, {0xff, 0x00, 0x01}, client_errc::incomplete_message, \"\"},\n        {\"code_lt_min\",\n         db_flavor::mariadb,\n         err_builder().code(999).message(\"abc\").build_body_without_header(),\n         error_code(999, get_mariadb_server_category()),\n         \"abc\"},\n        {\"code_common\",\n         db_flavor::mariadb,\n         err_builder().code(1064).message(\"abc\").build_body_without_header(),\n         common_server_errc::er_parse_error,\n         \"abc\"},\n        {\"code_common_hole_mysql\",\n         db_flavor::mysql,\n         err_builder().code(1076).build_body_without_header(),\n         error_code(1076, get_mysql_server_category()),\n         \"\"},\n        {\"code_common_hole_mariadb\",\n         db_flavor::mariadb,\n         err_builder().code(1076).build_body_without_header(),\n         error_code(1076, get_mariadb_server_category()),\n         \"\"},\n        {\"code_mysql\",\n         db_flavor::mysql,\n         err_builder().code(4004).build_body_without_header(),\n         error_code(4004, get_mysql_server_category()),\n         \"\"},\n        {\"code_mariadb\",\n         db_flavor::mariadb,\n         err_builder().code(4004).build_body_without_header(),\n         error_code(4004, get_mariadb_server_category()),\n         \"\"},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            diagnostics diag;\n            auto ec = process_error_packet(tc.serialized, tc.flavor, diag);\n            BOOST_TEST(ec == tc.ec);\n            BOOST_TEST(diag.server_message() == tc.msg);\n        }\n    }\n}\n\n//\n// coldef\n//\nBOOST_AUTO_TEST_CASE(coldef_view_success)\n{\n    struct\n    {\n        const char* name;\n        coldef_view expected;\n        deserialization_buffer serialized;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"numeric_auto_increment_primary_key\",\n            meta_builder()\n                .database(\"awesome\")\n                .table(\"test_table\")\n                .org_table(\"test_table\")\n                .name(\"id\")\n                .org_name(\"id\")\n                .collation_id(collations::binary)\n                .column_length(11)\n                .type(column_type::int_)\n                .flags(\n                    column_flags::not_null | column_flags::pri_key | column_flags::auto_increment |\n                    column_flags::part_key\n                )\n                .decimals(0)\n                .build_coldef(),\n            {\n                0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74,\n                0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, 0x74, 0x65, 0x73, 0x74,\n                0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x02, 0x69, 0x64, 0x02, 0x69, 0x64, 0x0c, 0x3f,\n                0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x03, 0x42, 0x00, 0x00, 0x00\n            },\n        },\n        {\n            \"varchar_field_aliased_field_and_table_names_join\",\n            meta_builder()\n                .database(\"awesome\")\n                .table(\"child\")\n                .org_table(\"child_table\")\n                .name(\"field_alias\")\n                .org_name(\"field_varchar\")\n                .collation_id(collations::utf8_general_ci)\n                .column_length(765)\n                .type(column_type::varchar)\n                .flags(0)\n                .decimals(0)\n                .build_coldef(),\n            {\n                0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65,\n                0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68, 0x69,\n                0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64,\n                0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0b, 0x66,\n                0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69,\n                0x61, 0x73, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64,\n                0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72,\n                0x0c, 0x21, 0x00, 0xfd, 0x02, 0x00, 0x00, 0xfd,\n                0x00, 0x00, 0x00, 0x00, 0x00\n            },\n        },\n        {\n            \"float_field\",\n            meta_builder()\n                .database(\"awesome\")\n                .table(\"test_table\")\n                .org_table(\"test_table\")\n                .name(\"field_float\")\n                .org_name(\"field_float\")\n                .collation_id(collations::binary)\n                .column_length(12)\n                .type(column_type::float_)\n                .flags(0)\n                .decimals(31)\n                .build_coldef(),\n            {\n                0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65,\n                0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73,\n                0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a,\n                0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62,\n                0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64,\n                0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x0b, 0x66,\n                0x69, 0x65, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x6f,\n                0x61, 0x74, 0x0c, 0x3f, 0x00, 0x0c, 0x00, 0x00,\n                0x00, 0x04, 0x00, 0x00, 0x1f, 0x00, 0x00\n            },\n        },\n        {\n            \"no_final_padding\", // edge case\n            meta_builder()\n                .database(\"awesome\")\n                .table(\"test_table\")\n                .org_table(\"test_table\")\n                .name(\"field_float\")\n                .org_name(\"field_float\")\n                .collation_id(collations::binary)\n                .column_length(12)\n                .type(column_type::float_)\n                .flags(0)\n                .decimals(31)\n                .build_coldef(),\n            {\n                0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65,\n                0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73,\n                0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a,\n                0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62,\n                0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64,\n                0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x0b, 0x66,\n                0x69, 0x65, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x6f,\n                0x61, 0x74, 0x0a, 0x3f, 0x00, 0x0c, 0x00, 0x00,\n                0x00, 0x04, 0x00, 0x00, 0x1f\n            },\n        },\n        {\n            \"more_final_padding\", // test for extensibility - we don't fail if mysql adds more fields in the end\n            meta_builder()\n                .database(\"awesome\")\n                .table(\"test_table\")\n                .org_table(\"test_table\")\n                .name(\"field_float\")\n                .org_name(\"field_float\")\n                .collation_id(collations::binary)\n                .column_length(12)\n                .type(column_type::float_)\n                .flags(0)\n                .decimals(31)\n                .build_coldef(),\n            {\n                0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65,\n                0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73,\n                0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a,\n                0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62,\n                0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64,\n                0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x0b, 0x66,\n                0x69, 0x65, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x6f,\n                0x61, 0x74, 0x0d, 0x3f, 0x00, 0x0c, 0x00, 0x00,\n                0x00, 0x04, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00\n            },\n        },\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            coldef_view actual{};\n            error_code err = deserialize_column_definition(tc.serialized, actual);\n\n            // No error\n            BOOST_TEST_REQUIRE(err == error_code());\n\n            // Actual value\n            BOOST_TEST(actual.database == tc.expected.database);\n            BOOST_TEST(actual.table == tc.expected.table);\n            BOOST_TEST(actual.org_table == tc.expected.org_table);\n            BOOST_TEST(actual.name == tc.expected.name);\n            BOOST_TEST(actual.org_name == tc.expected.org_name);\n            BOOST_TEST(actual.collation_id == tc.expected.collation_id);\n            BOOST_TEST(actual.column_length == tc.expected.column_length);\n            BOOST_TEST(actual.type == tc.expected.type);\n            BOOST_TEST(actual.flags == tc.expected.flags);\n            BOOST_TEST(actual.decimals == tc.expected.decimals);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(coldef_view_error)\n{\n    struct\n    {\n        const char* name;\n        error_code expected_err;\n        deserialization_buffer serialized;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"empty\",\n            client_errc::incomplete_message,\n            {}\n        },\n        {\n            \"error_catalog\",\n            client_errc::incomplete_message,\n            {0xff}\n        },\n        {\n            \"error_database\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0xff}\n        },\n        {\n            \"error_table\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0xff}\n        },\n        {   \"error_org_table\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05,\n            0x63, 0x68, 0x69, 0x6c, 0x64, 0xff}\n        },\n        {\n            \"error_name\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68, 0x69,\n            0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0xff}\n        },\n        {\n            \"error_org_name\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68,\n            0x69, 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65,\n            0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0xff}\n        },\n        {\n            \"error_fixed_fields\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68,\n            0x69, 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65,\n            0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x0d, 0x66, 0x69,\n            0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72, 0xff}\n        },\n        {\n            \"error_collation_id\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68,\n            0x69, 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65,\n            0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x0d, 0x66, 0x69,\n            0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72, 0x01, 0x00}\n        },\n        {\n            \"error_column_length\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68,\n            0x69, 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65,\n            0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x0d, 0x66, 0x69,\n            0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72, 0x03, 0x00, 0x00, 0x00}\n        },\n        {\n            \"error_column_type\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63, 0x68, 0x69,\n            0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0b, 0x66,\n            0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64,\n            0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\n        },\n        {\n            \"error_flags\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05,\n            0x63, 0x68, 0x69, 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74,\n            0x61, 0x62, 0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c,\n            0x69, 0x61, 0x73, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x72,\n            0x63, 0x68, 0x61, 0x72, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\n        },\n        {\n            \"error_decimals\",\n            client_errc::incomplete_message,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x05, 0x63,\n            0x68, 0x69, 0x6c, 0x64, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x61, 0x62,\n            0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73,\n            0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x76, 0x61, 0x72, 0x63, 0x68, 0x61, 0x72,\n            0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\n        },\n        {\n            \"extra_bytes\",\n            client_errc::extra_bytes,\n            {0x03, 0x64, 0x65, 0x66, 0x07, 0x61, 0x77, 0x65,\n            0x73, 0x6f, 0x6d, 0x65, 0x0a, 0x74, 0x65, 0x73,\n            0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a,\n            0x74, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x61, 0x62,\n            0x6c, 0x65, 0x0b, 0x66, 0x69, 0x65, 0x6c, 0x64,\n            0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x0b, 0x66,\n            0x69, 0x65, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x6f,\n            0x61, 0x74, 0x0d, 0x3f, 0x00, 0x0c, 0x00, 0x00,\n            0x00, 0x04, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xff}\n        }\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            coldef_view value{};\n            error_code err = deserialize_column_definition(tc.serialized, value);\n            BOOST_TEST(err == tc.expected_err);\n        }\n    }\n}\n\n// OK response (ping & reset connection)\nBOOST_AUTO_TEST_CASE(deserialize_ok_response_)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer message;\n        error_code expected_err;\n        const char* expected_msg;\n        bool expected_backslash_escapes;\n    } test_cases[] = {\n        {\"success\",                      create_ok_body(ok_builder().build()),                error_code(),                      \"\", true },\n        {\"success_no_backslash_escapes\",\n         create_ok_body(ok_builder().no_backslash_escapes(true).build()),\n         error_code(),\n         \"\",                                                                                                                         false},\n        {\"empty_message\",                {},                                                  client_errc::incomplete_message,   \"\", true },\n        {\"invalid_message_type\",         {0xab},                                              client_errc::protocol_value_error, \"\", true },\n        {\"bad_ok_packet\",                {0x00, 0x01},                                        client_errc::incomplete_message,   \"\", true },\n        {\"err_packet\",\n         err_builder().code(common_server_errc::er_bad_db_error).message(\"abc\").build_body(),\n         common_server_errc::er_bad_db_error,\n         \"abc\",                                                                                                                      true },\n        {\"bad_err_packet\",               {0xff, 0x01},                                        client_errc::incomplete_message,   \"\", true },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            diagnostics diag;\n            bool backslash_escapes = true;\n            auto err = deserialize_ok_response(tc.message, db_flavor::mariadb, diag, backslash_escapes);\n\n            BOOST_TEST(err == tc.expected_err);\n            BOOST_TEST(diag.server_message() == tc.expected_msg);\n            BOOST_TEST(backslash_escapes == tc.expected_backslash_escapes);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_prepare_stmt_response_impl_success)\n{\n    // Data (statement_id, num fields, num params)\n    prepare_stmt_response expected{1, 2, 3};\n    deserialization_buffer serialized{0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00};\n    prepare_stmt_response actual{};\n    auto err = deserialize_prepare_stmt_response_impl(serialized, actual);\n\n    // No error\n    BOOST_TEST_REQUIRE(err == error_code());\n\n    // Actual value\n    BOOST_TEST(actual.id == expected.id);\n    BOOST_TEST(actual.num_columns == expected.num_columns);\n    BOOST_TEST(actual.num_params == expected.num_params);\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_prepare_stmt_response_impl_error)\n{\n    struct\n    {\n        const char* name;\n        error_code expected_err;\n        deserialization_buffer serialized;\n    } test_cases[] = {\n        {\"empty\",              client_errc::incomplete_message, {}                                              },\n        {\"error_id\",           client_errc::incomplete_message, {0x01}                                          },\n        {\"error_num_columns\",  client_errc::incomplete_message, {0x01, 0x00, 0x00, 0x00, 0x02}                  },\n        {\"error_num_params\",   client_errc::incomplete_message, {0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03}      },\n        {\"error_reserved\",     client_errc::incomplete_message, {0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00}},\n        {\"error_num_warnings\",\n         client_errc::incomplete_message,\n         {0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00}                                           },\n        {\"extra_bytes\",\n         client_errc::extra_bytes,\n         {0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff}                               },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            prepare_stmt_response output{};\n            auto err = deserialize_prepare_stmt_response_impl(tc.serialized, output);\n            BOOST_TEST(err == tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_prepare_stmt_response_success)\n{\n    // Data (statement_id, num fields, num params)\n    prepare_stmt_response expected{1, 2, 3};\n    deserialization_buffer serialized{0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00};\n    prepare_stmt_response actual{};\n    diagnostics diag;\n\n    auto err = deserialize_prepare_stmt_response(serialized, db_flavor::mysql, actual, diag);\n\n    // No error\n    BOOST_TEST_REQUIRE(err == error_code());\n    BOOST_TEST(diag == diagnostics());\n\n    // Actual value\n    BOOST_TEST(actual.id == expected.id);\n    BOOST_TEST(actual.num_columns == expected.num_columns);\n    BOOST_TEST(actual.num_params == expected.num_params);\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_prepare_stmt_response_error)\n{\n    struct\n    {\n        const char* name;\n        error_code expected_err;\n        const char* expected_diag;\n        deserialization_buffer serialized;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"error_message_type\",\n            client_errc::incomplete_message,\n            \"\",\n            {},\n        },\n        {\n            \"unknown_message_type\",\n            client_errc::protocol_value_error,\n            \"\",\n            {0xab, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00},\n        },\n        {\n            \"error_packet\",\n            common_server_errc::er_bad_db_error,\n            \"bad db\",\n            err_builder().code(common_server_errc::er_bad_db_error).message(\"bad db\").build_body(),\n        },\n        {\n            \"error_deserializing_response\",\n            client_errc::incomplete_message,\n            \"\",\n            {0x00, 0x01, 0x00},\n        },\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            prepare_stmt_response output{};\n            diagnostics diag;\n\n            auto err = deserialize_prepare_stmt_response(tc.serialized, db_flavor::mariadb, output, diag);\n\n            BOOST_TEST(err == tc.expected_err);\n            BOOST_TEST(diag.server_message() == tc.expected_diag);\n        }\n    }\n}\n\n//\n// execute response\n//\nBOOST_AUTO_TEST_CASE(deserialize_execute_response_ok_packet)\n{\n    deserialization_buffer serialized{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};\n    diagnostics diag;\n\n    auto response = deserialize_execute_response(serialized, db_flavor::mariadb, diag);\n\n    BOOST_TEST_REQUIRE(response.type == execute_response::type_t::ok_packet);\n    BOOST_TEST(response.data.ok_pack.affected_rows == 0u);\n    BOOST_TEST(response.data.ok_pack.status_flags == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_execute_response_num_fields)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer serialized;\n        std::size_t num_fields;\n    } test_cases[] = {\n        {\"1\",                    {0x01},             1     },\n        {\"0xfa\",                 {0xfa},             0xfa  },\n        {\"0xfb_no_local_infile\", {0xfb},             0xfb  }, // legal when LOCAL INFILE capability not enabled\n        {\"0xfb_local_infile\",    {0xfc, 0xfb, 0x00}, 0xfb  }, // sent LOCAL INFILE capability is enabled\n        {\"0xff\",                 {0xfc, 0xff, 0x00}, 0xff  },\n        {\"0x01ff\",               {0xfc, 0xff, 0x01}, 0x01ff},\n        {\"max\",                  {0xfc, 0xff, 0xff}, 0xffff},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            diagnostics diag;\n\n            auto response = deserialize_execute_response(tc.serialized, db_flavor::mysql, diag);\n\n            BOOST_TEST_REQUIRE(response.type == execute_response::type_t::num_fields);\n            BOOST_TEST(response.data.num_fields == tc.num_fields);\n            BOOST_TEST(diag.server_message() == \"\");\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_execute_response_error)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer serialized;\n        error_code err;\n        const char* expected_info;\n    } test_cases[] = {\n        {\"server_error\",\n         {0xff, 0x7a, 0x04, 0x23, 0x34, 0x32, 0x53, 0x30, 0x32, 0x54, 0x61, 0x62, 0x6c, 0x65,\n          0x20, 0x27, 0x6d, 0x79, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x61, 0x62, 0x63, 0x27, 0x20,\n          0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74},\n         common_server_errc::er_no_such_table,\n         \"Table 'mytest.abc' doesn't exist\"                                                                                   },\n        {\"bad_server_error\", {0xff, 0x00},                                               client_errc::incomplete_message,   \"\"},\n        {\"bad_ok_packet\",    {0x00, 0xff},                                               client_errc::incomplete_message,   \"\"},\n        {\"bad_num_fields\",   {0xfc, 0xff, 0x00, 0x01},                                   client_errc::extra_bytes,          \"\"},\n        {\"zero_num_fields\",  {0xfc, 0x00, 0x00},                                         client_errc::protocol_value_error, \"\"},\n        {\"3byte_integer\",    {0xfd, 0xff, 0xff, 0xff},                                   client_errc::protocol_value_error, \"\"},\n        {\"8byte_integer\",\n         {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},\n         client_errc::protocol_value_error,\n         \"\"                                                                                                                   },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            diagnostics diag;\n\n            auto response = deserialize_execute_response(tc.serialized, db_flavor::mysql, diag);\n\n            BOOST_TEST_REQUIRE(response.type == execute_response::type_t::error);\n            BOOST_TEST(response.data.err == tc.err);\n            BOOST_TEST(diag.server_message() == tc.expected_info);\n        }\n    }\n}\n\n//\n// row message\n//\nBOOST_AUTO_TEST_CASE(deserialize_row_message_row)\n{\n    deserialization_buffer serialized{create_text_row_body(\"abc\", 10)};\n    diagnostics diag;\n\n    auto response = deserialize_row_message(serialized, db_flavor::mysql, diag);\n\n    BOOST_TEST_REQUIRE(response.type == row_message::type_t::row);\n    BOOST_TEST(response.data.row.data() == serialized.data());\n    BOOST_TEST(response.data.row.size() == serialized.size());\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_row_message_ok_packet)\n{\n    deserialization_buffer serialized{\n        create_eof_body(ok_builder().affected_rows(42).last_insert_id(1).info(\"abc\").build())\n    };\n    diagnostics diag;\n\n    auto response = deserialize_row_message(serialized, db_flavor::mysql, diag);\n\n    BOOST_TEST_REQUIRE(response.type == row_message::type_t::ok_packet);\n    BOOST_TEST(response.data.ok_pack.affected_rows == 42u);\n    BOOST_TEST(response.data.ok_pack.last_insert_id == 1u);\n    BOOST_TEST(response.data.ok_pack.info == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_row_message_error)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer serialized;\n        error_code expected_error;\n        const char* expected_info;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"invalid_ok_packet\",\n            { 0xfe, 0x00, 0x00, 0x02, 0x00, 0x00 }, // 1 byte missing\n            client_errc::incomplete_message,\n            \"\"\n        },\n        {\n            \"error_packet\",\n            {\n                0xff, 0x19, 0x04, 0x23, 0x34, 0x32, 0x30, 0x30, 0x30, 0x55, 0x6e, 0x6b,\n                0x6e, 0x6f, 0x77, 0x6e, 0x20, 0x64, 0x61, 0x74,\n                0x61, 0x62, 0x61, 0x73, 0x65, 0x20, 0x27, 0x61, 0x27\n            },\n            common_server_errc::er_bad_db_error,\n            \"Unknown database 'a'\"\n        },\n        {\n            \"invalid_error_packet\",\n            { 0xff, 0x19 }, // bytes missing\n            client_errc::incomplete_message,\n            \"\"\n        },\n        {\n            \"empty_message\",\n            {},\n            client_errc::incomplete_message,\n            \"\"\n        }  // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            diagnostics diag;\n\n            auto msg = deserialize_row_message(tc.serialized, db_flavor::mysql, diag);\n\n            BOOST_TEST_REQUIRE(msg.type == row_message::type_t::error);\n            BOOST_TEST(msg.data.err == tc.expected_error);\n            BOOST_TEST(diag.server_message() == tc.expected_info);\n        }\n    }\n}\n\n//\n// deserialize_row\n//\nBOOST_AUTO_TEST_CASE(deserialize_row_success)\n{\n    struct\n    {\n        const char* name;\n        resultset_encoding encoding;\n        deserialization_buffer serialized;\n        std::vector<field_view> expected;\n        std::vector<metadata> meta;\n    } test_cases[] = {\n        // clang-format off\n        // Text\n        {\n            \"text_one_value\",\n            resultset_encoding::text,\n            {0x01, 0x35},\n            make_fv_vector(std::int64_t(5)),\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"text_one_null\",\n            resultset_encoding::text,\n            {0xfb},\n            make_fv_vector(nullptr),\n            create_metas({ column_type::tinyint} )\n        },\n        {\n            \"text_several_values\",\n            resultset_encoding::text,\n            {0x03, 0x76, 0x61, 0x6c, 0x02, 0x32, 0x31, 0x03, 0x30, 0x2e, 0x30},\n            make_fv_vector(\"val\", std::int64_t(21), 0.0f),\n            create_metas({ column_type::varchar, column_type::int_, column_type::float_})\n        },\n        {\n            \"text_several_values_one_null\",\n            resultset_encoding::text,\n            {0x03, 0x76, 0x61, 0x6c, 0xfb, 0x03, 0x76, 0x61, 0x6c},\n            make_fv_vector(\"val\", nullptr, \"val\"),\n            create_metas({ column_type::varchar, column_type::int_, column_type::varchar })\n        },\n        {\n            \"text_several_nulls\",\n            resultset_encoding::text,\n            {0xfb, 0xfb, 0xfb},\n            make_fv_vector(nullptr, nullptr, nullptr),\n            create_metas({ column_type::varchar, column_type::int_, column_type::datetime })\n        },\n\n        // Binary\n        {\n            \"binary_one_value\",\n            resultset_encoding::binary,\n            {0x00, 0x00, 0x14},\n            make_fv_vector(std::int64_t(20)),\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"binary_one_null\",\n            resultset_encoding::binary,\n            {0x00, 0x04},\n            make_fv_vector(nullptr),\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"binary_two_values\",\n            resultset_encoding::binary,\n            {0x00, 0x00, 0x03, 0x6d, 0x69, 0x6e, 0x6d, 0x07},\n            make_fv_vector(\"min\", std::int64_t(1901)),\n            create_metas({ column_type::varchar, column_type::smallint })\n        },\n        {\n            \"binary_one_value_one_null\",\n            resultset_encoding::binary,\n            {0x00, 0x08, 0x03, 0x6d, 0x61, 0x78},\n            make_fv_vector(\"max\", nullptr),\n            create_metas({ column_type::varchar, column_type::tinyint })\n        },\n        {\n            \"binary_two_nulls\",\n            resultset_encoding::binary,\n            {0x00, 0x0c},\n            make_fv_vector(nullptr, nullptr),\n            create_metas({ column_type::tinyint, column_type::tinyint })\n        },\n        {\n            \"binary_six_nulls\",\n            resultset_encoding::binary,\n            {0x00, 0xfc},\n            std::vector<field_view>(6, field_view()),\n            std::vector<metadata>(6, create_meta(column_type::tinyint))\n        },\n        {\n            \"binary_seven_nulls\",\n            resultset_encoding::binary,\n            {0x00, 0xfc, 0x01},\n            std::vector<field_view>(7, field_view()),\n            std::vector<metadata>(7, create_meta(column_type::tinyint))\n        },\n        {\n            \"binary_several_values\",\n            resultset_encoding::binary,\n            {\n                0x00, 0x90, 0x00, 0xfd, 0x03, 0x61, 0x62, 0x63,\n                0xc3, 0xf5, 0x48, 0x40, 0x02, 0x61, 0x62, 0x04,\n                0xe2, 0x07, 0x0a, 0x05, 0x71, 0x99, 0x6d, 0xe2,\n                0x93, 0x4d, 0xf5, 0x3d\n            },\n            make_fv_vector(\n                std::int64_t(-3),\n                \"abc\",\n                nullptr,\n                3.14f,\n                \"ab\",\n                nullptr,\n                date(2018u, 10u, 5u),\n                3.10e-10\n            ),\n            create_metas({\n                column_type::tinyint,\n                column_type::varchar,\n                column_type::int_,\n                column_type::float_,\n                column_type::char_,\n                column_type::int_,\n                column_type::date,\n                column_type::double_,\n            })\n        }\n    };\n    // clang-format on\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Allocate exactly what is expected, to facilitate tooling for overrun detection\n            std::unique_ptr<field_view[]> actual{new field_view[tc.expected.size()]};\n            span<field_view> actual_span{actual.get(), tc.expected.size()};\n\n            auto err = deserialize_row(tc.encoding, tc.serialized, tc.meta, actual_span);\n\n            BOOST_TEST_REQUIRE(err == error_code());\n            std::vector<field_view> actual_vec{actual_span.begin(), actual_span.end()};\n            BOOST_TEST(actual_vec == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_row_error)\n{\n    struct\n    {\n        const char* name;\n        resultset_encoding encoding;\n        deserialization_buffer serialized;\n        error_code expected;\n        std::vector<metadata> meta;\n    } test_cases[] = {\n        // clang-format off\n        // text\n        {\n            \"text_no_space_string_single\",\n            resultset_encoding::text,\n            {0x02, 0x00},\n            client_errc::incomplete_message,\n            create_metas({ column_type::smallint })\n        },\n        {\n            \"text_no_space_string_final\",\n            resultset_encoding::text,\n            {0x01, 0x35, 0x02, 0x35},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint, column_type::smallint }),\n        },\n        {\n            \"text_no_space_null_single\",\n            resultset_encoding::text,\n            {},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"text_no_space_null_final\",\n            resultset_encoding::text,\n            {0xfb},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint, column_type::tinyint }),\n        },\n        {\n            \"text_extra_bytes\",\n            resultset_encoding::text,\n            {0x01, 0x35, 0xfb, 0x00},\n            client_errc::extra_bytes,\n            create_metas({ column_type::tinyint, column_type::tinyint })\n        },\n        {\n            \"text_contained_value_error_single\",\n            resultset_encoding::text,\n            {0x01, 0x00},\n            client_errc::protocol_value_error,\n            create_metas({ column_type::date })\n        },\n        {\n            \"text_contained_value_error_middle\",\n            resultset_encoding::text,\n            {0xfb, 0x01, 0x00, 0xfb},\n            client_errc::protocol_value_error,\n            create_metas({ column_type::date, column_type::date, column_type::date })\n        },\n        {\n            \"text_row_for_empty_meta\",\n            resultset_encoding::text,\n            {0xfb, 0x01, 0x00, 0xfb},\n            client_errc::extra_bytes,\n            {}\n        },\n\n        // binary\n        {\n            \"binary_no_space_null_bitmap_1\",\n            resultset_encoding::binary,\n            {0x00},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"binary_no_space_null_bitmap_2\",\n            resultset_encoding::binary,\n            {0x00, 0xfc},\n            client_errc::incomplete_message,\n            std::vector<metadata>(7, create_meta(column_type::tinyint))\n        },\n        {\n            \"binary_no_space_value_single\",\n            resultset_encoding::binary,\n            {0x00, 0x00},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"binary_no_space_value_last\",\n            resultset_encoding::binary,\n            {0x00, 0x00, 0x01},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint, column_type::tinyint })\n        },\n        {\n            \"binary_no_space_value_middle\",\n            resultset_encoding::binary,\n            {0x00, 0x00, 0x01},\n            client_errc::incomplete_message,\n            create_metas({ column_type::tinyint, column_type::tinyint, column_type::tinyint })\n        },\n        {\n            \"binary_extra_bytes\",\n            resultset_encoding::binary,\n            {0x00, 0x00, 0x01, 0x02},\n            client_errc::extra_bytes,\n            create_metas({ column_type::tinyint })\n        },\n        {\n            \"binary_row_for_empty_meta\",\n            resultset_encoding::binary,\n            {0xfb, 0x01, 0x00, 0xfb},\n            client_errc::extra_bytes,\n            {}\n        },\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Allocate exactly what is expected, to facilitate tooling for overrun detection\n            std::unique_ptr<field_view[]> actual{new field_view[tc.meta.size()]};\n            span<field_view> actual_span{actual.get(), tc.meta.size()};\n\n            auto err = deserialize_row(tc.encoding, tc.serialized, tc.meta, actual_span);\n\n            BOOST_TEST(err == tc.expected);\n        }\n    }\n}\n\n//\n// server hello\n//\nBOOST_AUTO_TEST_CASE(deserialize_server_hello_impl_success)\n{\n    // Data\n    constexpr std::uint8_t auth_plugin_data[] = {0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f, 0x03, 0x5a,\n                                                 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62};\n\n    constexpr auto caps = capabilities::long_password | capabilities::found_rows | capabilities::long_flag |\n                          capabilities::connect_with_db | capabilities::no_schema | capabilities::compress |\n                          capabilities::odbc | capabilities::local_files | capabilities::ignore_space |\n                          capabilities::protocol_41 | capabilities::interactive |\n                          capabilities::ignore_sigpipe | capabilities::transactions |\n                          capabilities::reserved |           // old flag, but set in this frame\n                          capabilities::secure_connection |  // old flag, but set in this frame\n                          capabilities::multi_statements | capabilities::multi_results |\n                          capabilities::ps_multi_results | capabilities::plugin_auth |\n                          capabilities::connect_attrs | capabilities::plugin_auth_lenenc_data |\n                          capabilities::can_handle_expired_passwords | capabilities::session_track |\n                          capabilities::deprecate_eof | capabilities::remember_options;\n\n    deserialization_buffer serialized{0x35, 0x2e, 0x37, 0x2e, 0x32, 0x37, 0x2d, 0x30, 0x75, 0x62, 0x75, 0x6e,\n                                      0x74, 0x75, 0x30, 0x2e, 0x31, 0x39, 0x2e, 0x30, 0x34, 0x2e, 0x31, 0x00,\n                                      0x02, 0x00, 0x00, 0x00, 0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n                                      0x00, 0xff, 0xf7, 0x08, 0x02, 0x00, 0xff, 0x81, 0x15, 0x00, 0x00, 0x00,\n                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5a, 0x74, 0x05, 0x28,\n                                      0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62, 0x00, 0x6d, 0x79, 0x73, 0x71,\n                                      0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73,\n                                      0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};\n\n    // Deserialize\n    server_hello actual{};\n    auto err = deserialize_server_hello_impl(serialized, actual);\n\n    // No error\n    BOOST_TEST_REQUIRE(err == error_code());\n\n    // Actual value\n    BOOST_TEST(actual.server == db_flavor::mysql);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(actual.auth_plugin_data, auth_plugin_data);\n    BOOST_TEST(actual.server_capabilities == caps);\n    BOOST_TEST(actual.connection_id == 2u);\n    BOOST_TEST(actual.auth_plugin_name == \"mysql_native_password\");\n\n    // TODO: mysql8, mariadb, edge case where auth plugin length is < 13\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_server_hello_impl_error)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer serialized;\n        error_code expected_err;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"error_server_version\",\n            {0x10, 0x11}, // no NULL-terminator\n            client_errc::incomplete_message\n        },  \n        {\n            \"error_connection_id\",\n            {0x2e, 0x31, 0x00,\n            0x02},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_auth_plugin_data_1\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_auth_plugin_data_filler\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_capability_flags_low\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_character_set\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_status_flags\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08,\n            0x02},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_capability_flags_high\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08,\n            0x02, 0x00,\n            0xff},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_auth_plugin_data_length\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08,\n            0x02, 0x00,\n            0xff, 0x81},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_reserved\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08,\n            0x02, 0x00,\n            0xff, 0x81,\n            0x15,\n            0x00, 0x00},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_auth_plugin_data_2\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08, // charset\n            0x02, 0x00,\n            0xff, 0x81, // caps high\n            0x15, // auth plugin data len\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved\n            // plugin data 2 has 1 byte less\n            0x03, 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62},\n            client_errc::incomplete_message\n        },\n        {\n            \"error_auth_plugin_name\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08, // charset\n            0x02, 0x00,\n            0xff, 0x81, // caps high\n            0x15, // auth plugin data len\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved\n            0x03, 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62, 0x00, // plugin data 2\n            // plugin name\n            0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74,\n            0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64}, // no NULL terminator\n            client_errc::incomplete_message\n        },\n        {\n            \"no_plugin_auth_capability\",\n            {0x2e, 0x31, 0x00,\n            0x02, 0x00, 0x00, 0x00,\n            0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f,\n            0x00,\n            0xff, 0xf7,\n            0x08, // charset\n            0x02, 0x00,\n            0xf7, 0x81, // caps high - no CLIENT_PLUGIN_AUTH\n            0x00, // auth plugin data len\n            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved\n            0x03, 0x5a, 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62, 0x00, // plugin data 2\n            },\n            client_errc::server_unsupported\n        }\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            server_hello value{};\n            auto err = deserialize_server_hello_impl(tc.serialized, value);\n            BOOST_TEST(err == tc.expected_err);\n        }\n    }\n}\n\n//\n// deserialize_server_hello\n//\nBOOST_AUTO_TEST_CASE(deserialize_server_hello_success)\n{\n    // Data\n    constexpr std::uint8_t auth_plugin_data[] = {0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70, 0x2f, 0x03, 0x5a,\n                                                 0x74, 0x05, 0x28, 0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62};\n\n    constexpr auto caps = capabilities::long_password | capabilities::found_rows | capabilities::long_flag |\n                          capabilities::connect_with_db | capabilities::no_schema | capabilities::compress |\n                          capabilities::odbc | capabilities::local_files | capabilities::ignore_space |\n                          capabilities::protocol_41 | capabilities::interactive |\n                          capabilities::ignore_sigpipe | capabilities::transactions |\n                          capabilities::reserved |           // old flag, but set in this frame\n                          capabilities::secure_connection |  // old flag, but set in this frame\n                          capabilities::multi_statements | capabilities::multi_results |\n                          capabilities::ps_multi_results | capabilities::plugin_auth |\n                          capabilities::connect_attrs | capabilities::plugin_auth_lenenc_data |\n                          capabilities::can_handle_expired_passwords | capabilities::session_track |\n                          capabilities::deprecate_eof | capabilities::remember_options;\n\n    deserialization_buffer serialized{0x0a, 0x35, 0x2e, 0x37, 0x2e, 0x32, 0x37, 0x2d, 0x30, 0x75, 0x62, 0x75,\n                                      0x6e, 0x74, 0x75, 0x30, 0x2e, 0x31, 0x39, 0x2e, 0x30, 0x34, 0x2e, 0x31,\n                                      0x00, 0x02, 0x00, 0x00, 0x00, 0x52, 0x1a, 0x50, 0x3a, 0x4b, 0x12, 0x70,\n                                      0x2f, 0x00, 0xff, 0xf7, 0x08, 0x02, 0x00, 0xff, 0x81, 0x15, 0x00, 0x00,\n                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5a, 0x74, 0x05,\n                                      0x28, 0x2b, 0x7f, 0x21, 0x43, 0x4a, 0x21, 0x62, 0x00, 0x6d, 0x79, 0x73,\n                                      0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61,\n                                      0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00};\n\n    // Deserialize\n    server_hello actual{};\n    diagnostics diag;\n    auto err = deserialize_server_hello(serialized, actual, diag);\n\n    // No error\n    BOOST_TEST_REQUIRE(err == error_code());\n    BOOST_TEST(diag == diagnostics());\n\n    // Actual value\n    BOOST_TEST(actual.server == db_flavor::mysql);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(actual.auth_plugin_data, auth_plugin_data);\n    BOOST_TEST(actual.server_capabilities == caps);\n    BOOST_TEST(actual.connection_id == 2u);\n    BOOST_TEST(actual.auth_plugin_name == \"mysql_native_password\");\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_server_hello_error)\n{\n    struct\n    {\n        const char* name;\n        deserialization_buffer serialized;\n        error_code expected_err;\n        diagnostics expected_diag;\n    } test_cases[] = {\n        // Regression check: we were failing to deserialize this correctly because of\n        // missing sql_state\n        {\"err_packet\",\n         {0xff, 0x10, 0x04, 0x54, 0x6f, 0x6f, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20,\n          0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73},\n         common_server_errc::er_con_count_error,\n         create_server_diag(\"Too many connections\")},\n        {\"handshake_v9\",\n         {0x09, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00},\n         client_errc::server_unsupported,\n         {}},\n        {\"bad_server_hello\", {0x0a, 0x11}, client_errc::incomplete_message, {}},\n        {\"unknown_header\", {0xab, 0x00, 0x01}, client_errc::protocol_value_error, {}},\n        {\"empty_message\", {}, client_errc::incomplete_message, {}},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            server_hello msg{};\n            diagnostics diag;\n\n            // Deserialize\n            auto err = deserialize_server_hello(tc.serialized, msg, diag);\n\n            // Check\n            BOOST_TEST(err == tc.expected_err);\n            BOOST_TEST(diag == tc.expected_diag);\n        }\n    }\n}\n\n//\n// auth switch\n//\nBOOST_AUTO_TEST_CASE(deserialize_auth_switch_success)\n{\n    // Data\n    constexpr std::uint8_t auth_data[] = {0x49, 0x49, 0x7e, 0x51, 0x5d, 0x1f, 0x19, 0x6a, 0x0f, 0x5a,\n                                          0x63, 0x15, 0x3e, 0x28, 0x31, 0x3e, 0x3c, 0x79, 0x09, 0x7c};\n\n    deserialization_buffer serialized{0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76,\n                                      0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00,\n                                      0x49, 0x49, 0x7e, 0x51, 0x5d, 0x1f, 0x19, 0x6a, 0x0f, 0x5a, 0x63,\n                                      0x15, 0x3e, 0x28, 0x31, 0x3e, 0x3c, 0x79, 0x09, 0x7c, 0x00};\n\n    // Deserialize\n    auth_switch actual{};\n    auto err = deserialize_auth_switch(serialized, actual);\n\n    // No error\n    BOOST_TEST_REQUIRE(err == error_code());\n\n    // Actual value\n    BOOST_TEST(actual.plugin_name == \"mysql_native_password\");\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(actual.auth_data, auth_data);\n\n    // TODO: error in plugin_name, extra bytes (?)\n    // TODO: edge case where plugin data is empty or doesn't end in a 0\n}\n\n//\n// handshake server response\n//\nBOOST_AUTO_TEST_CASE(deserialize_handshake_server_response_more_data)\n{\n    constexpr std::uint8_t auth_data[] = {0x61, 0x62, 0x63};\n\n    deserialization_buffer serialized{0x01, 0x61, 0x62, 0x63};\n\n    // Deserialize\n    diagnostics diag;\n    auto response = deserialize_handshake_server_response(serialized, db_flavor::mysql, diag);\n\n    // Actual value\n    BOOST_TEST_REQUIRE(response.type == handshake_server_response::type_t::auth_more_data);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(response.data.more_data, auth_data);\n}\n// TODO: ok packet\n// TODO: error packet\n// TODO: auth switch\n// TODO: error in message type, unknown message type, bad OK packet, bad auth switch\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/protocol/deserialization_context.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstdint>\n#include <limits>\n\n#include \"operators.hpp\"\n\nusing namespace boost::mysql::detail;\nusing boost::mysql::client_errc;\nusing boost::mysql::error_code;\n\nBOOST_AUTO_TEST_SUITE(test_deserialization_context)\n\nBOOST_AUTO_TEST_CASE(first_last_size)\n{\n    const std::array<std::uint8_t, 5> buff{\n        {1, 2, 3, 4, 5}\n    };\n    deserialization_context ctx(buff);\n\n    BOOST_TEST(ctx.first() == buff.data());\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 5u);\n}\n\nBOOST_AUTO_TEST_CASE(advance)\n{\n    const std::array<std::uint8_t, 5> buff{\n        {1, 2, 3, 4, 5}\n    };\n    deserialization_context ctx(buff);\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.first() == buff.data() + 1u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 4u);\n\n    ctx.advance(0);\n    BOOST_TEST(ctx.first() == buff.data() + 1u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 4u);\n\n    ctx.advance(3);\n    BOOST_TEST(ctx.first() == buff.data() + 4u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 1u);\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.first() == buff.data() + 5u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(rewind)\n{\n    const std::array<std::uint8_t, 5> buff{\n        {1, 2, 3, 4, 5}\n    };\n    deserialization_context ctx(buff);\n\n    ctx.advance(4);\n    BOOST_TEST(ctx.first() == buff.data() + 4u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 1u);\n\n    ctx.rewind(2);\n    BOOST_TEST(ctx.first() == buff.data() + 2u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 3u);\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.first() == buff.data() + 3u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 2u);\n\n    ctx.rewind(0);\n    BOOST_TEST(ctx.first() == buff.data() + 3u);\n    BOOST_TEST(ctx.last() == buff.data() + 5u);\n    BOOST_TEST(ctx.size() == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(enough_size)\n{\n    const std::array<std::uint8_t, 5> buff{\n        {1, 2, 3, 4, 5}\n    };\n    deserialization_context ctx(buff);\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.enough_size(0));\n    BOOST_TEST(ctx.enough_size(1));\n    BOOST_TEST(ctx.enough_size(3));\n    BOOST_TEST(ctx.enough_size(4));\n    BOOST_TEST(!ctx.enough_size(5));\n    BOOST_TEST(!ctx.enough_size((std::numeric_limits<std::size_t>::max)()));\n\n    ctx.advance(2);\n    BOOST_TEST(ctx.enough_size(2));\n    BOOST_TEST(!ctx.enough_size(3));\n\n    ctx.advance(2);\n    BOOST_TEST(ctx.enough_size(0));\n    BOOST_TEST(!ctx.enough_size(1));\n}\n\nBOOST_AUTO_TEST_CASE(get_string)\n{\n    const std::array<std::uint8_t, 5> buff{\n        {0x61, 0x62, 0x63, 0x64, 0x65}\n    };\n    deserialization_context ctx(buff);\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.get_string(0) == \"\");\n    BOOST_TEST(ctx.get_string(1) == \"b\");\n    BOOST_TEST(ctx.get_string(2) == \"bc\");\n    BOOST_TEST(ctx.get_string(4) == \"bcde\");\n\n    ctx.advance(2);\n    BOOST_TEST(ctx.get_string(1) == \"d\");\n    BOOST_TEST(ctx.get_string(2) == \"de\");\n\n    ctx.advance(2);\n    BOOST_TEST(ctx.get_string(0) == \"\");\n}\n\nBOOST_AUTO_TEST_CASE(check_extra_bytes)\n{\n    const std::array<std::uint8_t, 5> buff{\n        {1, 2, 3, 4, 5}\n    };\n    deserialization_context ctx(buff);\n\n    BOOST_TEST(ctx.check_extra_bytes() == error_code(client_errc::extra_bytes));\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.check_extra_bytes() == error_code(client_errc::extra_bytes));\n\n    ctx.advance(3);\n    BOOST_TEST(ctx.check_extra_bytes() == error_code(client_errc::extra_bytes));\n\n    ctx.advance(1);\n    BOOST_TEST(ctx.check_extra_bytes() == error_code());\n}\n\n// Spotcheck: everything works even if an empty span is passed\nBOOST_AUTO_TEST_CASE(no_data)\n{\n    deserialization_context ctx({});\n    BOOST_TEST(ctx.first() == nullptr);\n    BOOST_TEST(ctx.last() == nullptr);\n    BOOST_TEST(ctx.size() == 0u);\n    BOOST_TEST(ctx.enough_size(0u));\n    BOOST_TEST(!ctx.enough_size(1u));\n    BOOST_TEST(ctx.check_extra_bytes() == error_code());\n}\n\n// Spotcheck: chain deserialize stops if one of the operations fails\nBOOST_AUTO_TEST_CASE(chain_deserialize_error)\n{\n    // A Deserializable that keeps track of calls and allows setting the return value\n    struct mock_deserializable\n    {\n        deserialize_errc will_return;\n        bool called{false};\n\n        mock_deserializable(deserialize_errc e) : will_return(e) {}\n\n        deserialize_errc deserialize(deserialization_context&)\n        {\n            called = true;\n            return will_return;\n        }\n    };\n\n    // Setup\n    const std::array<std::uint8_t, 5> buff{\n        {1, 2, 3, 4, 5}\n    };\n    deserialization_context ctx(buff);\n    mock_deserializable values[] = {\n        {deserialize_errc::ok},\n        {deserialize_errc::incomplete_message},\n        {deserialize_errc::ok}\n    };\n\n    // Call the function\n    auto err = ctx.deserialize(values[0], values[1], values[2]);\n\n    // Validate\n    BOOST_TEST(err == deserialize_errc::incomplete_message);\n    BOOST_TEST(values[0].called);\n    BOOST_TEST(values[1].called);\n    BOOST_TEST(!values[2].called);\n}\n\n// going from deserialize_errc to error code\nBOOST_AUTO_TEST_CASE(to_error_code_)\n{\n    BOOST_TEST(to_error_code(deserialize_errc::ok) == error_code());\n    BOOST_TEST(\n        to_error_code(deserialize_errc::incomplete_message) == error_code(client_errc::incomplete_message)\n    );\n    BOOST_TEST(\n        to_error_code(deserialize_errc::protocol_value_error) == error_code(client_errc::protocol_value_error)\n    );\n    BOOST_TEST(\n        to_error_code(deserialize_errc::server_unsupported) == error_code(client_errc::server_unsupported)\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/protocol/frame_header.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/protocol/frame_header.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <memory>\n\n#include \"serialization_test.hpp\"\n#include \"test_common/assert_buffer_equals.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nusing boost::span;\n\nBOOST_AUTO_TEST_CASE(test_frame_header)\n{\n    struct\n    {\n        const char* name;\n        frame_header header;\n        std::array<std::uint8_t, 4> serialized;\n    } test_cases[] = {\n        {\"small_packet_seqnum_0\",     {3, 0},           {{0x03, 0x00, 0x00, 0x00}}},\n        {\"small_packet_seqnum_not_0\", {9, 2},           {{0x09, 0x00, 0x00, 0x02}}},\n        {\"big_packet_seqnum_0\",       {0xcacbcc, 0xfa}, {{0xcc, 0xcb, 0xca, 0xfa}}},\n        {\"max_packet_max_seqnum\",     {0xffffff, 0xff}, {{0xff, 0xff, 0xff, 0xff}}}\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name << \" serialization\")\n        {\n            std::unique_ptr<std::uint8_t[]> buff{new std::uint8_t[4]};\n            span<std::uint8_t, frame_header_size> buff_span(buff.get(), 4);\n            serialize_frame_header(buff_span, tc.header);\n            BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff_span, tc.serialized);\n        }\n        BOOST_TEST_CONTEXT(tc.name << \" deserialization\")\n        {\n            deserialization_buffer buffer(tc.serialized);\n            auto actual = deserialize_frame_header(span<const std::uint8_t, frame_header_size>(buffer));\n            BOOST_TEST(actual.size == tc.header.size);\n            BOOST_TEST(actual.sequence_number == tc.header.sequence_number);\n        }\n    }\n}\n"
  },
  {
    "path": "test/unit/test/protocol/null_bitmap.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/field_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstdint>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::unit_test;\nusing namespace boost::mysql::test;\nusing boost::mysql::field_view;\n\nBOOST_AUTO_TEST_SUITE(test_null_bitmap)\n\nBOOST_AUTO_TEST_SUITE(parser)\n\nBOOST_AUTO_TEST_CASE(byte_count)\n{\n    struct\n    {\n        std::size_t num_fields;\n        std::size_t expected;\n    } test_cases[] = {\n        {0,  1},\n        {1,  1},\n        {2,  1},\n        {3,  1},\n        {4,  1},\n        {5,  1},\n        {6,  1},\n        {7,  2},\n        {8,  2},\n        {9,  2},\n        {10, 2},\n        {11, 2},\n        {12, 2},\n        {13, 2},\n        {14, 2},\n        {15, 3},\n        {16, 3},\n        {17, 3},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.num_fields)\n        {\n            null_bitmap_parser parser{tc.num_fields};\n            BOOST_TEST(parser.byte_count() == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(is_null_coverage)\n{\n    // Given a null bitmap with 17 fields, and the following buffer, vary the field offset\n    // 0b10110100, 0b11111111, 0b00000000\n    struct\n    {\n        std::size_t pos;\n        bool expected;\n    } test_cases[] = {\n        {0,  true },\n        {1,  false},\n        {2,  true },\n        {3,  true },\n        {4,  false},\n        {5,  true },\n        {6,  true },\n        {7,  true },\n        {8,  true },\n        {9,  true },\n        {10, true },\n        {11, true },\n        {12, true },\n        {13, true },\n        {14, false},\n        {15, false},\n        {16, false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.pos)\n        {\n            const std::array<std::uint8_t, 3> buffer{\n                {0xb4, 0xff, 0x00}\n            };\n            null_bitmap_parser parser{17};  // 17 fields\n            bool actual = parser.is_null(buffer.data(), tc.pos);\n            BOOST_TEST(actual == tc.expected);\n        }\n    }\n}\n\n// spotcheck: we handle the offset correctly, ignoring the first two bits\nBOOST_AUTO_TEST_CASE(is_null_first_bit)\n{\n    struct\n    {\n        std::uint8_t buffer;\n        bool expected;\n    } test_cases[] = {\n        {0x00, false},\n        {0x01, false},\n        {0x02, false},\n        {0x03, false},\n        {0x04, true },\n        {0x05, true },\n        {0x06, true },\n        {0x07, true },\n        {0x08, false},\n        {0x09, false},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.buffer)\n        {\n            null_bitmap_parser parser{1};  // 1 field\n            bool actual = parser.is_null(&tc.buffer, 0);\n            BOOST_TEST(actual == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(generator)\n\nBOOST_AUTO_TEST_CASE(coverage)\n{\n    // Creates a generator and calls it until exhausted\n    auto gen_null_bitmap = [](boost::span<const field_view> params) {\n        std::vector<std::uint8_t> res;\n        null_bitmap_generator gen(params);\n        while (!gen.done())\n            res.push_back(gen.next());\n        return res;\n    };\n\n    struct\n    {\n        const char* name;\n        std::vector<field_view> params;\n        std::vector<std::uint8_t> expected;\n    } test_cases[] = {\n        // All combinations for up to 2 values\n        {\"empty\", {}, {}},\n        {\"N\", make_fv_vector(nullptr), {0x01}},\n        {\"V\", make_fv_vector(1), {0x00}},\n        {\"NV\", make_fv_vector(nullptr, 1), {0x01}},\n        {\"NN\", make_fv_vector(nullptr, nullptr), {0x03}},\n        {\"VV\", make_fv_vector(1, 1), {0x00}},\n        {\"VN\", make_fv_vector(1, nullptr), {0x02}},\n\n        // Last value null - checking we set the right bit\n        {\"VVN\", make_fv_vector(1, 1, nullptr), {0x04}},\n        {\"VVVN\", make_fv_vector(1, 1, 1, nullptr), {0x08}},\n        {\"VVVVN\", make_fv_vector(1, 1, 1, 1, nullptr), {0x10}},\n        {\"VVVVVN\", make_fv_vector(1, 1, 1, 1, 1, nullptr), {0x20}},\n        {\"VVVVVVN\", make_fv_vector(1, 1, 1, 1, 1, 1, nullptr), {0x40}},\n        {\"VVVVVVVN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, nullptr), {0x80}},\n        {\"VVVVVVVV_N\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x01}},\n        {\"VVVVVVVV_VN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x02}},\n        {\"VVVVVVVV_VVN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x04}},\n        {\"VVVVVVVV_VVVN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x08}},\n        {\"VVVVVVVV_VVVVN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x10}},\n        {\"VVVVVVVV_VVVVVN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x20}},\n        {\"VVVVVVVV_VVVVVVN\", make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr), {0x00, 0x40}},\n        {\"VVVVVVVV_VVVVVVVN\",\n         make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr),\n         {0x00, 0x80}},\n        {\"VVVVVVVV_VVVVVVVV_N\",\n         make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, nullptr),\n         {0x00, 0x00, 0x01}},\n\n        // Some arbitrary combinations\n        {\"VNVVNVVN\", make_fv_vector(1, nullptr, 1, 1, nullptr, 1, 1, nullptr), {0x92}},\n        {\"NVVVVNVV_VVNVN\",\n         make_fv_vector(nullptr, 1, 1, 1, 1, nullptr, 1, 1, 1, 1, nullptr, 1, nullptr),\n         {0x21, 0x14}},\n        {\"VVVVVVVV_VVVVVVVV_V\",\n         make_fv_vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),\n         {0x00, 0x00, 0x00}},\n        {\"NNNNNNNN_NNNNNNNN_NNN\", std::vector<field_view>(19, field_view()), {0xff, 0xff, 0x07}},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            auto actual = gen_null_bitmap(tc.params);\n            BOOST_MYSQL_ASSERT_BUFFER_EQUALS(actual, tc.expected);\n        }\n    }\n}\n\n// Spotcheck: generating step-by-step yields the expected results\nBOOST_AUTO_TEST_CASE(step_by_step)\n{\n    // Setup\n    auto params = make_fv_arr(\n        // byte 1\n        nullptr,\n        1,\n        1,\n        1,\n        nullptr,\n        nullptr,\n        1,\n        1,\n\n        // byte 2\n        1,\n        nullptr,\n        nullptr,\n        1,\n        1,\n        1,\n        1,\n        nullptr,\n\n        // byte 3\n        1,\n        1,\n        1,\n        nullptr,\n        1,\n        nullptr\n    );\n    null_bitmap_generator gen(params);\n\n    // Initiates as not done\n    BOOST_TEST(!gen.done());\n\n    // Generate first byte\n    BOOST_TEST(gen.next() == 0x31u);\n    BOOST_TEST(!gen.done());\n\n    // Generate second byte\n    BOOST_TEST(gen.next() == 0x86u);\n    BOOST_TEST(!gen.done());\n\n    // Generate last byte\n    BOOST_TEST(gen.next() == 0x28u);\n    BOOST_TEST(gen.done());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()  // test_null_bitmap_traits\n"
  },
  {
    "path": "test/unit/test/protocol/operators.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_PROTOCOL_OPERATORS_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_PROTOCOL_OPERATORS_HPP\n\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n\n#include <cstring>\n#include <ostream>\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// deserialize_errc\ninline std::ostream& operator<<(std::ostream& os, deserialize_errc v)\n{\n    switch (v)\n    {\n    case deserialize_errc::ok: return os << \"ok\";\n    case deserialize_errc::incomplete_message: return os << \"incomplete_message\";\n    case deserialize_errc::protocol_value_error: return os << \"protocol_value_error\";\n    case deserialize_errc::server_unsupported: return os << \"server_unsupported\";\n    default: return os << \"unknown\";\n    }\n}\n\n// int_holder\ntemplate <class T>\ninline bool operator==(int_holder<T> lhs, int_holder<T> rhs) noexcept\n{\n    return lhs.value == rhs.value;\n}\n\ntemplate <class T>\ninline std::ostream& operator<<(std::ostream& os, int_holder<T> value)\n{\n    return os << value.value;\n}\n\n// int3\ninline bool operator==(int3 lhs, int3 rhs) noexcept { return lhs.value == rhs.value; }\ninline std::ostream& operator<<(std::ostream& os, int3 value) { return os << value.value; }\n\n// int_lenenc\ninline bool operator==(int_lenenc lhs, int_lenenc rhs) noexcept { return lhs.value == rhs.value; }\ninline std::ostream& operator<<(std::ostream& os, int_lenenc value) { return os << value.value; }\n\n// string_fixed\ntemplate <std::size_t N>\ninline bool operator==(string_fixed<N> lhs, string_fixed<N> rhs) noexcept\n{\n    return std::memcmp(lhs.value.data(), rhs.value.data(), N) == 0;\n}\n\ntemplate <std::size_t N>\ninline std::ostream& operator<<(std::ostream& os, string_fixed<N> value)\n{\n    return os << string_view(value.value.data(), N);\n}\n\n// string_null\ninline bool operator==(string_null lhs, string_null rhs) noexcept { return lhs.value == rhs.value; }\ninline std::ostream& operator<<(std::ostream& os, string_null value) { return os << value.value; }\n\n// string_lenenc\ninline bool operator==(string_lenenc lhs, string_lenenc rhs) noexcept { return lhs.value == rhs.value; }\ninline std::ostream& operator<<(std::ostream& os, string_lenenc value) { return os << value.value; }\n\n// string_eof\ninline bool operator==(string_eof lhs, string_eof rhs) noexcept { return lhs.value == rhs.value; }\ninline std::ostream& operator<<(std::ostream& os, string_eof value) { return os << value.value; }\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/protocol/protocol_field_type.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>\n\n#include <boost/test/unit_test.hpp>\n\nusing namespace boost::mysql::detail;\nnamespace collations = boost::mysql::mysql_collations;\nusing boost::mysql::column_type;\n\nnamespace boost {\nnamespace mysql {\nnamespace detail {\n\n// protocol_field_type\ninline std::ostream& operator<<(std::ostream& os, protocol_field_type t)\n{\n    switch (t)\n    {\n    case protocol_field_type::decimal: return os << \"decimal\";\n    case protocol_field_type::tiny: return os << \"tiny\";\n    case protocol_field_type::short_: return os << \"short_\";\n    case protocol_field_type::long_: return os << \"long_\";\n    case protocol_field_type::float_: return os << \"float_\";\n    case protocol_field_type::double_: return os << \"double_\";\n    case protocol_field_type::null: return os << \"null\";\n    case protocol_field_type::timestamp: return os << \"timestamp\";\n    case protocol_field_type::longlong: return os << \"longlong\";\n    case protocol_field_type::int24: return os << \"int24\";\n    case protocol_field_type::date: return os << \"date\";\n    case protocol_field_type::time: return os << \"time\";\n    case protocol_field_type::datetime: return os << \"datetime\";\n    case protocol_field_type::year: return os << \"year\";\n    case protocol_field_type::varchar: return os << \"varchar\";\n    case protocol_field_type::bit: return os << \"bit\";\n    case protocol_field_type::newdecimal: return os << \"newdecimal\";\n    case protocol_field_type::enum_: return os << \"enum_\";\n    case protocol_field_type::set: return os << \"set\";\n    case protocol_field_type::tiny_blob: return os << \"tiny_blob\";\n    case protocol_field_type::medium_blob: return os << \"medium_blob\";\n    case protocol_field_type::long_blob: return os << \"long_blob\";\n    case protocol_field_type::blob: return os << \"blob\";\n    case protocol_field_type::var_string: return os << \"var_string\";\n    case protocol_field_type::string: return os << \"string\";\n    case protocol_field_type::geometry: return os << \"geometry\";\n    default: return os << \"unknown\";\n    }\n}\n\n}  // namespace detail\n}  // namespace mysql\n}  // namespace boost\n\nBOOST_AUTO_TEST_SUITE(test_protocol_field_type)\n\n// Tests edge cases not covered by database_types, where the DB sends\n// a protocol_field_type that is supposed not to be sent. Introduced due\n// to a bug with recent MariaDB versions that were sending medium_blob only\n// if you SELECT'ed TEXT variables\nBOOST_AUTO_TEST_CASE(compute_column_type_legacy_types)\n{\n    struct\n    {\n        const char* name;\n        protocol_field_type proto_type;\n        std::uint16_t flags;\n        std::uint16_t collation;\n        column_type expected;\n    } test_cases[] = {\n        {\"tiny_text\",      protocol_field_type::tiny_blob,   0, collations::utf8mb4_general_ci, column_type::text     },\n        {\"tiny_blob\",      protocol_field_type::tiny_blob,   0, collations::binary,             column_type::blob     },\n        {\"medium_text\",    protocol_field_type::medium_blob, 0, collations::utf8mb4_general_ci, column_type::text\n        },\n        {\"medium_blob\",    protocol_field_type::medium_blob, 0, collations::binary,             column_type::blob     },\n        {\"long_text\",      protocol_field_type::long_blob,   0, collations::utf8mb4_general_ci, column_type::text     },\n        {\"long_blob\",      protocol_field_type::long_blob,   0, collations::binary,             column_type::blob     },\n        {\"varchar_string\",\n         protocol_field_type::varchar,\n         0,                                                     collations::utf8mb4_general_ci,\n         column_type::varchar                                                                                         },\n        {\"varchar_binary\", protocol_field_type::varchar,     0, collations::binary,             column_type::varbinary},\n        {\"enum\",           protocol_field_type::enum_,       0, collations::utf8mb4_general_ci, column_type::enum_    },\n        {\"set\",            protocol_field_type::set,         0, collations::utf8mb4_general_ci, column_type::set      },\n        {\"null\",           protocol_field_type::null,        0, collations::binary,             column_type::unknown  },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            auto res = compute_column_type(tc.proto_type, tc.flags, tc.collation);\n            BOOST_TEST(res == tc.expected);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/protocol/protocol_types.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n#include <memory>\n\n#include \"operators.hpp\"\n#include \"serialization_test.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nusing boost::mysql::client_errc;\nusing boost::mysql::error_code;\nusing boost::mysql::string_view;\n\nBOOST_AUTO_TEST_SUITE(test_protocol_types)\n\ntemplate <std::size_t N>\nconst char* get_string_N()\n{\n    static std::string res(N, 'a');\n    return res.c_str();\n}\n\ntemplate <std::size_t N>\nstring_fixed<N> makesfixed(const char (&value)[N + 1])\n{\n    static_assert(N >= 1, \"Expected a C-array literal\");\n    string_fixed<N> res;\n    std::memcpy(res.value.data(), value, N);\n    return res;\n}\n\nclass test_case\n{\n    const char* name_;\n\npublic:\n    test_case(const char* name) noexcept : name_(name) {}\n    virtual ~test_case() {}\n    virtual void serialize_test() = 0;\n    virtual void deserialize_test() = 0;\n    virtual void deserialize_space_test() = 0;\n    virtual void deserialize_not_enough_space_test() = 0;\n    const char* name() const noexcept { return name_; }\n};\n\ntemplate <class T>\nclass test_case_impl final : public test_case\n{\n    T value_;\n    std::vector<std::uint8_t> serialized_;\n    bool do_space_;\n\npublic:\n    test_case_impl(const char* name, T value, std::vector<std::uint8_t> serialized, bool do_space = true)\n        : test_case(name), value_(value), serialized_(std::move(serialized)), do_space_(do_space)\n    {\n    }\n    void serialize_test() override final { do_serialize_test(value_, serialized_); }\n    void deserialize_test() override final { do_deserialize_test(value_, serialized_); }\n    void deserialize_space_test() override final\n    {\n        if (do_space_)\n            do_deserialize_extra_space_test(value_, serialized_);\n    }\n    void deserialize_not_enough_space_test() override final\n    {\n        if (do_space_)\n            do_deserialize_not_enough_space_test<T>(serialized_);\n    }\n};\n\ntemplate <class T>\nstd::shared_ptr<test_case> make_test(\n    const char* name,\n    T value,\n    std::vector<std::uint8_t> serialized,\n    bool do_space = true\n)\n{\n    return std::make_shared<test_case_impl<T>>(name, value, std::move(serialized), do_space);\n}\n\nstd::vector<std::shared_ptr<test_case>> make_all_cases()\n{\n    return {\n        // basic integers\n        make_test(\"int1\", int1{0xff}, {0xff}),\n        make_test(\"int2\", int2{0xfeff}, {0xff, 0xfe}),\n        make_test(\"int3\", int3{0xfdfeff}, {0xff, 0xfe, 0xfd}),\n        make_test(\"int4\", int4{0xfcfdfeff}, {0xff, 0xfe, 0xfd, 0xfc}),\n        make_test(\"int8\", int8{0xf8f9fafbfcfdfeff}, {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}),\n        make_test(\"sint1_positive\", int_holder<std::int8_t>{0x01}, {0x01}),\n        make_test(\"sint1_negative\", int_holder<std::int8_t>{-1}, {0xff}),\n        make_test(\"sint2_positive\", int_holder<std::int16_t>{0x0201}, {0x01, 0x02}),\n        make_test(\"sint2_negative\", int_holder<std::int16_t>{-0x101}, {0xff, 0xfe}),\n        make_test(\"sint4_positive\", int_holder<std::int32_t>{0x04030201}, {0x01, 0x02, 0x03, 0x04}),\n        make_test(\"sint4_negative\", int_holder<std::int32_t>{-0x3020101}, {0xff, 0xfe, 0xfd, 0xfc}),\n        make_test(\n            \"sint8_positive\",\n            sint8{0x0807060504030201},\n            {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}\n        ),\n        make_test(\n            \"sint8_negative\",\n            sint8{-0x0706050403020101},\n            {0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}\n        ),\n\n        // int_lenenc\n        make_test(\"int_lenenc_1_byte_regular\", int_lenenc{1}, {0x01}),\n        make_test(\"int_lenenc_1_byte_max\", int_lenenc{250}, {0xfa}),\n        make_test(\"int_lenenc_2_bytes_regular\", int_lenenc{0xfeb7}, {0xfc, 0xb7, 0xfe}),\n        make_test(\"int_lenenc_2_bytes_max\", int_lenenc{0xffff}, {0xfc, 0xff, 0xff}),\n        make_test(\"int_lenenc_3_bytes_regular\", int_lenenc{0xa0feff}, {0xfd, 0xff, 0xfe, 0xa0}),\n        make_test(\"int_lenenc_3_bytes_max\", int_lenenc{0xffffff}, {0xfd, 0xff, 0xff, 0xff}),\n        make_test(\n            \"int_lenenc_8_bytes_regular\",\n            int_lenenc{0xf8f9fafbfcfdfeff},\n            {0xfe, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}\n        ),\n        make_test(\n            \"int_lenenc_8_bytes_max\",\n            int_lenenc{0xffffffffffffffff},\n            {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}\n        ),\n\n        // string_fixed\n        make_test(\"4c_regular_characters\", makesfixed<4>(\"abde\"), {0x61, 0x62, 0x64, 0x65}),\n        make_test(\"3c_null_characters\", makesfixed<3>(\"\\0\\1a\"), {0x00, 0x01, 0x61}),\n        make_test(\"3c_utf8_characters\", string_fixed<3>{{{'\\xc3', '\\xb1', 'a'}}}, {0xc3, 0xb1, 0x61}),\n        make_test(\"1c_regular_characters\", makesfixed<1>(\"a\"), {0x61}),\n\n        // string_null\n        make_test(\"regular_characters\", string_null{\"abc\"}, {0x61, 0x62, 0x63, 0x00}),\n        make_test(\"utf8_characters\", string_null{\"\\xc3\\xb1\"}, {0xc3, 0xb1, 0x00}),\n        make_test(\"empty\", string_null{\"\"}, {0x00}),\n\n        // string_lenenc\n        make_test(\"empty\", string_lenenc{\"\"}, {0x00}),\n        make_test(\"1_byte_size_regular_characters\", string_lenenc{\"abc\"}, {0x03, 0x61, 0x62, 0x63}),\n        make_test(\"1_byte_size_null_characters\", string_lenenc{makesv(\"a\\0b\")}, {0x03, 0x61, 0x00, 0x62}),\n        make_test(\n            \"1_byte_size_max\",\n            string_lenenc{get_string_N<250>()},\n            concat({250}, std::vector<std::uint8_t>(250, 0x61))\n        ),\n        make_test(\n            \"2_byte_size_min\",\n            string_lenenc{get_string_N<251>()},\n            concat({0xfc, 251, 0}, std::vector<std::uint8_t>(251, 0x61))\n        ),\n        make_test(\n            \"2_byte_size_max\",\n            string_lenenc{get_string_N<0xffff>()},\n            concat({0xfc, 0xff, 0xff}, std::vector<std::uint8_t>(0xffff, 0x61))\n        ),\n        make_test(\n            \"3_byte_size_min\",\n            string_lenenc{get_string_N<0x10000>()},\n            concat({0xfd, 0x00, 0x00, 0x01}, std::vector<std::uint8_t>(0x10000, 0x61))\n        ),\n    };\n}\n\nstd::vector<std::shared_ptr<test_case>> all_cases()\n{\n    static auto res = make_all_cases();\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(serialize)\n{\n    for (const auto& sample : all_cases())\n    {\n        BOOST_TEST_CONTEXT(sample->name()) { sample->serialize_test(); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(deserialize)\n{\n    for (const auto& sample : all_cases())\n    {\n        BOOST_TEST_CONTEXT(sample->name()) { sample->deserialize_test(); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(deserialize_extra_space)\n{\n    for (const auto& sample : all_cases())\n    {\n        BOOST_TEST_CONTEXT(sample->name()) { sample->deserialize_space_test(); }\n    }\n}\nBOOST_AUTO_TEST_CASE(deserialize_not_enough_space)\n{\n    for (const auto& sample : all_cases())\n    {\n        BOOST_TEST_CONTEXT(sample->name()) { sample->deserialize_not_enough_space_test(); }\n    }\n}\n\n// string_eof can be serialized/deserialized, but is space sensitive, so extra space/not enough space tests\n// shouldn't be performed\nBOOST_AUTO_TEST_CASE(string_eof_)\n{\n    struct\n    {\n        const char* name;\n        string_eof value;\n        std::vector<std::uint8_t> serialized;\n    } test_cases[] = {\n        {\"regular_characters\", string_eof{\"abc\"},          {0x61, 0x62, 0x63}},\n        {\"null_characters\",    string_eof{makesv(\"a\\0b\")}, {0x61, 0x00, 0x62}},\n        {\"empty\",              string_eof{\"\"},             {}                },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name << \", serialization\") { do_serialize_test(tc.value, tc.serialized); }\n        BOOST_TEST_CONTEXT(tc.name << \", deserialization\") { do_deserialize_test(tc.value, tc.serialized); }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/protocol/serialization.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/serialization.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstdint>\n#include <vector>\n\n#include \"serialization_test.hpp\"\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/mock_message.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nnamespace collations = boost::mysql::mysql_collations;\nusing boost::span;\nusing boost::mysql::date;\nusing boost::mysql::datetime;\nusing boost::mysql::error_code;\nusing boost::mysql::field_view;\nusing boost::mysql::string_view;\n\nBOOST_AUTO_TEST_SUITE(test_serialization)\n\n// spotcheck: multi-frame messages handled correctly by serialize_top_level\nBOOST_AUTO_TEST_CASE(serialize_top_level_multiframe)\n{\n    constexpr std::size_t frame_size = 8u;\n    const std::array<std::uint8_t, 11> payload{\n        {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}\n    };\n    const std::vector<std::uint8_t> expected{80, 81, 82, 83, 85, 8, 0, 0, 42, 1, 2,  3,\n                                             4,  5,  6,  7,  8,  3, 0, 0, 43, 9, 10, 11};\n\n    std::vector<std::uint8_t> buff{80, 81, 82, 83, 85};\n    auto result = serialize_top_level(mock_message{payload}, buff, 42, 0xffff, frame_size);\n    BOOST_TEST(result.err == error_code());\n    BOOST_TEST(result.seqnum == 44u);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\n// spotcheck: max size correctly propagated\nBOOST_AUTO_TEST_CASE(serialize_top_level_error_max_size)\n{\n    const std::array<std::uint8_t, 11> payload{\n        {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}\n    };\n    std::vector<std::uint8_t> buff;\n    auto result = serialize_top_level(mock_message{payload}, buff, 42, 8u);\n    BOOST_TEST(result.err == boost::mysql::client_errc::max_buffer_size_exceeded);\n    BOOST_TEST(result.seqnum == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(quit)\n{\n    quit_command cmd;\n    const std::uint8_t serialized[] = {0x01};\n    do_serialize_test(cmd, serialized);\n}\n\nBOOST_AUTO_TEST_CASE(ping)\n{\n    ping_command cmd;\n    const std::uint8_t serialized[] = {0x0e};\n    do_serialize_test(cmd, serialized);\n}\n\nBOOST_AUTO_TEST_CASE(reset_connection)\n{\n    reset_connection_command cmd;\n    const std::uint8_t serialized[] = {0x1f};\n    do_serialize_test(cmd, serialized);\n}\n\nBOOST_AUTO_TEST_CASE(query)\n{\n    query_command cmd{\"show databases\"};\n    const std::uint8_t serialized[] =\n        {0x03, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73};\n    do_serialize_test(cmd, serialized);\n}\n\nBOOST_AUTO_TEST_CASE(prepare_statement)\n{\n    prepare_stmt_command cmd{\"SELECT * from three_rows_table WHERE id = ?\"};\n    const std::uint8_t serialized[] = {0x16, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x20, 0x2a, 0x20, 0x66,\n                                       0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x5f, 0x72,\n                                       0x6f, 0x77, 0x73, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x57,\n                                       0x48, 0x45, 0x52, 0x45, 0x20, 0x69, 0x64, 0x20, 0x3d, 0x20, 0x3f};\n    do_serialize_test(cmd, serialized);\n}\n\nBOOST_AUTO_TEST_CASE(execute_statement)\n{\n    constexpr std::uint8_t blob_buffer[] = {0x70, 0x00, 0x01, 0xff};\n\n    struct\n    {\n        const char* name;\n        std::uint32_t stmt_id;\n        std::vector<field_view> params;\n        std::vector<std::uint8_t> serialized;\n    } test_cases[] = {\n        // clang-format off\n        {\n            \"uint64_t\",\n            1,\n            make_fv_vector(std::uint64_t(0xabffffabacadae)),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x08, 0x80, 0xae, 0xad, 0xac, 0xab, 0xff, 0xff, 0xab, 0x00},\n        },\n        {\n            \"int64_t\",\n            1,\n            make_fv_vector(std::int64_t(-0xabffffabacadae)),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x08, 0x00, 0x52, 0x52, 0x53, 0x54, 0x00, 0x00, 0x54, 0xff}\n        },\n        {\n            \"string\",\n            1,\n            make_fv_vector(string_view(\"test\")),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0xfe, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74}\n        },\n        {\n            \"blob\",\n            1,\n            make_fv_vector(span<const std::uint8_t>(blob_buffer)),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0xfc, 0x00, 0x04, 0x70, 0x00, 0x01, 0xff}\n        },\n        {\n            \"float\",\n            1,\n            make_fv_vector(3.14e20f),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x04, 0x00, 0x01, 0x2d, 0x88, 0x61}\n        },\n        {\n            \"double\",\n            1,\n            make_fv_vector(2.1e214),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x05, 0x00, 0x56, 0xc0, 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c}\n        },\n        {\n            \"date\",\n            1,\n            make_fv_vector(date(2010u, 9u, 3u)),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x0a, 0x00, 0x04, 0xda, 0x07, 0x09, 0x03}\n        },\n        {\n            \"datetime\",\n            1,\n            make_fv_vector(datetime(2010u, 9u, 3u, 10u, 30u, 59u, 231800u)),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x0c, 0x00, 0x0b, 0xda, 0x07, 0x09, 0x03, 0x0a, 0x1e, 0x3b,\n            0x78, 0x89, 0x03, 0x00}\n        },\n        {\n            \"time\",\n            1,\n            make_fv_vector(maket(230, 30, 59, 231800)),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n            0x01, 0x0b, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x1e,\n            0x3b, 0x78, 0x89, 0x03, 0x00}\n        },\n        {\n            \"null\",\n            1,\n            make_fv_vector(nullptr),\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x06, 0x00}\n        },\n        {\n            \"several_params\",\n            2,\n            make_fv_vector(\n                std::uint64_t(0xabffffabacadae),\n                std::int64_t(-0xabffffabacadae),\n                string_view(\"test\"),\n                nullptr,\n                2.1e214,\n                date(2010u, 9u, 3u),\n                datetime(2010u, 9u, 3u, 10u, 30u, 59u, 231800u),\n                maket(230, 30, 59, 231800),\n                nullptr\n            ),\n            {0x17, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01,\n            0x01, 0x08, 0x80, 0x08, 0x00, 0xfe, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0a,\n            0x00, 0x0c, 0x00, 0x0b, 0x00, 0x06, 0x00, 0xae, 0xad, 0xac, 0xab, 0xff,\n            0xff, 0xab, 0x00, 0x52, 0x52, 0x53, 0x54, 0x00, 0x00, 0x54, 0xff, 0x04,\n            0x74, 0x65, 0x73, 0x74, 0x56, 0xc0, 0xee, 0xa6, 0x95, 0x30, 0x6f, 0x6c,\n            0x04, 0xda, 0x07, 0x09, 0x03, 0x0b, 0xda, 0x07, 0x09, 0x03, 0x0a, 0x1e,\n            0x3b, 0x78, 0x89, 0x03, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e,\n            0x1e, 0x3b, 0x78, 0x89, 0x03, 0x00}\n        },\n        {\n            \"empty\",\n            1,\n            {},\n            {0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}\n        }\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            execute_stmt_command cmd{tc.stmt_id, tc.params};\n            do_serialize_test(cmd, tc.serialized);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(close_statement)\n{\n    close_stmt_command cmd{1};\n    const std::uint8_t serialized[] = {0x19, 0x01, 0x00, 0x00, 0x00};\n    do_serialize_test(cmd, serialized);\n}\n\nBOOST_AUTO_TEST_CASE(login_request_)\n{\n    constexpr std::array<std::uint8_t, 20> auth_data{\n        {0xfe, 0xc6, 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, 0xc5, 0x51,\n         0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, 0x34, 0xc9}\n    };\n\n    constexpr auto caps = capabilities::long_password | capabilities::long_flag | capabilities::local_files |\n                          capabilities::protocol_41 | capabilities::interactive | capabilities::transactions |\n                          capabilities::secure_connection | capabilities::multi_statements |\n                          capabilities::multi_results | capabilities::ps_multi_results |\n                          capabilities::plugin_auth | capabilities::connect_attrs |\n                          capabilities::plugin_auth_lenenc_data | capabilities::can_handle_expired_passwords |\n                          capabilities::session_track | capabilities::deprecate_eof;\n\n    struct\n    {\n        const char* name;\n        login_request value;\n        std::vector<std::uint8_t> serialized;\n    } test_cases[] = {\n        {\n         \"without_db\", {\n                caps,\n                16777216,  // max packet size\n                collations::utf8_general_ci,\n                \"root\",  // username\n                auth_data,\n                \"\",                       // database; irrelevant, not using connect with DB capability\n                \"mysql_native_password\",  // auth plugin name\n            }, {0x85, 0xa6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n             0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xfe, 0xc6, 0x2c, 0x9f, 0xab, 0x43, 0x69, 0x46, 0xc5, 0x51,\n             0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, 0x34, 0xc9, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f,\n             0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00},\n         },\n        {\n         \"with_db\",            {\n                caps | capabilities::connect_with_db,\n                16777216,  // max packet size\n                collations::utf8_general_ci,\n                \"root\",  // username\n                auth_data,\n                \"database\",               // DB name\n                \"mysql_native_password\",  // auth plugin name\n            },                                    {0x8d, 0xa6, 0xff, 0x01, 0x00, 0x00, 0x00, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n             0x00, 0x00, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x14, 0xfe, 0xc6, 0x2c, 0x9f, 0xab, 0x43, 0x69,\n             0x46, 0xc5, 0x51, 0x35, 0xa5, 0xff, 0xdb, 0x3f, 0x48, 0xe6, 0xfc, 0x34, 0xc9, 0x64, 0x61,\n             0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x6d, 0x79, 0x73, 0x71, 0x6c, 0x5f, 0x6e, 0x61,\n             0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00},\n         },\n    };\n\n    // TODO: test case with collation > 0xff\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name) { do_serialize_test(tc.value, tc.serialized); }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(ssl_request_)\n{\n    constexpr auto caps = capabilities::long_flag | capabilities::local_files | capabilities::protocol_41 |\n                          capabilities::interactive | capabilities::ssl | capabilities::transactions |\n                          capabilities::secure_connection | capabilities::multi_statements |\n                          capabilities::multi_results | capabilities::ps_multi_results |\n                          capabilities::plugin_auth | capabilities::connect_attrs |\n                          capabilities::session_track | static_cast<capabilities>(1UL << 29);\n\n    // Data\n    ssl_request value{\n        capabilities(caps),\n        0x1000000,  // max packet size\n        collations::utf8mb4_general_ci,\n    };\n\n    const std::uint8_t serialized[] = {0x84, 0xae, 0x9f, 0x20, 0x00, 0x00, 0x00, 0x01, 0x2d, 0x00, 0x00,\n                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n    do_serialize_test(value, serialized);\n\n    // TODO: test case with collation > 0xff\n}\n\nBOOST_AUTO_TEST_CASE(auth_switch_response_)\n{\n    constexpr std::array<std::uint8_t, 20> auth_data{\n        {0xba, 0x55, 0x9c, 0xc5, 0x9c, 0xbf, 0xca, 0x06, 0x91, 0xff,\n         0xaa, 0x72, 0x59, 0xfc, 0x53, 0xdf, 0x88, 0x2d, 0xf9, 0xcf}\n    };\n\n    auth_switch_response value{auth_data};\n\n    constexpr std::array<std::uint8_t, 20> serialized{\n        {0xba, 0x55, 0x9c, 0xc5, 0x9c, 0xbf, 0xca, 0x06, 0x91, 0xff,\n         0xaa, 0x72, 0x59, 0xfc, 0x53, 0xdf, 0x88, 0x2d, 0xf9, 0xcf}\n    };\n\n    do_serialize_test(value, serialized);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/protocol/serialization_context.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_serialization_context)\n\nstruct framing_test_case\n{\n    string_view name;\n    std::size_t expected_next_frame_offset;  // not counting previous contents\n    std::vector<std::uint8_t> payload;\n    std::vector<std::uint8_t> expected_buffer;  // not counting previous contents\n};\n\nstd::vector<framing_test_case> make_test_cases()\n{\n    return {\n        // clang-format off\n        {\"0 bytes\",     12,   {},                          {0, 0, 0, 0}                                       },\n        {\"1 byte\",      12,   {1},                         {0, 0, 0, 0, 1}                                    },\n        {\"5 bytes\",     12,   {1, 2, 3, 4, 5},             {0, 0, 0, 0, 1, 2, 3, 4, 5}                        },\n        {\"fs-1 bytes\",  12,   {1, 2, 3, 4, 5, 6, 7},       {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7}                  },\n        {\"fs bytes\",    24,   {1, 2, 3, 4, 5, 6, 7, 8},    {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0}   },\n        {\"fs+1 bytes\",  24,   {1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9}},\n        {\"2fs bytes\",   36,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n            {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0}    },\n        {\"2fs+1 bytes\", 36,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n            {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17}},\n        {\"2fs+5 bytes\", 36,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21},\n            {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 21}},\n        {\"3fs-1 bytes\", 36,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},\n            {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 21, 22, 23}},\n        {\"3fs bytes\",   48,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24},\n            {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0}},\n        {\"3fs+1 bytes\", 48,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},\n            {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 25}},\n        // clang-format on\n    };\n}\n\nBOOST_AUTO_TEST_CASE(add)\n{\n    constexpr std::size_t fs = 8u;  // frame size\n    const std::vector<std::uint8_t> initial_buffer{0xaa, 0xbb, 0xcc, 0xdd, 0xee};\n\n    for (const auto& tc : make_test_cases())\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            std::vector<std::uint8_t> buff{initial_buffer};\n            detail::serialization_context ctx(buff, 0xffff, fs);\n\n            // Add the payload\n            ctx.add(tc.payload);\n\n            // Check\n            auto expected = test::concat(initial_buffer, tc.expected_buffer);\n            BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n            BOOST_TEST(ctx.next_header_offset() == tc.expected_next_frame_offset + initial_buffer.size());\n            BOOST_TEST(ctx.error() == error_code());\n        }\n    }\n}\n\n// Spotcheck: if the initial buffer is empty, everything works fine\nBOOST_AUTO_TEST_CASE(add_initial_buffer_empty)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 0xffff, 8);\n\n    // Add data\n    const std::array<std::uint8_t, 10> payload{\n        {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}\n    };\n    ctx.add(payload);\n\n    // Check\n    const std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 9, 10};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.next_header_offset() == 24u);\n    BOOST_TEST(ctx.error() == error_code());\n}\n\n// Spotcheck: adding single bytes or in chunks also works fine\nBOOST_AUTO_TEST_CASE(chunks)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 0xffff, 8);\n    const std::array<std::uint8_t, 4> payload1{\n        {1, 2, 3, 4}\n    };\n    const std::array<std::uint8_t, 5> payload2{\n        {5, 6, 7, 8, 9}\n    };\n\n    // Add byte\n    ctx.add(0xff);\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 0xff};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.error() == error_code());\n\n    // Add buffer\n    ctx.add(payload1);\n    expected = {0, 0, 0, 0, 0xff, 1, 2, 3, 4};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.error() == error_code());\n\n    // Add byte\n    ctx.add(0xfe);\n    expected = {0, 0, 0, 0, 0xff, 1, 2, 3, 4, 0xfe};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.error() == error_code());\n\n    // Add buffer\n    ctx.add(payload2);\n    expected = {0, 0, 0, 0, 0xff, 1, 2, 3, 4, 0xfe, 5, 6, 0, 0, 0, 0, 7, 8, 9};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.error() == error_code());\n\n    // Add byte\n    ctx.add(0xfc);\n    expected = {0, 0, 0, 0, 0xff, 1, 2, 3, 4, 0xfe, 5, 6, 0, 0, 0, 0, 7, 8, 9, 0xfc};\n    BOOST_TEST(ctx.next_header_offset() == 24u);\n    BOOST_TEST(ctx.error() == error_code());\n}\n\n// Spotcheck: adding a single byte that causes a frame header to be written works\nBOOST_AUTO_TEST_CASE(add_byte_fills_frame)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 0xffff, 8);\n    const std::array<std::uint8_t, 7> payload{\n        {1, 2, 3, 4, 5, 6, 7}\n    };\n\n    // Add payload\n    ctx.add(payload);\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.next_header_offset() == 12u);\n    BOOST_TEST(ctx.error() == error_code());\n\n    // Add byte\n    ctx.add(0xab);\n    expected = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0xab, 0, 0, 0, 0};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.next_header_offset() == 24u);\n    BOOST_TEST(ctx.error() == error_code());\n}\n\nBOOST_AUTO_TEST_CASE(write_frame_headers)\n{\n    struct\n    {\n        string_view name;\n        std::uint8_t expected_seqnum;\n        std::vector<std::uint8_t> payload;\n        std::vector<std::uint8_t> expected;\n    } test_cases[] = {\n        // clang-format off\n        {\"0 bytes\",     43,   {},                          {0, 0, 0, 42}                                       },\n        {\"1 byte\",      43,   {1},                         {1, 0, 0, 42, 1}                                    },\n        {\"5 bytes\",     43,   {1, 2, 3, 4, 5},             {5, 0, 0, 42, 1, 2, 3, 4, 5}                        },\n        {\"fs-1 bytes\",  43,   {1, 2, 3, 4, 5, 6, 7},       {7, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7}                  },\n        {\"fs bytes\",    44,   {1, 2, 3, 4, 5, 6, 7, 8},    {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 43}   },\n        {\"fs+1 bytes\",  44,   {1, 2, 3, 4, 5, 6, 7, 8, 9}, {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 1, 0, 0, 43, 9}},\n        {\"2fs bytes\",   45,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},\n            {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 0, 43, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 0, 44}    },\n        {\"2fs+1 bytes\", 45,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},\n            {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 0, 43, 9, 10, 11, 12, 13, 14, 15, 16, 1, 0, 0, 44, 17}},\n        {\"2fs+5 bytes\", 45,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21},\n            {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 0, 43, 9, 10, 11, 12, 13, 14, 15, 16, 5, 0, 0, 44, 17, 18, 19, 20, 21}},\n        {\"3fs-1 bytes\", 45,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},\n            {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 0, 43, 9, 10, 11, 12, 13, 14, 15, 16, 7, 0, 0, 44, 17, 18, 19, 20, 21, 22, 23}},\n        {\"3fs bytes\",   46,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24},\n            {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 0, 43, 9, 10, 11, 12, 13, 14, 15, 16, 8, 0, 0, 44, 17, 18, 19, 20, 21, 22, 23, 24,\n                0, 0, 0, 45}},\n        {\"3fs+1 bytes\", 46,   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25},\n            {8, 0, 0, 42, 1, 2, 3, 4, 5, 6, 7, 8, 8, 0, 0, 43, 9, 10, 11, 12, 13, 14, 15, 16, 8, 0, 0, 44, 17, 18, 19, 20, 21, 22, 23, 24,\n                1, 0, 0, 45, 25}},\n        // clang-format on\n    };\n\n    const std::vector<std::uint8_t> initial_buffer{90, 91, 92, 93, 94};\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            std::vector<std::uint8_t> buff{initial_buffer};\n            detail::serialization_context ctx(buff, 0xffff, 8);\n            ctx.add(tc.payload);\n\n            // Call and check\n            auto seqnum = ctx.write_frame_headers(42, initial_buffer.size());\n            const auto expected = test::concat(initial_buffer, tc.expected);\n            BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n            BOOST_TEST(seqnum == tc.expected_seqnum);\n            BOOST_TEST(ctx.error() == error_code());\n        }\n    }\n}\n\n// Spotcheck: we correctly wrap sequence numbers when going over 0xff\nBOOST_AUTO_TEST_CASE(write_frame_headers_seqnum_wrap)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 0xffff, 8);\n    for (std::uint8_t i = 1; i <= 20; ++i)\n        ctx.add(i);\n\n    // Call and check\n    const std::vector<std::uint8_t> expected{\n        8, 0, 0, 0xfe, 1,  2,  3,  4,  5,  6,  7,  8,   // frame 1\n        8, 0, 0, 0xff, 9,  10, 11, 12, 13, 14, 15, 16,  // frame 2\n        4, 0, 0, 0,    17, 18, 19, 20                   // frame 3\n    };\n    auto seqnum = ctx.write_frame_headers(0xfe, 0);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(seqnum == 1u);\n    BOOST_TEST(ctx.error() == error_code());\n}\n\n// Spotcheck: disable framing works\nBOOST_AUTO_TEST_CASE(disable_framing)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 0xffff, detail::disable_framing);\n\n    // Add data using the several functions available\n    const std::array<std::uint8_t, 5> payload1{\n        {1, 2, 3, 4, 5}\n    };\n    const std::array<std::uint8_t, 4> payload2{\n        {6, 7, 8, 9}\n    };\n    ctx.add(42);\n    ctx.add(payload1);\n    ctx.add(payload2);\n\n    // We didn't add any framing\n    const std::vector<std::uint8_t> expected{42, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n    BOOST_TEST(ctx.error() == error_code());\n}\n\nBOOST_AUTO_TEST_SUITE(max_buffer_size_error)\n\nBOOST_AUTO_TEST_CASE(header_exceeds_maxsize)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 3u);\n\n    // Buffer can't hold the header\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_CASE(contents_exceed_maxsize)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 8u);\n\n    // Header plus content would exceed max size\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5, 6});\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n\n    // Only header written\n    std::array<std::uint8_t, 4> expected{};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\nBOOST_AUTO_TEST_CASE(subsequent_header_exceeds_maxsize)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 13u, 8u);\n\n    // Successfully add some data\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5, 6});\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5, 6};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Add data triggering a header that can't fit\n    ctx.add(std::vector<std::uint8_t>{7, 8});\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_CASE(maxsize_zero)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 0u);\n\n    // Buffer can't hold the header\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_CASE(error_by_one_byte)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 12u);\n\n    // Successfully add data until max size\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5, 6, 7, 8});\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding more data fails. No data is written to the buffer\n    ctx.add(std::vector<std::uint8_t>{1});\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\n// Spotcheck: adding a single byte triggers the same behavior\nBOOST_AUTO_TEST_CASE(error_add_u8)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 12u);\n\n    // Successfully add data until max size\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5, 6, 7, 8});\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding more data fails. No data is written to the buffer\n    ctx.add(42);\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\n// Edge case: if the input buffer exceeded the max size, we fail\nBOOST_AUTO_TEST_CASE(buffer_exceeds_max_size)\n{\n    std::vector<std::uint8_t> buff(48u, 0);\n    detail::serialization_context ctx(buff, 12u);\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n}\n\n// Previous contents are taken into account for size checks\nBOOST_AUTO_TEST_CASE(buffer_with_previous_contents)\n{\n    // Setup\n    std::vector<std::uint8_t> buff{1, 2, 3};\n    detail::serialization_context ctx(buff, 8u);\n\n    // Just max size\n    ctx.add(42);\n    std::vector<std::uint8_t> expected{1, 2, 3, 0, 0, 0, 0, 42};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Past max size\n    ctx.add(80);\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\nBOOST_AUTO_TEST_CASE(several_errors)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 12u);\n\n    // Successfully add some data\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5});\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding more data fails. No data is written to the buffer\n    ctx.add(std::vector<std::uint8_t>{6, 7, 8, 9});\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding more data again does nothing\n    ctx.add(std::vector<std::uint8_t>{10, 11, 12});\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\nBOOST_AUTO_TEST_CASE(success_after_error)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff, 12u);\n\n    // Successfully add some data\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5});\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding more data fails. No data is written to the buffer\n    ctx.add(std::vector<std::uint8_t>{6, 7, 8, 9});\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding more data again does nothing, even if the data would fit\n    ctx.add(1);\n    BOOST_TEST(ctx.error() == client_errc::max_buffer_size_exceeded);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\nBOOST_AUTO_TEST_CASE(add_error)\n{\n    // Setup\n    std::vector<std::uint8_t> buff;\n    detail::serialization_context ctx(buff);\n\n    // Successfully add some data\n    ctx.add(std::vector<std::uint8_t>{1, 2, 3, 4, 5});\n    std::vector<std::uint8_t> expected{0, 0, 0, 0, 1, 2, 3, 4, 5};\n    BOOST_TEST(ctx.error() == error_code());\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Add an error\n    ctx.add_error(client_errc::invalid_encoding);\n    BOOST_TEST(ctx.error() == client_errc::invalid_encoding);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding further data with the error set does nothing\n    ctx.add(std::vector<std::uint8_t>{8, 9, 10});\n    BOOST_TEST(ctx.error() == client_errc::invalid_encoding);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    // Adding another error does nothing\n    ctx.add_error(client_errc::protocol_value_error);\n    BOOST_TEST(ctx.error() == client_errc::invalid_encoding);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n\n    ctx.add_error(error_code());\n    BOOST_TEST(ctx.error() == client_errc::invalid_encoding);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff, expected);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/protocol/serialization_test.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_PROTOCOL_SERIALIZATION_TEST_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_PROTOCOL_SERIALIZATION_TEST_HPP\n\n#include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n\n#include <boost/asio/buffer.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <cstring>\n#include <initializer_list>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_unit/serialize_to_vector.hpp\"\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// A special buffer for deserialization tests. Allocates the exact size of the serialized message (contrary to\n// std::vector), making it easier for sanitizers to detect overruns\nclass deserialization_buffer\n{\n    std::size_t size_;\n    std::unique_ptr<std::uint8_t[]> data_;\n\npublic:\n    explicit deserialization_buffer(std::size_t size) : size_(size), data_(new std::uint8_t[size]) {}\n    deserialization_buffer(std::size_t size, std::uint8_t value) : deserialization_buffer(size)\n    {\n        std::memset(data(), value, size);\n    }\n    deserialization_buffer(span<const std::uint8_t> data) : size_(data.size())\n    {\n        if (!data.empty())\n        {\n            data_.reset(new std::uint8_t[data.size()]);\n            std::memcpy(data_.get(), data.data(), data.size());\n        }\n    }\n    deserialization_buffer(const std::vector<std::uint8_t>& data)\n        : deserialization_buffer(span<const std::uint8_t>(data))\n    {\n    }\n    deserialization_buffer(std::initializer_list<std::uint8_t> data)\n        : size_(data.size()), data_(new std::uint8_t[data.size()])\n    {\n        std::copy(data.begin(), data.end(), data_.get());\n    }\n    span<const std::uint8_t> to_span() const noexcept { return {data_.get(), size_}; }\n    operator span<const std::uint8_t>() const noexcept { return to_span(); }\n    std::uint8_t* data() noexcept { return data_.get(); }\n    const std::uint8_t* data() const noexcept { return data_.get(); }\n    std::size_t size() const noexcept { return size_; }\n};\n\ntemplate <class T>\nvoid do_serialize_test(T value, span<const std::uint8_t> expected)\n{\n    // Serialize\n    auto actual = serialize_to_vector([&](detail::serialization_context& ctx) { value.serialize(ctx); });\n\n    // Check\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(expected, actual);\n}\n\ntemplate <class T>\nvoid do_deserialize_test(T value, span<const std::uint8_t> serialized)\n{\n    deserialization_buffer buffer(serialized);\n    auto expected_first = buffer.data() + buffer.size();\n    detail::deserialization_context ctx(buffer);\n    T actual{};\n    detail::deserialize_errc err = actual.deserialize(ctx);\n\n    // No error\n    BOOST_TEST(err == detail::deserialize_errc::ok);\n\n    // Iterator advanced\n    BOOST_TEST(ctx.first() == expected_first);\n\n    // Actual value\n    BOOST_TEST(actual == value);\n}\n\ntemplate <class T>\nvoid do_deserialize_extra_space_test(T value, span<const std::uint8_t> serialized)\n{\n    // Create a buffer with extra data\n    deserialization_buffer buffer(serialized.size() + 1);\n    std::memcpy(buffer.data(), serialized.data(), serialized.size());\n    buffer.data()[serialized.size()] = 0xff;\n\n    // Deserialize\n    detail::deserialization_context ctx(buffer);\n    T actual{};\n    detail::deserialize_errc err = actual.deserialize(ctx);\n\n    // No error\n    BOOST_TEST(err == detail::deserialize_errc::ok);\n\n    // Iterator advanced\n    BOOST_TEST(ctx.first() == buffer.data() + serialized.size());\n\n    // Actual value\n    BOOST_TEST(actual == value);\n}\n\ntemplate <class T>\nvoid do_deserialize_not_enough_space_test(span<const std::uint8_t> serialized)\n{\n    // Create a new buffer with one less byte\n    deserialization_buffer buffer(serialized.subspan(0, serialized.size() - 1));\n    detail::deserialization_context ctx(buffer.to_span());\n\n    T value{};\n    detail::deserialize_errc err = value.deserialize(ctx);\n    BOOST_TEST(err == detail::deserialize_errc::incomplete_message);\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/protocol/static_buffer.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/protocol/static_buffer.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n\nusing namespace boost::mysql::test;\nusing boost::mysql::detail::static_buffer;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_static_buffer)\n\n// Constructors\nBOOST_AUTO_TEST_CASE(default_constructor)\n{\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(static_buffer<32>(), std::vector<std::uint8_t>());\n}\n\nBOOST_AUTO_TEST_CASE(init_constructor)\n{\n    // Zero size\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(static_buffer<32>(0), std::vector<std::uint8_t>());\n\n    // Intermediate size\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(static_buffer<32>(10), std::vector<std::uint8_t>(10, 0x00));\n\n    // Max size\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(static_buffer<32>(32), std::vector<std::uint8_t>(32, 0x00));\n}\n\n// Accessors\nBOOST_AUTO_TEST_CASE(data_size_const)\n{\n    const static_buffer<32> buff(8);\n    BOOST_TEST(buff.data() != nullptr);\n    BOOST_TEST(buff.size() == 8u);\n}\n\nBOOST_AUTO_TEST_CASE(data_size_nonconst)\n{\n    static_buffer<32> buff(8);\n    BOOST_TEST(buff.data() != nullptr);\n    BOOST_TEST(buff.size() == 8u);\n}\n\n// clear\nBOOST_AUTO_TEST_CASE(clear_empty)\n{\n    static_buffer<32> v;\n    v.clear();\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, std::vector<std::uint8_t>());\n}\n\nBOOST_AUTO_TEST_CASE(clear_not_empty)\n{\n    static_buffer<32> v;\n    v.append(std::array<std::uint8_t, 5>{\n        {0, 1, 2, 3, 4}\n    });\n    BOOST_TEST(v.size() == 5u);\n    v.clear();\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, std::vector<std::uint8_t>());\n}\n\n// append\nBOOST_AUTO_TEST_CASE(append_from_empty_to_empty)\n{\n    static_buffer<32> v;\n    v.append({});\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, std::vector<std::uint8_t>());\n}\n\nBOOST_AUTO_TEST_CASE(append_from_empty_to_midsize)\n{\n    const std::array<std::uint8_t, 3> data{\n        {1, 2, 3}\n    };\n    static_buffer<32> v;\n    v.append(std::vector<std::uint8_t>(data.begin(), data.end()));  // verify we make a copy\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, data);\n}\n\nBOOST_AUTO_TEST_CASE(append_from_empty_to_maxsize)\n{\n    const std::vector<std::uint8_t> data(32, 0xde);\n    static_buffer<32> v;\n    v.append(data);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, data);\n}\n\nBOOST_AUTO_TEST_CASE(append_from_midsize_to_midsize)\n{\n    // Initial\n    static_buffer<32> v;\n    v.append(std::vector<std::uint8_t>{2, 2, 2});\n\n    // Append more data\n    v.append(std::vector<std::uint8_t>{1, 2, 3});\n\n    // Verify\n    const std::vector<std::uint8_t> expected{2, 2, 2, 1, 2, 3};\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, expected);\n}\n\nBOOST_AUTO_TEST_CASE(append_from_midsize_to_maxsize)\n{\n    // Initial\n    static_buffer<32> v;\n    v.append(std::vector<std::uint8_t>{1, 2, 3});\n\n    // Append\n    v.append(std::vector<std::uint8_t>(29, 0xde));\n\n    // Verify\n    const std::array<std::uint8_t, 32> expected{\n        {0x01, 0x02, 0x03, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,\n         0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde}\n    };\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(v, expected);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/protocol/text_protocol.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/date.hpp>\n#include <boost/mysql/datetime.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/metadata.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/text_protocol.hpp>\n\n#include <boost/test/data/monomorphic/collection.hpp>\n#include <boost/test/data/test_case.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"operators.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/create_meta.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing namespace boost::unit_test;\n\nnamespace {\n\n// clang-format off\n\nBOOST_AUTO_TEST_SUITE(test_text_protocol)\n\n// Success cases\nBOOST_AUTO_TEST_SUITE(deserialize_success)\n\nstruct success_sample\n{\n    std::string name;\n    std::string from;\n    field_view expected;\n    metadata meta;\n\n    template <class T>\n    success_sample(\n        std::string name,\n        std::string from,\n        T&& expected_value,\n        metadata meta\n    ) :\n        name(std::move(name)),\n        from(std::move(from)),\n        expected(std::forward<T>(expected_value)),\n        meta(std::move(meta))\n    {\n    }\n};\n\nstd::ostream& operator<<(std::ostream& os, const success_sample& input)\n{\n    return os << \"(input=\" << input.from\n              << \", type=\" << input.meta.type()\n              << \", name=\" << input.name\n              << \")\";\n}\n\nvoid add_string_samples(std::vector<success_sample>& output)\n{\n    output.emplace_back(\"varchar_non_empty\", \"string\", \"string\", create_meta(column_type::varchar));\n    output.emplace_back(\"varchar_empty\", \"\", \"\", create_meta(column_type::varchar));\n    output.emplace_back(\"char\", \"\", \"\", create_meta(column_type::char_));\n    output.emplace_back(\"text\", \"value\", \"value\", create_meta(column_type::text));\n    output.emplace_back(\"enum\", \"value\", \"value\", create_meta(column_type::enum_));\n    output.emplace_back(\"set\", \"value1,value2\", \"value1,value2\", create_meta(column_type::set));\n    output.emplace_back(\"decimal\", \"1\", \"1\", create_meta(column_type::decimal));\n    output.emplace_back(\"json\", \"{}\", \"{}\", create_meta(column_type::json));\n}\n\nvoid add_blob_samples(std::vector<success_sample>& output)\n{\n    static constexpr std::uint8_t buff [] = { 0x00, 0x01, 0x02, 0x03 };\n    std::string from { 0x00, 0x01, 0x02, 0x03 };\n\n    output.emplace_back(\"varbinary_non_empty\", from, blob_view(buff), create_meta(column_type::varbinary));\n    output.emplace_back(\"varbinary_empty\", \"\", blob_view(), create_meta(column_type::varbinary));\n    output.emplace_back(\"binary\", from, blob_view(buff), create_meta(column_type::binary));\n    output.emplace_back(\"blob\", from, blob_view(buff), create_meta(column_type::blob));\n    output.emplace_back(\"geometry\", from, blob_view(buff), create_meta(column_type::geometry));\n\n    // Anything we don't know what it is, we interpret as a blob\n    output.emplace_back(\"unknown_protocol_type\", from, blob_view(buff), create_meta(column_type::unknown));\n}\n\nvoid add_int_samples_helper(\n    std::string signed_max_s,\n    std::int64_t signed_max_b,\n    std::string signed_min_s,\n    std::int64_t signed_min_b,\n    std::string unsigned_max_s,\n    std::uint64_t unsigned_max_b,\n    std::string zerofill_s,\n    std::uint64_t zerofill_b,\n    column_type type,\n    std::vector<success_sample>& output\n)\n{\n    output.emplace_back(\"signed\", \"20\", std::int64_t(20), create_meta(type));\n    output.emplace_back(\"signed_max\", std::move(signed_max_s), signed_max_b, create_meta(type));\n    output.emplace_back(\"signed_negative\", \"-20\", std::int64_t(-20), create_meta(type));\n    output.emplace_back(\"signed_min\", std::move(signed_min_s), signed_min_b, create_meta(type));\n    output.emplace_back(\"unsigned\", \"20\", std::uint64_t(20), meta_builder().type(type).unsigned_flag(true).build());\n    output.emplace_back(\"unsigned_min\", \"0\", std::uint64_t(0), meta_builder().type(type).unsigned_flag(true).build());\n    output.emplace_back(\"unsigned_max\", std::move(unsigned_max_s),\n        unsigned_max_b, meta_builder().type(type).unsigned_flag(true).build());\n    output.emplace_back(\"unsigned_zerofill\", std::move(zerofill_s),\n        zerofill_b, meta_builder().type(type).unsigned_flag(true).zerofill(true).build());\n}\n\nvoid add_int_samples(std::vector<success_sample>& output)\n{\n    add_int_samples_helper(\n        \"127\", 127,\n        \"-128\", -128,\n        \"255\", 255,\n        \"010\", 10,\n        column_type::tinyint,\n        output\n    );\n    add_int_samples_helper(\n        \"32767\", 32767,\n        \"-32768\", -32768,\n        \"65535\", 65535,\n        \"00535\", 535,\n        column_type::smallint,\n        output\n    );\n    add_int_samples_helper(\n        \"8388607\", 8388607,\n        \"-8388608\",-8388608,\n        \"16777215\", 16777215,\n        \"00007215\", 7215,\n        column_type::mediumint,\n        output\n    );\n    add_int_samples_helper(\n        \"2147483647\", 2147483647,\n        \"-2147483648\", -2147483647 - 1, // minus is not part of literal, avoids warning\n        \"4294967295\", 4294967295,\n        \"0000067295\", 67295,\n        column_type::int_,\n        output\n    );\n    add_int_samples_helper(\n        \"9223372036854775807\", 9223372036854775807,\n        \"-9223372036854775808\", -9223372036854775807 - 1, // minus is not part of literal, avoids warning\n        \"18446744073709551615\", 18446744073709551615ULL, // suffix needed to avoid warning\n        \"0000067295\", 67295,\n        column_type::bigint,\n        output\n    );\n\n    // YEAR\n    auto year_meta = meta_builder().type(column_type::year).unsigned_flag(true).build();\n    output.emplace_back(\"regular_value\", \"1999\", std::uint64_t(1999), year_meta);\n    output.emplace_back(\"min\", \"1901\", std::uint64_t(1901), year_meta);\n    output.emplace_back(\"max\", \"2155\", std::uint64_t(2155), year_meta);\n    output.emplace_back(\"zero\", \"0000\", std::uint64_t(0), year_meta);\n}\n\n// bit\nvoid add_bit_types(std::vector<success_sample>& output)\n{\n    auto bit_meta = meta_builder().type(column_type::bit).unsigned_flag(true).build();\n    output.emplace_back(\"bit_8\", \"\\x12\", std::uint64_t(0x12), bit_meta);\n    output.emplace_back(\"bit_16\", \"\\x12\\x34\", std::uint64_t(0x1234), bit_meta);\n    output.emplace_back(\"bit_24\", \"\\x12\\x34\\x56\", std::uint64_t(0x123456), bit_meta);\n    output.emplace_back(\"bit_32\", \"\\x12\\x34\\x56\\x78\", std::uint64_t(0x12345678), bit_meta);\n    output.emplace_back(\"bit_40\", \"\\x12\\x34\\x56\\x78\\x9a\", std::uint64_t(0x123456789a), bit_meta);\n    output.emplace_back(\"bit_48\", \"\\x12\\x34\\x56\\x78\\x9a\\xbc\", std::uint64_t(0x123456789abc), bit_meta);\n    output.emplace_back(\"bit_56\", \"\\x12\\x34\\x56\\x78\\x9a\\xbc\\xde\", std::uint64_t(0x123456789abcde), bit_meta);\n    output.emplace_back(\"bit_64\", \"\\x12\\x34\\x56\\x78\\x9a\\xbc\\xde\\xf0\", std::uint64_t(0x123456789abcdef0), bit_meta);\n}\n\ntemplate <class T>\nvoid add_float_samples(\n    column_type type,\n    std::vector<success_sample>& output\n)\n{\n    output.emplace_back(\"zero\", \"0\", T(0.0), create_meta(type));\n    output.emplace_back(\"integer_positive\", \"4\", T(4.0), create_meta(type));\n    output.emplace_back(\"integer_negative\", \"-5\", T(-5.0), create_meta(type));\n    output.emplace_back(\"fractional_positive\", \"3.147\", T(3.147), create_meta(type));\n    output.emplace_back(\"fractional_negative\", \"-3.147\", T(-3.147), create_meta(type));\n    output.emplace_back(\"positive_exponent_positive_integer\", \"3e20\", T(3e20), create_meta(type));\n    output.emplace_back(\"positive_exponent_negative_integer\", \"-3e20\", T(-3e20), create_meta(type));\n    output.emplace_back(\"positive_exponent_positive_fractional\", \"3.14e20\", T(3.14e20), create_meta(type));\n    output.emplace_back(\"positive_exponent_negative_fractional\", \"-3.45e20\", T(-3.45e20), create_meta(type));\n    output.emplace_back(\"negative_exponent_positive_integer\", \"3e-20\", T(3e-20), create_meta(type));\n    output.emplace_back(\"negative_exponent_negative_integer\", \"-3e-20\", T(-3e-20), create_meta(type));\n    output.emplace_back(\"negative_exponent_positive_fractional\", \"3.14e-20\", T(3.14e-20), create_meta(type));\n    output.emplace_back(\"negative_exponent_negative_fractional\", \"-3.45e-20\", T(-3.45e-20), create_meta(type));\n}\n\nvoid add_date_samples(std::vector<success_sample>& output)\n{\n    output.emplace_back(\"regular_date\", \"2019-02-28\", date(2019u, 2u, 28u), create_meta(column_type::date));\n    output.emplace_back(\"leap_year\", \"1788-02-29\", date(1788u, 2u, 29u), create_meta(column_type::date));\n    output.emplace_back(\"min\", \"0000-01-01\", date(0u, 1u, 1u), create_meta(column_type::date));\n    output.emplace_back(\"max\", \"9999-12-31\", date(9999u, 12u, 31u), create_meta(column_type::date));\n    output.emplace_back(\"zero\", \"0000-00-00\", date(), create_meta(column_type::date));\n    output.emplace_back(\"zero_month\", \"0000-00-01\", date(0u, 0u, 1u), create_meta(column_type::date));\n    output.emplace_back(\"zero_day\", \"0000-01-00\", date(0u, 1u, 0u), create_meta(column_type::date));\n    output.emplace_back(\"zero_month_day_nonzero_year\", \"2010-00-00\", date(2010u, 0u, 0u), create_meta(column_type::date));\n    output.emplace_back(\"invalid_date\", \"2010-11-31\", date(2010u, 11u, 31u), create_meta(column_type::date));\n}\n\nvoid add_datetime_samples(\n    column_type type,\n    std::vector<success_sample>& output\n)\n{\n    auto meta_0decimals = meta_builder().type(type).decimals(0).build();\n    output.emplace_back(\"0_decimals_date\", \"2010-02-15 00:00:00\", datetime(2010u, 2u, 15u), meta_0decimals);\n    output.emplace_back(\"0_decimals_h\", \"2010-02-15 02:00:00\", datetime(2010u, 2u, 15u, 2u), meta_0decimals);\n    output.emplace_back(\"0_decimals_hm\", \"2010-02-15 02:05:00\", datetime(2010u, 2u, 15u, 2u, 5u), meta_0decimals);\n    output.emplace_back(\"0_decimals_hms\", \"2010-02-15 02:05:30\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_0decimals);\n    output.emplace_back(\"0_decimals_min\", \"0000-01-01 00:00:00\", datetime(0u, 1u, 1u), meta_0decimals);\n    output.emplace_back(\"0_decimals_max\", \"9999-12-31 23:59:59\", datetime(9999u, 12u, 31u, 23u, 59u, 59u), meta_0decimals);\n\n    auto meta_1decimal = meta_builder().type(type).decimals(1).build();\n    output.emplace_back(\"1_decimals_date\", \"2010-02-15 00:00:00.0\", datetime(2010u, 2u, 15u), meta_1decimal);\n    output.emplace_back(\"1_decimals_h\", \"2010-02-15 02:00:00.0\", datetime(2010u, 2u, 15u, 2u), meta_1decimal);\n    output.emplace_back(\"1_decimals_hm\", \"2010-02-15 02:05:00.0\", datetime(2010u, 2u, 15u, 2u, 5u), meta_1decimal);\n    output.emplace_back(\"1_decimals_hms\", \"2010-02-15 02:05:30.0\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_1decimal);\n    output.emplace_back(\"1_decimals_hmsu\", \"2010-02-15 02:05:30.5\", datetime(2010u, 2u, 15u, 2u, 5u, 30u, 500000u), meta_1decimal);\n    output.emplace_back(\"1_decimals_min\", \"0000-01-01 00:00:00.0\", datetime(0u, 1u, 1u), meta_1decimal);\n    output.emplace_back(\"1_decimals_max\", \"9999-12-31 23:59:59.9\", datetime(9999u, 12u, 31u, 23u, 59u, 59u, 900000u), meta_1decimal);\n\n    auto meta_2decimals = meta_builder().type(type).decimals(2).build();\n    output.emplace_back(\"2_decimals_hms\", \"2010-02-15 02:05:30.00\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_2decimals);\n    output.emplace_back(\"2_decimals_hmsu\", \"2010-02-15 02:05:30.05\", datetime(2010u, 2u, 15u, 2u, 5u, 30u, 50000u), meta_2decimals);\n    output.emplace_back(\"2_decimals_min\", \"0000-01-01 00:00:00.00\", datetime(0u, 1u, 1u), meta_2decimals);\n    output.emplace_back(\"2_decimals_max\", \"9999-12-31 23:59:59.99\", datetime(9999u, 12u, 31u, 23u, 59u, 59u, 990000u), meta_2decimals);\n\n    auto meta_3decimals = meta_builder().type(type).decimals(3).build();\n    output.emplace_back(\"3_decimals_hms\", \"2010-02-15 02:05:30.000\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_3decimals);\n    output.emplace_back(\"3_decimals_hmsu\", \"2010-02-15 02:05:30.420\", datetime(2010u, 2u, 15u, 2u, 5u, 30u, 420000u), meta_3decimals);\n    output.emplace_back(\"3_decimals_min\", \"0000-01-01 00:00:00.000\", datetime(0u, 1u, 1u), meta_3decimals);\n    output.emplace_back(\"3_decimals_max\", \"9999-12-31 23:59:59.999\", datetime(9999u, 12u, 31u, 23u, 59u, 59u, 999000u), meta_3decimals);\n\n    auto meta_4decimals = meta_builder().type(type).decimals(4).build();\n    output.emplace_back(\"4_decimals_hms\", \"2010-02-15 02:05:30.0000\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_4decimals);\n    output.emplace_back(\"4_decimals_hmsu\", \"2010-02-15 02:05:30.4267\", datetime(2010u, 2u, 15u, 2u, 5u, 30u, 426700u), meta_4decimals);\n    output.emplace_back(\"4_decimals_min\", \"0000-01-01 00:00:00.0000\", datetime(0u, 1u, 1u), meta_4decimals);\n    output.emplace_back(\"4_decimals_max\", \"9999-12-31 23:59:59.9999\", datetime(9999u, 12u, 31u, 23u, 59u, 59u, 999900u), meta_4decimals);\n\n    auto meta_5decimals = meta_builder().type(type).decimals(5).build();\n    output.emplace_back(\"5_decimals_hms\", \"2010-02-15 02:05:30.00000\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_5decimals);\n    output.emplace_back(\"5_decimals_hmsu\", \"2010-02-15 02:05:30.00239\", datetime(2010u, 2u, 15u, 2u, 5u, 30u, 2390u), meta_5decimals);\n    output.emplace_back(\"5_decimals_min\", \"0000-01-01 00:00:00.00000\", datetime(0u, 1u, 1u), meta_5decimals);\n    output.emplace_back(\"5_decimals_max\", \"9999-12-31 23:59:59.99999\", datetime(9999u, 12u, 31u, 23u, 59u, 59u, 999990u), meta_5decimals);\n\n    auto meta_6decimals = meta_builder().type(type).decimals(6).build();\n    output.emplace_back(\"6_decimals_hms\", \"2010-02-15 02:05:30.000000\", datetime(2010u, 2u, 15u, 2u, 5u, 30u), meta_6decimals);\n    output.emplace_back(\"6_decimals_hmsu\", \"2010-02-15 02:05:30.002395\", datetime(2010u, 2u, 15u, 2u, 5u, 30u, 2395u), meta_6decimals);\n    output.emplace_back(\"6_decimals_min\", \"0000-01-01 00:00:00.000000\", datetime(0u, 1u, 1u), meta_6decimals);\n    output.emplace_back(\"6_decimals_max\", \"9999-12-31 23:59:59.999999\", datetime(9999u, 12u, 31u, 23u, 59u, 59u, 999999u), meta_6decimals);\n\n    // not a real case, we cap decimals to 6\n    auto meta_7decimals = meta_builder().type(type).decimals(7).build();\n    output.emplace_back(\"7_decimals\", \"2010-02-15 02:05:30.002395\", datetime(2010, 2, 15, 2, 5, 30, 2395), meta_7decimals);\n\n    // Invalid datetimes (because their date is invalid)\n    output.emplace_back(\"0_decimals_zero\", \"0000-00-00 00:00:00\", datetime(), meta_0decimals);\n    output.emplace_back(\"0_decimals_invalid_date\", \"2010-11-31 01:10:59\", datetime(2010u, 11u, 31u, 1u, 10u, 59u), meta_0decimals);\n    output.emplace_back(\"0_decimals_zero_month\", \"2010-00-31 01:10:59\", datetime(2010u, 0u, 31u, 1u, 10u, 59u), meta_0decimals);\n    output.emplace_back(\"0_decimals_zero_day\", \"2010-11-00 01:10:59\", datetime(2010u, 11u, 0u, 1u, 10u, 59u), meta_0decimals);\n    output.emplace_back(\"0_decimals_zero_month_day\", \"2010-00-00 01:10:59\", datetime(2010u, 0u, 0u, 1u, 10u, 59u), meta_0decimals);\n\n    output.emplace_back(\"1_decimals_zero\", \"0000-00-00 00:00:00.0\", datetime(), meta_1decimal);\n    output.emplace_back(\"1_decimals_invalid_date\", \"2010-11-31 01:10:59.9\", datetime(2010u, 11u, 31u, 1u, 10u, 59u, 900000u), meta_1decimal);\n    output.emplace_back(\"1_decimals_zero_month\", \"2010-00-31 01:10:59.9\", datetime(2010u, 0u, 31u, 1u, 10u, 59u, 900000u), meta_1decimal);\n    output.emplace_back(\"1_decimals_zero_day\", \"2010-11-00 01:10:59.9\", datetime(2010u, 11u, 0u, 1u, 10u, 59u, 900000u), meta_1decimal);\n    output.emplace_back(\"1_decimals_zero_month_day\", \"2010-00-00 01:10:59.9\", datetime(2010u, 0u, 0u, 1u, 10u, 59u, 900000u), meta_1decimal);\n\n    output.emplace_back(\"2_decimals_zero\", \"0000-00-00 00:00:00.00\", datetime(), meta_2decimals);\n    output.emplace_back(\"2_decimals_invalid_date\", \"2010-11-31 01:10:59.98\", datetime(2010u, 11u, 31u, 1u, 10u, 59u, 980000u), meta_2decimals);\n    output.emplace_back(\"2_decimals_zero_month\", \"2010-00-31 01:10:59.98\", datetime(2010u, 0u, 31u, 1u, 10u, 59u, 980000u), meta_2decimals);\n    output.emplace_back(\"2_decimals_zero_day\", \"2010-11-00 01:10:59.98\", datetime(2010u, 11u, 0u, 1u, 10u, 59u, 980000u), meta_2decimals);\n    output.emplace_back(\"2_decimals_zero_month_day\", \"2010-00-00 01:10:59.98\", datetime(2010u, 0u, 0u, 1u, 10u, 59u, 980000u), meta_2decimals);\n\n    output.emplace_back(\"3_decimals_zero\", \"0000-00-00 00:00:00.000\", datetime(), meta_3decimals);\n    output.emplace_back(\"3_decimals_invalid_date\", \"2010-11-31 01:10:59.987\", datetime(2010u, 11u, 31u, 1u, 10u, 59u, 987000u), meta_3decimals);\n    output.emplace_back(\"3_decimals_zero_month\", \"2010-00-31 01:10:59.987\", datetime(2010u, 0u, 31u, 1u, 10u, 59u, 987000u), meta_3decimals);\n    output.emplace_back(\"3_decimals_zero_day\", \"2010-11-00 01:10:59.987\", datetime(2010u, 11u, 0u, 1u, 10u, 59u, 987000u), meta_3decimals);\n    output.emplace_back(\"3_decimals_zero_month_day\", \"2010-00-00 01:10:59.987\", datetime(2010u, 0u, 0u, 1u, 10u, 59u, 987000u), meta_3decimals);\n\n    output.emplace_back(\"4_decimals_zero\", \"0000-00-00 00:00:00.0000\", datetime(), meta_4decimals);\n    output.emplace_back(\"4_decimals_invalid_date\", \"2010-11-31 01:10:59.9876\", datetime(2010u, 11u, 31u, 1u, 10u, 59u, 987600u), meta_4decimals);\n    output.emplace_back(\"4_decimals_zero_month\", \"2010-00-31 01:10:59.9876\", datetime(2010u, 0u, 31u, 1u, 10u, 59u, 987600u), meta_4decimals);\n    output.emplace_back(\"4_decimals_zero_day\", \"2010-11-00 01:10:59.9876\", datetime(2010u, 11u, 0u, 1u, 10u, 59u, 987600u), meta_4decimals);\n    output.emplace_back(\"4_decimals_zero_month_day\", \"2010-00-00 01:10:59.9876\", datetime(2010u, 0u, 0u, 1u, 10u, 59u, 987600u), meta_4decimals);\n\n    output.emplace_back(\"5_decimals_zero\", \"0000-00-00 00:00:00.00000\", datetime(), meta_5decimals);\n    output.emplace_back(\"5_decimals_invalid_date\", \"2010-11-31 01:10:59.98765\", datetime(2010u, 11u, 31u, 1u, 10u, 59u, 987650u), meta_5decimals);\n    output.emplace_back(\"5_decimals_zero_month\", \"2010-00-31 01:10:59.98765\", datetime(2010u, 0u, 31u, 1u, 10u, 59u, 987650u), meta_5decimals);\n    output.emplace_back(\"5_decimals_zero_day\", \"2010-11-00 01:10:59.98765\", datetime(2010u, 11u, 0u, 1u, 10u, 59u, 987650u), meta_5decimals);\n    output.emplace_back(\"5_decimals_zero_month_day\", \"2010-00-00 01:10:59.98765\", datetime(2010u, 0u, 0u, 1u, 10u, 59u, 987650u), meta_5decimals);\n\n    output.emplace_back(\"6_decimals_zero\", \"0000-00-00 00:00:00.000000\", datetime(), meta_6decimals);\n    output.emplace_back(\"6_decimals_invalid_date\", \"2010-11-31 01:10:59.987654\", datetime(2010u, 11u, 31u, 1u, 10u, 59u, 987654u), meta_6decimals);\n    output.emplace_back(\"6_decimals_zero_month\", \"2010-00-31 01:10:59.987654\", datetime(2010u, 0u, 31u, 1u, 10u, 59u, 987654u), meta_6decimals);\n    output.emplace_back(\"6_decimals_zero_day\", \"2010-11-00 01:10:59.987654\", datetime(2010u, 11u, 0u, 1u, 10u, 59u, 987654u), meta_6decimals);\n    output.emplace_back(\"6_decimals_zero_month_day\", \"2010-00-00 01:10:59.987654\", datetime(2010u, 0u, 0u, 1u, 10u, 59u, 987654u), meta_6decimals);\n}\n\nvoid add_time_samples(std::vector<success_sample>& output)\n{\n    auto meta_0decimals = meta_builder().type(column_type::time).decimals(0).build();\n    output.emplace_back(\"0_decimals_positive_h\", \"01:00:00\", maket(1, 0, 0), meta_0decimals);\n    output.emplace_back(\"0_decimals_positive_hm\", \"12:03:00\", maket(12, 3, 0), meta_0decimals);\n    output.emplace_back(\"0_decimals_positive_hms\", \"14:51:23\", maket(14, 51, 23), meta_0decimals);\n    output.emplace_back(\"0_decimals_max\", \"838:59:59\", maket(838, 59, 59), meta_0decimals);\n    output.emplace_back(\"0_decimals_negative_h\", \"-06:00:00\", -maket(6, 0, 0), meta_0decimals);\n    output.emplace_back(\"0_decimals_negative_hm\", \"-12:03:00\", -maket(12, 3, 0), meta_0decimals);\n    output.emplace_back(\"0_decimals_negative_hms\", \"-14:51:23\", -maket(14, 51, 23), meta_0decimals);\n    output.emplace_back(\"0_decimals_min\", \"-838:59:59\", -maket(838, 59, 59), meta_0decimals);\n    output.emplace_back(\"0_decimals_zero\", \"00:00:00\", maket(0, 0, 0), meta_0decimals);\n    output.emplace_back(\"0_decimals_negative_h0\", \"-00:51:23\", -maket(0, 51, 23), meta_0decimals);\n\n    auto meta_1decimal = meta_builder().type(column_type::time).decimals(1).build();\n    output.emplace_back(\"1_decimals_positive_hms\", \"14:51:23.0\", maket(14, 51, 23), meta_1decimal);\n    output.emplace_back(\"1_decimals_positive_hmsu\", \"14:51:23.5\", maket(14, 51, 23, 500000), meta_1decimal);\n    output.emplace_back(\"1_decimals_max\", \"838:59:58.9\", maket(838, 59, 58, 900000), meta_1decimal);\n    output.emplace_back(\"1_decimals_negative_hms\", \"-14:51:23.0\", -maket(14, 51, 23), meta_1decimal);\n    output.emplace_back(\"1_decimals_negative_hmsu\", \"-14:51:23.5\", -maket(14, 51, 23, 500000), meta_1decimal);\n    output.emplace_back(\"1_decimals_min\", \"-838:59:58.9\", -maket(838, 59, 58, 900000), meta_1decimal);\n    output.emplace_back(\"1_decimals_zero\", \"00:00:00.0\", maket(0, 0, 0), meta_1decimal);\n    output.emplace_back(\"1_decimals_negative_h0\", \"-00:51:23.1\", -maket(0, 51, 23, 100000), meta_1decimal);\n\n    auto meta_2decimals = meta_builder().type(column_type::time).decimals(2).build();\n    output.emplace_back(\"2_decimals_positive_hms\", \"14:51:23.00\", maket(14, 51, 23), meta_2decimals);\n    output.emplace_back(\"2_decimals_positive_hmsu\", \"14:51:23.52\", maket(14, 51, 23, 520000), meta_2decimals);\n    output.emplace_back(\"2_decimals_max\", \"838:59:58.99\", maket(838, 59, 58, 990000), meta_2decimals);\n    output.emplace_back(\"2_decimals_negative_hms\", \"-14:51:23.00\", -maket(14, 51, 23), meta_2decimals);\n    output.emplace_back(\"2_decimals_negative_hmsu\", \"-14:51:23.50\", -maket(14, 51, 23, 500000), meta_2decimals);\n    output.emplace_back(\"2_decimals_min\", \"-838:59:58.99\", -maket(838, 59, 58, 990000), meta_2decimals);\n    output.emplace_back(\"2_decimals_zero\", \"00:00:00.00\", maket(0, 0, 0), meta_2decimals);\n    output.emplace_back(\"2_decimals_negative_h0\", \"-00:51:23.12\", -maket(0, 51, 23, 120000), meta_2decimals);\n\n    auto meta_3decimals = meta_builder().type(column_type::time).decimals(3).build();\n    output.emplace_back(\"3_decimals_positive_hms\", \"14:51:23.000\", maket(14, 51, 23), meta_3decimals);\n    output.emplace_back(\"3_decimals_positive_hmsu\", \"14:51:23.501\", maket(14, 51, 23, 501000), meta_3decimals);\n    output.emplace_back(\"3_decimals_max\", \"838:59:58.999\", maket(838, 59, 58, 999000), meta_3decimals);\n    output.emplace_back(\"3_decimals_negative_hms\", \"-14:51:23.000\", -maket(14, 51, 23), meta_3decimals);\n    output.emplace_back(\"3_decimals_negative_hmsu\", \"-14:51:23.003\", -maket(14, 51, 23, 3000), meta_3decimals);\n    output.emplace_back(\"3_decimals_min\", \"-838:59:58.999\", -maket(838, 59, 58, 999000), meta_3decimals);\n    output.emplace_back(\"3_decimals_zero\", \"00:00:00.000\", maket(0, 0, 0), meta_3decimals);\n    output.emplace_back(\"3_decimals_negative_h0\", \"-00:51:23.123\", -maket(0, 51, 23, 123000), meta_3decimals);\n\n    auto meta_4decimals = meta_builder().type(column_type::time).decimals(4).build();\n    output.emplace_back(\"4_decimals_positive_hms\", \"14:51:23.0000\", maket(14, 51, 23), meta_4decimals);\n    output.emplace_back(\"4_decimals_positive_hmsu\", \"14:51:23.5017\", maket(14, 51, 23, 501700), meta_4decimals);\n    output.emplace_back(\"4_decimals_max\", \"838:59:58.9999\", maket(838, 59, 58, 999900), meta_4decimals);\n    output.emplace_back(\"4_decimals_negative_hms\", \"-14:51:23.0000\", -maket(14, 51, 23), meta_4decimals);\n    output.emplace_back(\"4_decimals_negative_hmsu\", \"-14:51:23.0038\", -maket(14, 51, 23, 3800), meta_4decimals);\n    output.emplace_back(\"4_decimals_min\", \"-838:59:58.9999\", -maket(838, 59, 58, 999900), meta_4decimals);\n    output.emplace_back(\"4_decimals_zero\", \"00:00:00.0000\", maket(0, 0, 0), meta_4decimals);\n    output.emplace_back(\"4_decimals_negative_h0\", \"-00:51:23.1234\", -maket(0, 51, 23, 123400), meta_4decimals);\n\n    auto meta_5decimals = meta_builder().type(column_type::time).decimals(5).build();\n    output.emplace_back(\"5_decimals_positive_hms\", \"14:51:23.00000\", maket(14, 51, 23), meta_5decimals);\n    output.emplace_back(\"5_decimals_positive_hmsu\", \"14:51:23.50171\", maket(14, 51, 23, 501710), meta_5decimals);\n    output.emplace_back(\"5_decimals_max\", \"838:59:58.99999\", maket(838, 59, 58, 999990), meta_5decimals);\n    output.emplace_back(\"5_decimals_negative_hms\", \"-14:51:23.00000\", -maket(14, 51, 23), meta_5decimals);\n    output.emplace_back(\"5_decimals_negative_hmsu\", \"-14:51:23.00009\", -maket(14, 51, 23, 90), meta_5decimals);\n    output.emplace_back(\"5_decimals_min\", \"-838:59:58.99999\", -maket(838, 59, 58, 999990), meta_5decimals);\n    output.emplace_back(\"5_decimals_zero\", \"00:00:00.00000\", maket(0, 0, 0), meta_5decimals);\n    output.emplace_back(\"5_decimals_negative_h0\", \"-00:51:23.12345\", -maket(0, 51, 23, 123450), meta_5decimals);\n\n    auto meta_6decimals = meta_builder().type(column_type::time).decimals(6).build();\n    output.emplace_back(\"6_decimals_positive_hms\", \"14:51:23.000000\", maket(14, 51, 23), meta_6decimals);\n    output.emplace_back(\"6_decimals_positive_hmsu\", \"14:51:23.501717\", maket(14, 51, 23, 501717), meta_6decimals);\n    output.emplace_back(\"6_decimals_max\", \"838:59:58.999999\", maket(838, 59, 58, 999999), meta_6decimals);\n    output.emplace_back(\"6_decimals_negative_hms\", \"-14:51:23.000000\", -maket(14, 51, 23), meta_6decimals);\n    output.emplace_back(\"6_decimals_negative_hmsu\", \"-14:51:23.900000\", -maket(14, 51, 23, 900000), meta_6decimals);\n    output.emplace_back(\"6_decimals_min\", \"-838:59:58.999999\", -maket(838, 59, 58, 999999), meta_6decimals);\n    output.emplace_back(\"6_decimals_zero\", \"00:00:00.000000\", maket(0, 0, 0), meta_6decimals);\n    output.emplace_back(\"6_decimals_negative_h0\", \"-00:51:23.123456\", -maket(0, 51, 23, 123456), meta_6decimals);\n\n    // This is not a real case - we cap anything above 6 decimals to 6\n    auto meta_7decimals = meta_builder().type(column_type::time).decimals(7).build();\n    output.emplace_back(\"7_decimals\", \"14:51:23.501717\", maket(14, 51, 23, 501717), meta_7decimals);\n}\n\nstd::vector<success_sample> make_all_samples()\n{\n    std::vector<success_sample> res;\n    add_string_samples(res);\n    add_blob_samples(res);\n    add_int_samples(res);\n    add_bit_types(res);\n    add_float_samples<float>(column_type::float_, res);\n    add_float_samples<double>(column_type::double_, res);\n    add_date_samples(res);\n    add_datetime_samples(column_type::datetime, res);\n    add_datetime_samples(column_type::timestamp, res);\n    add_time_samples(res);\n    return res;\n}\n\nBOOST_DATA_TEST_CASE(ok, data::make(make_all_samples()))\n{\n    field_view actual_value;\n    auto err = detail::deserialize_text_field(sample.from, sample.meta, actual_value);\n\n    BOOST_TEST(err == detail::deserialize_errc::ok);\n    BOOST_TEST(actual_value == sample.expected);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n//\n// Error cases\n//\n\nBOOST_AUTO_TEST_SUITE(deserialize_error)\n\nstruct error_sample\n{\n    std::string name;\n    string_view from;\n    metadata meta;\n    detail::deserialize_errc expected_err;\n\n    error_sample(\n        std::string&& name,\n        string_view from,\n        metadata meta,\n        detail::deserialize_errc expected_err = detail::deserialize_errc::protocol_value_error\n    ) :\n        name(std::move(name)),\n        from(from),\n        meta(std::move(meta)),\n        expected_err(expected_err)\n    {\n    }\n};\n\nstd::ostream& operator<<(std::ostream& os, const error_sample& input)\n{\n    return os << \"(input=\" << input.from\n              << \", type=\" << input.meta.type()\n              << \", name=\" << input.name\n              << \")\";\n}\n\nvoid add_int_samples(\n    column_type t,\n    std::vector<error_sample>& output\n)\n{\n    auto meta_signed = create_meta(t);\n    output.emplace_back(\"signed_blank\", \"\", meta_signed);\n    output.emplace_back(\"signed_non_number\", \"abtrf\", meta_signed);\n    output.emplace_back(\"signed_hex\", \"0x01\", meta_signed);\n    output.emplace_back(\"signed_fractional\", \"1.1\", meta_signed);\n    output.emplace_back(\"signed_exp\", \"2e10\", meta_signed);\n    output.emplace_back(\"signed_lt_min\", \"-9223372036854775809\", meta_signed);\n    output.emplace_back(\"signed_gt_max\", \"9223372036854775808\", meta_signed);\n\n    auto meta_unsigned = meta_builder().type(t).unsigned_flag(true).build();\n    output.emplace_back(\"unsigned_blank\", \"\", meta_unsigned);\n    output.emplace_back(\"unsigned_non_number\", \"abtrf\", meta_unsigned);\n    output.emplace_back(\"unsigned_hex\", \"0x01\", meta_unsigned);\n    output.emplace_back(\"unsigned_fractional\", \"1.1\", meta_unsigned);\n    output.emplace_back(\"unsigned_exp\", \"2e10\", meta_unsigned);\n    output.emplace_back(\"unsigned_lt_min\", \"-18446744073709551616\", meta_unsigned);\n    output.emplace_back(\"unsigned_gt_max\", \"18446744073709551616\", meta_unsigned);\n}\n\nvoid add_bit_samples(\n    std::vector<error_sample>& output\n)\n{\n    auto meta = meta_builder().type(column_type::bit).unsigned_flag(true).build();\n    output.emplace_back(\"bit_string_view_too_short\", \"\", meta);\n    output.emplace_back(\"bit_string_view_too_long\", \"123456789\", meta);\n}\n\nvoid add_float_samples(\n    column_type t,\n    string_view lt_min,\n    string_view gt_max,\n    std::vector<error_sample>& output\n)\n{\n    auto meta = create_meta(t);\n    output.emplace_back(\"blank\", \"\", meta);\n    output.emplace_back(\"non_number\", \"abtrf\", meta);\n    output.emplace_back(\"lt_min\", lt_min, meta);\n    output.emplace_back(\"gt_max\", gt_max, meta);\n    output.emplace_back(\"inf\", \"inf\", meta); // inf values not allowed by SQL std\n    output.emplace_back(\"minus_inf\", \"-inf\", meta);\n    output.emplace_back(\"nan\", \"nan\", meta); // nan values not allowed by SQL std\n    output.emplace_back(\"minus_nan\", \"-nan\", meta);\n}\n\nvoid add_date_samples(std::vector<error_sample>& output)\n{\n    auto meta = create_meta(column_type::date);\n    output.emplace_back(\"empty\",            \"\", meta);\n    output.emplace_back(\"too_short\",        \"2020-05-2\", meta);\n    output.emplace_back(\"too_long\",         \"02020-05-02\", meta);\n    output.emplace_back(\"bad_delimiter\",    \"2020:05:02\", meta);\n    output.emplace_back(\"too_many_groups\",  \"20-20-05-2\", meta);\n    output.emplace_back(\"too_few_groups\",   \"2020-00005\", meta);\n    output.emplace_back(\"incomplete_year\",  \"999-05-005\", meta);\n    output.emplace_back(\"hex\",              \"ffff-ff-ff\", meta);\n    output.emplace_back(\"null_value\",       makesv(\"2020-05-\\02\"), meta);\n    output.emplace_back(\"long_year\",     \"10000-05-2\", meta);\n    output.emplace_back(\"long_month\",       \"2010-005-2\", meta);\n    output.emplace_back(\"long_day\",         \"2010-5-002\", meta);\n    output.emplace_back(\"negative_year\",    \"-001-05-02\", meta);\n    output.emplace_back(\"invalid_month\",    \"2010-13-02\", meta);\n    output.emplace_back(\"invalid_month_max\",\"2010-99-02\", meta);\n    output.emplace_back(\"negative_month\",   \"2010--5-02\", meta);\n    output.emplace_back(\"invalid_day\",      \"2010-05-32\", meta);\n    output.emplace_back(\"invalid_day_max\",  \"2010-05-99\", meta);\n    output.emplace_back(\"negative_day\",     \"2010-05--2\", meta);\n}\n\nvoid add_datetime_samples(\n    column_type t,\n    std::vector<error_sample>& output\n)\n{\n    auto meta_0decimals = meta_builder().type(t).decimals(0).build();\n    auto meta_1decimals = meta_builder().type(t).decimals(1).build();\n    auto meta_2decimals = meta_builder().type(t).decimals(2).build();\n    auto meta_3decimals = meta_builder().type(t).decimals(3).build();\n    auto meta_4decimals = meta_builder().type(t).decimals(4).build();\n    auto meta_5decimals = meta_builder().type(t).decimals(5).build();\n    auto meta_6decimals = meta_builder().type(t).decimals(6).build();\n\n    output.emplace_back(\"empty\",            \"\", meta_0decimals);\n    output.emplace_back(\"too_short_0\",      \"2020-05-02 23:01:0\", meta_0decimals);\n    output.emplace_back(\"too_short_1\",      \"2020-05-02 23:01:0.1\", meta_1decimals);\n    output.emplace_back(\"too_short_2\",      \"2020-05-02 23:01:00.1\", meta_2decimals);\n    output.emplace_back(\"too_short_3\",      \"2020-05-02 23:01:00.11\", meta_3decimals);\n    output.emplace_back(\"too_short_4\",      \"2020-05-02 23:01:00.111\", meta_4decimals);\n    output.emplace_back(\"too_short_5\",      \"2020-05-02 23:01:00.1111\", meta_5decimals);\n    output.emplace_back(\"too_short_6\",      \"2020-05-02 23:01:00.11111\", meta_6decimals);\n    output.emplace_back(\"too_long_0\",       \"2020-05-02 23:01:00.8\", meta_0decimals);\n    output.emplace_back(\"too_long_1\",       \"2020-05-02 23:01:00.98\", meta_1decimals);\n    output.emplace_back(\"too_long_2\",       \"2020-05-02 23:01:00.998\", meta_2decimals);\n    output.emplace_back(\"too_long_3\",       \"2020-05-02 23:01:00.9998\", meta_3decimals);\n    output.emplace_back(\"too_long_4\",       \"2020-05-02 23:01:00.99998\", meta_4decimals);\n    output.emplace_back(\"too_long_5\",       \"2020-05-02 23:01:00.999998\", meta_5decimals);\n    output.emplace_back(\"too_long_6\",       \"2020-05-02 23:01:00.9999998\", meta_6decimals);\n    output.emplace_back(\"no_decimals_1\",    \"2020-05-02 23:01:00  \", meta_1decimals);\n    output.emplace_back(\"no_decimals_2\",    \"2020-05-02 23:01:00   \", meta_2decimals);\n    output.emplace_back(\"no_decimals_3\",    \"2020-05-02 23:01:00     \", meta_3decimals);\n    output.emplace_back(\"no_decimals_4\",    \"2020-05-02 23:01:00      \", meta_4decimals);\n    output.emplace_back(\"no_decimals_5\",    \"2020-05-02 23:01:00       \", meta_5decimals);\n    output.emplace_back(\"no_decimals_6\",    \"2020-05-02 23:01:00        \", meta_6decimals);\n    output.emplace_back(\"trailing_0\",       \"2020-05-02 23:01:0p\", meta_0decimals);\n    output.emplace_back(\"trailing_1\",       \"2020-05-02 23:01:00.p\", meta_1decimals);\n    output.emplace_back(\"trailing_2\",       \"2020-05-02 23:01:00.1p\", meta_2decimals);\n    output.emplace_back(\"trailing_3\",       \"2020-05-02 23:01:00.12p\", meta_3decimals);\n    output.emplace_back(\"trailing_4\",       \"2020-05-02 23:01:00.123p\", meta_4decimals);\n    output.emplace_back(\"trailing_5\",       \"2020-05-02 23:01:00.1234p\", meta_5decimals);\n    output.emplace_back(\"trailing_6\",       \"2020-05-02 23:01:00.12345p\", meta_6decimals);\n    output.emplace_back(\"bad_delimiter\",    \"2020-05-02 23-01-00\", meta_0decimals);\n    output.emplace_back(\"missing_1gp_0\",    \"2020-05-02 23:01:  \", meta_0decimals);\n    output.emplace_back(\"missing_2gp_0\",    \"2020-05-02 23:     \", meta_0decimals);\n    output.emplace_back(\"missing_3gp_0\",    \"2020-05-02         \", meta_0decimals);\n    output.emplace_back(\"missing_1gp_1\",    \"2020-05-02 23:01:.9  \", meta_0decimals);\n    output.emplace_back(\"missing_2gp_1\",    \"2020-05-02 23:.9     \", meta_0decimals);\n    output.emplace_back(\"missing_3gp_1\",    \"2020-05-02.9         \", meta_0decimals);\n    output.emplace_back(\"invalid_year\",     \"10000-05-02 24:20:20.1\", meta_2decimals);\n    output.emplace_back(\"negative_year\",    \"-100-05-02 24:20:20\", meta_0decimals);\n    output.emplace_back(\"invalid_month\",    \"2020-13-02 24:20:20\", meta_0decimals);\n    output.emplace_back(\"negative_month\",   \"2020--5-02 24:20:20\", meta_0decimals);\n    output.emplace_back(\"invalid_day\",      \"2020-05-32 24:20:20\", meta_0decimals);\n    output.emplace_back(\"negative_day\",     \"2020-05--2 24:20:20\", meta_0decimals);\n    output.emplace_back(\"invalid_hour\",     \"2020-05-02 24:20:20\", meta_0decimals);\n    output.emplace_back(\"negative_hour\",    \"2020-05-02 -2:20:20\", meta_0decimals);\n    output.emplace_back(\"invalid_min\",      \"2020-05-02 22:60:20\", meta_0decimals);\n    output.emplace_back(\"negative_min\",     \"2020-05-02 22:-1:20\", meta_0decimals);\n    output.emplace_back(\"invalid_sec\",      \"2020-05-02 22:06:60\", meta_0decimals);\n    output.emplace_back(\"negative_sec\",     \"2020-05-02 22:06:-1\", meta_0decimals);\n    output.emplace_back(\"negative_micro_2\", \"2020-05-02 22:06:01.-1\", meta_2decimals);\n    output.emplace_back(\"negative_micro_3\", \"2020-05-02 22:06:01.-12\", meta_3decimals);\n    output.emplace_back(\"negative_micro_4\", \"2020-05-02 22:06:01.-123\", meta_4decimals);\n    output.emplace_back(\"negative_micro_5\", \"2020-05-02 22:06:01.-1234\", meta_5decimals);\n    output.emplace_back(\"negative_micro_6\", \"2020-05-02 22:06:01.-12345\", meta_6decimals);\n}\n\nvoid add_time_samples(std::vector<error_sample>& output)\n{\n    auto meta_0decimals = meta_builder().type(column_type::time).decimals(0).build();\n    auto meta_1decimals = meta_builder().type(column_type::time).decimals(1).build();\n    auto meta_2decimals = meta_builder().type(column_type::time).decimals(2).build();\n    auto meta_3decimals = meta_builder().type(column_type::time).decimals(3).build();\n    auto meta_4decimals = meta_builder().type(column_type::time).decimals(4).build();\n    auto meta_5decimals = meta_builder().type(column_type::time).decimals(5).build();\n    auto meta_6decimals = meta_builder().type(column_type::time).decimals(6).build();\n\n    output.emplace_back(\"empty\",           \"\", meta_0decimals);\n    output.emplace_back(\"not_numbers\",     \"abjkjdb67\", meta_0decimals);\n    output.emplace_back(\"too_short_0\",     \"1:20:20\", meta_0decimals);\n    output.emplace_back(\"too_short_1\",     \"1:20:20.1\", meta_1decimals);\n    output.emplace_back(\"too_short_2\",     \"01:20:20.1\", meta_2decimals);\n    output.emplace_back(\"too_short_3\",     \"01:20:20.12\", meta_3decimals);\n    output.emplace_back(\"too_short_4\",     \"01:20:20.123\", meta_4decimals);\n    output.emplace_back(\"too_short_5\",     \"01:20:20.1234\", meta_5decimals);\n    output.emplace_back(\"too_short_6\",     \"01:20:20.12345\", meta_6decimals);\n    output.emplace_back(\"too_long_0\",      \"-9999:40:40\", meta_0decimals);\n    output.emplace_back(\"too_long_1\",      \"-9999:40:40.1\", meta_1decimals);\n    output.emplace_back(\"too_long_2\",      \"-9999:40:40.12\", meta_2decimals);\n    output.emplace_back(\"too_long_3\",      \"-9999:40:40.123\", meta_3decimals);\n    output.emplace_back(\"too_long_4\",      \"-9999:40:40.1234\", meta_4decimals);\n    output.emplace_back(\"too_long_5\",      \"-9999:40:40.12345\", meta_5decimals);\n    output.emplace_back(\"too_long_6\",      \"-9999:40:40.123456\", meta_6decimals);\n    output.emplace_back(\"extra_long\",      \"-99999999:40:40.12345678\", meta_6decimals);\n    output.emplace_back(\"extra_long2\",     \"99999999999:40:40\", meta_6decimals);\n    output.emplace_back(\"decimals_0\",      \"01:20:20.1\", meta_0decimals);\n    output.emplace_back(\"no_decimals_1\",   \"01:20:20  \", meta_1decimals);\n    output.emplace_back(\"no_decimals_2\",   \"01:20:20   \", meta_2decimals);\n    output.emplace_back(\"no_decimals_3\",   \"01:20:20    \", meta_3decimals);\n    output.emplace_back(\"no_decimals_4\",   \"01:20:20     \", meta_4decimals);\n    output.emplace_back(\"no_decimals_5\",   \"01:20:20      \", meta_5decimals);\n    output.emplace_back(\"no_decimals_6\",   \"01:20:20       \", meta_6decimals);\n    output.emplace_back(\"bad_delimiter\",   \"01-20-20\", meta_0decimals);\n    output.emplace_back(\"missing_1gp_0\",   \"23:01:  \", meta_0decimals);\n    output.emplace_back(\"missing_2gp_0\",   \"23:     \", meta_0decimals);\n    output.emplace_back(\"missing_1gp_1\",   \"23:01:.9  \", meta_1decimals);\n    output.emplace_back(\"missing_2gp_1\",   \"23:.9     \", meta_1decimals);\n    output.emplace_back(\"invalid_min\",     \"22:60:20\", meta_0decimals);\n    output.emplace_back(\"negative_min\",    \"22:-1:20\", meta_0decimals);\n    output.emplace_back(\"invalid_sec\",     \"22:06:60\", meta_0decimals);\n    output.emplace_back(\"negative_sec\",    \"22:06:-1\", meta_0decimals);\n    output.emplace_back(\"invalid_micro_1\", \"22:06:01.99\", meta_1decimals);\n    output.emplace_back(\"invalid_micro_2\", \"22:06:01.999\", meta_2decimals);\n    output.emplace_back(\"invalid_micro_3\", \"22:06:01.9999\", meta_3decimals);\n    output.emplace_back(\"invalid_micro_4\", \"22:06:01.99999\", meta_4decimals);\n    output.emplace_back(\"invalid_micro_5\", \"22:06:01.999999\", meta_5decimals);\n    output.emplace_back(\"invalid_micro_6\", \"22:06:01.9999999\", meta_6decimals);\n    output.emplace_back(\"negative_micro\",  \"22:06:01.-1\", meta_2decimals);\n    output.emplace_back(\"lt_min\",          \"-900:00:00.00\", meta_2decimals);\n    output.emplace_back(\"gt_max\",          \"900:00:00.00\", meta_2decimals);\n    output.emplace_back(\"invalid_sign\",    \"x670:00:00.00\", meta_2decimals);\n    output.emplace_back(\"null_char\",       makesv(\"20:00:\\00.00\"), meta_2decimals);\n    output.emplace_back(\"trailing_0\",      \"22:06:01k\", meta_0decimals);\n    output.emplace_back(\"trailing_1\",      \"22:06:01.1k\", meta_1decimals);\n    output.emplace_back(\"trailing_2\",      \"22:06:01.12k\", meta_2decimals);\n    output.emplace_back(\"trailing_3\",      \"22:06:01.123k\", meta_3decimals);\n    output.emplace_back(\"trailing_4\",      \"22:06:01.1234k\", meta_4decimals);\n    output.emplace_back(\"trailing_5\",      \"22:06:01.12345k\", meta_5decimals);\n    output.emplace_back(\"trailing_6\",      \"22:06:01.123456k\", meta_6decimals);\n    output.emplace_back(\"double_sign\",     \"--22:06:01.123456\", meta_6decimals);\n}\n\nstd::vector<error_sample> make_all_samples()\n{\n    std::vector<error_sample> res;\n    add_int_samples(column_type::tinyint, res);\n    add_int_samples(column_type::smallint, res);\n    add_int_samples(column_type::mediumint, res);\n    add_int_samples(column_type::int_, res);\n    add_int_samples(column_type::bigint, res);\n    add_int_samples(column_type::year, res);\n    add_bit_samples(res);\n    add_float_samples(column_type::float_, \"-2e90\", \"2e90\", res);\n    add_float_samples(column_type::double_, \"-2e9999\", \"2e9999\", res);\n    add_date_samples(res);\n    add_datetime_samples(column_type::datetime, res);\n    add_datetime_samples(column_type::timestamp, res);\n    add_time_samples(res);\n    return res;\n}\n\nBOOST_DATA_TEST_CASE(error, data::make(make_all_samples()))\n{\n    field_view actual_value;\n    auto err = detail::deserialize_text_field(sample.from, sample.meta, actual_value);\n    \n    BOOST_TEST(err == sample.expected_err);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// clang-format on\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/results.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <stdexcept>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_TEST_DONT_PRINT_LOG_VALUE(results::iterator)\n\nBOOST_AUTO_TEST_SUITE(test_results)\n\nresults create_initial_results()\n{\n    results res;\n    exec_access(get_iface(res))\n        .meta({meta_builder().type(column_type::varchar).build_coldef()})\n        .row(\"abc\")\n        .row(nullptr)\n        .ok(ok_builder().affected_rows(1).last_insert_id(2).warnings(3).info(\"1st\").more_results(true).build()\n        )\n        .meta({meta_builder().type(column_type::tinyint).build_coldef()})\n        .row(42)\n        .ok(ok_builder()\n                .affected_rows(4)\n                .last_insert_id(5)\n                .warnings(6)\n                .info(\"2nd\")\n                .out_params(true)\n                .more_results(true)\n                .build())\n        .ok(ok_builder().info(\"3rd\").build());\n    return res;\n}\n\nstruct fixture\n{\n    results result{create_initial_results()};\n};\n\nBOOST_AUTO_TEST_CASE(has_value)\n{\n    // Default construction\n    results result;\n    BOOST_TEST_REQUIRE(!result.has_value());\n\n    // With value\n    result = create_initial_results();\n    BOOST_TEST_REQUIRE(result.has_value());\n}\n\nBOOST_AUTO_TEST_SUITE(iterators)\n\nBOOST_FIXTURE_TEST_CASE(basic, fixture)\n{\n    // Obtain iterators\n    auto it = result.begin();   // should point to resultset 0\n    auto itend = result.end();  // should point to resultset 3 (1 past end)\n\n    // Check dereference\n    BOOST_TEST((*it).info() == \"1st\");\n    BOOST_TEST(it->info() == \"1st\");\n\n    // Check ==\n    BOOST_TEST(!(it == itend));\n    BOOST_TEST(!(itend == it));\n    BOOST_TEST(it == result.begin());\n    BOOST_TEST(it == it);\n    BOOST_TEST(itend == result.end());\n    BOOST_TEST(itend == itend);\n\n    // Check !=\n    BOOST_TEST(it != itend);\n    BOOST_TEST(itend != it);\n    BOOST_TEST(!(it != result.begin()));\n    BOOST_TEST(!(it != it));\n    BOOST_TEST(!(itend != result.end()));\n    BOOST_TEST(!(itend != itend));\n}\n\nBOOST_FIXTURE_TEST_CASE(prefix_increment, fixture)\n{\n    auto it = result.begin();\n    auto& ref = (++it);\n    BOOST_TEST(&ref == &it);\n    BOOST_TEST(it->info() == \"2nd\");\n    BOOST_TEST(it == result.begin() + 1);\n}\n\nBOOST_FIXTURE_TEST_CASE(postfix_increment, fixture)\n{\n    auto it = result.begin();\n    auto it2 = it++;\n    BOOST_TEST(it2 == result.begin());\n    BOOST_TEST(it == result.begin() + 1);\n    BOOST_TEST(it->info() == \"2nd\");\n}\n\nBOOST_FIXTURE_TEST_CASE(prefix_decrement, fixture)\n{\n    auto it = result.end();\n    auto& ref = (--it);\n    BOOST_TEST(&ref == &it);\n    BOOST_TEST(it->info() == \"3rd\");\n    BOOST_TEST(it == result.begin() + 2);\n}\n\nBOOST_FIXTURE_TEST_CASE(postfix_decrement, fixture)\n{\n    auto it = result.end();\n    auto it2 = it--;\n    BOOST_TEST(it2 == result.end());\n    BOOST_TEST(it == result.begin() + 2);\n    BOOST_TEST(it->info() == \"3rd\");\n}\n\nBOOST_FIXTURE_TEST_CASE(operator_square_brackets, fixture)\n{\n    auto it = result.begin();\n    BOOST_TEST(it[0].info() == \"1st\");\n    BOOST_TEST(it[1].info() == \"2nd\");\n    BOOST_TEST(it[2].info() == \"3rd\");\n}\n\nBOOST_FIXTURE_TEST_CASE(operator_plus, fixture)\n{\n    auto it = result.begin();\n\n    // Increment by 1\n    auto it2 = it + 1;\n    BOOST_TEST(it2->info() == \"2nd\");\n\n    // Reversed operands\n    it2 = 1 + it2;\n    BOOST_TEST(it2->info() == \"3rd\");\n\n    // Increment by more than 1\n    BOOST_TEST(result.begin() + 3 == result.end());\n\n    // Increment by 0\n    BOOST_TEST(result.begin() + 0 == result.begin());\n\n    // Negative increment\n    BOOST_TEST(result.end() + (-2) == result.begin() + 1);\n}\n\nBOOST_FIXTURE_TEST_CASE(operator_plus_equals, fixture)\n{\n    auto it = result.begin();\n\n    // Increment by 1\n    it += 1;\n    BOOST_TEST(it->info() == \"2nd\");\n\n    // Increment by more than\n    it += 2;\n    BOOST_TEST(it == result.end());\n\n    // Increment by 0\n    it += 0;\n    BOOST_TEST(it == result.end());\n\n    // Negative increment\n    it += (-2);\n    BOOST_TEST(it == result.begin() + 1);\n}\n\nBOOST_FIXTURE_TEST_CASE(operator_minus, fixture)\n{\n    auto it = result.end();\n\n    // Decrement by 1\n    auto it2 = it - 1;\n    BOOST_TEST(it2->info() == \"3rd\");\n\n    // Decrement by more than 1\n    BOOST_TEST(result.end() - 3 == result.begin());\n\n    // Decrement by 0\n    BOOST_TEST(result.end() - 0 == result.end());\n\n    // Negative decrement\n    BOOST_TEST(result.begin() - (-2) == result.begin() + 2);\n}\n\nBOOST_FIXTURE_TEST_CASE(operator_minus_equals, fixture)\n{\n    auto it = result.end();\n\n    // Decrement by 1\n    it -= 1;\n    BOOST_TEST(it->info() == \"3rd\");\n\n    // Decrement by more than 1\n    it -= 2;\n    BOOST_TEST(it == result.begin());\n\n    // Decrement by 0\n    it -= 0;\n    BOOST_TEST(it == result.begin());\n\n    // Negative decrement\n    it -= (-2);\n    BOOST_TEST(it == result.begin() + 2);\n}\n\nBOOST_FIXTURE_TEST_CASE(difference, fixture)\n{\n    auto first = result.begin();\n    auto second = result.begin() + 1;\n    auto last = result.end();\n\n    BOOST_TEST(last - first == 3);\n    BOOST_TEST(last - second == 2);\n    BOOST_TEST(last - last == 0);\n    BOOST_TEST(first - last == -3);\n    BOOST_TEST(second - last == -2);\n    BOOST_TEST(last - last == 0);\n    BOOST_TEST(first - first == 0);\n}\n\nBOOST_FIXTURE_TEST_CASE(relational, fixture)\n{\n    auto first = result.begin();\n    auto second = result.begin() + 1;\n    auto third = result.begin() + 2;\n\n    // Less than\n    BOOST_TEST(first < second);\n    BOOST_TEST(first <= second);\n    BOOST_TEST(!(first > second));\n    BOOST_TEST(!(first >= second));\n\n    // Equal\n    BOOST_TEST(!(second < second));\n    BOOST_TEST(second <= second);\n    BOOST_TEST(!(second > second));\n    BOOST_TEST(second >= second);\n\n    // Greater than\n    BOOST_TEST(!(third < second));\n    BOOST_TEST(!(third <= second));\n    BOOST_TEST(third > second);\n    BOOST_TEST(third >= second);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_FIXTURE_TEST_CASE(collection_fns, fixture)\n{\n    // at\n    BOOST_TEST(result.at(0).info() == \"1st\");\n    BOOST_TEST(result.at(1).info() == \"2nd\");\n    BOOST_TEST(result.at(2).info() == \"3rd\");\n    BOOST_CHECK_THROW(result.at(3), std::out_of_range);\n\n    // operator[]\n    BOOST_TEST(result[0].info() == \"1st\");\n    BOOST_TEST(result[1].info() == \"2nd\");\n    BOOST_TEST(result[2].info() == \"3rd\");\n\n    // front & back\n    BOOST_TEST(result.front().info() == \"1st\");\n    BOOST_TEST(result.back().info() == \"3rd\");\n\n    // size & empty\n    BOOST_TEST(result.size() == 3u);\n    BOOST_TEST(!result.empty());\n}\n\n// Verify view validity\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Having this in heap helps spot lifetime issues\n    std::unique_ptr<results> result{new results(create_initial_results())};\n\n    // Obtain references. Note that iterators and resultset_view's don't remain valid.\n    auto rws = result->rows();\n    auto meta = result->meta();\n    auto info = result->info();\n\n    // Move construct\n    results result2(std::move(*result));\n    result.reset();\n\n    // Make sure that views are still valid\n    BOOST_TEST(rws == makerows(1, \"abc\", nullptr));\n    check_meta(meta, {column_type::varchar});\n    BOOST_TEST(info == \"1st\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(result2.has_value());\n    BOOST_TEST(result2.rows() == makerows(1, \"abc\", nullptr));\n    check_meta(result2.meta(), {column_type::varchar});\n    BOOST_TEST(result2.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assignment)\n{\n    // Having this in heap helps spot lifetime issues\n    std::unique_ptr<results> result{new results(create_initial_results())};\n\n    // Obtain references\n    auto rws = result->rows();\n    auto meta = result->meta();\n    auto info = result->info();\n\n    // Move construct\n    results result2;\n    result2 = std::move(*result);\n    result.reset();\n\n    // Make sure that views are still valid\n    BOOST_TEST(rws == makerows(1, \"abc\", nullptr));\n    check_meta(meta, {column_type::varchar});\n    BOOST_TEST(info == \"1st\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(result2.has_value());\n    BOOST_TEST(result2.rows() == makerows(1, \"abc\", nullptr));\n    check_meta(result2.meta(), {column_type::varchar});\n    BOOST_TEST(result2.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/resultset.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/resultset.hpp>\n#include <boost/mysql/resultset_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_resultset)\n\nresults create_initial_results()\n{\n    results res;\n    exec_access(get_iface(res))\n        .meta({meta_builder().type(column_type::varchar).build_coldef()})\n        .row(\"abc\")\n        .row(nullptr)\n        .ok(ok_builder().affected_rows(1).last_insert_id(2).warnings(3).info(\"1st\").more_results(true).build()\n        )\n        .meta({meta_builder().type(column_type::tinyint).build_coldef()})\n        .row(42)\n        .ok(ok_builder().affected_rows(4).last_insert_id(5).warnings(6).info(\"2nd\").out_params(true).build());\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    resultset r;\n    BOOST_TEST(!r.has_value());\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_view_empty)\n{\n    resultset r{resultset_view{}};\n    BOOST_TEST(!r.has_value());\n}\n\nBOOST_AUTO_TEST_CASE(ctor_from_view)\n{\n    results result = create_initial_results();\n    resultset r{result.at(0)};\n    result = results();\n\n    BOOST_TEST_REQUIRE(r.has_value());\n    BOOST_TEST(r.rows() == makerows(1, \"abc\", nullptr));\n    check_meta(r.meta(), {column_type::varchar});\n    BOOST_TEST(r.affected_rows() == 1u);\n    BOOST_TEST(r.last_insert_id() == 2u);\n    BOOST_TEST(r.warning_count() == 3u);\n    BOOST_TEST(r.info() == \"1st\");\n    BOOST_TEST(!r.is_out_params());\n}\n\nBOOST_AUTO_TEST_CASE(assignment_from_view_empty)\n{\n    results result = create_initial_results();\n    resultset r{result.at(0)};\n    r = resultset();\n    result = results();\n\n    BOOST_TEST(!r.has_value());\n}\n\nBOOST_AUTO_TEST_CASE(assignment_from_view)\n{\n    results result = create_initial_results();\n    resultset r{result.at(0)};\n    r = result.at(1);\n    result = results();\n\n    BOOST_TEST_REQUIRE(r.has_value());\n    BOOST_TEST(r.rows() == makerows(1, 42));\n    check_meta(r.meta(), {column_type::tinyint});\n    BOOST_TEST(r.affected_rows() == 4u);\n    BOOST_TEST(r.last_insert_id() == 5u);\n    BOOST_TEST(r.warning_count() == 6u);\n    BOOST_TEST(r.info() == \"2nd\");\n    BOOST_TEST(r.is_out_params());\n}\n\n// View validity\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Construct object\n    results result = create_initial_results();\n    resultset r1(result.at(0));\n\n    // Obtain references\n    auto rws = r1.rows();\n    auto meta = r1.meta();\n    auto info = r1.info();\n\n    // Move construct\n    resultset r2(std::move(r1));\n    r1 = resultset();\n\n    // Make sure that views are still valid\n    BOOST_TEST(rws == makerows(1, \"abc\", nullptr));\n    check_meta(meta, {column_type::varchar});\n    BOOST_TEST(info == \"1st\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(r2.has_value());\n    BOOST_TEST(r2.rows() == makerows(1, \"abc\", nullptr));\n    check_meta(r2.meta(), {column_type::varchar});\n    BOOST_TEST(r2.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assignment)\n{\n    // Construct object\n    results result = create_initial_results();\n    resultset r1(result.at(0));\n\n    // Obtain references\n    auto rws = r1.rows();\n    auto meta = r1.meta();\n    auto info = r1.info();\n\n    // Move construct\n    resultset r2;\n    r2 = std::move(r1);\n    r1 = resultset();\n\n    // Make sure that views are still valid\n    BOOST_TEST(rws == makerows(1, \"abc\", nullptr));\n    BOOST_TEST_REQUIRE(meta.size() == 1u);\n    BOOST_TEST(meta[0].type() == column_type::varchar);\n    BOOST_TEST(info == \"1st\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(r2.has_value());\n    BOOST_TEST(r2.rows() == makerows(1, \"abc\", nullptr));\n    check_meta(r2.meta(), {column_type::varchar});\n    BOOST_TEST(r2.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/resultset_view.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/resultset_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_resultset_view)\n\nBOOST_AUTO_TEST_CASE(null_view)\n{\n    resultset_view v;\n    BOOST_TEST(!v.has_value());\n}\n\nBOOST_AUTO_TEST_CASE(valid_view)\n{\n    results result;\n    exec_access(get_iface(result))\n        .meta({meta_builder().type(column_type::tinyint).build_coldef()})\n        .row(42)\n        .ok(ok_builder().affected_rows(4).last_insert_id(5).warnings(6).info(\"2nd\").out_params(true).build());\n\n    auto v = result.at(0);\n    BOOST_TEST_REQUIRE(v.has_value());\n    BOOST_TEST(v.rows() == makerows(1, 42));\n    check_meta(v.meta(), {column_type::tinyint});\n    BOOST_TEST(v.affected_rows() == 4u);\n    BOOST_TEST(v.last_insert_id() == 5u);\n    BOOST_TEST(v.warning_count() == 6u);\n    BOOST_TEST(v.info() == \"2nd\");\n    BOOST_TEST(v.is_out_params());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/row.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <string>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_row)\n\n// Check that references, pointers and iterators to certain row's contents survive an operation\nstruct reference_checker\n{\n    row::const_iterator it;\n    row_view rv;\n\n    reference_checker(const row& r) : it(r.begin()), rv(r) {}\n\n    void check(const row& new_row)\n    {\n        BOOST_TEST(it == new_row.begin());\n        BOOST_TEST(rv == new_row);\n    }\n};\n\nstruct reference_checker_strs : reference_checker\n{\n    std::size_t string_index, blob_index;  // indices in the row where a string/blob field resides\n    const char* string_ptr;\n    const unsigned char* blob_ptr;\n\n    static void assert_ptrs_equal(const char* ptr1, const char* ptr2)\n    {\n        // Otherwise, UTF thinks it's a C string, tries to print it and causes Valgrind errors\n        BOOST_TEST(static_cast<const void*>(ptr1) == static_cast<const void*>(ptr2));\n    }\n\n    reference_checker_strs(const row& r, std::size_t string_index, std::size_t blob_index)\n        : reference_checker(r),\n          string_index(string_index),\n          blob_index(blob_index),\n          string_ptr(r.at(string_index).as_string().data()),\n          blob_ptr(r.at(blob_index).as_blob().data())\n    {\n    }\n\n    void check(const row& new_row)\n    {\n        reference_checker::check(new_row);\n        assert_ptrs_equal(string_ptr, new_row.at(string_index).as_string().data());\n        BOOST_TEST(blob_ptr == new_row.at(blob_index).as_blob().data());\n    }\n};\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    row r;\n    BOOST_TEST(r.empty());\n}\n\nBOOST_AUTO_TEST_SUITE(ctor_from_frow_view)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_view v;\n    row r(v);\n    BOOST_TEST(r.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    std::string s1(\"test\"), s2(\"\");\n    blob b{0x00, 0xab, 0xf5};\n    auto fields = make_fv_arr(42, s1, 5.0f, b, s2);\n    row r(makerowv(fields.data(), fields.size()));\n\n    // Fields still valid even when the original source of the view changed\n    fields = make_fv_arr(0, 0, 0, 0, 0);\n    s1 = \"other\";\n    s2 = \"abcdef\";\n    b = {0xff, 0xa4, 0x02};\n\n    BOOST_TEST(r.size() == 5u);\n    BOOST_TEST(r[0] == field_view(42));\n    BOOST_TEST(r[1] == field_view(\"test\"));\n    BOOST_TEST(r[2] == field_view(5.0f));\n    BOOST_TEST(r[3] == field_view(makebv(\"\\0\\xab\\xf5\")));\n    BOOST_TEST(r[4] == field_view(\"\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_ctor)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r1;\n    row r2(r1);\n    r1 = makerow(42, \"test\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    row r1 = makerow(\"\", 42, \"test\", makebv(\"\\0\\3\\2\"));\n    row r2(r1);\n    r1 = makerow(\"another_string\", 4.2f, \"\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.size() == 4u);\n    BOOST_TEST(r2[0] == field_view(\"\"));\n    BOOST_TEST(r2[1] == field_view(42));\n    BOOST_TEST(r2[2] == field_view(\"test\"));\n    BOOST_TEST(r2[3] == field_view(makebv(\"\\0\\3\\2\")));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_ctor)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r1;\n\n    // References, pointers, etc. should remain valid\n    reference_checker refcheck(r1);\n\n    row r2(std::move(r1));\n    r1 = makerow(42, \"test\");  // r2 should be independent of r1\n\n    BOOST_TEST(r2.empty());\n    refcheck.check(r2);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    row r1 = makerow(\"\", 42, \"test\", makebv(\"\\0\\5\\xff\"));\n\n    // References, pointers, etc should remain valid\n    reference_checker_strs refcheck(r1, 2, 3);\n\n    // Move\n    row r2(std::move(r1));\n    r1 = makerow(\"another_string\", 4.2f, \"\", makebv(\"\\1\\5\\xab\"));  // r2 should be independent of r1\n\n    BOOST_TEST(r2.size() == 4u);\n    BOOST_TEST(r2[0] == field_view(\"\"));\n    BOOST_TEST(r2[1] == field_view(42));\n    BOOST_TEST(r2[2] == field_view(\"test\"));\n    BOOST_TEST(r2[3] == field_view(makebv(\"\\0\\5\\xff\")));\n\n    // References, pointers, etc still valid\n    refcheck.check(r2);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_assignment)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r1 = makerow(42, \"abcdef\");\n    row r2;\n    r1 = r2;\n    r2 = makerow(90, nullptr);  // r1 is independent of r2\n    BOOST_TEST(r1.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    row r1 = makerow(42, \"abcdef\", makebv(\"\\0\\1\\2\"));\n    row r2 = makerow(\"a_very_long_string\", nullptr, \"\", makebv(\"\\3\\4\\5\"));\n    r1 = r2;\n    r2 = makerow(\"another_string\", 90, \"yet_another\");  // r1 is independent of r2\n\n    BOOST_TEST(r1.size() == 4u);\n    BOOST_TEST(r1[0] == field_view(\"a_very_long_string\"));\n    BOOST_TEST(r1[1] == field_view());\n    BOOST_TEST(r1[2] == field_view(\"\"));\n    BOOST_TEST(r1[3] == field_view(makebv(\"\\3\\4\\5\")));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    row r = makerow(\"abc\", 50u, \"fgh\");\n    const row& ref = r;\n    r = ref;\n\n    BOOST_TEST(r.size() == 3u);\n    BOOST_TEST(r[0] == field_view(\"abc\"));\n    BOOST_TEST(r[1] == field_view(50u));\n    BOOST_TEST(r[2] == field_view(\"fgh\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_assignment)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r1 = makerow(42, \"abcdef\");\n    row r2;\n    row_view rv(r2);\n    r1 = std::move(r2);\n    r2 = makerow(90, nullptr);  // r1 is independent of r2\n    BOOST_TEST(r1.empty());\n    BOOST_TEST(rv == r1);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    row r1 = makerow(42, \"abcdef\", makebv(\"\\0\\4\\1\"));\n    row r2 = makerow(\"a_very_long_string\", nullptr, \"\", makebv(\"\\7\\1\\2\"));\n\n    // References, pointers, etc should remain valid\n    reference_checker_strs refcheck(r2, 0, 3);\n\n    // Move\n    r1 = std::move(r2);\n    r2 = makerow(\"another_string\", 90, \"yet_another\", makebv(\"\\0\\0\"));  // r1 is independent of r2\n\n    BOOST_TEST(r1.size() == 4u);\n    BOOST_TEST(r1[0] == field_view(\"a_very_long_string\"));\n    BOOST_TEST(r1[1] == field_view());\n    BOOST_TEST(r1[2] == field_view(\"\"));\n    BOOST_TEST(r1[3] == field_view(makebv(\"\\7\\1\\2\")));\n\n    // References, pointers, etc still valid\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    row r = makerow(\"abc\", 50u, \"fgh\", makebv(\"\\0\\4\"));\n    row&& ref = std::move(r);\n    r = std::move(ref);  // this should leave r in a valid but unspecified state\n\n    // r is in a valid but unspecified state; can be assigned to\n    r = makerow(\"abcdef\");\n    BOOST_TEST(r.size() == 1u);\n    BOOST_TEST(r[0] == field_view(\"abcdef\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(assignment_from_view)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r = makerow(42, \"abcdef\", makebv(\"\\0\\xae\"));\n    r = row_view();\n    BOOST_TEST(r.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    std::string s1(\"a_very_long_string\"), s2(\"\");\n    blob b{0x00, 0xfa};\n    row r = makerow(42, \"abcdef\", makebv(\"\\0\\1\"));\n    auto fields = make_fv_arr(s1, nullptr, s2, b);\n    r = makerowv(fields.data(), fields.size());\n    fields = make_fv_arr(\"abc\", 42u, 9, nullptr);  // r should be independent of the original fields\n    s1 = \"another_string\";                         // r should be independent of the original strings\n    s2 = \"yet_another\";\n    b = {0xac, 0x32, 0x21, 0x50};\n\n    BOOST_TEST(r.size() == 4u);\n    BOOST_TEST(r[0] == field_view(\"a_very_long_string\"));\n    BOOST_TEST(r[1] == field_view());\n    BOOST_TEST(r[2] == field_view(\"\"));\n    BOOST_TEST(r[3] == field_view(makebv(\"\\0\\xfa\")));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    row r = makerow(\"abcdef\", 42, \"plk\");\n    r = row_view(r);\n\n    BOOST_TEST(r.size() == 3u);\n    BOOST_TEST(r[0] == field_view(\"abcdef\"));\n    BOOST_TEST(r[1] == field_view(42));\n    BOOST_TEST(r[2] == field_view(\"plk\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(at)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r;\n    BOOST_CHECK_THROW(r.at(0), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(in_range)\n{\n    row r = makerow(42, 50u, \"test\");\n    BOOST_TEST(r.at(0) == field_view(42));\n    BOOST_TEST(r.at(1) == field_view(50u));\n    BOOST_TEST(r.at(2) == field_view(\"test\"));\n}\n\nBOOST_AUTO_TEST_CASE(out_of_range)\n{\n    row r = makerow(42, 50u, \"test\");\n    BOOST_CHECK_THROW(r.at(3), std::out_of_range);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE(front)\n{\n    auto r = makerow(42, 50u, \"test\");\n    BOOST_TEST(r.front() == field_view(42));\n}\n\nBOOST_AUTO_TEST_CASE(back)\n{\n    BOOST_TEST(makerow(42, 50u, \"test\").front() == field_view(42));\n    BOOST_TEST(makerow(42).back() == field_view(42));\n}\n\nBOOST_AUTO_TEST_CASE(empty)\n{\n    BOOST_TEST(row().empty());\n    BOOST_TEST(!makerow(42).empty());\n    BOOST_TEST(!makerow(42, 50u).empty());\n}\n\nBOOST_AUTO_TEST_CASE(size)\n{\n    BOOST_TEST(row().size() == 0u);\n    BOOST_TEST(makerow(42).size() == 1u);\n    BOOST_TEST(makerow(50, nullptr).size() == 2u);\n}\n\n// As iterators are regular pointers, we don't perform\n// exhaustive testing on iteration\nBOOST_AUTO_TEST_SUITE(iterators)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    const row r{};  // can be called on const objects\n    BOOST_TEST(r.begin() == nullptr);\n    BOOST_TEST(r.end() == nullptr);\n    std::vector<field_view> vec{r.begin(), r.end()};\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(multiple_elms)\n{\n    const row r = makerow(42, 50u, \"test\");  // can be called on const objects\n    BOOST_TEST(r.begin() != nullptr);\n    BOOST_TEST(r.end() != nullptr);\n    BOOST_TEST(std::distance(r.begin(), r.end()) == 3);\n\n    std::vector<field_view> vec{r.begin(), r.end()};\n    BOOST_TEST(vec.size() == 3u);\n    BOOST_TEST(vec[0] == field_view(42));\n    BOOST_TEST(vec[1] == field_view(50u));\n    BOOST_TEST(vec[2] == field_view(\"test\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(operator_row_view)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row r;\n    row_view rv(r);\n\n    BOOST_TEST(rv.empty());\n    BOOST_TEST(rv.size() == 0u);\n    BOOST_TEST(rv.begin() == nullptr);\n    BOOST_TEST(rv.end() == nullptr);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    row r = makerow(\"abc\", 24, \"def\");\n    row_view rv(r);\n\n    BOOST_TEST(rv.size() == 3u);\n    BOOST_TEST(rv[0] == field_view(\"abc\"));\n    BOOST_TEST(rv[1] == field_view(24));\n    BOOST_TEST(rv[2] == field_view(\"def\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(as_vector)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    std::vector<field> vec{field_view(\"abc\")};\n    row r;\n    r.as_vector(vec);\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    std::vector<field> vec{field_view(\"abc\")};\n    row r = makerow(42u, \"abc\");\n    r.as_vector(vec);\n    BOOST_TEST(vec.size() == 2u);\n    BOOST_TEST(vec[0].as_uint64() == 42u);\n    BOOST_TEST(vec[1].as_string() == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(return_value)\n{\n    auto vec = makerow(42u, \"abc\").as_vector();\n    BOOST_TEST(vec.size() == 2u);\n    BOOST_TEST(vec[0].as_uint64() == 42u);\n    BOOST_TEST(vec[1].as_string() == \"abc\");\n}\nBOOST_AUTO_TEST_SUITE_END()\n\n// operator== relies on row_view's operator==, so only\n// a small subset of tests here\nBOOST_AUTO_TEST_SUITE(operator_equals)\nBOOST_AUTO_TEST_CASE(row_row)\n{\n    row r1 = makerow(\"abc\", 4);\n    row r2 = r1;\n    row r3 = makerow(nullptr, 4);\n\n    BOOST_TEST(r1 == r2);\n    BOOST_TEST(!(r1 != r2));\n\n    BOOST_TEST(!(r1 == r3));\n    BOOST_TEST(r1 != r3);\n}\n\nBOOST_AUTO_TEST_CASE(row_rowview)\n{\n    row r1 = makerow(\"abc\", 4);\n    row r2 = makerow(nullptr, 4);\n    auto fields = make_fv_arr(\"abc\", 4);\n    auto rv = makerowv(fields.data(), fields.size());\n\n    BOOST_TEST(r1 == rv);\n    BOOST_TEST(!(r1 != rv));\n    BOOST_TEST(rv == r1);\n    BOOST_TEST(!(rv != r1));\n\n    BOOST_TEST(!(r2 == rv));\n    BOOST_TEST(r2 != rv);\n    BOOST_TEST(!(rv == r2));\n    BOOST_TEST(rv != r2);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()  // test_row\n"
  },
  {
    "path": "test/unit/test/row_view.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/field.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/row_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <stdexcept>\n#include <vector>\n\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_row_view)\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    row_view v;\n    BOOST_TEST(v.empty());\n}\n\nBOOST_AUTO_TEST_SUITE(at)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    row_view v;\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(in_range)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v.at(0) == field_view(42));\n    BOOST_TEST(v.at(1) == field_view(50u));\n    BOOST_TEST(v.at(2) == field_view(\"test\"));\n}\n\nBOOST_AUTO_TEST_CASE(out_of_range)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_CHECK_THROW(v.at(3), std::out_of_range);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE(operator_square_brackets)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v[0] == field_view(42));\n    BOOST_TEST(v[1] == field_view(50u));\n    BOOST_TEST(v[2] == field_view(\"test\"));\n}\n\nBOOST_AUTO_TEST_CASE(front)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v.front() == field_view(42));\n}\n\nBOOST_AUTO_TEST_SUITE(back)\nBOOST_AUTO_TEST_CASE(multiple_elms)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v.back() == field_view(\"test\"));\n}\n\nBOOST_AUTO_TEST_CASE(single_elm)\n{\n    auto fields = make_fv_arr(42);\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v.back() == field_view(42));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(empty)\nBOOST_AUTO_TEST_CASE(true_) { BOOST_TEST(row_view().empty()); }\n\nBOOST_AUTO_TEST_CASE(single_elm)\n{\n    auto fields = make_fv_arr(42);\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(!v.empty());\n}\n\nBOOST_AUTO_TEST_CASE(multiple_elms)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(!v.empty());\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(size)\nBOOST_AUTO_TEST_CASE(zero) { BOOST_TEST(row_view().size() == 0u); }\n\nBOOST_AUTO_TEST_CASE(single_elm)\n{\n    auto fields = make_fv_arr(42);\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v.size() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(multiple_elms)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    auto v = makerowv(fields.data(), fields.size());\n    BOOST_TEST(v.size() == 3u);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\n// As iterators are regular pointers, we don't perform\n// exhaustive testing on iteration\nBOOST_AUTO_TEST_SUITE(iterators)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    const row_view v{};  // can be called on const objects\n    BOOST_TEST(v.begin() == nullptr);\n    BOOST_TEST(v.end() == nullptr);\n    std::vector<field_view> vec{v.begin(), v.end()};\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(multiple_elms)\n{\n    auto fields = make_fv_arr(42, 50u, \"test\");\n    const auto v = makerowv(fields.data(), fields.size());  // can be called on const objects\n    BOOST_TEST(v.begin() != nullptr);\n    BOOST_TEST(v.end() != nullptr);\n    BOOST_TEST(std::distance(v.begin(), v.end()) == 3);\n\n    std::vector<field_view> vec{v.begin(), v.end()};\n    BOOST_TEST(vec.size() == 3u);\n    BOOST_TEST(vec[0] == field_view(42));\n    BOOST_TEST(vec[1] == field_view(50u));\n    BOOST_TEST(vec[2] == field_view(\"test\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(as_vector)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    std::vector<field> vec{field_view(\"abc\")};\n    row_view v;\n    v.as_vector(vec);\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    std::vector<field> vec{field_view(\"abc\")};\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowv(fields.data(), fields.size());\n    v.as_vector(vec);\n    BOOST_TEST(vec.size() == 2u);\n    BOOST_TEST(vec[0].as_uint64() == 42u);\n    BOOST_TEST(vec[1].as_string() == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(return_value)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowv(fields.data(), fields.size());\n    auto vec = v.as_vector();\n    BOOST_TEST(vec.size() == 2u);\n    BOOST_TEST(vec[0].as_uint64() == 42u);\n    BOOST_TEST(vec[1].as_string() == \"abc\");\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE(operator_equals)\n{\n    // clang-format off\n    struct\n    {\n        const char* name;\n        std::vector<field_view> f1;\n        std::vector<field_view> f2;\n        bool is_equal;\n    } test_cases [] = {\n        { \"empty_empty\", make_fv_vector(), make_fv_vector(), true },\n        { \"empty_nonempty\", make_fv_vector(), make_fv_vector(\"test\"), false },\n        { \"subset\", make_fv_vector(\"test\", 42), make_fv_vector(\"test\"), false },\n        { \"same_size_different_values\", make_fv_vector(\"test\", 42), make_fv_vector(\"test\", 50), false },\n        { \"same_size_and_values\", make_fv_vector(\"test\", 42), make_fv_vector(\"test\", 42), true }\n    };\n    // clang-format on\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            auto v1 = makerowv(tc.f1.data(), tc.f1.size());\n            auto v2 = makerowv(tc.f2.data(), tc.f2.size());\n\n            if (tc.is_equal)\n            {\n                BOOST_TEST(v1 == v2);\n                BOOST_TEST(v2 == v1);\n                BOOST_TEST(!(v1 != v2));\n                BOOST_TEST(!(v2 != v1));\n            }\n            else\n            {\n                BOOST_TEST(!(v1 == v2));\n                BOOST_TEST(!(v2 == v1));\n                BOOST_TEST(v1 != v2);\n                BOOST_TEST(v2 != v1);\n            }\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/rows.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/blob_view.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/rows.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <stdexcept>\n\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_TEST_DONT_PRINT_LOG_VALUE(boost::mysql::detail::rows_iterator)\n\nBOOST_AUTO_TEST_SUITE(test_rows)\n\n// Check that references, pointers and iterators to certain rows' contents survive an operation\nstruct reference_checker\n{\n    rows::const_iterator it;\n    rows_view rv;\n\n    reference_checker(const rows& r) : it(r.begin()), rv(r) {}\n\n    void check(const rows& new_row)\n    {\n        BOOST_TEST(it == new_row.begin());\n        BOOST_TEST(rv == new_row);\n    }\n};\n\nstruct reference_checker_strs : reference_checker\n{\n    // indices in the matrix where a string/blob field resides\n    std::size_t string_row_index, string_col_index, blob_row_index, blob_col_index;\n    const char* string_ptr;\n    const unsigned char* blob_ptr;\n\n    static void assert_ptrs_equal(const char* ptr1, const char* ptr2)\n    {\n        // Otherwise, UTF thinks it's a C string, tries to print it and causes Valgrind errors\n        BOOST_TEST(static_cast<const void*>(ptr1) == static_cast<const void*>(ptr2));\n    }\n\n    reference_checker_strs(\n        const rows& r,\n        std::size_t string_row_index,\n        std::size_t string_col_index,\n        std::size_t blob_row_index,\n        std::size_t blob_col_index\n    )\n        : reference_checker(r),\n          string_row_index(string_row_index),\n          string_col_index(string_col_index),\n          blob_row_index(blob_row_index),\n          blob_col_index(blob_col_index),\n          string_ptr(r.at(string_row_index).at(string_col_index).as_string().data()),\n          blob_ptr(r.at(blob_row_index).at(blob_col_index).as_blob().data())\n    {\n    }\n\n    void check(const rows& new_row)\n    {\n        reference_checker::check(new_row);\n        assert_ptrs_equal(string_ptr, new_row.at(string_row_index).at(string_col_index).as_string().data());\n        BOOST_TEST(blob_ptr == new_row.at(blob_row_index).at(blob_col_index).as_blob().data());\n    }\n};\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    rows r;\n    BOOST_TEST(r.empty());\n}\n\nBOOST_AUTO_TEST_SUITE(ctor_from_rows_view)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows_view v;\n    rows r(v);\n    BOOST_TEST(r.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    std::string s1(\"abc\"), s2(\"\");\n    blob b{0x64, 0x10, 0x01};\n    auto fields = make_fv_arr(s1, 1.0f, nullptr, s2, -1, b);\n    auto v = makerowsv(fields.data(), fields.size(), 3);\n    rows r(v);\n\n    // r should be independent of the original fields/strings\n    fields = make_fv_arr(0, 0, 0, 0, 0, 0);\n    s1 = \"other\";\n    s2 = \"yet_another\";\n    b = {0x11, 0x12, 0x13};\n\n    BOOST_TEST(r.size() == 2u);\n    BOOST_TEST(r[0] == makerow(\"abc\", 1.0f, nullptr));\n    BOOST_TEST(r[1] == makerow(\"\", -1, makebv(\"\\x64\\x10\\1\")));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_ctor)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r1;\n    rows r2(r1);\n    BOOST_TEST(r2.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    rows r1 = makerows(3, \"abc\", 21.0f, makebv(\"\"), \"cdefg\", 22.0f, makebv(\"\\1\\3\\5\"));\n    rows r2(r1);\n    r1 = makerows(2, 0, 0, 0, 0);  // r2 should be independent of r1\n\n    BOOST_TEST(r2.size() == 2u);\n    BOOST_TEST(r2[0] == makerow(\"abc\", 21.0f, makebv(\"\")));\n    BOOST_TEST(r2[1] == makerow(\"cdefg\", 22.0f, makebv(\"\\1\\3\\5\")));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_ctor)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r1;\n\n    // References, pointers, etc. should remain valid\n    reference_checker refcheck(r1);\n\n    rows r2(std::move(r1));\n    r1 = makerows(1, \"abc\", 22);  // r2 should be independent of r1\n\n    BOOST_TEST(r2.empty());\n    refcheck.check(r2);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    rows r1 = makerows(3, makebv(\"abc\"), 21.0f, \"\", makebv(\"\\0\\1\\0\"), 22.0f, \"aaa\");\n\n    // References, pointers, etc. should remain valid\n    reference_checker_strs refcheck(r1, 1, 2, 1, 0);\n\n    rows r2(std::move(r1));\n    r1 = makerows(2, 0, 0, 0, 0);  // r2 should be independent of r1\n\n    BOOST_TEST(r2.size() == 2u);\n    BOOST_TEST(r2[0] == makerow(makebv(\"abc\"), 21.0f, \"\"));\n    BOOST_TEST(r2[1] == makerow(makebv(\"\\0\\1\\0\"), 22.0f, \"aaa\"));\n    refcheck.check(r2);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(copy_assignment)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r1 = makerows(2, 42, \"abcdef\");\n    rows r2;\n    r1 = r2;\n    r2 = makerows(2, 90, nullptr);  // r1 is independent of r2\n    BOOST_TEST(r1.empty());\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    rows r1 = makerows(1, 42, \"abcdef\", makebv(\"\\0\\2\\1\"));\n    rows r2 = makerows(2, \"a_very_long_string\", nullptr, \"\", makebv(\"\\7\\0\"), \"cde\", blob_view());\n    r1 = r2;\n    r2 = makerows(1, \"another_string\", 90, \"yet_another\");  // r1 is independent of r2\n\n    BOOST_TEST(r1.size() == 3u);\n    BOOST_TEST(r1[0] == makerow(\"a_very_long_string\", nullptr));\n    BOOST_TEST(r1[1] == makerow(\"\", makebv(\"\\7\\0\")));\n    BOOST_TEST(r1[2] == makerow(\"cde\", blob_view()));\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    rows r = makerows(2, \"abc\", 50u, \"\", makebv(\"abc\"));\n    const rows& ref = r;\n    r = ref;\n\n    BOOST_TEST(r.size() == 2u);\n    BOOST_TEST(r[0] == makerow(\"abc\", 50u));\n    BOOST_TEST(r[1] == makerow(\"\", makebv(\"abc\")));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_assignment)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r1 = makerows(1, 42, \"abcdef\");\n    rows r2;\n\n    // References, pointers, etc. should remain valid\n    reference_checker refcheck(r2);\n    r1 = std::move(r2);\n    r2 = makerows(2, 90, nullptr);  // r1 is independent of r2\n\n    BOOST_TEST(r1.empty());\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    rows r1 = makerows(1, 42, \"abcdef\");\n    rows r2 = makerows(3, \"a_very_long_string\", blob_view(), 50, \"\", makebv(\"\\2\\5\\1\"), 42);\n\n    // References, pointers, etc. should remain valid\n    reference_checker_strs refcheck(r2, 0, 0, 1, 1);\n\n    r1 = std::move(r2);\n    r2 = makerows(1, \"another_string\", 90, \"yet_another\");  // r1 is independent of r2\n\n    BOOST_TEST(r1.size() == 2u);\n    BOOST_TEST(r1[0] == makerow(\"a_very_long_string\", blob_view(), 50));\n    BOOST_TEST(r1[1] == makerow(\"\", makebv(\"\\2\\5\\1\"), 42));\n    refcheck.check(r1);\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    rows r = makerows(3, \"abc\", 50u, \"fgh\");\n    rows&& ref = std::move(r);\n    r = std::move(ref);  // this should leave r in a valid but unspecified state\n\n    // r is in a valid but unspecified state; can be assigned to\n    r = makerows(1, \"abcdef\");\n    BOOST_TEST(r.size() == 1u);\n    BOOST_TEST(r[0] == makerow(\"abcdef\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(assignment_from_view)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r = makerows(1, 42, \"abcdef\");\n    r = rows_view();\n    BOOST_TEST(r.empty());\n    BOOST_TEST(r.num_columns() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(empty_different_num_columns)\n{\n    rows r;\n    r = makerowsv(nullptr, 0, 2);\n\n    BOOST_TEST(r.empty());\n    BOOST_TEST(r.size() == 0u);\n    BOOST_TEST(r.num_columns() == 2u);\n\n    r = makerowsv(nullptr, 0, 3);\n\n    BOOST_TEST(r.empty());\n    BOOST_TEST(r.size() == 0u);\n    BOOST_TEST(r.num_columns() == 3u);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    std::string s1(\"a_very_long_string\"), s2(\"\");\n    blob b{0x78, 0x01, 0xff};\n    rows r = makerows(1, 42, \"abcdef\", 90, \"hij\");\n    auto fields = make_fv_arr(s1, nullptr, blob_view(), s2, \"bec\", b);\n    r = makerowsv(fields.data(), fields.size(), 3);\n    fields = make_fv_arr(\"abc\", 42u, 9, 0, 0, 0);  // r should be independent of the original fields\n    s1 = \"another_string\";                         // r should be independent of the original strings\n    s2 = \"yet_another\";\n    b = {0x00, 0xab, 0xcc, 0x78};\n\n    BOOST_TEST_REQUIRE(r.size() == 2u);\n    BOOST_TEST(r[0] == makerow(\"a_very_long_string\", nullptr, blob_view()));\n    BOOST_TEST(r[1] == makerow(\"\", \"bec\", makebv(\"\\x78\\1\\xff\")));\n    BOOST_TEST(r.num_columns() == 3u);\n}\n\nBOOST_AUTO_TEST_CASE(self_assignment)\n{\n    rows r = makerows(2, \"abcdef\", 42, \"plk\", \"uv\");\n    r = rows_view(r);\n\n    BOOST_TEST_REQUIRE(r.size() == 2u);\n    BOOST_TEST(r[0] == makerow(\"abcdef\", 42));\n    BOOST_TEST(r[1] == makerow(\"plk\", \"uv\"));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(at)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows v;\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_one_row)\n{\n    rows r = makerows(1, 42u);\n    BOOST_TEST(r.at(0) == makerow(42u));\n    BOOST_CHECK_THROW(r.at(1), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_several_rows)\n{\n    rows r = makerows(1, 42u, \"abc\");\n    BOOST_TEST(r.at(0) == makerow(42u));\n    BOOST_TEST(r.at(1) == makerow(\"abc\"));\n    BOOST_CHECK_THROW(r.at(2), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_one_row)\n{\n    rows r = makerows(2, 42u, \"abc\");\n    BOOST_TEST(r.at(0) == makerow(42u, \"abc\"));\n    BOOST_CHECK_THROW(r.at(1), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_several_rows)\n{\n    rows r = makerows(2, 42u, \"abc\", nullptr, \"bcd\", 90u, nullptr);\n    BOOST_TEST(r.at(0) == makerow(42u, \"abc\"));\n    BOOST_TEST(r.at(1) == makerow(nullptr, \"bcd\"));\n    BOOST_TEST(r.at(2) == makerow(90u, nullptr));\n    BOOST_CHECK_THROW(r.at(3), std::out_of_range);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(operator_square_brackets)\nBOOST_AUTO_TEST_CASE(one_column_one_row)\n{\n    rows r = makerows(1, 42u);\n    BOOST_TEST(r[0] == makerow(42u));\n}\n\nBOOST_AUTO_TEST_CASE(one_column_several_rows)\n{\n    rows r = makerows(1, 42u, \"abc\");\n    BOOST_TEST(r[0] == makerow(42u));\n    BOOST_TEST(r[1] == makerow(\"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_one_row)\n{\n    rows r = makerows(2, 42u, \"abc\");\n    BOOST_TEST(r[0] == makerow(42u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_several_rows)\n{\n    rows r = makerows(2, 42u, \"abc\", nullptr, \"bcd\", 90u, nullptr);\n    BOOST_TEST(r[0] == makerow(42u, \"abc\"));\n    BOOST_TEST(r[1] == makerow(nullptr, \"bcd\"));\n    BOOST_TEST(r[2] == makerow(90u, nullptr));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE(front)\n{\n    rows r = makerows(2, 42u, \"abc\", nullptr, \"bcde\");\n    BOOST_TEST(r.front() == makerow(42u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(back)\n{\n    rows r = makerows(2, 70.0f, \"abc\", nullptr, \"bcde\");\n    BOOST_TEST(r.back() == makerow(nullptr, \"bcde\"));\n}\n\nBOOST_AUTO_TEST_CASE(empty)\n{\n    BOOST_TEST(rows().empty());\n    BOOST_TEST(!makerows(1, 42u).empty());\n}\n\nBOOST_AUTO_TEST_SUITE(size)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r;\n    BOOST_TEST(r.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_one_row)\n{\n    rows r = makerows(1, 42u);\n    BOOST_TEST(r.size() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_several_rows)\n{\n    rows r = makerows(1, 42u, \"abc\");\n    BOOST_TEST(r.size() == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_one_row)\n{\n    rows r = makerows(2, 42u, \"abc\");\n    BOOST_TEST(r.size() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_several_rows)\n{\n    rows r = makerows(3, 42u, \"abc\", nullptr, \"bcd\", 90u, nullptr);\n    BOOST_TEST(r.size() == 2u);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(operator_rows_view)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows r;\n    auto rv = static_cast<rows_view>(r);\n    BOOST_TEST(rv.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(non_empty)\n{\n    rows r = makerows(3, 42u, 4.2f, \"abcde\", 90u, nullptr, \"def\");\n    auto rv = static_cast<rows_view>(r);\n    BOOST_TEST(rv.size() == 2u);\n    BOOST_TEST(rv[0] == makerow(42u, 4.2f, \"abcde\"));\n    BOOST_TEST(rv[1] == makerow(90u, nullptr, \"def\"));\n}\n\nBOOST_AUTO_TEST_CASE(cleared)\n{\n    rows r = makerows(3, 42u, 4.2f, \"abcde\", 90u, nullptr, \"def\");\n    r = rows();\n    auto rv = static_cast<rows_view>(r);\n    BOOST_TEST(rv.empty());\n    BOOST_TEST(rv.size() == 0u);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/rows_view.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <stdexcept>\n\n#include \"test_common/create_basic.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_rows_view)\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    rows_view v;\n    BOOST_TEST(v.empty());\n}\n\n// Regression checks. The cases below caused segfaults in debug builds\nBOOST_AUTO_TEST_SUITE(init_ctor)\nBOOST_AUTO_TEST_CASE(fieldsnonnull_nfieldszero_ncolsnonzero)\n{\n    field_view fv;\n    auto v = makerowsv(&fv, 0, 3);\n    BOOST_TEST(v.empty());\n    BOOST_TEST(v.size() == 0u);\n    BOOST_TEST(v.num_columns() == 3u);\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n    std::vector<row_view> vec(v.begin(), v.end());\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(fieldsnonnull_nfieldszero_ncolszero)\n{\n    field_view fv;\n    auto v = makerowsv(&fv, 0, 0);\n    BOOST_TEST(v.empty());\n    BOOST_TEST(v.size() == 0u);\n    BOOST_TEST(v.num_columns() == 0u);\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n    std::vector<row_view> vec(v.begin(), v.end());\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(fieldsnull_nfieldszero_ncolsnonzero)\n{\n    auto v = makerowsv(nullptr, 0, 2);\n    BOOST_TEST(v.empty());\n    BOOST_TEST(v.size() == 0u);\n    BOOST_TEST(v.num_columns() == 2u);\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n    std::vector<row_view> vec(v.begin(), v.end());\n    BOOST_TEST(vec.empty());\n}\n\nBOOST_AUTO_TEST_CASE(fieldsnull_nfieldszero_ncolszero)\n{\n    auto v = makerowsv(nullptr, 0, 0);\n    BOOST_TEST(v.empty());\n    BOOST_TEST(v.size() == 0u);\n    BOOST_TEST(v.num_columns() == 0u);\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n    std::vector<row_view> vec(v.begin(), v.end());\n    BOOST_TEST(vec.empty());\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(at)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows_view v;\n    BOOST_CHECK_THROW(v.at(0), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_one_row)\n{\n    auto fields = make_fv_arr(42u);\n    auto v = makerowsv(fields.data(), 1, 1);\n    BOOST_TEST(v.at(0) == makerow(42u));\n    BOOST_CHECK_THROW(v.at(1), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_several_rows)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowsv(fields.data(), 2, 1);\n    BOOST_TEST(v.at(0) == makerow(42u));\n    BOOST_TEST(v.at(1) == makerow(\"abc\"));\n    BOOST_CHECK_THROW(v.at(2), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_one_row)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowsv(fields.data(), 2, 2);\n    BOOST_TEST(v.at(0) == makerow(42u, \"abc\"));\n    BOOST_CHECK_THROW(v.at(1), std::out_of_range);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_several_rows)\n{\n    auto fields = make_fv_arr(42u, \"abc\", nullptr, \"bcd\", 90u, nullptr);\n    auto v = makerowsv(fields.data(), 6, 2);\n    BOOST_TEST(v.at(0) == makerow(42u, \"abc\"));\n    BOOST_TEST(v.at(1) == makerow(nullptr, \"bcd\"));\n    BOOST_TEST(v.at(2) == makerow(90u, nullptr));\n    BOOST_CHECK_THROW(v.at(3), std::out_of_range);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(operator_square_brackets)\nBOOST_AUTO_TEST_CASE(one_column_one_row)\n{\n    auto fields = make_fv_arr(42u);\n    auto v = makerowsv(fields.data(), 1, 1);\n    BOOST_TEST(v[0] == makerow(42u));\n}\n\nBOOST_AUTO_TEST_CASE(one_column_several_rows)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowsv(fields.data(), 2, 1);\n    BOOST_TEST(v[0] == makerow(42u));\n    BOOST_TEST(v[1] == makerow(\"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_one_row)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowsv(fields.data(), 2, 2);\n    BOOST_TEST(v[0] == makerow(42u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_several_rows)\n{\n    auto fields = make_fv_arr(42u, \"abc\", nullptr, \"bcd\", 90u, nullptr);\n    auto v = makerowsv(fields.data(), 6, 2);\n    BOOST_TEST(v[0] == makerow(42u, \"abc\"));\n    BOOST_TEST(v[1] == makerow(nullptr, \"bcd\"));\n    BOOST_TEST(v[2] == makerow(90u, nullptr));\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_CASE(front)\n{\n    auto fields = make_fv_arr(42u, \"abc\", nullptr, \"bcde\");\n    auto v = makerowsv(fields.data(), 4, 2);\n    BOOST_TEST(v.front() == makerow(42u, \"abc\"));\n}\n\nBOOST_AUTO_TEST_CASE(back)\n{\n    auto fields = make_fv_arr(42u, \"abc\", nullptr, \"bcde\");\n    auto v = makerowsv(fields.data(), 4, 2);\n    BOOST_TEST(v.back() == makerow(nullptr, \"bcde\"));\n}\n\nBOOST_AUTO_TEST_CASE(empty)\n{\n    BOOST_TEST(rows_view().empty());\n\n    auto fields = make_fv_arr(42u);\n    BOOST_TEST(!makerowsv(fields.data(), 1, 1).empty());\n}\n\nBOOST_AUTO_TEST_SUITE(size)\nBOOST_AUTO_TEST_CASE(empty)\n{\n    rows_view v;\n    BOOST_TEST(v.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_one_row)\n{\n    auto fields = make_fv_arr(42u);\n    auto v = makerowsv(fields.data(), 1, 1);\n    BOOST_TEST(v.size() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(one_column_several_rows)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowsv(fields.data(), 2, 1);\n    BOOST_TEST(v.size() == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_one_row)\n{\n    auto fields = make_fv_arr(42u, \"abc\");\n    auto v = makerowsv(fields.data(), 2, 2);\n    BOOST_TEST(v.size() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(several_columns_several_rows)\n{\n    auto fields = make_fv_arr(42u, \"abc\", nullptr, \"bcd\", 90u, nullptr);\n    auto v = makerowsv(fields.data(), 6, 2);\n    BOOST_TEST(v.size() == 3u);\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/close_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/sansio/close_connection.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <vector>\n\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_frame.hpp\"\n\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_close_connection)\n\nstruct fixture : algo_fixture_base\n{\n    detail::close_connection_algo algo{{}};\n};\n\n// A serialized quit request\nstd::vector<std::uint8_t> expected_request() { return create_frame(0, {0x01}); }\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())\n        .expect_close()\n        .will_set_status(connection_status::not_connected)\n        .check(fix);\n}\n\n// If we're using TLS, close calls quit, which shuts it down\nBOOST_AUTO_TEST_CASE(success_tls)\n{\n    // Setup\n    fixture fix;\n    fix.st.tls_active = true;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())\n        .expect_ssl_shutdown()\n        .expect_close()\n        .will_set_status(connection_status::not_connected)\n        .will_set_tls_active(false)\n        .check(fix);\n}\n\n// If the session hasn't been established, or has been already torn down, close is a no-op\nBOOST_AUTO_TEST_CASE(success_multi_function)\n{\n    // Setup\n    fixture fix;\n    fix.st.status = connection_status::engaged_in_multi_function;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())\n        .expect_close()\n        .will_set_status(connection_status::not_connected)\n        .check(fix);\n}\n\n// Close runs normally even if the connection is engaged in a multi-function operation\nBOOST_AUTO_TEST_CASE(not_connected)\n{\n    // Setup\n    fixture fix;\n    fix.st.status = connection_status::not_connected;\n\n    // Run the algo\n    algo_test().check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(error_close)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())\n        .expect_close(asio::error::network_reset)\n        .will_set_status(connection_status::not_connected)  // State change happens even if close fails\n        .check(fix, asio::error::network_reset);\n}\n\nBOOST_AUTO_TEST_CASE(error_quit)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request(), asio::error::network_reset)\n        .expect_close()                                     // close is issued even if quit fails\n        .will_set_status(connection_status::not_connected)  // state change happens even if quit fails\n        .check(fix, asio::error::network_reset);            // error code is propagated\n}\n\nBOOST_AUTO_TEST_CASE(error_quit_close)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request(), asio::error::network_reset)\n        .expect_close(asio::error::shut_down)\n        .will_set_status(connection_status::not_connected)  // state change happens even if quit fails\n        .check(fix, asio::error::network_reset);            // the 1st error code wins\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/close_statement.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/impl/internal/sansio/close_statement.hpp>\n#include <boost/mysql/impl/internal/sansio/run_pipeline.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <cstdint>\n\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\n// setup_close_statement_pipeline: running a pipeline with these parameters\n// has the intended effect\nBOOST_AUTO_TEST_SUITE(test_close_statement)\n\n// A close_statement request pipelined with a ping (frame headers included)\nstatic std::vector<std::uint8_t> expected_request()\n{\n    return concat(create_frame(0, {0x19, 0x03, 0x00, 0x00, 0x00}), create_frame(0, {0x0e}));\n}\n\nstruct fixture : algo_fixture_base\n{\n    detail::run_pipeline_algo algo{detail::setup_close_statement_pipeline(st, {3})};\n};\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())                       // requests\n        .expect_read(create_ok_frame(1, ok_builder().build()))  // response to the ping request\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(success_no_backslash_escapes)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())  // requests\n        .expect_read(create_ok_frame(1, ok_builder().no_backslash_escapes(true).build())\n        )  // response to the ping request\n        .will_set_backslash_escapes(false)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(error_network)\n{\n    algo_test()\n        .expect_write(expected_request())                       // requests\n        .expect_read(create_ok_frame(1, ok_builder().build()))  // response to the ping request\n        .check_network_errors<fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(error_response)\n{\n    // Setup\n    fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_write(expected_request())  // Ping request\n        .expect_read(err_builder()\n                         .seqnum(1)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())  // Error response\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/execute.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/execution_processor/execution_processor.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/sansio/execute.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/mock_execution_processor.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::mysql::detail::any_execution_request;\nusing boost::mysql::detail::execution_processor;\nusing boost::mysql::detail::resultset_encoding;\n\nBOOST_AUTO_TEST_SUITE(test_execute)\n\n// The serialized form of a SELECT 1 query request\nstatic constexpr std::uint8_t serialized_select_1[] = {0x03, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x20, 0x31};\n\nstruct read_response_fixture : algo_fixture_base\n{\n    mock_execution_processor proc;\n    detail::read_execute_response_algo algo{&proc};\n\n    read_response_fixture() { proc.sequence_number() = 42; }\n};\n\nBOOST_AUTO_TEST_CASE(read_response_eof)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_ok_frame(42, ok_builder().affected_rows(60u).info(\"abc\").build()))\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls().on_head_ok_packet(1).validate();\n    BOOST_TEST(fix.proc.affected_rows() == 60u);\n    BOOST_TEST(fix.proc.info() == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(read_response_single_row_batch)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo. Rows and OK are received in a single go (one call to read_some_rows)\n    algo_test()\n        .expect_read(create_frame(42, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(43, meta_builder().type(column_type::bigint).build_coldef()))\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(44, 42))\n                         .add(create_text_row_message(45, 43))\n                         .add(create_eof_frame(46, ok_builder().affected_rows(10u).info(\"1st\").build()))\n                         .build())\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(1)\n        .on_row(2)\n        .on_row_batch_finish(1)\n        .on_row_ok_packet(1)\n        .validate();\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.num_meta() == 1u);\n    check_meta(fix.proc.meta(), {column_type::bigint});\n    BOOST_TEST(fix.proc.affected_rows() == 10u);\n    BOOST_TEST(fix.proc.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(read_response_multiple_row_batches)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo. Multiple read_some_rows calls are required\n    algo_test()\n        .expect_read(create_frame(42, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(43, meta_builder().type(column_type::tinyint).build_coldef()))\n        .expect_read(create_text_row_message(44, 42))\n        .expect_read(create_text_row_message(45, 43))\n        .expect_read(create_eof_frame(46, ok_builder().affected_rows(10u).info(\"1st\").build()))\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(3)\n        .on_row(2)\n        .on_row_batch_finish(3)\n        .on_row_ok_packet(1)\n        .validate();\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.num_meta() == 1u);\n    check_meta(fix.proc.meta(), {column_type::tinyint});\n    BOOST_TEST(fix.proc.affected_rows() == 10u);\n    BOOST_TEST(fix.proc.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(read_response_multiple_resultsets)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo. Multiple read_some_rows calls are required\n    algo_test()\n        .expect_read(create_frame(42, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(43, meta_builder().type(column_type::tinyint).build_coldef()))\n        .expect_read(create_text_row_message(44, 42))\n        .expect_read(\n            create_eof_frame(45, ok_builder().affected_rows(10u).info(\"1st\").more_results(true).build())\n        )\n        .expect_read(create_frame(46, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(47, meta_builder().type(column_type::varchar).build_coldef()))\n        .expect_read(\n            create_eof_frame(48, ok_builder().affected_rows(11u).info(\"2nd\").more_results(true).build())\n        )\n        .expect_read(create_ok_frame(49, ok_builder().affected_rows(12u).info(\"3rd\").build()))\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls()\n        .on_num_meta(2)\n        .on_meta(2)\n        .on_row_batch_start(3)\n        .on_row(1)\n        .on_row_batch_finish(3)\n        .on_row_ok_packet(2)\n        .on_head_ok_packet(1)\n        .validate();\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.num_meta() == 1u);\n    BOOST_TEST(fix.proc.affected_rows() == 12u);\n    BOOST_TEST(fix.proc.info() == \"3rd\");\n}\n\n// Tests error on write, while reading head and while reading rows (error spotcheck)\nBOOST_AUTO_TEST_CASE(read_response_error_network_error)\n{\n    algo_test()\n        .expect_read(create_frame(42, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(43, meta_builder().type(column_type::tinyint).build_coldef()))\n        .expect_read(create_text_row_message(44, 42))\n        .expect_read(create_text_row_message(45, 43))\n        .expect_read(create_eof_frame(46, ok_builder().affected_rows(10u).info(\"1st\").build()))\n        .check_network_errors<read_response_fixture>();\n}\n\nstruct execute_fixture : algo_fixture_base\n{\n    mock_execution_processor proc;\n    detail::execute_algo algo;\n\n    execute_fixture(any_execution_request req = {\"SELECT 1\"}) : algo({req, &proc}) {}\n};\n\nBOOST_AUTO_TEST_CASE(execute_success_eof)\n{\n    // Setup\n    execute_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_frame(0, serialized_select_1))\n        .expect_read(create_ok_frame(1, ok_builder().affected_rows(60u).info(\"abc\").build()))\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls().reset(1).on_head_ok_packet(1).validate();\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.affected_rows() == 60u);\n    BOOST_TEST(fix.proc.info() == \"abc\");\n}\n\nBOOST_AUTO_TEST_CASE(execute_success_rows)\n{\n    // Setup\n    execute_fixture fix;\n\n    // Run the algo. Rows and OK are received in a single go (one call to read_some_rows)\n    algo_test()\n        .expect_write(create_frame(0, serialized_select_1))\n        .expect_read(create_frame(1, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(2, meta_builder().type(column_type::bigint).build_coldef()))\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(3, 42))\n                         .add(create_text_row_message(4, 43))\n                         .add(create_eof_frame(5, ok_builder().affected_rows(10u).info(\"1st\").build()))\n                         .build())\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls()\n        .reset(1)\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(1)\n        .on_row(2)\n        .on_row_batch_finish(1)\n        .on_row_ok_packet(1)\n        .validate();\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.num_meta() == 1u);\n    check_meta(fix.proc.meta(), {column_type::bigint});\n    BOOST_TEST(fix.proc.affected_rows() == 10u);\n    BOOST_TEST(fix.proc.info() == \"1st\");\n}\n\n// Test that immediate completion with errors in start_execution are propagated correctlty\nBOOST_AUTO_TEST_CASE(execute_error_num_params)\n{\n    // Setup\n    const auto params = make_fv_arr(\"test\", nullptr, 42);  // too many params\n    execute_fixture fix(any_execution_request({std::uint32_t(1), std::uint16_t(2), params}));\n\n    // Run the algo. Nothing should be written to the server\n    algo_test().check(fix, client_errc::wrong_num_params);\n}\n\n// Tests error on write, while reading head and while reading rows (error spotcheck)\nBOOST_AUTO_TEST_CASE(execute_error_network_error)\n{\n    algo_test()\n        .expect_write(create_frame(0, serialized_select_1))\n        .expect_read(create_frame(1, {0x01}))  // OK, 1 column\n        .expect_read(create_coldef_frame(2, meta_builder().type(column_type::tinyint).build_coldef()))\n        .expect_read(create_text_row_message(3, 42))\n        .expect_read(create_text_row_message(4, 43))\n        .expect_read(create_eof_frame(5, ok_builder().affected_rows(10u).info(\"1st\").build()))\n        .check_network_errors<execute_fixture>();\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(execute_error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            execute_fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_categories.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/mariadb_server_errc.hpp>\n\n#include <vector>\n\n#include \"handshake_common.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::capabilities;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake)\n\n//\n// Errors processing server hello\n//\n\n// The initial hello is invalid\nBOOST_AUTO_TEST_CASE(hello_deserialize_error)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(create_frame(0, {0x09, 0x00}))  // unsupported v9 protocol\n        .check(fix, client_errc::server_unsupported);\n}\n\n// The authentication plugin reports an error while hashing the password\n// with the data in the initial hello\nBOOST_AUTO_TEST_CASE(hello_hash_password_error)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(std::vector<std::uint8_t>(21, 0x0a)).build())\n        .check(fix, client_errc::protocol_value_error);\n}\n\n// The auth plugin supplied in hello is unknown\nBOOST_AUTO_TEST_CASE(hello_unknown_plugin)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_plugin(\"unknown\").auth_data(csha2p_scramble).build())\n        .check(fix, client_errc::unknown_auth_plugin);\n}\n\n// If the plugin is unknown, the scramble size might be different\nBOOST_AUTO_TEST_CASE(hello_unknown_plugin_different_scramble_size)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .auth_plugin(\"unknown\")\n                         .auth_data(std::vector<std::uint8_t>(30, 0xab))\n                         .build())\n        .check(fix, client_errc::unknown_auth_plugin);\n}\n\n//\n// Errors processing the initial server response\n//\n\n// Deserialization happens with the correct db_flavor\nBOOST_AUTO_TEST_CASE(initial_response_error_flavor)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).version(\"11.4.2-MariaDB-ubu2404\").build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(\n            err_builder().seqnum(2).code(mariadb_server_errc::er_bad_data).message(\"bad data\").build_frame()\n        )\n        .check(\n            fix,\n            error_code(mariadb_server_errc::er_bad_data, get_mariadb_server_category()),\n            create_server_diag(\"bad data\")\n        );\n}\n\n//\n// Errors processing the auth switch\n//\n\n// The auth switch fails because the plugin reports an error\n// while hashing the password with the data supplied in the auth switch\nBOOST_AUTO_TEST_CASE(authswitch_hash_password_error)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"mysql_native_password\", std::vector<std::uint8_t>(21, 0x0a))\n        )\n        .check(fix, client_errc::protocol_value_error);\n}\n\n// The auth switch flow fails because of a server error\nBOOST_AUTO_TEST_CASE(authswitch_error)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"mysql_native_password\", mnp_scramble))\n        .expect_write(create_frame(3, mnp_hash))\n        .expect_read(err_builder()\n                         .seqnum(4)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Denied\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Denied\"));\n}\n\n// We pass the correct db_flavor to process any errors generated by the auth switch\nBOOST_AUTO_TEST_CASE(authswitch_error_flavor)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .version(\"11.4.2-MariaDB-ubu2404\")\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"mysql_native_password\", mnp_scramble))\n        .expect_write(create_frame(3, mnp_hash))\n        .expect_read(\n            err_builder().seqnum(4).code(mariadb_server_errc::er_bad_data).message(\"Denied\").build_frame()\n        )\n        .check(\n            fix,\n            error_code(mariadb_server_errc::er_bad_data, get_mariadb_server_category()),\n            create_server_diag(\"Denied\")\n        );\n}\n\n// Receiving an auth switch after an auth switch is illegal\nBOOST_AUTO_TEST_CASE(authswitch_authswitch)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"mysql_native_password\", mnp_scramble))\n        .expect_write(create_frame(3, mnp_hash))\n        .expect_read(create_auth_switch_frame(4, \"mysql_native_password\", mnp_scramble))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// The plugin in the auth switch is unknown\nBOOST_AUTO_TEST_CASE(authswitch_unknown_plugin)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"unknown\", mnp_scramble))\n        .check(fix, client_errc::unknown_auth_plugin);\n}\n\n// If the plugin is unknown, the scramble may have a different size\nBOOST_AUTO_TEST_CASE(authswitch_unknown_plugin_different_scramble_size)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"unknown\", std::vector<std::uint8_t>(30, 0xab)))\n        .check(fix, client_errc::unknown_auth_plugin);\n}\n\n// Performing an auth switch to the same plugin is okay\nBOOST_AUTO_TEST_CASE(authswitch_to_itself)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"caching_sha2_password\", csha2p_scramble))\n        .expect_write(create_frame(3, csha2p_hash))\n        .expect_read(create_more_data_frame(4, csha2p_fast_auth_ok))\n        .expect_read(create_ok_frame(5, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n//\n// Errors in the more_data package exchange\n//\n\n// Receiving an auth switch after a more_data package is illegal\nBOOST_AUTO_TEST_CASE(moredata_authswitch)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(create_auth_switch_frame(3, \"mysql_native_password\", mnp_scramble))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\nBOOST_AUTO_TEST_CASE(authswitch_moredata_authswitch)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"mysql_native_password\").auth_data(mnp_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"mysql_native_password\").auth_response(mnp_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"caching_sha2_password\", csha2p_scramble))\n        .expect_write(create_frame(3, csha2p_hash))\n        .expect_read(create_auth_switch_frame(4, \"caching_sha2_password\", csha2p_scramble))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// We pass the correct db_flavor to error packets deserialized in the more_data exchange\nBOOST_AUTO_TEST_CASE(moredata_error_flavor)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .version(\"11.4.2-MariaDB-ubu2404\")\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(\n            err_builder().seqnum(3).code(mariadb_server_errc::er_bad_data).message(\"Denied\").build_frame()\n        )\n        .check(\n            fix,\n            error_code(mariadb_server_errc::er_bad_data, get_mariadb_server_category()),\n            create_server_diag(\"Denied\")\n        );\n}\n\n//\n// Network errors\n//\n\n// Covers everything except for an error after a plugin requests to read a packet\nBOOST_AUTO_TEST_CASE(network_errors)\n{\n    // Setup\n    struct fixture_type : handshake_fixture\n    {\n        fixture_type() { st.tls_supported = true; }\n    };\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(tls_caps).auth_data(mnp_scramble).build())\n        .expect_write(create_ssl_request())\n        .expect_ssl_handshake()\n        .expect_write(login_request_builder().seqnum(2).caps(tls_caps).auth_response(mnp_hash).build())\n        .expect_read(create_auth_switch_frame(3, \"caching_sha2_password\", csha2p_scramble))\n        .expect_write(create_frame(4, csha2p_hash))\n        .expect_read(create_more_data_frame(5, csha2p_perform_full_auth))\n        .expect_write(create_frame(6, null_terminated_password()))\n        .expect_read(create_ok_frame(7, ok_builder().build()))\n        .check_network_errors<fixture_type>();\n}\n\nBOOST_AUTO_TEST_CASE(network_errors_read_moredata)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(client_errc::wrong_num_params)\n        .check(fix, client_errc::wrong_num_params);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_capabilities.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include \"handshake_common.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::capabilities;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake_capabilities)\n\n//\n// connect with db\n//\n\nconstexpr auto db_caps = min_caps | capabilities::connect_with_db;\n\nBOOST_AUTO_TEST_CASE(db_nonempty_supported)\n{\n    // Setup\n    handshake_fixture fix(handshake_params(\"example_user\", \"example_password\", \"mydb\"));\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(db_caps).auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().caps(db_caps).auth_response(mnp_hash).db(\"mydb\").build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(db_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(db_nonempty_unsupported)\n{\n    // Setup\n    handshake_fixture fix(handshake_params(\"example_user\", \"example_password\", \"mydb\"));\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(min_caps).auth_data(mnp_scramble).build())\n        .check(fix, client_errc::server_unsupported);\n}\n\n// If the user didn't request a DB, we don't send it\nBOOST_AUTO_TEST_CASE(db_empty_supported)\n{\n    // Setup\n    handshake_fixture fix(handshake_params(\"example_user\", \"example_password\", \"\"));\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(db_caps).auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().caps(min_caps).auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// If the server doesn't support connect with DB but the user didn't request it, we don't fail\nBOOST_AUTO_TEST_CASE(db_empty_unsupported)\n{\n    // Setup\n    handshake_fixture fix(handshake_params(\"example_user\", \"example_password\", \"\"));\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n//\n// multi_queries\n//\n\nconstexpr auto multiq_caps = min_caps | capabilities::multi_statements;\n\n// We request it and the server supports it\nBOOST_AUTO_TEST_CASE(multiq_true_supported)\n{\n    // Setup\n    handshake_params hparams(\"example_user\", \"example_password\");\n    hparams.set_multi_queries(true);\n    handshake_fixture fix(hparams);\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(multiq_caps).auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().caps(multiq_caps).auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(multiq_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// We request is but the serve doesn't support it\nBOOST_AUTO_TEST_CASE(multiq_true_unsupported)\n{\n    // Setup\n    handshake_params hparams(\"example_user\", \"example_password\");\n    hparams.set_multi_queries(true);\n    handshake_fixture fix(hparams);\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(min_caps).auth_data(mnp_scramble).build())\n        .check(fix, client_errc::server_unsupported);\n}\n\n// We don't request it but the server supports it. We request the server to disable it\nBOOST_AUTO_TEST_CASE(multiq_false_supported)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(multiq_caps).auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().caps(min_caps).auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// We don't request it and the server doesn't support it, either. That's OK\nBOOST_AUTO_TEST_CASE(multiq_false_unsupported)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(min_caps).auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().caps(min_caps).auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n//\n// TLS\n//\n\n// Cases where we successfully negotiate the use of TLS\nBOOST_AUTO_TEST_CASE(tls_on)\n{\n    for (auto mode : {ssl_mode::enable, ssl_mode::require})\n    {\n        BOOST_TEST_CONTEXT(mode)\n        {\n            // Setup\n            handshake_params hparams(\"example_user\", \"example_password\");\n            hparams.set_ssl(mode);\n            handshake_fixture fix(hparams, false);  // TLS only negotiated when the transport is not secure\n            fix.st.tls_supported = true;            // TLS only negotiated if supported\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().caps(tls_caps).auth_data(mnp_scramble).build())\n                .expect_write(create_ssl_request())\n                .expect_ssl_handshake()\n                .expect_write(login_request_builder().seqnum(2).caps(tls_caps).auth_response(mnp_hash).build()\n                )\n                .expect_read(create_ok_frame(3, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_tls_active(true)\n                .will_set_capabilities(tls_caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(42)\n                .check(fix);\n        }\n    }\n}\n\n// Cases where we negotiate that we won't use any TLS\nBOOST_AUTO_TEST_CASE(tls_off)\n{\n    // TODO: handshake should be in charge of not negotiating\n    // TLS when a secure channel is in place. Enable these tests then\n    // constexpr struct\n    // {\n    //     const char* name;\n    //     ssl_mode mode;\n    //     bool secure_transport;\n    //     bool transport_supports_tls;\n    //     capabilities server_caps;\n    // } test_cases[] = {\n    //     {\"disable_insecure_clino_serverno\",   ssl_mode::disable, false, false, min_caps},\n    //     {\"disable_insecure_clino_serveryes\",  ssl_mode::disable, false, false, tls_caps},\n    //     {\"disable_insecure_cliyes_serverno\",  ssl_mode::disable, false, true,  min_caps},\n    //     {\"disable_insecure_cliyes_serveryes\", ssl_mode::disable, false, true,  tls_caps},\n    //     {\"disable_secure_clino_serverno\",     ssl_mode::disable, true,  false, min_caps},\n    //     {\"disable_secure_clino_serveryes\",    ssl_mode::disable, true,  false, tls_caps},\n    //     {\"disable_secure_cliyes_serverno\",    ssl_mode::disable, true,  true,  min_caps},\n    //     {\"disable_secure_cliyes_serveryes\",   ssl_mode::disable, true,  true,  tls_caps},\n\n    //     {\"enable_insecure_clino_serverno\",    ssl_mode::enable,  false, false, min_caps},\n    //     {\"enable_insecure_clino_serveryes\",   ssl_mode::enable,  false, false, tls_caps},\n    //     {\"enable_insecure_cliyes_serverno\",   ssl_mode::enable,  false, true,  min_caps},\n    //     {\"enable_secure_clino_serverno\",      ssl_mode::enable,  true,  false, min_caps},\n    //     {\"enable_secure_clino_serveryes\",     ssl_mode::enable,  true,  false, tls_caps},\n    //     {\"enable_secure_cliyes_serverno\",     ssl_mode::enable,  true,  true,  min_caps},\n    //     // {\"enable_secure_cliyes_serveryes\",    ssl_mode::enable,  true,  true,  tls_caps},\n\n    //     {\"require_insecure_clino_serverno\",   ssl_mode::require, false, false, min_caps},\n    //     {\"require_insecure_clino_serveryes\",  ssl_mode::require, false, false, tls_caps},\n    //     {\"require_secure_clino_serverno\",     ssl_mode::require, true,  false, min_caps},\n    //     {\"require_secure_clino_serveryes\",    ssl_mode::require, true,  false, tls_caps},\n    //     {\"require_secure_cliyes_serverno\",    ssl_mode::require, true,  true,  min_caps},\n    //     {\"require_secure_cliyes_serveryes\",   ssl_mode::require, true,  true,  tls_caps},\n    // };\n\n    constexpr struct\n    {\n        const char* name;\n        ssl_mode mode;\n        bool transport_supports_tls;\n        capabilities server_caps;\n    } test_cases[] = {\n        {\"disable_clino_serverno\",   ssl_mode::disable, false, min_caps},\n        {\"disable_clino_serveryes\",  ssl_mode::disable, false, tls_caps},\n        {\"disable_cliyes_serverno\",  ssl_mode::disable, true,  min_caps},\n        {\"disable_cliyes_serveryes\", ssl_mode::disable, true,  tls_caps},\n\n        {\"enable_clino_serverno\",    ssl_mode::enable,  false, min_caps},\n        {\"enable_clino_serveryes\",   ssl_mode::enable,  false, tls_caps},\n        {\"enable_cliyes_serverno\",   ssl_mode::enable,  true,  min_caps},\n\n        {\"require_clino_serverno\",   ssl_mode::require, false, min_caps},\n        {\"require_clino_serveryes\",  ssl_mode::require, false, tls_caps},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            handshake_params hparams(\"example_user\", \"example_password\");\n            hparams.set_ssl(tc.mode);\n            handshake_fixture fix(hparams, false);\n            fix.st.tls_supported = tc.transport_supports_tls;\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().caps(tc.server_caps).auth_data(mnp_scramble).build())\n                .expect_write(login_request_builder().caps(min_caps).auth_response(mnp_hash).build())\n                .expect_read(create_ok_frame(2, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_capabilities(min_caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(42)\n                .check(fix);\n        }\n    }\n}\n\n// We strongly want TLS but the server doesn't support it\nBOOST_AUTO_TEST_CASE(tls_error_unsupported)\n{\n    // Setup\n    handshake_params hparams(\"example_user\", \"example_password\");\n    hparams.set_ssl(ssl_mode::require);\n    handshake_fixture fix(hparams, false);  // This doesn't happen if the transport is already secure\n    fix.st.tls_supported = true;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(min_caps).auth_data(mnp_scramble).build())\n        .check(fix, client_errc::server_doesnt_support_ssl);\n}\n\n//\n// Base capabilities\n//\n\n// If the server doesn't have these, we can't talk to it\nBOOST_AUTO_TEST_CASE(caps_mandatory)\n{\n    constexpr struct\n    {\n        const char* name;\n        capabilities caps;\n    } test_cases[] = {\n        {\"no_plugin_auth\",\n         capabilities::protocol_41 | capabilities::plugin_auth_lenenc_data | capabilities::deprecate_eof |\n             capabilities::secure_connection                                                            },\n        {\"no_protocol_41\",\n         capabilities::plugin_auth | capabilities::plugin_auth_lenenc_data | capabilities::deprecate_eof |\n             capabilities::secure_connection                                                            },\n        {\"no_plugin_auth_lenenc_data\",\n         capabilities::plugin_auth | capabilities::protocol_41 | capabilities::deprecate_eof |\n             capabilities::secure_connection                                                            },\n        {\"no_deprecate_eof\",\n         capabilities::plugin_auth | capabilities::protocol_41 | capabilities::plugin_auth_lenenc_data |\n             capabilities::secure_connection                                                            },\n        {\"no_secure_connection\",\n         capabilities::plugin_auth | capabilities::protocol_41 | capabilities::plugin_auth_lenenc_data |\n             capabilities::deprecate_eof                                                                },\n        {\"several_missing\",            capabilities::plugin_auth | capabilities::plugin_auth_lenenc_data},\n        {\"none\",                       capabilities{}                                                   },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            handshake_fixture fix;\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().caps(tc.caps).auth_data(mnp_scramble).build())\n                .check(fix, client_errc::server_unsupported);\n        }\n    }\n}\n\n// If the server doesn't have them, it's OK (but better if it has them)\nBOOST_AUTO_TEST_CASE(caps_optional)\n{\n    constexpr struct\n    {\n        const char* name;\n        capabilities caps;\n    } test_cases[] = {\n        {\"multi_results\",    capabilities::multi_results   },\n        {\"ps_multi_results\", capabilities::ps_multi_results},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            handshake_fixture fix;\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().caps(min_caps | tc.caps).auth_data(mnp_scramble).build())\n                .expect_write(login_request_builder().caps(min_caps | tc.caps).auth_response(mnp_hash).build()\n                )\n                .expect_read(create_ok_frame(2, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_capabilities(min_caps | tc.caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(42)\n                .check(fix);\n        }\n    }\n}\n\n// We don't understand these capabilities, so we set them to off even if the server supports them\nBOOST_AUTO_TEST_CASE(caps_ignored)\n{\n    constexpr struct\n    {\n        const char* name;\n        capabilities caps;\n    } test_cases[] = {\n        {\"long_password\",                capabilities::long_password               },\n        {\"found_rows\",                   capabilities::found_rows                  },\n        {\"long_flag\",                    capabilities::long_flag                   },\n        {\"no_schema\",                    capabilities::no_schema                   },\n        {\"compress\",                     capabilities::compress                    },\n        {\"odbc\",                         capabilities::odbc                        },\n        {\"local_files\",                  capabilities::local_files                 },\n        {\"ignore_space\",                 capabilities::ignore_space                },\n        {\"interactive\",                  capabilities::interactive                 },\n        {\"ignore_sigpipe\",               capabilities::ignore_sigpipe              },\n        {\"transactions\",                 capabilities::transactions                },\n        {\"reserved\",                     capabilities::reserved                    },\n        {\"connect_attrs\",                capabilities::connect_attrs               },\n        {\"can_handle_expired_passwords\", capabilities::can_handle_expired_passwords},\n        {\"session_track\",                capabilities::session_track               },\n        {\"ssl_verify_server_cert\",       capabilities::ssl_verify_server_cert      },\n        {\"optional_resultset_metadata\",  capabilities::optional_resultset_metadata },\n        {\"remember_options\",             capabilities::remember_options            },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            handshake_fixture fix;\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().caps(min_caps | tc.caps).auth_data(mnp_scramble).build())\n                .expect_write(login_request_builder().caps(min_caps).auth_response(mnp_hash).build())\n                .expect_read(create_ok_frame(2, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_capabilities(min_caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(42)\n                .check(fix);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_common.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_SANSIO_HANDSHAKE_HANDSHAKE_COMMON_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_SANSIO_HANDSHAKE_HANDSHAKE_COMMON_HPP\n\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/protocol/capabilities.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/sansio/handshake.hpp>\n\n#include <algorithm>\n\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/serialize_to_vector.hpp\"\n\n// Functions and constants common to all handshake tests\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Capabilities\nconstexpr auto min_caps = detail::capabilities::plugin_auth | detail::capabilities::protocol_41 |\n                          detail::capabilities::plugin_auth_lenenc_data |\n                          detail::capabilities::deprecate_eof | detail::capabilities::secure_connection;\n\nconstexpr auto tls_caps = min_caps | detail::capabilities::ssl;\n\n// Helpers to create the relevant packets\nclass server_hello_builder\n{\n    string_view server_version_{\"8.1.33\"};\n    std::vector<std::uint8_t> auth_plugin_data_;\n    detail::capabilities server_caps_{min_caps};\n    string_view auth_plugin_name_{\"mysql_native_password\"};\n    std::uint32_t connection_id_{42};\n\npublic:\n    server_hello_builder& version(string_view v)\n    {\n        server_version_ = v;\n        return *this;\n    }\n    server_hello_builder& auth_data(span<const std::uint8_t> v)\n    {\n        BOOST_ASSERT(v.size() >= 8u);  // split in two parts, and the 1st one is fixed size at 8 bytes\n        BOOST_ASSERT(v.size() <= 0xfeu);\n        auth_plugin_data_.assign(v.begin(), v.end());\n        return *this;\n    }\n    server_hello_builder& caps(detail::capabilities v)\n    {\n        server_caps_ = v;\n        return *this;\n    }\n    server_hello_builder& auth_plugin(string_view v)\n    {\n        auth_plugin_name_ = v;\n        return *this;\n    }\n    server_hello_builder& connection_id(std::uint32_t v)\n    {\n        connection_id_ = v;\n        return *this;\n    }\n\n    std::vector<std::uint8_t> build() const\n    {\n        return create_frame(\n            0,\n            serialize_to_vector([this](detail::serialization_context& ctx) {\n                using namespace detail;\n\n                // Auth plugin data is separated in two parts\n                string_fixed<8> plugin_data_1{};\n                auto plug_data_begin = reinterpret_cast<const char*>(auth_plugin_data_.data());\n                std::copy(plug_data_begin, plug_data_begin + 8, plugin_data_1.value.data());\n                auto plugin_data_2 = boost::span<const std::uint8_t>(auth_plugin_data_).subspan(8);\n\n                // Capabilities is also divided in 2 parts\n                string_fixed<2> caps_low{};\n                string_fixed<2> caps_high{};\n                std::uint32_t caps_little = boost::endian::native_to_little(\n                    static_cast<std::uint32_t>(server_caps_)\n                );\n                auto* caps_begin = reinterpret_cast<const char*>(&caps_little);\n                std::copy(caps_begin, caps_begin + 2, caps_low.value.data());\n                std::copy(caps_begin + 2, caps_begin + 4, caps_high.value.data());\n\n                ctx.serialize(\n                    int1{10},  // protocol_version\n                    string_null{server_version_},\n                    int4{connection_id_},  // connection_id\n                    plugin_data_1,         // plugin data, 1st part\n                    int1{0},               // filler\n                    caps_low,\n                    int1{25},  // character set\n                    int2{0},   // status flags\n                    caps_high,\n                    int1{static_cast<std::uint8_t>(auth_plugin_data_.size() + 1u)\n                    },                  // auth plugin data length\n                    string_fixed<10>{}  // reserved\n                );\n                ctx.add(plugin_data_2);\n                ctx.add(0);  // extra null byte that mysql adds here\n                ctx.serialize(string_null{auth_plugin_name_});\n            })\n        );\n    }\n};\n\nclass login_request_builder\n{\n    std::uint8_t seqnum_{1};\n    detail::capabilities caps_{min_caps};\n    std::uint32_t collation_id_{45};  // utf8_general_ci\n    string_view username_{\"example_user\"};\n    std::vector<std::uint8_t> auth_response_;\n    string_view database_{};\n    string_view auth_plugin_name_{\"mysql_native_password\"};\n\npublic:\n    login_request_builder() = default;\n\n    login_request_builder& seqnum(std::uint8_t v)\n    {\n        seqnum_ = v;\n        return *this;\n    }\n\n    login_request_builder& caps(detail::capabilities v)\n    {\n        caps_ = v;\n        return *this;\n    }\n\n    login_request_builder& collation(std::uint32_t v)\n    {\n        collation_id_ = v;\n        return *this;\n    }\n\n    login_request_builder& username(string_view v)\n    {\n        username_ = v;\n        return *this;\n    }\n\n    login_request_builder& auth_response(span<const std::uint8_t> v)\n    {\n        auth_response_.assign(v.begin(), v.end());\n        return *this;\n    }\n\n    login_request_builder& db(string_view v)\n    {\n        database_ = v;\n        return *this;\n    }\n\n    login_request_builder& auth_plugin(string_view v)\n    {\n        auth_plugin_name_ = v;\n        return *this;\n    }\n\n    std::vector<std::uint8_t> build() const\n    {\n        auto body = serialize_to_vector([this](detail::serialization_context& ctx) {\n            ctx.serialize(detail::login_request{\n                caps_,\n                detail::max_packet_size,\n                collation_id_,\n                username_,\n                auth_response_,\n                database_,\n                auth_plugin_name_\n            });\n        });\n        return create_frame(seqnum_, body);\n    }\n};\n\ninline std::vector<std::uint8_t> create_ssl_request()\n{\n    const auto body = serialize_to_vector([](detail::serialization_context& ctx) {\n        constexpr std::uint32_t collation_id = 45;  // utf8_general_ci\n        detail::ssl_request req{tls_caps, detail::max_packet_size, collation_id};\n        req.serialize(ctx);\n    });\n    return create_frame(1, body);\n}\n\ninline std::vector<std::uint8_t> create_auth_switch_frame(\n    std::uint8_t seqnum,\n    string_view plugin_name,\n    boost::span<const std::uint8_t> data\n)\n{\n    return create_frame(seqnum, serialize_to_vector([=](detail::serialization_context& ctx) {\n                            ctx.add(0xfe);  // auth switch header\n                            detail::string_null{plugin_name}.serialize(ctx);\n                            ctx.add(data);\n                            ctx.add(std::uint8_t(0));  // This has a NULL byte at the end\n                        }));\n}\n\ninline std::vector<std::uint8_t> create_more_data_frame(\n    std::uint8_t seqnum,\n    boost::span<const std::uint8_t> data\n)\n{\n    return create_frame(seqnum, serialize_to_vector([=](detail::serialization_context& ctx) {\n                            ctx.add(0x01);  // more data header\n                            ctx.add(data);\n                        }));\n}\n\n// These scrambles/hashes have been captured with Wireshark.\nconstexpr const char* password = \"example_password\";\n\nconstexpr std::uint8_t mnp_scramble[] = {\n    0x1b, 0x0f, 0x6e, 0x59, 0x1b, 0x70, 0x33, 0x01, 0x0c, 0x01,\n    0x7e, 0x2e, 0x30, 0x7a, 0x79, 0x5c, 0x02, 0x50, 0x51, 0x35,\n};\n\nconstexpr std::uint8_t mnp_hash[] = {\n    0xbe, 0xa5, 0xb5, 0xe7, 0x9c, 0x05, 0x23, 0x34, 0xda, 0x06,\n    0x1d, 0xaf, 0xd9, 0x8b, 0x4b, 0x09, 0x86, 0xe5, 0xd1, 0x4a,\n};\n\nconstexpr std::uint8_t csha2p_scramble[] = {\n    0x6f, 0x1b, 0x3b, 0x64, 0x39, 0x01, 0x46, 0x44, 0x53, 0x3b,\n    0x74, 0x3c, 0x3e, 0x3c, 0x3c, 0x0b, 0x30, 0x77, 0x1a, 0x49,\n};\n\nconstexpr std::uint8_t csha2p_hash[] = {\n    0xa7, 0xc3, 0x7f, 0x88, 0x25, 0xec, 0x92, 0x2c, 0x88, 0xba, 0x47, 0x04, 0x14, 0xd2, 0xa3, 0xa3,\n    0x5e, 0xa9, 0x41, 0x8e, 0xdc, 0x89, 0xeb, 0xe2, 0xa1, 0xec, 0xd8, 0x4f, 0x73, 0xa1, 0x49, 0x60,\n};\n\nconstexpr std::uint8_t csha2p_request_key[] = {0x02};\nconstexpr std::uint8_t csha2p_fast_auth_ok[] = {0x03};\nconstexpr std::uint8_t csha2p_perform_full_auth[] = {0x04};\n\n// Null-terminated password, as required by the plugin\ninline boost::span<const std::uint8_t> null_terminated_password()\n{\n    return {reinterpret_cast<const std::uint8_t*>(password), std::strlen(password) + 1};\n}\n\nstruct handshake_fixture : algo_fixture_base\n{\n    detail::handshake_algo algo;\n\n    handshake_fixture(\n        const handshake_params& hparams = handshake_params(\"example_user\", password),\n        bool secure_transport = false\n    )\n        : algo({hparams, secure_transport})\n    {\n        st.status = detail::connection_status::not_connected;\n    }\n\n    handshake_fixture(bool secure_transport)\n        : handshake_fixture(handshake_params(\"example_user\", password), secure_transport)\n    {\n    }\n};\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_connection_state_data.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include \"handshake_common.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::capabilities;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake_connection_state_data)\n\n// connection_id: no value causes trouble\nBOOST_AUTO_TEST_CASE(hello_connection_id)\n{\n    for (std::uint32_t value : {0u, 10u, 0xffffffffu})\n    {\n        BOOST_TEST_CONTEXT(value)\n        {\n            // Setup\n            handshake_fixture fix;\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().connection_id(value).auth_data(mnp_scramble).build())\n                .expect_write(login_request_builder().auth_response(mnp_hash).build())\n                .expect_read(create_ok_frame(2, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_capabilities(min_caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(value)\n                .check(fix);\n        }\n    }\n}\n\n// Flavor is set, regardless of what we had before\nBOOST_AUTO_TEST_CASE(flavor)\n{\n    struct\n    {\n        string_view version;\n        detail::db_flavor flavor;\n    } test_cases[] = {\n        {\"11.4.2-MariaDB-ubu2404\",             detail::db_flavor::mariadb},\n        {\"8.4.1 MySQL Community Server - GPL\", detail::db_flavor::mysql  },\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.flavor)\n        {\n            // Setup\n            handshake_fixture fix;\n            fix.st.flavor = static_cast<detail::db_flavor>(0xffff);  // make sure that we set the value\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().version(tc.version).auth_data(mnp_scramble).build())\n                .expect_write(login_request_builder().auth_response(mnp_hash).build())\n                .expect_read(create_ok_frame(2, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_capabilities(min_caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(42)\n                .will_set_flavor(tc.flavor)\n                .check(fix);\n        }\n    }\n}\n\n// The value of character_set is cleared if the collation_id is unknown.\n// We don't test all supported collations here because we need to verify\n// that all supported servers support them (so it's an integration test).\nBOOST_AUTO_TEST_CASE(unknown_collation)\n{\n    // Setup\n    handshake_params hparams(\"example_user\", \"example_password\");\n    hparams.set_connection_collation(mysql_collations::utf8mb4_0900_as_ci);\n    handshake_fixture fix(hparams);\n    fix.st.current_charset = {\"other\", detail::next_char_utf8mb4};  // make sure that we set the value\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder()\n                          .collation(mysql_collations::utf8mb4_0900_as_ci)\n                          .auth_response(mnp_hash)\n                          .build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(character_set{})\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// The value of backslash_escapes in the final OK packet doesn't get ignored\nBOOST_AUTO_TEST_CASE(backslash_escapes)\n{\n    // Setup\n    handshake_fixture fix;\n    fix.st.backslash_escapes = true;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().no_backslash_escapes(true).build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_backslash_escapes(false)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// Handshake should not modify the value of metadata mode\nBOOST_AUTO_TEST_CASE(meta_mode)\n{\n    // Setup\n    handshake_fixture fix;\n    fix.st.meta_mode = metadata_mode::full;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n//\n// Connection status\n//\n\n// On success, set to ready, regardless of the initial value\nBOOST_AUTO_TEST_CASE(connection_status_success)\n{\n    constexpr connection_status all_status[] = {\n        connection_status::not_connected,\n        connection_status::ready,\n        connection_status::engaged_in_multi_function\n    };\n\n    for (auto initial_status : all_status)\n    {\n        BOOST_TEST_CONTEXT(initial_status)\n        {\n            // Setup\n            handshake_fixture fix;\n            fix.st.status = initial_status;\n\n            // Run the test\n            algo_test()\n                .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n                .expect_write(login_request_builder().auth_response(mnp_hash).build())\n                .expect_read(create_ok_frame(2, ok_builder().build()))\n                .will_set_status(connection_status::ready)\n                .will_set_capabilities(min_caps)\n                .will_set_current_charset(utf8mb4_charset)\n                .will_set_connection_id(42)\n                .check(fix);\n        }\n    }\n}\n\n// On success, set to not connected, regardless of the initial value\nBOOST_AUTO_TEST_CASE(connection_status_error)\n{\n    constexpr connection_status all_status[] = {\n        connection_status::not_connected,\n        connection_status::ready,\n        connection_status::engaged_in_multi_function\n    };\n\n    for (auto initial_status : all_status)\n    {\n        BOOST_TEST_CONTEXT(initial_status)\n        {\n            // Setup\n            handshake_fixture fix;\n            fix.st.status = initial_status;\n\n            // Run the test\n            algo_test()\n                .expect_read(client_errc::sequence_number_mismatch)\n                .will_set_status(connection_status::not_connected)\n                .check(fix, client_errc::sequence_number_mismatch);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_csha2p.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n\n#include <boost/core/span.hpp>\n\n#include <cstring>\n#include <vector>\n\n#include \"handshake_common.hpp\"\n#include \"handshake_csha2p_keys.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::capabilities;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake_csha2p)\n\n// Edge case: we tolerate a direct OK packet in the fast path, without a fast auth OK\nBOOST_AUTO_TEST_CASE(ok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// Edge case: we tolerate a direct error packet in the fast path, without a fast auth OK\n// (password errors trigger a perform full auth flow)\nBOOST_AUTO_TEST_CASE(err)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(err_builder()\n                         .seqnum(2)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Denied\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Denied\"));\n}\n\n// Receiving an unknown more data frame (something != fullauth or fastok) is illegal\nBOOST_AUTO_TEST_CASE(moredata)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, std::vector<std::uint8_t>{3, 4}))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Usual success path when using the fast track\nBOOST_AUTO_TEST_CASE(fastok_ok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(create_ok_frame(3, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// Password errors don't trigger this path (they always go through full auth),\n// but other errors (like incorrect database) trigger this path\nBOOST_AUTO_TEST_CASE(fastok_err)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(err_builder()\n                         .seqnum(3)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Denied\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Denied\"));\n}\n\n// Receiving two consecutive more_data frames with fast OK contents is illegal\nBOOST_AUTO_TEST_CASE(fastok_fastok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(create_more_data_frame(3, csha2p_fast_auth_ok))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Receiving a full auth request after a fast track OK is illegal\nBOOST_AUTO_TEST_CASE(fastok_fullauth)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(create_more_data_frame(3, csha2p_perform_full_auth))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Receiving an unknown data frame after a fast track OK fails as expected\nBOOST_AUTO_TEST_CASE(fastok_moredata)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_fast_auth_ok))\n        .expect_read(create_more_data_frame(3, std::vector<std::uint8_t>{10, 20, 30}))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Auth switch flows with fast OK work\nBOOST_AUTO_TEST_CASE(authswitch_fastok_ok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"mysql_native_password\").auth_data(mnp_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"mysql_native_password\").auth_response(mnp_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"caching_sha2_password\", csha2p_scramble))\n        .expect_write(create_frame(3, csha2p_hash))\n        .expect_read(create_more_data_frame(4, csha2p_fast_auth_ok))\n        .expect_read(create_ok_frame(5, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// If the server requests us to perform full auth and we're using plaintext,\n// we request the server's public key\nBOOST_AUTO_TEST_CASE(fullauth_key_ok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .caps(tls_caps)\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, csha2p_request_key))\n        .expect_read(create_more_data_frame(4, public_key_2048))\n        .expect_any_write()  // the exact encryption result is not deterministic\n        .expect_read(create_ok_frame(6, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// The server might send us an error after we sent the password (e.g. unauthorized)\nBOOST_AUTO_TEST_CASE(fullauth_key_error)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .caps(tls_caps)\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, csha2p_request_key))\n        .expect_read(create_more_data_frame(4, public_key_2048))\n        .expect_any_write()  // the exact encryption result is not deterministic\n        .expect_read(err_builder()\n                         .seqnum(6)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Denied\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Denied\"));\n}\n\n// The server might send us an error instead of the key,\n// if the key pair for caching_sha2_password was misconfigured\nBOOST_AUTO_TEST_CASE(fullauth_error)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .caps(tls_caps)\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, csha2p_request_key))\n        .expect_read(err_builder()\n                         .seqnum(4)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Bad key\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Bad key\"));\n}\n\n// If encryption fails (e.g. because the server sent us an invalid key), we fail appropriately.\n// Size checks are the only ones that yield a predictable error code\nBOOST_AUTO_TEST_CASE(fullauth_encrypterror)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .caps(tls_caps)\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, csha2p_request_key))\n        .expect_read(create_more_data_frame(4, std::vector<std::uint8_t>(2u * 1024u * 1024u, 0xab)))\n        .check(fix, client_errc::protocol_value_error);\n}\n\n// After encrypting the password, no more messages are expected\nBOOST_AUTO_TEST_CASE(fullauth_key_moredata)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .caps(tls_caps)\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, csha2p_request_key))\n        .expect_read(create_more_data_frame(4, public_key_2048))\n        .expect_any_write()  // the exact encryption result is not deterministic\n        .expect_read(create_more_data_frame(6, csha2p_perform_full_auth))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// If we're using a secure transport (e.g. UNIX socket), caching_sha2_password\n// just sends the raw password\nBOOST_AUTO_TEST_CASE(securetransport_fullauth_ok)\n{\n    // Setup\n    handshake_fixture fix(true);\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, null_terminated_password()))\n        .expect_read(create_ok_frame(4, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// Same, but failing\n// If we're using a secure transport (e.g. UNIX socket), caching_sha2_password\n// just sends the raw password\nBOOST_AUTO_TEST_CASE(securetransport_fullauth_err)\n{\n    // Setup\n    handshake_fixture fix(true);\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, null_terminated_password()))\n        .expect_read(err_builder()\n                         .seqnum(4)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Denied\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Denied\"));\n}\n\n// A fast track OK after a fullauth request is not legal\nBOOST_AUTO_TEST_CASE(securetransport_fullauth_fastok)\n{\n    // Setup\n    handshake_fixture fix(true);\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, null_terminated_password()))\n        .expect_read(create_more_data_frame(4, csha2p_fast_auth_ok))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Two consecutive full auth requests are not legal\nBOOST_AUTO_TEST_CASE(securetransport_fullauth_fullauth)\n{\n    // Setup\n    handshake_fixture fix(true);\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, null_terminated_password()))\n        .expect_read(create_more_data_frame(4, csha2p_perform_full_auth))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Any subsequent more data frames are illegal\nBOOST_AUTO_TEST_CASE(securetransport_fullauth_moredata)\n{\n    // Setup\n    handshake_fixture fix(true);\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_more_data_frame(2, csha2p_perform_full_auth))\n        .expect_write(create_frame(3, null_terminated_password()))\n        .expect_read(create_more_data_frame(4, std::vector<std::uint8_t>{4, 3, 2}))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\n// Spotcheck: TLS counts as a secure channel\nBOOST_AUTO_TEST_CASE(tls)\n{\n    // Setup\n    handshake_fixture fix;\n    fix.st.tls_supported = true;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder()\n                         .caps(tls_caps)\n                         .auth_plugin(\"caching_sha2_password\")\n                         .auth_data(csha2p_scramble)\n                         .build())\n        .expect_write(create_ssl_request())\n        .expect_ssl_handshake()\n        .expect_write(login_request_builder()\n                          .seqnum(2)\n                          .caps(tls_caps)\n                          .auth_plugin(\"caching_sha2_password\")\n                          .auth_response(csha2p_hash)\n                          .build())\n        .expect_read(create_more_data_frame(3, csha2p_perform_full_auth))\n        .expect_write(create_frame(4, null_terminated_password()))\n        .expect_read(create_ok_frame(5, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(tls_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .will_set_tls_active(true)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_csha2p_encrypt_password.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/sansio/csha2p_encrypt_password.hpp>\n\n#include <boost/asio/ssl/error.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n#include <openssl/bio.h>\n#include <openssl/evp.h>\n#include <openssl/pem.h>\n#include <string>\n#include <vector>\n\n#include \"handshake_csha2p_keys.hpp\"\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::asio::error::ssl_category;\nusing detail::csha2p_encrypt_password;\n\nusing buffer_type = boost::container::small_vector<std::uint8_t, 512>;\n\nnamespace {\n\n// Encrypting with RSA and OAEP padding involves random numbers for padding.\n// There isn't a reliable way to seed OpenSSL's random number generators so that\n// the output is deterministic. So we do the following:\n//    1. We know the server's public and private keys and the password (the constants below).\n//    2. We capture a scramble and a corresponding ciphertext using Wireshark.\n//    3. We decrypt the ciphertext with OpenSSL to obtain the expected plaintext (the salted password).\n//    4. Tests run csha2p_encrypt_password, decrypt its output, and verify that it matches the expected\n//    plaintext.\nBOOST_AUTO_TEST_SUITE(test_handshake_csha2p_encrypt_password)\n\nconstexpr std::uint8_t scramble[] = {\n    0x0f, 0x64, 0x4f, 0x2f, 0x2b, 0x3b, 0x27, 0x6b, 0x45, 0x5c,\n    0x53, 0x01, 0x13, 0x7e, 0x4f, 0x10, 0x26, 0x23, 0x5d, 0x27,\n};\n\n// Decrypts the output of\nstd::vector<std::uint8_t> decrypt(span<const std::uint8_t> private_key, span<const std::uint8_t> ciphertext)\n{\n    // RAII helpers\n    struct bio_deleter\n    {\n        void operator()(BIO* bio) const noexcept { BIO_free(bio); }\n    };\n    using unique_bio = std::unique_ptr<BIO, bio_deleter>;\n\n    struct evp_pkey_deleter\n    {\n        void operator()(EVP_PKEY* pkey) const noexcept { EVP_PKEY_free(pkey); }\n    };\n    using unique_evp_pkey = std::unique_ptr<EVP_PKEY, evp_pkey_deleter>;\n\n    struct evp_pkey_ctx_deleter\n    {\n        void operator()(EVP_PKEY_CTX* ctx) const noexcept { EVP_PKEY_CTX_free(ctx); }\n    };\n    using unique_evp_pkey_ctx = std::unique_ptr<EVP_PKEY_CTX, evp_pkey_ctx_deleter>;\n\n    // Create a BIO with the key\n    unique_bio bio(BIO_new_mem_buf(private_key.data(), static_cast<int>(private_key.size())));\n    BOOST_TEST_REQUIRE((bio != nullptr), \"Creating a BIO failed: \" << ERR_get_error());\n\n    // Load the key\n    unique_evp_pkey pkey(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));\n    BOOST_TEST_REQUIRE((bio != nullptr), \"Loading the key failed: \" << ERR_get_error());\n\n    // Create a decryption context\n    unique_evp_pkey_ctx ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));\n    BOOST_TEST_REQUIRE((ctx != nullptr), \"Creating a context failed: \" << ERR_get_error());\n\n    // Initialize it\n    BOOST_TEST_REQUIRE(\n        EVP_PKEY_decrypt_init(ctx.get()) > 0,\n        \"Initializing decryption failed: \" << ERR_get_error()\n    );\n\n    // Set the padding scheme\n    BOOST_TEST_REQUIRE(\n        EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) > 0,\n        \"Setting the padding scheme failed: \" << ERR_get_error()\n    );\n\n    // Determine the size of the decrypted buffer\n    std::size_t out_size = 0;\n    BOOST_TEST_REQUIRE(\n        EVP_PKEY_decrypt(ctx.get(), nullptr, &out_size, ciphertext.data(), ciphertext.size()) > 0,\n        \"Determining decryption size failed: \" << ERR_get_error()\n    );\n    std::vector<std::uint8_t> res(out_size, 0);\n\n    // Actually decrypt\n    BOOST_TEST_REQUIRE(\n        EVP_PKEY_decrypt(ctx.get(), res.data(), &out_size, ciphertext.data(), ciphertext.size()) > 0,\n        \"Decrypting failed: \" << ERR_get_error()\n    );\n    res.resize(out_size);\n\n    // Done\n    return res;\n}\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    // A password with all the possible ASCII values\n    std::string all_chars_password;\n    for (int i = 0; i < 256; ++i)\n        all_chars_password.push_back(static_cast<char>(i));\n\n    struct\n    {\n        string_view name;\n        std::string password;\n        span<const std::uint8_t> public_key;\n        span<const std::uint8_t> private_key;\n        std::vector<std::uint8_t> expected_decrypted;\n    } test_cases[] = {\n        // clang-format off\n        // An empty password does not cause trouble. This is an edge case, since\n        // an empty password should employ a different workflow\n        {\n            \"password_empty\",\n            {},\n            span<const unsigned char>(public_key_2048),\n            span<const unsigned char>(private_key_2048),\n            {0x0f}\n        },\n\n        // Password is < length of the scramble\n        {\n            \"password_shorter_scramble\",\n            \"csha2p_password\",\n            span<const unsigned char>(public_key_2048),\n            span<const unsigned char>(private_key_2048), \n            {\n                0x6c, 0x17, 0x27, 0x4e, 0x19, 0x4b, 0x78, 0x1b, 0x24, 0x2f, 0x20, 0x76, 0x7c, 0x0c, 0x2b, 0x10\n            }\n        },\n\n        // Password (with NULL byte) is equal to the length of the scramble\n        {\n            \"password_same_size_scramble\",\n            \"hjbjd923KKLiosoi90J\",\n            span<const unsigned char>(public_key_2048),\n            span<const unsigned char>(private_key_2048),\n            {\n                0x67, 0x0e, 0x2d, 0x45, 0x4f, 0x02, 0x15, 0x58, 0x0e, 0x17,\n                0x1f, 0x68, 0x7c, 0x0d, 0x20, 0x79, 0x1f, 0x13, 0x17, 0x27\n            }\n        },\n\n        // Passwords longer than the scramble use it cyclically\n        {\n            \"password_longer_scramble\",\n            \"kjaski829380jvnnM,ka;::_kshf93IJCLIJO)jcjsnaklO?a\",\n            span<const unsigned char>(public_key_2048),\n            span<const unsigned char>(private_key_2048),\n            {\n                0x64, 0x0e, 0x2e, 0x5c, 0x40, 0x52, 0x1f, 0x59, 0x7c, 0x6f, 0x6b, 0x31, 0x79, 0x08, 0x21, 0x7e, 0x6b,\n                0x0f, 0x36, 0x46, 0x34, 0x5e, 0x75, 0x70, 0x40, 0x48, 0x4f, 0x0d, 0x7c, 0x6f, 0x1a, 0x4b, 0x50, 0x32,\n                0x06, 0x5a, 0x69, 0x0a, 0x37, 0x44, 0x65, 0x17, 0x21, 0x4e, 0x40, 0x57, 0x68, 0x54, 0x24, 0x5c,\n            }\n        },\n\n        // The longest password that a 2048 RSA key can encrypt with the OAEP scheme\n        {\n            \"password_max_size_2048\",\n            \"hjbjd923KKLkjbdkcjwhekiy8393ou2weusidhiahJBKJKHCIHCKJIu9KHO09IJIpojaf0w39jalsjMMKjkjhiue93I=))\"\n                \"UXIOJKXNKNhkai8923oiawiakssaknhakhIIHICHIO)CU)\"\n                \"IHCKHCKJhisiweioHHJHUCHIIIJIOPkjgwijiosoi9jsu84HHUHCHI9839hdjsbsdjuUHJjbJ\",\n            span<const unsigned char>(public_key_2048),\n            span<const unsigned char>(private_key_2048),\n            {\n                0x67, 0x0e, 0x2d, 0x45, 0x4f, 0x02, 0x15, 0x58, 0x0e, 0x17, 0x1f, 0x6a, 0x79, 0x1c, 0x2b, 0x7b, 0x45,\n                0x49, 0x2a, 0x4f, 0x6a, 0x0f, 0x26, 0x56, 0x13, 0x08, 0x1e, 0x58, 0x2a, 0x29, 0x61, 0x76, 0x76, 0x0b,\n                0x3c, 0x79, 0x42, 0x4b, 0x34, 0x46, 0x67, 0x2e, 0x0d, 0x64, 0x61, 0x70, 0x6f, 0x28, 0x0c, 0x14, 0x10,\n                0x4a, 0x59, 0x37, 0x3a, 0x29, 0x6d, 0x6b, 0x12, 0x17, 0x36, 0x2d, 0x05, 0x66, 0x5b, 0x54, 0x4d, 0x0a,\n                0x23, 0x6c, 0x24, 0x32, 0x2a, 0x14, 0x2e, 0x7c, 0x55, 0x49, 0x10, 0x6a, 0x44, 0x0e, 0x24, 0x45, 0x43,\n                0x52, 0x52, 0x0e, 0x7c, 0x6f, 0x1a, 0x3c, 0x3a, 0x57, 0x1a, 0x48, 0x6f, 0x6c, 0x17, 0x6c, 0x57, 0x2a,\n                0x04, 0x61, 0x43, 0x50, 0x46, 0x02, 0x7d, 0x65, 0x61, 0x32, 0x7c, 0x17, 0x2e, 0x67, 0x4f, 0x42, 0x36,\n                0x54, 0x7c, 0x05, 0x24, 0x41, 0x43, 0x5a, 0x4c, 0x03, 0x0c, 0x15, 0x1b, 0x48, 0x50, 0x36, 0x06, 0x5f,\n                0x0f, 0x60, 0x08, 0x0e, 0x46, 0x2c, 0x0c, 0x64, 0x63, 0x78, 0x6c, 0x21, 0x2d, 0x35, 0x20, 0x68, 0x64,\n                0x1b, 0x26, 0x7f, 0x6e, 0x6b, 0x17, 0x6f, 0x5a, 0x27, 0x07, 0x66, 0x62, 0x72, 0x6d, 0x22, 0x0a, 0x0c,\n                0x38, 0x6b, 0x74, 0x09, 0x26, 0x7a, 0x4f, 0x4c, 0x2e, 0x48, 0x66, 0x5d, 0x25, 0x5c, 0x5e, 0x03, 0x13,\n                0x23, 0x0d, 0x09, 0x1b, 0x42, 0x5b, 0x37, 0x76, 0x28, 0x15, 0x1a, 0x35, 0x43, 0x65, 0x17, 0x2d, 0x5c,\n                0x4f, 0x51, 0x52, 0x3e, 0x0d, 0x16, 0x39, 0x63, 0x59, 0x7e,\n            }\n        },\n\n        // Longer passwords are accepted if the key supports them.\n        // Concretely, passwords longer than 512 (size of our SBO) are supported\n        {\n            \"password_longer_sbo\",\n            std::string(600, '5'),\n            span<const unsigned char>(public_key_8192),\n            span<const unsigned char>(private_key_8192),\n            {\n                0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13,\n                0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b,\n                0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66,\n                0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e,\n                0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e,\n                0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51,\n                0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68,\n                0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25,\n                0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26,\n                0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69,\n                0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12,\n                0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a,\n                0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a,\n                0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16,\n                0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a,\n                0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34,\n                0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70,\n                0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e,\n                0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a,\n                0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12,\n                0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13,\n                0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b,\n                0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66,\n                0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e,\n                0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e,\n                0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51,\n                0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68,\n                0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25,\n                0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26,\n                0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69,\n                0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12,\n                0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a,\n                0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16, 0x68, 0x12, 0x3a,\n                0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a, 0x25, 0x13, 0x16,\n                0x68, 0x12, 0x3a, 0x51, 0x7a, 0x1a, 0x1e, 0x0e, 0x12, 0x5e, 0x70, 0x69, 0x66, 0x34, 0x26, 0x4b, 0x7a,\n                0x25, 0x13, 0x16, 0x68, 0x12, 0x0f\n            }\n        },\n\n        // No character causes trouble\n        {\n            \"password_all_characters\",\n            all_chars_password,\n            span<const unsigned char>(public_key_8192),\n            span<const unsigned char>(private_key_8192),\n            {\n                0x0f, 0x65, 0x4d, 0x2c, 0x2f, 0x3e, 0x21, 0x6c, 0x4d, 0x55, 0x59, 0x0a, 0x1f, 0x73, 0x41, 0x1f, 0x36,\n                0x32, 0x4f, 0x34, 0x1b, 0x71, 0x59, 0x38, 0x33, 0x22, 0x3d, 0x70, 0x59, 0x41, 0x4d, 0x1e, 0x33, 0x5f,\n                0x6d, 0x33, 0x02, 0x06, 0x7b, 0x00, 0x27, 0x4d, 0x65, 0x04, 0x07, 0x16, 0x09, 0x44, 0x75, 0x6d, 0x61,\n                0x32, 0x27, 0x4b, 0x79, 0x27, 0x1e, 0x1a, 0x67, 0x1c, 0x33, 0x59, 0x71, 0x10, 0x6b, 0x7a, 0x65, 0x28,\n                0x01, 0x19, 0x15, 0x46, 0x5b, 0x37, 0x05, 0x5b, 0x6a, 0x6e, 0x13, 0x68, 0x5f, 0x35, 0x1d, 0x7c, 0x7f,\n                0x6e, 0x71, 0x3c, 0x1d, 0x05, 0x09, 0x5a, 0x4f, 0x23, 0x11, 0x4f, 0x46, 0x42, 0x3f, 0x44, 0x6b, 0x01,\n                0x29, 0x48, 0x43, 0x52, 0x4d, 0x00, 0x29, 0x31, 0x3d, 0x6e, 0x63, 0x0f, 0x3d, 0x63, 0x52, 0x56, 0x2b,\n                0x50, 0x77, 0x1d, 0x35, 0x54, 0x57, 0x46, 0x59, 0x14, 0xc5, 0xdd, 0xd1, 0x82, 0x97, 0xfb, 0xc9, 0x97,\n                0xae, 0xaa, 0xd7, 0xac, 0x83, 0xe9, 0xc1, 0xa0, 0xbb, 0xaa, 0xb5, 0xf8, 0xd1, 0xc9, 0xc5, 0x96, 0x8b,\n                0xe7, 0xd5, 0x8b, 0xba, 0xbe, 0xc3, 0xb8, 0xaf, 0xc5, 0xed, 0x8c, 0x8f, 0x9e, 0x81, 0xcc, 0xed, 0xf5,\n                0xf9, 0xaa, 0xbf, 0xd3, 0xe1, 0xbf, 0x96, 0x92, 0xef, 0x94, 0xbb, 0xd1, 0xf9, 0x98, 0x93, 0x82, 0x9d,\n                0xd0, 0xf9, 0xe1, 0xed, 0xbe, 0xd3, 0xbf, 0x8d, 0xd3, 0xe2, 0xe6, 0x9b, 0xe0, 0xc7, 0xad, 0x85, 0xe4,\n                0xe7, 0xf6, 0xe9, 0xa4, 0x95, 0x8d, 0x81, 0xd2, 0xc7, 0xab, 0x99, 0xc7, 0xfe, 0xfa, 0x87, 0xfc, 0xd3,\n                0xb9, 0x91, 0xf0, 0xcb, 0xda, 0xc5, 0x88, 0xa1, 0xb9, 0xb5, 0xe6, 0xfb, 0x97, 0xa5, 0xfb, 0xca, 0xce,\n                0xb3, 0xc8, 0xff, 0x95, 0xbd, 0xdc, 0xdf, 0xce, 0xd1, 0x9c, 0xbd, 0xa5, 0xa9, 0xfa, 0xef, 0x83, 0xb1,\n                0xef, 0x26\n            }\n        }\n\n        // clang-format on\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            buffer_type buff;\n\n            // Call the function\n            auto ec = csha2p_encrypt_password(tc.password, scramble, tc.public_key, buff, ssl_category);\n\n            // Verify\n            BOOST_TEST_REQUIRE(ec == error_code());\n            BOOST_MYSQL_ASSERT_BUFFER_EQUALS(decrypt(tc.private_key, buff), tc.expected_decrypted);\n        }\n    }\n}\n\n//\n// Errors. For OpenSSL errors, it's not defined what exact code will each function return.\n//\n\n// We passed an empty buffer to the key parser\nBOOST_AUTO_TEST_CASE(error_key_buffer_empty)\n{\n    buffer_type buff;\n    auto ec = csha2p_encrypt_password(\"csha2p_password\", scramble, {}, buff, ssl_category);\n    BOOST_TEST((ec.category() == ssl_category));\n    BOOST_TEST(ec.value() > 0);      // is an error\n    BOOST_TEST(ec.message() != \"\");  // produces some output\n    BOOST_TEST(ec.has_location());\n}\n\nBOOST_AUTO_TEST_CASE(error_key_malformed)\n{\n    constexpr std::uint8_t key_buffer[] = \"-----BEGIN PUBLIC KEY-----zwIDAQAB__kaj0?))=\";\n    buffer_type buff;\n    auto ec = csha2p_encrypt_password(\"csha2p_password\", scramble, key_buffer, buff, ssl_category);\n    BOOST_TEST((ec.category() == ssl_category));\n    BOOST_TEST(ec.value() > 0);      // is an error\n    BOOST_TEST(ec.message() != \"\");  // produces some output\n    BOOST_TEST(ec.has_location());\n}\n\n// Passing in a public key type that does not support encryption operations\n// (like ECDSA) fails\nBOOST_AUTO_TEST_CASE(error_key_doesnt_support_encryption)\n{\n    constexpr unsigned char key_buffer[] = R\"%(-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERDkCI/degPJXEIYYncyvGsTdj9YI\n4xQ6KPTzoF+DY2jM09w1TCncxk9XV1eOo44UMDUuK9K01halQy70mohFSQ==\n-----END PUBLIC KEY-----\n)%\";\n\n    buffer_type buff;\n    auto ec = csha2p_encrypt_password(\"csha2p_password\", scramble, key_buffer, buff, ssl_category);\n    BOOST_TEST((ec.category() == ssl_category));\n    BOOST_TEST(ec.value() > 0);      // is an error\n    BOOST_TEST(ec.message() != \"\");  // produces some output\n    BOOST_TEST(ec.has_location());\n}\n\n// Passing in a public key type that allows encryption but is not RSA fails as expected.\n// This is a SM2 key, generated by:\n//   openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:sm2 -out public.pem\n//   openssl pkey -in private.pem -pubout -out public.pem\nBOOST_AUTO_TEST_CASE(error_key_not_rsa)\n{\n    // ECDSA public key set up for SM2 encryption\n    constexpr unsigned char public_key_sm2[] = R\"%(-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEWGAXSpPHb2bWQjROuegjWPcuVwNW\nmVpTh++3j7pnpWUjnFuarvWmWh/H6t96/pTx566FKGxZpLn3H9TLHZJsog==\n-----END PUBLIC KEY-----\n)%\";\n\n    buffer_type buff;\n    auto ec = csha2p_encrypt_password(\"csha2p_password\", scramble, public_key_sm2, buff, ssl_category);\n    BOOST_TEST(ec.failed());  // OpenSSL might or might not provide an error code here\n    BOOST_TEST(ec.has_location());\n}\n\nBOOST_AUTO_TEST_CASE(error_key_too_big)\n{\n    buffer_type buff;\n    std::vector<std::uint8_t> key_buffer(2u * 1024u * 1024u, 0x0a);\n    auto ec = csha2p_encrypt_password(\"csha2p_password\", scramble, key_buffer, buff, ssl_category);\n    BOOST_TEST(ec == client_errc::protocol_value_error);\n    BOOST_TEST(ec.has_location());\n}\n\n// If a password longer than the longest allowed plaintext is provided, we fail\nBOOST_AUTO_TEST_CASE(error_password_too_big)\n{\n    buffer_type buff;\n    std::string passwd(214u, 'a');  // 213 is the max RSA/OAEP plaintext size\n    auto ec = csha2p_encrypt_password(passwd, scramble, public_key_2048, buff, ssl_category);\n    BOOST_TEST((ec.category() == ssl_category));\n    BOOST_TEST(ec.value() > 0);      // is an error\n    BOOST_TEST(ec.message() != \"\");  // produces some output\n    BOOST_TEST(ec.has_location());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_csha2p_hash_password.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/sansio/caching_sha2_password.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n\nusing namespace boost::mysql;\nusing detail::csha2p_hash_password;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake_csha2p_hash_password)\n\n// Values snooped using Wireshark\nconstexpr std::uint8_t scramble[20] = {\n    0x3e, 0x3b, 0x4,  0x55, 0x4,  0x70, 0x16, 0x3a, 0x4c, 0x15,\n    0x35, 0x3,  0x15, 0x76, 0x73, 0x22, 0x46, 0x8,  0x18, 0x1,\n};\n\nBOOST_AUTO_TEST_CASE(nonempty_password)\n{\n    constexpr std::uint8_t expected_hash[32] = {\n        0xa1, 0xc1, 0xe1, 0xe9, 0x1b, 0xb6, 0x54, 0x4b, 0xa7, 0x37, 0x4b, 0x9c, 0x56, 0x6d, 0x69, 0x3e,\n        0x6,  0xca, 0x7,  0x2,  0x98, 0xac, 0xd1, 0x6,  0x18, 0xc6, 0x90, 0x38, 0x9d, 0x88, 0xe1, 0x20,\n    };\n\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(csha2p_hash_password(\"hola\", scramble), expected_hash);\n}\n\nBOOST_AUTO_TEST_CASE(empty_password)\n{\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(csha2p_hash_password(\"\", scramble), std::vector<std::uint8_t>());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_csha2p_keys.hpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#ifndef BOOST_MYSQL_TEST_UNIT_TEST_SANSIO_HANDSHAKE_HANDSHAKE_CSHA2P_KEYS_HPP\n#define BOOST_MYSQL_TEST_UNIT_TEST_SANSIO_HANDSHAKE_HANDSHAKE_CSHA2P_KEYS_HPP\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\nconstexpr unsigned char public_key_2048[] = R\"%(-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA36OYSpdiy1lFDrdO1Vux\nGwjPTo35R2+mXqW2SZV7kH5C6BSCeoTk6STVRBJbgOCabtp5bpUZ+x2bYWOZp4fs\nJakC75CN2YTJoYg5z5U6XUBEWn6WNBpvEoSJaUtrzfU69J07uWqB6v0MdJf3JTgd\nILfGKvk2T+maxqUiYObs0BJd5eKJZDlUaf2r4a9KC8zGUZzHdgtZEXlkHVNLEbbD\nJu4KjtCtJCG1NEBAh3oSnNp/Q1FKFywqU7YnEBWI0B9C5UcKNFbg7M35daimXfGp\nV7WJKhO9w7iBJYL1SW+PwyUCh3DNsuSm3nLmuwKhTvGQHZJS/5OVdSHgZhjDnk2V\nWwIDAQAB\n-----END PUBLIC KEY-----\n)%\";\n\nconstexpr unsigned char private_key_2048[] = R\"%(-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDfo5hKl2LLWUUO\nt07VW7EbCM9OjflHb6ZepbZJlXuQfkLoFIJ6hOTpJNVEEluA4Jpu2nlulRn7HZth\nY5mnh+wlqQLvkI3ZhMmhiDnPlTpdQERafpY0Gm8ShIlpS2vN9Tr0nTu5aoHq/Qx0\nl/clOB0gt8Yq+TZP6ZrGpSJg5uzQEl3l4olkOVRp/avhr0oLzMZRnMd2C1kReWQd\nU0sRtsMm7gqO0K0kIbU0QECHehKc2n9DUUoXLCpTticQFYjQH0LlRwo0VuDszfl1\nqKZd8alXtYkqE73DuIElgvVJb4/DJQKHcM2y5Kbecua7AqFO8ZAdklL/k5V1IeBm\nGMOeTZVbAgMBAAECggEANI0UtDJunKoVeCfK9ofdTiT70dG6yfaKeaMm+pONvZ5t\nymtHXdLsl3x4QM6vgdFFeNcNwdZ3jHKgmHn3GU7vRso4TmMBciOp3bNNImJGnLMF\nXN5yHTw47XkHcR6v7m25tNFdv2wvqzBbROqQwMY20gFdJ6v3/z89h4A2W97nttyp\nixcNdSTHOfu6iUceEGi2PjHrvw4STPQeihXFNTnYG7hvlWzAerQ5STx5K2n4JoXz\nxI5MuHS6PGj5EBPUoq0+EQhmhORWBdNCMcijpHqobVDjifPRY2JbI3zZHtVjYpGH\notmc72hIDjNW7RX1ePKW/gsq6p2by3U8+4dOdya4AQKBgQDz4/6uo7atJSTgVo3d\nZr/7UJ4Qi2mlc992jLAqTQle6JchhNERoPvb19Qy8BaOz6LcxmuMXnRij05mxdyb\nLmoH8TPe6RFLCOJrRapkUjUtRD8dIg6UNFLk98LD5t3o5PoHwNpBFfokRlchwoHL\nuBvbEHQkrPX2xPbgla5e7zJLgQKBgQDqvjCUMvmap9+AlqxGFhv51V9dIlKvT0xW\np5KEMVfs3JXCHAM7o0ClZ8NitHXw18E8+iMG4pWw3+FX4K6tKGR+rCeGCUNGuiQT\nFzXjrEej+Pnuk8zacjXkbS+PNnEqhpSq6STZVFn2UW+ZWAoq2iAMR7qw0eAjylln\nh//Wad3+2wKBgAjwWEtKUM2zyNA4G+b7dxnc8I4mre6UeqI7sdE7FZbW64Mc/RSq\nU9DQ7kQXrJv7XDq/Qv3YEGf0XKlDozxEzToRSxdmb23Sm4nW+dHHeY95Kt8EeohQ\nCqG9uvO3KHb6vXc/SECOb6aYtWTVXjB7RPoYdklJ1ZH/0hSVJ9ju52cBAoGBAK63\nA90p25F6ZOWGP46iogve/e2JwFTvBnhwnKJ7P1/yBhzFULqwlUsG4euzOR0a2J6T\n5kIXnyZYW5ZWimwi5jlJ1Nj0R/h6TqNO4TMlZOTsSMmDhDMKUoZDpeRHtw7ZwAk9\nIcoH+DVXA2L0ngyq8LNzJ8a3TsYUs1pVZNunTC2FAoGARe4x29tdri8akxxwF3BV\nbjJ9qRUIfIDK8rGWRdw94vVCB7XVmSWCEchmLqA1DqGYvAhYMYjkXTg9akfBTUQS\ns+8JasUuQam8Y88JAfC0QqGbLgUsh0TpRUOXj+YQuoNiMVu14NNgYgFkx71WtvAq\nkUmkxr/moPcZ+O1ahVjv/Us=\n-----END PRIVATE KEY-----\n)%\";\n\nconstexpr unsigned char public_key_8192[] = R\"%(-----BEGIN PUBLIC KEY-----\nMIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEA43dhEnCSwC/hAAm9XrZc\nt0QaC4bkoSifeiL00+U8xBbAuAYnZSQ4PBbEERnxIRLpgCf0b2SDvCXPJmXB6lKz\n1W4vVcw2fVuG4Kmp5C9skhXeGXrXoEOgSxBp8VkWWWB1tbpKmKwdGnh6O0JOwWRq\nwWxefR3J9EWBNTz0vvbjGxYWt0XfcCjULPuXuPVlrbZkTsdCl8ncWG8G/OjRNHr3\nf9eiWHb2gA+xsUJfP/iWlUmy+9MiEGBT+JMW2wZAOu7JgVbyZWXV/pkwodP1IVFy\nc9RTexnC7Th3dDlT+HcAWXDCTuWwq2KhD/WUnfXO6uZEjyp3aJiJOa7Mceag0B9t\nT9d1AZkXQs3PZYn+Sl1cF3hq6e8OoKHZsA95PAtNrXfDe7vkyICB4sp1Dkqg75Ws\narOTC45CWcr/woReqCDYRiSr0aQodlJmSvSIlOz5IAyB40nFzA3VgEgTgHJ4mU7O\nQcsOSStmZNvk6Hl9xfUfJi9xTB/vwf7FKWe+IcDGdkU9WV3yJ6UTXPW4TQu25uTc\n6WoK4Us8Lk2h7f+Tk2dsyt+VTDOma5qbwTT8U/NKSd8Se5ewS4++ERqaRikLmp0o\nAciYxH00Wk3ZLPFUn9/svcA4BAwOCTkYjIQvW/gLDrYyu4qyrgkGXiNs0L2QYB7l\nAUTOl5M0Bmez5Nl8SIdaVk4bj5D+4BbHrDZGLMkkP1KWRgNFOJOfLT3JgMPxDwme\nn4qFs/HV/d4qh8kzyjITsBRQj1EloqqU+40WJ9X3mIEo7xQ1DPloQMWADDYrO/bX\nfFtYnTtnJLV6ndTSdQz0yZ7ubROJFatPy1VQ6AiBeN24sq9iKm6NXuWjszS0paZ/\nJfO+QOTB9D3lVnFzV2yHRIboHNpm/X1eVeXDlzzVTobqVr4eN78bL4+VQiGQav1I\n8ebv3Gx9+NO1qVfsWHC89I+hw9HSN69gEyCmeWwIuY8hMGfTBgERVKPkWhSPM0cU\nJlkM+ER1Pngz93TR7tWPsp9tYaKMG4DVth0fINRSVsFFkeHu1CLeKboUW8QMoH+A\nvPDVnSE2M3ecAeFz0yNXTwVtHbQT2YpYZ88gnYvYcRNdqeOvRKkrGUON0fDGvBnF\nxxcuNzZVP2wBEUTkYljnLrJ5zR+uabPgrQiIhTVdDplRRZd6DVRh9s357L5b94tX\nwtNAFfHT3AsU/C5p8O6taxckrxYMqNsOJ/6zYp7gUTTdb3e/V1c3xgi/x8+gUrUn\nivGZZdOaWUbSDZf1cz2kfQPsaiDDPVKL7goo0ZA5gnbjkhHUNpGmE5KauHek9rxO\n2KX3dpjl3YJyHSmOKv7Lf46Uja0cNWbTh/0nHlG5xtbzBNGvxF90iGmHDmr+u6BT\nzwIDAQAB\n-----END PUBLIC KEY-----\n)%\";\n\nconstexpr unsigned char private_key_8192[] = R\"%(-----BEGIN PRIVATE KEY-----\nMIISQgIBADANBgkqhkiG9w0BAQEFAASCEiwwghIoAgEAAoIEAQDjd2EScJLAL+EA\nCb1etly3RBoLhuShKJ96IvTT5TzEFsC4BidlJDg8FsQRGfEhEumAJ/RvZIO8Jc8m\nZcHqUrPVbi9VzDZ9W4bgqankL2ySFd4ZetegQ6BLEGnxWRZZYHW1ukqYrB0aeHo7\nQk7BZGrBbF59Hcn0RYE1PPS+9uMbFha3Rd9wKNQs+5e49WWttmROx0KXydxYbwb8\n6NE0evd/16JYdvaAD7GxQl8/+JaVSbL70yIQYFP4kxbbBkA67smBVvJlZdX+mTCh\n0/UhUXJz1FN7GcLtOHd0OVP4dwBZcMJO5bCrYqEP9ZSd9c7q5kSPKndomIk5rsxx\n5qDQH21P13UBmRdCzc9lif5KXVwXeGrp7w6godmwD3k8C02td8N7u+TIgIHiynUO\nSqDvlaxqs5MLjkJZyv/ChF6oINhGJKvRpCh2UmZK9IiU7PkgDIHjScXMDdWASBOA\ncniZTs5Byw5JK2Zk2+ToeX3F9R8mL3FMH+/B/sUpZ74hwMZ2RT1ZXfInpRNc9bhN\nC7bm5NzpagrhSzwuTaHt/5OTZ2zK35VMM6ZrmpvBNPxT80pJ3xJ7l7BLj74RGppG\nKQuanSgByJjEfTRaTdks8VSf3+y9wDgEDA4JORiMhC9b+AsOtjK7irKuCQZeI2zQ\nvZBgHuUBRM6XkzQGZ7Pk2XxIh1pWThuPkP7gFsesNkYsySQ/UpZGA0U4k58tPcmA\nw/EPCZ6fioWz8dX93iqHyTPKMhOwFFCPUSWiqpT7jRYn1feYgSjvFDUM+WhAxYAM\nNis79td8W1idO2cktXqd1NJ1DPTJnu5tE4kVq0/LVVDoCIF43biyr2Iqbo1e5aOz\nNLSlpn8l875A5MH0PeVWcXNXbIdEhugc2mb9fV5V5cOXPNVOhupWvh43vxsvj5VC\nIZBq/Ujx5u/cbH3407WpV+xYcLz0j6HD0dI3r2ATIKZ5bAi5jyEwZ9MGARFUo+Ra\nFI8zRxQmWQz4RHU+eDP3dNHu1Y+yn21hoowbgNW2HR8g1FJWwUWR4e7UIt4puhRb\nxAygf4C88NWdITYzd5wB4XPTI1dPBW0dtBPZilhnzyCdi9hxE12p469EqSsZQ43R\n8Ma8GcXHFy43NlU/bAERRORiWOcusnnNH65ps+CtCIiFNV0OmVFFl3oNVGH2zfns\nvlv3i1fC00AV8dPcCxT8Lmnw7q1rFySvFgyo2w4n/rNinuBRNN1vd79XVzfGCL/H\nz6BStSeK8Zll05pZRtINl/VzPaR9A+xqIMM9UovuCijRkDmCduOSEdQ2kaYTkpq4\nd6T2vE7Ypfd2mOXdgnIdKY4q/st/jpSNrRw1ZtOH/SceUbnG1vME0a/EX3SIaYcO\nav67oFPPAgMBAAECggQAfigr0opVGfp0FA1S1kDWU16WA2ahTzC0oozYtN0jQq5L\n3MSs/M+F0O3feIymy+0tTELcsxtQZP2jUmyFjGyqCOm/nxpP7l7hA6GV9FTJJoyy\nTfdvuBdJw9gqqgz69D8nic70qJBs482GHW+9Nk13WCe+kC4BYFVcQCa6p19OvisW\nFjfOoOpEI16224JfDmVmZLrnGECA0RtjCMonna/FrUXvaJkyRfxuVR22rkg1XD8v\n4bNL5UFH0UnjFz70SLs/T1jlv48njLlx248vGXeOvuc4FcJH9kGnHvLcu6VksDZ1\nzkReI+/j3HIcJy+5v1ZPGAg5ie1vzmpAQbvj3QpRGkMpReWenRKAwJQ0URJOjUXg\nJjbMKhMaJSev2bl7L4aJCQtA7GM5posbOP3zHG4q3lMSbwpLinmoOD4qMZ1l1iFo\nmjEtr9Iroc7WIaL82OWW9HRqG65gh3FyP389m+m1Q5BXMAW+GJpM7xLSywQUbp1J\nfSsJUtL2juxW62l7qQTl7bbJI2vOvXQa78BbhNvSGjMSLboIerXb5aAmPU7TbAFt\nUIIk/vEVCadVe0ooHah3G80Zng7vH5VdkyQYp3waQEL9V50JeDxNAzwl7zXGm8cM\nSlJVRpBAKU725U9A8rvij1lxmEyxF20WYP+CH42C/Z0n57Fg3VyOzZJB+Af59nr3\n43o0nwpFVB8BkqxHXmB9sYD+G+hTeGfzytmR6JGMJPT5RBcNfjYjlfe05pzg22Iq\nmOAy8b0ceHgAWUjfvU/xl9J7RqPCT8RM4ZbQloO5hmmPV6Zt6KMZKEzN/f3nRFro\nNUEr6NRqIFYL0DTzlK9dQqOR5Ep5VKo1MoqOJ+AlfyXpcUcTkbAGXJgE2pDYg7jp\nFpP33SgAUT/hhbDTgBY6Xd80gGn9xzPZDd3pzW4fSIkDxz4o/GX73lbRrjeCkQ6i\nTxv1/dI9GjLUk0+iD+ZRFA48PghBb8YZvuVaMnNbPh2wH0nsGN4P4rosrLogETuM\nz2SY22EknApNU3X1XjivqhJYgekpdZAnSJFgSB0eHnc4fU/e5esJvGnTKhrwkwst\nt26ZU4rWqNLp5wIvFiUuwwvcWhKDOgYvJpA5I/AoOt7qT6zfj1gha0Y4Gt50eWBE\nL5ramkxKMDnFTycxVu9B6R9r96EBT1yVny3bDJw8tFcgTmVQJSXO5B6L5vuLZwiC\nMLZi+CsV+d2w0DTKUh651++OBPY63ir7OfBwHdqNXYxEkC1v7b9QKvMxmSdt1jeG\n9C7vcT6YxeREbgLr7fZAXw/09rptLj6c8cMLWYmxVcv+Nq8kW7M9zDZ0i7+eGT81\n985boD7Sp5UWaCaGJhaVE/73XoZ9u59zWoF8x3EJIQKCAgEA9HVjuYVhsRyUGyr2\nGxvaJNN3kvY0ax5nReAkekGWypZlnuFbIj8mtDtu5gcXw0pI2gAPlKHdoX05zCRz\neIJh+Yq1oDAYqG4n7kph8Kn1kK1SYaJXGnFAZUQ203n/ltiYPYwI9wdXuYhO7wsS\nR81Hdl9CIjiA0vNz7TmNQlfHFEtIckP+8SloSiXOQSMo1BZs+aRXSJ5qNdpBWgx+\n5FlHkroxtbYuA1c10+RSgVxWIH6qA1WP8k+8JeQiXuJpu2Ct3Il4dZMs1VJeKzwZ\nQ5XoA5W6tpvhHx5RJ4dU7lmiPZQNaAHXrU8FXrB/cFUiFJH+2Xzrs5gBKudfjcSE\nwFI1yJBRgW4gadhhjGvGxlsDdkSh/B8WlBhhy2hofpWL+jH205bMlyYv2wRUEYK7\nAPsW4TEBURNV/Xo+h0upwdYBRrRHVjPU+ovYrPWJV9tYqvoyeru5K4v9Bwp99FsX\nRh3olGT3x/2kC4eccaSugBcyvkna+RgJlJDe/rqIIoSaI/oembATl3m56S2DlEoB\nhOdepj5zKDDEknnEEdO96C1Un5PZ7cYPcqwRct51diJN5+o0h2BO7EwHb77cwvPQ\noBDQE52abwMvu7pHOw3F1+W8B6y7JuLSvCa1LO12ol/unFfwHGer24iAXgt8aqZd\nBEDwEgihhJ5TmGTT+9dO3XZZGW0CggIBAO40nZ7gZFDqtiiEIrEqoI9Lu9hequ8z\nPYnHAwwSThY4+Pc2FyCtelgY1Lg1TM1eBrH0AhFXdSa6N0fAGePCFi2BlVq8X8VK\nnD2fNSdY+4BDyWVn/WsMh84inIPSFzfkq+Nj+b5bSlqWhp7lb60/uS3GOOb6fYkR\ndziuc0uFsZJbQDXg5BdUdUHaE3Ooby0MdCk9y0dE9dIR/tNCxhpO6Dd+nl2FjLYF\n6/BKAtdsBBCKnmWxeOYwCzExvMdRu7mJnmpVGLowjUh9NBR7Ezt3Jvti9OQ1lI3k\nHscK7hrHzM1u7tRlxl9lq/X6vQqOaZurtza1HyMdFDgGq3jBAMRjYstjwgxma6AT\n+cEJiWy+eVIWHmahgfgEpYXyf9z066n7MiXHDMgaLjdFROSbj84/DHtJkJaqBbIc\nYCdsnfXakGyD0PZdT7lUfy4bvDOGI0H7RvcKMfRkPnBokDsFfYFNmQoCj9O0mf2T\nsPKpOzM4gGz03zpNvE8b6fBEUNUz4JBMEOc5GLAS8WCrH1iVAu2Mw0jAi4VmCvhR\nfsnr/HaLkRPBKNcsz1asZZbHqb9u9fEL6ZYk9txEDHgiduHyxPdytPAz6F2E3Eu0\n98rxjCe/k4qluV9kGOlDsYKa+f50r7W6E51QfHQLAYpCqtbp2WTj4P8q3nlQ06Bm\nM+9E0uMzbrirAoICAF1O3WS3w6Utyl5gVJXeWLKLwO1oanOkpDioqGO920eyhlFR\npU56GlTbBqZoeKqDFTGYqlnKOuVj/gastyJ9adYtGsxs70yC11z+KUoKJYA2l+ZK\nZ8LhDXpZwi+QNn2maN29MMLRm6tmmvJlIHIlqaxGCeEz/gAHCu22dPOou4VEgv+S\ncqIscvEyYvq7596kPK5BC0vdo56wkxdDA8A3T7lytnysb/24cQRS9ycHTpySnGQv\naYVM5/zyiif7de4epd4y3rbKGWfHS8hm5SHF+0w6/4yqDRCqqsFSx5k+v02P0Fot\nsdwl+F+/MLV42UxOuZ7cLr9bOr7cl71uEFm0R3EpnOKxXU/pVrqZfMLDhJvE8Kti\nVmTqtZFFZfVDMa2rGpKC0c6ztbp8eXZBlw11ybLk2KLQpZbd7TYJLF+fRtdtAnml\nyRpk/KxwAB93yu1gGJp+QtybT1Y7q/30MvsBeYAC1g0RBGeeOJmsCSs9L5IwcJN5\nmFaLwYIrQsEiKg+nbbyt15yOyuZ1B+83HENVaOw9lAj4LF/YeH1xe+A+RTmv3pQC\ncG0Nvo9A2EbiKyhlXe16VkWdc400peEH3U7re/CwzHypE7QtEvk4dZbFyrKHPNxH\n4bYNdEQU056AzXwBmNXOwGtIO+8ppTC0FXcFLl1DzBrpr/DQM5XCBglEHhg1AoIC\nAFWj4Q9fyXE2EWubpgVgN/2M0upFjtsU5wkD3dqXMi/XJ9tpPQNom1XVB5V6xDQJ\nnAqamau2b84OoRVQwX4bJ3IQ5quKkjwSSP32oVuWKEXDGUM2EexMwv6ffvn9rI9R\nzWKhbQa9N4w+FgRGpNH62Q7V91tDr6J5/w0H2zfJxz/BQuKcCiVBHi8gwmGQqvfd\nRF4Xc2AaMO7nvWAi36pRuDdLdJBXFXHTyzHGyiK9GPEBhVU2aysHFt8G7MIUZpOc\nILJGCe/WyNTI/tJmNVHp0sAKodTyVoh0/YO+MEC8mKs7OO5v8NQXb62uCg0jimCH\nagVnNNyg9cX2z+tIKIhy2vAY24ktwX/57o8yaJAKIwAaJ6/qXRnYQdJYjxPXkmq4\nfx0J5VSD5R3F77DpJNiX3lrs5ejlE8snXIKQEHJ1s/rvoU8R2TneYSMooY88qKxu\nNONYbQFakQBE96XgoXC9f0oUBbWtdreuQ63anggaRkHl/+OsUwl2FbNmPFGKpy/5\nyRH4eyHCjbmdjFWCrVzOgN9FKmQ5fbQtSJI8H7ZXEz+w8If7+kdFD/kXq7XBpPaW\nu9JZU895P6ppaahuadY1DUxWvTHyNGmblIMIOMWJoPf2ASGEkVg8GDPGmB6dwRZq\n4eZrK3NlCZa1xUojJR+atifHN9kR8CP42q8pZVB+C06lAoICAQDkowYg/d2KXdgs\nmYJTOoE4XA/2lGrF9k4dKcqgljThVAP8NiUW4u+874Y8Xq0hPD/KaatfomcaQZUX\nu62kz7Jd3OkRxYieG95c0vRlad9xxyrlre7slCsG9jNungMF3P/TyC767kOBgkEJ\ndWtQB1veFGE0fcU34Y7OrPijfmECBuxmtGwO2l3LAW86PBFWVCUCnYhQVwjBYzGE\nIpZazNG+xoeoLWrSg1ehOTTZZqgQrVVrIMHLKV1bM9NFv2qBx8wSPfQKgtpA1LE3\n0Ssbepqv/N5WRXzSJ/maWG4BF0qpXaYti0TGDv8iqN1FXcYIBL4BXCgLzJlMmg2I\nK+V38fXkhHULlGcvu/9rA3m1OWhs1pPrUTb7v5afHdyd9zSteof5QIsk6CaaiWxg\nTW0M6vXmSoiUWIbKl71TCCsSVSJ82ZA9Wn0xtITqaFz9oqiaQbV+Cj9VzX332zGM\nY2dEck/00yPVI30T+ycwX3xN3jnpusWv/omDKQ/UMrBXPzzJpIzAaRnfm13sZcvh\nFsKX4nSNK6rJ1uONSJu+dIiOA1YCabhCab7NRMCn+Bj+fHHkpvir24QbmqX1R8Au\n415sPjVLQr2FNiHaXDzwiCS0jdNhTLGV8xaykv8bKAzH19lNfqZcZStwSP2DoQ8O\n2vrUYCC8gWblftYH+yTWu2bQ4Y1pDw==\n-----END PRIVATE KEY-----\n)%\";\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_mnp.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n\n#include \"handshake_common.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::capabilities;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake_mnp)\n\nBOOST_AUTO_TEST_CASE(ok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(2, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(err)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(err_builder()\n                         .seqnum(2)\n                         .code(common_server_errc::er_access_denied_error)\n                         .message(\"Denied\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_access_denied_error, create_server_diag(\"Denied\"));\n}\n\n// The flows with auth switch work\nBOOST_AUTO_TEST_CASE(authswitch_ok)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"mysql_native_password\", mnp_scramble))\n        .expect_write(create_frame(3, mnp_hash))\n        .expect_read(create_ok_frame(4, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_capabilities(min_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// mysql_native_password doesn't have interactions with TLS\nBOOST_AUTO_TEST_CASE(mnp_tls)\n{\n    // Setup\n    handshake_fixture fix;\n    fix.st.tls_supported = true;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().caps(tls_caps).auth_data(mnp_scramble).build())\n        .expect_write(create_ssl_request())\n        .expect_ssl_handshake()\n        .expect_write(login_request_builder().seqnum(2).caps(tls_caps).auth_response(mnp_hash).build())\n        .expect_read(create_ok_frame(3, ok_builder().build()))\n        .will_set_status(connection_status::ready)\n        .will_set_tls_active(true)\n        .will_set_capabilities(tls_caps)\n        .will_set_current_charset(utf8mb4_charset)\n        .will_set_connection_id(42)\n        .check(fix);\n}\n\n// mysql_native_password does not support more_data packets\nBOOST_AUTO_TEST_CASE(moredata)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(server_hello_builder().auth_data(mnp_scramble).build())\n        .expect_write(login_request_builder().auth_response(mnp_hash).build())\n        .expect_read(create_more_data_frame(2, mnp_scramble))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\nBOOST_AUTO_TEST_CASE(authswitch_moredata)\n{\n    // Setup\n    handshake_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(\n            server_hello_builder().auth_plugin(\"caching_sha2_password\").auth_data(csha2p_scramble).build()\n        )\n        .expect_write(\n            login_request_builder().auth_plugin(\"caching_sha2_password\").auth_response(csha2p_hash).build()\n        )\n        .expect_read(create_auth_switch_frame(2, \"mysql_native_password\", mnp_scramble))\n        .expect_write(create_frame(3, mnp_hash))\n        .expect_read(create_more_data_frame(4, mnp_scramble))\n        .check(fix, client_errc::bad_handshake_packet_type);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/handshake/handshake_mnp_hash_password.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n\n#include <boost/mysql/impl/internal/sansio/mysql_native_password.hpp>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing detail::mnp_hash_password;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_handshake_mnp_hash_password)\n\n// Values snooped using Wireshark\nconstexpr std::uint8_t scramble[20] = {\n    0x79, 0x64, 0x3d, 0x12, 0x1d, 0x71, 0x74, 0x47, 0x5f, 0x48,\n    0x3e, 0x3e, 0x0b, 0x62, 0x0a, 0x03, 0x3d, 0x27, 0x3a, 0x4c,\n};\n\nBOOST_AUTO_TEST_CASE(nonempty_password)\n{\n    constexpr std::uint8_t expected_hash[20] = {\n        0xf1, 0xb2, 0xfb, 0x1c, 0x8d, 0xe7, 0x5d, 0xb8, 0xeb, 0xa8,\n        0x12, 0x6a, 0xd1, 0x0f, 0xe9, 0xb1, 0x10, 0x50, 0xd4, 0x28,\n    };\n\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(mnp_hash_password(\"root\", scramble), expected_hash);\n}\n\nBOOST_AUTO_TEST_CASE(empty_password)\n{\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(mnp_hash_password(\"\", scramble), std::vector<std::uint8_t>());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/message_reader.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/sansio/message_reader.hpp>\n#include <boost/mysql/impl/internal/sansio/read_buffer.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_frame.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::mysql::client_errc;\nusing boost::mysql::error_code;\n\nusing u8vec = std::vector<std::uint8_t>;\n\nBOOST_AUTO_TEST_SUITE(test_message_reader)\n\nclass reader_fixture\n{\npublic:\n    message_reader reader;\n    std::uint8_t seqnum{42};\n\n    reader_fixture(\n        std::vector<std::uint8_t> contents,\n        std::size_t buffsize = 512,\n        std::size_t max_size = static_cast<std::size_t>(-1),\n        std::size_t max_frame_size = 64 // max frame size is 64\n    )\n        : reader(buffsize, max_size, max_frame_size),\n          contents_(std::move(contents)),\n          buffer_first_(reader.internal_buffer().first())\n    {\n    }\n\n    void set_contents(u8vec value)\n    {\n        contents_ = std::move(value);\n        bytes_written_ = 0u;\n    }\n\n    // Reads bytes until reader.done() or all bytes in contents have been read.\n    // Resizes the buffer as required\n    void read_until_completion()\n    {\n        while (!reader.done() && remaining_bytes())\n        {\n            auto ec = reader.prepare_buffer();\n            BOOST_TEST(ec == error_code());\n            std::size_t bytes_to_copy = (std::min)(reader.buffer().size(), contents_.size() - bytes_written_);\n            read_bytes(bytes_to_copy);\n        }\n        BOOST_TEST(reader.done());\n        BOOST_TEST(remaining_bytes() == 0u);\n    }\n\n    // Simulates a read of num_bytes against the read buffer, then processes the result.\n    // Doesn't resize the buffer\n    void read_bytes(std::size_t num_bytes)\n    {\n        // Simulate a write against the buffer\n        if (num_bytes)\n        {\n            assert(num_bytes <= reader.buffer().size());\n            std::memcpy(reader.buffer().data(), contents_.data() + bytes_written_, num_bytes);\n            bytes_written_ += num_bytes;\n        }\n\n        // Trigger the op\n        reader.resume(num_bytes);\n    }\n\n    span<const std::uint8_t> check_message(const std::vector<std::uint8_t>& expected)\n    {\n        BOOST_TEST_REQUIRE(reader.done());\n        BOOST_TEST_REQUIRE(reader.error() == error_code());\n        auto msg = reader.message();\n        BOOST_MYSQL_ASSERT_BUFFER_EQUALS(msg, expected);\n        return msg;\n    }\n\n    void record_buffer_first() noexcept { buffer_first_ = reader.internal_buffer().first(); }\n    void check_buffer_stability() { BOOST_TEST(reader.internal_buffer().first() == buffer_first_); }\n    std::size_t buffsize() const noexcept { return reader.internal_buffer().size(); }\n\nprivate:\n    std::vector<std::uint8_t> contents_;\n    std::size_t bytes_written_{0};\n    const std::uint8_t* buffer_first_;\n\n    std::size_t remaining_bytes() const noexcept { return contents_.size() - bytes_written_; }\n};\n\n// Parsing algorithm. Without buffer relocations or short reads\nBOOST_AUTO_TEST_CASE(parsing_algorithm_success)\n{\n    struct\n    {\n        const char* name;\n        u8vec input;\n        u8vec expected_msg;\n        std::uint8_t expected_seqnum;\n    } test_cases[] = {\n        {\"empty_message\", create_empty_frame(42), {}, 43},\n        {\"one_frame\", create_frame(42, {0x01, 0x02, 0x03}), {0x01, 0x02, 0x03}, 43},\n        {\"one_frame_max_size\",\n         buffer_builder().add(create_frame(42, u8vec(64, 0x04))).add(create_empty_frame(43)).build(),\n         u8vec(64, 0x04),\n         44},\n        {\"two_frames\",\n         buffer_builder().add(create_frame(42, u8vec(64, 0x04))).add(create_frame(43, {0x05, 0x06})).build(),\n         concat(u8vec(64, 0x04), {0x05, 0x06}),\n         44},\n        {\"two_frames_max_size\",\n         buffer_builder()\n             .add(create_frame(42, u8vec(64, 0x04)))\n             .add(create_frame(43, u8vec(64, 0x05)))\n             .add(create_empty_frame(44))\n             .build(),\n         concat(u8vec(64, 0x04), u8vec(64, 0x05)),\n         45},\n        {\"three_frames\",\n         buffer_builder()\n             .add(create_frame(42, u8vec(64, 0x04)))\n             .add(create_frame(43, u8vec(64, 0x05)))\n             .add(create_frame(44, {0x0a}))\n             .build(),\n         buffer_builder().add(u8vec(64, 0x04)).add(u8vec(64, 0x05)).add({0x0a}).build(),\n         45},\n    };\n\n    for (auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            reader_fixture fix(tc.input);\n            fix.reader.prepare_read(fix.seqnum);\n            BOOST_TEST(!fix.reader.done());\n\n            // Receive the message\n            fix.read_bytes(tc.input.size());\n\n            // Check\n            fix.check_message(tc.expected_msg);\n            BOOST_TEST(fix.seqnum == tc.expected_seqnum);\n\n            // Buffer didn't reallocate\n            fix.check_buffer_stability();\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(seqnum_overflow)\n{\n    // message to be parsed\n    reader_fixture fix(\n        buffer_builder()\n            .add(create_frame(255, std::vector<std::uint8_t>(64, 0x04)))\n            .add(create_frame(0, {0x05, 0x06, 0x07}))\n            .build(),\n        64 + 16\n    );\n    fix.seqnum = 255;\n\n    // Setup\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n\n    // all in one\n    fix.read_bytes(64 + 4 * 2 + 3);\n    fix.check_message(concat(std::vector<std::uint8_t>(64, 0x04), {0x05, 0x06, 0x07}));\n    BOOST_TEST(fix.seqnum == 1u);\n\n    // Buffer didn't reallocate\n    fix.check_buffer_stability();\n}\n\nBOOST_AUTO_TEST_CASE(seqnum_mismatch)\n{\n    struct\n    {\n        const char* name;\n        u8vec input;\n    } test_cases[] = {\n        {\"1st_frame\", create_frame(1, {0x01, 0x02})},\n        {\"2nd_frame\", concat(create_frame(42, u8vec(64, 0x04)), create_frame(44, {0x01}))},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            reader_fixture fix(tc.input);\n            fix.reader.prepare_read(fix.seqnum);\n            fix.read_bytes(tc.input.size());\n            BOOST_TEST(fix.reader.done());\n            BOOST_TEST(fix.reader.error() == error_code(client_errc::sequence_number_mismatch));\n        }\n    }\n}\n\n// Long read: we received two messages at once.\n// We don't consume the next message while parsing the first one\n// We don't get rid of the first message while there's space for the second one\nBOOST_AUTO_TEST_CASE(long_read)\n{\n    // message to be parsed\n    std::vector<std::uint8_t> first_msg_body{0x01, 0x02, 0x03};\n    std::vector<std::uint8_t> second_msg_body{0x04, 0x05, 0x06, 0x07};\n    reader_fixture fix(concat(create_frame(42, first_msg_body), create_frame(2, second_msg_body)));\n\n    // Prepare first read\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n\n    // The read yields two messages at once\n    fix.read_bytes(15);\n    fix.check_message(first_msg_body);\n    BOOST_TEST(fix.seqnum == 43u);\n\n    // We can read the 2nd message, too\n    std::uint8_t seqnum2 = 2u;\n    fix.reader.prepare_read(seqnum2);\n    fix.check_message(second_msg_body);\n    BOOST_TEST(fix.seqnum == 43u);  // old seqnum not updated\n    BOOST_TEST(seqnum2 == 3u);      // new seqnum updated\n\n    // Buffer shouldn't reallocate\n    fix.check_buffer_stability();\n}\n\n// Short reads\nBOOST_AUTO_TEST_CASE(short_reads_multiple)\n{\n    // message to be parsed\n    reader_fixture fix(create_frame(42, {0x01, 0x02, 0x03}));\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n\n    // 1 byte in the header received\n    fix.read_bytes(1);\n    BOOST_TEST(!fix.reader.done());\n\n    // Another 2 bytes received\n    fix.read_bytes(2);\n    BOOST_TEST(!fix.reader.done());\n\n    // Header fully received\n    fix.read_bytes(1);\n    BOOST_TEST(!fix.reader.done());\n\n    // 1 byte in body received\n    fix.read_bytes(1);\n    BOOST_TEST(!fix.reader.done());\n\n    // body fully received\n    fix.read_bytes(2);\n    fix.check_message({0x01, 0x02, 0x03});\n    BOOST_TEST(fix.seqnum == 43u);\n\n    // Buffer shouldn't reallocate\n    fix.check_buffer_stability();\n}\n\nBOOST_AUTO_TEST_CASE(short_reads_header_size)\n{\n    // message to be parsed\n    reader_fixture fix(create_frame(42, {0x01, 0x02, 0x03}));\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n\n    // Full header received\n    fix.read_bytes(4);\n    BOOST_TEST(!fix.reader.done());\n\n    // Full body received\n    fix.read_bytes(3);\n    fix.check_message({0x01, 0x02, 0x03});\n    BOOST_TEST(fix.seqnum == 43u);\n\n    // Buffer didn't reallocate\n    fix.check_buffer_stability();\n}\n\nBOOST_AUTO_TEST_CASE(short_reads_two_frames)\n{\n    // message to be parsed\n    reader_fixture fix(\n        buffer_builder()\n            .add(create_frame(42, std::vector<std::uint8_t>(64, 0x04)))\n            .add(create_frame(43, {0x05, 0x06, 0x07}))\n            .build(),\n        64 + 16\n    );\n    auto expected_message = concat(std::vector<std::uint8_t>(64, 0x04), {0x05, 0x06, 0x07});\n\n    // Setup\n    fix.reader.prepare_read(fix.seqnum);\n\n    // part of header 1\n    fix.read_bytes(3);\n    BOOST_TEST(!fix.reader.done());\n\n    // header 1 full\n    fix.read_bytes(1);\n    BOOST_TEST(!fix.reader.done());\n\n    // part of body 1\n    fix.read_bytes(64 - 8);\n    BOOST_TEST(!fix.reader.done());\n\n    // rest of body 1\n    fix.read_bytes(8);\n    BOOST_TEST(!fix.reader.done());\n\n    // part of header 2\n    fix.read_bytes(1);\n    BOOST_TEST(!fix.reader.done());\n\n    // another part of header 2\n    fix.read_bytes(2);\n    BOOST_TEST(!fix.reader.done());\n\n    // rest of header 2 and part of body 1\n    fix.read_bytes(2);\n    BOOST_TEST(!fix.reader.done());\n\n    // another part of body 2\n    fix.read_bytes(1);\n    BOOST_TEST(!fix.reader.done());\n\n    // remaining of body 2\n    fix.read_bytes(1);\n    fix.check_message(expected_message);\n    BOOST_TEST(fix.seqnum == 44u);\n\n    // Buffer shouldn't reallocate\n    fix.check_buffer_stability();\n}\n\n// Buffer resizing\nBOOST_AUTO_TEST_CASE(buffer_resizing_not_enough_space)\n{\n    // Setup\n    reader_fixture fix(create_frame(42, u8vec(50, 0x04)), 0);\n    BOOST_TEST(fix.buffsize() == 0u);\n\n    // Prepare read. The buffer hasn't resized.\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n    BOOST_TEST(fix.buffsize() == 0u);\n\n    // Resize the buffer\n    auto ec = fix.reader.prepare_buffer();\n    BOOST_TEST(ec == error_code());\n    fix.record_buffer_first();\n    BOOST_TEST(fix.buffsize() == 4u);\n\n    // Read the header. The buffer didn't reallocate\n    fix.read_bytes(4);\n    BOOST_TEST(!fix.reader.done());\n    fix.check_buffer_stability();\n\n    // Resize the buffer again\n    ec = fix.reader.prepare_buffer();\n    BOOST_TEST(ec == error_code());\n    fix.record_buffer_first();\n    BOOST_TEST(fix.buffsize() == 64u);\n\n    // Finish reading\n    fix.read_bytes(50);\n    fix.check_message(u8vec(50, 0x04));\n    BOOST_TEST(fix.seqnum == 43u);\n}\n\nBOOST_AUTO_TEST_CASE(buffer_resizing_old_messages_removed)\n{\n    // prepare_buffer removes old messages\n    // so the buffer doesn't grow indefinitely\n\n    // Setup\n    reader_fixture fix(create_frame(42, u8vec(60, 0x04)), 0);\n\n    // Parse an entire message, to make space in the buffer\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_until_completion();\n    fix.check_message(u8vec(60, 0x04));\n\n    // Record size, as this should not increase\n    BOOST_TEST(fix.buffsize() == 64u);\n\n    // Parse new messages\n    for (std::uint8_t i = 0u; i < 100u; ++i)\n    {\n        // Setup\n        u8vec msg_body(50, i);\n        fix.seqnum = i;\n        fix.set_contents(create_frame(i, msg_body));\n\n        // Prepare read\n        fix.reader.prepare_read(fix.seqnum);\n\n        // Read the message into the buffer and trigger the op until completion.\n        // This will call prepare_buffer() internally\n        fix.read_until_completion();\n\n        // Check results\n        BOOST_TEST_REQUIRE(fix.reader.error() == error_code());\n        BOOST_MYSQL_ASSERT_BUFFER_EQUALS(fix.reader.message(), msg_body);\n    }\n\n    // Buffer size should be the same\n    BOOST_TEST(fix.buffsize() == 64u);\n}\n\nBOOST_AUTO_TEST_CASE(buffer_resizing_size_eq_max_size)\n{\n    // Reading a frame of exactly max_size works\n    // Setup\n    reader_fixture fix(create_frame(42, u8vec(32, 0x04)), 0, 32);\n    BOOST_TEST(fix.buffsize() == 0u);\n\n    // Prepare read. The buffer hasn't resized.\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n    BOOST_TEST(fix.buffsize() == 0u);\n\n    // Execute the read successfully\n    fix.read_until_completion();\n    fix.check_message(u8vec(32, 0x04));\n    BOOST_TEST(fix.seqnum == 43u);\n}\n\nBOOST_AUTO_TEST_CASE(buffer_resizing_max_size_exceeded)\n{\n    // Setup\n    reader_fixture fix(create_frame(42, u8vec(50, 0x04)), 16, 32);\n    BOOST_TEST(fix.buffsize() == 16u);\n    fix.record_buffer_first();\n\n    // Prepare read. The buffer hasn't resized.\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n    BOOST_TEST(fix.buffsize() == 16u);\n    fix.check_buffer_stability();\n\n    // We have enough size for the header\n    auto ec = fix.reader.prepare_buffer();\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(fix.buffsize() == 16u);\n    fix.record_buffer_first();\n\n    // Read the header. The buffer didn't reallocate\n    fix.read_bytes(4);\n    BOOST_TEST(!fix.reader.done());\n    fix.check_buffer_stability();\n\n    // Resizing the buffer here would require exceeding max size and fails\n    ec = fix.reader.prepare_buffer();\n    BOOST_TEST(ec == client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_CASE(buffer_resizing_max_size_exceeded_subsequent_frames)\n{\n    // Setup\n    reader_fixture fix(create_frame(42, u8vec(90, 0x04)), 80, 80);\n    BOOST_TEST(fix.buffsize() == 80u);\n    fix.record_buffer_first();\n\n    // Prepare read\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n\n    // Read header, body 1, header 2, part of body 2\n    auto ec = fix.reader.prepare_buffer();\n    BOOST_TEST(ec == error_code());\n    fix.read_bytes(80);\n    BOOST_TEST(!fix.reader.done());\n\n    // Resizing the buffer here would require exceeding max size and fails\n    ec = fix.reader.prepare_buffer();\n    BOOST_TEST(ec == client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_CASE(buffer_resizing_size_power_of_two)\n{\n    // Setup\n    reader_fixture fix(create_frame(42, u8vec(4, 0x04)), 0, 1024, 1024);\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_until_completion();\n    BOOST_TEST(fix.buffsize() == 4u);\n    \n    std::size_t test_sizes[] = {\n        5, 7, 8,\n        9, 15, 16,\n        17, 31, 32,\n        33, 63, 64,\n        65, 127, 128,\n        129, 255, 256,\n        257, 511, 512, 513\n    };\n\n    // Test that buffer capacity grows to powers of two for various payload sizes\n    for (auto new_size : test_sizes)\n    {\n        BOOST_TEST_CONTEXT(new_size)\n        {\n            // Setup\n            u8vec msg_body(new_size, 0x04);\n            fix.seqnum = static_cast<std::uint8_t>(new_size);\n            fix.set_contents(create_frame(fix.seqnum, msg_body));\n            std::size_t next_power_of_two = 1;\n            while (next_power_of_two < new_size)\n                next_power_of_two *= 2;\n\n            // Prepare read\n            fix.reader.prepare_read(fix.seqnum);\n\n            // Read the message into the buffer and trigger the op until completion.\n            // This will call prepare_buffer() internally\n            fix.read_until_completion();\n\n            // Check results\n            BOOST_TEST_REQUIRE(fix.reader.error() == error_code());\n            BOOST_MYSQL_ASSERT_BUFFER_EQUALS(fix.reader.message(), msg_body);\n            BOOST_TEST(fix.buffsize() == next_power_of_two);\n        }\n    }\n}\n\n// Keep parsing state\nBOOST_AUTO_TEST_CASE(keep_state_continuation)\n{\n    // Setup. We use a multiframe message to verify that we update the sequence number reference correctly\n    u8vec msg1_body{0x01, 0x02, 0x03};\n    u8vec msg2_body(65, 0x04);\n    reader_fixture fix(\n        buffer_builder()\n            .add(create_frame(42, msg1_body))\n            .add(create_frame(43, u8vec(64, 0x04)))\n            .add(create_frame(44, {0x04}))\n            .build(),\n        16\n    );\n\n    // Read the first message and part of the second\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_bytes(16);\n    auto msg = fix.check_message({0x01, 0x02, 0x03});\n    BOOST_TEST(fix.seqnum == 43u);\n\n    // Prepare the second read. We don't have enough bytes or buffer space\n    fix.reader.prepare_read(fix.seqnum);\n    BOOST_TEST(!fix.reader.done());\n    fix.check_buffer_stability();                      // Didn't reallocate\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(msg, msg1_body);  // Old message still valid\n    BOOST_TEST(fix.seqnum == 44u);                     // Updated to the last received seqnum\n\n    // Prepare a read as a continuation. This will not throw away the parsing state\n    std::uint8_t new_seqnum{fix.seqnum};\n    fix.reader.prepare_read(new_seqnum, true);\n    fix.read_until_completion();\n    fix.check_message(msg2_body);\n    BOOST_TEST(fix.seqnum == 44u);  // Old seqnum not updated\n    BOOST_TEST(new_seqnum == 45u);  // New seqnum updated\n}\n\nBOOST_AUTO_TEST_CASE(keep_state_done)\n{\n    // Passing keep_state=true won't have effect if the operation is already done\n    reader_fixture fix(\n        buffer_builder().add(create_frame(42, {0x01, 0x02, 0x03})).add(create_frame(43, {0x04, 0x05})).build()\n    );\n\n    // Read the first message\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_bytes(7);\n    fix.check_message({0x01, 0x02, 0x03});\n    BOOST_TEST(fix.seqnum == 43u);\n\n    // Prepare a read as a continuation. As the operation is done, this will reset parsing state\n    fix.reader.prepare_read(fix.seqnum, true);\n    BOOST_TEST(!fix.reader.done());\n    fix.read_bytes(6);\n    fix.check_message({0x04, 0x05});\n    BOOST_TEST(fix.seqnum == 44u);\n}\n\nBOOST_AUTO_TEST_CASE(keep_state_initial)\n{\n    // Passing keep_state=true with a reader that hasn't been used works\n    reader_fixture fix(create_frame(42, {0x01, 0x02, 0x03}));\n    fix.reader.prepare_read(fix.seqnum, true);\n    fix.read_bytes(7);\n    fix.check_message({0x01, 0x02, 0x03});\n    BOOST_TEST(fix.seqnum == 43u);\n}\n\n// Resetting\nBOOST_AUTO_TEST_CASE(reset_done)\n{\n    // Read a message until completion\n    reader_fixture fix(create_frame(42, {0x01, 0x02, 0x03}));\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_until_completion();\n\n    // Reset\n    fix.reader.reset();\n\n    // A new message can be read now\n    fix.set_contents(create_frame(20, {0x09, 0x0a}));\n    fix.seqnum = 20;\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_until_completion();\n    fix.check_message({0x09, 0x0a});\n    fix.check_buffer_stability();  // No reallocation happened\n    BOOST_TEST(fix.seqnum == 21u);\n}\n\nBOOST_AUTO_TEST_CASE(reset_message_half_read)\n{\n    // Read part of a message\n    reader_fixture fix(create_frame(42, {0x01, 0x02, 0x03}));\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_bytes(3);\n\n    // Reset\n    fix.reader.reset();\n\n    // A new message can be read now\n    fix.set_contents(create_frame(20, {0x09, 0x0a}));\n    fix.seqnum = 20;\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_until_completion();\n    fix.check_message({0x09, 0x0a});\n    fix.check_buffer_stability();  // No reallocation happened\n    BOOST_TEST(fix.seqnum == 21u);\n}\n\nBOOST_AUTO_TEST_CASE(reset_keep_state_true)\n{\n    // Read part of a message\n    reader_fixture fix(create_frame(42, {0x01, 0x02, 0x03}));\n    fix.reader.prepare_read(fix.seqnum, true);\n    fix.read_bytes(3);\n\n    // Reset\n    fix.reader.reset();\n\n    // A new message can be read now\n    fix.set_contents(create_frame(20, {0x09, 0x0a}));\n    fix.seqnum = 20;\n    fix.reader.prepare_read(fix.seqnum);\n    fix.read_until_completion();\n    fix.check_message({0x09, 0x0a});\n    fix.check_buffer_stability();  // No reallocation happened\n    BOOST_TEST(fix.seqnum == 21u);\n}\n\nBOOST_AUTO_TEST_CASE(memmove_avoided)\n{\n    // Test that std::memmove() is avoided for large messages (>1024 bytes)\n    // when the buffer has sufficient free space.\n\n    // Setup\n    reader_fixture fix(create_frame(0, u8vec(0, 0)), 4096, 4096, 4096);\n\n    // Buffer is free\n    std::size_t free_bytes = fix.reader.buffer().size();\n    BOOST_TEST(free_bytes == 4096u);\n\n    // Small messages (<=1024 bytes): memmove is expected\n    {\n        constexpr std::size_t small_msg_size = 200;\n        // First frame and second frame header expected to\n        // be memmoved, when second payload will be parsed\n        std::size_t expected = 4096 - small_msg_size;\n        auto first_frame = create_frame(42, u8vec(small_msg_size, 0x0a));\n        auto second_frame = create_frame(43, u8vec(small_msg_size, 0x0a));\n        fix.seqnum = 42;\n        fix.set_contents(concat(first_frame, second_frame));\n        fix.reader.prepare_read(fix.seqnum);\n        auto ec = fix.reader.prepare_buffer();\n        BOOST_TEST(ec == error_code());\n        fix.read_bytes(2 * (frame_header_size + small_msg_size));\n        fix.reader.prepare_read(fix.seqnum);\n        ec = fix.reader.prepare_buffer();\n        BOOST_TEST(ec == error_code());\n        free_bytes = fix.reader.buffer().size();\n        BOOST_TEST(free_bytes == expected);\n    }\n\n    // Large messages (>1024 bytes): memmove is avoided if free space is big enough\n    {\n        constexpr std::size_t large_msg_size = 1025;\n        // First frame expected not to be memmoved,\n        // when we parse second message\n        constexpr std::size_t expected = 4096 - 2 * (frame_header_size + large_msg_size);\n        auto first_frame = create_frame(42, u8vec(large_msg_size, 0x0a));\n        auto second_frame = create_frame(43, u8vec(large_msg_size, 0x0a));\n        fix.seqnum = 42;\n        fix.set_contents(concat(first_frame, second_frame));\n        fix.reader.prepare_read(fix.seqnum);\n        auto ec = fix.reader.prepare_buffer();\n        BOOST_TEST(ec == error_code());\n        fix.read_bytes(2 * (frame_header_size + large_msg_size));\n        fix.reader.prepare_read(fix.seqnum);\n        ec = fix.reader.prepare_buffer();\n        BOOST_TEST(ec == error_code());\n        free_bytes = fix.reader.buffer().size();\n        BOOST_TEST(free_bytes == expected);\n    }\n\n    // Buffer cannot fit second message: memmove is expected\n    {\n        constexpr std::size_t very_large_msg_size = 2048;\n        // First frame and second frame header expected to\n        // be memmoved, when second payload will be parsed\n        constexpr std::size_t expected = 4096 - very_large_msg_size;\n        auto first_frame = create_frame(42, u8vec(very_large_msg_size, 0x0a));\n        auto second_frame = create_frame(43, u8vec(very_large_msg_size, 0x0a));\n        fix.seqnum = 42;\n        fix.set_contents(concat(first_frame, second_frame));\n        fix.reader.prepare_read(fix.seqnum);\n        auto ec = fix.reader.prepare_buffer();\n        BOOST_TEST(ec == error_code());\n        fix.read_bytes(4092);\n        fix.reader.prepare_read(fix.seqnum);\n        ec = fix.reader.prepare_buffer();\n        // Read what is left\n        fix.read_bytes(12);\n        BOOST_TEST(ec == error_code());\n        free_bytes = fix.reader.buffer().size();\n        BOOST_TEST(free_bytes == expected);\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/ping.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/ping.hpp>\n#include <boost/mysql/impl/internal/sansio/run_pipeline.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_ping)\n\n//\n// read_ping_response_algo\n//\nstruct read_response_fixture : algo_fixture_base\n{\n    detail::read_ping_response_algo algo{57};\n};\n\nBOOST_AUTO_TEST_CASE(read_response_success)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(create_ok_frame(57, ok_builder().build()))  // OK response\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_success_no_backslash_escapes)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(create_ok_frame(57, ok_builder().no_backslash_escapes(true).build()))  // OK response\n        .will_set_backslash_escapes(false)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_network)\n{\n    algo_test()\n        .expect_read(create_ok_frame(57, ok_builder().build()))\n        .check_network_errors<read_response_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_packet)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(err_builder()\n                         .seqnum(57)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())  // Error response\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\n//\n// setup_ping_pipeline: running a pipeline with these parameters\n// has the intended effect\n//\n\nstruct ping_fixture : algo_fixture_base\n{\n    detail::run_pipeline_algo algo{detail::setup_ping_pipeline(st)};\n};\n\nBOOST_AUTO_TEST_CASE(ping_success)\n{\n    // Setup\n    ping_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_write({0x01, 0x00, 0x00, 0x00, 0x0e})           // ping request\n        .expect_read(create_ok_frame(1, ok_builder().build()))  // OK response\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(ping_error_network)\n{\n    // Check for net errors for each read/write\n    algo_test()\n        .expect_write({0x01, 0x00, 0x00, 0x00, 0x0e})\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .check_network_errors<ping_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(ping_error_response)\n{\n    // Setup\n    ping_fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_write({0x01, 0x00, 0x00, 0x00, 0x0e})  // Ping request\n        .expect_read(err_builder()\n                         .seqnum(1)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())  // Error response\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(ping_error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            ping_fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/prepare_statement.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>\n#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>\n#include <boost/mysql/impl/internal/sansio/prepare_statement.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_prepare_statement_response.hpp\"\n#include \"test_unit/create_query_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_prepare_statement)\n\n//\n// read_prepare_statement_response_algo\n//\nstruct read_response_fixture : algo_fixture_base\n{\n    detail::read_prepare_statement_response_algo algo{19};\n\n    statement result() const { return algo.result(st); }\n};\n\nBOOST_AUTO_TEST_CASE(read_response_success)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(prepare_stmt_response_builder().seqnum(19).id(1).num_columns(1).num_params(2).build())\n        .expect_read(create_coldef_frame(20, meta_builder().name(\"abc\").build_coldef()))\n        .expect_read(create_coldef_frame(21, meta_builder().name(\"other\").build_coldef()))\n        .expect_read(create_coldef_frame(22, meta_builder().name(\"final\").build_coldef()))\n        .check(fix);\n\n    // The statement was created successfully\n    auto stmt = fix.result();\n    BOOST_TEST(stmt.id() == 1u);\n    BOOST_TEST(stmt.num_params() == 2u);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_success_0cols)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(prepare_stmt_response_builder().seqnum(19).id(5).num_columns(0).num_params(1).build())\n        .expect_read(create_coldef_frame(20, meta_builder().name(\"abc\").build_coldef()))\n        .check(fix);\n\n    // The statement was created successfully\n    auto stmt = fix.result();\n    BOOST_TEST(stmt.id() == 5u);\n    BOOST_TEST(stmt.num_params() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_success_0params)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(prepare_stmt_response_builder().seqnum(19).id(214).num_columns(2).num_params(0).build())\n        .expect_read(create_coldef_frame(20, meta_builder().name(\"abc\").build_coldef()))\n        .expect_read(create_coldef_frame(21, meta_builder().name(\"defff\").build_coldef()))\n        .check(fix);\n\n    // The statement was created successfully\n    auto stmt = fix.result();\n    BOOST_TEST(stmt.id() == 214u);\n    BOOST_TEST(stmt.num_params() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_success_0cols_0params)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(prepare_stmt_response_builder().seqnum(19).id(98).num_columns(0).num_params(0).build())\n        .check(fix);\n\n    // The statement was created successfully\n    auto stmt = fix.result();\n    BOOST_TEST(stmt.id() == 98u);\n    BOOST_TEST(stmt.num_params() == 0u);\n}\n\n// A statement_id == 0 doesn't cause trouble\nBOOST_AUTO_TEST_CASE(read_response_success_0id)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(prepare_stmt_response_builder().seqnum(19).id(0).num_columns(0).num_params(1).build())\n        .expect_read(create_coldef_frame(20, meta_builder().name(\"abc\").build_coldef()))\n        .check(fix);\n\n    // The statement was created successfully\n    auto stmt = fix.result();\n    BOOST_TEST(stmt.id() == 0u);\n    BOOST_TEST(stmt.num_params() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_network)\n{\n    algo_test()\n        .expect_read(prepare_stmt_response_builder().seqnum(19).id(1).num_columns(1).num_params(2).build())\n        .expect_read(create_coldef_frame(20, meta_builder().name(\"abc\").build_coldef()))\n        .expect_read(create_coldef_frame(21, meta_builder().name(\"other\").build_coldef()))\n        .expect_read(create_coldef_frame(22, meta_builder().name(\"final\").build_coldef()))\n        .check_network_errors<read_response_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_packet)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(err_builder()\n                         .seqnum(19)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\n//\n// prepare_statement_algo\n//\nstruct prepare_fixture : algo_fixture_base\n{\n    detail::prepare_statement_algo algo{{\"SELECT 1\"}};\n\n    prepare_fixture() = default;\n    prepare_fixture(std::size_t max_bufsize) : algo_fixture_base(max_bufsize) {}\n\n    statement result() const { return algo.result(st); }\n};\n\nBOOST_AUTO_TEST_CASE(prepare_success)\n{\n    // Setup\n    prepare_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_prepare_statement_frame(0, \"SELECT 1\"))\n        .expect_read(prepare_stmt_response_builder().seqnum(1).id(29).num_columns(0).num_params(2).build())\n        .expect_read(create_coldef_frame(2, meta_builder().name(\"abc\").build_coldef()))\n        .expect_read(create_coldef_frame(3, meta_builder().name(\"other\").build_coldef()))\n        .check(fix);\n\n    // The statement was created successfully\n    auto stmt = fix.result();\n    BOOST_TEST(stmt.id() == 29u);\n    BOOST_TEST(stmt.num_params() == 2u);\n}\n\n// Spotcheck: an error while reading the response is propagated correctly\nBOOST_AUTO_TEST_CASE(prepare_error_packet)\n{\n    // Setup\n    prepare_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_prepare_statement_frame(0, \"SELECT 1\"))\n        .expect_read(err_builder()\n                         .seqnum(1)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\nBOOST_AUTO_TEST_CASE(prepare_network_error)\n{\n    // This covers errors in the request and the response\n    algo_test()\n        .expect_write(create_prepare_statement_frame(0, \"SELECT 1\"))\n        .expect_read(prepare_stmt_response_builder().seqnum(1).id(29).num_columns(0).num_params(1).build())\n        .expect_read(create_coldef_frame(2, meta_builder().name(\"abc\").build_coldef()))\n        .check_network_errors<prepare_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(prepare_error_max_buffer_size)\n{\n    // Setup\n    prepare_fixture fix(10u);\n\n    // Run the algo\n    algo_test().check(fix, client_errc::max_buffer_size_exceeded);\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(prepare_error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            prepare_fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/quit_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/quit_connection.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <vector>\n\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nnamespace asio = boost::asio;\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing detail::connection_status;\n\nnamespace {\n\nBOOST_AUTO_TEST_SUITE(test_quit_connection)\n\nstruct fixture : algo_fixture_base\n{\n    detail::quit_connection_algo algo{{}};\n};\n\n// A serialized quit request\nstd::vector<std::uint8_t> expected_request() { return create_frame(0, {0x01}); }\n\nBOOST_AUTO_TEST_CASE(plaintext_success)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test().expect_write(expected_request()).will_set_status(connection_status::not_connected).check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(plaintext_error_network)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo. State change happens even if the quit request fails\n    algo_test()\n        .expect_write(expected_request(), asio::error::network_reset)\n        .will_set_status(connection_status::not_connected)\n        .check(fix, asio::error::network_reset);\n}\n\nBOOST_AUTO_TEST_CASE(ssl_success)\n{\n    // Setup\n    fixture fix;\n    fix.st.tls_active = true;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())\n        .expect_ssl_shutdown()\n        .will_set_status(connection_status::not_connected)\n        .will_set_tls_active(false)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(ssl_error_quit)\n{\n    // Setup\n    fixture fix;\n    fix.st.tls_active = true;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request(), asio::error::network_reset)\n        .will_set_status(connection_status::not_connected)\n        .will_set_tls_active(false)\n        .check(fix, asio::error::network_reset);\n}\n\nBOOST_AUTO_TEST_CASE(ssl_error_shutdown)\n{\n    // Setup\n    fixture fix;\n    fix.st.tls_active = true;\n\n    // Run the algo\n    algo_test()\n        .expect_write(expected_request())\n        .expect_ssl_shutdown(asio::error::network_reset)\n        .will_set_status(connection_status::not_connected)\n        .will_set_tls_active(false)\n        .check(fix);  // SSL shutdown errors ignored\n}\n\n// quit runs regardless of the session status we have\nBOOST_AUTO_TEST_CASE(status_ignored)\n{\n    constexpr connection_status test_status[] = {\n        connection_status::not_connected,\n        connection_status::engaged_in_multi_function\n    };\n\n    for (const auto status : test_status)\n    {\n        BOOST_TEST_CONTEXT(status)\n        {\n            // Setup\n            fixture fix;\n            fix.st.status = connection_status::not_connected;\n\n            // Run the algo\n            algo_test().expect_write(expected_request()).check(fix);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n}  // namespace\n"
  },
  {
    "path": "test/unit/test/sansio/read_buffer.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/sansio/read_buffer.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <algorithm>\n#include <cstddef>\n#include <cstdint>\n#include <cstring>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql::detail;\nusing boost::mysql::client_errc;\nusing boost::mysql::error_code;\n\nBOOST_AUTO_TEST_SUITE(test_read_buffer)\n\n// Records the buffer first pointer and size to verify the buffer\n// didn't do any re-allocation\nclass stability_checker\n{\n    read_buffer& b_;\n    const std::uint8_t* first_;\n    std::size_t total_size_;\n\npublic:\n    stability_checker(read_buffer& b) noexcept : b_(b), first_(b.first()), total_size_(b.size()) {}\n    void check_stability()\n    {\n        BOOST_TEST(b_.first() == first_);\n        BOOST_TEST(b_.size() == total_size_);\n    }\n    void check_reallocation()\n    {\n        BOOST_TEST(b_.first() != first_);\n        BOOST_TEST(b_.size() > total_size_);\n    }\n};\n\nstatic void check_buffer(\n    read_buffer& buff,\n    const std::uint8_t* reserved_first,\n    const std::uint8_t* current_message_first,\n    const std::uint8_t* pending_first,\n    const std::uint8_t* free_first,\n    std::size_t reserved_size,\n    std::size_t current_message_size,\n    std::size_t pending_size,\n    std::size_t free_size\n)\n{\n    BOOST_TEST(buff.reserved_first() == reserved_first);\n    BOOST_TEST(buff.current_message_first() == current_message_first);\n    BOOST_TEST(buff.pending_first() == pending_first);\n    BOOST_TEST(buff.free_first() == free_first);\n\n    BOOST_TEST(buff.reserved_area().data() == reserved_first);\n    BOOST_TEST(buff.current_message().data() == current_message_first);\n    BOOST_TEST(buff.pending_area().data() == pending_first);\n    BOOST_TEST(buff.free_area().data() == free_first);\n\n    BOOST_TEST(buff.reserved_size() == reserved_size);\n    BOOST_TEST(buff.current_message_size() == current_message_size);\n    BOOST_TEST(buff.pending_size() == pending_size);\n    BOOST_TEST(buff.free_size() == free_size);\n\n    BOOST_TEST(buff.reserved_area().size() == reserved_size);\n    BOOST_TEST(buff.current_message().size() == current_message_size);\n    BOOST_TEST(buff.pending_area().size() == pending_size);\n    BOOST_TEST(buff.free_area().size() == free_size);\n\n    BOOST_TEST(buff.size() == reserved_size + current_message_size + pending_size + free_size);\n}\n\nstatic void check_buffer(\n    read_buffer& buff,\n    const std::vector<std::uint8_t>& reserved,\n    const std::vector<std::uint8_t>& current_message,\n    const std::vector<std::uint8_t>& pending,\n    std::size_t free_size\n)\n{\n    std::size_t current_message_offset = reserved.size();\n    std::size_t pending_offset = current_message_offset + current_message.size();\n    std::size_t free_offset = pending_offset + pending.size();\n\n    BOOST_TEST(buff.first() != nullptr);\n\n    check_buffer(\n        buff,\n        buff.first(),\n        buff.first() + current_message_offset,\n        buff.first() + pending_offset,\n        buff.first() + free_offset,\n        reserved.size(),\n        current_message.size(),\n        pending.size(),\n        free_size\n    );\n\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff.reserved_area(), reserved);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff.current_message(), current_message);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(buff.pending_area(), pending);\n}\n\nstatic void check_empty_buffer(read_buffer& buff)\n{\n    check_buffer(buff, nullptr, nullptr, nullptr, nullptr, 0, 0, 0, 0);\n}\n\nstatic void copy_to_free_area(read_buffer& buff, const std::vector<std::uint8_t>& bytes)\n{\n    std::copy(bytes.begin(), bytes.end(), buff.free_first());\n}\n\nBOOST_AUTO_TEST_SUITE(init_ctor)\n\nBOOST_AUTO_TEST_CASE(some_initial_size)\n{\n    read_buffer buff(531);\n    check_buffer(buff, {}, {}, {}, 531);\n}\n\nBOOST_AUTO_TEST_CASE(zero_initial_size)\n{\n    read_buffer buff(0);\n\n    check_empty_buffer(buff);\n\n    // Calling all other functions with 0 values on this buffer doesn't cause UB\n    buff.move_to_pending(0);\n    buff.move_to_current_message(0);\n    buff.move_to_reserved(0);\n    buff.remove_reserved();\n    auto ec = buff.grow_to_fit(0);\n    BOOST_TEST(ec == error_code());\n    check_empty_buffer(buff);\n}\n\nBOOST_AUTO_TEST_CASE(initial_size_eq_max_size)\n{\n    read_buffer buff(16, 16);\n    check_buffer(buff, {}, {}, {}, 16);\n    BOOST_TEST(buff.max_size() == 16u);\n\n    // Using the buffer works normally\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04});\n    buff.move_to_pending(4);\n    buff.move_to_current_message(3);\n    buff.move_to_reserved(1);\n    check_buffer(buff, {0x01}, {0x02, 0x03}, {0x04}, 12);\n\n    // Growing works\n    auto ec = buff.grow_to_fit(12);\n    BOOST_TEST(ec == error_code());\n    ec = buff.grow_to_fit(13);\n    BOOST_TEST(ec == client_errc::max_buffer_size_exceeded);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_to_pending)\n\nBOOST_AUTO_TEST_CASE(some_bytes)\n{\n    read_buffer buff(512);\n    stability_checker checker(buff);\n    std::vector<std::uint8_t> contents{0x01, 0x02, 0x03, 0x04};\n    copy_to_free_area(buff, contents);\n    buff.move_to_pending(4);\n\n    check_buffer(buff, {}, {}, contents, 508);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(all_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    std::vector<std::uint8_t> contents(8, 0x01);\n    copy_to_free_area(buff, contents);\n    buff.move_to_pending(buff.size());\n\n    check_buffer(buff, {}, {}, contents, 0);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(zero_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    buff.move_to_pending(0);\n\n    check_buffer(buff, {}, {}, {}, 8);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(several_calls)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    std::vector<std::uint8_t> contents{0x01, 0x02, 0x03, 0x04};\n    copy_to_free_area(buff, contents);\n    buff.move_to_pending(2);\n    buff.move_to_pending(2);\n\n    check_buffer(buff, {}, {}, contents, 4);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_to_current_message)\n\nBOOST_AUTO_TEST_CASE(some_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(2);\n\n    check_buffer(buff, {}, {0x01, 0x02}, {0x03, 0x04, 0x05, 0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(all_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(6);\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(zero_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(0);\n\n    check_buffer(buff, {}, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(several_calls)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(2);\n    buff.move_to_current_message(3);\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05}, {0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(move_to_reserved)\n\nBOOST_AUTO_TEST_CASE(some_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(5);\n    buff.move_to_reserved(3);\n\n    check_buffer(buff, {0x01, 0x02, 0x03}, {0x04, 0x05}, {0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(all_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(5);\n    buff.move_to_reserved(5);\n\n    check_buffer(buff, {0x01, 0x02, 0x03, 0x04, 0x05}, {}, {0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(zero_bytes)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(5);\n    buff.move_to_reserved(0);\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05}, {0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(several_calls)\n{\n    read_buffer buff(8);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06});\n    buff.move_to_pending(6);\n    buff.move_to_current_message(5);\n    buff.move_to_reserved(1);\n    buff.move_to_reserved(2);\n\n    check_buffer(buff, {0x01, 0x02, 0x03}, {0x04, 0x05}, {0x06}, 2);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(remove_current_message_last)\n\nBOOST_AUTO_TEST_CASE(some_bytes)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    buff.move_to_reserved(1);\n    buff.remove_current_message_last(2);\n\n    check_buffer(buff, {0x01}, {0x02, 0x03, 0x04}, {0x07, 0x08}, 10);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(all_bytes)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    buff.move_to_reserved(1);\n    buff.remove_current_message_last(5);\n\n    check_buffer(buff, {0x01}, {}, {0x07, 0x08}, 13);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(without_pending)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(8);\n    buff.move_to_reserved(1);\n    buff.remove_current_message_last(4);\n\n    check_buffer(buff, {0x01}, {0x02, 0x03, 0x04}, {}, 12);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(without_reserved)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    buff.remove_current_message_last(4);\n\n    check_buffer(buff, {}, {0x01, 0x02}, {0x07, 0x08}, 12);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(remove_reserved)\n\nBOOST_AUTO_TEST_CASE(with_other_areas)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    buff.move_to_reserved(2);\n    buff.remove_reserved();\n\n    check_buffer(buff, {}, {0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 10);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(without_other_areas)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(8);\n    buff.move_to_reserved(8);\n    buff.remove_reserved();\n\n    check_buffer(buff, {}, {}, {}, 16);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(zero_bytes)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    buff.remove_reserved();\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 8);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(grow_to_fit)\n\nBOOST_AUTO_TEST_CASE(not_enough_space)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    auto ec = buff.grow_to_fit(100);\n\n    BOOST_TEST(ec == error_code());\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 120);\n    checker.check_reallocation();\n}\n\nBOOST_AUTO_TEST_CASE(one_missing_byte)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n\n    auto ec = buff.grow_to_fit(9);\n\n    BOOST_TEST(ec == error_code());\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 24);\n    checker.check_reallocation();\n}\n\nBOOST_AUTO_TEST_CASE(enough_space)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    auto ec = buff.grow_to_fit(8);\n    BOOST_TEST(ec == error_code());\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 8);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(zero_bytes)\n{\n    read_buffer buff(16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n    auto ec = buff.grow_to_fit(0);\n    BOOST_TEST(ec == error_code());\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 8);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(from_size_0)\n{\n    // Regression check: growing from size 0 works\n    read_buffer buff(0, 1024);\n    check_empty_buffer(buff);\n\n    auto ec = buff.grow_to_fit(16);\n    BOOST_TEST(ec == error_code());\n    check_buffer(buff, {}, {}, {}, 16);\n}\n\nBOOST_AUTO_TEST_CASE(lt_max_size)\n{\n    read_buffer buff(8, 16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n\n    // Grow past the current size, but not reaching max size\n    auto ec = buff.grow_to_fit(7);\n    BOOST_TEST(ec == error_code());\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 8);\n    checker.check_reallocation();\n}\n\nBOOST_AUTO_TEST_CASE(eq_max_size)\n{\n    read_buffer buff(8, 16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n\n    // Grow past the current size, reaching max_size\n    auto ec = buff.grow_to_fit(8);\n    BOOST_TEST(ec == error_code());\n\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 8);\n    checker.check_reallocation();\n}\n\nBOOST_AUTO_TEST_CASE(gt_max_size)\n{\n    read_buffer buff(8, 16);\n    stability_checker checker(buff);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n\n    // Try to grow past max size\n    auto ec = buff.grow_to_fit(10);\n    BOOST_TEST(ec == client_errc::max_buffer_size_exceeded);\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 0);\n    checker.check_stability();\n}\n\nBOOST_AUTO_TEST_CASE(several_grows)\n{\n    read_buffer buff(8, 16);\n    copy_to_free_area(buff, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});\n    buff.move_to_pending(8);\n    buff.move_to_current_message(6);\n\n    // Grow with reallocation\n    auto ec = buff.grow_to_fit(4);\n    BOOST_TEST(ec == error_code());\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08}, 8);\n\n    // Place some more bytes in the buffer\n    copy_to_free_area(buff, {0x09, 0x0a});\n    buff.move_to_pending(2);\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08, 0x09, 0x0a}, 6);\n\n    // Grow without reallocation\n    ec = buff.grow_to_fit(2);\n    BOOST_TEST(ec == error_code());\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08, 0x09, 0x0a}, 6);\n    copy_to_free_area(buff, {0x0b, 0x0c});\n    buff.move_to_pending(2);\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}, 4);\n\n    // Fail when attempting to grow past max size\n    ec = buff.grow_to_fit(5);\n    BOOST_TEST(ec == client_errc::max_buffer_size_exceeded);\n    check_buffer(buff, {}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, {0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}, 4);\n}\n\nBOOST_AUTO_TEST_CASE(is_power_of_two)\n{\n    read_buffer buff(8);\n\n    std::size_t test_sizes[] = {\n        5, 7, 8,\n        9, 15, 16,\n        17, 31, 32,\n        33, 63, 64,\n        65, 127, 128,\n        129, 255, 256,\n        257, 511, 512, 513\n    };\n\n    // Test that buffer capacity grows to powers of two\n    for (auto new_size : test_sizes)\n    {\n        BOOST_TEST_CONTEXT(new_size)\n        {\n            std::size_t next_power_of_two = 1;\n            while (next_power_of_two < new_size)\n                next_power_of_two *= 2;\n            auto ec = buff.grow_to_fit(new_size);\n            BOOST_TEST(ec == error_code());\n            BOOST_TEST(buff.size() == next_power_of_two);\n        }\n    }\n    BOOST_TEST(buff.size() == 1024u);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(reset)\n\nBOOST_AUTO_TEST_CASE(zero_size_buffer)\n{\n    read_buffer buff(0, 1024);\n    buff.reset();\n    BOOST_TEST(buff.size() == 0u);\n    BOOST_TEST(buff.max_size() == 1024u);\n}\n\nBOOST_AUTO_TEST_CASE(free_buffer)\n{\n    read_buffer buff(16, 1024);\n    stability_checker checker(buff);\n    buff.reset();\n    check_buffer(buff, {}, {}, {}, 16);\n    checker.check_stability();\n    BOOST_TEST(buff.max_size() == 1024u);\n}\n\nBOOST_AUTO_TEST_CASE(pending_bytes)\n{\n    read_buffer buff(16, 512);\n    stability_checker checker(buff);\n    buff.move_to_pending(4);\n    buff.reset();\n    check_buffer(buff, {}, {}, {}, 16);\n    checker.check_stability();\n    BOOST_TEST(buff.max_size() == 512u);\n}\n\nBOOST_AUTO_TEST_CASE(current_message_bytes)\n{\n    read_buffer buff(16, 512);\n    stability_checker checker(buff);\n    buff.move_to_pending(4);\n    buff.move_to_current_message(4);\n    buff.reset();\n    check_buffer(buff, {}, {}, {}, 16);\n    checker.check_stability();\n    BOOST_TEST(buff.max_size() == 512u);\n}\n\nBOOST_AUTO_TEST_CASE(reserved_bytes)\n{\n    read_buffer buff(16, 512u);\n    stability_checker checker(buff);\n    buff.move_to_pending(4);\n    buff.move_to_current_message(4);\n    buff.move_to_reserved(4);\n    buff.reset();\n    check_buffer(buff, {}, {}, {}, 16);\n    checker.check_stability();\n    BOOST_TEST(buff.max_size() == 512u);\n}\n\nBOOST_AUTO_TEST_CASE(bytes_in_all_areas)\n{\n    read_buffer buff(16, 1024);\n    stability_checker checker(buff);\n    buff.move_to_pending(10);\n    buff.move_to_current_message(8);\n    buff.move_to_reserved(2);\n    buff.reset();\n    check_buffer(buff, {}, {}, {}, 16);\n    checker.check_stability();\n    BOOST_TEST(buff.max_size() == 1024u);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/read_resultset_head.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/read_resultset_head.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/mock_execution_processor.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nusing detail::connection_status;\n\nBOOST_AUTO_TEST_SUITE(test_read_resultset_head)\n\nstruct fixture : algo_fixture_base\n{\n    mock_execution_processor proc;\n    detail::read_resultset_head_algo algo;\n\n    fixture(\n        bool is_top_level = true,\n        connection_status initial_status = connection_status::engaged_in_multi_function\n    )\n        : algo({&proc}, is_top_level)\n    {\n        st.status = initial_status;\n\n        // The initial request writing should have advanced this to 1 (or bigger)\n        proc.sequence_number() = 1;\n    }\n};\n\n// Test cases to verify is_top_level = true and false.\n// With is_top_level = false, status checks and transitions are not performed.\n// Using connection_status::not_connected in this case helps verify that no transition is performed.\nconstexpr struct\n{\n    const char* name;\n    bool is_top_level;\n    connection_status initial_status;\n} top_level_test_cases[] = {\n    {\"top_level\",   true,  connection_status::engaged_in_multi_function},\n    {\"subordinate\", false, connection_status::not_connected            },\n};\n\nBOOST_AUTO_TEST_CASE(success_meta)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. The multi-function operation is still in-progress\n            algo_test()\n                .expect_read(create_frame(1, {0x01}))  // 1 metadata follows\n                .expect_read(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n                .check(fix);\n\n            // Verify\n            fix.proc.num_calls().on_num_meta(1).on_meta(1).validate();\n            BOOST_TEST(fix.proc.is_reading_rows());\n            BOOST_TEST(fix.proc.sequence_number() == 3u);\n            BOOST_TEST(fix.proc.num_meta() == 1u);\n            check_meta(fix.proc.meta(), {std::make_pair(column_type::varchar, \"mycol\")});\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(success_ok_packet)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo\n            algo_test()\n                .expect_read(create_ok_frame(1, ok_builder().affected_rows(42).info(\"abc\").build()))\n                .will_set_status(\n                    // Multi-function operation finished. Status changes only if we're the top level algo\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix);\n\n            // Verify\n            fix.proc.num_calls().on_head_ok_packet(1).validate();\n            BOOST_TEST(fix.proc.meta().size() == 0u);\n            BOOST_TEST(fix.proc.is_complete());\n            BOOST_TEST(fix.proc.affected_rows() == 42u);\n            BOOST_TEST(fix.proc.info() == \"abc\");\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(success_ok_packet_no_backslash_escapes)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_ok_frame(1, ok_builder().no_backslash_escapes(true).build()))\n        .will_set_status(connection_status::ready)  // Multi-function operation finished\n        .will_set_backslash_escapes(false)\n        .check(fix);\n\n    // Verify\n    fix.proc.num_calls().on_head_ok_packet(1).validate();\n}\n\n// Check that we don't attempt to read the rows even if they're available\nBOOST_AUTO_TEST_CASE(success_rows_available)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo. The multi-function operation is still in-progress\n    algo_test()\n        .expect_read(create_frame(1, {0x01}))  // 1 metadata follows\n        .expect_read(buffer_builder()\n                         .add(create_coldef_frame(\n                             2,\n                             meta_builder().type(column_type::varchar).name(\"f1\").build_coldef()\n                         ))\n                         .add(create_text_row_message(3, \"abc\"))\n                         .build())\n        .check(fix);\n\n    // We've read the response but not the rows\n    fix.proc.num_calls().on_num_meta(1).on_meta(1).validate();\n    BOOST_TEST(fix.proc.is_reading_rows());\n    BOOST_TEST(fix.proc.sequence_number() == 3u);\n}\n\n// Check that we don't attempt to read the next resultset even if it's available\nBOOST_AUTO_TEST_CASE(success_ok_packet_next_resultset)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. The multi-function operation is still in progress\n            algo_test()\n                .expect_read(buffer_builder()\n                                 .add(create_ok_frame(1, ok_builder().info(\"1st\").more_results(true).build()))\n                                 .add(create_ok_frame(2, ok_builder().info(\"2nd\").build()))\n                                 .build())\n                .check(fix);\n\n            // Verify\n            fix.proc.num_calls().on_head_ok_packet(1).validate();\n            BOOST_TEST(fix.proc.is_reading_first_subseq());\n            BOOST_TEST(fix.proc.info() == \"1st\");\n        }\n    }\n}\n\n// If the execution state is not reading head, we do nothing.\n// This check has precedence over the connection status checks\nBOOST_AUTO_TEST_CASE(state_complete)\n{\n    constexpr connection_status all_status[] = {\n        connection_status::engaged_in_multi_function,\n        connection_status::not_connected,\n        connection_status::ready\n    };\n\n    for (const auto status : all_status)\n    {\n        BOOST_TEST_CONTEXT(status)\n        {\n            // Setup\n            fixture fix;\n            add_ok(fix.proc, ok_builder().affected_rows(42).build());\n\n            // Should be a no-op\n            algo_test().check(fix);\n\n            // Nothing changed\n            fix.proc.num_calls().on_head_ok_packet(1).validate();\n            BOOST_TEST(fix.proc.is_complete());\n            BOOST_TEST(fix.proc.affected_rows() == 42u);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(state_reading_rows)\n{\n    constexpr connection_status all_status[] = {\n        connection_status::engaged_in_multi_function,\n        connection_status::not_connected,\n        connection_status::ready\n    };\n\n    for (const auto status : all_status)\n    {\n        BOOST_TEST_CONTEXT(status)\n        {\n            // Setup\n            fixture fix;\n            add_meta(fix.proc, {meta_builder().type(column_type::bit).build_coldef()});\n\n            // Should be a no-op\n            algo_test().check(fix);\n\n            // Nothing changed\n            fix.proc.num_calls().on_num_meta(1).on_meta(1).validate();\n            BOOST_TEST(fix.proc.is_reading_rows());\n            check_meta(fix.proc.meta(), {column_type::bit});\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_network_error_top_level)\n{\n    // This covers testing for network errors for all the reads we perform\n    algo_test()\n        .expect_read(create_frame(1, {0x02}))\n        .expect_read(\n            create_coldef_frame(2, meta_builder().type(column_type::varchar).name(\"f1\").build_coldef())\n        )\n        .expect_read(\n            create_coldef_frame(3, meta_builder().type(column_type::tinyint).name(\"f2\").build_coldef())\n        )\n        .will_set_status(connection_status::ready)  // errors end multi-function operations\n        .check_network_errors<fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(error_network_error_subordinate)\n{\n    struct subordinate_fixture : fixture\n    {\n        subordinate_fixture() : fixture(false, connection_status::not_connected) {}\n    };\n\n    // This covers testing for network errors for all the reads we perform\n    algo_test()\n        .expect_read(create_frame(1, {0x02}))\n        .expect_read(\n            create_coldef_frame(2, meta_builder().type(column_type::varchar).name(\"f1\").build_coldef())\n        )\n        .expect_read(\n            create_coldef_frame(3, meta_builder().type(column_type::tinyint).name(\"f2\").build_coldef())\n        )\n        .check_network_errors<subordinate_fixture>();\n}\n\n// All cases where the deserialization of the execution_response\n// yields an error are handled uniformly, so it's enough with this test\nBOOST_AUTO_TEST_CASE(error_deserialize_execution_response)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo\n            algo_test()\n                .expect_read(err_builder()\n                                 .seqnum(1)\n                                 .code(common_server_errc::er_bad_db_error)\n                                 .message(\"no_db\")\n                                 .build_frame())\n                .will_set_status(\n                    // errors end multi-function operations. Transition performed only if is_top_level=true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"no_db\"));\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_deserialize_metadata)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo\n            algo_test()\n                .expect_read(create_frame(1, {0x01}))\n                .expect_read(create_frame(2, {0x08, 0x03}))  // bad coldef\n                .will_set_status(\n                    // errors end multi-function operations. Transition performed only if is_top_level=true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, client_errc::incomplete_message);\n        }\n    }\n}\n\n// The execution processor signals an error on head packet (e.g. meta mismatch)\nBOOST_AUTO_TEST_CASE(error_on_head_ok_packet)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n            fix.proc.set_fail_count(\n                fail_count(0, client_errc::metadata_check_failed),\n                create_client_diag(\"some message\")\n            );\n\n            // Run the algo\n            algo_test()\n                .expect_read(create_ok_frame(1, ok_builder().affected_rows(42).info(\"abc\").build()))\n                .will_set_status(\n                    // errors end multi-function operations. Transition performed only if is_top_level=true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, client_errc::metadata_check_failed, create_client_diag(\"some message\"));\n\n            // Verify\n            fix.proc.num_calls().on_head_ok_packet(1).validate();\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_on_meta)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n            fix.proc.set_fail_count(\n                fail_count(0, client_errc::metadata_check_failed),\n                create_client_diag(\"some message\")\n            );\n\n            // Run the algo\n            algo_test()\n                .expect_read(create_frame(1, {0x01}))\n                .expect_read(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n                .will_set_status(\n                    // errors end multi-function operations. Transition performed only if is_top_level=true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, client_errc::metadata_check_failed, create_client_diag(\"some message\"));\n\n            // Verify\n            fix.proc.num_calls().on_num_meta(1).on_meta(1).validate();\n        }\n    }\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(error_invalid_connection_status)\n{\n    struct\n    {\n        connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {connection_status::not_connected, client_errc::not_connected                },\n        {connection_status::ready,         client_errc::not_engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(reset)\n{\n    // Setup\n    fixture fix(false);\n\n    // Run the algo once\n    algo_test()\n        .expect_read(create_frame(1, {0x01}))  // 1 metadata follows\n        .expect_read(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n        .check(fix);\n    fix.proc.num_calls().on_num_meta(1).on_meta(1).validate();\n\n    // Reset. Place the processor into a state where we can read head again\n    fix.algo.reset();\n    add_ok(fix.proc, ok_builder().more_results(true).build());\n\n    // Run it again\n    algo_test().expect_read(create_ok_frame(3, ok_builder().more_results(true).build())).check(fix);\n    fix.proc.num_calls().on_num_meta(1).on_meta(1).on_row_ok_packet(1).on_head_ok_packet(1).validate();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/read_some_rows.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/read_some_rows.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <cstddef>\n\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/mock_execution_processor.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing boost::span;\nusing detail::connection_status;\nusing detail::output_ref;\n\nBOOST_AUTO_TEST_SUITE(test_read_some_rows)\n\nstruct fixture : algo_fixture_base\n{\n    using row1 = std::tuple<int>;\n\n    mock_execution_processor proc;\n    std::array<row1, 3> storage;\n    detail::read_some_rows_algo algo;\n\n    output_ref ref() noexcept { return output_ref(span<row1>(storage), 0); }\n\n    fixture(\n        bool is_top_level = true,\n        connection_status initial_status = connection_status::engaged_in_multi_function\n    )\n        : algo({&proc, ref()}, is_top_level)\n    {\n        st.status = initial_status;\n\n        // Prepare the processor, such that it's ready to read rows\n        add_meta(\n            proc,\n            {meta_builder().type(column_type::varchar).name(\"fvarchar\").nullable(false).build_coldef()}\n        );\n        proc.sequence_number() = 42;\n    }\n\n    void validate_refs(std::size_t num_rows)\n    {\n        BOOST_TEST_REQUIRE(proc.refs().size() == num_rows);\n        for (std::size_t i = 0; i < num_rows; ++i)\n            BOOST_TEST(proc.refs()[i].offset() == i);\n    }\n\n    std::size_t result() const { return algo.result(st); }\n};\n\n// Test cases to verify is_top_level = true and false.\n// With is_top_level = false, status checks and transitions are not performed.\n// Using connection_status::not_connected in this case helps verify that no transition is performed.\nconstexpr struct\n{\n    const char* name;\n    bool is_top_level;\n    connection_status initial_status;\n} top_level_test_cases[] = {\n    {\"top_level\",   true,  connection_status::engaged_in_multi_function},\n    {\"subordinate\", false, connection_status::not_connected            },\n};\n\nBOOST_AUTO_TEST_CASE(eof)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the test\n            algo_test()\n                .expect_read(create_eof_frame(42, ok_builder().affected_rows(1).info(\"1st\").build()))\n                .will_set_status(\n                    // EOF finish multi-function operations. Transition only performed if is_top_level = true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix);\n\n            BOOST_TEST(fix.result() == 0u);  // num read rows\n            BOOST_TEST(fix.proc.is_complete());\n            BOOST_TEST(fix.proc.affected_rows() == 1u);\n            BOOST_TEST(fix.proc.info() == \"1st\");\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(eof_more_results)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the test\n            algo_test()\n                .expect_read(\n                    create_eof_frame(42, ok_builder().affected_rows(1).info(\"1st\").more_results(true).build())\n                )\n                .check(fix);\n\n            BOOST_TEST(fix.result() == 0u);  // num read rows\n            BOOST_TEST(fix.proc.is_reading_head());\n            BOOST_TEST(fix.proc.affected_rows() == 1u);\n            BOOST_TEST(fix.proc.info() == \"1st\");\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(eof_no_backslash_escapes)\n{\n    // Setup\n    fixture fix;\n\n    // Run the test\n    algo_test()\n        .expect_read(create_eof_frame(42, ok_builder().no_backslash_escapes(true).more_results(true).build()))\n        .will_set_backslash_escapes(false)\n        .check(fix);\n\n    BOOST_TEST(fix.result() == 0u);  // num read rows\n    BOOST_TEST(fix.proc.is_reading_head());\n}\n\nBOOST_AUTO_TEST_CASE(batch_with_rows)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. Single, long read that yields two rows\n            algo_test()\n                .expect_read(buffer_builder()\n                                 .add(create_text_row_message(42, \"abc\"))\n                                 .add(create_text_row_message(43, \"von\"))\n                                 .build())\n                .check(fix);\n\n            // Validate\n            BOOST_TEST(fix.result() == 2u);  // num read rows\n            BOOST_TEST(fix.proc.is_reading_rows());\n            fix.validate_refs(2);\n            fix.proc.num_calls()\n                .on_num_meta(1)\n                .on_meta(1)\n                .on_row_batch_start(1)\n                .on_row(2)\n                .on_row_batch_finish(1)\n                .validate();\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(batch_with_rows_eof)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. Single, long read that yields rows and eof\n            algo_test()\n                .expect_read(buffer_builder()\n                                 .add(create_text_row_message(42, \"abc\"))\n                                 .add(create_text_row_message(43, \"von\"))\n                                 .add(create_eof_frame(\n                                     44,\n                                     ok_builder().affected_rows(1).info(\"1st\").more_results(true).build()\n                                 ))\n                                 .build())\n                .check(fix);\n\n            // Validate\n            BOOST_TEST(fix.result() == 2u);  // num read rows\n            BOOST_TEST_REQUIRE(fix.proc.is_reading_head());\n            BOOST_TEST(fix.proc.affected_rows() == 1u);\n            BOOST_TEST(fix.proc.info() == \"1st\");\n            fix.validate_refs(2);\n            fix.proc.num_calls()\n                .on_num_meta(1)\n                .on_meta(1)\n                .on_row_batch_start(1)\n                .on_row(2)\n                .on_row_ok_packet(1)\n                .on_row_batch_finish(1)\n                .validate();\n        }\n    }\n}\n\n// Regression check: don't attempt to continue reading after the 1st EOF for multi-result\nBOOST_AUTO_TEST_CASE(batch_with_rows_eof_more_results)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo. Single, long read that yields the next resultset's OK packet\n    algo_test()\n        .expect_read(\n            buffer_builder()\n                .add(create_text_row_message(42, \"abc\"))\n                .add(\n                    create_eof_frame(43, ok_builder().affected_rows(1).info(\"1st\").more_results(true).build())\n                )\n                .add(create_ok_frame(44, ok_builder().info(\"2nd\").build()))\n                .build()\n        )\n        .check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 1u);  // num read rows\n    BOOST_TEST_REQUIRE(fix.proc.is_reading_head());\n    BOOST_TEST(fix.proc.affected_rows() == 1u);\n    BOOST_TEST(fix.proc.info() == \"1st\");\n    fix.validate_refs(1);\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(1)\n        .on_row(1)\n        .on_row_ok_packet(1)\n        .on_row_batch_finish(1)\n        .validate();\n}\n\nBOOST_AUTO_TEST_CASE(batch_with_rows_out_of_span_space)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo. Single, long read that yields 4 rows.\n    // We have only space for 3\n    algo_test()\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(42, \"aaa\"))\n                         .add(create_text_row_message(43, \"bbb\"))\n                         .add(create_text_row_message(44, \"ccc\"))\n                         .add(create_text_row_message(45, \"ddd\"))\n                         .build())\n        .check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 3u);  // num read rows\n    fix.validate_refs(3);\n    BOOST_TEST(fix.proc.is_reading_rows());\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(1)\n        .on_row(3)\n        .on_row_batch_finish(1)\n        .validate();\n}\n\nBOOST_AUTO_TEST_CASE(successive_calls_keep_parsing_state)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    auto eof = create_eof_frame(44, ok_builder().affected_rows(1).info(\"1st\").build());\n    algo_test()\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(42, \"aaa\"))\n                         .add(create_text_row_message(43, \"bbb\"))\n                         .add(boost::span<const std::uint8_t>(eof).subspan(0, 6))  // OK partially received\n                         .build())\n        .check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 2u);  // num read rows\n    fix.validate_refs(2);\n    BOOST_TEST(fix.proc.is_reading_rows());\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(1)\n        .on_row(2)\n        .on_row_batch_finish(1)\n        .validate();\n\n    // Run the algo again\n    fix.algo = detail::read_some_rows_algo({&fix.proc, fix.ref()});\n    algo_test()\n        .expect_read(buffer_builder().add(boost::span<const std::uint8_t>(eof).subspan(6)).build())\n        .will_set_status(connection_status::ready)\n        .check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 0u);  // num read rows\n    BOOST_TEST(fix.proc.is_complete());\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(2)\n        .on_row(2)\n        .on_row_batch_finish(2)\n        .on_row_ok_packet(1)\n        .validate();\n    BOOST_TEST(fix.proc.affected_rows() == 1u);\n    BOOST_TEST(fix.proc.info() == \"1st\");\n}\n\n// read_some_rows is a no-op if !st.should_read_rows()\nBOOST_AUTO_TEST_CASE(state_complete)\n{\n    // Setup\n    fixture fix;\n    add_ok(fix.proc, ok_builder().affected_rows(20).build());\n\n    // Run the algo\n    algo_test().check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 0u);  // num read rows\n    BOOST_TEST(fix.proc.is_complete());\n    fix.proc.num_calls().on_num_meta(1).on_meta(1).on_row_ok_packet(1).validate();\n}\n\nBOOST_AUTO_TEST_CASE(state_reading_head)\n{\n    // Setup\n    fixture fix;\n    add_ok(fix.proc, ok_builder().affected_rows(42).more_results(true).build());\n\n    // Run the algo\n    algo_test().check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 0u);  // num read rows\n    BOOST_TEST(fix.proc.is_reading_head());\n    fix.proc.num_calls().on_num_meta(1).on_meta(1).on_row_ok_packet(1).validate();\n}\n\nBOOST_AUTO_TEST_CASE(error_network_error)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the test\n            algo_test()\n                .expect_read(asio::error::network_reset)\n                .will_set_status(\n                    // Errors finish multi-function ops. Transition only performed if is_top_level = true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, asio::error::network_reset);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_seqnum_mismatch_successive_messages)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo\n            algo_test()\n                .expect_read(buffer_builder()\n                                 .add(create_text_row_message(42, \"abc\"))\n                                 .add(create_text_row_message(45, \"von\"))  // seqnum mismatch here\n                                 .build())\n                .will_set_status(\n                    // Errors finish multi-function ops. Transition only performed if is_top_level = true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, client_errc::sequence_number_mismatch);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_on_row)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Mock a failure\n            fix.proc.set_fail_count(fail_count(0, client_errc::static_row_parsing_error));\n\n            // Run the algo\n            algo_test()\n                .expect_read(create_text_row_message(42, 10))\n                .will_set_status(\n                    // Errors finish multi-function ops. Transition only performed if is_top_level = true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, client_errc::static_row_parsing_error);\n\n            // Validate\n            fix.proc.num_calls().on_num_meta(1).on_meta(1).on_row(1).on_row_batch_start(1).validate();\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_on_row_ok_packet)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Mock a failure\n            fix.proc.set_fail_count(fail_count(0, client_errc::num_resultsets_mismatch));\n\n            // Run the algo\n            algo_test()\n                .expect_read(create_eof_frame(42, ok_builder().build()))\n                .will_set_status(\n                    // Errors finish multi-function ops. Transition only performed if is_top_level = true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, client_errc::num_resultsets_mismatch);\n\n            // Validate\n            fix.proc.num_calls().on_num_meta(1).on_meta(1).on_row_ok_packet(1).on_row_batch_start(1).validate(\n            );\n        }\n    }\n}\n\n// deserialize_row_message covers cases like getting an error packet, deserialization errors, etc.\nBOOST_AUTO_TEST_CASE(error_deserialize_row_message)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo\n            algo_test()\n                .expect_read(err_builder()\n                                 .seqnum(42)\n                                 .code(common_server_errc::er_alter_info)\n                                 .message(\"abc\")\n                                 .build_frame())\n                .will_set_status(\n                    // Errors finish multi-function ops. Transition only performed if is_top_level = true\n                    tc.is_top_level ? connection_status::ready : fix.st.status\n                )\n                .check(fix, common_server_errc::er_alter_info, create_server_diag(\"abc\"));\n\n            // Validate\n            fix.proc.num_calls().on_num_meta(1).on_meta(1).on_row_batch_start(1).validate();\n        }\n    }\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(error_invalid_connection_status)\n{\n    struct\n    {\n        connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {connection_status::not_connected, client_errc::not_connected                },\n        {connection_status::ready,         client_errc::not_engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(reset)\n{\n    // Setup\n    fixture fix(false);\n\n    // Run the algo. Read a row\n    algo_test().expect_read(create_text_row_message(42, \"abc\")).check(fix);\n\n    // Validate\n    BOOST_TEST(fix.result() == 1u);  // num read rows\n    BOOST_TEST(fix.proc.is_reading_rows());\n    fix.validate_refs(1);\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(1)\n        .on_row(1)\n        .on_row_batch_finish(1)\n        .validate();\n\n    // Reset\n    fix.algo.reset();\n\n    // Run the algo again. Read an OK packet\n    algo_test().expect_read(create_eof_frame(43, ok_builder().build())).check(fix);\n\n    // Check\n    BOOST_TEST(fix.result() == 0u);  // num read rows\n    BOOST_TEST(fix.proc.is_complete());\n    fix.proc.num_calls()\n        .on_num_meta(1)\n        .on_meta(1)\n        .on_row_batch_start(2)\n        .on_row(1)\n        .on_row_batch_finish(2)\n        .on_row_ok_packet(1)\n        .validate();\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/read_some_rows_dynamic.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/mysql/detail/execution_processor/execution_state_impl.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/read_some_rows_dynamic.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::mysql::detail::execution_state_impl;\n\nBOOST_AUTO_TEST_SUITE(test_read_some_rows_dynamic)\n\nstruct fixture : algo_fixture_base\n{\n    execution_state_impl exec_st;\n    detail::read_some_rows_dynamic_algo algo{{&exec_st}};\n\n    fixture()\n    {\n        // This algorithm requires us to be engaged in a multi-function op\n        st.status = detail::connection_status::engaged_in_multi_function;\n\n        // Prepare the state, such that it's ready to read rows\n        add_meta(exec_st, {meta_builder().type(column_type::varchar).build_coldef()});\n        exec_st.sequence_number() = 42;\n\n        // Put something in shared_fields, simulating a previous read\n        st.shared_fields.push_back(field_view(\"prev\"));\n    }\n\n    rows_view result() const { return algo.result(st); }\n};\n\nBOOST_AUTO_TEST_CASE(eof)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_eof_frame(42, ok_builder().affected_rows(1).info(\"1st\").build()))\n        .will_set_status(detail::connection_status::ready)\n        .check(fix);\n\n    BOOST_TEST(fix.result() == makerows(1));\n    BOOST_TEST_REQUIRE(fix.exec_st.is_complete());\n    BOOST_TEST(fix.exec_st.get_affected_rows() == 1u);\n    BOOST_TEST(fix.exec_st.get_info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(batch_with_rows)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(42, \"abc\"))\n                         .add(create_text_row_message(43, \"von\"))\n                         .build())\n        .check(fix);\n\n    // Check\n    BOOST_TEST(fix.result() == makerows(1, \"abc\", \"von\"));\n    BOOST_TEST(fix.exec_st.is_reading_rows());\n}\n\nBOOST_AUTO_TEST_CASE(batch_with_rows_eof)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(42, \"abc\"))\n                         .add(create_text_row_message(43, \"von\"))\n                         .add(create_eof_frame(44, ok_builder().affected_rows(1).info(\"1st\").build()))\n                         .build())\n        .will_set_status(detail::connection_status::ready)\n        .check(fix);\n\n    // Check\n    BOOST_TEST(fix.result() == makerows(1, \"abc\", \"von\"));\n    BOOST_TEST_REQUIRE(fix.exec_st.is_complete());\n    BOOST_TEST(fix.exec_st.get_affected_rows() == 1u);\n    BOOST_TEST(fix.exec_st.get_info() == \"1st\");\n}\n\n// All the other error cases are already tested in read_some_rows_impl. Spotcheck\nBOOST_AUTO_TEST_CASE(error)\n{\n    // Setup\n    fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(client_errc::incomplete_message)\n        .will_set_status(detail::connection_status::ready)  // Errors finish multi-function operations\n        .check(fix, client_errc::incomplete_message);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/reset_connection.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/impl/internal/sansio/reset_connection.hpp>\n#include <boost/mysql/impl/internal/sansio/run_pipeline.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_reset_connection)\n\n//\n// read_reset_connection_response_algo\n//\nstruct read_response_fixture : algo_fixture_base\n{\n    detail::read_reset_connection_response_algo algo{11};\n};\n\nBOOST_AUTO_TEST_CASE(read_response_success)\n{\n    // Setup\n    read_response_fixture fix;\n    fix.st.current_charset = utf8mb4_charset;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_ok_frame(11, ok_builder().build()))\n        .will_set_current_charset(character_set{})  // the charset was reset\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_success_no_backslash_escapes)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_ok_frame(11, ok_builder().no_backslash_escapes(true).build()))\n        .will_set_backslash_escapes(false)          // OK packet processed\n        .will_set_current_charset(character_set{})  // charset was reset\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_network)\n{\n    algo_test()\n        .expect_read(create_ok_frame(11, ok_builder().build()))\n        .check_network_errors<read_response_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_packet)\n{\n    // Setup\n    read_response_fixture fix;\n    fix.st.current_charset = utf8mb4_charset;\n\n    // Run the algo. The character set is not updated.\n    algo_test()\n        .expect_read(err_builder()\n                         .seqnum(11)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\n//\n// setup_reset_connection_pipeline: running a pipeline with these parameters\n// has the intended effect\n//\nstruct reset_conn_fixture : algo_fixture_base\n{\n    detail::run_pipeline_algo algo{detail::setup_reset_connection_pipeline(st)};\n};\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    // Setup\n    reset_conn_fixture fix;\n    fix.st.current_charset = utf8mb4_charset;\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_frame(0, {0x1f}))\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .will_set_current_charset(character_set{})  // charset was reset\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(reset_conn_error_network)\n{\n    // This covers errors in read and write\n    algo_test()\n        .expect_write(create_frame(0, {0x1f}))\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .check_network_errors<reset_conn_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(reset_conn_error_response)\n{\n    // Setup\n    reset_conn_fixture fix;\n    fix.st.current_charset = utf8mb4_charset;\n\n    // Run the algo. The current charset was not updated\n    algo_test()\n        .expect_write(create_frame(0, {0x1f}))\n        .expect_read(err_builder()\n                         .seqnum(1)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(reset_conn_error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            reset_conn_fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/run_pipeline.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/algo_params.hpp>\n#include <boost/mysql/detail/pipeline.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/sansio/run_pipeline.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/tools/detail/per_element_manip.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstddef>\n#include <cstdint>\n#include <vector>\n\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_prepare_statement_response.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/create_statement.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\nusing boost::span;\nusing boost::test_tools::per_element;\nusing detail::pipeline_request_stage;\nusing detail::pipeline_stage_kind;\nusing detail::resultset_encoding;\n\nBOOST_AUTO_TEST_SUITE(test_run_pipeline)\n\nconst std::vector<std::uint8_t> mock_request{1, 2, 3, 4, 5, 6, 7, 9, 21};\n\nstruct fixture_base : algo_fixture_base\n{\n    detail::run_pipeline_algo algo;\n\n    fixture_base(\n        span<const pipeline_request_stage> stages,\n        span<const std::uint8_t> req_buffer = mock_request,\n        std::vector<stage_response>* response = nullptr\n    )\n        : algo({req_buffer, stages, response})\n    {\n    }\n};\n\nstruct fixture : fixture_base\n{\n    std::vector<stage_response> resp;\n\n    fixture(span<const pipeline_request_stage> stages, span<const std::uint8_t> req_buffer = mock_request)\n        : fixture_base(stages, req_buffer, &resp)\n    {\n    }\n\n    // Verify that all stages succeeded\n    void check_all_stages_succeeded()\n    {\n        for (const auto& item : resp)\n        {\n            BOOST_TEST(item.error() == error_code());\n            BOOST_TEST(item.diag() == diagnostics());\n        }\n    }\n\n    // Verify that a certain step failed\n    void check_stage_error(std::size_t i, error_code expected_ec, const diagnostics& expected_diag)\n    {\n        BOOST_TEST(resp.at(i).error() == expected_ec);\n        BOOST_TEST(resp.at(i).diag() == expected_diag);\n    }\n};\n\n// All stage kinds work properly\nBOOST_AUTO_TEST_CASE(execute_success)\n{\n    // Setup. Each step has a different encoding\n    const std::array<pipeline_request_stage, 2> stages{\n        {\n         {pipeline_stage_kind::execute, 42u, resultset_encoding::binary},\n         {pipeline_stage_kind::execute, 11u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(42, ok_builder().info(\"1st\").build()))  // 1st op ok\n        .expect_read(create_frame(11, {0x01}))                               // 2nd op OK, 1 column\n        .expect_read(create_coldef_frame(12, meta_builder().type(column_type::tinyint).build_coldef()))\n        .expect_read(buffer_builder()\n                         .add(create_text_row_message(13, 42))\n                         .add(create_text_row_message(14, 43))\n                         .add(create_eof_frame(15, ok_builder().info(\"2nd\").build()))\n                         .build())\n        .check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n\n    // Check results\n    const auto& res0 = fix.resp.at(0).as_results();\n    BOOST_TEST(res0.rows() == rows(), per_element());\n    BOOST_TEST(res0.info() == \"1st\");\n    BOOST_TEST(detail::access::get_impl(res0).encoding() == resultset_encoding::binary);\n\n    const auto& res1 = fix.resp.at(1).as_results();\n    BOOST_TEST(res1.rows() == makerows(1, 42, 43), per_element());\n    BOOST_TEST(res1.info() == \"2nd\");\n    BOOST_TEST(detail::access::get_impl(res1).encoding() == resultset_encoding::text);\n}\n\nBOOST_AUTO_TEST_CASE(prepare_statement_success)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 2> stages{\n        {\n         {pipeline_stage_kind::prepare_statement, 42u, {}},\n         {pipeline_stage_kind::prepare_statement, 11u, {}},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test. 1st statement has 2 meta, 2nd has 1\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(prepare_stmt_response_builder().seqnum(42).id(7).num_columns(0).num_params(2).build())\n        .expect_read(create_coldef_frame(43, meta_builder().name(\"abc\").build_coldef()))\n        .expect_read(create_coldef_frame(44, meta_builder().name(\"def\").build_coldef()))\n        .expect_read(prepare_stmt_response_builder().seqnum(11).id(9).num_columns(0).num_params(1).build())\n        .expect_read(create_coldef_frame(12, meta_builder().name(\"aaa\").build_coldef()))\n        .check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n\n    // Check the resulting statements\n    auto stmt0 = fix.resp.at(0).as_statement();\n    BOOST_TEST(stmt0.id() == 7u);\n    BOOST_TEST(stmt0.num_params() == 2u);\n\n    auto stmt1 = fix.resp.at(1).as_statement();\n    BOOST_TEST(stmt1.id() == 9u);\n    BOOST_TEST(stmt1.num_params() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(close_statement_success)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 2> stages{\n        {\n         {pipeline_stage_kind::close_statement, 3u, {}},\n         {pipeline_stage_kind::close_statement, 8u, {}},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test. Close statement doesn't have a response\n    algo_test().expect_write(mock_request).check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n}\n\nBOOST_AUTO_TEST_CASE(reset_connection)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 1> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 3u, {}},\n         }\n    };\n    fixture fix(stages);\n    fix.st.current_charset = utf8mb4_charset;\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(3, ok_builder().build()))\n        .will_set_current_charset(character_set{})  // charset was reset\n        .check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n}\n\nBOOST_AUTO_TEST_CASE(set_character_set)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 1> stages{\n        {\n         {pipeline_stage_kind::set_character_set, 19u, utf8mb4_charset},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(19, ok_builder().build()))\n        .will_set_current_charset(utf8mb4_charset)  // character set updated\n        .check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n}\n\nBOOST_AUTO_TEST_CASE(ping)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 1> stages{\n        {\n         {pipeline_stage_kind::ping, 32u, {}},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(32, ok_builder().no_backslash_escapes(true).build()))\n        .will_set_backslash_escapes(false)  // OK packet processed\n        .check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n}\n\nBOOST_AUTO_TEST_CASE(combination)\n{\n    // Setup. Typical connection setup pipeline, where we reset, set names,\n    // set the time_zone and prepare some statements\n    const std::array<pipeline_request_stage, 5> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         {pipeline_stage_kind::prepare_statement, 0u, {}},\n         {pipeline_stage_kind::prepare_statement, 1u, {}},\n         }\n    };\n    fixture fix(stages);\n    fix.st.backslash_escapes = false;\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(32, ok_builder().build()))\n        .expect_read(create_ok_frame(16, ok_builder().build()))\n        .expect_read(create_ok_frame(10, ok_builder().build()))\n        .expect_read(prepare_stmt_response_builder().seqnum(0).id(3).num_columns(1).num_params(1).build())\n        .expect_read(create_coldef_frame(1, meta_builder().name(\"abc\").build_coldef()))\n        .expect_read(create_coldef_frame(2, meta_builder().name(\"def\").build_coldef()))\n        .expect_read(prepare_stmt_response_builder().seqnum(1).id(1).num_columns(0).num_params(0).build())\n        .will_set_backslash_escapes(true)           // updated by all the OK packets\n        .will_set_current_charset(utf8mb4_charset)  // updated by set character set\n        .check(fix);\n\n    // All stages succeeded\n    BOOST_TEST_REQUIRE(fix.resp.size() == stages.size());\n    fix.check_all_stages_succeeded();\n\n    // The pipeline had its intended effect\n    BOOST_TEST(fix.resp.at(3).as_statement().id() == 3u);\n    BOOST_TEST(fix.resp.at(4).as_statement().id() == 1u);\n}\n\nBOOST_AUTO_TEST_CASE(no_requests)\n{\n    // Setup\n    fixture fix({}, {});\n\n    // Run the test. We complete immediately\n    algo_test().check(fix);\n\n    // The response was cleared\n    BOOST_TEST(fix.resp.size() == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(error_writing_request)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test. No response reading is attempted\n    algo_test().expect_write(mock_request, asio::error::eof).check(fix, asio::error::eof);\n\n    // All requests were marked as failed\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, asio::error::eof, {});\n    fix.check_stage_error(1, asio::error::eof, {});\n    fix.check_stage_error(2, asio::error::eof, {});\n}\n\nBOOST_AUTO_TEST_CASE(nonfatal_errors)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::prepare_statement, 32u, {}},\n         {pipeline_stage_kind::prepare_statement, 16u, {}},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test. Steps 1 and 3 fail.\n    // The first error is the operation's result\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(err_builder()\n                         .seqnum(32)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .expect_read(prepare_stmt_response_builder().seqnum(16).id(3).num_columns(0).num_params(0).build())\n        .expect_read(err_builder()\n                         .seqnum(10)\n                         .code(common_server_errc::er_bad_field_error)\n                         .message(\"other_msg\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n\n    // Stage errors\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n    fix.check_stage_error(1, {}, {});\n    fix.check_stage_error(2, common_server_errc::er_bad_field_error, create_server_diag(\"other_msg\"));\n\n    // The operation that succeeded had its result set\n    BOOST_TEST(fix.resp.at(1).as_statement().id() == 3u);\n}\n\nBOOST_AUTO_TEST_CASE(nonfatal_errors_middle)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::prepare_statement, 32u, {}},\n         {pipeline_stage_kind::prepare_statement, 16u, {}},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test. Steps 1 and 3 fail.\n    // The first error is the operation's result\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(prepare_stmt_response_builder().seqnum(32).id(3).num_columns(0).num_params(0).build())\n        .expect_read(err_builder()\n                         .seqnum(16)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .expect_read(create_ok_frame(10, ok_builder().no_backslash_escapes(true).build()))\n        .will_set_backslash_escapes(false)  // we processed the OK packet correctly\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n\n    // Stage errors\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, {}, {});\n    fix.check_stage_error(1, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n    fix.check_stage_error(2, {}, {});\n}\n\nBOOST_AUTO_TEST_CASE(fatal_error_first)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test. Reading the first response fails, and we don't further reading\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(asio::error::network_reset)\n        .check(fix, asio::error::network_reset);\n\n    // All subsequent requests were marked as failed\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, asio::error::network_reset, {});\n    fix.check_stage_error(1, asio::error::network_reset, {});\n    fix.check_stage_error(2, asio::error::network_reset, {});\n}\n\nBOOST_AUTO_TEST_CASE(fatal_error_middle)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(32, ok_builder().build()))\n        .expect_read(asio::error::network_reset)\n        .check(fix, asio::error::network_reset);\n\n    // All subsequent requests were marked as failed\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, {}, {});\n    fix.check_stage_error(1, asio::error::network_reset, {});\n    fix.check_stage_error(2, asio::error::network_reset, {});\n}\n\n// If there are fatal and non-fatal errors, the fatal one is the result of the operation\nBOOST_AUTO_TEST_CASE(nonfatal_then_fatal_error)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(err_builder()\n                         .seqnum(32)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .expect_read(asio::error::already_connected)\n        .check(fix, asio::error::already_connected);\n\n    // Stage results\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n    fix.check_stage_error(1, asio::error::already_connected, {});\n    fix.check_stage_error(2, asio::error::already_connected, {});\n}\n\n// Edge case: fatal error with non-empty diagnostics\nBOOST_AUTO_TEST_CASE(fatal_error_with_diag)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 3> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::execute, 10u, resultset_encoding::text},\n         }\n    };\n    fixture fix(stages);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(\n            err_builder().seqnum(32).code(common_server_errc::er_bad_db_error).message(\"bad db\").build_frame()\n        )\n        .expect_read(err_builder()\n                         .seqnum(16)\n                         .code(common_server_errc::er_aborting_connection)\n                         .message(\"aborting connection\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_aborting_connection, create_server_diag(\"aborting connection\"));\n\n    // Stage results\n    BOOST_TEST(fix.resp.size() == stages.size());\n    fix.check_stage_error(0, common_server_errc::er_bad_db_error, create_server_diag(\"bad db\"));\n    fix.check_stage_error(\n        1,\n        common_server_errc::er_aborting_connection,\n        create_server_diag(\"aborting connection\")\n    );\n    fix.check_stage_error(\n        2,\n        common_server_errc::er_aborting_connection,\n        create_server_diag(\"aborting connection\")\n    );\n}\n\n// Running a pipeline without a response should work for\n// close statement, set character set, reset connection and ping\nBOOST_AUTO_TEST_CASE(no_response_success)\n{\n    // Setup. One stage of each type\n    const std::array<pipeline_request_stage, 4> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::close_statement, 10u, {}},\n         {pipeline_stage_kind::ping, 0u, {}},\n         }\n    };\n    fixture_base fix(stages);\n    fix.st.backslash_escapes = false;\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(32, ok_builder().build()))\n        .expect_read(create_ok_frame(16, ok_builder().build()))\n        .expect_read(create_ok_frame(0, ok_builder().build()))\n        .will_set_backslash_escapes(true)           // updated by all the OK packets\n        .will_set_current_charset(utf8mb4_charset)  // updated by set character set\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(no_response_error_1)\n{\n    // Setup. One stage of each type\n    const std::array<pipeline_request_stage, 4> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::close_statement, 10u, {}},\n         {pipeline_stage_kind::ping, 0u, {}},\n         }\n    };\n    fixture_base fix(stages);\n    fix.st.backslash_escapes = false;\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(err_builder()\n                         .seqnum(32)\n                         .code(common_server_errc::er_bad_db_error)\n                         .message(\"my_message\")\n                         .build_frame())\n        .expect_read(create_ok_frame(16, ok_builder().build()))\n        .expect_read(err_builder()\n                         .seqnum(0)\n                         .code(common_server_errc::er_bad_table_error)\n                         .message(\"other_msg\")\n                         .build_frame())\n        .will_set_backslash_escapes(true)           // OK packet processed\n        .will_set_current_charset(utf8mb4_charset)  // set character set succeeded\n        .check(fix, common_server_errc::er_bad_db_error, create_server_diag(\"my_message\"));\n}\n\nBOOST_AUTO_TEST_CASE(no_response_error_2)\n{\n    // Setup. One stage of each type\n    const std::array<pipeline_request_stage, 4> stages{\n        {\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::close_statement, 10u, {}},\n         {pipeline_stage_kind::ping, 0u, {}},\n         }\n    };\n    fixture_base fix(stages);\n    fix.st.backslash_escapes = false;\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(32, ok_builder().build()))\n        .expect_read(err_builder()\n                         .seqnum(16)\n                         .code(common_server_errc::er_unknown_character_set)\n                         .message(\"bad_charset\")\n                         .build_frame())\n        .expect_read(create_ok_frame(0, ok_builder().build()))\n        .will_set_backslash_escapes(true)           // OK packet processed\n        .will_set_current_charset(character_set{})  // reset connection succeeded\n        .check(fix, common_server_errc::er_unknown_character_set, create_server_diag(\"bad_charset\"));\n}\n\nBOOST_AUTO_TEST_CASE(no_response_fatal_error)\n{\n    // Setup. One stage of each type, plus an initial stage for the fatal error\n    const std::array<pipeline_request_stage, 5> stages{\n        {\n         {pipeline_stage_kind::ping, 7, {}},\n         {pipeline_stage_kind::reset_connection, 32u, {}},\n         {pipeline_stage_kind::set_character_set, 16u, utf8mb4_charset},\n         {pipeline_stage_kind::close_statement, 10u, {}},\n         {pipeline_stage_kind::ping, 0u, {}},\n         }\n    };\n    fixture_base fix(stages);\n    fix.st.backslash_escapes = false;\n\n    // Run the test. This checks that the state was not modified\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(asio::error::network_reset)\n        .check(fix, asio::error::network_reset);\n}\n\nBOOST_AUTO_TEST_CASE(reusing_responses)\n{\n    // Setup\n    const std::array<pipeline_request_stage, 2> stages{\n        {\n         {pipeline_stage_kind::ping, 7, {}},\n         {pipeline_stage_kind::execute, 32u, resultset_encoding::text},\n         }\n    };\n    std::vector<stage_response> resp(3);                  // an extra item that should be removed\n    detail::access::get_impl(resp[0]).emplace_results();  // results to error\n    detail::access::get_impl(resp[1]).set_result(statement_builder().build());  // statement to results\n    fixture_base fix(stages, mock_request, &resp);\n\n    // Run the test\n    algo_test()\n        .expect_write(mock_request)\n        .expect_read(create_ok_frame(7, ok_builder().build()))\n        .expect_read(create_ok_frame(32, ok_builder().info(\"msg\").build()))\n        .check(fix);\n\n    BOOST_TEST(resp.size() == 2u);\n    BOOST_TEST(resp.at(0).error() == error_code());\n    BOOST_TEST(resp.at(0).diag() == diagnostics());\n    BOOST_TEST(resp.at(1).as_results().info() == \"msg\");\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            const std::array<pipeline_request_stage, 2> stages{\n                {\n                 {pipeline_stage_kind::execute, 42u, resultset_encoding::binary},\n                 {pipeline_stage_kind::prepare_statement, 11u, {}},\n                 }\n            };\n            fixture fix(stages);\n            fix.st.status = tc.status;\n\n            // Run the test\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/set_character_set.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/impl/internal/sansio/set_character_set.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_query_frame.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\n\nBOOST_AUTO_TEST_SUITE(test_set_character_set)\n\n//\n// compose_set_names\n//\nBOOST_AUTO_TEST_CASE(compose_set_names_success)\n{\n    BOOST_TEST(detail::compose_set_names(utf8mb4_charset).value() == \"SET NAMES 'utf8mb4'\");\n    BOOST_TEST(detail::compose_set_names(ascii_charset).value() == \"SET NAMES 'ascii'\");\n}\n\nBOOST_AUTO_TEST_CASE(compose_set_names_needs_escaping)\n{\n    // We don't create vulnerabilities when creating SET NAMES statements\n    character_set mock_charset{\"ab'cd\\\"e\", utf8mb4_charset.next_char};\n    BOOST_TEST(detail::compose_set_names(mock_charset).value() == \"SET NAMES 'ab\\\\'cd\\\\\\\"e'\");\n}\n\nBOOST_AUTO_TEST_CASE(compose_set_names_error)\n{\n    struct\n    {\n        string_view name;\n        const char* charset_name;\n    } test_cases[] = {\n        {\"utf8\",     \"test-\\xc3\\xb1\"}, // anything non-ascii is rejected\n        {\"non_utf8\", \"test-\\xb1-abc\"},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.charset_name)\n        {\n            character_set charset{tc.charset_name, utf8mb4_charset.next_char};\n            BOOST_TEST(detail::compose_set_names(charset).error() == client_errc::invalid_encoding);\n        }\n    }\n}\n\n//\n// read_set_character_set_response_algo\n//\nstruct read_response_fixture : algo_fixture_base\n{\n    detail::read_set_character_set_response_algo algo;\n\n    read_response_fixture(character_set charset = utf8mb4_charset) : algo(charset, 29) {}\n};\n\nBOOST_AUTO_TEST_CASE(read_response_success)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_ok_frame(29, ok_builder().build()))\n        .will_set_current_charset(utf8mb4_charset)  // charset updated\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_success_previous_charset)\n{\n    // Setup\n    read_response_fixture fix;\n    fix.st.current_charset = ascii_charset;\n\n    // Run the algo\n    algo_test()\n        .expect_read(create_ok_frame(29, ok_builder().build()))\n        .will_set_current_charset(utf8mb4_charset)  // charset updated\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_network)\n{\n    // This covers errors in read and write\n    algo_test()\n        .expect_read(create_ok_frame(29, ok_builder().build()))\n        .check_network_errors<read_response_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(read_response_error_packet)\n{\n    // Setup\n    read_response_fixture fix;\n\n    // Run the algo. The current charset was not updated\n    algo_test()\n        .expect_read(err_builder()\n                         .seqnum(29)\n                         .code(common_server_errc::er_unknown_character_set)\n                         .message(\"Unknown charset\")\n                         .build_frame())\n        .check(fix, common_server_errc::er_unknown_character_set, create_server_diag(\"Unknown charset\"));\n}\n\n//\n// set_character_set_algo\n//\nstruct set_charset_fixture : algo_fixture_base\n{\n    detail::set_character_set_algo algo;\n\n    set_charset_fixture(character_set charset = utf8mb4_charset) : algo({charset}) {}\n    set_charset_fixture(std::size_t max_bufsize) : algo_fixture_base(max_bufsize), algo({utf8mb4_charset}) {}\n};\n\nBOOST_AUTO_TEST_CASE(set_charset_success)\n{\n    // Setup\n    set_charset_fixture fix;\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_query_frame(0, \"SET NAMES 'utf8mb4'\"))\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .will_set_current_charset(utf8mb4_charset)  // charset updated\n        .check(fix);\n}\n\n// Ensure we don't create vulnerabilities when composing SET NAMES\nBOOST_AUTO_TEST_CASE(set_charset_name_needs_escaping)\n{\n    // Setup\n    const character_set new_charset{\"lat'in\\\\\", utf8mb4_charset.next_char};\n    set_charset_fixture fix(new_charset);\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_query_frame(0, \"SET NAMES 'lat\\\\'in\\\\\\\\'\"))\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .will_set_current_charset(new_charset)\n        .check(fix);\n}\n\nBOOST_AUTO_TEST_CASE(set_charset_error_composing_request)\n{\n    // Setup\n    set_charset_fixture fix({\"lat\\xc3\\xadn\", utf8mb4_charset.next_char});\n    fix.st.current_charset = ascii_charset;\n\n    // Run the algo. The current charset was not updated\n    algo_test().check(fix, client_errc::invalid_encoding);\n}\n\nBOOST_AUTO_TEST_CASE(set_charset_error_network)\n{\n    // This covers errors in reading the response\n    algo_test()\n        .expect_write(create_query_frame(0, \"SET NAMES 'utf8mb4'\"))\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .check_network_errors<set_charset_fixture>();\n}\n\nBOOST_AUTO_TEST_CASE(set_charset_error_max_buffer_size)\n{\n    // Setup\n    set_charset_fixture fix(16u);\n\n    // Run the algo\n    algo_test().check(fix, client_errc::max_buffer_size_exceeded);\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(set_charset_error_invalid_connection_status)\n{\n    struct\n    {\n        detail::connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {detail::connection_status::not_connected,             client_errc::not_connected            },\n        {detail::connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            set_charset_fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/start_execution.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/metadata_mode.hpp>\n\n#include <boost/mysql/detail/any_execution_request.hpp>\n#include <boost/mysql/detail/resultset_encoding.hpp>\n\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/start_execution.hpp>\n\n#include <boost/asio/error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <string>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/create_basic.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_unit/algo_test.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_query_frame.hpp\"\n#include \"test_unit/mock_execution_processor.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\nusing detail::any_execution_request;\nusing detail::connection_status;\nusing detail::resultset_encoding;\n\nBOOST_AUTO_TEST_SUITE(test_start_execution)\n\nstruct fixture : algo_fixture_base\n{\n    mock_execution_processor proc;\n    detail::start_execution_algo algo;\n\n    fixture(\n        any_execution_request req = any_execution_request(\"SELECT 1\"),\n        std::size_t max_bufsize = default_max_buffsize\n    )\n        : algo_fixture_base(max_bufsize), algo({req, &proc})\n    {\n    }\n\n    fixture(bool is_top_level, connection_status initial_status)\n        : algo({any_execution_request(\"SELECT 1\"), &proc}, is_top_level)\n    {\n        st.status = initial_status;\n    }\n};\n\n// Test cases to verify is_top_level = true and false.\n// With is_top_level = false, status checks and transitions are not performed.\n// Using connection_status::not_connected in this case helps verify that no transition is performed.\nconstexpr struct\n{\n    const char* name;\n    bool is_top_level;\n    connection_status initial_status;\n} top_level_test_cases[] = {\n    {\"top_level\",   true,  connection_status::ready        },\n    {\"subordinate\", false, connection_status::not_connected},\n};\n\n//\n// State transitions and errors\n//\nBOOST_AUTO_TEST_CASE(success_rows)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo\n            algo_test()\n                .expect_write(create_query_frame(0, \"SELECT 1\"))\n                .expect_read(create_frame(1, {0x01}))\n                .expect_read(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n                .will_set_status(\n                    // Initiates a multi-function op. Transition performed only if is_top_level = true\n                    tc.is_top_level ? connection_status::engaged_in_multi_function : fix.st.status\n                )\n                .check(fix);\n\n            // Verify\n            BOOST_TEST(fix.proc.is_reading_rows());\n            check_meta(fix.proc.meta(), {column_type::varchar});\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(success_eof)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. No state transition happens here in either case\n            // (the multi-function operation started and finished here)\n            algo_test()\n                .expect_write(create_query_frame(0, \"SELECT 1\"))\n                .expect_read(create_ok_frame(1, ok_builder().build()))\n                .check(fix);\n\n            // Verify\n            BOOST_TEST(fix.proc.is_complete());\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_network_write_request)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. If writing the request failed, the multi-function operation\n            // isn't really started\n            algo_test()\n                .expect_write(create_query_frame(0, \"SELECT 1\"), asio::error::network_reset)\n                .check(fix, asio::error::network_reset);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_read_resultset_head)\n{\n    for (const auto& tc : top_level_test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.name)\n        {\n            // Setup\n            fixture fix(tc.is_top_level, tc.initial_status);\n\n            // Run the algo. If is_top_level = false, no transition occurs.\n            // Otherwise, the operation is started and finished straight away\n            algo_test()\n                .expect_write(create_query_frame(0, \"SELECT 1\"))\n                .expect_read(err_builder()\n                                 .seqnum(1)\n                                 .code(common_server_errc::er_syntax_error)\n                                 .message(\"Some error\")\n                                 .build_frame())\n                .check(fix, common_server_errc::er_syntax_error, create_server_diag(\"Some error\"));\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(error_max_buffer_size)\n{\n    // Setup\n    std::string query(512, 'a');\n    fixture fix(any_execution_request(query), 512u);\n\n    // Run the algo\n    algo_test().check(fix, client_errc::max_buffer_size_exceeded);\n}\n\n// Connection status checked correctly\nBOOST_AUTO_TEST_CASE(error_invalid_connection_status)\n{\n    struct\n    {\n        connection_status status;\n        error_code expected_err;\n    } test_cases[] = {\n        {connection_status::not_connected,             client_errc::not_connected            },\n        {connection_status::engaged_in_multi_function, client_errc::engaged_in_multi_function},\n    };\n\n    for (const auto& tc : test_cases)\n    {\n        BOOST_TEST_CONTEXT(tc.status)\n        {\n            // Setup\n            fixture fix;\n            fix.st.status = tc.status;\n\n            // Run the algo\n            algo_test().check(fix, tc.expected_err);\n        }\n    }\n}\n\n//\n// Different execution requests\n//\nBOOST_AUTO_TEST_CASE(text_query)\n{\n    // Setup\n    fixture fix(any_execution_request(\"SELECT 1\"));\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_query_frame(0, \"SELECT 1\"))\n        .expect_read(create_frame(1, {0x01}))\n        .expect_read(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n        .will_set_status(detail::connection_status::engaged_in_multi_function)  // Starts a multi-function op\n        .check(fix);\n\n    // Verify\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.sequence_number() == 3u);\n    BOOST_TEST(fix.proc.is_reading_rows());\n    check_meta(fix.proc.meta(), {column_type::varchar});\n    fix.proc.num_calls().reset(1).on_num_meta(1).on_meta(1).validate();\n}\n\nBOOST_AUTO_TEST_CASE(stmt_success)\n{\n    // Setup\n    const auto params = make_fv_arr(\"test\", nullptr);\n    fixture fix(any_execution_request({std::uint32_t(1u), std::uint16_t(2u), params}));\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_frame(\n            0,\n            {\n                0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,\n                0x01, 0xfe, 0x00, 0x06, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,\n            }\n        ))\n        .expect_read(create_frame(1, {0x01}))\n        .expect_read(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n        .will_set_status(detail::connection_status::engaged_in_multi_function)  // Starts a multi-function op\n        .check(fix);\n\n    // Verify\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::binary);\n    BOOST_TEST(fix.proc.sequence_number() == 3u);\n    BOOST_TEST(fix.proc.is_reading_rows());\n    check_meta(fix.proc.meta(), {column_type::varchar});\n    fix.proc.num_calls().reset(1).on_num_meta(1).on_meta(1).validate();\n}\n\nBOOST_AUTO_TEST_CASE(stmt_error_num_params)\n{\n    // Setup\n    const auto params = make_fv_arr(\"test\", nullptr, 42);  // too many params\n    fixture fix(any_execution_request({std::uint32_t(1u), std::uint16_t(2u), params}));\n\n    // Run the algo. Nothing should be written to the server\n    algo_test().check(fix, client_errc::wrong_num_params);\n}\n\nBOOST_AUTO_TEST_CASE(with_params_success)\n{\n    // Setup\n    const std::array<format_arg, 2> args{\n        {{\"\", \"abc\"}, {\"\", 42}}\n    };\n    fixture fix(any_execution_request({\"SELECT {}, {}\", args}));\n    fix.st.current_charset = utf8mb4_charset;\n\n    // Run the algo\n    algo_test()\n        .expect_write(create_query_frame(0, \"SELECT 'abc', 42\"))\n        .expect_read(create_ok_frame(1, ok_builder().build()))\n        .check(fix);\n\n    // Verify\n    BOOST_TEST(fix.proc.encoding() == resultset_encoding::text);\n    BOOST_TEST(fix.proc.sequence_number() == 2u);\n    BOOST_TEST(fix.proc.is_complete());\n    fix.proc.num_calls().reset(1).on_head_ok_packet(1).validate();\n}\n\nBOOST_AUTO_TEST_CASE(with_params_error_unknown_charset)\n{\n    // Setup\n    const std::array<format_arg, 2> args{\n        {{\"\", \"abc\"}, {\"\", 42}}\n    };\n    fixture fix(any_execution_request({\"SELECT {}, {}\", args}));\n    fix.st.current_charset = {};\n\n    // The algo fails immediately\n    algo_test().check(fix, client_errc::unknown_character_set);\n}\n\nBOOST_AUTO_TEST_CASE(with_params_error_formatting)\n{\n    // Setup\n    const std::array<format_arg, 1> args{{{\"\", \"abc\"}}};\n    fixture fix(any_execution_request({\"SELECT {}, {}\", args}));\n    fix.st.current_charset = utf8mb4_charset;\n\n    // The algo fails immediately\n    algo_test().check(fix, client_errc::format_arg_not_found);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/sansio/top_level_algo.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/next_action.hpp>\n\n#include <boost/mysql/impl/internal/protocol/frame_header.hpp>\n#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>\n#include <boost/mysql/impl/internal/sansio/message_reader.hpp>\n#include <boost/mysql/impl/internal/sansio/top_level_algo.hpp>\n\n#include <boost/asio/coroutine.hpp>\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <array>\n#include <cstdint>\n#include <cstring>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/mock_message.hpp\"\n#include \"test_unit/printing.hpp\"\n\nusing namespace boost::mysql::detail;\nusing namespace boost::mysql::test;\nusing boost::span;\nusing boost::asio::coroutine;\nusing boost::mysql::client_errc;\nusing boost::mysql::diagnostics;\nusing boost::mysql::error_code;\n\nBOOST_AUTO_TEST_SUITE(test_top_level_algo)\n\nvoid transfer(span<std::uint8_t> buff, span<const std::uint8_t> bytes)\n{\n    assert(buff.size() >= bytes.size());\n    std::memcpy(buff.data(), bytes.data(), bytes.size());\n}\n\nconst std::vector<std::uint8_t> msg1{0x01, 0x02, 0x03};\nconst std::vector<std::uint8_t> msg2(50, 0x04);\n\nBOOST_AUTO_TEST_CASE(read_cached)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.read(seqnum);\n                BOOST_TEST(ec == error_code());\n                BOOST_TEST(seqnum == 1u);\n                BOOST_MYSQL_ASSERT_BUFFER_EQUALS(st.reader.message(), msg1);\n                BOOST_ASIO_CORO_YIELD return st.read(seqnum);\n                BOOST_TEST(ec == error_code());\n                BOOST_TEST(seqnum == 2u);\n                BOOST_MYSQL_ASSERT_BUFFER_EQUALS(st.reader.message(), msg2);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(512);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a read request. We don't have cached data, so run_op returns it\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::read);\n    BOOST_TEST(act.read_args().buffer.data() == st.reader.buffer().data());\n    BOOST_TEST(act.read_args().buffer.size() == st.reader.buffer().size());\n    BOOST_TEST(!act.read_args().use_ssl);\n\n    // Acknowledge the read request\n    auto bytes = concat(create_frame(0, msg1), create_frame(1, msg2));\n    transfer(act.read_args().buffer, bytes);\n    act = algo.resume(error_code(), bytes.size());\n\n    // The second read request is acknowledged directly, since it has cached data\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(read_short_and_buffer_resizing)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.read(seqnum);\n                BOOST_TEST(ec == error_code());\n                BOOST_TEST(seqnum == 1u);\n                BOOST_MYSQL_ASSERT_BUFFER_EQUALS(st.reader.message(), msg2);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a read request and resizes the buffer appropriately\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::read);\n    BOOST_TEST(act.read_args().buffer.data() == st.reader.buffer().data());\n    BOOST_TEST(act.read_args().buffer.size() == st.reader.buffer().size());\n    BOOST_TEST(!act.read_args().use_ssl);\n\n    // Acknowledge the read request. There is space for the header, at least\n    auto bytes = create_frame(0, msg2);\n    transfer(act.read_args().buffer, span<const std::uint8_t>(bytes.data(), 4));\n    act = algo.resume(error_code(), 4);\n\n    // The read request wasn't completely satisfied, so more bytes are asked for\n    BOOST_TEST(act.type() == next_action_type::read);\n\n    // Read part of the body\n    transfer(act.read_args().buffer, span<const std::uint8_t>(bytes.data() + 4, 10));\n    act = algo.resume(error_code(), 10);\n    BOOST_TEST(act.type() == next_action_type::read);\n\n    // Complete\n    transfer(act.read_args().buffer, span<const std::uint8_t>(bytes.data() + 14, bytes.size() - 14));\n    act = algo.resume(error_code(), bytes.size() - 14);\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(read_parsing_error)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{42u};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.read(seqnum);\n                BOOST_TEST(ec == client_errc::sequence_number_mismatch);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(512);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a read request. We don't have cached data, so run_op returns it\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::read);\n\n    // Acknowledge the read request. This causes a seqnum mismatch that is transmitted to the op\n    auto bytes = create_frame(0, msg1);\n    transfer(act.read_args().buffer, bytes);\n    act = algo.resume(error_code(), bytes.size());\n\n    // Op done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(read_io_error)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.read(seqnum);\n                BOOST_TEST(ec == client_errc::wrong_num_params);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(512);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a read request. We don't have cached data, so run_op returns it\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::read);\n\n    // Read request fails with an error\n    act = algo.resume(client_errc::wrong_num_params, 0);\n\n    // Op done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(read_buffer_size_exceeded)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{42u};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.read(seqnum);\n                BOOST_TEST(ec == client_errc::max_buffer_size_exceeded);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(32, 64);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a read request. We don't have cached data, so resume returns it\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::read);\n\n    // Acknowledge the read request. This attempts to resize the buffer past max_size and errors\n    std::array<std::uint8_t, 4> header{};\n    serialize_frame_header(header, {80, 42});\n    transfer(act.read_args().buffer, header);\n    act = algo.resume(error_code(), header.size());\n\n    // Op done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(read_ssl_active)\n{\n    struct mock_algo\n    {\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_TEST(ec == error_code());\n            return st.read(seqnum);\n        }\n    };\n\n    connection_state_data st(512);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n    st.tls_active = true;\n\n    // Yielding a read with ssl active sets the use_ssl flag\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::read);\n    BOOST_TEST(act.read_args().buffer.data() == st.reader.buffer().data());\n    BOOST_TEST(act.read_args().buffer.size() == st.reader.buffer().size());\n    BOOST_TEST(act.read_args().use_ssl);\n}\n\nBOOST_AUTO_TEST_CASE(write_short)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.write(mock_message{msg1}, seqnum);\n                BOOST_TEST(ec == error_code());\n                BOOST_TEST(seqnum == 1u);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a write request\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::write);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(act.write_args().buffer, create_frame(0, msg1));\n    BOOST_TEST(!act.write_args().use_ssl);\n\n    // Acknowledge part of the write. This will ask for more bytes to be written\n    act = algo.resume(error_code(), 4);\n    BOOST_TEST(act.type() == next_action_type::write);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(act.write_args().buffer, msg1);\n\n    // Complete\n    act = algo.resume(error_code(), 3);\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(write_io_error)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.write(mock_message{msg1}, seqnum);\n                BOOST_TEST(ec == client_errc::wrong_num_params);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a write request. Fail it\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::write);\n    act = algo.resume(client_errc::wrong_num_params, 0);\n\n    // Done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(write_max_buffer_size_exact)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        std::uint8_t seqnum{};\n        const std::array<std::uint8_t, 60> long_msg{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return st.write(mock_message{long_msg}, seqnum);\n                BOOST_TEST(ec == error_code());\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(32, 64);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a write request, exactly of max_size. This succeeds\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::write);\n    BOOST_TEST(act.write_args().buffer.size() == 64u);\n    act = algo.resume(error_code(), 64);\n\n    // Done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(write_ssl_active)\n{\n    struct mock_algo\n    {\n        std::uint8_t seqnum{};\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_TEST(ec == error_code());\n            return st.write(mock_message{msg1}, seqnum);\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n    st.tls_active = true;\n\n    // Yielding a write request when ssl_active() returns an action with the flag set\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::write);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(act.write_args().buffer, create_frame(0, msg1));\n    BOOST_TEST(act.write_args().use_ssl);\n}\n\nBOOST_AUTO_TEST_CASE(ssl_handshake)\n{\n    struct mock_algo\n    {\n        boost::asio::coroutine coro;\n\n        next_action resume(connection_state_data&, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return next_action::ssl_handshake();\n                BOOST_TEST(ec == client_errc::wrong_num_params);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a SSL handshake request. These are always returned\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::ssl_handshake);\n\n    // Fail the op\n    act = algo.resume(client_errc::wrong_num_params, 0);\n\n    // Done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(ssl_shutdown)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n\n        next_action resume(connection_state_data&, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return next_action::ssl_shutdown();\n                BOOST_TEST(ec == client_errc::wrong_num_params);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a SSL handshake request. These are always returned\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::ssl_shutdown);\n\n    // Fail the op\n    act = algo.resume(client_errc::wrong_num_params, 0);\n\n    // Done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(connect)\n{\n    struct mock_algo\n    {\n        boost::asio::coroutine coro;\n\n        next_action resume(connection_state_data&, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return next_action::connect(reinterpret_cast<const void*>(42u));\n                BOOST_TEST(ec == client_errc::wrong_num_params);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a connect request. These are always returned.\n    // The connect argument is not used, only forwarded\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::connect);\n    BOOST_TEST(act.connect_endpoint() == reinterpret_cast<const void*>(42u));\n\n    // Fail the op\n    act = algo.resume(client_errc::wrong_num_params, 0);\n\n    // Done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(close)\n{\n    struct mock_algo\n    {\n        boost::asio::coroutine coro;\n\n        next_action resume(connection_state_data&, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return next_action::close();\n                BOOST_TEST(ec == client_errc::wrong_num_params);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields a close request. These are always returned\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::close);\n\n    // Fail the op\n    act = algo.resume(client_errc::wrong_num_params, 0);\n\n    // Done\n    BOOST_TEST(act.success());\n}\n\nBOOST_AUTO_TEST_CASE(immediate_completion)\n{\n    struct mock_algo\n    {\n        boost::asio::coroutine coro;\n\n        next_action resume(connection_state_data&, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(ec == error_code());\n                BOOST_ASIO_CORO_YIELD return next_action();\n                BOOST_TEST(false);  // Should never be called again after next_action() is returned\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initial run yields completion\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.success());\n}\n\n// Diagnostics are correctly passed around\nBOOST_AUTO_TEST_CASE(diagnostics_passed)\n{\n    struct mock_algo\n    {\n        coroutine coro;\n        const diagnostics* expected_diag;\n\n        explicit mock_algo(const diagnostics* expected_diag) : expected_diag(expected_diag) {}\n\n        next_action resume(connection_state_data&, diagnostics& diag, error_code)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                // Diagnostics passed by reference\n                BOOST_TEST(&diag == expected_diag);\n\n                // We can set the output value\n                diag = create_server_diag(\"abc\");\n                BOOST_ASIO_CORO_YIELD return next_action::ssl_handshake();\n\n                // The same object is passed again\n                BOOST_TEST(&diag == expected_diag);\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(512);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag, &diag);\n\n    // Initiate\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::ssl_handshake);\n\n    // We can see the diagnostics set by the algorithm\n    BOOST_TEST(diag == create_server_diag(\"abc\"));\n\n    // Continue\n    act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.success());\n\n    // Diagnostics still the same\n    BOOST_TEST(diag == create_server_diag(\"abc\"));\n}\n\n// The in-progress flag is set and cleared\nBOOST_AUTO_TEST_CASE(in_progress_flag_success)\n{\n    struct mock_algo\n    {\n        boost::asio::coroutine coro;\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(st.op_in_progress);  // always set when running an algo\n                BOOST_ASIO_CORO_YIELD return next_action::ssl_handshake();\n                BOOST_TEST(st.op_in_progress);  // always set when running an algo\n            }\n            return next_action();\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initiating sets the flag\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::ssl_handshake);\n    BOOST_TEST(st.op_in_progress);\n\n    // Finishing clears it\n    act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.success());\n    BOOST_TEST(!st.op_in_progress);\n}\n\nBOOST_AUTO_TEST_CASE(in_progress_flag_error)\n{\n    struct mock_algo\n    {\n        boost::asio::coroutine coro;\n\n        next_action resume(connection_state_data& st, diagnostics&, error_code ec)\n        {\n            BOOST_ASIO_CORO_REENTER(coro)\n            {\n                BOOST_TEST(st.op_in_progress);  // always set when running an algo\n                BOOST_ASIO_CORO_YIELD return next_action::ssl_handshake();\n                BOOST_TEST(st.op_in_progress);  // always set when running an algo\n            }\n            return ec;  // return the error passed to the algo\n        }\n    };\n\n    connection_state_data st(0);\n    diagnostics diag;\n    top_level_algo<mock_algo> algo(st, diag);\n\n    // Initiating sets the flag\n    auto act = algo.resume(error_code(), 0);\n    BOOST_TEST(act.type() == next_action_type::ssl_handshake);\n    BOOST_TEST(st.op_in_progress);\n\n    // Finishing clears it, even if there was an error either in the algo itself\n    // or in the code managed by top_level_algo (e.g. a network error)\n    act = algo.resume(client_errc::sequence_number_mismatch, 0);\n    BOOST_TEST(act.error() == client_errc::sequence_number_mismatch);\n    BOOST_TEST(!st.op_in_progress);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/spotchecks/connection_use_after_move.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/results.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_connection_use_after_move)\n\nBOOST_FIXTURE_TEST_CASE(use_move_constructed_connection, io_context_fixture)\n{\n    // Construct connection\n    auto conn = create_test_any_connection(ctx);\n\n    // Use it\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    results result;\n    conn.async_execute(\"SELECT * FROM myt\", result, as_netresult).validate_no_error();\n\n    // Move construct another connection from conn\n    any_connection conn2(std::move(conn));\n\n    // Using it works (no dangling pointer)\n    get_stream(conn2).add_bytes(create_ok_frame(1, ok_builder().affected_rows(42).build()));\n    conn2.async_execute(\"DELETE FROM myt\", result, as_netresult).validate_no_error();\n    BOOST_TEST(result.affected_rows() == 42u);\n}\n\nBOOST_FIXTURE_TEST_CASE(use_move_assigned_connection, io_context_fixture)\n{\n    // Construct two connections\n    auto conn1 = create_test_any_connection(ctx);\n    auto conn2 = create_test_any_connection(ctx);\n\n    // Use them\n    get_stream(conn1).add_bytes(create_ok_frame(1, ok_builder().build()));\n    get_stream(conn2).add_bytes(create_ok_frame(1, ok_builder().build()));\n    results result;\n    conn1.async_execute(\"SELECT * FROM myt\", result, as_netresult).validate_no_error();\n    conn2.async_execute(\"SELECT * FROM myt\", result, as_netresult).validate_no_error();\n\n    // Move assign\n    conn2 = std::move(conn1);\n\n    // Using it works (no dangling pointer)\n    get_stream(conn2).add_bytes(create_ok_frame(1, ok_builder().affected_rows(42).build()));\n    conn2.async_execute(\"DELETE FROM myt\", result, as_netresult).validate_no_error();\n    BOOST_TEST(result.affected_rows() == 42u);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/spotchecks/default_completion_tokens.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/handshake_params.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n#include <boost/mysql/tcp_ssl.hpp>\n\n#include <boost/asio/awaitable.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/asio/ip/tcp.hpp>\n#include <boost/asio/ssl/context.hpp>\n#include <boost/asio/use_awaitable.hpp>\n\n#include <tuple>\n\n#ifdef BOOST_ASIO_HAS_CO_AWAIT\n\nnamespace boost {\nnamespace mysql {\nnamespace test {\n\n// Verify that default completion tokens compile.\n// This is just a spotcheck, this function is never called\nboost::asio::awaitable<void> test_default_completion_tokens()\n{\n    using conn_type = boost::asio::use_awaitable_t<>::as_default_on_t<boost::mysql::tcp_ssl_connection>;\n\n    // Connection\n    boost::asio::io_context ctx;\n    boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);\n    conn_type conn{ctx, ssl_ctx};\n\n    // Helpers\n    diagnostics diag;\n    boost::asio::ip::tcp::endpoint ep{};\n    handshake_params params{\"user\", \"pass\"};\n    results result;\n    static_execution_state<std::tuple<>> static_st;\n    execution_state st;\n    statement stmt;\n    std::vector<field_view> stmt_params;\n\n    // Tests\n    co_await conn.async_connect(ep, params);\n    co_await conn.async_connect(ep, params, diag);\n\n    co_await conn.async_handshake(params);\n    co_await conn.async_handshake(params, diag);\n\n    co_await conn.async_prepare_statement(\"SELECT 1\");\n    co_await conn.async_prepare_statement(\"SELECT 1\", diag);\n\n    co_await conn.async_execute(\"SELECT 1\", result);\n    co_await conn.async_execute(\"SELECT 1\", result, diag);\n\n    co_await conn.async_start_execution(\"SELECT 1\", st);\n    co_await conn.async_start_execution(\"SELECT 1\", st, diag);\n\n    co_await conn.async_close_statement(stmt);\n    co_await conn.async_close_statement(stmt, diag);\n\n    co_await conn.async_read_resultset_head(st);\n    co_await conn.async_read_resultset_head(st, diag);\n\n    co_await conn.async_read_some_rows(st);\n    co_await conn.async_read_some_rows(st, diag);\n\n    co_await conn.async_ping();\n    co_await conn.async_ping(diag);\n\n    co_await conn.async_quit();\n    co_await conn.async_quit(diag);\n\n    co_await conn.async_close();\n    co_await conn.async_close(diag);\n\n    co_await conn.async_read_some_rows(static_st, boost::span<std::tuple<>>());\n    co_await conn.async_read_some_rows(static_st, boost::span<std::tuple<>>(), diag);\n}\n\n}  // namespace test\n}  // namespace mysql\n}  // namespace boost\n\n#endif\n"
  },
  {
    "path": "test/unit/test/spotchecks/execution_requests.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n// Since integration tests can't reliably test multifunction operations\n// that span over multiple messages, we test the complete multifn fllow in this unit tests.\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/character_set.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/string_view.hpp>\n#include <boost/mysql/tcp.hpp>\n#include <boost/mysql/with_params.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/detached.hpp>\n#include <boost/asio/io_context.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/test/unit_test_suite.hpp>\n\n#include <algorithm>\n#include <cstddef>\n#include <memory>\n#include <string>\n#include <vector>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_query_frame.hpp\"\n#include \"test_unit/create_statement.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n#include \"test_unit/test_stream.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_execution_requests)\n\n// The execution request is forwarded correctly, and non-const objects work correctly.\n// This is relevant for with_params involving ranges::views::filter, for instance\n// Note: netmakers intentionally not used here\nBOOST_AUTO_TEST_SUITE(forwarding_constness)\n\nstruct fixture : io_context_fixture\n{\n    any_connection conn{create_test_any_connection(ctx)};\n    results result;\n    execution_state st;\n\n    fixture() { get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build())); }\n\n    void validate_bytes_written()\n    {\n        BOOST_MYSQL_ASSERT_BUFFER_EQUALS(\n            get_stream(conn).bytes_written(),\n            create_query_frame(0, \"SELECT 'abc'\")\n        );\n    }\n\n    struct request\n    {\n        string_view value;\n        operator string_view() { return value; }  // Intentionally non-const\n    };\n    static request make_request() { return {\"SELECT 'abc'\"}; }\n};\n\nBOOST_FIXTURE_TEST_CASE(execute_sync_errc, fixture)\n{\n    // Setup\n    error_code ec;\n    diagnostics diag;\n\n    // Run\n    conn.execute(make_request(), result, ec, diag);\n\n    // Validate\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(diag == diagnostics());\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_sync_exc, fixture)\n{\n    conn.execute(make_request(), result);\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_diag, fixture)\n{\n    diagnostics diag;\n    conn.async_execute(make_request(), result, diag, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_nodiag, fixture)\n{\n    conn.async_execute(make_request(), result, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_deferred, fixture)\n{\n    // Spotcheck: deferred works correctly\n    auto op = conn.async_execute(make_request(), result, asio::deferred);\n    std::move(op)(as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_sync_errc, fixture)\n{\n    // Setup\n    error_code ec;\n    diagnostics diag;\n\n    // Run\n    conn.start_execution(make_request(), st, ec, diag);\n\n    // Validate\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(diag == diagnostics());\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_sync_exc, fixture)\n{\n    conn.start_execution(make_request(), st);\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_diag, fixture)\n{\n    diagnostics diag;\n    conn.async_start_execution(make_request(), st, diag, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_nodiag, fixture)\n{\n    conn.async_start_execution(make_request(), st, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_deferred, fixture)\n{\n    // Spotcheck: deferred works correctly\n    auto op = conn.async_start_execution(make_request(), st, asio::deferred);\n    std::move(op)(as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\n// Spotcheck: old connection doesn't generate compile errors.\n// Intentionally not run\nvoid old_connection()\n{\n    asio::io_context ctx;\n    tcp_connection conn(ctx);\n    auto req = fixture::make_request();\n    results result;\n    execution_state st;\n    error_code ec;\n    diagnostics diag;\n\n    conn.execute(req, result, ec, diag);\n    conn.execute(req, result);\n    conn.async_execute(req, result, asio::detached);\n    conn.async_execute(req, result, diag, asio::detached);\n    conn.async_execute(req, result, diag, asio::deferred)(asio::detached);\n    conn.start_execution(req, st, ec, diag);\n    conn.start_execution(req, st);\n    conn.async_start_execution(req, st, asio::detached);\n    conn.async_start_execution(req, st, diag, asio::detached);\n    conn.async_start_execution(req, st, diag, asio::deferred)(asio::detached);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// The execution request is forwarded with the correct value category, and is moved if required.\n// Move-only objects work correctly\nBOOST_AUTO_TEST_SUITE(forwarding_rvalues)\n\nstruct fixture : io_context_fixture\n{\n    any_connection conn{create_test_any_connection(ctx)};\n    results result;\n    execution_state st;\n\n    fixture() { get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build())); }\n\n    void validate_bytes_written()\n    {\n        BOOST_MYSQL_ASSERT_BUFFER_EQUALS(\n            get_stream(conn).bytes_written(),\n            create_query_frame(0, \"SELECT 'abcd'\")\n        );\n    }\n\n    // An execution request that doesn't support copies\n    struct request\n    {\n        std::unique_ptr<char[]> buff;\n        std::size_t size;\n\n        request(string_view v) : buff(new char[v.size()]), size(v.size())\n        {\n            std::copy(v.begin(), v.end(), buff.get());\n        }\n\n        operator string_view() const { return {buff.get(), size}; }\n    };\n    static request make_request() { return {\"SELECT 'abcd'\"}; }\n};\n\nBOOST_FIXTURE_TEST_CASE(execute_sync_errc, fixture)\n{\n    // Setup\n    error_code ec;\n    diagnostics diag;\n\n    // Execute\n    conn.execute(make_request(), result, ec, diag);\n\n    // Check\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(diag == diagnostics());\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_sync_exc, fixture)\n{\n    conn.execute(make_request(), result);\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_diag, fixture)\n{\n    diagnostics diag;\n    conn.async_execute(make_request(), result, diag, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_nodiag, fixture)\n{\n    conn.async_execute(make_request(), result, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_deferred, fixture)\n{\n    auto op = conn.async_execute(make_request(), result, asio::deferred);\n    std::move(op)(as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_sync_errc, fixture)\n{\n    // Setup\n    error_code ec;\n    diagnostics diag;\n\n    // Execute\n    conn.start_execution(make_request(), st, ec, diag);\n\n    // Check\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(diag == diagnostics());\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_sync_exc, fixture)\n{\n    conn.start_execution(make_request(), st);\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_diag, fixture)\n{\n    diagnostics diag;\n    conn.async_start_execution(make_request(), st, diag, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_nodiag, fixture)\n{\n    conn.async_start_execution(make_request(), st, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_deferred, fixture)\n{\n    auto op = conn.async_start_execution(make_request(), st, asio::deferred);\n    std::move(op)(as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n// Spotcheck: old connection doesn't generate compile errors.\n// Intentionally not run\nvoid old_connection()\n{\n    asio::io_context ctx;\n    tcp_connection conn(ctx);\n    results result;\n    execution_state st;\n    error_code ec;\n    diagnostics diag;\n\n    conn.execute(fixture::make_request(), result, ec, diag);\n    conn.execute(fixture::make_request(), result);\n    conn.async_execute(fixture::make_request(), result, asio::detached);\n    conn.async_execute(fixture::make_request(), result, diag, asio::detached);\n    conn.async_execute(fixture::make_request(), result, diag, asio::deferred)(asio::detached);\n    conn.start_execution(fixture::make_request(), st, ec, diag);\n    conn.start_execution(fixture::make_request(), st);\n    conn.async_start_execution(fixture::make_request(), st, asio::detached);\n    conn.async_start_execution(fixture::make_request(), st, diag, asio::detached);\n    conn.async_start_execution(fixture::make_request(), st, diag, asio::deferred)(asio::detached);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// The execution request is forwarded correctly, with the correct value category.\n// Lvalues are not moved\nBOOST_AUTO_TEST_SUITE(forwarding_lvalues)\n\nstruct fixture : io_context_fixture\n{\n    // A request where we can detect moved-from state.\n    // std::string move-constructor doesn't offer guarantees about moved-from objects,\n    // while std::vector does\n    struct vector_request\n    {\n        std::vector<char> buff;\n\n        vector_request(string_view v) : buff(v.begin(), v.end()) {}\n\n        operator string_view() const { return {buff.data(), buff.size()}; }\n    };\n\n    any_connection conn{create_test_any_connection(ctx)};\n    results result;\n    execution_state st;\n    vector_request req{\"SELECT 'abcd'\"};\n\n    fixture() { get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build())); }\n\n    void validate_bytes_written()\n    {\n        BOOST_MYSQL_ASSERT_BUFFER_EQUALS(\n            get_stream(conn).bytes_written(),\n            create_query_frame(0, \"SELECT 'abcd'\")\n        );\n        BOOST_TEST(static_cast<string_view>(req) == \"SELECT 'abcd'\");\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE(execute_sync_errc, fixture)\n{\n    // Setup\n    error_code ec;\n    diagnostics diag;\n\n    // Execute\n    conn.execute(req, result, ec, diag);\n\n    // Validate\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(diag == diagnostics());\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_sync_exc, fixture)\n{\n    conn.execute(req, result);\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_diag, fixture)\n{\n    diagnostics diag;\n    conn.async_execute(req, result, diag, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_nodiag, fixture)\n{\n    conn.async_execute(req, result, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(execute_async_deferred, fixture)\n{\n    auto op = conn.async_execute(req, result, asio::deferred);\n    std::move(op)(as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_sync_errc, fixture)\n{\n    // Setup\n    error_code ec;\n    diagnostics diag;\n\n    // Execute\n    conn.start_execution(req, st, ec, diag);\n\n    // Check\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(diag == diagnostics());\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_sync_exc, fixture)\n{\n    conn.start_execution(req, st);\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_diag, fixture)\n{\n    diagnostics diag;\n    conn.async_start_execution(req, st, diag, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_nodiag, fixture)\n{\n    conn.async_start_execution(req, st, as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution_async_deferred, fixture)\n{\n    auto op = conn.async_start_execution(req, st, asio::deferred);\n    std::move(op)(as_netresult).validate_no_error();\n    validate_bytes_written();\n}\n\n// Spotcheck: old connection doesn't generate compile errors.\n// Intentionally not run\nvoid old_connection()\n{\n    asio::io_context ctx;\n    tcp_connection conn(ctx);\n    results result;\n    execution_state st;\n    error_code ec;\n    diagnostics diag;\n    const fixture::vector_request req{\"SELECT 'abc'\"};\n\n    conn.execute(req, result, ec, diag);\n    conn.execute(req, result);\n    conn.async_execute(req, result, asio::detached);\n    conn.async_execute(req, result, diag, asio::detached);\n    conn.async_execute(req, result, diag, asio::deferred)(asio::detached);\n    conn.start_execution(req, st, ec, diag);\n    conn.start_execution(req, st);\n    conn.async_start_execution(req, st, asio::detached);\n    conn.async_start_execution(req, st, diag, asio::detached);\n    conn.async_start_execution(req, st, diag, asio::deferred)(asio::detached);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// Deferred tokens appropriately decay-copy lvalues\nBOOST_AUTO_TEST_SUITE(deferred_tokens_lvalues)\n\nBOOST_FIXTURE_TEST_CASE(execute, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    results result;\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    std::string req(128, 'a');\n\n    // Create a deferred op\n    auto op = conn.async_execute(req, result, asio::deferred);\n\n    // Mutate the argument\n    std::fill(req.begin(), req.end(), 'b');\n\n    // Initiate\n    std::move(op)(as_netresult).validate_no_error();\n\n    // We wrote the initial value\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(\n        get_stream(conn).bytes_written(),\n        create_query_frame(0, std::string(128, 'a'))\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE(start_execution, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    execution_state st;\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    std::string req(128, 'a');\n\n    // Create a deferred op\n    auto op = conn.async_start_execution(req, st, asio::deferred);\n\n    // Mutate the argument\n    std::fill(req.begin(), req.end(), 'b');\n\n    // Initiate\n    std::move(op)(as_netresult).validate_no_error();\n\n    // We wrote the initial value\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(\n        get_stream(conn).bytes_written(),\n        create_query_frame(0, std::string(128, 'a'))\n    );\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n// Spotcheck: the types returned by with_params are correct\nBOOST_AUTO_TEST_CASE(with_params_types)\n{\n    {\n        // const references\n        const std::string s = \"abc\";\n        auto p1 = with_params(\"SELECT {}\", s);\n        static_assert(std::is_same<decltype(p1), with_params_t<std::string>>::value, \"\");\n    }\n    {\n        // references\n        std::string s = \"abc\";\n        auto p = with_params(\"SELECT {}\", s);\n        static_assert(std::is_same<decltype(p), with_params_t<std::string>>::value, \"\");\n    }\n    {\n        // rvalue references\n        std::string s = \"abc\";\n        auto p = with_params(\"SELECT {}\", std::move(s));\n        static_assert(std::is_same<decltype(p), with_params_t<std::string>>::value, \"\");\n    }\n    {\n        // pure rvalues\n        auto p = with_params(\"SELECT {}\", std::string());\n        static_assert(std::is_same<decltype(p), with_params_t<std::string>>::value, \"\");\n    }\n    {\n        // std::ref\n        std::string s = \"abc\";\n        auto p = with_params(\"SELECT {}\", std::ref(s));\n        static_assert(std::is_same<decltype(p), with_params_t<std::string&>>::value, \"\");\n    }\n    {\n        // std::ref (const)\n        const std::string s = \"abc\";\n        auto p = with_params(\"SELECT {}\", std::ref(s));\n        static_assert(std::is_same<decltype(p), with_params_t<const std::string&>>::value, \"\");\n    }\n}\n\n// Regression test: async_execute() doesn't cause side effects in the initiation\nBOOST_FIXTURE_TEST_CASE(async_execute_side_effects_in_initiation, io_context_fixture)\n{\n    auto conn = create_test_any_connection(ctx);\n    results result1, result2;\n\n    // Resultsets will be complete as soon as a message is read\n    get_stream(conn)\n        .add_bytes(create_ok_frame(1, ok_builder().affected_rows(2).build()))\n        .add_bytes(create_ok_frame(1, ok_builder().affected_rows(1).build()));\n\n    // Create two queries as deferred objects, but don't run them yet\n    auto q1 = conn.async_execute(\"Q1\", result1, asio::deferred);\n    auto q2 = conn.async_execute(\"Q2\", result2, asio::deferred);\n\n    // Run them in reverse order\n    std::move(q2)(as_netresult).validate_no_error();\n    std::move(q1)(as_netresult).validate_no_error();\n\n    // Check that we wrote Q2's message first, then Q1's\n    auto expected = concat(\n        create_frame(0, {0x03, 0x51, 0x32}),  // query request Q2\n        create_frame(0, {0x03, 0x51, 0x31})   // query request Q1\n    );\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(get_stream(conn).bytes_written(), expected);\n\n    // Check that the results got the right ok_packets\n    BOOST_TEST(result2.affected_rows() == 2u);\n    BOOST_TEST(result1.affected_rows() == 1u);\n}\n\n// Regression test: bound statements correctly store statement handle and params\n// when used with deferred tokens\nBOOST_FIXTURE_TEST_CASE(async_execute_deferred_lifetimes, io_context_fixture)\n{\n    // Setup\n    constexpr std::uint8_t expected_msg[] = {\n        0x15, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,\n        0x00, 0x02, 0x01, 0xfe, 0x00, 0x06, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,\n    };\n    results result;\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n\n    // Create a bound statement on the heap. This helps tooling detect memory errors\n    using bound_stmt_t = bound_statement_tuple<std::tuple<std::string, std::nullptr_t>>;\n    std::unique_ptr<bound_stmt_t> stmt_ptr{\n        new bound_stmt_t{statement_builder().id(1).num_params(2).build().bind(std::string(\"test\"), nullptr)}\n    };\n\n    // Deferred op\n    auto op = conn.async_execute(*stmt_ptr, result, asio::deferred);\n\n    // Free the statement\n    stmt_ptr.reset();\n\n    // Actually run the op\n    std::move(op)(as_netresult).validate_no_error();\n\n    // verify that the op had the intended effects\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(get_stream(conn).bytes_written(), expected_msg);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/spotchecks/misc.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/blob.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/connection.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/mysql_collations.hpp>\n#include <boost/mysql/pipeline.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/rows_view.hpp>\n#include <boost/mysql/statement.hpp>\n#include <boost/mysql/string_view.hpp>\n\n#include <boost/mysql/detail/access.hpp>\n#include <boost/mysql/detail/engine.hpp>\n#include <boost/mysql/detail/engine_impl.hpp>\n#include <boost/mysql/detail/engine_stream_adaptor.hpp>\n\n#include <boost/asio/deferred.hpp>\n#include <boost/asio/error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <memory>\n\n#include \"test_common/assert_buffer_equals.hpp\"\n#include \"test_common/buffer_concat.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/netfun_maker.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/create_statement.hpp\"\n#include \"test_unit/fail_count.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_misc)\n\n// spotcheck for the dynamic interface\n// Verifies that execute (dynamic interface) works when rows come in separate batches\n// This is testing the interaction between the network algorithm and results\nBOOST_FIXTURE_TEST_CASE(execute_multiple_batches, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    results result;\n\n    // Message sequence (each on its own read)\n    get_stream(conn)\n        .add_bytes(create_frame(1, {0x02}))  // OK, 2 columns\n        .add_break()\n        .add_bytes(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))  // meta\n        .add_break()\n        .add_bytes(create_coldef_frame(\n            3,\n            meta_builder().type(column_type::blob).collation_id(mysql_collations::binary).build_coldef()\n        ))  // meta\n        .add_break()\n        .add_bytes(create_text_row_message(4, \"abcd\", makebv(\"\\0\\1\\0\")))  // row 1\n        .add_break()\n        .add_bytes(create_text_row_message(5, \"defghi\", makebv(\"\\3\\4\\3\\0\")))  // row 2\n        .add_break()\n        .add_bytes(create_eof_frame(6, ok_builder().affected_rows(10u).info(\"1st\").more_results(true).build())\n        )\n        .add_break()\n        .add_bytes(create_ok_frame(7, ok_builder().affected_rows(20u).info(\"2nd\").more_results(true).build()))\n        .add_break()\n        .add_bytes(create_frame(8, {0x01}))  // OK, 1 metadata\n        .add_break()\n        .add_bytes(create_coldef_frame(9, meta_builder().type(column_type::varchar).build_coldef()))  // meta\n        .add_break()\n        .add_bytes(create_text_row_message(10, \"ab\"))  // row 1\n        .add_break()\n        .add_bytes(create_eof_frame(11, ok_builder().affected_rows(30u).info(\"3rd\").build()));\n\n    // Call the function\n    conn.execute(\"abc\", result);\n\n    // We've written the query request\n    auto expected_msg = create_frame(0, {0x03, 0x61, 0x62, 0x63});  // ASCII \"abc\" (plus length)\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(get_stream(conn).bytes_written(), expected_msg);\n\n    // We've populated the results\n    BOOST_TEST_REQUIRE(result.size() == 3u);\n    BOOST_TEST(result[0].affected_rows() == 10u);\n    BOOST_TEST(result[0].info() == \"1st\");\n    BOOST_TEST(result[0].rows() == makerows(2, \"abcd\", makebv(\"\\0\\1\\0\"), \"defghi\", makebv(\"\\3\\4\\3\\0\")));\n    BOOST_TEST(result[1].affected_rows() == 20u);\n    BOOST_TEST(result[1].info() == \"2nd\");\n    BOOST_TEST(result[1].rows() == rows());\n    BOOST_TEST(result[2].affected_rows() == 30u);\n    BOOST_TEST(result[2].info() == \"3rd\");\n    BOOST_TEST(result[2].rows() == makerows(1, \"ab\"));\n}\n\n// Regression check: async_close_statement doesn't require the passed-in statement to be alive\n// when used with deferred tokens.\nBOOST_FIXTURE_TEST_CASE(async_close_statement_handle_deferred_tokens, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    std::unique_ptr<statement> stmt{new statement(statement_builder().id(3).build())};\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n\n    // Deferred op\n    auto op = conn.async_close_statement(*stmt, asio::deferred);\n\n    // Invalidate the original variable\n    stmt.reset();\n\n    // Run the operation\n    std::move(op)(as_netresult).validate_no_error();\n\n    // verify that the op had the intended effects\n    const auto expected_message = concat(\n        create_frame(0, {0x19, 0x03, 0x00, 0x00, 0x00}),\n        create_frame(0, {0x0e})\n    );\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(get_stream(conn).bytes_written(), expected_message);\n}\n\n// Regression check: when there is a network error, sync functions\n// returning a value fail with an assertion\nBOOST_AUTO_TEST_CASE(net_error_prepare_statement)\n{\n    using netmaker_stmt = netfun_maker<statement, any_connection, string_view>;\n    struct\n    {\n        const char* name;\n        netmaker_stmt::signature prepare_statement;\n    } fns[] = {\n        {\"sync\",  netmaker_stmt::sync_errc(&any_connection::prepare_statement)       },\n        {\"async\", netmaker_stmt::async_diag(&any_connection::async_prepare_statement)},\n    };\n\n    for (const auto& fn : fns)\n    {\n        BOOST_TEST_CONTEXT(fn.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            auto conn = create_test_any_connection(fix.ctx);\n            get_stream(conn).set_fail_count(fail_count(0, boost::asio::error::connection_reset));\n\n            fn.prepare_statement(conn, \"SELECT 1\").validate_error(boost::asio::error::connection_reset);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(net_error_read_some_rows)\n{\n    using netmaker_stmt = netfun_maker<rows_view, any_connection, execution_state&>;\n    struct\n    {\n        const char* name;\n        netmaker_stmt::signature read_some_rows;\n    } fns[] = {\n        {\"sync\",  netmaker_stmt::sync_errc(&any_connection::read_some_rows)       },\n        {\"async\", netmaker_stmt::async_diag(&any_connection::async_read_some_rows)},\n    };\n\n    for (const auto& fn : fns)\n    {\n        BOOST_TEST_CONTEXT(fn.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            auto conn = create_test_any_connection(\n                fix.ctx,\n                {},\n                detail::connection_status::engaged_in_multi_function\n            );\n            get_stream(conn).set_fail_count(fail_count(0, boost::asio::error::connection_reset));\n            execution_state st;\n            add_meta(get_iface(st), {column_type::bigint});\n\n            fn.read_some_rows(conn, st).validate_error(boost::asio::error::connection_reset);\n        }\n    }\n}\n\nBOOST_AUTO_TEST_CASE(net_error_void_signature)\n{\n    using netmaker_execute = netfun_maker<void, any_connection, const string_view&, results&>;\n    struct\n    {\n        const char* name;\n        netmaker_execute::signature execute;\n    } fns[] = {\n        {\"sync\",  netmaker_execute::sync_errc(&any_connection::execute)       },\n        {\"async\", netmaker_execute::async_diag(&any_connection::async_execute)},\n    };\n\n    for (const auto& fn : fns)\n    {\n        BOOST_TEST_CONTEXT(fn.name)\n        {\n            // Setup\n            io_context_fixture fix;\n            auto conn = create_test_any_connection(fix.ctx);\n            get_stream(conn).set_fail_count(fail_count(0, boost::asio::error::connection_reset));\n            results r;\n\n            fn.execute(conn, \"SELECT 1\", r).validate_error(boost::asio::error::connection_reset);\n        }\n    }\n}\n\n// empty pipelines complete immediately, posting adequately\nBOOST_FIXTURE_TEST_CASE(empty_pipeline, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    pipeline_request req;\n    std::vector<stage_response> res;\n\n    // Run it. It should complete immediately, posting to the correct executor (verified by the testing\n    // infrastructure)\n    conn.async_run_pipeline(req, res, as_netresult).validate_no_error();\n    BOOST_TEST(res.size() == 0u);\n    BOOST_MYSQL_ASSERT_BUFFER_EQUALS(get_stream(conn).bytes_written(), blob{});\n}\n\n// fatal errors in pipelines behave correctly\nBOOST_FIXTURE_TEST_CASE(pipeline_fatal_error, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    pipeline_request req;\n    std::vector<stage_response> res;\n    req.add_execute(\"SELECT 1\").add_execute(\"SELECT 2\");\n\n    // The first read will fail\n    get_stream(conn).set_fail_count(fail_count(1, boost::asio::error::network_reset));\n\n    // Run it\n    conn.async_run_pipeline(req, res, as_netresult).validate_error(boost::asio::error::network_reset);\n\n    // Validate the results\n    BOOST_TEST(res.size() == 2u);\n    BOOST_TEST(res[0].error() == boost::asio::error::network_reset);\n    BOOST_TEST(res[0].diag() == diagnostics());\n    BOOST_TEST(res[1].error() == boost::asio::error::network_reset);\n    BOOST_TEST(res[1].diag() == diagnostics());\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/spotchecks/multifn.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n// Since integration tests can't reliably test multifunction operations\n// that span over multiple messages, we test the complete multifn fllow in this unit tests.\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/execution_state.hpp>\n#include <boost/mysql/rows_view.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_unit/create_coldef_frame.hpp\"\n#include \"test_unit/create_frame.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n#include \"test_unit/test_stream.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_multifn)\n\nBOOST_FIXTURE_TEST_CASE(separate_batches, io_context_fixture)\n{\n    execution_state st;\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn)\n        .add_bytes(create_frame(1, {0x01}))\n        .add_break()\n        .add_bytes(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n        .add_break()\n        .add_bytes(create_text_row_message(3, \"abc\"))\n        .add_break()\n        .add_bytes(create_eof_frame(4, ok_builder().affected_rows(10u).info(\"1st\").more_results(true).build())\n        )\n        .add_break()\n        .add_bytes(create_frame(5, {0x01}))\n        .add_break()\n        .add_bytes(create_coldef_frame(6, meta_builder().type(column_type::decimal).build_coldef()))\n        .add_break()\n        .add_bytes(create_text_row_message(7, \"ab\"))\n        .add_bytes(create_text_row_message(8, \"plo\"))\n        .add_break()\n        .add_bytes(create_text_row_message(9, \"hju\"))\n        .add_bytes(create_eof_frame(10, ok_builder().affected_rows(30u).info(\"2nd\").build()));\n\n    // Start\n    conn.async_start_execution(\"SELECT 1\", st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    check_meta(st.meta(), {column_type::varchar});\n\n    // 1st resultset, row\n    auto rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    BOOST_TEST(rv == makerows(1, \"abc\"));\n\n    // 1st resultset, eof\n    rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(rv == makerows(1));\n    BOOST_TEST(st.affected_rows() == 10u);\n    BOOST_TEST(st.info() == \"1st\");\n\n    // 2nd resultset, head\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    check_meta(st.meta(), {column_type::decimal});\n\n    // 2nd resultset, row batch\n    rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    BOOST_TEST(rv == makerows(1, \"ab\", \"plo\"));\n\n    // 2nd resultset, last row & eof\n    rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(rv == makerows(1, \"hju\"));\n    BOOST_TEST(st.affected_rows() == 30u);\n    BOOST_TEST(st.info() == \"2nd\");\n}\n\n// The server sent us a single, big message with everything\nBOOST_FIXTURE_TEST_CASE(single_read, io_context_fixture)\n{\n    execution_state st;\n    any_connection_params params;\n    params.initial_buffer_size = 4096;\n    auto conn = create_test_any_connection(ctx, params);\n\n    get_stream(conn)\n        .add_bytes(create_frame(1, {0x01}))\n        .add_bytes(create_coldef_frame(2, meta_builder().type(column_type::varchar).build_coldef()))\n        .add_bytes(create_text_row_message(3, \"abc\"))\n        .add_bytes(create_eof_frame(4, ok_builder().affected_rows(10u).info(\"1st\").more_results(true).build())\n        )\n        .add_bytes(create_frame(5, {0x01}))\n        .add_bytes(create_coldef_frame(6, meta_builder().type(column_type::decimal).build_coldef()))\n        .add_bytes(create_text_row_message(7, \"ab\"))\n        .add_bytes(create_text_row_message(8, \"plo\"))\n        .add_bytes(create_text_row_message(9, \"hju\"))\n        .add_bytes(create_eof_frame(10, ok_builder().affected_rows(30u).info(\"2nd\").build()));\n\n    // Start\n    conn.async_start_execution(\"SELECT 1\", st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    check_meta(st.meta(), {column_type::varchar});\n\n    // First resultset\n    auto rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(rv == makerows(1, \"abc\"));\n    BOOST_TEST(st.affected_rows() == 10u);\n    BOOST_TEST(st.info() == \"1st\");\n\n    // 2nd resultset, head\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n    check_meta(st.meta(), {column_type::decimal});\n\n    // 2nd resultset\n    rv = conn.async_read_some_rows(st, as_netresult).get();\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(rv == makerows(1, \"ab\", \"plo\", \"hju\"));\n    BOOST_TEST(st.affected_rows() == 30u);\n    BOOST_TEST(st.info() == \"2nd\");\n}\n\nBOOST_FIXTURE_TEST_CASE(empty_resultsets, io_context_fixture)\n{\n    execution_state st;\n    any_connection_params params;\n    params.initial_buffer_size = 4096;\n    auto conn = create_test_any_connection(ctx, params);\n\n    get_stream(conn)\n        .add_bytes(create_ok_frame(1, ok_builder().affected_rows(10u).info(\"1st\").more_results(true).build()))\n        .add_bytes(create_ok_frame(2, ok_builder().affected_rows(20u).info(\"2nd\").more_results(true).build()))\n        .add_bytes(create_ok_frame(3, ok_builder().affected_rows(30u).info(\"3rd\").build()));\n\n    // Start\n    conn.async_start_execution(\"SELECT 1\", st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(st.meta().size() == 0u);\n    BOOST_TEST(st.affected_rows() == 10u);\n    BOOST_TEST(st.info() == \"1st\");\n\n    // 2nd resultset\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.should_read_head());\n    BOOST_TEST(st.meta().size() == 0u);\n    BOOST_TEST(st.affected_rows() == 20u);\n    BOOST_TEST(st.info() == \"2nd\");\n\n    // 3rd resultset\n    conn.async_read_resultset_head(st, as_netresult).validate_no_error();\n    BOOST_TEST_REQUIRE(st.complete());\n    BOOST_TEST(st.meta().size() == 0u);\n    BOOST_TEST(st.affected_rows() == 30u);\n    BOOST_TEST(st.info() == \"3rd\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/spotchecks/read_some_rows_static.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/any_connection.hpp>\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n\n#include <boost/core/span.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/network_result.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_row_message.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n#include \"test_unit/test_stream.hpp\"\n\nusing namespace boost::mysql::test;\nusing namespace boost::mysql;\nusing boost::span;\n\nBOOST_AUTO_TEST_SUITE(test_read_some_rows_static)\n\nusing row1 = std::tuple<int, float>;\nusing row2 = std::tuple<double>;\n\nusing state_t = static_execution_state<row1, row1, row2, row1, row2>;\n\nstruct fixture : io_context_fixture\n{\n    state_t st;\n    any_connection conn{\n        create_test_any_connection(ctx, {}, detail::connection_status::engaged_in_multi_function)\n    };\n    std::array<row1, 3> storage1;\n    std::array<row2, 3> storage2;\n\n    span<row1> storage1_span() { return storage1; }\n    span<row2> storage2_span() { return storage2; }\n\n    test_stream& stream() noexcept { return get_stream(conn); }\n\n    void add_ok() { ::add_ok(get_iface(st), ok_builder().more_results(true).build()); }\n\n    void add_meta_row1()\n    {\n        add_meta(\n            get_iface(st),\n            {\n                meta_builder().type(column_type::int_).nullable(false).build_coldef(),\n                meta_builder().type(column_type::float_).nullable(false).build_coldef(),\n            }\n        );\n    }\n\n    void add_meta_row2()\n    {\n        add_meta(\n            get_iface(st),\n            {\n                meta_builder().type(column_type::double_).nullable(false).build_coldef(),\n            }\n        );\n    }\n};\n\nBOOST_FIXTURE_TEST_CASE(repeated_row_types, fixture)\n{\n    add_meta_row1();\n\n    // 1st resultset: row1\n    stream().add_bytes(create_text_row_message(0, 10, 4.2f)).add_bytes(create_text_row_message(1, 11, 4.3f));\n\n    std::size_t num_rows = conn.async_read_some_rows(st, storage1_span(), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 2u);\n    BOOST_TEST((storage1[0] == row1{10, 4.2f}));\n    BOOST_TEST((storage1[1] == row1{11, 4.3f}));\n\n    // Advance resultset\n    add_ok();\n    add_meta_row1();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // 2nd resultset: row1 again\n    stream().add_bytes(create_text_row_message(2, 13, 0.2f));\n    num_rows = conn.async_read_some_rows(st, storage1_span(), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((storage1[0] == row1{13, 0.2f}));\n\n    // Advance resultset\n    add_ok();\n    add_meta_row2();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // 3rd resultset: row2\n    stream().add_bytes(create_text_row_message(3, 9.1));\n    num_rows = conn.async_read_some_rows(st, storage2_span(), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((storage2[0] == row2{9.1}));\n\n    // Advance resultset\n    add_ok();\n    add_meta_row1();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // 4th resultset: row1\n    stream().add_bytes(create_text_row_message(4, 43, 0.7f));\n    num_rows = conn.async_read_some_rows(st, storage1_span(), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((storage1[0] == row1{43, 0.7f}));\n\n    // Advance resultset\n    add_ok();\n    add_meta_row2();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // 5th resultset: row2\n    stream().add_bytes(create_text_row_message(5, 99.9));\n    num_rows = conn.async_read_some_rows(st, storage2_span(), as_netresult).get();\n    BOOST_TEST_REQUIRE(num_rows == 1u);\n    BOOST_TEST((storage2[0] == row2{99.9}));\n}\n\nBOOST_FIXTURE_TEST_CASE(error_row_type_mismatch_1, fixture)\n{\n    add_meta_row1();\n\n    // 1st resultset: row1\n    stream().add_bytes(create_text_row_message(0, 10, 4.2f));\n    conn.async_read_some_rows(st, storage2_span(), as_netresult)\n        .validate_error(client_errc::row_type_mismatch);\n}\n\nBOOST_FIXTURE_TEST_CASE(error_row_type_mismatch_2, fixture)\n{\n    // Advance resultset to the 3rd resultset\n    add_meta_row1();\n    add_ok();\n    add_meta_row1();\n    add_ok();\n    add_meta_row2();\n    BOOST_TEST_REQUIRE(st.should_read_rows());\n\n    // 3rd resultset: row2\n    stream().add_bytes(create_text_row_message(0, 9.1));\n    conn.async_read_some_rows(st, storage1_span(), as_netresult)\n        .validate_error(client_errc::row_type_mismatch);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/unit/test/statement.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/field_view.hpp>\n#include <boost/mysql/statement.hpp>\n\n#include <boost/test/unit_test.hpp>\n\n#include <tuple>\n\n#include \"test_common/create_basic.hpp\"\n#include \"test_unit/create_statement.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_statement)\n\nBOOST_AUTO_TEST_CASE(default_ctor)\n{\n    statement stmt;\n    BOOST_TEST(!stmt.valid());\n}\n\nBOOST_AUTO_TEST_CASE(member_fns)\n{\n    auto stmt = statement_builder().id(1).num_params(3).build();\n\n    BOOST_TEST(stmt.valid());\n    BOOST_TEST(stmt.num_params() == 3u);\n    BOOST_TEST(stmt.id() == 1u);\n}\n\nstatement create_valid_stmt() { return statement_builder().id(1).build(); }\n\nBOOST_AUTO_TEST_SUITE(bind_field_like)\nBOOST_AUTO_TEST_CASE(regular)\n{\n    std::string s(\"def\");\n    blob blb;\n    auto b = create_valid_stmt().bind(42, std::string(\"abc\"), std::ref(s), s, blb);\n    using tup_type = std::tuple<int, std::string, std::string&, std::string, blob>;\n    static_assert(std::is_same<decltype(b), bound_statement_tuple<tup_type>>::value, \"\");\n}\n\nBOOST_AUTO_TEST_CASE(empty)\n{\n    auto b = create_valid_stmt().bind();\n    static_assert(std::is_same<decltype(b), bound_statement_tuple<std::tuple<>>>::value, \"\");\n}\n\nBOOST_AUTO_TEST_CASE(stmt_const)\n{\n    const statement stmt = create_valid_stmt();\n    auto b = stmt.bind();  // compiles\n    static_assert(std::is_same<decltype(b), bound_statement_tuple<std::tuple<>>>::value, \"\");\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(bind_field_like_tuple)\nBOOST_AUTO_TEST_CASE(regular)\n{\n    auto b = create_valid_stmt().bind(std::make_tuple(42, 4.2f));\n    using expected_type = bound_statement_tuple<std::tuple<int, float>>;\n    static_assert(std::is_same<decltype(b), expected_type>::value, \"\");\n}\n\nBOOST_AUTO_TEST_CASE(tuple_const_reference)\n{\n    const auto params = std::make_tuple(42, 4.2f);\n    auto b = create_valid_stmt().bind(params);\n    using expected_type = bound_statement_tuple<std::tuple<int, float>>;\n    static_assert(std::is_same<decltype(b), expected_type>::value, \"\");\n}\n\nBOOST_AUTO_TEST_CASE(tuple_reference)\n{\n    auto params = std::make_tuple(42, 4.2f);\n    auto b = create_valid_stmt().bind(params);\n    using expected_type = bound_statement_tuple<std::tuple<int, float>>;\n    static_assert(std::is_same<decltype(b), expected_type>::value, \"\");\n}\n\nBOOST_AUTO_TEST_CASE(stmt_const)\n{\n    const statement stmt = create_valid_stmt();\n    auto b = stmt.bind(std::make_tuple(42));  // compiles\n    using expected_type = bound_statement_tuple<std::tuple<int>>;\n    static_assert(std::is_same<decltype(b), expected_type>::value, \"\");\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE(bind_iterator_range)\nBOOST_AUTO_TEST_CASE(regular)\n{\n    auto fvs = make_fv_arr(42, \"abc\");\n    auto b = create_valid_stmt().bind(fvs.begin(), fvs.end());\n    using expected_type = bound_statement_iterator_range<std::array<field_view, 2>::iterator>;\n    static_assert(std::is_same<decltype(b), expected_type>::value, \"\");\n}\n\nBOOST_AUTO_TEST_CASE(stmt_const)\n{\n    const statement stmt = create_valid_stmt();\n    auto fvs = make_fv_arr(42, \"abc\");\n    auto b = stmt.bind(fvs.begin(), fvs.end());  // compiles\n    using expected_type = bound_statement_iterator_range<std::array<field_view, 2>::iterator>;\n    static_assert(std::is_same<decltype(b), expected_type>::value, \"\");\n}\nBOOST_AUTO_TEST_SUITE_END()\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/static_execution_state.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/static_execution_state.hpp>\n\n#include <boost/describe/class.hpp>\n#include <boost/describe/operators.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_static_execution_state)\n\nstruct row1\n{\n    std::string f1;\n    float f2;\n};\nBOOST_DESCRIBE_STRUCT(row1, (), (f1, f2))\n\nusing boost::describe::operators::operator==;\nusing boost::describe::operators::operator<<;\n\nusing row2 = std::tuple<double>;\nusing empty = std::tuple<>;\n\nusing execst_t = static_execution_state<row1, row2, empty>;\n\n// The functionality has been tested in static_execution_state_impl already.\n// Just spotchecks here\nBOOST_AUTO_TEST_CASE(spotchecks)\n{\n    execst_t st;\n    auto& impl = get_iface(st);\n    diagnostics diag;\n\n    // Initial\n    BOOST_TEST(st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    BOOST_TEST(st.meta().size() == 0u);\n\n    // Meta\n    add_meta(\n        impl,\n        {\n            meta_builder().type(column_type::varchar).nullable(false).name(\"f1\").build_coldef(),\n            meta_builder().type(column_type::float_).nullable(false).name(\"f2\").build_coldef(),\n        }\n    );\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::varchar, column_type::float_});\n\n    // First resultset OK\n    add_ok(\n        impl,\n        ok_builder()\n            .affected_rows(1)\n            .last_insert_id(2)\n            .warnings(4)\n            .info(\"abc\")\n            .more_results(true)\n            .out_params(true)\n            .build()\n    );\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::varchar, column_type::float_});\n    BOOST_TEST(st.affected_rows() == 1u);\n    BOOST_TEST(st.last_insert_id() == 2u);\n    BOOST_TEST(st.warning_count() == 4u);\n    BOOST_TEST(st.info() == \"abc\");\n    BOOST_TEST(st.is_out_params());\n\n    // Second resultset meta\n    add_meta(impl, {meta_builder().type(column_type::double_).nullable(false).build_coldef()});\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::double_});\n\n    // Second resultset OK\n    add_ok(\n        impl,\n        ok_builder().affected_rows(4).last_insert_id(5).warnings(6).info(\"2nd\").more_results(true).build()\n    );\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(!st.complete());\n    check_meta(st.meta(), {column_type::double_});\n    BOOST_TEST(st.affected_rows() == 4u);\n    BOOST_TEST(st.last_insert_id() == 5u);\n    BOOST_TEST(st.warning_count() == 6u);\n    BOOST_TEST(st.info() == \"2nd\");\n    BOOST_TEST(!st.is_out_params());\n\n    // Third, empty resultset\n    add_ok(impl, ok_builder().info(\"3rd\").build());\n    BOOST_TEST(!st.should_start_op());\n    BOOST_TEST(!st.should_read_head());\n    BOOST_TEST(!st.should_read_rows());\n    BOOST_TEST(st.complete());\n    BOOST_TEST(st.meta().empty());\n    BOOST_TEST(st.affected_rows() == 0u);\n    BOOST_TEST(st.last_insert_id() == 0u);\n    BOOST_TEST(st.warning_count() == 0u);\n    BOOST_TEST(st.info() == \"3rd\");\n    BOOST_TEST(!st.is_out_params());\n}\n\nstd::unique_ptr<execst_t> create_heap_state()\n{\n    std::unique_ptr<execst_t> res{new execst_t};\n    add_meta(\n        get_iface(*res),\n        {\n            meta_builder().type(column_type::varchar).nullable(false).name(\"f1\").build_coldef(),\n            meta_builder().type(column_type::float_).nullable(false).name(\"f2\").build_coldef(),\n        }\n    );\n    add_ok(\n        get_iface(*res),\n        ok_builder().affected_rows(1).last_insert_id(2).warnings(4).info(\"1st\").more_results(true).build()\n    );\n    return res;\n}\n\n// Verify that the lifetime guarantees we make are correct\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Having this in heap helps detect lifetime issues\n    auto st = create_heap_state();\n\n    // Obtain references\n    auto meta = st->meta();\n    auto info = st->info();\n\n    // Move construct\n    execst_t st2(std::move(*st));\n    st.reset();\n\n    // Make sure that views are still valid\n    check_meta(meta, {column_type::varchar, column_type::float_});\n    BOOST_TEST(info == \"1st\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(st2.should_read_head());\n    check_meta(st2.meta(), {column_type::varchar, column_type::float_});\n    BOOST_TEST(st2.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assignment)\n{\n    // Having this in heap helps detect lifetime issues\n    auto st = create_heap_state();\n\n    // Obtain references\n    auto meta = st->meta();\n    auto info = st->info();\n\n    // Move assign\n    execst_t st2;\n    st2 = std::move(*st);\n    st.reset();\n\n    // Make sure that views are still valid\n    check_meta(meta, {column_type::varchar, column_type::float_});\n    BOOST_TEST(info == \"1st\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(st2.should_read_head());\n    check_meta(st2.meta(), {column_type::varchar, column_type::float_});\n    BOOST_TEST(st2.info() == \"1st\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/unit/test/static_results.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifdef BOOST_MYSQL_CXX14\n\n#include <boost/mysql/column_type.hpp>\n#include <boost/mysql/static_results.hpp>\n\n#include <boost/describe/class.hpp>\n#include <boost/describe/operators.hpp>\n\n#include <tuple>\n\n#include \"test_common/check_meta.hpp\"\n#include \"test_unit/create_execution_processor.hpp\"\n#include \"test_unit/create_meta.hpp\"\n#include \"test_unit/create_ok.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_static_results)\n\nstruct row1\n{\n    std::string f1;\n    float f2;\n};\nBOOST_DESCRIBE_STRUCT(row1, (), (f1, f2))\n\nusing boost::describe::operators::operator==;\nusing boost::describe::operators::operator<<;\n\nusing row2 = std::tuple<double>;\nusing empty = std::tuple<>;\n\nusing results_t = static_results<row1, row2, empty>;\n\nresults_t create_initial_results()\n{\n    results_t res;\n    exec_access(get_iface(res))\n        .meta({\n            meta_builder().type(column_type::varchar).nullable(false).name(\"f1\").build_coldef(),\n            meta_builder().type(column_type::float_).nullable(false).name(\"f2\").build_coldef(),\n        })\n        .row(\"abc\", 10.1f)\n        .row(\"def\", 20.0f)\n        .ok(ok_builder().affected_rows(1).last_insert_id(2).warnings(3).info(\"1st\").more_results(true).build()\n        )\n        .meta({meta_builder().type(column_type::double_).nullable(false).build_coldef()})\n        .row(42.0)\n        .ok(ok_builder().affected_rows(4).last_insert_id(5).warnings(6).info(\"2nd\").more_results(true).build()\n        )\n        .ok(ok_builder().info(\"3rd\").build());\n    return res;\n}\n\nstd::unique_ptr<results_t> create_heap_results()\n{\n    return std::unique_ptr<results_t>(new results_t(create_initial_results()));\n}\n\nBOOST_AUTO_TEST_CASE(has_value)\n{\n    // Default construction\n    results_t result;\n    BOOST_TEST_REQUIRE(!result.has_value());\n\n    // With value\n    result = create_initial_results();\n    BOOST_TEST_REQUIRE(result.has_value());\n}\n\nBOOST_AUTO_TEST_CASE(accessors)\n{\n    auto result = create_initial_results();\n\n    // Rows\n    BOOST_TEST_REQUIRE(result.rows<0>().size() == 2u);\n    BOOST_TEST((result.rows<0>()[0] == row1{\"abc\", 10.1f}));\n    BOOST_TEST((result.rows<0>()[1] == row1{\"def\", 20.0f}));\n    BOOST_TEST_REQUIRE(result.rows<1>().size() == 1u);\n    BOOST_TEST((result.rows<1>()[0] == row2{42.0}));\n    BOOST_TEST((result.rows<2>().size() == 0u));\n\n    // Meta\n    check_meta(result.meta<0>(), {column_type::varchar, column_type::float_});\n    check_meta(result.meta<1>(), {column_type::double_});\n    BOOST_TEST(result.meta<2>().empty());\n\n    // OK packet data\n    BOOST_TEST(result.affected_rows<0>() == 1u);\n    BOOST_TEST(result.last_insert_id<0>() == 2u);\n    BOOST_TEST(result.warning_count<0>() == 3u);\n    BOOST_TEST(result.info<0>() == \"1st\");\n    BOOST_TEST(result.affected_rows<1>() == 4u);\n    BOOST_TEST(result.last_insert_id<1>() == 5u);\n    BOOST_TEST(result.warning_count<1>() == 6u);\n    BOOST_TEST(result.info<1>() == \"2nd\");\n    BOOST_TEST(result.affected_rows<2>() == 0u);\n    BOOST_TEST(result.last_insert_id<2>() == 0u);\n    BOOST_TEST(result.warning_count<2>() == 0u);\n    BOOST_TEST(result.info<2>() == \"3rd\");\n}\n\n// Verify view validity\nBOOST_AUTO_TEST_CASE(move_constructor)\n{\n    // Having this in heap makes easier to spot lifetime problems\n    auto result = create_heap_results();\n\n    // Obtain references\n    auto rws0 = result->rows<0>();\n    auto rws1 = result->rows<1>();\n    auto meta0 = result->meta<0>();\n    auto meta1 = result->meta<1>();\n    auto info0 = result->info<0>();\n    auto info1 = result->info<1>();\n\n    // Move construct\n    results_t result2(std::move(*result));\n    result.reset();\n\n    // Make sure that views are still valid\n    BOOST_TEST((rws0[0] == row1{\"abc\", 10.1f}));\n    BOOST_TEST((rws0[1] == row1{\"def\", 20.0f}));\n    BOOST_TEST((rws1[0] == row2{42.0}));\n    check_meta(meta0, {column_type::varchar, column_type::float_});\n    check_meta(meta1, {column_type::double_});\n    BOOST_TEST(info0 == \"1st\");\n    BOOST_TEST(info1 == \"2nd\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(result2.has_value());\n    BOOST_TEST((result2.rows<0>()[0] == row1{\"abc\", 10.1f}));\n    check_meta(result2.meta<0>(), {column_type::varchar, column_type::float_});\n    BOOST_TEST(result2.info<0>() == \"1st\");\n}\n\nBOOST_AUTO_TEST_CASE(move_assignment)\n{\n    // Having this in heap makes easier to spot lifetime problems\n    auto result = create_heap_results();\n\n    // Obtain references\n    auto rws0 = result->rows<0>();\n    auto rws1 = result->rows<1>();\n    auto meta0 = result->meta<0>();\n    auto meta1 = result->meta<1>();\n    auto info0 = result->info<0>();\n    auto info1 = result->info<1>();\n\n    // Move construct\n    results_t result2;\n    result2 = std::move(*result);\n    result.reset();\n\n    // Make sure that views are still valid\n    BOOST_TEST((rws0[0] == row1{\"abc\", 10.1f}));\n    BOOST_TEST((rws0[1] == row1{\"def\", 20.0f}));\n    BOOST_TEST((rws1[0] == row2{42.0}));\n    check_meta(meta0, {column_type::varchar, column_type::float_});\n    check_meta(meta1, {column_type::double_});\n    BOOST_TEST(info0 == \"1st\");\n    BOOST_TEST(info1 == \"2nd\");\n\n    // The new object holds the same data\n    BOOST_TEST_REQUIRE(result2.has_value());\n    BOOST_TEST((result2.rows<0>()[0] == row1{\"abc\", 10.1f}));\n    check_meta(result2.meta<0>(), {column_type::varchar, column_type::float_});\n    BOOST_TEST(result2.info<0>() == \"1st\");\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n\n#endif\n"
  },
  {
    "path": "test/unit/test/throw_on_error.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/client_errc.hpp>\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/throw_on_error.hpp>\n\n#include <boost/system/system_error.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/printing.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\n\nBOOST_AUTO_TEST_SUITE(test_throw_on_error)\n\nBOOST_AUTO_TEST_CASE(success)\n{\n    error_code ec;\n    auto diag = create_server_diag(\"abc\");\n    BOOST_CHECK_NO_THROW(throw_on_error(ec, diag));\n}\n\nBOOST_AUTO_TEST_CASE(server_failure)\n{\n    error_code ec(boost::mysql::common_server_errc::er_bad_db_error);\n    auto diag = create_server_diag(\"abc\");\n    BOOST_CHECK_EXCEPTION(\n        throw_on_error(ec, diag),\n        error_with_diagnostics,\n        [&](const error_with_diagnostics& err) {\n            BOOST_TEST(err.what() == string_view(\"er_bad_db_error [mysql.common-server:1049]\"));\n            BOOST_TEST(err.code() == ec);\n            BOOST_TEST(err.get_diagnostics() == diag);\n            return true;\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE(client_failure)\n{\n    error_code ec(boost::mysql::client_errc::incomplete_message);\n    auto diag = create_client_diag(\"abc\");\n    BOOST_CHECK_EXCEPTION(\n        throw_on_error(ec, diag),\n        error_with_diagnostics,\n        [&](const error_with_diagnostics& err) {\n            BOOST_TEST(\n                err.what() ==\n                string_view(\"abc: An incomplete message was received from the server [mysql.client:1]\")\n            );\n            BOOST_TEST(err.code() == ec);\n            BOOST_TEST(err.get_diagnostics() == diag);\n            return true;\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE(client_failure_no_message)\n{\n    error_code ec(boost::mysql::client_errc::incomplete_message);\n    BOOST_CHECK_EXCEPTION(\n        throw_on_error(ec, diagnostics()),\n        error_with_diagnostics,\n        [&](const error_with_diagnostics& err) {\n            BOOST_TEST(\n                err.what() ==\n                string_view(\"An incomplete message was received from the server [mysql.client:1]\")\n            );\n            BOOST_TEST(err.code() == ec);\n            BOOST_TEST(err.get_diagnostics() == diagnostics());\n            return true;\n        }\n    );\n}\n\nBOOST_AUTO_TEST_CASE(no_diagnostics)\n{\n    error_code ec(boost::mysql::client_errc::incomplete_message);\n    BOOST_CHECK_EXCEPTION(throw_on_error(ec), error_with_diagnostics, [&](const error_with_diagnostics& err) {\n        BOOST_TEST(\n            err.what() == string_view(\"An incomplete message was received from the server [mysql.client:1]\")\n        );\n        BOOST_TEST(err.code() == ec);\n        BOOST_TEST(err.get_diagnostics() == diagnostics());\n        return true;\n    });\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test/with_diagnostics.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#include <boost/mysql/common_server_errc.hpp>\n#include <boost/mysql/diagnostics.hpp>\n#include <boost/mysql/error_code.hpp>\n#include <boost/mysql/error_with_diagnostics.hpp>\n#include <boost/mysql/results.hpp>\n#include <boost/mysql/with_diagnostics.hpp>\n\n#include <boost/asio/async_result.hpp>\n#include <boost/asio/bind_executor.hpp>\n#include <boost/asio/cancel_after.hpp>\n#include <boost/asio/consign.hpp>\n#include <boost/core/ignore_unused.hpp>\n#include <boost/test/unit_test.hpp>\n\n#include <exception>\n#include <memory>\n#include <type_traits>\n\n#include \"test_common/create_diagnostics.hpp\"\n#include \"test_common/io_context_fixture.hpp\"\n#include \"test_common/poll_until.hpp\"\n#include \"test_common/printing.hpp\"\n#include \"test_common/tracker_executor.hpp\"\n#include \"test_unit/create_err.hpp\"\n#include \"test_unit/create_ok.hpp\"\n#include \"test_unit/create_ok_frame.hpp\"\n#include \"test_unit/test_any_connection.hpp\"\n\nusing namespace boost::mysql;\nusing namespace boost::mysql::test;\nnamespace asio = boost::asio;\n\nBOOST_AUTO_TEST_SUITE(test_with_diagnostics)\n\n// Validate that an exception_ptr contains the expected values\nvoid check_exception(std::exception_ptr exc, error_code expected_ec, const diagnostics& expected_diag)\n{\n    BOOST_CHECK_EXCEPTION(\n        std::rethrow_exception(exc),\n        error_with_diagnostics,\n        [&](const error_with_diagnostics& e) {\n            BOOST_TEST(e.code() == expected_ec);\n            BOOST_TEST(e.get_diagnostics() == expected_diag);\n            return true;\n        }\n    );\n}\n\nBOOST_FIXTURE_TEST_CASE(success, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    bool called = false;\n\n    // Execute\n    conn.async_reset_connection(with_diagnostics([&](std::exception_ptr exc) {\n        called = true;\n        BOOST_TEST((exc == nullptr));\n    }));\n    poll_until(ctx, &called);\n}\n\nBOOST_FIXTURE_TEST_CASE(error, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(err_builder()\n                                   .code(common_server_errc::er_no_such_user)\n                                   .message(\"Invalid user\")\n                                   .seqnum(1)\n                                   .build_frame());\n    bool called = false;\n\n    // Execute\n    conn.async_reset_connection(with_diagnostics([&](std::exception_ptr exc) {\n        called = true;\n        check_exception(exc, common_server_errc::er_no_such_user, create_server_diag(\"Invalid user\"));\n    }));\n    poll_until(ctx, &called);\n}\n\nstruct nulldiag_initiation\n{\n    template <class Handler>\n    void operator()(Handler&& handler, diagnostics* diag)\n    {\n        // with_diagnostics should have allocated a diagnostics object for us\n        BOOST_TEST_REQUIRE(diag != nullptr);\n\n        // set diagnostics\n        *diag = create_server_diag(\"Invalid user\");\n\n        // call the handler\n        std::move(handler)(common_server_errc::er_no_such_user);\n    }\n};\n\ntemplate <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code)) CompletionToken>\nvoid async_nulldiag(CompletionToken&& token)\n{\n    diagnostics* diag = nullptr;\n    asio::async_initiate<CompletionToken, void(error_code)>(nulldiag_initiation{}, token, diag);\n}\n\nBOOST_AUTO_TEST_CASE(diagnostics_null)\n{\n    // Setup\n    bool called = false;\n\n    // Execute\n    async_nulldiag(with_diagnostics([&](std::exception_ptr exc) {\n        called = true;\n        check_exception(exc, common_server_errc::er_no_such_user, create_server_diag(\"Invalid user\"));\n    }));\n\n    // Sanity check\n    BOOST_TEST(called);\n}\n\nBOOST_FIXTURE_TEST_CASE(associated_properties, io_context_fixture)\n{\n    // Uses intermediate_handler internally, so we just perform a sanity check here\n    // Setup\n    auto ex_result = create_tracker_executor(ctx.get_executor());\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(err_builder()\n                                   .code(common_server_errc::er_no_such_user)\n                                   .message(\"Invalid user\")\n                                   .seqnum(1)\n                                   .build_frame());\n    bool called = false;\n    auto check_fn = [&](std::exception_ptr exc) {\n        called = true;\n        const int expected_stack[] = {ex_result.executor_id};\n        BOOST_TEST(executor_stack() == expected_stack, boost::test_tools::per_element());\n        check_exception(exc, common_server_errc::er_no_such_user, create_server_diag(\"Invalid user\"));\n    };\n\n    // Call the op\n    conn.async_reset_connection(with_diagnostics(asio::bind_executor(ex_result.ex, check_fn)));\n    poll_until(ctx, &called);\n}\n\n// We correctly forward initiation args\nstruct test_initiation\n{\n    template <class Handler, class T1, class T2, class T3>\n    void operator()(Handler&& handler, T1&& arg1, T2&& arg2, T3&& arg3, diagnostics*)\n    {\n        // T1 should be a non-const lvalue\n        static_assert(std::is_same<T1, std::shared_ptr<int>&>::value, \"\");\n        BOOST_TEST(arg1 != nullptr);\n\n        // T2 should be a const lvalue\n        static_assert(std::is_same<T2, const std::shared_ptr<int>&>::value, \"\");\n        BOOST_TEST(arg2 != nullptr);\n\n        // T3 should be a rvalue\n        static_assert(std::is_same<T3, std::shared_ptr<int>>::value, \"\");\n        BOOST_TEST(arg3 != nullptr);\n        auto arg3_move = std::move(arg3);\n        boost::ignore_unused(arg3_move);\n\n        // Just call the handler\n        std::move(handler)(error_code());\n    }\n};\n\ntemplate <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code)) CompletionToken>\nvoid async_test(\n    std::shared_ptr<int>& arg1,\n    const std::shared_ptr<int>& arg2,\n    std::shared_ptr<int>&& arg3,\n    diagnostics& diag,\n    CompletionToken&& token\n)\n{\n    asio::async_initiate<CompletionToken, void(error_code)>(\n        test_initiation{},\n        token,\n        arg1,\n        arg2,\n        std::move(arg3),\n        &diag\n    );\n}\n\nBOOST_AUTO_TEST_CASE(initiation_args_forwarding)\n{\n    // Setup\n    auto arg1 = std::make_shared<int>(42);\n    auto arg2 = arg1;\n    auto arg3 = arg1;\n    bool called = false;\n    auto handler = [&](std::exception_ptr) { called = true; };\n    diagnostics diag;\n\n    // Call the operation\n    async_test(arg1, arg2, std::move(arg3), diag, with_diagnostics(handler));\n\n    // lvalues not moved, rvalue moved\n    BOOST_TEST(arg1 != nullptr);\n    BOOST_TEST(arg2 != nullptr);\n    BOOST_TEST(arg3 == nullptr);\n}\n\n// Works fine if the token is a lvalue\nBOOST_FIXTURE_TEST_CASE(token_lvalue, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    bool called = false;\n    auto token = with_diagnostics([&](std::exception_ptr) { called = true; });\n\n    // Call the op\n    conn.async_reset_connection(token);\n    poll_until(ctx, &called);\n}\n\nBOOST_FIXTURE_TEST_CASE(token_const_lvalue, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    bool called = false;\n    const auto token = with_diagnostics([&](std::exception_ptr) { called = true; });\n\n    // Call the op\n    conn.async_reset_connection(token);\n    poll_until(ctx, &called);\n}\n\n// with_diagnostics' initiation has the same executor as the initiation that gets passed,\n// and thus with_diagnostics(asio::cancel_after(...)) works\nBOOST_FIXTURE_TEST_CASE(initiation_propagates_executor, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(create_ok_frame(1, ok_builder().build()));\n    bool called = false;\n    const auto cb = [&](std::exception_ptr) { called = true; };\n\n    // Call the op\n    conn.async_reset_connection(with_diagnostics(asio::cancel_after(std::chrono::seconds(1), cb)));\n    poll_until(ctx, &called);\n}\n\n// Edge case: if a diagnostics* gets passed as an argument\n// to consign(), we don't mess things up\nBOOST_FIXTURE_TEST_CASE(several_diagnostics_args, io_context_fixture)\n{\n    // Setup\n    auto conn = create_test_any_connection(ctx);\n    get_stream(conn).add_bytes(err_builder()\n                                   .code(common_server_errc::er_no_such_user)\n                                   .message(\"Invalid user\")\n                                   .seqnum(1)\n                                   .build_frame());\n    diagnostics other_diag;\n    bool called = false;\n\n    // Execute\n    conn.async_reset_connection(asio::consign(\n        with_diagnostics([&](std::exception_ptr exc) {\n            called = true;\n            check_exception(exc, common_server_errc::er_no_such_user, create_server_diag(\"Invalid user\"));\n        }),\n        &other_diag\n    ));\n    poll_until(ctx, &called);\n\n    // Unmodified\n    BOOST_TEST(other_diag == diagnostics());\n}\n\n// with_diagnostics decays correctly\nstruct test_fn\n{\n    void operator()(error_code) {}\n};\nstatic_assert(\n    std::is_same<decltype(with_diagnostics(std::declval<test_fn>())), with_diagnostics_t<test_fn>>::value,\n    \"\"\n);\nstatic_assert(\n    std::is_same<decltype(with_diagnostics(std::declval<test_fn&>())), with_diagnostics_t<test_fn>>::value,\n    \"\"\n);\nstatic_assert(\n    std::is_same<decltype(with_diagnostics(std::declval<const test_fn&>())), with_diagnostics_t<test_fn>>::\n        value,\n    \"\"\n);\nstatic_assert(\n    std::is_same<decltype(with_diagnostics(std::declval<test_fn&&>())), with_diagnostics_t<test_fn>>::value,\n    \"\"\n);\n\n// Applying with_diagnostics to an unknown signature is a pass-through\nstruct no_ec_initiation\n{\n    template <class Handler, class T1, class T2, class T3>\n    void operator()(Handler&& handler, T1&& arg1, T2&& arg2, T3&& arg3)\n    {\n        // T1 should be a non-const lvalue\n        static_assert(std::is_same<T1, std::shared_ptr<int>&>::value, \"\");\n        BOOST_TEST(arg1 != nullptr);\n\n        // T2 should be a const lvalue\n        static_assert(std::is_same<T2, const std::shared_ptr<int>&>::value, \"\");\n        BOOST_TEST(arg2 != nullptr);\n\n        // T3 should be a rvalue\n        static_assert(std::is_same<T3, std::shared_ptr<int>>::value, \"\");\n        BOOST_TEST(arg3 != nullptr);\n        auto arg3_move = std::move(arg3);\n        boost::ignore_unused(arg3_move);\n\n        // Just call the handler\n        std::move(handler)(42);\n    }\n};\n\ntemplate <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(int)) CompletionToken>\nvoid async_no_ec(\n    std::shared_ptr<int>& arg1,\n    const std::shared_ptr<int>& arg2,\n    std::shared_ptr<int>&& arg3,\n    CompletionToken&& token\n)\n{\n    asio::async_initiate<CompletionToken, void(int)>(no_ec_initiation{}, token, arg1, arg2, std::move(arg3));\n}\n\nBOOST_AUTO_TEST_CASE(signature_no_ec)\n{\n    // Setup\n    auto arg1 = std::make_shared<int>(42);\n    auto arg2 = arg1;\n    auto arg3 = arg1;\n    bool called = false;\n    auto handler = [&](int val) {\n        BOOST_TEST(val == 42);\n        called = true;\n    };\n\n    // Call the operation\n    async_no_ec(arg1, arg2, std::move(arg3), with_diagnostics(handler));\n\n    // lvalues not moved, rvalue moved\n    BOOST_TEST(arg1 != nullptr);\n    BOOST_TEST(arg2 != nullptr);\n    BOOST_TEST(arg3 == nullptr);\n}\n\nBOOST_AUTO_TEST_SUITE_END()\n"
  },
  {
    "path": "test/unit/test_csha2p_encrypt_password_errors.cpp",
    "content": "//\n// Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n\n#define BOOST_TEST_MODULE test_csha2p_encrypt_password_errors\n\n#include <boost/mysql/impl/internal/sansio/csha2p_encrypt_password.hpp>\n\n#include <boost/container/small_vector.hpp>\n#include <boost/system/error_category.hpp>\n#include <boost/test/unit_test.hpp>\n#include <boost/test/unit_test_suite.hpp>\n\n#include <cstdint>\n#include <string>\n\nusing namespace boost::mysql;\nusing detail::csha2p_encrypt_password;\n\n// Contains tests that need mocking OpenSSL functions.\n// We do this at link time, by defining the functions declared in OpenSSL headers here\n// and not linking to libssl/libcrypto.\n// These tests cover cases that can't be covered directly by the unit tests using the real OpenSSL.\n// Try to put as few tests here as possible.\n// Some of the mocked functions are macros in OpenSSL versions before 3, so this setup can't work\n\n#if OPENSSL_VERSION_NUMBER >= 0x30000000L\n\nnamespace {\n\n// If we use asio::error::ssl_category, many more other OpenSSL functions\n// become used, and mocking becomes problematic.\nclass mock_ssl_category final : public boost::system::error_category\n{\npublic:\n    const char* name() const noexcept override { return \"mock_ssl\"; }\n    std::string message(int) const override { return {}; }\n} ssl_category;\n\nconstexpr std::uint8_t scramble[20]{};\n\nusing vector_type = boost::container::small_vector<std::uint8_t, 512>;\n\nstruct\n{\n    // Number of times that each function has been called.\n    // Tracking this helps us to check that we're actually covering the case we want\n    std::size_t BIO_new_mem_buf_calls{};\n    std::size_t PEM_read_bio_PUBKEY_calls{};\n    std::size_t EVP_PKEY_CTX_new_calls{};\n    std::size_t EVP_PKEY_encrypt_init_calls{};\n    std::size_t EVP_PKEY_CTX_set_rsa_padding_calls{};\n    std::size_t EVP_PKEY_get_size_calls{};\n    std::size_t EVP_PKEY_encrypt_calls{};\n\n    BIO* bio{reinterpret_cast<BIO*>(static_cast<std::uintptr_t>(100))};\n    EVP_PKEY* key{reinterpret_cast<EVP_PKEY*>(static_cast<std::uintptr_t>(200))};\n    EVP_PKEY_CTX* ctx{reinterpret_cast<EVP_PKEY_CTX*>(static_cast<std::uintptr_t>(300))};\n    int set_rsa_padding_result{1};\n    int get_size_result{256};\n    std::size_t actual_ciphertext_size{256u};\n    unsigned long last_error{0u};\n\n} openssl_mock;\n\nBOOST_AUTO_TEST_CASE(error_creating_bio)\n{\n    // Setup\n    openssl_mock = {};\n    openssl_mock.bio = nullptr;\n    openssl_mock.last_error = 42u;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec == error_code(42, ssl_category));\n    BOOST_TEST(ec.has_location());\n    BOOST_TEST(openssl_mock.BIO_new_mem_buf_calls == 1u);\n    BOOST_TEST(openssl_mock.PEM_read_bio_PUBKEY_calls == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(error_creating_pkey_ctx)\n{\n    // Setup\n    openssl_mock = {};\n    openssl_mock.ctx = nullptr;\n    openssl_mock.last_error = 42u;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec == error_code(42, ssl_category));\n    BOOST_TEST(ec.has_location());\n    BOOST_TEST(openssl_mock.EVP_PKEY_CTX_new_calls == 1u);\n    BOOST_TEST(openssl_mock.EVP_PKEY_encrypt_init_calls == 0u);\n}\n\nBOOST_AUTO_TEST_CASE(error_setting_rsa_padding)\n{\n    // Setup. The return value should be != -2, which indicates\n    // operation not supported and is handled separately\n    openssl_mock = {};\n    openssl_mock.set_rsa_padding_result = -1;\n    openssl_mock.last_error = 42u;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec == error_code(42, ssl_category));\n    BOOST_TEST(ec.has_location());\n    BOOST_TEST(openssl_mock.EVP_PKEY_CTX_set_rsa_padding_calls == 1u);\n    BOOST_TEST(openssl_mock.EVP_PKEY_encrypt_calls == 0u);\n}\n\n// Getting a zero size as max buffer size might happen in theory (although it shouldn't for RSA)\nBOOST_AUTO_TEST_CASE(get_size_zero)\n{\n    // Setup\n    openssl_mock = {};\n    openssl_mock.get_size_result = 0;\n    openssl_mock.last_error = 42u;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec == error_code(42, ssl_category));\n    BOOST_TEST(ec.has_location());\n    BOOST_TEST(openssl_mock.EVP_PKEY_get_size_calls == 1u);\n    BOOST_TEST(openssl_mock.EVP_PKEY_encrypt_calls == 0u);\n}\n\n// In theory, the encryption function may communicate that it didn't use all the bytes\n// in the buffer. This shouldn't happen in RSA, but we handle the case anyway\nBOOST_AUTO_TEST_CASE(encrypt_actual_size_lt_max_size)\n{\n    // Setup\n    openssl_mock = {};\n    openssl_mock.get_size_result = 256;\n    openssl_mock.actual_ciphertext_size = 200u;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec == error_code());\n    BOOST_TEST(out.size() == 200u);\n}\n\n// OpenSSL functions might fail without adding an error to the stack.\n// If that's the case, the operation must still fail\nBOOST_AUTO_TEST_CASE(error_code_zero)\n{\n    // Setup. The return value should be != -2, which indicates\n    // operation not supported and is handled separately\n    openssl_mock = {};\n    openssl_mock.set_rsa_padding_result = -1;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec == error_code(client_errc::unknown_openssl_error));\n    BOOST_TEST(ec.has_location());\n    BOOST_TEST(openssl_mock.EVP_PKEY_CTX_set_rsa_padding_calls == 1u);\n    BOOST_TEST(openssl_mock.EVP_PKEY_encrypt_calls == 0u);\n}\n\n// OpenSSL 3+ might report system errors represented as codes > 0x80000000\nBOOST_AUTO_TEST_CASE(error_code_system)\n{\n    // Setup. The return value should be != -2, which indicates\n    // operation not supported and is handled separately\n    openssl_mock = {};\n    openssl_mock.set_rsa_padding_result = -1;\n    openssl_mock.last_error = 0x800000ab;\n    vector_type out;\n\n    // Call the function\n    auto ec = csha2p_encrypt_password(\"passwd\", scramble, {}, out, ssl_category);\n\n    // Check\n    BOOST_TEST(ec.failed());\n    BOOST_TEST(ec.has_location());\n    BOOST_TEST((ec.category() == boost::system::system_category()));\n    BOOST_TEST(openssl_mock.EVP_PKEY_CTX_set_rsa_padding_calls == 1u);\n    BOOST_TEST(openssl_mock.EVP_PKEY_encrypt_calls == 0u);\n}\n\n}  // namespace\n\n// Implement the OpenSSL functions\nBIO* BIO_new_mem_buf(const void*, int)\n{\n    ++openssl_mock.BIO_new_mem_buf_calls;\n    return openssl_mock.bio;\n}\nint BIO_free(BIO*) { return 0; }\n\nEVP_PKEY* PEM_read_bio_PUBKEY(BIO* bio, EVP_PKEY**, pem_password_cb*, void*)\n{\n    ++openssl_mock.PEM_read_bio_PUBKEY_calls;\n    BOOST_TEST(bio == openssl_mock.bio);\n    return openssl_mock.key;\n}\nvoid EVP_PKEY_free(EVP_PKEY*) {}\n\nEVP_PKEY_CTX* EVP_PKEY_CTX_new(EVP_PKEY* pkey, ENGINE*)\n{\n    ++openssl_mock.EVP_PKEY_CTX_new_calls;\n    BOOST_TEST(pkey == openssl_mock.key);\n    return openssl_mock.ctx;\n}\nvoid EVP_PKEY_CTX_free(EVP_PKEY_CTX*) {}\nint EVP_PKEY_encrypt_init(EVP_PKEY_CTX* ctx)\n{\n    ++openssl_mock.EVP_PKEY_encrypt_init_calls;\n    BOOST_TEST(ctx == openssl_mock.ctx);\n    return 1;\n}\nint EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int)\n{\n    ++openssl_mock.EVP_PKEY_CTX_set_rsa_padding_calls;\n    BOOST_TEST(ctx == openssl_mock.ctx);\n    return openssl_mock.set_rsa_padding_result;\n}\n\nint EVP_PKEY_get_size(const EVP_PKEY* pkey)\n{\n    ++openssl_mock.EVP_PKEY_get_size_calls;\n    BOOST_TEST(pkey == openssl_mock.key);\n    return openssl_mock.get_size_result;\n}\nint EVP_PKEY_encrypt(EVP_PKEY_CTX* ctx, unsigned char*, size_t* actual_size, const unsigned char*, size_t)\n{\n    ++openssl_mock.EVP_PKEY_encrypt_calls;\n    BOOST_TEST(ctx == openssl_mock.ctx);\n    if (actual_size)\n        *actual_size = openssl_mock.actual_ciphertext_size;\n    return 1;\n}\n\nunsigned long ERR_get_error() { return openssl_mock.last_error; }\n\n#else\nBOOST_AUTO_TEST_CASE(dummy) {}\n#endif\n"
  },
  {
    "path": "tools/ci/ci_util/__init__.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n"
  },
  {
    "path": "tools/ci/ci_util/b2.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nimport os\nfrom typing import List, Optional\nfrom .common import run, IS_WINDOWS\nfrom .db_setup import db_setup\nfrom .install_boost import install_boost\n\n\ndef _conditional_run(args: List[Optional[str]]) -> None:\n    run([elm for elm in args if elm is not None])\n\n\ndef _conditional(arg: str, condition: bool) -> Optional[str]:\n    return arg if condition else None\n\n\ndef _win_openssl_line(address_model: int) -> str:\n    s = 'using openssl : : <include>\"C:/openssl-{0}/include\" <search>\"C:/openssl-{0}/lib\" <ssl-name>libssl <crypto-name>libcrypto : <address-model>{0} ;\\n'\n    return s.format(address_model)\n\n\ndef _write_windows_user_config() -> None:\n    config_path = str(Path.home().joinpath('user-config.jam'))\n    print(' + Writing user-config.jam to {}'.format(config_path))\n    with open(config_path, 'wt', encoding='utf-8') as f:\n        for am in (32, 64):\n            f.write(_win_openssl_line(am))\n\n\ndef b2_build(\n    source_dir: Path,\n    toolset: str,\n    cxxstd: str,\n    variant: str,\n    stdlib: str,\n    address_model: str,\n    boost_branch: str,\n    server_host: str,\n    separate_compilation: bool,\n    address_sanitizer: bool,\n    undefined_sanitizer: bool,\n    use_ts_executor: bool,\n    disable_local_sockets: Optional[str],\n    coverage: bool,\n    valgrind: bool,\n    fail_if_no_openssl: bool,\n) -> None:\n    # Config\n    os.environ['UBSAN_OPTIONS'] = 'print_stacktrace=1'\n    if IS_WINDOWS:\n        _write_windows_user_config()\n\n    # Get Boost. This leaves us inside boost root\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Setup DB\n    db_setup(source_dir, server_host)\n\n    # Invoke b2\n    _conditional_run([\n        'b2',\n        '--abbreviate-paths',\n        'toolset={}'.format(toolset),\n        'cxxstd={}'.format(cxxstd),\n        'address-model={}'.format(address_model),\n        'variant={}'.format(variant),\n        'stdlib={}'.format(stdlib),\n        'boost.mysql.separate-compilation={}'.format('on' if separate_compilation else 'off'),\n        'boost.mysql.use-ts-executor={}'.format('on' if use_ts_executor else 'off'),\n        _conditional('boost.mysql.disable-local-sockets={}'.format(disable_local_sockets), disable_local_sockets is not None),\n        _conditional('address-sanitizer=norecover', address_sanitizer),\n        _conditional('undefined-sanitizer=norecover', undefined_sanitizer),\n        _conditional('coverage=on', coverage),\n        _conditional('boost.mysql.valgrind=on', valgrind),\n        'warnings=extra',\n        'warnings-as-errors=on',\n        '-j4',\n        'libs/mysql/test',\n        'libs/mysql/test/integration//boost_mysql_integrationtests',\n        'libs/mysql/test/thread_safety',\n        'libs/mysql/example',\n        _conditional('libs/mysql/test//fail_if_no_openssl', fail_if_no_openssl)\n    ])\n"
  },
  {
    "path": "tools/ci/ci_util/bench.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Functions to run the benchmarks. The actual bench build is in cmake.py\n\nfrom pathlib import Path\nfrom subprocess import check_output\n\n_results_file = 'benchmark-results.txt'\n\n\ndef _record_measurement(bench: str, time: int) -> None:\n    print('{}: {}ms'.format(bench, time), flush=True)\n    with open(_results_file, 'at') as f:\n        f.write('{},{}\\n'.format(bench, time))\n\n\ndef _run_connection_pool(\n    exe_dir: Path,\n    iters: int,\n    server_host: str,\n) -> None:\n    # The benchmarks to run\n    benchmarks = [\n        \"nopool-tcp\",\n        \"nopool-tcpssl\",\n        \"nopool-unix\",\n        \"pool-tcp\",\n        \"pool-tcpssl\",\n        \"pool-unix\",\n    ]\n\n    exe = exe_dir.joinpath('boost_mysql_bench_connection_pool')\n\n    for bench in benchmarks:\n        for _ in range(iters):\n            time = int(check_output([exe, bench, server_host]).decode())\n            _record_measurement(bench, time)\n\n\ndef _run_protocol(\n    exe_dir: Path,\n    iters: int,\n) -> None:\n    # The benchmarks to run\n    benchmarks = [\n        \"one_small_row_boost\",\n        \"one_small_row_libmysqlclient\",\n        \"one_small_row_libmariadb\",\n        \"one_big_row_boost\",\n        \"one_big_row_libmysqlclient\",\n        \"one_big_row_libmariadb\",\n        \"many_rows_boost\",\n        \"many_rows_libmysqlclient\",\n        \"many_rows_libmariadb\",\n        \"stmt_params_boost\",\n        \"stmt_params_libmysqlclient\",\n        \"stmt_params_libmariadb\",\n    ]\n\n    for bench in benchmarks:\n        exe = exe_dir.joinpath('boost_mysql_bench_' + bench)\n        for _ in range(iters):\n            time = int(check_output([exe]).decode())\n            _record_measurement(bench, time)\n\n\ndef run_benchmarks(\n    exe_dir: Path,\n    server_host: str,\n    connection_pool_iters: int,\n    protocol_iters: int,\n) -> None:\n    # Truncate the results file, if it exists\n    with open(_results_file, 'wt') as f:\n        pass\n\n    # Run the benchmarks\n    _run_connection_pool(exe_dir, connection_pool_iters, server_host)\n    _run_protocol(exe_dir, protocol_iters)\n"
  },
  {
    "path": "tools/ci/ci_util/cmake.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nimport os\nfrom typing import Optional, Dict\nfrom .common import run, BOOST_ROOT, IS_WINDOWS, mkdir_and_cd\nfrom .db_setup import db_setup, db_setup_bench\nfrom .install_boost import install_boost\nfrom .bench import run_benchmarks\n\n\ndef _cmake_prefix_path(extra_path: Optional[Path] = None) -> str:\n    prefix_path_args = [extra_path, 'C:\\\\openssl-64' if IS_WINDOWS else None]\n    return ';'.join(str(p) for p in prefix_path_args if p is not None)\n\n\ndef _cmake_bool(value: bool) -> str:\n    return 'ON' if value else 'OFF'\n\n\nclass _CMakeRunner:\n    def __init__(self, generator: str, build_type: str) -> None:\n        self._generator = generator\n        self._build_type = build_type\n        os.environ['CMAKE_BUILD_PARALLEL_LEVEL'] = '4'\n\n\n    def configure(self, source_dir: Path, binary_dir: Path, variables: Dict[str, str]) -> None:\n        mkdir_and_cd(binary_dir)\n        run(\n            [\n                'cmake',\n                '-G',\n                self._generator,\n                '-DCMAKE_BUILD_TYPE={}'.format(self._build_type),\n            ] +\n            ['-D{}={}'.format(name, value) for name, value in variables.items()] +\n            [str(source_dir)]\n        )\n\n\n    def build(self, target: str) -> None:\n        run(['cmake', '--build', '.', '--target', target, '--config', self._build_type])\n    \n\n    def build_all(self) -> None:\n        run(['cmake', '--build', '.', '--config', self._build_type])\n\n\n    def ctest(self, no_tests_error: bool = True) -> None:\n        run(\n            ['ctest', '--output-on-failure'] +\n            (['--no-tests=error'] if no_tests_error else []) +\n            ['--build-config', self._build_type]\n        )\n\n\n# Regular CMake build\ndef cmake_build(\n    source_dir: Path,\n    boost_branch: str,\n    generator: str,\n    build_shared_libs: bool,\n    build_type: str,\n    cxxstd: str,\n    server_host: str,\n    install_test: bool,\n) -> None:\n    # Config\n    cmake_distro = Path(os.path.expanduser('~')).joinpath('cmake-distro')\n    test_folder = BOOST_ROOT.joinpath('libs', 'mysql', 'test', 'cmake_test')\n    runner = _CMakeRunner(generator=generator, build_type=build_type)\n\n    # Get Boost\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Setup DB\n    db_setup(source_dir, server_host)\n\n    # Build the library, run the tests, and install, as the Boost superproject does\n    bin_dir = BOOST_ROOT.joinpath('__build')\n    runner.configure(\n        source_dir=BOOST_ROOT,\n        binary_dir=bin_dir,\n        variables={\n            'CMAKE_PREFIX_PATH': _cmake_prefix_path(),\n            'BOOST_INCLUDE_LIBRARIES': 'mysql',\n            'BUILD_SHARED_LIBS': _cmake_bool(build_shared_libs),\n            'CMAKE_INSTALL_PREFIX': str(cmake_distro),\n            'BUILD_TESTING': 'ON',\n            'CMAKE_INSTALL_MESSAGE': 'NEVER',\n            'BOOST_MYSQL_INTEGRATION_TESTS': 'ON',\n            **({ 'CMAKE_CXX_STANDARD': cxxstd } if cxxstd else {})\n        }\n    )\n    runner.build(target='tests')\n    runner.ctest()\n    runner.build(target='install')\n\n    # The library can be consumed using add_subdirectory\n    runner.configure(\n        source_dir=test_folder,\n        binary_dir=test_folder.joinpath('__build_add_subdirectory'),\n        variables={\n            'CMAKE_PREFIX_PATH': _cmake_prefix_path(),\n            'BOOST_CI_INSTALL_TEST': 'OFF',\n            'BUILD_SHARED_LIBS': _cmake_bool(build_shared_libs)\n        }\n    )\n    runner.build_all()\n    runner.ctest()\n\n    # The library can be consumed using find_package on a Boost distro built by cmake.\n    # Generating a modular installation requires CMake 3.13+, so this test can be disabled\n    # for jobs running old cmake versions\n    if install_test:\n        runner.configure(\n            source_dir=test_folder,\n            binary_dir=test_folder.joinpath('__build_find_package'),\n            variables={\n                'BOOST_CI_INSTALL_TEST': 'ON',\n                'BUILD_SHARED_LIBS': _cmake_bool(build_shared_libs),\n                'CMAKE_PREFIX_PATH': _cmake_prefix_path(cmake_distro)\n            }\n        )\n        runner.build_all()\n        runner.ctest()\n\n\n# Check that we bail out correctly when no OpenSSL is available\ndef cmake_noopenssl_build(\n    source_dir: Path,\n    boost_branch: str,\n    generator: str\n):\n    # Config\n    runner = _CMakeRunner(generator=generator, build_type='Release')\n\n    # Get Boost\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Build Boost and install. This won't build the library if there is no OpenSSL,\n    # but shouldn't cause any error.\n    runner.configure(\n        source_dir=BOOST_ROOT,\n        binary_dir=BOOST_ROOT.joinpath('__build'),\n        variables={\n            'BOOST_INCLUDE_LIBRARIES': 'mysql',\n            'BOOST_MYSQL_INTEGRATION_TESTS': 'ON',\n            'BUILD_TESTING': 'ON',\n            'CMAKE_INSTALL_MESSAGE': 'NEVER',\n        }\n    )\n    runner.build(target='tests')\n    runner.ctest(no_tests_error=False)\n    runner.build(target='install')\n\n\n# Check that disabling integration tests works\ndef cmake_nointeg_build(\n    source_dir: Path,\n    boost_branch: str,\n    generator: str\n):\n    # Config\n    runner = _CMakeRunner(generator=generator, build_type='Release')\n\n    # Get Boost\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Build the library and run the tests, as the Boost superproject does\n    bin_dir = BOOST_ROOT.joinpath('__build')\n    runner.configure(\n        source_dir=BOOST_ROOT,\n        binary_dir=bin_dir,\n        variables={\n            'CMAKE_PREFIX_PATH': _cmake_prefix_path(),\n            'BOOST_INCLUDE_LIBRARIES': 'mysql',\n            'BUILD_TESTING': 'ON'\n        }\n    )\n    runner.build(target='tests')\n    runner.ctest()\n    runner.build(target='install')\n\n\n# Check that CMake can consume a Boost distribution created by b2\ndef find_package_b2_test(\n    source_dir: Path,\n    boost_branch: str,\n    generator: str\n) -> None:\n    # Config\n    b2_distro = Path(os.path.expanduser('~')).joinpath('b2-distro')\n    prefix_path = _cmake_prefix_path(b2_distro)\n    runner = _CMakeRunner(generator=generator, build_type='Release')\n\n    # Get Boost\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Generate a b2 Boost distribution\n    run([\n        'b2',\n        '--prefix={}'.format(b2_distro),\n        '--with-charconv',\n        '-d0',\n        'install'\n    ])\n\n    # Check that the library can be consumed using find_package on the distro above\n    test_dir = BOOST_ROOT.joinpath('libs', 'mysql', 'test', 'cmake_b2_test')\n    runner.configure(\n        source_dir=test_dir,\n        binary_dir=test_dir.joinpath('__build'),\n        variables={\n            'CMAKE_PREFIX_PATH': prefix_path,\n            'BUILD_TESTING': 'ON'\n        }\n    )\n    runner.build_all()\n    runner.ctest()\n\n    # Same as the above, but for separate-build mode\n    test_dir = BOOST_ROOT.joinpath('libs', 'mysql', 'test', 'cmake_b2_separate_compilation_test')\n    runner.configure(\n        source_dir=test_dir,\n        binary_dir=test_dir.joinpath('__build'),\n        variables={\n            'CMAKE_PREFIX_PATH': prefix_path,\n            'BUILD_TESTING': 'ON'\n        }\n    )\n    runner.build_all()\n    runner.ctest()\n\n\ndef bench_build(\n    source_dir: Path,\n    boost_branch: str,\n    connection_pool_iters: int,\n    protocol_iters: int,\n    server_host: str,\n) -> None:\n    # Get Boost\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Setup DB\n    db_setup_bench(source_dir)\n\n    # Build the benchmark code\n    runner = _CMakeRunner(generator='Ninja', build_type='Release')\n    bin_dir = BOOST_ROOT.joinpath('__build')\n    runner.configure(\n        source_dir=BOOST_ROOT,\n        binary_dir=bin_dir,\n        variables={\n            'CMAKE_PREFIX_PATH': '/opt/mysql-8.4.4', # Container's location\n            'BOOST_INCLUDE_LIBRARIES': 'mysql',\n            'BOOST_MYSQL_BENCH': 'ON',\n            'CMAKE_CXX_STANDARD': '23',\n        }\n    )\n    runner.build(target='boost_mysql_bench')\n\n    # Run the benchmarks\n    run_benchmarks(\n        exe_dir=bin_dir.joinpath('stage', 'bin'),\n        server_host=server_host,\n        connection_pool_iters=connection_pool_iters,\n        protocol_iters=protocol_iters,\n    )\n"
  },
  {
    "path": "tools/ci/ci_util/common.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nimport os\nfrom typing import List\nimport subprocess\n\nREPO_BASE = Path(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', '..')).absolute()\nBOOST_ROOT = Path(os.path.expanduser('~')).joinpath('boost-root')\nIS_WINDOWS = os.name == 'nt'\n\n\ndef run(args: List[str]) -> None:\n    print('+ ', args, flush=True)\n    subprocess.run(args, check=True)\n\n\ndef mkdir_and_cd(path: Path) -> None:\n    os.makedirs(str(path), exist_ok=True)\n    os.chdir(str(path))\n"
  },
  {
    "path": "tools/ci/ci_util/db_setup.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom typing import List, Dict\nfrom pathlib import Path\nimport subprocess\nimport os\nfrom .common import IS_WINDOWS\nfrom enum import Enum\nimport re\n\n\nclass _DbSystemType(Enum):\n    mysql5 = 1\n    mysql8 = 2\n    mysql9 = 3\n    mariadb = 4\n\n\ndef _run_piped_stdin(args: List[str], fname: Path) -> None:\n    with open(str(fname), 'rt', encoding='utf8') as f:\n        content = f.read()\n    print('+ ', args, '(with < {})'.format(fname), flush=True)\n    subprocess.run(args, input=content.encode(), check=True)\n\n\ndef _run_piped_stdout(args: List[str]) -> str:\n    print('+ ', args, flush=True)\n    return subprocess.check_output(args).decode()\n\n\ndef _run_sql_file(fname: Path) -> None:\n    _run_piped_stdin(['mysql', '-u', 'root'], fname)\n\n\ndef _get_server_version() -> str:\n    return _run_piped_stdout([\n        'mysql', '-u', 'root', '--column-names=0',  '--batch', '-e', 'SELECT VERSION()'\n    ])\n\n\ndef _parse_db_version(db: str) -> _DbSystemType:\n    # Parse the version string\n    match = re.match(r'([0-9]*)\\.[0-9]*\\.[0-9]*(\\-MariaDB)?.*', db, re.IGNORECASE)\n    if match is None:\n        raise ValueError('Bad DB version: {}'.format(db))\n    vmaj = int(match.group(1))\n    is_mariadb = match.group(2) is not None\n\n    # Perform the matching\n    if is_mariadb:\n        return _DbSystemType.mariadb\n    elif vmaj == 8:\n        return _DbSystemType.mysql8\n    elif vmaj >= 9:\n        return _DbSystemType.mysql9\n    else:\n        return _DbSystemType.mysql5\n\n\ndef _compute_disabled_features(db: _DbSystemType) -> Dict[str, bool]:\n    return {\n        # UNIX sockets. Only Windows CI servers don't have them enabled\n        'unix-sockets': IS_WINDOWS,\n\n        # sha256. Disabled on mysql5 and mariadb\n        'sha256': db in (_DbSystemType.mysql5, _DbSystemType.mariadb),\n\n        # JSON type. Disabled in mariadb\n        'json-type': db == _DbSystemType.mariadb,\n\n        # regex-error-codes. Disabled in mysql5 and mariadb\n        'regex-error-codes': db in (_DbSystemType.mysql5, _DbSystemType.mariadb),\n\n        # dup-query-error-codes. Disabled in mysql systems\n        'dup-query-error-codes': db in (_DbSystemType.mysql5, _DbSystemType.mysql8, _DbSystemType.mysql9),\n\n        # mysql_native_password. Disabled in mysql9\n        'mnp': db == _DbSystemType.mysql9,\n    }\n\n\ndef db_setup(\n    source_dir: Path,\n    server_host: str,\n) -> None:\n    # Get the server version\n    db = _get_server_version()\n    print('+ Server version: {}'.format(db), flush=True)\n\n    # Get the disabled server features\n    disabled_features = _compute_disabled_features(_parse_db_version(db))\n    disabled_features_str = ' '.join(feature for feature, disabled in disabled_features.items() if disabled)\n    print('+ Disabled server features: {}'.format(disabled_features_str))\n\n    # Source files\n    _run_sql_file(source_dir.joinpath('example', 'db_setup.sql'))\n    _run_sql_file(source_dir.joinpath('example', '3_advanced', 'http_server_cpp20', 'db_setup.sql'))\n    _run_sql_file(source_dir.joinpath('test', 'integration', 'db_setup.sql'))\n    if not disabled_features['sha256']:\n        _run_sql_file(source_dir.joinpath('test', 'integration', 'db_setup_sha256.sql'))\n    if not disabled_features['mnp']:\n        _run_sql_file(source_dir.joinpath('test', 'integration', 'db_setup_mnp.sql'))\n    \n    # Setup environment variables\n    os.environ['BOOST_MYSQL_SERVER_HOST'] = server_host\n    os.environ['BOOST_MYSQL_DISABLED_SERVER_FEATURES'] = disabled_features_str\n\n\n# Loads benchmark data. This takes around 15s, so we don't do it unless necessary\ndef db_setup_bench(source_dir: Path) -> None:\n    _run_sql_file(source_dir.joinpath('bench', 'db_setup.sql'))\n"
  },
  {
    "path": "tools/ci/ci_util/docs.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nimport os\nfrom shutil import copytree, rmtree\nfrom .common import BOOST_ROOT, run\nfrom .install_boost import install_boost\n\n\ndef docs_build(\n    source_dir: Path,\n    boost_branch: str\n):\n    # Get Boost. This leaves us inside boost root\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n        docs_install=True,\n    )\n\n    # Write the config file\n    config_path = os.path.expanduser('~/user-config.jam')\n    with open(config_path, 'wt') as f:\n        f.writelines(['using doxygen ;\\n', 'using boostbook ;\\n'])\n\n    # Run b2\n    run(['b2', 'libs/mysql/doc//boostrelease'])\n\n    # Copy the resulting docs into a well-known path\n    output_dir = source_dir.joinpath('doc', 'html')\n    if output_dir.exists():\n        rmtree(output_dir)\n    copytree(BOOST_ROOT.joinpath('libs', 'mysql', 'doc', 'html'), output_dir)\n"
  },
  {
    "path": "tools/ci/ci_util/fuzz.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nimport os\nfrom shutil import unpack_archive, make_archive\nfrom .common import run\nfrom .seed_corpus import generate_seed_corpus\nfrom .db_setup import db_setup\nfrom .install_boost import install_boost\n\n\ndef fuzz_build(\n    source_dir: Path,\n    boost_branch: str,\n    server_host: str,\n) -> None:\n    # Config\n    os.environ['UBSAN_OPTIONS'] = 'print_stacktrace=1'\n\n    # Get Boost. This leaves us inside boost root\n    install_boost(\n        source_dir=source_dir,\n        boost_branch=boost_branch,\n    )\n\n    # Setup corpus from previous runs. /tmp/corpus.tar.gz is restored by the CI\n    old_corpus = Path('/tmp/corpus.tar.gz')\n    if old_corpus.exists():\n        print('+  Restoring old corpus')\n        unpack_archive(old_corpus, extract_dir='/tmp/corpus')\n    else:\n        print('+  No old corpus found')\n    \n    # Setup the seed corpus\n    print('+  Generating seed corpus')\n    generate_seed_corpus()\n\n    # Setup DB (required for injection testing)\n    db_setup(source_dir, server_host)\n\n    # Build and run the fuzzing targets\n    run([\n        'b2',\n        '--abbreviate-paths',\n        'toolset=clang',\n        'cxxstd=20',\n        'warnings-as-errors=on',\n        '-j4',\n        'libs/mysql/test/fuzzing',\n    ])\n\n    # Archive the generated corpus, so the CI caches it\n    name = make_archive(str(old_corpus).rstrip('.tar.gz'), 'gztar', '/tmp/mincorpus')\n    print('  + Created min corpus archive {}'.format(name))\n    \n"
  },
  {
    "path": "tools/ci/ci_util/install_boost.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom shutil import rmtree, ignore_patterns, copytree\nimport stat\nimport sys\nfrom pathlib import Path\nimport os\nfrom .common import run, IS_WINDOWS, BOOST_ROOT\n\ndef _remove_readonly(func, path, _):\n    os.chmod(path, stat.S_IWRITE)\n    func(path)\n\ndef _copy_lib_to_boost(source_dir: Path):\n    # Config\n    supports_dir_exist_ok = sys.version_info.minor >= 8\n    lib_dir = BOOST_ROOT.joinpath('libs', 'mysql')\n    \n    # Old versions of Python don't support dirs_exist_ok.\n    # For these, we need to remove any old copies of our lib before copying\n    if lib_dir.exists() and not supports_dir_exist_ok:\n        rmtree(str(lib_dir), onerror=_remove_readonly)\n    \n    # Do the copying\n    copytree(\n        str(source_dir),\n        str(lib_dir),\n        ignore=ignore_patterns('__build*__', '.git'),\n        **({ 'dirs_exist_ok': True } if supports_dir_exist_ok else {}) # type: ignore\n    )\n\n\ndef install_boost(\n    source_dir: Path,\n    boost_branch: str,\n    docs_install: bool = False\n) -> None:\n    assert source_dir.is_absolute()\n    \n    # If BOOST_ROOT already exists, this is a re-build.\n    # Copy our library into libs/ and exit\n    if BOOST_ROOT.exists():\n        os.chdir(str(BOOST_ROOT))\n        _copy_lib_to_boost(source_dir)\n        return\n\n    # Clone Boost\n    run(['git', 'clone', '-b', boost_branch, '--depth', '1', 'https://github.com/boostorg/boost.git', str(BOOST_ROOT)])\n    os.chdir(str(BOOST_ROOT))\n\n    # Put our library inside boost root\n    _copy_lib_to_boost(source_dir)\n\n    # Install Boost dependencies\n    submodules = [\n        'libs/context',\n        'tools/boostdep',\n        'tools/boostbook',\n        'tools/docca',\n        'tools/quickbook'\n    ] if docs_install else [\n        'tools/boostdep'\n    ]\n    run([\"git\", \"config\", \"submodule.fetchJobs\", \"8\"])\n    run([\"git\", \"submodule\", \"update\", \"-q\", \"--init\"] + submodules)\n\n    if docs_install:\n        run(['python', 'tools/boostdep/depinst/depinst.py', '../tools/quickbook'])\n    else:\n        run([\"python\", \"tools/boostdep/depinst/depinst.py\", \"--include\", \"example\", \"mysql\"])\n    \n    # Bootstrap\n    if IS_WINDOWS:\n        run(['cmd', '/q', '/c', 'bootstrap.bat'])\n    else:\n        run(['bash', 'bootstrap.sh'])\n    run(['b2', 'headers'])\n"
  },
  {
    "path": "tools/ci/ci_util/main.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nfrom typing import Union\nimport os\nimport argparse\nfrom .common import IS_WINDOWS, BOOST_ROOT\nfrom .cmake import cmake_build, cmake_noopenssl_build, cmake_nointeg_build, find_package_b2_test, bench_build\nfrom .b2 import b2_build\nfrom .docs import docs_build\n\n\ndef _add_to_path(path: Path) -> None:\n    sep = ';' if IS_WINDOWS  else ':'\n    os.environ['PATH'] = '{}{}{}'.format(path, sep, os.environ[\"PATH\"])\n\n\ndef _str2bool(v: Union[bool, str]) -> bool:\n    if isinstance(v, bool):\n        return v\n    elif v == '1':\n        return True\n    elif v == '0':\n        return False\n    else:\n        raise argparse.ArgumentTypeError('Boolean value expected.')\n\n\ndef _deduce_boost_branch() -> str:\n    # Are we in GitHub Actions?\n    if os.environ.get('GITHUB_ACTIONS') is not None:\n        ci = 'GitHub Actions'\n        ref = os.environ.get('GITHUB_BASE_REF', '') or os.environ.get('GITHUB_REF', '')\n        res = 'master' if ref == 'master' or ref.endswith('/master') else 'develop'\n    elif os.environ.get('DRONE') is not None:\n        ref = os.environ.get('DRONE_BRANCH', '')\n        ci = 'Drone'\n        res = 'master' if ref == 'master' else 'develop'\n    else:\n        ci = 'Unknown'\n        ref = ''\n        res = 'develop'\n    \n    print('+  Found CI {}, ref={}, deduced branch {}'.format(ci, ref, res))\n\n    return res\n\n\n# Adds any DB args for builds requiring these\ndef _add_db_args(subp: argparse.ArgumentParser) -> None:\n    subp.add_argument('--server-host', default='127.0.0.1')\n\n\n# Fuzzing uses some Python features only available in newer CIs,\n# so we use a dynamic import to avoid failures in older CIs\ndef _do_fuzz_build(**kwargs):\n    from .fuzz import fuzz_build\n    fuzz_build(**kwargs)\n\n\ndef main():\n    # Main parser\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--source-dir', type=Path, required=True)\n    parser.add_argument('--boost-branch', default=None) # None means \"let this script deduce it\"\n    subparsers = parser.add_subparsers()\n\n    # b2\n    subp = subparsers.add_parser('b2', help='B2 build')\n    _add_db_args(subp)\n    subp.add_argument('--toolset', default='clang')\n    subp.add_argument('--cxxstd', default='20')\n    subp.add_argument('--variant', default='release')\n    subp.add_argument('--stdlib', choices=['native', 'libc++'], default='native')\n    subp.add_argument('--address-model', choices=['32', '64'], default='64')\n    subp.add_argument('--separate-compilation', type=_str2bool, default=True)\n    subp.add_argument('--use-ts-executor', type=_str2bool, default=False)\n    subp.add_argument('--disable-local-sockets', default=None)\n    subp.add_argument('--address-sanitizer', type=_str2bool, default=False)\n    subp.add_argument('--undefined-sanitizer', type=_str2bool, default=False)\n    subp.add_argument('--coverage', type=_str2bool, default=False)\n    subp.add_argument('--valgrind', type=_str2bool, default=False)\n    subp.add_argument('--fail-if-no-openssl', type=_str2bool, default=True)\n    subp.set_defaults(func=b2_build)\n\n    # cmake\n    subp = subparsers.add_parser('cmake', help='CMake build')\n    _add_db_args(subp)\n    subp.add_argument('--generator', default='Ninja')\n    subp.add_argument('--cmake-build-type', choices=['Debug', 'Release', 'MinSizeRel'], default='Debug', dest='build_type')\n    subp.add_argument('--build-shared-libs', type=_str2bool, default=True)\n    subp.add_argument('--cxxstd', default='20')\n    subp.add_argument('--install-test', type=_str2bool, default=True)\n    subp.set_defaults(func=cmake_build)\n\n    # cmake without openssl\n    subp = subparsers.add_parser('cmake-noopenssl', help='CMake build without OpenSSL')\n    subp.add_argument('--generator', default='Ninja')\n    subp.set_defaults(func=cmake_noopenssl_build)\n\n    # cmake without integratin tests\n    subp = subparsers.add_parser('cmake-nointeg', help='CMake build without integration tests')\n    subp.add_argument('--generator', default='Ninja')\n    subp.set_defaults(func=cmake_nointeg_build)\n\n    # find_package with b2 distribution\n    subp = subparsers.add_parser('find-package-b2', help='find_package with b2 distribution test')\n    subp.add_argument('--generator', default='Ninja')\n    subp.set_defaults(func=find_package_b2_test)\n\n    # bench\n    subp = subparsers.add_parser('bench', help='build and run the benchmarks')\n    _add_db_args(subp)\n    subp.add_argument('--connection-pool-iters', type=int, required=True)\n    subp.add_argument('--protocol-iters', type=int, required=True)\n    subp.set_defaults(func=bench_build)\n\n    # fuzz\n    subp = subparsers.add_parser('fuzz', help='Fuzzing')\n    _add_db_args(subp)\n    subp.set_defaults(func=_do_fuzz_build)\n\n    # docs\n    subp = subparsers.add_parser('docs', help='Docs build')\n    subp.set_defaults(func=docs_build)\n\n    # Parse the arguments\n    args = parser.parse_args()\n\n    # Adjust Boost branch\n    if args.boost_branch is None:\n        args.boost_branch = _deduce_boost_branch()\n    \n    # Common code\n    _add_to_path(BOOST_ROOT)\n    \n    # Call the build function, removing the func attribute\n    args.func(**{name: value for name, value in vars(args).items() if name != 'func'})\n"
  },
  {
    "path": "tools/ci/ci_util/seed_corpus.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom pathlib import Path\nfrom os import makedirs\nfrom io import BytesIO\nimport struct\nfrom datetime import datetime, date\nfrom typing import NamedTuple, List\nimport csv\nimport itertools\nimport shutil\nfrom .common import REPO_BASE\n\n\nSEED_CORPUS_PATH = Path('/tmp/seedcorpus')\n\n\nclass _Sample(NamedTuple):\n    fuzzer: str\n    name: str\n    content: bytes\n\n\n# Generates a list of samples by reading one of the CSV files\ndef _read_csv(fname: str) -> List[_Sample]:\n    csv_path = REPO_BASE.joinpath('tools', 'seed_corpus', fname)\n    with open(csv_path, 'rt') as f:\n        return [\n            _Sample(s['fuzzer'], s['name'], bytes.fromhex(s['content']))\n            for s in csv.DictReader(f)\n        ]\n\n\ndef _gen_utf8mb4_valid() -> List[_Sample]:\n    samples = [\n        (\"euro_symbol\", \"€.\"),\n        (\"greek\", \"Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.\"),\n        (\"icelandic\", \"Ég get etið gler án þess að meiða mig.\"),\n        (\"polish\", \"Mogę jeść szkło, i mi nie szkodzi.\"),\n        (\"romanian\", \"Pot să mănânc sticlă și ea nu mă rănește.\"),\n        (\"ukrainian\", \"Я можу їсти шкло, й воно мені не пошкодить.\"),\n        (\"armenian\", \"Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։\"),\n        (\"georgian\", \"მინას ვჭამ და არა მტკივა.\"),\n        (\"hindi\", \"मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती.\"),\n        (\"hebrew\", \"אני יכול לאכול זכוכית וזה לא מזיק לי.\"),\n        (\"yiddish\", \"איך קען עסן גלאָז און עס טוט מיר נישט װײ.\"),\n        (\"arabic\", \"أنا قادر على أكل الزجاج و هذا لا يؤلمني.\"),\n        (\"japanese\", \"私はガラスを食べられます。それは私を傷つけません。\"),\n        (\"thai\", \"ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ\"),\n        (\"emoji\", \"😋😛😜🤪\"),\n    ]\n\n    return [\n        _Sample('fuzz_utf8mb4', name, content.encode())\n        for name, content in samples\n    ]\n\n\ndef _gen_utf8mb4_invalid() -> List[_Sample]:\n    samples = [\n        (\"c2_ltmin\", \"c27f\"),\n        (\"c2_gtmax\", \"c2c0\"),\n        (\"de_gtmax\", \"dec0\"),\n        (\"df_ltmin\", \"df7f\"),\n        (\"df_gtmax\", \"dfc0\"),\n        (\"e0_ltmin_ok\", \"e09f91\"),\n        (\"e3_ltmin_ok\", \"e37f91\"),\n        (\"ed_ok_ltmin\", \"eda07f\"),\n        (\"ed_surrogate_min\", \"eda080\"),\n        (\"f0_ltmin_ok_ok\", \"f08f8080\"),\n        (\"f2_ok_gtmax_ok\", \"f2a1c0a3\"),\n        (\"f4_ok_ok_gtmax\", \"f4a1a2c0\"),\n        (\"overlong_slash_2byte\", \"c0af\"),\n        (\"overlong_slash_3byte\", \"e080af\"),\n        (\"overlong_slash_4byte\", \"f08080af\"),\n        (\"overlong_slash_5byte\", \"f8808080af\"),\n        (\"overlong_slash_6byte\", \"f880808080af\"),\n    ]\n\n    return [\n        _Sample('fuzz_utf8mb4', name, bytes.fromhex(content))\n        for name, content in samples\n    ]\n\n\ndef _gen_escape_string() -> List[_Sample]:\n    # Some base cases that cover most of the escaping we do\n    base_cases = [\n        (\"empty\",                  b\"\"),\n        (\"no_escape_ascii\",        b\"this is A test string\"),\n        (\"escape_quotes\",          b'some \"dq\"\\'sq\\' `bt` \\\\bl\\\\'),\n        (\"escape_others\",          b\"this '\\0' null \\x1a \\n\\r some chrs \\\\\"),\n        (\"utf8_2byte\",              \"2byte \\\" ñ UTF-8\\\\ ò` \\\\\".encode()),\n        (\"utf8_3byte\",              \"3byte '\\uffff UTF-8'\".encode()),\n        (\"utf8_4byte\",              \"4byte \\r'𐀀 UTF-8\\n\".encode()),\n        (\"invalid_utf8\",           b\"This \\\"has\\\" invalid \\xc3\\\\ chars\"),\n        (\"injection_1\",            b\"' or \\\"\"),\n        (\"injection_2\",            b\"' OR 'x'='x\\\\\"),\n        (\"injection_3\",            b\"'''''''''''''UNION SELECT '2\"),\n    ]\n\n    # The first byte in the input contains options for backslash_escapes\n    # and the quoting context\n    backslash_escapes = [\n        (0,      'bn'),\n        (1 << 0, 'by'),\n    ]\n\n    quot_ctx = [\n        (0,               'squot'),\n        (1 << 1,          'btick'),\n        (1 << 1 | 1 << 2, 'dquot'),\n    ]\n\n    # Generate all the cases by dot product\n    cases: List[_Sample] = []\n    for bl_byte, bl_name in backslash_escapes:\n        for quot_byte, quot_name in quot_ctx:\n            cases += [_Sample(\n                'fuzz_escape_string',\n                f'{bl_name}_{quot_name}_{name}',\n                struct.pack('<B', bl_byte | quot_byte) + value\n            ) for name, value in base_cases]\n        \n    return cases\n\n\ndef _gen_format_string() -> List[_Sample]:\n    cases = [\n        (\"no_replacement\", \"1\"),\n        (\"escaped_curly_1\", \"'{{}}'\"),\n        (\"escaped_curly_2\", \"'}}}}{{'\"),\n        (\"escaped_curly_3\", \"'}}'\"),\n        (\"escaped_curly_4\", \"'{{name}}'\"),\n        (\"one_replacement\", \"{} OR 1=1\"),\n        (\"replacement_end\", \"{}\"),\n        (\"replacement_start\", \"{} AND {}\"),\n        (\"several_replacements\", \"{}, {}, {}, {}, {}, {}, {}, {}\"),\n        (\"indexed_args_1\", \"{0}\"),\n        (\"indexed_args_2\", \"{1}, {0}\"),\n        (\"indexed_args_3\", \"{07}, {1}, {0}, {2}\"),\n        (\"named_args_1\", \"{name}, {val}\"),\n        (\"named_args_2\", \"{_name}, {0}, {k}, {v}\"),\n        (\"named_args_3\", \"{}, {name}, {}, {k}\"),\n        (\"utf8_1\", \"`eñe` + {};\"),\n        (\"utf8_2\", \"uni 🤡 {} code\"),\n        (\"unbalanced_1\", \"{} { bad\"),\n        (\"unbalanced_2\", \"}}} bad\"),\n        (\"invalid_name_1\", \"{0name}\"),\n        (\"invalid_name_2\", \"{ name }\"),\n        (\"invalid_name_3\", \"{eñe}\"),\n        (\"invalid_index_1\", \"{999999}\"),\n        (\"invalid_index_2\", \"{0x10}\"),\n        (\"invalid_index_3\", \"{4.2}\"),\n        (\"index_to_manual\", \"{0}, {}\"),\n        (\"auto_to_manual\", \"{}, {1}, {2}\"),\n    ]\n\n    return [_Sample(\n        'fuzz_format_strings',\n        name,\n        content.encode()\n    ) for name, content in cases]\n\n\ndef _gen_format_args() -> List[_Sample]:\n    # Helper to output samples\n    class Packer:\n        def __init__(self) -> None:\n            self.io = BytesIO()\n        \n        def add_null(self, v: None):\n            pass\n        \n        def add_int64(self, v: int):\n            self.io.write(struct.pack('<q', v))\n        \n        def add_uint64(self, v: int):\n            self.io.write(struct.pack('<Q', v))\n        \n        def add_float(self, v: float):\n            self.io.write(struct.pack('<f', v))\n        \n        def add_double(self, v: float):\n            self.io.write(struct.pack('<d', v))\n\n        def add_string(self, v: str):\n            self.add_blob(v.encode())\n        \n        def add_blob(self, v: bytes):\n            self.io.write(struct.pack('<B', len(v)))\n            self.io.write(v)\n        \n        def add_date(self, v: date):\n            self.io.write(struct.pack('<HBB', v.year, v.month, v.day))\n        \n        def add_datetime(self, v: datetime):\n            self.io.write(struct.pack('<HBBBBBL', v.year, v.month, v.day, v.hour, v.minute, v.second, v.microsecond))\n        \n        def pack(self, type1: int, type2: int, fn1, fn2, val1, val2) -> bytes:\n            # Sample format: type code, value 1, value 2\n            self.io.write(struct.pack('<B', type1 | type2 << 4))\n            fn1(self, val1)\n            fn2(self, val2)\n            return self.io.getvalue()\n\n    # Possible types, with type codes\n    types = [\n        ('null',     0x00, Packer.add_null, None, None),\n        ('int64',    0x01, Packer.add_int64, -1, 42),\n        ('uint64',   0x02, Packer.add_uint64, 0xffffffffff, 23),\n        ('float',    0x03, Packer.add_float, 4.2, -10e20),\n        ('double',   0x04, Packer.add_double, -2.1e-216, 0.0),\n        ('string',   0x05, Packer.add_string, 'ab\\0\\n\\'\\\\\"', 'm\\r`\\\\\\\\abc'),\n        ('blob',     0x06, Packer.add_blob,   b'\\0ab\\\\\\n`', b'a'*64),\n        ('date',     0x07, Packer.add_date, date(2021, 10, 11), date(1970, 1, 1)),\n        ('datetime', 0x08, Packer.add_datetime, datetime(2021, 11, 9, 10, 1, 20, 91), datetime(2100, 10, 1)),\n        ('time',     0x09, Packer.add_int64, -90, 439389289202),\n    ]\n\n    # Perform a dot product of all cases\n    cases: List[_Sample] = []\n    for name1, type1, fn1, val1, _ in types:\n        cases += [\n            _Sample(\n                'fuzz_format_args',\n                f'{name1}_{name2}',\n                Packer().pack(type1, type2, fn1, fn2, val1, val2)\n            )\n            for name2, type2, fn2, _, val2 in types\n        ]\n    \n    return cases\n\ndef _gen_format_identifiers() -> List[_Sample]:\n    cases = [\n        '',\n        'employee',\n        'some_table',\n        'with spaces',\n        'wíth uñicode',\n        'need`ds esc``aping',\n        '`',\n        '\\'\"ab[]def',\n    ]\n\n    return [\n        _Sample('fuzz_format_identifier', str(i), s.encode())\n        for i, s in enumerate(cases)\n    ]\n\n\n# The payloads in the text file have been generated by running\n# sqlmap (https://sqlmap.org/) on a test server\ndef _gen_format_sql_injection() -> List[_Sample]:\n    with open(REPO_BASE.joinpath('tools', 'seed_corpus', 'sql_injection_payloads.txt'), 'rt', encoding='utf-8') as f:\n        payloads = filter(lambda p: p != '', f.read().split('\\n'))\n    \n    return [_Sample(\n        'fuzz_format_sql_injection',\n        str(i),\n        payload.encode()\n    ) for i, payload in enumerate(payloads)]\n\n\ndef generate_seed_corpus():\n    # Generate the samples in memory\n    samples = list(itertools.chain(\n        _read_csv('field_table.csv'),\n        _read_csv('protocol_messages.csv'),\n        _gen_utf8mb4_valid(),\n        _gen_utf8mb4_invalid(),\n        _gen_escape_string(),\n        _gen_format_string(),\n        _gen_format_args(),\n        _gen_format_sql_injection(),\n        _gen_format_identifiers(),\n    ))\n\n    # Generate the directory structure\n    fuzzers = list(set(s.fuzzer for s in samples))\n    if SEED_CORPUS_PATH.exists():\n        shutil.rmtree(SEED_CORPUS_PATH, )\n    for f in fuzzers:\n        makedirs(SEED_CORPUS_PATH.joinpath(f))\n    \n    # Generate the samples\n    for s in samples:\n        with open(SEED_CORPUS_PATH.joinpath(s.fuzzer, s.name + '.bin'), 'wb') as f:\n            f.write(s.content)\n"
  },
  {
    "path": "tools/ci/main.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom ci_util.main import main\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tools/ci/run_benchmarks.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# This script is a utility, and not used by CI. Having it here simplifies imports, though.\n\nfrom ci_util.bench import run_benchmarks\nfrom pathlib import Path\nimport sys\n\nif __name__ == '__main__':\n    run_benchmarks(\n        exe_dir=Path(sys.argv[1]),\n        server_host='localhost',\n        connection_pool_iters=0,\n        protocol_iters=25\n    )\n"
  },
  {
    "path": "tools/ci/seed_corpus.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom ci_util.seed_corpus import generate_seed_corpus\n\nif __name__ == '__main__':\n    generate_seed_corpus()\n"
  },
  {
    "path": "tools/docker/build-msvc.dockerfile",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nARG BASE_IMAGE=cppalliance/dronevs2022:1\nFROM ${BASE_IMAGE}\n\nCOPY tools/win-ci.cnf C:/my.cnf\nCOPY tools/ssl C:/ssl\n\nRUN choco install --no-progress -y mysql --version 8.0.20\n\nRUN powershell -Command \\\n    $ErrorActionPreference = 'Stop' ; \\\n    $OPENSSL_VERSION = '1.1.1.1900' ; \\\n    choco install --no-progress -y --force --forceX86 --version $OPENSSL_VERSION openssl ; \\\n    Copy-Item 'C:/Program Files (x86)/OpenSSL-Win32/' -Recurse -Destination 'C:/openssl-32/' ; \\\n    choco install --no-progress -y --force --version $OPENSSL_VERSION openssl ; \\\n    Copy-Item 'C:/Program Files/OpenSSL-Win64/' -Recurse -Destination 'C:/openssl-64/' ; \\\n    choco uninstall -y openssl ; \\\n    pip install requests\n"
  },
  {
    "path": "tools/error_codes.csv",
    "content": "numbr,symbol,category\n1000,ER_HASHCHK,common\n1001,ER_NISAMCHK,common\n1002,ER_NO,common\n1003,ER_YES,common\n1004,ER_CANT_CREATE_FILE,common\n1005,ER_CANT_CREATE_TABLE,common\n1006,ER_CANT_CREATE_DB,common\n1007,ER_DB_CREATE_EXISTS,common\n1008,ER_DB_DROP_EXISTS,common\n1009,ER_DB_DROP_DELETE,common\n1010,ER_DB_DROP_RMDIR,common\n1011,ER_CANT_DELETE_FILE,common\n1012,ER_CANT_FIND_SYSTEM_REC,common\n1013,ER_CANT_GET_STAT,common\n1014,ER_CANT_GET_WD,common\n1015,ER_CANT_LOCK,common\n1016,ER_CANT_OPEN_FILE,common\n1017,ER_FILE_NOT_FOUND,common\n1018,ER_CANT_READ_DIR,common\n1019,ER_CANT_SET_WD,common\n1020,ER_CHECKREAD,common\n1021,ER_DISK_FULL,common\n1022,ER_DUP_KEY,common\n1023,ER_ERROR_ON_CLOSE,common\n1024,ER_ERROR_ON_READ,common\n1025,ER_ERROR_ON_RENAME,common\n1026,ER_ERROR_ON_WRITE,common\n1027,ER_FILE_USED,common\n1028,ER_FILSORT_ABORT,common\n1029,ER_FORM_NOT_FOUND,common\n1030,ER_GET_ERRNO,common\n1031,ER_ILLEGAL_HA,common\n1032,ER_KEY_NOT_FOUND,common\n1033,ER_NOT_FORM_FILE,common\n1034,ER_NOT_KEYFILE,common\n1035,ER_OLD_KEYFILE,common\n1036,ER_OPEN_AS_READONLY,common\n1037,ER_OUTOFMEMORY,common\n1038,ER_OUT_OF_SORTMEMORY,common\n1039,ER_UNEXPECTED_EOF,common\n1040,ER_CON_COUNT_ERROR,common\n1041,ER_OUT_OF_RESOURCES,common\n1042,ER_BAD_HOST_ERROR,common\n1043,ER_HANDSHAKE_ERROR,common\n1044,ER_DBACCESS_DENIED_ERROR,common\n1045,ER_ACCESS_DENIED_ERROR,common\n1046,ER_NO_DB_ERROR,common\n1047,ER_UNKNOWN_COM_ERROR,common\n1048,ER_BAD_NULL_ERROR,common\n1049,ER_BAD_DB_ERROR,common\n1050,ER_TABLE_EXISTS_ERROR,common\n1051,ER_BAD_TABLE_ERROR,common\n1052,ER_NON_UNIQ_ERROR,common\n1053,ER_SERVER_SHUTDOWN,common\n1054,ER_BAD_FIELD_ERROR,common\n1055,ER_WRONG_FIELD_WITH_GROUP,common\n1056,ER_WRONG_GROUP_FIELD,common\n1057,ER_WRONG_SUM_SELECT,common\n1058,ER_WRONG_VALUE_COUNT,common\n1059,ER_TOO_LONG_IDENT,common\n1060,ER_DUP_FIELDNAME,common\n1061,ER_DUP_KEYNAME,common\n1062,ER_DUP_ENTRY,common\n1063,ER_WRONG_FIELD_SPEC,common\n1064,ER_PARSE_ERROR,common\n1065,ER_EMPTY_QUERY,common\n1066,ER_NONUNIQ_TABLE,common\n1067,ER_INVALID_DEFAULT,common\n1068,ER_MULTIPLE_PRI_KEY,common\n1069,ER_TOO_MANY_KEYS,common\n1070,ER_TOO_MANY_KEY_PARTS,common\n1071,ER_TOO_LONG_KEY,common\n1072,ER_KEY_COLUMN_DOES_NOT_EXITS,common\n1073,ER_BLOB_USED_AS_KEY,common\n1074,ER_TOO_BIG_FIELDLENGTH,common\n1075,ER_WRONG_AUTO_KEY,common\n1076,ER_BINLOG_CANT_DELETE_GTID_DOMAIN,mariadb\n1076,ER_READY,mysql\n1077,ER_NORMAL_SHUTDOWN,common\n1078,ER_GOT_SIGNAL,common\n1079,ER_SHUTDOWN_COMPLETE,common\n1080,ER_FORCING_CLOSE,common\n1081,ER_IPSOCK_ERROR,common\n1082,ER_NO_SUCH_INDEX,common\n1083,ER_WRONG_FIELD_TERMINATORS,common\n1084,ER_BLOBS_AND_NO_TERMINATED,common\n1085,ER_TEXTFILE_NOT_READABLE,common\n1086,ER_FILE_EXISTS_ERROR,common\n1087,ER_LOAD_INFO,common\n1088,ER_ALTER_INFO,common\n1089,ER_WRONG_SUB_KEY,common\n1090,ER_CANT_REMOVE_ALL_FIELDS,common\n1091,ER_CANT_DROP_FIELD_OR_KEY,common\n1092,ER_INSERT_INFO,common\n1093,ER_UPDATE_TABLE_USED,common\n1094,ER_NO_SUCH_THREAD,common\n1095,ER_KILL_DENIED_ERROR,common\n1096,ER_NO_TABLES_USED,common\n1097,ER_TOO_BIG_SET,common\n1098,ER_NO_UNIQUE_LOGFILE,common\n1099,ER_TABLE_NOT_LOCKED_FOR_WRITE,common\n1100,ER_TABLE_NOT_LOCKED,common\n1101,ER_BLOB_CANT_HAVE_DEFAULT,mysql\n1102,ER_WRONG_DB_NAME,common\n1103,ER_WRONG_TABLE_NAME,common\n1104,ER_TOO_BIG_SELECT,common\n1105,ER_UNKNOWN_ERROR,common\n1106,ER_UNKNOWN_PROCEDURE,common\n1107,ER_WRONG_PARAMCOUNT_TO_PROCEDURE,common\n1108,ER_WRONG_PARAMETERS_TO_PROCEDURE,common\n1109,ER_UNKNOWN_TABLE,common\n1110,ER_FIELD_SPECIFIED_TWICE,common\n1111,ER_INVALID_GROUP_FUNC_USE,common\n1112,ER_UNSUPPORTED_EXTENSION,common\n1113,ER_TABLE_MUST_HAVE_COLUMNS,common\n1114,ER_RECORD_FILE_FULL,common\n1115,ER_UNKNOWN_CHARACTER_SET,common\n1116,ER_TOO_MANY_TABLES,common\n1117,ER_TOO_MANY_FIELDS,common\n1118,ER_TOO_BIG_ROWSIZE,common\n1119,ER_STACK_OVERRUN,common\n1120,ER_WRONG_OUTER_JOIN,mariadb\n1120,ER_WRONG_OUTER_JOIN_UNUSED,mysql\n1121,ER_NULL_COLUMN_IN_INDEX,common\n1122,ER_CANT_FIND_UDF,common\n1123,ER_CANT_INITIALIZE_UDF,common\n1124,ER_UDF_NO_PATHS,common\n1125,ER_UDF_EXISTS,common\n1126,ER_CANT_OPEN_LIBRARY,common\n1127,ER_CANT_FIND_DL_ENTRY,common\n1128,ER_FUNCTION_NOT_DEFINED,common\n1129,ER_HOST_IS_BLOCKED,common\n1130,ER_HOST_NOT_PRIVILEGED,common\n1131,ER_PASSWORD_ANONYMOUS_USER,common\n1132,ER_PASSWORD_NOT_ALLOWED,common\n1133,ER_PASSWORD_NO_MATCH,common\n1134,ER_UPDATE_INFO,common\n1135,ER_CANT_CREATE_THREAD,common\n1136,ER_WRONG_VALUE_COUNT_ON_ROW,common\n1137,ER_CANT_REOPEN_TABLE,common\n1138,ER_INVALID_USE_OF_NULL,common\n1139,ER_REGEXP_ERROR,common\n1140,ER_MIX_OF_GROUP_FUNC_AND_FIELDS,common\n1141,ER_NONEXISTING_GRANT,common\n1142,ER_TABLEACCESS_DENIED_ERROR,common\n1143,ER_COLUMNACCESS_DENIED_ERROR,common\n1144,ER_ILLEGAL_GRANT_FOR_TABLE,common\n1145,ER_GRANT_WRONG_HOST_OR_USER,common\n1146,ER_NO_SUCH_TABLE,common\n1147,ER_NONEXISTING_TABLE_GRANT,common\n1148,ER_NOT_ALLOWED_COMMAND,common\n1149,ER_SYNTAX_ERROR,common\n1150,ER_DELAYED_CANT_CHANGE_LOCK,mariadb\n1151,ER_TOO_MANY_DELAYED_THREADS,mariadb\n1152,ER_ABORTING_CONNECTION,common\n1153,ER_NET_PACKET_TOO_LARGE,common\n1154,ER_NET_READ_ERROR_FROM_PIPE,common\n1155,ER_NET_FCNTL_ERROR,common\n1156,ER_NET_PACKETS_OUT_OF_ORDER,common\n1157,ER_NET_UNCOMPRESS_ERROR,common\n1158,ER_NET_READ_ERROR,common\n1159,ER_NET_READ_INTERRUPTED,common\n1160,ER_NET_ERROR_ON_WRITE,common\n1161,ER_NET_WRITE_INTERRUPTED,common\n1162,ER_TOO_LONG_STRING,common\n1163,ER_TABLE_CANT_HANDLE_BLOB,common\n1164,ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,common\n1165,ER_DELAYED_INSERT_TABLE_LOCKED,mariadb\n1166,ER_WRONG_COLUMN_NAME,common\n1167,ER_WRONG_KEY_COLUMN,common\n1168,ER_WRONG_MRG_TABLE,common\n1169,ER_DUP_UNIQUE,common\n1170,ER_BLOB_KEY_WITHOUT_LENGTH,common\n1171,ER_PRIMARY_CANT_HAVE_NULL,common\n1172,ER_TOO_MANY_ROWS,common\n1173,ER_REQUIRES_PRIMARY_KEY,common\n1174,ER_NO_RAID_COMPILED,common\n1175,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,common\n1176,ER_KEY_DOES_NOT_EXISTS,mariadb\n1176,ER_KEY_DOES_NOT_EXITS,mysql\n1177,ER_CHECK_NO_SUCH_TABLE,common\n1178,ER_CHECK_NOT_IMPLEMENTED,common\n1179,ER_CANT_DO_THIS_DURING_AN_TRANSACTION,common\n1180,ER_ERROR_DURING_COMMIT,common\n1181,ER_ERROR_DURING_ROLLBACK,common\n1182,ER_ERROR_DURING_FLUSH_LOGS,common\n1183,ER_ERROR_DURING_CHECKPOINT,common\n1184,ER_NEW_ABORTING_CONNECTION,common\n1185,ER_DUMP_NOT_IMPLEMENTED,mysql\n1186,ER_FLUSH_MASTER_BINLOG_CLOSED,common\n1187,ER_INDEX_REBUILD,common\n1188,ER_MASTER,common\n1189,ER_MASTER_NET_READ,common\n1190,ER_MASTER_NET_WRITE,common\n1191,ER_FT_MATCHING_KEY_NOT_FOUND,common\n1192,ER_LOCK_OR_ACTIVE_TRANSACTION,common\n1193,ER_UNKNOWN_SYSTEM_VARIABLE,common\n1194,ER_CRASHED_ON_USAGE,common\n1195,ER_CRASHED_ON_REPAIR,common\n1196,ER_WARNING_NOT_COMPLETE_ROLLBACK,common\n1197,ER_TRANS_CACHE_FULL,common\n1198,ER_SLAVE_MUST_STOP,common\n1199,ER_SLAVE_NOT_RUNNING,common\n1200,ER_BAD_SLAVE,common\n1201,ER_MASTER_INFO,common\n1202,ER_SLAVE_THREAD,common\n1203,ER_TOO_MANY_USER_CONNECTIONS,common\n1204,ER_SET_CONSTANTS_ONLY,common\n1205,ER_LOCK_WAIT_TIMEOUT,common\n1206,ER_LOCK_TABLE_FULL,common\n1207,ER_READ_ONLY_TRANSACTION,common\n1208,ER_DROP_DB_WITH_READ_LOCK,common\n1209,ER_CREATE_DB_WITH_READ_LOCK,common\n1210,ER_WRONG_ARGUMENTS,common\n1211,ER_NO_PERMISSION_TO_CREATE_USER,common\n1212,ER_UNION_TABLES_IN_DIFFERENT_DIR,common\n1213,ER_LOCK_DEADLOCK,common\n1214,ER_TABLE_CANT_HANDLE_FT,common\n1215,ER_CANNOT_ADD_FOREIGN,common\n1216,ER_NO_REFERENCED_ROW,common\n1217,ER_ROW_IS_REFERENCED,common\n1218,ER_CONNECT_TO_MASTER,common\n1219,ER_QUERY_ON_MASTER,common\n1220,ER_ERROR_WHEN_EXECUTING_COMMAND,common\n1221,ER_WRONG_USAGE,common\n1222,ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,common\n1223,ER_CANT_UPDATE_WITH_READLOCK,common\n1224,ER_MIXING_NOT_ALLOWED,common\n1225,ER_DUP_ARGUMENT,common\n1226,ER_USER_LIMIT_REACHED,common\n1227,ER_SPECIFIC_ACCESS_DENIED_ERROR,common\n1228,ER_LOCAL_VARIABLE,common\n1229,ER_GLOBAL_VARIABLE,common\n1230,ER_NO_DEFAULT,common\n1231,ER_WRONG_VALUE_FOR_VAR,common\n1232,ER_WRONG_TYPE_FOR_VAR,common\n1233,ER_VAR_CANT_BE_READ,common\n1234,ER_CANT_USE_OPTION_HERE,common\n1235,ER_NOT_SUPPORTED_YET,common\n1236,ER_MASTER_FATAL_ERROR_READING_BINLOG,common\n1237,ER_SLAVE_IGNORED_TABLE,common\n1238,ER_INCORRECT_GLOBAL_LOCAL_VAR,common\n1239,ER_WRONG_FK_DEF,common\n1240,ER_KEY_REF_DO_NOT_MATCH_TABLE_REF,common\n1241,ER_OPERAND_COLUMNS,common\n1242,ER_SUBQUERY_NO_1_ROW,common\n1243,ER_UNKNOWN_STMT_HANDLER,common\n1244,ER_CORRUPT_HELP_DB,common\n1245,ER_CYCLIC_REFERENCE,common\n1246,ER_AUTO_CONVERT,common\n1247,ER_ILLEGAL_REFERENCE,common\n1248,ER_DERIVED_MUST_HAVE_ALIAS,common\n1249,ER_SELECT_REDUCED,common\n1250,ER_TABLENAME_NOT_ALLOWED_HERE,common\n1251,ER_NOT_SUPPORTED_AUTH_MODE,common\n1252,ER_SPATIAL_CANT_HAVE_NULL,common\n1253,ER_COLLATION_CHARSET_MISMATCH,common\n1254,ER_SLAVE_WAS_RUNNING,common\n1255,ER_SLAVE_WAS_NOT_RUNNING,common\n1256,ER_TOO_BIG_FOR_UNCOMPRESS,common\n1257,ER_ZLIB_Z_MEM_ERROR,common\n1258,ER_ZLIB_Z_BUF_ERROR,common\n1259,ER_ZLIB_Z_DATA_ERROR,common\n1260,ER_CUT_VALUE_GROUP_CONCAT,common\n1261,ER_WARN_TOO_FEW_RECORDS,common\n1262,ER_WARN_TOO_MANY_RECORDS,common\n1263,ER_WARN_NULL_TO_NOTNULL,common\n1264,ER_WARN_DATA_OUT_OF_RANGE,common\n1265,WARN_DATA_TRUNCATED,common\n1266,ER_WARN_USING_OTHER_HANDLER,common\n1267,ER_CANT_AGGREGATE_2COLLATIONS,common\n1268,ER_DROP_USER,common\n1269,ER_REVOKE_GRANTS,common\n1270,ER_CANT_AGGREGATE_3COLLATIONS,common\n1271,ER_CANT_AGGREGATE_NCOLLATIONS,common\n1272,ER_VARIABLE_IS_NOT_STRUCT,common\n1273,ER_UNKNOWN_COLLATION,common\n1274,ER_SLAVE_IGNORED_SSL_PARAMS,common\n1275,ER_SERVER_IS_IN_SECURE_AUTH_MODE,common\n1276,ER_WARN_FIELD_RESOLVED,common\n1277,ER_BAD_SLAVE_UNTIL_COND,common\n1278,ER_MISSING_SKIP_SLAVE,common\n1279,ER_UNTIL_COND_IGNORED,common\n1280,ER_WRONG_NAME_FOR_INDEX,common\n1281,ER_WRONG_NAME_FOR_CATALOG,common\n1282,ER_WARN_QC_RESIZE,common\n1283,ER_BAD_FT_COLUMN,common\n1284,ER_UNKNOWN_KEY_CACHE,common\n1285,ER_WARN_HOSTNAME_WONT_WORK,common\n1286,ER_UNKNOWN_STORAGE_ENGINE,common\n1287,ER_WARN_DEPRECATED_SYNTAX,common\n1288,ER_NON_UPDATABLE_TABLE,common\n1289,ER_FEATURE_DISABLED,common\n1290,ER_OPTION_PREVENTS_STATEMENT,common\n1291,ER_DUPLICATED_VALUE_IN_TYPE,common\n1292,ER_TRUNCATED_WRONG_VALUE,common\n1293,ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,common\n1294,ER_INVALID_ON_UPDATE,common\n1295,ER_UNSUPPORTED_PS,common\n1296,ER_GET_ERRMSG,common\n1297,ER_GET_TEMPORARY_ERRMSG,common\n1298,ER_UNKNOWN_TIME_ZONE,common\n1299,ER_WARN_INVALID_TIMESTAMP,common\n1300,ER_INVALID_CHARACTER_STRING,common\n1301,ER_WARN_ALLOWED_PACKET_OVERFLOWED,common\n1302,ER_CONFLICTING_DECLARATIONS,common\n1303,ER_SP_NO_RECURSIVE_CREATE,common\n1304,ER_SP_ALREADY_EXISTS,common\n1305,ER_SP_DOES_NOT_EXIST,common\n1306,ER_SP_DROP_FAILED,common\n1307,ER_SP_STORE_FAILED,common\n1308,ER_SP_LILABEL_MISMATCH,common\n1309,ER_SP_LABEL_REDEFINE,common\n1310,ER_SP_LABEL_MISMATCH,common\n1311,ER_SP_UNINIT_VAR,common\n1312,ER_SP_BADSELECT,common\n1313,ER_SP_BADRETURN,common\n1314,ER_SP_BADSTATEMENT,common\n1315,ER_UPDATE_LOG_DEPRECATED_IGNORED,common\n1316,ER_UPDATE_LOG_DEPRECATED_TRANSLATED,common\n1317,ER_QUERY_INTERRUPTED,common\n1318,ER_SP_WRONG_NO_OF_ARGS,common\n1319,ER_SP_COND_MISMATCH,common\n1320,ER_SP_NORETURN,common\n1321,ER_SP_NORETURNEND,common\n1322,ER_SP_BAD_CURSOR_QUERY,common\n1323,ER_SP_BAD_CURSOR_SELECT,common\n1324,ER_SP_CURSOR_MISMATCH,common\n1325,ER_SP_CURSOR_ALREADY_OPEN,common\n1326,ER_SP_CURSOR_NOT_OPEN,common\n1327,ER_SP_UNDECLARED_VAR,common\n1328,ER_SP_WRONG_NO_OF_FETCH_ARGS,common\n1329,ER_SP_FETCH_NO_DATA,common\n1330,ER_SP_DUP_PARAM,common\n1331,ER_SP_DUP_VAR,common\n1332,ER_SP_DUP_COND,common\n1333,ER_SP_DUP_CURS,common\n1334,ER_SP_CANT_ALTER,common\n1335,ER_SP_SUBSELECT_NYI,common\n1336,ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG,common\n1337,ER_SP_VARCOND_AFTER_CURSHNDLR,common\n1338,ER_SP_CURSOR_AFTER_HANDLER,common\n1339,ER_SP_CASE_NOT_FOUND,common\n1340,ER_FPARSER_TOO_BIG_FILE,common\n1341,ER_FPARSER_BAD_HEADER,common\n1342,ER_FPARSER_EOF_IN_COMMENT,common\n1343,ER_FPARSER_ERROR_IN_PARAMETER,common\n1344,ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER,common\n1345,ER_VIEW_NO_EXPLAIN,common\n1346,ER_FRM_UNKNOWN_TYPE,common\n1347,ER_WRONG_OBJECT,common\n1348,ER_NONUPDATEABLE_COLUMN,common\n1349,ER_VIEW_SELECT_DERIVED,mariadb\n1349,ER_VIEW_SELECT_DERIVED_UNUSED,mysql\n1350,ER_VIEW_SELECT_CLAUSE,common\n1351,ER_VIEW_SELECT_VARIABLE,common\n1352,ER_VIEW_SELECT_TMPTABLE,common\n1353,ER_VIEW_WRONG_LIST,common\n1354,ER_WARN_VIEW_MERGE,common\n1355,ER_WARN_VIEW_WITHOUT_KEY,common\n1356,ER_VIEW_INVALID,common\n1357,ER_SP_NO_DROP_SP,common\n1358,ER_SP_GOTO_IN_HNDLR,common\n1359,ER_TRG_ALREADY_EXISTS,common\n1360,ER_TRG_DOES_NOT_EXIST,common\n1361,ER_TRG_ON_VIEW_OR_TEMP_TABLE,common\n1362,ER_TRG_CANT_CHANGE_ROW,common\n1363,ER_TRG_NO_SUCH_ROW_IN_TRG,common\n1364,ER_NO_DEFAULT_FOR_FIELD,common\n1365,ER_DIVISION_BY_ZERO,common\n1366,ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,common\n1367,ER_ILLEGAL_VALUE_FOR_TYPE,common\n1368,ER_VIEW_NONUPD_CHECK,common\n1369,ER_VIEW_CHECK_FAILED,common\n1370,ER_PROCACCESS_DENIED_ERROR,common\n1371,ER_RELAY_LOG_FAIL,common\n1372,ER_PASSWD_LENGTH,common\n1373,ER_UNKNOWN_TARGET_BINLOG,common\n1374,ER_IO_ERR_LOG_INDEX_READ,common\n1375,ER_BINLOG_PURGE_PROHIBITED,common\n1376,ER_FSEEK_FAIL,common\n1377,ER_BINLOG_PURGE_FATAL_ERR,common\n1378,ER_LOG_IN_USE,common\n1379,ER_LOG_PURGE_UNKNOWN_ERR,common\n1380,ER_RELAY_LOG_INIT,common\n1381,ER_NO_BINARY_LOGGING,common\n1382,ER_RESERVED_SYNTAX,common\n1383,ER_WSAS_FAILED,common\n1384,ER_DIFF_GROUPS_PROC,common\n1385,ER_NO_GROUP_FOR_PROC,common\n1386,ER_ORDER_WITH_PROC,common\n1387,ER_LOGGING_PROHIBIT_CHANGING_OF,common\n1388,ER_NO_FILE_MAPPING,common\n1389,ER_WRONG_MAGIC,common\n1390,ER_PS_MANY_PARAM,common\n1391,ER_KEY_PART_0,common\n1392,ER_VIEW_CHECKSUM,common\n1393,ER_VIEW_MULTIUPDATE,common\n1394,ER_VIEW_NO_INSERT_FIELD_LIST,common\n1395,ER_VIEW_DELETE_MERGE_VIEW,common\n1396,ER_CANNOT_USER,common\n1397,ER_XAER_NOTA,common\n1398,ER_XAER_INVAL,common\n1399,ER_XAER_RMFAIL,common\n1400,ER_XAER_OUTSIDE,common\n1401,ER_XAER_RMERR,common\n1402,ER_XA_RBROLLBACK,common\n1403,ER_NONEXISTING_PROC_GRANT,common\n1404,ER_PROC_AUTO_GRANT_FAIL,common\n1405,ER_PROC_AUTO_REVOKE_FAIL,common\n1406,ER_DATA_TOO_LONG,common\n1407,ER_SP_BAD_SQLSTATE,common\n1408,ER_STARTUP,common\n1409,ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR,common\n1410,ER_CANT_CREATE_USER_WITH_GRANT,common\n1411,ER_WRONG_VALUE_FOR_TYPE,common\n1412,ER_TABLE_DEF_CHANGED,common\n1413,ER_SP_DUP_HANDLER,common\n1414,ER_SP_NOT_VAR_ARG,common\n1415,ER_SP_NO_RETSET,common\n1416,ER_CANT_CREATE_GEOMETRY_OBJECT,common\n1417,ER_FAILED_ROUTINE_BREAK_BINLOG,common\n1418,ER_BINLOG_UNSAFE_ROUTINE,common\n1419,ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,common\n1420,ER_EXEC_STMT_WITH_OPEN_CURSOR,common\n1421,ER_STMT_HAS_NO_OPEN_CURSOR,common\n1422,ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG,common\n1423,ER_NO_DEFAULT_FOR_VIEW_FIELD,common\n1424,ER_SP_NO_RECURSION,common\n1425,ER_TOO_BIG_SCALE,common\n1426,ER_TOO_BIG_PRECISION,common\n1427,ER_M_BIGGER_THAN_D,common\n1428,ER_WRONG_LOCK_OF_SYSTEM_TABLE,common\n1429,ER_CONNECT_TO_FOREIGN_DATA_SOURCE,common\n1430,ER_QUERY_ON_FOREIGN_DATA_SOURCE,common\n1431,ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST,common\n1432,ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE,common\n1433,ER_FOREIGN_DATA_STRING_INVALID,common\n1434,ER_CANT_CREATE_FEDERATED_TABLE,common\n1435,ER_TRG_IN_WRONG_SCHEMA,common\n1436,ER_STACK_OVERRUN_NEED_MORE,common\n1437,ER_TOO_LONG_BODY,common\n1438,ER_WARN_CANT_DROP_DEFAULT_KEYCACHE,common\n1439,ER_TOO_BIG_DISPLAYWIDTH,common\n1440,ER_XAER_DUPID,common\n1441,ER_DATETIME_FUNCTION_OVERFLOW,common\n1442,ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG,common\n1443,ER_VIEW_PREVENT_UPDATE,common\n1444,ER_PS_NO_RECURSION,common\n1445,ER_SP_CANT_SET_AUTOCOMMIT,common\n1446,ER_MALFORMED_DEFINER,common\n1447,ER_VIEW_FRM_NO_USER,common\n1448,ER_VIEW_OTHER_USER,common\n1449,ER_NO_SUCH_USER,common\n1450,ER_FORBID_SCHEMA_CHANGE,common\n1451,ER_ROW_IS_REFERENCED_2,common\n1452,ER_NO_REFERENCED_ROW_2,common\n1453,ER_SP_BAD_VAR_SHADOW,common\n1454,ER_TRG_NO_DEFINER,common\n1455,ER_OLD_FILE_FORMAT,common\n1456,ER_SP_RECURSION_LIMIT,common\n1457,ER_SP_PROC_TABLE_CORRUPT,common\n1458,ER_SP_WRONG_NAME,common\n1459,ER_TABLE_NEEDS_UPGRADE,common\n1460,ER_SP_NO_AGGREGATE,common\n1461,ER_MAX_PREPARED_STMT_COUNT_REACHED,common\n1462,ER_VIEW_RECURSIVE,common\n1463,ER_NON_GROUPING_FIELD_USED,common\n1464,ER_TABLE_CANT_HANDLE_SPKEYS,common\n1465,ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA,common\n1466,ER_REMOVED_SPACES,common\n1467,ER_AUTOINC_READ_FAILED,common\n1468,ER_USERNAME,common\n1469,ER_HOSTNAME,common\n1470,ER_WRONG_STRING_LENGTH,common\n1471,ER_NON_INSERTABLE_TABLE,common\n1472,ER_ADMIN_WRONG_MRG_TABLE,common\n1473,ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,common\n1474,ER_NAME_BECOMES_EMPTY,common\n1475,ER_AMBIGUOUS_FIELD_TERM,common\n1476,ER_FOREIGN_SERVER_EXISTS,common\n1477,ER_FOREIGN_SERVER_DOESNT_EXIST,common\n1478,ER_ILLEGAL_HA_CREATE_OPTION,common\n1479,ER_PARTITION_REQUIRES_VALUES_ERROR,common\n1480,ER_PARTITION_WRONG_VALUES_ERROR,common\n1481,ER_PARTITION_MAXVALUE_ERROR,common\n1482,ER_PARTITION_SUBPARTITION_ERROR,common\n1483,ER_PARTITION_SUBPART_MIX_ERROR,common\n1484,ER_PARTITION_WRONG_NO_PART_ERROR,common\n1485,ER_PARTITION_WRONG_NO_SUBPART_ERROR,common\n1486,ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,common\n1487,ER_NOT_CONSTANT_EXPRESSION,mariadb\n1487,ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR,mysql\n1488,ER_FIELD_NOT_FOUND_PART_ERROR,common\n1489,ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR,common\n1490,ER_INCONSISTENT_PARTITION_INFO_ERROR,common\n1491,ER_PARTITION_FUNC_NOT_ALLOWED_ERROR,common\n1492,ER_PARTITIONS_MUST_BE_DEFINED_ERROR,common\n1493,ER_RANGE_NOT_INCREASING_ERROR,common\n1494,ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR,common\n1495,ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR,common\n1496,ER_PARTITION_ENTRY_ERROR,common\n1497,ER_MIX_HANDLER_ERROR,common\n1498,ER_PARTITION_NOT_DEFINED_ERROR,common\n1499,ER_TOO_MANY_PARTITIONS_ERROR,common\n1500,ER_SUBPARTITION_ERROR,common\n1501,ER_CANT_CREATE_HANDLER_FILE,common\n1502,ER_BLOB_FIELD_IN_PART_FUNC_ERROR,common\n1503,ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF,common\n1504,ER_NO_PARTS_ERROR,common\n1505,ER_PARTITION_MGMT_ON_NONPARTITIONED,common\n1506,ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING,mariadb\n1506,ER_FOREIGN_KEY_ON_PARTITIONED,mysql\n1507,ER_DROP_PARTITION_NON_EXISTENT,common\n1508,ER_DROP_LAST_PARTITION,common\n1509,ER_COALESCE_ONLY_ON_HASH_PARTITION,common\n1510,ER_REORG_HASH_ONLY_ON_SAME_NO,common\n1511,ER_REORG_NO_PARAM_ERROR,common\n1512,ER_ONLY_ON_RANGE_LIST_PARTITION,common\n1513,ER_ADD_PARTITION_SUBPART_ERROR,common\n1514,ER_ADD_PARTITION_NO_NEW_PARTITION,common\n1515,ER_COALESCE_PARTITION_NO_PARTITION,common\n1516,ER_REORG_PARTITION_NOT_EXIST,common\n1517,ER_SAME_NAME_PARTITION,common\n1518,ER_NO_BINLOG_ERROR,common\n1519,ER_CONSECUTIVE_REORG_PARTITIONS,common\n1520,ER_REORG_OUTSIDE_RANGE,common\n1521,ER_PARTITION_FUNCTION_FAILURE,common\n1522,ER_PART_STATE_ERROR,common\n1523,ER_LIMITED_PART_RANGE,common\n1524,ER_PLUGIN_IS_NOT_LOADED,common\n1525,ER_WRONG_VALUE,common\n1526,ER_NO_PARTITION_FOR_GIVEN_VALUE,common\n1527,ER_FILEGROUP_OPTION_ONLY_ONCE,common\n1528,ER_CREATE_FILEGROUP_FAILED,common\n1529,ER_DROP_FILEGROUP_FAILED,common\n1530,ER_TABLESPACE_AUTO_EXTEND_ERROR,common\n1531,ER_WRONG_SIZE_NUMBER,common\n1532,ER_SIZE_OVERFLOW_ERROR,common\n1533,ER_ALTER_FILEGROUP_FAILED,common\n1534,ER_BINLOG_ROW_LOGGING_FAILED,common\n1535,ER_BINLOG_ROW_WRONG_TABLE_DEF,common\n1536,ER_BINLOG_ROW_RBR_TO_SBR,common\n1537,ER_EVENT_ALREADY_EXISTS,common\n1538,ER_EVENT_STORE_FAILED,common\n1539,ER_EVENT_DOES_NOT_EXIST,common\n1540,ER_EVENT_CANT_ALTER,common\n1541,ER_EVENT_DROP_FAILED,common\n1542,ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG,common\n1543,ER_EVENT_ENDS_BEFORE_STARTS,common\n1544,ER_EVENT_EXEC_TIME_IN_THE_PAST,common\n1545,ER_EVENT_OPEN_TABLE_FAILED,common\n1546,ER_EVENT_NEITHER_M_EXPR_NOR_M_AT,common\n1547,ER_OBSOLETE_COL_COUNT_DOESNT_MATCH_CORRUPTED,mysql\n1548,ER_OBSOLETE_CANNOT_LOAD_FROM_TABLE,mysql\n1549,ER_EVENT_CANNOT_DELETE,common\n1550,ER_EVENT_COMPILE_ERROR,common\n1551,ER_EVENT_SAME_NAME,common\n1552,ER_EVENT_DATA_TOO_LONG,common\n1553,ER_DROP_INDEX_FK,common\n1554,ER_WARN_DEPRECATED_SYNTAX_WITH_VER,common\n1555,ER_CANT_WRITE_LOCK_LOG_TABLE,common\n1556,ER_CANT_LOCK_LOG_TABLE,common\n1557,ER_FOREIGN_DUPLICATE_KEY_OLD_UNUSED,mysql\n1558,ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE,common\n1559,ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR,common\n1560,ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT,common\n1561,ER_NDB_CANT_SWITCH_BINLOG_FORMAT,mysql\n1562,ER_PARTITION_NO_TEMPORARY,common\n1563,ER_PARTITION_CONST_DOMAIN_ERROR,common\n1564,ER_PARTITION_FUNCTION_IS_NOT_ALLOWED,common\n1565,ER_DDL_LOG_ERROR,common\n1566,ER_NULL_IN_VALUES_LESS_THAN,common\n1567,ER_WRONG_PARTITION_NAME,common\n1568,ER_CANT_CHANGE_TX_CHARACTERISTICS,common\n1569,ER_DUP_ENTRY_AUTOINCREMENT_CASE,common\n1570,ER_EVENT_MODIFY_QUEUE_ERROR,common\n1571,ER_EVENT_SET_VAR_ERROR,common\n1572,ER_PARTITION_MERGE_ERROR,common\n1573,ER_CANT_ACTIVATE_LOG,common\n1574,ER_RBR_NOT_AVAILABLE,common\n1575,ER_BASE64_DECODE_ERROR,common\n1576,ER_EVENT_RECURSION_FORBIDDEN,common\n1577,ER_EVENTS_DB_ERROR,common\n1578,ER_ONLY_INTEGERS_ALLOWED,common\n1579,ER_UNSUPORTED_LOG_ENGINE,common\n1580,ER_BAD_LOG_STATEMENT,common\n1581,ER_CANT_RENAME_LOG_TABLE,common\n1582,ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT,common\n1583,ER_WRONG_PARAMETERS_TO_NATIVE_FCT,common\n1584,ER_WRONG_PARAMETERS_TO_STORED_FCT,common\n1585,ER_NATIVE_FCT_NAME_COLLISION,common\n1586,ER_DUP_ENTRY_WITH_KEY_NAME,common\n1587,ER_BINLOG_PURGE_EMFILE,common\n1588,ER_EVENT_CANNOT_CREATE_IN_THE_PAST,common\n1589,ER_EVENT_CANNOT_ALTER_IN_THE_PAST,common\n1590,ER_SLAVE_INCIDENT,common\n1591,ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT,common\n1592,ER_BINLOG_UNSAFE_STATEMENT,common\n1593,ER_SLAVE_FATAL_ERROR,mariadb\n1593,ER_BINLOG_FATAL_ERROR,mysql\n1594,ER_SLAVE_RELAY_LOG_READ_FAILURE,common\n1595,ER_SLAVE_RELAY_LOG_WRITE_FAILURE,common\n1596,ER_SLAVE_CREATE_EVENT_FAILURE,common\n1597,ER_SLAVE_MASTER_COM_FAILURE,common\n1598,ER_BINLOG_LOGGING_IMPOSSIBLE,common\n1599,ER_VIEW_NO_CREATION_CTX,common\n1600,ER_VIEW_INVALID_CREATION_CTX,common\n1601,ER_SR_INVALID_CREATION_CTX,common\n1602,ER_TRG_CORRUPTED_FILE,common\n1603,ER_TRG_NO_CREATION_CTX,common\n1604,ER_TRG_INVALID_CREATION_CTX,common\n1605,ER_EVENT_INVALID_CREATION_CTX,common\n1606,ER_TRG_CANT_OPEN_TABLE,common\n1607,ER_CANT_CREATE_SROUTINE,common\n1608,ER_NEVER_USED,mysql\n1609,ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,common\n1610,ER_SLAVE_CORRUPT_EVENT,common\n1611,ER_LOAD_DATA_INVALID_COLUMN,mariadb\n1611,ER_LOAD_DATA_INVALID_COLUMN_UNUSED,mysql\n1612,ER_LOG_PURGE_NO_FILE,common\n1613,ER_XA_RBTIMEOUT,common\n1614,ER_XA_RBDEADLOCK,common\n1615,ER_NEED_REPREPARE,common\n1616,ER_DELAYED_NOT_SUPPORTED,common\n1617,WARN_NO_MASTER_INFO,common\n1618,WARN_OPTION_IGNORED,common\n1619,ER_PLUGIN_DELETE_BUILTIN,common\n1620,WARN_PLUGIN_BUSY,common\n1621,ER_VARIABLE_IS_READONLY,common\n1622,ER_WARN_ENGINE_TRANSACTION_ROLLBACK,common\n1623,ER_SLAVE_HEARTBEAT_FAILURE,common\n1624,ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE,common\n1625,ER_NDB_REPLICATION_SCHEMA_ERROR,mysql\n1626,ER_CONFLICT_FN_PARSE_ERROR,common\n1627,ER_EXCEPTIONS_WRITE_ERROR,common\n1628,ER_TOO_LONG_TABLE_COMMENT,common\n1629,ER_TOO_LONG_FIELD_COMMENT,common\n1630,ER_FUNC_INEXISTENT_NAME_COLLISION,common\n1631,ER_DATABASE_NAME,common\n1632,ER_TABLE_NAME,common\n1633,ER_PARTITION_NAME,common\n1634,ER_SUBPARTITION_NAME,common\n1635,ER_TEMPORARY_NAME,common\n1636,ER_RENAMED_NAME,common\n1637,ER_TOO_MANY_CONCURRENT_TRXS,common\n1638,WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED,common\n1639,ER_DEBUG_SYNC_TIMEOUT,common\n1640,ER_DEBUG_SYNC_HIT_LIMIT,common\n1641,ER_DUP_SIGNAL_SET,common\n1642,ER_SIGNAL_WARN,common\n1643,ER_SIGNAL_NOT_FOUND,common\n1644,ER_SIGNAL_EXCEPTION,common\n1645,ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER,common\n1646,ER_SIGNAL_BAD_CONDITION_TYPE,common\n1647,WARN_COND_ITEM_TRUNCATED,common\n1648,ER_COND_ITEM_TOO_LONG,common\n1649,ER_UNKNOWN_LOCALE,common\n1650,ER_SLAVE_IGNORE_SERVER_IDS,common\n1651,ER_QUERY_CACHE_DISABLED,common\n1652,ER_SAME_NAME_PARTITION_FIELD,common\n1653,ER_PARTITION_COLUMN_LIST_ERROR,common\n1654,ER_WRONG_TYPE_COLUMN_VALUE_ERROR,common\n1655,ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR,common\n1656,ER_MAXVALUE_IN_VALUES_IN,common\n1657,ER_TOO_MANY_VALUES_ERROR,common\n1658,ER_ROW_SINGLE_PARTITION_FIELD_ERROR,common\n1659,ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD,common\n1660,ER_PARTITION_FIELDS_TOO_LONG,common\n1661,ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE,common\n1662,ER_BINLOG_ROW_MODE_AND_STMT_ENGINE,common\n1663,ER_BINLOG_UNSAFE_AND_STMT_ENGINE,common\n1664,ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE,common\n1665,ER_BINLOG_STMT_MODE_AND_ROW_ENGINE,common\n1666,ER_BINLOG_ROW_INJECTION_AND_STMT_MODE,common\n1667,ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,common\n1668,ER_BINLOG_UNSAFE_LIMIT,common\n1669,ER_BINLOG_UNSAFE_INSERT_DELAYED,mariadb\n1670,ER_BINLOG_UNSAFE_SYSTEM_TABLE,common\n1671,ER_BINLOG_UNSAFE_AUTOINC_COLUMNS,common\n1672,ER_BINLOG_UNSAFE_UDF,common\n1673,ER_BINLOG_UNSAFE_SYSTEM_VARIABLE,common\n1674,ER_BINLOG_UNSAFE_SYSTEM_FUNCTION,common\n1675,ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS,common\n1676,ER_MESSAGE_AND_STATEMENT,common\n1677,ER_SLAVE_CONVERSION_FAILED,common\n1678,ER_SLAVE_CANT_CREATE_CONVERSION,common\n1679,ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT,common\n1680,ER_PATH_LENGTH,common\n1681,ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT,common\n1682,ER_WRONG_NATIVE_TABLE_STRUCTURE,common\n1683,ER_WRONG_PERFSCHEMA_USAGE,common\n1684,ER_WARN_I_S_SKIPPED_TABLE,common\n1685,ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT,common\n1686,ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT,common\n1687,ER_SPATIAL_MUST_HAVE_GEOM_COL,common\n1688,ER_TOO_LONG_INDEX_COMMENT,common\n1689,ER_LOCK_ABORTED,common\n1690,ER_DATA_OUT_OF_RANGE,common\n1691,ER_WRONG_SPVAR_TYPE_IN_LIMIT,common\n1692,ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,common\n1693,ER_BINLOG_UNSAFE_MIXED_STATEMENT,common\n1694,ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN,common\n1695,ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN,common\n1696,ER_FAILED_READ_FROM_PAR_FILE,common\n1697,ER_VALUES_IS_NOT_INT_TYPE_ERROR,common\n1698,ER_ACCESS_DENIED_NO_PASSWORD_ERROR,common\n1699,ER_SET_PASSWORD_AUTH_PLUGIN,common\n1700,ER_GRANT_PLUGIN_USER_EXISTS,common\n1701,ER_TRUNCATE_ILLEGAL_FK,common\n1702,ER_PLUGIN_IS_PERMANENT,common\n1703,ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN,common\n1704,ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX,common\n1705,ER_STMT_CACHE_FULL,common\n1706,ER_MULTI_UPDATE_KEY_CONFLICT,common\n1707,ER_TABLE_NEEDS_REBUILD,common\n1708,WARN_OPTION_BELOW_LIMIT,common\n1709,ER_INDEX_COLUMN_TOO_LONG,common\n1710,ER_ERROR_IN_TRIGGER_BODY,common\n1711,ER_ERROR_IN_UNKNOWN_TRIGGER_BODY,common\n1712,ER_INDEX_CORRUPT,common\n1713,ER_UNDO_RECORD_TOO_BIG,common\n1714,ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT,common\n1715,ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE,common\n1716,ER_BINLOG_UNSAFE_REPLACE_SELECT,common\n1717,ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT,common\n1718,ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT,common\n1719,ER_BINLOG_UNSAFE_UPDATE_IGNORE,common\n1720,ER_PLUGIN_NO_UNINSTALL,mysql\n1721,ER_PLUGIN_NO_INSTALL,mysql\n1722,ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT,common\n1723,ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,common\n1724,ER_BINLOG_UNSAFE_INSERT_TWO_KEYS,common\n1725,ER_TABLE_IN_FK_CHECK,mysql\n1726,ER_VERS_NOT_ALLOWED,mariadb\n1726,ER_UNSUPPORTED_ENGINE,mysql\n1727,ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST,common\n1728,ER_CANNOT_LOAD_FROM_TABLE_V2,common\n1729,ER_MASTER_DELAY_VALUE_OUT_OF_RANGE,common\n1730,ER_ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT,common\n1731,ER_PARTITION_EXCHANGE_DIFFERENT_OPTION,common\n1732,ER_PARTITION_EXCHANGE_PART_TABLE,common\n1733,ER_PARTITION_EXCHANGE_TEMP_TABLE,common\n1734,ER_PARTITION_INSTEAD_OF_SUBPARTITION,common\n1735,ER_UNKNOWN_PARTITION,common\n1736,ER_TABLES_DIFFERENT_METADATA,common\n1737,ER_ROW_DOES_NOT_MATCH_PARTITION,common\n1738,ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX,common\n1739,ER_WARN_INDEX_NOT_APPLICABLE,common\n1740,ER_PARTITION_EXCHANGE_FOREIGN_KEY,common\n1741,ER_NO_SUCH_KEY_VALUE,common\n1742,ER_VALUE_TOO_LONG,mariadb\n1742,ER_RPL_INFO_DATA_TOO_LONG,mysql\n1743,ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE,common\n1744,ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE,common\n1745,ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX,common\n1746,ER_CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT,common\n1747,ER_PARTITION_CLAUSE_ON_NONPARTITIONED,common\n1748,ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET,common\n1750,ER_CHANGE_RPL_INFO_REPOSITORY_FAILURE,common\n1751,ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE,common\n1752,ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE,common\n1753,ER_MTS_FEATURE_IS_NOT_SUPPORTED,common\n1754,ER_MTS_UPDATED_DBS_GREATER_MAX,common\n1755,ER_MTS_CANT_PARALLEL,common\n1756,ER_MTS_INCONSISTENT_DATA,common\n1757,ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING,common\n1758,ER_DA_INVALID_CONDITION_NUMBER,common\n1759,ER_INSECURE_PLAIN_TEXT,common\n1760,ER_INSECURE_CHANGE_MASTER,common\n1761,ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO,common\n1762,ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO,common\n1763,ER_SQLTHREAD_WITH_SECURE_SLAVE,common\n1764,ER_TABLE_HAS_NO_FT,common\n1765,ER_VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER,common\n1766,ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION,common\n1767,ER_GTID_NEXT_IS_NOT_IN_GTID_NEXT_LIST,common\n1768,ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION_WHEN_GTID_NEXT_LIST_IS_NULL,mariadb\n1768,ER_CANT_CHANGE_GTID_NEXT_IN_TRANSACTION,mysql\n1769,ER_SET_STATEMENT_CANNOT_INVOKE_FUNCTION,common\n1770,ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL,common\n1771,ER_SKIPPING_LOGGED_TRANSACTION,common\n1772,ER_MALFORMED_GTID_SET_SPECIFICATION,common\n1773,ER_MALFORMED_GTID_SET_ENCODING,common\n1774,ER_MALFORMED_GTID_SPECIFICATION,common\n1775,ER_GNO_EXHAUSTED,common\n1776,ER_BAD_SLAVE_AUTO_POSITION,common\n1777,ER_AUTO_POSITION_REQUIRES_GTID_MODE_ON,mariadb\n1777,ER_AUTO_POSITION_REQUIRES_GTID_MODE_NOT_OFF,mysql\n1778,ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET,common\n1779,ER_GTID_MODE_2_OR_3_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON,mariadb\n1779,ER_GTID_MODE_ON_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON,mysql\n1780,ER_GTID_MODE_REQUIRES_BINLOG,common\n1781,ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF,common\n1782,ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON,common\n1783,ER_CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF,common\n1784,ER_FOUND_GTID_EVENT_WHEN_GTID_MODE_IS_OFF,mariadb\n1785,ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE,common\n1786,ER_GTID_UNSAFE_CREATE_SELECT,common\n1787,ER_GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION,common\n1788,ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME,common\n1789,ER_MASTER_HAS_PURGED_REQUIRED_GTIDS,common\n1790,ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID,common\n1791,ER_UNKNOWN_EXPLAIN_FORMAT,common\n1792,ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION,common\n1793,ER_TOO_LONG_TABLE_PARTITION_COMMENT,common\n1794,ER_SLAVE_CONFIGURATION,common\n1795,ER_INNODB_FT_LIMIT,common\n1796,ER_INNODB_NO_FT_TEMP_TABLE,common\n1797,ER_INNODB_FT_WRONG_DOCID_COLUMN,common\n1798,ER_INNODB_FT_WRONG_DOCID_INDEX,common\n1799,ER_INNODB_ONLINE_LOG_TOO_BIG,common\n1800,ER_UNKNOWN_ALTER_ALGORITHM,common\n1801,ER_UNKNOWN_ALTER_LOCK,common\n1802,ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS,common\n1803,ER_MTS_RECOVERY_FAILURE,common\n1804,ER_MTS_RESET_WORKERS,common\n1805,ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2,common\n1806,ER_SLAVE_SILENT_RETRY_TRANSACTION,common\n1807,ER_DISCARD_FK_CHECKS_RUNNING,mysql\n1808,ER_TABLE_SCHEMA_MISMATCH,common\n1809,ER_TABLE_IN_SYSTEM_TABLESPACE,common\n1810,ER_IO_READ_ERROR,common\n1811,ER_IO_WRITE_ERROR,common\n1812,ER_TABLESPACE_MISSING,common\n1813,ER_TABLESPACE_EXISTS,common\n1814,ER_TABLESPACE_DISCARDED,common\n1815,ER_INTERNAL_ERROR,common\n1816,ER_INNODB_IMPORT_ERROR,common\n1817,ER_INNODB_INDEX_CORRUPT,common\n1818,ER_INVALID_YEAR_COLUMN_LENGTH,common\n1819,ER_NOT_VALID_PASSWORD,common\n1820,ER_MUST_CHANGE_PASSWORD,common\n1821,ER_FK_NO_INDEX_CHILD,common\n1822,ER_FK_NO_INDEX_PARENT,common\n1823,ER_FK_FAIL_ADD_SYSTEM,common\n1824,ER_FK_CANNOT_OPEN_PARENT,common\n1825,ER_FK_INCORRECT_OPTION,common\n1826,ER_DUP_CONSTRAINT_NAME,mariadb\n1826,ER_FK_DUP_NAME,mysql\n1827,ER_PASSWORD_FORMAT,common\n1828,ER_FK_COLUMN_CANNOT_DROP,common\n1829,ER_FK_COLUMN_CANNOT_DROP_CHILD,common\n1830,ER_FK_COLUMN_NOT_NULL,common\n1831,ER_DUP_INDEX,common\n1832,ER_FK_COLUMN_CANNOT_CHANGE,common\n1833,ER_FK_COLUMN_CANNOT_CHANGE_CHILD,common\n1834,ER_FK_CANNOT_DELETE_PARENT,mariadb\n1835,ER_MALFORMED_PACKET,common\n1836,ER_READ_ONLY_MODE,common\n1837,ER_GTID_NEXT_TYPE_UNDEFINED_GROUP,mariadb\n1837,ER_GTID_NEXT_TYPE_UNDEFINED_GTID,mysql\n1838,ER_VARIABLE_NOT_SETTABLE_IN_SP,common\n1839,ER_CANT_SET_GTID_PURGED_WHEN_GTID_MODE_IS_OFF,common\n1840,ER_CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY,common\n1841,ER_CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY,common\n1842,ER_GTID_PURGED_WAS_CHANGED,common\n1843,ER_GTID_EXECUTED_WAS_CHANGED,common\n1844,ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES,common\n1845,ER_ALTER_OPERATION_NOT_SUPPORTED,common\n1846,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON,common\n1847,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY,common\n1848,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION,common\n1849,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME,common\n1850,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE,common\n1851,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK,common\n1852,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE,mariadb\n1853,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK,common\n1854,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC,common\n1855,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS,common\n1856,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS,common\n1857,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS,common\n1858,ER_SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE,common\n1859,ER_DUP_UNKNOWN_IN_INDEX,common\n1860,ER_IDENT_CAUSES_TOO_LONG_PATH,common\n1861,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL,common\n1862,ER_MUST_CHANGE_PASSWORD_LOGIN,common\n1863,ER_ROW_IN_WRONG_PARTITION,common\n1864,ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX,common\n1865,ER_INNODB_NO_FT_USES_PARSER,common\n1866,ER_BINLOG_LOGICAL_CORRUPTION,common\n1867,ER_WARN_PURGE_LOG_IN_USE,common\n1868,ER_WARN_PURGE_LOG_IS_ACTIVE,common\n1869,ER_AUTO_INCREMENT_CONFLICT,common\n1870,WARN_ON_BLOCKHOLE_IN_RBR,common\n1871,ER_SLAVE_MI_INIT_REPOSITORY,common\n1872,ER_SLAVE_RLI_INIT_REPOSITORY,common\n1873,ER_ACCESS_DENIED_CHANGE_USER_ERROR,common\n1874,ER_INNODB_READ_ONLY,common\n1875,ER_STOP_SLAVE_SQL_THREAD_TIMEOUT,common\n1876,ER_STOP_SLAVE_IO_THREAD_TIMEOUT,common\n1877,ER_TABLE_CORRUPT,common\n1878,ER_TEMP_FILE_WRITE_FAILURE,common\n1879,ER_INNODB_FT_AUX_NOT_HEX_ID,common\n1880,ER_OLD_TEMPORALS_UPGRADED,mysql\n1881,ER_INNODB_FORCED_RECOVERY,mysql\n1882,ER_AES_INVALID_IV,mysql\n1883,ER_PLUGIN_CANNOT_BE_UNINSTALLED,mysql\n1884,ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_ASSIGNED_GTID,mysql\n1885,ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER,mysql\n1886,ER_MISSING_KEY,mysql\n1887,WARN_NAMED_PIPE_ACCESS_EVERYONE,mysql\n1888,ER_FOUND_MISSING_GTIDS,mysql\n1901,ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED,mariadb\n1903,ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN,mariadb\n1904,ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN,mariadb\n1905,ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN,mariadb\n1906,ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,mariadb\n1907,ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN,mariadb\n1910,ER_UNSUPPORTED_ENGINE_FOR_GENERATED_COLUMNS,mariadb\n1911,ER_UNKNOWN_OPTION,mariadb\n1912,ER_BAD_OPTION_VALUE,mariadb\n1916,ER_DATA_OVERFLOW,mariadb\n1917,ER_DATA_TRUNCATED,mariadb\n1918,ER_BAD_DATA,mariadb\n1919,ER_DYN_COL_WRONG_FORMAT,mariadb\n1920,ER_DYN_COL_IMPLEMENTATION_LIMIT,mariadb\n1921,ER_DYN_COL_DATA,mariadb\n1922,ER_DYN_COL_WRONG_CHARSET,mariadb\n1923,ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES,mariadb\n1924,ER_QUERY_CACHE_IS_DISABLED,mariadb\n1925,ER_QUERY_CACHE_IS_GLOBALY_DISABLED,mariadb\n1926,ER_VIEW_ORDERBY_IGNORED,mariadb\n1927,ER_CONNECTION_KILLED,mariadb\n1929,ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SKIP_REPLICATION,mariadb\n1930,ER_STORED_FUNCTION_PREVENTS_SWITCH_SKIP_REPLICATION,mariadb\n1931,ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT,mariadb\n1932,ER_NO_SUCH_TABLE_IN_ENGINE,mariadb\n1933,ER_TARGET_NOT_EXPLAINABLE,mariadb\n1934,ER_CONNECTION_ALREADY_EXISTS,mariadb\n1935,ER_MASTER_LOG_PREFIX,mariadb\n1936,ER_CANT_START_STOP_SLAVE,mariadb\n1937,ER_SLAVE_STARTED,mariadb\n1938,ER_SLAVE_STOPPED,mariadb\n1939,ER_SQL_DISCOVER_ERROR,mariadb\n1940,ER_FAILED_GTID_STATE_INIT,mariadb\n1941,ER_INCORRECT_GTID_STATE,mariadb\n1942,ER_CANNOT_UPDATE_GTID_STATE,mariadb\n1943,ER_DUPLICATE_GTID_DOMAIN,mariadb\n1944,ER_GTID_OPEN_TABLE_FAILED,mariadb\n1945,ER_GTID_POSITION_NOT_FOUND_IN_BINLOG,mariadb\n1946,ER_CANNOT_LOAD_SLAVE_GTID_STATE,mariadb\n1947,ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG,mariadb\n1948,ER_MASTER_GTID_POS_MISSING_DOMAIN,mariadb\n1949,ER_UNTIL_REQUIRES_USING_GTID,mariadb\n1950,ER_GTID_STRICT_OUT_OF_ORDER,mariadb\n1951,ER_GTID_START_FROM_BINLOG_HOLE,mariadb\n1952,ER_SLAVE_UNEXPECTED_MASTER_SWITCH,mariadb\n1953,ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO,mariadb\n1954,ER_STORED_FUNCTION_PREVENTS_SWITCH_GTID_DOMAIN_ID_SEQ_NO,mariadb\n1955,ER_GTID_POSITION_NOT_FOUND_IN_BINLOG2,mariadb\n1956,ER_BINLOG_MUST_BE_EMPTY,mariadb\n1957,ER_NO_SUCH_QUERY,mariadb\n1958,ER_BAD_BASE64_DATA,mariadb\n1959,ER_INVALID_ROLE,mariadb\n1960,ER_INVALID_CURRENT_USER,mariadb\n1961,ER_CANNOT_GRANT_ROLE,mariadb\n1962,ER_CANNOT_REVOKE_ROLE,mariadb\n1963,ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE,mariadb\n1964,ER_PRIOR_COMMIT_FAILED,mariadb\n1965,ER_IT_IS_A_VIEW,mariadb\n1966,ER_SLAVE_SKIP_NOT_IN_GTID,mariadb\n1967,ER_TABLE_DEFINITION_TOO_BIG,mariadb\n1968,ER_PLUGIN_INSTALLED,mariadb\n1969,ER_STATEMENT_TIMEOUT,mariadb\n1970,ER_SUBQUERIES_NOT_SUPPORTED,mariadb\n1971,ER_SET_STATEMENT_NOT_SUPPORTED,mariadb\n1973,ER_USER_CREATE_EXISTS,mariadb\n1974,ER_USER_DROP_EXISTS,mariadb\n1975,ER_ROLE_CREATE_EXISTS,mariadb\n1976,ER_ROLE_DROP_EXISTS,mariadb\n1977,ER_CANNOT_CONVERT_CHARACTER,mariadb\n1978,ER_INVALID_DEFAULT_VALUE_FOR_FIELD,mariadb\n1979,ER_KILL_QUERY_DENIED_ERROR,mariadb\n1980,ER_NO_EIS_FOR_FIELD,mariadb\n1981,ER_WARN_AGGFUNC_DEPENDENCE,mariadb\n1982,WARN_INNODB_PARTITION_OPTION_IGNORED,mariadb\n3000,ER_FILE_CORRUPT,mariadb\n3000,ER_FILE_CORRUPT,mysql\n3001,ER_ERROR_ON_MASTER,mariadb\n3001,ER_ERROR_ON_MASTER,mysql\n3002,ER_INCONSISTENT_ERROR,mariadb\n3002,ER_INCONSISTENT_ERROR,mysql\n3003,ER_STORAGE_ENGINE_NOT_LOADED,mariadb\n3003,ER_STORAGE_ENGINE_NOT_LOADED,mysql\n3004,ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER,mariadb\n3004,ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER,mysql\n3005,ER_WARN_LEGACY_SYNTAX_CONVERTED,mariadb\n3005,ER_WARN_LEGACY_SYNTAX_CONVERTED,mysql\n3006,ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN,mariadb\n3006,ER_BINLOG_UNSAFE_FULLTEXT_PLUGIN,mysql\n3007,ER_CANNOT_DISCARD_TEMPORARY_TABLE,mariadb\n3007,ER_CANNOT_DISCARD_TEMPORARY_TABLE,mysql\n3008,ER_FK_DEPTH_EXCEEDED,mariadb\n3008,ER_FK_DEPTH_EXCEEDED,mysql\n3009,ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2,mariadb\n3009,ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE_V2,mysql\n3010,ER_WARN_TRIGGER_DOESNT_HAVE_CREATED,mariadb\n3010,ER_WARN_TRIGGER_DOESNT_HAVE_CREATED,mysql\n3011,ER_REFERENCED_TRG_DOES_NOT_EXIST_MYSQL,mariadb\n3011,ER_REFERENCED_TRG_DOES_NOT_EXIST,mysql\n3012,ER_EXPLAIN_NOT_SUPPORTED,mariadb\n3012,ER_EXPLAIN_NOT_SUPPORTED,mysql\n3013,ER_INVALID_FIELD_SIZE,mariadb\n3013,ER_INVALID_FIELD_SIZE,mysql\n3014,ER_MISSING_HA_CREATE_OPTION,mariadb\n3014,ER_MISSING_HA_CREATE_OPTION,mysql\n3015,ER_ENGINE_OUT_OF_MEMORY,mariadb\n3015,ER_ENGINE_OUT_OF_MEMORY,mysql\n3016,ER_PASSWORD_EXPIRE_ANONYMOUS_USER,mariadb\n3016,ER_PASSWORD_EXPIRE_ANONYMOUS_USER,mysql\n3017,ER_SLAVE_SQL_THREAD_MUST_STOP,mariadb\n3017,ER_SLAVE_SQL_THREAD_MUST_STOP,mysql\n3018,ER_NO_FT_MATERIALIZED_SUBQUERY,mariadb\n3018,ER_NO_FT_MATERIALIZED_SUBQUERY,mysql\n3019,ER_INNODB_UNDO_LOG_FULL,mariadb\n3019,ER_INNODB_UNDO_LOG_FULL,mysql\n3020,ER_INVALID_ARGUMENT_FOR_LOGARITHM,mariadb\n3020,ER_INVALID_ARGUMENT_FOR_LOGARITHM,mysql\n3021,ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP,mariadb\n3021,ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP,mysql\n3022,ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO,mariadb\n3022,ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO,mysql\n3023,ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS,mariadb\n3023,ER_WARN_ONLY_MASTER_LOG_FILE_NO_POS,mysql\n3024,ER_QUERY_TIMEOUT,mariadb\n3024,ER_QUERY_TIMEOUT,mysql\n3025,ER_NON_RO_SELECT_DISABLE_TIMER,mariadb\n3025,ER_NON_RO_SELECT_DISABLE_TIMER,mysql\n3026,ER_DUP_LIST_ENTRY,mariadb\n3026,ER_DUP_LIST_ENTRY,mysql\n3027,ER_SQL_MODE_NO_EFFECT,mariadb\n3027,ER_SQL_MODE_NO_EFFECT,mysql\n3028,ER_AGGREGATE_ORDER_FOR_UNION,mariadb\n3028,ER_AGGREGATE_ORDER_FOR_UNION,mysql\n3029,ER_AGGREGATE_ORDER_NON_AGG_QUERY,mariadb\n3029,ER_AGGREGATE_ORDER_NON_AGG_QUERY,mysql\n3030,ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR,mariadb\n3030,ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR,mysql\n3031,ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER,mariadb\n3031,ER_DONT_SUPPORT_SLAVE_PRESERVE_COMMIT_ORDER,mysql\n3032,ER_SERVER_OFFLINE_MODE,mariadb\n3032,ER_SERVER_OFFLINE_MODE,mysql\n3033,ER_GIS_DIFFERENT_SRIDS,mariadb\n3033,ER_GIS_DIFFERENT_SRIDS,mysql\n3034,ER_GIS_UNSUPPORTED_ARGUMENT,mariadb\n3034,ER_GIS_UNSUPPORTED_ARGUMENT,mysql\n3035,ER_GIS_UNKNOWN_ERROR,mariadb\n3035,ER_GIS_UNKNOWN_ERROR,mysql\n3036,ER_GIS_UNKNOWN_EXCEPTION,mariadb\n3036,ER_GIS_UNKNOWN_EXCEPTION,mysql\n3037,ER_GIS_INVALID_DATA,mariadb\n3037,ER_GIS_INVALID_DATA,mysql\n3038,ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION,mariadb\n3038,ER_BOOST_GEOMETRY_EMPTY_INPUT_EXCEPTION,mysql\n3039,ER_BOOST_GEOMETRY_CENTROID_EXCEPTION,mariadb\n3039,ER_BOOST_GEOMETRY_CENTROID_EXCEPTION,mysql\n3040,ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION,mariadb\n3040,ER_BOOST_GEOMETRY_OVERLAY_INVALID_INPUT_EXCEPTION,mysql\n3041,ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION,mariadb\n3041,ER_BOOST_GEOMETRY_TURN_INFO_EXCEPTION,mysql\n3042,ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION,mariadb\n3042,ER_BOOST_GEOMETRY_SELF_INTERSECTION_POINT_EXCEPTION,mysql\n3043,ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION,mariadb\n3043,ER_BOOST_GEOMETRY_UNKNOWN_EXCEPTION,mysql\n3044,ER_STD_BAD_ALLOC_ERROR,mariadb\n3044,ER_STD_BAD_ALLOC_ERROR,mysql\n3045,ER_STD_DOMAIN_ERROR,mariadb\n3045,ER_STD_DOMAIN_ERROR,mysql\n3046,ER_STD_LENGTH_ERROR,mariadb\n3046,ER_STD_LENGTH_ERROR,mysql\n3047,ER_STD_INVALID_ARGUMENT,mariadb\n3047,ER_STD_INVALID_ARGUMENT,mysql\n3048,ER_STD_OUT_OF_RANGE_ERROR,mariadb\n3048,ER_STD_OUT_OF_RANGE_ERROR,mysql\n3049,ER_STD_OVERFLOW_ERROR,mariadb\n3049,ER_STD_OVERFLOW_ERROR,mysql\n3050,ER_STD_RANGE_ERROR,mariadb\n3050,ER_STD_RANGE_ERROR,mysql\n3051,ER_STD_UNDERFLOW_ERROR,mariadb\n3051,ER_STD_UNDERFLOW_ERROR,mysql\n3052,ER_STD_LOGIC_ERROR,mariadb\n3052,ER_STD_LOGIC_ERROR,mysql\n3053,ER_STD_RUNTIME_ERROR,mariadb\n3053,ER_STD_RUNTIME_ERROR,mysql\n3054,ER_STD_UNKNOWN_EXCEPTION,mariadb\n3054,ER_STD_UNKNOWN_EXCEPTION,mysql\n3055,ER_GIS_DATA_WRONG_ENDIANESS,mariadb\n3055,ER_GIS_DATA_WRONG_ENDIANESS,mysql\n3056,ER_CHANGE_MASTER_PASSWORD_LENGTH,mariadb\n3056,ER_CHANGE_MASTER_PASSWORD_LENGTH,mysql\n3057,ER_USER_LOCK_WRONG_NAME,mariadb\n3057,ER_USER_LOCK_WRONG_NAME,mysql\n3058,ER_USER_LOCK_DEADLOCK,mariadb\n3058,ER_USER_LOCK_DEADLOCK,mysql\n3059,ER_REPLACE_INACCESSIBLE_ROWS,mariadb\n3059,ER_REPLACE_INACCESSIBLE_ROWS,mysql\n3060,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS,mariadb\n3060,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS,mysql\n3061,ER_ILLEGAL_USER_VAR,mysql\n3062,ER_GTID_MODE_OFF,mysql\n3063,ER_UNSUPPORTED_BY_REPLICATION_THREAD,mysql\n3064,ER_INCORRECT_TYPE,mysql\n3065,ER_FIELD_IN_ORDER_NOT_SELECT,mysql\n3066,ER_AGGREGATE_IN_ORDER_NOT_SELECT,mysql\n3067,ER_INVALID_RPL_WILD_TABLE_FILTER_PATTERN,mysql\n3068,ER_NET_OK_PACKET_TOO_LARGE,mysql\n3069,ER_INVALID_JSON_DATA,mysql\n3070,ER_INVALID_GEOJSON_MISSING_MEMBER,mysql\n3071,ER_INVALID_GEOJSON_WRONG_TYPE,mysql\n3072,ER_INVALID_GEOJSON_UNSPECIFIED,mysql\n3073,ER_DIMENSION_UNSUPPORTED,mysql\n3074,ER_SLAVE_CHANNEL_DOES_NOT_EXIST,mysql\n3075,ER_SLAVE_MULTIPLE_CHANNELS_HOST_PORT,mysql\n3076,ER_SLAVE_CHANNEL_NAME_INVALID_OR_TOO_LONG,mysql\n3077,ER_SLAVE_NEW_CHANNEL_WRONG_REPOSITORY,mysql\n3078,ER_SLAVE_CHANNEL_DELETE,mysql\n3079,ER_SLAVE_MULTIPLE_CHANNELS_CMD,mysql\n3080,ER_SLAVE_MAX_CHANNELS_EXCEEDED,mysql\n3081,ER_SLAVE_CHANNEL_MUST_STOP,mysql\n3082,ER_SLAVE_CHANNEL_NOT_RUNNING,mysql\n3083,ER_SLAVE_CHANNEL_WAS_RUNNING,mysql\n3084,ER_SLAVE_CHANNEL_WAS_NOT_RUNNING,mysql\n3085,ER_SLAVE_CHANNEL_SQL_THREAD_MUST_STOP,mysql\n3086,ER_SLAVE_CHANNEL_SQL_SKIP_COUNTER,mysql\n3087,ER_WRONG_FIELD_WITH_GROUP_V2,mysql\n3088,ER_MIX_OF_GROUP_FUNC_AND_FIELDS_V2,mysql\n3089,ER_WARN_DEPRECATED_SYSVAR_UPDATE,mysql\n3090,ER_WARN_DEPRECATED_SQLMODE,mysql\n3091,ER_CANNOT_LOG_PARTIAL_DROP_DATABASE_WITH_GTID,mysql\n3092,ER_GROUP_REPLICATION_CONFIGURATION,mysql\n3093,ER_GROUP_REPLICATION_RUNNING,mysql\n3094,ER_GROUP_REPLICATION_APPLIER_INIT_ERROR,mysql\n3095,ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT,mysql\n3096,ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR,mysql\n3097,ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR,mysql\n3098,ER_BEFORE_DML_VALIDATION_ERROR,mysql\n3099,ER_PREVENTS_VARIABLE_WITHOUT_RBR,mysql\n3100,ER_RUN_HOOK_ERROR,mysql\n3101,ER_TRANSACTION_ROLLBACK_DURING_COMMIT,mysql\n3102,ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED,mysql\n3103,ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN,mysql\n3104,ER_WRONG_FK_OPTION_FOR_GENERATED_COLUMN,mysql\n3105,ER_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,mysql\n3106,ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN,mysql\n3107,ER_GENERATED_COLUMN_NON_PRIOR,mysql\n3108,ER_DEPENDENT_BY_GENERATED_COLUMN,mysql\n3109,ER_GENERATED_COLUMN_REF_AUTO_INC,mysql\n3110,ER_FEATURE_NOT_AVAILABLE,mysql\n3111,ER_CANT_SET_GTID_MODE,mysql\n3112,ER_CANT_USE_AUTO_POSITION_WITH_GTID_MODE_OFF,mysql\n3113,ER_CANT_REPLICATE_ANONYMOUS_WITH_AUTO_POSITION,mysql\n3114,ER_CANT_REPLICATE_ANONYMOUS_WITH_GTID_MODE_ON,mysql\n3115,ER_CANT_REPLICATE_GTID_WITH_GTID_MODE_OFF,mysql\n3116,ER_CANT_ENFORCE_GTID_CONSISTENCY_WITH_ONGOING_GTID_VIOLATING_TX,mysql\n3117,ER_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TX,mysql\n3118,ER_ACCOUNT_HAS_BEEN_LOCKED,mysql\n3119,ER_WRONG_TABLESPACE_NAME,mysql\n3120,ER_TABLESPACE_IS_NOT_EMPTY,mysql\n3121,ER_WRONG_FILE_NAME,mysql\n3122,ER_BOOST_GEOMETRY_INCONSISTENT_TURNS_EXCEPTION,mysql\n3123,ER_WARN_OPTIMIZER_HINT_SYNTAX_ERROR,mysql\n3124,ER_WARN_BAD_MAX_EXECUTION_TIME,mysql\n3125,ER_WARN_UNSUPPORTED_MAX_EXECUTION_TIME,mysql\n3126,ER_WARN_CONFLICTING_HINT,mysql\n3127,ER_WARN_UNKNOWN_QB_NAME,mysql\n3128,ER_UNRESOLVED_HINT_NAME,mysql\n3129,ER_WARN_ON_MODIFYING_GTID_EXECUTED_TABLE,mysql\n3130,ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED,mysql\n3131,ER_LOCKING_SERVICE_WRONG_NAME,mysql\n3132,ER_LOCKING_SERVICE_DEADLOCK,mysql\n3133,ER_LOCKING_SERVICE_TIMEOUT,mysql\n3134,ER_GIS_MAX_POINTS_IN_GEOMETRY_OVERFLOWED,mysql\n3135,ER_SQL_MODE_MERGED,mysql\n3136,ER_VTOKEN_PLUGIN_TOKEN_MISMATCH,mysql\n3137,ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND,mysql\n3138,ER_CANT_SET_VARIABLE_WHEN_OWNING_GTID,mysql\n3139,ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED,mysql\n3140,ER_INVALID_JSON_TEXT,mysql\n3141,ER_INVALID_JSON_TEXT_IN_PARAM,mysql\n3142,ER_INVALID_JSON_BINARY_DATA,mysql\n3143,ER_INVALID_JSON_PATH,mysql\n3144,ER_INVALID_JSON_CHARSET,mysql\n3145,ER_INVALID_JSON_CHARSET_IN_FUNCTION,mysql\n3146,ER_INVALID_TYPE_FOR_JSON,mysql\n3147,ER_INVALID_CAST_TO_JSON,mysql\n3148,ER_INVALID_JSON_PATH_CHARSET,mysql\n3149,ER_INVALID_JSON_PATH_WILDCARD,mysql\n3150,ER_JSON_VALUE_TOO_BIG,mysql\n3151,ER_JSON_KEY_TOO_BIG,mysql\n3152,ER_JSON_USED_AS_KEY,mysql\n3153,ER_JSON_VACUOUS_PATH,mysql\n3154,ER_JSON_BAD_ONE_OR_ALL_ARG,mysql\n3155,ER_NUMERIC_JSON_VALUE_OUT_OF_RANGE,mysql\n3156,ER_INVALID_JSON_VALUE_FOR_CAST,mysql\n3157,ER_JSON_DOCUMENT_TOO_DEEP,mysql\n3158,ER_JSON_DOCUMENT_NULL_KEY,mysql\n3159,ER_SECURE_TRANSPORT_REQUIRED,mysql\n3160,ER_NO_SECURE_TRANSPORTS_CONFIGURED,mysql\n3161,ER_DISABLED_STORAGE_ENGINE,mysql\n3162,ER_USER_DOES_NOT_EXIST,mysql\n3163,ER_USER_ALREADY_EXISTS,mysql\n3164,ER_AUDIT_API_ABORT,mysql\n3165,ER_INVALID_JSON_PATH_ARRAY_CELL,mysql\n3166,ER_BUFPOOL_RESIZE_INPROGRESS,mysql\n3167,ER_FEATURE_DISABLED_SEE_DOC,mysql\n3168,ER_SERVER_ISNT_AVAILABLE,mysql\n3169,ER_SESSION_WAS_KILLED,mysql\n3170,ER_CAPACITY_EXCEEDED,mysql\n3171,ER_CAPACITY_EXCEEDED_IN_RANGE_OPTIMIZER,mysql\n3172,ER_TABLE_NEEDS_UPG_PART,mysql\n3173,ER_CANT_WAIT_FOR_EXECUTED_GTID_SET_WHILE_OWNING_A_GTID,mysql\n3174,ER_CANNOT_ADD_FOREIGN_BASE_COL_VIRTUAL,mysql\n3175,ER_CANNOT_CREATE_VIRTUAL_INDEX_CONSTRAINT,mysql\n3176,ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE,mysql\n3177,ER_LOCK_REFUSED_BY_ENGINE,mysql\n3178,ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN,mysql\n3179,ER_MASTER_KEY_ROTATION_NOT_SUPPORTED_BY_SE,mysql\n3180,ER_MASTER_KEY_ROTATION_ERROR_BY_SE,mysql\n3181,ER_MASTER_KEY_ROTATION_BINLOG_FAILED,mysql\n3182,ER_MASTER_KEY_ROTATION_SE_UNAVAILABLE,mysql\n3183,ER_TABLESPACE_CANNOT_ENCRYPT,mysql\n3184,ER_INVALID_ENCRYPTION_OPTION,mysql\n3185,ER_CANNOT_FIND_KEY_IN_KEYRING,mysql\n3186,ER_CAPACITY_EXCEEDED_IN_PARSER,mysql\n3187,ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE,mysql\n3188,ER_KEYRING_UDF_KEYRING_SERVICE_ERROR,mysql\n3189,ER_USER_COLUMN_OLD_LENGTH,mysql\n3190,ER_CANT_RESET_MASTER,mysql\n3191,ER_GROUP_REPLICATION_MAX_GROUP_SIZE,mysql\n3192,ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED,mysql\n3193,ER_TABLE_REFERENCED,mysql\n3194,ER_PARTITION_ENGINE_DEPRECATED_FOR_TABLE,mysql\n3195,ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID_ZERO,mysql\n3196,ER_WARN_USING_GEOMFROMWKB_TO_SET_SRID,mysql\n3197,ER_XA_RETRY,mysql\n3198,ER_KEYRING_AWS_UDF_AWS_KMS_ERROR,mysql\n3199,ER_BINLOG_UNSAFE_XA,mysql\n3200,ER_UDF_ERROR,mysql\n3201,ER_KEYRING_MIGRATION_FAILURE,mysql\n3202,ER_KEYRING_ACCESS_DENIED_ERROR,mysql\n3203,ER_KEYRING_MIGRATION_STATUS,mysql\n3204,ER_PLUGIN_FAILED_TO_OPEN_TABLES,mysql\n3205,ER_PLUGIN_FAILED_TO_OPEN_TABLE,mysql\n3206,ER_AUDIT_LOG_NO_KEYRING_PLUGIN_INSTALLED,mysql\n3207,ER_AUDIT_LOG_ENCRYPTION_PASSWORD_HAS_NOT_BEEN_SET,mysql\n3208,ER_AUDIT_LOG_COULD_NOT_CREATE_AES_KEY,mysql\n3209,ER_AUDIT_LOG_ENCRYPTION_PASSWORD_CANNOT_BE_FETCHED,mysql\n3210,ER_AUDIT_LOG_JSON_FILTERING_NOT_ENABLED,mysql\n3211,ER_AUDIT_LOG_UDF_INSUFFICIENT_PRIVILEGE,mysql\n3212,ER_AUDIT_LOG_SUPER_PRIVILEGE_REQUIRED,mysql\n3213,ER_COULD_NOT_REINITIALIZE_AUDIT_LOG_FILTERS,mysql\n3214,ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_TYPE,mysql\n3215,ER_AUDIT_LOG_UDF_INVALID_ARGUMENT_COUNT,mysql\n3216,ER_AUDIT_LOG_HAS_NOT_BEEN_INSTALLED,mysql\n3217,ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_TYPE,mysql\n3218,ER_AUDIT_LOG_UDF_READ_INVALID_MAX_ARRAY_LENGTH_ARG_VALUE,mysql\n3219,ER_AUDIT_LOG_JSON_FILTER_PARSING_ERROR,mysql\n3220,ER_AUDIT_LOG_JSON_FILTER_NAME_CANNOT_BE_EMPTY,mysql\n3221,ER_AUDIT_LOG_JSON_USER_NAME_CANNOT_BE_EMPTY,mysql\n3222,ER_AUDIT_LOG_JSON_FILTER_DOES_NOT_EXISTS,mysql\n3223,ER_AUDIT_LOG_USER_FIRST_CHARACTER_MUST_BE_ALPHANUMERIC,mysql\n3224,ER_AUDIT_LOG_USER_NAME_INVALID_CHARACTER,mysql\n3225,ER_AUDIT_LOG_HOST_NAME_INVALID_CHARACTER,mysql\n3226,OBSOLETE_WARN_DEPRECATED_MAXDB_SQL_MODE_FOR_TIMESTAMP,mysql\n3228,ER_CANT_OPEN_ERROR_LOG,mysql\n3230,ER_CANT_START_SERVER_NAMED_PIPE,mysql\n3231,ER_WRITE_SET_EXCEEDS_LIMIT,mysql\n3232,ER_DEPRECATED_TLS_VERSION_SESSION,mysql\n3233,ER_WARN_DEPRECATED_TLS_VERSION,mysql\n3234,ER_WARN_WRONG_NATIVE_TABLE_STRUCTURE,mysql\n3235,ER_AES_INVALID_KDF_NAME,mysql\n3236,ER_AES_INVALID_KDF_ITERATIONS,mysql\n3237,WARN_AES_KEY_SIZE,mysql\n3238,ER_AES_INVALID_KDF_OPTION_SIZE,mysql\n3500,ER_UNSUPPORT_COMPRESSED_TEMPORARY_TABLE,mysql\n3501,ER_ACL_OPERATION_FAILED,mysql\n3502,ER_UNSUPPORTED_INDEX_ALGORITHM,mysql\n3503,ER_NO_SUCH_DB,mysql\n3504,ER_TOO_BIG_ENUM,mysql\n3505,ER_TOO_LONG_SET_ENUM_VALUE,mysql\n3506,ER_INVALID_DD_OBJECT,mysql\n3507,ER_UPDATING_DD_TABLE,mysql\n3508,ER_INVALID_DD_OBJECT_ID,mysql\n3509,ER_INVALID_DD_OBJECT_NAME,mysql\n3510,ER_TABLESPACE_MISSING_WITH_NAME,mysql\n3511,ER_TOO_LONG_ROUTINE_COMMENT,mysql\n3512,ER_SP_LOAD_FAILED,mysql\n3513,ER_INVALID_BITWISE_OPERANDS_SIZE,mysql\n3514,ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE,mysql\n3515,ER_WARN_UNSUPPORTED_HINT,mysql\n3516,ER_UNEXPECTED_GEOMETRY_TYPE,mysql\n3517,ER_SRS_PARSE_ERROR,mysql\n3518,ER_SRS_PROJ_PARAMETER_MISSING,mysql\n3519,ER_WARN_SRS_NOT_FOUND,mysql\n3520,ER_SRS_NOT_CARTESIAN,mysql\n3521,ER_SRS_NOT_CARTESIAN_UNDEFINED,mysql\n3522,ER_PK_INDEX_CANT_BE_INVISIBLE,mysql\n3523,ER_UNKNOWN_AUTHID,mysql\n3524,ER_FAILED_ROLE_GRANT,mysql\n3525,ER_OPEN_ROLE_TABLES,mysql\n3526,ER_FAILED_DEFAULT_ROLES,mysql\n3527,ER_COMPONENTS_NO_SCHEME,mysql\n3528,ER_COMPONENTS_NO_SCHEME_SERVICE,mysql\n3529,ER_COMPONENTS_CANT_LOAD,mysql\n3530,ER_ROLE_NOT_GRANTED,mysql\n3531,ER_FAILED_REVOKE_ROLE,mysql\n3532,ER_RENAME_ROLE,mysql\n3533,ER_COMPONENTS_CANT_ACQUIRE_SERVICE_IMPLEMENTATION,mysql\n3534,ER_COMPONENTS_CANT_SATISFY_DEPENDENCY,mysql\n3535,ER_COMPONENTS_LOAD_CANT_REGISTER_SERVICE_IMPLEMENTATION,mysql\n3536,ER_COMPONENTS_LOAD_CANT_INITIALIZE,mysql\n3537,ER_COMPONENTS_UNLOAD_NOT_LOADED,mysql\n3538,ER_COMPONENTS_UNLOAD_CANT_DEINITIALIZE,mysql\n3539,ER_COMPONENTS_CANT_RELEASE_SERVICE,mysql\n3540,ER_COMPONENTS_UNLOAD_CANT_UNREGISTER_SERVICE,mysql\n3541,ER_COMPONENTS_CANT_UNLOAD,mysql\n3542,ER_WARN_UNLOAD_THE_NOT_PERSISTED,mysql\n3543,ER_COMPONENT_TABLE_INCORRECT,mysql\n3544,ER_COMPONENT_MANIPULATE_ROW_FAILED,mysql\n3545,ER_COMPONENTS_UNLOAD_DUPLICATE_IN_GROUP,mysql\n3546,ER_CANT_SET_GTID_PURGED_DUE_SETS_CONSTRAINTS,mysql\n3547,ER_CANNOT_LOCK_USER_MANAGEMENT_CACHES,mysql\n3548,ER_SRS_NOT_FOUND,mysql\n3549,ER_VARIABLE_NOT_PERSISTED,mysql\n3550,ER_IS_QUERY_INVALID_CLAUSE,mysql\n3551,ER_UNABLE_TO_STORE_STATISTICS,mysql\n3552,ER_NO_SYSTEM_SCHEMA_ACCESS,mysql\n3553,ER_NO_SYSTEM_TABLESPACE_ACCESS,mysql\n3554,ER_NO_SYSTEM_TABLE_ACCESS,mysql\n3555,ER_NO_SYSTEM_TABLE_ACCESS_FOR_DICTIONARY_TABLE,mysql\n3556,ER_NO_SYSTEM_TABLE_ACCESS_FOR_SYSTEM_TABLE,mysql\n3557,ER_NO_SYSTEM_TABLE_ACCESS_FOR_TABLE,mysql\n3558,ER_INVALID_OPTION_KEY,mysql\n3559,ER_INVALID_OPTION_VALUE,mysql\n3560,ER_INVALID_OPTION_KEY_VALUE_PAIR,mysql\n3561,ER_INVALID_OPTION_START_CHARACTER,mysql\n3562,ER_INVALID_OPTION_END_CHARACTER,mysql\n3563,ER_INVALID_OPTION_CHARACTERS,mysql\n3564,ER_DUPLICATE_OPTION_KEY,mysql\n3565,ER_WARN_SRS_NOT_FOUND_AXIS_ORDER,mysql\n3566,ER_NO_ACCESS_TO_NATIVE_FCT,mysql\n3567,ER_RESET_MASTER_TO_VALUE_OUT_OF_RANGE,mysql\n3568,ER_UNRESOLVED_TABLE_LOCK,mysql\n3569,ER_DUPLICATE_TABLE_LOCK,mysql\n3570,ER_BINLOG_UNSAFE_SKIP_LOCKED,mysql\n3571,ER_BINLOG_UNSAFE_NOWAIT,mysql\n3572,ER_LOCK_NOWAIT,mysql\n3573,ER_CTE_RECURSIVE_REQUIRES_UNION,mysql\n3574,ER_CTE_RECURSIVE_REQUIRES_NONRECURSIVE_FIRST,mysql\n3575,ER_CTE_RECURSIVE_FORBIDS_AGGREGATION,mysql\n3576,ER_CTE_RECURSIVE_FORBIDDEN_JOIN_ORDER,mysql\n3577,ER_CTE_RECURSIVE_REQUIRES_SINGLE_REFERENCE,mysql\n3578,ER_SWITCH_TMP_ENGINE,mysql\n3579,ER_WINDOW_NO_SUCH_WINDOW,mysql\n3580,ER_WINDOW_CIRCULARITY_IN_WINDOW_GRAPH,mysql\n3581,ER_WINDOW_NO_CHILD_PARTITIONING,mysql\n3582,ER_WINDOW_NO_INHERIT_FRAME,mysql\n3583,ER_WINDOW_NO_REDEFINE_ORDER_BY,mysql\n3584,ER_WINDOW_FRAME_START_ILLEGAL,mysql\n3585,ER_WINDOW_FRAME_END_ILLEGAL,mysql\n3586,ER_WINDOW_FRAME_ILLEGAL,mysql\n3587,ER_WINDOW_RANGE_FRAME_ORDER_TYPE,mysql\n3588,ER_WINDOW_RANGE_FRAME_TEMPORAL_TYPE,mysql\n3589,ER_WINDOW_RANGE_FRAME_NUMERIC_TYPE,mysql\n3590,ER_WINDOW_RANGE_BOUND_NOT_CONSTANT,mysql\n3591,ER_WINDOW_DUPLICATE_NAME,mysql\n3592,ER_WINDOW_ILLEGAL_ORDER_BY,mysql\n3593,ER_WINDOW_INVALID_WINDOW_FUNC_USE,mysql\n3594,ER_WINDOW_INVALID_WINDOW_FUNC_ALIAS_USE,mysql\n3595,ER_WINDOW_NESTED_WINDOW_FUNC_USE_IN_WINDOW_SPEC,mysql\n3596,ER_WINDOW_ROWS_INTERVAL_USE,mysql\n3597,ER_WINDOW_NO_GROUP_ORDER_UNUSED,mysql\n3598,ER_WINDOW_EXPLAIN_JSON,mysql\n3599,ER_WINDOW_FUNCTION_IGNORES_FRAME,mysql\n3600,ER_WL9236_NOW_UNUSED,mysql\n3601,ER_INVALID_NO_OF_ARGS,mysql\n3602,ER_FIELD_IN_GROUPING_NOT_GROUP_BY,mysql\n3603,ER_TOO_LONG_TABLESPACE_COMMENT,mysql\n3604,ER_ENGINE_CANT_DROP_TABLE,mysql\n3605,ER_ENGINE_CANT_DROP_MISSING_TABLE,mysql\n3606,ER_TABLESPACE_DUP_FILENAME,mysql\n3607,ER_DB_DROP_RMDIR2,mysql\n3608,ER_IMP_NO_FILES_MATCHED,mysql\n3609,ER_IMP_SCHEMA_DOES_NOT_EXIST,mysql\n3610,ER_IMP_TABLE_ALREADY_EXISTS,mysql\n3611,ER_IMP_INCOMPATIBLE_MYSQLD_VERSION,mysql\n3612,ER_IMP_INCOMPATIBLE_DD_VERSION,mysql\n3613,ER_IMP_INCOMPATIBLE_SDI_VERSION,mysql\n3614,ER_WARN_INVALID_HINT,mysql\n3615,ER_VAR_DOES_NOT_EXIST,mysql\n3616,ER_LONGITUDE_OUT_OF_RANGE,mysql\n3617,ER_LATITUDE_OUT_OF_RANGE,mysql\n3618,ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS,mysql\n3619,ER_ILLEGAL_PRIVILEGE_LEVEL,mysql\n3620,ER_NO_SYSTEM_VIEW_ACCESS,mysql\n3621,ER_COMPONENT_FILTER_FLABBERGASTED,mysql\n3622,ER_PART_EXPR_TOO_LONG,mysql\n3623,ER_UDF_DROP_DYNAMICALLY_REGISTERED,mysql\n3624,ER_UNABLE_TO_STORE_COLUMN_STATISTICS,mysql\n3625,ER_UNABLE_TO_UPDATE_COLUMN_STATISTICS,mysql\n3626,ER_UNABLE_TO_DROP_COLUMN_STATISTICS,mysql\n3627,ER_UNABLE_TO_BUILD_HISTOGRAM,mysql\n3628,ER_MANDATORY_ROLE,mysql\n3629,ER_MISSING_TABLESPACE_FILE,mysql\n3630,ER_PERSIST_ONLY_ACCESS_DENIED_ERROR,mysql\n3631,ER_CMD_NEED_SUPER,mysql\n3632,ER_PATH_IN_DATADIR,mysql\n3633,ER_CLONE_DDL_IN_PROGRESS,mysql\n3634,ER_CLONE_TOO_MANY_CONCURRENT_CLONES,mysql\n3635,ER_APPLIER_LOG_EVENT_VALIDATION_ERROR,mysql\n3636,ER_CTE_MAX_RECURSION_DEPTH,mysql\n3637,ER_NOT_HINT_UPDATABLE_VARIABLE,mysql\n3638,ER_CREDENTIALS_CONTRADICT_TO_HISTORY,mysql\n3639,ER_WARNING_PASSWORD_HISTORY_CLAUSES_VOID,mysql\n3640,ER_CLIENT_DOES_NOT_SUPPORT,mysql\n3641,ER_I_S_SKIPPED_TABLESPACE,mysql\n3642,ER_TABLESPACE_ENGINE_MISMATCH,mysql\n3643,ER_WRONG_SRID_FOR_COLUMN,mysql\n3644,ER_CANNOT_ALTER_SRID_DUE_TO_INDEX,mysql\n3645,ER_WARN_BINLOG_PARTIAL_UPDATES_DISABLED,mysql\n3646,ER_WARN_BINLOG_V1_ROW_EVENTS_DISABLED,mysql\n3647,ER_WARN_BINLOG_PARTIAL_UPDATES_SUGGESTS_PARTIAL_IMAGES,mysql\n3648,ER_COULD_NOT_APPLY_JSON_DIFF,mysql\n3649,ER_CORRUPTED_JSON_DIFF,mysql\n3650,ER_RESOURCE_GROUP_EXISTS,mysql\n3651,ER_RESOURCE_GROUP_NOT_EXISTS,mysql\n3652,ER_INVALID_VCPU_ID,mysql\n3653,ER_INVALID_VCPU_RANGE,mysql\n3654,ER_INVALID_THREAD_PRIORITY,mysql\n3655,ER_DISALLOWED_OPERATION,mysql\n3656,ER_RESOURCE_GROUP_BUSY,mysql\n3657,ER_RESOURCE_GROUP_DISABLED,mysql\n3658,ER_FEATURE_UNSUPPORTED,mysql\n3659,ER_ATTRIBUTE_IGNORED,mysql\n3660,ER_INVALID_THREAD_ID,mysql\n3661,ER_RESOURCE_GROUP_BIND_FAILED,mysql\n3662,ER_INVALID_USE_OF_FORCE_OPTION,mysql\n3663,ER_GROUP_REPLICATION_COMMAND_FAILURE,mysql\n3664,ER_SDI_OPERATION_FAILED,mysql\n3665,ER_MISSING_JSON_TABLE_VALUE,mysql\n3666,ER_WRONG_JSON_TABLE_VALUE,mysql\n3667,ER_TF_MUST_HAVE_ALIAS,mysql\n3668,ER_TF_FORBIDDEN_JOIN_TYPE,mysql\n3669,ER_JT_VALUE_OUT_OF_RANGE,mysql\n3670,ER_JT_MAX_NESTED_PATH,mysql\n3671,ER_PASSWORD_EXPIRATION_NOT_SUPPORTED_BY_AUTH_METHOD,mysql\n3672,ER_INVALID_GEOJSON_CRS_NOT_TOP_LEVEL,mysql\n3673,ER_BAD_NULL_ERROR_NOT_IGNORED,mysql\n3674,WARN_USELESS_SPATIAL_INDEX,mysql\n3675,ER_DISK_FULL_NOWAIT,mysql\n3676,ER_PARSE_ERROR_IN_DIGEST_FN,mysql\n3677,ER_UNDISCLOSED_PARSE_ERROR_IN_DIGEST_FN,mysql\n3678,ER_SCHEMA_DIR_EXISTS,mysql\n3679,ER_SCHEMA_DIR_MISSING,mysql\n3680,ER_SCHEMA_DIR_CREATE_FAILED,mysql\n3681,ER_SCHEMA_DIR_UNKNOWN,mysql\n3682,ER_ONLY_IMPLEMENTED_FOR_SRID_0_AND_4326,mysql\n3683,ER_BINLOG_EXPIRE_LOG_DAYS_AND_SECS_USED_TOGETHER,mysql\n3684,ER_REGEXP_BUFFER_OVERFLOW,mysql\n3685,ER_REGEXP_ILLEGAL_ARGUMENT,mysql\n3686,ER_REGEXP_INDEX_OUTOFBOUNDS_ERROR,mysql\n3687,ER_REGEXP_INTERNAL_ERROR,mysql\n3688,ER_REGEXP_RULE_SYNTAX,mysql\n3689,ER_REGEXP_BAD_ESCAPE_SEQUENCE,mysql\n3690,ER_REGEXP_UNIMPLEMENTED,mysql\n3691,ER_REGEXP_MISMATCHED_PAREN,mysql\n3692,ER_REGEXP_BAD_INTERVAL,mysql\n3693,ER_REGEXP_MAX_LT_MIN,mysql\n3694,ER_REGEXP_INVALID_BACK_REF,mysql\n3695,ER_REGEXP_LOOK_BEHIND_LIMIT,mysql\n3696,ER_REGEXP_MISSING_CLOSE_BRACKET,mysql\n3697,ER_REGEXP_INVALID_RANGE,mysql\n3698,ER_REGEXP_STACK_OVERFLOW,mysql\n3699,ER_REGEXP_TIME_OUT,mysql\n3700,ER_REGEXP_PATTERN_TOO_BIG,mysql\n3701,ER_CANT_SET_ERROR_LOG_SERVICE,mysql\n3702,ER_EMPTY_PIPELINE_FOR_ERROR_LOG_SERVICE,mysql\n3703,ER_COMPONENT_FILTER_DIAGNOSTICS,mysql\n3704,ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS,mysql\n3705,ER_NOT_IMPLEMENTED_FOR_PROJECTED_SRS,mysql\n3706,ER_NONPOSITIVE_RADIUS,mysql\n3707,ER_RESTART_SERVER_FAILED,mysql\n3708,ER_SRS_MISSING_MANDATORY_ATTRIBUTE,mysql\n3709,ER_SRS_MULTIPLE_ATTRIBUTE_DEFINITIONS,mysql\n3710,ER_SRS_NAME_CANT_BE_EMPTY_OR_WHITESPACE,mysql\n3711,ER_SRS_ORGANIZATION_CANT_BE_EMPTY_OR_WHITESPACE,mysql\n3712,ER_SRS_ID_ALREADY_EXISTS,mysql\n3713,ER_WARN_SRS_ID_ALREADY_EXISTS,mysql\n3714,ER_CANT_MODIFY_SRID_0,mysql\n3715,ER_WARN_RESERVED_SRID_RANGE,mysql\n3716,ER_CANT_MODIFY_SRS_USED_BY_COLUMN,mysql\n3717,ER_SRS_INVALID_CHARACTER_IN_ATTRIBUTE,mysql\n3718,ER_SRS_ATTRIBUTE_STRING_TOO_LONG,mysql\n3719,ER_DEPRECATED_UTF8_ALIAS,mysql\n3720,ER_DEPRECATED_NATIONAL,mysql\n3721,ER_INVALID_DEFAULT_UTF8MB4_COLLATION,mysql\n3722,ER_UNABLE_TO_COLLECT_LOG_STATUS,mysql\n3723,ER_RESERVED_TABLESPACE_NAME,mysql\n3724,ER_UNABLE_TO_SET_OPTION,mysql\n3725,ER_SLAVE_POSSIBLY_DIVERGED_AFTER_DDL,mysql\n3726,ER_SRS_NOT_GEOGRAPHIC,mysql\n3727,ER_POLYGON_TOO_LARGE,mysql\n3728,ER_SPATIAL_UNIQUE_INDEX,mysql\n3729,ER_INDEX_TYPE_NOT_SUPPORTED_FOR_SPATIAL_INDEX,mysql\n3730,ER_FK_CANNOT_DROP_PARENT,mysql\n3731,ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE,mysql\n3732,ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE,mysql\n3733,ER_FK_CANNOT_USE_VIRTUAL_COLUMN,mysql\n3734,ER_FK_NO_COLUMN_PARENT,mysql\n3735,ER_CANT_SET_ERROR_SUPPRESSION_LIST,mysql\n3736,ER_SRS_GEOGCS_INVALID_AXES,mysql\n3737,ER_SRS_INVALID_SEMI_MAJOR_AXIS,mysql\n3738,ER_SRS_INVALID_INVERSE_FLATTENING,mysql\n3739,ER_SRS_INVALID_ANGULAR_UNIT,mysql\n3740,ER_SRS_INVALID_PRIME_MERIDIAN,mysql\n3741,ER_TRANSFORM_SOURCE_SRS_NOT_SUPPORTED,mysql\n3742,ER_TRANSFORM_TARGET_SRS_NOT_SUPPORTED,mysql\n3743,ER_TRANSFORM_SOURCE_SRS_MISSING_TOWGS84,mysql\n3744,ER_TRANSFORM_TARGET_SRS_MISSING_TOWGS84,mysql\n3745,ER_TEMP_TABLE_PREVENTS_SWITCH_SESSION_BINLOG_FORMAT,mysql\n3746,ER_TEMP_TABLE_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT,mysql\n3747,ER_RUNNING_APPLIER_PREVENTS_SWITCH_GLOBAL_BINLOG_FORMAT,mysql\n3748,ER_CLIENT_GTID_UNSAFE_CREATE_DROP_TEMP_TABLE_IN_TRX_IN_SBR,mysql\n3750,ER_TABLE_WITHOUT_PK,mysql\n3751,ER_WARN_DATA_TRUNCATED_FUNCTIONAL_INDEX,mysql\n3752,ER_WARN_DATA_OUT_OF_RANGE_FUNCTIONAL_INDEX,mysql\n3753,ER_FUNCTIONAL_INDEX_ON_JSON_OR_GEOMETRY_FUNCTION,mysql\n3754,ER_FUNCTIONAL_INDEX_REF_AUTO_INCREMENT,mysql\n3755,ER_CANNOT_DROP_COLUMN_FUNCTIONAL_INDEX,mysql\n3756,ER_FUNCTIONAL_INDEX_PRIMARY_KEY,mysql\n3757,ER_FUNCTIONAL_INDEX_ON_LOB,mysql\n3758,ER_FUNCTIONAL_INDEX_FUNCTION_IS_NOT_ALLOWED,mysql\n3759,ER_FULLTEXT_FUNCTIONAL_INDEX,mysql\n3760,ER_SPATIAL_FUNCTIONAL_INDEX,mysql\n3761,ER_WRONG_KEY_COLUMN_FUNCTIONAL_INDEX,mysql\n3762,ER_FUNCTIONAL_INDEX_ON_FIELD,mysql\n3763,ER_GENERATED_COLUMN_NAMED_FUNCTION_IS_NOT_ALLOWED,mysql\n3764,ER_GENERATED_COLUMN_ROW_VALUE,mysql\n3765,ER_GENERATED_COLUMN_VARIABLES,mysql\n3766,ER_DEPENDENT_BY_DEFAULT_GENERATED_VALUE,mysql\n3767,ER_DEFAULT_VAL_GENERATED_NON_PRIOR,mysql\n3768,ER_DEFAULT_VAL_GENERATED_REF_AUTO_INC,mysql\n3769,ER_DEFAULT_VAL_GENERATED_FUNCTION_IS_NOT_ALLOWED,mysql\n3770,ER_DEFAULT_VAL_GENERATED_NAMED_FUNCTION_IS_NOT_ALLOWED,mysql\n3771,ER_DEFAULT_VAL_GENERATED_ROW_VALUE,mysql\n3772,ER_DEFAULT_VAL_GENERATED_VARIABLES,mysql\n3773,ER_DEFAULT_AS_VAL_GENERATED,mysql\n3774,ER_UNSUPPORTED_ACTION_ON_DEFAULT_VAL_GENERATED,mysql\n3775,ER_GTID_UNSAFE_ALTER_ADD_COL_WITH_DEFAULT_EXPRESSION,mysql\n3776,ER_FK_CANNOT_CHANGE_ENGINE,mysql\n3777,ER_WARN_DEPRECATED_USER_SET_EXPR,mysql\n3778,ER_WARN_DEPRECATED_UTF8MB3_COLLATION,mysql\n3779,ER_WARN_DEPRECATED_NESTED_COMMENT_SYNTAX,mysql\n3780,ER_FK_INCOMPATIBLE_COLUMNS,mysql\n3781,ER_GR_HOLD_WAIT_TIMEOUT,mysql\n3782,ER_GR_HOLD_KILLED,mysql\n3783,ER_GR_HOLD_MEMBER_STATUS_ERROR,mysql\n3784,ER_RPL_ENCRYPTION_FAILED_TO_FETCH_KEY,mysql\n3785,ER_RPL_ENCRYPTION_KEY_NOT_FOUND,mysql\n3786,ER_RPL_ENCRYPTION_KEYRING_INVALID_KEY,mysql\n3787,ER_RPL_ENCRYPTION_HEADER_ERROR,mysql\n3788,ER_RPL_ENCRYPTION_FAILED_TO_ROTATE_LOGS,mysql\n3789,ER_RPL_ENCRYPTION_KEY_EXISTS_UNEXPECTED,mysql\n3790,ER_RPL_ENCRYPTION_FAILED_TO_GENERATE_KEY,mysql\n3791,ER_RPL_ENCRYPTION_FAILED_TO_STORE_KEY,mysql\n3792,ER_RPL_ENCRYPTION_FAILED_TO_REMOVE_KEY,mysql\n3793,ER_RPL_ENCRYPTION_UNABLE_TO_CHANGE_OPTION,mysql\n3794,ER_RPL_ENCRYPTION_MASTER_KEY_RECOVERY_FAILED,mysql\n3795,ER_SLOW_LOG_MODE_IGNORED_WHEN_NOT_LOGGING_TO_FILE,mysql\n3796,ER_GRP_TRX_CONSISTENCY_NOT_ALLOWED,mysql\n3797,ER_GRP_TRX_CONSISTENCY_BEFORE,mysql\n3798,ER_GRP_TRX_CONSISTENCY_AFTER_ON_TRX_BEGIN,mysql\n3799,ER_GRP_TRX_CONSISTENCY_BEGIN_NOT_ALLOWED,mysql\n3800,ER_FUNCTIONAL_INDEX_ROW_VALUE_IS_NOT_ALLOWED,mysql\n3801,ER_RPL_ENCRYPTION_FAILED_TO_ENCRYPT,mysql\n3802,ER_PAGE_TRACKING_NOT_STARTED,mysql\n3803,ER_PAGE_TRACKING_RANGE_NOT_TRACKED,mysql\n3804,ER_PAGE_TRACKING_CANNOT_PURGE,mysql\n3805,ER_RPL_ENCRYPTION_CANNOT_ROTATE_BINLOG_MASTER_KEY,mysql\n3806,ER_BINLOG_MASTER_KEY_RECOVERY_OUT_OF_COMBINATION,mysql\n3807,ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_OPERATE_KEY,mysql\n3808,ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_ROTATE_LOGS,mysql\n3809,ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_REENCRYPT_LOG,mysql\n3810,ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_CLEANUP_UNUSED_KEYS,mysql\n3811,ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_CLEANUP_AUX_KEY,mysql\n3812,ER_NON_BOOLEAN_EXPR_FOR_CHECK_CONSTRAINT,mysql\n3813,ER_COLUMN_CHECK_CONSTRAINT_REFERENCES_OTHER_COLUMN,mysql\n3814,ER_CHECK_CONSTRAINT_NAMED_FUNCTION_IS_NOT_ALLOWED,mysql\n3815,ER_CHECK_CONSTRAINT_FUNCTION_IS_NOT_ALLOWED,mysql\n3816,ER_CHECK_CONSTRAINT_VARIABLES,mysql\n3817,ER_CHECK_CONSTRAINT_ROW_VALUE,mysql\n3818,ER_CHECK_CONSTRAINT_REFERS_AUTO_INCREMENT_COLUMN,mysql\n3819,ER_CHECK_CONSTRAINT_VIOLATED,mysql\n3820,ER_CHECK_CONSTRAINT_REFERS_UNKNOWN_COLUMN,mysql\n3821,ER_CHECK_CONSTRAINT_NOT_FOUND,mysql\n3822,ER_CHECK_CONSTRAINT_DUP_NAME,mysql\n3823,ER_CHECK_CONSTRAINT_CLAUSE_USING_FK_REFER_ACTION_COLUMN,mysql\n3824,WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB,mysql\n3825,ER_INVALID_ENCRYPTION_REQUEST,mysql\n3826,ER_CANNOT_SET_TABLE_ENCRYPTION,mysql\n3827,ER_CANNOT_SET_DATABASE_ENCRYPTION,mysql\n3828,ER_CANNOT_SET_TABLESPACE_ENCRYPTION,mysql\n3829,ER_TABLESPACE_CANNOT_BE_ENCRYPTED,mysql\n3830,ER_TABLESPACE_CANNOT_BE_DECRYPTED,mysql\n3831,ER_TABLESPACE_TYPE_UNKNOWN,mysql\n3832,ER_TARGET_TABLESPACE_UNENCRYPTED,mysql\n3833,ER_CANNOT_USE_ENCRYPTION_CLAUSE,mysql\n3834,ER_INVALID_MULTIPLE_CLAUSES,mysql\n3835,ER_UNSUPPORTED_USE_OF_GRANT_AS,mysql\n3836,ER_UKNOWN_AUTH_ID_OR_ACCESS_DENIED_FOR_GRANT_AS,mysql\n3837,ER_DEPENDENT_BY_FUNCTIONAL_INDEX,mysql\n3838,ER_PLUGIN_NOT_EARLY,mysql\n3839,ER_INNODB_REDO_LOG_ARCHIVE_START_SUBDIR_PATH,mysql\n3840,ER_INNODB_REDO_LOG_ARCHIVE_START_TIMEOUT,mysql\n3841,ER_INNODB_REDO_LOG_ARCHIVE_DIRS_INVALID,mysql\n3842,ER_INNODB_REDO_LOG_ARCHIVE_LABEL_NOT_FOUND,mysql\n3843,ER_INNODB_REDO_LOG_ARCHIVE_DIR_EMPTY,mysql\n3844,ER_INNODB_REDO_LOG_ARCHIVE_NO_SUCH_DIR,mysql\n3845,ER_INNODB_REDO_LOG_ARCHIVE_DIR_CLASH,mysql\n3846,ER_INNODB_REDO_LOG_ARCHIVE_DIR_PERMISSIONS,mysql\n3847,ER_INNODB_REDO_LOG_ARCHIVE_FILE_CREATE,mysql\n3848,ER_INNODB_REDO_LOG_ARCHIVE_ACTIVE,mysql\n3849,ER_INNODB_REDO_LOG_ARCHIVE_INACTIVE,mysql\n3850,ER_INNODB_REDO_LOG_ARCHIVE_FAILED,mysql\n3851,ER_INNODB_REDO_LOG_ARCHIVE_SESSION,mysql\n3852,ER_STD_REGEX_ERROR,mysql\n3853,ER_INVALID_JSON_TYPE,mysql\n3854,ER_CANNOT_CONVERT_STRING,mysql\n3855,ER_DEPENDENT_BY_PARTITION_FUNC,mysql\n3856,ER_WARN_DEPRECATED_FLOAT_AUTO_INCREMENT,mysql\n3857,ER_RPL_CANT_STOP_SLAVE_WHILE_LOCKED_BACKUP,mysql\n3858,ER_WARN_DEPRECATED_FLOAT_DIGITS,mysql\n3859,ER_WARN_DEPRECATED_FLOAT_UNSIGNED,mysql\n3860,ER_WARN_DEPRECATED_INTEGER_DISPLAY_WIDTH,mysql\n3861,ER_WARN_DEPRECATED_ZEROFILL,mysql\n3862,ER_CLONE_DONOR,mysql\n3863,ER_CLONE_PROTOCOL,mysql\n3864,ER_CLONE_DONOR_VERSION,mysql\n3865,ER_CLONE_OS,mysql\n3866,ER_CLONE_PLATFORM,mysql\n3867,ER_CLONE_CHARSET,mysql\n3868,ER_CLONE_CONFIG,mysql\n3869,ER_CLONE_SYS_CONFIG,mysql\n3870,ER_CLONE_PLUGIN_MATCH,mysql\n3871,ER_CLONE_LOOPBACK,mysql\n3872,ER_CLONE_ENCRYPTION,mysql\n3873,ER_CLONE_DISK_SPACE,mysql\n3874,ER_CLONE_IN_PROGRESS,mysql\n3875,ER_CLONE_DISALLOWED,mysql\n3876,ER_CANNOT_GRANT_ROLES_TO_ANONYMOUS_USER,mysql\n3877,ER_SECONDARY_ENGINE_PLUGIN,mysql\n3878,ER_SECOND_PASSWORD_CANNOT_BE_EMPTY,mysql\n3879,ER_DB_ACCESS_DENIED,mysql\n3880,ER_DA_AUTH_ID_WITH_SYSTEM_USER_PRIV_IN_MANDATORY_ROLES,mysql\n3881,ER_DA_RPL_GTID_TABLE_CANNOT_OPEN,mysql\n3882,ER_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT,mysql\n3883,ER_DA_PLUGIN_INSTALL_ERROR,mysql\n3884,ER_NO_SESSION_TEMP,mysql\n3885,ER_DA_UNKNOWN_ERROR_NUMBER,mysql\n3886,ER_COLUMN_CHANGE_SIZE,mysql\n3887,ER_REGEXP_INVALID_CAPTURE_GROUP_NAME,mysql\n3888,ER_DA_SSL_LIBRARY_ERROR,mysql\n3889,ER_SECONDARY_ENGINE,mysql\n3890,ER_SECONDARY_ENGINE_DDL,mysql\n3891,ER_INCORRECT_CURRENT_PASSWORD,mysql\n3892,ER_MISSING_CURRENT_PASSWORD,mysql\n3893,ER_CURRENT_PASSWORD_NOT_REQUIRED,mysql\n3894,ER_PASSWORD_CANNOT_BE_RETAINED_ON_PLUGIN_CHANGE,mysql\n3895,ER_CURRENT_PASSWORD_CANNOT_BE_RETAINED,mysql\n3896,ER_PARTIAL_REVOKES_EXIST,mysql\n3897,ER_CANNOT_GRANT_SYSTEM_PRIV_TO_MANDATORY_ROLE,mysql\n3898,ER_XA_REPLICATION_FILTERS,mysql\n3899,ER_UNSUPPORTED_SQL_MODE,mysql\n3900,ER_REGEXP_INVALID_FLAG,mysql\n3901,ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS,mysql\n3902,ER_UNIT_NOT_FOUND,mysql\n3903,ER_INVALID_JSON_VALUE_FOR_FUNC_INDEX,mysql\n3904,ER_JSON_VALUE_OUT_OF_RANGE_FOR_FUNC_INDEX,mysql\n3905,ER_EXCEEDED_MV_KEYS_NUM,mysql\n3906,ER_EXCEEDED_MV_KEYS_SPACE,mysql\n3907,ER_FUNCTIONAL_INDEX_DATA_IS_TOO_LONG,mysql\n3908,ER_WRONG_MVI_VALUE,mysql\n3909,ER_WARN_FUNC_INDEX_NOT_APPLICABLE,mysql\n3910,ER_GRP_RPL_UDF_ERROR,mysql\n3911,ER_UPDATE_GTID_PURGED_WITH_GR,mysql\n3912,ER_GROUPING_ON_TIMESTAMP_IN_DST,mysql\n3913,ER_TABLE_NAME_CAUSES_TOO_LONG_PATH,mysql\n3914,ER_AUDIT_LOG_INSUFFICIENT_PRIVILEGE,mysql\n3916,ER_DA_GRP_RPL_STARTED_AUTO_REJOIN,mysql\n3917,ER_SYSVAR_CHANGE_DURING_QUERY,mysql\n3918,ER_GLOBSTAT_CHANGE_DURING_QUERY,mysql\n3919,ER_GRP_RPL_MESSAGE_SERVICE_INIT_FAILURE,mysql\n3920,ER_CHANGE_MASTER_WRONG_COMPRESSION_ALGORITHM_CLIENT,mysql\n3921,ER_CHANGE_MASTER_WRONG_COMPRESSION_LEVEL_CLIENT,mysql\n3922,ER_WRONG_COMPRESSION_ALGORITHM_CLIENT,mysql\n3923,ER_WRONG_COMPRESSION_LEVEL_CLIENT,mysql\n3924,ER_CHANGE_MASTER_WRONG_COMPRESSION_ALGORITHM_LIST_CLIENT,mysql\n3925,ER_CLIENT_PRIVILEGE_CHECKS_USER_CANNOT_BE_ANONYMOUS,mysql\n3926,ER_CLIENT_PRIVILEGE_CHECKS_USER_DOES_NOT_EXIST,mysql\n3927,ER_CLIENT_PRIVILEGE_CHECKS_USER_CORRUPT,mysql\n3928,ER_CLIENT_PRIVILEGE_CHECKS_USER_NEEDS_RPL_APPLIER_PRIV,mysql\n3929,ER_WARN_DA_PRIVILEGE_NOT_REGISTERED,mysql\n3930,ER_CLIENT_KEYRING_UDF_KEY_INVALID,mysql\n3931,ER_CLIENT_KEYRING_UDF_KEY_TYPE_INVALID,mysql\n3932,ER_CLIENT_KEYRING_UDF_KEY_TOO_LONG,mysql\n3933,ER_CLIENT_KEYRING_UDF_KEY_TYPE_TOO_LONG,mysql\n3934,ER_JSON_SCHEMA_VALIDATION_ERROR_WITH_DETAILED_REPORT,mysql\n3935,ER_DA_UDF_INVALID_CHARSET_SPECIFIED,mysql\n3936,ER_DA_UDF_INVALID_CHARSET,mysql\n3937,ER_DA_UDF_INVALID_COLLATION,mysql\n3938,ER_DA_UDF_INVALID_EXTENSION_ARGUMENT_TYPE,mysql\n3939,ER_MULTIPLE_CONSTRAINTS_WITH_SAME_NAME,mysql\n3940,ER_CONSTRAINT_NOT_FOUND,mysql\n3941,ER_ALTER_CONSTRAINT_ENFORCEMENT_NOT_SUPPORTED,mysql\n3942,ER_TABLE_VALUE_CONSTRUCTOR_MUST_HAVE_COLUMNS,mysql\n3943,ER_TABLE_VALUE_CONSTRUCTOR_CANNOT_HAVE_DEFAULT,mysql\n3944,ER_CLIENT_QUERY_FAILURE_INVALID_NON_ROW_FORMAT,mysql\n3945,ER_REQUIRE_ROW_FORMAT_INVALID_VALUE,mysql\n3946,ER_FAILED_TO_DETERMINE_IF_ROLE_IS_MANDATORY,mysql\n3947,ER_FAILED_TO_FETCH_MANDATORY_ROLE_LIST,mysql\n3948,ER_CLIENT_LOCAL_FILES_DISABLED,mysql\n3949,ER_IMP_INCOMPATIBLE_CFG_VERSION,mysql\n3950,ER_DA_OOM,mysql\n3951,ER_DA_UDF_INVALID_ARGUMENT_TO_SET_CHARSET,mysql\n3952,ER_DA_UDF_INVALID_RETURN_TYPE_TO_SET_CHARSET,mysql\n3953,ER_MULTIPLE_INTO_CLAUSES,mysql\n3954,ER_MISPLACED_INTO,mysql\n3955,ER_USER_ACCESS_DENIED_FOR_USER_ACCOUNT_BLOCKED_BY_PASSWORD_LOCK,mysql\n3956,ER_WARN_DEPRECATED_YEAR_UNSIGNED,mysql\n3957,ER_CLONE_NETWORK_PACKET,mysql\n3958,ER_SDI_OPERATION_FAILED_MISSING_RECORD,mysql\n3959,ER_DEPENDENT_BY_CHECK_CONSTRAINT,mysql\n3960,ER_GRP_OPERATION_NOT_ALLOWED_GR_MUST_STOP,mysql\n3961,ER_WARN_DEPRECATED_JSON_TABLE_ON_ERROR_ON_EMPTY,mysql\n3962,ER_WARN_DEPRECATED_INNER_INTO,mysql\n3963,ER_WARN_DEPRECATED_VALUES_FUNCTION_ALWAYS_NULL,mysql\n3964,ER_WARN_DEPRECATED_SQL_CALC_FOUND_ROWS,mysql\n3965,ER_WARN_DEPRECATED_FOUND_ROWS,mysql\n3966,ER_MISSING_JSON_VALUE,mysql\n3967,ER_MULTIPLE_JSON_VALUES,mysql\n3968,ER_HOSTNAME_TOO_LONG,mysql\n3969,ER_WARN_CLIENT_DEPRECATED_PARTITION_PREFIX_KEY,mysql\n3970,ER_GROUP_REPLICATION_USER_EMPTY_MSG,mysql\n3971,ER_GROUP_REPLICATION_USER_MANDATORY_MSG,mysql\n3972,ER_GROUP_REPLICATION_PASSWORD_LENGTH,mysql\n3973,ER_SUBQUERY_TRANSFORM_REJECTED,mysql\n3974,ER_DA_GRP_RPL_RECOVERY_ENDPOINT_FORMAT,mysql\n3975,ER_DA_GRP_RPL_RECOVERY_ENDPOINT_INVALID,mysql\n3976,ER_WRONG_VALUE_FOR_VAR_PLUS_ACTIONABLE_PART,mysql\n3977,ER_STATEMENT_NOT_ALLOWED_AFTER_START_TRANSACTION,mysql\n3978,ER_FOREIGN_KEY_WITH_ATOMIC_CREATE_SELECT,mysql\n3979,ER_NOT_ALLOWED_WITH_START_TRANSACTION,mysql\n3980,ER_INVALID_JSON_ATTRIBUTE,mysql\n3981,ER_ENGINE_ATTRIBUTE_NOT_SUPPORTED,mysql\n3982,ER_INVALID_USER_ATTRIBUTE_JSON,mysql\n3983,ER_INNODB_REDO_DISABLED,mysql\n3984,ER_INNODB_REDO_ARCHIVING_ENABLED,mysql\n3985,ER_MDL_OUT_OF_RESOURCES,mysql\n3986,ER_IMPLICIT_COMPARISON_FOR_JSON,mysql\n3987,ER_FUNCTION_DOES_NOT_SUPPORT_CHARACTER_SET,mysql\n3988,ER_IMPOSSIBLE_STRING_CONVERSION,mysql\n3989,ER_SCHEMA_READ_ONLY,mysql\n3990,ER_RPL_ASYNC_RECONNECT_GTID_MODE_OFF,mysql\n3991,ER_RPL_ASYNC_RECONNECT_AUTO_POSITION_OFF,mysql\n3992,ER_DISABLE_GTID_MODE_REQUIRES_ASYNC_RECONNECT_OFF,mysql\n3993,ER_DISABLE_AUTO_POSITION_REQUIRES_ASYNC_RECONNECT_OFF,mysql\n3994,ER_INVALID_PARAMETER_USE,mysql\n3995,ER_CHARACTER_SET_MISMATCH,mysql\n3996,ER_WARN_VAR_VALUE_CHANGE_NOT_SUPPORTED,mysql\n3997,ER_INVALID_TIME_ZONE_INTERVAL,mysql\n3998,ER_INVALID_CAST,mysql\n3999,ER_HYPERGRAPH_NOT_SUPPORTED_YET,mysql\n4000,ER_WARN_HYPERGRAPH_EXPERIMENTAL,mysql\n4001,ER_DA_NO_ERROR_LOG_PARSER_CONFIGURED,mysql\n4002,ER_WITH_COL_WRONG_LIST,mariadb\n4002,ER_DA_ERROR_LOG_TABLE_DISABLED,mysql\n4003,ER_TOO_MANY_DEFINITIONS_IN_WITH_CLAUSE,mariadb\n4003,ER_DA_ERROR_LOG_MULTIPLE_FILTERS,mysql\n4004,ER_DUP_QUERY_NAME,mariadb\n4004,ER_DA_CANT_OPEN_ERROR_LOG,mysql\n4005,ER_RECURSIVE_WITHOUT_ANCHORS,mariadb\n4005,ER_USER_REFERENCED_AS_DEFINER,mysql\n4006,ER_UNACCEPTABLE_MUTUAL_RECURSION,mariadb\n4006,ER_CANNOT_USER_REFERENCED_AS_DEFINER,mysql\n4007,ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED,mariadb\n4007,ER_REGEX_NUMBER_TOO_BIG,mysql\n4008,ER_NOT_STANDARD_COMPLIANT_RECURSIVE,mariadb\n4008,ER_SPVAR_NONINTEGER_TYPE,mysql\n4009,ER_WRONG_WINDOW_SPEC_NAME,mariadb\n4009,WARN_UNSUPPORTED_ACL_TABLES_READ,mysql\n4010,ER_DUP_WINDOW_NAME,mariadb\n4010,ER_BINLOG_UNSAFE_ACL_TABLE_READ_IN_DML_DDL,mysql\n4011,ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC,mariadb\n4011,ER_STOP_REPLICA_MONITOR_IO_THREAD_TIMEOUT,mysql\n4012,ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC,mariadb\n4012,ER_STARTING_REPLICA_MONITOR_IO_THREAD,mysql\n4013,ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC,mariadb\n4013,ER_CANT_USE_ANONYMOUS_TO_GTID_WITH_GTID_MODE_NOT_ON,mysql\n4014,ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS,mariadb\n4014,ER_CANT_COMBINE_ANONYMOUS_TO_GTID_AND_AUTOPOSITION,mysql\n4015,ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION,mariadb\n4015,ER_ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS_REQUIRES_GTID_MODE_ON,mysql\n4016,ER_WINDOW_FUNCTION_IN_WINDOW_SPEC,mariadb\n4016,ER_SQL_SLAVE_SKIP_COUNTER_USED_WITH_GTID_MODE_ON,mysql\n4017,ER_NOT_ALLOWED_WINDOW_FRAME,mariadb\n4017,ER_USING_ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS_AS_LOCAL_OR_UUID,mysql\n4018,ER_NO_ORDER_LIST_IN_WINDOW_SPEC,mariadb\n4018,ER_CANT_SET_ANONYMOUS_TO_GTID_AND_WAIT_UNTIL_SQL_THD_AFTER_GTIDS,mysql\n4019,ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY,mariadb\n4019,ER_CANT_SET_SQL_AFTER_OR_BEFORE_GTIDS_WITH_ANONYMOUS_TO_GTID,mysql\n4020,ER_WRONG_TYPE_FOR_ROWS_FRAME,mariadb\n4020,ER_ANONYMOUS_TO_GTID_UUID_SAME_AS_GROUP_NAME,mysql\n4021,ER_WRONG_TYPE_FOR_RANGE_FRAME,mariadb\n4021,ER_CANT_USE_SAME_UUID_AS_GROUP_NAME,mysql\n4022,ER_FRAME_EXCLUSION_NOT_SUPPORTED,mariadb\n4022,ER_GRP_RPL_RECOVERY_CHANNEL_STILL_RUNNING,mysql\n4023,ER_WINDOW_FUNCTION_DONT_HAVE_FRAME,mariadb\n4023,ER_INNODB_INVALID_AUTOEXTEND_SIZE_VALUE,mysql\n4024,ER_INVALID_NTILE_ARGUMENT,mariadb\n4024,ER_INNODB_INCOMPATIBLE_WITH_TABLESPACE,mysql\n4025,ER_CONSTRAINT_FAILED,mariadb\n4025,ER_INNODB_AUTOEXTEND_SIZE_OUT_OF_RANGE,mysql\n4026,ER_EXPRESSION_IS_TOO_BIG,mariadb\n4026,ER_CANNOT_USE_AUTOEXTEND_SIZE_CLAUSE,mysql\n4027,ER_ERROR_EVALUATING_EXPRESSION,mariadb\n4027,ER_ROLE_GRANTED_TO_ITSELF,mysql\n4028,ER_CALCULATING_DEFAULT_VALUE,mariadb\n4028,ER_TABLE_MUST_HAVE_A_VISIBLE_COLUMN,mysql\n4029,ER_EXPRESSION_REFERS_TO_UNINIT_FIELD,mariadb\n4029,ER_INNODB_COMPRESSION_FAILURE,mysql\n4030,ER_PARTITION_DEFAULT_ERROR,mariadb\n4030,ER_WARN_ASYNC_CONN_FAILOVER_NETWORK_NAMESPACE,mysql\n4031,ER_REFERENCED_TRG_DOES_NOT_EXIST,mariadb\n4031,ER_CLIENT_INTERACTION_TIMEOUT,mysql\n4032,ER_INVALID_DEFAULT_PARAM,mariadb\n4032,ER_INVALID_CAST_TO_GEOMETRY,mysql\n4033,ER_BINLOG_NON_SUPPORTED_BULK,mariadb\n4033,ER_INVALID_CAST_POLYGON_RING_DIRECTION,mysql\n4034,ER_BINLOG_UNCOMPRESS_ERROR,mariadb\n4034,ER_GIS_DIFFERENT_SRIDS_AGGREGATION,mysql\n4035,ER_JSON_BAD_CHR,mariadb\n4035,ER_RELOAD_KEYRING_FAILURE,mysql\n4036,ER_JSON_NOT_JSON_CHR,mariadb\n4036,ER_SDI_GET_KEYS_INVALID_TABLESPACE,mysql\n4037,ER_JSON_EOS,mariadb\n4037,ER_CHANGE_RPL_SRC_WRONG_COMPRESSION_ALGORITHM_SIZE,mysql\n4038,ER_JSON_SYNTAX,mariadb\n4039,ER_JSON_ESCAPING,mariadb\n4039,ER_CANT_USE_SAME_UUID_AS_VIEW_CHANGE_UUID,mysql\n4040,ER_JSON_DEPTH,mariadb\n4040,ER_ANONYMOUS_TO_GTID_UUID_SAME_AS_VIEW_CHANGE_UUID,mysql\n4041,ER_JSON_PATH_EOS,mariadb\n4041,ER_GRP_RPL_VIEW_CHANGE_UUID_FAIL_GET_VARIABLE,mysql\n4042,ER_JSON_PATH_SYNTAX,mariadb\n4042,ER_WARN_ADUIT_LOG_MAX_SIZE_AND_PRUNE_SECONDS,mysql\n4043,ER_JSON_PATH_DEPTH,mariadb\n4043,ER_WARN_ADUIT_LOG_MAX_SIZE_CLOSE_TO_ROTATE_ON_SIZE,mysql\n4044,ER_JSON_PATH_NO_WILDCARD,mariadb\n4044,ER_KERBEROS_CREATE_USER,mysql\n4045,ER_JSON_PATH_ARRAY,mariadb\n4045,ER_INSTALL_PLUGIN_CONFLICT_CLIENT,mysql\n4046,ER_JSON_ONE_OR_ALL,mariadb\n4046,ER_DA_ERROR_LOG_COMPONENT_FLUSH_FAILED,mysql\n4047,ER_UNSUPPORTED_COMPRESSED_TABLE,mariadb\n4047,ER_WARN_SQL_AFTER_MTS_GAPS_GAP_NOT_CALCULATED,mysql\n4048,ER_GEOJSON_INCORRECT,mariadb\n4048,ER_INVALID_ASSIGNMENT_TARGET,mysql\n4049,ER_GEOJSON_TOO_FEW_POINTS,mariadb\n4049,ER_OPERATION_NOT_ALLOWED_ON_GR_SECONDARY,mysql\n4050,ER_GEOJSON_NOT_CLOSED,mariadb\n4050,ER_GRP_RPL_FAILOVER_CHANNEL_STATUS_PROPAGATION,mysql\n4051,ER_JSON_PATH_EMPTY,mariadb\n4051,ER_WARN_AUDIT_LOG_FORMAT_UNIX_TIMESTAMP_ONLY_WHEN_JSON,mysql\n4052,ER_SLAVE_SAME_ID,mariadb\n4052,ER_INVALID_MFA_PLUGIN_SPECIFIED,mysql\n4053,ER_FLASHBACK_NOT_SUPPORTED,mariadb\n4053,ER_IDENTIFIED_BY_UNSUPPORTED,mysql\n4054,ER_KEYS_OUT_OF_ORDER,mariadb\n4054,ER_INVALID_PLUGIN_FOR_REGISTRATION,mysql\n4055,ER_OVERLAPPING_KEYS,mariadb\n4055,ER_PLUGIN_REQUIRES_REGISTRATION,mysql\n4056,ER_REQUIRE_ROW_BINLOG_FORMAT,mariadb\n4056,ER_MFA_METHOD_EXISTS,mysql\n4057,ER_ISOLATION_MODE_NOT_SUPPORTED,mariadb\n4057,ER_MFA_METHOD_NOT_EXISTS,mysql\n4058,ER_ON_DUPLICATE_DISABLED,mariadb\n4058,ER_AUTHENTICATION_POLICY_MISMATCH,mysql\n4059,ER_UPDATES_WITH_CONSISTENT_SNAPSHOT,mariadb\n4059,ER_PLUGIN_REGISTRATION_DONE,mysql\n4060,ER_ROLLBACK_ONLY,mariadb\n4060,ER_INVALID_USER_FOR_REGISTRATION,mysql\n4061,ER_ROLLBACK_TO_SAVEPOINT,mariadb\n4061,ER_USER_REGISTRATION_FAILED,mysql\n4062,ER_ISOLATION_LEVEL_WITH_CONSISTENT_SNAPSHOT,mariadb\n4062,ER_MFA_METHODS_INVALID_ORDER,mysql\n4063,ER_UNSUPPORTED_COLLATION,mariadb\n4063,ER_MFA_METHODS_IDENTICAL,mysql\n4064,ER_METADATA_INCONSISTENCY,mariadb\n4064,ER_INVALID_MFA_OPERATIONS_FOR_PASSWORDLESS_USER,mysql\n4065,ER_CF_DIFFERENT,mariadb\n4065,ER_CHANGE_REPLICATION_SOURCE_NO_OPTIONS_FOR_GTID_ONLY,mysql\n4066,ER_RDB_TTL_DURATION_FORMAT,mariadb\n4066,ER_CHANGE_REP_SOURCE_CANT_DISABLE_REQ_ROW_FORMAT_WITH_GTID_ONLY,mysql\n4067,ER_RDB_STATUS_GENERAL,mariadb\n4067,ER_CHANGE_REP_SOURCE_CANT_DISABLE_AUTO_POSITION_WITH_GTID_ONLY,mysql\n4068,ER_RDB_STATUS_MSG,mariadb\n4068,ER_CHANGE_REP_SOURCE_CANT_DISABLE_GTID_ONLY_WITHOUT_POSITIONS,mysql\n4069,ER_RDB_TTL_UNSUPPORTED,mariadb\n4069,ER_CHANGE_REP_SOURCE_CANT_DISABLE_AUTO_POS_WITHOUT_POSITIONS,mysql\n4070,ER_RDB_TTL_COL_FORMAT,mariadb\n4070,ER_CHANGE_REP_SOURCE_GR_CHANNEL_WITH_GTID_MODE_NOT_ON,mysql\n4071,ER_PER_INDEX_CF_DEPRECATED,mariadb\n4071,ER_CANT_USE_GTID_ONLY_WITH_GTID_MODE_NOT_ON,mysql\n4072,ER_KEY_CREATE_DURING_ALTER,mariadb\n4072,ER_WARN_C_DISABLE_GTID_ONLY_WITH_SOURCE_AUTO_POS_INVALID_POS,mysql\n4073,ER_SK_POPULATE_DURING_ALTER,mariadb\n4073,ER_DA_SSL_FIPS_MODE_ERROR,mysql\n4074,ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG,mariadb\n4074,ER_VALUE_OUT_OF_RANGE,mysql\n4075,ER_NET_OK_PACKET_TOO_LARGE,mariadb\n4075,ER_FULLTEXT_WITH_ROLLUP,mysql\n4076,ER_GEOJSON_EMPTY_COORDINATES,mariadb\n4076,ER_REGEXP_MISSING_RESOURCE,mysql\n4077,ER_MYROCKS_CANT_NOPAD_COLLATION,mariadb\n4077,ER_WARN_REGEXP_USING_DEFAULT,mysql\n4078,ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION,mariadb\n4078,ER_REGEXP_MISSING_FILE,mysql\n4079,ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION,mariadb\n4079,ER_WARN_DEPRECATED_COLLATION,mysql\n4080,ER_WRONG_PARAMCOUNT_TO_CURSOR,mariadb\n4080,ER_CONCURRENT_PROCEDURE_USAGE,mysql\n4081,ER_UNKNOWN_STRUCTURED_VARIABLE,mariadb\n4081,ER_DA_GLOBAL_CONN_LIMIT,mysql\n4082,ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD,mariadb\n4082,ER_DA_CONN_LIMIT,mysql\n4083,ER_END_IDENTIFIER_DOES_NOT_MATCH,mariadb\n4083,ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE_INSTANT,mysql\n4084,ER_SEQUENCE_RUN_OUT,mariadb\n4084,ER_WARN_SF_UDF_NAME_COLLISION,mysql\n4085,ER_SEQUENCE_INVALID_DATA,mariadb\n4085,ER_CANNOT_PURGE_BINLOG_WITH_BACKUP_LOCK,mysql\n4086,ER_SEQUENCE_INVALID_TABLE_STRUCTURE,mariadb\n4086,ER_TOO_MANY_WINDOWS,mysql\n4087,ER_SEQUENCE_ACCESS_ERROR,mariadb\n4087,ER_MYSQLBACKUP_CLIENT_MSG,mysql\n4088,ER_SEQUENCE_BINLOG_FORMAT,mariadb\n4088,ER_COMMENT_CONTAINS_INVALID_STRING,mysql\n4089,ER_NOT_SEQUENCE,mariadb\n4089,ER_DEFINITION_CONTAINS_INVALID_STRING,mysql\n4090,ER_NOT_SEQUENCE2,mariadb\n4090,ER_CANT_EXECUTE_COMMAND_WITH_ASSIGNED_GTID_NEXT,mysql\n4091,ER_UNKNOWN_SEQUENCES,mariadb\n4091,ER_XA_TEMP_TABLE,mysql\n4092,ER_UNKNOWN_VIEW,mariadb\n4092,ER_INNODB_MAX_ROW_VERSION,mysql\n4093,ER_WRONG_INSERT_INTO_SEQUENCE,mariadb\n4094,ER_SP_STACK_TRACE,mariadb\n4094,ER_OPERATION_NOT_ALLOWED_WHILE_PRIMARY_CHANGE_IS_RUNNING,mysql\n4095,ER_PACKAGE_ROUTINE_IN_SPEC_NOT_DEFINED_IN_BODY,mariadb\n4095,ER_WARN_DEPRECATED_DATETIME_DELIMITER,mysql\n4096,ER_PACKAGE_ROUTINE_FORWARD_DECLARATION_NOT_DEFINED,mariadb\n4096,ER_WARN_DEPRECATED_SUPERFLUOUS_DELIMITER,mysql\n4097,ER_COMPRESSED_COLUMN_USED_AS_KEY,mariadb\n4097,ER_CANNOT_PERSIST_SENSITIVE_VARIABLES,mysql\n4098,ER_UNKNOWN_COMPRESSION_METHOD,mariadb\n4098,ER_WARN_CANNOT_SECURELY_PERSIST_SENSITIVE_VARIABLES,mysql\n4099,ER_WRONG_NUMBER_OF_VALUES_IN_TVC,mariadb\n4099,ER_WARN_TRG_ALREADY_EXISTS,mysql\n4100,ER_FIELD_REFERENCE_IN_TVC,mariadb\n4100,ER_IF_NOT_EXISTS_UNSUPPORTED_TRG_EXISTS_ON_DIFFERENT_TABLE,mysql\n4101,ER_WRONG_TYPE_FOR_PERCENTILE_FUNC,mariadb\n4101,ER_IF_NOT_EXISTS_UNSUPPORTED_UDF_NATIVE_FCT_NAME_COLLISION,mysql\n4102,ER_ARGUMENT_NOT_CONSTANT,mariadb\n4102,ER_SET_PASSWORD_AUTH_PLUGIN_ERROR,mysql\n4103,ER_ARGUMENT_OUT_OF_RANGE,mariadb\n4104,ER_WRONG_TYPE_OF_ARGUMENT,mariadb\n4105,ER_NOT_AGGREGATE_FUNCTION,mariadb\n4105,ER_SRS_INVALID_LATITUDE_OF_ORIGIN,mysql\n4106,ER_INVALID_AGGREGATE_FUNCTION,mariadb\n4106,ER_SRS_INVALID_LONGITUDE_OF_ORIGIN,mysql\n4107,ER_INVALID_VALUE_TO_LIMIT,mariadb\n4107,ER_SRS_UNUSED_PROJ_PARAMETER_PRESENT,mysql\n4108,ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT,mariadb\n4108,ER_GIPK_COLUMN_EXISTS,mysql\n4109,ER_UPDATE_INFO_WITH_SYSTEM_VERSIONING,mariadb\n4109,ER_GIPK_FAILED_AUTOINC_COLUMN_EXISTS,mysql\n4110,ER_VERS_FIELD_WRONG_TYPE,mariadb\n4110,ER_GIPK_COLUMN_ALTER_NOT_ALLOWED,mysql\n4111,ER_VERS_ENGINE_UNSUPPORTED,mariadb\n4111,ER_DROP_PK_COLUMN_TO_DROP_GIPK,mysql\n4112,ER_CREATE_SELECT_WITH_GIPK_DISALLOWED_IN_SBR,mysql\n4113,ER_PARTITION_WRONG_TYPE,mariadb\n4113,ER_DA_EXPIRE_LOGS_DAYS_IGNORED,mysql\n4114,WARN_VERS_PART_FULL,mariadb\n4114,ER_CTE_RECURSIVE_NOT_UNION,mysql\n4115,WARN_VERS_PARAMETERS,mariadb\n4115,ER_COMMAND_BACKEND_FAILED_TO_FETCH_SECURITY_CTX,mysql\n4116,ER_VERS_DROP_PARTITION_INTERVAL,mariadb\n4116,ER_COMMAND_SERVICE_BACKEND_FAILED,mysql\n4117,ER_CLIENT_FILE_PRIVILEGE_FOR_REPLICATION_CHECKS,mysql\n4118,WARN_VERS_PART_NON_HISTORICAL,mariadb\n4118,ER_GROUP_REPLICATION_FORCE_MEMBERS_COMMAND_FAILURE,mysql\n4119,ER_VERS_ALTER_NOT_ALLOWED,mariadb\n4119,ER_WARN_DEPRECATED_IDENT,mysql\n4120,ER_VERS_ALTER_ENGINE_PROHIBITED,mariadb\n4120,ER_INTERSECT_ALL_MAX_DUPLICATES_EXCEEDED,mysql\n4121,ER_VERS_RANGE_PROHIBITED,mariadb\n4121,ER_TP_QUERY_THRS_PER_GRP_EXCEEDS_TXN_THR_LIMIT,mysql\n4122,ER_CONFLICTING_FOR_SYSTEM_TIME,mariadb\n4122,ER_BAD_TIMESTAMP_FORMAT,mysql\n4123,ER_VERS_TABLE_MUST_HAVE_COLUMNS,mariadb\n4123,ER_SHAPE_PRIDICTION_UDF,mysql\n4124,ER_VERS_NOT_VERSIONED,mariadb\n4124,ER_SRS_INVALID_HEIGHT,mysql\n4125,ER_MISSING,mariadb\n4125,ER_SRS_INVALID_SCALING,mysql\n4126,ER_VERS_PERIOD_COLUMNS,mariadb\n4126,ER_SRS_INVALID_ZONE_WIDTH,mysql\n4127,ER_PART_WRONG_VALUE,mariadb\n4127,ER_SRS_INVALID_LATITUDE_POLAR_STERE_VAR_A,mysql\n4128,ER_VERS_WRONG_PARTS,mariadb\n4128,ER_WARN_DEPRECATED_CLIENT_NO_SCHEMA_OPTION,mysql\n4129,ER_VERS_NO_TRX_ID,mariadb\n4129,ER_TABLE_NOT_EMPTY,mysql\n4130,ER_VERS_ALTER_SYSTEM_FIELD,mariadb\n4130,ER_TABLE_NO_PRIMARY_KEY,mysql\n4131,ER_DROP_VERSIONING_SYSTEM_TIME_PARTITION,mariadb\n4131,ER_TABLE_IN_SHARED_TABLESPACE,mysql\n4132,ER_VERS_DB_NOT_SUPPORTED,mariadb\n4132,ER_INDEX_OTHER_THAN_PK,mysql\n4133,ER_VERS_TRT_IS_DISABLED,mariadb\n4133,ER_LOAD_BULK_DATA_UNSORTED,mysql\n4134,ER_VERS_DUPLICATE_ROW_START_END,mariadb\n4134,ER_BULK_EXECUTOR_ERROR,mysql\n4135,ER_VERS_ALREADY_VERSIONED,mariadb\n4135,ER_BULK_READER_LIBCURL_INIT_FAILED,mysql\n4136,ER_BULK_READER_LIBCURL_ERROR,mysql\n4137,ER_VERS_NOT_SUPPORTED,mariadb\n4137,ER_BULK_READER_SERVER_ERROR,mysql\n4138,ER_VERS_TRX_PART_HISTORIC_ROW_NOT_SUPPORTED,mariadb\n4138,ER_BULK_READER_COMMUNICATION_ERROR,mysql\n4139,ER_INDEX_FILE_FULL,mariadb\n4139,ER_BULK_LOAD_DATA_FAILED,mysql\n4140,ER_UPDATED_COLUMN_ONLY_ONCE,mariadb\n4140,ER_BULK_LOADER_COLUMN_TOO_BIG_FOR_LEFTOVER_BUFFER,mysql\n4141,ER_EMPTY_ROW_IN_TVC,mariadb\n4141,ER_BULK_LOADER_COMPONENT_ERROR,mysql\n4142,ER_VERS_QUERY_IN_PARTITION,mariadb\n4142,ER_BULK_LOADER_FILE_CONTAINS_LESS_LINES_THAN_IGNORE_CLAUSE,mysql\n4143,ER_KEY_DOESNT_SUPPORT,mariadb\n4143,ER_BULK_PARSER_MISSING_ENCLOSED_BY,mysql\n4144,ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD,mariadb\n4144,ER_BULK_PARSER_ROW_BUFFER_MAX_TOTAL_COLS_EXCEEDED,mysql\n4145,ER_BACKUP_LOCK_IS_ACTIVE,mariadb\n4145,ER_BULK_PARSER_COPY_BUFFER_SIZE_EXCEEDED,mysql\n4146,ER_BACKUP_NOT_RUNNING,mariadb\n4146,ER_BULK_PARSER_UNEXPECTED_END_OF_INPUT,mysql\n4147,ER_BACKUP_WRONG_STAGE,mariadb\n4147,ER_BULK_PARSER_UNEXPECTED_ROW_TERMINATOR,mysql\n4148,ER_BACKUP_STAGE_FAILED,mariadb\n4148,ER_BULK_PARSER_UNEXPECTED_CHAR_AFTER_ENDING_ENCLOSED_BY,mysql\n4149,ER_BACKUP_UNKNOWN_STAGE,mariadb\n4149,ER_BULK_PARSER_UNEXPECTED_CHAR_AFTER_NULL_ESCAPE,mysql\n4150,ER_USER_IS_BLOCKED,mariadb\n4150,ER_BULK_PARSER_UNEXPECTED_CHAR_AFTER_COLUMN_TERMINATOR,mysql\n4151,ER_ACCOUNT_HAS_BEEN_LOCKED,mariadb\n4151,ER_BULK_PARSER_INCOMPLETE_ESCAPE_SEQUENCE,mysql\n4152,ER_PERIOD_TEMPORARY_NOT_ALLOWED,mariadb\n4152,ER_LOAD_BULK_DATA_FAILED,mysql\n4153,ER_PERIOD_TYPES_MISMATCH,mariadb\n4153,ER_LOAD_BULK_DATA_WRONG_VALUE_FOR_FIELD,mysql\n4154,ER_MORE_THAN_ONE_PERIOD,mariadb\n4154,ER_LOAD_BULK_DATA_WARN_NULL_TO_NOTNULL,mysql\n4155,ER_PERIOD_FIELD_WRONG_ATTRIBUTES,mariadb\n4155,ER_REQUIRE_TABLE_PRIMARY_KEY_CHECK_GENERATE_WITH_GR,mysql\n4156,ER_PERIOD_NOT_FOUND,mariadb\n4156,ER_CANT_CHANGE_SYS_VAR_IN_READ_ONLY_MODE,mysql\n4157,ER_PERIOD_COLUMNS_UPDATED,mariadb\n4157,ER_INNODB_INSTANT_ADD_DROP_NOT_SUPPORTED_MAX_SIZE,mysql\n4158,ER_PERIOD_CONSTRAINT_DROP,mariadb\n4158,ER_INNODB_INSTANT_ADD_NOT_SUPPORTED_MAX_FIELDS,mysql\n4159,ER_TOO_LONG_KEYPART,mariadb\n4159,ER_CANT_SET_PERSISTED,mysql\n4160,ER_TOO_LONG_DATABASE_COMMENT,mariadb\n4160,ER_INSTALL_COMPONENT_SET_NULL_VALUE,mysql\n4161,ER_UNKNOWN_DATA_TYPE,mariadb\n4161,ER_INSTALL_COMPONENT_SET_UNUSED_VALUE,mysql\n4162,ER_UNKNOWN_OPERATOR,mariadb\n4162,ER_WARN_DEPRECATED_USER_DEFINED_COLLATIONS,mysql\n4163,ER_WARN_HISTORY_ROW_START_TIME,mariadb\n4163,ER_USER_LOCK_OVERLONG_NAME,mysql\n4164,ER_PART_STARTS_BEYOND_INTERVAL,mariadb\n4164,ER_WARN_NO_SPACE_VERSION_COMMENT,mysql\n4165,ER_GALERA_REPLICATION_NOT_SUPPORTED,mariadb\n4165,ER_VALIDATE_PASSWORD_INSUFFICIENT_CHANGED_CHARACTERS,mysql\n4166,ER_LOAD_INFILE_CAPABILITY_DISABLED,mariadb\n4166,ER_WARN_DEPRECATED_WITH_NOTE,mysql\n4167,ER_NO_SECURE_TRANSPORTS_CONFIGURED,mariadb\n4168,ER_SLAVE_IGNORED_SHARED_TABLE,mariadb\n4169,ER_NO_AUTOINCREMENT_WITH_UNIQUE,mariadb\n4170,ER_KEY_CONTAINS_PERIOD_FIELDS,mariadb\n4171,ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS,mariadb\n4172,ER_NOT_ALLOWED_IN_THIS_CONTEXT,mariadb\n4173,ER_DATA_WAS_COMMITED_UNDER_ROLLBACK,mariadb\n4174,ER_PK_INDEX_CANT_BE_IGNORED,mariadb\n4175,ER_BINLOG_UNSAFE_SKIP_LOCKED,mariadb\n4176,ER_JSON_TABLE_ERROR_ON_FIELD,mariadb\n4177,ER_JSON_TABLE_ALIAS_REQUIRED,mariadb\n4178,ER_JSON_TABLE_SCALAR_EXPECTED,mariadb\n4179,ER_JSON_TABLE_MULTIPLE_MATCHES,mariadb\n4180,ER_WITH_TIES_NEEDS_ORDER,mariadb\n4181,ER_REMOVED_ORPHAN_TRIGGER,mariadb\n4182,ER_STORAGE_ENGINE_DISABLED,mariadb\n4183,WARN_SFORMAT_ERROR,mariadb\n4184,ER_PARTITION_CONVERT_SUBPARTITIONED,mariadb\n4185,ER_PROVIDER_NOT_LOADED,mariadb\n4186,ER_JSON_HISTOGRAM_PARSE_FAILED,mariadb\n4187,ER_SF_OUT_INOUT_ARG_NOT_ALLOWED,mariadb\n4188,ER_INCONSISTENT_SLAVE_TEMP_TABLE,mariadb\n4189,ER_VERS_HIST_PART_FAILED,mariadb\n4190,WARN_OPTION_CHANGING,mariadb\n4191,ER_CM_OPTION_MISSING_REQUIREMENT,mariadb\n4192,ER_SLAVE_STATEMENT_TIMEOUT,mariadb\n4193,ER_JSON_INVALID_VALUE_FOR_KEYWORD,mariadb\n4194,ER_JSON_SCHEMA_KEYWORD_UNSUPPORTED,mariadb\n"
  },
  {
    "path": "tools/osx-ci.cnf",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n[mysqld]\nsocket=/var/run/mysqld/mysqld.sock\nssl-ca=/etc/ssl/certs/mysql/ca-cert.pem\nssl-cert=/etc/ssl/certs/mysql/server-cert.pem\nssl-key=/etc/ssl/certs/mysql/server-key.pem\n\n[client]\nsocket=/var/run/mysqld/mysqld.sock"
  },
  {
    "path": "tools/scripts/build_unix_local.sh",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nset -e\n\nrepo_base=$(realpath $(dirname $(realpath $0))/../..)\n\nBK=cmake\nIMAGE=build-gcc13\nIMAGE_VERSION=1\nCONTAINER=builder-$IMAGE\nFULL_IMAGE=ghcr.io/anarthal/cpp-ci-containers/$IMAGE:$IMAGE_VERSION\nDB=mysql-9_4_0\nDB_VERSION=1\n\ndocker start $DB || docker run -d \\\n    --name $DB \\\n    -v /var/run/mysqld:/var/run/mysqld \\\n    -p 3306:3306 \\\n    ghcr.io/anarthal/cpp-ci-containers/$DB:$DB_VERSION\ndocker start $CONTAINER || docker run -dit \\\n    --name $CONTAINER \\\n    -v \"$repo_base:/opt/boost-mysql\" \\\n    -v /var/run/mysqld:/var/run/mysqld \\\n    $FULL_IMAGE\ndocker network connect my-net $DB || echo \"DB already connected\"\ndocker network connect my-net $CONTAINER || echo \"Network already connected\"\n\n# Command line\ndb_args=\"--server-host=$DB\"\ncase $BK in\n    b2) cmd=\"$db_args\n            --toolset=clang\n            --cxxstd=11\n            --variant=release\n            --stdlib=native\n            --address-model=64\n            --separate-compilation=1\n            --use-ts-executor=0\n            --address-sanitizer=0\n            --undefined-sanitizer=0\n            --coverage=0\n            --valgrind=0\"\n        ;;\n    \n    cmake) cmd=\"$db_args\n            --cmake-build-type=Debug\n            --build-shared-libs=1\n            --cxxstd=11\n            --install-test=0\n            \"\n        ;;\n    \n    fuzz) cmd=\"$db_args\" ;;\n\n    bench) cmd=\"$db_args\n                --protocol-iters=10\n                --connection-pool-iters=0\n                \"\n        ;;\n\n    *) cmd=\"\" ;;\nesac\n\n# Run\ndocker exec $CONTAINER python /opt/boost-mysql/tools/ci/main.py --source-dir=/opt/boost-mysql $BK $cmd\n"
  },
  {
    "path": "tools/scripts/build_windows_local.bat",
    "content": "@REM\n@REM Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n@REM\n@REM Distributed under the Boost Software License, Version 1.0. (See accompanying\n@REM file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n@REM\n\nSET IMAGE=build-msvc14_3\nSET IMAGE_TAG=latest\nSET SCRIPT_PATH=%~dp0\n\nSET CONTAINER=\"builder-%IMAGE%\"\ndocker start %CONTAINER% || docker run -dit --name %CONTAINER% -v \"%SCRIPT_PATH%..\\..:C:\\boost-mysql\" \"ghcr.io/anarthal-containers/%IMAGE%:%IMAGE_TAG%\" || exit /b 1\ndocker exec %CONTAINER% python.exe \"C:\\boost-mysql\\tools\\ci\\main.py\" --source-dir=C:\\boost-mysql b2 --toolset=msvc ^\n    --cxxstd=20 ^\n    --variant=debug ^\n    --address-model=64 || exit /b 1\n"
  },
  {
    "path": "tools/scripts/check_links.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport requests\nfrom bs4 import BeautifulSoup\nimport os\nfrom os import path\n\nREPO_BASE = path.abspath(path.join(path.dirname(__file__), '..', '..'))\nDOC_PATH = path.join(REPO_BASE, 'doc', 'html')\n\ndef list_doc_files():\n    all_files = []\n    for base_dir, _, files in os.walk(DOC_PATH):\n        all_files += [path.join(base_dir, f) for f in files if f.endswith('.html')]\n    return all_files\n\ndef get_href(elm, current_file):\n    try:\n        res = elm['href']\n    except KeyError:\n        return None\n    if res.startswith('http://') or res.startswith('https://'):\n        if '#error_er_' in res:\n            return res.split('#error_er_')[0]\n        else:\n            return res\n    else:\n        curdir = path.dirname(current_file)\n        return path.realpath(path.join(curdir, res.split('#')[0]))\n\ndef extract_links():\n    external_links = {}\n    internal_links = {}\n    \n    for fname in list_doc_files():\n        with open(fname, 'rt') as f:\n            html_doc = f.read()\n        soup = BeautifulSoup(html_doc, 'html.parser')\n        links = [get_href(elm, fname) for elm in soup.find_all('a')]\n        internal_links.update({ elm: fname for elm in links if elm is not None and elm.startswith('/')})\n        external_links.update({ elm: fname for elm in links if elm is not None and \\\n                              (elm.startswith('http://') or elm.startswith('https://'))})\n        \n    return (external_links, internal_links)\n\ndef check_external_links(links):\n    s = requests.Session()\n    for url in sorted(links.keys()):\n        print('Checking ', url)\n        response = s.head(url, allow_redirects=True)\n        if response.status_code != 200:\n            print('  ++++ {} response code: {}'.format(url, response.status_code))\n            \ndef check_internal_links(links):\n    for target, link_file in links.items():\n        if not path.exists(target):\n            print('  ++++ Link {} in file {} does not exist'.format(target, link_file))\n            \ndef main():\n    external, internal = extract_links()\n    check_external_links(external)\n    check_internal_links(internal)\n    \nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tools/scripts/collations.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# This script generates the collation headers, given a dump of the SHOW COLLATION\n# statement for MySQL and MariaDB. MySQL 5 and 8 are compatible, while MariaDB\n# renamed some collations in a way that makes having them in a separate header preferable.\n# e.g. mysql -u root -e \"SHOW COLLATION\" > private/mysql-collations.txt\n#      mysql -u root -e \"SHOW COLLATION\" > private/mariadb-collations.txt\n\nimport pandas as pd\nfrom pathlib import Path\nfrom os import path\nfrom typing import Literal\nfrom subprocess import run\n\nREPO_BASE = Path(path.abspath(path.join(path.dirname(path.realpath(__file__)), '..', '..')))\nMYSQL_SHOW_COLLATION = REPO_BASE.joinpath('private', 'mysql-collations.txt')\nMARIADB_SHOW_COLLATION = REPO_BASE.joinpath('private', 'mariadb-collations.txt')\n\nCOLLATIONS_ENTRY_TEMPLATE = '''\n// Identifies the {collation} collation in {flavor} servers.\nBOOST_INLINE_CONSTEXPR std::uint16_t {collation} = {id};\n'''\n\nCOLLATIONS_HEADER_TEMPLATE = '''\n#ifndef BOOST_MYSQL_{flavor}_COLLATION_IDS_HPP\n#define BOOST_MYSQL_{flavor}_COLLATION_IDS_HPP\n\n// This header was generated by collations.py - do not edit directly\n\n#include <cstdint>\n\n#include <boost/config.hpp>\n\nnamespace boost {{\nnamespace mysql {{\nnamespace {flavor}_collations {{\n{entries}\n}}  // namespace {flavor}_collations\n}}  // namespace mysql\n}}  // namespace boost\n\n#endif\n'''\n\ndef parse_show_collation(fname: Path) -> pd.DataFrame:\n    return pd \\\n        .read_table(fname)[['Collation', 'Id']] \\\n        .rename(columns={ 'Collation': 'collation', 'Id': 'id'}) \\\n        .sort_values(by='id')\n\n\ndef render_collations_header(flavor: Literal['mysql', 'mariadb'], df_collations: pd.DataFrame) -> str:\n    entries = ''.join(COLLATIONS_ENTRY_TEMPLATE.format(\n        collation=r.collation,\n        id=r.id,\n        flavor=flavor\n    ) for r in df_collations.itertuples())\n    return COLLATIONS_HEADER_TEMPLATE.format(flavor=flavor, entries=entries)\n\n\n# Actually perform the generation\ndef write_headers(df_mysql: pd.DataFrame, df_mariadb: pd.DataFrame) -> None:\n    for flavor, df in [('mysql', df_mysql), ('mariadb', df_mariadb)]:\n        fname = REPO_BASE.joinpath('include', 'boost', 'mysql', f'{flavor}_collations.hpp')\n        with open(fname, 'wt') as f:\n            f.write(render_collations_header(flavor, df))\n\n\n# We need to run file_headers.py to set copyrights and headers\ndef invoke_file_headers() -> None:\n    run(['python', str(REPO_BASE.joinpath('tools', 'scripts', 'file_headers.py'))])\n\n\ndef main():\n    df_mysql = parse_show_collation(MYSQL_SHOW_COLLATION)\n    df_mariadb = parse_show_collation(MARIADB_SHOW_COLLATION)\n    write_headers(df_mysql, df_mariadb)\n    invoke_file_headers()\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tools/scripts/corpus_field_table.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Generates the seed corpus for field and row fuzzers from captured wireshark frames.\n\nimport json\nfrom enum import Enum\nfrom pathlib import Path\nfrom os import path\nimport struct\nfrom typing import List, NamedTuple\nimport csv\n\n_REPO_BASE = Path(path.join(path.dirname(path.realpath(__file__)), '..', '..')).absolute()\n_TEXT_JSON = _REPO_BASE.joinpath('private', 'fuzzing', 'text.json')\n_BINARY_JSON = _REPO_BASE.joinpath('private', 'fuzzing', 'binary.json')\n\nclass _ProtocolFieldType(Enum):\n    decimal = 0x00\n    tiny = 0x01\n    short_ = 0x02\n    long_ = 0x03\n    float_ = 0x04\n    double_ = 0x05\n    null = 0x06\n    timestamp = 0x07\n    longlong = 0x08\n    int24 = 0x09\n    date = 0x0a\n    time = 0x0b\n    datetime = 0x0c\n    year = 0x0d\n    varchar = 0x0f\n    bit = 0x10\n    json = 0xf5\n    newdecimal = 0xf6\n    blob = 0xfc\n    var_string = 0xfd\n    string = 0xfe\n    geometry = 0xff\n\n\nclass _ColumnType(Enum):\n    tinyint = 0\n    smallint = 1\n    mediumint = 2\n    int_ = 3\n    bigint = 4\n    float_ = 5\n    double_ = 6\n    decimal = 7\n    bit = 8\n    year = 9\n    time = 10\n    date = 11\n    datetime = 12\n    timestamp = 13\n    char_ = 14\n    varchar = 15\n    binary = 16\n    varbinary = 17\n    text = 18\n    blob = 19\n    enum_ = 20\n    set = 21\n    json = 22\n    geometry = 23\n    unknown = 24\n\n\nclass _Encoding(Enum):\n    text = 0\n    binary = 1\n\n\n_TYPE_MAP = {\n    _ProtocolFieldType.decimal: _ColumnType.decimal,\n    _ProtocolFieldType.newdecimal: _ColumnType.decimal,\n    _ProtocolFieldType.geometry: _ColumnType.geometry,\n    _ProtocolFieldType.tiny: _ColumnType.tinyint,\n    _ProtocolFieldType.short_: _ColumnType.smallint,\n    _ProtocolFieldType.int24: _ColumnType.mediumint,\n    _ProtocolFieldType.long_: _ColumnType.int_,\n    _ProtocolFieldType.longlong: _ColumnType.bigint,\n    _ProtocolFieldType.float_: _ColumnType.float_,\n    _ProtocolFieldType.double_: _ColumnType.double_,\n    _ProtocolFieldType.bit: _ColumnType.bit,\n    _ProtocolFieldType.date: _ColumnType.date,\n    _ProtocolFieldType.datetime: _ColumnType.datetime,\n    _ProtocolFieldType.timestamp: _ColumnType.timestamp,\n    _ProtocolFieldType.time: _ColumnType.time,\n    _ProtocolFieldType.year: _ColumnType.year,\n    _ProtocolFieldType.json: _ColumnType.json,\n}\n\n\ndef _compute_column_type(mysql_frame) -> _ColumnType:\n    type = _ProtocolFieldType(int(mysql_frame['mysql.field.type_raw'][0], 16))\n    isbin = mysql_frame['mysql.field.charsetnr_raw'][0] == '3f00'\n    if type == _ProtocolFieldType.string:\n        if mysql_frame['mysql.field.flags_tree']['mysql.field.flags.set_raw'][0] != '0':\n            return _ColumnType.set\n        elif mysql_frame['mysql.field.flags_tree']['mysql.field.flags.enum_raw'][0] != '0':\n            return _ColumnType.enum_\n        elif isbin:\n            return _ColumnType.binary\n        else:\n            return _ColumnType.char_\n    elif type == _ProtocolFieldType.var_string:\n        if isbin:\n            return _ColumnType.varbinary\n        else:\n            return _ColumnType.varchar\n    elif type == _ProtocolFieldType.blob:\n        if isbin:\n            return _ColumnType.blob\n        else:\n            return _ColumnType.text\n    else:\n        return _TYPE_MAP[type]\n\n\nclass _Sample(NamedTuple):\n    fuzzer: str\n    name: str\n    content: bytes\n\n\ndef _encoding_to_str(enc: _Encoding) -> str:\n    return 'text' if enc == _Encoding.text else 'binary'\n\n\n# meta: spans 2 bytes\n# meta[0][low 7 bits]: column_type\n# meta[0][high bit]: is unsigned flag\n# meta[1]: decimals\ndef _gen_meta(mysql_frame) -> bytes:\n    type = _compute_column_type(mysql_frame)\n    unsigned_flag = int(mysql_frame['mysql.field.flags_tree']['mysql.field.flags.unsigned_raw'][0])\n    assert unsigned_flag == 0 or unsigned_flag == 1\n    decimals = int(mysql_frame['mysql.field.decimals_raw'][0], 16)\n    return struct.pack(\n        '<BB',\n        type.value | (unsigned_flag << 7),\n        decimals\n    )\n\n# Parses a text row into its fields. Relies on int_lenencs not being more than 1 byte\ndef _parse_text_row(r: bytes, num_fields: int) -> List[bytes]:\n    res: List[bytes] = []\n    offset = 0\n    for _ in range(num_fields):\n        (length,) = struct.unpack('<B', r[offset:offset+1])\n        if length >= 0xfb: # Too long or NULL samples\n            continue\n        res.append(r[offset+1:offset+1+length])\n        offset += length + 1\n    return res\n\n\ndef _gen_text_field_samples(response, table: str) -> List[_Sample]:\n    mysql_raw = response['_source']['layers']['mysql_raw']\n    mysql = response['_source']['layers']['mysql']\n\n    num_fields = int(mysql[0]['mysql.num_fields_raw'][0], 16)\n    metas = [_gen_meta(mysql[i + 1]) for i in range(num_fields)]\n\n    res: List[_Sample] = []\n    for i, rec in enumerate(mysql_raw[1 + num_fields:-1]):\n        row = bytes.fromhex(rec[0][2*4:])\n        fields = _parse_text_row(row, num_fields)\n        res += [_Sample(\n            fuzzer='fuzz_text_field',\n            name=f'{table}_{i}_{j}',\n            content=meta + field\n        ) for j, (meta, field) in enumerate(zip(metas, fields))]\n\n    return res\n\n\ndef _gen_row_samples(response, enc: _Encoding, table: str) -> List[_Sample]:\n    mysql_raw = response['_source']['layers']['mysql_raw']\n    mysql = response['_source']['layers']['mysql']\n\n    # Header[0][low 7 bits]: num_fields\n    # Header[0][high bit]: encoding\n    num_fields = int(mysql[0]['mysql.num_fields_raw'][0], 16)\n    header = struct.pack('<B', num_fields | (enc.value << 7))\n\n    # As many meta blocks as num_fields\n    meta = b''.join(_gen_meta(mysql[i + 1]) for i in range(num_fields))\n\n    # Rows\n    return [\n        _Sample(\n            fuzzer='fuzz_row',\n            name=f'{_encoding_to_str(enc)}_{table}_{i}',\n            content=b''.join((header, meta, bytes.fromhex(rec[0][2*4:])))\n        )\n        for i, rec in enumerate(mysql_raw[1 + num_fields:-1])\n    ]\n\n\n# Frames should be captured with wireshark (see below for each protocol encoding)\n# and saved as pcapng files. They should be converted to jsonraw using\n# tshark -r fname.pcapng -T jsonraw --no-duplicate-keys -Y 'mysql' > fname.json\ndef main():\n    corpus: List[_Sample] = []\n\n    # Text. These should contain frames generated by running SELECT * FROM <table>\n    # repeatedly over the set of tables, from mysql command line.\n    # This generates two frames (request and response) for each select\n    with open(_TEXT_JSON, 'rt') as f:\n        obj = json.load(f)\n    for query, response in zip(*(iter(obj),) * 2):\n        table = bytes.fromhex(query['_source']['layers']['mysql']['mysql.payload_raw'][0])[1:].decode().split(' ')[-1]\n        corpus += _gen_row_samples(response, _Encoding.text, table)\n        corpus += _gen_text_field_samples(response, table)\n\n    # Binary. These should contain frames generated by running SELECT * FROM <table>\n    # repeatedly over the set of tables, from the Python mysql protocol driver,\n    # with code like:\n    #    cursor = cnx.cursor(prepared=True)\n    #    cursor.execute(f'SELECT * FROM {table}')\n    #    cursor.fetchall()\n    # This generates 7 frames for each table, since the driver prepares, executes and resets the statement.\n    with open(_BINARY_JSON, 'rt') as f:\n        obj = json.load(f)\n    for reqclose, query, qres, reset, resetres, exec, response in zip(*(iter(obj),) * 7):\n        table = bytes.fromhex(query['_source']['layers']['mysql']['mysql.request_raw'][0])[1:].decode().split(' ')[-1]\n        corpus += _gen_row_samples(response, _Encoding.binary, table)\n    \n    # Write all frames to a CSV file\n    csv_path = _REPO_BASE.joinpath('tools', 'seed_corpus', 'field_table.csv') \n    with open(csv_path, 'wt') as f:\n        writer = csv.DictWriter(f, fieldnames=_Sample._fields)\n        writer.writeheader()\n        writer.writerows({\n            \"fuzzer\": sample.fuzzer,\n            \"name\": sample.name,\n            \"content\": sample.content.hex()\n        } for sample in corpus)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tools/scripts/examples_qbk.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nfrom typing import NamedTuple, List\nfrom os import path, listdir\n\nREPO_BASE = path.abspath(path.join(path.dirname(path.realpath(__file__)), '..', '..'))\n\nclass Example(NamedTuple):\n    id: str\n    path: str\n    title: str\n\n\nclass MultiExample(NamedTuple):\n    id: str\n    paths: List[str]\n    title: str\n\n\nLINK_TEMPLATE = '* [link mysql.examples.{example.id} {example.title}]'\nSECTION_TEMPLATE = '''\n[section:{example.id} {example.title}]\n\nThis example assumes you have gone through the [link mysql.examples.setup setup].\n\n{example_cpps}\n\n[endsect]\n'''\n\nTEMPLATE='''[/\n    Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n   \n    Distributed under the Boost Software License, Version 1.0. (See accompanying\n    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n]\n\n[/ This file was auto-generated by examples_qbk.py. Do not edit directly ]\n\n[section:examples Examples]\n\nTo run the examples, please go through the [link mysql.examples.setup setup] first.\n\nHere is a list of available examples:\n\n[heading Tutorials]\n\nSelf-contained programs demonstrating the basic concepts.\n\n{tutorial_links}\n\n[heading Simple programs]\n\nSelf-contained programs demonstrating more advanced concepts and techniques.\n\n{simple_links}\n\n[heading Advanced examples]\n\nPrograms implementing real-world functionality.\n\n{advanced_links}\n# [@https://github.com/anarthal/servertech-chat The BoostServerTech chat project uses Boost.MySQL and Boost.Redis to implement a chat server]\n\n[heading Setup]\n\nTo run the examples, you need a MySQL server you can connect to.\nExamples make use of a database named `boost_mysql_examples`.\nThe server hostname and credentials (username and password) are passed \nto the examples via the command line.\n\nYou can spin up a server quickly by using Docker:\n\n[!teletype]\n```\n    # Remove the \"-v /var/run/mysqld:/var/run/mysqld\" part if you don't need UNIX sockets\n    > docker run --name some-mysql -p 3306:3306 -v /var/run/mysqld:/var/run/mysqld -d -e MYSQL_ROOT_PASSWORD= -e MYSQL_ALLOW_EMPTY_PASSWORD=1 -d mysql\n\n    # All the required data can be loaded by running example/db_setup.sql.\n    # If you're using the above container, the root user has a blank password\n    > mysql -u root < example/db_setup.sql\n```\n\nPlease note that this container is just for demonstrative purposes,\nand is not suitable for production.\n\nThe root MySQL user for these containers is `root` and has an empty password.\n\n{all_examples}\n\n[endsect]\n\n'''\n\n# List all examples here\nTUTORIALS = [\n    Example('tutorial_sync',                 '1_tutorial/1_sync.cpp',                 'Tutorial 1 listing: hello world!'),\n    Example('tutorial_async',                '1_tutorial/2_async.cpp',                'Tutorial 2 listing: going async with C++20 coroutines'),\n    Example('tutorial_with_params',          '1_tutorial/3_with_params.cpp',          'Tutorial 3 listing: queries with parameters'),\n    Example('tutorial_static_interface',     '1_tutorial/4_static_interface.cpp',     'Tutorial 4 listing: the static interface'),\n    Example('tutorial_updates_transactions', '1_tutorial/5_updates_transactions.cpp', 'Tutorial 5 listing: UPDATEs, transactions and multi-queries'),\n    Example('tutorial_connection_pool',      '1_tutorial/6_connection_pool.cpp',      'Tutorial 6 listing: connection pools'),\n    Example('tutorial_error_handling',       '1_tutorial/7_error_handling.cpp',       'Tutorial 7 listing: error handling'),\n]\n\nSIMPLE_EXAMPLES = [\n    Example('inserts', '2_simple/inserts.cpp', 'INSERTs, last_insert_id() and NULL values'),\n    Example('deletes', '2_simple/deletes.cpp', 'DELETEs and affected_rows()'),\n    Example('prepared_statements', '2_simple/prepared_statements.cpp', 'Prepared statements'),\n    Example('disable_tls', '2_simple/disable_tls.cpp', 'Disabling TLS for a connection'),\n    Example('tls_certificate_verification', '2_simple/tls_certificate_verification.cpp', 'Setting TLS options: enabling TLS certificate verification'),\n    Example('metadata', '2_simple/metadata.cpp', 'Metadata'),\n    Example('multi_function', '2_simple/multi_function.cpp', 'Reading rows in batches with multi-function operations'),\n    Example('callbacks', '2_simple/callbacks.cpp', 'Callbacks (async functions in C++11)'),\n    Example('coroutines_cpp11', '2_simple/coroutines_cpp11.cpp', 'Stackful coroutines (async functions in C++11)'),\n    Example('unix_socket', '2_simple/unix_socket.cpp', 'UNIX sockets'),\n    Example('batch_inserts', '2_simple/batch_inserts.cpp', 'Batch inserts using client-side query formatting'),\n    Example('batch_inserts_generic', '2_simple/batch_inserts_generic.cpp', 'Generic batch inserts with Boost.Describe'),\n    Example('dynamic_filters', '2_simple/dynamic_filters.cpp', 'Queries with dynamic filters'),\n    Example('patch_updates', '2_simple/patch_updates.cpp', 'Dynamic UPDATE queries with PATCH-like semantics'),\n    Example('source_script', '2_simple/source_script.cpp', 'Sourcing a .sql file using multi-queries'),\n    Example('pipeline', '2_simple/pipeline.cpp', '(Experimental) Pipelines'),\n]\n\nADVANCED_EXAMPLES = [\n    MultiExample('http_server_cpp20', [\n        '3_advanced/http_server_cpp20/main.cpp',\n        '3_advanced/http_server_cpp20/types.hpp',\n        '3_advanced/http_server_cpp20/error.hpp',\n        '3_advanced/http_server_cpp20/error.cpp',\n        '3_advanced/http_server_cpp20/repository.hpp',\n        '3_advanced/http_server_cpp20/repository.cpp',\n        '3_advanced/http_server_cpp20/handle_request.hpp',\n        '3_advanced/http_server_cpp20/handle_request.cpp',\n        '3_advanced/http_server_cpp20/server.hpp',\n        '3_advanced/http_server_cpp20/server.cpp',\n    ], 'A REST API server that uses C++20 coroutines'),\n\n    MultiExample('http_server_cpp14_coroutines', [\n        '3_advanced/http_server_cpp14_coroutines/main.cpp',\n        '3_advanced/http_server_cpp14_coroutines/types.hpp',\n        '3_advanced/http_server_cpp14_coroutines/repository.hpp',\n        '3_advanced/http_server_cpp14_coroutines/repository.cpp',\n        '3_advanced/http_server_cpp14_coroutines/handle_request.hpp',\n        '3_advanced/http_server_cpp14_coroutines/handle_request.cpp',\n        '3_advanced/http_server_cpp14_coroutines/server.hpp',\n        '3_advanced/http_server_cpp14_coroutines/server.cpp',\n    ], 'A C++14 REST API server that uses asio::yield_context'),\n]\n\nALL_EXAMPLES = TUTORIALS + SIMPLE_EXAMPLES + ADVANCED_EXAMPLES\n\ndef _render_links(examples: List[Example]) -> str:\n    return '\\n'.join(LINK_TEMPLATE.format(example=elm) for elm in examples)\n\ndef _write_file(relpath: List[str], contents: str) -> None:\n    output_file = path.join(REPO_BASE, *relpath)\n    with open(output_file, 'wt') as f:\n        f.write(contents)\n\ndef _render_simple_cpp(id: str) -> str:\n    return f'[example_{id}]'\n\ndef _render_multi_cpp(id: str, paths: List[str]) -> str:\n    def get_file_id(p: str):\n        # File IDs follow the below convention\n        converted_id = path.basename(p).replace('.', '_')\n        return f'{id}_{converted_id}'\n\n    return '\\n\\n'.join(_render_simple_cpp(get_file_id(p)) for p in paths)\n\ndef _collect_snippets() -> List[str]:\n    snippets_relpath = ['test', 'integration', 'test', 'snippets']\n    return [\n        path.join(*snippets_relpath, p)\n        for p in  listdir(path.join(REPO_BASE, *snippets_relpath))\n    ]\n\ndef _replace_imports(import_contents: str) -> None:\n    # Read the file\n    with open(path.join(REPO_BASE, 'doc', 'qbk', '00_main.qbk'), 'rt') as f:\n        contents = f.read()\n    \n    # Replace\n    begin_marker = '[/ AUTOGENERATED IMPORTS BEGIN ]\\n'\n    end_marker = '\\n[/ AUTOGENERATED IMPORTS END ]'\n    begin_pos = contents.find(begin_marker)\n    end_pos = contents.find(end_marker)\n    assert begin_pos != -1\n    assert end_pos != -1\n    final_contents = contents[:begin_pos + len(begin_marker)] + import_contents + contents[end_pos:]\n\n    # Write the file\n    _write_file(['doc', 'qbk', '00_main.qbk'], final_contents)\n\n\ndef main():\n    # Collect all files to be imported\n    example_paths = [e.path for e in ALL_EXAMPLES if isinstance(e, Example)]\n    for p in [e.paths for e in ALL_EXAMPLES if isinstance(e, MultiExample)]:\n        example_paths += p\n    all_paths = [f'example/{p}' for p in example_paths]\n    all_paths += _collect_snippets()\n    \n\n    # Render\n    import_contents = '\\n'.join(f'[import ../../{p}]' for p in all_paths)\n    example_contents = TEMPLATE.format(\n        tutorial_links=_render_links(TUTORIALS),\n        simple_links=_render_links(SIMPLE_EXAMPLES),\n        advanced_links='',\n        all_examples='\\n\\n\\n'.join(SECTION_TEMPLATE.format(\n            example=elm,\n            example_cpps=_render_multi_cpp(elm.id, elm.paths) if isinstance(elm, MultiExample) else _render_simple_cpp(elm.id)\n        ) for elm in ALL_EXAMPLES)\n    )\n\n    # Write to output file\n    _replace_imports(import_contents)\n    _write_file(['doc', 'qbk', '21_examples.qbk'], example_contents)\n    \n\nif __name__ == '__main__':\n    main()"
  },
  {
    "path": "tools/scripts/file_headers.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nimport os\nfrom pathlib import Path\nfrom os import path\nfrom typing import List, Tuple\nimport glob\nfrom abc import abstractmethod, ABCMeta\nimport sys\n\nTHIS_FOLDER = path.abspath(path.dirname(path.realpath(__file__)))\nsys.path.append(path.join(THIS_FOLDER))\n\nimport examples_qbk\n\n# Script to get file headers (copyright notices\n# and include guards) okay and up to date\n\nVERBOSE = False\n\nREPO_BASE = path.abspath(path.join(path.dirname(path.realpath(__file__)), '..', '..'))\nBASE_FOLDERS = [\n    'cmake',\n    'doc',\n    'example',\n    'include',\n    'src',\n    'test',\n    'tools',\n    'bench',\n    '.github'\n]\nBASE_FILES = [\n    'CMakeLists.txt',\n    '.drone.star',\n    '.codecov.yml'\n]\nHTML_GEN_PATH = path.join(REPO_BASE, 'doc', 'html')\n\nHEADER_TEMPLATE = '''{begin}\n{linesym} Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n{linesym}\n{linesym} Distributed under the Boost Software License, Version 1.0. (See accompanying\n{linesym} file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n{end}'''\n\nSRC_HPP_TEMPLATE = '''\n// This file is meant to be included once, in a translation unit of\n// the program, with the macro BOOST_MYSQL_SEPARATE_COMPILATION defined.\n\n#include <boost/mysql/detail/config.hpp>\n\n#ifndef BOOST_MYSQL_SEPARATE_COMPILATION\n#error You need to define BOOST_MYSQL_SEPARATE_COMPILATION in all translation units that use the compiled version of Boost.MySQL, \\\\\n    as well as the one where this file is included.\n#endif\n\n{includes}\n\n#endif'''\n\nMYSQL_ERROR_HEADER = path.join(REPO_BASE, 'private', 'mysqld_error.h')\nMARIADB_ERROR_HEADER = path.join(REPO_BASE, 'private', 'mariadb_error.h')\n\ndef find_first_blank(lines: List[str]) -> int:\n    return next((i for i, line in enumerate(lines) if line.replace('\\n', '') == ''), len(lines))\n\ndef read_file(fpath):\n    with open(fpath, 'rt') as f:\n        try:\n            return f.readlines()\n        except Exception as err:\n            raise SystemError(f'Error processing file {fpath}') from err\n    \ndef write_file(fpath, lines):\n    with open(fpath, 'wt') as f:\n        f.writelines(lines)\n\ndef text_to_lines(text):\n    return [line + '\\n' for line in text.split('\\n')]\n\ndef gen_header(linesym, opensym=None, closesym=None, shebang=None, include_guard=None):\n    opensym = linesym if opensym is None else opensym\n    closesym = linesym if closesym is None else closesym\n    if shebang is None:\n        begin = opensym\n    else:\n        begin = shebang + '\\n' + opensym\n    if include_guard is None:\n        end = closesym\n    else:\n        end = closesym + '\\n\\n#ifndef {0}\\n#define {0}'.format(include_guard)\n    return text_to_lines(HEADER_TEMPLATE.format(begin=begin, end=end, linesym=linesym))\n\nclass BaseProcessor(metaclass=ABCMeta):\n    skip = False\n\n    @abstractmethod\n    def process(self, lines: List[str], fpath: str) -> List[str]:\n        return lines\n    \n    name = ''\n\nclass NormalProcessor(BaseProcessor):\n    def __init__(self, name, header):\n        self.header = header\n        self.name = name\n        \n    def process(self, lines: List[str], _: str) -> List[str]:\n        first_blank = find_first_blank(lines)\n        lines = self.header + lines[first_blank:]\n        return lines\n        \nclass HppProcessor(BaseProcessor):\n    name = 'hpp'\n    \n    def process(self, lines: List[str], fpath: str) -> List[str]:\n        first_content = [i for i, line in enumerate(lines) if line.startswith('#define')][0] + 1\n        iguard = self._gen_include_guard(fpath)\n        header = gen_header('//', include_guard=iguard)\n        lines = header + lines[first_content:]\n        return lines\n        \n        \n    @staticmethod\n    def _gen_include_guard(fpath):\n        include_base = path.join(REPO_BASE, 'include')\n        if fpath.startswith(include_base):\n            relpath = path.relpath(fpath, include_base)\n        else:\n            relpath = path.join('boost', 'mysql', path.relpath(fpath, REPO_BASE))\n        return relpath.replace('/', '_').replace('.', '_').upper()\n\n\nclass SrcHppProcessor(HppProcessor):\n    name = 'src.hpp'\n\n    def process(self, _: List[str], fpath: str) -> List[str]:\n        base = Path(REPO_BASE)\n        includes = [\n            fname.relative_to(base.joinpath('include'))\n            for fname in sorted(base.joinpath('include', 'boost', 'mysql', 'impl').rglob('*.ipp'))\n        ]\n        return gen_header('//', include_guard=self._gen_include_guard(fpath)) + \\\n            text_to_lines(\n                SRC_HPP_TEMPLATE.format(\n                    includes='\\n'.join(f'#include <{inc}>' for inc in includes)\n                )\n            )\n\n\nclass MysqlHppProcessor(HppProcessor):\n    name = 'mysql.hpp'\n\n    def process(self, _: List[str], fpath: str) -> List[str]:\n        base = Path(REPO_BASE)\n        exclusions = ('src.hpp', 'pfr.hpp')\n        includes = [\n            fname.relative_to(base.joinpath('include'))\n            for fname in sorted(base.joinpath('include', 'boost', 'mysql').glob('*.hpp'))\n            if fname.name not in exclusions\n        ]\n        return gen_header('//', include_guard=self._gen_include_guard(fpath)) + \\\n            ['\\n'] + \\\n            [f'#include <{inc}>\\n' for inc in includes] + \\\n            ['\\n', '#endif\\n']\n\n\nclass XmlProcessor(BaseProcessor):\n    name = 'xml'\n    header = gen_header('   ', '<!--', '-->')\n    \n    def process(self, lines: List[str], fpath: str) -> List[str]:\n        if lines[0].startswith('<?'):\n            first_blank = [i for i, line in enumerate(lines) if line.strip() == ''][0]\n            first_content = [i for i, line in enumerate(lines[first_blank:]) \\\n                             if line.startswith('<') and not line.startswith('<!--')][0] + first_blank\n            lines = lines[0:first_blank] + ['\\n'] + self.header + ['\\n'] + lines[first_content:]\n        else:\n            lines = NormalProcessor('xml', self.header).process(lines, fpath)\n        \n        return lines\n        \n        \nclass IgnoreProcessor(BaseProcessor):\n    name = 'ignore'\n    skip = True\n    \n    def process(self, lines: List[str], _: str) -> List[str]:\n        return lines\n        \nhash_processor = NormalProcessor('hash', gen_header('#'))\nqbk_processor = NormalProcessor('qbk', gen_header('   ', opensym='[/', closesym=']'))\nsql_processor = NormalProcessor('sql', gen_header('--'))\ncpp_processor = NormalProcessor('cpp', gen_header('//'))\npy_processor = NormalProcessor('py', gen_header('#', shebang='#!/usr/bin/python3'))\nbash_processor = NormalProcessor('bash', gen_header('#', shebang='#!/bin/bash'))\nbat_processor = NormalProcessor('bat', gen_header('@REM'))\n\nFILE_PROCESSORS : List[Tuple[str, BaseProcessor]] = [\n    ('src.hpp', SrcHppProcessor()),\n    ('mysql.hpp', MysqlHppProcessor()),\n    ('CMakeLists.txt', hash_processor),\n    ('.cmake', hash_processor),\n    ('.cmake.in', hash_processor),\n    ('Jamfile', hash_processor),\n    ('.jam', hash_processor),\n    ('Doxyfile', hash_processor),\n    ('.qbk', qbk_processor),\n    ('.sql', sql_processor),\n    ('.py', py_processor),\n    ('.sh', bash_processor),\n    ('.bat', bat_processor),\n    ('.ps1', hash_processor),\n    ('.yml', hash_processor),\n    ('.cnf', hash_processor),\n    ('.dockerfile', hash_processor),\n    ('.star', hash_processor),\n    ('.cpp', cpp_processor),\n    ('.hpp', HppProcessor()),\n    ('.ipp', HppProcessor()),\n    ('.xml', XmlProcessor()),\n    ('.xsl', XmlProcessor()),\n    ('.svg', IgnoreProcessor()),\n    ('valgrind_suppressions.txt', IgnoreProcessor()),\n    ('.pem', IgnoreProcessor()),\n    ('.md', IgnoreProcessor()),\n    ('.csv', IgnoreProcessor()),\n    ('.tar.gz', IgnoreProcessor()),\n    ('.json', IgnoreProcessor()),\n    ('.txt', IgnoreProcessor()),\n    ('.pyc', IgnoreProcessor()),\n    ('.ipynb', IgnoreProcessor()),\n    ('.png', IgnoreProcessor()),\n]\n\ndef process_file(fpath: str):\n    try:\n        for ext, processor in FILE_PROCESSORS:\n            if fpath.endswith(ext):\n                if VERBOSE:\n                    print('Processing file {} with processor {}'.format(fpath, processor.name))\n                if not processor.skip:\n                    lines = read_file(fpath)\n                    output_lines = processor.process(lines, fpath)\n                    if output_lines != lines:\n                        write_file(fpath, output_lines)\n                break\n        else:\n            raise ValueError('Could not find a suitable processor for file: ' + fpath)\n    except Exception:\n        print(f'Found error processing {fpath}')\n        raise\n    \ndef process_all_files():\n    for base_folder in BASE_FOLDERS:\n        base_folder_abs = path.join(REPO_BASE, base_folder)\n        for curdir, _, files in os.walk(base_folder_abs):\n            if curdir.startswith(HTML_GEN_PATH):\n                if VERBOSE:\n                    print('Ignored directory {}'.format(curdir))\n                continue\n            for fname in files:\n                process_file(path.join(curdir, fname))\n    for fname in BASE_FILES:\n        process_file(path.join(REPO_BASE, fname))\n\n\n# Check that cmake and b2 test source files are equal\ndef verify_test_consistency():\n    for test_type in ('unit', 'integration'):\n        for ftocheck in ('Jamfile', 'CMakeLists.txt'):\n            base_path = path.join(REPO_BASE, 'test', test_type)\n            tests = glob.glob(base_path + '/test/**/*.cpp', recursive=True)\n            tests = [elm.replace(base_path + '/', '') for elm in tests]\n\n            with open(path.join(REPO_BASE, 'test', test_type, ftocheck), 'rt') as f:\n                contents = f.readlines()\n                contents = ''.join(elm for elm in contents if not '#' in elm)\n\n            for t in tests:\n                if ' ' + t not in contents:\n                    print(f'File {t} not in {test_type}/{ftocheck}')\n\n            \ndef main():\n    process_all_files()\n    verify_test_consistency()\n    examples_qbk.main()\n            \n            \nif __name__ == '__main__':\n    main()\n        \n"
  },
  {
    "path": "tools/scripts/server_errors.py",
    "content": "#!/usr/bin/python3\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# This scripts generates files containing the server defined error codes,\n# and code to convert from error codes to strings. This is complex because:\n#  - There are *a lot* of error codes.\n#  - There are common error codes and MariaDB/MySQL specific ones.\n#  - Some codes have been repurposed, renamed or removed from MySQL 5.x to MySQL 8.x and MariaDB.\n# To generate precise output, we need the mysqld_error.h header for MySQL 5.x, 8.x and MariaDB.\n# MySQL and MariaDB often rename, deprecate, etc. codes. To attempt to maintain sanity,\n# we generate a CSV file with what we did for the previous version. We load it and combine it\n# with the new errors, and we only perform backwards-compatible changes.\n#\n# To update the codes for a new release:\n#   - MySQL: https://dev.mysql.com/downloads/mysql/\n#   - MariaDB: https://mariadb.org/connector-c/all-releases/\n\nimport pandas as pd\nfrom os import path\nfrom pathlib import Path\nfrom typing import Literal, List, Optional, cast, NamedTuple\nfrom subprocess import run\n\n\n# DataFrames have 'symbol', 'numbr' columns\nclass ErrorCodes(NamedTuple):\n    common: pd.DataFrame\n    mysql: pd.DataFrame\n    mariadb: pd.DataFrame\n\n\nREPO_BASE = Path(path.abspath(path.join(path.dirname(path.realpath(__file__)), '..', '..')))\n_CSV_PATH = REPO_BASE.joinpath('tools', 'error_codes.csv')\n\n# All server errors range between 1000 and 4999. Errors between 2000 and 2999\n# are reserved for the client and are not used. In theory, codes between COMMON_ERROR_FIRST\n# and COMMON_ERROR_LAST are shared between MySQL and MariaDB. However, some exceptions apply -\n# some codes were not used originally by MySQL and are now used only by MariaDB, some have been renamed,\n# etc. All codes >= COMMON_ERROR_LAST are server-specific. Codes between [COMMON_ERROR_FIRST, COMMON_ERROR_LAST)\n# may be euther common or server-specific.\nCOMMON_ERROR_FIRST = 1000\nCOMMON_ERROR_LAST = 1880\nSERVER_ERROR_LAST = 5000\n\nCOMMON_SERVER_ERRC_ENTRY = '''\n    /**\n     * \\\\brief Common server error. Error number: {number}, symbol:\n     * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_{symbol_lower}\">{symbol_upper}</a>.\n     */\n    {symbol_lower} = {number},\n'''\n\nCOMMON_SERVER_ERRC_TEMPLATE = '''\n#ifndef BOOST_MYSQL_COMMON_SERVER_ERRC_HPP\n#define BOOST_MYSQL_COMMON_SERVER_ERRC_HPP\n\n#include <boost/mysql/error_code.hpp>\n\n#include <boost/mysql/detail/config.hpp>\n\n#include <boost/system/error_category.hpp>\n\nnamespace boost {{\nnamespace mysql {{\n\n/**\n * \\\\brief Server-defined error codes, shared between MySQL and MariaDB.\n * \\\\details The numeric value and semantics match the ones described in the MySQL documentation.\n * For more info, consult the error reference for\n * <a href=\"https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html\">MySQL 8.0</a>, \n * <a href=\"https://dev.mysql.com/doc/mysql-errors/5.7/en/server-error-reference.html\">MySQL 5.7</a>,\n * <a href=\"https://mariadb.com/kb/en/mariadb-error-codes/\">MariaDB</a>.\n */\nenum class common_server_errc : int\n{{\n{}\n}};\n\nBOOST_MYSQL_DECL\nconst boost::system::error_category& get_common_server_category() noexcept;\n\n/// Creates an \\\\ref error_code from a \\\\ref common_server_errc.\ninline error_code make_error_code(common_server_errc error)\n{{\n    return error_code(static_cast<int>(error), get_common_server_category());\n}}\n\n}}  // namespace mysql\n\n#ifndef BOOST_MYSQL_DOXYGEN\nnamespace system {{\n\ntemplate <>\nstruct is_error_code_enum<::boost::mysql::common_server_errc>\n{{\n    static constexpr bool value = true;\n}};\n\n}}  // namespace system\n#endif\n\n}}  // namespace boost\n\n#ifdef BOOST_MYSQL_HEADER_ONLY\n#include <boost/mysql/impl/error_categories.ipp>\n#endif\n\n#endif\n'''\n\n# Render the enumeration with common codes\ndef render_common_server_errc(df_common: pd.DataFrame) -> str:\n    entries = ''.join(COMMON_SERVER_ERRC_ENTRY.format(\n        number=r.numbr,\n        symbol_upper=r.symbol,\n        symbol_lower=r.symbol.lower()\n    ) for r in df_common.itertuples())\n    return COMMON_SERVER_ERRC_TEMPLATE.format(entries)\n\n\nSPECIFIC_SERVER_ERRC_ENTRY = '''\n/// Server error specific to {flavor}. Error number: {number}, symbol: {symbol_upper}.\nBOOST_INLINE_CONSTEXPR int {symbol_lower} = {number};\n'''\n\nSPECIFIC_SERVER_ERRC_TEMPLATE = '''\n#ifndef BOOST_MYSQL_{flavor}_SERVER_ERRC_HPP\n#define BOOST_MYSQL_{flavor}_SERVER_ERRC_HPP\n\n#include <boost/config.hpp>\n\nnamespace boost {{\nnamespace mysql {{\n\nnamespace {flavor}_server_errc {{\n{entries}\n}}  // namespace {flavor}_server_errc\n\n}}  // namespace mysql\n}}  // namespace boost\n\n#endif\n'''\n\n# Render error codes specific to a server\ndef render_server_specific_errc(flavor: Literal['mysql', 'mariadb'], df_db: pd.DataFrame):\n    entries = ''.join(SPECIFIC_SERVER_ERRC_ENTRY.format(\n        number=r.numbr,\n        symbol_upper=r.symbol,\n        symbol_lower=r.symbol.lower(),\n        flavor=flavor\n    ) for r in df_db.itertuples())\n    return SPECIFIC_SERVER_ERRC_TEMPLATE.format(entries=entries, flavor=flavor)\n\nSERVER_ERROR_TO_STRING_TEMPLATE_ENTRY='    case {number}: return \"{symbol_lower}\";\\n'\n\nSERVER_ERROR_TO_STRING_TEMPLATE='''\n#ifndef BOOST_MYSQL_IMPL_INTERNAL_ERROR_SERVER_ERROR_TO_STRING_HPP\n#define BOOST_MYSQL_IMPL_INTERNAL_ERROR_SERVER_ERROR_TO_STRING_HPP\n\n// This file was generated by server_errors.py - do not edit directly.\n\n#include <boost/config.hpp>\n#include <boost/mysql/impl/internal/error/server_error_to_string.hpp>\n\nnamespace boost {{\nnamespace mysql {{\nnamespace detail {{\n\nBOOST_INLINE_CONSTEXPR const char* common_error_messages[] = {{\n{common_entries}\n}};\n\n}} // namespace detail\n}} // namespace mysql\n}} // namespace boost\n\nconst char* boost::mysql::detail::common_error_to_string(int v)\n{{\n    constexpr int first = {common_error_first};\n    constexpr int last = first + sizeof(common_error_messages) / sizeof(const char*);\n    return (v >= first && v < last) ? common_error_messages[v - first] : nullptr;\n}}\n\nconst char* boost::mysql::detail::mysql_error_to_string(int v)\n{{\n    switch (v)\n    {{\n{mysql_entries}\n    default: return \"<unknown MySQL-specific server error>\";\n    }}\n}}\n\nconst char* boost::mysql::detail::mariadb_error_to_string(int v)\n{{\n    switch (v)\n    {{\n{mariadb_entries}\n    default: return \"<unknown MariaDB-specific server error>\";\n    }}\n}}\n\n#endif\n\n'''\n\n# Renders the cpp that implements server error codes to strings\ndef render_server_error_to_string(df_common: pd.DataFrame, df_mysql: pd.DataFrame, df_mariadb: pd.DataFrame) -> str:\n    # Common entries. We need to include non-present entries here, too (as nullptr's)\n    number_to_symbol = df_common.set_index('numbr')['symbol']\n    symbols = [cast(Optional[str], number_to_symbol.get(i)) for i in range(COMMON_ERROR_FIRST, COMMON_ERROR_LAST)]\n    common_entries_list = [f'\"{elm.lower()}\"' if elm is not None else 'nullptr' for elm in symbols]\n    common_entries = ''.join(f'    {elm},\\n' for elm in common_entries_list)\n\n    # DB specific entries\n    def _gen_specific_entries(df_db: pd.DataFrame) -> str:\n        return ''.join(SERVER_ERROR_TO_STRING_TEMPLATE_ENTRY.format(\n            number=r.numbr,\n            symbol_lower=r.symbol.lower()\n        ) for r in df_db.itertuples())\n    mysql_entries = _gen_specific_entries(df_mysql)\n    mariadb_entries = _gen_specific_entries(df_mariadb)\n     \n    return SERVER_ERROR_TO_STRING_TEMPLATE.format(\n        common_error_first=COMMON_ERROR_FIRST,\n        common_entries=common_entries,\n        mysql_entries=mysql_entries,\n        mariadb_entries=mariadb_entries\n    )\n\n\n# Parse a header into a dataframe of (number, symbol) pairs\ndef parse_err_header(fname: Path) -> pd.DataFrame:\n    with open(fname, 'rt') as f:\n        lines = f.read().split('\\n')\n    v = [elm for elm in lines if elm.startswith('#define')]\n    v = [elm.split(' ')[1:] for elm in v]\n    df = pd.DataFrame(v, columns=['symbol', 'numbr'])\n    df = df[~df['numbr'].isna()]\n    df['numbr'] = df['numbr'].astype(int)\n    df = df[df['numbr'] < SERVER_ERROR_LAST]\n    # Discard pseudo error codes that some header have\n    df = df[df['symbol'].map(lambda x: not (\n        x.startswith('ER_ERROR_FIRST') or\n        x.startswith('ER_ERROR_LAST') or\n        x == 'ER_LAST_MYSQL_ERROR_MESSAGE' or\n        x.startswith('ER_UNUSED') or\n        x.endswith('__UNUSED')\n    ))]\n    return df\n\n\n# MySQL 5.x and 8.x don't fully agree on error names. Some names have been\n# removed, others have been added and others have been renamed. We merge\n# both so the library can be used with both systems. In case of conflict, pick the 8.x name\n# (they generally add a _UNUSED suffix for the codes they no longer use).\n# Some symbols appear both in 5.x and 8.x but with different values - we pick the 8.x in\n# case of conflict. \ndef merge_mysql_errors(df_mysql5: pd.DataFrame, df_mysql8: pd.DataFrame) -> pd.DataFrame:\n    def resolve_symbol(r):\n        s5 = r['symbol_5']\n        s8 = r['symbol_8']\n        if not pd.isna(s5) and pd.isna(s8):\n            symbol, dbver = s5, 5\n        else:\n            symbol, dbver = s8, 8\n        return pd.Series(dict(numbr=r['numbr'], symbol=symbol, dbver=dbver))\n    \n    return df_mysql5 \\\n        .join(df_mysql8.set_index('numbr'), how='outer', on='numbr', lsuffix='_5', rsuffix='_8') \\\n        .apply(resolve_symbol, axis=1) \\\n        .sort_values(by='dbver') \\\n        .drop_duplicates(['symbol'], keep='last') \\\n        .drop(columns=['dbver'])\n\n\n# Split between common and specific codes\ndef generate_error_ranges(df_mysql: pd.DataFrame, df_mariadb: pd.DataFrame) -> ErrorCodes:\n    # Join\n    joined = df_mysql.join(df_mariadb.set_index('numbr'), how='outer', on='numbr', lsuffix='_mysql', rsuffix='_mariadb')\n    joined = joined[joined['numbr'] < COMMON_ERROR_LAST]\n\n    # Common range\n    res_common = joined[joined['symbol_mysql'] == joined['symbol_mariadb']]\n    res_common = res_common.rename(columns={'symbol_mysql': 'symbol'}).drop(columns=['symbol_mariadb'])\n\n    # Values in the common range that differ between mysql and mariadb\n    joined_different = joined[joined['symbol_mysql'] != joined['symbol_mariadb']]\n    res_mysql_1 = joined_different[joined_different['symbol_mysql'].notna()].rename(columns={'symbol_mysql': 'symbol'}).drop(columns=['symbol_mariadb'])\n    res_mariadb_1 = joined_different[joined_different['symbol_mariadb'].notna()].rename(columns={'symbol_mariadb': 'symbol'}).drop(columns=['symbol_mysql'])\n\n    # Values that are outside the common range\n    res_mysql_2 = df_mysql[df_mysql['numbr'] >= COMMON_ERROR_LAST]\n    res_mariadb_2 = df_mariadb[df_mariadb['numbr'] >= COMMON_ERROR_LAST]\n\n    return ErrorCodes(\n        common=res_common.sort_values(by='numbr'),\n        mysql=pd.concat([res_mysql_1, res_mysql_2]).sort_values(by='numbr'),\n        mariadb=pd.concat([res_mariadb_1, res_mariadb_2]).sort_values(by='numbr')\n    )\n\n# Does the full process. folder should contain the relevant headers\ndef parse_headers(folder: Path) -> ErrorCodes:\n    df_mysql8_header = parse_err_header(folder.joinpath('mysql8.h'))\n    df_mysql5_header = parse_err_header(folder.joinpath('mysql5.h'))\n    df_mariadb_header = parse_err_header(folder.joinpath('mariadb.h'))\n    df_mysql_header = merge_mysql_errors(df_mysql5_header, df_mysql8_header)\n    return generate_error_ranges(df_mysql_header, df_mariadb_header)\n\n\n# Writes a CSV file with the contents of headers, so we can keep track of what we did in the last Boost version\ndef write_csv(codes: ErrorCodes) -> None:\n    df = pd.concat([\n        codes.common.assign(category='common'),\n        codes.mysql.assign(category='mysql'),\n        codes.mariadb.assign(category='mariadb')\n    ]).sort_values(by=['numbr', 'category'])\n    df.to_csv(_CSV_PATH, index=False)\n\n\n# Loads the CSV file from the previous version\ndef load_csv() -> ErrorCodes:\n    df = pd.read_csv(_CSV_PATH)\n    return ErrorCodes(\n        common=df[df['category'] == 'common'].drop(columns=['category']),\n        mysql=df[df['category'] == 'mysql'].drop(columns=['category']),\n        mariadb=df[df['category'] == 'mariadb'].drop(columns=['category']),\n    )\n\n\ndef _merge_new_codes_single(df_common: pd.DataFrame, df_old: pd.DataFrame, df_new: pd.DataFrame) -> pd.DataFrame:\n    # Remove anything that's already present in the current headers\n    temp = pd.concat([df_common, df_new, df_common]).drop_duplicates(subset='numbr', keep=False)\n    temp = pd.concat([df_old, temp, df_old]).drop_duplicates(subset='numbr', keep=False)\n    return pd.concat([df_old, temp])\n\n\ndef merge_new_codes(old: ErrorCodes, new: ErrorCodes) -> ErrorCodes:\n    return ErrorCodes(\n        common=old.common, # the common range never gets modified\n        mysql=_merge_new_codes_single(old.common, old.mysql, new.mysql),\n        mariadb=_merge_new_codes_single(old.common, old.mariadb, new.mariadb),\n    )\n\n\n# Actually perform the generation\ndef write_headers(codes: ErrorCodes) -> None:\n    def header_path(p: List[str]) -> Path:\n        return REPO_BASE.joinpath('include', 'boost', 'mysql', *p)\n\n    # common_server_errc.hpp\n    with open(header_path(['common_server_errc.hpp']), 'wt') as f:\n        f.write(render_common_server_errc(codes.common))\n    \n    # mysql_server_errc.hpp\n    with open(header_path(['mysql_server_errc.hpp']), 'wt') as f:\n        f.write(render_server_specific_errc('mysql', codes.mysql))\n\n    # mariadb_server_errc.hpp\n    with open(header_path(['mariadb_server_errc.hpp']), 'wt') as f:\n        f.write(render_server_specific_errc('mariadb', codes.mariadb))\n    \n    # detail/auxiliar/server_errc_strings.hpp\n    with open(header_path(['impl', 'internal', 'error', 'server_error_to_string.ipp']), 'wt') as f:\n        f.write(render_server_error_to_string(codes.common, codes.mysql, codes.mariadb))\n\n\n# We need to run file_headers.py to set copyrights and headers\ndef invoke_file_headers() -> None:\n    run(['python', str(REPO_BASE.joinpath('tools', 'scripts', 'file_headers.py'))])\n\n\ndef main():\n    old_codes = load_csv()\n    new_codes = parse_headers(REPO_BASE.joinpath('private', 'errors', '1.86'))\n    codes = merge_new_codes(old_codes, new_codes)\n    write_csv(codes)\n    write_headers(codes)\n    invoke_file_headers()\n\n            \nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "tools/seed_corpus/field_table.csv",
    "content": "fuzzer,name,content\r\nfuzz_row,text_multifield_table_0,0503000f000300051f061f01310361616102313103312e3103302e31\r\nfuzz_row,text_multifield_table_1,0503000f000300051f061f013203626262023232fb03302e32\r\nfuzz_text_field,multifield_table_0_0,030031\r\nfuzz_text_field,multifield_table_0_1,0f00616161\r\nfuzz_text_field,multifield_table_0_2,03003131\r\nfuzz_text_field,multifield_table_0_3,051f312e31\r\nfuzz_text_field,multifield_table_0_4,061f302e31\r\nfuzz_text_field,multifield_table_1_0,030032\r\nfuzz_text_field,multifield_table_1_1,0f00626262\r\nfuzz_text_field,multifield_table_1_2,03003232\r\nfuzz_row,text_types_bigint_0,050f000400840004008400036d61781339323233333732303336383534373735383037143138343436373434303733373039353531363135fbfb\r\nfuzz_row,text_types_bigint_1,050f000400840004008400036d696e142d393232333337323033363835343737353830380130fb0730303030303030\r\nfuzz_row,text_types_bigint_2,050f000400840004008400086e65676174697665032d3230fb032d3230fb\r\nfuzz_row,text_types_bigint_3,050f00040084000400840007726567756c61720232300232300232300730303030303230\r\nfuzz_text_field,types_bigint_0_0,0f006d6178\r\nfuzz_text_field,types_bigint_0_1,040039323233333732303336383534373735383037\r\nfuzz_text_field,types_bigint_0_2,84003138343436373434303733373039353531363135\r\nfuzz_text_field,types_bigint_1_0,0f006d696e\r\nfuzz_text_field,types_bigint_1_1,04002d39323233333732303336383534373735383038\r\nfuzz_text_field,types_bigint_1_2,840030\r\nfuzz_text_field,types_bigint_2_0,0f006e65676174697665\r\nfuzz_text_field,types_bigint_2_1,04002d3230\r\nfuzz_text_field,types_bigint_3_0,0f00726567756c6172\r\nfuzz_text_field,types_bigint_3_1,04003230\r\nfuzz_text_field,types_bigint_3_2,84003230\r\nfuzz_text_field,types_bigint_3_3,04003230\r\nfuzz_text_field,types_bigint_3_4,840030303030303230\r\nfuzz_row,text_types_binary_0,070f0010001100130013001300130005656d7074790a000000000000000000000000000000\r\nfuzz_row,text_types_binary_1,070f00100011001300130013001300086e6f6e61736369690a00ff00000000000000000201fe0202fd0203fc0204fb0205fa\r\nfuzz_row,text_types_binary_2,070f0010001100130013001300130007726567756c61720a005f62696e61727900000b005f76617262696e6172790a005f74696e79626c6f6206005f626c6f620c005f6d656469756d626c6f620a005f6c6f6e67626c6f62\r\nfuzz_text_field,types_binary_0_0,0f00656d707479\r\nfuzz_text_field,types_binary_0_1,100000000000000000000000\r\nfuzz_text_field,types_binary_0_2,1100\r\nfuzz_text_field,types_binary_0_3,1300\r\nfuzz_text_field,types_binary_0_4,1300\r\nfuzz_text_field,types_binary_0_5,1300\r\nfuzz_text_field,types_binary_0_6,1300\r\nfuzz_text_field,types_binary_1_0,0f006e6f6e6173636969\r\nfuzz_text_field,types_binary_1_1,100000ff0000000000000000\r\nfuzz_text_field,types_binary_1_2,110001fe\r\nfuzz_text_field,types_binary_1_3,130002fd\r\nfuzz_text_field,types_binary_1_4,130003fc\r\nfuzz_text_field,types_binary_1_5,130004fb\r\nfuzz_text_field,types_binary_1_6,130005fa\r\nfuzz_text_field,types_binary_2_0,0f00726567756c6172\r\nfuzz_text_field,types_binary_2_1,1000005f62696e6172790000\r\nfuzz_text_field,types_binary_2_2,1100005f76617262696e617279\r\nfuzz_text_field,types_binary_2_3,1300005f74696e79626c6f62\r\nfuzz_text_field,types_binary_2_4,1300005f626c6f62\r\nfuzz_text_field,types_binary_2_5,1300005f6d656469756d626c6f62\r\nfuzz_text_field,types_binary_2_6,1300005f6c6f6e67626c6f62\r\nfuzz_row,text_types_bit_0,0c0f0088008800880088008800880088008800880088008800036d6178010101ff023fff02ffff03ffffff0401ffffff04ffffffff05ffffffffff06ffffffffffff07ffffffffffffff08ffffffffffffffff\r\nfuzz_row,text_types_bit_1,0c0f0088008800880088008800880088008800880088008800036d696e010001000200000200000300000004000000000400000000050000000000060000000000000700000000000000080000000000000000\r\nfuzz_row,text_types_bit_2,0c0f008800880088008800880088008800880088008800880007726567756c61720101019e021e2a02123403123456040154abe0041234567805123456789a06123456789abc07123456789abcde081234567812345678\r\nfuzz_text_field,types_bit_0_0,0f006d6178\r\nfuzz_text_field,types_bit_0_1,880001\r\nfuzz_text_field,types_bit_0_2,8800ff\r\nfuzz_text_field,types_bit_0_3,88003fff\r\nfuzz_text_field,types_bit_0_4,8800ffff\r\nfuzz_text_field,types_bit_0_5,8800ffffff\r\nfuzz_text_field,types_bit_0_6,880001ffffff\r\nfuzz_text_field,types_bit_0_7,8800ffffffff\r\nfuzz_text_field,types_bit_0_8,8800ffffffffff\r\nfuzz_text_field,types_bit_0_9,8800ffffffffffff\r\nfuzz_text_field,types_bit_0_10,8800ffffffffffffff\r\nfuzz_text_field,types_bit_0_11,8800ffffffffffffffff\r\nfuzz_text_field,types_bit_1_0,0f006d696e\r\nfuzz_text_field,types_bit_1_1,880000\r\nfuzz_text_field,types_bit_1_2,880000\r\nfuzz_text_field,types_bit_1_3,88000000\r\nfuzz_text_field,types_bit_1_4,88000000\r\nfuzz_text_field,types_bit_1_5,8800000000\r\nfuzz_text_field,types_bit_1_6,880000000000\r\nfuzz_text_field,types_bit_1_7,880000000000\r\nfuzz_text_field,types_bit_1_8,88000000000000\r\nfuzz_text_field,types_bit_1_9,8800000000000000\r\nfuzz_text_field,types_bit_1_10,880000000000000000\r\nfuzz_text_field,types_bit_1_11,88000000000000000000\r\nfuzz_text_field,types_bit_2_0,0f00726567756c6172\r\nfuzz_text_field,types_bit_2_1,880001\r\nfuzz_text_field,types_bit_2_2,88009e\r\nfuzz_text_field,types_bit_2_3,88001e2a\r\nfuzz_text_field,types_bit_2_4,88001234\r\nfuzz_text_field,types_bit_2_5,8800123456\r\nfuzz_text_field,types_bit_2_6,88000154abe0\r\nfuzz_text_field,types_bit_2_7,880012345678\r\nfuzz_text_field,types_bit_2_8,8800123456789a\r\nfuzz_text_field,types_bit_2_9,8800123456789abc\r\nfuzz_text_field,types_bit_2_10,8800123456789abcde\r\nfuzz_text_field,types_bit_2_11,88001234567812345678\r\nfuzz_row,text_types_bool_0,020f0000000566616c73650130\r\nfuzz_row,text_types_bool_1,020f00000004747275650131\r\nfuzz_text_field,types_bool_0_0,0f0066616c7365\r\nfuzz_text_field,types_bool_0_1,000030\r\nfuzz_text_field,types_bool_1_0,0f0074727565\r\nfuzz_text_field,types_bool_1_1,000031\r\nfuzz_row,text_types_date_0,020f000b00086c6561705f3430300a323030302d30322d3239\r\nfuzz_row,text_types_date_1,020f000b000c6c6561705f726567756c61720a313738382d30322d3239\r\nfuzz_row,text_types_date_2,020f000b00036d61780a393939392d31322d3331\r\nfuzz_row,text_types_date_3,020f000b00036d696e0a303030302d30312d3031\r\nfuzz_row,text_types_date_4,020f000b0007726567756c61720a323031302d30332d3238\r\nfuzz_row,text_types_date_5,020f000b001579726567756c61725f696e76616c69645f646174650a323032302d31312d3331\r\nfuzz_row,text_types_date_6,020f000b001d79726567756c61725f696e76616c69645f646174655f6c6561703130300a313930302d30322d3239\r\nfuzz_row,text_types_date_7,020f000b002179726567756c61725f696e76616c69645f646174655f6c656170726567756c61720a313939392d30322d3239\r\nfuzz_row,text_types_date_8,020f000b001779726567756c61725f6d726567756c61725f647a65726f0a323032302d31312d3030\r\nfuzz_row,text_types_date_9,020f000b001779726567756c61725f6d7a65726f5f64726567756c61720a323032302d30302d3230\r\nfuzz_row,text_types_date_10,020f000b001479726567756c61725f6d7a65726f5f647a65726f0a323032302d30302d3030\r\nfuzz_row,text_types_date_11,020f000b0012797a65726f5f696e76616c69645f646174650a303030302d31312d3331\r\nfuzz_row,text_types_date_12,020f000b0014797a65726f5f6d726567756c61725f647a65726f0a303030302d31312d3030\r\nfuzz_row,text_types_date_13,020f000b0014797a65726f5f6d7a65726f5f64726567756c61720a303030302d30302d3230\r\nfuzz_row,text_types_date_14,020f000b00047a65726f0a303030302d30302d3030\r\nfuzz_text_field,types_date_0_0,0f006c6561705f343030\r\nfuzz_text_field,types_date_0_1,0b00323030302d30322d3239\r\nfuzz_text_field,types_date_1_0,0f006c6561705f726567756c6172\r\nfuzz_text_field,types_date_1_1,0b00313738382d30322d3239\r\nfuzz_text_field,types_date_2_0,0f006d6178\r\nfuzz_text_field,types_date_2_1,0b00393939392d31322d3331\r\nfuzz_text_field,types_date_3_0,0f006d696e\r\nfuzz_text_field,types_date_3_1,0b00303030302d30312d3031\r\nfuzz_text_field,types_date_4_0,0f00726567756c6172\r\nfuzz_text_field,types_date_4_1,0b00323031302d30332d3238\r\nfuzz_text_field,types_date_5_0,0f0079726567756c61725f696e76616c69645f64617465\r\nfuzz_text_field,types_date_5_1,0b00323032302d31312d3331\r\nfuzz_text_field,types_date_6_0,0f0079726567756c61725f696e76616c69645f646174655f6c656170313030\r\nfuzz_text_field,types_date_6_1,0b00313930302d30322d3239\r\nfuzz_text_field,types_date_7_0,0f0079726567756c61725f696e76616c69645f646174655f6c656170726567756c6172\r\nfuzz_text_field,types_date_7_1,0b00313939392d30322d3239\r\nfuzz_text_field,types_date_8_0,0f0079726567756c61725f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_date_8_1,0b00323032302d31312d3030\r\nfuzz_text_field,types_date_9_0,0f0079726567756c61725f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_date_9_1,0b00323032302d30302d3230\r\nfuzz_text_field,types_date_10_0,0f0079726567756c61725f6d7a65726f5f647a65726f\r\nfuzz_text_field,types_date_10_1,0b00323032302d30302d3030\r\nfuzz_text_field,types_date_11_0,0f00797a65726f5f696e76616c69645f64617465\r\nfuzz_text_field,types_date_11_1,0b00303030302d31312d3331\r\nfuzz_text_field,types_date_12_0,0f00797a65726f5f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_date_12_1,0b00303030302d31312d3030\r\nfuzz_text_field,types_date_13_0,0f00797a65726f5f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_date_13_1,0b00303030302d30302d3230\r\nfuzz_text_field,types_date_14_0,0f007a65726f\r\nfuzz_text_field,types_date_14_1,0b00303030302d30302d3030\r\nfuzz_row,text_types_datetime_0,080f000c000c010c020c030c040c050c06046461746513323031302d30352d30322030303a30303a303015323031302d30352d30322030303a30303a30302e3016323031302d30352d30322030303a30303a30302e303017323031302d30352d30322030303a30303a30302e30303018323031302d30352d30322030303a30303a30302e3030303019323031302d30352d30322030303a30303a30302e30303030301a323031302d30352d30322030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_1,080f000c000c010c020c030c040c050c060a646174655f6c6561703413323030342d30322d32392030303a30303a303015323030342d30322d32392030303a30303a30302e3016323030342d30322d32392030303a30303a30302e303017323030342d30322d32392030303a30303a30302e30303018323030342d30322d32392030303a30303a30302e3030303019323030342d30322d32392030303a30303a30302e30303030301a323030342d30322d32392030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_2,080f000c000c010c020c030c040c050c060c646174655f6c65617034303013323030302d30322d32392030303a30303a303015323030302d30322d32392030303a30303a30302e3016323030302d30322d32392030303a30303a30302e303017323030302d30322d32392030303a30303a30302e30303018323030302d30322d32392030303a30303a30302e3030303019323030302d30322d32392030303a30303a30302e30303030301a323030302d30322d32392030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_3,080f000c000c010c020c030c040c050c061a646174655f79726567756c61725f696e76616c69645f6461746513323032302d31312d33312030303a30303a303015323032302d31312d33312030303a30303a30302e3016323032302d31312d33312030303a30303a30302e303017323032302d31312d33312030303a30303a30302e30303018323032302d31312d33312030303a30303a30302e3030303019323032302d31312d33312030303a30303a30302e30303030301a323032302d31312d33312030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_4,080f000c000c010c020c030c040c050c0622646174655f79726567756c61725f696e76616c69645f646174655f6c65617031303013313930302d30322d32392030303a30303a303015313930302d30322d32392030303a30303a30302e3016313930302d30322d32392030303a30303a30302e303017313930302d30322d32392030303a30303a30302e30303018313930302d30322d32392030303a30303a30302e3030303019313930302d30322d32392030303a30303a30302e30303030301a313930302d30322d32392030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_5,080f000c000c010c020c030c040c050c0626646174655f79726567756c61725f696e76616c69645f646174655f6c656170726567756c617213313939392d30322d32392030303a30303a303015313939392d30322d32392030303a30303a30302e3016313939392d30322d32392030303a30303a30302e303017313939392d30322d32392030303a30303a30302e30303018313939392d30322d32392030303a30303a30302e3030303019313939392d30322d32392030303a30303a30302e30303030301a313939392d30322d32392030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_6,080f000c000c010c020c030c040c050c061c646174655f79726567756c61725f6d726567756c61725f647a65726f13323032302d31302d30302030303a30303a303015323032302d31302d30302030303a30303a30302e3016323032302d31302d30302030303a30303a30302e303017323032302d31302d30302030303a30303a30302e30303018323032302d31302d30302030303a30303a30302e3030303019323032302d31302d30302030303a30303a30302e30303030301a323032302d31302d30302030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_7,080f000c000c010c020c030c040c050c061c646174655f79726567756c61725f6d7a65726f5f64726567756c617213323032302d30302d31302030303a30303a303015323032302d30302d31302030303a30303a30302e3016323032302d30302d31302030303a30303a30302e303017323032302d30302d31302030303a30303a30302e30303018323032302d30302d31302030303a30303a30302e3030303019323032302d30302d31302030303a30303a30302e30303030301a323032302d30302d31302030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_8,080f000c000c010c020c030c040c050c0619646174655f79726567756c61725f6d7a65726f5f647a65726f13323032302d30302d30302030303a30303a303015323032302d30302d30302030303a30303a30302e3016323032302d30302d30302030303a30303a30302e303017323032302d30302d30302030303a30303a30302e30303018323032302d30302d30302030303a30303a30302e3030303019323032302d30302d30302030303a30303a30302e30303030301a323032302d30302d30302030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_9,080f000c000c010c020c030c040c050c0617646174655f797a65726f5f696e76616c69645f6461746513303030302d31312d33312030303a30303a303015303030302d31312d33312030303a30303a30302e3016303030302d31312d33312030303a30303a30302e303017303030302d31312d33312030303a30303a30302e30303018303030302d31312d33312030303a30303a30302e3030303019303030302d31312d33312030303a30303a30302e30303030301a303030302d31312d33312030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_10,080f000c000c010c020c030c040c050c0619646174655f797a65726f5f6d726567756c61725f647a65726f13303030302d31302d30302030303a30303a303015303030302d31302d30302030303a30303a30302e3016303030302d31302d30302030303a30303a30302e303017303030302d31302d30302030303a30303a30302e30303018303030302d31302d30302030303a30303a30302e3030303019303030302d31302d30302030303a30303a30302e30303030301a303030302d31302d30302030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_11,080f000c000c010c020c030c040c050c0619646174655f797a65726f5f6d7a65726f5f64726567756c617213303030302d30302d31302030303a30303a303015303030302d30302d31302030303a30303a30302e3016303030302d30302d31302030303a30303a30302e303017303030302d30302d31302030303a30303a30302e30303018303030302d30302d31302030303a30303a30302e3030303019303030302d30302d31302030303a30303a30302e30303030301a303030302d30302d31302030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_12,080f000c000c010c020c030c040c050c0609646174655f7a65726f13303030302d30302d30302030303a30303a303015303030302d30302d30302030303a30303a30302e3016303030302d30302d30302030303a30303a30302e303017303030302d30302d30302030303a30303a30302e30303018303030302d30302d30302030303a30303a30302e3030303019303030302d30302d30302030303a30303a30302e30303030301a303030302d30302d30302030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_13,080f000c000c010c020c030c040c050c06016813323031302d30352d30322032333a30303a303015323031302d30352d30322032333a30303a30302e3016323031302d30352d30322032333a30303a30302e303017323031302d30352d30322032333a30303a30302e30303018323031302d30352d30322032333a30303a30302e3030303019323031302d30352d30322032333a30303a30302e30303030301a323031302d30352d30322032333a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_14,080f000c000c010c020c030c040c050c0602686d13323031302d30352d30322032333a30313a303015323031302d30352d30322032333a30313a30302e3016323031302d30352d30322032333a30313a30302e303017323031302d30352d30322032333a30313a30302e30303018323031302d30352d30322032333a30313a30302e3030303019323031302d30352d30322032333a30313a30302e30303030301a323031302d30352d30322032333a30313a30302e303030303030\r\nfuzz_row,text_types_datetime_15,080f000c000c010c020c030c040c050c0603686d7313323031302d30352d30322032333a30313a353015323031302d30352d30322032333a30313a35302e3016323031302d30352d30322032333a30313a35302e303017323031302d30352d30322032333a30313a35302e30303018323031302d30352d30322032333a30313a35302e3030303019323031302d30352d30322032333a30313a35302e30303030301a323031302d30352d30322032333a30313a35302e303030303030\r\nfuzz_row,text_types_datetime_16,080f000c000c010c020c030c040c050c0619686d735f79726567756c61725f696e76616c69645f6461746513323032302d31312d33312031303a32303a333015323032302d31312d33312031303a32303a33302e3016323032302d31312d33312031303a32303a33302e303017323032302d31312d33312031303a32303a33302e30303018323032302d31312d33312031303a32303a33302e3030303019323032302d31312d33312031303a32303a33302e30303030301a323032302d31312d33312031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_17,080f000c000c010c020c030c040c050c0621686d735f79726567756c61725f696e76616c69645f646174655f6c65617031303013313930302d30322d32392031303a32303a333015313930302d30322d32392031303a32303a33302e3016313930302d30322d32392031303a32303a33302e303017313930302d30322d32392031303a32303a33302e30303018313930302d30322d32392031303a32303a33302e3030303019313930302d30322d32392031303a32303a33302e30303030301a313930302d30322d32392031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_18,080f000c000c010c020c030c040c050c0625686d735f79726567756c61725f696e76616c69645f646174655f6c656170726567756c617213313939392d30322d32392031303a32303a333015313939392d30322d32392031303a32303a33302e3016313939392d30322d32392031303a32303a33302e303017313939392d30322d32392031303a32303a33302e30303018313939392d30322d32392031303a32303a33302e3030303019313939392d30322d32392031303a32303a33302e30303030301a313939392d30322d32392031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_19,080f000c000c010c020c030c040c050c061b686d735f79726567756c61725f6d726567756c61725f647a65726f13323032302d31302d30302031303a32303a333015323032302d31302d30302031303a32303a33302e3016323032302d31302d30302031303a32303a33302e303017323032302d31302d30302031303a32303a33302e30303018323032302d31302d30302031303a32303a33302e3030303019323032302d31302d30302031303a32303a33302e30303030301a323032302d31302d30302031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_20,080f000c000c010c020c030c040c050c061b686d735f79726567756c61725f6d7a65726f5f64726567756c617213323032302d30302d31302031303a32303a333015323032302d30302d31302031303a32303a33302e3016323032302d30302d31302031303a32303a33302e303017323032302d30302d31302031303a32303a33302e30303018323032302d30302d31302031303a32303a33302e3030303019323032302d30302d31302031303a32303a33302e30303030301a323032302d30302d31302031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_21,080f000c000c010c020c030c040c050c0618686d735f79726567756c61725f6d7a65726f5f647a65726f13323032302d30302d30302031303a32303a333015323032302d30302d30302031303a32303a33302e3016323032302d30302d30302031303a32303a33302e303017323032302d30302d30302031303a32303a33302e30303018323032302d30302d30302031303a32303a33302e3030303019323032302d30302d30302031303a32303a33302e30303030301a323032302d30302d30302031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_22,080f000c000c010c020c030c040c050c0616686d735f797a65726f5f696e76616c69645f6461746513303030302d31312d33312031303a32303a333015303030302d31312d33312031303a32303a33302e3016303030302d31312d33312031303a32303a33302e303017303030302d31312d33312031303a32303a33302e30303018303030302d31312d33312031303a32303a33302e3030303019303030302d31312d33312031303a32303a33302e30303030301a303030302d31312d33312031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_23,080f000c000c010c020c030c040c050c0618686d735f797a65726f5f6d726567756c61725f647a65726f13303030302d31302d30302031303a32303a333015303030302d31302d30302031303a32303a33302e3016303030302d31302d30302031303a32303a33302e303017303030302d31302d30302031303a32303a33302e30303018303030302d31302d30302031303a32303a33302e3030303019303030302d31302d30302031303a32303a33302e30303030301a303030302d31302d30302031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_24,080f000c000c010c020c030c040c050c0618686d735f797a65726f5f6d7a65726f5f64726567756c617213303030302d30302d31302031303a32303a333015303030302d30302d31302031303a32303a33302e3016303030302d30302d31302031303a32303a33302e303017303030302d30302d31302031303a32303a33302e30303018303030302d30302d31302031303a32303a33302e3030303019303030302d30302d31302031303a32303a33302e30303030301a303030302d30302d31302031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_25,080f000c000c010c020c030c040c050c0608686d735f7a65726f13303030302d30302d30302031303a32303a333015303030302d30302d30302031303a32303a33302e3016303030302d30302d30302031303a32303a33302e303017303030302d30302d30302031303a32303a33302e30303018303030302d30302d30302031303a32303a33302e3030303019303030302d30302d30302031303a32303a33302e30303030301a303030302d30302d30302031303a32303a33302e303030303030\r\nfuzz_row,text_types_datetime_26,080f000c000c010c020c030c040c050c0604686d7375fb15323031302d30352d30322032333a30313a35302e3116323031302d30352d30322032333a30313a35302e313217323031302d30352d30322032333a30313a35302e31323318323031302d30352d30322032333a30313a35302e3132333419323031302d30352d30322032333a30313a35302e31323334351a323031302d30352d30322032333a30313a35302e313233343536\r\nfuzz_row,text_types_datetime_27,080f000c000c010c020c030c040c050c061a686d73755f79726567756c61725f696e76616c69645f6461746513323032302d31312d33312031303a32303a333015323032302d31312d33312031303a32303a33302e3916323032302d31312d33312031303a32303a33302e393917323032302d31312d33312031303a32303a33302e39393918323032302d31312d33312031303a32303a33302e3939393919323032302d31312d33312031303a32303a33302e39393939391a323032302d31312d33312031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_28,080f000c000c010c020c030c040c050c0622686d73755f79726567756c61725f696e76616c69645f646174655f6c65617031303013313930302d30322d32392031303a32303a333015313930302d30322d32392031303a32303a33302e3916313930302d30322d32392031303a32303a33302e393917313930302d30322d32392031303a32303a33302e39393918313930302d30322d32392031303a32303a33302e3939393919313930302d30322d32392031303a32303a33302e39393939391a313930302d30322d32392031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_29,080f000c000c010c020c030c040c050c0626686d73755f79726567756c61725f696e76616c69645f646174655f6c656170726567756c617213313939392d30322d32392031303a32303a333015313939392d30322d32392031303a32303a33302e3916313939392d30322d32392031303a32303a33302e393917313939392d30322d32392031303a32303a33302e39393918313939392d30322d32392031303a32303a33302e3939393919313939392d30322d32392031303a32303a33302e39393939391a313939392d30322d32392031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_30,080f000c000c010c020c030c040c050c061c686d73755f79726567756c61725f6d726567756c61725f647a65726f13323032302d31302d30302031303a32303a333015323032302d31302d30302031303a32303a33302e3916323032302d31302d30302031303a32303a33302e393917323032302d31302d30302031303a32303a33302e39393918323032302d31302d30302031303a32303a33302e3939393919323032302d31302d30302031303a32303a33302e39393939391a323032302d31302d30302031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_31,080f000c000c010c020c030c040c050c061c686d73755f79726567756c61725f6d7a65726f5f64726567756c617213323032302d30302d31302031303a32303a333015323032302d30302d31302031303a32303a33302e3916323032302d30302d31302031303a32303a33302e393917323032302d30302d31302031303a32303a33302e39393918323032302d30302d31302031303a32303a33302e3939393919323032302d30302d31302031303a32303a33302e39393939391a323032302d30302d31302031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_32,080f000c000c010c020c030c040c050c0619686d73755f79726567756c61725f6d7a65726f5f647a65726f13323032302d30302d30302031303a32303a333015323032302d30302d30302031303a32303a33302e3916323032302d30302d30302031303a32303a33302e393917323032302d30302d30302031303a32303a33302e39393918323032302d30302d30302031303a32303a33302e3939393919323032302d30302d30302031303a32303a33302e39393939391a323032302d30302d30302031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_33,080f000c000c010c020c030c040c050c0617686d73755f797a65726f5f696e76616c69645f6461746513303030302d31312d33312031303a32303a333015303030302d31312d33312031303a32303a33302e3916303030302d31312d33312031303a32303a33302e393917303030302d31312d33312031303a32303a33302e39393918303030302d31312d33312031303a32303a33302e3939393919303030302d31312d33312031303a32303a33302e39393939391a303030302d31312d33312031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_34,080f000c000c010c020c030c040c050c0619686d73755f797a65726f5f6d726567756c61725f647a65726f13303030302d31302d30302031303a32303a333015303030302d31302d30302031303a32303a33302e3916303030302d31302d30302031303a32303a33302e393917303030302d31302d30302031303a32303a33302e39393918303030302d31302d30302031303a32303a33302e3939393919303030302d31302d30302031303a32303a33302e39393939391a303030302d31302d30302031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_35,080f000c000c010c020c030c040c050c0619686d73755f797a65726f5f6d7a65726f5f64726567756c617213303030302d30302d31302031303a32303a333015303030302d30302d31302031303a32303a33302e3916303030302d30302d31302031303a32303a33302e393917303030302d30302d31302031303a32303a33302e39393918303030302d30302d31302031303a32303a33302e3939393919303030302d30302d31302031303a32303a33302e39393939391a303030302d30302d31302031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_36,080f000c000c010c020c030c040c050c0609686d73755f7a65726f13303030302d30302d30302031303a32303a333015303030302d30302d30302031303a32303a33302e3916303030302d30302d30302031303a32303a33302e393917303030302d30302d30302031303a32303a33302e39393918303030302d30302d30302031303a32303a33302e3939393919303030302d30302d30302031303a32303a33302e39393939391a303030302d30302d30302031303a32303a33302e393939393939\r\nfuzz_row,text_types_datetime_37,080f000c000c010c020c030c040c050c0603686d75fb15323031302d30352d30322032333a30313a30302e3116323031302d30352d30322032333a30313a30302e313217323031302d30352d30322032333a30313a30302e31323318323031302d30352d30322032333a30313a30302e3132333419323031302d30352d30322032333a30313a30302e31323334351a323031302d30352d30322032333a30313a30302e313233343536\r\nfuzz_row,text_types_datetime_38,080f000c000c010c020c030c040c050c0602687313323031302d30352d30322032333a30303a353015323031302d30352d30322032333a30303a35302e3016323031302d30352d30322032333a30303a35302e303017323031302d30352d30322032333a30303a35302e30303018323031302d30352d30322032333a30303a35302e3030303019323031302d30352d30322032333a30303a35302e30303030301a323031302d30352d30322032333a30303a35302e303030303030\r\nfuzz_row,text_types_datetime_39,080f000c000c010c020c030c040c050c0603687375fb15323031302d30352d30322032333a30303a35302e3116323031302d30352d30322032333a30303a35302e313217323031302d30352d30322032333a30303a35302e31323318323031302d30352d30322032333a30303a35302e3132333419323031302d30352d30322032333a30303a35302e31323334351a323031302d30352d30322032333a30303a35302e313233343536\r\nfuzz_row,text_types_datetime_40,080f000c000c010c020c030c040c050c06026875fb15323031302d30352d30322032333a30303a30302e3116323031302d30352d30322032333a30303a30302e313217323031302d30352d30322032333a30303a30302e31323318323031302d30352d30322032333a30303a30302e3132333419323031302d30352d30322032333a30303a30302e31323334351a323031302d30352d30322032333a30303a30302e313233343536\r\nfuzz_row,text_types_datetime_41,080f000c000c010c020c030c040c050c06016d13323031302d30352d30322030303a30313a303015323031302d30352d30322030303a30313a30302e3016323031302d30352d30322030303a30313a30302e303017323031302d30352d30322030303a30313a30302e30303018323031302d30352d30322030303a30313a30302e3030303019323031302d30352d30322030303a30313a30302e30303030301a323031302d30352d30322030303a30313a30302e303030303030\r\nfuzz_row,text_types_datetime_42,080f000c000c010c020c030c040c050c06036d617813393939392d31322d33312032333a35393a353915393939392d31322d33312032333a35393a35392e3916393939392d31322d33312032333a35393a35392e393917393939392d31322d33312032333a35393a35392e39393918393939392d31322d33312032333a35393a35392e3939393919393939392d31322d33312032333a35393a35392e39393939391a393939392d31322d33312032333a35393a35392e393939393939\r\nfuzz_row,text_types_datetime_43,080f000c000c010c020c030c040c050c06036d696e13303030302d30312d30312030303a30303a303015303030302d30312d30312030303a30303a30302e3016303030302d30312d30312030303a30303a30302e303017303030302d30312d30312030303a30303a30302e30303018303030302d30312d30312030303a30303a30302e3030303019303030302d30312d30312030303a30303a30302e30303030301a303030302d30312d30312030303a30303a30302e303030303030\r\nfuzz_row,text_types_datetime_44,080f000c000c010c020c030c040c050c06026d7313323031302d30352d30322030303a30313a353015323031302d30352d30322030303a30313a35302e3016323031302d30352d30322030303a30313a35302e303017323031302d30352d30322030303a30313a35302e30303018323031302d30352d30322030303a30313a35302e3030303019323031302d30352d30322030303a30313a35302e30303030301a323031302d30352d30322030303a30313a35302e303030303030\r\nfuzz_row,text_types_datetime_45,080f000c000c010c020c030c040c050c06036d7375fb15323031302d30352d30322030303a30313a35302e3116323031302d30352d30322030303a30313a35302e313217323031302d30352d30322030303a30313a35302e31323318323031302d30352d30322030303a30313a35302e3132333419323031302d30352d30322030303a30313a35302e31323334351a323031302d30352d30322030303a30313a35302e313233343536\r\nfuzz_row,text_types_datetime_46,080f000c000c010c020c030c040c050c06026d75fb15323031302d30352d30322030303a30313a30302e3116323031302d30352d30322030303a30313a30302e313217323031302d30352d30322030303a30313a30302e31323318323031302d30352d30322030303a30313a30302e3132333419323031302d30352d30322030303a30313a30302e31323334351a323031302d30352d30322030303a30313a30302e313233343536\r\nfuzz_row,text_types_datetime_47,080f000c000c010c020c030c040c050c06017313323031302d30352d30322030303a30303a353015323031302d30352d30322030303a30303a35302e3016323031302d30352d30322030303a30303a35302e303017323031302d30352d30322030303a30303a35302e30303018323031302d30352d30322030303a30303a35302e3030303019323031302d30352d30322030303a30303a35302e30303030301a323031302d30352d30322030303a30303a35302e303030303030\r\nfuzz_row,text_types_datetime_48,080f000c000c010c020c030c040c050c06027375fb15323031302d30352d30322030303a30303a35302e3116323031302d30352d30322030303a30303a35302e313217323031302d30352d30322030303a30303a35302e31323318323031302d30352d30322030303a30303a35302e3132333419323031302d30352d30322030303a30303a35302e31323334351a323031302d30352d30322030303a30303a35302e313233343536\r\nfuzz_row,text_types_datetime_49,080f000c000c010c020c030c040c050c060175fb15323031302d30352d30322030303a30303a30302e3116323031302d30352d30322030303a30303a30302e313217323031302d30352d30322030303a30303a30302e31323318323031302d30352d30322030303a30303a30302e3132333419323031302d30352d30322030303a30303a30302e31323334351a323031302d30352d30322030303a30303a30302e313233343536\r\nfuzz_text_field,types_datetime_0_0,0f0064617465\r\nfuzz_text_field,types_datetime_0_1,0c00323031302d30352d30322030303a30303a3030\r\nfuzz_text_field,types_datetime_0_2,0c01323031302d30352d30322030303a30303a30302e30\r\nfuzz_text_field,types_datetime_0_3,0c02323031302d30352d30322030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_0_4,0c03323031302d30352d30322030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_0_5,0c04323031302d30352d30322030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_0_6,0c05323031302d30352d30322030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_0_7,0c06323031302d30352d30322030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_1_0,0f00646174655f6c65617034\r\nfuzz_text_field,types_datetime_1_1,0c00323030342d30322d32392030303a30303a3030\r\nfuzz_text_field,types_datetime_1_2,0c01323030342d30322d32392030303a30303a30302e30\r\nfuzz_text_field,types_datetime_1_3,0c02323030342d30322d32392030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_1_4,0c03323030342d30322d32392030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_1_5,0c04323030342d30322d32392030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_1_6,0c05323030342d30322d32392030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_1_7,0c06323030342d30322d32392030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_2_0,0f00646174655f6c656170343030\r\nfuzz_text_field,types_datetime_2_1,0c00323030302d30322d32392030303a30303a3030\r\nfuzz_text_field,types_datetime_2_2,0c01323030302d30322d32392030303a30303a30302e30\r\nfuzz_text_field,types_datetime_2_3,0c02323030302d30322d32392030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_2_4,0c03323030302d30322d32392030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_2_5,0c04323030302d30322d32392030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_2_6,0c05323030302d30322d32392030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_2_7,0c06323030302d30322d32392030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_3_0,0f00646174655f79726567756c61725f696e76616c69645f64617465\r\nfuzz_text_field,types_datetime_3_1,0c00323032302d31312d33312030303a30303a3030\r\nfuzz_text_field,types_datetime_3_2,0c01323032302d31312d33312030303a30303a30302e30\r\nfuzz_text_field,types_datetime_3_3,0c02323032302d31312d33312030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_3_4,0c03323032302d31312d33312030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_3_5,0c04323032302d31312d33312030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_3_6,0c05323032302d31312d33312030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_3_7,0c06323032302d31312d33312030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_4_0,0f00646174655f79726567756c61725f696e76616c69645f646174655f6c656170313030\r\nfuzz_text_field,types_datetime_4_1,0c00313930302d30322d32392030303a30303a3030\r\nfuzz_text_field,types_datetime_4_2,0c01313930302d30322d32392030303a30303a30302e30\r\nfuzz_text_field,types_datetime_4_3,0c02313930302d30322d32392030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_4_4,0c03313930302d30322d32392030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_4_5,0c04313930302d30322d32392030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_4_6,0c05313930302d30322d32392030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_4_7,0c06313930302d30322d32392030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_5_0,0f00646174655f79726567756c61725f696e76616c69645f646174655f6c656170726567756c6172\r\nfuzz_text_field,types_datetime_5_1,0c00313939392d30322d32392030303a30303a3030\r\nfuzz_text_field,types_datetime_5_2,0c01313939392d30322d32392030303a30303a30302e30\r\nfuzz_text_field,types_datetime_5_3,0c02313939392d30322d32392030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_5_4,0c03313939392d30322d32392030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_5_5,0c04313939392d30322d32392030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_5_6,0c05313939392d30322d32392030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_5_7,0c06313939392d30322d32392030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_6_0,0f00646174655f79726567756c61725f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_datetime_6_1,0c00323032302d31302d30302030303a30303a3030\r\nfuzz_text_field,types_datetime_6_2,0c01323032302d31302d30302030303a30303a30302e30\r\nfuzz_text_field,types_datetime_6_3,0c02323032302d31302d30302030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_6_4,0c03323032302d31302d30302030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_6_5,0c04323032302d31302d30302030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_6_6,0c05323032302d31302d30302030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_6_7,0c06323032302d31302d30302030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_7_0,0f00646174655f79726567756c61725f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_datetime_7_1,0c00323032302d30302d31302030303a30303a3030\r\nfuzz_text_field,types_datetime_7_2,0c01323032302d30302d31302030303a30303a30302e30\r\nfuzz_text_field,types_datetime_7_3,0c02323032302d30302d31302030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_7_4,0c03323032302d30302d31302030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_7_5,0c04323032302d30302d31302030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_7_6,0c05323032302d30302d31302030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_7_7,0c06323032302d30302d31302030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_8_0,0f00646174655f79726567756c61725f6d7a65726f5f647a65726f\r\nfuzz_text_field,types_datetime_8_1,0c00323032302d30302d30302030303a30303a3030\r\nfuzz_text_field,types_datetime_8_2,0c01323032302d30302d30302030303a30303a30302e30\r\nfuzz_text_field,types_datetime_8_3,0c02323032302d30302d30302030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_8_4,0c03323032302d30302d30302030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_8_5,0c04323032302d30302d30302030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_8_6,0c05323032302d30302d30302030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_8_7,0c06323032302d30302d30302030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_9_0,0f00646174655f797a65726f5f696e76616c69645f64617465\r\nfuzz_text_field,types_datetime_9_1,0c00303030302d31312d33312030303a30303a3030\r\nfuzz_text_field,types_datetime_9_2,0c01303030302d31312d33312030303a30303a30302e30\r\nfuzz_text_field,types_datetime_9_3,0c02303030302d31312d33312030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_9_4,0c03303030302d31312d33312030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_9_5,0c04303030302d31312d33312030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_9_6,0c05303030302d31312d33312030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_9_7,0c06303030302d31312d33312030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_10_0,0f00646174655f797a65726f5f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_datetime_10_1,0c00303030302d31302d30302030303a30303a3030\r\nfuzz_text_field,types_datetime_10_2,0c01303030302d31302d30302030303a30303a30302e30\r\nfuzz_text_field,types_datetime_10_3,0c02303030302d31302d30302030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_10_4,0c03303030302d31302d30302030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_10_5,0c04303030302d31302d30302030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_10_6,0c05303030302d31302d30302030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_10_7,0c06303030302d31302d30302030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_11_0,0f00646174655f797a65726f5f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_datetime_11_1,0c00303030302d30302d31302030303a30303a3030\r\nfuzz_text_field,types_datetime_11_2,0c01303030302d30302d31302030303a30303a30302e30\r\nfuzz_text_field,types_datetime_11_3,0c02303030302d30302d31302030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_11_4,0c03303030302d30302d31302030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_11_5,0c04303030302d30302d31302030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_11_6,0c05303030302d30302d31302030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_11_7,0c06303030302d30302d31302030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_12_0,0f00646174655f7a65726f\r\nfuzz_text_field,types_datetime_12_1,0c00303030302d30302d30302030303a30303a3030\r\nfuzz_text_field,types_datetime_12_2,0c01303030302d30302d30302030303a30303a30302e30\r\nfuzz_text_field,types_datetime_12_3,0c02303030302d30302d30302030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_12_4,0c03303030302d30302d30302030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_12_5,0c04303030302d30302d30302030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_12_6,0c05303030302d30302d30302030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_12_7,0c06303030302d30302d30302030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_13_0,0f0068\r\nfuzz_text_field,types_datetime_13_1,0c00323031302d30352d30322032333a30303a3030\r\nfuzz_text_field,types_datetime_13_2,0c01323031302d30352d30322032333a30303a30302e30\r\nfuzz_text_field,types_datetime_13_3,0c02323031302d30352d30322032333a30303a30302e3030\r\nfuzz_text_field,types_datetime_13_4,0c03323031302d30352d30322032333a30303a30302e303030\r\nfuzz_text_field,types_datetime_13_5,0c04323031302d30352d30322032333a30303a30302e30303030\r\nfuzz_text_field,types_datetime_13_6,0c05323031302d30352d30322032333a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_13_7,0c06323031302d30352d30322032333a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_14_0,0f00686d\r\nfuzz_text_field,types_datetime_14_1,0c00323031302d30352d30322032333a30313a3030\r\nfuzz_text_field,types_datetime_14_2,0c01323031302d30352d30322032333a30313a30302e30\r\nfuzz_text_field,types_datetime_14_3,0c02323031302d30352d30322032333a30313a30302e3030\r\nfuzz_text_field,types_datetime_14_4,0c03323031302d30352d30322032333a30313a30302e303030\r\nfuzz_text_field,types_datetime_14_5,0c04323031302d30352d30322032333a30313a30302e30303030\r\nfuzz_text_field,types_datetime_14_6,0c05323031302d30352d30322032333a30313a30302e3030303030\r\nfuzz_text_field,types_datetime_14_7,0c06323031302d30352d30322032333a30313a30302e303030303030\r\nfuzz_text_field,types_datetime_15_0,0f00686d73\r\nfuzz_text_field,types_datetime_15_1,0c00323031302d30352d30322032333a30313a3530\r\nfuzz_text_field,types_datetime_15_2,0c01323031302d30352d30322032333a30313a35302e30\r\nfuzz_text_field,types_datetime_15_3,0c02323031302d30352d30322032333a30313a35302e3030\r\nfuzz_text_field,types_datetime_15_4,0c03323031302d30352d30322032333a30313a35302e303030\r\nfuzz_text_field,types_datetime_15_5,0c04323031302d30352d30322032333a30313a35302e30303030\r\nfuzz_text_field,types_datetime_15_6,0c05323031302d30352d30322032333a30313a35302e3030303030\r\nfuzz_text_field,types_datetime_15_7,0c06323031302d30352d30322032333a30313a35302e303030303030\r\nfuzz_text_field,types_datetime_16_0,0f00686d735f79726567756c61725f696e76616c69645f64617465\r\nfuzz_text_field,types_datetime_16_1,0c00323032302d31312d33312031303a32303a3330\r\nfuzz_text_field,types_datetime_16_2,0c01323032302d31312d33312031303a32303a33302e30\r\nfuzz_text_field,types_datetime_16_3,0c02323032302d31312d33312031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_16_4,0c03323032302d31312d33312031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_16_5,0c04323032302d31312d33312031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_16_6,0c05323032302d31312d33312031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_16_7,0c06323032302d31312d33312031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_17_0,0f00686d735f79726567756c61725f696e76616c69645f646174655f6c656170313030\r\nfuzz_text_field,types_datetime_17_1,0c00313930302d30322d32392031303a32303a3330\r\nfuzz_text_field,types_datetime_17_2,0c01313930302d30322d32392031303a32303a33302e30\r\nfuzz_text_field,types_datetime_17_3,0c02313930302d30322d32392031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_17_4,0c03313930302d30322d32392031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_17_5,0c04313930302d30322d32392031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_17_6,0c05313930302d30322d32392031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_17_7,0c06313930302d30322d32392031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_18_0,0f00686d735f79726567756c61725f696e76616c69645f646174655f6c656170726567756c6172\r\nfuzz_text_field,types_datetime_18_1,0c00313939392d30322d32392031303a32303a3330\r\nfuzz_text_field,types_datetime_18_2,0c01313939392d30322d32392031303a32303a33302e30\r\nfuzz_text_field,types_datetime_18_3,0c02313939392d30322d32392031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_18_4,0c03313939392d30322d32392031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_18_5,0c04313939392d30322d32392031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_18_6,0c05313939392d30322d32392031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_18_7,0c06313939392d30322d32392031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_19_0,0f00686d735f79726567756c61725f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_datetime_19_1,0c00323032302d31302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_19_2,0c01323032302d31302d30302031303a32303a33302e30\r\nfuzz_text_field,types_datetime_19_3,0c02323032302d31302d30302031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_19_4,0c03323032302d31302d30302031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_19_5,0c04323032302d31302d30302031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_19_6,0c05323032302d31302d30302031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_19_7,0c06323032302d31302d30302031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_20_0,0f00686d735f79726567756c61725f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_datetime_20_1,0c00323032302d30302d31302031303a32303a3330\r\nfuzz_text_field,types_datetime_20_2,0c01323032302d30302d31302031303a32303a33302e30\r\nfuzz_text_field,types_datetime_20_3,0c02323032302d30302d31302031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_20_4,0c03323032302d30302d31302031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_20_5,0c04323032302d30302d31302031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_20_6,0c05323032302d30302d31302031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_20_7,0c06323032302d30302d31302031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_21_0,0f00686d735f79726567756c61725f6d7a65726f5f647a65726f\r\nfuzz_text_field,types_datetime_21_1,0c00323032302d30302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_21_2,0c01323032302d30302d30302031303a32303a33302e30\r\nfuzz_text_field,types_datetime_21_3,0c02323032302d30302d30302031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_21_4,0c03323032302d30302d30302031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_21_5,0c04323032302d30302d30302031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_21_6,0c05323032302d30302d30302031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_21_7,0c06323032302d30302d30302031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_22_0,0f00686d735f797a65726f5f696e76616c69645f64617465\r\nfuzz_text_field,types_datetime_22_1,0c00303030302d31312d33312031303a32303a3330\r\nfuzz_text_field,types_datetime_22_2,0c01303030302d31312d33312031303a32303a33302e30\r\nfuzz_text_field,types_datetime_22_3,0c02303030302d31312d33312031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_22_4,0c03303030302d31312d33312031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_22_5,0c04303030302d31312d33312031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_22_6,0c05303030302d31312d33312031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_22_7,0c06303030302d31312d33312031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_23_0,0f00686d735f797a65726f5f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_datetime_23_1,0c00303030302d31302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_23_2,0c01303030302d31302d30302031303a32303a33302e30\r\nfuzz_text_field,types_datetime_23_3,0c02303030302d31302d30302031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_23_4,0c03303030302d31302d30302031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_23_5,0c04303030302d31302d30302031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_23_6,0c05303030302d31302d30302031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_23_7,0c06303030302d31302d30302031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_24_0,0f00686d735f797a65726f5f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_datetime_24_1,0c00303030302d30302d31302031303a32303a3330\r\nfuzz_text_field,types_datetime_24_2,0c01303030302d30302d31302031303a32303a33302e30\r\nfuzz_text_field,types_datetime_24_3,0c02303030302d30302d31302031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_24_4,0c03303030302d30302d31302031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_24_5,0c04303030302d30302d31302031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_24_6,0c05303030302d30302d31302031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_24_7,0c06303030302d30302d31302031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_25_0,0f00686d735f7a65726f\r\nfuzz_text_field,types_datetime_25_1,0c00303030302d30302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_25_2,0c01303030302d30302d30302031303a32303a33302e30\r\nfuzz_text_field,types_datetime_25_3,0c02303030302d30302d30302031303a32303a33302e3030\r\nfuzz_text_field,types_datetime_25_4,0c03303030302d30302d30302031303a32303a33302e303030\r\nfuzz_text_field,types_datetime_25_5,0c04303030302d30302d30302031303a32303a33302e30303030\r\nfuzz_text_field,types_datetime_25_6,0c05303030302d30302d30302031303a32303a33302e3030303030\r\nfuzz_text_field,types_datetime_25_7,0c06303030302d30302d30302031303a32303a33302e303030303030\r\nfuzz_text_field,types_datetime_26_0,0f00686d7375\r\nfuzz_text_field,types_datetime_27_0,0f00686d73755f79726567756c61725f696e76616c69645f64617465\r\nfuzz_text_field,types_datetime_27_1,0c00323032302d31312d33312031303a32303a3330\r\nfuzz_text_field,types_datetime_27_2,0c01323032302d31312d33312031303a32303a33302e39\r\nfuzz_text_field,types_datetime_27_3,0c02323032302d31312d33312031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_27_4,0c03323032302d31312d33312031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_27_5,0c04323032302d31312d33312031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_27_6,0c05323032302d31312d33312031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_27_7,0c06323032302d31312d33312031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_28_0,0f00686d73755f79726567756c61725f696e76616c69645f646174655f6c656170313030\r\nfuzz_text_field,types_datetime_28_1,0c00313930302d30322d32392031303a32303a3330\r\nfuzz_text_field,types_datetime_28_2,0c01313930302d30322d32392031303a32303a33302e39\r\nfuzz_text_field,types_datetime_28_3,0c02313930302d30322d32392031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_28_4,0c03313930302d30322d32392031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_28_5,0c04313930302d30322d32392031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_28_6,0c05313930302d30322d32392031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_28_7,0c06313930302d30322d32392031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_29_0,0f00686d73755f79726567756c61725f696e76616c69645f646174655f6c656170726567756c6172\r\nfuzz_text_field,types_datetime_29_1,0c00313939392d30322d32392031303a32303a3330\r\nfuzz_text_field,types_datetime_29_2,0c01313939392d30322d32392031303a32303a33302e39\r\nfuzz_text_field,types_datetime_29_3,0c02313939392d30322d32392031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_29_4,0c03313939392d30322d32392031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_29_5,0c04313939392d30322d32392031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_29_6,0c05313939392d30322d32392031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_29_7,0c06313939392d30322d32392031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_30_0,0f00686d73755f79726567756c61725f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_datetime_30_1,0c00323032302d31302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_30_2,0c01323032302d31302d30302031303a32303a33302e39\r\nfuzz_text_field,types_datetime_30_3,0c02323032302d31302d30302031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_30_4,0c03323032302d31302d30302031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_30_5,0c04323032302d31302d30302031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_30_6,0c05323032302d31302d30302031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_30_7,0c06323032302d31302d30302031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_31_0,0f00686d73755f79726567756c61725f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_datetime_31_1,0c00323032302d30302d31302031303a32303a3330\r\nfuzz_text_field,types_datetime_31_2,0c01323032302d30302d31302031303a32303a33302e39\r\nfuzz_text_field,types_datetime_31_3,0c02323032302d30302d31302031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_31_4,0c03323032302d30302d31302031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_31_5,0c04323032302d30302d31302031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_31_6,0c05323032302d30302d31302031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_31_7,0c06323032302d30302d31302031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_32_0,0f00686d73755f79726567756c61725f6d7a65726f5f647a65726f\r\nfuzz_text_field,types_datetime_32_1,0c00323032302d30302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_32_2,0c01323032302d30302d30302031303a32303a33302e39\r\nfuzz_text_field,types_datetime_32_3,0c02323032302d30302d30302031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_32_4,0c03323032302d30302d30302031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_32_5,0c04323032302d30302d30302031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_32_6,0c05323032302d30302d30302031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_32_7,0c06323032302d30302d30302031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_33_0,0f00686d73755f797a65726f5f696e76616c69645f64617465\r\nfuzz_text_field,types_datetime_33_1,0c00303030302d31312d33312031303a32303a3330\r\nfuzz_text_field,types_datetime_33_2,0c01303030302d31312d33312031303a32303a33302e39\r\nfuzz_text_field,types_datetime_33_3,0c02303030302d31312d33312031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_33_4,0c03303030302d31312d33312031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_33_5,0c04303030302d31312d33312031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_33_6,0c05303030302d31312d33312031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_33_7,0c06303030302d31312d33312031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_34_0,0f00686d73755f797a65726f5f6d726567756c61725f647a65726f\r\nfuzz_text_field,types_datetime_34_1,0c00303030302d31302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_34_2,0c01303030302d31302d30302031303a32303a33302e39\r\nfuzz_text_field,types_datetime_34_3,0c02303030302d31302d30302031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_34_4,0c03303030302d31302d30302031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_34_5,0c04303030302d31302d30302031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_34_6,0c05303030302d31302d30302031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_34_7,0c06303030302d31302d30302031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_35_0,0f00686d73755f797a65726f5f6d7a65726f5f64726567756c6172\r\nfuzz_text_field,types_datetime_35_1,0c00303030302d30302d31302031303a32303a3330\r\nfuzz_text_field,types_datetime_35_2,0c01303030302d30302d31302031303a32303a33302e39\r\nfuzz_text_field,types_datetime_35_3,0c02303030302d30302d31302031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_35_4,0c03303030302d30302d31302031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_35_5,0c04303030302d30302d31302031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_35_6,0c05303030302d30302d31302031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_35_7,0c06303030302d30302d31302031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_36_0,0f00686d73755f7a65726f\r\nfuzz_text_field,types_datetime_36_1,0c00303030302d30302d30302031303a32303a3330\r\nfuzz_text_field,types_datetime_36_2,0c01303030302d30302d30302031303a32303a33302e39\r\nfuzz_text_field,types_datetime_36_3,0c02303030302d30302d30302031303a32303a33302e3939\r\nfuzz_text_field,types_datetime_36_4,0c03303030302d30302d30302031303a32303a33302e393939\r\nfuzz_text_field,types_datetime_36_5,0c04303030302d30302d30302031303a32303a33302e39393939\r\nfuzz_text_field,types_datetime_36_6,0c05303030302d30302d30302031303a32303a33302e3939393939\r\nfuzz_text_field,types_datetime_36_7,0c06303030302d30302d30302031303a32303a33302e393939393939\r\nfuzz_text_field,types_datetime_37_0,0f00686d75\r\nfuzz_text_field,types_datetime_38_0,0f006873\r\nfuzz_text_field,types_datetime_38_1,0c00323031302d30352d30322032333a30303a3530\r\nfuzz_text_field,types_datetime_38_2,0c01323031302d30352d30322032333a30303a35302e30\r\nfuzz_text_field,types_datetime_38_3,0c02323031302d30352d30322032333a30303a35302e3030\r\nfuzz_text_field,types_datetime_38_4,0c03323031302d30352d30322032333a30303a35302e303030\r\nfuzz_text_field,types_datetime_38_5,0c04323031302d30352d30322032333a30303a35302e30303030\r\nfuzz_text_field,types_datetime_38_6,0c05323031302d30352d30322032333a30303a35302e3030303030\r\nfuzz_text_field,types_datetime_38_7,0c06323031302d30352d30322032333a30303a35302e303030303030\r\nfuzz_text_field,types_datetime_39_0,0f00687375\r\nfuzz_text_field,types_datetime_40_0,0f006875\r\nfuzz_text_field,types_datetime_41_0,0f006d\r\nfuzz_text_field,types_datetime_41_1,0c00323031302d30352d30322030303a30313a3030\r\nfuzz_text_field,types_datetime_41_2,0c01323031302d30352d30322030303a30313a30302e30\r\nfuzz_text_field,types_datetime_41_3,0c02323031302d30352d30322030303a30313a30302e3030\r\nfuzz_text_field,types_datetime_41_4,0c03323031302d30352d30322030303a30313a30302e303030\r\nfuzz_text_field,types_datetime_41_5,0c04323031302d30352d30322030303a30313a30302e30303030\r\nfuzz_text_field,types_datetime_41_6,0c05323031302d30352d30322030303a30313a30302e3030303030\r\nfuzz_text_field,types_datetime_41_7,0c06323031302d30352d30322030303a30313a30302e303030303030\r\nfuzz_text_field,types_datetime_42_0,0f006d6178\r\nfuzz_text_field,types_datetime_42_1,0c00393939392d31322d33312032333a35393a3539\r\nfuzz_text_field,types_datetime_42_2,0c01393939392d31322d33312032333a35393a35392e39\r\nfuzz_text_field,types_datetime_42_3,0c02393939392d31322d33312032333a35393a35392e3939\r\nfuzz_text_field,types_datetime_42_4,0c03393939392d31322d33312032333a35393a35392e393939\r\nfuzz_text_field,types_datetime_42_5,0c04393939392d31322d33312032333a35393a35392e39393939\r\nfuzz_text_field,types_datetime_42_6,0c05393939392d31322d33312032333a35393a35392e3939393939\r\nfuzz_text_field,types_datetime_42_7,0c06393939392d31322d33312032333a35393a35392e393939393939\r\nfuzz_text_field,types_datetime_43_0,0f006d696e\r\nfuzz_text_field,types_datetime_43_1,0c00303030302d30312d30312030303a30303a3030\r\nfuzz_text_field,types_datetime_43_2,0c01303030302d30312d30312030303a30303a30302e30\r\nfuzz_text_field,types_datetime_43_3,0c02303030302d30312d30312030303a30303a30302e3030\r\nfuzz_text_field,types_datetime_43_4,0c03303030302d30312d30312030303a30303a30302e303030\r\nfuzz_text_field,types_datetime_43_5,0c04303030302d30312d30312030303a30303a30302e30303030\r\nfuzz_text_field,types_datetime_43_6,0c05303030302d30312d30312030303a30303a30302e3030303030\r\nfuzz_text_field,types_datetime_43_7,0c06303030302d30312d30312030303a30303a30302e303030303030\r\nfuzz_text_field,types_datetime_44_0,0f006d73\r\nfuzz_text_field,types_datetime_44_1,0c00323031302d30352d30322030303a30313a3530\r\nfuzz_text_field,types_datetime_44_2,0c01323031302d30352d30322030303a30313a35302e30\r\nfuzz_text_field,types_datetime_44_3,0c02323031302d30352d30322030303a30313a35302e3030\r\nfuzz_text_field,types_datetime_44_4,0c03323031302d30352d30322030303a30313a35302e303030\r\nfuzz_text_field,types_datetime_44_5,0c04323031302d30352d30322030303a30313a35302e30303030\r\nfuzz_text_field,types_datetime_44_6,0c05323031302d30352d30322030303a30313a35302e3030303030\r\nfuzz_text_field,types_datetime_44_7,0c06323031302d30352d30322030303a30313a35302e303030303030\r\nfuzz_text_field,types_datetime_45_0,0f006d7375\r\nfuzz_text_field,types_datetime_46_0,0f006d75\r\nfuzz_text_field,types_datetime_47_0,0f0073\r\nfuzz_text_field,types_datetime_47_1,0c00323031302d30352d30322030303a30303a3530\r\nfuzz_text_field,types_datetime_47_2,0c01323031302d30352d30322030303a30303a35302e30\r\nfuzz_text_field,types_datetime_47_3,0c02323031302d30352d30322030303a30303a35302e3030\r\nfuzz_text_field,types_datetime_47_4,0c03323031302d30352d30322030303a30303a35302e303030\r\nfuzz_text_field,types_datetime_47_5,0c04323031302d30352d30322030303a30303a35302e30303030\r\nfuzz_text_field,types_datetime_47_6,0c05323031302d30352d30322030303a30303a35302e3030303030\r\nfuzz_text_field,types_datetime_47_7,0c06323031302d30352d30322030303a30303a35302e303030303030\r\nfuzz_text_field,types_datetime_48_0,0f007375\r\nfuzz_text_field,types_datetime_49_0,0f0075\r\nfuzz_row,text_types_double_0,050f00061f861f060a861f136672616374696f6e616c5f6e65676174697665042d342e32fb0d2d342e32303030303030303030fb\r\nfuzz_row,text_types_double_1,050f00061f861f060a861f136672616374696f6e616c5f706f73697469766503342e3203342e320c342e323030303030303030301630303030303030303030303030303030303030342e32\r\nfuzz_row,text_types_double_2,050f00061f861f060a861f0c696e745f6e65676174697665022d34fbfbfb\r\nfuzz_row,text_types_double_3,050f00061f861f060a861f0c696e745f706f7369746976650134fbfbfb\r\nfuzz_row,text_types_double_4,050f00061f861f060a861f206e656761746976655f6578705f706f7369746976655f6672616374696f6e616c09332e3134652d323030fbfb1630303030303030303030303030332e3134652d323030\r\nfuzz_row,text_types_double_5,050f00061f861f060a861f20706f7369746976655f6578705f6e656761746976655f6672616374696f6e616c092d332e313465323030fbfbfb\r\nfuzz_row,text_types_double_6,050f00061f861f060a861f19706f7369746976655f6578705f6e656761746976655f696e74062d3365323030fbfbfb\r\nfuzz_row,text_types_double_7,050f00061f861f060a861f20706f7369746976655f6578705f706f7369746976655f6672616374696f6e616c08332e313465323030fbfb163030303030303030303030303030332e313465323030\r\nfuzz_row,text_types_double_8,050f00061f861f060a861f19706f7369746976655f6578705f706f7369746976655f696e74053365323030fbfbfb\r\nfuzz_row,text_types_double_9,050f00061f861f060a861f047a65726f013001300c302e303030303030303030301630303030303030303030303030303030303030303030\r\nfuzz_text_field,types_double_0_0,0f006672616374696f6e616c5f6e65676174697665\r\nfuzz_text_field,types_double_0_1,061f2d342e32\r\nfuzz_text_field,types_double_1_0,0f006672616374696f6e616c5f706f736974697665\r\nfuzz_text_field,types_double_1_1,061f342e32\r\nfuzz_text_field,types_double_1_2,861f342e32\r\nfuzz_text_field,types_double_1_3,060a342e32303030303030303030\r\nfuzz_text_field,types_double_1_4,861f30303030303030303030303030303030303030342e32\r\nfuzz_text_field,types_double_2_0,0f00696e745f6e65676174697665\r\nfuzz_text_field,types_double_2_1,061f2d34\r\nfuzz_text_field,types_double_3_0,0f00696e745f706f736974697665\r\nfuzz_text_field,types_double_3_1,061f34\r\nfuzz_text_field,types_double_4_0,0f006e656761746976655f6578705f706f7369746976655f6672616374696f6e616c\r\nfuzz_text_field,types_double_4_1,061f332e3134652d323030\r\nfuzz_text_field,types_double_5_0,0f00706f7369746976655f6578705f6e656761746976655f6672616374696f6e616c\r\nfuzz_text_field,types_double_5_1,061f2d332e313465323030\r\nfuzz_text_field,types_double_6_0,0f00706f7369746976655f6578705f6e656761746976655f696e74\r\nfuzz_text_field,types_double_6_1,061f2d3365323030\r\nfuzz_text_field,types_double_7_0,0f00706f7369746976655f6578705f706f7369746976655f6672616374696f6e616c\r\nfuzz_text_field,types_double_7_1,061f332e313465323030\r\nfuzz_text_field,types_double_8_0,0f00706f7369746976655f6578705f706f7369746976655f696e74\r\nfuzz_text_field,types_double_8_1,061f3365323030\r\nfuzz_text_field,types_double_9_0,0f007a65726f\r\nfuzz_text_field,types_double_9_1,061f30\r\nfuzz_text_field,types_double_9_2,861f30\r\nfuzz_text_field,types_double_9_3,060a302e30303030303030303030\r\nfuzz_text_field,types_double_9_4,861f30303030303030303030303030303030303030303030\r\nfuzz_row,text_types_flags_0,060f000d0003000e00030003000764656661756c74fb0235300463686172023231023432\r\nfuzz_text_field,types_flags_0_0,0f0064656661756c74\r\nfuzz_row,text_types_float_0,050f00051f851f050a851f136672616374696f6e616c5f6e65676174697665042d342e32fb0d2d342e31393939393938303933fb\r\nfuzz_row,text_types_float_1,050f00051f851f050a851f136672616374696f6e616c5f706f73697469766503342e3203342e320c342e313939393939383039330c303030303030303030342e32\r\nfuzz_row,text_types_float_2,050f00051f851f050a851f0c696e745f6e65676174697665022d34fbfbfb\r\nfuzz_row,text_types_float_3,050f00051f851f050a851f0c696e745f706f7369746976650134fbfbfb\r\nfuzz_row,text_types_float_4,050f00051f851f050a851f206e656761746976655f6578705f706f7369746976655f6672616374696f6e616c08332e3134652d3230fbfb0c30303030332e3134652d3230\r\nfuzz_row,text_types_float_5,050f00051f851f050a851f20706f7369746976655f6578705f6e656761746976655f6672616374696f6e616c082d332e3134653230fbfbfb\r\nfuzz_row,text_types_float_6,050f00051f851f050a851f19706f7369746976655f6578705f6e656761746976655f696e74052d33653230fbfbfb\r\nfuzz_row,text_types_float_7,050f00051f851f050a851f20706f7369746976655f6578705f706f7369746976655f6672616374696f6e616c07332e3134653230fbfb0c3030303030332e3134653230\r\nfuzz_row,text_types_float_8,050f00051f851f050a851f19706f7369746976655f6578705f706f7369746976655f696e740433653230fbfbfb\r\nfuzz_row,text_types_float_9,050f00051f851f050a851f047a65726f013001300c302e303030303030303030300c303030303030303030303030\r\nfuzz_text_field,types_float_0_0,0f006672616374696f6e616c5f6e65676174697665\r\nfuzz_text_field,types_float_0_1,051f2d342e32\r\nfuzz_text_field,types_float_1_0,0f006672616374696f6e616c5f706f736974697665\r\nfuzz_text_field,types_float_1_1,051f342e32\r\nfuzz_text_field,types_float_1_2,851f342e32\r\nfuzz_text_field,types_float_1_3,050a342e31393939393938303933\r\nfuzz_text_field,types_float_1_4,851f303030303030303030342e32\r\nfuzz_text_field,types_float_2_0,0f00696e745f6e65676174697665\r\nfuzz_text_field,types_float_2_1,051f2d34\r\nfuzz_text_field,types_float_3_0,0f00696e745f706f736974697665\r\nfuzz_text_field,types_float_3_1,051f34\r\nfuzz_text_field,types_float_4_0,0f006e656761746976655f6578705f706f7369746976655f6672616374696f6e616c\r\nfuzz_text_field,types_float_4_1,051f332e3134652d3230\r\nfuzz_text_field,types_float_5_0,0f00706f7369746976655f6578705f6e656761746976655f6672616374696f6e616c\r\nfuzz_text_field,types_float_5_1,051f2d332e3134653230\r\nfuzz_text_field,types_float_6_0,0f00706f7369746976655f6578705f6e656761746976655f696e74\r\nfuzz_text_field,types_float_6_1,051f2d33653230\r\nfuzz_text_field,types_float_7_0,0f00706f7369746976655f6578705f706f7369746976655f6672616374696f6e616c\r\nfuzz_text_field,types_float_7_1,051f332e3134653230\r\nfuzz_text_field,types_float_8_0,0f00706f7369746976655f6578705f706f7369746976655f696e74\r\nfuzz_text_field,types_float_8_1,051f33653230\r\nfuzz_text_field,types_float_9_0,0f007a65726f\r\nfuzz_text_field,types_float_9_1,051f30\r\nfuzz_text_field,types_float_9_2,851f30\r\nfuzz_text_field,types_float_9_3,050a302e30303030303030303030\r\nfuzz_text_field,types_float_9_4,851f303030303030303030303030\r\nfuzz_row,text_types_int_0,050f000300830003008300036d61780a323134373438333634370a34323934393637323935fbfb\r\nfuzz_row,text_types_int_1,050f000300830003008300036d696e0b2d323134373438333634380130fb0730303030303030\r\nfuzz_row,text_types_int_2,050f000300830003008300086e65676174697665032d3230fb032d3230fb\r\nfuzz_row,text_types_int_3,050f00030083000300830007726567756c61720232300232300232300730303030303230\r\nfuzz_text_field,types_int_0_0,0f006d6178\r\nfuzz_text_field,types_int_0_1,030032313437343833363437\r\nfuzz_text_field,types_int_0_2,830034323934393637323935\r\nfuzz_text_field,types_int_1_0,0f006d696e\r\nfuzz_text_field,types_int_1_1,03002d32313437343833363438\r\nfuzz_text_field,types_int_1_2,830030\r\nfuzz_text_field,types_int_2_0,0f006e65676174697665\r\nfuzz_text_field,types_int_2_1,03002d3230\r\nfuzz_text_field,types_int_3_0,0f00726567756c6172\r\nfuzz_text_field,types_int_3_1,03003230\r\nfuzz_text_field,types_int_3_2,83003230\r\nfuzz_text_field,types_int_3_3,03003230\r\nfuzz_text_field,types_int_3_4,830030303030303230\r\nfuzz_row,text_types_json_0,020f00160005656d707479027b7d\r\nfuzz_row,text_types_json_1,020f00160007726567756c61722a5b6e756c6c2c2034322c2066616c73652c2022616263222c207b226b6579223a202276616c7565227d5d\r\nfuzz_row,text_types_json_2,020f0016000e756e69636f64655f657363617065155b225c753030303076616c75655c7530303030225d\r\nfuzz_row,text_types_json_3,020f00160004757466380a5b22616469c3b373225d\r\nfuzz_text_field,types_json_0_0,0f00656d707479\r\nfuzz_text_field,types_json_0_1,16007b7d\r\nfuzz_text_field,types_json_1_0,0f00726567756c6172\r\nfuzz_text_field,types_json_1_1,16005b6e756c6c2c2034322c2066616c73652c2022616263222c207b226b6579223a202276616c7565227d5d\r\nfuzz_text_field,types_json_2_0,0f00756e69636f64655f657363617065\r\nfuzz_text_field,types_json_2_1,16005b225c753030303076616c75655c7530303030225d\r\nfuzz_text_field,types_json_3_0,0f0075746638\r\nfuzz_text_field,types_json_3_1,16005b22616469c3b373225d\r\nfuzz_row,text_types_mediumint_0,050f000200820002008200036d61780738333838363037083136373737323135fbfb\r\nfuzz_row,text_types_mediumint_1,050f000200820002008200036d696e082d383338383630380130fb0730303030303030\r\nfuzz_row,text_types_mediumint_2,050f000200820002008200086e65676174697665032d3230fb032d3230fb\r\nfuzz_row,text_types_mediumint_3,050f00020082000200820007726567756c61720232300232300232300730303030303230\r\nfuzz_text_field,types_mediumint_0_0,0f006d6178\r\nfuzz_text_field,types_mediumint_0_1,020038333838363037\r\nfuzz_text_field,types_mediumint_0_2,82003136373737323135\r\nfuzz_text_field,types_mediumint_1_0,0f006d696e\r\nfuzz_text_field,types_mediumint_1_1,02002d38333838363038\r\nfuzz_text_field,types_mediumint_1_2,820030\r\nfuzz_text_field,types_mediumint_2_0,0f006e65676174697665\r\nfuzz_text_field,types_mediumint_2_1,02002d3230\r\nfuzz_text_field,types_mediumint_3_0,0f00726567756c6172\r\nfuzz_text_field,types_mediumint_3_1,02003230\r\nfuzz_text_field,types_mediumint_3_2,82003230\r\nfuzz_text_field,types_mediumint_3_3,02003230\r\nfuzz_text_field,types_mediumint_3_4,820030303030303230\r\nfuzz_row,text_types_not_implemented_0,030f000700170007726567756c61720333303019000000000101000000000000000000f03f0000000000000040\r\nfuzz_text_field,types_not_implemented_0_0,0f00726567756c6172\r\nfuzz_text_field,types_not_implemented_0_1,0700333030\r\nfuzz_text_field,types_not_implemented_0_2,1700000000000101000000000000000000f03f0000000000000040\r\nfuzz_row,text_types_smallint_0,050f000100810001008100036d6178053332373637053635353335fbfb\r\nfuzz_row,text_types_smallint_1,050f000100810001008100036d696e062d33323736380130fb0730303030303030\r\nfuzz_row,text_types_smallint_2,050f000100810001008100086e65676174697665032d3230fb032d3230fb\r\nfuzz_row,text_types_smallint_3,050f00010081000100810007726567756c61720232300232300232300730303030303230\r\nfuzz_text_field,types_smallint_0_0,0f006d6178\r\nfuzz_text_field,types_smallint_0_1,01003332373637\r\nfuzz_text_field,types_smallint_0_2,81003635353335\r\nfuzz_text_field,types_smallint_1_0,0f006d696e\r\nfuzz_text_field,types_smallint_1_1,01002d3332373638\r\nfuzz_text_field,types_smallint_1_2,810030\r\nfuzz_text_field,types_smallint_2_0,0f006e65676174697665\r\nfuzz_text_field,types_smallint_2_1,01002d3230\r\nfuzz_text_field,types_smallint_3_0,0f00726567756c6172\r\nfuzz_text_field,types_smallint_3_1,01003230\r\nfuzz_text_field,types_smallint_3_2,81003230\r\nfuzz_text_field,types_smallint_3_3,01003230\r\nfuzz_text_field,types_smallint_3_4,810030303030303230\r\nfuzz_row,text_types_string_0,0a0f000e000f00120012001200120012001400150005656d70747900000000000000fb00\r\nfuzz_row,text_types_string_1,0a0f000e000f00120012001200120012001400150007726567756c617209746573745f636861720c746573745f766172636861720d746573745f74696e797465787409746573745f746578740f746573745f6d656469756d746578740d746573745f6c6f6e67746578740b746573745f62696e636f6c03726564097265642c677265656e\r\nfuzz_row,text_types_string_2,0a0f000e000f001200120012001200120014001500047574663802c3b102c39102c3a102c3a902c3ad02c3b302c3bafbfb\r\nfuzz_text_field,types_string_0_0,0f00656d707479\r\nfuzz_text_field,types_string_0_1,0e00\r\nfuzz_text_field,types_string_0_2,0f00\r\nfuzz_text_field,types_string_0_3,1200\r\nfuzz_text_field,types_string_0_4,1200\r\nfuzz_text_field,types_string_0_5,1200\r\nfuzz_text_field,types_string_0_6,1200\r\nfuzz_text_field,types_string_0_7,1200\r\nfuzz_text_field,types_string_1_0,0f00726567756c6172\r\nfuzz_text_field,types_string_1_1,0e00746573745f63686172\r\nfuzz_text_field,types_string_1_2,0f00746573745f76617263686172\r\nfuzz_text_field,types_string_1_3,1200746573745f74696e7974657874\r\nfuzz_text_field,types_string_1_4,1200746573745f74657874\r\nfuzz_text_field,types_string_1_5,1200746573745f6d656469756d74657874\r\nfuzz_text_field,types_string_1_6,1200746573745f6c6f6e6774657874\r\nfuzz_text_field,types_string_1_7,1200746573745f62696e636f6c\r\nfuzz_text_field,types_string_1_8,1400726564\r\nfuzz_text_field,types_string_1_9,15007265642c677265656e\r\nfuzz_text_field,types_string_2_0,0f0075746638\r\nfuzz_text_field,types_string_2_1,0e00c3b1\r\nfuzz_text_field,types_string_2_2,0f00c391\r\nfuzz_text_field,types_string_2_3,1200c3a1\r\nfuzz_text_field,types_string_2_4,1200c3a9\r\nfuzz_text_field,types_string_2_5,1200c3ad\r\nfuzz_text_field,types_string_2_6,1200c3b3\r\nfuzz_text_field,types_string_2_7,1200c3ba\r\nfuzz_row,text_types_time_0,080f000a000a010a020a030a040a050a0601640834383a30303a30300a34383a30303a30302e300b34383a30303a30302e30300c34383a30303a30302e3030300d34383a30303a30302e303030300e34383a30303a30302e30303030300f34383a30303a30302e303030303030\r\nfuzz_row,text_types_time_1,080f000a000a010a020a030a040a050a060264680837313a30303a30300a37313a30303a30302e300b37313a30303a30302e30300c37313a30303a30302e3030300d37313a30303a30302e303030300e37313a30303a30302e30303030300f37313a30303a30302e303030303030\r\nfuzz_row,text_types_time_2,080f000a000a010a020a030a040a050a060364686d0837313a30313a30300a37313a30313a30302e300b37313a30313a30302e30300c37313a30313a30302e3030300d37313a30313a30302e303030300e37313a30313a30302e30303030300f37313a30313a30302e303030303030\r\nfuzz_row,text_types_time_3,080f000a000a010a020a030a040a050a060464686d730837313a30313a35300a37313a30313a35302e300b37313a30313a35302e30300c37313a30313a35302e3030300d37313a30313a35302e303030300e37313a30313a35302e30303030300f37313a30313a35302e303030303030\r\nfuzz_row,text_types_time_4,080f000a000a010a020a030a040a050a060564686d7375fb0a37313a30313a35302e310b37313a30313a35302e31320c37313a30313a35302e3132330d37313a30313a35302e313233340e37313a30313a35302e31323334350f37313a30313a35302e313233343536\r\nfuzz_row,text_types_time_5,080f000a000a010a020a030a040a050a060464686d75fb0a37313a30313a30302e310b37313a30313a30302e31320c37313a30313a30302e3132330d37313a30313a30302e313233340e37313a30313a30302e31323334350f37313a30313a30302e313233343536\r\nfuzz_row,text_types_time_6,080f000a000a010a020a030a040a050a06036468730837313a30303a35300a37313a30303a35302e300b37313a30303a35302e30300c37313a30303a35302e3030300d37313a30303a35302e303030300e37313a30303a35302e30303030300f37313a30303a35302e303030303030\r\nfuzz_row,text_types_time_7,080f000a000a010a020a030a040a050a060464687375fb0a37313a30303a35302e310b37313a30303a35302e31320c37313a30303a35302e3132330d37313a30303a35302e313233340e37313a30303a35302e31323334350f37313a30303a35302e313233343536\r\nfuzz_row,text_types_time_8,080f000a000a010a020a030a040a050a0603646875fb0a37313a30303a30302e310b37313a30303a30302e31320c37313a30303a30302e3132330d37313a30303a30302e313233340e37313a30303a30302e31323334350f37313a30303a30302e313233343536\r\nfuzz_row,text_types_time_9,080f000a000a010a020a030a040a050a0602646d0834383a30313a30300a34383a30313a30302e300b34383a30313a30302e30300c34383a30313a30302e3030300d34383a30313a30302e303030300e34383a30313a30302e30303030300f34383a30313a30302e303030303030\r\nfuzz_row,text_types_time_10,080f000a000a010a020a030a040a050a0603646d730834383a30313a35300a34383a30313a35302e300b34383a30313a35302e30300c34383a30313a35302e3030300d34383a30313a35302e303030300e34383a30313a35302e30303030300f34383a30313a35302e303030303030\r\nfuzz_row,text_types_time_11,080f000a000a010a020a030a040a050a0604646d7375fb0a34383a30313a35302e310b34383a30313a35302e31320c34383a30313a35302e3132330d34383a30313a35302e313233340e34383a30313a35302e31323334350f34383a30313a35302e313233343536\r\nfuzz_row,text_types_time_12,080f000a000a010a020a030a040a050a0603646d75fb0a34383a30313a30302e310b34383a30313a30302e31320c34383a30313a30302e3132330d34383a30313a30302e313233340e34383a30313a30302e31323334350f34383a30313a30302e313233343536\r\nfuzz_row,text_types_time_13,080f000a000a010a020a030a040a050a060264730834383a30303a35300a34383a30303a35302e300b34383a30303a35302e30300c34383a30303a35302e3030300d34383a30303a35302e303030300e34383a30303a35302e30303030300f34383a30303a35302e303030303030\r\nfuzz_row,text_types_time_14,080f000a000a010a020a030a040a050a0603647375fb0a34383a30303a35302e310b34383a30303a35302e31320c34383a30303a35302e3132330d34383a30303a35302e313233340e34383a30303a35302e31323334350f34383a30303a35302e313233343536\r\nfuzz_row,text_types_time_15,080f000a000a010a020a030a040a050a06026475fb0a34383a30303a30302e310b34383a30303a30302e31320c34383a30303a30302e3132330d34383a30303a30302e313233340e34383a30303a30302e31323334350f34383a30303a30302e313233343536\r\nfuzz_row,text_types_time_16,080f000a000a010a020a030a040a050a0601680832333a30303a30300a32333a30303a30302e300b32333a30303a30302e30300c32333a30303a30302e3030300d32333a30303a30302e303030300e32333a30303a30302e30303030300f32333a30303a30302e303030303030\r\nfuzz_row,text_types_time_17,080f000a000a010a020a030a040a050a0602686d0832333a30313a30300a32333a30313a30302e300b32333a30313a30302e30300c32333a30313a30302e3030300d32333a30313a30302e303030300e32333a30313a30302e30303030300f32333a30313a30302e303030303030\r\nfuzz_row,text_types_time_18,080f000a000a010a020a030a040a050a0603686d730832333a30313a35300a32333a30313a35302e300b32333a30313a35302e30300c32333a30313a35302e3030300d32333a30313a35302e303030300e32333a30313a35302e30303030300f32333a30313a35302e303030303030\r\nfuzz_row,text_types_time_19,080f000a000a010a020a030a040a050a0604686d7375fb0a32333a30313a35302e310b32333a30313a35302e31320c32333a30313a35302e3132330d32333a30313a35302e313233340e32333a30313a35302e31323334350f32333a30313a35302e313233343536\r\nfuzz_row,text_types_time_20,080f000a000a010a020a030a040a050a0603686d75fb0a32333a30313a30302e310b32333a30313a30302e31320c32333a30313a30302e3132330d32333a30313a30302e313233340e32333a30313a30302e31323334350f32333a30313a30302e313233343536\r\nfuzz_row,text_types_time_21,080f000a000a010a020a030a040a050a060268730832333a30303a35300a32333a30303a35302e300b32333a30303a35302e30300c32333a30303a35302e3030300d32333a30303a35302e303030300e32333a30303a35302e30303030300f32333a30303a35302e303030303030\r\nfuzz_row,text_types_time_22,080f000a000a010a020a030a040a050a0603687375fb0a32333a30303a35302e310b32333a30303a35302e31320c32333a30303a35302e3132330d32333a30303a35302e313233340e32333a30303a35302e31323334350f32333a30303a35302e313233343536\r\nfuzz_row,text_types_time_23,080f000a000a010a020a030a040a050a06026875fb0a32333a30303a30302e310b32333a30303a30302e31320c32333a30303a30302e3132330d32333a30303a30302e313233340e32333a30303a30302e31323334350f32333a30303a30302e313233343536\r\nfuzz_row,text_types_time_24,080f000a000a010a020a030a040a050a06016d0830303a30313a30300a30303a30313a30302e300b30303a30313a30302e30300c30303a30313a30302e3030300d30303a30313a30302e303030300e30303a30313a30302e30303030300f30303a30313a30302e303030303030\r\nfuzz_row,text_types_time_25,080f000a000a010a020a030a040a050a06036d6178093833383a35393a35390b3833383a35393a35382e390c3833383a35393a35382e39390d3833383a35393a35382e3939390e3833383a35393a35382e393939390f3833383a35393a35382e3939393939103833383a35393a35382e393939393939\r\nfuzz_row,text_types_time_26,080f000a000a010a020a030a040a050a06036d696e0a2d3833383a35393a35390c2d3833383a35393a35382e390d2d3833383a35393a35382e39390e2d3833383a35393a35382e3939390f2d3833383a35393a35382e39393939102d3833383a35393a35382e3939393939112d3833383a35393a35382e393939393939\r\nfuzz_row,text_types_time_27,080f000a000a010a020a030a040a050a06026d730830303a30313a35300a30303a30313a35302e300b30303a30313a35302e30300c30303a30313a35302e3030300d30303a30313a35302e303030300e30303a30313a35302e30303030300f30303a30313a35302e303030303030\r\nfuzz_row,text_types_time_28,080f000a000a010a020a030a040a050a06036d7375fb0a30303a30313a35302e310b30303a30313a35302e31320c30303a30313a35302e3132330d30303a30313a35302e313233340e30303a30313a35302e31323334350f30303a30313a35302e313233343536\r\nfuzz_row,text_types_time_29,080f000a000a010a020a030a040a050a06026d75fb0a30303a30313a30302e310b30303a30313a30302e31320c30303a30313a30302e3132330d30303a30313a30302e313233340e30303a30313a30302e31323334350f30303a30313a30302e313233343536\r\nfuzz_row,text_types_time_30,080f000a000a010a020a030a040a050a060a6e656761746976655f64092d34383a30303a30300b2d34383a30303a30302e300c2d34383a30303a30302e30300d2d34383a30303a30302e3030300e2d34383a30303a30302e303030300f2d34383a30303a30302e3030303030102d34383a30303a30302e303030303030\r\nfuzz_row,text_types_time_31,080f000a000a010a020a030a040a050a060b6e656761746976655f6468092d37313a30303a30300b2d37313a30303a30302e300c2d37313a30303a30302e30300d2d37313a30303a30302e3030300e2d37313a30303a30302e303030300f2d37313a30303a30302e3030303030102d37313a30303a30302e303030303030\r\nfuzz_row,text_types_time_32,080f000a000a010a020a030a040a050a060c6e656761746976655f64686d092d37313a30313a30300b2d37313a30313a30302e300c2d37313a30313a30302e30300d2d37313a30313a30302e3030300e2d37313a30313a30302e303030300f2d37313a30313a30302e3030303030102d37313a30313a30302e303030303030\r\nfuzz_row,text_types_time_33,080f000a000a010a020a030a040a050a060d6e656761746976655f64686d73092d37313a30313a35300b2d37313a30313a35302e300c2d37313a30313a35302e30300d2d37313a30313a35302e3030300e2d37313a30313a35302e303030300f2d37313a30313a35302e3030303030102d37313a30313a35302e303030303030\r\nfuzz_row,text_types_time_34,080f000a000a010a020a030a040a050a060e6e656761746976655f64686d7375fb0b2d37313a30313a35302e310c2d37313a30313a35302e31320d2d37313a30313a35302e3132330e2d37313a30313a35302e313233340f2d37313a30313a35302e3132333435102d37313a30313a35302e313233343536\r\nfuzz_row,text_types_time_35,080f000a000a010a020a030a040a050a060d6e656761746976655f64686d75fb0b2d37313a30313a30302e310c2d37313a30313a30302e31320d2d37313a30313a30302e3132330e2d37313a30313a30302e313233340f2d37313a30313a30302e3132333435102d37313a30313a30302e313233343536\r\nfuzz_row,text_types_time_36,080f000a000a010a020a030a040a050a060c6e656761746976655f646873092d37313a30303a35300b2d37313a30303a35302e300c2d37313a30303a35302e30300d2d37313a30303a35302e3030300e2d37313a30303a35302e303030300f2d37313a30303a35302e3030303030102d37313a30303a35302e303030303030\r\nfuzz_row,text_types_time_37,080f000a000a010a020a030a040a050a060d6e656761746976655f64687375fb0b2d37313a30303a35302e310c2d37313a30303a35302e31320d2d37313a30303a35302e3132330e2d37313a30303a35302e313233340f2d37313a30303a35302e3132333435102d37313a30303a35302e313233343536\r\nfuzz_row,text_types_time_38,080f000a000a010a020a030a040a050a060c6e656761746976655f646875fb0b2d37313a30303a30302e310c2d37313a30303a30302e31320d2d37313a30303a30302e3132330e2d37313a30303a30302e313233340f2d37313a30303a30302e3132333435102d37313a30303a30302e313233343536\r\nfuzz_row,text_types_time_39,080f000a000a010a020a030a040a050a060b6e656761746976655f646d092d34383a30313a30300b2d34383a30313a30302e300c2d34383a30313a30302e30300d2d34383a30313a30302e3030300e2d34383a30313a30302e303030300f2d34383a30313a30302e3030303030102d34383a30313a30302e303030303030\r\nfuzz_row,text_types_time_40,080f000a000a010a020a030a040a050a060c6e656761746976655f646d73092d34383a30313a35300b2d34383a30313a35302e300c2d34383a30313a35302e30300d2d34383a30313a35302e3030300e2d34383a30313a35302e303030300f2d34383a30313a35302e3030303030102d34383a30313a35302e303030303030\r\nfuzz_row,text_types_time_41,080f000a000a010a020a030a040a050a060d6e656761746976655f646d7375fb0b2d34383a30313a35302e310c2d34383a30313a35302e31320d2d34383a30313a35302e3132330e2d34383a30313a35302e313233340f2d34383a30313a35302e3132333435102d34383a30313a35302e313233343536\r\nfuzz_row,text_types_time_42,080f000a000a010a020a030a040a050a060c6e656761746976655f646d75fb0b2d34383a30313a30302e310c2d34383a30313a30302e31320d2d34383a30313a30302e3132330e2d34383a30313a30302e313233340f2d34383a30313a30302e3132333435102d34383a30313a30302e313233343536\r\nfuzz_row,text_types_time_43,080f000a000a010a020a030a040a050a060b6e656761746976655f6473092d34383a30303a35300b2d34383a30303a35302e300c2d34383a30303a35302e30300d2d34383a30303a35302e3030300e2d34383a30303a35302e303030300f2d34383a30303a35302e3030303030102d34383a30303a35302e303030303030\r\nfuzz_row,text_types_time_44,080f000a000a010a020a030a040a050a060c6e656761746976655f647375fb0b2d34383a30303a35302e310c2d34383a30303a35302e31320d2d34383a30303a35302e3132330e2d34383a30303a35302e313233340f2d34383a30303a35302e3132333435102d34383a30303a35302e313233343536\r\nfuzz_row,text_types_time_45,080f000a000a010a020a030a040a050a060b6e656761746976655f6475fb0b2d34383a30303a30302e310c2d34383a30303a30302e31320d2d34383a30303a30302e3132330e2d34383a30303a30302e313233340f2d34383a30303a30302e3132333435102d34383a30303a30302e313233343536\r\nfuzz_row,text_types_time_46,080f000a000a010a020a030a040a050a060a6e656761746976655f68092d32333a30303a30300b2d32333a30303a30302e300c2d32333a30303a30302e30300d2d32333a30303a30302e3030300e2d32333a30303a30302e303030300f2d32333a30303a30302e3030303030102d32333a30303a30302e303030303030\r\nfuzz_row,text_types_time_47,080f000a000a010a020a030a040a050a060b6e656761746976655f686d092d32333a30313a30300b2d32333a30313a30302e300c2d32333a30313a30302e30300d2d32333a30313a30302e3030300e2d32333a30313a30302e303030300f2d32333a30313a30302e3030303030102d32333a30313a30302e303030303030\r\nfuzz_row,text_types_time_48,080f000a000a010a020a030a040a050a060c6e656761746976655f686d73092d32333a30313a35300b2d32333a30313a35302e300c2d32333a30313a35302e30300d2d32333a30313a35302e3030300e2d32333a30313a35302e303030300f2d32333a30313a35302e3030303030102d32333a30313a35302e303030303030\r\nfuzz_row,text_types_time_49,080f000a000a010a020a030a040a050a060d6e656761746976655f686d7375fb0b2d32333a30313a35302e310c2d32333a30313a35302e31320d2d32333a30313a35302e3132330e2d32333a30313a35302e313233340f2d32333a30313a35302e3132333435102d32333a30313a35302e313233343536\r\nfuzz_row,text_types_time_50,080f000a000a010a020a030a040a050a060c6e656761746976655f686d75fb0b2d32333a30313a30302e310c2d32333a30313a30302e31320d2d32333a30313a30302e3132330e2d32333a30313a30302e313233340f2d32333a30313a30302e3132333435102d32333a30313a30302e313233343536\r\nfuzz_row,text_types_time_51,080f000a000a010a020a030a040a050a060b6e656761746976655f6873092d32333a30303a35300b2d32333a30303a35302e300c2d32333a30303a35302e30300d2d32333a30303a35302e3030300e2d32333a30303a35302e303030300f2d32333a30303a35302e3030303030102d32333a30303a35302e303030303030\r\nfuzz_row,text_types_time_52,080f000a000a010a020a030a040a050a060c6e656761746976655f687375fb0b2d32333a30303a35302e310c2d32333a30303a35302e31320d2d32333a30303a35302e3132330e2d32333a30303a35302e313233340f2d32333a30303a35302e3132333435102d32333a30303a35302e313233343536\r\nfuzz_row,text_types_time_53,080f000a000a010a020a030a040a050a060b6e656761746976655f6875fb0b2d32333a30303a30302e310c2d32333a30303a30302e31320d2d32333a30303a30302e3132330e2d32333a30303a30302e313233340f2d32333a30303a30302e3132333435102d32333a30303a30302e313233343536\r\nfuzz_row,text_types_time_54,080f000a000a010a020a030a040a050a060a6e656761746976655f6d092d30303a30313a30300b2d30303a30313a30302e300c2d30303a30313a30302e30300d2d30303a30313a30302e3030300e2d30303a30313a30302e303030300f2d30303a30313a30302e3030303030102d30303a30313a30302e303030303030\r\nfuzz_row,text_types_time_55,080f000a000a010a020a030a040a050a060b6e656761746976655f6d73092d30303a30313a35300b2d30303a30313a35302e300c2d30303a30313a35302e30300d2d30303a30313a35302e3030300e2d30303a30313a35302e303030300f2d30303a30313a35302e3030303030102d30303a30313a35302e303030303030\r\nfuzz_row,text_types_time_56,080f000a000a010a020a030a040a050a060c6e656761746976655f6d7375fb0b2d30303a30313a35302e310c2d30303a30313a35302e31320d2d30303a30313a35302e3132330e2d30303a30313a35302e313233340f2d30303a30313a35302e3132333435102d30303a30313a35302e313233343536\r\nfuzz_row,text_types_time_57,080f000a000a010a020a030a040a050a060b6e656761746976655f6d75fb0b2d30303a30313a30302e310c2d30303a30313a30302e31320d2d30303a30313a30302e3132330e2d30303a30313a30302e313233340f2d30303a30313a30302e3132333435102d30303a30313a30302e313233343536\r\nfuzz_row,text_types_time_58,080f000a000a010a020a030a040a050a060a6e656761746976655f73092d30303a30303a35300b2d30303a30303a35302e300c2d30303a30303a35302e30300d2d30303a30303a35302e3030300e2d30303a30303a35302e303030300f2d30303a30303a35302e3030303030102d30303a30303a35302e303030303030\r\nfuzz_row,text_types_time_59,080f000a000a010a020a030a040a050a060b6e656761746976655f7375fb0b2d30303a30303a35302e310c2d30303a30303a35302e31320d2d30303a30303a35302e3132330e2d30303a30303a35302e313233340f2d30303a30303a35302e3132333435102d30303a30303a35302e313233343536\r\nfuzz_row,text_types_time_60,080f000a000a010a020a030a040a050a060a6e656761746976655f75fb0b2d30303a30303a30302e310c2d30303a30303a30302e31320d2d30303a30303a30302e3132330e2d30303a30303a30302e313233340f2d30303a30303a30302e3132333435102d30303a30303a30302e313233343536\r\nfuzz_row,text_types_time_61,080f000a000a010a020a030a040a050a0601730830303a30303a35300a30303a30303a35302e300b30303a30303a35302e30300c30303a30303a35302e3030300d30303a30303a35302e303030300e30303a30303a35302e30303030300f30303a30303a35302e303030303030\r\nfuzz_row,text_types_time_62,080f000a000a010a020a030a040a050a06027375fb0a30303a30303a35302e310b30303a30303a35302e31320c30303a30303a35302e3132330d30303a30303a35302e313233340e30303a30303a35302e31323334350f30303a30303a35302e313233343536\r\nfuzz_row,text_types_time_63,080f000a000a010a020a030a040a050a060175fb0a30303a30303a30302e310b30303a30303a30302e31320c30303a30303a30302e3132330d30303a30303a30302e313233340e30303a30303a30302e31323334350f30303a30303a30302e313233343536\r\nfuzz_row,text_types_time_64,080f000a000a010a020a030a040a050a06047a65726f0830303a30303a30300a30303a30303a30302e300b30303a30303a30302e30300c30303a30303a30302e3030300d30303a30303a30302e303030300e30303a30303a30302e30303030300f30303a30303a30302e303030303030\r\nfuzz_text_field,types_time_0_0,0f0064\r\nfuzz_text_field,types_time_0_1,0a0034383a30303a3030\r\nfuzz_text_field,types_time_0_2,0a0134383a30303a30302e30\r\nfuzz_text_field,types_time_0_3,0a0234383a30303a30302e3030\r\nfuzz_text_field,types_time_0_4,0a0334383a30303a30302e303030\r\nfuzz_text_field,types_time_0_5,0a0434383a30303a30302e30303030\r\nfuzz_text_field,types_time_0_6,0a0534383a30303a30302e3030303030\r\nfuzz_text_field,types_time_0_7,0a0634383a30303a30302e303030303030\r\nfuzz_text_field,types_time_1_0,0f006468\r\nfuzz_text_field,types_time_1_1,0a0037313a30303a3030\r\nfuzz_text_field,types_time_1_2,0a0137313a30303a30302e30\r\nfuzz_text_field,types_time_1_3,0a0237313a30303a30302e3030\r\nfuzz_text_field,types_time_1_4,0a0337313a30303a30302e303030\r\nfuzz_text_field,types_time_1_5,0a0437313a30303a30302e30303030\r\nfuzz_text_field,types_time_1_6,0a0537313a30303a30302e3030303030\r\nfuzz_text_field,types_time_1_7,0a0637313a30303a30302e303030303030\r\nfuzz_text_field,types_time_2_0,0f0064686d\r\nfuzz_text_field,types_time_2_1,0a0037313a30313a3030\r\nfuzz_text_field,types_time_2_2,0a0137313a30313a30302e30\r\nfuzz_text_field,types_time_2_3,0a0237313a30313a30302e3030\r\nfuzz_text_field,types_time_2_4,0a0337313a30313a30302e303030\r\nfuzz_text_field,types_time_2_5,0a0437313a30313a30302e30303030\r\nfuzz_text_field,types_time_2_6,0a0537313a30313a30302e3030303030\r\nfuzz_text_field,types_time_2_7,0a0637313a30313a30302e303030303030\r\nfuzz_text_field,types_time_3_0,0f0064686d73\r\nfuzz_text_field,types_time_3_1,0a0037313a30313a3530\r\nfuzz_text_field,types_time_3_2,0a0137313a30313a35302e30\r\nfuzz_text_field,types_time_3_3,0a0237313a30313a35302e3030\r\nfuzz_text_field,types_time_3_4,0a0337313a30313a35302e303030\r\nfuzz_text_field,types_time_3_5,0a0437313a30313a35302e30303030\r\nfuzz_text_field,types_time_3_6,0a0537313a30313a35302e3030303030\r\nfuzz_text_field,types_time_3_7,0a0637313a30313a35302e303030303030\r\nfuzz_text_field,types_time_4_0,0f0064686d7375\r\nfuzz_text_field,types_time_5_0,0f0064686d75\r\nfuzz_text_field,types_time_6_0,0f00646873\r\nfuzz_text_field,types_time_6_1,0a0037313a30303a3530\r\nfuzz_text_field,types_time_6_2,0a0137313a30303a35302e30\r\nfuzz_text_field,types_time_6_3,0a0237313a30303a35302e3030\r\nfuzz_text_field,types_time_6_4,0a0337313a30303a35302e303030\r\nfuzz_text_field,types_time_6_5,0a0437313a30303a35302e30303030\r\nfuzz_text_field,types_time_6_6,0a0537313a30303a35302e3030303030\r\nfuzz_text_field,types_time_6_7,0a0637313a30303a35302e303030303030\r\nfuzz_text_field,types_time_7_0,0f0064687375\r\nfuzz_text_field,types_time_8_0,0f00646875\r\nfuzz_text_field,types_time_9_0,0f00646d\r\nfuzz_text_field,types_time_9_1,0a0034383a30313a3030\r\nfuzz_text_field,types_time_9_2,0a0134383a30313a30302e30\r\nfuzz_text_field,types_time_9_3,0a0234383a30313a30302e3030\r\nfuzz_text_field,types_time_9_4,0a0334383a30313a30302e303030\r\nfuzz_text_field,types_time_9_5,0a0434383a30313a30302e30303030\r\nfuzz_text_field,types_time_9_6,0a0534383a30313a30302e3030303030\r\nfuzz_text_field,types_time_9_7,0a0634383a30313a30302e303030303030\r\nfuzz_text_field,types_time_10_0,0f00646d73\r\nfuzz_text_field,types_time_10_1,0a0034383a30313a3530\r\nfuzz_text_field,types_time_10_2,0a0134383a30313a35302e30\r\nfuzz_text_field,types_time_10_3,0a0234383a30313a35302e3030\r\nfuzz_text_field,types_time_10_4,0a0334383a30313a35302e303030\r\nfuzz_text_field,types_time_10_5,0a0434383a30313a35302e30303030\r\nfuzz_text_field,types_time_10_6,0a0534383a30313a35302e3030303030\r\nfuzz_text_field,types_time_10_7,0a0634383a30313a35302e303030303030\r\nfuzz_text_field,types_time_11_0,0f00646d7375\r\nfuzz_text_field,types_time_12_0,0f00646d75\r\nfuzz_text_field,types_time_13_0,0f006473\r\nfuzz_text_field,types_time_13_1,0a0034383a30303a3530\r\nfuzz_text_field,types_time_13_2,0a0134383a30303a35302e30\r\nfuzz_text_field,types_time_13_3,0a0234383a30303a35302e3030\r\nfuzz_text_field,types_time_13_4,0a0334383a30303a35302e303030\r\nfuzz_text_field,types_time_13_5,0a0434383a30303a35302e30303030\r\nfuzz_text_field,types_time_13_6,0a0534383a30303a35302e3030303030\r\nfuzz_text_field,types_time_13_7,0a0634383a30303a35302e303030303030\r\nfuzz_text_field,types_time_14_0,0f00647375\r\nfuzz_text_field,types_time_15_0,0f006475\r\nfuzz_text_field,types_time_16_0,0f0068\r\nfuzz_text_field,types_time_16_1,0a0032333a30303a3030\r\nfuzz_text_field,types_time_16_2,0a0132333a30303a30302e30\r\nfuzz_text_field,types_time_16_3,0a0232333a30303a30302e3030\r\nfuzz_text_field,types_time_16_4,0a0332333a30303a30302e303030\r\nfuzz_text_field,types_time_16_5,0a0432333a30303a30302e30303030\r\nfuzz_text_field,types_time_16_6,0a0532333a30303a30302e3030303030\r\nfuzz_text_field,types_time_16_7,0a0632333a30303a30302e303030303030\r\nfuzz_text_field,types_time_17_0,0f00686d\r\nfuzz_text_field,types_time_17_1,0a0032333a30313a3030\r\nfuzz_text_field,types_time_17_2,0a0132333a30313a30302e30\r\nfuzz_text_field,types_time_17_3,0a0232333a30313a30302e3030\r\nfuzz_text_field,types_time_17_4,0a0332333a30313a30302e303030\r\nfuzz_text_field,types_time_17_5,0a0432333a30313a30302e30303030\r\nfuzz_text_field,types_time_17_6,0a0532333a30313a30302e3030303030\r\nfuzz_text_field,types_time_17_7,0a0632333a30313a30302e303030303030\r\nfuzz_text_field,types_time_18_0,0f00686d73\r\nfuzz_text_field,types_time_18_1,0a0032333a30313a3530\r\nfuzz_text_field,types_time_18_2,0a0132333a30313a35302e30\r\nfuzz_text_field,types_time_18_3,0a0232333a30313a35302e3030\r\nfuzz_text_field,types_time_18_4,0a0332333a30313a35302e303030\r\nfuzz_text_field,types_time_18_5,0a0432333a30313a35302e30303030\r\nfuzz_text_field,types_time_18_6,0a0532333a30313a35302e3030303030\r\nfuzz_text_field,types_time_18_7,0a0632333a30313a35302e303030303030\r\nfuzz_text_field,types_time_19_0,0f00686d7375\r\nfuzz_text_field,types_time_20_0,0f00686d75\r\nfuzz_text_field,types_time_21_0,0f006873\r\nfuzz_text_field,types_time_21_1,0a0032333a30303a3530\r\nfuzz_text_field,types_time_21_2,0a0132333a30303a35302e30\r\nfuzz_text_field,types_time_21_3,0a0232333a30303a35302e3030\r\nfuzz_text_field,types_time_21_4,0a0332333a30303a35302e303030\r\nfuzz_text_field,types_time_21_5,0a0432333a30303a35302e30303030\r\nfuzz_text_field,types_time_21_6,0a0532333a30303a35302e3030303030\r\nfuzz_text_field,types_time_21_7,0a0632333a30303a35302e303030303030\r\nfuzz_text_field,types_time_22_0,0f00687375\r\nfuzz_text_field,types_time_23_0,0f006875\r\nfuzz_text_field,types_time_24_0,0f006d\r\nfuzz_text_field,types_time_24_1,0a0030303a30313a3030\r\nfuzz_text_field,types_time_24_2,0a0130303a30313a30302e30\r\nfuzz_text_field,types_time_24_3,0a0230303a30313a30302e3030\r\nfuzz_text_field,types_time_24_4,0a0330303a30313a30302e303030\r\nfuzz_text_field,types_time_24_5,0a0430303a30313a30302e30303030\r\nfuzz_text_field,types_time_24_6,0a0530303a30313a30302e3030303030\r\nfuzz_text_field,types_time_24_7,0a0630303a30313a30302e303030303030\r\nfuzz_text_field,types_time_25_0,0f006d6178\r\nfuzz_text_field,types_time_25_1,0a003833383a35393a3539\r\nfuzz_text_field,types_time_25_2,0a013833383a35393a35382e39\r\nfuzz_text_field,types_time_25_3,0a023833383a35393a35382e3939\r\nfuzz_text_field,types_time_25_4,0a033833383a35393a35382e393939\r\nfuzz_text_field,types_time_25_5,0a043833383a35393a35382e39393939\r\nfuzz_text_field,types_time_25_6,0a053833383a35393a35382e3939393939\r\nfuzz_text_field,types_time_25_7,0a063833383a35393a35382e393939393939\r\nfuzz_text_field,types_time_26_0,0f006d696e\r\nfuzz_text_field,types_time_26_1,0a002d3833383a35393a3539\r\nfuzz_text_field,types_time_26_2,0a012d3833383a35393a35382e39\r\nfuzz_text_field,types_time_26_3,0a022d3833383a35393a35382e3939\r\nfuzz_text_field,types_time_26_4,0a032d3833383a35393a35382e393939\r\nfuzz_text_field,types_time_26_5,0a042d3833383a35393a35382e39393939\r\nfuzz_text_field,types_time_26_6,0a052d3833383a35393a35382e3939393939\r\nfuzz_text_field,types_time_26_7,0a062d3833383a35393a35382e393939393939\r\nfuzz_text_field,types_time_27_0,0f006d73\r\nfuzz_text_field,types_time_27_1,0a0030303a30313a3530\r\nfuzz_text_field,types_time_27_2,0a0130303a30313a35302e30\r\nfuzz_text_field,types_time_27_3,0a0230303a30313a35302e3030\r\nfuzz_text_field,types_time_27_4,0a0330303a30313a35302e303030\r\nfuzz_text_field,types_time_27_5,0a0430303a30313a35302e30303030\r\nfuzz_text_field,types_time_27_6,0a0530303a30313a35302e3030303030\r\nfuzz_text_field,types_time_27_7,0a0630303a30313a35302e303030303030\r\nfuzz_text_field,types_time_28_0,0f006d7375\r\nfuzz_text_field,types_time_29_0,0f006d75\r\nfuzz_text_field,types_time_30_0,0f006e656761746976655f64\r\nfuzz_text_field,types_time_30_1,0a002d34383a30303a3030\r\nfuzz_text_field,types_time_30_2,0a012d34383a30303a30302e30\r\nfuzz_text_field,types_time_30_3,0a022d34383a30303a30302e3030\r\nfuzz_text_field,types_time_30_4,0a032d34383a30303a30302e303030\r\nfuzz_text_field,types_time_30_5,0a042d34383a30303a30302e30303030\r\nfuzz_text_field,types_time_30_6,0a052d34383a30303a30302e3030303030\r\nfuzz_text_field,types_time_30_7,0a062d34383a30303a30302e303030303030\r\nfuzz_text_field,types_time_31_0,0f006e656761746976655f6468\r\nfuzz_text_field,types_time_31_1,0a002d37313a30303a3030\r\nfuzz_text_field,types_time_31_2,0a012d37313a30303a30302e30\r\nfuzz_text_field,types_time_31_3,0a022d37313a30303a30302e3030\r\nfuzz_text_field,types_time_31_4,0a032d37313a30303a30302e303030\r\nfuzz_text_field,types_time_31_5,0a042d37313a30303a30302e30303030\r\nfuzz_text_field,types_time_31_6,0a052d37313a30303a30302e3030303030\r\nfuzz_text_field,types_time_31_7,0a062d37313a30303a30302e303030303030\r\nfuzz_text_field,types_time_32_0,0f006e656761746976655f64686d\r\nfuzz_text_field,types_time_32_1,0a002d37313a30313a3030\r\nfuzz_text_field,types_time_32_2,0a012d37313a30313a30302e30\r\nfuzz_text_field,types_time_32_3,0a022d37313a30313a30302e3030\r\nfuzz_text_field,types_time_32_4,0a032d37313a30313a30302e303030\r\nfuzz_text_field,types_time_32_5,0a042d37313a30313a30302e30303030\r\nfuzz_text_field,types_time_32_6,0a052d37313a30313a30302e3030303030\r\nfuzz_text_field,types_time_32_7,0a062d37313a30313a30302e303030303030\r\nfuzz_text_field,types_time_33_0,0f006e656761746976655f64686d73\r\nfuzz_text_field,types_time_33_1,0a002d37313a30313a3530\r\nfuzz_text_field,types_time_33_2,0a012d37313a30313a35302e30\r\nfuzz_text_field,types_time_33_3,0a022d37313a30313a35302e3030\r\nfuzz_text_field,types_time_33_4,0a032d37313a30313a35302e303030\r\nfuzz_text_field,types_time_33_5,0a042d37313a30313a35302e30303030\r\nfuzz_text_field,types_time_33_6,0a052d37313a30313a35302e3030303030\r\nfuzz_text_field,types_time_33_7,0a062d37313a30313a35302e303030303030\r\nfuzz_text_field,types_time_34_0,0f006e656761746976655f64686d7375\r\nfuzz_text_field,types_time_35_0,0f006e656761746976655f64686d75\r\nfuzz_text_field,types_time_36_0,0f006e656761746976655f646873\r\nfuzz_text_field,types_time_36_1,0a002d37313a30303a3530\r\nfuzz_text_field,types_time_36_2,0a012d37313a30303a35302e30\r\nfuzz_text_field,types_time_36_3,0a022d37313a30303a35302e3030\r\nfuzz_text_field,types_time_36_4,0a032d37313a30303a35302e303030\r\nfuzz_text_field,types_time_36_5,0a042d37313a30303a35302e30303030\r\nfuzz_text_field,types_time_36_6,0a052d37313a30303a35302e3030303030\r\nfuzz_text_field,types_time_36_7,0a062d37313a30303a35302e303030303030\r\nfuzz_text_field,types_time_37_0,0f006e656761746976655f64687375\r\nfuzz_text_field,types_time_38_0,0f006e656761746976655f646875\r\nfuzz_text_field,types_time_39_0,0f006e656761746976655f646d\r\nfuzz_text_field,types_time_39_1,0a002d34383a30313a3030\r\nfuzz_text_field,types_time_39_2,0a012d34383a30313a30302e30\r\nfuzz_text_field,types_time_39_3,0a022d34383a30313a30302e3030\r\nfuzz_text_field,types_time_39_4,0a032d34383a30313a30302e303030\r\nfuzz_text_field,types_time_39_5,0a042d34383a30313a30302e30303030\r\nfuzz_text_field,types_time_39_6,0a052d34383a30313a30302e3030303030\r\nfuzz_text_field,types_time_39_7,0a062d34383a30313a30302e303030303030\r\nfuzz_text_field,types_time_40_0,0f006e656761746976655f646d73\r\nfuzz_text_field,types_time_40_1,0a002d34383a30313a3530\r\nfuzz_text_field,types_time_40_2,0a012d34383a30313a35302e30\r\nfuzz_text_field,types_time_40_3,0a022d34383a30313a35302e3030\r\nfuzz_text_field,types_time_40_4,0a032d34383a30313a35302e303030\r\nfuzz_text_field,types_time_40_5,0a042d34383a30313a35302e30303030\r\nfuzz_text_field,types_time_40_6,0a052d34383a30313a35302e3030303030\r\nfuzz_text_field,types_time_40_7,0a062d34383a30313a35302e303030303030\r\nfuzz_text_field,types_time_41_0,0f006e656761746976655f646d7375\r\nfuzz_text_field,types_time_42_0,0f006e656761746976655f646d75\r\nfuzz_text_field,types_time_43_0,0f006e656761746976655f6473\r\nfuzz_text_field,types_time_43_1,0a002d34383a30303a3530\r\nfuzz_text_field,types_time_43_2,0a012d34383a30303a35302e30\r\nfuzz_text_field,types_time_43_3,0a022d34383a30303a35302e3030\r\nfuzz_text_field,types_time_43_4,0a032d34383a30303a35302e303030\r\nfuzz_text_field,types_time_43_5,0a042d34383a30303a35302e30303030\r\nfuzz_text_field,types_time_43_6,0a052d34383a30303a35302e3030303030\r\nfuzz_text_field,types_time_43_7,0a062d34383a30303a35302e303030303030\r\nfuzz_text_field,types_time_44_0,0f006e656761746976655f647375\r\nfuzz_text_field,types_time_45_0,0f006e656761746976655f6475\r\nfuzz_text_field,types_time_46_0,0f006e656761746976655f68\r\nfuzz_text_field,types_time_46_1,0a002d32333a30303a3030\r\nfuzz_text_field,types_time_46_2,0a012d32333a30303a30302e30\r\nfuzz_text_field,types_time_46_3,0a022d32333a30303a30302e3030\r\nfuzz_text_field,types_time_46_4,0a032d32333a30303a30302e303030\r\nfuzz_text_field,types_time_46_5,0a042d32333a30303a30302e30303030\r\nfuzz_text_field,types_time_46_6,0a052d32333a30303a30302e3030303030\r\nfuzz_text_field,types_time_46_7,0a062d32333a30303a30302e303030303030\r\nfuzz_text_field,types_time_47_0,0f006e656761746976655f686d\r\nfuzz_text_field,types_time_47_1,0a002d32333a30313a3030\r\nfuzz_text_field,types_time_47_2,0a012d32333a30313a30302e30\r\nfuzz_text_field,types_time_47_3,0a022d32333a30313a30302e3030\r\nfuzz_text_field,types_time_47_4,0a032d32333a30313a30302e303030\r\nfuzz_text_field,types_time_47_5,0a042d32333a30313a30302e30303030\r\nfuzz_text_field,types_time_47_6,0a052d32333a30313a30302e3030303030\r\nfuzz_text_field,types_time_47_7,0a062d32333a30313a30302e303030303030\r\nfuzz_text_field,types_time_48_0,0f006e656761746976655f686d73\r\nfuzz_text_field,types_time_48_1,0a002d32333a30313a3530\r\nfuzz_text_field,types_time_48_2,0a012d32333a30313a35302e30\r\nfuzz_text_field,types_time_48_3,0a022d32333a30313a35302e3030\r\nfuzz_text_field,types_time_48_4,0a032d32333a30313a35302e303030\r\nfuzz_text_field,types_time_48_5,0a042d32333a30313a35302e30303030\r\nfuzz_text_field,types_time_48_6,0a052d32333a30313a35302e3030303030\r\nfuzz_text_field,types_time_48_7,0a062d32333a30313a35302e303030303030\r\nfuzz_text_field,types_time_49_0,0f006e656761746976655f686d7375\r\nfuzz_text_field,types_time_50_0,0f006e656761746976655f686d75\r\nfuzz_text_field,types_time_51_0,0f006e656761746976655f6873\r\nfuzz_text_field,types_time_51_1,0a002d32333a30303a3530\r\nfuzz_text_field,types_time_51_2,0a012d32333a30303a35302e30\r\nfuzz_text_field,types_time_51_3,0a022d32333a30303a35302e3030\r\nfuzz_text_field,types_time_51_4,0a032d32333a30303a35302e303030\r\nfuzz_text_field,types_time_51_5,0a042d32333a30303a35302e30303030\r\nfuzz_text_field,types_time_51_6,0a052d32333a30303a35302e3030303030\r\nfuzz_text_field,types_time_51_7,0a062d32333a30303a35302e303030303030\r\nfuzz_text_field,types_time_52_0,0f006e656761746976655f687375\r\nfuzz_text_field,types_time_53_0,0f006e656761746976655f6875\r\nfuzz_text_field,types_time_54_0,0f006e656761746976655f6d\r\nfuzz_text_field,types_time_54_1,0a002d30303a30313a3030\r\nfuzz_text_field,types_time_54_2,0a012d30303a30313a30302e30\r\nfuzz_text_field,types_time_54_3,0a022d30303a30313a30302e3030\r\nfuzz_text_field,types_time_54_4,0a032d30303a30313a30302e303030\r\nfuzz_text_field,types_time_54_5,0a042d30303a30313a30302e30303030\r\nfuzz_text_field,types_time_54_6,0a052d30303a30313a30302e3030303030\r\nfuzz_text_field,types_time_54_7,0a062d30303a30313a30302e303030303030\r\nfuzz_text_field,types_time_55_0,0f006e656761746976655f6d73\r\nfuzz_text_field,types_time_55_1,0a002d30303a30313a3530\r\nfuzz_text_field,types_time_55_2,0a012d30303a30313a35302e30\r\nfuzz_text_field,types_time_55_3,0a022d30303a30313a35302e3030\r\nfuzz_text_field,types_time_55_4,0a032d30303a30313a35302e303030\r\nfuzz_text_field,types_time_55_5,0a042d30303a30313a35302e30303030\r\nfuzz_text_field,types_time_55_6,0a052d30303a30313a35302e3030303030\r\nfuzz_text_field,types_time_55_7,0a062d30303a30313a35302e303030303030\r\nfuzz_text_field,types_time_56_0,0f006e656761746976655f6d7375\r\nfuzz_text_field,types_time_57_0,0f006e656761746976655f6d75\r\nfuzz_text_field,types_time_58_0,0f006e656761746976655f73\r\nfuzz_text_field,types_time_58_1,0a002d30303a30303a3530\r\nfuzz_text_field,types_time_58_2,0a012d30303a30303a35302e30\r\nfuzz_text_field,types_time_58_3,0a022d30303a30303a35302e3030\r\nfuzz_text_field,types_time_58_4,0a032d30303a30303a35302e303030\r\nfuzz_text_field,types_time_58_5,0a042d30303a30303a35302e30303030\r\nfuzz_text_field,types_time_58_6,0a052d30303a30303a35302e3030303030\r\nfuzz_text_field,types_time_58_7,0a062d30303a30303a35302e303030303030\r\nfuzz_text_field,types_time_59_0,0f006e656761746976655f7375\r\nfuzz_text_field,types_time_60_0,0f006e656761746976655f75\r\nfuzz_text_field,types_time_61_0,0f0073\r\nfuzz_text_field,types_time_61_1,0a0030303a30303a3530\r\nfuzz_text_field,types_time_61_2,0a0130303a30303a35302e30\r\nfuzz_text_field,types_time_61_3,0a0230303a30303a35302e3030\r\nfuzz_text_field,types_time_61_4,0a0330303a30303a35302e303030\r\nfuzz_text_field,types_time_61_5,0a0430303a30303a35302e30303030\r\nfuzz_text_field,types_time_61_6,0a0530303a30303a35302e3030303030\r\nfuzz_text_field,types_time_61_7,0a0630303a30303a35302e303030303030\r\nfuzz_text_field,types_time_62_0,0f007375\r\nfuzz_text_field,types_time_63_0,0f0075\r\nfuzz_text_field,types_time_64_0,0f007a65726f\r\nfuzz_text_field,types_time_64_1,0a0030303a30303a3030\r\nfuzz_text_field,types_time_64_2,0a0130303a30303a30302e30\r\nfuzz_text_field,types_time_64_3,0a0230303a30303a30302e3030\r\nfuzz_text_field,types_time_64_4,0a0330303a30303a30302e303030\r\nfuzz_text_field,types_time_64_5,0a0430303a30303a30302e30303030\r\nfuzz_text_field,types_time_64_6,0a0530303a30303a30302e3030303030\r\nfuzz_text_field,types_time_64_7,0a0630303a30303a30302e303030303030\r\nfuzz_row,text_types_timestamp_0,080f000d000d010d020d030d040d050d06046461746513323031302d30352d30312032323a30303a303015323031302d30352d30312032323a30303a30302e3016323031302d30352d30312032323a30303a30302e303017323031302d30352d30312032323a30303a30302e30303018323031302d30352d30312032323a30303a30302e3030303019323031302d30352d30312032323a30303a30302e30303030301a323031302d30352d30312032323a30303a30302e303030303030\r\nfuzz_row,text_types_timestamp_1,080f000d000d010d020d030d040d050d060a646174655f6c6561703413323030342d30322d32382032323a30303a303015323030342d30322d32382032323a30303a30302e3016323030342d30322d32382032323a30303a30302e303017323030342d30322d32382032323a30303a30302e30303018323030342d30322d32382032323a30303a30302e3030303019323030342d30322d32382032323a30303a30302e30303030301a323030342d30322d32382032323a30303a30302e303030303030\r\nfuzz_row,text_types_timestamp_2,080f000d000d010d020d030d040d050d060c646174655f6c65617034303013323030302d30322d32382032323a30303a303015323030302d30322d32382032323a30303a30302e3016323030302d30322d32382032323a30303a30302e303017323030302d30322d32382032323a30303a30302e30303018323030302d30322d32382032323a30303a30302e3030303019323030302d30322d32382032323a30303a30302e30303030301a323030302d30322d32382032323a30303a30302e303030303030\r\nfuzz_row,text_types_timestamp_3,080f000d000d010d020d030d040d050d06016813323031302d30352d30322032313a30303a303015323031302d30352d30322032313a30303a30302e3016323031302d30352d30322032313a30303a30302e303017323031302d30352d30322032313a30303a30302e30303018323031302d30352d30322032313a30303a30302e3030303019323031302d30352d30322032313a30303a30302e30303030301a323031302d30352d30322032313a30303a30302e303030303030\r\nfuzz_row,text_types_timestamp_4,080f000d000d010d020d030d040d050d0602686d13323031302d30352d30322032313a30313a303015323031302d30352d30322032313a30313a30302e3016323031302d30352d30322032313a30313a30302e303017323031302d30352d30322032313a30313a30302e30303018323031302d30352d30322032313a30313a30302e3030303019323031302d30352d30322032313a30313a30302e30303030301a323031302d30352d30322032313a30313a30302e303030303030\r\nfuzz_row,text_types_timestamp_5,080f000d000d010d020d030d040d050d0603686d7313323031302d30352d30322032313a30313a353015323031302d30352d30322032313a30313a35302e3016323031302d30352d30322032313a30313a35302e303017323031302d30352d30322032313a30313a35302e30303018323031302d30352d30322032313a30313a35302e3030303019323031302d30352d30322032313a30313a35302e30303030301a323031302d30352d30322032313a30313a35302e303030303030\r\nfuzz_row,text_types_timestamp_6,080f000d000d010d020d030d040d050d0604686d7375fb15323031302d30352d30322032313a30313a35302e3116323031302d30352d30322032313a30313a35302e313217323031302d30352d30322032313a30313a35302e31323318323031302d30352d30322032313a30313a35302e3132333419323031302d30352d30322032313a30313a35302e31323334351a323031302d30352d30322032313a30313a35302e313233343536\r\nfuzz_row,text_types_timestamp_7,080f000d000d010d020d030d040d050d0603686d75fb15323031302d30352d30322032313a30313a30302e3116323031302d30352d30322032313a30313a30302e313217323031302d30352d30322032313a30313a30302e31323318323031302d30352d30322032313a30313a30302e3132333419323031302d30352d30322032313a30313a30302e31323334351a323031302d30352d30322032313a30313a30302e313233343536\r\nfuzz_row,text_types_timestamp_8,080f000d000d010d020d030d040d050d0602687313323031302d30352d30322032313a30303a353015323031302d30352d30322032313a30303a35302e3016323031302d30352d30322032313a30303a35302e303017323031302d30352d30322032313a30303a35302e30303018323031302d30352d30322032313a30303a35302e3030303019323031302d30352d30322032313a30303a35302e30303030301a323031302d30352d30322032313a30303a35302e303030303030\r\nfuzz_row,text_types_timestamp_9,080f000d000d010d020d030d040d050d0603687375fb15323031302d30352d30322032313a30303a35302e3116323031302d30352d30322032313a30303a35302e313217323031302d30352d30322032313a30303a35302e31323318323031302d30352d30322032313a30303a35302e3132333419323031302d30352d30322032313a30303a35302e31323334351a323031302d30352d30322032313a30303a35302e313233343536\r\nfuzz_row,text_types_timestamp_10,080f000d000d010d020d030d040d050d06026875fb15323031302d30352d30322032313a30303a30302e3116323031302d30352d30322032313a30303a30302e313217323031302d30352d30322032313a30303a30302e31323318323031302d30352d30322032313a30303a30302e3132333419323031302d30352d30322032313a30303a30302e31323334351a323031302d30352d30322032313a30303a30302e313233343536\r\nfuzz_row,text_types_timestamp_11,080f000d000d010d020d030d040d050d06016d13323031302d30352d30312032323a30313a303015323031302d30352d30312032323a30313a30302e3016323031302d30352d30312032323a30313a30302e303017323031302d30352d30312032323a30313a30302e30303018323031302d30352d30312032323a30313a30302e3030303019323031302d30352d30312032323a30313a30302e30303030301a323031302d30352d30312032323a30313a30302e303030303030\r\nfuzz_row,text_types_timestamp_12,080f000d000d010d020d030d040d050d06036d617813323033382d30312d31392030333a31343a303715323033382d30312d31392030333a31343a30372e3916323033382d30312d31392030333a31343a30372e393917323033382d30312d31392030333a31343a30372e39393918323033382d30312d31392030333a31343a30372e3939393919323033382d30312d31392030333a31343a30372e39393939391a323033382d30312d31392030333a31343a30372e393939393939\r\nfuzz_row,text_types_timestamp_13,080f000d000d010d020d030d040d050d06036d696e13313937302d30312d30312030303a30303a303115313937302d30312d30312030303a30303a30312e3016313937302d30312d30312030303a30303a30312e303017313937302d30312d30312030303a30303a30312e30303018313937302d30312d30312030303a30303a30312e3030303019313937302d30312d30312030303a30303a30312e30303030301a313937302d30312d30312030303a30303a30312e303030303030\r\nfuzz_row,text_types_timestamp_14,080f000d000d010d020d030d040d050d06026d7313323031302d30352d30312032323a30313a353015323031302d30352d30312032323a30313a35302e3016323031302d30352d30312032323a30313a35302e303017323031302d30352d30312032323a30313a35302e30303018323031302d30352d30312032323a30313a35302e3030303019323031302d30352d30312032323a30313a35302e30303030301a323031302d30352d30312032323a30313a35302e303030303030\r\nfuzz_row,text_types_timestamp_15,080f000d000d010d020d030d040d050d06036d7375fb15323031302d30352d30312032323a30313a35302e3116323031302d30352d30312032323a30313a35302e313217323031302d30352d30312032323a30313a35302e31323318323031302d30352d30312032323a30313a35302e3132333419323031302d30352d30312032323a30313a35302e31323334351a323031302d30352d30312032323a30313a35302e313233343536\r\nfuzz_row,text_types_timestamp_16,080f000d000d010d020d030d040d050d06026d75fb15323031302d30352d30312032323a30313a30302e3116323031302d30352d30312032323a30313a30302e313217323031302d30352d30312032323a30313a30302e31323318323031302d30352d30312032323a30313a30302e3132333419323031302d30352d30312032323a30313a30302e31323334351a323031302d30352d30312032323a30313a30302e313233343536\r\nfuzz_row,text_types_timestamp_17,080f000d000d010d020d030d040d050d06017313323031302d30352d30312032323a30303a353015323031302d30352d30312032323a30303a35302e3016323031302d30352d30312032323a30303a35302e303017323031302d30352d30312032323a30303a35302e30303018323031302d30352d30312032323a30303a35302e3030303019323031302d30352d30312032323a30303a35302e30303030301a323031302d30352d30312032323a30303a35302e303030303030\r\nfuzz_row,text_types_timestamp_18,080f000d000d010d020d030d040d050d06027375fb15323031302d30352d30312032323a30303a35302e3116323031302d30352d30312032323a30303a35302e313217323031302d30352d30312032323a30303a35302e31323318323031302d30352d30312032323a30303a35302e3132333419323031302d30352d30312032323a30303a35302e31323334351a323031302d30352d30312032323a30303a35302e313233343536\r\nfuzz_row,text_types_timestamp_19,080f000d000d010d020d030d040d050d060175fb15323031302d30352d30312032323a30303a30302e3116323031302d30352d30312032323a30303a30302e313217323031302d30352d30312032323a30303a30302e31323318323031302d30352d30312032323a30303a30302e3132333419323031302d30352d30312032323a30303a30302e31323334351a323031302d30352d30312032323a30303a30302e313233343536\r\nfuzz_row,text_types_timestamp_20,080f000d000d010d020d030d040d050d06047a65726f13303030302d30302d30302030303a30303a303015303030302d30302d30302030303a30303a30302e3016303030302d30302d30302030303a30303a30302e303017303030302d30302d30302030303a30303a30302e30303018303030302d30302d30302030303a30303a30302e3030303019303030302d30302d30302030303a30303a30302e30303030301a303030302d30302d30302030303a30303a30302e303030303030\r\nfuzz_text_field,types_timestamp_0_0,0f0064617465\r\nfuzz_text_field,types_timestamp_0_1,0d00323031302d30352d30312032323a30303a3030\r\nfuzz_text_field,types_timestamp_0_2,0d01323031302d30352d30312032323a30303a30302e30\r\nfuzz_text_field,types_timestamp_0_3,0d02323031302d30352d30312032323a30303a30302e3030\r\nfuzz_text_field,types_timestamp_0_4,0d03323031302d30352d30312032323a30303a30302e303030\r\nfuzz_text_field,types_timestamp_0_5,0d04323031302d30352d30312032323a30303a30302e30303030\r\nfuzz_text_field,types_timestamp_0_6,0d05323031302d30352d30312032323a30303a30302e3030303030\r\nfuzz_text_field,types_timestamp_0_7,0d06323031302d30352d30312032323a30303a30302e303030303030\r\nfuzz_text_field,types_timestamp_1_0,0f00646174655f6c65617034\r\nfuzz_text_field,types_timestamp_1_1,0d00323030342d30322d32382032323a30303a3030\r\nfuzz_text_field,types_timestamp_1_2,0d01323030342d30322d32382032323a30303a30302e30\r\nfuzz_text_field,types_timestamp_1_3,0d02323030342d30322d32382032323a30303a30302e3030\r\nfuzz_text_field,types_timestamp_1_4,0d03323030342d30322d32382032323a30303a30302e303030\r\nfuzz_text_field,types_timestamp_1_5,0d04323030342d30322d32382032323a30303a30302e30303030\r\nfuzz_text_field,types_timestamp_1_6,0d05323030342d30322d32382032323a30303a30302e3030303030\r\nfuzz_text_field,types_timestamp_1_7,0d06323030342d30322d32382032323a30303a30302e303030303030\r\nfuzz_text_field,types_timestamp_2_0,0f00646174655f6c656170343030\r\nfuzz_text_field,types_timestamp_2_1,0d00323030302d30322d32382032323a30303a3030\r\nfuzz_text_field,types_timestamp_2_2,0d01323030302d30322d32382032323a30303a30302e30\r\nfuzz_text_field,types_timestamp_2_3,0d02323030302d30322d32382032323a30303a30302e3030\r\nfuzz_text_field,types_timestamp_2_4,0d03323030302d30322d32382032323a30303a30302e303030\r\nfuzz_text_field,types_timestamp_2_5,0d04323030302d30322d32382032323a30303a30302e30303030\r\nfuzz_text_field,types_timestamp_2_6,0d05323030302d30322d32382032323a30303a30302e3030303030\r\nfuzz_text_field,types_timestamp_2_7,0d06323030302d30322d32382032323a30303a30302e303030303030\r\nfuzz_text_field,types_timestamp_3_0,0f0068\r\nfuzz_text_field,types_timestamp_3_1,0d00323031302d30352d30322032313a30303a3030\r\nfuzz_text_field,types_timestamp_3_2,0d01323031302d30352d30322032313a30303a30302e30\r\nfuzz_text_field,types_timestamp_3_3,0d02323031302d30352d30322032313a30303a30302e3030\r\nfuzz_text_field,types_timestamp_3_4,0d03323031302d30352d30322032313a30303a30302e303030\r\nfuzz_text_field,types_timestamp_3_5,0d04323031302d30352d30322032313a30303a30302e30303030\r\nfuzz_text_field,types_timestamp_3_6,0d05323031302d30352d30322032313a30303a30302e3030303030\r\nfuzz_text_field,types_timestamp_3_7,0d06323031302d30352d30322032313a30303a30302e303030303030\r\nfuzz_text_field,types_timestamp_4_0,0f00686d\r\nfuzz_text_field,types_timestamp_4_1,0d00323031302d30352d30322032313a30313a3030\r\nfuzz_text_field,types_timestamp_4_2,0d01323031302d30352d30322032313a30313a30302e30\r\nfuzz_text_field,types_timestamp_4_3,0d02323031302d30352d30322032313a30313a30302e3030\r\nfuzz_text_field,types_timestamp_4_4,0d03323031302d30352d30322032313a30313a30302e303030\r\nfuzz_text_field,types_timestamp_4_5,0d04323031302d30352d30322032313a30313a30302e30303030\r\nfuzz_text_field,types_timestamp_4_6,0d05323031302d30352d30322032313a30313a30302e3030303030\r\nfuzz_text_field,types_timestamp_4_7,0d06323031302d30352d30322032313a30313a30302e303030303030\r\nfuzz_text_field,types_timestamp_5_0,0f00686d73\r\nfuzz_text_field,types_timestamp_5_1,0d00323031302d30352d30322032313a30313a3530\r\nfuzz_text_field,types_timestamp_5_2,0d01323031302d30352d30322032313a30313a35302e30\r\nfuzz_text_field,types_timestamp_5_3,0d02323031302d30352d30322032313a30313a35302e3030\r\nfuzz_text_field,types_timestamp_5_4,0d03323031302d30352d30322032313a30313a35302e303030\r\nfuzz_text_field,types_timestamp_5_5,0d04323031302d30352d30322032313a30313a35302e30303030\r\nfuzz_text_field,types_timestamp_5_6,0d05323031302d30352d30322032313a30313a35302e3030303030\r\nfuzz_text_field,types_timestamp_5_7,0d06323031302d30352d30322032313a30313a35302e303030303030\r\nfuzz_text_field,types_timestamp_6_0,0f00686d7375\r\nfuzz_text_field,types_timestamp_7_0,0f00686d75\r\nfuzz_text_field,types_timestamp_8_0,0f006873\r\nfuzz_text_field,types_timestamp_8_1,0d00323031302d30352d30322032313a30303a3530\r\nfuzz_text_field,types_timestamp_8_2,0d01323031302d30352d30322032313a30303a35302e30\r\nfuzz_text_field,types_timestamp_8_3,0d02323031302d30352d30322032313a30303a35302e3030\r\nfuzz_text_field,types_timestamp_8_4,0d03323031302d30352d30322032313a30303a35302e303030\r\nfuzz_text_field,types_timestamp_8_5,0d04323031302d30352d30322032313a30303a35302e30303030\r\nfuzz_text_field,types_timestamp_8_6,0d05323031302d30352d30322032313a30303a35302e3030303030\r\nfuzz_text_field,types_timestamp_8_7,0d06323031302d30352d30322032313a30303a35302e303030303030\r\nfuzz_text_field,types_timestamp_9_0,0f00687375\r\nfuzz_text_field,types_timestamp_10_0,0f006875\r\nfuzz_text_field,types_timestamp_11_0,0f006d\r\nfuzz_text_field,types_timestamp_11_1,0d00323031302d30352d30312032323a30313a3030\r\nfuzz_text_field,types_timestamp_11_2,0d01323031302d30352d30312032323a30313a30302e30\r\nfuzz_text_field,types_timestamp_11_3,0d02323031302d30352d30312032323a30313a30302e3030\r\nfuzz_text_field,types_timestamp_11_4,0d03323031302d30352d30312032323a30313a30302e303030\r\nfuzz_text_field,types_timestamp_11_5,0d04323031302d30352d30312032323a30313a30302e30303030\r\nfuzz_text_field,types_timestamp_11_6,0d05323031302d30352d30312032323a30313a30302e3030303030\r\nfuzz_text_field,types_timestamp_11_7,0d06323031302d30352d30312032323a30313a30302e303030303030\r\nfuzz_text_field,types_timestamp_12_0,0f006d6178\r\nfuzz_text_field,types_timestamp_12_1,0d00323033382d30312d31392030333a31343a3037\r\nfuzz_text_field,types_timestamp_12_2,0d01323033382d30312d31392030333a31343a30372e39\r\nfuzz_text_field,types_timestamp_12_3,0d02323033382d30312d31392030333a31343a30372e3939\r\nfuzz_text_field,types_timestamp_12_4,0d03323033382d30312d31392030333a31343a30372e393939\r\nfuzz_text_field,types_timestamp_12_5,0d04323033382d30312d31392030333a31343a30372e39393939\r\nfuzz_text_field,types_timestamp_12_6,0d05323033382d30312d31392030333a31343a30372e3939393939\r\nfuzz_text_field,types_timestamp_12_7,0d06323033382d30312d31392030333a31343a30372e393939393939\r\nfuzz_text_field,types_timestamp_13_0,0f006d696e\r\nfuzz_text_field,types_timestamp_13_1,0d00313937302d30312d30312030303a30303a3031\r\nfuzz_text_field,types_timestamp_13_2,0d01313937302d30312d30312030303a30303a30312e30\r\nfuzz_text_field,types_timestamp_13_3,0d02313937302d30312d30312030303a30303a30312e3030\r\nfuzz_text_field,types_timestamp_13_4,0d03313937302d30312d30312030303a30303a30312e303030\r\nfuzz_text_field,types_timestamp_13_5,0d04313937302d30312d30312030303a30303a30312e30303030\r\nfuzz_text_field,types_timestamp_13_6,0d05313937302d30312d30312030303a30303a30312e3030303030\r\nfuzz_text_field,types_timestamp_13_7,0d06313937302d30312d30312030303a30303a30312e303030303030\r\nfuzz_text_field,types_timestamp_14_0,0f006d73\r\nfuzz_text_field,types_timestamp_14_1,0d00323031302d30352d30312032323a30313a3530\r\nfuzz_text_field,types_timestamp_14_2,0d01323031302d30352d30312032323a30313a35302e30\r\nfuzz_text_field,types_timestamp_14_3,0d02323031302d30352d30312032323a30313a35302e3030\r\nfuzz_text_field,types_timestamp_14_4,0d03323031302d30352d30312032323a30313a35302e303030\r\nfuzz_text_field,types_timestamp_14_5,0d04323031302d30352d30312032323a30313a35302e30303030\r\nfuzz_text_field,types_timestamp_14_6,0d05323031302d30352d30312032323a30313a35302e3030303030\r\nfuzz_text_field,types_timestamp_14_7,0d06323031302d30352d30312032323a30313a35302e303030303030\r\nfuzz_text_field,types_timestamp_15_0,0f006d7375\r\nfuzz_text_field,types_timestamp_16_0,0f006d75\r\nfuzz_text_field,types_timestamp_17_0,0f0073\r\nfuzz_text_field,types_timestamp_17_1,0d00323031302d30352d30312032323a30303a3530\r\nfuzz_text_field,types_timestamp_17_2,0d01323031302d30352d30312032323a30303a35302e30\r\nfuzz_text_field,types_timestamp_17_3,0d02323031302d30352d30312032323a30303a35302e3030\r\nfuzz_text_field,types_timestamp_17_4,0d03323031302d30352d30312032323a30303a35302e303030\r\nfuzz_text_field,types_timestamp_17_5,0d04323031302d30352d30312032323a30303a35302e30303030\r\nfuzz_text_field,types_timestamp_17_6,0d05323031302d30352d30312032323a30303a35302e3030303030\r\nfuzz_text_field,types_timestamp_17_7,0d06323031302d30352d30312032323a30303a35302e303030303030\r\nfuzz_text_field,types_timestamp_18_0,0f007375\r\nfuzz_text_field,types_timestamp_19_0,0f0075\r\nfuzz_text_field,types_timestamp_20_0,0f007a65726f\r\nfuzz_text_field,types_timestamp_20_1,0d00303030302d30302d30302030303a30303a3030\r\nfuzz_text_field,types_timestamp_20_2,0d01303030302d30302d30302030303a30303a30302e30\r\nfuzz_text_field,types_timestamp_20_3,0d02303030302d30302d30302030303a30303a30302e3030\r\nfuzz_text_field,types_timestamp_20_4,0d03303030302d30302d30302030303a30303a30302e303030\r\nfuzz_text_field,types_timestamp_20_5,0d04303030302d30302d30302030303a30303a30302e30303030\r\nfuzz_text_field,types_timestamp_20_6,0d05303030302d30302d30302030303a30303a30302e3030303030\r\nfuzz_text_field,types_timestamp_20_7,0d06303030302d30302d30302030303a30303a30302e303030303030\r\nfuzz_row,text_types_tinyint_0,050f000000800000008000036d61780331323703323535fbfb\r\nfuzz_row,text_types_tinyint_1,050f000000800000008000036d696e042d3132380130fb06303030303030\r\nfuzz_row,text_types_tinyint_2,050f000000800000008000086e65676174697665032d3230fb032d3230fb\r\nfuzz_row,text_types_tinyint_3,050f00000080000000800007726567756c617202323002323002323006303030303230\r\nfuzz_text_field,types_tinyint_0_0,0f006d6178\r\nfuzz_text_field,types_tinyint_0_1,0000313237\r\nfuzz_text_field,types_tinyint_0_2,8000323535\r\nfuzz_text_field,types_tinyint_1_0,0f006d696e\r\nfuzz_text_field,types_tinyint_1_1,00002d313238\r\nfuzz_text_field,types_tinyint_1_2,800030\r\nfuzz_text_field,types_tinyint_2_0,0f006e65676174697665\r\nfuzz_text_field,types_tinyint_2_1,00002d3230\r\nfuzz_text_field,types_tinyint_3_0,0f00726567756c6172\r\nfuzz_text_field,types_tinyint_3_1,00003230\r\nfuzz_text_field,types_tinyint_3_2,80003230\r\nfuzz_text_field,types_tinyint_3_3,00003230\r\nfuzz_text_field,types_tinyint_3_4,8000303030303230\r\nfuzz_row,text_types_year_0,020f008900036d61780432313535\r\nfuzz_row,text_types_year_1,020f008900036d696e0431393031\r\nfuzz_row,text_types_year_2,020f00890007726567756c61720432303139\r\nfuzz_row,text_types_year_3,020f008900047a65726f0430303030\r\nfuzz_text_field,types_year_0_0,0f006d6178\r\nfuzz_text_field,types_year_0_1,890032313535\r\nfuzz_text_field,types_year_1_0,0f006d696e\r\nfuzz_text_field,types_year_1_1,890031393031\r\nfuzz_text_field,types_year_2_0,0f00726567756c6172\r\nfuzz_text_field,types_year_2_1,890032303139\r\nfuzz_text_field,types_year_3_0,0f007a65726f\r\nfuzz_text_field,types_year_3_1,890030303030\r\nfuzz_row,binary_multifield_table_0,8503000f000300051f061f000001000000036161610b000000cdcc8c3f9a9999999999b93f\r\nfuzz_row,binary_multifield_table_1,8503000f000300051f061f00200200000003626262160000009a9999999999c93f\r\nfuzz_row,binary_one_row_table_0,8203000f00000001000000026630\r\nfuzz_row,binary_three_rows_table_0,8203000f00000001000000026630\r\nfuzz_row,binary_three_rows_table_1,8203000f00000002000000026631\r\nfuzz_row,binary_three_rows_table_2,8203000f00000003000000026632\r\nfuzz_row,binary_two_rows_table_0,8203000f00000001000000026630\r\nfuzz_row,binary_two_rows_table_1,8203000f00000002000000026631\r\nfuzz_row,binary_types_bigint_0,850f0004008400040084000060036d6178ffffffffffffff7fffffffffffffffff\r\nfuzz_row,binary_types_bigint_1,850f0004008400040084000020036d696e000000000000008000000000000000000000000000000000\r\nfuzz_row,binary_types_bigint_2,850f0004008400040084000050086e65676174697665ecffffffffffffffecffffffffffffff\r\nfuzz_row,binary_types_bigint_3,850f000400840004008400000007726567756c61721400000000000000140000000000000014000000000000001400000000000000\r\nfuzz_row,binary_types_binary_0,870f0010001100130013001300130000000005656d7074790a000000000000000000000000000000\r\nfuzz_row,binary_types_binary_1,870f00100011001300130013001300000000086e6f6e61736369690a00ff00000000000000000201fe0202fd0203fc0204fb0205fa\r\nfuzz_row,binary_types_binary_2,870f0010001100130013001300130000000007726567756c61720a005f62696e61727900000b005f76617262696e6172790a005f74696e79626c6f6206005f626c6f620c005f6d656469756d626c6f620a005f6c6f6e67626c6f62\r\nfuzz_row,binary_types_bit_0,8c0f0088008800880088008800880088008800880088008800000000036d6178010101ff023fff02ffff03ffffff0401ffffff04ffffffff05ffffffffff06ffffffffffff07ffffffffffffff08ffffffffffffffff\r\nfuzz_row,binary_types_bit_1,8c0f0088008800880088008800880088008800880088008800000000036d696e010001000200000200000300000004000000000400000000050000000000060000000000000700000000000000080000000000000000\r\nfuzz_row,binary_types_bit_2,8c0f008800880088008800880088008800880088008800880000000007726567756c61720101019e021e2a02123403123456040154abe0041234567805123456789a06123456789abc07123456789abcde081234567812345678\r\nfuzz_row,binary_types_bool_0,820f00000000000566616c736500\r\nfuzz_row,binary_types_bool_1,820f0000000000047472756501\r\nfuzz_row,binary_types_date_0,820f000b000000086c6561705f34303004d007021d\r\nfuzz_row,binary_types_date_1,820f000b0000000c6c6561705f726567756c617204fc06021d\r\nfuzz_row,binary_types_date_2,820f000b000000036d6178040f270c1f\r\nfuzz_row,binary_types_date_3,820f000b000000036d696e0400000101\r\nfuzz_row,binary_types_date_4,820f000b00000007726567756c617204da07031c\r\nfuzz_row,binary_types_date_5,820f000b0000001579726567756c61725f696e76616c69645f6461746504e4070b1f\r\nfuzz_row,binary_types_date_6,820f000b0000001d79726567756c61725f696e76616c69645f646174655f6c656170313030046c07021d\r\nfuzz_row,binary_types_date_7,820f000b0000002179726567756c61725f696e76616c69645f646174655f6c656170726567756c617204cf07021d\r\nfuzz_row,binary_types_date_8,820f000b0000001779726567756c61725f6d726567756c61725f647a65726f04e4070b00\r\nfuzz_row,binary_types_date_9,820f000b0000001779726567756c61725f6d7a65726f5f64726567756c617204e4070014\r\nfuzz_row,binary_types_date_10,820f000b0000001479726567756c61725f6d7a65726f5f647a65726f04e4070000\r\nfuzz_row,binary_types_date_11,820f000b00000012797a65726f5f696e76616c69645f646174650400000b1f\r\nfuzz_row,binary_types_date_12,820f000b00000014797a65726f5f6d726567756c61725f647a65726f0400000b00\r\nfuzz_row,binary_types_date_13,820f000b00000014797a65726f5f6d7a65726f5f64726567756c61720400000014\r\nfuzz_row,binary_types_date_14,820f000b000000047a65726f00\r\nfuzz_row,binary_types_datetime_0,880f000c000c010c020c030c040c050c06000000046461746504da07050204da07050204da07050204da07050204da07050204da07050204da070502\r\nfuzz_row,binary_types_datetime_1,880f000c000c010c020c030c040c050c060000000a646174655f6c6561703404d407021d04d407021d04d407021d04d407021d04d407021d04d407021d04d407021d\r\nfuzz_row,binary_types_datetime_2,880f000c000c010c020c030c040c050c060000000c646174655f6c65617034303004d007021d04d007021d04d007021d04d007021d04d007021d04d007021d04d007021d\r\nfuzz_row,binary_types_datetime_3,880f000c000c010c020c030c040c050c060000001a646174655f79726567756c61725f696e76616c69645f6461746504e4070b1f04e4070b1f04e4070b1f04e4070b1f04e4070b1f04e4070b1f04e4070b1f\r\nfuzz_row,binary_types_datetime_4,880f000c000c010c020c030c040c050c0600000022646174655f79726567756c61725f696e76616c69645f646174655f6c656170313030046c07021d046c07021d046c07021d046c07021d046c07021d046c07021d046c07021d\r\nfuzz_row,binary_types_datetime_5,880f000c000c010c020c030c040c050c0600000026646174655f79726567756c61725f696e76616c69645f646174655f6c656170726567756c617204cf07021d04cf07021d04cf07021d04cf07021d04cf07021d04cf07021d04cf07021d\r\nfuzz_row,binary_types_datetime_6,880f000c000c010c020c030c040c050c060000001c646174655f79726567756c61725f6d726567756c61725f647a65726f04e4070a0004e4070a0004e4070a0004e4070a0004e4070a0004e4070a0004e4070a00\r\nfuzz_row,binary_types_datetime_7,880f000c000c010c020c030c040c050c060000001c646174655f79726567756c61725f6d7a65726f5f64726567756c617204e407000a04e407000a04e407000a04e407000a04e407000a04e407000a04e407000a\r\nfuzz_row,binary_types_datetime_8,880f000c000c010c020c030c040c050c0600000019646174655f79726567756c61725f6d7a65726f5f647a65726f04e407000004e407000004e407000004e407000004e407000004e407000004e4070000\r\nfuzz_row,binary_types_datetime_9,880f000c000c010c020c030c040c050c0600000017646174655f797a65726f5f696e76616c69645f646174650400000b1f0400000b1f0400000b1f0400000b1f0400000b1f0400000b1f0400000b1f\r\nfuzz_row,binary_types_datetime_10,880f000c000c010c020c030c040c050c0600000019646174655f797a65726f5f6d726567756c61725f647a65726f0400000a000400000a000400000a000400000a000400000a000400000a000400000a00\r\nfuzz_row,binary_types_datetime_11,880f000c000c010c020c030c040c050c0600000019646174655f797a65726f5f6d7a65726f5f64726567756c6172040000000a040000000a040000000a040000000a040000000a040000000a040000000a\r\nfuzz_row,binary_types_datetime_12,880f000c000c010c020c030c040c050c0600000009646174655f7a65726f00000000000000\r\nfuzz_row,binary_types_datetime_13,880f000c000c010c020c030c040c050c06000000016807da07050217000007da07050217000007da07050217000007da07050217000007da07050217000007da07050217000007da070502170000\r\nfuzz_row,binary_types_datetime_14,880f000c000c010c020c030c040c050c0600000002686d07da07050217010007da07050217010007da07050217010007da07050217010007da07050217010007da07050217010007da070502170100\r\nfuzz_row,binary_types_datetime_15,880f000c000c010c020c030c040c050c0600000003686d7307da07050217013207da07050217013207da07050217013207da07050217013207da07050217013207da07050217013207da070502170132\r\nfuzz_row,binary_types_datetime_16,880f000c000c010c020c030c040c050c0600000019686d735f79726567756c61725f696e76616c69645f6461746507e4070b1f0a141e07e4070b1f0a141e07e4070b1f0a141e07e4070b1f0a141e07e4070b1f0a141e07e4070b1f0a141e07e4070b1f0a141e\r\nfuzz_row,binary_types_datetime_17,880f000c000c010c020c030c040c050c0600000021686d735f79726567756c61725f696e76616c69645f646174655f6c656170313030076c07021d0a141e076c07021d0a141e076c07021d0a141e076c07021d0a141e076c07021d0a141e076c07021d0a141e076c07021d0a141e\r\nfuzz_row,binary_types_datetime_18,880f000c000c010c020c030c040c050c0600000025686d735f79726567756c61725f696e76616c69645f646174655f6c656170726567756c617207cf07021d0a141e07cf07021d0a141e07cf07021d0a141e07cf07021d0a141e07cf07021d0a141e07cf07021d0a141e07cf07021d0a141e\r\nfuzz_row,binary_types_datetime_19,880f000c000c010c020c030c040c050c060000001b686d735f79726567756c61725f6d726567756c61725f647a65726f07e4070a000a141e07e4070a000a141e07e4070a000a141e07e4070a000a141e07e4070a000a141e07e4070a000a141e07e4070a000a141e\r\nfuzz_row,binary_types_datetime_20,880f000c000c010c020c030c040c050c060000001b686d735f79726567756c61725f6d7a65726f5f64726567756c617207e407000a0a141e07e407000a0a141e07e407000a0a141e07e407000a0a141e07e407000a0a141e07e407000a0a141e07e407000a0a141e\r\nfuzz_row,binary_types_datetime_21,880f000c000c010c020c030c040c050c0600000018686d735f79726567756c61725f6d7a65726f5f647a65726f07e40700000a141e07e40700000a141e07e40700000a141e07e40700000a141e07e40700000a141e07e40700000a141e07e40700000a141e\r\nfuzz_row,binary_types_datetime_22,880f000c000c010c020c030c040c050c0600000016686d735f797a65726f5f696e76616c69645f646174650700000b1f0a141e0700000b1f0a141e0700000b1f0a141e0700000b1f0a141e0700000b1f0a141e0700000b1f0a141e0700000b1f0a141e\r\nfuzz_row,binary_types_datetime_23,880f000c000c010c020c030c040c050c0600000018686d735f797a65726f5f6d726567756c61725f647a65726f0700000a000a141e0700000a000a141e0700000a000a141e0700000a000a141e0700000a000a141e0700000a000a141e0700000a000a141e\r\nfuzz_row,binary_types_datetime_24,880f000c000c010c020c030c040c050c0600000018686d735f797a65726f5f6d7a65726f5f64726567756c6172070000000a0a141e070000000a0a141e070000000a0a141e070000000a0a141e070000000a0a141e070000000a0a141e070000000a0a141e\r\nfuzz_row,binary_types_datetime_25,880f000c000c010c020c030c040c050c0600000008686d735f7a65726f07000000000a141e07000000000a141e07000000000a141e07000000000a141e07000000000a141e07000000000a141e07000000000a141e\r\nfuzz_row,binary_types_datetime_26,880f000c000c010c020c030c040c050c0600080004686d73750bda070502170132a08601000bda070502170132c0d401000bda07050217013278e001000bda07050217013208e201000bda0705021701323ae201000bda07050217013240e20100\r\nfuzz_row,binary_types_datetime_27,880f000c000c010c020c030c040c050c060000001a686d73755f79726567756c61725f696e76616c69645f6461746507e4070b1f0a141e0be4070b1f0a141ea0bb0d000be4070b1f0a141e301b0f000be4070b1f0a141e583e0f000be4070b1f0a141edc410f000be4070b1f0a141e36420f000be4070b1f0a141e3f420f00\r\nfuzz_row,binary_types_datetime_28,880f000c000c010c020c030c040c050c0600000022686d73755f79726567756c61725f696e76616c69645f646174655f6c656170313030076c07021d0a141e0b6c07021d0a141ea0bb0d000b6c07021d0a141e301b0f000b6c07021d0a141e583e0f000b6c07021d0a141edc410f000b6c07021d0a141e36420f000b6c07021d0a141e3f420f00\r\nfuzz_row,binary_types_datetime_29,880f000c000c010c020c030c040c050c0600000026686d73755f79726567756c61725f696e76616c69645f646174655f6c656170726567756c617207cf07021d0a141e0bcf07021d0a141ea0bb0d000bcf07021d0a141e301b0f000bcf07021d0a141e583e0f000bcf07021d0a141edc410f000bcf07021d0a141e36420f000bcf07021d0a141e3f420f00\r\nfuzz_row,binary_types_datetime_30,880f000c000c010c020c030c040c050c060000001c686d73755f79726567756c61725f6d726567756c61725f647a65726f07e4070a000a141e0be4070a000a141ea0bb0d000be4070a000a141e301b0f000be4070a000a141e583e0f000be4070a000a141edc410f000be4070a000a141e36420f000be4070a000a141e3f420f00\r\nfuzz_row,binary_types_datetime_31,880f000c000c010c020c030c040c050c060000001c686d73755f79726567756c61725f6d7a65726f5f64726567756c617207e407000a0a141e0be407000a0a141ea0bb0d000be407000a0a141e301b0f000be407000a0a141e583e0f000be407000a0a141edc410f000be407000a0a141e36420f000be407000a0a141e3f420f00\r\nfuzz_row,binary_types_datetime_32,880f000c000c010c020c030c040c050c0600000019686d73755f79726567756c61725f6d7a65726f5f647a65726f07e40700000a141e0be40700000a141ea0bb0d000be40700000a141e301b0f000be40700000a141e583e0f000be40700000a141edc410f000be40700000a141e36420f000be40700000a141e3f420f00\r\nfuzz_row,binary_types_datetime_33,880f000c000c010c020c030c040c050c0600000017686d73755f797a65726f5f696e76616c69645f646174650700000b1f0a141e0b00000b1f0a141ea0bb0d000b00000b1f0a141e301b0f000b00000b1f0a141e583e0f000b00000b1f0a141edc410f000b00000b1f0a141e36420f000b00000b1f0a141e3f420f00\r\nfuzz_row,binary_types_datetime_34,880f000c000c010c020c030c040c050c0600000019686d73755f797a65726f5f6d726567756c61725f647a65726f0700000a000a141e0b00000a000a141ea0bb0d000b00000a000a141e301b0f000b00000a000a141e583e0f000b00000a000a141edc410f000b00000a000a141e36420f000b00000a000a141e3f420f00\r\nfuzz_row,binary_types_datetime_35,880f000c000c010c020c030c040c050c0600000019686d73755f797a65726f5f6d7a65726f5f64726567756c6172070000000a0a141e0b0000000a0a141ea0bb0d000b0000000a0a141e301b0f000b0000000a0a141e583e0f000b0000000a0a141edc410f000b0000000a0a141e36420f000b0000000a0a141e3f420f00\r\nfuzz_row,binary_types_datetime_36,880f000c000c010c020c030c040c050c0600000009686d73755f7a65726f07000000000a141e0b000000000a141ea0bb0d000b000000000a141e301b0f000b000000000a141e583e0f000b000000000a141edc410f000b000000000a141e36420f000b000000000a141e3f420f00\r\nfuzz_row,binary_types_datetime_37,880f000c000c010c020c030c040c050c0600080003686d750bda070502170100a08601000bda070502170100c0d401000bda07050217010078e001000bda07050217010008e201000bda0705021701003ae201000bda07050217010040e20100\r\nfuzz_row,binary_types_datetime_38,880f000c000c010c020c030c040c050c0600000002687307da07050217003207da07050217003207da07050217003207da07050217003207da07050217003207da07050217003207da070502170032\r\nfuzz_row,binary_types_datetime_39,880f000c000c010c020c030c040c050c06000800036873750bda070502170032a08601000bda070502170032c0d401000bda07050217003278e001000bda07050217003208e201000bda0705021700323ae201000bda07050217003240e20100\r\nfuzz_row,binary_types_datetime_40,880f000c000c010c020c030c040c050c060008000268750bda070502170000a08601000bda070502170000c0d401000bda07050217000078e001000bda07050217000008e201000bda0705021700003ae201000bda07050217000040e20100\r\nfuzz_row,binary_types_datetime_41,880f000c000c010c020c030c040c050c06000000016d07da07050200010007da07050200010007da07050200010007da07050200010007da07050200010007da07050200010007da070502000100\r\nfuzz_row,binary_types_datetime_42,880f000c000c010c020c030c040c050c06000000036d6178070f270c1f173b3b0b0f270c1f173b3ba0bb0d000b0f270c1f173b3b301b0f000b0f270c1f173b3b583e0f000b0f270c1f173b3bdc410f000b0f270c1f173b3b36420f000b0f270c1f173b3b3f420f00\r\nfuzz_row,binary_types_datetime_43,880f000c000c010c020c030c040c050c06000000036d696e0400000101040000010104000001010400000101040000010104000001010400000101\r\nfuzz_row,binary_types_datetime_44,880f000c000c010c020c030c040c050c06000000026d7307da07050200013207da07050200013207da07050200013207da07050200013207da07050200013207da07050200013207da070502000132\r\nfuzz_row,binary_types_datetime_45,880f000c000c010c020c030c040c050c06000800036d73750bda070502000132a08601000bda070502000132c0d401000bda07050200013278e001000bda07050200013208e201000bda0705020001323ae201000bda07050200013240e20100\r\nfuzz_row,binary_types_datetime_46,880f000c000c010c020c030c040c050c06000800026d750bda070502000100a08601000bda070502000100c0d401000bda07050200010078e001000bda07050200010008e201000bda0705020001003ae201000bda07050200010040e20100\r\nfuzz_row,binary_types_datetime_47,880f000c000c010c020c030c040c050c06000000017307da07050200003207da07050200003207da07050200003207da07050200003207da07050200003207da07050200003207da070502000032\r\nfuzz_row,binary_types_datetime_48,880f000c000c010c020c030c040c050c060008000273750bda070502000032a08601000bda070502000032c0d401000bda07050200003278e001000bda07050200003208e201000bda0705020000323ae201000bda07050200003240e20100\r\nfuzz_row,binary_types_datetime_49,880f000c000c010c020c030c040c050c0600080001750bda070502000000a08601000bda070502000000c0d401000bda07050200000078e001000bda07050200000008e201000bda0705020000003ae201000bda07050200000040e20100\r\nfuzz_row,binary_types_double_0,850f00061f861f060a861f0050136672616374696f6e616c5f6e65676174697665cdcccccccccc10c0cdcccccccccc10c0\r\nfuzz_row,binary_types_double_1,850f00061f861f060a861f0000136672616374696f6e616c5f706f736974697665cdcccccccccc1040cdcccccccccc1040cdcccccccccc1040cdcccccccccc1040\r\nfuzz_row,binary_types_double_2,850f00061f861f060a861f00700c696e745f6e6567617469766500000000000010c0\r\nfuzz_row,binary_types_double_3,850f00061f861f060a861f00700c696e745f706f7369746976650000000000001040\r\nfuzz_row,binary_types_double_4,850f00061f861f060a861f0030206e656761746976655f6578705f706f7369746976655f6672616374696f6e616c394f16e0653a8316394f16e0653a8316\r\nfuzz_row,binary_types_double_5,850f00061f861f060a861f007020706f7369746976655f6578705f6e656761746976655f6672616374696f6e616cce463c769c6890e9\r\nfuzz_row,binary_types_double_6,850f00061f861f060a861f007019706f7369746976655f6578705f6e656761746976655f696e748713c343a55a8fe9\r\nfuzz_row,binary_types_double_7,850f00061f861f060a861f003020706f7369746976655f6578705f706f7369746976655f6672616374696f6e616cce463c769c689069ce463c769c689069\r\nfuzz_row,binary_types_double_8,850f00061f861f060a861f007019706f7369746976655f6578705f706f7369746976655f696e748713c343a55a8f69\r\nfuzz_row,binary_types_double_9,850f00061f861f060a861f0000047a65726f0000000000000000000000000000000000000000000000000000000000000000\r\nfuzz_row,binary_types_flags_0,860f000d0003000e000300030000080764656661756c74320000000463686172150000002a000000\r\nfuzz_row,binary_types_float_0,850f00051f851f050a851f0050136672616374696f6e616c5f6e65676174697665666686c0666686c0\r\nfuzz_row,binary_types_float_1,850f00051f851f050a851f0000136672616374696f6e616c5f706f73697469766566668640666686406666864066668640\r\nfuzz_row,binary_types_float_2,850f00051f851f050a851f00700c696e745f6e65676174697665000080c0\r\nfuzz_row,binary_types_float_3,850f00051f851f050a851f00700c696e745f706f73697469766500008040\r\nfuzz_row,binary_types_float_4,850f00051f851f050a851f0030206e656761746976655f6578705f706f7369746976655f6672616374696f6e616c4548141f4548141f\r\nfuzz_row,binary_types_float_5,850f00051f851f050a851f007020706f7369746976655f6578705f6e656761746976655f6672616374696f6e616c012d88e1\r\nfuzz_row,binary_types_float_6,850f00051f851f050a851f007019706f7369746976655f6578705f6e656761746976655f696e74b11a82e1\r\nfuzz_row,binary_types_float_7,850f00051f851f050a851f003020706f7369746976655f6578705f706f7369746976655f6672616374696f6e616c012d8861012d8861\r\nfuzz_row,binary_types_float_8,850f00051f851f050a851f007019706f7369746976655f6578705f706f7369746976655f696e74b11a8261\r\nfuzz_row,binary_types_float_9,850f00051f851f050a851f0000047a65726f00000000000000000000000000000000\r\nfuzz_row,binary_types_int_0,850f0003008300030083000060036d6178ffffff7fffffffff\r\nfuzz_row,binary_types_int_1,850f0003008300030083000020036d696e000000800000000000000000\r\nfuzz_row,binary_types_int_2,850f0003008300030083000050086e65676174697665ecffffffecffffff\r\nfuzz_row,binary_types_int_3,850f000300830003008300000007726567756c617214000000140000001400000014000000\r\nfuzz_row,binary_types_json_0,820f001600000005656d707479027b7d\r\nfuzz_row,binary_types_json_1,820f001600000007726567756c61722a5b6e756c6c2c2034322c2066616c73652c2022616263222c207b226b6579223a202276616c7565227d5d\r\nfuzz_row,binary_types_json_2,820f00160000000e756e69636f64655f657363617065155b225c753030303076616c75655c7530303030225d\r\nfuzz_row,binary_types_json_3,820f001600000004757466380a5b22616469c3b373225d\r\nfuzz_row,binary_types_mediumint_0,850f0002008200020082000060036d6178ffff7f00ffffff00\r\nfuzz_row,binary_types_mediumint_1,850f0002008200020082000020036d696e000080ff0000000000000000\r\nfuzz_row,binary_types_mediumint_2,850f0002008200020082000050086e65676174697665ecffffffecffffff\r\nfuzz_row,binary_types_mediumint_3,850f000200820002008200000007726567756c617214000000140000001400000014000000\r\nfuzz_row,binary_types_not_implemented_0,830f0007001700000007726567756c61720333303019000000000101000000000000000000f03f0000000000000040\r\nfuzz_row,binary_types_smallint_0,850f0001008100010081000060036d6178ff7fffff\r\nfuzz_row,binary_types_smallint_1,850f0001008100010081000020036d696e008000000000\r\nfuzz_row,binary_types_smallint_2,850f0001008100010081000050086e65676174697665ecffecff\r\nfuzz_row,binary_types_smallint_3,850f000100810001008100000007726567756c61721400140014001400\r\nfuzz_row,binary_types_string_0,8a0f000e000f00120012001200120012001400150000000405656d7074790000000000000000\r\nfuzz_row,binary_types_string_1,8a0f000e000f00120012001200120012001400150000000007726567756c617209746573745f636861720c746573745f766172636861720d746573745f74696e797465787409746573745f746578740f746573745f6d656469756d746578740d746573745f6c6f6e67746578740b746573745f62696e636f6c03726564097265642c677265656e\r\nfuzz_row,binary_types_string_2,8a0f000e000f00120012001200120012001400150000000c047574663802c3b102c39102c3a102c3a902c3ad02c3b302c3ba\r\nfuzz_row,binary_types_time_0,880f000a000a010a020a030a040a050a060000000164080002000000000000080002000000000000080002000000000000080002000000000000080002000000000000080002000000000000080002000000000000\r\nfuzz_row,binary_types_time_1,880f000a000a010a020a030a040a050a06000000026468080002000000170000080002000000170000080002000000170000080002000000170000080002000000170000080002000000170000080002000000170000\r\nfuzz_row,binary_types_time_2,880f000a000a010a020a030a040a050a060000000364686d080002000000170100080002000000170100080002000000170100080002000000170100080002000000170100080002000000170100080002000000170100\r\nfuzz_row,binary_types_time_3,880f000a000a010a020a030a040a050a060000000464686d73080002000000170132080002000000170132080002000000170132080002000000170132080002000000170132080002000000170132080002000000170132\r\nfuzz_row,binary_types_time_4,880f000a000a010a020a030a040a050a060008000564686d73750c0002000000170132a08601000c0002000000170132c0d401000c000200000017013278e001000c000200000017013208e201000c00020000001701323ae201000c000200000017013240e20100\r\nfuzz_row,binary_types_time_5,880f000a000a010a020a030a040a050a060008000464686d750c0002000000170100a08601000c0002000000170100c0d401000c000200000017010078e001000c000200000017010008e201000c00020000001701003ae201000c000200000017010040e20100\r\nfuzz_row,binary_types_time_6,880f000a000a010a020a030a040a050a0600000003646873080002000000170032080002000000170032080002000000170032080002000000170032080002000000170032080002000000170032080002000000170032\r\nfuzz_row,binary_types_time_7,880f000a000a010a020a030a040a050a0600080004646873750c0002000000170032a08601000c0002000000170032c0d401000c000200000017003278e001000c000200000017003208e201000c00020000001700323ae201000c000200000017003240e20100\r\nfuzz_row,binary_types_time_8,880f000a000a010a020a030a040a050a06000800036468750c0002000000170000a08601000c0002000000170000c0d401000c000200000017000078e001000c000200000017000008e201000c00020000001700003ae201000c000200000017000040e20100\r\nfuzz_row,binary_types_time_9,880f000a000a010a020a030a040a050a0600000002646d080002000000000100080002000000000100080002000000000100080002000000000100080002000000000100080002000000000100080002000000000100\r\nfuzz_row,binary_types_time_10,880f000a000a010a020a030a040a050a0600000003646d73080002000000000132080002000000000132080002000000000132080002000000000132080002000000000132080002000000000132080002000000000132\r\nfuzz_row,binary_types_time_11,880f000a000a010a020a030a040a050a0600080004646d73750c0002000000000132a08601000c0002000000000132c0d401000c000200000000013278e001000c000200000000013208e201000c00020000000001323ae201000c000200000000013240e20100\r\nfuzz_row,binary_types_time_12,880f000a000a010a020a030a040a050a0600080003646d750c0002000000000100a08601000c0002000000000100c0d401000c000200000000010078e001000c000200000000010008e201000c00020000000001003ae201000c000200000000010040e20100\r\nfuzz_row,binary_types_time_13,880f000a000a010a020a030a040a050a06000000026473080002000000000032080002000000000032080002000000000032080002000000000032080002000000000032080002000000000032080002000000000032\r\nfuzz_row,binary_types_time_14,880f000a000a010a020a030a040a050a06000800036473750c0002000000000032a08601000c0002000000000032c0d401000c000200000000003278e001000c000200000000003208e201000c00020000000000323ae201000c000200000000003240e20100\r\nfuzz_row,binary_types_time_15,880f000a000a010a020a030a040a050a060008000264750c0002000000000000a08601000c0002000000000000c0d401000c000200000000000078e001000c000200000000000008e201000c00020000000000003ae201000c000200000000000040e20100\r\nfuzz_row,binary_types_time_16,880f000a000a010a020a030a040a050a060000000168080000000000170000080000000000170000080000000000170000080000000000170000080000000000170000080000000000170000080000000000170000\r\nfuzz_row,binary_types_time_17,880f000a000a010a020a030a040a050a0600000002686d080000000000170100080000000000170100080000000000170100080000000000170100080000000000170100080000000000170100080000000000170100\r\nfuzz_row,binary_types_time_18,880f000a000a010a020a030a040a050a0600000003686d73080000000000170132080000000000170132080000000000170132080000000000170132080000000000170132080000000000170132080000000000170132\r\nfuzz_row,binary_types_time_19,880f000a000a010a020a030a040a050a0600080004686d73750c0000000000170132a08601000c0000000000170132c0d401000c000000000017013278e001000c000000000017013208e201000c00000000001701323ae201000c000000000017013240e20100\r\nfuzz_row,binary_types_time_20,880f000a000a010a020a030a040a050a0600080003686d750c0000000000170100a08601000c0000000000170100c0d401000c000000000017010078e001000c000000000017010008e201000c00000000001701003ae201000c000000000017010040e20100\r\nfuzz_row,binary_types_time_21,880f000a000a010a020a030a040a050a06000000026873080000000000170032080000000000170032080000000000170032080000000000170032080000000000170032080000000000170032080000000000170032\r\nfuzz_row,binary_types_time_22,880f000a000a010a020a030a040a050a06000800036873750c0000000000170032a08601000c0000000000170032c0d401000c000000000017003278e001000c000000000017003208e201000c00000000001700323ae201000c000000000017003240e20100\r\nfuzz_row,binary_types_time_23,880f000a000a010a020a030a040a050a060008000268750c0000000000170000a08601000c0000000000170000c0d401000c000000000017000078e001000c000000000017000008e201000c00000000001700003ae201000c000000000017000040e20100\r\nfuzz_row,binary_types_time_24,880f000a000a010a020a030a040a050a06000000016d080000000000000100080000000000000100080000000000000100080000000000000100080000000000000100080000000000000100080000000000000100\r\nfuzz_row,binary_types_time_25,880f000a000a010a020a030a040a050a06000000036d6178080022000000163b3b0c0022000000163b3aa0bb0d000c0022000000163b3a301b0f000c0022000000163b3a583e0f000c0022000000163b3adc410f000c0022000000163b3a36420f000c0022000000163b3a3f420f00\r\nfuzz_row,binary_types_time_26,880f000a000a010a020a030a040a050a06000000036d696e080122000000163b3b0c0122000000163b3aa0bb0d000c0122000000163b3a301b0f000c0122000000163b3a583e0f000c0122000000163b3adc410f000c0122000000163b3a36420f000c0122000000163b3a3f420f00\r\nfuzz_row,binary_types_time_27,880f000a000a010a020a030a040a050a06000000026d73080000000000000132080000000000000132080000000000000132080000000000000132080000000000000132080000000000000132080000000000000132\r\nfuzz_row,binary_types_time_28,880f000a000a010a020a030a040a050a06000800036d73750c0000000000000132a08601000c0000000000000132c0d401000c000000000000013278e001000c000000000000013208e201000c00000000000001323ae201000c000000000000013240e20100\r\nfuzz_row,binary_types_time_29,880f000a000a010a020a030a040a050a06000800026d750c0000000000000100a08601000c0000000000000100c0d401000c000000000000010078e001000c000000000000010008e201000c00000000000001003ae201000c000000000000010040e20100\r\nfuzz_row,binary_types_time_30,880f000a000a010a020a030a040a050a060000000a6e656761746976655f64080102000000000000080102000000000000080102000000000000080102000000000000080102000000000000080102000000000000080102000000000000\r\nfuzz_row,binary_types_time_31,880f000a000a010a020a030a040a050a060000000b6e656761746976655f6468080102000000170000080102000000170000080102000000170000080102000000170000080102000000170000080102000000170000080102000000170000\r\nfuzz_row,binary_types_time_32,880f000a000a010a020a030a040a050a060000000c6e656761746976655f64686d080102000000170100080102000000170100080102000000170100080102000000170100080102000000170100080102000000170100080102000000170100\r\nfuzz_row,binary_types_time_33,880f000a000a010a020a030a040a050a060000000d6e656761746976655f64686d73080102000000170132080102000000170132080102000000170132080102000000170132080102000000170132080102000000170132080102000000170132\r\nfuzz_row,binary_types_time_34,880f000a000a010a020a030a040a050a060008000e6e656761746976655f64686d73750c0102000000170132a08601000c0102000000170132c0d401000c010200000017013278e001000c010200000017013208e201000c01020000001701323ae201000c010200000017013240e20100\r\nfuzz_row,binary_types_time_35,880f000a000a010a020a030a040a050a060008000d6e656761746976655f64686d750c0102000000170100a08601000c0102000000170100c0d401000c010200000017010078e001000c010200000017010008e201000c01020000001701003ae201000c010200000017010040e20100\r\nfuzz_row,binary_types_time_36,880f000a000a010a020a030a040a050a060000000c6e656761746976655f646873080102000000170032080102000000170032080102000000170032080102000000170032080102000000170032080102000000170032080102000000170032\r\nfuzz_row,binary_types_time_37,880f000a000a010a020a030a040a050a060008000d6e656761746976655f646873750c0102000000170032a08601000c0102000000170032c0d401000c010200000017003278e001000c010200000017003208e201000c01020000001700323ae201000c010200000017003240e20100\r\nfuzz_row,binary_types_time_38,880f000a000a010a020a030a040a050a060008000c6e656761746976655f6468750c0102000000170000a08601000c0102000000170000c0d401000c010200000017000078e001000c010200000017000008e201000c01020000001700003ae201000c010200000017000040e20100\r\nfuzz_row,binary_types_time_39,880f000a000a010a020a030a040a050a060000000b6e656761746976655f646d080102000000000100080102000000000100080102000000000100080102000000000100080102000000000100080102000000000100080102000000000100\r\nfuzz_row,binary_types_time_40,880f000a000a010a020a030a040a050a060000000c6e656761746976655f646d73080102000000000132080102000000000132080102000000000132080102000000000132080102000000000132080102000000000132080102000000000132\r\nfuzz_row,binary_types_time_41,880f000a000a010a020a030a040a050a060008000d6e656761746976655f646d73750c0102000000000132a08601000c0102000000000132c0d401000c010200000000013278e001000c010200000000013208e201000c01020000000001323ae201000c010200000000013240e20100\r\nfuzz_row,binary_types_time_42,880f000a000a010a020a030a040a050a060008000c6e656761746976655f646d750c0102000000000100a08601000c0102000000000100c0d401000c010200000000010078e001000c010200000000010008e201000c01020000000001003ae201000c010200000000010040e20100\r\nfuzz_row,binary_types_time_43,880f000a000a010a020a030a040a050a060000000b6e656761746976655f6473080102000000000032080102000000000032080102000000000032080102000000000032080102000000000032080102000000000032080102000000000032\r\nfuzz_row,binary_types_time_44,880f000a000a010a020a030a040a050a060008000c6e656761746976655f6473750c0102000000000032a08601000c0102000000000032c0d401000c010200000000003278e001000c010200000000003208e201000c01020000000000323ae201000c010200000000003240e20100\r\nfuzz_row,binary_types_time_45,880f000a000a010a020a030a040a050a060008000b6e656761746976655f64750c0102000000000000a08601000c0102000000000000c0d401000c010200000000000078e001000c010200000000000008e201000c01020000000000003ae201000c010200000000000040e20100\r\nfuzz_row,binary_types_time_46,880f000a000a010a020a030a040a050a060000000a6e656761746976655f68080100000000170000080100000000170000080100000000170000080100000000170000080100000000170000080100000000170000080100000000170000\r\nfuzz_row,binary_types_time_47,880f000a000a010a020a030a040a050a060000000b6e656761746976655f686d080100000000170100080100000000170100080100000000170100080100000000170100080100000000170100080100000000170100080100000000170100\r\nfuzz_row,binary_types_time_48,880f000a000a010a020a030a040a050a060000000c6e656761746976655f686d73080100000000170132080100000000170132080100000000170132080100000000170132080100000000170132080100000000170132080100000000170132\r\nfuzz_row,binary_types_time_49,880f000a000a010a020a030a040a050a060008000d6e656761746976655f686d73750c0100000000170132a08601000c0100000000170132c0d401000c010000000017013278e001000c010000000017013208e201000c01000000001701323ae201000c010000000017013240e20100\r\nfuzz_row,binary_types_time_50,880f000a000a010a020a030a040a050a060008000c6e656761746976655f686d750c0100000000170100a08601000c0100000000170100c0d401000c010000000017010078e001000c010000000017010008e201000c01000000001701003ae201000c010000000017010040e20100\r\nfuzz_row,binary_types_time_51,880f000a000a010a020a030a040a050a060000000b6e656761746976655f6873080100000000170032080100000000170032080100000000170032080100000000170032080100000000170032080100000000170032080100000000170032\r\nfuzz_row,binary_types_time_52,880f000a000a010a020a030a040a050a060008000c6e656761746976655f6873750c0100000000170032a08601000c0100000000170032c0d401000c010000000017003278e001000c010000000017003208e201000c01000000001700323ae201000c010000000017003240e20100\r\nfuzz_row,binary_types_time_53,880f000a000a010a020a030a040a050a060008000b6e656761746976655f68750c0100000000170000a08601000c0100000000170000c0d401000c010000000017000078e001000c010000000017000008e201000c01000000001700003ae201000c010000000017000040e20100\r\nfuzz_row,binary_types_time_54,880f000a000a010a020a030a040a050a060000000a6e656761746976655f6d080100000000000100080100000000000100080100000000000100080100000000000100080100000000000100080100000000000100080100000000000100\r\nfuzz_row,binary_types_time_55,880f000a000a010a020a030a040a050a060000000b6e656761746976655f6d73080100000000000132080100000000000132080100000000000132080100000000000132080100000000000132080100000000000132080100000000000132\r\nfuzz_row,binary_types_time_56,880f000a000a010a020a030a040a050a060008000c6e656761746976655f6d73750c0100000000000132a08601000c0100000000000132c0d401000c010000000000013278e001000c010000000000013208e201000c01000000000001323ae201000c010000000000013240e20100\r\nfuzz_row,binary_types_time_57,880f000a000a010a020a030a040a050a060008000b6e656761746976655f6d750c0100000000000100a08601000c0100000000000100c0d401000c010000000000010078e001000c010000000000010008e201000c01000000000001003ae201000c010000000000010040e20100\r\nfuzz_row,binary_types_time_58,880f000a000a010a020a030a040a050a060000000a6e656761746976655f73080100000000000032080100000000000032080100000000000032080100000000000032080100000000000032080100000000000032080100000000000032\r\nfuzz_row,binary_types_time_59,880f000a000a010a020a030a040a050a060008000b6e656761746976655f73750c0100000000000032a08601000c0100000000000032c0d401000c010000000000003278e001000c010000000000003208e201000c01000000000000323ae201000c010000000000003240e20100\r\nfuzz_row,binary_types_time_60,880f000a000a010a020a030a040a050a060008000a6e656761746976655f750c0100000000000000a08601000c0100000000000000c0d401000c010000000000000078e001000c010000000000000008e201000c01000000000000003ae201000c010000000000000040e20100\r\nfuzz_row,binary_types_time_61,880f000a000a010a020a030a040a050a060000000173080000000000000032080000000000000032080000000000000032080000000000000032080000000000000032080000000000000032080000000000000032\r\nfuzz_row,binary_types_time_62,880f000a000a010a020a030a040a050a060008000273750c0000000000000032a08601000c0000000000000032c0d401000c000000000000003278e001000c000000000000003208e201000c00000000000000323ae201000c000000000000003240e20100\r\nfuzz_row,binary_types_time_63,880f000a000a010a020a030a040a050a0600080001750c0000000000000000a08601000c0000000000000000c0d401000c000000000000000078e001000c000000000000000008e201000c00000000000000003ae201000c000000000000000040e20100\r\nfuzz_row,binary_types_time_64,880f000a000a010a020a030a040a050a06000000047a65726f00000000000000\r\nfuzz_row,binary_types_timestamp_0,880f000d000d010d020d030d040d050d06000000046461746507da07050116000007da07050116000007da07050116000007da07050116000007da07050116000007da07050116000007da070501160000\r\nfuzz_row,binary_types_timestamp_1,880f000d000d010d020d030d040d050d060000000a646174655f6c6561703407d407021c16000007d407021c16000007d407021c16000007d407021c16000007d407021c16000007d407021c16000007d407021c160000\r\nfuzz_row,binary_types_timestamp_2,880f000d000d010d020d030d040d050d060000000c646174655f6c65617034303007d007021c16000007d007021c16000007d007021c16000007d007021c16000007d007021c16000007d007021c16000007d007021c160000\r\nfuzz_row,binary_types_timestamp_3,880f000d000d010d020d030d040d050d06000000016807da07050215000007da07050215000007da07050215000007da07050215000007da07050215000007da07050215000007da070502150000\r\nfuzz_row,binary_types_timestamp_4,880f000d000d010d020d030d040d050d0600000002686d07da07050215010007da07050215010007da07050215010007da07050215010007da07050215010007da07050215010007da070502150100\r\nfuzz_row,binary_types_timestamp_5,880f000d000d010d020d030d040d050d0600000003686d7307da07050215013207da07050215013207da07050215013207da07050215013207da07050215013207da07050215013207da070502150132\r\nfuzz_row,binary_types_timestamp_6,880f000d000d010d020d030d040d050d0600080004686d73750bda070502150132a08601000bda070502150132c0d401000bda07050215013278e001000bda07050215013208e201000bda0705021501323ae201000bda07050215013240e20100\r\nfuzz_row,binary_types_timestamp_7,880f000d000d010d020d030d040d050d0600080003686d750bda070502150100a08601000bda070502150100c0d401000bda07050215010078e001000bda07050215010008e201000bda0705021501003ae201000bda07050215010040e20100\r\nfuzz_row,binary_types_timestamp_8,880f000d000d010d020d030d040d050d0600000002687307da07050215003207da07050215003207da07050215003207da07050215003207da07050215003207da07050215003207da070502150032\r\nfuzz_row,binary_types_timestamp_9,880f000d000d010d020d030d040d050d06000800036873750bda070502150032a08601000bda070502150032c0d401000bda07050215003278e001000bda07050215003208e201000bda0705021500323ae201000bda07050215003240e20100\r\nfuzz_row,binary_types_timestamp_10,880f000d000d010d020d030d040d050d060008000268750bda070502150000a08601000bda070502150000c0d401000bda07050215000078e001000bda07050215000008e201000bda0705021500003ae201000bda07050215000040e20100\r\nfuzz_row,binary_types_timestamp_11,880f000d000d010d020d030d040d050d06000000016d07da07050116010007da07050116010007da07050116010007da07050116010007da07050116010007da07050116010007da070501160100\r\nfuzz_row,binary_types_timestamp_12,880f000d000d010d020d030d040d050d06000000036d617807f6070113030e070bf6070113030e07a0bb0d000bf6070113030e07301b0f000bf6070113030e07583e0f000bf6070113030e07dc410f000bf6070113030e0736420f000bf6070113030e073f420f00\r\nfuzz_row,binary_types_timestamp_13,880f000d000d010d020d030d040d050d06000000036d696e07b207010100000107b207010100000107b207010100000107b207010100000107b207010100000107b207010100000107b2070101000001\r\nfuzz_row,binary_types_timestamp_14,880f000d000d010d020d030d040d050d06000000026d7307da07050116013207da07050116013207da07050116013207da07050116013207da07050116013207da07050116013207da070501160132\r\nfuzz_row,binary_types_timestamp_15,880f000d000d010d020d030d040d050d06000800036d73750bda070501160132a08601000bda070501160132c0d401000bda07050116013278e001000bda07050116013208e201000bda0705011601323ae201000bda07050116013240e20100\r\nfuzz_row,binary_types_timestamp_16,880f000d000d010d020d030d040d050d06000800026d750bda070501160100a08601000bda070501160100c0d401000bda07050116010078e001000bda07050116010008e201000bda0705011601003ae201000bda07050116010040e20100\r\nfuzz_row,binary_types_timestamp_17,880f000d000d010d020d030d040d050d06000000017307da07050116003207da07050116003207da07050116003207da07050116003207da07050116003207da07050116003207da070501160032\r\nfuzz_row,binary_types_timestamp_18,880f000d000d010d020d030d040d050d060008000273750bda070501160032a08601000bda070501160032c0d401000bda07050116003278e001000bda07050116003208e201000bda0705011600323ae201000bda07050116003240e20100\r\nfuzz_row,binary_types_timestamp_19,880f000d000d010d020d030d040d050d0600080001750bda070501160000a08601000bda070501160000c0d401000bda07050116000078e001000bda07050116000008e201000bda0705011600003ae201000bda07050116000040e20100\r\nfuzz_row,binary_types_timestamp_20,880f000d000d010d020d030d040d050d06000000047a65726f00000000000000\r\nfuzz_row,binary_types_tinyint_0,850f0000008000000080000060036d61787fff\r\nfuzz_row,binary_types_tinyint_1,850f0000008000000080000020036d696e800000\r\nfuzz_row,binary_types_tinyint_2,850f0000008000000080000050086e65676174697665ecec\r\nfuzz_row,binary_types_tinyint_3,850f000000800000008000000007726567756c617214141414\r\nfuzz_row,binary_types_year_0,820f0089000000036d61786b08\r\nfuzz_row,binary_types_year_1,820f0089000000036d696e6d07\r\nfuzz_row,binary_types_year_2,820f008900000007726567756c6172e307\r\nfuzz_row,binary_types_year_3,820f0089000000047a65726f0000\r\nfuzz_row,binary_updates_table_0,8303000f0003000000010000000266302a000000\r\nfuzz_row,binary_updates_table_1,8303000f0003000000020000000266312b000000\r\nfuzz_row,binary_updates_table_2,8303000f00030000100300000005666e756c6c\r\n"
  },
  {
    "path": "tools/seed_corpus/protocol_messages.csv",
    "content": "fuzzer,name,content\r\nfuzz_ok_packet,successful_update,04002200000028526f7773206d6174636865643a203520204368616e6765643a203420205761726e696e67733a2030\r\nfuzz_ok_packet,successful_insert,010602000000\r\nfuzz_ok_packet,successful_login,000002000000\r\nfuzz_err_packet,wrong_use_database,1904233432303030556e6b6e6f776e20646174616261736520276127\r\nfuzz_err_packet,unknown_table,7a042334325330325461626c652027617765736f6d652e756e6b6e6f776e2720646f65736e2774206578697374\r\nfuzz_err_packet,failed_login,15042332383030304163636573732064656e69656420666f7220757365722027726f6f742740276c6f63616c686f73742720287573696e672070617373776f72643a2059455329\r\nfuzz_err_packet,no_error_message,1504233238303030\r\nfuzz_column_definition,numeric_auto_increment_primary_key,0364656607617765736f6d650a746573745f7461626c650a746573745f7461626c650269640269640c3f000b000000030342000000\r\nfuzz_column_definition,varchar_field_aliased_field_and_table_names_join,0364656607617765736f6d65056368696c640b6368696c645f7461626c650b6669656c645f616c6961730d6669656c645f766172636861720c2100fd020000fd0000000000\r\nfuzz_column_definition,float_field,0364656607617765736f6d650a746573745f7461626c650a746573745f7461626c650b6669656c645f666c6f61740b6669656c645f666c6f61740c3f000c0000000400001f0000\r\nfuzz_column_definition,no_final_padding,0364656607617765736f6d650a746573745f7461626c650a746573745f7461626c650b6669656c645f666c6f61740b6669656c645f666c6f61740a3f000c0000000400001f\r\nfuzz_column_definition,more_final_padding,0364656607617765736f6d650a746573745f7461626c650a746573745f7461626c650b6669656c645f666c6f61740b6669656c645f666c6f61740d3f000c0000000400001f000000\r\nfuzz_ok_response,success,00010602000000\r\nfuzz_ok_response,err_packet,ff1504233238303030\r\nfuzz_prepare_stmt_response,success,000100000002000300000000\r\nfuzz_prepare_stmt_response,err_packet,ff1504233238303030\r\nfuzz_execute_response,num_fields,01\r\nfuzz_execute_response,num_fields_multibyte,fcff00\r\nfuzz_execute_response,ok_packet,00000002000000\r\nfuzz_execute_response,err_packet,ff7a042334325330325461626c6520276d79746573742e6162632720646f65736e2774206578697374\r\nfuzz_row_message,row,086c6561705f3430300a323030302d30322d3239\r\nfuzz_row_message,ok_packet,fe000002000000\r\nfuzz_row_message,err_packet,ff1504233238303030\r\nfuzz_server_hello,hello,352e372e32372d307562756e7475302e31392e30342e310002000000521a503a4b12702f00fff7080200ff811500000000000000000000035a7405282b7f21434a2162006d7973716c5f6e61746976655f70617373776f726400\r\nfuzz_auth_switch,default,6d7973716c5f6e61746976655f70617373776f72640049497e515d1f196a0f5a63153e28313e3c79097c00\r\nfuzz_handshake_server_response,more_data,01616263\r\nfuzz_handshake_server_response,ok_packet,00000002000000\r\nfuzz_handshake_server_response,err_packet,15042332383030304163636573732064656e69656420666f7220757365722027726f6f742740276c6f63616c686f73742720287573696e672070617373776f72643a2059455329\r\n"
  },
  {
    "path": "tools/seed_corpus/sql_injection_payloads.txt",
    "content": "6772\nf0',\"(..)())\nf0'Zsstap<'\">TJPatz\nf0) AND 8959=3845-- XGtb\nf0) AND 4531=4531-- mqZt\nf0' AND 6396=8996-- PYds\nf0' AND 4531=4531-- WKgw\nf0) AND 7063=6741 AND (8582=8582\nf0) AND 4531=4531 AND (4502=4502\nf0)) AND 3299=9968 AND ((3319=3319\nf0)) AND 4531=4531 AND ((7226=7226\nf0))) AND 9766=7660 AND (((4155=4155\nf0))) AND 4531=4531 AND (((6740=6740\nf0 AND 8959=7008\nf0 AND 4531=4531\nf0') AND 7815=9179 AND ('PLkm'='PLkm\nf0') AND 4531=4531 AND ('wkON'='wkON\nf0')) AND 7318=1210 AND (('rmap'='rmap\nf0')) AND 4531=4531 AND (('pgrZ'='pgrZ\nf0'))) AND 7925=6432 AND ((('LZxA'='LZxA\nf0'))) AND 4531=4531 AND ((('jVAA'='jVAA\nf0' AND 7864=6910 AND 'eprB'='eprB\nf0' AND 4531=4531 AND 'XfLu'='XfLu\nf0') AND 5469=9821 AND ('UWqX' LIKE 'UWqX\nf0') AND 4531=4531 AND ('glRL' LIKE 'glRL\nf0')) AND 8692=4535 AND (('VufD' LIKE 'VufD\nf0')) AND 4531=4531 AND (('HBkW' LIKE 'HBkW\nf0%' AND 3064=4066 AND 'IDlo%'='IDlo\nf0%' AND 4531=4531 AND 'jVSr%'='jVSr\nf0' AND 6134=4598 AND 'LJuE' LIKE 'LJuE\nf0' AND 4531=4531 AND 'EkOD' LIKE 'EkOD\nf0\") AND 5358=5172 AND (\"tXPu\"=\"tXPu\nf0\") AND 4531=4531 AND (\"lxaw\"=\"lxaw\nf0\")) AND 2372=2459 AND ((\"QeBd\"=\"QeBd\nf0\")) AND 4531=4531 AND ((\"BPZc\"=\"BPZc\nf0\" AND 1560=8031 AND \"StAy\"=\"StAy\nf0\" AND 4531=4531 AND \"lNIh\"=\"lNIh\nf0\") AND 4858=8434 AND (\"DMgP\" LIKE \"DMgP\nf0\") AND 4531=4531 AND (\"cgFe\" LIKE \"cgFe\nf0\" AND 1939=3348 AND \"cRfl\" LIKE \"cRfl\nf0\" AND 4531=4531 AND \"ytdT\" LIKE \"ytdT\nf0 AND 8243=7035-- FNiX\nf0 AND 4531=4531-- bPrH\nf0 AND 9918=5861# mGZS\nf0 AND 4531=4531# HfKH\nf0' AND 8315=7511 OR 'GfFr'='vwVE\nf0' AND 4531=4531 OR 'dDVo'='qiLP\n-6469\n-6426) OR 4640=5042-- LMFf\n-3878) OR 1957=1957-- phCp\n-2550' OR 9017=1336-- sqpL\n-3595' OR 1957=1957-- zIrz\n-2606) OR 6934=7574 AND (7039=7039\n-1628) OR 1957=1957 AND (7334=7334\n-1629)) OR 1004=5646 AND ((9245=9245\n-8712)) OR 1957=1957 AND ((3026=3026\n-8903))) OR 4609=1925 AND (((8461=8461\n-4674))) OR 1957=1957 AND (((3287=3287\n-3278 OR 6514=2093\n-5401 OR 1957=1957\n-8123') OR 8329=7278 AND ('BWUr'='BWUr\n-7648') OR 1957=1957 AND ('AmgC'='AmgC\n-4920')) OR 2783=9608 AND (('rLIW'='rLIW\n-5452')) OR 1957=1957 AND (('PLpI'='PLpI\n-1958'))) OR 3704=5034 AND ((('PtDU'='PtDU\n-2609'))) OR 1957=1957 AND ((('CMMj'='CMMj\n-8537' OR 7729=7714 AND 'CLdS'='CLdS\n-9788' OR 1957=1957 AND 'GemB'='GemB\n-4843') OR 4790=4844 AND ('PKon' LIKE 'PKon\n-2090') OR 1957=1957 AND ('GtEb' LIKE 'GtEb\n-8354')) OR 2670=7893 AND (('mVdX' LIKE 'mVdX\n-7474')) OR 1957=1957 AND (('IuYe' LIKE 'IuYe\n-1157%' OR 4070=4967 AND 'ZyXU%'='ZyXU\n-7981%' OR 1957=1957 AND 'fDqp%'='fDqp\n-4209' OR 2210=2768 AND 'lltt' LIKE 'lltt\n-6857' OR 1957=1957 AND 'XwZI' LIKE 'XwZI\n-3320\") OR 7479=3476 AND (\"fmwU\"=\"fmwU\n-8137\") OR 1957=1957 AND (\"VIgz\"=\"VIgz\n-4729\")) OR 1733=1134 AND ((\"PweF\"=\"PweF\n-9187\")) OR 1957=1957 AND ((\"WRHT\"=\"WRHT\n-6869\" OR 3948=9404 AND \"yBKP\"=\"yBKP\n-3855\" OR 1957=1957 AND \"ncaP\"=\"ncaP\n-9193\") OR 9526=6368 AND (\"pKyx\" LIKE \"pKyx\n-7538\") OR 1957=1957 AND (\"HqMS\" LIKE \"HqMS\n-5185\" OR 2378=7723 AND \"TsbJ\" LIKE \"TsbJ\n-2966\" OR 1957=1957 AND \"hYEl\" LIKE \"hYEl\n-6724 OR 7709=2534-- HPGv\n-5761 OR 1957=1957-- MOkF\n-1569 OR 2755=4165# KcFG\n-3286 OR 1957=1957# xUZP\n-1602' OR 8014=7747 OR 'HSLO'='NUMN\n-2302' OR 1957=1957 OR 'SrXh'='wEKD\nf0) OR NOT 7429=7625-- pISW\nf0) OR NOT 9480=9480-- MsJn\nf0' OR NOT 9683=5619-- ibYd\nf0' OR NOT 9480=9480-- udSh\nf0) OR NOT 5913=4262 AND (8922=8922\nf0) OR NOT 9480=9480 AND (8230=8230\nf0)) OR NOT 8495=8664 AND ((5574=5574\nf0)) OR NOT 9480=9480 AND ((7818=7818\nf0))) OR NOT 4140=4905 AND (((9124=9124\nf0))) OR NOT 9480=9480 AND (((5658=5658\nf0 OR NOT 7144=3213\nf0 OR NOT 9480=9480\nf0') OR NOT 5794=6699 AND ('iVqj'='iVqj\nf0') OR NOT 9480=9480 AND ('JBxm'='JBxm\nf0')) OR NOT 9407=3767 AND (('fRxb'='fRxb\nf0')) OR NOT 9480=9480 AND (('diwF'='diwF\nf0'))) OR NOT 2582=8887 AND ((('Bmxa'='Bmxa\nf0'))) OR NOT 9480=9480 AND ((('PvXo'='PvXo\nf0' OR NOT 1519=4176 AND 'lEAI'='lEAI\nf0' OR NOT 9480=9480 AND 'Twca'='Twca\nf0') OR NOT 9158=2119 AND ('uGts' LIKE 'uGts\nf0') OR NOT 9480=9480 AND ('goWK' LIKE 'goWK\nf0')) OR NOT 3717=4479 AND (('bJNN' LIKE 'bJNN\nf0')) OR NOT 9480=9480 AND (('Issd' LIKE 'Issd\nf0%' OR NOT 6838=7215 AND 'qhof%'='qhof\nf0%' OR NOT 9480=9480 AND 'VrkB%'='VrkB\nf0' OR NOT 9149=6840 AND 'iBMm' LIKE 'iBMm\nf0' OR NOT 9480=9480 AND 'Ifho' LIKE 'Ifho\nf0\") OR NOT 6509=6697 AND (\"TZng\"=\"TZng\nf0\") OR NOT 9480=9480 AND (\"OfaT\"=\"OfaT\nf0\")) OR NOT 2027=9428 AND ((\"tWaa\"=\"tWaa\nf0\")) OR NOT 9480=9480 AND ((\"EjIE\"=\"EjIE\nf0\" OR NOT 2178=3946 AND \"wdml\"=\"wdml\nf0\" OR NOT 9480=9480 AND \"jDCH\"=\"jDCH\nf0\") OR NOT 7418=8925 AND (\"Wggx\" LIKE \"Wggx\nf0\") OR NOT 9480=9480 AND (\"HbBC\" LIKE \"HbBC\nf0\" OR NOT 7507=6669 AND \"oJda\" LIKE \"oJda\nf0\" OR NOT 9480=9480 AND \"OSNL\" LIKE \"OSNL\nf0 OR NOT 9102=8265-- XwSL\nf0 OR NOT 9480=9480-- Euta\nf0 OR NOT 3099=7841# AxYG\nf0 OR NOT 9480=9480# reeV\nf0' OR NOT 2581=1347 OR 'YRKc'='LLCG\nf0' OR NOT 9480=9480 OR 'avtl'='LkSn\nf0) AND 7363=(SELECT (CASE WHEN (7363=5849) THEN 7363 ELSE (SELECT 5849 UNION SELECT 7424) END))-- -\nf0) AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0' AND 4726=(SELECT (CASE WHEN (4726=7076) THEN 4726 ELSE (SELECT 7076 UNION SELECT 5032) END))-- -\nf0' AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0)) AND 2056=(SELECT (CASE WHEN (2056=2185) THEN 2056 ELSE (SELECT 2185 UNION SELECT 2766) END))-- -\nf0)) AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0))) AND 7407=(SELECT (CASE WHEN (7407=2983) THEN 7407 ELSE (SELECT 2983 UNION SELECT 9401) END))-- -\nf0))) AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0 AND 2863=(SELECT (CASE WHEN (2863=8210) THEN 2863 ELSE (SELECT 8210 UNION SELECT 6900) END))-- -\nf0 AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0') AND 6960=(SELECT (CASE WHEN (6960=2600) THEN 6960 ELSE (SELECT 2600 UNION SELECT 7048) END))-- -\nf0') AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0')) AND 2114=(SELECT (CASE WHEN (2114=4152) THEN 2114 ELSE (SELECT 4152 UNION SELECT 2117) END))-- -\nf0')) AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0'))) AND 9223=(SELECT (CASE WHEN (9223=1156) THEN 9223 ELSE (SELECT 1156 UNION SELECT 1025) END))-- -\nf0'))) AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0%' AND 9496=(SELECT (CASE WHEN (9496=4624) THEN 9496 ELSE (SELECT 4624 UNION SELECT 9702) END))-- -\nf0%' AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0\") AND 9790=(SELECT (CASE WHEN (9790=9248) THEN 9790 ELSE (SELECT 9248 UNION SELECT 7670) END))-- -\nf0\") AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0\")) AND 5541=(SELECT (CASE WHEN (5541=6055) THEN 5541 ELSE (SELECT 6055 UNION SELECT 9394) END))-- -\nf0\")) AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\nf0\" AND 6194=(SELECT (CASE WHEN (6194=4519) THEN 6194 ELSE (SELECT 4519 UNION SELECT 9436) END))-- -\nf0\" AND 4962=(SELECT (CASE WHEN (4962=4962) THEN 4962 ELSE (SELECT 8677 UNION SELECT 3275) END))-- -\n-7891) OR 5460=(SELECT (CASE WHEN (5460=5370) THEN 5460 ELSE (SELECT 5370 UNION SELECT 5941) END))-- -\n-1560) OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-1407' OR 7657=(SELECT (CASE WHEN (7657=4269) THEN 7657 ELSE (SELECT 4269 UNION SELECT 1925) END))-- -\n-4180' OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-9949)) OR 6970=(SELECT (CASE WHEN (6970=4714) THEN 6970 ELSE (SELECT 4714 UNION SELECT 2701) END))-- -\n-6363)) OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-4332))) OR 6952=(SELECT (CASE WHEN (6952=8980) THEN 6952 ELSE (SELECT 8980 UNION SELECT 3108) END))-- -\n-4218))) OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-7057 OR 6812=(SELECT (CASE WHEN (6812=3587) THEN 6812 ELSE (SELECT 3587 UNION SELECT 4359) END))-- -\n-9237 OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-2400') OR 9765=(SELECT (CASE WHEN (9765=5693) THEN 9765 ELSE (SELECT 5693 UNION SELECT 6573) END))-- -\n-5874') OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-1432')) OR 8902=(SELECT (CASE WHEN (8902=8292) THEN 8902 ELSE (SELECT 8292 UNION SELECT 2714) END))-- -\n-4054')) OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-7797'))) OR 2693=(SELECT (CASE WHEN (2693=7891) THEN 2693 ELSE (SELECT 7891 UNION SELECT 5054) END))-- -\n-3396'))) OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-8882%' OR 9624=(SELECT (CASE WHEN (9624=5590) THEN 9624 ELSE (SELECT 5590 UNION SELECT 1840) END))-- -\n-6906%' OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-1071\") OR 6798=(SELECT (CASE WHEN (6798=9125) THEN 6798 ELSE (SELECT 9125 UNION SELECT 1012) END))-- -\n-6623\") OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-9200\")) OR 4661=(SELECT (CASE WHEN (4661=4240) THEN 4661 ELSE (SELECT 4240 UNION SELECT 1990) END))-- -\n-7730\")) OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\n-5972\" OR 6887=(SELECT (CASE WHEN (6887=1211) THEN 6887 ELSE (SELECT 1211 UNION SELECT 9594) END))-- -\n-6708\" OR 3059=(SELECT (CASE WHEN (3059=3059) THEN 3059 ELSE (SELECT 3727 UNION SELECT 2491) END))-- -\nf0) AND 8351=4354-- -\nf0) AND 3425=3425-- -\nf0' AND 8445=8156-- -\nf0' AND 3425=3425-- -\nf0)) AND 7614=3171-- -\nf0)) AND 3425=3425-- -\nf0))) AND 6748=2276-- -\nf0))) AND 3425=3425-- -\nf0 AND 2837=8777-- -\nf0 AND 3425=3425-- -\nf0') AND 1996=9992-- -\nf0') AND 3425=3425-- -\nf0')) AND 4194=2474-- -\nf0')) AND 3425=3425-- -\nf0'))) AND 2448=6320-- -\nf0'))) AND 3425=3425-- -\nf0%' AND 1043=1238-- -\nf0%' AND 3425=3425-- -\nf0\") AND 9284=7217-- -\nf0\") AND 3425=3425-- -\nf0\")) AND 7908=5205-- -\nf0\")) AND 3425=3425-- -\nf0\" AND 2580=8932-- -\nf0\" AND 3425=3425-- -\n-4729) OR 4651=4694-- -\n-9949) OR 2800=2800-- -\n-6215' OR 5801=1147-- -\n-3004' OR 2800=2800-- -\n-3313)) OR 8303=3905-- -\n-7257)) OR 2800=2800-- -\n-3129))) OR 9573=4346-- -\n-6728))) OR 2800=2800-- -\n-7144 OR 4019=1632-- -\n-8847 OR 2800=2800-- -\n-4862') OR 9224=6553-- -\n-7073') OR 2800=2800-- -\n-1536')) OR 8582=5519-- -\n-9035')) OR 2800=2800-- -\n-9188'))) OR 7525=7521-- -\n-4836'))) OR 2800=2800-- -\n-7932%' OR 3401=5834-- -\n-1795%' OR 2800=2800-- -\n-2384\") OR 6328=3079-- -\n-1668\") OR 2800=2800-- -\n-4570\")) OR 7291=8570-- -\n-6408\")) OR 2800=2800-- -\n-6000\" OR 8686=2068-- -\n-7732\" OR 2800=2800-- -\n(SELECT (CASE WHEN (4700=5809) THEN 0x6630 ELSE (SELECT 5809 UNION SELECT 2229) END))\n(SELECT (CASE WHEN (7382=7382) THEN 0x6630 ELSE (SELECT 3745 UNION SELECT 4295) END))\n(CASE WHEN (1554=7133) THEN 1554 ELSE 1554*(SELECT 1554 FROM DUAL UNION SELECT 7133 FROM DUAL) END)\n(CASE WHEN (3305=3305) THEN 3305 ELSE 3305*(SELECT 3305 FROM DUAL UNION SELECT 3256 FROM DUAL) END)\n(CASE WHEN (8906=1347) THEN 0x6630 ELSE 8906*(SELECT 8906 FROM DUAL UNION SELECT 1347 FROM DUAL) END)\n(CASE WHEN (6275=6275) THEN 0x6630 ELSE 6275*(SELECT 6275 FROM DUAL UNION SELECT 4878 FROM DUAL) END)\n(CASE WHEN 8688=5531 THEN 8688 ELSE NULL END)\n(CASE WHEN 2011=2011 THEN 2011 ELSE NULL END)\n(CASE WHEN 1134=9933 THEN 0x6630 ELSE NULL END)\n(CASE WHEN 6028=6028 THEN 0x6630 ELSE NULL END)\nf0) HAVING 2440=4990-- XAzm\nf0) HAVING 2142=2142-- nhGE\nf0' HAVING 4948=1416-- ORhY\nf0' HAVING 2142=2142-- oUKC\nf0) HAVING 6487=6870 AND (5574=5574\nf0) HAVING 2142=2142 AND (3944=3944\nf0)) HAVING 6250=8650 AND ((9653=9653\nf0)) HAVING 2142=2142 AND ((5477=5477\nf0))) HAVING 6019=9757 AND (((4509=4509\nf0))) HAVING 2142=2142 AND (((7009=7009\nf0 HAVING 7924=9462\nf0 HAVING 2142=2142\nf0') HAVING 6180=4681 AND ('fXdl'='fXdl\nf0') HAVING 2142=2142 AND ('sprp'='sprp\nf0')) HAVING 2867=2633 AND (('AovG'='AovG\nf0')) HAVING 2142=2142 AND (('erKM'='erKM\nf0'))) HAVING 6587=3226 AND ((('mbAD'='mbAD\nf0'))) HAVING 2142=2142 AND ((('mIhm'='mIhm\nf0' HAVING 6798=5705 AND 'Dcek'='Dcek\nf0' HAVING 2142=2142 AND 'nAOr'='nAOr\nf0') HAVING 1595=6831 AND ('qrbB' LIKE 'qrbB\nf0') HAVING 2142=2142 AND ('APOb' LIKE 'APOb\nf0')) HAVING 7313=7000 AND (('Xkgk' LIKE 'Xkgk\nf0')) HAVING 2142=2142 AND (('WvcV' LIKE 'WvcV\nf0%' HAVING 1299=5899 AND 'ePVW%'='ePVW\nf0%' HAVING 2142=2142 AND 'gCgG%'='gCgG\nf0' HAVING 1964=1256 AND 'qoKK' LIKE 'qoKK\nf0' HAVING 2142=2142 AND 'WecZ' LIKE 'WecZ\nf0\") HAVING 3286=6591 AND (\"AzWw\"=\"AzWw\nf0\") HAVING 2142=2142 AND (\"BzTr\"=\"BzTr\nf0\")) HAVING 3921=4513 AND ((\"hoER\"=\"hoER\nf0\")) HAVING 2142=2142 AND ((\"LLin\"=\"LLin\nf0\" HAVING 8186=4149 AND \"vRKq\"=\"vRKq\nf0\" HAVING 2142=2142 AND \"BVKg\"=\"BVKg\nf0\") HAVING 4885=3587 AND (\"iaRm\" LIKE \"iaRm\nf0\") HAVING 2142=2142 AND (\"JmWM\" LIKE \"JmWM\nf0\" HAVING 8842=5378 AND \"GuLX\" LIKE \"GuLX\nf0\" HAVING 2142=2142 AND \"WPTa\" LIKE \"WPTa\nf0 HAVING 5685=9824-- cBdg\nf0 HAVING 2142=2142-- HMIw\nf0 HAVING 9491=7674# ovRB\nf0 HAVING 2142=2142# gKqq\nf0' HAVING 2893=2315 OR 'CeTw'='TmND\nf0' HAVING 2142=2142 OR 'EjIq'='WTLV\n(SELECT CONCAT(CONCAT(0x71626a7171,(CASE WHEN (2328=2328) THEN 0x31 ELSE 0x30 END)),0x716a6a7171))\nf0) AND 5133=5227#\nf0) AND 8780=8780#\nf0' AND 6028=6939#\nf0' AND 8780=8780#\nf0)) AND 6454=4709#\nf0)) AND 8780=8780#\nf0))) AND 2351=3792#\nf0))) AND 8780=8780#\nf0 AND 1325=1357#\nf0 AND 8780=8780#\nf0') AND 4694=7069#\nf0') AND 8780=8780#\nf0')) AND 8330=4391#\nf0')) AND 8780=8780#\nf0'))) AND 4180=7417#\nf0'))) AND 8780=8780#\nf0%' AND 6385=9362#\nf0%' AND 8780=8780#\nf0\") AND 9026=5856#\nf0\") AND 8780=8780#\nf0\")) AND 5693=4162#\nf0\")) AND 8780=8780#\nf0\" AND 7547=3738#\nf0\" AND 8780=8780#\n-4199) OR 2882=6732#\n-6782) OR 5124=5124#\n-4009' OR 4587=9285#\n-2830' OR 5124=5124#\n-7532)) OR 9245=5857#\n-4608)) OR 5124=5124#\n-8296))) OR 5392=8704#\n-6327))) OR 5124=5124#\n-2613 OR 6363=8520#\n-5573 OR 5124=5124#\n-3658') OR 5632=9874#\n-4305') OR 5124=5124#\n-7240')) OR 1627=5296#\n-6209')) OR 5124=5124#\n-4484'))) OR 4631=1332#\n-4955'))) OR 5124=5124#\n-5525%' OR 8626=3085#\n-9932%' OR 5124=5124#\n-1028\") OR 1468=9516#\n-8317\") OR 5124=5124#\n-5427\")) OR 7800=5698#\n-9107\")) OR 5124=5124#\n-2455\" OR 5910=2827#\n-2839\" OR 5124=5124#\nf0) OR NOT 5069=7210#\nf0) OR NOT 7625=7625#\nf0' OR NOT 1815=4075#\nf0' OR NOT 7625=7625#\nf0)) OR NOT 2255=6729#\nf0)) OR NOT 7625=7625#\nf0))) OR NOT 1380=2063#\nf0))) OR NOT 7625=7625#\nf0 OR NOT 4680=5212#\nf0 OR NOT 7625=7625#\nf0') OR NOT 8442=9021#\nf0') OR NOT 7625=7625#\nf0')) OR NOT 3935=5693#\nf0')) OR NOT 7625=7625#\nf0'))) OR NOT 3793=9331#\nf0'))) OR NOT 7625=7625#\nf0%' OR NOT 9274=7906#\nf0%' OR NOT 7625=7625#\nf0\") OR NOT 8928=4303#\nf0\") OR NOT 7625=7625#\nf0\")) OR NOT 9442=3410#\nf0\")) OR NOT 7625=7625#\nf0\" OR NOT 4203=6643#\nf0\" OR NOT 7625=7625#\nf0) RLIKE (SELECT (CASE WHEN (4074=5891) THEN 0x6630 ELSE 0x28 END))-- cJIS\nf0) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END))-- PvfQ\nf0' RLIKE (SELECT (CASE WHEN (3190=1268) THEN 0x6630 ELSE 0x28 END))-- uvfG\nf0' RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END))-- KYzI\nf0) RLIKE (SELECT (CASE WHEN (9110=4941) THEN 0x6630 ELSE 0x28 END)) AND (6006=6006\nf0) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND (5830=5830\nf0)) RLIKE (SELECT (CASE WHEN (6438=3165) THEN 0x6630 ELSE 0x28 END)) AND ((6956=6956\nf0)) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND ((6627=6627\nf0))) RLIKE (SELECT (CASE WHEN (4621=2003) THEN 0x6630 ELSE 0x28 END)) AND (((3024=3024\nf0))) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND (((9386=9386\nf0 RLIKE (SELECT (CASE WHEN (8452=1556) THEN 0x6630 ELSE 0x28 END))\nf0 RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END))\nf0') RLIKE (SELECT (CASE WHEN (8083=3929) THEN 0x6630 ELSE 0x28 END)) AND ('vsGy'='vsGy\nf0') RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND ('RMfF'='RMfF\nf0')) RLIKE (SELECT (CASE WHEN (1873=8752) THEN 0x6630 ELSE 0x28 END)) AND (('SZeD'='SZeD\nf0')) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND (('XjBc'='XjBc\nf0'))) RLIKE (SELECT (CASE WHEN (1747=6083) THEN 0x6630 ELSE 0x28 END)) AND ((('QzIm'='QzIm\nf0'))) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND ((('UFih'='UFih\nf0' RLIKE (SELECT (CASE WHEN (1799=7236) THEN 0x6630 ELSE 0x28 END)) AND 'DHGh'='DHGh\nf0' RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND 'wHEA'='wHEA\nf0') RLIKE (SELECT (CASE WHEN (3497=3976) THEN 0x6630 ELSE 0x28 END)) AND ('jQPq' LIKE 'jQPq\nf0') RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND ('mvcS' LIKE 'mvcS\nf0')) RLIKE (SELECT (CASE WHEN (6835=6473) THEN 0x6630 ELSE 0x28 END)) AND (('CDCz' LIKE 'CDCz\nf0')) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND (('OAEh' LIKE 'OAEh\nf0%' RLIKE (SELECT (CASE WHEN (1126=7605) THEN 0x6630 ELSE 0x28 END)) AND 'JLeP%'='JLeP\nf0%' RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND 'PcNE%'='PcNE\nf0' RLIKE (SELECT (CASE WHEN (7628=2815) THEN 0x6630 ELSE 0x28 END)) AND 'vSOI' LIKE 'vSOI\nf0' RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND 'OPLw' LIKE 'OPLw\nf0\") RLIKE (SELECT (CASE WHEN (4760=9678) THEN 0x6630 ELSE 0x28 END)) AND (\"svTB\"=\"svTB\nf0\") RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND (\"Rxzv\"=\"Rxzv\nf0\")) RLIKE (SELECT (CASE WHEN (1264=3227) THEN 0x6630 ELSE 0x28 END)) AND ((\"MKjj\"=\"MKjj\nf0\")) RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND ((\"xqVl\"=\"xqVl\nf0\" RLIKE (SELECT (CASE WHEN (2535=5280) THEN 0x6630 ELSE 0x28 END)) AND \"sdin\"=\"sdin\nf0\" RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND \"wYQW\"=\"wYQW\nf0\") RLIKE (SELECT (CASE WHEN (3441=2572) THEN 0x6630 ELSE 0x28 END)) AND (\"oIXi\" LIKE \"oIXi\nf0\") RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND (\"qpHX\" LIKE \"qpHX\nf0\" RLIKE (SELECT (CASE WHEN (2497=1042) THEN 0x6630 ELSE 0x28 END)) AND \"DLhs\" LIKE \"DLhs\nf0\" RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) AND \"gRCc\" LIKE \"gRCc\nf0 RLIKE (SELECT (CASE WHEN (9120=1686) THEN 0x6630 ELSE 0x28 END))-- iypo\nf0 RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END))-- neer\nf0 RLIKE (SELECT (CASE WHEN (1086=5503) THEN 0x6630 ELSE 0x28 END))# Tfev\nf0 RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END))# ArZU\nf0' RLIKE (SELECT (CASE WHEN (9927=5697) THEN 0x6630 ELSE 0x28 END)) OR 'yCpP'='daSK\nf0' RLIKE (SELECT (CASE WHEN (3368=3368) THEN 0x6630 ELSE 0x28 END)) OR 'bJlG'='iXUX\nf0) AND MAKE_SET(3169=5783,5783)-- WbUn\nf0) AND MAKE_SET(3486=3486,7088)-- PPUm\nf0' AND MAKE_SET(7737=9241,9241)-- rsSM\nf0' AND MAKE_SET(3486=3486,7088)-- doKs\nf0) AND MAKE_SET(4416=4229,4229) AND (6922=6922\nf0) AND MAKE_SET(3486=3486,7088) AND (7002=7002\nf0)) AND MAKE_SET(2041=7520,7520) AND ((5076=5076\nf0)) AND MAKE_SET(3486=3486,7088) AND ((9830=9830\nf0))) AND MAKE_SET(4702=9132,9132) AND (((5051=5051\nf0))) AND MAKE_SET(3486=3486,7088) AND (((6124=6124\nf0 AND MAKE_SET(2706=1764,1764)\nf0 AND MAKE_SET(3486=3486,7088)\nf0') AND MAKE_SET(8582=2450,2450) AND ('tZWb'='tZWb\nf0') AND MAKE_SET(3486=3486,7088) AND ('jBtd'='jBtd\nf0')) AND MAKE_SET(9205=8632,8632) AND (('CKdQ'='CKdQ\nf0')) AND MAKE_SET(3486=3486,7088) AND (('VWmg'='VWmg\nf0'))) AND MAKE_SET(8974=2235,2235) AND ((('RcIL'='RcIL\nf0'))) AND MAKE_SET(3486=3486,7088) AND ((('IMaF'='IMaF\nf0' AND MAKE_SET(2737=9639,9639) AND 'ayVA'='ayVA\nf0' AND MAKE_SET(3486=3486,7088) AND 'vLIL'='vLIL\nf0') AND MAKE_SET(4272=2869,2869) AND ('qNxu' LIKE 'qNxu\nf0') AND MAKE_SET(3486=3486,7088) AND ('wNLH' LIKE 'wNLH\nf0')) AND MAKE_SET(8593=1016,1016) AND (('bNdU' LIKE 'bNdU\nf0')) AND MAKE_SET(3486=3486,7088) AND (('Ouzx' LIKE 'Ouzx\nf0%' AND MAKE_SET(2369=1044,1044) AND 'fZYK%'='fZYK\nf0%' AND MAKE_SET(3486=3486,7088) AND 'riPV%'='riPV\nf0' AND MAKE_SET(4671=2471,2471) AND 'ylty' LIKE 'ylty\nf0' AND MAKE_SET(3486=3486,7088) AND 'ZLwc' LIKE 'ZLwc\nf0\") AND MAKE_SET(2231=6272,6272) AND (\"hnyf\"=\"hnyf\nf0\") AND MAKE_SET(3486=3486,7088) AND (\"xJPJ\"=\"xJPJ\nf0\")) AND MAKE_SET(1999=6197,6197) AND ((\"pZHP\"=\"pZHP\nf0\")) AND MAKE_SET(3486=3486,7088) AND ((\"lxuR\"=\"lxuR\nf0\" AND MAKE_SET(5334=5133,5133) AND \"DQQX\"=\"DQQX\nf0\" AND MAKE_SET(3486=3486,7088) AND \"zRzk\"=\"zRzk\nf0\") AND MAKE_SET(8334=3333,3333) AND (\"wYDn\" LIKE \"wYDn\nf0\") AND MAKE_SET(3486=3486,7088) AND (\"bQXo\" LIKE \"bQXo\nf0\" AND MAKE_SET(6666=9746,9746) AND \"Qdcd\" LIKE \"Qdcd\nf0\" AND MAKE_SET(3486=3486,7088) AND \"gxRr\" LIKE \"gxRr\nf0 AND MAKE_SET(2624=1784,1784)-- lZWw\nf0 AND MAKE_SET(3486=3486,7088)-- YwRB\nf0 AND MAKE_SET(7609=5195,5195)# mwmv\nf0 AND MAKE_SET(3486=3486,7088)# afYz\nf0' AND MAKE_SET(6719=2818,2818) OR 'qyWe'='Rqxg\nf0' AND MAKE_SET(3486=3486,7088) OR 'AOvt'='PUtC\n-9483) OR MAKE_SET(6906=8088,8088)-- BBOV\n-6228) OR MAKE_SET(6015=6015,5404)-- ayhD\n-7193' OR MAKE_SET(2406=3564,3564)-- Fqis\n-9225' OR MAKE_SET(6015=6015,5404)-- vTJC\n-2309) OR MAKE_SET(6699=7533,7533) AND (1072=1072\n-4086) OR MAKE_SET(6015=6015,5404) AND (4508=4508\n-9035)) OR MAKE_SET(8994=9497,9497) AND ((4799=4799\n-5311)) OR MAKE_SET(6015=6015,5404) AND ((8671=8671\n-4869))) OR MAKE_SET(3518=3966,3966) AND (((4899=4899\n-2101))) OR MAKE_SET(6015=6015,5404) AND (((7923=7923\n-3062 OR MAKE_SET(5857=9247,9247)\n-3754 OR MAKE_SET(6015=6015,5404)\n-6946') OR MAKE_SET(5787=9619,9619) AND ('qYGe'='qYGe\n-1896') OR MAKE_SET(6015=6015,5404) AND ('bpaS'='bpaS\n-6455')) OR MAKE_SET(9671=4871,4871) AND (('qACE'='qACE\n-4999')) OR MAKE_SET(6015=6015,5404) AND (('UfBi'='UfBi\n-1330'))) OR MAKE_SET(1537=9562,9562) AND ((('DDRQ'='DDRQ\n-2401'))) OR MAKE_SET(6015=6015,5404) AND ((('pdXR'='pdXR\n-3979' OR MAKE_SET(9290=8540,8540) AND 'YaNG'='YaNG\n-9365' OR MAKE_SET(6015=6015,5404) AND 'KOJy'='KOJy\n-7602') OR MAKE_SET(4061=6862,6862) AND ('pDqR' LIKE 'pDqR\n-3369') OR MAKE_SET(6015=6015,5404) AND ('DQNr' LIKE 'DQNr\n-9530')) OR MAKE_SET(9699=6969,6969) AND (('fmTX' LIKE 'fmTX\n-8358')) OR MAKE_SET(6015=6015,5404) AND (('iqXW' LIKE 'iqXW\n-3871%' OR MAKE_SET(7411=7017,7017) AND 'bffG%'='bffG\n-2186%' OR MAKE_SET(6015=6015,5404) AND 'kiZQ%'='kiZQ\n-8208' OR MAKE_SET(6776=6854,6854) AND 'TyuD' LIKE 'TyuD\n-7603' OR MAKE_SET(6015=6015,5404) AND 'GNLh' LIKE 'GNLh\n-9823\") OR MAKE_SET(7334=3392,3392) AND (\"pgsi\"=\"pgsi\n-1480\") OR MAKE_SET(6015=6015,5404) AND (\"YNQT\"=\"YNQT\n-3763\")) OR MAKE_SET(7354=1439,1439) AND ((\"MKfv\"=\"MKfv\n-4903\")) OR MAKE_SET(6015=6015,5404) AND ((\"HqKI\"=\"HqKI\n-8658\" OR MAKE_SET(1678=8748,8748) AND \"KSYl\"=\"KSYl\n-8671\" OR MAKE_SET(6015=6015,5404) AND \"dCoF\"=\"dCoF\n-2564\") OR MAKE_SET(7309=6608,6608) AND (\"BFjI\" LIKE \"BFjI\n-5175\") OR MAKE_SET(6015=6015,5404) AND (\"GooX\" LIKE \"GooX\n-1664\" OR MAKE_SET(1566=9834,9834) AND \"GOij\" LIKE \"GOij\n-5894\" OR MAKE_SET(6015=6015,5404) AND \"KuMD\" LIKE \"KuMD\n-8028 OR MAKE_SET(4603=8375,8375)-- teAl\n-8916 OR MAKE_SET(6015=6015,5404)-- tRAc\n-8410 OR MAKE_SET(6852=4690,4690)# Qvsp\n-2677 OR MAKE_SET(6015=6015,5404)# DIKh\n-4512' OR MAKE_SET(4819=5540,5540) OR 'xJhW'='RDfD\n-9891' OR MAKE_SET(6015=6015,5404) OR 'XeKd'='aMoG\nf0',(SELECT (CASE WHEN (3990=4709) THEN 1 ELSE 3990*(SELECT 3990 FROM INFORMATION_SCHEMA.PLUGINS) END))-- rlgG\nf0',(SELECT (CASE WHEN (6046=6046) THEN 1 ELSE 6046*(SELECT 6046 FROM INFORMATION_SCHEMA.PLUGINS) END))-- nTao\nf0,(SELECT (CASE WHEN (1682=5873) THEN 1 ELSE 1682*(SELECT 1682 FROM INFORMATION_SCHEMA.PLUGINS) END))\nf0,(SELECT (CASE WHEN (6046=6046) THEN 1 ELSE 6046*(SELECT 6046 FROM INFORMATION_SCHEMA.PLUGINS) END))\nf0',(SELECT (CASE WHEN (6987=6645) THEN 0x6630 ELSE 6987*(SELECT 6987 FROM INFORMATION_SCHEMA.PLUGINS) END))-- IqkO\nf0',(SELECT (CASE WHEN (6507=6507) THEN 0x6630 ELSE 6507*(SELECT 6507 FROM INFORMATION_SCHEMA.PLUGINS) END))-- YzeM\nf0,(SELECT (CASE WHEN (1127=6683) THEN 0x6630 ELSE 1127*(SELECT 1127 FROM INFORMATION_SCHEMA.PLUGINS) END))\nf0,(SELECT (CASE WHEN (6507=6507) THEN 0x6630 ELSE 6507*(SELECT 6507 FROM INFORMATION_SCHEMA.PLUGINS) END))\nf0) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- IlMJ\nf0' AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- yDyd\nf0) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (5575=5575\nf0)) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ((1568=1568\nf0))) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (((9563=9563\nf0 AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)\nf0') AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ('eCcr'='eCcr\nf0')) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (('jyxd'='jyxd\nf0'))) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ((('RveO'='RveO\nf0' AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'eeiK'='eeiK\nf0') AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ('MHTX' LIKE 'MHTX\nf0')) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (('JDUS' LIKE 'JDUS\nf0%' AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Chei%'='Chei\nf0' AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Ubnc' LIKE 'Ubnc\nf0\") AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (\"nwHK\"=\"nwHK\nf0\")) AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ((\"sYoy\"=\"sYoy\nf0\" AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND \"UMbK\"=\"UMbK\nf0\") AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (\"pnQH\" LIKE \"pnQH\nf0\" AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND \"IRHf\" LIKE \"IRHf\nf0 AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- BftB\nf0 AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)# IoXH\nf0' AND (SELECT 4582 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4582=4582,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) OR 'Uxmv'='EfJE\nf0) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- rzfn\nf0' OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- brRP\nf0) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (4961=4961\nf0)) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ((5960=5960\nf0))) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (((9710=9710\nf0 OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)\nf0') OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ('yhzC'='yhzC\nf0')) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (('MuSr'='MuSr\nf0'))) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ((('eSgr'='eSgr\nf0' OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'vsoi'='vsoi\nf0') OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ('MwbY' LIKE 'MwbY\nf0')) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (('ObiO' LIKE 'ObiO\nf0%' OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'SPMZ%'='SPMZ\nf0' OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'Zhme' LIKE 'Zhme\nf0\") OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (\"TDvQ\"=\"TDvQ\nf0\")) OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND ((\"pgbI\"=\"pgbI\nf0\" OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND \"scUl\"=\"scUl\nf0\") OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND (\"DrXO\" LIKE \"DrXO\nf0\" OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND \"HyiE\" LIKE \"HyiE\nf0 OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- pNcn\nf0 OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)# ZWFR\nf0' OR (SELECT 5189 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(5189=5189,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) OR 'iIcx'='LVnQ\nf0) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171))-- sItp\nf0' AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171))-- irCa\nf0) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND (9361=9361\nf0)) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND ((4825=4825\nf0))) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND (((1502=1502\nf0 AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171))\nf0') AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND ('CsAE'='CsAE\nf0')) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND (('nkTG'='nkTG\nf0'))) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND ((('JUOQ'='JUOQ\nf0' AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND 'lhJY'='lhJY\nf0') AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND ('uFLV' LIKE 'uFLV\nf0')) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND (('pAKr' LIKE 'pAKr\nf0%' AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND 'HJkN%'='HJkN\nf0' AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND 'aroD' LIKE 'aroD\nf0\") AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND (\"jivW\"=\"jivW\nf0\")) AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND ((\"asta\"=\"asta\nf0\" AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND \"WSEk\"=\"WSEk\nf0\") AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND (\"adRg\" LIKE \"adRg\nf0\" AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) AND \"VoNF\" LIKE \"VoNF\nf0 AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171))-- DbCQ\nf0 AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171))# RRJM\nf0' AND EXTRACTVALUE(8287,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(8287=8287,1))),0x716a6a7171)) OR 'dHns'='svFb\nf0) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171))-- FfjJ\nf0' OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171))-- tRzv\nf0) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND (3747=3747\nf0)) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND ((9580=9580\nf0))) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND (((9006=9006\nf0 OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171))\nf0') OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND ('TUQM'='TUQM\nf0')) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND (('BLgk'='BLgk\nf0'))) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND ((('pYpj'='pYpj\nf0' OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND 'sBMg'='sBMg\nf0') OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND ('GbxH' LIKE 'GbxH\nf0')) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND (('hWxC' LIKE 'hWxC\nf0%' OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND 'jwfz%'='jwfz\nf0' OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND 'KxPq' LIKE 'KxPq\nf0\") OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND (\"otQX\"=\"otQX\nf0\")) OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND ((\"VkLe\"=\"VkLe\nf0\" OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND \"uaFM\"=\"uaFM\nf0\") OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND (\"tZWK\" LIKE \"tZWK\nf0\" OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) AND \"JlsB\" LIKE \"JlsB\nf0 OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171))-- ybtr\nf0 OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171))# KQxi\nf0' OR EXTRACTVALUE(6500,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6500=6500,1))),0x716a6a7171)) OR 'UFlg'='fjGQ\nf0) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556)-- HiYp\nf0' AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556)-- CZdV\nf0) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND (6032=6032\nf0)) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND ((9483=9483\nf0))) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND (((7583=7583\nf0 AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556)\nf0') AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND ('skuf'='skuf\nf0')) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND (('rkFE'='rkFE\nf0'))) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND ((('wQji'='wQji\nf0' AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND 'AFnW'='AFnW\nf0') AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND ('bfaa' LIKE 'bfaa\nf0')) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND (('GAoh' LIKE 'GAoh\nf0%' AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND 'LPEP%'='LPEP\nf0' AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND 'EwlP' LIKE 'EwlP\nf0\") AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND (\"lFSy\"=\"lFSy\nf0\")) AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND ((\"buLA\"=\"buLA\nf0\" AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND \"dEYF\"=\"dEYF\nf0\") AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND (\"lzAc\" LIKE \"lzAc\nf0\" AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) AND \"venW\" LIKE \"venW\nf0 AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556)-- raRi\nf0 AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556)# TEpc\nf0' AND UPDATEXML(9486,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(9486=9486,1))),0x716a6a7171),2556) OR 'lEQb'='kCbr\nf0) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101)-- CLou\nf0' OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101)-- rgEM\nf0) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND (7224=7224\nf0)) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND ((4578=4578\nf0))) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND (((3942=3942\nf0 OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101)\nf0') OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND ('dBVJ'='dBVJ\nf0')) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND (('xVzG'='xVzG\nf0'))) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND ((('fNXK'='fNXK\nf0' OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND 'vYKM'='vYKM\nf0') OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND ('Trkw' LIKE 'Trkw\nf0')) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND (('jTyX' LIKE 'jTyX\nf0%' OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND 'oagm%'='oagm\nf0' OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND 'WaZO' LIKE 'WaZO\nf0\") OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND (\"VdtL\"=\"VdtL\nf0\")) OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND ((\"sWtm\"=\"sWtm\nf0\" OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND \"LxEH\"=\"LxEH\nf0\") OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND (\"HUHq\" LIKE \"HUHq\nf0\" OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) AND \"cGVq\" LIKE \"cGVq\nf0 OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101)-- hFEf\nf0 OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101)# kSfc\nf0' OR UPDATEXML(5437,CONCAT(0x2e,0x71626a7171,(SELECT (ELT(5437=5437,1))),0x716a6a7171),9101) OR 'bTeF'='idvq\nf0) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x)-- Qsmk\nf0' AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x)-- qhxJ\nf0) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND (5067=5067\nf0)) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND ((5522=5522\nf0))) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND (((4498=4498\nf0 AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x)\nf0') AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND ('oOJU'='oOJU\nf0')) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND (('EGJd'='EGJd\nf0'))) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND ((('YJMz'='YJMz\nf0' AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND 'dnGV'='dnGV\nf0') AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND ('ENhl' LIKE 'ENhl\nf0')) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND (('bcEy' LIKE 'bcEy\nf0%' AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND 'hmUF%'='hmUF\nf0' AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND 'zkCy' LIKE 'zkCy\nf0\") AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND (\"UvhF\"=\"UvhF\nf0\")) AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND ((\"TJCN\"=\"TJCN\nf0\" AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND \"Zsnl\"=\"Zsnl\nf0\") AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND (\"SzGR\" LIKE \"SzGR\nf0\" AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) AND \"zFxN\" LIKE \"zFxN\nf0 AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x)-- KiLE\nf0 AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x)# Oxxz\nf0' AND ROW(3164,9057)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3164=3164,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 6949 UNION SELECT 6262 UNION SELECT 2516 UNION SELECT 7555)a GROUP BY x) OR 'hwfK'='swJV\nf0) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x)-- Tlis\nf0' OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x)-- Ishx\nf0) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND (9057=9057\nf0)) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND ((3747=3747\nf0))) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND (((9821=9821\nf0 OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x)\nf0') OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND ('kznN'='kznN\nf0')) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND (('dOvl'='dOvl\nf0'))) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND ((('IurR'='IurR\nf0' OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND 'FtAA'='FtAA\nf0') OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND ('XQYe' LIKE 'XQYe\nf0')) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND (('uJrn' LIKE 'uJrn\nf0%' OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND 'kiJi%'='kiJi\nf0' OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND 'uKMZ' LIKE 'uKMZ\nf0\") OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND (\"DlNe\"=\"DlNe\nf0\")) OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND ((\"JVoV\"=\"JVoV\nf0\" OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND \"sRyk\"=\"sRyk\nf0\") OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND (\"ontP\" LIKE \"ontP\nf0\" OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) AND \"FLrS\" LIKE \"FLrS\nf0 OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x)-- pfTh\nf0 OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x)# mHRd\nf0' OR ROW(9259,1295)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(9259=9259,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 4598 UNION SELECT 6479 UNION SELECT 9777 UNION SELECT 5335)a GROUP BY x) OR 'umtK'='pMMF\nf0) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1)-- FjMy\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1)-- qpZd\nf0) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND (2391=2391\nf0)) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND ((3843=3843\nf0))) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND (((3309=3309\nf0 PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1)\nf0') PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND ('yhDD'='yhDD\nf0')) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND (('TLlP'='TLlP\nf0'))) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND ((('QNDt'='QNDt\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND 'GAKG'='GAKG\nf0') PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND ('hjie' LIKE 'hjie\nf0')) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND (('dMte' LIKE 'dMte\nf0%' PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND 'EBMr%'='EBMr\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND 'FEZR' LIKE 'FEZR\nf0\") PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND (\"UIsm\"=\"UIsm\nf0\")) PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND ((\"xRVb\"=\"xRVb\nf0\" PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND \"Bpjc\"=\"Bpjc\nf0\") PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND (\"YoJE\" LIKE \"YoJE\nf0\" PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) AND \"PAJJ\" LIKE \"PAJJ\nf0 PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1)-- LUnE\nf0 PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1)# iMVa\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(2744,CONCAT(0x5c,0x71626a7171,(SELECT (CASE WHEN (2744=2744) THEN 1 ELSE 0 END)),0x716a6a7171)),1) OR 'Btqz'='JAgt\n(SELECT 4288 FROM(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(4288=4288,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)\n(EXTRACTVALUE(6628,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(6628=6628,1))),0x716a6a7171)))\nf0',EXTRACTVALUE(7813,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(7813=7813,1))),0x716a6a7171))-- iUHr\nf0,EXTRACTVALUE(7813,CONCAT(0x5c,0x71626a7171,(SELECT (ELT(7813=7813,1))),0x716a6a7171))\nf0',(SELECT 3402 FROM (SELECT ROW(3402,1030)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3402=3402,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 7626 UNION SELECT 7953 UNION SELECT 8218 UNION SELECT 8107)a GROUP BY x))s)-- zSde\nf0,(SELECT 3402 FROM (SELECT ROW(3402,1030)>(SELECT COUNT(*),CONCAT(0x71626a7171,(SELECT (ELT(3402=3402,1))),0x716a6a7171,FLOOR(RAND(0)*2))x FROM (SELECT 7626 UNION SELECT 7953 UNION SELECT 8218 UNION SELECT 8107)a GROUP BY x))s)\n(SELECT CONCAT(0x71626a7171,(ELT(7153=7153,1)),0x716a6a7171))\nf0);SELECT SLEEP(5)#\nf0';SELECT SLEEP(5)#\nf0));SELECT SLEEP(5)#\nf0)));SELECT SLEEP(5)#\nf0;SELECT SLEEP(5)#\nf0');SELECT SLEEP(5)#\nf0'));SELECT SLEEP(5)#\nf0')));SELECT SLEEP(5)#\nf0%';SELECT SLEEP(5)#\nf0\");SELECT SLEEP(5)#\nf0\"));SELECT SLEEP(5)#\nf0\";SELECT SLEEP(5)#\nf0);SELECT SLEEP(5)-- UwML\nf0';SELECT SLEEP(5)-- Kotq\nf0);SELECT SLEEP(5) AND (5986=5986\nf0));SELECT SLEEP(5) AND ((7992=7992\nf0)));SELECT SLEEP(5) AND (((8517=8517\nf0;SELECT SLEEP(5)\nf0');SELECT SLEEP(5) AND ('PnOC'='PnOC\nf0'));SELECT SLEEP(5) AND (('KknJ'='KknJ\nf0')));SELECT SLEEP(5) AND ((('aotd'='aotd\nf0';SELECT SLEEP(5) AND 'iuCM'='iuCM\nf0');SELECT SLEEP(5) AND ('sGkw' LIKE 'sGkw\nf0'));SELECT SLEEP(5) AND (('sFWq' LIKE 'sFWq\nf0%';SELECT SLEEP(5) AND 'gmDv%'='gmDv\nf0';SELECT SLEEP(5) AND 'PdYG' LIKE 'PdYG\nf0\");SELECT SLEEP(5) AND (\"HcMH\"=\"HcMH\nf0\"));SELECT SLEEP(5) AND ((\"OHXO\"=\"OHXO\nf0\";SELECT SLEEP(5) AND \"gxwn\"=\"gxwn\nf0\");SELECT SLEEP(5) AND (\"Bdll\" LIKE \"Bdll\nf0\";SELECT SLEEP(5) AND \"UrgW\" LIKE \"UrgW\nf0;SELECT SLEEP(5)-- qdAH\nf0;SELECT SLEEP(5)# VTQH\nf0';SELECT SLEEP(5) OR 'XfvF'='LnxY\nf0);(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0';(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0));(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0)));(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0;(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0');(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0'));(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0')));(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0%';(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0\");(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0\"));(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0\";(SELECT * FROM (SELECT(SLEEP(5)))gWjP)#\nf0);SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0';SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0));SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0)));SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0;SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0');SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0'));SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0')));SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0%';SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0\");SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0\"));SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0\";SELECT BENCHMARK(5000000,MD5(0x78435778))#\nf0) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa)-- mBCY\nf0' AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa)-- NUDo\nf0) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND (6987=6987\nf0)) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND ((2467=2467\nf0))) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND (((4228=4228\nf0 AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa)\nf0') AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND ('sRDX'='sRDX\nf0')) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND (('qdlx'='qdlx\nf0'))) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND ((('hmqT'='hmqT\nf0' AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND 'Isly'='Isly\nf0') AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND ('gUqG' LIKE 'gUqG\nf0')) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND (('gXiZ' LIKE 'gXiZ\nf0%' AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND 'mWJs%'='mWJs\nf0' AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND 'JgJi' LIKE 'JgJi\nf0\") AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND (\"ExOI\"=\"ExOI\nf0\")) AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND ((\"XjRO\"=\"XjRO\nf0\" AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND \"FnYQ\"=\"FnYQ\nf0\") AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND (\"JdZo\" LIKE \"JdZo\nf0\" AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) AND \"eAoH\" LIKE \"eAoH\nf0 AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa)-- sVdo\nf0 AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa)# vuEn\nf0' AND (SELECT 7962 FROM (SELECT(SLEEP(5)))XSoa) OR 'IKVl'='tXeZ\nf0) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG)-- jDph\nf0' OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG)-- FLuZ\nf0) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND (8139=8139\nf0)) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND ((6418=6418\nf0))) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND (((9101=9101\nf0 OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG)\nf0') OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND ('iqCu'='iqCu\nf0')) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND (('lXfb'='lXfb\nf0'))) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND ((('AQGI'='AQGI\nf0' OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND 'PMhN'='PMhN\nf0') OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND ('MjhS' LIKE 'MjhS\nf0')) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND (('gdFg' LIKE 'gdFg\nf0%' OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND 'cFLh%'='cFLh\nf0' OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND 'erEX' LIKE 'erEX\nf0\") OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND (\"mEvF\"=\"mEvF\nf0\")) OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND ((\"sdEa\"=\"sdEa\nf0\" OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND \"GuFx\"=\"GuFx\nf0\") OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND (\"Zzqm\" LIKE \"Zzqm\nf0\" OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) AND \"YZcI\" LIKE \"YZcI\nf0 OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG)-- DLYT\nf0 OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG)# jisK\nf0' OR (SELECT 2317 FROM (SELECT(SLEEP(5)))mAAG) OR 'wEbX'='fTBL\nf0) AND SLEEP(5)-- sMCl\nf0' AND SLEEP(5)-- vNOX\nf0) AND SLEEP(5) AND (9459=9459\nf0)) AND SLEEP(5) AND ((7076=7076\nf0))) AND SLEEP(5) AND (((7589=7589\nf0 AND SLEEP(5)\nf0') AND SLEEP(5) AND ('jtVl'='jtVl\nf0')) AND SLEEP(5) AND (('dFLP'='dFLP\nf0'))) AND SLEEP(5) AND ((('Evsj'='Evsj\nf0' AND SLEEP(5) AND 'DBtN'='DBtN\nf0') AND SLEEP(5) AND ('GCEq' LIKE 'GCEq\nf0')) AND SLEEP(5) AND (('DERX' LIKE 'DERX\nf0%' AND SLEEP(5) AND 'jxHj%'='jxHj\nf0' AND SLEEP(5) AND 'gsfQ' LIKE 'gsfQ\nf0\") AND SLEEP(5) AND (\"aUYK\"=\"aUYK\nf0\")) AND SLEEP(5) AND ((\"OOBB\"=\"OOBB\nf0\" AND SLEEP(5) AND \"WuhK\"=\"WuhK\nf0\") AND SLEEP(5) AND (\"DZOQ\" LIKE \"DZOQ\nf0\" AND SLEEP(5) AND \"vdPS\" LIKE \"vdPS\nf0 AND SLEEP(5)-- SLQk\nf0 AND SLEEP(5)# CCbg\nf0' AND SLEEP(5) OR 'ggIr'='geSa\nf0) OR SLEEP(5)-- fahk\nf0' OR SLEEP(5)-- GLHI\nf0) OR SLEEP(5) AND (1421=1421\nf0)) OR SLEEP(5) AND ((4035=4035\nf0))) OR SLEEP(5) AND (((2730=2730\nf0 OR SLEEP(5)\nf0') OR SLEEP(5) AND ('KSRO'='KSRO\nf0')) OR SLEEP(5) AND (('TdRo'='TdRo\nf0'))) OR SLEEP(5) AND ((('NzOY'='NzOY\nf0' OR SLEEP(5) AND 'Gngs'='Gngs\nf0') OR SLEEP(5) AND ('tVUz' LIKE 'tVUz\nf0')) OR SLEEP(5) AND (('mCFx' LIKE 'mCFx\nf0%' OR SLEEP(5) AND 'Qqcv%'='Qqcv\nf0' OR SLEEP(5) AND 'SjIb' LIKE 'SjIb\nf0\") OR SLEEP(5) AND (\"AAqN\"=\"AAqN\nf0\")) OR SLEEP(5) AND ((\"bgGm\"=\"bgGm\nf0\" OR SLEEP(5) AND \"Csof\"=\"Csof\nf0\") OR SLEEP(5) AND (\"JAKv\" LIKE \"JAKv\nf0\" OR SLEEP(5) AND \"wicw\" LIKE \"wicw\nf0 OR SLEEP(5)-- fbtY\nf0 OR SLEEP(5)# DITX\nf0' OR SLEEP(5) OR 'AUZm'='oQAx\nf0) AND SLEEP(5)#\nf0' AND SLEEP(5)#\nf0)) AND SLEEP(5)#\nf0))) AND SLEEP(5)#\nf0 AND SLEEP(5)#\nf0') AND SLEEP(5)#\nf0')) AND SLEEP(5)#\nf0'))) AND SLEEP(5)#\nf0%' AND SLEEP(5)#\nf0\") AND SLEEP(5)#\nf0\")) AND SLEEP(5)#\nf0\" AND SLEEP(5)#\nf0) OR SLEEP(5)#\nf0' OR SLEEP(5)#\nf0)) OR SLEEP(5)#\nf0))) OR SLEEP(5)#\nf0 OR SLEEP(5)#\nf0') OR SLEEP(5)#\nf0')) OR SLEEP(5)#\nf0'))) OR SLEEP(5)#\nf0%' OR SLEEP(5)#\nf0\") OR SLEEP(5)#\nf0\")) OR SLEEP(5)#\nf0\" OR SLEEP(5)#\nf0) AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0' AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0)) AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0))) AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0 AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0') AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0')) AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0'))) AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0%' AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0\") AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0\")) AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0\" AND (SELECT 2839 FROM (SELECT(SLEEP(5)))SiqZ)#\nf0) OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0' OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0)) OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0))) OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0 OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0') OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0')) OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0'))) OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0%' OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0\") OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0\")) OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0\" OR (SELECT 8484 FROM (SELECT(SLEEP(5)))yOZJ)#\nf0) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c))-- flRy\nf0' AND 5533=BENCHMARK(5000000,MD5(0x55554d4c))-- TZUN\nf0) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND (2379=2379\nf0)) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND ((9503=9503\nf0))) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND (((4362=4362\nf0 AND 5533=BENCHMARK(5000000,MD5(0x55554d4c))\nf0') AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND ('oVRe'='oVRe\nf0')) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND (('rSsF'='rSsF\nf0'))) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND ((('jQiN'='jQiN\nf0' AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND 'vfhv'='vfhv\nf0') AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND ('nvZu' LIKE 'nvZu\nf0')) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND (('KZga' LIKE 'KZga\nf0%' AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND 'ykaH%'='ykaH\nf0' AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND 'Nrku' LIKE 'Nrku\nf0\") AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND (\"ccRj\"=\"ccRj\nf0\")) AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND ((\"TjCk\"=\"TjCk\nf0\" AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND \"gTBT\"=\"gTBT\nf0\") AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND (\"tJIf\" LIKE \"tJIf\nf0\" AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) AND \"puNL\" LIKE \"puNL\nf0 AND 5533=BENCHMARK(5000000,MD5(0x55554d4c))-- DBrx\nf0 AND 5533=BENCHMARK(5000000,MD5(0x55554d4c))# vzyu\nf0' AND 5533=BENCHMARK(5000000,MD5(0x55554d4c)) OR 'RXxW'='gBzA\nf0) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- ZsTi\nf0' AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- IIuQ\nf0) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (5392=5392\nf0)) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ((9071=9071\nf0))) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (((3890=3890\nf0 AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)\nf0') AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ('BZFU'='BZFU\nf0')) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (('LGCr'='LGCr\nf0'))) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ((('HxBJ'='HxBJ\nf0' AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND 'opbY'='opbY\nf0') AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ('TkQh' LIKE 'TkQh\nf0')) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (('ctDE' LIKE 'ctDE\nf0%' AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND 'QwyL%'='QwyL\nf0' AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND 'NFJr' LIKE 'NFJr\nf0\") AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (\"Ewek\"=\"Ewek\nf0\")) AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ((\"rbWJ\"=\"rbWJ\nf0\" AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND \"TQth\"=\"TQth\nf0\") AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (\"uGpc\" LIKE \"uGpc\nf0\" AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND \"ORtL\" LIKE \"ORtL\nf0 AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- hAwV\nf0 AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)# qnCf\nf0' AND 6572=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) OR 'QLkl'='YfVr\nf0) OR 6546=BENCHMARK(5000000,MD5(0x5449596e))-- jVhQ\nf0' OR 6546=BENCHMARK(5000000,MD5(0x5449596e))-- TzTt\nf0) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND (6311=6311\nf0)) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND ((8213=8213\nf0))) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND (((2373=2373\nf0 OR 6546=BENCHMARK(5000000,MD5(0x5449596e))\nf0') OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND ('dTZx'='dTZx\nf0')) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND (('xFjh'='xFjh\nf0'))) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND ((('JhQQ'='JhQQ\nf0' OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND 'ZyQk'='ZyQk\nf0') OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND ('FVpr' LIKE 'FVpr\nf0')) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND (('PdSF' LIKE 'PdSF\nf0%' OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND 'MkLB%'='MkLB\nf0' OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND 'Havd' LIKE 'Havd\nf0\") OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND (\"wSTB\"=\"wSTB\nf0\")) OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND ((\"Hsvm\"=\"Hsvm\nf0\" OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND \"sKLs\"=\"sKLs\nf0\") OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND (\"tuvu\" LIKE \"tuvu\nf0\" OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) AND \"VMdA\" LIKE \"VMdA\nf0 OR 6546=BENCHMARK(5000000,MD5(0x5449596e))-- iqFZ\nf0 OR 6546=BENCHMARK(5000000,MD5(0x5449596e))# aiZL\nf0' OR 6546=BENCHMARK(5000000,MD5(0x5449596e)) OR 'BeMI'='wQrq\nf0) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- wUWd\nf0' OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- JHiQ\nf0) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (5732=5732\nf0)) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ((8108=8108\nf0))) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (((9012=9012\nf0 OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)\nf0') OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ('MrxQ'='MrxQ\nf0')) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (('RpgH'='RpgH\nf0'))) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ((('dlOP'='dlOP\nf0' OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND 'DBaC'='DBaC\nf0') OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ('BppV' LIKE 'BppV\nf0')) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (('bFAd' LIKE 'bFAd\nf0%' OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND 'CoPt%'='CoPt\nf0' OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND 'NSyn' LIKE 'NSyn\nf0\") OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (\"qBbf\"=\"qBbf\nf0\")) OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND ((\"pvvP\"=\"pvvP\nf0\" OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND \"PInJ\"=\"PInJ\nf0\") OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND (\"qZEw\" LIKE \"qZEw\nf0\" OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) AND \"vOYG\" LIKE \"vOYG\nf0 OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- GgtE\nf0 OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)# XRSD\nf0' OR 9739=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1) OR 'uXhQ'='xnUD\nf0) RLIKE SLEEP(5)-- Kufn\nf0' RLIKE SLEEP(5)-- LZxW\nf0) RLIKE SLEEP(5) AND (2137=2137\nf0)) RLIKE SLEEP(5) AND ((5105=5105\nf0))) RLIKE SLEEP(5) AND (((4986=4986\nf0 RLIKE SLEEP(5)\nf0') RLIKE SLEEP(5) AND ('iggO'='iggO\nf0')) RLIKE SLEEP(5) AND (('fkzw'='fkzw\nf0'))) RLIKE SLEEP(5) AND ((('SuQo'='SuQo\nf0' RLIKE SLEEP(5) AND 'yGSk'='yGSk\nf0') RLIKE SLEEP(5) AND ('sNzg' LIKE 'sNzg\nf0')) RLIKE SLEEP(5) AND (('OPUJ' LIKE 'OPUJ\nf0%' RLIKE SLEEP(5) AND 'ZDpY%'='ZDpY\nf0' RLIKE SLEEP(5) AND 'RKUR' LIKE 'RKUR\nf0\") RLIKE SLEEP(5) AND (\"lAfW\"=\"lAfW\nf0\")) RLIKE SLEEP(5) AND ((\"yhKE\"=\"yhKE\nf0\" RLIKE SLEEP(5) AND \"lIss\"=\"lIss\nf0\") RLIKE SLEEP(5) AND (\"Rrka\" LIKE \"Rrka\nf0\" RLIKE SLEEP(5) AND \"bioR\" LIKE \"bioR\nf0 RLIKE SLEEP(5)-- wavW\nf0 RLIKE SLEEP(5)# hXGS\nf0' RLIKE SLEEP(5) OR 'MqbR'='vMQW\nf0) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC)-- smiv\nf0' RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC)-- KRar\nf0) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND (5031=5031\nf0)) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND ((5776=5776\nf0))) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND (((1423=1423\nf0 RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC)\nf0') RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND ('sZyt'='sZyt\nf0')) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND (('bqdA'='bqdA\nf0'))) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND ((('LwyR'='LwyR\nf0' RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND 'wPxr'='wPxr\nf0') RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND ('AIUN' LIKE 'AIUN\nf0')) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND (('UmNC' LIKE 'UmNC\nf0%' RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND 'jUXp%'='jUXp\nf0' RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND 'usNE' LIKE 'usNE\nf0\") RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND (\"HAbP\"=\"HAbP\nf0\")) RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND ((\"bmiA\"=\"bmiA\nf0\" RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND \"vkjP\"=\"vkjP\nf0\") RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND (\"CCQD\" LIKE \"CCQD\nf0\" RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) AND \"xrqK\" LIKE \"xrqK\nf0 RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC)-- HYfh\nf0 RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC)# kLIL\nf0' RLIKE (SELECT 6447 FROM (SELECT(SLEEP(5)))fZZC) OR 'bPls'='YZLS\nf0) AND ELT(9112=9112,SLEEP(5))-- cGwL\nf0' AND ELT(9112=9112,SLEEP(5))-- JqxP\nf0) AND ELT(9112=9112,SLEEP(5)) AND (4993=4993\nf0)) AND ELT(9112=9112,SLEEP(5)) AND ((6551=6551\nf0))) AND ELT(9112=9112,SLEEP(5)) AND (((8163=8163\nf0 AND ELT(9112=9112,SLEEP(5))\nf0') AND ELT(9112=9112,SLEEP(5)) AND ('XMmS'='XMmS\nf0')) AND ELT(9112=9112,SLEEP(5)) AND (('tfqD'='tfqD\nf0'))) AND ELT(9112=9112,SLEEP(5)) AND ((('XQRO'='XQRO\nf0' AND ELT(9112=9112,SLEEP(5)) AND 'USfG'='USfG\nf0') AND ELT(9112=9112,SLEEP(5)) AND ('UDcF' LIKE 'UDcF\nf0')) AND ELT(9112=9112,SLEEP(5)) AND (('NKft' LIKE 'NKft\nf0%' AND ELT(9112=9112,SLEEP(5)) AND 'EFkR%'='EFkR\nf0' AND ELT(9112=9112,SLEEP(5)) AND 'SIcT' LIKE 'SIcT\nf0\") AND ELT(9112=9112,SLEEP(5)) AND (\"Bdnq\"=\"Bdnq\nf0\")) AND ELT(9112=9112,SLEEP(5)) AND ((\"HLDc\"=\"HLDc\nf0\" AND ELT(9112=9112,SLEEP(5)) AND \"Rvfu\"=\"Rvfu\nf0\") AND ELT(9112=9112,SLEEP(5)) AND (\"Kufx\" LIKE \"Kufx\nf0\" AND ELT(9112=9112,SLEEP(5)) AND \"tGsa\" LIKE \"tGsa\nf0 AND ELT(9112=9112,SLEEP(5))-- unjp\nf0 AND ELT(9112=9112,SLEEP(5))# HVrA\nf0' AND ELT(9112=9112,SLEEP(5)) OR 'fMNZ'='qFiv\nf0) OR ELT(9382=9382,SLEEP(5))-- fCyE\nf0' OR ELT(9382=9382,SLEEP(5))-- pXLl\nf0) OR ELT(9382=9382,SLEEP(5)) AND (9931=9931\nf0)) OR ELT(9382=9382,SLEEP(5)) AND ((4072=4072\nf0))) OR ELT(9382=9382,SLEEP(5)) AND (((3826=3826\nf0 OR ELT(9382=9382,SLEEP(5))\nf0') OR ELT(9382=9382,SLEEP(5)) AND ('WHas'='WHas\nf0')) OR ELT(9382=9382,SLEEP(5)) AND (('VMvM'='VMvM\nf0'))) OR ELT(9382=9382,SLEEP(5)) AND ((('TqfW'='TqfW\nf0' OR ELT(9382=9382,SLEEP(5)) AND 'jxcF'='jxcF\nf0') OR ELT(9382=9382,SLEEP(5)) AND ('yJza' LIKE 'yJza\nf0')) OR ELT(9382=9382,SLEEP(5)) AND (('iZfa' LIKE 'iZfa\nf0%' OR ELT(9382=9382,SLEEP(5)) AND 'XuBN%'='XuBN\nf0' OR ELT(9382=9382,SLEEP(5)) AND 'giEw' LIKE 'giEw\nf0\") OR ELT(9382=9382,SLEEP(5)) AND (\"fSgU\"=\"fSgU\nf0\")) OR ELT(9382=9382,SLEEP(5)) AND ((\"sWIy\"=\"sWIy\nf0\" OR ELT(9382=9382,SLEEP(5)) AND \"Xthm\"=\"Xthm\nf0\") OR ELT(9382=9382,SLEEP(5)) AND (\"KdEp\" LIKE \"KdEp\nf0\" OR ELT(9382=9382,SLEEP(5)) AND \"rvmT\" LIKE \"rvmT\nf0 OR ELT(9382=9382,SLEEP(5))-- ijso\nf0 OR ELT(9382=9382,SLEEP(5))# ZfSi\nf0' OR ELT(9382=9382,SLEEP(5)) OR 'PyXh'='upGw\nf0) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1)-- amgk\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1)-- yulq\nf0) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND (7936=7936\nf0)) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND ((7985=7985\nf0))) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND (((3020=3020\nf0 PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1)\nf0') PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND ('vZjo'='vZjo\nf0')) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND (('lTvq'='lTvq\nf0'))) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND ((('ECGM'='ECGM\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND 'MVCV'='MVCV\nf0') PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND ('rLQM' LIKE 'rLQM\nf0')) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND (('AePQ' LIKE 'AePQ\nf0%' PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND 'dJIP%'='dJIP\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND 'iuDf' LIKE 'iuDf\nf0\") PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND (\"FBHF\"=\"FBHF\nf0\")) PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND ((\"bctK\"=\"bctK\nf0\" PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND \"bCeo\"=\"bCeo\nf0\") PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND (\"EDEy\" LIKE \"EDEy\nf0\" PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) AND \"AwUN\" LIKE \"AwUN\nf0 PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1)-- pPzM\nf0 PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1)# lgnB\nf0' PROCEDURE ANALYSE(EXTRACTVALUE(8336,CONCAT(0x5c,(BENCHMARK(5000000,MD5(0x61465255))))),1) OR 'HqwJ'='QZVN\n(CASE WHEN (4458=4458) THEN SLEEP(5) ELSE 4458 END)\n(SELECT 8558 FROM (SELECT(SLEEP(5)))EWKF)\nf0',(SELECT (CASE WHEN (8089=8089) THEN SLEEP(5) ELSE 8089 END))-- gfzl\nf0,(SELECT (CASE WHEN (8089=8089) THEN SLEEP(5) ELSE 8089 END))\nf0) ORDER BY 1-- -\nf0' ORDER BY 1-- -\nf0) ORDER BY 1-- -\nf0)) ORDER BY 1-- -\nf0))) ORDER BY 1-- -\nf0 ORDER BY 1-- -\nf0') ORDER BY 1-- -\nf0')) ORDER BY 1-- -\nf0'))) ORDER BY 1-- -\nf0' ORDER BY 1-- -\nf0') ORDER BY 1-- -\nf0')) ORDER BY 1-- -\nf0%' ORDER BY 1-- -\nf0' ORDER BY 1-- -\nf0\") ORDER BY 1-- -\nf0\")) ORDER BY 1-- -\nf0\" ORDER BY 1-- -\nf0\") ORDER BY 1-- -\nf0\" ORDER BY 1-- -\nf0 ORDER BY 1-- -\nf0 ORDER BY 1-- -\nf0' ORDER BY 1-- -\n-4069) ORDER BY 1-- -\n-4012' ORDER BY 1-- -\n-4231) ORDER BY 1-- -\n-5010)) ORDER BY 1-- -\n-1573))) ORDER BY 1-- -\n-5207 ORDER BY 1-- -\n-3792') ORDER BY 1-- -\n-2353')) ORDER BY 1-- -\n-8911'))) ORDER BY 1-- -\n-2913' ORDER BY 1-- -\n-3279') ORDER BY 1-- -\n-3297')) ORDER BY 1-- -\n-1132%' ORDER BY 1-- -\n-4795' ORDER BY 1-- -\n-3105\") ORDER BY 1-- -\n-8528\")) ORDER BY 1-- -\n-4479\" ORDER BY 1-- -\n-4721\") ORDER BY 1-- -\n-3532\" ORDER BY 1-- -\n-7317 ORDER BY 1-- -\n-9795 ORDER BY 1-- -\n-2538' ORDER BY 1-- -\nf0) ORDER BY 1#\nf0' ORDER BY 1#\nf0) ORDER BY 1#\nf0)) ORDER BY 1#\nf0))) ORDER BY 1#\nf0 ORDER BY 1#\nf0') ORDER BY 1#\nf0')) ORDER BY 1#\nf0'))) ORDER BY 1#\nf0' ORDER BY 1#\nf0') ORDER BY 1#\nf0')) ORDER BY 1#\nf0%' ORDER BY 1#\nf0' ORDER BY 1#\nf0\") ORDER BY 1#\nf0\")) ORDER BY 1#\nf0\" ORDER BY 1#\nf0\") ORDER BY 1#\nf0\" ORDER BY 1#\nf0 ORDER BY 1#\nf0 ORDER BY 1#\nf0' ORDER BY 1#\n-3266) ORDER BY 1#\n-3682' ORDER BY 1#\n-8231) ORDER BY 1#\n-9202)) ORDER BY 1#\n-9175))) ORDER BY 1#\n-3904 ORDER BY 1#\n-9328') ORDER BY 1#\n-3263')) ORDER BY 1#\n-9743'))) ORDER BY 1#\n-7584' ORDER BY 1#\n-4057') ORDER BY 1#\n-1697')) ORDER BY 1#\n-6116%' ORDER BY 1#\n-4995' ORDER BY 1#\n-7733\") ORDER BY 1#\n-2201\")) ORDER BY 1#\n-7661\" ORDER BY 1#\n-9213\") ORDER BY 1#\n-9167\" ORDER BY 1#\n-3096 ORDER BY 1#\n-5168 ORDER BY 1#\n-2191' ORDER BY 1#"
  },
  {
    "path": "tools/setup_db_osx.sh",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n# Setup database. We can't use a Docker service as Docker\n# is not supported in osx.\n\n# Install the DB\nbrew install mysql@8.0\nexport PATH=\"/opt/homebrew/opt/mysql@8.0/bin:$PATH\"\n\n# Copy config files and set up paths\ncp tools/osx-ci.cnf ~/.my.cnf\nsudo mkdir -p /etc/ssl/certs/mysql/\nsudo cp tools/ssl/*.pem /etc/ssl/certs/mysql/\nsudo mkdir -p /var/run/mysqld/\nsudo chmod 777 /var/run/mysqld/\n\n# Start the server\nbrew services start mysql@8.0\n"
  },
  {
    "path": "tools/ssl/ca-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDZzCCAk+gAwIBAgIUWznm2UoxXw3j7HCcp9PpiayTvFQwDQYJKoZIhvcNAQEL\nBQAwQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAMBgNVBAoM\nBW15c3FsMQ4wDAYDVQQDDAVteXNxbDAgFw0yMDA0MDQxNDMwMjNaGA8zMDE5MDgw\nNjE0MzAyM1owQjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxDjAM\nBgNVBAoMBW15c3FsMQ4wDAYDVQQDDAVteXNxbDCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAN0WYdvsDb+a0TxOGPejcwZT0zvTrf921mmDUlrLN1Z0hJ/S\nydgQCSD7Q+6za4lTFZCXcvs52xvvS2gfC0yXyYLCT/jA4RQRxuF+/+w1gDWEbGk0\nKzEpsBuKrEIvEaVdoS78SxInnW/aegshdrRRocp4JQ6KHsZgkLTxSwPfYSUmMUo0\ncRO0Q/ak3VK8NP13A6ZFvZjrBxjS3cSw9HqilgADcyj1D4EokvfI1C9LrgwgLlZC\nXVkjjBqqoMXGGlnXOEK+pm8bU68HM/QvMBkb1Amo8pioNaaYgqJUCP0Ch0iu1nUU\nHtsWt6emXv0jANgIW0oga7xcT4MDGN/M+IRWLTECAwEAAaNTMFEwHQYDVR0OBBYE\nFNxhaGwf5ePPhzK7yOAKD3VF6wm2MB8GA1UdIwQYMBaAFNxhaGwf5ePPhzK7yOAK\nD3VF6wm2MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAoeJCAX\nIDCFoAaZoQ1niI6Ac/cds8G8It0UCcFGSg+HrZ0YujJxWIruRCUG60Q2OAbEvn0+\nuRpTm+4tV1Wt92WFeuRyqkomozx0g4CyfsxGX/x8mLhKPFK/7K9iTXM4/t+xQC4f\nJ+iRmPVsMKQ8YsHYiWVhlOMH9XJQiqERCB2kOKJCH6xkaF2k0GbM2sGgbS7Z6lrd\nfsFTOIVx0VxLVsZnWX3byE9ghnDR5jn18u30Cpb/R/ShxNUGIHqRa4DkM5la6uZX\nW1fpSW11JBSUv4WnOO0C2rlIu7UJWOROqZZ0OsybPRGGwagcyff2qVRuI2XFvAMk\nOzBrmpfHEhF6NDU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "tools/ssl/server-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDDTCCAfUCAQEwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCQVUxEzARBgNV\nBAgMClNvbWUtU3RhdGUxDjAMBgNVBAoMBW15c3FsMQ4wDAYDVQQDDAVteXNxbDAg\nFw0yMDA0MDQxNDMxMTJaGA8zMDE5MDgwNjE0MzExMlowVTELMAkGA1UEBhMCQVUx\nEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg\nUHR5IEx0ZDEOMAwGA1UEAwwFbXlzcWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQDMG6j417e444WQxqJTqYRldtXde2hYFzZd5owzrWW6f2dff8Hu+WcW\nozrulmyiRx3E3PRUwT6XbjVRMJdThoE8IgLC16Q95rEGStxRh/fLjyLBf8626HDW\n5d3T1N008lMKFy7MXVrdsSFcIQRYkmuTN7T2YXfvdS2Y5cx9oHw3hhNF+jfFBYEP\nUhtnvKbdVK7oezsULr8CjfyJWAcubODWTOny5yO/v2sI7X00M8qc/zCtB6I30rlI\nxPYs2nCYw+l89tm/XyJ7ayT7aE2jcR0Tnz0hB46jUxbESR+0aw8RiluFT0ec/Nxy\ny4AWd/inx3LJpzbgIzvlxCmJDoIohJeFAgMBAAEwDQYJKoZIhvcNAQELBQADggEB\nACVcNZdiTpCcd2Ic0SS3DdGeNP+0hyL6xx/7KLMT7FuLtHHMzwzTwwQCXmhZIhj8\n0gwzOsBR8YzYIM/TJnYN35e813lv0elfz2wlwOf4yWrdllj8ymfzaUbvaML/Z5qy\nvnMhnobsd2lgUD5ousfLdga7ueIKL1wE8TNJRIkrlObQgf3UOOMHBO707Y64FC5x\nqbIvhriMQJSCF+EPmqeLirzPg8LLvUzM6enuuos+I3/WxkntCHO1ONYSl//h2P2E\nYoigb6S89lAFPiuXL1fmtaJN7ALRKWu5k1mundDePG+RhVDVuWuVHyfc5dMBH6DK\nv4mGZ5Ie3C9dDM2qaz4fo+w=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "tools/ssl/server-key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAzBuo+Ne3uOOFkMaiU6mEZXbV3XtoWBc2XeaMM61lun9nX3/B\n7vlnFqM67pZsokcdxNz0VME+l241UTCXU4aBPCICwtekPeaxBkrcUYf3y48iwX/O\ntuhw1uXd09TdNPJTChcuzF1a3bEhXCEEWJJrkze09mF373UtmOXMfaB8N4YTRfo3\nxQWBD1IbZ7ym3VSu6Hs7FC6/Ao38iVgHLmzg1kzp8ucjv79rCO19NDPKnP8wrQei\nN9K5SMT2LNpwmMPpfPbZv18ie2sk+2hNo3EdE589IQeOo1MWxEkftGsPEYpbhU9H\nnPzccsuAFnf4p8dyyac24CM75cQpiQ6CKISXhQIDAQABAoIBAQCksGzW3LhRZsQO\n3Td9afp6JDjMTRcUfSZQ/gWCbRb4NHSkieFhgbu8eFjEyns9NUS/48kB2is25KYA\nrMRtkMoWSxsPPBA6IjoUabL71koK5aOVnhqdW1AxFai3k7opTp3SNoJ8Q5dd6d6R\nB9MJ5JsIXpqVcm/jtxjjlgg6FZQk94gqoskRbekih+QidRplFkeGDRDWpHz5621T\n92PSWu7C0au3Q+iMhaUeeKnWeIYNyCFWYGHxbJStBW0r1Xy6tkTJIBuOQN1JVT2S\nf196xqBnEj+kkWLV6rrZNqLrptP1PjcKxRGjKoYxlL1F/51FuJSpTiSnf42hJYCp\nTkS0ViABAoGBAPUxFwqPl9uw/dnugFztR9P/j0RRlcHEtsz4eK4CSVKKhRLiwMoB\nyKQ1B6fDshTdFRoNaMyByZ1NzsEsvIcYk9LOPtEy2kTsgVK+EW8QFkxIgJtZEy1r\n0nPV4a/latzyvjNl5xIdAgldxrpQEg7BAO7GVDnrPWETZ2TJV1Vq7u0FAoGBANUa\n9B8+7AHGMiRMkyKKHJh340FVqlKH7XVvsoooCiTi0olUPNB70sAleOMTi5BiWnwZ\n6z734eLFAHWsD8XyRQE6vW7NSqNqQ2g9Mv8i7tyn3P4AQwqpEXrdvklM+nc7clKu\nagIHFfeVeB0YmLXmq26z6m3dGQeqsEKMDlM5iwiBAoGBAN32UqV82DxJPYTMI+f7\n5cpEz61JLgj7y4BCbv0XlMjkHRO7skss0jXUy9lTjyLUAQZUnUqFM77zcPfvR7wE\nw81SaAt5vZ4ne+srpRyls4nbGJGJUZMMyLeUJ3rUdKkQFp7w4P3ExNM10XFYiwBQ\nOEfvws+r5SS8LB1RJ35sD18BAoGBAMgOaab7luuDeIcDLA18wqOPyNQI68BWwuFA\nXse8FunR1fv+DKlb1Nl1VCs4qgh9jJx8aI/QfUo5ztipEpWtfoJM9pESQENw+p7c\n9Qb3cG3NWHVLIaTcWwCRMpX1ohxUvlpISlRk+oZW10/ZS2NYjQ9771P8AAdmgdm3\nSatvlcoBAoGANyp6/KwFBNEwoFVGWUjIZ2GFH6lcgMjvX52gDN+aqhyN/vdR+rG6\nfekp/e9ef8VbPZS/nhZ+5TyhVKZ9Cw/4rDXvhNv7ir7wSGYs85Ry1n+ltQtNW3rV\nUZ0UdRlp8sLvKT5gqba1wVaYW76Y1PZiMltzaldYuVKqYIheoibxlm4=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "tools/user-config-osx-gha.jam",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\nusing openssl : : <include>/opt/homebrew/opt/openssl@3/include <search>/opt/homebrew/opt/openssl@3/lib ;\n"
  },
  {
    "path": "tools/valgrind_suppressions.txt",
    "content": ""
  },
  {
    "path": "tools/win-ci.cnf",
    "content": "#\n# Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)\n#\n# Distributed under the Boost Software License, Version 1.0. (See accompanying\n# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n#\n\n[mysqld]\nssl-ca=C:\\\\ssl\\\\ca-cert.pem\nssl-cert=C:\\\\ssl\\\\server-cert.pem\nssl-key=C:\\\\ssl\\\\server-key.pem\n"
  }
]