Lindenii Project Forge
Login

hare-pq

Hare bindings for libpq
Commit info
ID
4b334b8c0bfa5da27eaab326a867d555245379b3
Author
Runxi Yu <me@runxiyu.org>
Author date
Sun, 10 Aug 2025 09:53:38 +0800
Committer
Runxi Yu <me@runxiyu.org>
Committer date
Sun, 10 Aug 2025 09:53:38 +0800
Actions
Move library to pq/
use types::c;

export type conn = opaque;

export @symbol("PQconnectdb") fn connectdb(conninfo: const *c::char) *conn;
export @symbol("PQfinish") fn finish(conn: *conn) void;
export @symbol("PQstatus") fn status(conn: *conn) ConnStatusType;

export type ConnStatusType = enum int {
	OK,
	BAD,

	STARTED,
	MADE,
	AWAITING_RESPONSE,

	AUTH_OK,

	SETENV,
	SSL_STARTUP,
	NEEDED,
	CHECK_WRITABLE,
	CONSUME,
	GSS_STARTUP,
	CHECK_TARGET,

	CHECK_STANDBY,
	ALLOCATED,
};
use types::c;

export @symbol("PQerrorMessage") fn errorMessage(conn: *conn) *c::char;
use types::c;

export @symbol("PQexec") fn exec(conn: *conn, query: *c::char) *result;
use types::c;

export type result = opaque;

export @symbol("PQclear") fn clear(res: *result) void;

export @symbol("PQnfields") fn nfields(res: *result) int;
export @symbol("PQfname") fn fname(res: *result, field_num: int) *c::char;
export @symbol("PQntuples") fn ntuples(res: *result) int;
export @symbol("PQgetvalue") fn getvalue(res: *result, tup_num: int, field_num: int) *c::char;
export @symbol("PQgetlength") fn getlength(res: *result, tup_num: int, field_num: int) int;

export type ExecStatusType = enum int {
	EMPTY_QUERY = 0,
	COMMAND_OK,

	TUPLES_OK,

	COPY_OUT,
	COPY_IN,
	BAD_RESPONSE,

	NONFATAL_ERROR,
	FATAL_ERROR,
	COPY_BOTH,
	SINGLE_TUPLE,
	PIPELINE_SYNC,
	PIPELINE_ABORTED,

	TUPLES_CHUNK,
};

export @symbol("PQresultStatus") fn resultStatus(res: *result) ExecStatusType;
use fmt;
use types::c;

use ffi;
use pq::ffi;

export fn main() void = {
	const conn = ffi::connectdb(c::fromstr("")!);
	defer ffi::finish(conn);

	if (ffi::status(conn) != ffi::ConnStatusType::OK) {
		fmt::fatalf("Connection failed: {}\n", c::tostr_unsafe(ffi::errorMessage(conn)));
	};

	const res = ffi::exec(conn, c::fromstr("SELECT * FROM test")!);
	defer ffi::clear(res);

	const status = ffi::resultStatus(res);
	switch (status) {
	case ffi::ExecStatusType::TUPLES_OK => void;
	case => fmt::fatalf("Query failed with status {}: {}\n", status: int, c::tostr_unsafe(ffi::errorMessage(conn)));
	};

	const nrows = ffi::ntuples(res);
	const ncols = ffi::nfields(res);

	for (let i = 0; i < ncols; i += 1) {
		if (i > 0) {
			fmt::print("\t")!;
		};
		fmt::printf("{}", c::tostr_unsafe(ffi::fname(res, i)))!;
	};
	fmt::println("")!;

	for (let row = 0; row < nrows; row += 1) {
		for (let col = 0; col < ncols; col += 1) {
			if (col > 0) {
				fmt::print("\t")!;
			};
			const val = ffi::getvalue(res, row, col);
			fmt::printf("{}", c::tostr_unsafe(val))!;
		};
		fmt::println("")!;
	};
};