Files
2026-07-13 12:32:25 +08:00

128 lines
4.2 KiB
C

#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void die(SQLSMALLINT type, SQLHANDLE handle, const char *op) {
SQLCHAR state[6], msg[256];
SQLINTEGER native;
SQLSMALLINT len;
SQLGetDiagRec(type, handle, 1, state, &native, msg, sizeof(msg), &len);
fprintf(stderr, "%s failed: %s (state=%s)\n", op, msg, state);
exit(1);
}
#define CHECK_DBC(ret, h, op) do { if ((ret) != SQL_SUCCESS && (ret) != SQL_SUCCESS_WITH_INFO) die(SQL_HANDLE_DBC, (h), (op)); } while (0)
#define CHECK_STMT(ret, h, op) do { if ((ret) != SQL_SUCCESS && (ret) != SQL_SUCCESS_WITH_INFO) die(SQL_HANDLE_STMT, (h), (op)); } while (0)
static void exec_query(SQLHDBC dbc, const char *sql) {
SQLHSTMT stmt;
SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
SQLRETURN ret = SQLExecDirect(stmt, (SQLCHAR *)sql, SQL_NTS);
CHECK_STMT(ret, stmt, sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
}
static long long fetch_count(SQLHDBC dbc, const char *sql) {
SQLHSTMT stmt;
SQLCHAR buf[32];
SQLLEN indicator;
SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
SQLRETURN ret = SQLExecDirect(stmt, (SQLCHAR *)sql, SQL_NTS);
CHECK_STMT(ret, stmt, sql);
SQLFetch(stmt);
SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &indicator);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return atoll((char *)buf);
}
int main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s <user> <port>\n", argv[0]);
return 1;
}
const char *user = argv[1];
const char *port = argv[2];
SQLHENV env;
SQLHDBC dbc;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
char connStr[512];
snprintf(connStr, sizeof(connStr),
"Driver={PostgreSQL Unicode};Server=localhost;Port=%s;Database=postgres;UID=%s;PWD=password;",
port, user);
SQLCHAR outStr[1024];
SQLSMALLINT outLen;
ret = SQLDriverConnect(dbc, NULL, (SQLCHAR *)connStr, SQL_NTS,
outStr, sizeof(outStr), &outLen, SQL_DRIVER_NOPROMPT);
CHECK_DBC(ret, dbc, "SQLDriverConnect");
// SELECT from test_table (set up by bats setup())
{
SQLHSTMT stmt;
SQLINTEGER pk;
SQLLEN indicator;
SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
ret = SQLExecDirect(stmt, (SQLCHAR *)"SELECT pk FROM test_table LIMIT 1", SQL_NTS);
CHECK_STMT(ret, stmt, "SELECT pk FROM test_table LIMIT 1");
SQLFetch(stmt);
SQLGetData(stmt, 1, SQL_C_SLONG, &pk, sizeof(pk), &indicator);
if (pk != 1) {
fprintf(stderr, "expected pk=1, got %d\n", pk);
return 1;
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
}
exec_query(dbc, "INSERT INTO test_table VALUES (2)");
long long count = fetch_count(dbc, "SELECT COUNT(*) FROM test_table");
if (count != 2) {
fprintf(stderr, "expected count=2, got %lld\n", count);
return 1;
}
// Dolt workflow: create table, insert, commit, branch, insert, commit, merge
const char *dolt_queries[] = {
"DROP TABLE IF EXISTS test",
"CREATE TABLE test (pk int, value int, PRIMARY KEY(pk))",
"INSERT INTO test (pk, value) VALUES (0, 0)",
"SELECT dolt_add('-A')",
"SELECT dolt_commit('-m', 'added table test')",
"SELECT dolt_checkout('-b', 'mybranch')",
"INSERT INTO test VALUES (1, 1)",
"SELECT dolt_commit('-a', '-m', 'updated test')",
"SELECT dolt_checkout('main')",
"SELECT dolt_merge('mybranch')",
NULL
};
for (int i = 0; dolt_queries[i]; i++)
exec_query(dbc, dolt_queries[i]);
count = fetch_count(dbc, "SELECT COUNT(*) FROM dolt_log");
if (count != 4) {
fprintf(stderr, "expected 4 dolt_log entries, got %lld\n", count);
return 1;
}
count = fetch_count(dbc, "SELECT COUNT(*) FROM test");
if (count != 2) {
fprintf(stderr, "expected 2 rows in test, got %lld\n", count);
return 1;
}
SQLDisconnect(dbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
printf("psqlODBC test passed\n");
return 0;
}