[27526] trunk/base/src
source_changes at macosforge.org
source_changes at macosforge.org
Mon Aug 6 13:13:12 PDT 2007
Revision: 27526
http://trac.macosforge.org/projects/macports/changeset/27526
Author: sfiera at macports.org
Date: 2007-08-06 13:13:12 -0700 (Mon, 06 Aug 2007)
Log Message:
-----------
Whew! Lots of stuff, including: * Transactions can now be delimited outside cregistry * Things that write *need* to be inside a write transaction * Created a real reg_registry object that keeps track of its state * Finally got rid of some sqlite3 char signed-ness errors * registry::entry map/unmap take lists instead of variable argument counts * Removed unique logic from `reg_entry_map` entirely; it's the wrong place
Modified Paths:
--------------
trunk/base/src/cregistry/entry.c
trunk/base/src/cregistry/entry.h
trunk/base/src/cregistry/registry.c
trunk/base/src/cregistry/registry.h
trunk/base/src/cregistry/sql.c
trunk/base/src/cregistry/sql.h
trunk/base/src/registry2.0/entry.c
trunk/base/src/registry2.0/entryobj.c
trunk/base/src/registry2.0/registry.c
trunk/base/src/registry2.0/registry.h
trunk/base/src/registry2.0/tests/common.tcl
trunk/base/src/registry2.0/tests/entry.tcl
Modified: trunk/base/src/cregistry/entry.c
===================================================================
--- trunk/base/src/cregistry/entry.c 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/cregistry/entry.c 2007-08-06 20:13:12 UTC (rev 27526)
@@ -141,7 +141,6 @@
if (i == entry_count) {
return 1;
}
- begin_exclusive(db);
if (sqlite3_prepare(db, query, -1, &stmt, NULL)
== SQLITE_OK) {
for (i=0; i<entry_count; i++) {
@@ -156,17 +155,14 @@
} else {
sqlite3_finalize(stmt);
reg_sqlite_error(db, errPtr, query);
- commit_transaction(db);
return 0;
}
}
sqlite3_finalize(stmt);
- commit_transaction(db);
return 1;
} else {
sqlite3_finalize(stmt);
reg_sqlite_error(db, errPtr, query);
- commit_transaction(db);
}
return 0;
}
@@ -178,12 +174,15 @@
* required. That's OK because there's only one place this function is called,
* and it's called with all of them there.
*/
-reg_entry* reg_entry_create(sqlite3* db, char* name, char* version,
+reg_entry* reg_entry_create(reg_registry* reg, char* name, char* version,
char* revision, char* variants, char* epoch, reg_error* errPtr) {
sqlite3_stmt* stmt;
char* query = "INSERT INTO registry.ports "
"(name, version, revision, variants, epoch) VALUES (?, ?, ?, ?, ?)";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if (!reg_test_writable(reg, errPtr)) {
+ return NULL;
+ }
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
== SQLITE_OK)
&& (sqlite3_bind_text(stmt, 2, version, -1, SQLITE_STATIC)
@@ -197,11 +196,11 @@
&& (sqlite3_step(stmt) == SQLITE_DONE)) {
char* query = "INSERT INTO entries (id, address) VALUES (?, ?)";
reg_entry* entry = malloc(sizeof(reg_entry));
- entry->id = sqlite3_last_insert_rowid(db);
- entry->db = db;
+ entry->id = sqlite3_last_insert_rowid(reg->db);
+ entry->db = reg->db;
entry->proc = NULL;
sqlite3_finalize(stmt);
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL)
== SQLITE_OK)
&& (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
&& (sqlite3_bind_blob(stmt, 2, &entry, sizeof(reg_entry*),
@@ -209,24 +208,24 @@
&& (sqlite3_step(stmt) == SQLITE_DONE)) {
return entry;
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
}
free(entry);
return NULL;
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return NULL;
}
}
-reg_entry* reg_entry_open(sqlite3* db, char* name, char* version,
+reg_entry* reg_entry_open(reg_registry* reg, char* name, char* version,
char* revision, char* variants, char* epoch, reg_error* errPtr) {
sqlite3_stmt* stmt;
char* query = "SELECT registry.ports.id, entries.address "
"FROM registry.ports LEFT OUTER JOIN entries USING (id) "
"WHERE name=? AND version=? AND revision=? AND variants=? AND epoch=?";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
== SQLITE_OK)
&& (sqlite3_bind_text(stmt, 2, version, -1, SQLITE_STATIC)
@@ -241,9 +240,9 @@
reg_entry* entry;
switch (r) {
case SQLITE_ROW:
- if (reg_stmt_to_entry(db, (void**)&entry, stmt, errPtr)) {
+ if (reg_stmt_to_entry(reg->db, (void**)&entry, stmt, errPtr)) {
sqlite3_finalize(stmt);
- if (reg_save_addresses(db, &entry, 1, errPtr)) {
+ if (reg_save_addresses(reg->db, &entry, 1, errPtr)) {
return entry;
}
}
@@ -253,13 +252,13 @@
errPtr->free = NULL;
break;
default:
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
break;
}
sqlite3_finalize(stmt);
return NULL;
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return NULL;
}
@@ -268,16 +267,19 @@
/**
* deletes an entry; still needs to be freed
*/
-int reg_entry_delete(sqlite3* db, reg_entry* entry, reg_error* errPtr) {
+int reg_entry_delete(reg_registry* reg, reg_entry* entry, reg_error* errPtr) {
sqlite3_stmt* stmt;
char* query = "DELETE FROM registry.ports WHERE id=?";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if (!reg_test_writable(reg, errPtr)) {
+ return 0;
+ }
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
&& (sqlite3_step(stmt) == SQLITE_DONE)) {
- if (sqlite3_changes(db) > 0) {
+ if (sqlite3_changes(reg->db) > 0) {
sqlite3_finalize(stmt);
query = "DELETE FROM entries WHERE id=?";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
&& (sqlite3_step(stmt) == SQLITE_DONE)) {
sqlite3_finalize(stmt);
@@ -289,7 +291,7 @@
errPtr->free = NULL;
}
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
}
sqlite3_finalize(stmt);
return 0;
@@ -298,7 +300,7 @@
/*
* Frees the given entry - not good to expose?
*/
-static void reg_entry_free(sqlite3* db UNUSED, reg_entry* entry) {
+static void reg_entry_free(reg_registry* reg UNUSED, reg_entry* entry) {
sqlite3_stmt* stmt;
if (entry->proc != NULL) {
free(entry->proc);
@@ -366,7 +368,7 @@
* Vulnerable to SQL-injection attacks in the `keys` field. Pass it valid keys,
* please.
*/
-int reg_entry_search(sqlite3* db, char** keys, char** vals, int key_count,
+int reg_entry_search(reg_registry* reg, char** keys, char** vals, int key_count,
int strategy, reg_entry*** entries, reg_error* errPtr) {
int i;
char* kwd = " WHERE ";
@@ -389,10 +391,10 @@
kwd = " AND ";
}
/* do the query */
- result = reg_all_objects(db, query, query_len, (void***)entries,
+ result = reg_all_objects(reg->db, query, query_len, (void***)entries,
reg_stmt_to_entry, (free_function*)reg_entry_free, errPtr);
if (result > 0) {
- if (!reg_save_addresses(db, *entries, result, errPtr)) {
+ if (!reg_save_addresses(reg->db, *entries, result, errPtr)) {
free(entries);
return 0;
}
@@ -407,14 +409,14 @@
* to `reg_entry_installed`.
* @todo add more arguments (epoch, revision, variants), maybe
*
- * @param [in] db registry database as created by `registry_open`
+ * @param [in] reg registry object as created by `registry_open`
* @param [in] name specific port to find (NULL for any)
* @param [in] version specific version to find (NULL for any)
* @param [out] entries list of ports meeting the criteria
* @param [out] errPtr description of error encountered, if any
* @return the number of such ports found
*/
-int reg_entry_imaged(sqlite3* db, char* name, char* version,
+int reg_entry_imaged(reg_registry* reg, char* name, char* version,
reg_entry*** entries, reg_error* errPtr) {
char* format;
char* query;
@@ -430,10 +432,10 @@
"AND version='%q'";
}
query = sqlite3_mprintf(format, select, name, version);
- result = reg_all_objects(db, query, -1, (void***)entries,
+ result = reg_all_objects(reg->db, query, -1, (void***)entries,
reg_stmt_to_entry, (free_function*)reg_entry_free, errPtr);
if (result > 0) {
- if (!reg_save_addresses(db, *entries, result, errPtr)) {
+ if (!reg_save_addresses(reg->db, *entries, result, errPtr)) {
free(entries);
return 0;
}
@@ -447,13 +449,13 @@
* dependencies, and properly own the files they map.
* @todo add more arguments (epoch, revision, variants), maybe
*
- * @param [in] db registry database as created by `registry_open`
+ * @param [in] reg registry object as created by `registry_open`
* @param [in] name specific port to find (NULL for any)
* @param [out] entries list of ports meeting the criteria
* @param [out] errPtr description of error encountered, if any
* @return the number of such ports found
*/
-int reg_entry_installed(sqlite3* db, char* name, reg_entry*** entries,
+int reg_entry_installed(reg_registry* reg, char* name, reg_entry*** entries,
reg_error* errPtr) {
char* format;
char* query;
@@ -466,10 +468,10 @@
format = "%s WHERE state='installed' AND name='%q'";
}
query = sqlite3_mprintf(format, select, name);
- result = reg_all_objects(db, query, -1, (void***)entries,
+ result = reg_all_objects(reg->db, query, -1, (void***)entries,
reg_stmt_to_entry, (free_function*)reg_entry_free, errPtr);
if (result > 0) {
- if (!reg_save_addresses(db, *entries, result, errPtr)) {
+ if (!reg_save_addresses(reg->db, *entries, result, errPtr)) {
free(entries);
return 0;
}
@@ -478,7 +480,7 @@
return result;
}
-int reg_entry_owner(sqlite3* db, char* path, reg_entry** entry,
+int reg_entry_owner(reg_registry* reg, char* path, reg_entry** entry,
reg_error* errPtr) {
sqlite3_stmt* stmt;
reg_entry* result;
@@ -486,15 +488,15 @@
"FROM registry.files INNER JOIN registry.ports USING(id)"
" LEFT OUTER JOIN entries USING(id) "
"WHERE path=? AND registry.ports.state = 'installed'";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
== SQLITE_OK)) {
int r = sqlite3_step(stmt);
switch (r) {
case SQLITE_ROW:
- if (reg_stmt_to_entry(db, (void**)&result, stmt, errPtr)) {
+ if (reg_stmt_to_entry(reg->db, (void**)&result, stmt, errPtr)) {
sqlite3_finalize(stmt);
- if (reg_save_addresses(db, &result, 1, errPtr)) {
+ if (reg_save_addresses(reg->db, &result, 1, errPtr)) {
*entry = result;
return 1;
}
@@ -509,22 +511,23 @@
return 0;
}
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return 0;
}
}
-int reg_entry_propget(sqlite3* db, reg_entry* entry, char* key, char** value,
- reg_error* errPtr) {
+int reg_entry_propget(reg_registry* reg, reg_entry* entry, char* key,
+ char** value, reg_error* errPtr) {
sqlite3_stmt* stmt;
- char* query = sqlite3_mprintf("SELECT %q FROM registry.ports "
- "WHERE id=%lld", key, entry->id);
- if (sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK) {
+ char* query;
+ query = sqlite3_mprintf("SELECT %q FROM registry.ports WHERE id=%lld", key,
+ entry->id);
+ if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
int r = sqlite3_step(stmt);
switch (r) {
case SQLITE_ROW:
- *value = strdup(sqlite3_column_text(stmt, 0));
+ *value = strdup((const char*)sqlite3_column_text(stmt, 0));
sqlite3_finalize(stmt);
return 1;
case SQLITE_DONE:
@@ -534,22 +537,26 @@
sqlite3_finalize(stmt);
return 0;
default:
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return 0;
}
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
return 0;
}
}
-int reg_entry_propset(sqlite3* db, reg_entry* entry, char* key, char* value,
- reg_error* errPtr) {
+int reg_entry_propset(reg_registry* reg, reg_entry* entry, char* key,
+ char* value, reg_error* errPtr) {
sqlite3_stmt* stmt;
- char* query = sqlite3_mprintf("UPDATE registry.ports SET %q = '%q' "
- "WHERE id=%lld", key, value, entry->id);
- if (sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK) {
+ char* query;
+ if (!reg_test_writable(reg, errPtr)) {
+ return -1;
+ }
+ query = sqlite3_mprintf("UPDATE registry.ports SET %q = '%q' WHERE id=%lld",
+ key, value, entry->id);
+ if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
int r = sqlite3_step(stmt);
switch (r) {
case SQLITE_DONE:
@@ -564,86 +571,63 @@
sqlite3_finalize(stmt);
return 0;
default:
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return 0;
}
}
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
return 0;
}
}
-int reg_entry_map(sqlite3* db, reg_entry* entry, char** files, int file_count,
- reg_error* errPtr) {
+int reg_entry_map(reg_registry* reg, reg_entry* entry, char** files,
+ int file_count, reg_error* errPtr) {
sqlite3_stmt* stmt;
- sqlite3_stmt* stmt2 = NULL;
char* insert = "INSERT INTO registry.files (id, path) VALUES (?, ?)";
- char* select = "SELECT registry.ports.name FROM registry.files "
- "INNER JOIN registry.ports USING(id) WHERE registry.files.path=? AND "
- "registry.ports.state = 'installed'";
- begin_exclusive(db);
- if ((sqlite3_prepare(db, insert, -1, &stmt, NULL) == SQLITE_OK)
- && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
- && (sqlite3_prepare(db, select, -1, &stmt2, NULL) == SQLITE_OK)) {
+ if (!reg_test_writable(reg, errPtr)) {
+ return -1;
+ }
+ if ((sqlite3_prepare(reg->db, insert, -1, &stmt, NULL) == SQLITE_OK)
+ && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
int i;
for (i=0; i<file_count; i++) {
- if ((sqlite3_bind_text(stmt2, 1, files[i], -1, SQLITE_STATIC)
- == SQLITE_OK)
- && (sqlite3_step(stmt2) == SQLITE_ROW)) {
- const char* port = sqlite3_column_text(stmt2, 0);
- errPtr->code = "registry::already-owned";
- errPtr->description = sqlite3_mprintf("file at path \"%s\" is "
- "already owned by port %s", files[i], port);
- errPtr->free = (reg_error_destructor*)sqlite3_free;
- sqlite3_finalize(stmt);
- sqlite3_finalize(stmt2);
- rollback_transaction(db);
- return -1;
- }
if (sqlite3_bind_text(stmt, 2, files[i], -1, SQLITE_STATIC)
== SQLITE_OK) {
int r = sqlite3_step(stmt);
switch (r) {
case SQLITE_DONE:
sqlite3_reset(stmt);
- sqlite3_reset(stmt2);
continue;
default:
- reg_sqlite_error(db, errPtr, insert);
+ reg_sqlite_error(reg->db, errPtr, insert);
sqlite3_finalize(stmt);
- sqlite3_finalize(stmt2);
- rollback_transaction(db);
return i;
}
} else {
- reg_sqlite_error(db, errPtr, insert);
+ reg_sqlite_error(reg->db, errPtr, insert);
sqlite3_finalize(stmt);
- sqlite3_finalize(stmt2);
- rollback_transaction(db);
return i;
}
}
sqlite3_finalize(stmt);
- sqlite3_finalize(stmt2);
- commit_transaction(db);
return file_count;
} else {
- reg_sqlite_error(db, errPtr, insert);
+ reg_sqlite_error(reg->db, errPtr, insert);
sqlite3_finalize(stmt);
- sqlite3_finalize(stmt2);
- commit_transaction(db);
return 0;
}
}
-int reg_entry_unmap(sqlite3* db, reg_entry* entry, char** files, int file_count,
- reg_error* errPtr) {
+int reg_entry_unmap(reg_registry* reg, reg_entry* entry, char** files,
+ int file_count, reg_error* errPtr) {
sqlite3_stmt* stmt;
char* query = "DELETE FROM registry.files WHERE id=? AND path=?";
- begin_exclusive(db);
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if (!reg_test_writable(reg, errPtr)) {
+ return -1;
+ }
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
int i;
for (i=0; i<file_count; i++) {
@@ -652,47 +636,42 @@
int r = sqlite3_step(stmt);
switch (r) {
case SQLITE_DONE:
- if (sqlite3_changes(db) == 0) {
+ if (sqlite3_changes(reg->db) == 0) {
errPtr->code = "registry::not-owned";
errPtr->description = "this entry does not own the "
"given file";
errPtr->free = NULL;
sqlite3_finalize(stmt);
- rollback_transaction(db);
return i;
} else {
sqlite3_reset(stmt);
continue;
}
default:
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
- rollback_transaction(db);
return i;
}
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
- rollback_transaction(db);
return i;
}
}
sqlite3_finalize(stmt);
- commit_transaction(db);
return file_count;
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
- commit_transaction(db);
return 0;
}
}
-int reg_entry_files(sqlite3* db, reg_entry* entry, char*** files,
+int reg_entry_files(reg_registry* reg, reg_entry* entry, char*** files,
reg_error* errPtr) {
sqlite3_stmt* stmt;
char* query = "SELECT path FROM registry.files WHERE id=? ORDER BY path";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
char** result = malloc(10*sizeof(char*));
int result_count = 0;
@@ -704,7 +683,7 @@
r = sqlite3_step(stmt);
switch (r) {
case SQLITE_ROW:
- element = strdup(sqlite3_column_text(stmt, 0));
+ element = strdup((const char*)sqlite3_column_text(stmt, 0));
reg_listcat((void*)&result, &result_count, &result_space,
element);
break;
@@ -715,7 +694,7 @@
free(result[i]);
}
free(result);
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return -1;
}
@@ -724,20 +703,20 @@
*files = result;
return result_count;
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return -1;
}
}
-int reg_all_entries(sqlite3* db, reg_entry*** entries, reg_error* errPtr) {
+int reg_all_entries(reg_registry* reg, reg_entry*** entries, reg_error* errPtr){
reg_entry* entry;
void** results = malloc(10*sizeof(void*));
int result_count = 0;
int result_space = 10;
sqlite3_stmt* stmt;
char* query = "SELECT address FROM entries";
- if (sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK) {
+ if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
int r;
do {
r = sqlite3_step(stmt);
@@ -749,7 +728,7 @@
case SQLITE_DONE:
break;
default:
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
free(results);
return -1;
}
Modified: trunk/base/src/cregistry/entry.h
===================================================================
--- trunk/base/src/cregistry/entry.h 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/cregistry/entry.h 2007-08-06 20:13:12 UTC (rev 27526)
@@ -48,38 +48,38 @@
char* proc; /* name of Tcl proc, if using Tcl */
} reg_entry;
-reg_entry* reg_entry_create(sqlite3* db, char* name, char* version,
+reg_entry* reg_entry_create(reg_registry* reg, char* name, char* version,
char* revision, char* variants, char* epoch, reg_error* errPtr);
-reg_entry* reg_entry_open(sqlite3* db, char* name, char* version,
+reg_entry* reg_entry_open(reg_registry* reg, char* name, char* version,
char* revision, char* variants, char* epoch, reg_error* errPtr);
-int reg_entry_delete(sqlite3* db, reg_entry* entry, reg_error* errPtr);
+int reg_entry_delete(reg_registry* reg, reg_entry* entry, reg_error* errPtr);
-int reg_entry_search(sqlite3* db, char** keys, char** vals, int key_count,
+int reg_entry_search(reg_registry* reg, char** keys, char** vals, int key_count,
int strategy, reg_entry*** entries, reg_error* errPtr);
-int reg_entry_imaged(sqlite3* db, char* name, char* version,
+int reg_entry_imaged(reg_registry* reg, char* name, char* version,
reg_entry*** entries, reg_error* errPtr);
-int reg_entry_installed(sqlite3* db, char* name, reg_entry*** entries,
+int reg_entry_installed(reg_registry* reg, char* name, reg_entry*** entries,
reg_error* errPtr);
-int reg_entry_owner(sqlite3* db, char* path, reg_entry** entry,
+int reg_entry_owner(reg_registry* reg, char* path, reg_entry** entry,
reg_error* errPtr);
-int reg_entry_propget(sqlite3* db, reg_entry* entry, char* key, char** value,
- reg_error* errPtr);
-int reg_entry_propset(sqlite3* db, reg_entry* entry, char* key, char* value,
- reg_error* errPtr);
+int reg_entry_propget(reg_registry* reg, reg_entry* entry, char* key,
+ char** value, reg_error* errPtr);
+int reg_entry_propset(reg_registry* reg, reg_entry* entry, char* key,
+ char* value, reg_error* errPtr);
-int reg_entry_map(sqlite3* db, reg_entry* entry, char** files, int file_count,
+int reg_entry_map(reg_registry* reg, reg_entry* entry, char** files, int file_count,
reg_error* errPtr);
-int reg_entry_unmap(sqlite3* db, reg_entry* entry, char** files, int file_count,
+int reg_entry_unmap(reg_registry* reg, reg_entry* entry, char** files, int file_count,
reg_error* errPtr);
-int reg_entry_files(sqlite3* db, reg_entry* entry, char*** files,
+int reg_entry_files(reg_registry* reg, reg_entry* entry, char*** files,
reg_error* errPtr);
-int reg_all_entries(sqlite3* db, reg_entry*** entries, reg_error* errPtr);
+int reg_all_entries(reg_registry*, reg_entry*** entries, reg_error* errPtr);
#endif /* _CENTRY_H */
Modified: trunk/base/src/cregistry/registry.c
===================================================================
--- trunk/base/src/cregistry/registry.c 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/cregistry/registry.c 2007-08-06 20:13:12 UTC (rev 27526)
@@ -61,38 +61,73 @@
}
}
-int reg_open(sqlite3** dbPtr, reg_error* errPtr) {
- if (sqlite3_open(NULL, dbPtr) == SQLITE_OK) {
- if (init_db(*dbPtr, errPtr)) {
+/**
+ * Creates a new registry object. To start using a registry, one must first be
+ * attached with `reg_attach`.
+ *
+ * @param [out] regPtr address of the allocated registry
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_open(reg_registry** regPtr, reg_error* errPtr) {
+ reg_registry* reg = malloc(sizeof(reg_registry));
+ if (sqlite3_open(NULL, ®->db) == SQLITE_OK) {
+ if (init_db(reg->db, errPtr)) {
+ reg->status = reg_none;
+ *regPtr = reg;
return 1;
- } else {
- sqlite3_close(*dbPtr);
- *dbPtr = NULL;
}
} else {
- reg_sqlite_error(*dbPtr, errPtr, NULL);
- sqlite3_close(*dbPtr);
- *dbPtr = NULL;
+ reg_sqlite_error(reg->db, errPtr, NULL);
}
+ sqlite3_close(reg->db);
+ free(reg);
return 0;
}
-int reg_close(sqlite3* db, reg_error* errPtr) {
- if (sqlite3_close((sqlite3*)db) == SQLITE_OK) {
+/**
+ * Closes a registry object. Will detach if necessary.
+ *
+ * @param [in] reg the registry to close
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_close(reg_registry* reg, reg_error* errPtr) {
+ if ((reg->status & reg_attached) && !reg_detach(reg, errPtr)) {
+ return 0;
+ }
+ if (sqlite3_close(reg->db) == SQLITE_OK) {
+ free(reg);
return 1;
} else {
errPtr->code = "registry::not-closed";
errPtr->description = sqlite3_mprintf("error: registry db not closed "
- "correctly (%s)\n", sqlite3_errmsg((sqlite3*)db));
+ "correctly (%s)\n", sqlite3_errmsg(reg->db));
errPtr->free = (reg_error_destructor*)sqlite3_free;
return 0;
}
}
-int reg_attach(sqlite3* db, const char* path, reg_error* errPtr) {
+/**
+ * Attaches a registry database to the registry object. Prior to calling this,
+ * the registry object is not actually connected to the registry. This function
+ * attaches it so it can be queried and manipulated.
+ *
+ * @param [in] reg the registry to attach to
+ * @param [in] path path to the registry db on disk
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_attach(reg_registry* reg, const char* path, reg_error* errPtr) {
struct stat sb;
int needsInit = 0; /* registry doesn't yet exist */
int canWrite = 1; /* can write to this location */
+ if (reg->status & reg_attached) {
+ errPtr->code = "registry::already-attached";
+ errPtr->description = "a database is already attached to this registry";
+ errPtr->free = NULL;
+ return 0;
+ }
if (stat(path, &sb) != 0) {
if (errno == ENOENT) {
needsInit = 1;
@@ -103,14 +138,15 @@
if (!needsInit || canWrite) {
sqlite3_stmt* stmt;
char* query = sqlite3_mprintf("ATTACH DATABASE '%q' AS registry", path);
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_step(stmt) == SQLITE_DONE)) {
sqlite3_finalize(stmt);
- if (!needsInit || (create_tables(db, errPtr))) {
+ if (!needsInit || (create_tables(reg->db, errPtr))) {
+ reg->status |= reg_attached;
return 1;
}
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
}
} else {
@@ -121,14 +157,29 @@
return 0;
}
-int reg_detach(sqlite3* db, reg_error* errPtr) {
+/**
+ * Detaches a registry database from the registry object. This does some cleanup
+ * for an attached registry, then detaches it. Allocated `reg_entry` objects are
+ * deleted here.
+ *
+ * @param [in] reg registry to detach from
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_detach(reg_registry* reg, reg_error* errPtr) {
sqlite3_stmt* stmt;
char* query = "DETACH DATABASE registry";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK)
+ if (!(reg->status & reg_attached)) {
+ errPtr->code = "registry::not-attached";
+ errPtr->description = "no database is attached to this registry";
+ errPtr->free = NULL;
+ return 0;
+ }
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
&& (sqlite3_step(stmt) == SQLITE_DONE)) {
sqlite3_finalize(stmt);
query = "SELECT address FROM entries";
- if (sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK) {
+ if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
int r;
reg_entry* entry;
do {
@@ -140,28 +191,116 @@
free(entry->proc);
}
free(entry);
- /* reg_entry_free(db, entry); */
+ /* reg_entry_free(reg->db, entry); */
break;
case SQLITE_DONE:
break;
default:
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
return 0;
}
} while (r != SQLITE_DONE);
}
sqlite3_finalize(stmt);
query = "DELETE FROM entries";
- if ((sqlite3_prepare(db, query, -1, &stmt, NULL) != SQLITE_OK)
+ if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) != SQLITE_OK)
|| (sqlite3_step(stmt) != SQLITE_DONE)) {
sqlite3_finalize(stmt);
return 0;
}
+ sqlite3_finalize(stmt);
+ reg->status &= ~reg_attached;
return 1;
} else {
- reg_sqlite_error(db, errPtr, query);
+ reg_sqlite_error(reg->db, errPtr, query);
sqlite3_finalize(stmt);
return 0;
}
}
+static int reg_start(reg_registry* reg, const char* query, reg_error* errPtr) {
+ if (reg->status & reg_transacting) {
+ errPtr->code = "registry::cant-start";
+ errPtr->description = "couldn't start transaction because a "
+ "transaction is already open";
+ errPtr->free = NULL;
+ return 0;
+ } else {
+ int result;
+ do {
+ result = sqlite3_exec(reg->db, query, NULL, NULL, NULL);
+ if (result == SQLITE_ERROR) {
+ reg_sqlite_error(reg->db, errPtr, NULL);
+ return 0;
+ }
+ } while (result != SQLITE_OK);
+ return 1;
+ }
+}
+
+int reg_start_read(reg_registry* reg, reg_error* errPtr) {
+ if (reg_start(reg, "BEGIN", errPtr)) {
+ reg->status |= reg_transacting;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int reg_start_write(reg_registry* reg, reg_error* errPtr) {
+ if (reg_start(reg, "BEGIN EXCLUSIVE", errPtr)) {
+ reg->status |= reg_transacting | reg_can_write;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int reg_end(reg_registry* reg, const char* query, reg_error* errPtr) {
+ if (!(reg->status & reg_transacting)) {
+ errPtr->code = "registry::cant-end";
+ errPtr->description = "couldn't end transaction because no transaction "
+ "is open";
+ errPtr->free = NULL;
+ return 0;
+ } else {
+ int result;
+ do {
+ result = sqlite3_exec(reg->db, query, NULL, NULL, NULL);
+ if (result == SQLITE_ERROR) {
+ reg_sqlite_error(reg->db, errPtr, NULL);
+ return 0;
+ }
+ } while (result != SQLITE_OK);
+ return 1;
+ }
+}
+
+int reg_commit(reg_registry* reg, reg_error* errPtr) {
+ if (reg_end(reg, "COMMIT", errPtr)) {
+ reg->status &= ~(reg_transacting | reg_can_write);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int reg_rollback(reg_registry* reg, reg_error* errPtr) {
+ if (reg_end(reg, "ROLLBACK", errPtr)) {
+ reg->status &= ~(reg_transacting | reg_can_write);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int reg_test_writable(reg_registry* reg, reg_error* errPtr) {
+ if (reg->status & reg_can_write) {
+ return 1;
+ } else {
+ errPtr->code = "registry::no-write";
+ errPtr->description = "a write transaction has not been started";
+ errPtr->free = NULL;
+ return 0;
+ }
+}
Modified: trunk/base/src/cregistry/registry.h
===================================================================
--- trunk/base/src/cregistry/registry.h 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/cregistry/registry.h 2007-08-06 20:13:12 UTC (rev 27526)
@@ -49,10 +49,29 @@
reg_error* errPtr);
typedef void (free_function)(void* userdata, void* item);
-int reg_open(sqlite3** dbPtr, reg_error* errPtr);
-int reg_close(sqlite3* db, reg_error* errPtr);
+enum {
+ reg_none = 0,
+ reg_attached = 1,
+ reg_transacting = 2,
+ reg_can_write = 4
+};
-int reg_attach(sqlite3* db, const char* path, reg_error* errPtr);
-int reg_detach(sqlite3* db, reg_error* errPtr);
+typedef struct {
+ sqlite3* db;
+ int status;
+} reg_registry;
+int reg_open(reg_registry** regPtr, reg_error* errPtr);
+int reg_close(reg_registry* reg, reg_error* errPtr);
+
+int reg_attach(reg_registry* reg, const char* path, reg_error* errPtr);
+int reg_detach(reg_registry* reg, reg_error* errPtr);
+
+int reg_start_read(reg_registry* reg, reg_error* errPtr);
+int reg_start_write(reg_registry* reg, reg_error* errPtr);
+int reg_commit(reg_registry* reg, reg_error* errPtr);
+int reg_rollback(reg_registry* reg, reg_error* errPtr);
+
+int reg_test_writable(reg_registry* reg, reg_error* errPtr);
+
#endif /* _CREG_H */
Modified: trunk/base/src/cregistry/sql.c
===================================================================
--- trunk/base/src/cregistry/sql.c 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/cregistry/sql.c 2007-08-06 20:13:12 UTC (rev 27526)
@@ -61,47 +61,6 @@
}
/**
- * Acquires an exclusive lock on the database.
- */
-void begin_exclusive(sqlite3* db) {
- int status;
- do {
- status = sqlite3_exec(db, "BEGIN EXCLUSIVE", NULL, NULL, NULL);
- } while (status != SQLITE_OK);
-}
-
-/**
- * Acquires a shared lock on the database.
- */
-void begin_shared(sqlite3* db) {
- int status;
- do {
- status = sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
- } while (status != SQLITE_OK);
-}
-
-/**
- * Releases a shared or exclusive lock on the database and rolls back changes
- */
-void rollback_transaction(sqlite3* db) {
- int status;
- char* err;
- do {
- status = sqlite3_exec(db, "ROLLBACK", NULL, NULL, &err);
- } while (status != SQLITE_OK);
-}
-
-/**
- * Releases a shared or exclusive lock on the database and commits changes
- */
-void commit_transaction(sqlite3* db) {
- int status;
- do {
- status = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
- } while (status != SQLITE_OK);
-}
-
-/**
* REGEXP function for sqlite3.
*
* Takes two arguments; the first is the value and the second the pattern. If
@@ -112,8 +71,8 @@
*/
static void sql_regexp(sqlite3_context* context, int argc UNUSED,
sqlite3_value** argv) {
- const char* value = sqlite3_value_text(argv[0]);
- const char* pattern = sqlite3_value_text(argv[1]);
+ const char* value = (const char*)sqlite3_value_text(argv[0]);
+ const char* pattern = (const char*)sqlite3_value_text(argv[1]);
switch (Tcl_RegExpMatch(NULL, value, pattern)) {
case 0:
sqlite3_result_int(context, 0);
@@ -298,7 +257,7 @@
"CREATE TABLE registry.files (id, path, mtime)",
"CREATE INDEX registry.file_port ON files (id)",
- "END",
+ "COMMIT",
NULL
};
return do_queries(db, queries, errPtr);
@@ -325,7 +284,7 @@
/* entry addresses */
"CREATE TEMPORARY TABLE entries (id, address)",
- "END",
+ "COMMIT",
NULL
};
Modified: trunk/base/src/cregistry/sql.h
===================================================================
--- trunk/base/src/cregistry/sql.h 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/cregistry/sql.h 2007-08-06 20:13:12 UTC (rev 27526)
@@ -36,11 +36,6 @@
#include <cregistry/registry.h>
-void begin_exclusive(sqlite3* db);
-void begin_shared(sqlite3* db);
-void rollback_transaction(sqlite3* db);
-void commit_transaction(sqlite3* db);
-
int create_tables(sqlite3* db, reg_error* errPtr);
int init_db(sqlite3* db, reg_error* errPtr);
Modified: trunk/base/src/registry2.0/entry.c
===================================================================
--- trunk/base/src/registry2.0/entry.c 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/registry2.0/entry.c 2007-08-06 20:13:12 UTC (rev 27526)
@@ -134,12 +134,12 @@
* and it's called with all of them there.
*/
static int entry_create(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc != 7) {
Tcl_WrongNumArgs(interp, 2, objv, "name version revision variants "
"epoch");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char* name = Tcl_GetString(objv[2]);
@@ -148,7 +148,7 @@
char* variants = Tcl_GetString(objv[5]);
char* epoch = Tcl_GetString(objv[6]);
reg_error error;
- reg_entry* entry = reg_entry_create(db, name, version, revision,
+ reg_entry* entry = reg_entry_create(reg, name, version, revision,
variants, epoch, &error);
if (entry != NULL) {
Tcl_Obj* result;
@@ -167,17 +167,17 @@
* Deletes an entry from the registry (then closes it).
*/
static int entry_delete(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "delete entry");
return TCL_ERROR;
- } if (db == NULL) {
+ } if (reg == NULL) {
return TCL_ERROR;
} else {
reg_entry* entry;
reg_error error;
if (obj_to_entry(interp, &entry, objv[2], &error)) {
- if (reg_entry_delete(db, entry, &error)) {
+ if (reg_entry_delete(reg, entry, &error)) {
Tcl_DeleteCommand(interp, Tcl_GetString(objv[2]));
return TCL_OK;
}
@@ -192,12 +192,12 @@
* Opens an entry matching the given parameters.
*/
static int entry_open(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc != 7) {
Tcl_WrongNumArgs(interp, 1, objv, "open portname version revision "
"variants epoch");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char* name = Tcl_GetString(objv[2]);
@@ -206,8 +206,8 @@
char* variants = Tcl_GetString(objv[5]);
char* epoch = Tcl_GetString(objv[6]);
reg_error error;
- reg_entry* entry = reg_entry_open(db, name, version, revision, variants,
- epoch, &error);
+ reg_entry* entry = reg_entry_open(reg, name, version, revision,
+ variants, epoch, &error);
if (entry != NULL) {
Tcl_Obj* result;
if (entry_to_obj(interp, &result, entry, &error)) {
@@ -252,11 +252,11 @@
*/
static int entry_search(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
int i;
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc % 2 == 1) {
Tcl_WrongNumArgs(interp, 2, objv, "search ?key value ...?");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char** keys;
@@ -279,7 +279,7 @@
keys[i] = Tcl_GetString(objv[2*i+2]);
vals[i] = Tcl_GetString(objv[2*i+3]);
}
- entry_count = reg_entry_search(db, keys, vals, key_count,
+ entry_count = reg_entry_search(reg, keys, vals, key_count,
reg_strategy_equal, &entries, &error);
if (entry_count >= 0) {
Tcl_Obj* resultObj;
@@ -333,17 +333,18 @@
* TODO: add more arguments (epoch, revision, variants), maybe
*/
static int entry_imaged(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc > 4) {
Tcl_WrongNumArgs(interp, 2, objv, "?name? ?version?");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char* name = (objc >= 3) ? Tcl_GetString(objv[2]) : NULL;
char* version = (objc == 4) ? Tcl_GetString(objv[3]) : NULL;
reg_entry** entries;
reg_error error;
+ int entry_count;
/* name or version of "" means not specified */
if (name != NULL && *name == '\0') {
name = NULL;
@@ -351,13 +352,11 @@
if (version != NULL && *version == '\0') {
version = NULL;
}
- int entry_count = reg_entry_imaged(db, name, version, &entries,
- &error);
+ entry_count = reg_entry_imaged(reg, name, version, &entries, &error);
if (entry_count >= 0) {
Tcl_Obj* resultObj;
Tcl_Obj** objs;
- list_entry_to_obj(interp, &objs, entries, entry_count,
- &error);
+ list_entry_to_obj(interp, &objs, entries, entry_count, &error);
resultObj = Tcl_NewListObj(entry_count, objs);
Tcl_SetObjResult(interp, resultObj);
free(entries);
@@ -379,27 +378,26 @@
* satisfying a dependency.
*/
static int entry_installed(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]){
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc > 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?name?");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char* name = (objc == 3) ? Tcl_GetString(objv[2]) : NULL;
reg_entry** entries;
reg_error error;
+ int entry_count;
/* name of "" means not specified */
if (name != NULL && *name == '\0') {
name = NULL;
}
- int entry_count = reg_entry_installed(db, name, &entries,
- &error);
+ entry_count = reg_entry_installed(reg, name, &entries, &error);
if (entry_count >= 0) {
Tcl_Obj* resultObj;
Tcl_Obj** objs;
- list_entry_to_obj(interp, &objs, entries, entry_count,
- &error);
+ list_entry_to_obj(interp, &objs, entries, entry_count, &error);
resultObj = Tcl_NewListObj(entry_count, objs);
Tcl_SetObjResult(interp, resultObj);
free(entries);
@@ -413,17 +411,17 @@
/**
*/
static int entry_owner(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "path");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char* path = Tcl_GetString(objv[2]);
reg_entry* entry;
reg_error error;
- if (reg_entry_owner(db, path, &entry, &error)) {
+ if (reg_entry_owner(reg, path, &entry, &error)) {
if (entry == NULL) {
return TCL_OK;
} else {
Modified: trunk/base/src/registry2.0/entryobj.c
===================================================================
--- trunk/base/src/registry2.0/entryobj.c 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/registry2.0/entryobj.c 2007-08-06 20:13:12 UTC (rev 27526)
@@ -59,21 +59,22 @@
static int entry_obj_prop(Tcl_Interp* interp, reg_entry* entry, int objc,
Tcl_Obj* CONST objv[]) {
int index;
- sqlite3* db = registry_db(interp, 1);
if (objc > 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?value?");
return TCL_ERROR;
- } else if (db == NULL) {
- return TCL_ERROR;
}
if (objc == 2) {
/* ${entry} prop; return the current value */
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ }
if (Tcl_GetIndexFromObj(interp, objv[1], entry_props, "prop", 0, &index)
== TCL_OK) {
char* key = Tcl_GetString(objv[1]);
char* value;
reg_error error;
- if (reg_entry_propget(db, entry, key, &value, &error)) {
+ if (reg_entry_propget(reg, entry, key, &value, &error)) {
Tcl_Obj* result = Tcl_NewStringObj(value, -1);
Tcl_SetObjResult(interp, result);
return TCL_OK;
@@ -83,12 +84,16 @@
return TCL_ERROR;
} else {
/* ${entry} prop name value; set a new value */
+ reg_registry* reg = registry_for(interp, reg_attached | reg_can_write);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ }
if (Tcl_GetIndexFromObj(interp, objv[1], entry_props, "prop", 0, &index)
== TCL_OK) {
char* key = Tcl_GetString(objv[1]);
char* value = Tcl_GetString(objv[2]);
reg_error error;
- if (reg_entry_propset(db, entry, key, value, &error)) {
+ if (reg_entry_propset(reg, entry, key, value, &error)) {
return TCL_OK;
}
return registry_failed(interp, &error);
@@ -98,7 +103,7 @@
}
/*
- * ${entry} map ?file ...?
+ * ${entry} map file-list
*
* Maps the listed files to the port represented by ${entry}. This will throw an
* error if a file is mapped to an already-existing file, but not a very
@@ -108,14 +113,22 @@
*/
static int entry_obj_map(Tcl_Interp* interp, reg_entry* entry, int objc,
Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
- if (db == NULL) {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 1, objv, "map file-list");
return TCL_ERROR;
+ } else if (reg == NULL) {
+ return TCL_ERROR;
} else {
char** files;
reg_error error;
- if (list_obj_to_string(&files, objv+2, objc-2, &error)) {
- if (reg_entry_map(db, entry, files, objc-2, &error) == objc-2) {
+ Tcl_Obj** listv;
+ int listc;
+ if (Tcl_ListObjGetElements(interp, objv[2], &listc, &listv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (list_obj_to_string(&files, listv, listc, &error)) {
+ if (reg_entry_map(reg, entry, files, listc, &error) == listc) {
return TCL_OK;
}
}
@@ -124,21 +137,29 @@
}
/*
- * ${entry} unmap ?file ...?
+ * ${entry} unmap file-list
*
* Unmaps the listed files from the given port. Will throw an error if a file
* that is not mapped to the port is attempted to be unmapped.
*/
static int entry_obj_unmap(Tcl_Interp* interp, reg_entry* entry, int objc,
Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
- if (db == NULL) {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 1, objv, "map file-list");
return TCL_ERROR;
+ } else if (reg == NULL) {
+ return TCL_ERROR;
} else {
char** files;
reg_error error;
- if (list_obj_to_string(&files, objv+2, objc-2, &error)) {
- if (reg_entry_unmap(db, entry, files, objc-2, &error) == objc-2) {
+ Tcl_Obj** listv;
+ int listc;
+ if (Tcl_ListObjGetElements(interp, objv[2], &listc, &listv) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (list_obj_to_string(&files, listv, listc, &error)) {
+ if (reg_entry_unmap(reg, entry, files, listc, &error) == listc) {
return TCL_OK;
}
}
@@ -148,26 +169,26 @@
static int entry_obj_files(Tcl_Interp* interp, reg_entry* entry, int objc,
Tcl_Obj* CONST objv[]) {
- sqlite3* db = registry_db(interp, 1);
+ reg_registry* reg = registry_for(interp, reg_attached);
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "files");
return TCL_ERROR;
- } else if (db == NULL) {
+ } else if (reg == NULL) {
return TCL_ERROR;
} else {
char** files;
reg_error error;
- int file_count = reg_entry_files(db, entry, &files, &error);
+ int file_count = reg_entry_files(reg, entry, &files, &error);
if (file_count >= 0) {
int i;
Tcl_Obj** objs;
if (list_string_to_obj(&objs, files, file_count, &error)) {
+ Tcl_Obj* result = Tcl_NewListObj(file_count, objs);
+ Tcl_SetObjResult(interp, result);
for (i=0; i<file_count; i++) {
free(files[i]);
}
free(files);
- Tcl_Obj* result = Tcl_NewListObj(file_count, objs);
- Tcl_SetObjResult(interp, result);
return TCL_OK;
}
for (i=0; i<file_count; i++) {
Modified: trunk/base/src/registry2.0/registry.c
===================================================================
--- trunk/base/src/registry2.0/registry.c 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/registry2.0/registry.c 2007-08-06 20:13:12 UTC (rev 27526)
@@ -33,7 +33,6 @@
#include <stdio.h>
#include <unistd.h>
#include <tcl.h>
-#include <sqlite3.h>
#include <cregistry/registry.h>
#include <cregistry/entry.h>
@@ -51,9 +50,10 @@
return TCL_ERROR;
}
-int registry_tcl_detach(Tcl_Interp* interp, sqlite3* db, reg_error* errPtr) {
+int registry_tcl_detach(Tcl_Interp* interp, reg_registry* reg,
+ reg_error* errPtr) {
reg_entry** entries;
- int entry_count = reg_all_entries(db, &entries, errPtr);
+ int entry_count = reg_all_entries(reg, &entries, errPtr);
if (entry_count >= 0) {
int i;
for (i=0; i<entry_count; i++) {
@@ -61,8 +61,7 @@
Tcl_DeleteCommand(interp, entries[i]->proc);
}
}
- if (reg_detach(db, errPtr)) {
- Tcl_SetAssocData(interp, "registry::attached", NULL, (void*)0);
+ if (reg_detach(reg, errPtr)) {
return 1;
}
}
@@ -73,21 +72,21 @@
* Deletes the sqlite3 DB associated with interp.
*
* This function will close an interp's associated DB, although there doesn't
- * seem to be a way of verifying that it happened properly. This will be a
- * problem if we get lazy and forget to finalize a sqlite3_stmt somewhere, so
- * this function will be noisy and complain if we do.
+ * seem to be a way of ensuring that it happened properly. This will be a
+ * problem if we get lazy and forget to finish a sqlite3_stmt somewhere, so this
+ * function will be noisy and complain if we do.
*
* Then it will leak memory :(
*/
-static void delete_db(ClientData db, Tcl_Interp* interp) {
+static void delete_reg(ClientData reg, Tcl_Interp* interp UNUSED) {
reg_error error;
- if (Tcl_GetAssocData(interp, "registry::attached", NULL)) {
- if (!registry_tcl_detach(interp, (sqlite3*)db, &error)) {
+ if (((reg_registry*)reg)->status & reg_attached) {
+ if (!registry_tcl_detach(interp, (reg_registry*)reg, &error)) {
fprintf(stderr, error.description);
reg_error_destruct(&error);
}
}
- if (!reg_close((sqlite3*)db, &error)) {
+ if (!reg_close((reg_registry*)reg, &error)) {
fprintf(stderr, error.description);
reg_error_destruct(&error);
}
@@ -108,25 +107,29 @@
*
* This function sets its own Tcl result.
*/
-sqlite3* registry_db(Tcl_Interp* interp, int attached) {
- sqlite3* db = Tcl_GetAssocData(interp, "registry::db", NULL);
- if (db == NULL) {
+reg_registry* registry_for(Tcl_Interp* interp, int status) {
+ reg_registry* reg = Tcl_GetAssocData(interp, "registry::reg", NULL);
+ if (reg == NULL) {
reg_error error;
- if (reg_open(&db, &error)) {
- Tcl_SetAssocData(interp, "registry::db", delete_db, db);
+ if (reg_open(®, &error)) {
+ Tcl_SetAssocData(interp, "registry::reg", delete_reg, reg);
} else {
registry_failed(interp, &error);
return NULL;
}
}
- if (attached) {
- if (!Tcl_GetAssocData(interp, "registry::attached", NULL)) {
+ if ((reg->status & status) != status) {
+ if (status & reg_can_write) {
+ Tcl_SetErrorCode(interp, "registry::no-write", NULL);
+ Tcl_SetResult(interp, "a write transaction has not been started",
+ TCL_STATIC);
+ } else {
Tcl_SetErrorCode(interp, "registry::not-open", NULL);
Tcl_SetResult(interp, "registry is not open", TCL_STATIC);
- db = NULL;
}
+ reg = NULL;
}
- return db;
+ return reg;
}
static int registry_open(ClientData clientData UNUSED, Tcl_Interp* interp,
@@ -136,11 +139,11 @@
return TCL_ERROR;
} else {
char* path = Tcl_GetString(objv[1]);
- sqlite3* db = registry_db(interp, 0);
+ reg_registry* reg = registry_for(interp, 0);
reg_error error;
- if (reg_attach(db, path, &error)) {
- Tcl_SetAssocData(interp, "registry::attached", NULL,
- (void*)1);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ } else if (reg_attach(reg, path, &error)) {
return TCL_OK;
} else {
return registry_failed(interp, &error);
@@ -154,12 +157,12 @@
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
} else {
- sqlite3* db = registry_db(interp, 1);
- if (db == NULL) {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
return TCL_ERROR;
} else {
reg_error error;
- if (registry_tcl_detach(interp, db, &error)) {
+ if (registry_tcl_detach(interp, reg, &error)) {
return TCL_OK;
}
return registry_failed(interp, &error);
@@ -168,6 +171,78 @@
return TCL_ERROR;
}
+static int registry_read(ClientData clientData UNUSED, Tcl_Interp* interp,
+ int objc, Tcl_Obj* CONST objv[]) {
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "command");
+ return TCL_ERROR;
+ } else {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ } else {
+ reg_error error;
+ if (reg_start_read(reg, &error)) {
+ int status = Tcl_EvalObjEx(interp, objv[1], 0);
+ switch (status) {
+ case TCL_OK:
+ if (reg_commit(reg, &error)) {
+ return TCL_OK;
+ }
+ break;
+ case TCL_BREAK:
+ if (reg_rollback(reg, &error)) {
+ return TCL_OK;
+ }
+ break;
+ default:
+ if (reg_rollback(reg, &error)) {
+ return status;
+ }
+ break;
+ }
+ }
+ return registry_failed(interp, &error);
+ }
+ }
+}
+
+static int registry_write(ClientData clientData UNUSED, Tcl_Interp* interp,
+ int objc, Tcl_Obj* CONST objv[]) {
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "command");
+ return TCL_ERROR;
+ } else {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ } else {
+ reg_error error;
+ if (reg_start_write(reg, &error)) {
+ int status = Tcl_EvalObjEx(interp, objv[1], 0);
+ switch (status) {
+ case TCL_OK:
+ if (reg_commit(reg, &error)) {
+ return TCL_OK;
+ }
+ break;
+ case TCL_BREAK:
+ if (reg_rollback(reg, &error)) {
+ return TCL_OK;
+ }
+ break;
+ default:
+ if (reg_rollback(reg, &error)) {
+ return status;
+ }
+ break;
+ }
+ }
+ return registry_failed(interp, &error);
+ }
+ }
+}
+
/**
* Initializer for the registry lib.
*
@@ -178,10 +253,10 @@
if (Tcl_InitStubs(interp, "8.3", 0) == NULL) {
return TCL_ERROR;
}
- Tcl_CreateObjCommand(interp, "registry::open", registry_open, NULL,
- NULL);
- Tcl_CreateObjCommand(interp, "registry::close", registry_close, NULL,
- NULL);
+ Tcl_CreateObjCommand(interp, "registry::open", registry_open, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "registry::close", registry_close, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "registry::read", registry_read, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "registry::write", registry_write, NULL, NULL);
/* Tcl_CreateObjCommand(interp, "registry::graph", GraphCmd, NULL, NULL); */
/* Tcl_CreateObjCommand(interp, "registry::item", item_cmd, NULL, NULL); */
Tcl_CreateObjCommand(interp, "registry::entry", entry_cmd, NULL, NULL);
Modified: trunk/base/src/registry2.0/registry.h
===================================================================
--- trunk/base/src/registry2.0/registry.h 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/registry2.0/registry.h 2007-08-06 20:13:12 UTC (rev 27526)
@@ -36,7 +36,7 @@
#include <sqlite3.h>
#include <cregistry/entry.h>
-sqlite3* registry_db(Tcl_Interp* interp, int attached);
+reg_registry* registry_for(Tcl_Interp* interp, int status);
int registry_failed(Tcl_Interp* interp, reg_error* errPtr);
#endif /* _REGISTRY_H */
Modified: trunk/base/src/registry2.0/tests/common.tcl
===================================================================
--- trunk/base/src/registry2.0/tests/common.tcl 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/registry2.0/tests/common.tcl 2007-08-06 20:13:12 UTC (rev 27526)
@@ -35,7 +35,7 @@
proc test_throws {statement error} {
uplevel 1 "\
- puts -nonewline {checking if $statement throws $error... }
+ puts -nonewline {checking if \[$statement\] throws $error... }
if {\[catch {$statement} error\]} { \n\
if {\$::errorCode == {$error}} {
puts yes
Modified: trunk/base/src/registry2.0/tests/entry.tcl
===================================================================
--- trunk/base/src/registry2.0/tests/entry.tcl 2007-08-06 20:13:00 UTC (rev 27525)
+++ trunk/base/src/registry2.0/tests/entry.tcl 2007-08-06 20:13:12 UTC (rev 27526)
@@ -5,35 +5,46 @@
proc main {pextlibname} {
load $pextlibname
- file delete -force test.db
+ file delete [glob -nocomplain test.db*]
# can't use registry before it's opened
- test_throws {registry::entry search} registry::not-open
+ test_throws {registry::write {}} registry::not-open
registry::open test.db
- # create some (somewhat contrived) ports to play with
- set vim1 [registry::entry create vim 7.1.000 0 {multibyte +} 0]
- set vim2 [registry::entry create vim 7.1.002 0 {} 0]
- set vim3 [registry::entry create vim 7.1.002 0 {multibyte +} 0]
- set zlib [registry::entry create zlib 1.2.3 1 {} 0]
- set pcre [registry::entry create pcre 7.1 1 {utf8 +} 0]
+ test_throws {registry::entry create vim 7.1.000 0 {multibyte +} 0} \
+ registry::no-write
- # check that their properties can be set
- $vim1 state imaged
- $vim2 state imaged
- $vim3 state installed
- $zlib state installed
- $pcre state imaged
+ # write transaction
+ registry::write {
+ # create some (somewhat contrived) ports to play with
+ set vim1 [registry::entry create vim 7.1.000 0 {multibyte +} 0]
+ set vim2 [registry::entry create vim 7.1.002 0 {} 0]
+ set vim3 [registry::entry create vim 7.1.002 0 {multibyte +} 0]
+ set zlib [registry::entry create zlib 1.2.3 1 {} 0]
+ set pcre [registry::entry create pcre 7.1 1 {utf8 +} 0]
+
+ # check that their properties can be set
+ $vim1 state imaged
+ $vim2 state imaged
+ $vim3 state installed
+ $zlib state installed
+ $pcre state imaged
+
+ }
+
# check that their properties can be retrieved
- test_equal {[$vim1 name]} vim
- test_equal {[$vim2 epoch]} 0
- test_equal {[$vim3 version]} 7.1.002
- test_equal {[$zlib revision]} 1
- test_equal {[$pcre variants]} {utf8 +}
+ # (also try a read transaction)
+ registry::read {
+ test_equal {[$vim1 name]} vim
+ test_equal {[$vim2 epoch]} 0
+ test_equal {[$vim3 version]} 7.1.002
+ test_equal {[$zlib revision]} 1
+ test_equal {[$pcre variants]} {utf8 +}
- set imaged [registry::entry imaged]
- set installed [registry::entry installed]
+ set imaged [registry::entry imaged]
+ set installed [registry::entry installed]
+ }
# check that imaged and installed give correct results
# have to sort these because their orders aren't defined
@@ -47,30 +58,44 @@
test_equal {[lsort $vim71002]} {[lsort "$vim2 $vim3"]}
# try mapping files and checking their owners
- $vim3 map
- $vim3 map /opt/local/bin/vim
- $vim3 map /opt/local/bin/vimdiff /opt/local/bin/vimtutor
- test_equal {[registry::entry owner /opt/local/bin/vimtutor]} {$vim3}
- test_equal {[registry::entry owner /opt/local/bin/emacs]} {}
+ registry::write {
+ $vim3 map [list /opt/local/bin/vim]
+ $vim3 map [list /opt/local/bin/vimdiff /opt/local/bin/vimtutor]
+ test_equal {[registry::entry owner /opt/local/bin/vimtutor]} {$vim3}
+ test_equal {[registry::entry owner /opt/local/bin/emacs]} {}
- test_equal {[$vim3 files]} {/opt/local/bin/vim /opt/local/bin/vimdiff /opt/local/bin/vimtutor}
- test_equal {[$zlib files]} {}
+ # don't have to sort because order is defined as alpha
+ test_equal {[$vim3 files]} {[list /opt/local/bin/vim \
+ /opt/local/bin/vimdiff /opt/local/bin/vimtutor]}
+ test_equal {[$zlib files]} {[list]}
- # try unmapping and remapping
- $vim3 unmap /opt/local/bin/vim
- test_equal {[registry::entry owner /opt/local/bin/vim]} {}
- $vim3 map /opt/local/bin/vim
- test_equal {[registry::entry owner /opt/local/bin/vim]} {$vim3}
+ # try unmapping and remapping
+ $vim3 unmap {/opt/local/bin/vim}
+ test_equal {[registry::entry owner /opt/local/bin/vim]} {}
+ $vim3 map {/opt/local/bin/vim}
+ test_equal {[registry::entry owner /opt/local/bin/vim]} {$vim3}
- # make sure you can't map an already-owned file or unmap one you don't
- test_throws {$zlib map /opt/local/bin/vim} registry::already-owned
- test_throws {$zlib unmap /opt/local/bin/vim} registry::not-owned
- test_throws {$zlib unmap /opt/local/bin/emacs} registry::not-owned
+ # make sure you can't unmap a file you don't own
+ test_throws {$zlib unmap [list /opt/local/bin/vim]} \
+ registry::not-owned
+ test_throws {$zlib unmap [list /opt/local/bin/emacs]} \
+ registry::not-owned
+ }
# delete pcre
test_equal {[registry::entry imaged pcre]} {$pcre}
- registry::entry delete $pcre
- test_throws {[registry::entry open pcre 7.1 1 {utf8 +} 0]} registry::not-found
+ # try rolling it back
+ registry::write {
+ registry::entry delete $pcre
+ break
+ }
+ test_equal {[registry::entry open pcre 7.1 1 {utf8 +} 0]} {$pcre}
+ # try actually deleting it
+ registry::write {
+ registry::entry delete $pcre
+ }
+ test_throws {registry::entry open pcre 7.1 1 {utf8 +} 0} \
+ registry::not-found
test {![registry::entry exists $pcre]}
# close vim1
@@ -78,8 +103,8 @@
registry::entry close $vim1
test {![registry::entry exists $vim1]}
- # close the registry; make sure the registry isn't usable after being closed
- # and ensure state persists between open sessions
+ # close the registry; make sure the registry isn't usable after being
+ # closed, then ensure state persists between open sessions
registry::close
test_throws {registry::entry search} registry::not-open
test {![registry::entry exists $vim3]}
@@ -93,12 +118,13 @@
set zlib [registry::entry open zlib 1.2.3 1 {} 0]
test {[registry::entry exists $zlib]}
- # check that pcre is gone
- test_throws {[registry::entry open pcre 7.1 1 {utf8 +} 0]} registry::not-found
+ # check that pcre is still gone
+ test_throws {registry::entry open pcre 7.1 1 {utf8 +} 0} \
+ registry::not-found
registry::close
- file delete -force test.db
+ file delete [glob -nocomplain test.db*]
}
source tests/common.tcl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070806/0a05791a/attachment.html
More information about the macports-changes
mailing list