47 |
#include "strlimcpy.h" |
#include "strlimcpy.h" |
48 |
#include "test.h" |
#include "test.h" |
49 |
|
|
|
#ifdef USE_POSTGRES |
|
|
|
|
|
PGconn *conn = NULL; |
|
|
|
|
|
static int pgop_load_tagfile(const char *, STRBUF *); |
|
|
static int pgop_extract_from_tagfile(const char *, const char *, char *, int); |
|
|
DBOP *pgop_open(const char *, int, int, int); |
|
|
char *pgop_get(DBOP *, const char *); |
|
|
void pgop_put(DBOP *, const char *, const char *, const char *); |
|
|
void pgop_delete(DBOP *, const char *); |
|
|
char *pgop_getkey_by_fid(DBOP *, const char *); |
|
|
void pgop_delete_by_fid(DBOP *, const char *); |
|
|
void pgop_update(DBOP *, const char *, const char *, const char *); |
|
|
char *pgop_first(DBOP *, const char *, regex_t *, int); |
|
|
char *pgop_next(DBOP *); |
|
|
char *pgop_lastdat(DBOP *); |
|
|
void pgop_close(DBOP *); |
|
|
#endif /* USE_POSTGRES */ |
|
|
|
|
50 |
int print_statistics = 0; |
int print_statistics = 0; |
|
char *postgres_info; |
|
|
|
|
|
/* |
|
|
* dbop_setinfo: set info string. |
|
|
* |
|
|
* i) info info string |
|
|
* |
|
|
* Currently this method is used only for postgres. |
|
|
*/ |
|
|
void |
|
|
dbop_setinfo(info) |
|
|
char *info; |
|
|
{ |
|
|
postgres_info = info; |
|
|
} |
|
51 |
/* |
/* |
52 |
* dbop_open: open db database. |
* dbop_open: open db database. |
53 |
* |
* |
57 |
* i) flags |
* i) flags |
58 |
* DBOP_DUP: allow duplicate records. |
* DBOP_DUP: allow duplicate records. |
59 |
* DBOP_REMOVE: remove on closed. |
* DBOP_REMOVE: remove on closed. |
|
* DBOP_POSTGRES: use postgres database |
|
60 |
* r) descripter for dbop_xxx() |
* r) descripter for dbop_xxx() |
61 |
*/ |
*/ |
62 |
DBOP * |
DBOP * |
71 |
DBOP *dbop; |
DBOP *dbop; |
72 |
BTREEINFO info; |
BTREEINFO info; |
73 |
|
|
|
#ifdef USE_POSTGRES |
|
|
if (mode != 1 && pgop_load_tagfile(path, NULL)) |
|
|
flags |= DBOP_POSTGRES; |
|
|
if (flags & DBOP_POSTGRES) |
|
|
return pgop_open(path, mode, perm, flags); |
|
|
#endif /* USE_POSTGRES */ |
|
74 |
/* |
/* |
75 |
* setup arguments. |
* setup arguments. |
76 |
*/ |
*/ |
134 |
DBT key, dat; |
DBT key, dat; |
135 |
int status; |
int status; |
136 |
|
|
|
#ifdef USE_POSTGRES |
|
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
return pgop_get(dbop, name); |
|
|
#endif |
|
137 |
key.data = (char *)name; |
key.data = (char *)name; |
138 |
key.size = strlen(name)+1; |
key.size = strlen(name)+1; |
139 |
|
|
155 |
* i) dbop descripter |
* i) dbop descripter |
156 |
* i) name key |
* i) name key |
157 |
* i) data data |
* i) data data |
|
* i) fid file id (only for postgres) |
|
158 |
*/ |
*/ |
159 |
void |
void |
160 |
dbop_put(dbop, name, data, fid) |
dbop_put(dbop, name, data) |
161 |
DBOP *dbop; |
DBOP *dbop; |
162 |
const char *name; |
const char *name; |
163 |
const char *data; |
const char *data; |
|
const char *fid; |
|
164 |
{ |
{ |
165 |
DB *db = dbop->db; |
DB *db = dbop->db; |
166 |
DBT key, dat; |
DBT key, dat; |
171 |
die("primary key size == 0."); |
die("primary key size == 0."); |
172 |
if (len > MAXKEYLEN) |
if (len > MAXKEYLEN) |
173 |
die("primary key too long."); |
die("primary key too long."); |
|
#ifdef USE_POSTGRES |
|
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
return pgop_put(dbop, name, data, fid); |
|
|
#endif |
|
174 |
key.data = (char *)name; |
key.data = (char *)name; |
175 |
key.size = strlen(name)+1; |
key.size = strlen(name)+1; |
176 |
dat.data = (char *)data; |
dat.data = (char *)data; |
200 |
DBT key; |
DBT key; |
201 |
int status; |
int status; |
202 |
|
|
|
#ifdef USE_POSTGRES |
|
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
return pgop_delete(dbop, path); |
|
|
#endif |
|
203 |
if (path) { |
if (path) { |
204 |
key.data = (char *)path; |
key.data = (char *)path; |
205 |
key.size = strlen(path)+1; |
key.size = strlen(path)+1; |
215 |
* i) dbop descripter |
* i) dbop descripter |
216 |
* i) key key |
* i) key key |
217 |
* i) dat data |
* i) dat data |
|
* i) fid file id |
|
218 |
*/ |
*/ |
219 |
void |
void |
220 |
dbop_update(dbop, key, dat, fid) |
dbop_update(dbop, key, dat) |
221 |
DBOP *dbop; |
DBOP *dbop; |
222 |
const char *key; |
const char *key; |
223 |
const char *dat; |
const char *dat; |
|
const char *fid; |
|
224 |
{ |
{ |
225 |
#ifdef USE_POSTGRES |
dbop_put(dbop, key, dat); |
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
pgop_update(dbop, key, dat, fid); |
|
|
else |
|
|
#endif |
|
|
dbop_put(dbop, key, dat, fid); |
|
226 |
} |
} |
|
#ifdef USE_POSTGRES |
|
|
/* |
|
|
* dbop_getkey_by_fid: get key by fid. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) fid file id |
|
|
* r) pointer to data |
|
|
*/ |
|
|
char * |
|
|
dbop_getkey_by_fid(dbop, fid) |
|
|
DBOP *dbop; |
|
|
const char *fid; |
|
|
{ |
|
|
assert(dbop->openflags & DBOP_POSTGRES); |
|
|
return pgop_getkey_by_fid(dbop, fid); |
|
|
} |
|
|
/* |
|
|
* dbop_delete_by_fid: delete record by fid. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) fid file id |
|
|
*/ |
|
|
void |
|
|
dbop_delete_by_fid(dbop, fid) |
|
|
DBOP *dbop; |
|
|
const char *fid; |
|
|
{ |
|
|
assert(dbop->openflags & DBOP_POSTGRES); |
|
|
return pgop_delete_by_fid(dbop, fid); |
|
|
} |
|
|
#endif |
|
227 |
/* |
/* |
228 |
* dbop_first: get first record. |
* dbop_first: get first record. |
229 |
* |
* |
249 |
DBT key, dat; |
DBT key, dat; |
250 |
int status; |
int status; |
251 |
|
|
|
#ifdef USE_POSTGRES |
|
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
return pgop_first(dbop, name, preg, flags); |
|
|
#endif |
|
|
|
|
252 |
dbop->preg = preg; |
dbop->preg = preg; |
253 |
if (flags & DBOP_PREFIX && !name) |
if (flags & DBOP_PREFIX && !name) |
254 |
flags &= ~DBOP_PREFIX; |
flags &= ~DBOP_PREFIX; |
323 |
DBT key, dat; |
DBT key, dat; |
324 |
int status; |
int status; |
325 |
|
|
|
#ifdef USE_POSTGRES |
|
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
return pgop_next(dbop); |
|
|
#endif |
|
|
|
|
326 |
while ((status = (*db->seq)(db, &key, &dat, R_NEXT)) == RET_SUCCESS) { |
while ((status = (*db->seq)(db, &key, &dat, R_NEXT)) == RET_SUCCESS) { |
327 |
assert(dat.data != NULL); |
assert(dat.data != NULL); |
328 |
if (flags & DBOP_KEY && *((char *)key.data) == ' ') |
if (flags & DBOP_KEY && *((char *)key.data) == ' ') |
375 |
{ |
{ |
376 |
DB *db = dbop->db; |
DB *db = dbop->db; |
377 |
|
|
|
#ifdef USE_POSTGRES |
|
|
if (dbop->openflags & DBOP_POSTGRES) |
|
|
return pgop_close(dbop); |
|
|
#endif |
|
|
|
|
378 |
(void)db->close(db); |
(void)db->close(db); |
379 |
if (dbop->openflags & DBOP_REMOVE) |
if (dbop->openflags & DBOP_REMOVE) |
380 |
(void)unlink(dbop->dbname); |
(void)unlink(dbop->dbname); |
382 |
die("cannot change file mode."); |
die("cannot change file mode."); |
383 |
(void)free(dbop); |
(void)free(dbop); |
384 |
} |
} |
|
#ifdef USE_POSTGRES |
|
|
/* |
|
|
* pgop_execute: execute sql statement. |
|
|
* |
|
|
* i) dbop dbop descripter |
|
|
* i) sql sql statement |
|
|
* i) line line number |
|
|
*/ |
|
|
static void |
|
|
pgop_execute(dbop, sql, line) |
|
|
DBOP *dbop; |
|
|
char *sql; |
|
|
int line; |
|
|
{ |
|
|
extern int debug; |
|
|
|
|
|
if (debug) |
|
|
fprintf(stderr, "sql: '%s' at %d\n", sql, line); |
|
|
if (dbop->res) |
|
|
PQclear(dbop->res); |
|
|
if (*sql == '@') { |
|
|
dbop->res = PQexec(conn, sql + 1); |
|
|
} else { |
|
|
dbop->res = PQexec(conn, sql); |
|
|
if (!dbop->res || |
|
|
(PQresultStatus(dbop->res) != PGRES_COMMAND_OK && |
|
|
PQresultStatus(dbop->res) != PGRES_TUPLES_OK)) { |
|
|
fprintf(stderr, "%s: SQL statement failed at %d.\n", progname, line); |
|
|
fprintf(stderr, "sql: %s\n", sql); |
|
|
fprintf(stderr, "postgres: %s", PQerrorMessage(conn)); |
|
|
PQfinish(conn); |
|
|
abort(); |
|
|
exit(1); |
|
|
} |
|
|
} |
|
|
} |
|
|
/* |
|
|
* pgop_connect: connect to databse server. |
|
|
* |
|
|
* i) info connect string |
|
|
*/ |
|
|
static void |
|
|
pgop_connect(info) |
|
|
const char *info; |
|
|
{ |
|
|
if (conn) |
|
|
return; |
|
|
conn = PQconnectdb(info); |
|
|
if (PQstatus(conn) == CONNECTION_BAD) { |
|
|
fprintf(stderr, "%s: Connection to database failed.\n", progname); |
|
|
fprintf(stderr, "PQconnectdb('%s')", info); |
|
|
fprintf(stderr, "postgres: %s", PQerrorMessage(conn)); |
|
|
PQfinish(conn); |
|
|
exit(1); |
|
|
} |
|
|
} |
|
|
/* |
|
|
* pgop_load_tagfile: load tag file. |
|
|
* |
|
|
* i) path path of tag file |
|
|
* o) sb contents of tag file |
|
|
* r) 1: postgres tag file loaded |
|
|
* 0: file not exist or is not postgres tag file |
|
|
*/ |
|
|
static int |
|
|
pgop_load_tagfile(path, sb) |
|
|
const char *path; |
|
|
STRBUF *sb; |
|
|
{ |
|
|
char *p; |
|
|
int alloc = 0; |
|
|
int ispostgres = 0; |
|
|
FILE *fp = fopen(path, "r"); |
|
|
|
|
|
if (fp == NULL) |
|
|
return 0; |
|
|
if (sb == NULL) { |
|
|
sb = strbuf_open(0); |
|
|
alloc = 1; |
|
|
} |
|
|
if (strbuf_fgets(sb, fp, STRBUF_NOCRLF) == NULL) |
|
|
die("%s is empty.", path); |
|
|
fclose(fp); |
|
|
p = strbuf_value(sb); |
|
|
if (!strncmp(p, "postgres: ", strlen("postgres: "))) |
|
|
ispostgres = 1; |
|
|
if (alloc) |
|
|
strbuf_close(sb); |
|
|
return ispostgres; |
|
|
} |
|
|
/* |
|
|
* pgop_extract_from_tagfile: extract a parameter from loaded tag file. |
|
|
* |
|
|
* i) contents contents of loaded tag file |
|
|
* i) key key |
|
|
* o) buf buffer |
|
|
* i) size size of buf |
|
|
* r) 1: exist, 0: not exist |
|
|
*/ |
|
|
static int |
|
|
pgop_extract_from_tagfile(contents, key, buf, size) |
|
|
const char *contents; |
|
|
const char *key; |
|
|
char *buf; |
|
|
int size; |
|
|
{ |
|
|
STRBUF *sb = strbuf_open(0); |
|
|
char *p, *limit = buf + size; |
|
|
|
|
|
strbuf_putc(sb, ' '); |
|
|
strbuf_puts(sb, key); |
|
|
strbuf_putc(sb, '='); |
|
|
p = locatestring(contents, strbuf_value(sb), MATCH_FIRST); |
|
|
if (p == NULL) |
|
|
return 0; |
|
|
p += strbuf_getlen(sb); |
|
|
while (*p && *p != ' ') { |
|
|
if (buf >= limit) |
|
|
die("parameter in postgres tag file too long. '%s'", key); |
|
|
*buf++ = *p++; |
|
|
} |
|
|
*buf = 0; |
|
|
return 1; |
|
|
} |
|
|
/* |
|
|
* pgop_open: open postgres table. |
|
|
* |
|
|
* i) path tag file path |
|
|
* i) mode 0: read, 1: write, 2: update |
|
|
* i) perm permission for chmod(2) |
|
|
* i) flags flags |
|
|
*/ |
|
|
DBOP * |
|
|
pgop_open(path, mode, perm, flags) |
|
|
const char *path; |
|
|
int mode; |
|
|
int perm; |
|
|
int flags; |
|
|
{ |
|
|
DBOP *dbop; |
|
|
STRBUF *sb; |
|
|
char sql[1024], dir[MAXPATHLEN+1], *name; |
|
|
FILE *fp; |
|
|
|
|
|
/* |
|
|
* make dbop discripter. |
|
|
*/ |
|
|
if (!(dbop = (DBOP *)malloc(sizeof(DBOP)))) |
|
|
die("short of memory."); |
|
|
/* |
|
|
* make table name. |
|
|
*/ |
|
|
snprintf(dir, sizeof(dir), "%s", path); |
|
|
if (!(name = strrchr(dir, '/'))) { |
|
|
name = (char *)path; |
|
|
dir[0] = 0; |
|
|
} else |
|
|
*name++ = 0; |
|
|
strlimcpy(dbop->tblname, name, sizeof(dbop->tblname)); |
|
|
dbop->res = NULL; |
|
|
dbop->mode = mode; |
|
|
dbop->openflags = flags; |
|
|
dbop->lastdat = NULL; |
|
|
|
|
|
if (mode == 1) { |
|
|
/* |
|
|
* if the -P option includes info string then use it. |
|
|
*/ |
|
|
if (postgres_info) { |
|
|
snprintf(sql, sizeof(sql), "postgres: %s\n", postgres_info); |
|
|
} else { |
|
|
/* |
|
|
* else if GTAGS exist then load from 'GTAGS'. |
|
|
*/ |
|
|
sb = strbuf_open(0); |
|
|
strcat(dir, "/GTAGS"); |
|
|
if (pgop_load_tagfile(dir, sb)) |
|
|
snprintf(sql, sizeof(sql), "%s\n", strbuf_value(sb)); |
|
|
else |
|
|
die("Please specify info string for PQconnectdb(3) using --postgres='info'."); |
|
|
strbuf_close(sb); |
|
|
} |
|
|
fp = fopen(path, "w"); |
|
|
if (fp == NULL) |
|
|
die("cannot create '%s'.", path); |
|
|
fputs(sql, fp); |
|
|
fclose(fp); |
|
|
chmod(path, perm); |
|
|
} |
|
|
/* |
|
|
* load postgres tag file and make a connection. |
|
|
*/ |
|
|
{ |
|
|
char *p; |
|
|
|
|
|
sb = strbuf_open(0); |
|
|
if (!pgop_load_tagfile(path, sb)) |
|
|
die("%s not found.", path); |
|
|
/* skip 'postgres: ' */ |
|
|
p = strbuf_value(sb); |
|
|
if (strchr(p, ':')) |
|
|
p = strchr(p, ':') + 1; |
|
|
while (*p == ' ') |
|
|
p++; |
|
|
/* make connection to postgres */ |
|
|
pgop_connect(p); |
|
|
strbuf_close(sb); |
|
|
} |
|
|
|
|
|
/* |
|
|
* create table (GTAGS, GRTAGS, GSYMS, GPATH). |
|
|
*/ |
|
|
if (mode == 1) { |
|
|
snprintf(sql, sizeof(sql), "@DROP TABLE %s", dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
snprintf(sql, sizeof(sql), |
|
|
"CREATE TABLE %s (key TEXT, dat TEXT, fid INT4)", dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
snprintf(sql, sizeof(sql), "GRANT ALL ON %s TO public", dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
/* |
|
|
* Create order for speed up: |
|
|
* GTAGS,GRTAGS,GSYMS |
|
|
* create table -> put data -> create index |
|
|
* GPATH create table -> create index -> put data |
|
|
*/ |
|
|
if (!strcmp(name, "GPATH")) { |
|
|
snprintf(sql, sizeof(sql), |
|
|
"CREATE INDEX %s_i1 ON %s (key)", dbop->tblname, dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
snprintf(sql, sizeof(sql), |
|
|
"CREATE INDEX %s_i2 ON %s (fid)", dbop->tblname, dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
} |
|
|
} |
|
|
/* construct SQL statement. */ |
|
|
/* |
|
|
* pgop_delete(), pgop_delete_by_fid() |
|
|
*/ |
|
|
sb = strbuf_open(0); |
|
|
strbuf_puts(sb, "DELETE FROM "); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
strbuf_puts(sb, " WHERE "); |
|
|
strbuf_puts(sb, "fid = "); |
|
|
dbop->delete_stmt = sb; |
|
|
dbop->delete_stmt_len = strbuf_getlen(sb); |
|
|
/* |
|
|
* pgop_get(), pgop_getkey_by_fid() |
|
|
*/ |
|
|
sb = strbuf_open(0); |
|
|
strbuf_puts(sb, "SELECT * FROM "); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
strbuf_puts(sb, " WHERE "); |
|
|
dbop->get_stmt = sb; |
|
|
dbop->get_stmt_len = strbuf_getlen(sb); |
|
|
/* |
|
|
* pgop_put() |
|
|
*/ |
|
|
sb = strbuf_open(0); |
|
|
strbuf_puts(sb, "INSERT INTO "); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
strbuf_puts(sb, " VALUES "); |
|
|
dbop->put_stmt = sb; |
|
|
dbop->put_stmt_len = strbuf_getlen(sb); |
|
|
/* |
|
|
* pgop_first(), pgop_next() |
|
|
*/ |
|
|
sb = strbuf_open(0); |
|
|
strbuf_puts(sb, "FETCH 1 FROM c_"); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
dbop->fetch_stmt = sb; |
|
|
dbop->fetch_stmt_len = strbuf_getlen(sb); |
|
|
|
|
|
return dbop; |
|
|
} |
|
|
|
|
|
/* |
|
|
* pgop_get: get data by a key. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) name name |
|
|
* r) pointer to data |
|
|
*/ |
|
|
char * |
|
|
pgop_get(dbop, name) |
|
|
DBOP *dbop; |
|
|
const char *name; |
|
|
{ |
|
|
STRBUF *sb = dbop->get_stmt; |
|
|
|
|
|
strbuf_setlen(sb, dbop->get_stmt_len); /* truncate */ |
|
|
strbuf_puts(sb, "key = "); |
|
|
strbuf_putc(sb, '\''); |
|
|
strbuf_puts(sb, name); |
|
|
strbuf_putc(sb, '\''); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
if (PQntuples(dbop->res) == 0) |
|
|
return NULL; |
|
|
dbop->lastdat = PQgetvalue(dbop->res, 0, 1); |
|
|
return dbop->lastdat; |
|
|
} |
|
|
/* |
|
|
* pgop_put: put data by a key. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) name key |
|
|
* i) data data |
|
|
* i) fid file id |
|
|
*/ |
|
|
void |
|
|
pgop_put(dbop, key, dat, fid) |
|
|
DBOP *dbop; |
|
|
const char *key; |
|
|
const char *dat; |
|
|
const char *fid; |
|
|
{ |
|
|
STRBUF *sb = dbop->put_stmt; |
|
|
const char *p; |
|
|
|
|
|
strbuf_setlen(sb, dbop->put_stmt_len); /* truncate */ |
|
|
strbuf_puts(sb, "('"); |
|
|
strbuf_puts(sb, key); |
|
|
strbuf_puts(sb, "', '"); |
|
|
for (p = dat; *p; p++) { |
|
|
switch (*p) { |
|
|
case '\\': |
|
|
case '\'': |
|
|
strbuf_putc(sb, '\\'); |
|
|
break; |
|
|
} |
|
|
strbuf_putc(sb, *p); |
|
|
} |
|
|
strbuf_puts(sb, "', "); |
|
|
strbuf_puts(sb, fid); |
|
|
strbuf_puts(sb, ")"); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
} |
|
|
/* |
|
|
* pgop_delete: delete record by a key. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) path path name |
|
|
*/ |
|
|
void |
|
|
pgop_delete(dbop, path) |
|
|
DBOP *dbop; |
|
|
const char *path; |
|
|
{ |
|
|
STRBUF *sb = dbop->delete_stmt; |
|
|
|
|
|
strbuf_setlen(sb, dbop->delete_stmt_len); /* truncate */ |
|
|
strbuf_puts(sb, path); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
} |
|
|
/* |
|
|
* pgop_getkey_by_fid: get key by fid. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) fid file id |
|
|
* r) pointer to data |
|
|
*/ |
|
|
char * |
|
|
pgop_getkey_by_fid(dbop, fid) |
|
|
DBOP *dbop; |
|
|
const char *fid; |
|
|
{ |
|
|
STRBUF *sb = dbop->get_stmt; |
|
|
|
|
|
strbuf_setlen(sb, dbop->get_stmt_len); /* truncate */ |
|
|
strbuf_puts(sb, "fid = "); |
|
|
strbuf_puts(sb, fid); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
if (PQntuples(dbop->res) == 0) |
|
|
return NULL; |
|
|
dbop->lastdat = PQgetvalue(dbop->res, 0, 1); |
|
|
return PQgetvalue(dbop->res, 0, 0); |
|
|
} |
|
|
/* |
|
|
* pgop_delete_by_fid: delete record by fid. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) fid file id |
|
|
*/ |
|
|
void |
|
|
pgop_delete_by_fid(dbop, fid) |
|
|
DBOP *dbop; |
|
|
const char *fid; |
|
|
{ |
|
|
STRBUF *sb = dbop->delete_stmt; |
|
|
|
|
|
strbuf_setlen(sb, dbop->delete_stmt_len); /* truncate */ |
|
|
strbuf_puts(sb, fid); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
} |
|
|
/* |
|
|
* pgop_update: update record. |
|
|
* |
|
|
* i) dbop descripter |
|
|
* i) key key |
|
|
* i) dat data |
|
|
* i) fid file id |
|
|
*/ |
|
|
void |
|
|
pgop_update(dbop, key, dat, fid) |
|
|
DBOP *dbop; |
|
|
const char *key; |
|
|
const char *dat; |
|
|
const char *fid; |
|
|
{ |
|
|
char *p; |
|
|
STRBUF *sb = strbuf_open(0); |
|
|
|
|
|
strbuf_puts(sb, "UPDATE "); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
strbuf_puts(sb, " SET dat = "); |
|
|
strbuf_puts(sb, dat); |
|
|
strbuf_puts(sb, " WHERE key = '"); |
|
|
strbuf_puts(sb, key); |
|
|
strbuf_puts(sb, "'"); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
p = PQcmdTuples(dbop->res); |
|
|
if (!p || !*p || !strcmp(p, "0")) |
|
|
(void)pgop_put(dbop, key, dat, fid); |
|
|
} |
|
|
/* |
|
|
* pgop_first: get first record. |
|
|
* |
|
|
* i) dbop dbop descripter |
|
|
* i) name key value or prefix |
|
|
* includes regular expression: ~ read |
|
|
* !=NULL: = read |
|
|
* ==NULL: sequential read |
|
|
* i) preg compiled regular expression if any. |
|
|
* i) flags following pgop_next call take over this. |
|
|
* DBOP_KEY read key part |
|
|
* DBOP_PREFIX prefix read |
|
|
* only valied when sequential read |
|
|
* r) data |
|
|
*/ |
|
|
char * |
|
|
pgop_first(dbop, name, preg, flags) |
|
|
DBOP *dbop; |
|
|
const char *name; |
|
|
regex_t *preg; |
|
|
int flags; |
|
|
{ |
|
|
STRBUF *sb = strbuf_open(0); |
|
|
|
|
|
dbop->preg = preg; |
|
|
dbop->ioflags = flags; |
|
|
if (dbop->ioflags & DBOP_PREFIX && !name) |
|
|
dbop->ioflags &= ~DBOP_PREFIX; |
|
|
pgop_execute(dbop, "BEGIN", __LINE__); |
|
|
/* |
|
|
* construct SQL for read tags. |
|
|
*/ |
|
|
strbuf_puts(sb, "DECLARE c_"); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
strbuf_puts(sb, " CURSOR FOR SELECT key, dat FROM "); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
if (name) { |
|
|
strbuf_puts(sb, " WHERE key"); |
|
|
if (isregex(name) || dbop->ioflags & DBOP_PREFIX) { |
|
|
strbuf_puts(sb, " ~ '"); |
|
|
if (dbop->ioflags & DBOP_PREFIX) |
|
|
strbuf_putc(sb, '^'); |
|
|
strbuf_puts(sb, name); |
|
|
strbuf_puts(sb, "'"); |
|
|
} else { |
|
|
strbuf_puts(sb, " = '"); |
|
|
strbuf_puts(sb, name); |
|
|
strbuf_puts(sb, "'"); |
|
|
} |
|
|
} |
|
|
strbuf_puts(sb, " ORDER BY key"); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
strbuf_close(sb); |
|
|
for (;;) { |
|
|
pgop_execute(dbop, strbuf_value(dbop->fetch_stmt), __LINE__); |
|
|
if (PQntuples(dbop->res) == 0) { |
|
|
STRBUF *sb = strbuf_open(0); |
|
|
strbuf_puts(sb, "CLOSE c_"); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
strbuf_close(sb); |
|
|
pgop_execute(dbop, "COMMIT", __LINE__); |
|
|
return NULL; |
|
|
} |
|
|
if (preg && regexec(preg, PQgetvalue(dbop->res, 0, 0), 0, 0, 0) != 0) |
|
|
continue; |
|
|
dbop->lastdat = PQgetvalue(dbop->res, 0, 1); |
|
|
if (dbop->lastdat && *(dbop->lastdat) != ' ') |
|
|
break; |
|
|
} |
|
|
return PQgetvalue(dbop->res, 0, (dbop->ioflags & DBOP_KEY) ? 0 : 1); |
|
|
} |
|
|
/* |
|
|
* pgop_next: get next record. |
|
|
* |
|
|
* i) dbop dbop descripter |
|
|
* r) data |
|
|
* |
|
|
* Db_next always skip meta records. |
|
|
*/ |
|
|
char * |
|
|
pgop_next(dbop) |
|
|
DBOP *dbop; |
|
|
{ |
|
|
char *fetch = strbuf_value(dbop->fetch_stmt); |
|
|
for (;;) { |
|
|
pgop_execute(dbop, fetch, __LINE__); |
|
|
if (PQntuples(dbop->res) == 0) { |
|
|
STRBUF *sb = strbuf_open(0); |
|
|
strbuf_puts(sb, "CLOSE c_"); |
|
|
strbuf_puts(sb, dbop->tblname); |
|
|
pgop_execute(dbop, strbuf_value(sb), __LINE__); |
|
|
strbuf_close(sb); |
|
|
pgop_execute(dbop, "COMMIT", __LINE__); |
|
|
return NULL; |
|
|
} |
|
|
if (dbop->preg && regexec(dbop->preg, PQgetvalue(dbop->res, 0, 0), 0, 0, 0) != 0) |
|
|
continue; |
|
|
dbop->lastdat = PQgetvalue(dbop->res, 0, 1); |
|
|
if (dbop->lastdat && *(dbop->lastdat) != ' ') |
|
|
break; |
|
|
} |
|
|
|
|
|
return PQgetvalue(dbop->res, 0, (dbop->ioflags & DBOP_KEY) ? 0 : 1); |
|
|
} |
|
|
/* |
|
|
* pgop_lastdat: get last data |
|
|
* |
|
|
* i) dbop dbop descripter |
|
|
* r) last data |
|
|
*/ |
|
|
char * |
|
|
pgop_lastdat(dbop) |
|
|
DBOP *dbop; |
|
|
{ |
|
|
return dbop->lastdat; |
|
|
} |
|
|
/* |
|
|
* pgop_close: close db |
|
|
* |
|
|
* i) dbop dbop descripter |
|
|
*/ |
|
|
void |
|
|
pgop_close(dbop) |
|
|
DBOP *dbop; |
|
|
{ |
|
|
if (dbop->mode == 1 && strncmp(dbop->tblname, "GPATH", strlen("GPATH"))) { |
|
|
char sql[1024]; |
|
|
|
|
|
snprintf(sql, sizeof(sql), |
|
|
"CREATE INDEX %s_i1 ON %s (key)", dbop->tblname, dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
snprintf(sql, sizeof(sql), |
|
|
"CREATE INDEX %s_i2 ON %s (fid)", dbop->tblname, dbop->tblname); |
|
|
pgop_execute(dbop, sql, __LINE__); |
|
|
} |
|
|
if (dbop->res) |
|
|
PQclear(dbop->res); |
|
|
(void)free(dbop); |
|
|
} |
|
|
#endif /* USE_POSTGRES */ |
|