在duckdb 1.4中编译和使用postgresql协议插件duckdb-pgwire

编译步骤

https://github.com/euiko/duckdb-pgwire 下载源代码包,并进入pgwire @ 3055550目录下载它和其它第三方组件源代码包, 注意第三方组件的目录务必和存储库保持一致。

将所有源代码解压到/par/duckdb-pgwire-main及相应目录下,先按照https://github.com/euiko/pgwire 提示单独编译测试pgwire组件,

cpp 复制代码
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire# cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE -B build -DCMAKE_BUILD_TYPE=Release .
-- The C compiler identification is GNU 14.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/local/bin/gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Could NOT find QT (missing: QT_DIR)
CMake Warning (dev) at third_party/promise-cpp/CMakeLists.txt:44 (find_package):
  Policy CMP0084 is not set: The FindQt module does not exist for
  find_package().  Run "cmake --help-policy CMP0084" for policy details.  Use
  the cmake_policy command to set the policy and suppress this warning.

This warning is for project developers.  Use -Wno-dev to suppress it.

-- Could NOT find Qt3 (missing: QT_QT_LIBRARY QT_INCLUDE_DIR QT_MOC_EXECUTABLE)
CMake was unable to find desired Qt version: 3. Set advanced values QT_QMAKE_EXECUTABLE and QT3_QGLOBAL_H_FILE.
CMake Warning at third_party/promise-cpp/CMakeLists.txt:46 (message):
  QT not found, so project qt_timer will not be compiled


