[darwinbuild-changes] [749] branches/PR-7593824/darwinup
source_changes at macosforge.org
source_changes at macosforge.org
Mon Mar 8 16:20:01 PST 2010
Revision: 749
http://trac.macosforge.org/projects/darwinbuild/changeset/749
Author: wsiegrist at apple.com
Date: 2010-03-08 16:20:00 -0800 (Mon, 08 Mar 2010)
Log Message:
-----------
Support per-table and per-column versioning so we can do most upgrades automatically
Modified Paths:
--------------
branches/PR-7593824/darwinup/Column.cpp
branches/PR-7593824/darwinup/Column.h
branches/PR-7593824/darwinup/DB.cpp
branches/PR-7593824/darwinup/DB.h
branches/PR-7593824/darwinup/Database.cpp
branches/PR-7593824/darwinup/Database.h
branches/PR-7593824/darwinup/Table.cpp
branches/PR-7593824/darwinup/Table.h
Modified: branches/PR-7593824/darwinup/Column.cpp
===================================================================
--- branches/PR-7593824/darwinup/Column.cpp 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/Column.cpp 2010-03-09 00:20:00 UTC (rev 749)
@@ -39,25 +39,30 @@
Column::Column(const char* name, uint32_t type) {
m_name = strdup(name);
m_create_sql = NULL;
+ m_alter_sql = NULL;
m_type = type;
m_is_index = false;
m_is_pk = false;
m_is_unique = false;
+ m_version = 0;
}
Column::Column(const char* name, uint32_t type,
bool is_index, bool is_pk, bool is_unique) {
m_name = strdup(name);
m_create_sql = NULL;
+ m_alter_sql = NULL;
m_type = type;
m_is_index = is_index;
m_is_pk = is_pk;
m_is_unique = is_unique;
+ m_version = 0;
}
Column::~Column() {
free(m_name);
free(m_create_sql);
+ free(m_alter_sql);
}
const char* Column::name() {
@@ -80,6 +85,9 @@
return m_is_unique;
}
+uint32_t Column::version() {
+ return m_version;
+}
const char* Column::typestr() {
switch(m_type) {
@@ -117,3 +125,12 @@
}
return (const char*)m_create_sql;
}
+
+const char* Column::alter(const char* table_name) {
+ if (!m_alter_sql) {
+ asprintf(&m_alter_sql, "ALTER TABLE %s ADD COLUMN %s;",
+ table_name, this->create());
+ }
+ return (const char*)m_alter_sql;
+}
+
Modified: branches/PR-7593824/darwinup/Column.h
===================================================================
--- branches/PR-7593824/darwinup/Column.h 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/Column.h 2010-03-09 00:20:00 UTC (rev 749)
@@ -55,6 +55,8 @@
const bool is_pk();
const bool is_unique();
+ uint32_t version();
+
// return size of this column when packed into a result record
uint32_t size();
@@ -68,9 +70,13 @@
// generate the sql needed to create this column
const char* create();
+ // generate alter table sql for this column for table named table_name
+ const char* alter(const char* table_name);
char* m_name;
- char* m_create_sql;
+ uint32_t m_version; // schema version this was added
+ char* m_create_sql; // sql fragment for use in CREATE TABLE
+ char* m_alter_sql; // entire ALTER TABLE ADD COLUMN sql
uint32_t m_type; // SQLITE_* type definition
bool m_is_index;
bool m_is_pk;
Modified: branches/PR-7593824/darwinup/DB.cpp
===================================================================
--- branches/PR-7593824/darwinup/DB.cpp 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/DB.cpp 2010-03-09 00:20:00 UTC (rev 749)
@@ -34,7 +34,6 @@
DarwinupDatabase::DarwinupDatabase(const char* path) : Database(path) {
- m_schema_version = 1;
this->connect();
}
@@ -42,18 +41,23 @@
// parent automatically deallocates schema objects
}
-int DarwinupDatabase::init_schema() {
+int DarwinupDatabase::init_schema() {
+
+
+ SCHEMA_VERSION(0);
+
this->m_archives_table = new Table("archives");
+ ADD_TABLE(this->m_archives_table);
ADD_PK(m_archives_table, "serial");
ADD_INDEX(m_archives_table, "uuid", TYPE_BLOB, true);
ADD_TEXT(m_archives_table, "name");
ADD_INTEGER(m_archives_table, "date_added");
ADD_INTEGER(m_archives_table, "active");
ADD_INTEGER(m_archives_table, "info");
- ADD_TEXT(m_archives_table, "osbuild");
- assert(this->add_table(this->m_archives_table)==0);
+
this->m_files_table = new Table("files");
+ ADD_TABLE(this->m_files_table);
ADD_PK(m_files_table, "serial");
ADD_INDEX(m_files_table, "archive", TYPE_INTEGER, false);
ADD_INTEGER(m_files_table, "info");
@@ -63,19 +67,15 @@
ADD_INTEGER(m_files_table, "size");
ADD_BLOB(m_files_table, "digest");
ADD_INDEX(m_files_table, "path", TYPE_TEXT, false);
+
// custom index to protect from duplicate files
assert(this->m_files_table->set_custom_create("CREATE UNIQUE INDEX files_archive_path "
"ON files (archive, path);") == 0);
- assert(this->add_table(this->m_files_table)==0);
-
- return 0;
-}
-int DarwinupDatabase::upgrade_schema(uint32_t fromversion) {
- if (fromversion < 1) {
- this->sql_once("ALTER TABLE archives ADD COLUMN osbuild TEXT");
- }
+ SCHEMA_VERSION(1);
+
+ ADD_TEXT(m_archives_table, "osbuild");
return 0;
}
Modified: branches/PR-7593824/darwinup/DB.h
===================================================================
--- branches/PR-7593824/darwinup/DB.h 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/DB.h 2010-03-09 00:20:00 UTC (rev 749)
@@ -56,7 +56,7 @@
struct DarwinupDatabase : Database {
DarwinupDatabase(const char* path);
virtual ~DarwinupDatabase();
- void init_schema();
+ int init_schema();
uint64_t count_files(Archive* archive, const char* path);
uint64_t count_archives(bool include_rollbacks);
Modified: branches/PR-7593824/darwinup/Database.cpp
===================================================================
--- branches/PR-7593824/darwinup/Database.cpp 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/Database.cpp 2010-03-09 00:20:00 UTC (rev 749)
@@ -82,13 +82,17 @@
free(m_error);
}
+uint32_t Database::schema_version() {
+ return this->m_schema_version;
+}
-int Database::init_schema() {
- // do nothing... children should implement this
+void Database::schema_version(uint32_t v) {
+ this->m_schema_version = v;
}
-int Database::upgrade_schema(uint32_t fromversion) {
+int Database::init_schema() {
// do nothing... children should implement this
+ return DB_OK;
}
const char* Database::path() {
@@ -113,6 +117,7 @@
return res;
}
+ int exists = is_regular_file(m_path);
res = sqlite3_open(m_path, &m_db);
if (res) {
sqlite3_close(m_db);
@@ -128,6 +133,22 @@
return res;
}
+ if (!exists) {
+ // create schema since it is empty
+ assert(this->create_tables() == 0);
+ } else {
+ // not empty, but upgrade schema if needed
+ uint32_t version = this->get_schema_version();
+ if (version < this->m_schema_version) {
+ assert(this->upgrade_schema(version) == 0);
+ this->set_schema_version(this->m_schema_version);
+ }
+ if (version > this->m_schema_version) {
+ fprintf(stderr, "Error: this client is too old!\n");
+ return DB_ERROR;
+ }
+ }
+
return res;
}
@@ -139,7 +160,7 @@
}
int Database::post_connect() {
- int res = DB_OK
+ int res = DB_OK;
// prepare transaction statements
if (res == DB_OK)
@@ -157,19 +178,7 @@
if (verbosity & VERBOSE_SQL) {
sqlite3_trace(m_db, dbtrace, NULL);
}
-
- if (this->is_empty()) {
- // create schema since it is empty
- assert(this->create_tables() == 0);
- } else {
- // not empty, but upgrade schema if needed
- version = this->get_schema_version();
- if (version < this->m_schema_version) {
- assert(this->upgrade_schema(version) == 0);
- this->set_schema_version(this->m_schema_version);
- }
- }
-
+
return res;
}
@@ -596,6 +605,7 @@
m_table_max *= REALLOC_FACTOR;
}
m_tables[m_table_count++] = t;
+ t->m_version = this->m_schema_version;
return 0;
}
@@ -617,6 +627,16 @@
return res != SQLITE_OK;
}
+int Database::create_table(Table* table) {
+ int res = this->sql_once(table->create());
+ if (res != DB_OK) {
+ fprintf(stderr, "Error: sql error trying to create"
+ " table: %s: %s\n",
+ table->name(), m_error);
+ }
+ return res;
+}
+
int Database::create_tables() {
int res = SQLITE_OK;
for (uint32_t i=0; i<m_table_count; i++) {
@@ -630,24 +650,92 @@
return res;
}
+int Database::upgrade_schema(uint32_t version) {
+ int res = DB_OK;
+ this->begin_transaction();
+
+ res = this->upgrade_internal_schema(version);
+ if (res != DB_OK) {
+ fprintf(stderr, "Error: unable to upgrade internal schema.\n");
+ this->rollback_transaction();
+ return res;
+ }
+
+ for (uint32_t ti = 0; res == DB_OK && ti < m_table_count; ti++) {
+ if (m_tables[ti]->version() > version) {
+ // entire table is new
+ res = this->create_table(m_tables[ti]);
+ } else {
+ // table is same version, so check for new columns
+ for (uint32_t ci = 0; res == DB_OK && ci < m_tables[ti]->column_count(); ci++) {
+ if (m_tables[ti]->column(ci)->version() < version) {
+ // this should never happen
+ fprintf(stderr, "Error: internal error with schema versioning."
+ " Column %s is older than its table %s. \n",
+ m_tables[ti]->column(ci)->name(), m_tables[ti]->name());
+ }
+ if (m_tables[ti]->column(ci)->version() > version) {
+ // column is new
+ res = this->sql_once(m_tables[ti]->alter_add_column(ci));
+ if (res != DB_OK) {
+ fprintf(stderr, "Error: sql error trying to upgrade (alter)"
+ " table: %s column: %s : %s\n",
+ m_tables[ti]->name(), m_tables[ti]->column(ci)->name(),
+ m_error);
+ }
+ }
+ }
+ }
+ }
+
+ if (res == DB_OK) {
+ this->commit_transaction();
+ } else {
+ this->rollback_transaction();
+ }
+
+ return res;
+}
+
+int Database::upgrade_internal_schema(uint32_t version) {
+ int res = DB_OK;
+
+ if (version == 0) {
+ res = this->sql_once(this->m_information_table->create());
+ }
+
+ return res;
+}
+
int Database::init_internal_schema() {
this->m_information_table = new Table("database_information");
+ ADD_TABLE(this->m_information_table);
ADD_PK(m_information_table, "id");
ADD_INDEX(m_information_table, "variable", TYPE_TEXT, true);
ADD_TEXT(m_information_table, "value");
- assert(this->add_table(this->m_information_table)==0);
+ return DB_OK;
}
-int Database::get_information_value(char* variable, char** value) {
+int Database::get_information_value(const char* variable, char** value) {
return this->get_value("get_information_value",
- value,
+ (void**)value,
this->m_information_table,
- this->m_information_table->columns(1), // value
+ this->m_information_table->column(1), // value
1,
- this->m_information_table->columns(0), // variable
+ this->m_information_table->column(0), // variable
'=', variable);
}
+int Database::update_information_value(const char* variable, const char* value) {
+ return this->update_value("update_information_value",
+ this->m_information_table,
+ this->m_information_table->column(1), // value
+ (void**)value,
+ 1,
+ this->m_information_table->column(0), // variable
+ '=', variable);
+}
+
uint32_t Database::get_schema_version() {
char* vertxt;
int res = DB_OK;
@@ -663,23 +751,16 @@
}
}
-int Database::update_information_value(char* variable, char* value) {
- return this->update_value("update_information_value",
- this->m_information_table,
- this->m_information_table->columns(1), // value
- value,
- 1,
- this->m_information_table->columns(0), // variable
- '=', variable);
-}
-
int Database::set_schema_version(uint32_t version) {
int res = DB_OK;
- res = this->update_information_value("schema_version", &version);
+ char* vertxt;
+ asprintf(&vertxt, "%u", version);
+ if (!vertxt) return DB_ERROR;
+ res = this->update_information_value("schema_version", vertxt);
+ free(vertxt);
return res;
}
-
size_t Database::store_column(sqlite3_stmt* stmt, int column, uint8_t* output) {
size_t used;
int type = sqlite3_column_type(stmt, column);
Modified: branches/PR-7593824/darwinup/Database.h
===================================================================
--- branches/PR-7593824/darwinup/Database.h 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/Database.h 2010-03-09 00:20:00 UTC (rev 749)
@@ -67,19 +67,21 @@
#define FOUND(x) ((x & DB_FOUND) && !(x & DB_ERROR))
// Schema creation macros
+#define SCHEMA_VERSION(v) this->schema_version(v);
+#define ADD_TABLE(t) assert(this->add_table(t)==0);
#define ADD_COLUMN(table, name, type, index, pk, unique) \
- assert(table->add_column(new Column(name, type, index, pk, unique))==0);
+ assert(table->add_column(new Column(name, type, index, pk, unique), this->schema_version())==0);
#define ADD_INDEX(table, name, type, unique) \
- assert(table->add_column(new Column(name, type, true, false, unique))==0);
+ assert(table->add_column(new Column(name, type, true, false, unique), this->schema_version())==0);
#define ADD_PK(table, name) \
assert(table->add_column(new Column(name, TYPE_INTEGER, \
- false, true, false))==0);
+ false, true, false), this->schema_version())==0);
#define ADD_TEXT(table, name) \
- assert(table->add_column(new Column(name, TYPE_TEXT))==0);
+ assert(table->add_column(new Column(name, TYPE_TEXT), this->schema_version())==0);
#define ADD_INTEGER(table, name) \
- assert(table->add_column(new Column(name, TYPE_INTEGER))==0);
+ assert(table->add_column(new Column(name, TYPE_INTEGER), this->schema_version())==0);
#define ADD_BLOB(table, name) \
- assert(table->add_column(new Column(name, TYPE_BLOB))==0);
+ assert(table->add_column(new Column(name, TYPE_BLOB), this->schema_version())==0);
/**
@@ -92,18 +94,17 @@
Database(const char* path);
virtual ~Database();
+ // public setter/getter of class attr
+ uint32_t schema_version();
+ void schema_version(uint32_t v);
+
/**
* init_schema is called during db connection.
* Projects implementing a Database derived class
* should use Table::add_column() or the ADD_*
* macros in their init_schema() to define their schema
*/
- virtual int init_schema();
- /**
- * upgrade_schema should execute sql statements needed to
- * upgrade from fromversion to the current version
- */
- virtual int upgrade_schema(uint32_t fromversion);
+ virtual int init_schema();
const char* path();
const char* error();
@@ -177,6 +178,18 @@
int pre_connect();
int post_connect();
+ int upgrade_schema(uint32_t version);
+ int upgrade_internal_schema(uint32_t version);
+
+ int init_internal_schema();
+
+ int get_information_value(const char* variable, char** value);
+ int update_information_value(const char* variable, const char* value);
+
+ // get and set version info in actual database
+ int set_schema_version(uint32_t version);
+ uint32_t get_schema_version();
+
// execute query with printf-style format, does not cache statement
int sql_once(const char* fmt, ...);
// cache statement with name, execute query with printf-style format
@@ -188,6 +201,7 @@
// test if database has had its tables created
bool is_empty();
// create tables for the client
+ int create_table(Table* table);
int create_tables();
// create tables for ourselves
int create_internal_tables();
@@ -216,7 +230,7 @@
uint32_t m_schema_version;
Table* m_information_table;
- sqlite3_stmt m_get_information_value;
+ sqlite3_stmt* m_get_information_value;
Table** m_tables;
uint32_t m_table_count;
Modified: branches/PR-7593824/darwinup/Table.cpp
===================================================================
--- branches/PR-7593824/darwinup/Table.cpp 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/Table.cpp 2010-03-09 00:20:00 UTC (rev 749)
@@ -54,7 +54,8 @@
m_delete_sql = NULL;
m_prepared_insert = NULL;
m_prepared_update = NULL;
- m_prepared_delete = NULL;
+ m_prepared_delete = NULL;
+ m_version = 0;
}
Table::~Table() {
@@ -89,12 +90,16 @@
return m_name;
}
+uint32_t Table::version() {
+ return m_version;
+}
+
int Table::set_custom_create(const char* sql) {
this->m_custom_create_sql = strdup(sql);
return this->m_custom_create_sql == 0;
}
-int Table::add_column(Column* c) {
+int Table::add_column(Column* c, uint32_t schema_version) {
// accumulate offsets for columns in m_columns_size
c->m_offset = this->m_columns_size;
this->m_columns_size += c->size();
@@ -109,7 +114,7 @@
m_column_max *= REALLOC_FACTOR;
}
m_columns[m_column_count++] = c;
-
+ c->m_version = schema_version;
return 0;
}
@@ -471,6 +476,11 @@
return (const char*)m_create_sql;
}
+const char* Table::alter_add_column(uint32_t index) {
+ if (m_columns[index]) return m_columns[index]->alter(m_name);
+ return NULL;
+}
+
int Table::where_va_columns(uint32_t count, char* query, size_t size,
size_t* used, va_list args) {
char tmpstr[256];
Modified: branches/PR-7593824/darwinup/Table.h
===================================================================
--- branches/PR-7593824/darwinup/Table.h 2010-03-09 00:14:45 UTC (rev 748)
+++ branches/PR-7593824/darwinup/Table.h 2010-03-09 00:20:00 UTC (rev 749)
@@ -44,12 +44,13 @@
virtual ~Table();
const char* name();
+ uint32_t version();
// Add custom SQL to table initialization
int set_custom_create(const char* sql);
// Column handling
- int add_column(Column*);
+ int add_column(Column*, uint32_t schema_version);
Column* column(uint32_t index);
// get the result record offset for column at index
int offset(uint32_t index);
@@ -95,6 +96,7 @@
protected:
const char* create();
+ const char* alter_add_column(uint32_t index);
int where_va_columns(uint32_t count, char* query, size_t size,
size_t* used, va_list args);
@@ -106,6 +108,7 @@
void dump_results(FILE* f);
char* m_name;
+ uint32_t m_version; // schema version this was added
char* m_create_sql;
char* m_custom_create_sql;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/darwinbuild-changes/attachments/20100308/969426a3/attachment-0001.html>
More information about the darwinbuild-changes
mailing list