13#define PHAROS_SQLITE_BUSY_TIMEOUT_MS_RUNTIME 15000
40 PGconn *(*PQconnectdb)(
const char *conninfo);
42 char *(*PQerrorMessage)(
const PGconn *conn);
47 char *(*PQgetvalue)(
const PGresult *res,
int row_number,
int column_number);
52#define PHAROS_CONN_STATUS_OK_RUNTIME 0
53#define PHAROS_PGRES_COMMAND_OK_RUNTIME 1
54#define PHAROS_PGRES_TUPLES_OK_RUNTIME 2
55#define PHAROS_PGRES_SINGLE_TUPLE_RUNTIME 9
74 return app_root != NULL ?
path_join(app_root,
"data/framework/migration-fixture-v1.json") : NULL;
78 return app_root != NULL ?
path_join(app_root,
"data/framework/runtime-state-export-sqlite.sql") : NULL;
82 return app_root != NULL ?
path_join(app_root,
"data/framework/runtime-state-import-sqlite.sql") : NULL;
86 return app_root != NULL ?
path_join(app_root,
"data/framework/runtime-state-export-postgresql.sql") : NULL;
90 return app_root != NULL ?
path_join(app_root,
"data/framework/runtime-state-import-postgresql.sql") : NULL;
98 if (sqlite3_exec(db,
"PRAGMA journal_mode=WAL;", NULL, NULL, NULL) != SQLITE_OK) {
101 if (sqlite3_exec(db,
"PRAGMA synchronous=NORMAL;", NULL, NULL, NULL) != SQLITE_OK) {
109 sqlite3_stmt *stmt = NULL;
111 int step_result = SQLITE_DONE;
112 if (sqlite_path == NULL || sql_text == NULL) {
115 if (sqlite3_open(sqlite_path, &db) != SQLITE_OK) {
125 if (sqlite3_prepare_v2(db, sql_text, -1, &stmt, NULL) != SQLITE_OK) {
129 step_result = sqlite3_step(stmt);
130 if (step_result == SQLITE_ROW) {
131 const unsigned char *text = sqlite3_column_text(stmt, 0);
132 value = strdup(text != NULL ? (
const char *)text :
"");
134 sqlite3_finalize(stmt);
141 char *error_message = NULL;
143 if (sqlite_path == NULL || sql_text == NULL) {
146 if (sqlite3_open(sqlite_path, &db) != SQLITE_OK) {
156 if (sqlite3_exec(db, sql_text, NULL, NULL, &error_message) == SQLITE_OK) {
159 sqlite3_free(error_message);
167 if (sqlite_path == NULL || app_root == NULL || list == NULL || !
yyjson_arr_iter_init(list, &iter)) {
171 char *resolved_path = NULL;
172 char *sql_text = NULL;
178 sql_text = resolved_path != NULL ?
read_file_text(resolved_path) : NULL;
180 if (sql_text == NULL) {
194 const unsigned char *cursor = (
const unsigned char *)(value != NULL ? value :
"");
195 unsigned long long hash = 1469598103934665603ULL;
196 char *out = (
char *)malloc(17);
200 while (*cursor !=
'\0') {
201 hash ^= (
unsigned long long)(*cursor++);
202 hash *= 1099511628211ULL;
204 snprintf(out, 17,
"%016llx", hash);
215 char *forward_checksum = NULL;
216 char *migration_id = NULL;
217 char *payload = NULL;
220 if (app_root == NULL || migration_record == NULL || backend == NULL) {
231 char *resolved_path = NULL;
232 char *file_text = NULL;
238 if (resolved_path != NULL &&
path_exists(resolved_path)) {
240 if (file_text != NULL &&
buffer_append(&combined, file_text, strlen(file_text)) != 0) {
248 if (resolved_path != NULL) {
249 if (
buffer_append(&combined,
"\n-- pharos-path: ", strlen(
"\n-- pharos-path: ")) != 0
250 ||
buffer_append(&combined, resolved_path, strlen(resolved_path)) != 0
264 if (migration_id == NULL || forward_checksum == NULL) {
266 free(forward_checksum);
270 payload = (
char *)malloc(strlen(migration_id) + strlen(backend) + strlen(forward_checksum) + 64);
271 if (payload != NULL) {
272 snprintf(payload, strlen(migration_id) + strlen(backend) + strlen(forward_checksum) + 64,
273 "migration_id=%s\nbackend=%s\nforward_checksum=%s",
282 free(forward_checksum);
287 if (config == NULL) {
299 memset(config, 0,
sizeof(*config));
303 const char *app_root,
304 const char *runtime_conf_path,
307 if (app_root == NULL || app_root[0] ==
'\0' || config == NULL) {
310 memset(config, 0,
sizeof(*config));
322 config->
tls_mode = strdup(
"require");
324 if (config->
host == NULL || config->
host[0] ==
'\0'
325 || config->
port == NULL || config->
port[0] ==
'\0'
327 || config->
user == NULL || config->
user[0] ==
'\0'
347 const char *cursor = value != NULL ? value :
"";
348 if (buffer == NULL || key == NULL || key[0] ==
'\0' || value == NULL || value[0] ==
'\0') {
358 while (*cursor !=
'\0') {
359 if (escape_quotes && (*cursor ==
'\\' || *cursor ==
'\'')) {
374 if (path == NULL || path[0] ==
'\0') {
377 return dlopen(path, RTLD_NOW | RTLD_LOCAL);
383 static const char *
const basenames[] = {
"libpq.5.dylib",
"libpq.dylib",
"libpq.so.5",
"libpq.so", NULL};
384 const char *prefix = NULL;
390 memset(api, 0,
sizeof(*api));
394 prefix = getenv(
"PHAROS_LIBPQ_PREFIX");
395 if (prefix != NULL && prefix[0] !=
'\0') {
396 char *lib_dir =
path_join(prefix,
"lib");
397 if (lib_dir != NULL) {
398 for (index = 0; basenames[index] != NULL && api->
handle == NULL; index++) {
399 char *candidate =
path_join(lib_dir, basenames[index]);
408 for (index = 0; basenames[index] != NULL && api->
handle == NULL; index++) {
411 if (api->
handle == NULL) {
428 memset(api, 0,
sizeof(*api));
437 if (api != NULL && api->
handle != NULL) {
442 memset(api, 0,
sizeof(*api));
448 const char *password_value = NULL;
450 if (config == NULL) {
475 result = buffer.
data;
476 if (result == NULL) {
491 int column_count = 0;
493 int column_index = 0;
494 if (output_out != NULL) {
497 if (api == NULL || result == NULL || output_out == NULL) {
503 for (row_index = 0; row_index < row_count; row_index++) {
504 for (column_index = 0; column_index < column_count; column_index++) {
505 const char *value = api->
PQgetvalue(result, row_index, column_index);
506 if (column_index > 0 &&
buffer_append(&buffer,
"|", 1) != 0) {
510 if (value != NULL &&
buffer_append(&buffer, value, strlen(value)) != 0) {
515 if (row_index + 1 < row_count &&
buffer_append(&buffer,
"\n", 1) != 0) {
520 *output_out = buffer.
data != NULL ? buffer.
data : strdup(
"");
523 if (*output_out == NULL) {
532 const char *sql_text,
537 PGconn *connection = NULL;
539 char *conninfo = NULL;
542 if (output_out != NULL) {
545 if (config == NULL || sql_text == NULL) {
552 connection = conninfo != NULL ? api.
PQconnectdb(conninfo) : NULL;
554 fprintf(stderr,
"postgresql_runtime_error stage=connect message=%s\n", connection != NULL && api.
PQerrorMessage != NULL ? api.
PQerrorMessage(connection) :
"connection_failed");
557 result = api.
PQexec(connection, sql_text);
558 if (result == NULL) {
559 fprintf(stderr,
"postgresql_runtime_error stage=exec message=%s\n", api.
PQerrorMessage != NULL ? api.
PQerrorMessage(connection) :
"exec_failed");
563 if (capture_output) {
565 fprintf(stderr,
"postgresql_runtime_error stage=capture status=%d message=%s\n", status, api.
PQerrorMessage != NULL ? api.
PQerrorMessage(connection) :
"capture_failed");
572 fprintf(stderr,
"postgresql_runtime_error stage=status status=%d message=%s\n", status, api.
PQerrorMessage != NULL ? api.
PQerrorMessage(connection) :
"status_failed");
575 if (result != NULL) {
578 if (connection != NULL) {
588 const char *app_root,
597 char *resolved_path = NULL;
598 char *sql_text = NULL;
604 sql_text = resolved_path != NULL ?
read_file_text(resolved_path) : NULL;
606 if (sql_text == NULL) {
620 const char *placeholder = NULL;
621 size_t prefix_len = 0;
622 size_t suffix_len = 0;
623 char *sql_text = NULL;
624 if (sql_template == NULL || escaped_state_json == NULL) {
627 placeholder = strstr(sql_template,
"__STATE_JSON__");
628 if (placeholder == NULL) {
631 prefix_len = (size_t)(placeholder - sql_template);
632 suffix_len = strlen(placeholder + strlen(
"__STATE_JSON__"));
633 sql_text = (
char *)malloc(prefix_len + strlen(escaped_state_json) + suffix_len + 1);
634 if (sql_text == NULL) {
637 memcpy(sql_text, sql_template, prefix_len);
638 memcpy(sql_text + prefix_len, escaped_state_json, strlen(escaped_state_json));
639 memcpy(sql_text + prefix_len + strlen(escaped_state_json), placeholder + strlen(
"__STATE_JSON__"), suffix_len + 1);
644 const char *src = value != NULL ? value :
"";
648 while (*src !=
'\0') {
654 src = value != NULL ? value :
"";
655 out = (
char *)malloc(strlen(src) + extra + 1);
660 while (*src !=
'\0') {
681 if (backend != NULL && (
streq(backend,
"sqlite") ||
streq(backend,
"postgresql"))) {
689 const char *app_root,
690 const char *runtime_conf_path,
693 char *sqlite_path = NULL;
694 if (app_root == NULL || app_root[0] ==
'\0') {
698 if (sqlite_path != NULL && sqlite_path[0] !=
'\0') {
704 snprintf(buffer,
sizeof(buffer),
"/var/lib/pharos/%s.sqlite3", app_id != NULL && app_id[0] !=
'\0' ? app_id :
"app");
705 return strdup(buffer);
710 const char *app_root,
711 const char *runtime_conf_path,
715 char *sqlite_path = NULL;
716 char *parent_dir = NULL;
718 if (backend == NULL || !
streq(backend,
"sqlite")) {
723 parent_dir = sqlite_path != NULL ?
path_dirname(sqlite_path) : NULL;
734 const char *app_root,
735 const char *runtime_conf_path
741 if (backend != NULL &&
streq(backend,
"postgresql")
753 const char *app_root,
754 const char *runtime_conf_path
756 char *backend = NULL;
757 char *migration_fixture_path = NULL;
765 char *auth_present = NULL;
766 char *security_present = NULL;
767 char *user_count = NULL;
771 if (app_root == NULL || app_root[0] ==
'\0') {
775 if (backend == NULL || !
streq(backend,
"postgresql")) {
785 if (migration_fixture_path == NULL) {
790 if (migration_doc == NULL) {
802 "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'auth_user');",
806 "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'identity_password_reset');",
810 if ((auth_present == NULL || !
streq(auth_present,
"t")) || (security_present == NULL || !
streq(security_present,
"t"))) {
819 user_count = strdup(
"0");
821 if (user_count == NULL) {
825 if (
streq(user_count,
"0")) {
836 if (migrations != NULL) {
847 char *migration_id = NULL;
848 char *checksum_value = NULL;
849 char *escaped_migration_id = NULL;
850 char *escaped_checksum = NULL;
852 long schema_version = 0;
861 if (escaped_migration_id == NULL || escaped_checksum == NULL) {
863 free(checksum_value);
864 free(escaped_migration_id);
865 free(escaped_checksum);
869 sql = (
char *)malloc(strlen(escaped_migration_id) * 2 + strlen(escaped_checksum) * 2 + 640);
872 free(checksum_value);
873 free(escaped_migration_id);
874 free(escaped_checksum);
878 snprintf(sql, strlen(escaped_migration_id) * 2 + strlen(escaped_checksum) * 2 + 640,
879 "INSERT INTO pharos_schema_migration (migration_id, schema_version, backend, checksum_sha256) VALUES ('%s', %ld, 'postgresql', '%s') ON CONFLICT (migration_id) DO NOTHING;\nUPDATE pharos_schema_migration SET checksum_sha256 = '%s' WHERE migration_id = '%s' AND backend = 'postgresql' AND (checksum_sha256 IS NULL OR BTRIM(checksum_sha256) = '');",
880 escaped_migration_id,
884 escaped_migration_id);
887 free(checksum_value);
888 free(escaped_migration_id);
889 free(escaped_checksum);
895 free(checksum_value);
896 free(escaped_migration_id);
897 free(escaped_checksum);
905 free(migration_fixture_path);
907 free(security_present);
915 const char *app_root,
916 const char *runtime_conf_path,
919 char *backend = NULL;
920 char *sqlite_path = NULL;
921 char *parent_dir = NULL;
922 char *migration_fixture_path = NULL;
930 char *auth_present = NULL;
931 char *security_present = NULL;
932 char *user_count = NULL;
935 if (app_root == NULL || app_root[0] ==
'\0') {
939 if (backend == NULL || !
streq(backend,
"sqlite")) {
944 parent_dir = sqlite_path != NULL ?
path_dirname(sqlite_path) : NULL;
945 if (sqlite_path == NULL || parent_dir == NULL ||
ensure_directory(parent_dir) != 0) {
950 if (migration_fixture_path == NULL) {
955 if (migration_doc == NULL) {
968 if ((auth_present == NULL || auth_present[0] ==
'\0') || (security_present == NULL || security_present[0] ==
'\0')) {
975 if (user_count == NULL ||
streq(user_count,
"0")) {
986 if (migrations != NULL) {
997 char *migration_id = NULL;
998 char *checksum_value = NULL;
999 char *escaped_migration_id = NULL;
1000 char *escaped_checksum = NULL;
1002 long schema_version = 0;
1011 if (escaped_migration_id == NULL || escaped_checksum == NULL) {
1013 free(checksum_value);
1014 free(escaped_migration_id);
1015 free(escaped_checksum);
1019 sql = (
char *)malloc(strlen(escaped_migration_id) * 2 + strlen(escaped_checksum) * 2 + 512);
1022 free(checksum_value);
1023 free(escaped_migration_id);
1024 free(escaped_checksum);
1028 snprintf(sql, strlen(escaped_migration_id) * 2 + strlen(escaped_checksum) * 2 + 512,
1029 "INSERT OR IGNORE INTO pharos_schema_migration (migration_id, schema_version, backend, checksum_sha256) VALUES ('%s', %ld, 'sqlite', '%s');\nUPDATE pharos_schema_migration SET checksum_sha256 = '%s' WHERE migration_id = '%s' AND backend = 'sqlite' AND (checksum_sha256 IS NULL OR TRIM(checksum_sha256) = '');",
1030 escaped_migration_id,
1034 escaped_migration_id);
1037 free(checksum_value);
1038 free(escaped_migration_id);
1039 free(escaped_checksum);
1045 free(checksum_value);
1046 free(escaped_migration_id);
1047 free(escaped_checksum);
1057 free(migration_fixture_path);
1059 free(security_present);
1066 const char *app_root,
1067 const char *runtime_conf_path,
1071 char *sqlite_path = NULL;
1072 char *sql_path = NULL;
1073 char *sql_text = NULL;
1074 char *export_json = NULL;
1076 if (backend == NULL) {
1079 if (
streq(backend,
"sqlite")) {
1083 if (sqlite_path == NULL || sqlite_path[0] ==
'\0' || sql_text == NULL) {
1087 }
else if (
streq(backend,
"postgresql")) {
1108 const char *app_root,
1109 const char *runtime_conf_path,
1113 char *sqlite_path = NULL;
1114 char *table_present = NULL;
1115 char *count_text = NULL;
1117 if (backend == NULL) {
1120 if (
streq(backend,
"sqlite")) {
1122 if (sqlite_path != NULL && sqlite_path[0] !=
'\0') {
1124 if (table_present == NULL || table_present[0] ==
'\0') {
1125 count_text = strdup(
"0");
1130 }
else if (
streq(backend,
"postgresql")) {
1132 char *table_exists = NULL;
1134 "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'audit_event');",
1136 &table_exists) == 0) {
1137 if (table_exists != NULL &&
streq(table_exists,
"t")) {
1140 count_text = strdup(
"0");
1148 free(table_present);
1154 const char *app_root,
1155 const char *runtime_conf_path,
1157 const char *state_path,
1158 const char *expected_audit_count
1160 char *backend = NULL;
1161 char *sqlite_path = NULL;
1162 char *current_audit_count = NULL;
1163 char *state_json = NULL;
1164 char *escaped_state_json = NULL;
1165 char *sql_template_path = NULL;
1166 char *sql_template = NULL;
1167 char *sql_text = NULL;
1170 if (app_root == NULL || app_root[0] ==
'\0' || state_path == NULL || state_path[0] ==
'\0') {
1174 if (backend == NULL) {
1177 if (expected_audit_count != NULL && expected_audit_count[0] !=
'\0') {
1179 if (current_audit_count == NULL || !
streq(current_audit_count, expected_audit_count)) {
1186 if (
streq(backend,
"sqlite")) {
1189 sql_template = sql_template_path != NULL ?
read_file_text(sql_template_path) : NULL;
1191 if (sqlite_path == NULL || sqlite_path[0] ==
'\0' || sql_text == NULL) {
1195 }
else if (
streq(backend,
"postgresql")) {
1200 sql_template = sql_template_path != NULL ?
read_file_text(sql_template_path) : NULL;
1202 if (sql_text == NULL) {
1210 free(current_audit_count);
1212 free(escaped_state_json);
1213 free(sql_template_path);
1221 unsigned char *bytes = NULL;
1224 unsigned long long hash = 1469598103934665603ULL;
1225 char *signature = NULL;
1226 if (path == NULL || path[0] ==
'\0') {
1230 return strdup(
"missing");
1233 if (bytes == NULL) {
1236 for (index = 0; index < length; index++) {
1237 hash ^= (
unsigned long long)bytes[index];
1238 hash *= 1099511628211ULL;
1240 signature = (
char *)malloc(40);
1241 if (signature != NULL) {
1242 snprintf(signature, 40,
"%016llx:%llu", hash, (
unsigned long long)length);
1252 char *backend = NULL;
1253 char *export_json = NULL;
1254 char *state_dir = NULL;
1257 memset(sync, 0,
sizeof(*sync));
1259 if (app == NULL || app->
app_root == NULL || app->
state_path == NULL || sync == NULL) {
1263 if (backend == NULL) {
1267 if (
streq(backend,
"sqlite")) {
1269 fprintf(stderr,
"relational_prepare_failed step=sqlite_runtime_ready app_id=%s\n", app->
app_id != NULL ? app->
app_id :
"");
1275 fprintf(stderr,
"relational_prepare_failed step=sqlite_runtime_prepare app_id=%s code=%d\n", app->
app_id != NULL ? app->
app_id :
"", code);
1277 }
else if (
streq(backend,
"postgresql")) {
1279 fprintf(stderr,
"relational_prepare_failed step=postgresql_runtime_ready app_id=%s\n", app->
app_id != NULL ? app->
app_id :
"");
1285 fprintf(stderr,
"relational_prepare_failed step=postgresql_runtime_prepare app_id=%s code=%d\n", app->
app_id != NULL ? app->
app_id :
"", code);
1292 if (export_json == NULL) {
1293 fprintf(stderr,
"relational_prepare_failed step=runtime_export app_id=%s backend=%s\n", app->
app_id != NULL ? app->
app_id :
"", backend != NULL ? backend :
"");
1299 fprintf(stderr,
"relational_prepare_failed step=write_state app_id=%s path=%s\n", app->
app_id != NULL ? app->
app_id :
"", app->
state_path != NULL ? app->
state_path :
"");
1320 char *after_signature = NULL;
1322 if (app == NULL || sync == NULL || !sync->
enabled) {
1326 if (after_signature == NULL) {
1338 fprintf(stderr,
"relational_sync_back_failed app_id=%s code=%d\n", app->
app_id != NULL ? app->
app_id :
"", code);
1341 free(after_signature);
char * native_dynamic_config_merged_value_dup(const char *app_root, const char *runtime_conf_path, const char *key)
Loads one merged dynamic config value with runtime-conf precedence over app-local config.
Declares Pharos-owned dynamic runtime config resolution helpers.
static void free_native_libpq_api_runtime_local(NativeDynamicLibpqApi *api)
#define PHAROS_PGRES_TUPLES_OK_RUNTIME
int native_dynamic_relational_runtime_import_state(const char *app_root, const char *runtime_conf_path, const char *app_id, const char *state_path, const char *expected_audit_count)
Imports canonical runtime state JSON into the configured relational backend.
static yyjson_val * migration_backend_record_runtime_local(yyjson_val *root, const char *backend_value)
static char * checksum_string_dup_runtime_local(const char *value)
static void free_postgresql_runtime_config_runtime_local(NativeDynamicPostgresqlRuntimeConfig *config)
int native_dynamic_relational_postgresql_runtime_ready(const char *app_root, const char *runtime_conf_path)
Returns whether PostgreSQL runtime prerequisites are satisfied.
char * native_dynamic_relational_file_signature_dup(const char *path)
Computes a stable signature for one file path.
int native_dynamic_relational_postgresql_runtime_prepare(const char *app_root, const char *runtime_conf_path)
Prepares the PostgreSQL schema, seed data, and migration ledger for one dynamic app.
int native_dynamic_relational_sqlite_runtime_prepare(const char *app_root, const char *runtime_conf_path, const char *app_id)
Prepares the sqlite schema, seed data, and migration ledger for one dynamic app.
static int capture_postgresql_result_output_runtime_local(const NativeDynamicLibpqApi *api, PGresult *result, char **output_out)
#define PHAROS_PGRES_COMMAND_OK_RUNTIME
static char * sqlite_exec_first_value_dup_runtime_local(const char *sqlite_path, const char *sql_text)
static void * open_libpq_handle_candidate_runtime_local(const char *path)
static char * postgresql_conninfo_dup_runtime_local(const NativeDynamicPostgresqlRuntimeConfig *config)
static char * migration_fixture_path_dup_runtime_local(const char *app_root)
char * native_dynamic_relational_runtime_audit_count_dup(const char *app_root, const char *runtime_conf_path, const char *app_id)
Returns the current audit-event count from the configured relational backend.
int native_dynamic_relational_sqlite_runtime_ready(const char *app_root, const char *runtime_conf_path, const char *app_id)
Returns whether sqlite runtime prerequisites are satisfied.
void native_dynamic_relational_request_sync_free(NativeDynamicRelationalRequestSync *sync)
Clears heap-owned fields in a request-local relational sync record.
static char * runtime_state_export_postgresql_path_dup_runtime_local(const char *app_root)
static char * runtime_state_placeholder_sql_dup_runtime_local(const char *sql_template, const char *escaped_state_json)
char * native_dynamic_relational_runtime_export_json_dup(const char *app_root, const char *runtime_conf_path, const char *app_id)
Exports canonical runtime state JSON from the configured relational backend.
static int sqlite_configure_connection_runtime_local(sqlite3 *db)
static char * migration_expected_checksum_dup_runtime_local(const char *app_root, yyjson_val *migration_record, const char *backend)
static int sqlite_apply_file_list_runtime_local(const char *sqlite_path, const char *app_root, yyjson_val *list)
int native_dynamic_relational_prepare_request_state(const AppRuntime *app, NativeDynamicRelationalRequestSync *sync)
Exports relational state into the app state file before request handling when enabled.
static char * sql_literal_escape_dup_runtime_local(const char *value)
static char * runtime_state_import_sqlite_path_dup_runtime_local(const char *app_root)
static int conninfo_append_kv_runtime_local(Buffer *buffer, const char *key, const char *value, int escape_quotes)
#define PHAROS_CONN_STATUS_OK_RUNTIME
static int sqlite_exec_runtime_local(const char *sqlite_path, const char *sql_text)
char * native_dynamic_relational_backend_dup(const char *app_root, const char *runtime_conf_path)
Returns the configured relational backend when it is recognized.
struct pg_result PGresult
static char * runtime_state_export_sqlite_path_dup_runtime_local(const char *app_root)
static int load_native_libpq_api_runtime_local(NativeDynamicLibpqApi *api)
static int load_postgresql_runtime_config_runtime_local(const char *app_root, const char *runtime_conf_path, NativeDynamicPostgresqlRuntimeConfig *config)
#define PHAROS_SQLITE_BUSY_TIMEOUT_MS_RUNTIME
static char * runtime_state_import_postgresql_path_dup_runtime_local(const char *app_root)
int native_dynamic_relational_sync_back_if_changed(const AppRuntime *app, const NativeDynamicRelationalRequestSync *sync)
Imports the app state file back into the relational backend when it changed.
static int run_postgresql_sql_capture_runtime_local(const NativeDynamicPostgresqlRuntimeConfig *config, const char *sql_text, int capture_output, char **output_out)
char * native_dynamic_relational_sqlite_path_dup(const char *app_root, const char *runtime_conf_path, const char *app_id)
Returns the effective sqlite database path for a dynamic app.
#define PHAROS_PGRES_SINGLE_TUPLE_RUNTIME
static int postgresql_apply_file_list_runtime_local(const NativeDynamicPostgresqlRuntimeConfig *config, const char *app_root, yyjson_val *list)
Declares Pharos-owned native relational runtime helpers for dynamic apps.
int ensure_directory(const char *path)
Creates a directory path and any missing parent directories.
int write_text_file(const char *path, const char *content)
Writes a text buffer to a file path.
Declares native filesystem helper routines.
unsigned char * read_file_bytes_dup_runtime(const char *path, size_t *out_size)
Reads the full content of a binary file into a heap-allocated buffer.
void buffer_init(Buffer *buffer)
Initializes a growable buffer to an empty state.
char * path_join(const char *left, const char *right)
Joins two path segments using the native path separator.
void trim_in_place(char *text)
Trims leading and trailing ASCII whitespace from a string in place.
void buffer_free(Buffer *buffer)
Releases memory owned by a growable buffer.
int streq(const char *a, const char *b)
Tests whether two strings are exactly equal.
char * path_dirname(const char *path)
Returns the parent directory component of a path.
char * resolve_relative_to(const char *base_dir, const char *value)
Resolves a path value relative to a base directory when needed.
int buffer_append(Buffer *buffer, const void *data, size_t len)
Appends bytes to a growable buffer and maintains a trailing NUL byte.
char * read_file_text(const char *path)
Reads an entire file into a newly allocated text buffer.
int path_exists(const char *path)
Tests whether a filesystem path currently exists.
Declares shared low-level support helpers used across the Pharos native runtime.
yyjson_doc * native_json_doc_load_file(const char *path)
Parses a JSON file into an owned yyjson document.
long native_json_obj_get_long_default(yyjson_val *obj, const char *key, long default_value, int *found_out)
Reads a numeric object member or returns a fallback value.
void native_json_doc_free(yyjson_doc *doc)
Releases a document returned by the native yyjson helpers.
char * native_json_obj_get_string_dup(yyjson_val *obj, const char *key)
Duplicates a string-valued key from a JSON object.
yyjson_val * native_json_obj_get_array(yyjson_val *obj, const char *key)
Looks up an array-valued key from a JSON object value.
yyjson_val * native_json_obj_get(yyjson_val *obj, const char *key)
Looks up a key from a JSON object value.
Declares shared helper wrappers around vendored yyjson parsing and serialization APIs.
Loaded runtime metadata for one Pharos app artifact.
Growable byte buffer used by parsing and string assembly helpers.
PGresult *(* PQexec)(PGconn *conn, const char *query)
int(* PQresultStatus)(const PGresult *res)
int(* PQnfields)(const PGresult *res)
void(* PQclear)(PGresult *res)
char *(* PQgetvalue)(const PGresult *res, int row_number, int column_number)
int(* PQntuples)(const PGresult *res)
char *(* PQerrorMessage)(const PGconn *conn)
void(* PQfinish)(PGconn *conn)
PGconn *(* PQconnectdb)(const char *conninfo)
int(* PQstatus)(const PGconn *conn)
Carries resolved PostgreSQL runtime connection settings.
Carries request-local relational bridge state for one native request.
yyjson_api_inline bool yyjson_is_str(const yyjson_val *val)
yyjson_api_inline bool yyjson_is_obj(const yyjson_val *val)
yyjson_api_inline yyjson_val * yyjson_doc_get_root(const yyjson_doc *doc)
yyjson_api_inline bool yyjson_equals_str(const yyjson_val *val, const char *str)
yyjson_api_inline yyjson_val * yyjson_arr_iter_next(yyjson_arr_iter *iter)
yyjson_api_inline size_t yyjson_arr_size(const yyjson_val *arr)
yyjson_api_inline const char * yyjson_get_str(const yyjson_val *val)
yyjson_api_inline bool yyjson_arr_iter_init(const yyjson_val *arr, yyjson_arr_iter *iter)