在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)
相关推荐
破茧蝴蝶6 小时前
Python分布式爬虫完整教程
开发语言·python
数据库小学妹6 小时前
国产数据库怎么选?兼容、迁移、核心案例与融合架构四道关
数据库·架构·国产数据库·数据库迁移·融合数据库
狗凯之家源码网6 小时前
全新 PHP 轻量客服聊天室源码深度评测
开发语言·php·聊天室系统
远离UE47 小时前
UE5 Substrate Thin Film 源码拆析
开发语言·javascript·ue5
keyipatience7 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
IvorySQL7 小时前
PostgreSQL 日报| PgBouncer 修复三个 CVE 漏洞(10 月 15 日)
数据库·postgresql·区块链
饺子大魔王的男人7 小时前
后台表格、查询、流程总在重复写?我用ToolJet把PostgreSQL直接做成可远程访问的业务系统
数据库·postgresql
一拳一个呆瓜7 小时前
【STL】文件系统导航
c++·stl
All for pursuit.7 小时前
【动态规划-21】312.戳气球
数据结构·c++·算法·leetcode·动态规划