-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathquery.c
134 lines (98 loc) · 2.62 KB
/
query.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#define _GNU_SOURCE
#include "debug.h"
#include "query.h"
#include "path.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libpq-fe.h>
static PGresult *
db_query_v(PGconn *dbconn, const char *stmt, va_list ap)
{
PGresult *res;
char *buf;
vasprintf(&buf, stmt, ap);
res = PQexec(dbconn, buf);
free(buf);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
debug("query status was %s", PQresStatus(PQresultStatus(res)));
PQclear(res);
return NULL;
}
return res;
}
PGresult *
db_query(PGconn *dbconn, const char *stmt, ...)
{
PGresult *res;
va_list ap;
va_start(ap, stmt);
res = db_query_v(dbconn, stmt, ap);
va_end(ap);
return res;
}
static int
db_command_v(PGconn *dbconn, const char *stmt, va_list ap)
{
PGresult *res;
char *buf;
vasprintf(&buf, stmt, ap);
res = PQexec(dbconn, buf);
free(buf);
// TODO: communicate the SQLSTATE via some global variable back to errno
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
debug("command status was %s", PQresStatus(PQresultStatus(res)));
PQclear(res);
return -EIO;
}
return 0;
}
int
db_command(PGconn *dbconn, const char *stmt, ...)
{
int res;
va_list ap;
va_start(ap, stmt);
res = db_command_v(dbconn, stmt, ap);
va_end(ap);
return res;
}
int
db_row_exists(PGconn *dbconn, const char *stmt, ...)
{
PGresult *res;
int n;
va_list ap;
va_start(ap, stmt);
res = db_query_v(dbconn, stmt, ap);
va_end(ap);
n = PQntuples(res);
PQclear(res);
return n > 0;
}
int
dbpath_exists(const struct dbpath *dbpath, PGconn *dbconn)
{
if (dbpath_is_root(*dbpath))
return 1;
if (dbpath_is_database(*dbpath))
return db_row_exists(dbconn, "SELECT 1 FROM pg_database WHERE datname = '%s';", dbpath->database);
if (dbpath_is_schema(*dbpath))
return db_row_exists(dbconn, "SELECT 1 FROM pg_namespace WHERE nspname = '%s';", dbpath->schema);
if (dbpath_is_table(*dbpath))
return db_row_exists(dbconn, "SELECT 1 FROM pg_namespace n, pg_class c WHERE n.oid = c.relnamespace AND nspname = '%s' AND relname = '%s';", dbpath->schema, dbpath->table);
if (dbpath_is_row(*dbpath))
return db_row_exists(dbconn, "SELECT 1 FROM %s.%s WHERE ctid = '%s';", dbpath->schema, dbpath->table, rowname_to_ctid(dbpath->row));
if (dbpath_is_column(*dbpath))
return db_row_exists(dbconn, "SELECT 1 FROM pg_namespace n, pg_class c, pg_attribute a WHERE n.oid = c.relnamespace AND c.oid = a.attrelid AND nspname = '%s' AND relname = '%s' AND to_char(attnum, 'FM00') || '_' || attname = '%s';", dbpath->schema, dbpath->table, dbpath->column);
return 0;
}
const char *
rowname_to_ctid(const char *row)
{
return strrchr(row, '(');
}