# HG changeset patch # User Tero Marttila # Date 1224198243 -10800 # Node ID 7804cd7b5cd54674c166dfb1b0519b0393b263b6 # Parent d8fabd347a8e347a9a07394be6db44c7b5d45b75 write+setattr diff -r d8fabd347a8e -r 7804cd7b5cd5 Makefile --- a/Makefile Thu Oct 16 22:56:29 2008 +0300 +++ b/Makefile Fri Oct 17 02:04:03 2008 +0300 @@ -20,7 +20,7 @@ # complex modules EVSQL_OBJS = obj/evsql/evsql.o obj/evsql/util.o obj/evpq.o -DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o +DBFS_OBJS = obj/dbfs/dbfs.o obj/dbfs/common.o obj/dbfs/core.o obj/dbfs/op_base.o obj/dbfs/dirop.o obj/dirbuf.o obj/dbfs/fileop.o obj/dbfs/attr.o # first target all: ${BIN_PATHS} @@ -44,7 +44,9 @@ # other targets clean : - -rm obj/* bin/* build/deps/* + -rm obj/*.o obj/*/*.o + -rm bin/* + -rm build/deps/*.d build/deps/*/*.d clean-deps: -rm build/deps/*/*.d diff -r d8fabd347a8e -r 7804cd7b5cd5 doc/fuse_db.sql --- a/doc/fuse_db.sql Thu Oct 16 22:56:29 2008 +0300 +++ b/doc/fuse_db.sql Fri Oct 17 02:04:03 2008 +0300 @@ -1,11 +1,27 @@ -CREATE TABLE inodes (ino serial4 primary key, type char(3), mode int2, size int8); -CREATE TABLE file_tree ("offset" serial4 primary key, name varchar(256) NOT NULL, parent int4 references inodes(ino) NOT NULL, inode int4 references inodes(ino) NOT NULL); +CREATE TABLE inodes ( + ino serial4 primary key, + type char(3) NOT NULL, + mode int2 NOT NULL, + data oid +); -INSERT INTO inodes VALUES (1, 'DIR', 365, 0); -INSERT INTO inodes VALUES (2, 'REG', 292, 0); -INSERT INTO file_tree (name, parent, inode) VALUES ('foo', 1, 2); +CREATE TABLE file_tree ( + "offset" serial4 primary key, + name varchar(256), + parent int4 references inodes(ino), + inode int4 references inodes(ino) NOT NULL +); -ALTER TABLE file_tree ALTER COLUMN name DROP NOT NULL; -ALTER TABLE file_tree ALTER COLUMN parent DROP NOT NULL; -INSERT INTO file_tree (name, parent, inode) VALUES (NULL, NULL, 1); +INSERT INTO inodes VALUES + (1, 'DIR', 365, NULL), + (2, 'REG', 292, lo_create(0)); +INSERT INTO file_tree (name, parent, inode) VALUES + (NULL, NULL, 1 ), + ('foo', 1, 2 ); + +CREATE FUNCTION lo_size (oid) RETURNS int4 LANGUAGE SQL STABLE RETURNS NULL ON NULL INPUT AS 'select lo_lseek(lo_open($1, 262144), 0, 2);'; +CREATE FUNCTION lo_pread (IN fd int4, IN len int4, IN "off" int4) RETURNS bytea LANGUAGE SQL STRICT AS 'select lo_lseek($1, $3, 0); select loread($1, $2);'; +CREATE FUNCTION lo_pwrite (IN fd int4, IN buf bytea, IN "off" int4) RETURNS int4 LANGUAGE SQL STRICT AS 'select lo_lseek($1, $3, 0); select lowrite($1, $2);'; +CREATE FUNCTION lo_otruncate (IN oid, IN len int4) RETURNS oid LANGUAGE SQL STRICT AS 'select lo_truncate(lo_open($1, 393216), $2); select $1;'; + diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs.c --- a/src/dbfs.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs.c Fri Oct 17 02:04:03 2008 +0300 @@ -17,7 +17,7 @@ #include "lib/signals.h" #include "lib/misc.h" -#define CONNINFO_DEFAULT "dbname=test" +#define CONNINFO_DEFAULT "dbname=dbfs port=5433" int main (int argc, char **argv) { struct event_base *ev_base = NULL; diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/attr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/dbfs/attr.c Fri Oct 17 02:04:03 2008 +0300 @@ -0,0 +1,175 @@ + +#include "dbfs.h" +#include "../lib/log.h" +#include "../lib/misc.h" + +// max. size for a setattr UPDATE query +#define DBFS_SETATTR_SQL_MAX 512 + +// for building the setattr UPDATE +#define FIELD(to_set, flag, field, value) ((to_set) & (flag)) ? (field " = " value ", ") : "" + +void _dbfs_attr_res (const struct evsql_result_info *res, void *arg) { + struct fuse_req *req = arg; + struct stat st; ZINIT(st); + int err = 0; + + uint32_t ino; + + // check the results + if ((err = _dbfs_check_res(res, 1, 5))) + SERROR(err = (err == 1 ? ENOENT : EIO)); + + // get our data + if (0 + || evsql_result_uint32(res, 0, 0, &ino, 0 ) // inodes.ino + ) + EERROR(err = EIO, "invalid db data"); + + + INFO("[dbfs.getattr %p] -> ino=%lu, stat follows", req, (unsigned long int) ino); + + // stat attrs + if ((err = _dbfs_stat_info(&st, res, 0, 1))) + goto error; + + // XXX: we don't have the ino + st.st_ino = ino; + + // reply + if ((err = fuse_reply_attr(req, &st, st.st_nlink ? CACHE_TIMEOUT : 0))) + EERROR(err, "fuse_reply_entry"); + +error: + if (err && (err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); + + // free + evsql_result_free(res); +} + +void dbfs_getattr (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { + struct dbfs *ctx = fuse_req_userdata(req); + int err; + + (void) fi; + + INFO("[dbfs.getattr %p] ino=%lu", req, ino); + + const char *sql = + "SELECT" + " inodes.ino, " DBFS_STAT_COLS + " FROM inodes" + " WHERE inodes.ino = $1::int4" + " GROUP BY inodes.ino, inodes.type, inodes.mode, data"; + + static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + EVSQL_PARAM ( UINT32 ), + + EVSQL_PARAMS_END + }; + + // build params + if (0 + || evsql_param_uint32(¶ms, 0, ino) + ) + SERROR(err = EIO); + + // query + if (evsql_query_params(ctx->db, NULL, sql, ¶ms, _dbfs_attr_res, req) == NULL) + SERROR(err = EIO); + + // XXX: handle interrupts + + // wait + return; + +error: + if ((err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); +} + + +void dbfs_setattr (struct fuse_req *req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { + struct dbfs *ctx = fuse_req_userdata(req); + int err; + int ret; + + char sql_buf[DBFS_SETATTR_SQL_MAX]; + + static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + EVSQL_PARAM ( UINT16 ), // inodes.mode + EVSQL_PARAM ( UINT32 ), // inodes.uid + EVSQL_PARAM ( UINT32 ), // inodes.gid + EVSQL_PARAM ( UINT32 ), // data size + EVSQL_PARAM ( UINT32 ), // ino + + EVSQL_PARAMS_END + }; + + // log + INFO("[dbfs.setattr %p] ino=%lu, fileop=%p: ", req, ino, fi && fi->fh ? (void*) fi->fh : NULL); + + if (to_set & FUSE_SET_ATTR_MODE) { + // ignore the S_IFMT + attr->st_mode &= 07777; + + INFO("\tmode = %08o", attr->st_mode); + } + + if (to_set & FUSE_SET_ATTR_UID) + INFO("\tuid = %u", attr->st_uid); + + if (to_set & FUSE_SET_ATTR_GID) + INFO("\tgid = %u", attr->st_gid); + + if (to_set & FUSE_SET_ATTR_SIZE) + INFO("\tsize = %lu", attr->st_size); + + if (to_set & FUSE_SET_ATTR_ATIME) + INFO("\tatime = %lu", attr->st_atime); + + if (to_set & FUSE_SET_ATTR_MTIME) + INFO("\tmtime = %lu", attr->st_mtime); + + // the SQL + if ((ret = snprintf(sql_buf, DBFS_SETATTR_SQL_MAX, + "UPDATE inodes SET" + " %s%s%s%s ino = ino" + " WHERE inodes.ino = $5::int4" + " RETURNING inodes.ino, " DBFS_STAT_COLS_NOAGGREGATE, + + FIELD(to_set, FUSE_SET_ATTR_MODE, "mode", "$1::int2"), + FIELD(to_set, FUSE_SET_ATTR_UID, "uid", "$2::int4"), + FIELD(to_set, FUSE_SET_ATTR_GID, "gid", "$3::int4"), + FIELD(to_set, FUSE_SET_ATTR_SIZE, "data", "lo_otruncate(data, $4::int4)") + )) >= DBFS_SETATTR_SQL_MAX && (err = EIO)) + ERROR("sql_buf is too small: %i", ret); + + // the params... + if (0 + || ( evsql_params_clear(¶ms) ) + || ((to_set & FUSE_SET_ATTR_MODE ) && evsql_param_uint16(¶ms, 0, attr->st_mode) ) + || ((to_set & FUSE_SET_ATTR_UID ) && evsql_param_uint32(¶ms, 1, attr->st_uid) ) + || ((to_set & FUSE_SET_ATTR_GID ) && evsql_param_uint32(¶ms, 2, attr->st_gid) ) + || ((to_set & FUSE_SET_ATTR_SIZE ) && evsql_param_uint32(¶ms, 3, attr->st_size) ) + || ( evsql_param_uint32(¶ms, 4, ino) ) + ) + SERROR(err = EIO); + + // trace the query + evsql_query_debug(sql_buf, ¶ms); + + // query... we can pretend it's a getattr :) + if (evsql_query_params(ctx->db, NULL, sql_buf, ¶ms, _dbfs_attr_res, req) == NULL) + SERROR(err = EIO); + + // XXX: handle interrupts + + // wait + return; + +error: + if ((err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); +} diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/common.c --- a/src/dbfs/common.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs/common.c Fri Oct 17 02:04:03 2008 +0300 @@ -51,17 +51,17 @@ uint16_t mode; uint32_t size = 0; // NULL for non-REG inodes - uint64_t nlink; + uint64_t nlink = 0; // will be NULL for non-GROUP BY queries const char *type; // extract the data - if (0 + if ((0 || evsql_result_string(res, row, col_offset + 0, &type, 0 ) // inodes.type || evsql_result_uint16(res, row, col_offset + 1, &mode, 0 ) // inodes.mode || evsql_result_uint32(res, row, col_offset + 2, &size, 1 ) // size - || evsql_result_uint64(res, row, col_offset + 3, &nlink, 0 ) // count(*) - ) - EERROR(err = EIO, "invalid db data"); + || evsql_result_uint64(res, row, col_offset + 3, &nlink, 1 ) // count(*) + ) && (err = EIO)) + ERROR("invalid db data"); INFO("\tst_mode=S_IF%s | %ho, st_nlink=%llu, st_size=%llu", type, mode, (long long unsigned int) nlink, (long long unsigned int) size); @@ -74,7 +74,7 @@ return 0; error: - return -1; + return err; } diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/core.c --- a/src/dbfs/core.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs/core.c Fri Oct 17 02:04:03 2008 +0300 @@ -1,9 +1,8 @@ +#include "dbfs.h" #include "../lib/log.h" #include "../lib/misc.h" -#include "dbfs.h" - /* * Core fs functionality like lookup, getattr */ @@ -28,7 +27,7 @@ INFO("[dbfs.lookup] -> ino=%u", ino); // stat attrs - if (_dbfs_stat_info(&e.attr, res, 0, 1)) + if ((err = _dbfs_stat_info(&e.attr, res, 0, 1))) goto error; // other attrs @@ -57,7 +56,7 @@ // query and params const char *sql = "SELECT" - " inodes.ino, inodes.type, inodes.mode, dbfs_lo_size(data), count(*)" + " inodes.ino, " DBFS_STAT_COLS " FROM file_tree INNER JOIN inodes ON (file_tree.inode = inodes.ino)" " WHERE file_tree.parent = $1::int4 AND file_tree.name = $2::varchar" " GROUP BY inodes.ino, inodes.type, inodes.mode, data"; @@ -90,74 +89,3 @@ EWARNING(err, "fuse_reply_err"); } -void _dbfs_getattr_result (const struct evsql_result_info *res, void *arg) { - struct fuse_req *req = arg; - struct stat st; ZINIT(st); - int err = 0; - - // check the results - if ((err = _dbfs_check_res(res, 1, 4))) - SERROR(err = (err == 1 ? ENOENT : EIO)); - - INFO("[dbfs.getattr %p] -> (stat follows)", req); - - // stat attrs - if (_dbfs_stat_info(&st, res, 0, 0)) - goto error; - - // XXX: we don't have the ino - st.st_ino = 0; - - // reply - if ((err = fuse_reply_attr(req, &st, CACHE_TIMEOUT))) - EERROR(err, "fuse_reply_entry"); - -error: - if (err && (err = fuse_reply_err(req, err))) - EWARNING(err, "fuse_reply_err"); - - // free - evsql_result_free(res); -} - -void dbfs_getattr (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { - struct dbfs *ctx = fuse_req_userdata(req); - int err; - - (void) fi; - - INFO("[dbfs.getattr %p] ino=%lu", req, ino); - - const char *sql = - "SELECT" - " inodes.type, inodes.mode, dbfs_lo_size(data), count(*)" - " FROM inodes" - " WHERE inodes.ino = $1::int4" - " GROUP BY inodes.type, inodes.mode, data"; - - static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { - EVSQL_PARAM ( UINT32 ), - - EVSQL_PARAMS_END - }; - - // build params - if (0 - || evsql_param_uint32(¶ms, 0, ino) - ) - SERROR(err = EIO); - - // query - if (evsql_query_params(ctx->db, NULL, sql, ¶ms, _dbfs_getattr_result, req) == NULL) - SERROR(err = EIO); - - // XXX: handle interrupts - - // wait - return; - -error: - if ((err = fuse_reply_err(req, err))) - EWARNING(err, "fuse_reply_err"); -} - diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/dbfs.c --- a/src/dbfs/dbfs.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs/dbfs.c Fri Oct 17 02:04:03 2008 +0300 @@ -13,10 +13,11 @@ .lookup = dbfs_lookup, .getattr = dbfs_getattr, + .setattr = dbfs_setattr, .open = dbfs_open, .read = dbfs_read, - // .write = dbfs_write, + .write = dbfs_write, .flush = dbfs_flush, .release = dbfs_release, diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/dbfs.h --- a/src/dbfs/dbfs.h Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs/dbfs.h Fri Oct 17 02:04:03 2008 +0300 @@ -28,6 +28,10 @@ // XXX: not sure how this should work #define CACHE_TIMEOUT 1.0 +// columns used for stat_info +#define DBFS_STAT_COLS " inodes.type, inodes.mode, lo_size(data), count(*) " +#define DBFS_STAT_COLS_NOAGGREGATE " inodes.type, inodes.mode, lo_size(data), NULL " + /* * Convert the CHAR(4) inodes.type from SQL into a mode_t. * diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/fileop.c --- a/src/dbfs/fileop.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs/fileop.c Fri Oct 17 02:04:03 2008 +0300 @@ -139,7 +139,7 @@ SERROR(err = EIO); // get the data - if (evsql_result_buf(res, 0, 0, &buf, &size, 0)) + if (evsql_result_binary(res, 0, 0, &buf, &size, 0)) SERROR(err = EIO); INFO("[dbfs.read %p:%p] -> size=%zu", fop, fop->base.req, size); @@ -208,8 +208,83 @@ dbfs_op_fail(&fop->base, err); } +void dbfs_write_res (const struct evsql_result_info *res, void *arg) { + struct dbfs_fileop *fop = arg; + int err; + uint32_t size; + + // check the results + if ((err = _dbfs_check_res(res, 1, 1)) < 0) + SERROR(err = EIO); + + // get the size + if (evsql_result_uint32(res, 0, 0, &size, 0)) + SERROR(err = EIO); + + INFO("[dbfs.write %p:%p] -> size=%lu", fop, fop->base.req, (long unsigned int) size); + + // send it + if ((err = fuse_reply_write(fop->base.req, size))) + EERROR(err, "fuse_reply_write"); + + // ok, req handled + if ((err = dbfs_op_req_done(&fop->base))) + goto error; + + // good, fallthrough + err = 0; + +error: + if (err) + dbfs_op_fail(&fop->base, err); + + // free + evsql_result_free(res); +} + void dbfs_write (struct fuse_req *req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { + struct dbfs *ctx = fuse_req_userdata(req); + struct dbfs_fileop *fop; + int err; + + // get the op + if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL) + return; + // log + INFO("[dbfs.write %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags); + + // query + const char *sql = + "SELECT" + " lo_pwrite($1::int4, $2::bytea, $3::int4)"; + + static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + EVSQL_PARAM ( UINT32 ), // fd + EVSQL_PARAM ( BINARY ), // buf + EVSQL_PARAM ( UINT32 ), // off + + EVSQL_PARAMS_END + }; + + // build params + if (0 + || evsql_param_uint32(¶ms, 0, fop->lo_fd) + || evsql_param_binary(¶ms, 1, buf, size) + || evsql_param_uint32(¶ms, 2, off) + ) + SERROR(err = EIO); + + // query + if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_write_res, fop) == NULL) + SERROR(err = EIO); + + // ok, wait for the info results + return; + +error: + // fail it + dbfs_op_fail(&fop->base, err); } void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { diff -r d8fabd347a8e -r 7804cd7b5cd5 src/dbfs/ops.h --- a/src/dbfs/ops.h Thu Oct 16 22:56:29 2008 +0300 +++ b/src/dbfs/ops.h Fri Oct 17 02:04:03 2008 +0300 @@ -11,6 +11,9 @@ void dbfs_lookup (struct fuse_req *req, fuse_ino_t parent, const char *name); void dbfs_getattr (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); +/* setattr.c */ +void dbfs_setattr(struct fuse_req *req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi); + /* dirop.c */ void dbfs_opendir (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); void dbfs_readdir (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); @@ -19,6 +22,7 @@ /* fileop.c */ void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); +void dbfs_write (struct fuse_req *req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi); void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi); diff -r d8fabd347a8e -r 7804cd7b5cd5 src/evsql.h --- a/src/evsql.h Thu Oct 16 22:56:29 2008 +0300 +++ b/src/evsql.h Fri Oct 17 02:04:03 2008 +0300 @@ -47,8 +47,9 @@ enum evsql_param_type { EVSQL_PARAM_INVALID, - EVSQL_PARAM_NULL, - + EVSQL_PARAM_NULL_, + + EVSQL_PARAM_BINARY, EVSQL_PARAM_STRING, EVSQL_PARAM_UINT16, EVSQL_PARAM_UINT32, @@ -213,8 +214,18 @@ /* * Param-building functions */ +int evsql_param_binary (struct evsql_query_params *params, size_t param, const char *ptr, size_t len); int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr); +int evsql_param_uint16 (struct evsql_query_params *params, size_t param, uint16_t uval); int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval); +int evsql_params_clear (struct evsql_query_params *params); + +/* + * Query-handling functions + */ + +// print out a textual repr of the given query/params via DEBUG +void evsql_query_debug (const char *sql, const struct evsql_query_params *params); /* * Result-handling functions @@ -231,8 +242,7 @@ // fetch the raw binary value from a result set, and return it via ptr // if size is nonzero, check that the size of the field data matches -int evsql_result_buf (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok); -int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok); +int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok); int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok); // fetch certain kinds of values from a binary result set diff -r d8fabd347a8e -r 7804cd7b5cd5 src/evsql/evsql.c --- a/src/evsql/evsql.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/evsql/evsql.c Fri Oct 17 02:04:03 2008 +0300 @@ -852,7 +852,7 @@ // allocate the vertical storage for the parameters if (0 -// !(query->params.types = calloc(query->params.count, sizeof(Oid))) + || !(query->params.types = calloc(query->params.count, sizeof(Oid))) || !(query->params.values = calloc(query->params.count, sizeof(char *))) || !(query->params.lengths = calloc(query->params.count, sizeof(int))) || !(query->params.formats = calloc(query->params.count, sizeof(int))) @@ -861,8 +861,8 @@ // transform for (param = params->list, idx = 0; param->type; param++, idx++) { - // `types` stays NULL - // query->params.types[idx] = 0; + // `set for NULLs, otherwise not + query->params.types[idx] = param->data_raw ? 0 : 16; // values query->params.values[idx] = param->data_raw; @@ -870,8 +870,8 @@ // lengths query->params.lengths[idx] = param->length; - // formats, binary if length is nonzero - query->params.formats[idx] = param->length ? 1 : 0; + // formats, binary if length is nonzero, but text for NULLs + query->params.formats[idx] = param->length && param->data_raw ? 1 : 0; } // result format diff -r d8fabd347a8e -r 7804cd7b5cd5 src/evsql/util.c --- a/src/evsql/util.c Thu Oct 16 22:56:29 2008 +0300 +++ b/src/evsql/util.c Fri Oct 17 02:04:03 2008 +0300 @@ -1,9 +1,66 @@ #include #include "evsql.h" -#include "../lib/error.h" +#include "../lib/log.h" #include "../lib/misc.h" +#define _PARAM_TYPE_CASE(typenam) case EVSQL_PARAM_ ## typenam: return #typenam + +#define _PARAM_VAL_BUF_MAX 120 +#define _PARAM_VAL_CASE(typenam, ...) case EVSQL_PARAM_ ## typenam: if (param->data_raw) ret = snprintf(buf, _PARAM_VAL_BUF_MAX, __VA_ARGS__); else return "(null)"; break + +const char *evsql_param_type (const struct evsql_query_param *param) { + switch (param->type) { + _PARAM_TYPE_CASE (INVALID ); + _PARAM_TYPE_CASE (NULL_ ); + _PARAM_TYPE_CASE (BINARY ); + _PARAM_TYPE_CASE (STRING ); + _PARAM_TYPE_CASE (UINT16 ); + _PARAM_TYPE_CASE (UINT32 ); + _PARAM_TYPE_CASE (UINT64 ); + default: return "???"; + } +} + + +static const char *evsql_param_val (const struct evsql_query_param *param) { + static char buf[_PARAM_VAL_BUF_MAX]; + int ret; + + switch (param->type) { + _PARAM_VAL_CASE (INVALID, "???" ); + _PARAM_VAL_CASE (NULL_, "(null)" ); + _PARAM_VAL_CASE (BINARY, "%zu:%s", param->length, "..." ); + _PARAM_VAL_CASE (STRING, "%s", param->data_raw ); + _PARAM_VAL_CASE (UINT16, "%hu", (unsigned short int) ntohs(param->data.uint16) ); + _PARAM_VAL_CASE (UINT32, "%lu", (unsigned long int) ntohl(param->data.uint32) ); + _PARAM_VAL_CASE (UINT64, "%llu", (unsigned long long int) ntohq(param->data.uint64) ); + default: return "???"; + } + + return buf; +} + +int evsql_params_clear (struct evsql_query_params *params) { + struct evsql_query_param *param; + + for (param = params->list; param->type; param++) + param->data_raw = NULL; + + return 0; +} + +int evsql_param_binary (struct evsql_query_params *params, size_t param, const char *ptr, size_t len) { + struct evsql_query_param *p = ¶ms->list[param]; + + assert(p->type == EVSQL_PARAM_BINARY); + + p->data_raw = ptr; + p->length = len; + + return 0; +} + int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr) { struct evsql_query_param *p = ¶ms->list[param]; @@ -15,6 +72,18 @@ return 0; } +int evsql_param_uint16 (struct evsql_query_params *params, size_t param, uint16_t uval) { + struct evsql_query_param *p = ¶ms->list[param]; + + assert(p->type == EVSQL_PARAM_UINT16); + + p->data.uint16 = htons(uval); + p->data_raw = (const char *) &p->data.uint16; + p->length = sizeof(uval); + + return 0; +} + int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval) { struct evsql_query_param *p = ¶ms->list[param]; @@ -27,6 +96,22 @@ return 0; } +void evsql_query_debug (const char *sql, const struct evsql_query_params *params) { + const struct evsql_query_param *param; + size_t param_count = 0, idx = 0; + + // count the params + for (param = params->list; param->type; param++) + param_count++; + + DEBUG("sql: %s", sql); + DEBUG("params: %zu", param_count); + + for (param = params->list; param->type; param++) { + DEBUG("\t%2zu : %8s = %s", ++idx, evsql_param_type(param), evsql_param_val(param)); + } +} + const char *evsql_result_error (const struct evsql_result_info *res) { if (!res->error) return "No error"; @@ -64,7 +149,7 @@ } } -int evsql_result_buf (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok) { +int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok) { *ptr = NULL; switch (res->evsql->type) { @@ -92,11 +177,16 @@ return -1; } -int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { - size_t real_size; +int evsql_result_binlen (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { + size_t real_size = 0; - if (evsql_result_buf(res, row, col, ptr, &real_size, nullok)) + if (evsql_result_binary(res, row, col, ptr, &real_size, nullok)) goto error; + + if (*ptr == NULL) { + assert(nullok); + return 0; + } if (size && real_size != size) ERROR("[%zu:%zu] field size mismatch: %zu -> %zu", row, col, size, real_size); @@ -108,14 +198,24 @@ } int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok) { - return evsql_result_binary(res, row, col, ptr, 0, nullok); + size_t real_size; + + if (evsql_result_binary(res, row, col, ptr, &real_size, nullok)) + goto error; + + assert(real_size == strlen(*ptr)); + + return 0; + +error: + return -1; } int evsql_result_uint16 (const struct evsql_result_info *res, size_t row, size_t col, uint16_t *uval, int nullok) { const char *data; int16_t sval; - if (evsql_result_binary(res, row, col, &data, sizeof(*uval), nullok)) + if (evsql_result_binlen(res, row, col, &data, sizeof(*uval), nullok)) goto error; if (!data) @@ -138,7 +238,7 @@ const char *data; int32_t sval; - if (evsql_result_binary(res, row, col, &data, sizeof(*uval), nullok)) + if (evsql_result_binlen(res, row, col, &data, sizeof(*uval), nullok)) goto error; if (!data) @@ -161,7 +261,7 @@ const char *data; int64_t sval; - if (evsql_result_binary(res, row, col, &data, sizeof(*uval), nullok)) + if (evsql_result_binlen(res, row, col, &data, sizeof(*uval), nullok)) goto error; if (!data) diff -r d8fabd347a8e -r 7804cd7b5cd5 src/lib/log.h --- a/src/lib/log.h Thu Oct 16 22:56:29 2008 +0300 +++ b/src/lib/log.h Fri Oct 17 02:04:03 2008 +0300 @@ -40,6 +40,7 @@ // various kinds of ways to handle an error, 2**3 of them, *g* #define info(...) _generic_err( LOG_DISPLAY_STDOUT, NULL, 0, __VA_ARGS__ ) +#define info_nonl(...) _generic_err( LOG_DISPLAY_STDOUT | LOG_DISPLAY_NONL, NULL, 0, __VA_ARGS__ ) #define error(...) _generic_err( LOG_DISPLAY_STDERR, NULL, 0, __VA_ARGS__ ) #define err_exit(...) _generic_err_exit( LOG_DISPLAY_STDERR, NULL, 0, __VA_ARGS__ ) #define perr(...) _generic_err( LOG_DISPLAY_STDERR | LOG_DISPLAY_PERR, NULL, 0, __VA_ARGS__ ) @@ -85,6 +86,7 @@ #if INFO_ENABLED #define INFO(...) info(__VA_ARGS__) +#define INFON(...) info_nonl(__VA_ARGS__) #else #define INFO(...) (void) (__VA_ARGS__) #endif