-- Configuring done
-- Generating done
-- Build files have been written to: /par/duckdb-pgwire-main/pgwire/build
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire# cd build
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build# ls
CMakeCache.txt  DartConfiguration.tcl  Testing              compile_commands.json  test
CMakeFiles      Makefile               cmake_install.cmake  src                    third_party
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build# make
[  1%] Building CXX object third_party/promise-cpp/CMakeFiles/promise.dir/src/promise.cpp.o
[  2%] Linking CXX static library libpromise.a
[  2%] Built target promise
[  3%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/buffer.cpp.o
[  4%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/exception.cpp.o
[  4%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/io.cpp.o

[  3%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/log.cpp.o
[  4%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/protocol.cpp.o
[  5%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/server.cpp.o
[  6%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/session.cpp.o
[  6%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/types.cpp.o
[  7%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/utils.cpp.o
[  8%] Building CXX object src/pgwire/CMakeFiles/pgwire.dir/writer.cpp.o
[  9%] Linking CXX static library libpgwire.a
make[2]: warning:  Clock skew detected.  Your build may be incomplete.
[ 11%] Built target pgwire
[ 12%] Building CXX object src/demo/CMakeFiles/pgwire-demo.dir/main.cpp.o
[ 12%] Linking CXX executable pgwire-demo
[ 12%] Built target pgwire-demo
[ 12%] Building CXX object third_party/catch2/src/CMakeFiles/Catch2.dir/catch2/benchmark/catch_chronometer.cpp.o
...
[ 95%] Building CXX object third_party/catch2/src/CMakeFiles/Catch2.dir/catch2/matchers/catch_matchers_templated.cpp.o
[ 96%] Building CXX object third_party/catch2/src/CMakeFiles/Catch2.dir/catch2/matchers/internal/catch_matchers_impl.cpp.o
[ 96%] Linking CXX static library libCatch2.a
[ 96%] Built target Catch2
[ 97%] Building CXX object third_party/catch2/src/CMakeFiles/Catch2WithMain.dir/catch2/internal/catch_main.cpp.o
[ 98%] Linking CXX static library libCatch2Main.a
[ 98%] Built target Catch2WithMain
[ 99%] Building CXX object test/CMakeFiles/pgwire-test.dir/utils.cpp.o
[100%] Linking CXX executable pgwire-test
[100%] Built target pgwire-test

编译完成后执行测试,这个演示程序允许指定IP和端口,默认是127.0.0.1:15432

cpp 复制代码
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build# cd test
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build/test# ./pgwire-test
Randomness seeded to: 773044056
===============================================================================
All tests passed (3 assertions in 1 test case)

root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build/test#

root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build/test# cd ..
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire/build# cd ..
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire# ./build/src/demo/pgwire-demo --help
pgwire-demo is a demo program to showcase the usage of pgwire library
Usage: ./build/src/demo/pgwire-demo [OPTIONS]

Available options:
  --host (-H)        Host to listen on (default: 127.0.0.1)
  --port (-P)        Port to listen on (default: 15432)
  --help (-h)        To show this usage
root@6ae32a5ffcde:/par/duckdb-pgwire-main/pgwire# ./build/src/demo/pgwire-demo
2025-10-02T02:44:27+00:00 [INFO] Starting server on 127.0.0.1:15432
2025-10-02T02:45:13+00:00 [INFO] [session #1] started
2025-10-02T02:45:13+00:00 [INFO] [session #1] [query #1] executing query "SELECT * FROM dummy_query"
2025-10-02T02:45:13+00:00 [INFO] [session #1] [query #1] query done, elapsed = 0.61ms
2025-10-02T02:45:20+00:00 [INFO] [session #1] done

另开一个终端,输入命令行,可返回结果,并且服务端有相应提示

cpp 复制代码
root@6ae32a5ffcde:/# psql 'postgresql://localhost:15432/main' -c 'SELECT * FROM dummy_query'
   name   |  address  | age
----------+-----------+------
 kharista | indonesia |    1
 kharista | indonesia |    2
 kharista | indonesia |    3
 kharista | indonesia |    4
 kharista | indonesia |    5
 kharista | indonesia |    6
 kharista | indonesia |    7
 kharista | indonesia |    8

可见pgwire组件工作正常。

接下来编译duckdb_pgwire插件,先将各个组件的头文件目录全都加入查找路径,才能让g++识别。

cpp 复制代码
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# g++ -fPIC -shared -o libtest2.so duckdb_pgwire_extension.cpp -I /par/extension-template/duckdb/src/include -I include -I ../pgwire/include  -I ../pgwire/third_party/promise-cpp/include -I ../pgwire/third_party/asio/asio/include  -I ../pgwire/third_party/endian/src -lduckdb -L /par/libduckdb
In file included from ../pgwire/include/pgwire/server.hpp:3,
                from duckdb_pgwire_extension.cpp:17:
../pgwire/include/pgwire/session.hpp:11:10: fatal error: function2/function2.hpp: No such file or directory
  11 | #include <function2/function2.hpp>
     |          ^~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# g++ -fPIC -shared -o libtest2.so duckdb_pgwire_extension.cpp -I /par/extension-template/duckdb/src/include -I include -I ../pgwire/include  -I ../pgwire/third_party/promise-cpp/include -I ../pgwire/third_party/asio/asio/include  -I ../pgwire/third_party/endian/src -I ../pgwire/third_party/function2/include -lduckdb -L /par/libduckdb
In file included from duckdb_pgwire_extension.cpp:5:
include/duckdb_pgwire_extension.hpp:9:10: error: 'void duckdb::DuckdbPgwireExtension::Load(duckdb::DuckDB&)' marked 'override', but does not override
   9 |     void Load(DuckDB &db) override;
     |          ^~~~
In file included from duckdb_pgwire_extension.cpp:10:
/par/extension-template/duckdb/src/include/duckdb/main/extension_util.hpp:7:15: error: static assertion failed: The DuckDB 'ExtensionUtil' class has been removed, see this PR for more details: https://github.com/duckdb/duckdb/pull/17772
   7 | static_assert(false, "The DuckDB 'ExtensionUtil' class has been removed, see this PR for more details: "
     |               ^~~~~
duckdb_pgwire_extension.cpp: In function 'void duckdb::LoadInternal(DatabaseInstance&)':
duckdb_pgwire_extension.cpp:208:5: error: 'ExtensionUtil' has not been declared
 208 |     ExtensionUtil::RegisterFunction(instance,
     |     ^~~~~~~~~~~~~
duckdb_pgwire_extension.cpp:212:5: error: 'ExtensionUtil' has not been declared
 212 |     ExtensionUtil::RegisterFunction(instance, duckdb_pgwire_scalar_function);
     |     ^~~~~~~~~~~~~
duckdb_pgwire_extension.cpp: In function 'void duckdb_pgwire_init(duckdb::DatabaseInstance&)':
duckdb_pgwire_extension.cpp:226:16: error: 'class duckdb::DuckDB' has no member named 'LoadExtension'; did you mean 'LoadStaticExtension'?
 226 |     db_wrapper.LoadExtension<duckdb::DuckdbPgwireExtension>();
     |                ^~~~~~~~~~~~~
     |                LoadStaticExtension
duckdb_pgwire_extension.cpp:226:59: error: expected primary-expression before '>' token
 226 |     db_wrapper.LoadExtension<duckdb::DuckdbPgwireExtension>();
     |                                                           ^
duckdb_pgwire_extension.cpp:226:61: error: expected primary-expression before ')' token
 226 |     db_wrapper.LoadExtension<duckdb::DuckdbPgwireExtension>();
     |                                                             ^

因为duckdb_pgwire插件基于旧版DuckDB设计,很多函数在1.4版中都找不到了,需要对源代码修改。我参考1.4版的quack_extension修改duckdb_pgwire_extension.cpp如下

cpp 复制代码
#include "duckdb/common/types.hpp"
#include <unordered_map>
#define DUCKDB_EXTENSION_MAIN

#include <duckdb_pgwire_extension.hpp>

#include <duckdb/common/exception.hpp>
#include <duckdb/common/string_util.hpp>
#include <duckdb/function/scalar_function.hpp>
//#include <duckdb/main/extension_util.hpp>
#include <duckdb/main/extension/extension_loader.hpp>
#include <duckdb/parser/parsed_data/create_scalar_function_info.hpp>

#include <atomic>
#include <optional>
#include <pgwire/exception.hpp>
#include <pgwire/log.hpp>
#include <pgwire/server.hpp>
#include <pgwire/types.hpp>
#include <stdexcept>

namespace duckdb {

static std::atomic<bool> g_started;

static std::unordered_map<LogicalTypeId, pgwire::Oid> g_typemap = {
   {LogicalTypeId::FLOAT, pgwire::Oid::Float4},
   {LogicalTypeId::DOUBLE, pgwire::Oid::Float8},
   // {LogicalTypeId::TINYINT, pgwire::Oid::Char},
   {LogicalTypeId::SMALLINT, pgwire::Oid::Int2},
   {LogicalTypeId::INTEGER, pgwire::Oid::Int4},
   {LogicalTypeId::BIGINT, pgwire::Oid::Int8},
   // uses string
   {LogicalTypeId::VARCHAR, pgwire::Oid::Varchar},
   {LogicalTypeId::DATE, pgwire::Oid::Date},
   {LogicalTypeId::TIME, pgwire::Oid::Time},
   {LogicalTypeId::TIMESTAMP, pgwire::Oid::Timestamp},
   {LogicalTypeId::TIMESTAMP, pgwire::Oid::TimestampTz},
};

static pgwire::ParseHandler duckdb_handler(DatabaseInstance &db) {
   return [&db](std::string const &query) mutable {
       Connection conn(db);
       pgwire::PreparedStatement stmt;
       std::unique_ptr<PreparedStatement> prepared;
       std::optional<pgwire::SqlException> error;

       std::vector<std::string> column_names;
       std::vector<LogicalType> column_types;
       std::size_t column_total;

       try {
           prepared = conn.Prepare(query);
           if (!prepared) {
               throw std::runtime_error(
                   "failed prepare query with unknown error");
           }

           if (prepared->HasError()) {
               throw std::runtime_error(prepared->GetError());
           }

           column_names = prepared->GetNames();
           column_types = prepared->GetTypes();
           column_total = prepared->ColumnCount();
       } catch (std::exception &e) {
           error =
               pgwire::SqlException{e.what(), pgwire::SqlState::DataException};
       }

       // rethrow error
       if (error) {
           throw *error;
       }

       stmt.fields.reserve(column_total);
       for (std::size_t i = 0; i < column_total; i++) {
           auto &name = column_names[i];
           auto &type = column_types[i];

           auto it = g_typemap.find(type.id());
           if (it == g_typemap.end()) {
               continue;
           }
           auto oid = it->second;

           // can't uses emplace_back for POD struct in C++17
           stmt.fields.push_back({name, oid});
       }

       stmt.handler = [column_total, p = std::move(prepared)](
                          pgwire::Writer &writer,
                          pgwire::Values const &parameters) mutable {
           std::unique_ptr<QueryResult> result;
           std::optional<pgwire::SqlException> error;

           try {
               result = p->Execute();
               if (!result) {
                   throw std::runtime_error(
                       "failed to execute query with unknown error");
               }

               if (result->HasError()) {
                   throw std::runtime_error(result->GetError());
               }

           } catch (std::exception &e) {
               // std::cout << "error occured during execute:" << std::endl;
               error = pgwire::SqlException{e.what(),
                                            pgwire::SqlState::DataException};
           }

           if (error) {
               throw *error;
           }

           auto &column_types = p->GetTypes();

           for (auto &chunk : *result) {
               auto row = writer.add_row();

               for (std::size_t i = 0; i < column_total; i++) {
                   auto &type = column_types[i];

                   auto it = g_typemap.find(type.id());
                   if (it == g_typemap.end()) {
                       continue;
                   }

                   auto value = chunk.iterator.chunk->GetValue(i, chunk.row);
                   if (value.IsNull()) {
                       row.write_null();
                       continue;
                   }

                   switch (type.id()) {
                   case LogicalTypeId::FLOAT:
                       row.write_float4(chunk.GetValue<float>(i));
                       break;
                   case LogicalTypeId::DOUBLE:
                       row.write_float8(chunk.GetValue<double>(i));
                       break;
                   case LogicalTypeId::SMALLINT:
                       row.write_int2(chunk.GetValue<int16_t>(i));
                       break;
                   case LogicalTypeId::INTEGER:
                       row.write_int4(chunk.GetValue<int32_t>(i));
                       break;
                   case LogicalTypeId::BIGINT:
                       row.write_int8(chunk.GetValue<int64_t>(i));
                       break;
                   case LogicalTypeId::BOOLEAN:
                       row.write_bool(chunk.GetValue<bool>(i));
                       break;
                   case LogicalTypeId::VARCHAR:
                   case LogicalTypeId::DATE:
                   case LogicalTypeId::TIME:
                   case LogicalTypeId::TIMESTAMP:
                   case LogicalTypeId::TIMESTAMP_TZ:
                       row.write_string(chunk.GetValue<std::string>(i));
                       break;
                   default:
                       break;
                   }
               }
           }
       };
       return stmt;
   };
}

static void start_server(DatabaseInstance &db) {
   using namespace asio;
   if (g_started)
       return;

   g_started = true;

   io_context io_context;
   ip::tcp::endpoint endpoint(ip::tcp::v4(), 15432);

   pgwire::log::initialize(io_context, "duckdb_pgwire.log");

   pgwire::Server server(
       io_context, endpoint,
       [&db](pgwire::Session &sess) mutable { return duckdb_handler(db); });
   server.start();
}

inline void PgIsInRecovery(DataChunk &args, ExpressionState &state,
                          Vector &result) {
   result.SetValue(0, false);
}

inline void DuckdbPgwireScalarFun(DataChunk &args, ExpressionState &state, Vector &result) {
   auto &name_vector = args.data[0];
   UnaryExecutor::Execute<string_t, string_t>(
       name_vector, result, args.size(),
       [&](string_t name) {
   		return StringVector::AddString(result, "DuckdbPgwire "+name.GetString()+" 🐥");;
       });
}
/*
static void LoadInternal(DatabaseInstance &instance) {
   // Register a scalar function
   auto pg_is_in_recovery_scalar_function = ScalarFunction(
       "pg_is_in_recovery", {}, LogicalType::BOOLEAN, PgIsInRecovery);
   ExtensionUtil::RegisterFunction(instance,
                                   pg_is_in_recovery_scalar_function);

   auto duckdb_pgwire_scalar_function = ScalarFunction("duckdb_pgwire", {LogicalType::VARCHAR}, LogicalType::VARCHAR, DuckdbPgwireScalarFun);
   ExtensionUtil::RegisterFunction(instance, duckdb_pgwire_scalar_function);
   
   std::thread([&instance]() mutable { start_server(instance); }).detach();
}

void DuckdbPgwireExtension::Load(DuckDB &db) { LoadInternal(*db.instance); }
std::string DuckdbPgwireExtension::Name() { return "duckdb_pgwire"; }
*/

static void LoadInternal(ExtensionLoader &loader) {
   // Register a scalar function
   auto pg_is_in_recovery_scalar_function = ScalarFunction("pg_is_in_recovery", {}, LogicalType::BOOLEAN, PgIsInRecovery);
   loader.RegisterFunction(pg_is_in_recovery_scalar_function);

   // Register another scalar function
   auto duckdb_pgwire_scalar_function = ScalarFunction("duckdb_pgwire", {LogicalType::VARCHAR}, LogicalType::VARCHAR, DuckdbPgwireScalarFun);
   loader.RegisterFunction(duckdb_pgwire_scalar_function);
   DatabaseInstance & instance=loader.GetDatabaseInstance();
   std::thread([&instance]() mutable { start_server(instance); }).detach();
}

void DuckdbPgwireExtension::Load(ExtensionLoader &loader) {
   LoadInternal(loader);
}
std::string DuckdbPgwireExtension::Name() {
   return "duckdb_pgwire";
}
std::string DuckdbPgwireExtension::Version() const {
#ifdef EXT_VERSION_QUACK
   return EXT_VERSION_QUACK;
#else
   return "";
#endif
}

} // namespace duckdb

extern "C" {
/*
DUCKDB_EXTENSION_API void duckdb_pgwire_init(duckdb::DatabaseInstance &db) {
   duckdb::DuckDB db_wrapper(db);
   db_wrapper.LoadExtension<duckdb::DuckdbPgwireExtension>();
}

DUCKDB_EXTENSION_API const char *duckdb_pgwire_version() {
   return duckdb::DuckDB::LibraryVersion();
}
*/
DUCKDB_CPP_EXTENSION_ENTRY(duckdb_pgwire, loader) {
   duckdb::LoadInternal(loader);
}
}

#ifndef DUCKDB_EXTENSION_MAIN
#error DUCKDB_EXTENSION_MAIN not defined
#endif

同时修改include/duckdb_pgwire_extension.hpp如下

cpp 复制代码
#pragma once

#include <duckdb.hpp>

namespace duckdb {

class DuckdbPgwireExtension : public Extension {
  public:
    //void Load(DuckDB &db) override;
    void Load(ExtensionLoader &db);
    std::string Name() override;
	  std::string Version() const override;    
};

} // namespace duckdb 

编译完成后用python脚本添加元数据

cpp 复制代码
python3 /par/appendmetadata.py -l libtest2.so -n duckdb_pgwire -dv v1.4.0   --duckdb-platform linux_amd64 --extension-version 0.1 --abi-type ""

加载出错,有未定义的符号,想要静态链接libpgwire.a,也出错了

cpp 复制代码
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# export LD_LIBRARY_PATH=/par/libduckdb
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# /par/duckdb140 -unsigned
DuckDB v1.4.0 (Andium) b8a06e4a22
Enter ".help" for usage hints.
D load '/par/duckdb-pgwire-main/src/duckdb_pgwire.duckdb_extension';
IO Error:
Extension "/par/duckdb-pgwire-main/src/duckdb_pgwire.duckdb_extension" could not be loaded: /par/duckdb-pgwire-main/src/duckdb_pgwire.duckdb_extension: undefined symbol: _ZTIN6pgwire12SqlExceptionE
D .exit
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# g++ -fPIC -shared -o libtest2.so duckdb_pgwire_extension.cpp -I /par/extension-template/duckdb/src/include -I include -I ../pgwire/include  -I ../pgwire/third_party/promise-cpp/include -I ../pgwire/third_party/asio/asio/include  -I ../pgwire/third_party/endian/src -I ../pgwire/third_party/function2/include -lduckdb -L /par/libduckdb ../pgwire/build/src/pgwire/libpgwire.a
/usr/bin/ld: ../pgwire/build/src/pgwire/libpgwire.a(exception.cpp.o): relocation R_X86_64_32S against symbol `_ZTVN6pgwire12SqlExceptionE' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
collect2: error: ld returned 1 exit status

干脆把pgwire编成动态库libpgwire.so, 然后让duckdb-pgwire插件再动态链接它

cpp 复制代码
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# g++ -fPIC -shared -o libpgwire.so ../pgwire/src/pgwire/*.cpp -I /par/extension-template/duckdb/src/include -I include -I ../pgwire/include  -I ../pgwire/third_party/promise-cpp/include -I ../pg
wire/third_party/asio/asio/include  -I ../pgwire/third_party/endian/src -I ../pgwire/third_party/function2/include
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# g++ -fPIC -shared -o libtest2.so duckdb_pgwire_extension.cpp -I /par/extension-template/duckdb/src/include -I include -I ../pgwire/include  -I ../pgwire/third_party/promise-cpp/include -I ../pgwire/third_party/asio/asio/include  -I ../pgwire/third_party/endian/src -I ../pgwire/third_party/function2/include -lduckdb -L /par/libduckdb -lpgwire -L .
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# python3 /par/appendmetadata.py -l libtest2.so -n duckdb_pgwire -dv v1.4.0  --duckdb-platform linux_amd64 --extension-version 0.1 --abi-type ""

插件可以加载了

cpp 复制代码
root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# /par/duckdb140 -unsigned
DuckDB v1.4.0 (Andium) b8a06e4a22
Enter ".help" for usage hints.
D load '/par/duckdb-pgwire-main/src/duckdb_pgwire.duckdb_extension';

D select duckdb_pgwire('asdf');
┌───────────────────────┐
│ duckdb_pgwire('asdf') │
│        varchar        │
├───────────────────────┤
│ DuckdbPgwire asdf 🐥  │
└───────────────────────┘
D select pg_is_in_recovery();
┌─────────────────────┐
│ pg_is_in_recovery() │
│       boolean       │
├─────────────────────┤
│ false               │
└─────────────────────┘
D .exit

root@6ae32a5ffcde:/par/duckdb-pgwire-main/src# /par/duckdb140 -unsigned -cmd "load '/par/duckdb-pgwire-main/src/duckdb_pgwire.duckdb_extension'"
DuckDB v1.4.0 (Andium) b8a06e4a22
Enter ".help" for usage hints.
D select duckdb_pgwire('asdf');
┌───────────────────────┐
│ duckdb_pgwire('asdf') │
│        varchar        │
├───────────────────────┤
│ DuckdbPgwire asdf 🐥  │
└───────────────────────┘

但是再开一个客户端,用psql访问不行,

cpp 复制代码
root@6ae32a5ffcde:/# psql 'postgresql://localhost:15432/main' -c 'select * from generate_series(0, 4)'
psql: error: connection to server at "localhost" (127.0.0.1), port 15432 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?

仔细比对修改前后源代码,发现我遗漏了一句

cpp 复制代码
    std::thread([&instance]() mutable { start_server(instance); }).detach();

而这里需要的instance, 在函数参数里没有,怎么获取,查看duckdb/main/extension/extension_loader.cpp中定义

cpp 复制代码
namespace duckdb {

ExtensionLoader::ExtensionLoader(ExtensionActiveLoad &load_info)
    : db(load_info.db), extension_name(load_info.extension_name), extension_info(load_info.info) {
}

ExtensionLoader::ExtensionLoader(DatabaseInstance &db, const string &name) : db(db), extension_name(name) {
}

DatabaseInstance &ExtensionLoader::GetDatabaseInstance() {
	return db;
}

所以把上述语句改为

cpp 复制代码
	DatabaseInstance & instance=loader.GetDatabaseInstance();
	std::thread([&instance]() mutable { start_server(instance); }).detach();

重新编译,处理,加载,这次再用psql就能访问了。

cpp 复制代码
root@6ae32a5ffcde:/# psql 'postgresql://localhost:15432/main' -c 'select * from generate_series(0, 4)'
 generate_series
-----------------
               0
               1
               2
               3
               4
(5 rows)

至此,我们可以通过插件duckdb-pgwire为duckdb添加postgresql协议,用支持这个协议的工具来访问了。

cpp 复制代码
root@6ae32a5ffcde:/# psql 'postgresql://localhost:15432/main'
psql (15.13 (Debian 15.13-0+deb12u1), server 14)
Type "help" for help.

main=> select version();
 "version"()
-------------
 v1.4.0
(1 row)

main=> select * from duckdb_functions() where function_name like '%pgwire%';
 database_name | database_oid | schema_name | function_name | alias_of | function_type | description | comment | return_
type | varargs | macro_definition | function_oid | stability
---------------+--------------+-------------+---------------+----------+---------------+-------------+---------+--------
-----+---------+------------------+--------------+------------
 system        | 0            | main        | duckdb_pgwire |          | scalar        |             |         | VARCHAR
     |         |                  |         1998 | CONSISTENT
(1 row)
相关推荐
孤客网络科技工作室2 小时前
Python - 100天从新手到大师:第二十七天Python操作PDF文件
开发语言·python·pdf
liaojuajun2 小时前
可视化地图
开发语言·javascript·ecmascript
武子康2 小时前
Java-138 深入浅出 MySQL Spring Boot 事务传播机制全解析:从 REQUIRED 到 NESTED 的实战详解 传播机制原理
java·大数据·数据库·spring boot·sql·mysql·事务
m0_652545912 小时前
10.2总结
c语言·开发语言
snpgroupcn2 小时前
SAP S/4HANA迁移方法选哪种?选择性数据转换是否合适?企业需要考虑哪些关键因素!
运维·数据库·云计算
scilwb3 小时前
第二周任务:STM32 + 永刚VESC6电调 + N5065电机CAN通信控制
c++·开源·产品
敲码图一乐3 小时前
流量安全——基于Sentinel实现限流,熔断,降级
java·开发语言·数据库
做运维的阿瑞3 小时前
Python原生数据结构深度解析:从入门到精通
开发语言·数据结构·后端·python·系统架构
郝学胜_神的一滴3 小时前
深入理解C++完美转发失败的场景
c++