[darwinbuild-changes] [689] branches/PR-7489777/darwinup
source_changes at macosforge.org
source_changes at macosforge.org
Thu Feb 4 15:44:09 PST 2010
Revision: 689
http://trac.macosforge.org/projects/darwinbuild/changeset/689
Author: wsiegrist at apple.com
Date: 2010-02-04 15:44:08 -0800 (Thu, 04 Feb 2010)
Log Message:
-----------
Implement get_value for single value SELECTs and cache statements with libcache.
Modified Paths:
--------------
branches/PR-7489777/darwinup/DB.cpp
branches/PR-7489777/darwinup/DB.h
branches/PR-7489777/darwinup/Database.cpp
branches/PR-7489777/darwinup/Database.h
branches/PR-7489777/darwinup/Depot.cpp
branches/PR-7489777/darwinup/Depot.h
branches/PR-7489777/darwinup/Table.cpp
branches/PR-7489777/darwinup/Table.h
branches/PR-7489777/darwinup/main.cpp
Modified: branches/PR-7489777/darwinup/DB.cpp
===================================================================
--- branches/PR-7489777/darwinup/DB.cpp 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/DB.cpp 2010-02-04 23:44:08 UTC (rev 689)
@@ -46,6 +46,8 @@
}
void DarwinupDatabase::init_schema() {
+ // XXX: use macros to make this cleaner
+
this->m_archives_table = new Table("archives");
// index pk unique
assert(m_archives_table->add_column(new Column("serial", TYPE_INTEGER, false, true, false)));
@@ -70,6 +72,8 @@
assert(this->add_table(this->m_files_table));
}
+
+
uint64_t DarwinupDatabase::insert_archive(uuid_t uuid, uint32_t info, const char* name, time_t date_added) {
bool res = this->insert(this->m_archives_table,
@@ -88,8 +92,42 @@
return this->last_insert_id();
}
+bool DarwinupDatabase::update_file(Archive* archive, const char* path, uint32_t info, mode_t mode,
+ uid_t uid, gid_t gid, Digest* digest) {
+
+ bool res = false;
+
+ // get the serial for the file where archive and path match
+ uint64_t serial;
+ res = this->get_value("file_serial__archive_path",
+ (void**)&serial,
+ this->m_files_table,
+ this->m_files_table->column(0), // serial
+ 2, // number of where conditions
+ this->m_files_table->column(1), // archive
+ (uint64_t)archive->serial(),
+ this->m_files_table->column(8), // path
+ path);
+
+ // update the information
+ res = this->update(this->m_files_table, serial,
+ (uint64_t)archive->serial(),
+ (uint64_t)info,
+ (uint64_t)mode,
+ (uint64_t)uid,
+ (uint64_t)gid,
+ (uint64_t)0,
+ (uint8_t*)(digest ? digest->data() : NULL),
+ (uint32_t)(digest ? digest->size() : 0),
+ path);
+ if (!res) {
+ fprintf(stderr, "Error: unable to update file with serial %llu and path %s: %s \n",
+ serial, path, this->error());
+ }
+
+ return res;
+}
-
uint64_t DarwinupDatabase::insert_file(uint32_t info, mode_t mode, uid_t uid, gid_t gid,
Digest* digest, Archive* archive, const char* path) {
Modified: branches/PR-7489777/darwinup/DB.h
===================================================================
--- branches/PR-7489777/darwinup/DB.h 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/DB.h 2010-02-04 23:44:08 UTC (rev 689)
@@ -59,6 +59,8 @@
// inserts into tables, returns serial from primary key
uint64_t insert_archive(uuid_t uuid, uint32_t info, const char* name, time_t date);
+ bool update_file(Archive* archive, const char* path, uint32_t info, mode_t mode,
+ uid_t uid, gid_t gid, Digest* digest);
uint64_t insert_file(uint32_t info, mode_t mode, uid_t uid, gid_t gid,
Digest* digest, Archive* archive, const char* path);
Modified: branches/PR-7489777/darwinup/Database.cpp
===================================================================
--- branches/PR-7489777/darwinup/Database.cpp 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/Database.cpp 2010-02-04 23:44:08 UTC (rev 689)
@@ -30,18 +30,13 @@
* @APPLE_BSD_LICENSE_HEADER_END@
*/
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
#include "Database.h"
/**
* sqlite3_trace callback for debugging
*/
void dbtrace(void* context, const char* sql) {
- fprintf(stderr, "[TRACE] %s \n", sql);
+ IF_DEBUG("[TRACE] %s \n", sql);
}
Database::Database() {
@@ -49,6 +44,7 @@
m_table_max = 1;
m_table_count = 0;
m_tables = (Table**)malloc(sizeof(Table*) * m_table_max);
+ this->init_cache();
m_db = NULL;
m_path = NULL;
m_error_size = 1024;
@@ -59,6 +55,7 @@
m_table_max = 1;
m_table_count = 0;
m_tables = (Table**)malloc(sizeof(Table*) * m_table_max);
+ this->init_cache();
m_db = NULL;
m_path = strdup(path);
if (!m_path) {
@@ -72,15 +69,55 @@
for (uint32_t i = 0; i < m_table_count; i++) {
delete m_tables[i];
}
+ this->destroy_cache();
free(m_tables);
free(m_path);
free(m_error);
}
+
void Database::init_schema() {
// do nothing... children should implement this
}
+
+void Database::init_cache() {
+ cache_attributes_t attrs;
+ attrs.version = CACHE_ATTRIBUTES_VERSION_2;
+ attrs.key_hash_cb = cache_key_hash_cb_cstring;
+ attrs.key_is_equal_cb = cache_key_is_equal_cb_cstring;
+ attrs.key_retain_cb = cache_key_retain;
+ attrs.key_release_cb = cache_key_release;
+ attrs.value_release_cb = cache_value_release;
+ attrs.value_retain_cb = cache_value_retain;
+ cache_create("org.macosforge.darwinbuild.darwinup.statements", &attrs, &m_statement_cache);
+}
+
+void Database::destroy_cache() {
+ cache_destroy(m_statement_cache);
+}
+
+void cache_key_retain(void* key_in, void** key_out, void* user_data) {
+ fprintf(stderr, "CACHE: key_retain %s\n", (char*)key_in);
+ *key_out = strdup((char*)key_in);
+}
+
+void cache_key_release(void* key, void* user_data) {
+ fprintf(stderr, "CACHE: key_release %s\n", (char*)key);
+ free(key);
+}
+
+void cache_value_retain(void* value, void* user_data) {
+ fprintf(stderr, "CACHE: value_retain %p\n", value);
+ // do nothing
+}
+
+void cache_value_release(void* value, void* user_data) {
+ fprintf(stderr, "CACHE: value_release %p\n", value);
+ sqlite3_finalize((sqlite3_stmt*)value);
+}
+
+
const char* Database::path() {
return m_path;
}
@@ -99,6 +136,7 @@
fprintf(stderr, "Error: unable to connect to database at: %s \n", m_path);
return false;
}
+ sqlite3_trace(m_db, dbtrace, NULL);
if (this->empty()) {
assert(this->create_tables());
}
@@ -152,15 +190,6 @@
return res==SQLITE_OK;
}
-
-bool Database::update(Table* table, Column* column, const char* value, const char* where,
- uint32_t &count) {
- // not implemented
- assert(false);
- return false;
-}
-
-
#define __SQL(callback, context, fmt) \
va_list args; \
va_start(args, fmt); \
@@ -190,8 +219,157 @@
#undef __SQL
+#define __bind_all_columns(_lastarg) \
+ va_list args; \
+ va_start(args, _lastarg); \
+ for (uint32_t i=0; i<table->column_count(); i++) { \
+ Column* col = table->column(i); \
+ if (col->is_pk()) continue; \
+ uint8_t* bdata = NULL; \
+ uint32_t bsize = 0; \
+ switch(col->type()) { \
+ case TYPE_INTEGER: \
+ res = sqlite3_bind_int64(stmt, param++, va_arg(args, uint64_t)); \
+ break; \
+ case TYPE_TEXT: \
+ res = sqlite3_bind_text(stmt, param++, va_arg(args, char*), -1, SQLITE_STATIC); \
+ break; \
+ case TYPE_BLOB: \
+ bdata = va_arg(args, uint8_t*); \
+ bsize = va_arg(args, uint32_t); \
+ res = sqlite3_bind_blob(stmt, param++, \
+ bdata, \
+ bsize, \
+ SQLITE_STATIC); \
+ break; \
+ } \
+ if (res != SQLITE_OK) { \
+ fprintf(stderr, "Error: failed to bind parameter #%d with column #%d of type %d " \
+ "table %s \n", \
+ param, i, col->type(), table->name()); \
+ return false; \
+ } \
+ } \
+ va_end(args);
+
+#define __bind_va_columns(_lastarg) \
+ va_list args; \
+ va_start(args, _lastarg); \
+ for (uint32_t i=0; i<count; i++) { \
+ Column* col = va_arg(args, Column*); \
+ fprintf(stderr, "DEBUG: got a column from va_arg: %p \n", col); \
+ uint8_t* bdata = NULL; \
+ uint32_t bsize = 0; \
+ switch(col->type()) { \
+ case TYPE_INTEGER: \
+ fprintf(stderr, "DEBUG: param %d is integer\n", param); \
+ res = sqlite3_bind_int64(stmt, param++, va_arg(args, uint64_t)); \
+ break; \
+ case TYPE_TEXT: \
+ fprintf(stderr, "DEBUG: param %d is text\n", param); \
+ res = sqlite3_bind_text(stmt, param++, va_arg(args, char*), -1, SQLITE_STATIC); \
+ break; \
+ case TYPE_BLOB: \
+ fprintf(stderr, "DEBUG: param %d is blob\n", param); \
+ bdata = va_arg(args, uint8_t*); \
+ bsize = va_arg(args, uint32_t); \
+ res = sqlite3_bind_blob(stmt, param++, \
+ bdata, \
+ bsize, \
+ SQLITE_STATIC); \
+ break; \
+ } \
+ if (res != SQLITE_OK) { \
+ fprintf(stderr, "Error: failed to bind parameter #%d with column #%d of type %d " \
+ "table %s \n", \
+ param, i, col->type(), table->name()); \
+ return false; \
+ } \
+ } \
+ va_end(args);
+
+int Database::execute(sqlite3_stmt* stmt) {
+ int res = sqlite3_step(stmt);
+ if (res == SQLITE_DONE) res = SQLITE_OK;
+ sqlite3_reset(stmt);
+ return res;
+}
+
+
+bool Database::get_value(const char* name, void** output, Table* table, Column* value_column,
+ uint32_t count, ...) {
+ sqlite3_stmt* stmt;
+ char* key = strdup(name);
+ cache_get_and_retain(m_statement_cache, key, (void**)&stmt);
+ if (!stmt) {
+ // did not have stmt cached, so we need to generate it
+ fprintf(stderr, "DEBUG: get_value is generating query for %s \n", key);
+ va_list args;
+ va_start(args, count);
+ stmt = table->get_value(m_db, value_column, count, args);
+ va_end(args);
+ cache_set_and_retain(m_statement_cache, key, stmt, sizeof(stmt));
+ } else {
+ fprintf(stderr, "DEBUG: found get_value query for %s in cache: %p \n", key, stmt);
+ fprintf(stderr, "DEBUG: query is: %s \n", sqlite3_sql(stmt));
+ }
+
+ int res = SQLITE_OK;
+ uint32_t param = 1;
+ __bind_va_columns(count);
+
+ res = sqlite3_step(stmt);
+ if (res == SQLITE_ROW) {
+ switch(value_column->type()) {
+ case TYPE_INTEGER:
+ *(uint64_t*)output = sqlite3_column_int64(stmt, 0);
+ break;
+ case TYPE_TEXT:
+ *(const unsigned char**)output = sqlite3_column_text(stmt, 0);
+ break;
+ case TYPE_BLOB:
+ *(const void**)output = sqlite3_column_blob(stmt, 0);
+ break;
+ }
+ }
+ sqlite3_reset(stmt);
+ cache_release_value(m_statement_cache, &stmt);
+ free(key);
+ return output != NULL;
+}
+
/**
* Given a table and an arg list in the same order as Table::add_column() calls,
+ * binds and executes a sql update. The Table is responsible for preparing the
+ * statement in Table::update()
+ *
+ * All integer args must be cast to uint64_t
+ * All blob columns must provide 2 args in the list. The first arg is a uint8_t* of data
+ * and then the uint32_t value for size of the data.
+ *
+ */
+bool Database::update(Table* table, uint64_t pkvalue, ...) {
+ int res = SQLITE_OK;
+
+ // get the prepared statement
+ sqlite3_stmt* stmt = table->update(m_db);
+ if (!stmt) {
+ fprintf(stderr, "Error: %s table gave a NULL statement when trying to update.\n", table->name());
+ return false;
+ }
+
+ uint32_t param = 1; // counter to track placeholders in sql statement
+ __bind_all_columns(pkvalue);
+
+ // bind the primary key in the WHERE clause
+ res = sqlite3_bind_int64(stmt, param++, pkvalue);
+ res = this->execute(stmt);
+ return res == SQLITE_OK;
+}
+
+
+/**
+ * Given a table and an arg list in the same order as Table::add_column() calls,
* binds and executes a sql insertion. The Table is responsible for preparing the
* statement in Table::insert()
*
@@ -202,8 +380,6 @@
*/
bool Database::insert(Table* table, ...) {
int res = SQLITE_OK;
- va_list args;
- va_start(args, table);
// get the prepared statement
sqlite3_stmt* stmt = table->insert(m_db);
@@ -213,52 +389,13 @@
}
uint32_t param = 1; // counter to track placeholders in sql statement
-
- for (uint32_t i=0; i<table->column_count(); i++) {
- Column* col = table->column(i);
-
- // primary keys do not get inserted
- if (col->is_pk()) continue;
-
- // temp variable for blob columns
- uint8_t* bdata = NULL;
- uint32_t bsize = 0;
-
- switch(col->type()) {
- case SQLITE_INTEGER:
- res = sqlite3_bind_int64(stmt, param++, va_arg(args, uint64_t));
- break;
- case SQLITE_TEXT:
- res = sqlite3_bind_text(stmt, param++, va_arg(args, char*), -1, SQLITE_STATIC);
- break;
- case SQLITE_BLOB:
- bdata = va_arg(args, uint8_t*);
- bsize = va_arg(args, uint32_t);
- res = sqlite3_bind_blob(stmt, param++,
- bdata,
- bsize,
- SQLITE_STATIC);
- break;
-
- }
- if (res != SQLITE_OK) {
- fprintf(stderr, "Error: failed to bind parameter #%d with column #%d of type %d when inserting "
- "to table %s \n",
- param, i, col->type(), table->name());
- return false;
- }
- }
-
- sqlite3_trace(m_db, dbtrace, NULL);
-
- res = sqlite3_step(stmt);
- if (res == SQLITE_DONE) res = SQLITE_OK;
- sqlite3_reset(stmt);
-
- va_end(args);
+ __bind_all_columns(table);
+ res = this->execute(stmt);
return res == SQLITE_OK;
}
+#undef __bind_params
+
uint64_t Database::last_insert_id() {
return (uint64_t)sqlite3_last_insert_rowid(m_db);
}
Modified: branches/PR-7489777/darwinup/Database.h
===================================================================
--- branches/PR-7489777/darwinup/Database.h 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/Database.h 2010-02-04 23:44:08 UTC (rev 689)
@@ -33,13 +33,27 @@
#ifndef _DATABASE_H
#define _DATABASE_H
+#include <assert.h>
+#include <cache.h>
+#include <cache_callbacks.h>
+#include <sqlite3.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
-#include <stdint.h>
-#include <sqlite3.h>
#include "Table.h"
#include "Digest.h"
#include "Archive.h"
+// libcache callbacks
+void cache_key_retain(void* key_in, void** key_out, void* user_data);
+void cache_key_release(void* key, void* user_data);
+void cache_value_retain(void* value, void* user_data);
+void cache_value_release(void* value, void* user_data);
+
+
/**
*
* Generic sqlite abstraction
@@ -60,25 +74,42 @@
bool connect();
bool connect(const char* path);
- uint64_t last_insert_id();
- const char* get_value(Table* table, Column* column, const char* where);
+ bool begin_transaction();
+ bool rollback_transaction();
+ bool commit_transaction();
+
+
const char* get_row(Table* table, const char* where);
const char* get_column(Table* table, Column* column, const char* where);
const char* get_all(Table* table, const char* where);
uint32_t count(Table* table, const char* where);
- bool update(Table* table, Column* column, const char* value, const char* where,
- uint32_t &count);
bool del(Table* table, const char* where, uint32_t &count);
- bool insert(Table* table, ...);
- bool begin_transaction();
- bool rollback_transaction();
- bool commit_transaction();
+ bool get_value(void* value, Table* table, Column* value_column, ...);
+
+
+ /**
+ * SELECT statement caching and execution
+ *
+ * name is a string key that labels the query for caching purposes (63 char max)
+ * output is where we will store the value requested
+ * table and value_column are what value we'll give back
+ *
+ * everything else are Column*,value pairs for making a WHERE clause
+ *
+ */
+ bool get_value(const char* name, void** output, Table* table, Column* value_column, uint32_t count, ...);
+
+
+ bool update(Table* table, uint64_t pkvalue, ...);
+ bool insert(Table* table, ...);
+
bool add_table(Table*);
+ uint64_t last_insert_id();
protected:
@@ -87,6 +118,12 @@
bool create_tables();
int sql(const char* fmt, ...);
+ int execute(sqlite3_stmt* stmt);
+
+ // libcache
+ void init_cache();
+ void destroy_cache();
+
char* m_path;
sqlite3* m_db;
@@ -94,11 +131,11 @@
uint32_t m_table_count;
uint32_t m_table_max;
+ cache_t* m_statement_cache;
+
char* m_error;
size_t m_error_size;
-
- sqlite3_stmt** m_statements;
-
+
};
#endif
Modified: branches/PR-7489777/darwinup/Depot.cpp
===================================================================
--- branches/PR-7489777/darwinup/Depot.cpp 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/Depot.cpp 2010-02-04 23:44:08 UTC (rev 689)
@@ -76,6 +76,7 @@
Depot::~Depot() {
if (m_lock_fd != -1) this->unlock();
+ delete m_db2;
if (m_db) sqlite3_close(m_db);
if (m_prefix) free(m_prefix);
if (m_depot_path) free(m_depot_path);
@@ -133,6 +134,8 @@
this->SQL("CREATE INDEX files_path ON files (path)");
}
+ m_db2 = new DarwinupDatabase(m_database_path);
+
return res;
}
@@ -1218,30 +1221,11 @@
int Depot::insert(Archive* archive) {
// Don't insert an archive that is already in the database
assert(archive->serial() == 0);
-
- int res = 0;
- static sqlite3_stmt* stmt = NULL;
- if (stmt == NULL && m_db) {
- const char* query = "INSERT INTO archives (uuid, info, name, date_added) VALUES (?, ?, ?, ?)";
- res = sqlite3_prepare(m_db, query, -1, &stmt, NULL);
- if (res != 0) fprintf(stderr, "%s:%d: sqlite3_prepare: %s: %s (%d)\n", __FILE__, __LINE__, query, sqlite3_errmsg(m_db), res);
- }
- if (stmt && res == 0) {
- int i = 1;
- if (res == 0) res = sqlite3_bind_blob(stmt, i++, archive->uuid(), sizeof(uuid_t), SQLITE_STATIC);
- if (res == 0) res = sqlite3_bind_int(stmt, i++, archive->info());
- if (res == 0) res = sqlite3_bind_text(stmt, i++, archive->name(), -1, SQLITE_STATIC);
- if (res == 0) res = sqlite3_bind_int(stmt, i++, archive->date_installed());
- if (res == 0) res = sqlite3_step(stmt);
- if (res == SQLITE_DONE) {
- archive->m_serial = (uint64_t)sqlite3_last_insert_rowid(m_db);
- res = 0;
- } else {
- fprintf(stderr, "%s:%d: Could not add archive to database: %s (%d)\n", __FILE__, __LINE__, sqlite3_errmsg(m_db), res);
- }
- sqlite3_reset(stmt);
- }
- return res;
+ archive->m_serial = m_db2->insert_archive(archive->uuid(),
+ archive->info(),
+ archive->name(),
+ archive->date_installed());
+ return archive->m_serial == 0;
}
int Depot::insert(Archive* archive, File* file) {
Modified: branches/PR-7489777/darwinup/Depot.h
===================================================================
--- branches/PR-7489777/darwinup/Depot.h 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/Depot.h 2010-02-04 23:44:08 UTC (rev 689)
@@ -36,6 +36,7 @@
#include <sys/types.h>
#include <uuid/uuid.h>
#include <sqlite3.h>
+#include "DB.h"
struct Archive;
struct File;
@@ -149,15 +150,17 @@
virtual int SQL(const char* fmt, ...);
- sqlite3* m_db;
+ sqlite3* m_db;
+ DarwinupDatabase* m_db2;
+
mode_t m_depot_mode;
- char* m_prefix;
+ char* m_prefix;
char* m_depot_path;
char* m_database_path;
char* m_archives_path;
char* m_downloads_path;
- int m_lock_fd;
- int m_is_locked;
+ int m_lock_fd;
+ int m_is_locked;
};
#endif
Modified: branches/PR-7489777/darwinup/Table.cpp
===================================================================
--- branches/PR-7489777/darwinup/Table.cpp 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/Table.cpp 2010-02-04 23:44:08 UTC (rev 689)
@@ -56,11 +56,16 @@
for (uint32_t i = 0; i < m_column_count; i++) {
delete m_columns[i];
}
+
free(m_columns);
free(m_name);
+
free(m_create_sql);
free(m_insert_sql);
+ free(m_update_sql);
+
sqlite3_finalize(m_prepared_insert);
+ sqlite3_finalize(m_prepared_update);
}
@@ -142,7 +147,115 @@
return m_create_sql;
}
+#define __check_size \
+ if (used >= size-1) { \
+ size *= 4; \
+ query = (char*)realloc(query, size); \
+ if (!query) { \
+ fprintf(stderr, "Error: ran out of memory!\n"); \
+ return NULL; \
+ } \
+ }
+sqlite3_stmt* Table::get_value(sqlite3* db, Column* value_column, uint32_t count, va_list args) {
+ size_t size = 256;
+ size_t used = 0;
+ char* query = (char*)malloc(size);
+ sqlite3_stmt* stmt = (sqlite3_stmt*)malloc(sizeof(sqlite3_stmt*));
+
+ strlcpy(query, "SELECT ", size);
+ used = strlcat(query, value_column->name(), size);
+ __check_size;
+ used = strlcat(query, " FROM ", size);
+ __check_size;
+ used = strlcat(query, m_name, size);
+ __check_size;
+ used = strlcat(query, " WHERE 1", size);
+ __check_size;
+
+ char tmpstr[256];
+ int len;
+ for (uint32_t i=0; i < count; i++) {
+ Column* col = va_arg(args, Column*);
+ va_arg(args, void*); // pop off the value which we do not need this time around
+ len = snprintf(tmpstr, 256, " AND %s=?", col->name());
+ if (len >= 255) {
+ fprintf(stderr, "Error: column name is too big (limit: 248): %s\n", col->name());
+ return NULL;
+ }
+ used = strlcat(query, tmpstr, size);
+ __check_size;
+ }
+ strlcat(query, ";", size);
+
+ IF_DEBUG("[TABLE] get_value query: %s \n", query);
+
+ int res = sqlite3_prepare_v2(db, query, size, &stmt, NULL);
+ free(query);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to prepare statement for get_value.\n");
+ return NULL;
+ }
+
+ return stmt;
+}
+
+/**
+ * Prepare and cache the update statement.
+ * Assumes table only has 1 primary key
+ */
+sqlite3_stmt* Table::update(sqlite3* db) {
+ // we only need to prepare once, return if we already have it
+ if (m_prepared_update) return m_prepared_update;
+
+ uint32_t i = 0;
+ bool comma = false; // flag we set to start adding commas
+
+ // calculate the length of the sql statement
+ size_t size = 27 + 5*m_column_count;
+ for (i=0; i<m_column_count; i++) {
+ size += strlen(m_columns[i]->name());
+ }
+
+ // generate the sql query
+ m_update_sql = (char*)malloc(size);
+ strlcpy(m_update_sql, "UPDATE ", size);
+ strlcat(m_update_sql, m_name, size);
+ strlcat(m_update_sql, " SET ", size);
+ for (i=0; i<m_column_count; i++) {
+ // comma separate after 0th column
+ if (comma) strlcat(m_update_sql, ", ", size);
+ // primary keys do not get inserted
+ if (!m_columns[i]->is_pk()) {
+ strlcat(m_update_sql, m_columns[i]->name(), size);
+ strlcat(m_update_sql, "=?", size);
+ comma = true;
+ }
+ }
+
+ // WHERE statement using primary keys
+ strlcat(m_update_sql, " WHERE ", size);
+ for (i=0; i<m_column_count; i++) {
+ if (m_columns[i]->is_pk()) {
+ strlcat(m_update_sql, m_columns[i]->name(), size);
+ strlcat(m_update_sql, "=?", size);
+ break;
+ }
+ }
+ strlcat(m_update_sql, ";", size);
+
+ IF_DEBUG("[TABLE] prepared update: %s \n", m_update_sql);
+
+ // prepare
+ int res = sqlite3_prepare_v2(db, m_update_sql, strlen(m_update_sql), &m_prepared_update, NULL);
+ if (res != SQLITE_OK) {
+ fprintf(stderr, "Error: unable to prepare update statement for table: %s \n", m_name);
+ return NULL;
+ }
+ return m_prepared_update;
+}
+
+
sqlite3_stmt* Table::insert(sqlite3* db) {
// we only need to prepare once, return if we already have it
if (m_prepared_insert) return m_prepared_insert;
Modified: branches/PR-7489777/darwinup/Table.h
===================================================================
--- branches/PR-7489777/darwinup/Table.h 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/Table.h 2010-02-04 23:44:08 UTC (rev 689)
@@ -55,10 +55,11 @@
char* count(const char* where);
char* select(const char* where);
char* select_column(const char* column, const char* where);
- char* update(const char* set, const char* where, uint32_t &count);
char* del(const char* where, uint32_t &count);
+ sqlite3_stmt* get_value(sqlite3* db, Column* value_column, uint32_t count, va_list args);
sqlite3_stmt* insert(sqlite3* db);
+ sqlite3_stmt* update(sqlite3* db);
protected:
@@ -67,13 +68,14 @@
char* m_create_sql;
char* m_insert_sql;
+ char* m_update_sql;
Column** m_columns;
uint32_t m_column_count;
uint32_t m_column_max;
sqlite3_stmt* m_prepared_insert;
-
+ sqlite3_stmt* m_prepared_update;
};
#endif
Modified: branches/PR-7489777/darwinup/main.cpp
===================================================================
--- branches/PR-7489777/darwinup/main.cpp 2010-02-03 19:28:01 UTC (rev 688)
+++ branches/PR-7489777/darwinup/main.cpp 2010-02-04 23:44:08 UTC (rev 689)
@@ -147,11 +147,16 @@
DarwinupDatabase* testdb = new DarwinupDatabase("/.DarwinDepot/Database-V200");
Archive* a = new Archive("/.DarwinDepot/Archives/56E93DEE-E6BB-44B2-80A4-32E961751DD8.tar.bz2");
- uint64_t s = testdb->insert_archive(a->uuid(), a->info(), a->name(), a->date_installed());
+ //uint64_t s = testdb->insert_archive(a->uuid(), a->info(), a->name(), a->date_installed());
const char* mypath = "/etc/services";
File* f = FileFactory(mypath);
testdb->insert_file(1, 2, 3, 4, f->digest(), a, mypath);
+ testdb->update_file(a, mypath, 5, 6, 7, 8, f->digest());
+ testdb->update_file(a, mypath, 6, 7, 8, 9, f->digest());
+ testdb->update_file(a, mypath, 7, 8, 9, 0, f->digest());
+ testdb->update_file(a, mypath, 8, 9, 0, 1, f->digest());
+ testdb->update_file(a, mypath, 9, 0, 1, 2, f->digest());
exit(0);
// XXX
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/darwinbuild-changes/attachments/20100204/50b93dcc/attachment-0001.html>
More information about the darwinbuild-changes
mailing list