#include #include #include #include #include #include #include "db.h" static char * strdupn(const unsigned char *); /* * The `add' functions insert an att/post/user struct into the database. */ int addatt(struct att *att) { sqlite3_stmt *stmt; if(sqlite3_prepare(db, "INSERT INTO atts" " (post, name, description, mime, data)" " VALUES (?, ?, ?, ?, ?)", -1, &stmt, 0) != SQLITE_OK) goto err; if(sqlite3_bind_int(stmt, 1, att->post) != SQLITE_OK) goto err; if(sqlite3_bind_text(stmt, 2, att->name, -1, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_bind_text(stmt, 3, att->description, -1, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_bind_text(stmt, 4, att->mime, -1, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_bind_blob(stmt, 5, att->data, att->bytes, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_step(stmt) != SQLITE_DONE) goto err; sqlite3_finalize(stmt); return 1; err: sqlite3_finalize(stmt); return 0; } int adduser(struct user *user) { sqlite3_stmt *stmt; if(sqlite3_prepare(db, "INSERT INTO users" " (name, full, hash, created)" " VALUES (?, ?, ?, ?)", -1, &stmt, 0) != SQLITE_OK) goto err; if(sqlite3_bind_text(stmt, 1, user->name, -1, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_bind_text(stmt, 2, user->full, -1, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_bind_text(stmt, 3, user->hash, -1, SQLITE_STATIC) != SQLITE_OK) goto err; if(sqlite3_bind_int(stmt, 4, time(NULL)) != SQLITE_OK) goto err; if(sqlite3_step(stmt) != SQLITE_DONE) goto err; sqlite3_finalize(stmt); return 1; err: sqlite3_finalize(stmt); return 0; } /* * The `get' functions retrieve an att/post/user struct once, * after which the statement is automatically finalized. */ struct att * getatt(sqlite3_stmt *stmt) { struct att *att; att = nextatt(stmt); sqlite3_finalize(stmt); return att; } struct post * getpost(sqlite3_stmt *stmt) { struct post *post; post = nextpost(stmt); sqlite3_finalize(stmt); return post; } struct user * getuser(sqlite3_stmt *stmt) { struct user *user; user = nextuser(stmt); sqlite3_finalize(stmt); return user; } /* * The `next' functions create an att/post/user struct by querying * the database with the given stmt. They may be called multiple times * with the same stmt to retrieve multiple rows. */ struct att * nextatt(sqlite3_stmt *stmt) { struct att *att; if(!stmt) return NULL; if(sqlite3_step(stmt) != SQLITE_ROW) return NULL; if(!(att = malloc(sizeof(struct att)))) err(1, "malloc"); att->id = sqlite3_column_int(stmt, 0); att->post = sqlite3_column_int(stmt, 1); att->name = strdupn(sqlite3_column_text(stmt, 2)); att->description = strdupn(sqlite3_column_text(stmt, 3)); att->mime = strdupn(sqlite3_column_text(stmt, 4)); att->bytes = sqlite3_column_bytes(stmt, 5); if(!(att->data = malloc(att->bytes))) err(1, "malloc"); memcpy(att->data, sqlite3_column_blob(stmt, 5), att->bytes); return att; } struct post * nextpost(sqlite3_stmt *stmt) { struct post *post; if(!stmt) return NULL; if(sqlite3_step(stmt) != SQLITE_ROW) return NULL; if(!(post = malloc(sizeof(struct post)))) err(1, "malloc"); post->id = sqlite3_column_int(stmt, 0); post->parent = sqlite3_column_int(stmt, 1); post->user = sqlite3_column_int(stmt, 2); post->created = sqlite3_column_int(stmt, 3); post->edited = sqlite3_column_int(stmt, 4); post->subject = strdupn(sqlite3_column_text(stmt, 5)); post->text = strdupn(sqlite3_column_text(stmt, 6)); return post; } struct user * nextuser(sqlite3_stmt *stmt) { struct user *user; if(!stmt) return NULL; if(sqlite3_step(stmt) != SQLITE_ROW) return NULL; if(!(user = malloc(sizeof(struct user)))) err(1, "malloc"); user->id = sqlite3_column_int(stmt, 0); user->name = strdupn(sqlite3_column_text(stmt, 1)); user->full = strdupn(sqlite3_column_text(stmt, 2)); user->hash = strdupn(sqlite3_column_text(stmt, 3)); user->created = sqlite3_column_int(stmt, 4); return user; } /* * Create a statement that selects from a given table on a given integer. * The returned statement must eventually be finalized by calling * sqlite3_finalize(sqlite3_stmt *). */ sqlite3_stmt * selectbyint(char *table, char *field, int i) { char sql[100]; sqlite3_stmt *stmt; snprintf(sql, 100, "SELECT oid, * FROM %s WHERE %s = ?", table, field); if(sqlite3_prepare(db, sql, -1, &stmt, 0) != SQLITE_OK) return NULL; if(sqlite3_bind_int(stmt, 1, i) != SQLITE_OK) return NULL; return stmt; } /* Return an allocated copy of string unless NULL. */ char * strdupn(const unsigned char *s) { return s? strdup((char *)s): NULL; }